town_gui.cpp

Go to the documentation of this file.
00001 /* $Id: town_gui.cpp 21627 2010-12-24 15:08:19Z alberth $ */
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 "strings_func.h"
00024 #include "sound_func.h"
00025 #include "economy_func.h"
00026 #include "tilehighlight_func.h"
00027 #include "sortlist_type.h"
00028 #include "road_cmd.h"
00029 #include "landscape.h"
00030 #include "cargotype.h"
00031 #include "querystring_gui.h"
00032 #include "window_func.h"
00033 #include "townname_func.h"
00034 #include "townname_type.h"
00035 #include "core/geometry_func.hpp"
00036 #include "genworld.h"
00037 #include "sprite.h"
00038 
00039 #include "table/sprites.h"
00040 #include "table/strings.h"
00041 
00042 typedef GUIList<const Town*> GUITownList;
00043 
00045 enum TownAuthorityWidgets {
00046   TWA_CAPTION,
00047   TWA_RATING_INFO,  
00048   TWA_COMMAND_LIST, 
00049   TWA_SCROLLBAR,
00050   TWA_ACTION_INFO,  
00051   TWA_EXECUTE,      
00052 };
00053 
00054 static const NWidgetPart _nested_town_authority_widgets[] = {
00055   NWidget(NWID_HORIZONTAL),
00056     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
00057     NWidget(WWT_CAPTION, COLOUR_BROWN, TWA_CAPTION), SetDataTip(STR_LOCAL_AUTHORITY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00058     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
00059     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
00060   EndContainer(),
00061   NWidget(WWT_PANEL, COLOUR_BROWN, TWA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), EndContainer(),
00062   NWidget(NWID_HORIZONTAL),
00063     NWidget(WWT_PANEL, COLOUR_BROWN, TWA_COMMAND_LIST), SetMinimalSize(305, 52), SetResize(1, 0), SetDataTip(0x0, STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP), SetScrollbar(TWA_SCROLLBAR), EndContainer(),
00064     NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, TWA_SCROLLBAR),
00065   EndContainer(),
00066   NWidget(WWT_PANEL, COLOUR_BROWN, TWA_ACTION_INFO), SetMinimalSize(317, 52), SetResize(1, 0), EndContainer(),
00067   NWidget(NWID_HORIZONTAL),
00068     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),
00069     NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
00070   EndContainer()
00071 };
00072 
00074 struct TownAuthorityWindow : Window {
00075 private:
00076   Town *town;    
00077   int sel_index; 
00078   Scrollbar *vscroll;
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 = this->GetScrollbar(TWA_SCROLLBAR);
00107     this->vscroll->SetCapacity((this->GetWidget<NWidgetBase>(TWA_COMMAND_LIST)->current_y - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM) / FONT_HEIGHT_NORMAL);
00108   }
00109 
00110   virtual void OnPaint()
00111   {
00112     int numact;
00113     uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town);
00114 
00115     this->vscroll->SetCount(numact + 1);
00116 
00117     if (this->sel_index != -1 && !HasBit(buttons, this->sel_index)) {
00118       this->sel_index = -1;
00119     }
00120 
00121     this->SetWidgetDisabledState(TWA_EXECUTE, this->sel_index == -1);
00122 
00123     this->DrawWidgets();
00124     if (!this->IsShaded()) this->DrawRatings();
00125   }
00126 
00128   void DrawRatings()
00129   {
00130     NWidgetBase *nwid = this->GetWidget<NWidgetBase>(TWA_RATING_INFO);
00131     uint left = nwid->pos_x + WD_FRAMERECT_LEFT;
00132     uint right = nwid->pos_x + nwid->current_x - 1 - WD_FRAMERECT_RIGHT;
00133 
00134     uint y = nwid->pos_y + WD_FRAMERECT_TOP;
00135 
00136     DrawString(left, right, y, STR_LOCAL_AUTHORITY_COMPANY_RATINGS);
00137     y += FONT_HEIGHT_NORMAL;
00138 
00139     Dimension icon_size = GetSpriteSize(SPR_COMPANY_ICON);
00140     int icon_width      = icon_size.width;
00141     int icon_y_offset   = (FONT_HEIGHT_NORMAL - icon_size.height) / 2;
00142 
00143     Dimension exclusive_size = GetSpriteSize(SPR_EXCLUSIVE_TRANSPORT);
00144     int exclusive_width      = exclusive_size.width;
00145     int exclusive_y_offset   = (FONT_HEIGHT_NORMAL - exclusive_size.height) / 2;
00146 
00147     bool rtl = _current_text_dir == TD_RTL;
00148     uint text_left      = left  + (rtl ? 0 : icon_width + exclusive_width + 4);
00149     uint text_right     = right - (rtl ? icon_width + exclusive_width + 4 : 0);
00150     uint icon_left      = rtl ? right - icon_width : left;
00151     uint exclusive_left = rtl ? right - icon_width - exclusive_width - 2 : left + icon_width + 2;
00152 
00153     /* Draw list of companies */
00154     const Company *c;
00155     FOR_ALL_COMPANIES(c) {
00156       if ((HasBit(this->town->have_ratings, c->index) || this->town->exclusivity == c->index)) {
00157         DrawCompanyIcon(c->index, icon_left, y + icon_y_offset);
00158 
00159         SetDParam(0, c->index);
00160         SetDParam(1, c->index);
00161 
00162         int r = this->town->ratings[c->index];
00163         StringID str;
00164         (str = STR_CARGO_RATING_APPALLING, r <= RATING_APPALLING) || // Apalling
00165         (str++,                    r <= RATING_VERYPOOR)  || // Very Poor
00166         (str++,                    r <= RATING_POOR)      || // Poor
00167         (str++,                    r <= RATING_MEDIOCRE)  || // Mediocore
00168         (str++,                    r <= RATING_GOOD)      || // Good
00169         (str++,                    r <= RATING_VERYGOOD)  || // Very Good
00170         (str++,                    r <= RATING_EXCELLENT) || // Excellent
00171         (str++,                    true);                    // Outstanding
00172 
00173         SetDParam(2, str);
00174         if (this->town->exclusivity == c->index) {
00175           DrawSprite(SPR_EXCLUSIVE_TRANSPORT, COMPANY_SPRITE_COLOUR(c->index), exclusive_left, y + exclusive_y_offset);
00176         }
00177 
00178         DrawString(text_left, text_right, y, STR_LOCAL_AUTHORITY_COMPANY_RATING);
00179         y += FONT_HEIGHT_NORMAL;
00180       }
00181     }
00182 
00183     y = y + WD_FRAMERECT_BOTTOM - nwid->pos_y; // Compute needed size of the widget.
00184     if (y > nwid->current_y) {
00185       /* If the company list is too big to fit, mark ourself dirty and draw again. */
00186       ResizeWindow(this, 0, y - nwid->current_y);
00187     }
00188   }
00189 
00190   virtual void SetStringParameters(int widget) const
00191   {
00192     if (widget == TWA_CAPTION) SetDParam(0, this->window_number);
00193   }
00194 
00195   virtual void DrawWidget(const Rect &r, int widget) const
00196   {
00197     switch (widget) {
00198       case TWA_ACTION_INFO:
00199         if (this->sel_index != -1) {
00200           SetDParam(0, _price[PR_TOWN_ACTION] * _town_action_costs[this->sel_index] >> 8);
00201           DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM,
00202                 STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING + this->sel_index);
00203         }
00204         break;
00205       case TWA_COMMAND_LIST: {
00206         int numact;
00207         uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town);
00208         int y = r.top + WD_FRAMERECT_TOP;
00209         int pos = this->vscroll->GetPosition();
00210 
00211         if (--pos < 0) {
00212           DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTIONS_TITLE);
00213           y += FONT_HEIGHT_NORMAL;
00214         }
00215 
00216         for (int i = 0; buttons; i++, buttons >>= 1) {
00217           if (pos <= -5) break; 
00218 
00219           if ((buttons & 1) && --pos < 0) {
00220             DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y,
00221                 STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i, this->sel_index == i ? TC_WHITE : TC_ORANGE);
00222             y += FONT_HEIGHT_NORMAL;
00223           }
00224         }
00225         break;
00226       }
00227     }
00228   }
00229 
00230   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00231   {
00232     switch (widget) {
00233       case TWA_ACTION_INFO: {
00234         assert(size->width > padding.width && size->height > padding.height);
00235         size->width -= WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
00236         size->height -= WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
00237         Dimension d = {0, 0};
00238         for (int i = 0; i < TACT_COUNT; i++) {
00239           SetDParam(0, _price[PR_TOWN_ACTION] * _town_action_costs[i] >> 8);
00240           d = maxdim(d, GetStringMultiLineBoundingBox(STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING + i, *size));
00241         }
00242         *size = maxdim(*size, d);
00243         size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
00244         size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
00245         break;
00246       }
00247 
00248       case TWA_COMMAND_LIST:
00249         size->height = WD_FRAMERECT_TOP + 5 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM;
00250         size->width = GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTIONS_TITLE).width;
00251         for (uint i = 0; i < TACT_COUNT; i++ ) {
00252           size->width = max(size->width, GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i).width);
00253         }
00254         size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
00255         break;
00256 
00257       case TWA_RATING_INFO:
00258         resize->height = FONT_HEIGHT_NORMAL;
00259         size->height = WD_FRAMERECT_TOP + 9 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM;
00260         break;
00261     }
00262   }
00263 
00264   virtual void OnClick(Point pt, int widget, int click_count)
00265   {
00266     switch (widget) {
00267       case TWA_COMMAND_LIST: {
00268         int y = this->GetRowFromWidget(pt.y, TWA_COMMAND_LIST, 1, FONT_HEIGHT_NORMAL);
00269         if (!IsInsideMM(y, 0, 5)) return;
00270 
00271         y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_company, this->town), y + this->vscroll->GetPosition() - 1);
00272         if (y >= 0) {
00273           this->sel_index = y;
00274           this->SetDirty();
00275         }
00276         /* FALL THROUGH, when double-clicking. */
00277         if (click_count == 1 || y < 0) break;
00278       }
00279 
00280       case TWA_EXECUTE:
00281         DoCommandP(this->town->xy, this->window_number, this->sel_index, CMD_DO_TOWN_ACTION | CMD_MSG(STR_ERROR_CAN_T_DO_THIS));
00282         break;
00283     }
00284   }
00285 
00286   virtual void OnHundredthTick()
00287   {
00288     this->SetDirty();
00289   }
00290 };
00291 
00292 static const WindowDesc _town_authority_desc(
00293   WDP_AUTO, 317, 222,
00294   WC_TOWN_AUTHORITY, WC_NONE,
00295   WDF_UNCLICK_BUTTONS,
00296   _nested_town_authority_widgets, lengthof(_nested_town_authority_widgets)
00297 );
00298 
00299 static void ShowTownAuthorityWindow(uint town)
00300 {
00301   AllocateWindowDescFront<TownAuthorityWindow>(&_town_authority_desc, town);
00302 }
00303 
00305 enum TownViewWidgets {
00306   TVW_CAPTION,
00307   TVW_VIEWPORT,
00308   TVW_INFOPANEL,
00309   TVW_CENTERVIEW,
00310   TVW_SHOWAUTHORITY,
00311   TVW_CHANGENAME,
00312   TVW_EXPAND,
00313   TVW_DELETE,
00314 };
00315 
00316 /* Town view window. */
00317 struct TownViewWindow : Window {
00318 private:
00319   Town *town; 
00320 
00321 public:
00322   static const int TVW_HEIGHT_NORMAL = 150;
00323 
00324   TownViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
00325   {
00326     this->CreateNestedTree(desc);
00327 
00328     this->town = Town::Get(window_number);
00329     if (this->town->larger_town) this->GetWidget<NWidgetCore>(TVW_CAPTION)->widget_data = STR_TOWN_VIEW_CITY_CAPTION;
00330 
00331     this->FinishInitNested(desc, window_number);
00332 
00333     this->flags4 |= WF_DISABLE_VP_SCROLL;
00334     NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(TVW_VIEWPORT);
00335     nvp->InitializeViewport(this, this->town->xy, ZOOM_LVL_NEWS);
00336 
00337     /* disable renaming town in network games if you are not the server */
00338     this->SetWidgetDisabledState(TVW_CHANGENAME, _networking && !_network_server);
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 = _current_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_CHARS, MAX_LENGTH_TOWN_NAME_PIXELS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS);
00455         break;
00456 
00457       case TVW_EXPAND: { // expand town - only available on Scenario editor
00458         /* Warn the user if towns are not allowed to build roads, but do this only once per OpenTTD run. */
00459         static bool _warn_town_no_roads = false;
00460 
00461         if (!_settings_game.economy.allow_town_roads && !_warn_town_no_roads) {
00462           ShowErrorMessage(STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS, INVALID_STRING_ID, WL_WARNING);
00463           _warn_town_no_roads = true;
00464         }
00465 
00466         DoCommandP(0, this->window_number, 0, CMD_EXPAND_TOWN | CMD_MSG(STR_ERROR_CAN_T_EXPAND_TOWN));
00467         break;
00468       }
00469 
00470       case TVW_DELETE: // delete town - only available on Scenario editor
00471         DoCommandP(0, this->window_number, 0, CMD_DELETE_TOWN | CMD_MSG(STR_ERROR_TOWN_CAN_T_DELETE));
00472         break;
00473     }
00474   }
00475 
00476   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00477   {
00478     switch (widget) {
00479       case TVW_INFOPANEL:
00480         size->height = GetDesiredInfoHeight();
00481         break;
00482     }
00483   }
00484 
00489   uint GetDesiredInfoHeight() const
00490   {
00491     uint aimed_height = 3 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
00492 
00493     switch (_settings_game.game_creation.landscape) {
00494       case LT_ARCTIC:
00495         if (TilePixelHeight(this->town->xy) >= LowestSnowLine()) aimed_height += 2 * FONT_HEIGHT_NORMAL;
00496         break;
00497 
00498       case LT_TROPIC:
00499         if (GetTropicZone(this->town->xy) == TROPICZONE_DESERT) aimed_height += 3 * FONT_HEIGHT_NORMAL;
00500         break;
00501 
00502       default: break;
00503     }
00504 
00505     if (_settings_game.economy.station_noise_level) aimed_height += FONT_HEIGHT_NORMAL;
00506 
00507     return aimed_height;
00508   }
00509 
00510   void ResizeWindowAsNeeded()
00511   {
00512     const NWidgetBase *nwid_info = this->GetWidget<NWidgetBase>(TVW_INFOPANEL);
00513     uint aimed_height = GetDesiredInfoHeight();
00514     if (aimed_height > nwid_info->current_y || (aimed_height < nwid_info->current_y && nwid_info->current_y > nwid_info->smallest_y)) {
00515       this->ReInit();
00516     }
00517   }
00518 
00519   virtual void OnResize()
00520   {
00521     if (this->viewport != NULL) {
00522       NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(TVW_VIEWPORT);
00523       nvp->UpdateViewportCoordinates(this);
00524 
00525       ScrollWindowToTile(this->town->xy, this, true); // Re-center viewport.
00526     }
00527   }
00528 
00529   virtual void OnInvalidateData(int data = 0)
00530   {
00531     /* Called when setting station noise have changed, in order to resize the window */
00532     this->SetDirty(); // refresh display for current size. This will allow to avoid glitches when downgrading
00533     this->ResizeWindowAsNeeded();
00534   }
00535 
00536   virtual void OnQueryTextFinished(char *str)
00537   {
00538     if (str == NULL) return;
00539 
00540     DoCommandP(0, this->window_number, 0, CMD_RENAME_TOWN | CMD_MSG(STR_ERROR_CAN_T_RENAME_TOWN), NULL, str);
00541   }
00542 };
00543 
00544 static const NWidgetPart _nested_town_game_view_widgets[] = {
00545   NWidget(NWID_HORIZONTAL),
00546     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
00547     NWidget(WWT_CAPTION, COLOUR_BROWN, TVW_CAPTION), SetDataTip(STR_TOWN_VIEW_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00548     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
00549     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
00550   EndContainer(),
00551   NWidget(WWT_PANEL, COLOUR_BROWN),
00552     NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2),
00553       NWidget(NWID_VIEWPORT, INVALID_COLOUR, TVW_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 0), SetResize(1, 1), SetPadding(1, 1, 1, 1),
00554     EndContainer(),
00555   EndContainer(),
00556   NWidget(WWT_PANEL, COLOUR_BROWN, TVW_INFOPANEL), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(),
00557   NWidget(NWID_HORIZONTAL),
00558     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
00559       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),
00560       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),
00561       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),
00562     EndContainer(),
00563     NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
00564   EndContainer(),
00565 };
00566 
00567 static const WindowDesc _town_game_view_desc(
00568   WDP_AUTO, 260, TownViewWindow::TVW_HEIGHT_NORMAL,
00569   WC_TOWN_VIEW, WC_NONE,
00570   WDF_UNCLICK_BUTTONS,
00571   _nested_town_game_view_widgets, lengthof(_nested_town_game_view_widgets)
00572 );
00573 
00574 static const NWidgetPart _nested_town_editor_view_widgets[] = {
00575   NWidget(NWID_HORIZONTAL),
00576     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
00577     NWidget(WWT_CAPTION, COLOUR_BROWN, TVW_CAPTION), SetDataTip(STR_TOWN_VIEW_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00578     NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, TVW_CHANGENAME), SetMinimalSize(76, 14), SetDataTip(STR_BUTTON_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP),
00579     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
00580     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
00581   EndContainer(),
00582   NWidget(WWT_PANEL, COLOUR_BROWN),
00583     NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2),
00584       NWidget(NWID_VIEWPORT, INVALID_COLOUR, TVW_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 1), SetResize(1, 1), SetPadding(1, 1, 1, 1),
00585     EndContainer(),
00586   EndContainer(),
00587   NWidget(WWT_PANEL, COLOUR_BROWN, TVW_INFOPANEL), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(),
00588   NWidget(NWID_HORIZONTAL),
00589     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
00590       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),
00591       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),
00592       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),
00593     EndContainer(),
00594     NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
00595   EndContainer(),
00596 };
00597 
00598 static const WindowDesc _town_editor_view_desc(
00599   WDP_AUTO, 260, TownViewWindow::TVW_HEIGHT_NORMAL,
00600   WC_TOWN_VIEW, WC_NONE,
00601   WDF_UNCLICK_BUTTONS,
00602   _nested_town_editor_view_widgets, lengthof(_nested_town_editor_view_widgets)
00603 );
00604 
00605 void ShowTownViewWindow(TownID town)
00606 {
00607   if (_game_mode == GM_EDITOR) {
00608     AllocateWindowDescFront<TownViewWindow>(&_town_editor_view_desc, town);
00609   } else {
00610     AllocateWindowDescFront<TownViewWindow>(&_town_game_view_desc, town);
00611   }
00612 }
00613 
00615 enum TownDirectoryWidgets {
00616   TDW_SORTNAME,
00617   TDW_SORTPOPULATION,
00618   TDW_CENTERTOWN,
00619   TDW_SCROLLBAR,
00620   TDW_BOTTOM_PANEL,
00621   TDW_BOTTOM_TEXT,
00622 };
00623 
00624 static const NWidgetPart _nested_town_directory_widgets[] = {
00625   NWidget(NWID_HORIZONTAL),
00626     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
00627     NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_TOWN_DIRECTORY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00628     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
00629     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
00630   EndContainer(),
00631   NWidget(NWID_HORIZONTAL),
00632     NWidget(NWID_VERTICAL),
00633       NWidget(NWID_HORIZONTAL),
00634         NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, TDW_SORTNAME), SetMinimalSize(99, 12), SetDataTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0),
00635         NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, TDW_SORTPOPULATION), SetMinimalSize(97, 12), SetDataTip(STR_SORT_BY_CAPTION_POPULATION, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0),
00636       EndContainer(),
00637       NWidget(WWT_PANEL, COLOUR_BROWN, TDW_CENTERTOWN), SetMinimalSize(196, 0), SetDataTip(0x0, STR_TOWN_DIRECTORY_LIST_TOOLTIP),
00638               SetFill(1, 0), SetResize(0, 10), SetScrollbar(TDW_SCROLLBAR), EndContainer(),
00639       NWidget(WWT_PANEL, COLOUR_BROWN, TDW_BOTTOM_PANEL),
00640         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),
00641       EndContainer(),
00642     EndContainer(),
00643     NWidget(NWID_VERTICAL),
00644       NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, TDW_SCROLLBAR),
00645       NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
00646     EndContainer(),
00647   EndContainer(),
00648 };
00649 
00651 struct TownDirectoryWindow : public Window {
00652 private:
00653   /* Runtime saved values */
00654   static Listing last_sorting;
00655   static const Town *last_town;
00656 
00657   /* Constants for sorting towns */
00658   static GUITownList::SortFunction * const sorter_funcs[];
00659 
00660   GUITownList towns;
00661 
00662   Scrollbar *vscroll;
00663 
00664   void BuildSortTownList()
00665   {
00666     if (this->towns.NeedRebuild()) {
00667       this->towns.Clear();
00668 
00669       const Town *t;
00670       FOR_ALL_TOWNS(t) {
00671         *this->towns.Append() = t;
00672       }
00673 
00674       this->towns.Compact();
00675       this->towns.RebuildDone();
00676       this->vscroll->SetCount(this->towns.Length()); // Update scrollbar as well.
00677     }
00678     /* Always sort the towns. */
00679     this->last_town = NULL;
00680     this->towns.Sort();
00681   }
00682 
00684   static int CDECL TownNameSorter(const Town * const *a, const Town * const *b)
00685   {
00686     static char buf_cache[64];
00687     const Town *ta = *a;
00688     const Town *tb = *b;
00689     char buf[64];
00690 
00691     SetDParam(0, ta->index);
00692     GetString(buf, STR_TOWN_NAME, lastof(buf));
00693 
00694     /* If 'b' is the same town as in the last round, use the cached value
00695      * We do this to speed stuff up ('b' is called with the same value a lot of
00696      * times after eachother) */
00697     if (tb != last_town) {
00698       last_town = tb;
00699       SetDParam(0, tb->index);
00700       GetString(buf_cache, STR_TOWN_NAME, lastof(buf_cache));
00701     }
00702 
00703     return strnatcmp(buf, buf_cache); // Sort by name (natural sorting).
00704   }
00705 
00707   static int CDECL TownPopulationSorter(const Town * const *a, const Town * const *b)
00708   {
00709     return (*a)->population - (*b)->population;
00710   }
00711 
00712 public:
00713   TownDirectoryWindow(const WindowDesc *desc) : Window()
00714   {
00715     this->CreateNestedTree(desc);
00716 
00717     this->vscroll = this->GetScrollbar(TDW_SCROLLBAR);
00718 
00719     this->towns.SetListing(this->last_sorting);
00720     this->towns.SetSortFuncs(TownDirectoryWindow::sorter_funcs);
00721     this->towns.ForceRebuild();
00722     this->BuildSortTownList();
00723 
00724     this->FinishInitNested(desc, 0);
00725   }
00726 
00727   ~TownDirectoryWindow()
00728   {
00729     this->last_sorting = this->towns.GetListing();
00730   }
00731 
00732   virtual void SetStringParameters(int widget) const
00733   {
00734     if (widget == TDW_BOTTOM_TEXT) SetDParam(0, GetWorldPopulation());
00735   }
00736 
00737   virtual void DrawWidget(const Rect &r, int widget) const
00738   {
00739     switch (widget) {
00740       case TDW_SORTNAME:
00741         if (this->towns.SortType() == 0) this->DrawSortButtonState(widget, this->towns.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
00742         break;
00743 
00744       case TDW_SORTPOPULATION:
00745         if (this->towns.SortType() != 0) this->DrawSortButtonState(widget, this->towns.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
00746         break;
00747 
00748       case TDW_CENTERTOWN: {
00749         int n = 0;
00750         int y = r.top + WD_FRAMERECT_TOP;
00751         if (this->towns.Length() == 0) { // No towns available.
00752           DrawString(r.left + WD_FRAMERECT_LEFT, r.right, y, STR_TOWN_DIRECTORY_NONE);
00753           break;
00754         }
00755         /* At least one town available. */
00756         for (uint i = this->vscroll->GetPosition(); i < this->towns.Length(); i++) {
00757           const Town *t = this->towns[i];
00758 
00759           assert(t->xy != INVALID_TILE);
00760 
00761           SetDParam(0, t->index);
00762           SetDParam(1, t->population);
00763           DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TOWN_DIRECTORY_TOWN);
00764 
00765           y += this->resize.step_height;
00766           if (++n == this->vscroll->GetCapacity()) break; // max number of towns in 1 window
00767         }
00768         break;
00769       }
00770     }
00771   }
00772 
00773   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00774   {
00775     switch (widget) {
00776       case TDW_SORTNAME:
00777       case TDW_SORTPOPULATION: {
00778         Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
00779         d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2; // Doubled since the string is centred and it also looks better.
00780         d.height += padding.height;
00781         *size = maxdim(*size, d);
00782         break;
00783       }
00784       case TDW_CENTERTOWN: {
00785         Dimension d = GetStringBoundingBox(STR_TOWN_DIRECTORY_NONE);
00786         for (uint i = 0; i < this->towns.Length(); i++) {
00787           const Town *t = this->towns[i];
00788 
00789           assert(t != NULL);
00790 
00791           SetDParam(0, t->index);
00792           SetDParam(1, 10000000); // 10^7
00793           d = maxdim(d, GetStringBoundingBox(STR_TOWN_DIRECTORY_TOWN));
00794         }
00795         resize->height = d.height;
00796         d.height *= 5;
00797         d.width += padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
00798         d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
00799         *size = maxdim(*size, d);
00800         break;
00801       }
00802       case TDW_BOTTOM_TEXT: {
00803         SetDParam(0, 1000000000); // 10^9
00804         Dimension d = GetStringBoundingBox(STR_TOWN_POPULATION);
00805         d.width += padding.width;
00806         d.height += padding.height;
00807         *size = maxdim(*size, d);
00808         break;
00809       }
00810     }
00811   }
00812 
00813   virtual void OnClick(Point pt, int widget, int click_count)
00814   {
00815     switch (widget) {
00816       case TDW_SORTNAME: // Sort by Name ascending/descending
00817         if (this->towns.SortType() == 0) {
00818           this->towns.ToggleSortOrder();
00819         } else {
00820           this->towns.SetSortType(0);
00821         }
00822         this->BuildSortTownList();
00823         this->SetDirty();
00824         break;
00825 
00826       case TDW_SORTPOPULATION: // Sort by Population ascending/descending
00827         if (this->towns.SortType() == 1) {
00828           this->towns.ToggleSortOrder();
00829         } else {
00830           this->towns.SetSortType(1);
00831         }
00832         this->BuildSortTownList();
00833         this->SetDirty();
00834         break;
00835 
00836       case TDW_CENTERTOWN: { // Click on Town Matrix
00837         uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, TDW_CENTERTOWN, WD_FRAMERECT_TOP);
00838         if (id_v >= this->towns.Length()) return; // click out of town bounds
00839 
00840         const Town *t = this->towns[id_v];
00841         assert(t != NULL);
00842         if (_ctrl_pressed) {
00843           ShowExtraViewPortWindow(t->xy);
00844         } else {
00845           ScrollMainWindowToTile(t->xy);
00846         }
00847         break;
00848       }
00849     }
00850   }
00851 
00852   virtual void OnHundredthTick()
00853   {
00854     this->BuildSortTownList();
00855     this->SetDirty();
00856   }
00857 
00858   virtual void OnResize()
00859   {
00860     this->vscroll->SetCapacityFromWidget(this, TDW_CENTERTOWN);
00861   }
00862 
00863   virtual void OnInvalidateData(int data)
00864   {
00865     if (data == 0) {
00866       this->towns.ForceRebuild();
00867     } else {
00868       this->towns.ForceResort();
00869     }
00870     this->BuildSortTownList();
00871   }
00872 };
00873 
00874 Listing TownDirectoryWindow::last_sorting = {false, 0};
00875 const Town *TownDirectoryWindow::last_town = NULL;
00876 
00877 /* Available town directory sorting functions */
00878 GUITownList::SortFunction * const TownDirectoryWindow::sorter_funcs[] = {
00879   &TownNameSorter,
00880   &TownPopulationSorter,
00881 };
00882 
00883 static const WindowDesc _town_directory_desc(
00884   WDP_AUTO, 208, 202,
00885   WC_TOWN_DIRECTORY, WC_NONE,
00886   WDF_UNCLICK_BUTTONS,
00887   _nested_town_directory_widgets, lengthof(_nested_town_directory_widgets)
00888 );
00889 
00890 void ShowTownDirectory()
00891 {
00892   if (BringWindowToFrontById(WC_TOWN_DIRECTORY, 0)) return;
00893   new TownDirectoryWindow(&_town_directory_desc);
00894 }
00895 
00896 void CcFoundTown(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
00897 {
00898   if (result.Failed()) return;
00899 
00900   SndPlayTileFx(SND_1F_SPLAT, tile);
00901   if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
00902 }
00903 
00904 void CcFoundRandomTown(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
00905 {
00906   if (result.Succeeded()) ScrollMainWindowToTile(Town::Get(_new_town_id)->xy);
00907 }
00908 
00910 enum TownScenarioEditorWidgets {
00911   TSEW_BACKGROUND,
00912   TSEW_NEWTOWN,
00913   TSEW_RANDOMTOWN,
00914   TSEW_MANYRANDOMTOWNS,
00915   TSEW_TOWNNAME_TEXT,
00916   TSEW_TOWNNAME_EDITBOX,
00917   TSEW_TOWNNAME_RANDOM,
00918   TSEW_TOWNSIZE,
00919   TSEW_SIZE_SMALL,
00920   TSEW_SIZE_MEDIUM,
00921   TSEW_SIZE_LARGE,
00922   TSEW_SIZE_RANDOM,
00923   TSEW_CITY,
00924   TSEW_TOWNLAYOUT,
00925   TSEW_LAYOUT_ORIGINAL,
00926   TSEW_LAYOUT_BETTER,
00927   TSEW_LAYOUT_GRID2,
00928   TSEW_LAYOUT_GRID3,
00929   TSEW_LAYOUT_RANDOM,
00930 };
00931 
00932 static const NWidgetPart _nested_found_town_widgets[] = {
00933   NWidget(NWID_HORIZONTAL),
00934     NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
00935     NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_FOUND_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00936     NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN),
00937     NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
00938   EndContainer(),
00939   /* Construct new town(s) buttons. */
00940   NWidget(WWT_PANEL, COLOUR_DARK_GREEN, TSEW_BACKGROUND),
00941     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
00942     NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_NEWTOWN), SetMinimalSize(156, 12), SetFill(1, 0),
00943                     SetDataTip(STR_FOUND_TOWN_NEW_TOWN_BUTTON, STR_FOUND_TOWN_NEW_TOWN_TOOLTIP), SetPadding(0, 2, 1, 2),
00944     NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_RANDOMTOWN), SetMinimalSize(156, 12), SetFill(1, 0),
00945                     SetDataTip(STR_FOUND_TOWN_RANDOM_TOWN_BUTTON, STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP), SetPadding(0, 2, 1, 2),
00946     NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_MANYRANDOMTOWNS), SetMinimalSize(156, 12), SetFill(1, 0),
00947                     SetDataTip(STR_FOUND_TOWN_MANY_RANDOM_TOWNS, STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP), SetPadding(0, 2, 0, 2),
00948     /* Town name selection. */
00949     NWidget(WWT_LABEL, COLOUR_DARK_GREEN, TSEW_TOWNSIZE), SetMinimalSize(156, 14), SetPadding(0, 2, 0, 2), SetDataTip(STR_FOUND_TOWN_NAME_TITLE, STR_NULL),
00950     NWidget(WWT_EDITBOX, COLOUR_WHITE, TSEW_TOWNNAME_EDITBOX), SetMinimalSize(156, 12), SetPadding(0, 2, 3, 2),
00951                     SetDataTip(STR_FOUND_TOWN_NAME_EDITOR_TITLE, STR_FOUND_TOWN_NAME_EDITOR_HELP),
00952     NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_TOWNNAME_RANDOM), SetMinimalSize(78, 12), SetPadding(0, 2, 0, 2), SetFill(1, 0),
00953                     SetDataTip(STR_FOUND_TOWN_NAME_RANDOM_BUTTON, STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP),
00954     /* Town size selection. */
00955     NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
00956       NWidget(NWID_SPACER), SetFill(1, 0),
00957       NWidget(WWT_LABEL, COLOUR_DARK_GREEN, TSEW_TOWNSIZE), SetMinimalSize(148, 14), SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_TITLE, STR_NULL),
00958       NWidget(NWID_SPACER), SetFill(1, 0),
00959     EndContainer(),
00960     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2),
00961       NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_SIZE_SMALL), SetMinimalSize(78, 12), SetFill(1, 0),
00962                     SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP),
00963       NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_SIZE_MEDIUM), SetMinimalSize(78, 12), SetFill(1, 0),
00964                     SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP),
00965     EndContainer(),
00966     NWidget(NWID_SPACER), SetMinimalSize(0, 1),
00967     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2),
00968       NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_SIZE_LARGE), SetMinimalSize(78, 12), SetFill(1, 0),
00969                     SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP),
00970       NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_SIZE_RANDOM), SetMinimalSize(78, 12), SetFill(1, 0),
00971                     SetDataTip(STR_FOUND_TOWN_SIZE_RANDOM, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP),
00972     EndContainer(),
00973     NWidget(NWID_SPACER), SetMinimalSize(0, 3),
00974     NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_CITY), SetPadding(0, 2, 0, 2), SetMinimalSize(156, 12), SetFill(1, 0),
00975                     SetDataTip(STR_FOUND_TOWN_CITY, STR_FOUND_TOWN_CITY_TOOLTIP), SetFill(1, 0),
00976     /* Town roads selection. */
00977     NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
00978       NWidget(NWID_SPACER), SetFill(1, 0),
00979       NWidget(WWT_LABEL, COLOUR_DARK_GREEN, TSEW_TOWNLAYOUT), SetMinimalSize(148, 14), SetDataTip(STR_FOUND_TOWN_ROAD_LAYOUT, STR_NULL),
00980       NWidget(NWID_SPACER), SetFill(1, 0),
00981     EndContainer(),
00982     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2),
00983       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),
00984       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),
00985     EndContainer(),
00986     NWidget(NWID_SPACER), SetMinimalSize(0, 1),
00987     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2),
00988       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),
00989       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),
00990     EndContainer(),
00991     NWidget(NWID_SPACER), SetMinimalSize(0, 1),
00992     NWidget(WWT_TEXTBTN, COLOUR_GREY, TSEW_LAYOUT_RANDOM), SetPadding(0, 2, 0, 2), SetMinimalSize(0, 12), SetFill(1, 0),
00993                     SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), SetFill(1, 0),
00994     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
00995   EndContainer(),
00996 };
00997 
00999 struct FoundTownWindow : QueryStringBaseWindow {
01000 private:
01001   TownSize town_size;     
01002   TownLayout town_layout; 
01003   bool city;              
01004   bool townnamevalid;     
01005   uint32 townnameparts;   
01006   TownNameParams params;  
01007 
01008 public:
01009   FoundTownWindow(const WindowDesc *desc, WindowNumber window_number) :
01010       QueryStringBaseWindow(MAX_LENGTH_TOWN_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_TOWN_NAME_CHARS),
01011       town_size(TSZ_MEDIUM),
01012       town_layout(_settings_game.economy.town_layout),
01013       params(_settings_game.game_creation.town_name)
01014   {
01015     this->InitNested(desc, window_number);
01016     InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, this->max_chars, MAX_LENGTH_TOWN_NAME_PIXELS);
01017     this->RandomTownName();
01018     this->UpdateButtons(true);
01019   }
01020 
01021   void RandomTownName()
01022   {
01023     this->townnamevalid = GenerateTownName(&this->townnameparts);
01024 
01025     if (!this->townnamevalid) {
01026       this->edit_str_buf[0] = '\0';
01027     } else {
01028       GetTownName(this->edit_str_buf, &this->params, this->townnameparts, &this->edit_str_buf[this->edit_str_size - 1]);
01029     }
01030     UpdateTextBufferSize(&this->text);
01031     UpdateOSKOriginalText(this, TSEW_TOWNNAME_EDITBOX);
01032 
01033     this->SetWidgetDirty(TSEW_TOWNNAME_EDITBOX);
01034   }
01035 
01036   void UpdateButtons(bool check_availability)
01037   {
01038     if (check_availability && _game_mode != GM_EDITOR) {
01039       this->SetWidgetsDisabledState(true, TSEW_RANDOMTOWN, TSEW_MANYRANDOMTOWNS, TSEW_SIZE_LARGE, WIDGET_LIST_END);
01040       this->SetWidgetsDisabledState(_settings_game.economy.found_town != TF_CUSTOM_LAYOUT,
01041           TSEW_LAYOUT_ORIGINAL, TSEW_LAYOUT_BETTER, TSEW_LAYOUT_GRID2, TSEW_LAYOUT_GRID3, TSEW_LAYOUT_RANDOM, WIDGET_LIST_END);
01042       if (_settings_game.economy.found_town != TF_CUSTOM_LAYOUT) town_layout = _settings_game.economy.town_layout;
01043     }
01044 
01045     for (int i = TSEW_SIZE_SMALL; i <= TSEW_SIZE_RANDOM; i++) {
01046       this->SetWidgetLoweredState(i, i == TSEW_SIZE_SMALL + this->town_size);
01047     }
01048 
01049     this->SetWidgetLoweredState(TSEW_CITY, this->city);
01050 
01051     for (int i = TSEW_LAYOUT_ORIGINAL; i <= TSEW_LAYOUT_RANDOM; i++) {
01052       this->SetWidgetLoweredState(i, i == TSEW_LAYOUT_ORIGINAL + this->town_layout);
01053     }
01054 
01055     this->SetDirty();
01056   }
01057 
01058   void ExecuteFoundTownCommand(TileIndex tile, bool random, StringID errstr, CommandCallback cc)
01059   {
01060     const char *name = NULL;
01061 
01062     if (!this->townnamevalid) {
01063       name = this->edit_str_buf;
01064     } else {
01065       /* If user changed the name, send it */
01066       char buf[MAX_LENGTH_TOWN_NAME_CHARS * MAX_CHAR_LENGTH];
01067       GetTownName(buf, &this->params, this->townnameparts, lastof(buf));
01068       if (strcmp(buf, this->edit_str_buf) != 0) name = this->edit_str_buf;
01069     }
01070 
01071     bool success = DoCommandP(tile, this->town_size | this->city << 2 | this->town_layout << 3 | random << 6,
01072         townnameparts, CMD_FOUND_TOWN | CMD_MSG(errstr), cc, name);
01073 
01074     if (success) this->RandomTownName();
01075   }
01076 
01077   virtual void OnPaint()
01078   {
01079     this->DrawWidgets();
01080     if (!this->IsShaded()) this->DrawEditBox(TSEW_TOWNNAME_EDITBOX);
01081   }
01082 
01083   virtual void OnClick(Point pt, int widget, int click_count)
01084   {
01085     switch (widget) {
01086       case TSEW_NEWTOWN:
01087         HandlePlacePushButton(this, TSEW_NEWTOWN, SPR_CURSOR_TOWN, HT_RECT);
01088         break;
01089 
01090       case TSEW_RANDOMTOWN:
01091         this->HandleButtonClick(TSEW_RANDOMTOWN);
01092         this->ExecuteFoundTownCommand(0, true, STR_ERROR_CAN_T_GENERATE_TOWN, CcFoundRandomTown);
01093         break;
01094 
01095       case TSEW_TOWNNAME_RANDOM:
01096         this->RandomTownName();
01097         this->SetFocusedWidget(TSEW_TOWNNAME_EDITBOX);
01098         break;
01099 
01100       case TSEW_MANYRANDOMTOWNS:
01101         this->HandleButtonClick(TSEW_MANYRANDOMTOWNS);
01102 
01103         _generating_world = true;
01104         UpdateNearestTownForRoadTiles(true);
01105         if (!GenerateTowns(this->town_layout)) {
01106           ShowErrorMessage(STR_ERROR_CAN_T_GENERATE_TOWN, STR_ERROR_NO_SPACE_FOR_TOWN, WL_INFO);
01107         }
01108         UpdateNearestTownForRoadTiles(false);
01109         _generating_world = false;
01110         break;
01111 
01112       case TSEW_SIZE_SMALL: case TSEW_SIZE_MEDIUM: case TSEW_SIZE_LARGE: case TSEW_SIZE_RANDOM:
01113         this->town_size = (TownSize)(widget - TSEW_SIZE_SMALL);
01114         this->UpdateButtons(false);
01115         break;
01116 
01117       case TSEW_CITY:
01118         this->city ^= true;
01119         this->SetWidgetLoweredState(TSEW_CITY, this->city);
01120         this->SetDirty();
01121         break;
01122 
01123       case TSEW_LAYOUT_ORIGINAL: case TSEW_LAYOUT_BETTER: case TSEW_LAYOUT_GRID2:
01124       case TSEW_LAYOUT_GRID3: case TSEW_LAYOUT_RANDOM:
01125         this->town_layout = (TownLayout)(widget - TSEW_LAYOUT_ORIGINAL);
01126         this->UpdateButtons(false);
01127         break;
01128     }
01129   }
01130 
01131   virtual void OnTimeout()
01132   {
01133     this->RaiseWidget(TSEW_RANDOMTOWN);
01134     this->RaiseWidget(TSEW_MANYRANDOMTOWNS);
01135     this->SetDirty();
01136   }
01137 
01138   virtual void OnMouseLoop()
01139   {
01140     this->HandleEditBox(TSEW_TOWNNAME_EDITBOX);
01141   }
01142 
01143   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
01144   {
01145     EventState state = ES_NOT_HANDLED;
01146     if (this->HandleEditBoxKey(TSEW_TOWNNAME_EDITBOX, key, keycode, state) == HEBR_CANCEL) {
01147       this->UnfocusFocusedWidget();
01148     }
01149     return state;
01150   }
01151 
01152   virtual void OnPlaceObject(Point pt, TileIndex tile)
01153   {
01154     this->ExecuteFoundTownCommand(tile, false, STR_ERROR_CAN_T_FOUND_TOWN_HERE, CcFoundTown);
01155   }
01156 
01157   virtual void OnPlaceObjectAbort()
01158   {
01159     this->RaiseButtons();
01160     this->UpdateButtons(false);
01161   }
01162 
01163   virtual void OnInvalidateData(int)
01164   {
01165     this->UpdateButtons(true);
01166   }
01167 };
01168 
01169 static const WindowDesc _found_town_desc(
01170   WDP_AUTO, 160, 162,
01171   WC_FOUND_TOWN, WC_NONE,
01172   WDF_CONSTRUCTION,
01173   _nested_found_town_widgets, lengthof(_nested_found_town_widgets)
01174 );
01175 
01176 void ShowFoundTownWindow()
01177 {
01178   if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return;
01179   AllocateWindowDescFront<FoundTownWindow>(&_found_town_desc, 0);
01180 }

Generated on Thu Jan 20 22:57:42 2011 for OpenTTD by  doxygen 1.6.1