smallmap_gui.cpp

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

Generated on Sun Jan 9 16:02:01 2011 for OpenTTD by  doxygen 1.6.1