smallmap_gui.cpp

Go to the documentation of this file.
00001 /* $Id$ */
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 || o == OWNER_WATER) {
00546     if (t == MP_WATER) return MKCOLOUR(0xCACACACA);
00547     const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00548     return _smallmap_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour;
00549   } else if (o == OWNER_TOWN) {
00550     return MKCOLOUR(0xB4B4B4B4);
00551   }
00552 
00553   return _legend_land_owners[_company_to_list_pos[o]].colour * 0x01010101;
00554 }
00555 
00557 static const byte _vehicle_type_colours[6] = {
00558   184, 191, 152, 15, 215, 184
00559 };
00560 
00561 
00563 class SmallMapWindow : public Window {
00565   enum SmallMapType {
00566     SMT_CONTOUR,
00567     SMT_VEHICLES,
00568     SMT_INDUSTRY,
00569     SMT_ROUTES,
00570     SMT_VEGETATION,
00571     SMT_OWNER,
00572   };
00573 
00575   enum ZoomLevelChange {
00576     ZLC_INITIALIZE, 
00577     ZLC_ZOOM_OUT,   
00578     ZLC_ZOOM_IN,    
00579   };
00580 
00581   static SmallMapType map_type; 
00582   static bool show_towns;       
00583 
00584   static const uint LEGEND_BLOB_WIDTH = 8;              
00585   static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2; 
00586   uint min_number_of_fixed_rows; 
00587   uint column_width;             
00588 
00589   int32 scroll_x;  
00590   int32 scroll_y;  
00591   int32 subscroll; 
00592   int zoom;        
00593 
00594   static const uint8 FORCE_REFRESH_PERIOD = 0x1F; 
00595   uint8 refresh; 
00596 
00603   FORCEINLINE Point RemapTile(int tile_x, int tile_y) const
00604   {
00605     int x_offset = tile_x - this->scroll_x / (int)TILE_SIZE;
00606     int y_offset = tile_y - this->scroll_y / (int)TILE_SIZE;
00607 
00608     if (this->zoom == 1) return RemapCoords(x_offset, y_offset, 0);
00609 
00610     /* For negative offsets, round towards -inf. */
00611     if (x_offset < 0) x_offset -= this->zoom - 1;
00612     if (y_offset < 0) y_offset -= this->zoom - 1;
00613 
00614     return RemapCoords(x_offset / this->zoom, y_offset / this->zoom, 0);
00615   }
00616 
00627   FORCEINLINE Point PixelToTile(int px, int py, int *sub, bool add_sub = true) const
00628   {
00629     if (add_sub) px += this->subscroll;  // Total horizontal offset.
00630 
00631     /* For each two rows down, add a x and a y tile, and
00632      * For each four pixels to the right, move a tile to the right. */
00633     Point pt = {((py >> 1) - (px >> 2)) * this->zoom, ((py >> 1) + (px >> 2)) * this->zoom};
00634     px &= 3;
00635 
00636     if (py & 1) { // Odd number of rows, handle the 2 pixel shift.
00637       if (px < 2) {
00638         pt.x += this->zoom;
00639         px += 2;
00640       } else {
00641         pt.y += this->zoom;
00642         px -= 2;
00643       }
00644     }
00645 
00646     *sub = px;
00647     return pt;
00648   }
00649 
00659   Point ComputeScroll(int tx, int ty, int x, int y, int *sub)
00660   {
00661     assert(x >= 0 && y >= 0);
00662 
00663     int new_sub;
00664     Point tile_xy = PixelToTile(x, y, &new_sub, false);
00665     tx -= tile_xy.x;
00666     ty -= tile_xy.y;
00667 
00668     Point scroll;
00669     if (new_sub == 0) {
00670       *sub = 0;
00671       scroll.x = (tx + this->zoom) * TILE_SIZE;
00672       scroll.y = (ty - this->zoom) * TILE_SIZE;
00673     } else {
00674       *sub = 4 - new_sub;
00675       scroll.x = (tx + 2 * this->zoom) * TILE_SIZE;
00676       scroll.y = (ty - 2 * this->zoom) * TILE_SIZE;
00677     }
00678     return scroll;
00679   }
00680 
00687   void SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt)
00688   {
00689     static const int zoomlevels[] = {1, 2, 4, 6, 8}; // Available zoom levels. Bigger number means more zoom-out (further away).
00690     static const int MIN_ZOOM_INDEX = 0;
00691     static const int MAX_ZOOM_INDEX = lengthof(zoomlevels) - 1;
00692 
00693     int new_index, cur_index, sub;
00694     Point tile;
00695     switch (change) {
00696       case ZLC_INITIALIZE:
00697         cur_index = - 1; // Definitely different from new_index.
00698         new_index = MIN_ZOOM_INDEX;
00699         break;
00700 
00701       case ZLC_ZOOM_IN:
00702       case ZLC_ZOOM_OUT:
00703         for (cur_index = MIN_ZOOM_INDEX; cur_index <= MAX_ZOOM_INDEX; cur_index++) {
00704           if (this->zoom == zoomlevels[cur_index]) break;
00705         }
00706         assert(cur_index <= MAX_ZOOM_INDEX);
00707 
00708         tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub);
00709         new_index = Clamp(cur_index + ((change == ZLC_ZOOM_IN) ? -1 : 1), MIN_ZOOM_INDEX, MAX_ZOOM_INDEX);
00710         break;
00711 
00712       default: NOT_REACHED();
00713     }
00714 
00715     if (new_index != cur_index) {
00716       this->zoom = zoomlevels[new_index];
00717       if (cur_index >= 0) {
00718         Point new_tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub);
00719         this->SetNewScroll(this->scroll_x + (tile.x - new_tile.x) * TILE_SIZE,
00720             this->scroll_y + (tile.y - new_tile.y) * TILE_SIZE, sub);
00721       }
00722       this->SetWidgetDisabledState(SM_WIDGET_ZOOM_IN,  this->zoom == zoomlevels[MIN_ZOOM_INDEX]);
00723       this->SetWidgetDisabledState(SM_WIDGET_ZOOM_OUT, this->zoom == zoomlevels[MAX_ZOOM_INDEX]);
00724       this->SetDirty();
00725     }
00726   }
00727 
00733   inline uint32 GetTileColours(const TileArea &ta) const
00734   {
00735     int importance = 0;
00736     TileIndex tile = INVALID_TILE; // Position of the most important tile.
00737     TileType et = MP_VOID;         // Effective tile type at that position.
00738 
00739     TILE_AREA_LOOP(ti, ta) {
00740       TileType ttype = GetEffectiveTileType(ti);
00741       if (_tiletype_importance[ttype] > importance) {
00742         importance = _tiletype_importance[ttype];
00743         tile = ti;
00744         et = ttype;
00745       }
00746     }
00747 
00748     switch (this->map_type) {
00749       case SMT_CONTOUR:
00750         return GetSmallMapContoursPixels(tile, et);
00751 
00752       case SMT_VEHICLES:
00753         return GetSmallMapVehiclesPixels(tile, et);
00754 
00755       case SMT_INDUSTRY:
00756         return GetSmallMapIndustriesPixels(tile, et);
00757 
00758       case SMT_ROUTES:
00759         return GetSmallMapRoutesPixels(tile, et);
00760 
00761       case SMT_VEGETATION:
00762         return GetSmallMapVegetationPixels(tile, et);
00763 
00764       case SMT_OWNER:
00765         return GetSmallMapOwnerPixels(tile, et);
00766 
00767       default: NOT_REACHED();
00768     }
00769   }
00770 
00785   void DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const
00786   {
00787     void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height);
00788     uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0;
00789 
00790     do {
00791       /* Check if the tile (xc,yc) is within the map range */
00792       if (xc >= MapMaxX() || yc >= MapMaxY()) continue;
00793 
00794       /* Check if the dst pointer points to a pixel inside the screen buffer */
00795       if (dst < _screen.dst_ptr) continue;
00796       if (dst >= dst_ptr_abs_end) continue;
00797 
00798       /* Construct tilearea covered by (xc, yc, xc + this->zoom, yc + this->zoom) such that it is within min_xy limits. */
00799       TileArea ta;
00800       if (min_xy == 1 && (xc == 0 || yc == 0)) {
00801         if (this->zoom == 1) continue; // The tile area is empty, don't draw anything.
00802 
00803         ta = TileArea(TileXY(max(min_xy, xc), max(min_xy, yc)), this->zoom - (xc == 0), this->zoom - (yc == 0));
00804       } else {
00805         ta = TileArea(TileXY(xc, yc), this->zoom, this->zoom);
00806       }
00807       ta.ClampToMap(); // Clamp to map boundaries (may contain MP_VOID tiles!).
00808 
00809       uint32 val = this->GetTileColours(ta);
00810       uint8 *val8 = (uint8 *)&val;
00811       int idx = max(0, -start_pos);
00812       for (int pos = max(0, start_pos); pos < end_pos; pos++) {
00813         blitter->SetPixel(dst, idx, 0, val8[idx]);
00814         idx++;
00815       }
00816     /* Switch to next tile in the column */
00817     } while (xc += this->zoom, yc += this->zoom, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0);
00818   }
00819 
00825   void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const
00826   {
00827     const Vehicle *v;
00828     FOR_ALL_VEHICLES(v) {
00829       if (v->type == VEH_EFFECT) continue;
00830       if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue;
00831 
00832       /* Remap into flat coordinates. */
00833       Point pt = this->RemapTile(v->x_pos / TILE_SIZE, v->y_pos / TILE_SIZE);
00834 
00835       int y = pt.y - dpi->top;
00836       if (!IsInsideMM(y, 0, dpi->height)) continue; // y is out of bounds.
00837 
00838       bool skip = false; // Default is to draw both pixels.
00839       int x = pt.x - this->subscroll - 3 - dpi->left; // Offset X coordinate.
00840       if (x < 0) {
00841         /* if x+1 is 0, that means we're on the very left edge,
00842          * and should thus only draw a single pixel */
00843         if (++x != 0) continue;
00844         skip = true;
00845       } else if (x >= dpi->width - 1) {
00846         /* Check if we're at the very right edge, and if so draw only a single pixel */
00847         if (x != dpi->width - 1) continue;
00848         skip = true;
00849       }
00850 
00851       /* Calculate pointer to pixel and the colour */
00852       byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : 0xF;
00853 
00854       /* And draw either one or two pixels depending on clipping */
00855       blitter->SetPixel(dpi->dst_ptr, x, y, colour);
00856       if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour);
00857     }
00858   }
00859 
00864   void DrawTowns(const DrawPixelInfo *dpi) const
00865   {
00866     const Town *t;
00867     FOR_ALL_TOWNS(t) {
00868       /* Remap the town coordinate */
00869       Point pt = this->RemapTile(TileX(t->xy), TileY(t->xy));
00870       int x = pt.x - this->subscroll - (t->sign.width_small >> 1);
00871       int y = pt.y;
00872 
00873       /* Check if the town sign is within bounds */
00874       if (x + t->sign.width_small > dpi->left &&
00875           x < dpi->left + dpi->width &&
00876           y + FONT_HEIGHT_SMALL > dpi->top &&
00877           y < dpi->top + dpi->height) {
00878         /* And draw it. */
00879         SetDParam(0, t->index);
00880         DrawString(x, x + t->sign.width_small, y, STR_SMALLMAP_TOWN);
00881       }
00882     }
00883   }
00884 
00891   static inline void DrawVertMapIndicator(int x, int y, int y2)
00892   {
00893     GfxFillRect(x, y,      x, y + 3, 69);
00894     GfxFillRect(x, y2 - 3, x, y2,    69);
00895   }
00896 
00903   static inline void DrawHorizMapIndicator(int x, int x2, int y)
00904   {
00905     GfxFillRect(x,      y, x + 3, y, 69);
00906     GfxFillRect(x2 - 3, y, x2,    y, 69);
00907   }
00908 
00912   void DrawMapIndicators() const
00913   {
00914     /* Find main viewport. */
00915     const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
00916 
00917     Point tile = InverseRemapCoords(vp->virtual_left, vp->virtual_top);
00918     Point tl = this->RemapTile(tile.x >> 4, tile.y >> 4);
00919     tl.x -= this->subscroll;
00920 
00921     tile = InverseRemapCoords(vp->virtual_left + vp->virtual_width, vp->virtual_top + vp->virtual_height);
00922     Point br = this->RemapTile(tile.x >> 4, tile.y >> 4);
00923     br.x -= this->subscroll;
00924 
00925     SmallMapWindow::DrawVertMapIndicator(tl.x, tl.y, br.y);
00926     SmallMapWindow::DrawVertMapIndicator(br.x, tl.y, br.y);
00927 
00928     SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, tl.y);
00929     SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, br.y);
00930   }
00931 
00943   void DrawSmallMap(DrawPixelInfo *dpi) const
00944   {
00945     Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
00946     DrawPixelInfo *old_dpi;
00947 
00948     old_dpi = _cur_dpi;
00949     _cur_dpi = dpi;
00950 
00951     /* Clear it */
00952     GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, 0);
00953 
00954     /* Which tile is displayed at (dpi->left, dpi->top)? */
00955     int dx;
00956     Point tile = this->PixelToTile(dpi->left, dpi->top, &dx);
00957     int tile_x = this->scroll_x / (int)TILE_SIZE + tile.x;
00958     int tile_y = this->scroll_y / (int)TILE_SIZE + tile.y;
00959 
00960     void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0);
00961     int x = - dx - 4;
00962     int y = 0;
00963 
00964     for (;;) {
00965       /* Distance from left edge */
00966       if (x >= -3) {
00967         if (x >= dpi->width) break; // Exit the loop.
00968 
00969         int end_pos = min(dpi->width, x + 4);
00970         int reps = (dpi->height - y + 1) / 2; // Number of lines.
00971         if (reps > 0) {
00972           this->DrawSmallMapColumn(ptr, tile_x, tile_y, dpi->pitch * 2, reps, x, end_pos, blitter);
00973         }
00974       }
00975 
00976       if (y == 0) {
00977         tile_y += this->zoom;
00978         y++;
00979         ptr = blitter->MoveTo(ptr, 0, 1);
00980       } else {
00981         tile_x -= this->zoom;
00982         y--;
00983         ptr = blitter->MoveTo(ptr, 0, -1);
00984       }
00985       ptr = blitter->MoveTo(ptr, 2, 0);
00986       x += 2;
00987     }
00988 
00989     /* Draw vehicles */
00990     if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter);
00991 
00992     /* Draw town names */
00993     if (this->show_towns) this->DrawTowns(dpi);
00994 
00995     /* Draw map indicators */
00996     this->DrawMapIndicators();
00997 
00998     _cur_dpi = old_dpi;
00999   }
01000 
01004   void SetupWidgetData()
01005   {
01006     StringID legend_tooltip;
01007     StringID enable_all_tooltip;
01008     StringID disable_all_tooltip;
01009     int plane;
01010     switch (this->map_type) {
01011       case SMT_INDUSTRY:
01012         legend_tooltip = STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION;
01013         enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES;
01014         disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES;
01015         plane = 0;
01016         break;
01017 
01018       case SMT_OWNER:
01019         legend_tooltip = STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION;
01020         enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES;
01021         disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES;
01022         plane = 0;
01023         break;
01024 
01025       default:
01026         legend_tooltip = STR_NULL;
01027         enable_all_tooltip = STR_NULL;
01028         disable_all_tooltip = STR_NULL;
01029         plane = 1;
01030         break;
01031     }
01032 
01033     this->GetWidget<NWidgetCore>(SM_WIDGET_LEGEND)->SetDataTip(STR_NULL, legend_tooltip);
01034     this->GetWidget<NWidgetCore>(SM_WIDGET_ENABLE_ALL)->SetDataTip(STR_SMALLMAP_ENABLE_ALL, enable_all_tooltip);
01035     this->GetWidget<NWidgetCore>(SM_WIDGET_DISABLE_ALL)->SetDataTip(STR_SMALLMAP_DISABLE_ALL, disable_all_tooltip);
01036     this->GetWidget<NWidgetStacked>(SM_WIDGET_SELECT_BUTTONS)->SetDisplayedPlane(plane);
01037   }
01038 
01039 public:
01040   uint min_number_of_columns;    
01041 
01042   SmallMapWindow(const WindowDesc *desc, int window_number) : Window(), refresh(FORCE_REFRESH_PERIOD)
01043   {
01044     this->InitNested(desc, window_number);
01045     this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
01046 
01047     BuildLandLegend();
01048     this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_show_heightmap);
01049 
01050     this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
01051 
01052     this->SetupWidgetData();
01053 
01054     this->SetZoomLevel(ZLC_INITIALIZE, NULL);
01055     this->SmallMapCenterOnCurrentPos();
01056   }
01057 
01062   inline uint GetMinLegendWidth() const
01063   {
01064     return WD_FRAMERECT_LEFT + this->min_number_of_columns * this->column_width;
01065   }
01066 
01071   inline uint GetNumberColumnsLegend(uint width) const
01072   {
01073     return width / this->column_width;
01074   }
01075 
01081   uint GetLegendHeight(uint num_columns) const
01082   {
01083     uint num_rows = max(this->min_number_of_fixed_rows, CeilDiv(max(_smallmap_company_count, _smallmap_industry_count), num_columns));
01084     return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
01085   }
01086 
01087   virtual void SetStringParameters(int widget) const
01088   {
01089     switch (widget) {
01090       case SM_WIDGET_CAPTION:
01091         SetDParam(0, STR_SMALLMAP_TYPE_CONTOURS + this->map_type);
01092         break;
01093     }
01094   }
01095 
01096   virtual void OnInit()
01097   {
01098     uint min_width = 0;
01099     this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS;
01100     this->min_number_of_fixed_rows = 0;
01101     for (uint i = 0; i < lengthof(_legend_table); i++) {
01102       uint height = 0;
01103       uint num_columns = 1;
01104       for (const LegendAndColour *tbl = _legend_table[i]; !tbl->end; ++tbl) {
01105         StringID str;
01106         if (i == SMT_INDUSTRY) {
01107           SetDParam(0, tbl->legend);
01108           SetDParam(1, IndustryPool::MAX_SIZE);
01109           str = STR_SMALLMAP_INDUSTRY;
01110         } else if (i == SMT_OWNER) {
01111           if (tbl->company != INVALID_COMPANY) {
01112             if (!Company::IsValidID(tbl->company)) {
01113               /* Rebuild the owner legend. */
01114               BuildOwnerLegend();
01115               this->OnInit();
01116               return;
01117             }
01118             /* Non-fixed legend entries for the owner view. */
01119             SetDParam(0, tbl->company);
01120             str = STR_SMALLMAP_COMPANY;
01121           } else {
01122             str = tbl->legend;
01123           }
01124         } else {
01125           if (tbl->col_break) {
01126             this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
01127             height = 0;
01128             num_columns++;
01129           }
01130           height++;
01131           str = tbl->legend;
01132         }
01133         min_width = max(GetStringBoundingBox(str).width, min_width);
01134       }
01135       this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
01136       this->min_number_of_columns = max(this->min_number_of_columns, num_columns);
01137     }
01138 
01139     /* The width of a column is the minimum width of all texts + the size of the blob + some spacing */
01140     this->column_width = min_width + LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
01141   }
01142 
01143   virtual void OnPaint()
01144   {
01145     if (this->map_type == SMT_OWNER) {
01146       for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) {
01147         if (tbl->company != INVALID_COMPANY && !Company::IsValidID(tbl->company)) {
01148           /* Rebuild the owner legend. */
01149           BuildOwnerLegend();
01150           this->InvalidateData(1);
01151           break;
01152         }
01153       }
01154     }
01155 
01156     this->DrawWidgets();
01157   }
01158 
01159   virtual void DrawWidget(const Rect &r, int widget) const
01160   {
01161     switch (widget) {
01162       case SM_WIDGET_MAP: {
01163         DrawPixelInfo new_dpi;
01164         if (!FillDrawPixelInfo(&new_dpi, r.left + 1, r.top + 1, r.right - r.left - 1, r.bottom - r.top - 1)) return;
01165         this->DrawSmallMap(&new_dpi);
01166         break;
01167       }
01168 
01169       case SM_WIDGET_LEGEND: {
01170         uint columns = this->GetNumberColumnsLegend(r.right - r.left + 1);
01171         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);
01172         bool rtl = _current_text_dir == TD_RTL;
01173         uint y_org = r.top + WD_FRAMERECT_TOP;
01174         uint x = rtl ? r.right - this->column_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT;
01175         uint y = y_org;
01176         uint i = 0; // Row counter for industry legend.
01177         uint row_height = FONT_HEIGHT_SMALL;
01178 
01179         uint text_left  = rtl ? 0 : LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT;
01180         uint text_right = this->column_width - 1 - (rtl ? LEGEND_BLOB_WIDTH + WD_FRAMERECT_RIGHT : 0);
01181         uint blob_left  = rtl ? this->column_width - 1 - LEGEND_BLOB_WIDTH : 0;
01182         uint blob_right = rtl ? this->column_width - 1 : LEGEND_BLOB_WIDTH;
01183 
01184         for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) {
01185           if (tbl->col_break || ((this->map_type == SMT_INDUSTRY || this->map_type == SMT_OWNER) && i++ >= number_of_rows)) {
01186             /* Column break needed, continue at top, COLUMN_WIDTH pixels
01187              * (one "row") to the right. */
01188             x += rtl ? -(int)this->column_width : this->column_width;
01189             y = y_org;
01190             i = 1;
01191           }
01192 
01193           if (this->map_type == SMT_INDUSTRY) {
01194             /* Industry name must be formatted, since it's not in tiny font in the specs.
01195              * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font */
01196             SetDParam(0, tbl->legend);
01197             SetDParam(1, Industry::GetIndustryTypeCount(tbl->type));
01198             if (!tbl->show_on_map) {
01199               /* Simply draw the string, not the black border of the legend colour.
01200                * This will enforce the idea of the disabled item */
01201               DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_GREY);
01202             } else {
01203               DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_BLACK);
01204               GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0); // Outer border of the legend colour
01205             }
01206           } else if (this->map_type == SMT_OWNER && tbl->company != INVALID_COMPANY) {
01207             SetDParam(0, tbl->company);
01208             if (!tbl->show_on_map) {
01209               /* Simply draw the string, not the black border of the legend colour.
01210                * This will enforce the idea of the disabled item */
01211               DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_COMPANY, TC_GREY);
01212             } else {
01213               DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_COMPANY, TC_BLACK);
01214               GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0); // Outer border of the legend colour
01215             }
01216           } else {
01217             if (this->map_type == SMT_CONTOUR) SetDParam(0, tbl->height * TILE_HEIGHT_STEP);
01218 
01219             /* Anything that is not an industry or a company is using normal process */
01220             GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0);
01221             DrawString(x + text_left, x + text_right, y, tbl->legend);
01222           }
01223           GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + row_height - 2, tbl->colour); // Legend colour
01224 
01225           y += row_height;
01226         }
01227       }
01228     }
01229   }
01230 
01235   void SwitchMapType(SmallMapType map_type)
01236   {
01237     this->RaiseWidget(this->map_type + SM_WIDGET_CONTOUR);
01238     this->map_type = map_type;
01239     this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
01240 
01241     this->SetupWidgetData();
01242 
01243     this->SetDirty();
01244   }
01245 
01246   virtual void OnClick(Point pt, int widget, int click_count)
01247   {
01248     /* User clicked something, notify the industry chain window to stop sending newly selected industries. */
01249     InvalidateWindowClassesData(WC_INDUSTRY_CARGOES, NUM_INDUSTRYTYPES);
01250 
01251     switch (widget) {
01252       case SM_WIDGET_MAP: { // Map window
01253         /*
01254          * XXX: scrolling with the left mouse button is done by subsequently
01255          * clicking with the left mouse button; clicking once centers the
01256          * large map at the selected point. So by unclicking the left mouse
01257          * button here, it gets reclicked during the next inputloop, which
01258          * would make it look like the mouse is being dragged, while it is
01259          * actually being (virtually) clicked every inputloop.
01260          */
01261         _left_button_clicked = false;
01262 
01263         const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01264         Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
01265         int sub;
01266         pt = this->PixelToTile(pt.x - wid->pos_x, pt.y - wid->pos_y, &sub);
01267         pt = RemapCoords(this->scroll_x + pt.x * TILE_SIZE + this->zoom * (TILE_SIZE - sub * TILE_SIZE / 4),
01268             this->scroll_y + pt.y * TILE_SIZE + sub * this->zoom * TILE_SIZE / 4, 0);
01269 
01270         w->viewport->follow_vehicle = INVALID_VEHICLE;
01271         w->viewport->dest_scrollpos_x = pt.x - (w->viewport->virtual_width  >> 1);
01272         w->viewport->dest_scrollpos_y = pt.y - (w->viewport->virtual_height >> 1);
01273 
01274         this->SetDirty();
01275         break;
01276       }
01277 
01278       case SM_WIDGET_ZOOM_IN:
01279       case SM_WIDGET_ZOOM_OUT: {
01280         const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01281         Point pt = {wid->current_x / 2, wid->current_y / 2};
01282         this->SetZoomLevel((widget == SM_WIDGET_ZOOM_IN) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt);
01283         SndPlayFx(SND_15_BEEP);
01284         break;
01285       }
01286 
01287       case SM_WIDGET_CONTOUR:    // Show land contours
01288       case SM_WIDGET_VEHICLES:   // Show vehicles
01289       case SM_WIDGET_INDUSTRIES: // Show industries
01290       case SM_WIDGET_ROUTES:     // Show transport routes
01291       case SM_WIDGET_VEGETATION: // Show vegetation
01292       case SM_WIDGET_OWNERS:     // Show land owners
01293         this->SwitchMapType((SmallMapType)(widget - SM_WIDGET_CONTOUR));
01294         SndPlayFx(SND_15_BEEP);
01295         break;
01296 
01297       case SM_WIDGET_CENTERMAP: // Center the smallmap again
01298         this->SmallMapCenterOnCurrentPos();
01299         this->HandleButtonClick(SM_WIDGET_CENTERMAP);
01300         SndPlayFx(SND_15_BEEP);
01301         break;
01302 
01303       case SM_WIDGET_TOGGLETOWNNAME: // Toggle town names
01304         this->show_towns = !this->show_towns;
01305         this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
01306 
01307         this->SetDirty();
01308         SndPlayFx(SND_15_BEEP);
01309         break;
01310 
01311       case SM_WIDGET_LEGEND: // Legend
01312         /* If industry type small map*/
01313         if (this->map_type == SMT_INDUSTRY) {
01314           /* If click on industries label, find right industry type and enable/disable it */
01315           const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_LEGEND); // Label panel
01316           uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL;
01317           uint columns = this->GetNumberColumnsLegend(wi->current_x);
01318           uint number_of_rows = max(CeilDiv(max(_smallmap_company_count, _smallmap_industry_count), columns), this->min_number_of_fixed_rows);
01319           if (line >= number_of_rows) break;
01320 
01321           bool rtl = _current_text_dir == TD_RTL;
01322           int x = pt.x - wi->pos_x;
01323           if (rtl) x = wi->current_x - x;
01324           uint column = (x - WD_FRAMERECT_LEFT) / this->column_width;
01325 
01326           /* Check if click is on industry label*/
01327           int industry_pos = (column * number_of_rows) + line;
01328           if (industry_pos < _smallmap_industry_count) {
01329             if (_ctrl_pressed) {
01330               /* Disable all, except the clicked one */
01331               bool changes = false;
01332               for (int i = 0; i != _smallmap_industry_count; i++) {
01333                 bool new_state = i == industry_pos;
01334                 if (_legend_from_industries[i].show_on_map != new_state) {
01335                   changes = true;
01336                   _legend_from_industries[i].show_on_map = new_state;
01337                 }
01338               }
01339               if (!changes) {
01340                 /* Nothing changed? Then show all (again). */
01341                 for (int i = 0; i != _smallmap_industry_count; i++) {
01342                   _legend_from_industries[i].show_on_map = true;
01343                 }
01344               }
01345             } else {
01346               _legend_from_industries[industry_pos].show_on_map = !_legend_from_industries[industry_pos].show_on_map;
01347             }
01348           }
01349           this->SetDirty();
01350         } else if (this->map_type == SMT_OWNER) {
01351           /* If click on companies label, find right company and enable/disable it. */
01352           const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_LEGEND);
01353           uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL;
01354           uint columns = this->GetNumberColumnsLegend(wi->current_x);
01355           uint number_of_rows = max(CeilDiv(max(_smallmap_company_count, _smallmap_industry_count), columns), this->min_number_of_fixed_rows);
01356           if (line >= number_of_rows) break;
01357 
01358           bool rtl = _current_text_dir == TD_RTL;
01359           int x = pt.x - wi->pos_x;
01360           if (rtl) x = wi->current_x - x;
01361           uint column = (x - WD_FRAMERECT_LEFT) / this->column_width;
01362 
01363           /* Check if click is on company label. */
01364           int company_pos = (column * number_of_rows) + line;
01365           if (company_pos < NUM_NO_COMPANY_ENTRIES) break;
01366           if (company_pos < _smallmap_company_count) {
01367             if (_ctrl_pressed) {
01368               /* Disable all, except the clicked one */
01369               bool changes = false;
01370               for (int i = NUM_NO_COMPANY_ENTRIES; i != _smallmap_company_count; i++) {
01371                 bool new_state = i == company_pos;
01372                 if (_legend_land_owners[i].show_on_map != new_state) {
01373                   changes = true;
01374                   _legend_land_owners[i].show_on_map = new_state;
01375                 }
01376               }
01377               if (!changes) {
01378                 /* Nothing changed? Then show all (again). */
01379                 for (int i = NUM_NO_COMPANY_ENTRIES; i != _smallmap_company_count; i++) {
01380                   _legend_land_owners[i].show_on_map = true;
01381                 }
01382               }
01383             } else {
01384               _legend_land_owners[company_pos].show_on_map = !_legend_land_owners[company_pos].show_on_map;
01385             }
01386           }
01387           this->SetDirty();
01388         }
01389         break;
01390 
01391       case SM_WIDGET_ENABLE_ALL:
01392         if (this->map_type == SMT_INDUSTRY) {
01393           for (int i = 0; i != _smallmap_industry_count; i++) {
01394             _legend_from_industries[i].show_on_map = true;
01395           }
01396         } else if (this->map_type == SMT_OWNER) {
01397           for (int i = NUM_NO_COMPANY_ENTRIES; i != _smallmap_company_count; i++) {
01398             _legend_land_owners[i].show_on_map = true;
01399           }
01400         }
01401         this->SetDirty();
01402         break;
01403 
01404       case SM_WIDGET_DISABLE_ALL:
01405         if (this->map_type == SMT_INDUSTRY) {
01406           for (int i = 0; i != _smallmap_industry_count; i++) {
01407             _legend_from_industries[i].show_on_map = false;
01408           }
01409         } else {
01410           for (int i = NUM_NO_COMPANY_ENTRIES; i != _smallmap_company_count; i++) {
01411             _legend_land_owners[i].show_on_map = false;
01412           }
01413         }
01414         this->SetDirty();
01415         break;
01416 
01417       case SM_WIDGET_SHOW_HEIGHT: // Enable/disable showing of heightmap.
01418         _smallmap_show_heightmap = !_smallmap_show_heightmap;
01419         this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_show_heightmap);
01420         this->SetDirty();
01421         break;
01422     }
01423   }
01424 
01432   virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
01433   {
01434     if (!gui_scope) return;
01435     switch (data) {
01436       case 1:
01437         /* The owner legend has already been rebuilt. */
01438         this->ReInit();
01439         break;
01440 
01441       case 0: {
01442         extern uint64 _displayed_industries;
01443         if (this->map_type != SMT_INDUSTRY) this->SwitchMapType(SMT_INDUSTRY);
01444 
01445         for (int i = 0; i != _smallmap_industry_count; i++) {
01446           _legend_from_industries[i].show_on_map = HasBit(_displayed_industries, _legend_from_industries[i].type);
01447         }
01448         break;
01449       }
01450 
01451       default: NOT_REACHED();
01452     }
01453     this->SetDirty();
01454   }
01455 
01456   virtual bool OnRightClick(Point pt, int widget)
01457   {
01458     if (widget != SM_WIDGET_MAP || _scrolling_viewport) return false;
01459 
01460     _scrolling_viewport = true;
01461     return true;
01462   }
01463 
01464   virtual void OnMouseWheel(int wheel)
01465   {
01466     if (_settings_client.gui.scrollwheel_scrolling == 0) {
01467       const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01468       int cursor_x = _cursor.pos.x - this->left - wid->pos_x;
01469       int cursor_y = _cursor.pos.y - this->top  - wid->pos_y;
01470       if (IsInsideMM(cursor_x, 0, wid->current_x) && IsInsideMM(cursor_y, 0, wid->current_y)) {
01471         Point pt = {cursor_x, cursor_y};
01472         this->SetZoomLevel((wheel < 0) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt);
01473       }
01474     }
01475   }
01476 
01477   virtual void OnTick()
01478   {
01479     /* Update the window every now and then */
01480     if (--this->refresh != 0) return;
01481 
01482     this->refresh = FORCE_REFRESH_PERIOD;
01483     this->SetDirty();
01484   }
01485 
01493   void SetNewScroll(int sx, int sy, int sub)
01494   {
01495     const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01496     Point hv = InverseRemapCoords(wi->current_x * TILE_SIZE / 2, wi->current_y * TILE_SIZE / 2);
01497     hv.x *= this->zoom;
01498     hv.y *= this->zoom;
01499 
01500     if (sx < -hv.x) {
01501       sx = -hv.x;
01502       sub = 0;
01503     }
01504     if (sx > (int)(MapMaxX() * TILE_SIZE) - hv.x) {
01505       sx = MapMaxX() * TILE_SIZE - hv.x;
01506       sub = 0;
01507     }
01508     if (sy < -hv.y) {
01509       sy = -hv.y;
01510       sub = 0;
01511     }
01512     if (sy > (int)(MapMaxY() * TILE_SIZE) - hv.y) {
01513       sy = MapMaxY() * TILE_SIZE - hv.y;
01514       sub = 0;
01515     }
01516 
01517     this->scroll_x = sx;
01518     this->scroll_y = sy;
01519     this->subscroll = sub;
01520   }
01521 
01522   virtual void OnScroll(Point delta)
01523   {
01524     _cursor.fix_at = true;
01525 
01526     /* While tile is at (delta.x, delta.y)? */
01527     int sub;
01528     Point pt = this->PixelToTile(delta.x, delta.y, &sub);
01529     this->SetNewScroll(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, sub);
01530 
01531     this->SetDirty();
01532   }
01533 
01534   void SmallMapCenterOnCurrentPos()
01535   {
01536     const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
01537     Point pt = InverseRemapCoords(vp->virtual_left + vp->virtual_width  / 2, vp->virtual_top  + vp->virtual_height / 2);
01538 
01539     int sub;
01540     const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01541     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);
01542     this->SetNewScroll(sxy.x, sxy.y, sub);
01543     this->SetDirty();
01544   }
01545 };
01546 
01547 SmallMapWindow::SmallMapType SmallMapWindow::map_type = SMT_CONTOUR;
01548 bool SmallMapWindow::show_towns = true;
01549 
01558 class NWidgetSmallmapDisplay : public NWidgetContainer {
01559   const SmallMapWindow *smallmap_window; 
01560 public:
01561   NWidgetSmallmapDisplay() : NWidgetContainer(NWID_VERTICAL)
01562   {
01563     this->smallmap_window = NULL;
01564   }
01565 
01566   virtual void SetupSmallestSize(Window *w, bool init_array)
01567   {
01568     NWidgetBase *display = this->head;
01569     NWidgetBase *bar = display->next;
01570 
01571     display->SetupSmallestSize(w, init_array);
01572     bar->SetupSmallestSize(w, init_array);
01573 
01574     this->smallmap_window = dynamic_cast<SmallMapWindow *>(w);
01575     this->smallest_x = max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth());
01576     this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetLegendHeight(smallmap_window->min_number_of_columns));
01577     this->fill_x = max(display->fill_x, bar->fill_x);
01578     this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : min(display->fill_y, bar->fill_y);
01579     this->resize_x = max(display->resize_x, bar->resize_x);
01580     this->resize_y = min(display->resize_y, bar->resize_y);
01581   }
01582 
01583   virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01584   {
01585     this->pos_x = x;
01586     this->pos_y = y;
01587     this->current_x = given_width;
01588     this->current_y = given_height;
01589 
01590     NWidgetBase *display = this->head;
01591     NWidgetBase *bar = display->next;
01592 
01593     if (sizing == ST_SMALLEST) {
01594       this->smallest_x = given_width;
01595       this->smallest_y = given_height;
01596       /* Make display and bar exactly equal to their minimal size. */
01597       display->AssignSizePosition(ST_SMALLEST, x, y, display->smallest_x, display->smallest_y, rtl);
01598       bar->AssignSizePosition(ST_SMALLEST, x, y + display->smallest_y, bar->smallest_x, bar->smallest_y, rtl);
01599     }
01600 
01601     uint bar_height = max(bar->smallest_y, this->smallmap_window->GetLegendHeight(this->smallmap_window->GetNumberColumnsLegend(given_width - bar->smallest_x)));
01602     uint display_height = given_height - bar_height;
01603     display->AssignSizePosition(ST_RESIZE, x, y, given_width, display_height, rtl);
01604     bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl);
01605   }
01606 
01607   virtual NWidgetCore *GetWidgetFromPos(int x, int y)
01608   {
01609     if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
01610     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01611       NWidgetCore *widget = child_wid->GetWidgetFromPos(x, y);
01612       if (widget != NULL) return widget;
01613     }
01614     return NULL;
01615   }
01616 
01617   virtual void Draw(const Window *w)
01618   {
01619     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) child_wid->Draw(w);
01620   }
01621 };
01622 
01624 static const NWidgetPart _nested_smallmap_display[] = {
01625   NWidget(WWT_PANEL, COLOUR_BROWN, SM_WIDGET_MAP_BORDER),
01626     NWidget(WWT_INSET, COLOUR_BROWN, SM_WIDGET_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(),
01627   EndContainer(),
01628 };
01629 
01631 static const NWidgetPart _nested_smallmap_bar[] = {
01632   NWidget(WWT_PANEL, COLOUR_BROWN),
01633     NWidget(NWID_HORIZONTAL),
01634       NWidget(WWT_EMPTY, INVALID_COLOUR, SM_WIDGET_LEGEND), SetResize(1, 1),
01635       NWidget(NWID_VERTICAL),
01636         /* Top button row. */
01637         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01638           NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_IN),
01639               SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), SetFill(1, 1),
01640           NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_CENTERMAP),
01641               SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER), SetFill(1, 1),
01642           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_CONTOUR),
01643               SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP), SetFill(1, 1),
01644           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEHICLES),
01645               SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP), SetFill(1, 1),
01646           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_INDUSTRIES),
01647               SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP), SetFill(1, 1),
01648         EndContainer(),
01649         /* Bottom button row. */
01650         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01651           NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_OUT),
01652               SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), SetFill(1, 1),
01653           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_TOGGLETOWNNAME),
01654               SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF), SetFill(1, 1),
01655           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_ROUTES),
01656               SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON), SetFill(1, 1),
01657           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEGETATION),
01658               SetDataTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP), SetFill(1, 1),
01659           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_OWNERS),
01660               SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP), SetFill(1, 1),
01661         EndContainer(),
01662         NWidget(NWID_SPACER), SetResize(0, 1),
01663       EndContainer(),
01664     EndContainer(),
01665   EndContainer(),
01666 };
01667 
01668 static NWidgetBase *SmallMapDisplay(int *biggest_index)
01669 {
01670   NWidgetContainer *map_display = new NWidgetSmallmapDisplay;
01671 
01672   MakeNWidgets(_nested_smallmap_display, lengthof(_nested_smallmap_display), biggest_index, map_display);
01673   MakeNWidgets(_nested_smallmap_bar, lengthof(_nested_smallmap_bar), biggest_index, map_display);
01674   return map_display;
01675 }
01676 
01677 
01678 static const NWidgetPart _nested_smallmap_widgets[] = {
01679   NWidget(NWID_HORIZONTAL),
01680     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
01681     NWidget(WWT_CAPTION, COLOUR_BROWN, SM_WIDGET_CAPTION), SetDataTip(STR_SMALLMAP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01682     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
01683     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
01684   EndContainer(),
01685   NWidgetFunction(SmallMapDisplay), // Smallmap display and legend bar + image buttons.
01686   /* Bottom button row and resize box. */
01687   NWidget(NWID_HORIZONTAL),
01688     NWidget(WWT_PANEL, COLOUR_BROWN),
01689       NWidget(NWID_HORIZONTAL),
01690         NWidget(NWID_SELECTION, INVALID_COLOUR, SM_WIDGET_SELECT_BUTTONS),
01691           NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01692             NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, SM_WIDGET_ENABLE_ALL), SetDataTip(STR_SMALLMAP_ENABLE_ALL, STR_NULL),
01693             NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, SM_WIDGET_DISABLE_ALL), SetDataTip(STR_SMALLMAP_DISABLE_ALL, STR_NULL),
01694             NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_SHOW_HEIGHT), SetDataTip(STR_SMALLMAP_SHOW_HEIGHT, STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT),
01695           EndContainer(),
01696           NWidget(NWID_SPACER), SetFill(1, 1),
01697         EndContainer(),
01698         NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
01699       EndContainer(),
01700     EndContainer(),
01701     NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
01702   EndContainer(),
01703 };
01704 
01705 static const WindowDesc _smallmap_desc(
01706   WDP_AUTO, 446, 314,
01707   WC_SMALLMAP, WC_NONE,
01708   WDF_UNCLICK_BUTTONS,
01709   _nested_smallmap_widgets, lengthof(_nested_smallmap_widgets)
01710 );
01711 
01712 void ShowSmallMap()
01713 {
01714   AllocateWindowDescFront<SmallMapWindow>(&_smallmap_desc, 0);
01715 }
01716 
01725 bool ScrollMainWindowTo(int x, int y, int z, bool instant)
01726 {
01727   bool res = ScrollWindowTo(x, y, z, FindWindowById(WC_MAIN_WINDOW, 0), instant);
01728 
01729   /* If a user scrolls to a tile (via what way what so ever) and already is on
01730    * that tile (e.g.: pressed twice), move the smallmap to that location,
01731    * so you directly see where you are on the smallmap. */
01732 
01733   if (res) return res;
01734 
01735   SmallMapWindow *w = dynamic_cast<SmallMapWindow*>(FindWindowById(WC_SMALLMAP, 0));
01736   if (w != NULL) w->SmallMapCenterOnCurrentPos();
01737 
01738   return res;
01739 }

Generated on Wed Apr 13 00:47:54 2011 for OpenTTD by  doxygen 1.6.1