town_gui.cpp

Go to the documentation of this file.
00001 /* $Id: town_gui.cpp 19119 2010-02-13 14:02:36Z rubidium $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "openttd.h"
00014 #include "town.h"
00015 #include "viewport_func.h"
00016 #include "gfx_func.h"
00017 #include "gui.h"
00018 #include "command_func.h"
00019 #include "company_func.h"
00020 #include "company_base.h"
00021 #include "company_gui.h"
00022 #include "network/network.h"
00023 #include "variables.h"
00024 #include "strings_func.h"
00025 #include "sound_func.h"
00026 #include "economy_func.h"
00027 #include "tilehighlight_func.h"
00028 #include "sortlist_type.h"
00029 #include "road_cmd.h"
00030 #include "landscape.h"
00031 #include "cargotype.h"
00032 #include "querystring_gui.h"
00033 #include "window_func.h"
00034 #include "townname_func.h"
00035 #include "townname_type.h"
00036 #include "core/geometry_func.hpp"
00037 #include "station_base.h"
00038 #include "depot_base.h"
00039 
00040 #include "table/sprites.h"
00041 #include "table/strings.h"
00042 
00043 typedef GUIList<const Town*> GUITownList;
00044 
00046 enum TownAuthorityWidgets {
00047   TWA_CAPTION,
00048   TWA_RATING_INFO,  
00049   TWA_COMMAND_LIST, 
00050   TWA_SCROLLBAR,
00051   TWA_ACTION_INFO,  
00052   TWA_EXECUTE,      
00053 };
00054 
00055 static const NWidgetPart _nested_town_authority_widgets[] = {
00056   NWidget(NWID_HORIZONTAL),
00057     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
00058     NWidget(WWT_CAPTION, COLOUR_BROWN, TWA_CAPTION), SetDataTip(STR_LOCAL_AUTHORITY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00059     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
00060     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
00061   EndContainer(),
00062   NWidget(WWT_PANEL, COLOUR_BROWN, TWA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), EndContainer(),
00063   NWidget(NWID_HORIZONTAL),
00064     NWidget(WWT_PANEL, COLOUR_BROWN, TWA_COMMAND_LIST), SetMinimalSize(305, 52), SetResize(1, 0), SetDataTip(0x0, STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP), EndContainer(),
00065     NWidget(WWT_SCROLLBAR, COLOUR_BROWN, TWA_SCROLLBAR),
00066   EndContainer(),
00067   NWidget(WWT_PANEL, COLOUR_BROWN, TWA_ACTION_INFO), SetMinimalSize(317, 52), SetResize(1, 0), EndContainer(),
00068   NWidget(NWID_HORIZONTAL),
00069     NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, TWA_EXECUTE),  SetMinimalSize(317, 12), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_LOCAL_AUTHORITY_DO_IT_BUTTON, STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP),
00070     NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
00071   EndContainer()
00072 };
00073 
00075 struct TownAuthorityWindow : Window {
00076 private:
00077   Town *town;    
00078   int sel_index; 
00079 
00089   static int GetNthSetBit(uint32 bits, int n)
00090   {
00091     if (n >= 0) {
00092       uint i;
00093       FOR_EACH_SET_BIT(i, bits) {
00094         n--;
00095         if (n < 0) return i;
00096       }
00097     }
00098     return -1;
00099   }
00100 
00101 public:
00102   TownAuthorityWindow(const WindowDesc *desc, WindowNumber window_number) : Window(), sel_index(-1)
00103   {
00104     this->town = Town::Get(window_number);
00105     this->InitNested(desc, window_number);
00106     this->vscroll.SetCapacity((this->GetWidget<NWidgetBase>(TWA_COMMAND_LIST)->current_y - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM) / FONT_HEIGHT_NORMAL);
00107   }
00108 
00109   virtual void OnPaint()
00110   {
00111     int numact;
00112     uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town);
00113 
00114     this->vscroll.SetCount(numact + 1);
00115 
00116     if (this->sel_index != -1 && !HasBit(buttons, this->sel_index)) {
00117       this->sel_index = -1;
00118     }
00119 
00120     this->SetWidgetDisabledState(TWA_EXECUTE, this->sel_index == -1);
00121 
00122     this->DrawWidgets();
00123     if (!this->IsShaded()) this->DrawRatings();
00124   }
00125 
00127   void DrawRatings()
00128   {
00129     NWidgetBase *nwid = this->GetWidget<NWidgetBase>(TWA_RATING_INFO);
00130     uint left = nwid->pos_x + WD_FRAMERECT_LEFT;
00131     uint right = nwid->pos_x + nwid->current_x - 1 - WD_FRAMERECT_RIGHT;
00132 
00133     uint y = nwid->pos_y + WD_FRAMERECT_TOP;
00134 
00135     DrawString(left, right, y, STR_LOCAL_AUTHORITY_COMPANY_RATINGS);
00136     y += FONT_HEIGHT_NORMAL;
00137 
00138     int sprite_y_offset = (FONT_HEIGHT_NORMAL - 10) / 2;
00139     bool rtl = _dynlang.text_dir == TD_RTL;
00140     uint text_left  = left + (rtl ? 0 : 26);
00141     uint text_right = right - (rtl ? 26 : 0);
00142     uint icon_left  = rtl ? right - 14 : left;
00143     uint blob_left  = rtl ? right - 24 : left + 16;
00144 
00145     /* Draw list of companies */
00146     const Company *c;
00147     FOR_ALL_COMPANIES(c) {
00148       if ((HasBit(this->town->have_ratings, c->index) || this->town->exclusivity == c->index)) {
00149         DrawCompanyIcon(c->index, icon_left, y + sprite_y_offset);
00150 
00151         SetDParam(0, c->index);
00152         SetDParam(1, c->index);
00153 
00154         int r = this->town->ratings[c->index];
00155         StringID str;
00156         (str = STR_CARGO_RATING_APPALLING, r <= RATING_APPALLING) || // Apalling
00157         (str++,                    r <= RATING_VERYPOOR)  || // Very Poor
00158         (str++,                    r <= RATING_POOR)      || // Poor
00159         (str++,                    r <= RATING_MEDIOCRE)  || // Mediocore
00160         (str++,                    r <= RATING_GOOD)      || // Good
00161         (str++,                    r <= RATING_VERYGOOD)  || // Very Good
00162         (str++,                    r <= RATING_EXCELLENT) || // Excellent
00163         (str++,                    true);                    // Outstanding
00164 
00165         SetDParam(2, str);
00166         if (this->town->exclusivity == c->index) { // red icon for company with exclusive rights
00167           DrawSprite(SPR_BLOT, PALETTE_TO_RED, blob_left, y + sprite_y_offset);
00168         }
00169 
00170         DrawString(text_left, text_right, y, STR_LOCAL_AUTHORITY_COMPANY_RATING);
00171         y += FONT_HEIGHT_NORMAL;
00172       }
00173     }
00174 
00175     y = y + WD_FRAMERECT_BOTTOM - nwid->pos_y; // Compute needed size of the widget.
00176     if (y > nwid->current_y) {
00177       /* If the company list is too big to fit, mark ourself dirty and draw again. */
00178       ResizeWindow(this, 0, y - nwid->current_y);
00179     }
00180   }
00181 
00182   virtual void SetStringParameters(int widget) const
00183   {
00184     if (widget == TWA_CAPTION) SetDParam(0, this->window_number);
00185   }
00186 
00187   virtual void DrawWidget(const Rect &r, int widget) const
00188   {
00189     switch (widget) {
00190       case TWA_ACTION_INFO:
00191         if (this->sel_index != -1) {
00192           SetDParam(0, _price[PR_TOWN_ACTION] * _town_action_costs[this->sel_index] >> 8);
00193           DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM,
00194                 STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING + this->sel_index);
00195         }
00196         break;
00197       case TWA_COMMAND_LIST: {
00198         int numact;
00199         uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town);
00200         int y = r.top + WD_FRAMERECT_TOP;
00201         int pos = this->vscroll.GetPosition();
00202 
00203         if (--pos < 0) {
00204           DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTIONS_TITLE);
00205           y += FONT_HEIGHT_NORMAL;
00206         }
00207 
00208         for (int i = 0; buttons; i++, buttons >>= 1) {
00209           if (pos <= -5) break; 
00210 
00211           if ((buttons & 1) && --pos < 0) {
00212             DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y,
00213                 STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i, this->sel_index == i ? TC_WHITE : TC_ORANGE);
00214             y += FONT_HEIGHT_NORMAL;
00215           }
00216         }
00217         break;
00218       }
00219     }
00220   }
00221 
00222   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00223   {
00224     switch (widget) {
00225       case TWA_ACTION_INFO: {
00226         assert(size->width > padding.width && size->height > padding.height);
00227         size->width -= WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
00228         size->height -= WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
00229         Dimension d = {0, 0};
00230         for (int i = 0; i < TACT_COUNT; i++) {
00231           SetDParam(0, _price[PR_TOWN_ACTION] * _town_action_costs[i] >> 8);
00232           d = maxdim(d, GetStringMultiLineBoundingBox(STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING + i, *size));
00233         }
00234         *size = maxdim(*size, d);
00235         size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
00236         size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
00237         break;
00238       }
00239 
00240       case TWA_COMMAND_LIST:
00241         size->height = WD_FRAMERECT_TOP + 5 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM;
00242         size->width = GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTIONS_TITLE).width;
00243         for (uint i = 0; i < TACT_COUNT; i++ ) {
00244           size->width = max(size->width, GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i).width);
00245         }
00246         size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
00247         break;
00248 
00249       case TWA_RATING_INFO:
00250         resize->height = FONT_HEIGHT_NORMAL;
00251         size->height = WD_FRAMERECT_TOP + 9 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM;
00252         break;
00253     }
00254   }
00255 
00256   virtual void OnClick(Point pt, int widget, int click_count)
00257   {
00258     switch (widget) {
00259       case TWA_COMMAND_LIST: {
00260         int y = (pt.y - this->GetWidget<NWidgetBase>(TWA_COMMAND_LIST)->pos_y - 1) / FONT_HEIGHT_NORMAL;
00261 
00262         if (!IsInsideMM(y, 0, 5)) return;
00263 
00264         y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_company, this->town), y + this->vscroll.GetPosition() - 1);
00265         if (y >= 0) {
00266           this->sel_index = y;
00267           this->SetDirty();
00268         }
00269         /* Fall through to clicking in case we are double-clicked */
00270         if (click_count == 1 || y < 0) break;
00271       }
00272 
00273       case TWA_EXECUTE:
00274         DoCommandP(this->town->xy, this->window_number, this->sel_index, CMD_DO_TOWN_ACTION | CMD_MSG(STR_ERROR_CAN_T_DO_THIS));
00275         break;
00276     }
00277   }
00278 
00279   virtual void OnHundredthTick()
00280   {
00281     this->SetDirty();
00282   }
00283 };
00284 
00285 static const WindowDesc _town_authority_desc(
00286   WDP_AUTO, 317, 222,
00287   WC_TOWN_AUTHORITY, WC_NONE,
00288   WDF_UNCLICK_BUTTONS,
00289   _nested_town_authority_widgets, lengthof(_nested_town_authority_widgets)
00290 );
00291 
00292 static void ShowTownAuthorityWindow(uint town)
00293 {
00294   AllocateWindowDescFront<TownAuthorityWindow>(&_town_authority_desc, town);
00295 }
00296 
00298 enum TownViewWidgets {
00299   TVW_CAPTION,
00300   TVW_VIEWPORT,
00301   TVW_INFOPANEL,
00302   TVW_CENTERVIEW,
00303   TVW_SHOWAUTHORITY,
00304   TVW_CHANGENAME,
00305   TVW_EXPAND,
00306   TVW_DELETE,
00307 };
00308 
00309 /* Town view window. */
00310 struct TownViewWindow : Window {
00311 private:
00312   Town *town; 
00313 
00314 public:
00315   enum {
00316     TVW_HEIGHT_NORMAL = 150,
00317   };
00318 
00319   TownViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
00320   {
00321     this->CreateNestedTree(desc);
00322 
00323     this->town = Town::Get(window_number);
00324     if (this->town->larger_town) this->GetWidget<NWidgetCore>(TVW_CAPTION)->widget_data = STR_TOWN_VIEW_CITY_CAPTION;
00325 
00326     this->FinishInitNested(desc, window_number);
00327 
00328     this->flags4 |= WF_DISABLE_VP_SCROLL;
00329     NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(TVW_VIEWPORT);
00330     nvp->InitializeViewport(this, this->town->xy, ZOOM_LVL_NEWS);
00331 
00332     /* disable renaming town in network games if you are not the server */
00333     this->SetWidgetDisabledState(TVW_CHANGENAME, _networking && !_network_server);
00334   }
00335 
00336   virtual void OnPaint()
00337   {
00338     this->DrawWidgets();
00339   }
00340 
00341   virtual void SetStringParameters(int widget) const
00342   {
00343     if (widget == TVW_CAPTION) SetDParam(0, this->town->index);
00344   }
00345 
00351   const CargoSpec *FindFirstCargoWithTownEffect(TownEffect effect) const
00352   {
00353     const CargoSpec *cs;
00354     FOR_ALL_CARGOSPECS(cs) {
00355       if (cs->town_effect == effect) return cs;
00356     }
00357     return NULL;
00358   }
00359 
00360   virtual void DrawWidget(const Rect &r, int widget) const
00361   {
00362     if (widget != TVW_INFOPANEL) return;
00363 
00364     uint y = r.top + WD_FRAMERECT_TOP;
00365 
00366     SetDParam(0, this->town->population);
00367     SetDParam(1, this->town->num_houses);
00368     DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, STR_TOWN_VIEW_POPULATION_HOUSES);
00369 
00370     SetDParam(0, this->town->act_pass);
00371     SetDParam(1, this->town->max_pass);
00372     DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_PASSENGERS_LAST_MONTH_MAX);
00373 
00374     SetDParam(0, this->town->act_mail);
00375     SetDParam(1, this->town->max_mail);
00376     DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX);
00377 
00378     StringID required_text = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED;
00379     uint cargo_needed_for_growth = 0;
00380     switch (_settings_game.game_creation.landscape) {
00381       case LT_ARCTIC:
00382         if (TilePixelHeight(this->town->xy) >= LowestSnowLine()) cargo_needed_for_growth = 1;
00383         if (TilePixelHeight(this->town->xy) < GetSnowLine()) required_text = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER;
00384         break;
00385 
00386       case LT_TROPIC:
00387         if (GetTropicZone(this->town->xy) == TROPICZONE_DESERT) cargo_needed_for_growth = 2;
00388         break;
00389 
00390       default: break;
00391     }
00392 
00393     if (cargo_needed_for_growth > 0) {
00394       DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH);
00395 
00396       bool rtl = _dynlang.text_dir == TD_RTL;
00397       uint cargo_text_left = r.left + WD_FRAMERECT_LEFT + (rtl ? 0 : 20);
00398       uint cargo_text_right = r.right - WD_FRAMERECT_RIGHT - (rtl ? 20 : 0);
00399 
00400       const CargoSpec *food = FindFirstCargoWithTownEffect(TE_FOOD);
00401       CargoID first_food_cargo = (food != NULL) ? food->Index() : (CargoID)CT_INVALID;
00402       StringID food_name       = (food != NULL) ? food->name    : STR_CARGO_PLURAL_FOOD;
00403 
00404       const CargoSpec *water = FindFirstCargoWithTownEffect(TE_WATER);
00405       CargoID first_water_cargo = (water != NULL) ? water->Index() : (CargoID)CT_INVALID;
00406       StringID water_name       = (water != NULL) ? water->name    : STR_CARGO_PLURAL_WATER;
00407 
00408       if (first_food_cargo != CT_INVALID && this->town->act_food > 0) {
00409         SetDParam(0, first_food_cargo);
00410         SetDParam(1, this->town->act_food);
00411         DrawString(cargo_text_left, cargo_text_right, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_LAST_MONTH);
00412       } else {
00413         SetDParam(0, food_name);
00414         DrawString(cargo_text_left, cargo_text_right, y += FONT_HEIGHT_NORMAL, required_text);
00415       }
00416 
00417       if (cargo_needed_for_growth > 1) {
00418         if (first_water_cargo != CT_INVALID && this->town->act_water > 0) {
00419           SetDParam(0, first_water_cargo);
00420           SetDParam(1, this->town->act_water);
00421           DrawString(cargo_text_left, cargo_text_right, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_LAST_MONTH);
00422         } else {
00423           SetDParam(0, water_name);
00424           DrawString(cargo_text_left, cargo_text_right, y += FONT_HEIGHT_NORMAL, required_text);
00425         }
00426       }
00427     }
00428 
00429     /* only show the town noise, if the noise option is activated. */
00430     if (_settings_game.economy.station_noise_level) {
00431       SetDParam(0, this->town->noise_reached);
00432       SetDParam(1, this->town->MaxTownNoise());
00433       DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_NOISE_IN_TOWN);
00434     }
00435   }
00436 
00437   virtual void OnClick(Point pt, int widget, int click_count)
00438   {
00439     switch (widget) {
00440       case TVW_CENTERVIEW: // scroll to location
00441         if (_ctrl_pressed) {
00442           ShowExtraViewPortWindow(this->town->xy);
00443         } else {
00444           ScrollMainWindowToTile(this->town->xy);
00445         }
00446         break;
00447 
00448       case TVW_SHOWAUTHORITY: // town authority
00449         ShowTownAuthorityWindow(this->window_number);
00450         break;
00451 
00452       case TVW_CHANGENAME: // rename
00453         SetDParam(0, this->window_number);
00454         ShowQueryString(STR_TOWN_NAME, STR_TOWN_VIEW_RENAME_TOWN_BUTTON, MAX_LENGTH_TOWN_NAME_BYTES, MAX_LENGTH_TOWN_NAME_PIXELS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT);
00455         break;
00456 
00457       case TVW_EXPAND: // expand town - only available on Scenario editor
00458         ExpandTown(this->town);
00459         break;
00460 
00461       case TVW_DELETE: // delete town - only available on Scenario editor
00462         if (this->CanDeleteTown()) {
00463           delete this->town;
00464         } else {
00465           ShowErrorMessage(STR_ERROR_TOWN_CAN_T_DELETE, INVALID_STRING_ID, 0, 0);
00466         }
00467         break;
00468     }
00469   }
00470 
00476   bool CanDeleteTown() const
00477   {
00478     /* Stations refer to towns. */
00479     const Station *st;
00480     FOR_ALL_STATIONS(st) {
00481       if (st->town == this->town) {
00482         /* Non-oil rig stations are always a problem. */
00483         if (!(st->facilities & FACIL_AIRPORT) || st->airport_type != AT_OILRIG) return false;
00484         /* We can only automatically delete oil rigs *if* there's no vehicle on them. */
00485         if (DoCommand(st->airport_tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR).Failed()) return false;
00486       }
00487     }
00488 
00489     /* Depots refer to towns. */
00490     const Depot *d;
00491     FOR_ALL_DEPOTS(d) {
00492       if (d->town_index == this->town->index) return false;
00493     }
00494 
00495     /* Check all tiles for town ownership. */
00496     for (TileIndex tile = 0; tile < MapSize(); ++tile) {
00497       switch (GetTileType(tile)) {
00498         case MP_ROAD:
00499           if (HasTownOwnedRoad(tile) && GetTownIndex(tile) == this->town->index) {
00500             /* Can we clear this tile? */
00501             if (DoCommand(tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR).Failed()) return false;
00502           }
00503           break;
00504 
00505         case MP_TUNNELBRIDGE:
00506           if (IsTileOwner(tile, OWNER_TOWN) &&
00507               ClosestTownFromTile(tile, UINT_MAX) == this->town) {
00508             /* Can we clear this bridge? */
00509             if (DoCommand(tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR).Failed()) return false;
00510           }
00511           break;
00512 
00513         default:
00514           break;
00515       }
00516     }
00517 
00518     return true;
00519   }
00520 
00521   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00522   {
00523     switch (widget) {
00524       case TVW_INFOPANEL:
00525         size->height = GetDesiredInfoHeight();
00526         break;
00527     }
00528   }
00529 
00534   uint GetDesiredInfoHeight() const
00535   {
00536     uint aimed_height = 3 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
00537 
00538     switch (_settings_game.game_creation.landscape) {
00539       case LT_ARCTIC:
00540         if (TilePixelHeight(this->town->xy) >= LowestSnowLine()) aimed_height += 2 * FONT_HEIGHT_NORMAL;
00541         break;
00542 
00543       case LT_TROPIC:
00544         if (GetTropicZone(this->town->xy) == TROPICZONE_DESERT) aimed_height += 3 * FONT_HEIGHT_NORMAL;
00545         break;
00546 
00547       default: break;
00548     }
00549 
00550     if (_settings_game.economy.station_noise_level) aimed_height += FONT_HEIGHT_NORMAL;
00551 
00552     return aimed_height;
00553   }
00554 
00555   void ResizeWindowAsNeeded()
00556   {
00557     const NWidgetBase *nwid_info = this->GetWidget<NWidgetBase>(TVW_INFOPANEL);
00558     uint aimed_height = GetDesiredInfoHeight();
00559     if (aimed_height > nwid_info->current_y || (aimed_height < nwid_info->current_y && nwid_info->current_y > nwid_info->smallest_y)) {
00560       this->ReInit();
00561     }
00562   }
00563 
00564   virtual void OnResize()
00565   {
00566     if (this->viewport != NULL) {
00567       NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(TVW_VIEWPORT);
00568       nvp->UpdateViewportCoordinates(this);
00569     }
00570   }
00571 
00572   virtual void OnInvalidateData(int data = 0)
00573   {
00574     /* Called when setting station noise have changed, in order to resize the window */
00575     this->SetDirty(); // refresh display for current size. This will allow to avoid glitches when downgrading
00576     this->ResizeWindowAsNeeded();
00577   }
00578 
00579   virtual void OnQueryTextFinished(char *str)
00580   {
00581     if (str == NULL) return;
00582 
00583     DoCommandP(0, this->window_number, 0, CMD_RENAME_TOWN | CMD_MSG(STR_ERROR_CAN_T_RENAME_TOWN), NULL, str);
00584   }
00585 };
00586 
00587 static const NWidgetPart _nested_town_game_view_widgets[] = {
00588   NWidget(NWID_HORIZONTAL),
00589     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
00590     NWidget(WWT_CAPTION, COLOUR_BROWN, TVW_CAPTION), SetDataTip(STR_TOWN_VIEW_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00591     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
00592     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
00593   EndContainer(),
00594   NWidget(WWT_PANEL, COLOUR_BROWN),
00595     NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2),
00596       NWidget(NWID_VIEWPORT, INVALID_COLOUR, TVW_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 0), SetResize(1, 1), SetPadding(1, 1, 1, 1),
00597     EndContainer(),
00598   EndContainer(),
00599   NWidget(WWT_PANEL, COLOUR_BROWN, TVW_INFOPANEL), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(),
00600   NWidget(NWID_HORIZONTAL),
00601     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
00602       NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, TVW_CENTERVIEW), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP),
00603       NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, TVW_SHOWAUTHORITY), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON, STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP),
00604       NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, TVW_CHANGENAME), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP),
00605     EndContainer(),
00606     NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
00607   EndContainer(),
00608 };
00609 
00610 static const WindowDesc _town_game_view_desc(
00611   WDP_AUTO, 260, TownViewWindow::TVW_HEIGHT_NORMAL,
00612   WC_TOWN_VIEW, WC_NONE,
00613   WDF_UNCLICK_BUTTONS,
00614   _nested_town_game_view_widgets, lengthof(_nested_town_game_view_widgets)
00615 );
00616 
00617 static const NWidgetPart _nested_town_editor_view_widgets[] = {
00618   NWidget(NWID_HORIZONTAL),
00619     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
00620     NWidget(WWT_CAPTION, COLOUR_BROWN, TVW_CAPTION), SetDataTip(STR_TOWN_VIEW_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00621     NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, TVW_CHANGENAME), SetMinimalSize(76, 14), SetDataTip(STR_BUTTON_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP),
00622     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
00623     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
00624   EndContainer(),
00625   NWidget(WWT_PANEL, COLOUR_BROWN),
00626     NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2),
00627       NWidget(NWID_VIEWPORT, INVALID_COLOUR, TVW_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 1), SetResize(1, 1), SetPadding(1, 1, 1, 1),
00628     EndContainer(),
00629   EndContainer(),
00630   NWidget(WWT_PANEL, COLOUR_BROWN, TVW_INFOPANEL), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(),
00631   NWidget(NWID_HORIZONTAL),
00632     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
00633       NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, TVW_CENTERVIEW), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP),
00634       NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, TVW_EXPAND), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_EXPAND_BUTTON, STR_TOWN_VIEW_EXPAND_TOOLTIP),
00635       NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, TVW_DELETE), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_DELETE_BUTTON, STR_TOWN_VIEW_DELETE_TOOLTIP),
00636     EndContainer(),
00637     NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
00638   EndContainer(),
00639 };
00640 
00641 static const WindowDesc _town_editor_view_desc(
00642   WDP_AUTO, 260, TownViewWindow::TVW_HEIGHT_NORMAL,
00643   WC_TOWN_VIEW, WC_NONE,
00644   WDF_UNCLICK_BUTTONS,
00645   _nested_town_editor_view_widgets, lengthof(_nested_town_editor_view_widgets)
00646 );
00647 
00648 void ShowTownViewWindow(TownID town)
00649 {
00650   if (_game_mode == GM_EDITOR) {
00651     AllocateWindowDescFront<TownViewWindow>(&_town_editor_view_desc, town);
00652   } else {
00653     AllocateWindowDescFront<TownViewWindow>(&_town_game_view_desc, town);
00654   }
00655 }
00656 
00658 enum TownDirectoryWidgets {
00659   TDW_SORTNAME,
00660   TDW_SORTPOPULATION,
00661   TDW_CENTERTOWN,
00662   TDW_SCROLLBAR,
00663   TDW_BOTTOM_PANEL,
00664   TDW_BOTTOM_TEXT,
00665 };
00666 
00667 static const NWidgetPart _nested_town_directory_widgets[] = {
00668   NWidget(NWID_HORIZONTAL),
00669     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
00670     NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_TOWN_DIRECTORY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00671     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
00672     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
00673   EndContainer(),
00674   NWidget(NWID_HORIZONTAL),
00675     NWidget(NWID_VERTICAL),
00676       NWidget(NWID_HORIZONTAL),
00677         NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, TDW_SORTNAME), SetMinimalSize(99, 12), SetDataTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0),
00678         NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, TDW_SORTPOPULATION), SetMinimalSize(97, 12), SetDataTip(STR_SORT_BY_CAPTION_POPULATION, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0),
00679       EndContainer(),
00680       NWidget(WWT_PANEL, COLOUR_BROWN, TDW_CENTERTOWN), SetMinimalSize(196, 164), SetDataTip(0x0, STR_TOWN_DIRECTORY_LIST_TOOLTIP),
00681               SetFill(1, 0), SetResize(0, 10), EndContainer(),
00682       NWidget(WWT_PANEL, COLOUR_BROWN, TDW_BOTTOM_PANEL),
00683         NWidget(WWT_TEXT, COLOUR_BROWN, TDW_BOTTOM_TEXT), SetPadding(2, 0, 0, 2), SetMinimalSize(196, 12), SetFill(1, 0), SetDataTip(STR_TOWN_POPULATION, STR_NULL),
00684       EndContainer(),
00685     EndContainer(),
00686     NWidget(NWID_VERTICAL),
00687       NWidget(WWT_SCROLLBAR, COLOUR_BROWN, TDW_SCROLLBAR),
00688       NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
00689     EndContainer(),
00690   EndContainer(),
00691 };
00692 
00694 struct TownDirectoryWindow : public Window {
00695 private:
00696   /* Runtime saved values */
00697   static Listing last_sorting;
00698   static const Town *last_town;
00699 
00700   /* Constants for sorting towns */
00701   static GUITownList::SortFunction * const sorter_funcs[];
00702 
00703   GUITownList towns;
00704 
00705   void BuildSortTownList()
00706   {
00707     if (this->towns.NeedRebuild()) {
00708       this->towns.Clear();
00709 
00710       const Town *t;
00711       FOR_ALL_TOWNS(t) {
00712         *this->towns.Append() = t;
00713       }
00714 
00715       this->towns.Compact();
00716       this->towns.RebuildDone();
00717       this->vscroll.SetCount(this->towns.Length()); // Update scrollbar as well.
00718     }
00719     /* Always sort the towns. */
00720     this->last_town = NULL;
00721     this->towns.Sort();
00722   }
00723 
00725   static int CDECL TownNameSorter(const Town * const *a, const Town * const *b)
00726   {
00727     static char buf_cache[64];
00728     const Town *ta = *a;
00729     const Town *tb = *b;
00730     char buf[64];
00731 
00732     SetDParam(0, ta->index);
00733     GetString(buf, STR_TOWN_NAME, lastof(buf));
00734 
00735     /* If 'b' is the same town as in the last round, use the cached value
00736      * We do this to speed stuff up ('b' is called with the same value a lot of
00737      * times after eachother) */
00738     if (tb != last_town) {
00739       last_town = tb;
00740       SetDParam(0, tb->index);
00741       GetString(buf_cache, STR_TOWN_NAME, lastof(buf_cache));
00742     }
00743 
00744     return strcmp(buf, buf_cache);
00745   }
00746 
00748   static int CDECL TownPopulationSorter(const Town * const *a, const Town * const *b)
00749   {
00750     return (*a)->population - (*b)->population;
00751   }
00752 
00753 public:
00754   TownDirectoryWindow(const WindowDesc *desc) : Window()
00755   {
00756     this->towns.SetListing(this->last_sorting);
00757     this->towns.SetSortFuncs(TownDirectoryWindow::sorter_funcs);
00758     this->towns.ForceRebuild();
00759     this->BuildSortTownList();
00760 
00761     this->InitNested(desc, 0);
00762   }
00763 
00764   ~TownDirectoryWindow()
00765   {
00766     this->last_sorting = this->towns.GetListing();
00767   }
00768 
00769   virtual void OnPaint()
00770   {
00771     this->DrawWidgets();
00772   }
00773 
00774   virtual void SetStringParameters(int widget) const
00775   {
00776     if (widget == TDW_BOTTOM_TEXT) SetDParam(0, GetWorldPopulation());
00777   }
00778 
00779   virtual void DrawWidget(const Rect &r, int widget) const
00780   {
00781     switch (widget) {
00782       case TDW_SORTNAME:
00783         if (this->towns.SortType() == 0) this->DrawSortButtonState(widget, this->towns.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
00784         break;
00785 
00786       case TDW_SORTPOPULATION:
00787         if (this->towns.SortType() != 0) this->DrawSortButtonState(widget, this->towns.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
00788         break;
00789 
00790       case TDW_CENTERTOWN: {
00791         int n = 0;
00792         int y = r.top + WD_FRAMERECT_TOP;
00793         if (this->towns.Length() == 0) { // No towns available.
00794           DrawString(r.left + WD_FRAMERECT_LEFT, r.right, y, STR_TOWN_DIRECTORY_NONE);
00795           break;
00796         }
00797         /* At least one town available. */
00798         for (uint i = this->vscroll.GetPosition(); i < this->towns.Length(); i++) {
00799           const Town *t = this->towns[i];
00800 
00801           assert(t->xy != INVALID_TILE);
00802 
00803           SetDParam(0, t->index);
00804           SetDParam(1, t->population);
00805           DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TOWN_DIRECTORY_TOWN);
00806 
00807           y += this->resize.step_height;
00808           if (++n == this->vscroll.GetCapacity()) break; // max number of towns in 1 window
00809         }
00810       } break;
00811     }
00812   }
00813 
00814   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00815   {
00816     switch (widget) {
00817       case TDW_SORTNAME:
00818       case TDW_SORTPOPULATION: {
00819         Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
00820         d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the word is centered, also looks nice.
00821         d.height += padding.height;
00822         *size = maxdim(*size, d);
00823         break;
00824       }
00825       case TDW_CENTERTOWN: {
00826         Dimension d = GetStringBoundingBox(STR_TOWN_DIRECTORY_NONE);
00827         for (uint i = 0; i < this->towns.Length(); i++) {
00828           const Town *t = this->towns[i];
00829 
00830           assert(t != NULL);
00831 
00832           SetDParam(0, t->index);
00833           SetDParam(1, 10000000); // 10^7
00834           d = maxdim(d, GetStringBoundingBox(STR_TOWN_DIRECTORY_TOWN));
00835         }
00836         d.width += padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
00837         d.height += padding.height;
00838         *size = maxdim(*size, d);
00839         resize->height = d.height;
00840         break;
00841       }
00842       case TDW_BOTTOM_TEXT: {
00843         SetDParam(0, 1000000000); // 10^9
00844         Dimension d = GetStringBoundingBox(STR_TOWN_POPULATION);
00845         d.width += padding.width;
00846         d.height += padding.height;
00847         *size = maxdim(*size, d);
00848         break;
00849       }
00850     }
00851   }
00852 
00853   virtual void OnClick(Point pt, int widget, int click_count)
00854   {
00855     switch (widget) {
00856       case TDW_SORTNAME: // Sort by Name ascending/descending
00857         if (this->towns.SortType() == 0) {
00858           this->towns.ToggleSortOrder();
00859         } else {
00860           this->towns.SetSortType(0);
00861         }
00862         this->BuildSortTownList();
00863         this->SetDirty();
00864         break;
00865 
00866       case TDW_SORTPOPULATION: // Sort by Population ascending/descending
00867         if (this->towns.SortType() == 1) {
00868           this->towns.ToggleSortOrder();
00869         } else {
00870           this->towns.SetSortType(1);
00871         }
00872         this->BuildSortTownList();
00873         this->SetDirty();
00874         break;
00875 
00876       case TDW_CENTERTOWN: { // Click on Town Matrix
00877         uint16 id_v = (pt.y - this->GetWidget<NWidgetBase>(widget)->pos_y - WD_FRAMERECT_TOP) / this->resize.step_height;
00878 
00879         if (id_v >= this->vscroll.GetCapacity()) return; // click out of bounds
00880 
00881         id_v += this->vscroll.GetPosition();
00882 
00883         if (id_v >= this->towns.Length()) return; // click out of town bounds
00884 
00885         const Town *t = this->towns[id_v];
00886         assert(t != NULL);
00887         if (_ctrl_pressed) {
00888           ShowExtraViewPortWindow(t->xy);
00889         } else {
00890           ScrollMainWindowToTile(t->xy);
00891         }
00892         break;
00893       }
00894     }
00895   }
00896 
00897   virtual void OnHundredthTick()
00898   {
00899     this->BuildSortTownList();
00900     this->SetDirty();
00901   }
00902 
00903   virtual void OnResize()
00904   {
00905     this->vscroll.SetCapacityFromWidget(this, TDW_CENTERTOWN);
00906   }
00907 
00908   virtual void OnInvalidateData(int data)
00909   {
00910     if (data == 0) {
00911       this->towns.ForceRebuild();
00912     } else {
00913       this->towns.ForceResort();
00914     }
00915     this->BuildSortTownList();
00916   }
00917 };
00918 
00919 Listing TownDirectoryWindow::last_sorting = {false, 0};
00920 const Town *TownDirectoryWindow::last_town = NULL;
00921 
00922 /* Available town directory sorting functions */
00923 GUITownList::SortFunction * const TownDirectoryWindow::sorter_funcs[] = {
00924   &TownNameSorter,
00925   &TownPopulationSorter,
00926 };
00927 
00928 static const WindowDesc _town_directory_desc(
00929   WDP_AUTO, 208, 202,
00930   WC_TOWN_DIRECTORY, WC_NONE,
00931   WDF_UNCLICK_BUTTONS,
00932   _nested_town_directory_widgets, lengthof(_nested_town_directory_widgets)
00933 );
00934 
00935 void ShowTownDirectory()
00936 {
00937   if (BringWindowToFrontById(WC_TOWN_DIRECTORY, 0)) return;
00938   new TownDirectoryWindow(&_town_directory_desc);
00939 }
00940 
00941 void CcFoundTown(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
00942 {
00943   if (result.Failed()) return;
00944 
00945   SndPlayTileFx(SND_1F_SPLAT, tile);
00946   if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
00947 }
00948 
00949 void CcFoundRandomTown(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
00950 {
00951   if (result.Succeeded()) ScrollMainWindowToTile(Town::Get(_new_town_id)->xy);
00952 }
00953 
00955 enum TownScenarioEditorWidgets {
00956   TSEW_BACKGROUND,
00957   TSEW_NEWTOWN,
00958   TSEW_RANDOMTOWN,
00959   TSEW_MANYRANDOMTOWNS,
00960   TSEW_TOWNNAME_TEXT,
00961   TSEW_TOWNNAME_EDITBOX,
00962   TSEW_TOWNNAME_RANDOM,
00963   TSEW_TOWNSIZE,
00964   TSEW_SIZE_SMALL,
00965   TSEW_SIZE_MEDIUM,
00966   TSEW_SIZE_LARGE,
00967   TSEW_SIZE_RANDOM,
00968   TSEW_CITY,
00969   TSEW_TOWNLAYOUT,
00970   TSEW_LAYOUT_ORIGINAL,
00971   TSEW_LAYOUT_BETTER,
00972   TSEW_LAYOUT_GRID2,
00973   TSEW_LAYOUT_GRID3,
00974   TSEW_LAYOUT_RANDOM,
00975 };
00976 
00977 static const NWidgetPart _nested_found_town_widgets[] = {
00978   NWidget(NWID_HORIZONTAL),
00979     NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
00980     NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_FOUND_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00981     NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN),
00982     NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
00983   EndContainer(),
00984   /* Construct new town(s) buttons. */
00985   NWidget(WWT_PANEL, COLOUR_DARK_GREEN, TSEW_BACKGROUND),
00986     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
00987     NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_NEWTOWN), SetMinimalSize(156, 12), SetFill(1, 0),
00988                     SetDataTip(STR_FOUND_TOWN_NEW_TOWN_BUTTON, STR_FOUND_TOWN_NEW_TOWN_TOOLTIP), SetPadding(0, 2, 1, 2),
00989     NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_RANDOMTOWN), SetMinimalSize(156, 12), SetFill(1, 0),
00990                     SetDataTip(STR_FOUND_TOWN_RANDOM_TOWN_BUTTON, STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP), SetPadding(0, 2, 1, 2),
00991     NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_MANYRANDOMTOWNS), SetMinimalSize(156, 12), SetFill(1, 0),
00992                     SetDataTip(STR_FOUND_TOWN_MANY_RANDOM_TOWNS, STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP), SetPadding(0, 2, 0, 2),
00993     /* Town name selection. */
00994     NWidget(WWT_LABEL, COLOUR_DARK_GREEN, TSEW_TOWNSIZE), SetMinimalSize(156, 14), SetPadding(0, 2, 0, 2), SetDataTip(STR_FOUND_TOWN_NAME_TITLE, STR_NULL),
00995     NWidget(WWT_EDITBOX, COLOUR_WHITE, TSEW_TOWNNAME_EDITBOX), SetMinimalSize(156, 12), SetPadding(0, 2, 3, 2),
00996                     SetDataTip(STR_FOUND_TOWN_NAME_EDITOR_TITLE, STR_FOUND_TOWN_NAME_EDITOR_HELP),
00997     NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_TOWNNAME_RANDOM), SetMinimalSize(78, 12), SetPadding(0, 2, 0, 2), SetFill(1, 0),
00998                     SetDataTip(STR_FOUND_TOWN_NAME_RANDOM_BUTTON, STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP),
00999     /* Town size selection. */
01000     NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
01001       NWidget(NWID_SPACER), SetFill(1, 0),
01002       NWidget(WWT_LABEL, COLOUR_DARK_GREEN, TSEW_TOWNSIZE), SetMinimalSize(148, 14), SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_TITLE, STR_NULL),
01003       NWidget(NWID_SPACER), SetFill(1, 0),
01004     EndContainer(),
01005     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2),
01006       NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_SIZE_SMALL), SetMinimalSize(78, 12), SetFill(1, 0),
01007                     SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP),
01008       NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_SIZE_MEDIUM), SetMinimalSize(78, 12), SetFill(1, 0),
01009                     SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP),
01010     EndContainer(),
01011     NWidget(NWID_SPACER), SetMinimalSize(0, 1),
01012     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2),
01013       NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_SIZE_LARGE), SetMinimalSize(78, 12), SetFill(1, 0),
01014                     SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP),
01015       NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_SIZE_RANDOM), SetMinimalSize(78, 12), SetFill(1, 0),
01016                     SetDataTip(STR_FOUND_TOWN_SIZE_RANDOM, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP),
01017     EndContainer(),
01018     NWidget(NWID_SPACER), SetMinimalSize(0, 3),
01019     NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_CITY), SetPadding(0, 2, 0, 2), SetMinimalSize(156, 12), SetFill(1, 0),
01020                     SetDataTip(STR_FOUND_TOWN_CITY, STR_FOUND_TOWN_CITY_TOOLTIP), SetFill(1, 0),
01021     /* Town roads selection. */
01022     NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
01023       NWidget(NWID_SPACER), SetFill(1, 0),
01024       NWidget(WWT_LABEL, COLOUR_DARK_GREEN, TSEW_TOWNLAYOUT), SetMinimalSize(148, 14), SetDataTip(STR_FOUND_TOWN_ROAD_LAYOUT, STR_NULL),
01025       NWidget(NWID_SPACER), SetFill(1, 0),
01026     EndContainer(),
01027     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2),
01028       NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_LAYOUT_ORIGINAL), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT),
01029       NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_LAYOUT_BETTER), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT),
01030     EndContainer(),
01031     NWidget(NWID_SPACER), SetMinimalSize(0, 1),
01032     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2),
01033       NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_LAYOUT_GRID2), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT),
01034       NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_LAYOUT_GRID3), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT),
01035     EndContainer(),
01036     NWidget(NWID_SPACER), SetMinimalSize(0, 1),
01037     NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_LAYOUT_RANDOM), SetPadding(0, 2, 0, 2), SetMinimalSize(0, 12), SetFill(1, 0),
01038                     SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), SetFill(1, 0),
01039     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
01040   EndContainer(),
01041 };
01042 
01044 struct FoundTownWindow : QueryStringBaseWindow {
01045 private:
01046   TownSize town_size;     
01047   TownLayout town_layout; 
01048   bool city;              
01049   bool townnamevalid;     
01050   uint32 townnameparts;   
01051   TownNameParams params;  
01052 
01053 public:
01054   FoundTownWindow(const WindowDesc *desc, WindowNumber window_number) :
01055       QueryStringBaseWindow(MAX_LENGTH_TOWN_NAME_BYTES),
01056       town_size(TS_MEDIUM),
01057       town_layout(_settings_game.economy.town_layout),
01058       params(_settings_game.game_creation.town_name)
01059   {
01060     this->InitNested(desc, window_number);
01061     InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, MAX_LENGTH_TOWN_NAME_PIXELS);
01062     this->RandomTownName();
01063     this->UpdateButtons(true);
01064     this->SetFocusedWidget(TSEW_TOWNNAME_EDITBOX);
01065   }
01066 
01067   void RandomTownName()
01068   {
01069     this->townnamevalid = GenerateTownName(&this->townnameparts);
01070 
01071     if (!this->townnamevalid) {
01072       this->edit_str_buf[0] = '\0';
01073     } else {
01074       GetTownName(this->edit_str_buf, &this->params, this->townnameparts, &this->edit_str_buf[this->edit_str_size - 1]);
01075     }
01076     UpdateTextBufferSize(&this->text);
01077     UpdateOSKOriginalText(this, TSEW_TOWNNAME_EDITBOX);
01078 
01079     this->SetWidgetDirty(TSEW_TOWNNAME_EDITBOX);
01080   }
01081 
01082   void UpdateButtons(bool check_availability)
01083   {
01084     if (check_availability && _game_mode != GM_EDITOR) {
01085       this->SetWidgetsDisabledState(true, TSEW_RANDOMTOWN, TSEW_MANYRANDOMTOWNS, TSEW_SIZE_LARGE, WIDGET_LIST_END);
01086       this->SetWidgetsDisabledState(_settings_game.economy.found_town != TF_CUSTOM_LAYOUT,
01087           TSEW_LAYOUT_ORIGINAL, TSEW_LAYOUT_BETTER, TSEW_LAYOUT_GRID2, TSEW_LAYOUT_GRID3, TSEW_LAYOUT_RANDOM, WIDGET_LIST_END);
01088       if (_settings_game.economy.found_town != TF_CUSTOM_LAYOUT) town_layout = _settings_game.economy.town_layout;
01089     }
01090 
01091     for (int i = TSEW_SIZE_SMALL; i <= TSEW_SIZE_RANDOM; i++) {
01092       this->SetWidgetLoweredState(i, i == TSEW_SIZE_SMALL + this->town_size);
01093     }
01094 
01095     this->SetWidgetLoweredState(TSEW_CITY, this->city);
01096 
01097     for (int i = TSEW_LAYOUT_ORIGINAL; i <= TSEW_LAYOUT_RANDOM; i++) {
01098       this->SetWidgetLoweredState(i, i == TSEW_LAYOUT_ORIGINAL + this->town_layout);
01099     }
01100 
01101     this->SetDirty();
01102   }
01103 
01104   void ExecuteFoundTownCommand(TileIndex tile, bool random, StringID errstr, CommandCallback cc)
01105   {
01106     const char *name = NULL;
01107 
01108     if (!this->townnamevalid) {
01109       name = this->edit_str_buf;
01110     } else {
01111       /* If user changed the name, send it */
01112       char buf[MAX_LENGTH_TOWN_NAME_BYTES];
01113       GetTownName(buf, &this->params, this->townnameparts, lastof(buf));
01114       if (strcmp(buf, this->edit_str_buf) != 0) name = this->edit_str_buf;
01115     }
01116 
01117     bool success = DoCommandP(tile, this->town_size | this->city << 2 | this->town_layout << 3 | random << 6,
01118         townnameparts, CMD_FOUND_TOWN | CMD_MSG(errstr), cc, name);
01119 
01120     if (success) this->RandomTownName();
01121   }
01122 
01123   virtual void OnPaint()
01124   {
01125     this->DrawWidgets();
01126     if (!this->IsShaded()) this->DrawEditBox(TSEW_TOWNNAME_EDITBOX);
01127   }
01128 
01129   virtual void OnClick(Point pt, int widget, int click_count)
01130   {
01131     switch (widget) {
01132       case TSEW_NEWTOWN:
01133         HandlePlacePushButton(this, TSEW_NEWTOWN, SPR_CURSOR_TOWN, HT_RECT, NULL);
01134         break;
01135 
01136       case TSEW_RANDOMTOWN:
01137         this->HandleButtonClick(TSEW_RANDOMTOWN);
01138         this->ExecuteFoundTownCommand(0, true, STR_ERROR_CAN_T_GENERATE_TOWN, CcFoundRandomTown);
01139         break;
01140 
01141       case TSEW_TOWNNAME_RANDOM:
01142         this->RandomTownName();
01143         this->SetFocusedWidget(TSEW_TOWNNAME_EDITBOX);
01144         break;
01145 
01146       case TSEW_MANYRANDOMTOWNS:
01147         this->HandleButtonClick(TSEW_MANYRANDOMTOWNS);
01148 
01149         _generating_world = true;
01150         UpdateNearestTownForRoadTiles(true);
01151         if (!GenerateTowns(this->town_layout)) {
01152           ShowErrorMessage(STR_ERROR_CAN_T_GENERATE_TOWN, STR_ERROR_NO_SPACE_FOR_TOWN, 0, 0);
01153         }
01154         UpdateNearestTownForRoadTiles(false);
01155         _generating_world = false;
01156         break;
01157 
01158       case TSEW_SIZE_SMALL: case TSEW_SIZE_MEDIUM: case TSEW_SIZE_LARGE: case TSEW_SIZE_RANDOM:
01159         this->town_size = (TownSize)(widget - TSEW_SIZE_SMALL);
01160         this->UpdateButtons(false);
01161         break;
01162 
01163       case TSEW_CITY:
01164         this->city ^= true;
01165         this->SetWidgetLoweredState(TSEW_CITY, this->city);
01166         this->SetDirty();
01167         break;
01168 
01169       case TSEW_LAYOUT_ORIGINAL: case TSEW_LAYOUT_BETTER: case TSEW_LAYOUT_GRID2:
01170       case TSEW_LAYOUT_GRID3: case TSEW_LAYOUT_RANDOM:
01171         this->town_layout = (TownLayout)(widget - TSEW_LAYOUT_ORIGINAL);
01172         this->UpdateButtons(false);
01173         break;
01174     }
01175   }
01176 
01177   virtual void OnTimeout()
01178   {
01179     this->RaiseWidget(TSEW_RANDOMTOWN);
01180     this->RaiseWidget(TSEW_MANYRANDOMTOWNS);
01181     this->SetDirty();
01182   }
01183 
01184   virtual void OnMouseLoop()
01185   {
01186     this->HandleEditBox(TSEW_TOWNNAME_EDITBOX);
01187   }
01188 
01189   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
01190   {
01191     EventState state;
01192     if (this->HandleEditBoxKey(TSEW_TOWNNAME_EDITBOX, key, keycode, state) == HEBR_CANCEL) {
01193       this->UnfocusFocusedWidget();
01194     }
01195     return state;
01196   }
01197 
01198   virtual void OnPlaceObject(Point pt, TileIndex tile)
01199   {
01200     this->ExecuteFoundTownCommand(tile, false, STR_ERROR_CAN_T_FOUND_TOWN_HERE, CcFoundTown);
01201   }
01202 
01203   virtual void OnPlaceObjectAbort()
01204   {
01205     this->RaiseButtons();
01206     this->UpdateButtons(false);
01207   }
01208 
01209   virtual void OnInvalidateData(int)
01210   {
01211     this->UpdateButtons(true);
01212   }
01213 };
01214 
01215 static const WindowDesc _found_town_desc(
01216   WDP_AUTO, 160, 162,
01217   WC_FOUND_TOWN, WC_NONE,
01218   WDF_CONSTRUCTION,
01219   _nested_found_town_widgets, lengthof(_nested_found_town_widgets)
01220 );
01221 
01222 void ShowFoundTownWindow()
01223 {
01224   if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return;
01225   AllocateWindowDescFront<FoundTownWindow>(&_found_town_desc, 0);
01226 }

Generated on Wed Mar 31 22:43:30 2010 for OpenTTD by  doxygen 1.6.1