smallmap_gui.cpp

Go to the documentation of this file.
00001 /* $Id: smallmap_gui.cpp 21830 2011-01-17 19:40:06Z terkhen $ */
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     const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01465     int cursor_x = _cursor.pos.x - this->left - wid->pos_x;
01466     int cursor_y = _cursor.pos.y - this->top  - wid->pos_y;
01467     if (IsInsideMM(cursor_x, 0, wid->current_x) && IsInsideMM(cursor_y, 0, wid->current_y)) {
01468       Point pt = {cursor_x, cursor_y};
01469       this->SetZoomLevel((wheel < 0) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt);
01470     }
01471   }
01472 
01473   virtual void OnTick()
01474   {
01475     /* Update the window every now and then */
01476     if (--this->refresh != 0) return;
01477 
01478     this->refresh = FORCE_REFRESH_PERIOD;
01479     this->SetDirty();
01480   }
01481 
01489   void SetNewScroll(int sx, int sy, int sub)
01490   {
01491     const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01492     Point hv = InverseRemapCoords(wi->current_x * TILE_SIZE / 2, wi->current_y * TILE_SIZE / 2);
01493     hv.x *= this->zoom;
01494     hv.y *= this->zoom;
01495 
01496     if (sx < -hv.x) {
01497       sx = -hv.x;
01498       sub = 0;
01499     }
01500     if (sx > (int)(MapMaxX() * TILE_SIZE) - hv.x) {
01501       sx = MapMaxX() * TILE_SIZE - hv.x;
01502       sub = 0;
01503     }
01504     if (sy < -hv.y) {
01505       sy = -hv.y;
01506       sub = 0;
01507     }
01508     if (sy > (int)(MapMaxY() * TILE_SIZE) - hv.y) {
01509       sy = MapMaxY() * TILE_SIZE - hv.y;
01510       sub = 0;
01511     }
01512 
01513     this->scroll_x = sx;
01514     this->scroll_y = sy;
01515     this->subscroll = sub;
01516   }
01517 
01518   virtual void OnScroll(Point delta)
01519   {
01520     _cursor.fix_at = true;
01521 
01522     /* While tile is at (delta.x, delta.y)? */
01523     int sub;
01524     Point pt = this->PixelToTile(delta.x, delta.y, &sub);
01525     this->SetNewScroll(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, sub);
01526 
01527     this->SetDirty();
01528   }
01529 
01530   void SmallMapCenterOnCurrentPos()
01531   {
01532     const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
01533     Point pt = InverseRemapCoords(vp->virtual_left + vp->virtual_width  / 2, vp->virtual_top  + vp->virtual_height / 2);
01534 
01535     int sub;
01536     const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01537     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);
01538     this->SetNewScroll(sxy.x, sxy.y, sub);
01539     this->SetDirty();
01540   }
01541 };
01542 
01543 SmallMapWindow::SmallMapType SmallMapWindow::map_type = SMT_CONTOUR;
01544 bool SmallMapWindow::show_towns = true;
01545 
01554 class NWidgetSmallmapDisplay : public NWidgetContainer {
01555   const SmallMapWindow *smallmap_window; 
01556 public:
01557   NWidgetSmallmapDisplay() : NWidgetContainer(NWID_VERTICAL)
01558   {
01559     this->smallmap_window = NULL;
01560   }
01561 
01562   virtual void SetupSmallestSize(Window *w, bool init_array)
01563   {
01564     NWidgetBase *display = this->head;
01565     NWidgetBase *bar = display->next;
01566 
01567     display->SetupSmallestSize(w, init_array);
01568     bar->SetupSmallestSize(w, init_array);
01569 
01570     this->smallmap_window = dynamic_cast<SmallMapWindow *>(w);
01571     this->smallest_x = max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth());
01572     this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetLegendHeight(smallmap_window->min_number_of_columns));
01573     this->fill_x = max(display->fill_x, bar->fill_x);
01574     this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : min(display->fill_y, bar->fill_y);
01575     this->resize_x = max(display->resize_x, bar->resize_x);
01576     this->resize_y = min(display->resize_y, bar->resize_y);
01577   }
01578 
01579   virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01580   {
01581     this->pos_x = x;
01582     this->pos_y = y;
01583     this->current_x = given_width;
01584     this->current_y = given_height;
01585 
01586     NWidgetBase *display = this->head;
01587     NWidgetBase *bar = display->next;
01588 
01589     if (sizing == ST_SMALLEST) {
01590       this->smallest_x = given_width;
01591       this->smallest_y = given_height;
01592       /* Make display and bar exactly equal to their minimal size. */
01593       display->AssignSizePosition(ST_SMALLEST, x, y, display->smallest_x, display->smallest_y, rtl);
01594       bar->AssignSizePosition(ST_SMALLEST, x, y + display->smallest_y, bar->smallest_x, bar->smallest_y, rtl);
01595     }
01596 
01597     uint bar_height = max(bar->smallest_y, this->smallmap_window->GetLegendHeight(this->smallmap_window->GetNumberColumnsLegend(given_width - bar->smallest_x)));
01598     uint display_height = given_height - bar_height;
01599     display->AssignSizePosition(ST_RESIZE, x, y, given_width, display_height, rtl);
01600     bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl);
01601   }
01602 
01603   virtual NWidgetCore *GetWidgetFromPos(int x, int y)
01604   {
01605     if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
01606     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01607       NWidgetCore *widget = child_wid->GetWidgetFromPos(x, y);
01608       if (widget != NULL) return widget;
01609     }
01610     return NULL;
01611   }
01612 
01613   virtual void Draw(const Window *w)
01614   {
01615     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) child_wid->Draw(w);
01616   }
01617 };
01618 
01620 static const NWidgetPart _nested_smallmap_display[] = {
01621   NWidget(WWT_PANEL, COLOUR_BROWN, SM_WIDGET_MAP_BORDER),
01622     NWidget(WWT_INSET, COLOUR_BROWN, SM_WIDGET_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(),
01623   EndContainer(),
01624 };
01625 
01627 static const NWidgetPart _nested_smallmap_bar[] = {
01628   NWidget(WWT_PANEL, COLOUR_BROWN),
01629     NWidget(NWID_HORIZONTAL),
01630       NWidget(WWT_EMPTY, INVALID_COLOUR, SM_WIDGET_LEGEND), SetResize(1, 1),
01631       NWidget(NWID_VERTICAL),
01632         /* Top button row. */
01633         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01634           NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_IN),
01635               SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), SetFill(1, 1),
01636           NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_CENTERMAP),
01637               SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER), SetFill(1, 1),
01638           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_CONTOUR),
01639               SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP), SetFill(1, 1),
01640           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEHICLES),
01641               SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP), SetFill(1, 1),
01642           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_INDUSTRIES),
01643               SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP), SetFill(1, 1),
01644         EndContainer(),
01645         /* Bottom button row. */
01646         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01647           NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_OUT),
01648               SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), SetFill(1, 1),
01649           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_TOGGLETOWNNAME),
01650               SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF), SetFill(1, 1),
01651           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_ROUTES),
01652               SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON), SetFill(1, 1),
01653           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEGETATION),
01654               SetDataTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP), SetFill(1, 1),
01655           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_OWNERS),
01656               SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP), SetFill(1, 1),
01657         EndContainer(),
01658         NWidget(NWID_SPACER), SetResize(0, 1),
01659       EndContainer(),
01660     EndContainer(),
01661   EndContainer(),
01662 };
01663 
01664 static NWidgetBase *SmallMapDisplay(int *biggest_index)
01665 {
01666   NWidgetContainer *map_display = new NWidgetSmallmapDisplay;
01667 
01668   MakeNWidgets(_nested_smallmap_display, lengthof(_nested_smallmap_display), biggest_index, map_display);
01669   MakeNWidgets(_nested_smallmap_bar, lengthof(_nested_smallmap_bar), biggest_index, map_display);
01670   return map_display;
01671 }
01672 
01673 
01674 static const NWidgetPart _nested_smallmap_widgets[] = {
01675   NWidget(NWID_HORIZONTAL),
01676     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
01677     NWidget(WWT_CAPTION, COLOUR_BROWN, SM_WIDGET_CAPTION), SetDataTip(STR_SMALLMAP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01678     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
01679     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
01680   EndContainer(),
01681   NWidgetFunction(SmallMapDisplay), // Smallmap display and legend bar + image buttons.
01682   /* Bottom button row and resize box. */
01683   NWidget(NWID_HORIZONTAL),
01684     NWidget(WWT_PANEL, COLOUR_BROWN),
01685       NWidget(NWID_HORIZONTAL),
01686         NWidget(NWID_SELECTION, INVALID_COLOUR, SM_WIDGET_SELECT_BUTTONS),
01687           NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01688             NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, SM_WIDGET_ENABLE_ALL), SetDataTip(STR_SMALLMAP_ENABLE_ALL, STR_NULL),
01689             NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, SM_WIDGET_DISABLE_ALL), SetDataTip(STR_SMALLMAP_DISABLE_ALL, STR_NULL),
01690             NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_SHOW_HEIGHT), SetDataTip(STR_SMALLMAP_SHOW_HEIGHT, STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT),
01691           EndContainer(),
01692           NWidget(NWID_SPACER), SetFill(1, 1),
01693         EndContainer(),
01694         NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
01695       EndContainer(),
01696     EndContainer(),
01697     NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
01698   EndContainer(),
01699 };
01700 
01701 static const WindowDesc _smallmap_desc(
01702   WDP_AUTO, 446, 314,
01703   WC_SMALLMAP, WC_NONE,
01704   WDF_UNCLICK_BUTTONS,
01705   _nested_smallmap_widgets, lengthof(_nested_smallmap_widgets)
01706 );
01707 
01708 void ShowSmallMap()
01709 {
01710   AllocateWindowDescFront<SmallMapWindow>(&_smallmap_desc, 0);
01711 }
01712 
01721 bool ScrollMainWindowTo(int x, int y, int z, bool instant)
01722 {
01723   bool res = ScrollWindowTo(x, y, z, FindWindowById(WC_MAIN_WINDOW, 0), instant);
01724 
01725   /* If a user scrolls to a tile (via what way what so ever) and already is on
01726    * that tile (e.g.: pressed twice), move the smallmap to that location,
01727    * so you directly see where you are on the smallmap. */
01728 
01729   if (res) return res;
01730 
01731   SmallMapWindow *w = dynamic_cast<SmallMapWindow*>(FindWindowById(WC_SMALLMAP, 0));
01732   if (w != NULL) w->SmallMapCenterOnCurrentPos();
01733 
01734   return res;
01735 }

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