smallmap_gui.cpp

Go to the documentation of this file.
00001 /* $Id: smallmap_gui.cpp 21977 2011-02-05 16:36:37Z frosch $ */
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 "clear_map.h"
00014 #include "industry.h"
00015 #include "station_map.h"
00016 #include "landscape.h"
00017 #include "window_gui.h"
00018 #include "tree_map.h"
00019 #include "viewport_func.h"
00020 #include "town.h"
00021 #include "blitter/factory.hpp"
00022 #include "tunnelbridge_map.h"
00023 #include "strings_func.h"
00024 #include "core/endian_func.hpp"
00025 #include "vehicle_base.h"
00026 #include "sound_func.h"
00027 #include "window_func.h"
00028 #include "company_base.h"
00029 
00030 #include "table/strings.h"
00031 
00033 enum SmallMapWindowWidgets {
00034   SM_WIDGET_CAPTION,           
00035   SM_WIDGET_MAP_BORDER,        
00036   SM_WIDGET_MAP,               
00037   SM_WIDGET_LEGEND,            
00038   SM_WIDGET_ZOOM_IN,           
00039   SM_WIDGET_ZOOM_OUT,          
00040   SM_WIDGET_CONTOUR,           
00041   SM_WIDGET_VEHICLES,          
00042   SM_WIDGET_INDUSTRIES,        
00043   SM_WIDGET_ROUTES,            
00044   SM_WIDGET_VEGETATION,        
00045   SM_WIDGET_OWNERS,            
00046   SM_WIDGET_CENTERMAP,         
00047   SM_WIDGET_TOGGLETOWNNAME,    
00048   SM_WIDGET_SELECT_BUTTONS,    
00049   SM_WIDGET_ENABLE_ALL,        
00050   SM_WIDGET_DISABLE_ALL,       
00051   SM_WIDGET_SHOW_HEIGHT,       
00052 };
00053 
00054 static int _smallmap_industry_count; 
00055 static int _smallmap_company_count;  
00056 
00057 static const int NUM_NO_COMPANY_ENTRIES = 4; 
00058 
00060 #define MK(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, false}
00061 
00063 #define MC(height)  {0, STR_TINY_BLACK_HEIGHT, INVALID_INDUSTRYTYPE, height, INVALID_COMPANY, true, false, false}
00064 
00066 #define MO(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, false}
00067 
00069 #define MOEND() {0, 0, INVALID_INDUSTRYTYPE, 0, OWNER_NONE, true, true, false}
00070 
00072 #define MKEND() {0, STR_NULL, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, true, false}
00073 
00078 #define MS(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, true}
00079 
00081 struct LegendAndColour {
00082   uint8 colour;              
00083   StringID legend;           
00084   IndustryType type;         
00085   uint8 height;              
00086   CompanyID company;         
00087   bool show_on_map;          
00088   bool end;                  
00089   bool col_break;            
00090 };
00091 
00093 static LegendAndColour _legend_land_contours[] = {
00094   /* The colours for the following values are set at BuildLandLegend() based on each colour scheme. */
00095   MC(0),
00096   MC(4),
00097   MC(8),
00098   MC(12),
00099   MC(14),
00100 
00101   MS(0xD7, STR_SMALLMAP_LEGENDA_ROADS),
00102   MK(0x0A, STR_SMALLMAP_LEGENDA_RAILROADS),
00103   MK(0x98, STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS),
00104   MK(0xB5, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00105   MK(0x0F, STR_SMALLMAP_LEGENDA_VEHICLES),
00106   MKEND()
00107 };
00108 
00109 static const LegendAndColour _legend_vehicles[] = {
00110   MK(0xB8, STR_SMALLMAP_LEGENDA_TRAINS),
00111   MK(0xBF, STR_SMALLMAP_LEGENDA_ROAD_VEHICLES),
00112   MK(0x98, STR_SMALLMAP_LEGENDA_SHIPS),
00113   MK(0x0F, STR_SMALLMAP_LEGENDA_AIRCRAFT),
00114 
00115   MS(0xD7, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES),
00116   MK(0xB5, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00117   MKEND()
00118 };
00119 
00120 static const LegendAndColour _legend_routes[] = {
00121   MK(0xD7, STR_SMALLMAP_LEGENDA_ROADS),
00122   MK(0x0A, STR_SMALLMAP_LEGENDA_RAILROADS),
00123   MK(0xB5, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00124 
00125   MS(0x56, STR_SMALLMAP_LEGENDA_RAILROAD_STATION),
00126   MK(0xC2, STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY),
00127   MK(0xBF, STR_SMALLMAP_LEGENDA_BUS_STATION),
00128   MK(0xB8, STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT),
00129   MK(0x98, STR_SMALLMAP_LEGENDA_DOCK),
00130   MKEND()
00131 };
00132 
00133 static const LegendAndColour _legend_vegetation[] = {
00134   MK(0x52, STR_SMALLMAP_LEGENDA_ROUGH_LAND),
00135   MK(0x54, STR_SMALLMAP_LEGENDA_GRASS_LAND),
00136   MK(0x37, STR_SMALLMAP_LEGENDA_BARE_LAND),
00137   MK(0x25, STR_SMALLMAP_LEGENDA_FIELDS),
00138   MK(0x57, STR_SMALLMAP_LEGENDA_TREES),
00139   MK(0xD0, STR_SMALLMAP_LEGENDA_FOREST),
00140 
00141   MS(0x0A, STR_SMALLMAP_LEGENDA_ROCKS),
00142   MK(0xC2, STR_SMALLMAP_LEGENDA_DESERT),
00143   MK(0x98, STR_SMALLMAP_LEGENDA_SNOW),
00144   MK(0xD7, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES),
00145   MK(0xB5, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00146   MKEND()
00147 };
00148 
00149 static LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1] = {
00150   MO(0xCA, STR_SMALLMAP_LEGENDA_WATER),
00151   MO(0x00, STR_SMALLMAP_LEGENDA_NO_OWNER), // This colour will vary depending on settings.
00152   MO(0xB4, STR_SMALLMAP_LEGENDA_TOWNS),
00153   MO(0x20, STR_SMALLMAP_LEGENDA_INDUSTRIES),
00154   /* The legend will be terminated the first time it is used. */
00155   MOEND(),
00156 };
00157 
00158 #undef MK
00159 #undef MC
00160 #undef MS
00161 #undef MO
00162 #undef MOEND
00163 #undef MKEND
00164 
00169 static LegendAndColour _legend_from_industries[NUM_INDUSTRYTYPES + 1];
00171 static uint _industry_to_list_pos[NUM_INDUSTRYTYPES];
00173 static bool _smallmap_show_heightmap = false;
00175 static uint _company_to_list_pos[MAX_COMPANIES];
00176 
00180 void BuildIndustriesLegend()
00181 {
00182   uint j = 0;
00183 
00184   /* Add each name */
00185   for (uint8 i = 0; i < NUM_INDUSTRYTYPES; i++) {
00186     IndustryType ind = _sorted_industry_types[i];
00187     const IndustrySpec *indsp = GetIndustrySpec(ind);
00188     if (indsp->enabled) {
00189       _legend_from_industries[j].legend = indsp->name;
00190       _legend_from_industries[j].colour = indsp->map_colour;
00191       _legend_from_industries[j].type = ind;
00192       _legend_from_industries[j].show_on_map = true;
00193       _legend_from_industries[j].col_break = false;
00194       _legend_from_industries[j].end = false;
00195 
00196       /* Store widget number for this industry type. */
00197       _industry_to_list_pos[ind] = j;
00198       j++;
00199     }
00200   }
00201   /* Terminate the list */
00202   _legend_from_industries[j].end = true;
00203 
00204   /* Store number of enabled industries */
00205   _smallmap_industry_count = j;
00206 }
00207 
00208 static const LegendAndColour * const _legend_table[] = {
00209   _legend_land_contours,
00210   _legend_vehicles,
00211   _legend_from_industries,
00212   _legend_routes,
00213   _legend_vegetation,
00214   _legend_land_owners,
00215 };
00216 
00217 #define MKCOLOUR(x) TO_LE32X(x)
00218 
00220 static const uint32 _green_map_heights[] = {
00221   MKCOLOUR(0x5A5A5A5A),
00222   MKCOLOUR(0x5A5B5A5B),
00223   MKCOLOUR(0x5B5B5B5B),
00224   MKCOLOUR(0x5B5C5B5C),
00225   MKCOLOUR(0x5C5C5C5C),
00226   MKCOLOUR(0x5C5D5C5D),
00227   MKCOLOUR(0x5D5D5D5D),
00228   MKCOLOUR(0x5D5E5D5E),
00229   MKCOLOUR(0x5E5E5E5E),
00230   MKCOLOUR(0x5E5F5E5F),
00231   MKCOLOUR(0x5F5F5F5F),
00232   MKCOLOUR(0x5F1F5F1F),
00233   MKCOLOUR(0x1F1F1F1F),
00234   MKCOLOUR(0x1F271F27),
00235   MKCOLOUR(0x27272727),
00236   MKCOLOUR(0x27272727),
00237 };
00238 assert_compile(lengthof(_green_map_heights) == MAX_TILE_HEIGHT + 1);
00239 
00241 static const uint32 _dark_green_map_heights[] = {
00242   MKCOLOUR(0x60606060),
00243   MKCOLOUR(0x60616061),
00244   MKCOLOUR(0x61616161),
00245   MKCOLOUR(0x61626162),
00246   MKCOLOUR(0x62626262),
00247   MKCOLOUR(0x62636263),
00248   MKCOLOUR(0x63636363),
00249   MKCOLOUR(0x63646364),
00250   MKCOLOUR(0x64646464),
00251   MKCOLOUR(0x64656465),
00252   MKCOLOUR(0x65656565),
00253   MKCOLOUR(0x65666566),
00254   MKCOLOUR(0x66666666),
00255   MKCOLOUR(0x66676667),
00256   MKCOLOUR(0x67676767),
00257   MKCOLOUR(0x67676767),
00258 };
00259 assert_compile(lengthof(_dark_green_map_heights) == MAX_TILE_HEIGHT + 1);
00260 
00262 static const uint32 _violet_map_heights[] = {
00263   MKCOLOUR(0x80808080),
00264   MKCOLOUR(0x80818081),
00265   MKCOLOUR(0x81818181),
00266   MKCOLOUR(0x81828182),
00267   MKCOLOUR(0x82828282),
00268   MKCOLOUR(0x82838283),
00269   MKCOLOUR(0x83838383),
00270   MKCOLOUR(0x83848384),
00271   MKCOLOUR(0x84848484),
00272   MKCOLOUR(0x84858485),
00273   MKCOLOUR(0x85858585),
00274   MKCOLOUR(0x85868586),
00275   MKCOLOUR(0x86868686),
00276   MKCOLOUR(0x86878687),
00277   MKCOLOUR(0x87878787),
00278   MKCOLOUR(0x87878787),
00279 };
00280 assert_compile(lengthof(_violet_map_heights) == MAX_TILE_HEIGHT + 1);
00281 
00283 struct SmallMapColourScheme {
00284   const uint32 *height_colours; 
00285   uint32 default_colour;   
00286 };
00287 
00289 static const SmallMapColourScheme _heightmap_schemes[] = {
00290   {_green_map_heights,      MKCOLOUR(0x54545454)}, 
00291   {_dark_green_map_heights, MKCOLOUR(0x62626262)}, 
00292   {_violet_map_heights,     MKCOLOUR(0x82828282)}, 
00293 };
00294 
00295 void BuildLandLegend()
00296 {
00297   for (LegendAndColour *lc = _legend_land_contours; lc->legend == STR_TINY_BLACK_HEIGHT; lc++) {
00298     lc->colour = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].height_colours[lc->height];
00299   }
00300 }
00301 
00305 void BuildOwnerLegend()
00306 {
00307   _legend_land_owners[1].colour = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].default_colour;
00308 
00309   int i = NUM_NO_COMPANY_ENTRIES;
00310   const Company *c;
00311   FOR_ALL_COMPANIES(c) {
00312     _legend_land_owners[i].colour = _colour_gradient[c->colour][5];
00313     _legend_land_owners[i].company = c->index;
00314     _legend_land_owners[i].show_on_map = true;
00315     _legend_land_owners[i].col_break = false;
00316     _legend_land_owners[i].end = false;
00317     _company_to_list_pos[c->index] = i;
00318     i++;
00319   }
00320 
00321   /* Terminate the list */
00322   _legend_land_owners[i].end = true;
00323 
00324   /* Store maximum amount of owner legend entries. */
00325   _smallmap_company_count = i;
00326 }
00327 
00328 struct AndOr {
00329   uint32 mor;
00330   uint32 mand;
00331 };
00332 
00333 static inline uint32 ApplyMask(uint32 colour, const AndOr *mask)
00334 {
00335   return (colour & mask->mand) | mask->mor;
00336 }
00337 
00338 
00340 static const AndOr _smallmap_contours_andor[] = {
00341   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_CLEAR
00342   {MKCOLOUR(0x000A0A00), MKCOLOUR(0xFF0000FF)}, // MP_RAILWAY
00343   {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)}, // MP_ROAD
00344   {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)}, // MP_HOUSE
00345   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_TREES
00346   {MKCOLOUR(0x98989898), MKCOLOUR(0x00000000)}, // MP_STATION
00347   {MKCOLOUR(0xCACACACA), MKCOLOUR(0x00000000)}, // MP_WATER
00348   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_VOID
00349   {MKCOLOUR(0xB5B5B5B5), MKCOLOUR(0x00000000)}, // MP_INDUSTRY
00350   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_TUNNELBRIDGE
00351   {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)}, // MP_OBJECT
00352   {MKCOLOUR(0x000A0A00), MKCOLOUR(0xFF0000FF)},
00353 };
00354 
00356 static const AndOr _smallmap_vehicles_andor[] = {
00357   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_CLEAR
00358   {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)}, // MP_RAILWAY
00359   {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)}, // MP_ROAD
00360   {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)}, // MP_HOUSE
00361   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_TREES
00362   {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)}, // MP_STATION
00363   {MKCOLOUR(0xCACACACA), MKCOLOUR(0x00000000)}, // MP_WATER
00364   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_VOID
00365   {MKCOLOUR(0xB5B5B5B5), MKCOLOUR(0x00000000)}, // MP_INDUSTRY
00366   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_TUNNELBRIDGE
00367   {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)}, // MP_OBJECT
00368   {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)},
00369 };
00370 
00372 static const byte _tiletype_importance[] = {
00373   2, // MP_CLEAR
00374   8, // MP_RAILWAY
00375   7, // MP_ROAD
00376   5, // MP_HOUSE
00377   2, // MP_TREES
00378   9, // MP_STATION
00379   2, // MP_WATER
00380   1, // MP_VOID
00381   6, // MP_INDUSTRY
00382   8, // MP_TUNNELBRIDGE
00383   2, // MP_OBJECT
00384   0,
00385 };
00386 
00387 
00388 static inline TileType GetEffectiveTileType(TileIndex tile)
00389 {
00390   TileType t = GetTileType(tile);
00391 
00392   if (t == MP_TUNNELBRIDGE) {
00393     TransportType tt = GetTunnelBridgeTransportType(tile);
00394 
00395     switch (tt) {
00396       case TRANSPORT_RAIL: t = MP_RAILWAY; break;
00397       case TRANSPORT_ROAD: t = MP_ROAD;    break;
00398       default:             t = MP_WATER;   break;
00399     }
00400   }
00401   return t;
00402 }
00403 
00410 static inline uint32 GetSmallMapContoursPixels(TileIndex tile, TileType t)
00411 {
00412   const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00413   return ApplyMask(cs->height_colours[TileHeight(tile)], &_smallmap_contours_andor[t]);
00414 }
00415 
00423 static inline uint32 GetSmallMapVehiclesPixels(TileIndex tile, TileType t)
00424 {
00425   const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00426   return ApplyMask(cs->default_colour, &_smallmap_vehicles_andor[t]);
00427 }
00428 
00436 static inline uint32 GetSmallMapIndustriesPixels(TileIndex tile, TileType t)
00437 {
00438   if (t == MP_INDUSTRY) {
00439     /* If industry is allowed to be seen, use its colour on the map */
00440     if (_legend_from_industries[_industry_to_list_pos[Industry::GetByTile(tile)->type]].show_on_map) {
00441       return GetIndustrySpec(Industry::GetByTile(tile)->type)->map_colour * 0x01010101;
00442     } else {
00443       /* Otherwise, return the colour which will make it disappear */
00444       t = (IsTileOnWater(tile) ? MP_WATER : MP_CLEAR);
00445     }
00446   }
00447 
00448   const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00449   return ApplyMask(_smallmap_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour, &_smallmap_vehicles_andor[t]);
00450 }
00451 
00459 static inline uint32 GetSmallMapRoutesPixels(TileIndex tile, TileType t)
00460 {
00461   if (t == MP_STATION) {
00462     switch (GetStationType(tile)) {
00463       case STATION_RAIL:    return MKCOLOUR(0x56565656);
00464       case STATION_AIRPORT: return MKCOLOUR(0xB8B8B8B8);
00465       case STATION_TRUCK:   return MKCOLOUR(0xC2C2C2C2);
00466       case STATION_BUS:     return MKCOLOUR(0xBFBFBFBF);
00467       case STATION_DOCK:    return MKCOLOUR(0x98989898);
00468       default:              return MKCOLOUR(0xFFFFFFFF);
00469     }
00470   } else if (t == MP_RAILWAY) {
00471     AndOr andor = {
00472       GetRailTypeInfo(GetRailType(tile))->map_colour * MKCOLOUR(0x00010100),
00473       _smallmap_contours_andor[t].mand
00474     };
00475 
00476     const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00477     return ApplyMask(cs->default_colour, &andor);
00478   }
00479 
00480   /* Ground colour */
00481   const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00482   return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]);
00483 }
00484 
00485 
00486 static const uint32 _vegetation_clear_bits[] = {
00487   MKCOLOUR(0x54545454), 
00488   MKCOLOUR(0x52525252), 
00489   MKCOLOUR(0x0A0A0A0A), 
00490   MKCOLOUR(0x25252525), 
00491   MKCOLOUR(0x98989898), 
00492   MKCOLOUR(0xC2C2C2C2), 
00493   MKCOLOUR(0x54545454), 
00494   MKCOLOUR(0x54545454), 
00495 };
00496 
00504 static inline uint32 GetSmallMapVegetationPixels(TileIndex tile, TileType t)
00505 {
00506   switch (t) {
00507     case MP_CLEAR:
00508       return (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) < 3) ? MKCOLOUR(0x37373737) : _vegetation_clear_bits[GetClearGround(tile)];
00509 
00510     case MP_INDUSTRY:
00511       return GetIndustrySpec(Industry::GetByTile(tile)->type)->check_proc == CHECK_FOREST ? MKCOLOUR(0xD0D0D0D0) : MKCOLOUR(0xB5B5B5B5);
00512 
00513     case MP_TREES:
00514       if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT || GetTreeGround(tile) == TREE_GROUND_ROUGH_SNOW) {
00515         return (_settings_game.game_creation.landscape == LT_ARCTIC) ? MKCOLOUR(0x98575798) : MKCOLOUR(0xC25757C2);
00516       }
00517       return MKCOLOUR(0x54575754);
00518 
00519     default:
00520       return ApplyMask(MKCOLOUR(0x54545454), &_smallmap_vehicles_andor[t]);
00521   }
00522 }
00523 
00531 static inline uint32 GetSmallMapOwnerPixels(TileIndex tile, TileType t)
00532 {
00533   Owner o;
00534 
00535   switch (t) {
00536     case MP_INDUSTRY: return MKCOLOUR(0x20202020);
00537     case MP_HOUSE:    return MKCOLOUR(0xB4B4B4B4);
00538     default:          o = GetTileOwner(tile); break;
00539     /* FIXME: For MP_ROAD there are multiple owners.
00540      * GetTileOwner returns the rail owner (level crossing) resp. the owner of ROADTYPE_ROAD (normal road),
00541      * even if there are no ROADTYPE_ROAD bits on the tile.
00542      */
00543   }
00544 
00545   if ((o < MAX_COMPANIES && !_legend_land_owners[_company_to_list_pos[o]].show_on_map) || o == OWNER_NONE) {
00546     const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00547     return _smallmap_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour;
00548   } else if (o == OWNER_WATER) {
00549     return MKCOLOUR(0xCACACACA);
00550   } else if (o == OWNER_TOWN) {
00551     return MKCOLOUR(0xB4B4B4B4);
00552   }
00553 
00554   return _legend_land_owners[_company_to_list_pos[o]].colour * 0x01010101;
00555 }
00556 
00558 static const byte _vehicle_type_colours[6] = {
00559   184, 191, 152, 15, 215, 184
00560 };
00561 
00562 
00564 class SmallMapWindow : public Window {
00566   enum SmallMapType {
00567     SMT_CONTOUR,
00568     SMT_VEHICLES,
00569     SMT_INDUSTRY,
00570     SMT_ROUTES,
00571     SMT_VEGETATION,
00572     SMT_OWNER,
00573   };
00574 
00576   enum ZoomLevelChange {
00577     ZLC_INITIALIZE, 
00578     ZLC_ZOOM_OUT,   
00579     ZLC_ZOOM_IN,    
00580   };
00581 
00582   static SmallMapType map_type; 
00583   static bool show_towns;       
00584 
00585   static const uint LEGEND_BLOB_WIDTH = 8;              
00586   static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2; 
00587   uint min_number_of_fixed_rows; 
00588   uint column_width;             
00589 
00590   int32 scroll_x;  
00591   int32 scroll_y;  
00592   int32 subscroll; 
00593   int zoom;        
00594 
00595   static const uint8 FORCE_REFRESH_PERIOD = 0x1F; 
00596   uint8 refresh; 
00597 
00604   FORCEINLINE Point RemapTile(int tile_x, int tile_y) const
00605   {
00606     int x_offset = tile_x - this->scroll_x / (int)TILE_SIZE;
00607     int y_offset = tile_y - this->scroll_y / (int)TILE_SIZE;
00608 
00609     if (this->zoom == 1) return RemapCoords(x_offset, y_offset, 0);
00610 
00611     /* For negative offsets, round towards -inf. */
00612     if (x_offset < 0) x_offset -= this->zoom - 1;
00613     if (y_offset < 0) y_offset -= this->zoom - 1;
00614 
00615     return RemapCoords(x_offset / this->zoom, y_offset / this->zoom, 0);
00616   }
00617 
00628   FORCEINLINE Point PixelToTile(int px, int py, int *sub, bool add_sub = true) const
00629   {
00630     if (add_sub) px += this->subscroll;  // Total horizontal offset.
00631 
00632     /* For each two rows down, add a x and a y tile, and
00633      * For each four pixels to the right, move a tile to the right. */
00634     Point pt = {((py >> 1) - (px >> 2)) * this->zoom, ((py >> 1) + (px >> 2)) * this->zoom};
00635     px &= 3;
00636 
00637     if (py & 1) { // Odd number of rows, handle the 2 pixel shift.
00638       if (px < 2) {
00639         pt.x += this->zoom;
00640         px += 2;
00641       } else {
00642         pt.y += this->zoom;
00643         px -= 2;
00644       }
00645     }
00646 
00647     *sub = px;
00648     return pt;
00649   }
00650 
00660   Point ComputeScroll(int tx, int ty, int x, int y, int *sub)
00661   {
00662     assert(x >= 0 && y >= 0);
00663 
00664     int new_sub;
00665     Point tile_xy = PixelToTile(x, y, &new_sub, false);
00666     tx -= tile_xy.x;
00667     ty -= tile_xy.y;
00668 
00669     Point scroll;
00670     if (new_sub == 0) {
00671       *sub = 0;
00672       scroll.x = (tx + this->zoom) * TILE_SIZE;
00673       scroll.y = (ty - this->zoom) * TILE_SIZE;
00674     } else {
00675       *sub = 4 - new_sub;
00676       scroll.x = (tx + 2 * this->zoom) * TILE_SIZE;
00677       scroll.y = (ty - 2 * this->zoom) * TILE_SIZE;
00678     }
00679     return scroll;
00680   }
00681 
00688   void SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt)
00689   {
00690     static const int zoomlevels[] = {1, 2, 4, 6, 8}; // Available zoom levels. Bigger number means more zoom-out (further away).
00691     static const int MIN_ZOOM_INDEX = 0;
00692     static const int MAX_ZOOM_INDEX = lengthof(zoomlevels) - 1;
00693 
00694     int new_index, cur_index, sub;
00695     Point tile;
00696     switch (change) {
00697       case ZLC_INITIALIZE:
00698         cur_index = - 1; // Definitely different from new_index.
00699         new_index = MIN_ZOOM_INDEX;
00700         break;
00701 
00702       case ZLC_ZOOM_IN:
00703       case ZLC_ZOOM_OUT:
00704         for (cur_index = MIN_ZOOM_INDEX; cur_index <= MAX_ZOOM_INDEX; cur_index++) {
00705           if (this->zoom == zoomlevels[cur_index]) break;
00706         }
00707         assert(cur_index <= MAX_ZOOM_INDEX);
00708 
00709         tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub);
00710         new_index = Clamp(cur_index + ((change == ZLC_ZOOM_IN) ? -1 : 1), MIN_ZOOM_INDEX, MAX_ZOOM_INDEX);
00711         break;
00712 
00713       default: NOT_REACHED();
00714     }
00715 
00716     if (new_index != cur_index) {
00717       this->zoom = zoomlevels[new_index];
00718       if (cur_index >= 0) {
00719         Point new_tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub);
00720         this->SetNewScroll(this->scroll_x + (tile.x - new_tile.x) * TILE_SIZE,
00721             this->scroll_y + (tile.y - new_tile.y) * TILE_SIZE, sub);
00722       }
00723       this->SetWidgetDisabledState(SM_WIDGET_ZOOM_IN,  this->zoom == zoomlevels[MIN_ZOOM_INDEX]);
00724       this->SetWidgetDisabledState(SM_WIDGET_ZOOM_OUT, this->zoom == zoomlevels[MAX_ZOOM_INDEX]);
00725       this->SetDirty();
00726     }
00727   }
00728 
00734   inline uint32 GetTileColours(const TileArea &ta) const
00735   {
00736     int importance = 0;
00737     TileIndex tile = INVALID_TILE; // Position of the most important tile.
00738     TileType et = MP_VOID;         // Effective tile type at that position.
00739 
00740     TILE_AREA_LOOP(ti, ta) {
00741       TileType ttype = GetEffectiveTileType(ti);
00742       if (_tiletype_importance[ttype] > importance) {
00743         importance = _tiletype_importance[ttype];
00744         tile = ti;
00745         et = ttype;
00746       }
00747     }
00748 
00749     switch (this->map_type) {
00750       case SMT_CONTOUR:
00751         return GetSmallMapContoursPixels(tile, et);
00752 
00753       case SMT_VEHICLES:
00754         return GetSmallMapVehiclesPixels(tile, et);
00755 
00756       case SMT_INDUSTRY:
00757         return GetSmallMapIndustriesPixels(tile, et);
00758 
00759       case SMT_ROUTES:
00760         return GetSmallMapRoutesPixels(tile, et);
00761 
00762       case SMT_VEGETATION:
00763         return GetSmallMapVegetationPixels(tile, et);
00764 
00765       case SMT_OWNER:
00766         return GetSmallMapOwnerPixels(tile, et);
00767 
00768       default: NOT_REACHED();
00769     }
00770   }
00771 
00786   void DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const
00787   {
00788     void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height);
00789     uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0;
00790 
00791     do {
00792       /* Check if the tile (xc,yc) is within the map range */
00793       if (xc >= MapMaxX() || yc >= MapMaxY()) continue;
00794 
00795       /* Check if the dst pointer points to a pixel inside the screen buffer */
00796       if (dst < _screen.dst_ptr) continue;
00797       if (dst >= dst_ptr_abs_end) continue;
00798 
00799       /* Construct tilearea covered by (xc, yc, xc + this->zoom, yc + this->zoom) such that it is within min_xy limits. */
00800       TileArea ta;
00801       if (min_xy == 1 && (xc == 0 || yc == 0)) {
00802         if (this->zoom == 1) continue; // The tile area is empty, don't draw anything.
00803 
00804         ta = TileArea(TileXY(max(min_xy, xc), max(min_xy, yc)), this->zoom - (xc == 0), this->zoom - (yc == 0));
00805       } else {
00806         ta = TileArea(TileXY(xc, yc), this->zoom, this->zoom);
00807       }
00808       ta.ClampToMap(); // Clamp to map boundaries (may contain MP_VOID tiles!).
00809 
00810       uint32 val = this->GetTileColours(ta);
00811       uint8 *val8 = (uint8 *)&val;
00812       int idx = max(0, -start_pos);
00813       for (int pos = max(0, start_pos); pos < end_pos; pos++) {
00814         blitter->SetPixel(dst, idx, 0, val8[idx]);
00815         idx++;
00816       }
00817     /* Switch to next tile in the column */
00818     } while (xc += this->zoom, yc += this->zoom, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0);
00819   }
00820 
00826   void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const
00827   {
00828     const Vehicle *v;
00829     FOR_ALL_VEHICLES(v) {
00830       if (v->type == VEH_EFFECT) continue;
00831       if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue;
00832 
00833       /* Remap into flat coordinates. */
00834       Point pt = this->RemapTile(v->x_pos / TILE_SIZE, v->y_pos / TILE_SIZE);
00835 
00836       int y = pt.y - dpi->top;
00837       if (!IsInsideMM(y, 0, dpi->height)) continue; // y is out of bounds.
00838 
00839       bool skip = false; // Default is to draw both pixels.
00840       int x = pt.x - this->subscroll - 3 - dpi->left; // Offset X coordinate.
00841       if (x < 0) {
00842         /* if x+1 is 0, that means we're on the very left edge,
00843          * and should thus only draw a single pixel */
00844         if (++x != 0) continue;
00845         skip = true;
00846       } else if (x >= dpi->width - 1) {
00847         /* Check if we're at the very right edge, and if so draw only a single pixel */
00848         if (x != dpi->width - 1) continue;
00849         skip = true;
00850       }
00851 
00852       /* Calculate pointer to pixel and the colour */
00853       byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : 0xF;
00854 
00855       /* And draw either one or two pixels depending on clipping */
00856       blitter->SetPixel(dpi->dst_ptr, x, y, colour);
00857       if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour);
00858     }
00859   }
00860 
00865   void DrawTowns(const DrawPixelInfo *dpi) const
00866   {
00867     const Town *t;
00868     FOR_ALL_TOWNS(t) {
00869       /* Remap the town coordinate */
00870       Point pt = this->RemapTile(TileX(t->xy), TileY(t->xy));
00871       int x = pt.x - this->subscroll - (t->sign.width_small >> 1);
00872       int y = pt.y;
00873 
00874       /* Check if the town sign is within bounds */
00875       if (x + t->sign.width_small > dpi->left &&
00876           x < dpi->left + dpi->width &&
00877           y + FONT_HEIGHT_SMALL > dpi->top &&
00878           y < dpi->top + dpi->height) {
00879         /* And draw it. */
00880         SetDParam(0, t->index);
00881         DrawString(x, x + t->sign.width_small, y, STR_SMALLMAP_TOWN);
00882       }
00883     }
00884   }
00885 
00892   static inline void DrawVertMapIndicator(int x, int y, int y2)
00893   {
00894     GfxFillRect(x, y,      x, y + 3, 69);
00895     GfxFillRect(x, y2 - 3, x, y2,    69);
00896   }
00897 
00904   static inline void DrawHorizMapIndicator(int x, int x2, int y)
00905   {
00906     GfxFillRect(x,      y, x + 3, y, 69);
00907     GfxFillRect(x2 - 3, y, x2,    y, 69);
00908   }
00909 
00913   void DrawMapIndicators() const
00914   {
00915     /* Find main viewport. */
00916     const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
00917 
00918     Point tile = InverseRemapCoords(vp->virtual_left, vp->virtual_top);
00919     Point tl = this->RemapTile(tile.x >> 4, tile.y >> 4);
00920     tl.x -= this->subscroll;
00921 
00922     tile = InverseRemapCoords(vp->virtual_left + vp->virtual_width, vp->virtual_top + vp->virtual_height);
00923     Point br = this->RemapTile(tile.x >> 4, tile.y >> 4);
00924     br.x -= this->subscroll;
00925 
00926     SmallMapWindow::DrawVertMapIndicator(tl.x, tl.y, br.y);
00927     SmallMapWindow::DrawVertMapIndicator(br.x, tl.y, br.y);
00928 
00929     SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, tl.y);
00930     SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, br.y);
00931   }
00932 
00944   void DrawSmallMap(DrawPixelInfo *dpi) const
00945   {
00946     Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
00947     DrawPixelInfo *old_dpi;
00948 
00949     old_dpi = _cur_dpi;
00950     _cur_dpi = dpi;
00951 
00952     /* Clear it */
00953     GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, 0);
00954 
00955     /* Which tile is displayed at (dpi->left, dpi->top)? */
00956     int dx;
00957     Point tile = this->PixelToTile(dpi->left, dpi->top, &dx);
00958     int tile_x = this->scroll_x / (int)TILE_SIZE + tile.x;
00959     int tile_y = this->scroll_y / (int)TILE_SIZE + tile.y;
00960 
00961     void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0);
00962     int x = - dx - 4;
00963     int y = 0;
00964 
00965     for (;;) {
00966       /* Distance from left edge */
00967       if (x >= -3) {
00968         if (x >= dpi->width) break; // Exit the loop.
00969 
00970         int end_pos = min(dpi->width, x + 4);
00971         int reps = (dpi->height - y + 1) / 2; // Number of lines.
00972         if (reps > 0) {
00973           this->DrawSmallMapColumn(ptr, tile_x, tile_y, dpi->pitch * 2, reps, x, end_pos, blitter);
00974         }
00975       }
00976 
00977       if (y == 0) {
00978         tile_y += this->zoom;
00979         y++;
00980         ptr = blitter->MoveTo(ptr, 0, 1);
00981       } else {
00982         tile_x -= this->zoom;
00983         y--;
00984         ptr = blitter->MoveTo(ptr, 0, -1);
00985       }
00986       ptr = blitter->MoveTo(ptr, 2, 0);
00987       x += 2;
00988     }
00989 
00990     /* Draw vehicles */
00991     if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter);
00992 
00993     /* Draw town names */
00994     if (this->show_towns) this->DrawTowns(dpi);
00995 
00996     /* Draw map indicators */
00997     this->DrawMapIndicators();
00998 
00999     _cur_dpi = old_dpi;
01000   }
01001 
01005   void SetupWidgetData()
01006   {
01007     StringID legend_tooltip;
01008     StringID enable_all_tooltip;
01009     StringID disable_all_tooltip;
01010     int plane;
01011     switch (this->map_type) {
01012       case SMT_INDUSTRY:
01013         legend_tooltip = STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION;
01014         enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES;
01015         disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES;
01016         plane = 0;
01017         break;
01018 
01019       case SMT_OWNER:
01020         legend_tooltip = STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION;
01021         enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES;
01022         disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES;
01023         plane = 0;
01024         break;
01025 
01026       default:
01027         legend_tooltip = STR_NULL;
01028         enable_all_tooltip = STR_NULL;
01029         disable_all_tooltip = STR_NULL;
01030         plane = 1;
01031         break;
01032     }
01033 
01034     this->GetWidget<NWidgetCore>(SM_WIDGET_LEGEND)->SetDataTip(STR_NULL, legend_tooltip);
01035     this->GetWidget<NWidgetCore>(SM_WIDGET_ENABLE_ALL)->SetDataTip(STR_SMALLMAP_ENABLE_ALL, enable_all_tooltip);
01036     this->GetWidget<NWidgetCore>(SM_WIDGET_DISABLE_ALL)->SetDataTip(STR_SMALLMAP_DISABLE_ALL, disable_all_tooltip);
01037     this->GetWidget<NWidgetStacked>(SM_WIDGET_SELECT_BUTTONS)->SetDisplayedPlane(plane);
01038   }
01039 
01040 public:
01041   uint min_number_of_columns;    
01042 
01043   SmallMapWindow(const WindowDesc *desc, int window_number) : Window(), refresh(FORCE_REFRESH_PERIOD)
01044   {
01045     this->InitNested(desc, window_number);
01046     this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
01047 
01048     BuildLandLegend();
01049     this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_show_heightmap);
01050 
01051     this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
01052 
01053     this->SetupWidgetData();
01054 
01055     this->SetZoomLevel(ZLC_INITIALIZE, NULL);
01056     this->SmallMapCenterOnCurrentPos();
01057   }
01058 
01063   inline uint GetMinLegendWidth() const
01064   {
01065     return WD_FRAMERECT_LEFT + this->min_number_of_columns * this->column_width;
01066   }
01067 
01072   inline uint GetNumberColumnsLegend(uint width) const
01073   {
01074     return width / this->column_width;
01075   }
01076 
01082   uint GetLegendHeight(uint num_columns) const
01083   {
01084     uint num_rows = max(this->min_number_of_fixed_rows, CeilDiv(max(_smallmap_company_count, _smallmap_industry_count), num_columns));
01085     return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
01086   }
01087 
01088   virtual void SetStringParameters(int widget) const
01089   {
01090     switch (widget) {
01091       case SM_WIDGET_CAPTION:
01092         SetDParam(0, STR_SMALLMAP_TYPE_CONTOURS + this->map_type);
01093         break;
01094     }
01095   }
01096 
01097   virtual void OnInit()
01098   {
01099     uint min_width = 0;
01100     this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS;
01101     this->min_number_of_fixed_rows = 0;
01102     for (uint i = 0; i < lengthof(_legend_table); i++) {
01103       uint height = 0;
01104       uint num_columns = 1;
01105       for (const LegendAndColour *tbl = _legend_table[i]; !tbl->end; ++tbl) {
01106         StringID str;
01107         if (i == SMT_INDUSTRY) {
01108           SetDParam(0, tbl->legend);
01109           SetDParam(1, IndustryPool::MAX_SIZE);
01110           str = STR_SMALLMAP_INDUSTRY;
01111         } else if (i == SMT_OWNER) {
01112           if (tbl->company != INVALID_COMPANY) {
01113             if (!Company::IsValidID(tbl->company)) {
01114               /* Rebuild the owner legend. */
01115               BuildOwnerLegend();
01116               this->OnInit();
01117               return;
01118             }
01119             /* Non-fixed legend entries for the owner view. */
01120             SetDParam(0, tbl->company);
01121             str = STR_SMALLMAP_COMPANY;
01122           } else {
01123             str = tbl->legend;
01124           }
01125         } else {
01126           if (tbl->col_break) {
01127             this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
01128             height = 0;
01129             num_columns++;
01130           }
01131           height++;
01132           str = tbl->legend;
01133         }
01134         min_width = max(GetStringBoundingBox(str).width, min_width);
01135       }
01136       this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
01137       this->min_number_of_columns = max(this->min_number_of_columns, num_columns);
01138     }
01139 
01140     /* The width of a column is the minimum width of all texts + the size of the blob + some spacing */
01141     this->column_width = min_width + LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
01142   }
01143 
01144   virtual void OnPaint()
01145   {
01146     if (this->map_type == SMT_OWNER) {
01147       for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) {
01148         if (tbl->company != INVALID_COMPANY && !Company::IsValidID(tbl->company)) {
01149           /* Rebuild the owner legend. */
01150           BuildOwnerLegend();
01151           this->InvalidateData(1);
01152           break;
01153         }
01154       }
01155     }
01156 
01157     this->DrawWidgets();
01158   }
01159 
01160   virtual void DrawWidget(const Rect &r, int widget) const
01161   {
01162     switch (widget) {
01163       case SM_WIDGET_MAP: {
01164         DrawPixelInfo new_dpi;
01165         if (!FillDrawPixelInfo(&new_dpi, r.left + 1, r.top + 1, r.right - r.left - 1, r.bottom - r.top - 1)) return;
01166         this->DrawSmallMap(&new_dpi);
01167         break;
01168       }
01169 
01170       case SM_WIDGET_LEGEND: {
01171         uint columns = this->GetNumberColumnsLegend(r.right - r.left + 1);
01172         uint number_of_rows = max((this->map_type == SMT_INDUSTRY || this->map_type == SMT_OWNER) ? CeilDiv(max(_smallmap_company_count, _smallmap_industry_count), columns) : 0, this->min_number_of_fixed_rows);
01173         bool rtl = _current_text_dir == TD_RTL;
01174         uint y_org = r.top + WD_FRAMERECT_TOP;
01175         uint x = rtl ? r.right - this->column_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT;
01176         uint y = y_org;
01177         uint i = 0; // Row counter for industry legend.
01178         uint row_height = FONT_HEIGHT_SMALL;
01179 
01180         uint text_left  = rtl ? 0 : LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT;
01181         uint text_right = this->column_width - 1 - (rtl ? LEGEND_BLOB_WIDTH + WD_FRAMERECT_RIGHT : 0);
01182         uint blob_left  = rtl ? this->column_width - 1 - LEGEND_BLOB_WIDTH : 0;
01183         uint blob_right = rtl ? this->column_width - 1 : LEGEND_BLOB_WIDTH;
01184 
01185         for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) {
01186           if (tbl->col_break || ((this->map_type == SMT_INDUSTRY || this->map_type == SMT_OWNER) && i++ >= number_of_rows)) {
01187             /* Column break needed, continue at top, COLUMN_WIDTH pixels
01188              * (one "row") to the right. */
01189             x += rtl ? -(int)this->column_width : this->column_width;
01190             y = y_org;
01191             i = 1;
01192           }
01193 
01194           if (this->map_type == SMT_INDUSTRY) {
01195             /* Industry name must be formatted, since it's not in tiny font in the specs.
01196              * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font */
01197             SetDParam(0, tbl->legend);
01198             SetDParam(1, Industry::GetIndustryTypeCount(tbl->type));
01199             if (!tbl->show_on_map) {
01200               /* Simply draw the string, not the black border of the legend colour.
01201                * This will enforce the idea of the disabled item */
01202               DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_GREY);
01203             } else {
01204               DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_BLACK);
01205               GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0); // Outer border of the legend colour
01206             }
01207           } else if (this->map_type == SMT_OWNER && tbl->company != INVALID_COMPANY) {
01208             SetDParam(0, tbl->company);
01209             if (!tbl->show_on_map) {
01210               /* Simply draw the string, not the black border of the legend colour.
01211                * This will enforce the idea of the disabled item */
01212               DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_COMPANY, TC_GREY);
01213             } else {
01214               DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_COMPANY, TC_BLACK);
01215               GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0); // Outer border of the legend colour
01216             }
01217           } else {
01218             if (this->map_type == SMT_CONTOUR) SetDParam(0, tbl->height * TILE_HEIGHT_STEP);
01219 
01220             /* Anything that is not an industry or a company is using normal process */
01221             GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0);
01222             DrawString(x + text_left, x + text_right, y, tbl->legend);
01223           }
01224           GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + row_height - 2, tbl->colour); // Legend colour
01225 
01226           y += row_height;
01227         }
01228       }
01229     }
01230   }
01231 
01236   void SwitchMapType(SmallMapType map_type)
01237   {
01238     this->RaiseWidget(this->map_type + SM_WIDGET_CONTOUR);
01239     this->map_type = map_type;
01240     this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
01241 
01242     this->SetupWidgetData();
01243 
01244     this->SetDirty();
01245   }
01246 
01247   virtual void OnClick(Point pt, int widget, int click_count)
01248   {
01249     /* User clicked something, notify the industry chain window to stop sending newly selected industries. */
01250     InvalidateWindowClassesData(WC_INDUSTRY_CARGOES, NUM_INDUSTRYTYPES);
01251 
01252     switch (widget) {
01253       case SM_WIDGET_MAP: { // Map window
01254         /*
01255          * XXX: scrolling with the left mouse button is done by subsequently
01256          * clicking with the left mouse button; clicking once centers the
01257          * large map at the selected point. So by unclicking the left mouse
01258          * button here, it gets reclicked during the next inputloop, which
01259          * would make it look like the mouse is being dragged, while it is
01260          * actually being (virtually) clicked every inputloop.
01261          */
01262         _left_button_clicked = false;
01263 
01264         const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01265         Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
01266         int sub;
01267         pt = this->PixelToTile(pt.x - wid->pos_x, pt.y - wid->pos_y, &sub);
01268         pt = RemapCoords(this->scroll_x + pt.x * TILE_SIZE + this->zoom * (TILE_SIZE - sub * TILE_SIZE / 4),
01269             this->scroll_y + pt.y * TILE_SIZE + sub * this->zoom * TILE_SIZE / 4, 0);
01270 
01271         w->viewport->follow_vehicle = INVALID_VEHICLE;
01272         w->viewport->dest_scrollpos_x = pt.x - (w->viewport->virtual_width  >> 1);
01273         w->viewport->dest_scrollpos_y = pt.y - (w->viewport->virtual_height >> 1);
01274 
01275         this->SetDirty();
01276         break;
01277       }
01278 
01279       case SM_WIDGET_ZOOM_IN:
01280       case SM_WIDGET_ZOOM_OUT: {
01281         const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01282         Point pt = {wid->current_x / 2, wid->current_y / 2};
01283         this->SetZoomLevel((widget == SM_WIDGET_ZOOM_IN) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt);
01284         SndPlayFx(SND_15_BEEP);
01285         break;
01286       }
01287 
01288       case SM_WIDGET_CONTOUR:    // Show land contours
01289       case SM_WIDGET_VEHICLES:   // Show vehicles
01290       case SM_WIDGET_INDUSTRIES: // Show industries
01291       case SM_WIDGET_ROUTES:     // Show transport routes
01292       case SM_WIDGET_VEGETATION: // Show vegetation
01293       case SM_WIDGET_OWNERS:     // Show land owners
01294         this->SwitchMapType((SmallMapType)(widget - SM_WIDGET_CONTOUR));
01295         SndPlayFx(SND_15_BEEP);
01296         break;
01297 
01298       case SM_WIDGET_CENTERMAP: // Center the smallmap again
01299         this->SmallMapCenterOnCurrentPos();
01300         this->HandleButtonClick(SM_WIDGET_CENTERMAP);
01301         SndPlayFx(SND_15_BEEP);
01302         break;
01303 
01304       case SM_WIDGET_TOGGLETOWNNAME: // Toggle town names
01305         this->show_towns = !this->show_towns;
01306         this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
01307 
01308         this->SetDirty();
01309         SndPlayFx(SND_15_BEEP);
01310         break;
01311 
01312       case SM_WIDGET_LEGEND: // Legend
01313         /* If industry type small map*/
01314         if (this->map_type == SMT_INDUSTRY) {
01315           /* If click on industries label, find right industry type and enable/disable it */
01316           const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_LEGEND); // Label panel
01317           uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL;
01318           uint columns = this->GetNumberColumnsLegend(wi->current_x);
01319           uint number_of_rows = max(CeilDiv(max(_smallmap_company_count, _smallmap_industry_count), columns), this->min_number_of_fixed_rows);
01320           if (line >= number_of_rows) break;
01321 
01322           bool rtl = _current_text_dir == TD_RTL;
01323           int x = pt.x - wi->pos_x;
01324           if (rtl) x = wi->current_x - x;
01325           uint column = (x - WD_FRAMERECT_LEFT) / this->column_width;
01326 
01327           /* Check if click is on industry label*/
01328           int industry_pos = (column * number_of_rows) + line;
01329           if (industry_pos < _smallmap_industry_count) {
01330             if (_ctrl_pressed) {
01331               /* Disable all, except the clicked one */
01332               bool changes = false;
01333               for (int i = 0; i != _smallmap_industry_count; i++) {
01334                 bool new_state = i == industry_pos;
01335                 if (_legend_from_industries[i].show_on_map != new_state) {
01336                   changes = true;
01337                   _legend_from_industries[i].show_on_map = new_state;
01338                 }
01339               }
01340               if (!changes) {
01341                 /* Nothing changed? Then show all (again). */
01342                 for (int i = 0; i != _smallmap_industry_count; i++) {
01343                   _legend_from_industries[i].show_on_map = true;
01344                 }
01345               }
01346             } else {
01347               _legend_from_industries[industry_pos].show_on_map = !_legend_from_industries[industry_pos].show_on_map;
01348             }
01349           }
01350           this->SetDirty();
01351         } else if (this->map_type == SMT_OWNER) {
01352           /* If click on companies label, find right company and enable/disable it. */
01353           const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_LEGEND);
01354           uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL;
01355           uint columns = this->GetNumberColumnsLegend(wi->current_x);
01356           uint number_of_rows = max(CeilDiv(max(_smallmap_company_count, _smallmap_industry_count), columns), this->min_number_of_fixed_rows);
01357           if (line >= number_of_rows) break;
01358 
01359           bool rtl = _current_text_dir == TD_RTL;
01360           int x = pt.x - wi->pos_x;
01361           if (rtl) x = wi->current_x - x;
01362           uint column = (x - WD_FRAMERECT_LEFT) / this->column_width;
01363 
01364           /* Check if click is on company label. */
01365           int company_pos = (column * number_of_rows) + line;
01366           if (company_pos < NUM_NO_COMPANY_ENTRIES) break;
01367           if (company_pos < _smallmap_company_count) {
01368             if (_ctrl_pressed) {
01369               /* Disable all, except the clicked one */
01370               bool changes = false;
01371               for (int i = NUM_NO_COMPANY_ENTRIES; i != _smallmap_company_count; i++) {
01372                 bool new_state = i == company_pos;
01373                 if (_legend_land_owners[i].show_on_map != new_state) {
01374                   changes = true;
01375                   _legend_land_owners[i].show_on_map = new_state;
01376                 }
01377               }
01378               if (!changes) {
01379                 /* Nothing changed? Then show all (again). */
01380                 for (int i = NUM_NO_COMPANY_ENTRIES; i != _smallmap_company_count; i++) {
01381                   _legend_land_owners[i].show_on_map = true;
01382                 }
01383               }
01384             } else {
01385               _legend_land_owners[company_pos].show_on_map = !_legend_land_owners[company_pos].show_on_map;
01386             }
01387           }
01388           this->SetDirty();
01389         }
01390         break;
01391 
01392       case SM_WIDGET_ENABLE_ALL:
01393         if (this->map_type == SMT_INDUSTRY) {
01394           for (int i = 0; i != _smallmap_industry_count; i++) {
01395             _legend_from_industries[i].show_on_map = true;
01396           }
01397         } else if (this->map_type == SMT_OWNER) {
01398           for (int i = NUM_NO_COMPANY_ENTRIES; i != _smallmap_company_count; i++) {
01399             _legend_land_owners[i].show_on_map = true;
01400           }
01401         }
01402         this->SetDirty();
01403         break;
01404 
01405       case SM_WIDGET_DISABLE_ALL:
01406         if (this->map_type == SMT_INDUSTRY) {
01407           for (int i = 0; i != _smallmap_industry_count; i++) {
01408             _legend_from_industries[i].show_on_map = false;
01409           }
01410         } else {
01411           for (int i = NUM_NO_COMPANY_ENTRIES; i != _smallmap_company_count; i++) {
01412             _legend_land_owners[i].show_on_map = false;
01413           }
01414         }
01415         this->SetDirty();
01416         break;
01417 
01418       case SM_WIDGET_SHOW_HEIGHT: // Enable/disable showing of heightmap.
01419         _smallmap_show_heightmap = !_smallmap_show_heightmap;
01420         this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_show_heightmap);
01421         this->SetDirty();
01422         break;
01423     }
01424   }
01425 
01431   virtual void OnInvalidateData(int data)
01432   {
01433     switch (data) {
01434       case 1:
01435         /* The owner legend has already been rebuilt. */
01436         this->ReInit();
01437         break;
01438 
01439       case 0: {
01440         extern uint64 _displayed_industries;
01441         if (this->map_type != SMT_INDUSTRY) this->SwitchMapType(SMT_INDUSTRY);
01442 
01443         for (int i = 0; i != _smallmap_industry_count; i++) {
01444           _legend_from_industries[i].show_on_map = HasBit(_displayed_industries, _legend_from_industries[i].type);
01445         }
01446         break;
01447       }
01448 
01449       default: NOT_REACHED();
01450     }
01451     this->SetDirty();
01452   }
01453 
01454   virtual bool OnRightClick(Point pt, int widget)
01455   {
01456     if (widget != SM_WIDGET_MAP || _scrolling_viewport) return false;
01457 
01458     _scrolling_viewport = true;
01459     return true;
01460   }
01461 
01462   virtual void OnMouseWheel(int wheel)
01463   {
01464     if (_settings_client.gui.scrollwheel_scrolling == 0) {
01465       const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01466       int cursor_x = _cursor.pos.x - this->left - wid->pos_x;
01467       int cursor_y = _cursor.pos.y - this->top  - wid->pos_y;
01468       if (IsInsideMM(cursor_x, 0, wid->current_x) && IsInsideMM(cursor_y, 0, wid->current_y)) {
01469         Point pt = {cursor_x, cursor_y};
01470         this->SetZoomLevel((wheel < 0) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt);
01471       }
01472     }
01473   }
01474 
01475   virtual void OnTick()
01476   {
01477     /* Update the window every now and then */
01478     if (--this->refresh != 0) return;
01479 
01480     this->refresh = FORCE_REFRESH_PERIOD;
01481     this->SetDirty();
01482   }
01483 
01491   void SetNewScroll(int sx, int sy, int sub)
01492   {
01493     const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01494     Point hv = InverseRemapCoords(wi->current_x * TILE_SIZE / 2, wi->current_y * TILE_SIZE / 2);
01495     hv.x *= this->zoom;
01496     hv.y *= this->zoom;
01497 
01498     if (sx < -hv.x) {
01499       sx = -hv.x;
01500       sub = 0;
01501     }
01502     if (sx > (int)(MapMaxX() * TILE_SIZE) - hv.x) {
01503       sx = MapMaxX() * TILE_SIZE - hv.x;
01504       sub = 0;
01505     }
01506     if (sy < -hv.y) {
01507       sy = -hv.y;
01508       sub = 0;
01509     }
01510     if (sy > (int)(MapMaxY() * TILE_SIZE) - hv.y) {
01511       sy = MapMaxY() * TILE_SIZE - hv.y;
01512       sub = 0;
01513     }
01514 
01515     this->scroll_x = sx;
01516     this->scroll_y = sy;
01517     this->subscroll = sub;
01518   }
01519 
01520   virtual void OnScroll(Point delta)
01521   {
01522     _cursor.fix_at = true;
01523 
01524     /* While tile is at (delta.x, delta.y)? */
01525     int sub;
01526     Point pt = this->PixelToTile(delta.x, delta.y, &sub);
01527     this->SetNewScroll(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, sub);
01528 
01529     this->SetDirty();
01530   }
01531 
01532   void SmallMapCenterOnCurrentPos()
01533   {
01534     const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
01535     Point pt = InverseRemapCoords(vp->virtual_left + vp->virtual_width  / 2, vp->virtual_top  + vp->virtual_height / 2);
01536 
01537     int sub;
01538     const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01539     Point sxy = this->ComputeScroll(pt.x / TILE_SIZE, pt.y / TILE_SIZE, max(0, (int)wid->current_x / 2 - 2), wid->current_y / 2, &sub);
01540     this->SetNewScroll(sxy.x, sxy.y, sub);
01541     this->SetDirty();
01542   }
01543 };
01544 
01545 SmallMapWindow::SmallMapType SmallMapWindow::map_type = SMT_CONTOUR;
01546 bool SmallMapWindow::show_towns = true;
01547 
01556 class NWidgetSmallmapDisplay : public NWidgetContainer {
01557   const SmallMapWindow *smallmap_window; 
01558 public:
01559   NWidgetSmallmapDisplay() : NWidgetContainer(NWID_VERTICAL)
01560   {
01561     this->smallmap_window = NULL;
01562   }
01563 
01564   virtual void SetupSmallestSize(Window *w, bool init_array)
01565   {
01566     NWidgetBase *display = this->head;
01567     NWidgetBase *bar = display->next;
01568 
01569     display->SetupSmallestSize(w, init_array);
01570     bar->SetupSmallestSize(w, init_array);
01571 
01572     this->smallmap_window = dynamic_cast<SmallMapWindow *>(w);
01573     this->smallest_x = max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth());
01574     this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetLegendHeight(smallmap_window->min_number_of_columns));
01575     this->fill_x = max(display->fill_x, bar->fill_x);
01576     this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : min(display->fill_y, bar->fill_y);
01577     this->resize_x = max(display->resize_x, bar->resize_x);
01578     this->resize_y = min(display->resize_y, bar->resize_y);
01579   }
01580 
01581   virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01582   {
01583     this->pos_x = x;
01584     this->pos_y = y;
01585     this->current_x = given_width;
01586     this->current_y = given_height;
01587 
01588     NWidgetBase *display = this->head;
01589     NWidgetBase *bar = display->next;
01590 
01591     if (sizing == ST_SMALLEST) {
01592       this->smallest_x = given_width;
01593       this->smallest_y = given_height;
01594       /* Make display and bar exactly equal to their minimal size. */
01595       display->AssignSizePosition(ST_SMALLEST, x, y, display->smallest_x, display->smallest_y, rtl);
01596       bar->AssignSizePosition(ST_SMALLEST, x, y + display->smallest_y, bar->smallest_x, bar->smallest_y, rtl);
01597     }
01598 
01599     uint bar_height = max(bar->smallest_y, this->smallmap_window->GetLegendHeight(this->smallmap_window->GetNumberColumnsLegend(given_width - bar->smallest_x)));
01600     uint display_height = given_height - bar_height;
01601     display->AssignSizePosition(ST_RESIZE, x, y, given_width, display_height, rtl);
01602     bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl);
01603   }
01604 
01605   virtual NWidgetCore *GetWidgetFromPos(int x, int y)
01606   {
01607     if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
01608     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01609       NWidgetCore *widget = child_wid->GetWidgetFromPos(x, y);
01610       if (widget != NULL) return widget;
01611     }
01612     return NULL;
01613   }
01614 
01615   virtual void Draw(const Window *w)
01616   {
01617     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) child_wid->Draw(w);
01618   }
01619 };
01620 
01622 static const NWidgetPart _nested_smallmap_display[] = {
01623   NWidget(WWT_PANEL, COLOUR_BROWN, SM_WIDGET_MAP_BORDER),
01624     NWidget(WWT_INSET, COLOUR_BROWN, SM_WIDGET_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(),
01625   EndContainer(),
01626 };
01627 
01629 static const NWidgetPart _nested_smallmap_bar[] = {
01630   NWidget(WWT_PANEL, COLOUR_BROWN),
01631     NWidget(NWID_HORIZONTAL),
01632       NWidget(WWT_EMPTY, INVALID_COLOUR, SM_WIDGET_LEGEND), SetResize(1, 1),
01633       NWidget(NWID_VERTICAL),
01634         /* Top button row. */
01635         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01636           NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_IN),
01637               SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), SetFill(1, 1),
01638           NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_CENTERMAP),
01639               SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER), SetFill(1, 1),
01640           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_CONTOUR),
01641               SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP), SetFill(1, 1),
01642           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEHICLES),
01643               SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP), SetFill(1, 1),
01644           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_INDUSTRIES),
01645               SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP), SetFill(1, 1),
01646         EndContainer(),
01647         /* Bottom button row. */
01648         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01649           NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_OUT),
01650               SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), SetFill(1, 1),
01651           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_TOGGLETOWNNAME),
01652               SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF), SetFill(1, 1),
01653           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_ROUTES),
01654               SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON), SetFill(1, 1),
01655           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEGETATION),
01656               SetDataTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP), SetFill(1, 1),
01657           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_OWNERS),
01658               SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP), SetFill(1, 1),
01659         EndContainer(),
01660         NWidget(NWID_SPACER), SetResize(0, 1),
01661       EndContainer(),
01662     EndContainer(),
01663   EndContainer(),
01664 };
01665 
01666 static NWidgetBase *SmallMapDisplay(int *biggest_index)
01667 {
01668   NWidgetContainer *map_display = new NWidgetSmallmapDisplay;
01669 
01670   MakeNWidgets(_nested_smallmap_display, lengthof(_nested_smallmap_display), biggest_index, map_display);
01671   MakeNWidgets(_nested_smallmap_bar, lengthof(_nested_smallmap_bar), biggest_index, map_display);
01672   return map_display;
01673 }
01674 
01675 
01676 static const NWidgetPart _nested_smallmap_widgets[] = {
01677   NWidget(NWID_HORIZONTAL),
01678     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
01679     NWidget(WWT_CAPTION, COLOUR_BROWN, SM_WIDGET_CAPTION), SetDataTip(STR_SMALLMAP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01680     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
01681     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
01682   EndContainer(),
01683   NWidgetFunction(SmallMapDisplay), // Smallmap display and legend bar + image buttons.
01684   /* Bottom button row and resize box. */
01685   NWidget(NWID_HORIZONTAL),
01686     NWidget(WWT_PANEL, COLOUR_BROWN),
01687       NWidget(NWID_HORIZONTAL),
01688         NWidget(NWID_SELECTION, INVALID_COLOUR, SM_WIDGET_SELECT_BUTTONS),
01689           NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01690             NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, SM_WIDGET_ENABLE_ALL), SetDataTip(STR_SMALLMAP_ENABLE_ALL, STR_NULL),
01691             NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, SM_WIDGET_DISABLE_ALL), SetDataTip(STR_SMALLMAP_DISABLE_ALL, STR_NULL),
01692             NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_SHOW_HEIGHT), SetDataTip(STR_SMALLMAP_SHOW_HEIGHT, STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT),
01693           EndContainer(),
01694           NWidget(NWID_SPACER), SetFill(1, 1),
01695         EndContainer(),
01696         NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
01697       EndContainer(),
01698     EndContainer(),
01699     NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
01700   EndContainer(),
01701 };
01702 
01703 static const WindowDesc _smallmap_desc(
01704   WDP_AUTO, 446, 314,
01705   WC_SMALLMAP, WC_NONE,
01706   WDF_UNCLICK_BUTTONS,
01707   _nested_smallmap_widgets, lengthof(_nested_smallmap_widgets)
01708 );
01709 
01710 void ShowSmallMap()
01711 {
01712   AllocateWindowDescFront<SmallMapWindow>(&_smallmap_desc, 0);
01713 }
01714 
01723 bool ScrollMainWindowTo(int x, int y, int z, bool instant)
01724 {
01725   bool res = ScrollWindowTo(x, y, z, FindWindowById(WC_MAIN_WINDOW, 0), instant);
01726 
01727   /* If a user scrolls to a tile (via what way what so ever) and already is on
01728    * that tile (e.g.: pressed twice), move the smallmap to that location,
01729    * so you directly see where you are on the smallmap. */
01730 
01731   if (res) return res;
01732 
01733   SmallMapWindow *w = dynamic_cast<SmallMapWindow*>(FindWindowById(WC_SMALLMAP, 0));
01734   if (w != NULL) w->SmallMapCenterOnCurrentPos();
01735 
01736   return res;
01737 }

Generated on Fri Feb 18 21:53:46 2011 for OpenTTD by  doxygen 1.6.1