# bridge_gui.cpp

Go to the documentation of this file.

    00001 /* $Id: bridge_gui.cpp 15413 2009-02-08 15:45:34Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "gui.h"
    00007 #include "window_gui.h"
    00008 #include "command_func.h"
    00009 #include "economy_func.h"
    00010 #include "bridge.h"
    00011 #include "strings_func.h"
    00012 #include "window_func.h"
    00013 #include "sound_func.h"
    00014 #include "map_func.h"
    00015 #include "gfx_func.h"
    00016 #include "tunnelbridge.h"
    00017 #include "sortlist_type.h"
    00018 #include "widgets/dropdown_func.h"
    00019
    00020 #include "table/strings.h"
    00021
    00023 static BridgeType _last_railbridge_type = 0;
    00025 static BridgeType _last_roadbridge_type = 0;
    00026
    00030 struct BuildBridgeData {
    00031   BridgeType index;
    00032   const BridgeSpec *spec;
    00033   Money cost;
    00034 };
    00035
    00036 typedef GUIList<BuildBridgeData> GUIBridgeList;
    00037
    00046 void CcBuildBridge(bool success, TileIndex tile, uint32 p1, uint32 p2)
    00047 {
    00048   if (success) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, tile);
    00049 }
    00050
    00051 /* Names of the build bridge selection window */
    00052 enum BuildBridgeSelectionWidgets {
    00053   BBSW_CLOSEBOX = 0,
    00054   BBSW_CAPTION,
    00055   BBSW_DROPDOWN_ORDER,
    00056   BBSW_DROPDOWN_CRITERIA,
    00057   BBSW_BRIDGE_LIST,
    00058   BBSW_SCROLLBAR,
    00059   BBSW_RESIZEBOX
    00060 };
    00061
    00062 class BuildBridgeWindow : public Window {
    00063 private:
    00064   /* Runtime saved values */
    00065   static uint16 last_size;
    00066   static Listing last_sorting;
    00067
    00068   /* Constants for sorting the bridges */
    00069   static const StringID sorter_names[];
    00070   static GUIBridgeList::SortFunction *const sorter_funcs[];
    00071
    00072   /* Internal variables */
    00073   TileIndex start_tile;
    00074   TileIndex end_tile;
    00075   uint32 type;
    00076   GUIBridgeList *bridges;
    00077
    00079   static int CDECL BridgeIndexSorter(const BuildBridgeData *a, const BuildBridgeData *b)
    00080   {
    00081     return a->index - b->index;
    00082   }
    00083
    00085   static int CDECL BridgePriceSorter(const BuildBridgeData *a, const BuildBridgeData *b)
    00086   {
    00087     return a->cost - b->cost;
    00088   }
    00089
    00091   static int CDECL BridgeSpeedSorter(const BuildBridgeData *a, const BuildBridgeData *b)
    00092   {
    00093     return a->spec->speed - b->spec->speed;
    00094   }
    00095
    00096   void BuildBridge(uint8 i)
    00097   {
    00098     switch ((TransportType)(this->type >> 15)) {
    00099       case TRANSPORT_RAIL: _last_railbridge_type = this->bridges->Get(i)->index; break;
    00100       case TRANSPORT_ROAD: _last_roadbridge_type = this->bridges->Get(i)->index; break;
    00101       default: break;
    00102     }
    00103     DoCommandP(this->end_tile, this->start_tile, this->type | this->bridges->Get(i)->index,
    00104           CMD_BUILD_BRIDGE | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE), CcBuildBridge);
    00105   }
    00106
    00108   void SortBridgeList()
    00109   {
    00110     this->bridges->Sort();
    00111
    00112     /* Display the current sort variant */
    00113     this->widget[BBSW_DROPDOWN_CRITERIA].data = this->sorter_names[this->bridges->SortType()];
    00114
    00115     /* Set the modified widgets dirty */
    00116     this->InvalidateWidget(BBSW_DROPDOWN_CRITERIA);
    00117     this->InvalidateWidget(BBSW_BRIDGE_LIST);
    00118   }
    00119
    00120 public:
    00121   BuildBridgeWindow(const WindowDesc *desc, TileIndex start, TileIndex end, uint32 br_type, GUIBridgeList *bl) : Window(desc),
    00122     start_tile(start),
    00123     end_tile(end),
    00124     type(br_type),
    00125     bridges(bl)
    00126   {
    00127     this->parent = FindWindowById(WC_BUILD_TOOLBAR, GB(this->type, 15, 2));
    00128     this->bridges->SetListing(this->last_sorting);
    00129     this->bridges->SetSortFuncs(this->sorter_funcs);
    00130     this->bridges->NeedResort();
    00131     this->SortBridgeList();
    00132
    00133     /* Change the data, or the caption of the gui. Set it to road or rail, accordingly */
    00134     this->widget[BBSW_CAPTION].data = (GB(this->type, 15, 2) == TRANSPORT_ROAD) ? STR_1803_SELECT_ROAD_BRIDGE : STR_100D_SELECT_RAIL_BRIDGE;
    00135
    00136     this->resize.step_height = 22;
    00137     this->vscroll.count = bl->Length();
    00138
    00139     if (this->last_size <= 4) {
    00140       this->vscroll.cap = 4;
    00141     } else {
    00142       /* Resize the bridge selection window if we used a bigger one the last time */
    00143       this->vscroll.cap = min(this->last_size, this->vscroll.count);
    00144       ResizeWindow(this, 0, (this->vscroll.cap - 4) * this->resize.step_height);
    00145     }
    00146
    00147     this->FindWindowPlacementAndResize(desc);
    00148   }
    00149
    00150   ~BuildBridgeWindow()
    00151   {
    00152     this->last_sorting = this->bridges->GetListing();
    00153
    00154     delete bridges;
    00155   }
    00156
    00157   virtual void OnPaint()
    00158   {
    00159     this->DrawWidgets();
    00160
    00161     this->DrawSortButtonState(BBSW_DROPDOWN_ORDER, this->bridges->IsDescSortOrder() ? SBS_DOWN : SBS_UP);
    00162
    00163     uint y = this->widget[BBSW_BRIDGE_LIST].top + 2;
    00164
    00165     for (int i = this->vscroll.pos; (i < (this->vscroll.cap + this->vscroll.pos)) && (i < (int)this->bridges->Length()); i++) {
    00166       const BridgeSpec *b = this->bridges->Get(i)->spec;
    00167
    00168       SetDParam(2, this->bridges->Get(i)->cost);
    00169       SetDParam(1, b->speed);
    00170       SetDParam(0, b->material);
    00171
    00172       DrawSprite(b->sprite, b->pal, 3, y);
    00173       DrawString(44, y, STR_500D, TC_FROMSTRING);
    00174       y += this->resize.step_height;
    00175
    00176     }
    00177   }
    00178
    00179   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
    00180   {
    00181     const uint8 i = keycode - '1';
    00182     if (i < 9 && i < this->bridges->Length()) {
    00183       /* Build the requested bridge */
    00184       this->BuildBridge(i);
    00185       delete this;
    00186       return ES_HANDLED;
    00187     }
    00188     return ES_NOT_HANDLED;
    00189   }
    00190
    00191   virtual void OnClick(Point pt, int widget)
    00192   {
    00193     switch (widget) {
    00194       default: break;
    00195       case BBSW_BRIDGE_LIST: {
    00196         uint i = ((int)pt.y - this->widget[BBSW_BRIDGE_LIST].top) / this->resize.step_height;
    00197         if (i < this->vscroll.cap) {
    00198           i += this->vscroll.pos;
    00199           if (i < this->bridges->Length()) {
    00200             this->BuildBridge(i);
    00201             delete this;
    00202           }
    00203         }
    00204       } break;
    00205
    00206       case BBSW_DROPDOWN_ORDER:
    00207         this->bridges->ToggleSortOrder();
    00208         this->SetDirty();
    00209         break;
    00210
    00211       case BBSW_DROPDOWN_CRITERIA:
    00212         ShowDropDownMenu(this, this->sorter_names, this->bridges->SortType(), BBSW_DROPDOWN_CRITERIA, 0, 0);
    00213         break;
    00214     }
    00215   }
    00216
    00217   virtual void OnDropdownSelect(int widget, int index)
    00218   {
    00219     if (widget == BBSW_DROPDOWN_CRITERIA && this->bridges->SortType() != index) {
    00220       this->bridges->SetSortType(index);
    00221
    00222       this->SortBridgeList();
    00223     }
    00224   }
    00225
    00226   virtual void OnResize(Point new_size, Point delta)
    00227   {
    00228     this->vscroll.cap += delta.y / (int)this->resize.step_height;
    00229     this->widget[BBSW_BRIDGE_LIST].data = (this->vscroll.cap << 8) + 1;
    00230     SetVScrollCount(this, this->bridges->Length());
    00231
    00232     this->last_size = max(this->vscroll.cap, this->last_size);
    00233   }
    00234 };
    00235
    00236 /* Set the default size of the Build Bridge Window */
    00237 uint16 BuildBridgeWindow::last_size = 4;
    00238 /* Set the default sorting for the bridges */
    00239 Listing BuildBridgeWindow::last_sorting = {false, 0};
    00240
    00241 /* Availible bridge sorting functions */
    00242 GUIBridgeList::SortFunction * const BuildBridgeWindow::sorter_funcs[] = {
    00243   &BridgeIndexSorter,
    00244   &BridgePriceSorter,
    00245   &BridgeSpeedSorter
    00246 };
    00247
    00248 /* Names of the sorting functions */
    00249 const StringID BuildBridgeWindow::sorter_names[] = {
    00250   STR_SORT_BY_NUMBER,
    00251   STR_ENGINE_SORT_COST,
    00252   STR_SORT_BY_MAX_SPEED,
    00253   INVALID_STRING_ID
    00254 };
    00255
    00256 /* Widget definition for the rail bridge selection window */
    00257 static const Widget _build_bridge_widgets[] = {
    00258 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_DARK_GREEN,   0,  10,   0,  13, STR_00C5,                    STR_018B_CLOSE_WINDOW},            // BBSW_CLOSEBOX
    00259 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_DARK_GREEN,  11, 199,   0,  13, STR_100D_SELECT_RAIL_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS},  // BBSW_CAPTION
    00260
    00261 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,   0,  80,  14,  25, STR_SORT_BY,                 STR_SORT_ORDER_TIP},               // BBSW_DROPDOWN_ORDER
    00262 {   WWT_DROPDOWN,   RESIZE_NONE,  COLOUR_DARK_GREEN,  81, 199,  14,  25, 0x0,                         STR_SORT_CRITERIA_TIP},            // BBSW_DROPDOWN_CRITERIA
    00263
    00264 {     WWT_MATRIX, RESIZE_BOTTOM,  COLOUR_DARK_GREEN,   0, 187,  26, 113, 0x401,                       STR_101F_BRIDGE_SELECTION_CLICK},  // BBSW_BRIDGE_LIST
    00265 {  WWT_SCROLLBAR, RESIZE_BOTTOM,  COLOUR_DARK_GREEN, 188, 199,  26, 101, 0x0,                         STR_0190_SCROLL_BAR_SCROLLS_LIST}, // BBSW_SCROLLBAR
    00266 {  WWT_RESIZEBOX,     RESIZE_TB,  COLOUR_DARK_GREEN, 188, 199, 102, 113, 0x0,                         STR_RESIZE_BUTTON},                // BBSW_RESIZEBOX
    00267 {   WIDGETS_END},
    00268 };
    00269
    00270 /* Window definition for the rail bridge selection window */
    00271 static const WindowDesc _build_bridge_desc = {
    00272   WDP_AUTO, WDP_AUTO, 200, 114, 200, 114,
    00273   WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR,
    00274   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE | WDF_CONSTRUCTION,
    00275   _build_bridge_widgets,
    00276 };
    00277
    00288 void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transport_type, byte road_rail_type)
    00289 {
    00290   DeleteWindowById(WC_BUILD_BRIDGE, 0);
    00291
    00292   /* Data type for the bridge.
    00293    * Bit 16,15 = transport type,
    00294    *     14..8 = road/rail types,
    00295    *      7..0 = type of bridge */
    00296   uint32 type = (transport_type << 15) | (road_rail_type << 8);
    00297
    00298   /* The bridge length without ramps. */
    00299   const uint bridge_len = GetTunnelBridgeLength(start, end);
    00300
    00301   /* If Ctrl is being pressed, check wether the last bridge built is available
    00302    * If so, return this bridge type. Otherwise continue normally.
    00303    * We store bridge types for each transport type, so we have to check for
    00304    * the transport type beforehand.
    00305    */
    00306   BridgeType last_bridge_type = 0;
    00307   switch (transport_type) {
    00308     case TRANSPORT_ROAD: last_bridge_type = _last_roadbridge_type; break;
    00309     case TRANSPORT_RAIL: last_bridge_type = _last_railbridge_type; break;
    00310     default: break; // water ways and air routes don't have bridge types
    00311   }
    00312   if (_ctrl_pressed && CheckBridge_Stuff(last_bridge_type, bridge_len)) {
    00313     DoCommandP(end, start, type | last_bridge_type, CMD_BUILD_BRIDGE | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE), CcBuildBridge);
    00314     return;
    00315   }
    00316
    00317   /* only query bridge building possibility once, result is the same for all bridges!
    00318    * returns CMD_ERROR on failure, and price on success */
    00319   StringID errmsg = INVALID_STRING_ID;
    00320   CommandCost ret = DoCommand(end, start, type, DC_AUTO | DC_QUERY_COST, CMD_BUILD_BRIDGE);
    00321
    00322   GUIBridgeList *bl = NULL;
    00323   if (CmdFailed(ret)) {
    00324     errmsg = _error_message;
    00325   } else {
    00326     /* check which bridges can be built */
    00327     const uint tot_bridgedata_len = CalcBridgeLenCostFactor(bridge_len + 2);
    00328
    00329     bl = new GUIBridgeList();
    00330
    00331     /* loop for all bridgetypes */
    00332     for (BridgeType brd_type = 0; brd_type != MAX_BRIDGES; brd_type++) {
    00333       if (CheckBridge_Stuff(brd_type, bridge_len)) {
    00334         /* bridge is accepted, add to list */
    00335         BuildBridgeData *item = bl->Append();
    00336         item->index = brd_type;
    00337         item->spec = GetBridgeSpec(brd_type);
    00338         /* Add to terraforming & bulldozing costs the cost of the
    00339          * bridge itself (not computed with DC_QUERY_COST) */
    00340         item->cost = ret.GetCost() + (((int64)tot_bridgedata_len * _price.build_bridge * item->spec->price) >> 8);
    00341       }
    00342     }
    00343   }
    00344
    00345   if (bl != NULL && bl->Length() != 0) {
    00346     new BuildBridgeWindow(&_build_bridge_desc, start, end, type, bl);
    00347   } else {
    00348     if (bl != NULL) delete bl;
    00349     ShowErrorMessage(errmsg, STR_5015_CAN_T_BUILD_BRIDGE_HERE, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE);
    00350   }
    00351 }