smallmap_gui.cpp

Go to the documentation of this file.
00001 /* $Id: smallmap_gui.cpp 18966 2010-01-30 18:34:48Z frosch $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "clear_map.h"
00014 #include "industry.h"
00015 #include "station_map.h"
00016 #include "landscape.h"
00017 #include "window_gui.h"
00018 #include "tree_map.h"
00019 #include "viewport_func.h"
00020 #include "town.h"
00021 #include "blitter/factory.hpp"
00022 #include "tunnelbridge_map.h"
00023 #include "strings_func.h"
00024 #include "core/endian_func.hpp"
00025 #include "vehicle_base.h"
00026 #include "sound_func.h"
00027 #include "window_func.h"
00028 #include "company_base.h"
00029 
00030 #include "table/strings.h"
00031 #include "table/sprites.h"
00032 
00034 enum SmallMapWindowWidgets {
00035   SM_WIDGET_CAPTION,           
00036   SM_WIDGET_MAP_BORDER,        
00037   SM_WIDGET_MAP,               
00038   SM_WIDGET_LEGEND,            
00039   SM_WIDGET_CONTOUR,           
00040   SM_WIDGET_VEHICLES,          
00041   SM_WIDGET_INDUSTRIES,        
00042   SM_WIDGET_ROUTES,            
00043   SM_WIDGET_VEGETATION,        
00044   SM_WIDGET_OWNERS,            
00045   SM_WIDGET_CENTERMAP,         
00046   SM_WIDGET_TOGGLETOWNNAME,    
00047   SM_WIDGET_SELECTINDUSTRIES,  
00048   SM_WIDGET_ENABLEINDUSTRIES,  
00049   SM_WIDGET_DISABLEINDUSTRIES, 
00050   SM_WIDGET_SHOW_HEIGHT,       
00051 };
00052 
00053 static int _smallmap_industry_count; 
00054 
00056 #define MK(a, b) {a, b, INVALID_INDUSTRYTYPE, true, false, false}
00057 
00058 #define MKEND() {0, STR_NULL, INVALID_INDUSTRYTYPE, true, true, false}
00059 
00061 #define MS(a, b) {a, b, INVALID_INDUSTRYTYPE, true, false, true}
00062 
00064 struct LegendAndColour {
00065   uint8 colour;      
00066   StringID legend;   
00067   IndustryType type; 
00068   bool show_on_map;  
00069   bool end;          
00070   bool col_break;    
00071 };
00072 
00074 static const LegendAndColour _legend_land_contours[] = {
00075   MK(0x5A, STR_SMALLMAP_LEGENDA_100M),
00076   MK(0x5C, STR_SMALLMAP_LEGENDA_200M),
00077   MK(0x5E, STR_SMALLMAP_LEGENDA_300M),
00078   MK(0x1F, STR_SMALLMAP_LEGENDA_400M),
00079   MK(0x27, STR_SMALLMAP_LEGENDA_500M),
00080 
00081   MS(0xD7, STR_SMALLMAP_LEGENDA_ROADS),
00082   MK(0x0A, STR_SMALLMAP_LEGENDA_RAILROADS),
00083   MK(0x98, STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS),
00084   MK(0xB5, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00085   MK(0x0F, STR_SMALLMAP_LEGENDA_VEHICLES),
00086   MKEND()
00087 };
00088 
00089 static const LegendAndColour _legend_vehicles[] = {
00090   MK(0xB8, STR_SMALLMAP_LEGENDA_TRAINS),
00091   MK(0xBF, STR_SMALLMAP_LEGENDA_ROAD_VEHICLES),
00092   MK(0x98, STR_SMALLMAP_LEGENDA_SHIPS),
00093   MK(0x0F, STR_SMALLMAP_LEGENDA_AIRCRAFT),
00094 
00095   MS(0xD7, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES),
00096   MK(0xB5, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00097   MKEND()
00098 };
00099 
00100 static const LegendAndColour _legend_routes[] = {
00101   MK(0xD7, STR_SMALLMAP_LEGENDA_ROADS),
00102   MK(0x0A, STR_SMALLMAP_LEGENDA_RAILROADS),
00103   MK(0xB5, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00104 
00105   MS(0x56, STR_SMALLMAP_LEGENDA_RAILROAD_STATION),
00106   MK(0xC2, STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY),
00107   MK(0xBF, STR_SMALLMAP_LEGENDA_BUS_STATION),
00108   MK(0xB8, STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT),
00109   MK(0x98, STR_SMALLMAP_LEGENDA_DOCK),
00110   MKEND()
00111 };
00112 
00113 static const LegendAndColour _legend_vegetation[] = {
00114   MK(0x52, STR_SMALLMAP_LEGENDA_ROUGH_LAND),
00115   MK(0x54, STR_SMALLMAP_LEGENDA_GRASS_LAND),
00116   MK(0x37, STR_SMALLMAP_LEGENDA_BARE_LAND),
00117   MK(0x25, STR_SMALLMAP_LEGENDA_FIELDS),
00118   MK(0x57, STR_SMALLMAP_LEGENDA_TREES),
00119   MK(0xD0, STR_SMALLMAP_LEGENDA_FOREST),
00120 
00121   MS(0x0A, STR_SMALLMAP_LEGENDA_ROCKS),
00122   MK(0xC2, STR_SMALLMAP_LEGENDA_DESERT),
00123   MK(0x98, STR_SMALLMAP_LEGENDA_SNOW),
00124   MK(0xD7, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES),
00125   MK(0xB5, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00126   MKEND()
00127 };
00128 
00129 static const LegendAndColour _legend_land_owners[] = {
00130   MK(0xCA, STR_SMALLMAP_LEGENDA_WATER),
00131   MK(0x54, STR_SMALLMAP_LEGENDA_NO_OWNER),
00132   MK(0xB4, STR_SMALLMAP_LEGENDA_TOWNS),
00133   MK(0x20, STR_SMALLMAP_LEGENDA_INDUSTRIES),
00134   MKEND()
00135 };
00136 #undef MK
00137 #undef MS
00138 #undef MKEND
00139 
00142 static LegendAndColour _legend_from_industries[NUM_INDUSTRYTYPES + 1];
00143 /* For connecting industry type to position in industries list(small map legend) */
00144 static uint _industry_to_list_pos[NUM_INDUSTRYTYPES];
00146 static bool _smallmap_industry_show_heightmap;
00147 
00151 void BuildIndustriesLegend()
00152 {
00153   uint j = 0;
00154 
00155   /* Add each name */
00156   for (IndustryType i = 0; i < NUM_INDUSTRYTYPES; i++) {
00157     const IndustrySpec *indsp = GetIndustrySpec(i);
00158     if (indsp->enabled) {
00159       _legend_from_industries[j].legend = indsp->name;
00160       _legend_from_industries[j].colour = indsp->map_colour;
00161       _legend_from_industries[j].type = i;
00162       _legend_from_industries[j].show_on_map = true;
00163       _legend_from_industries[j].col_break = false;
00164       _legend_from_industries[j].end = false;
00165 
00166       /* Store widget number for this industry type */
00167       _industry_to_list_pos[i] = j;
00168       j++;
00169     }
00170   }
00171   /* Terminate the list */
00172   _legend_from_industries[j].end = true;
00173 
00174   /* Store number of enabled industries */
00175   _smallmap_industry_count = j;
00176 }
00177 
00178 static const LegendAndColour * const _legend_table[] = {
00179   _legend_land_contours,
00180   _legend_vehicles,
00181   _legend_from_industries,
00182   _legend_routes,
00183   _legend_vegetation,
00184   _legend_land_owners,
00185 };
00186 
00187 #define MKCOLOUR(x) TO_LE32X(x)
00188 
00192 static const uint32 _map_height_bits[] = {
00193   MKCOLOUR(0x5A5A5A5A),
00194   MKCOLOUR(0x5A5B5A5B),
00195   MKCOLOUR(0x5B5B5B5B),
00196   MKCOLOUR(0x5B5C5B5C),
00197   MKCOLOUR(0x5C5C5C5C),
00198   MKCOLOUR(0x5C5D5C5D),
00199   MKCOLOUR(0x5D5D5D5D),
00200   MKCOLOUR(0x5D5E5D5E),
00201   MKCOLOUR(0x5E5E5E5E),
00202   MKCOLOUR(0x5E5F5E5F),
00203   MKCOLOUR(0x5F5F5F5F),
00204   MKCOLOUR(0x5F1F5F1F),
00205   MKCOLOUR(0x1F1F1F1F),
00206   MKCOLOUR(0x1F271F27),
00207   MKCOLOUR(0x27272727),
00208   MKCOLOUR(0x27272727),
00209 };
00210 assert_compile(lengthof(_map_height_bits) == MAX_TILE_HEIGHT + 1);
00211 
00212 struct AndOr {
00213   uint32 mor;
00214   uint32 mand;
00215 };
00216 
00217 static inline uint32 ApplyMask(uint32 colour, const AndOr *mask)
00218 {
00219   return (colour & mask->mand) | mask->mor;
00220 }
00221 
00222 
00224 static const AndOr _smallmap_contours_andor[] = {
00225   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_CLEAR
00226   {MKCOLOUR(0x000A0A00), MKCOLOUR(0xFF0000FF)}, // MP_RAILWAY
00227   {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)}, // MP_ROAD
00228   {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)}, // MP_HOUSE
00229   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_TREES
00230   {MKCOLOUR(0x98989898), MKCOLOUR(0x00000000)}, // MP_STATION
00231   {MKCOLOUR(0xCACACACA), MKCOLOUR(0x00000000)}, // MP_WATER
00232   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_VOID
00233   {MKCOLOUR(0xB5B5B5B5), MKCOLOUR(0x00000000)}, // MP_INDUSTRY
00234   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_TUNNELBRIDGE
00235   {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)}, // MP_UNMOVABLE
00236   {MKCOLOUR(0x000A0A00), MKCOLOUR(0xFF0000FF)},
00237 };
00238 
00240 static const AndOr _smallmap_vehicles_andor[] = {
00241   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_CLEAR
00242   {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)}, // MP_RAILWAY
00243   {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)}, // MP_ROAD
00244   {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)}, // MP_HOUSE
00245   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_TREES
00246   {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)}, // MP_STATION
00247   {MKCOLOUR(0xCACACACA), MKCOLOUR(0x00000000)}, // MP_WATER
00248   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_VOID
00249   {MKCOLOUR(0xB5B5B5B5), MKCOLOUR(0x00000000)}, // MP_INDUSTRY
00250   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)}, // MP_TUNNELBRIDGE
00251   {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)}, // MP_UNMOVABLE
00252   {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)},
00253 };
00254 
00255 typedef uint32 GetSmallMapPixels(TileIndex tile); 
00256 
00257 
00258 static inline TileType GetEffectiveTileType(TileIndex tile)
00259 {
00260   TileType t = GetTileType(tile);
00261 
00262   if (t == MP_TUNNELBRIDGE) {
00263     TransportType tt = GetTunnelBridgeTransportType(tile);
00264 
00265     switch (tt) {
00266       case TRANSPORT_RAIL: t = MP_RAILWAY; break;
00267       case TRANSPORT_ROAD: t = MP_ROAD;    break;
00268       default:             t = MP_WATER;   break;
00269     }
00270   }
00271   return t;
00272 }
00273 
00279 static inline uint32 GetSmallMapContoursPixels(TileIndex tile)
00280 {
00281   TileType t = GetEffectiveTileType(tile);
00282 
00283   return ApplyMask(_map_height_bits[TileHeight(tile)], &_smallmap_contours_andor[t]);
00284 }
00285 
00292 static inline uint32 GetSmallMapVehiclesPixels(TileIndex tile)
00293 {
00294   TileType t = GetEffectiveTileType(tile);
00295 
00296   return ApplyMask(MKCOLOUR(0x54545454), &_smallmap_vehicles_andor[t]);
00297 }
00298 
00305 static inline uint32 GetSmallMapIndustriesPixels(TileIndex tile)
00306 {
00307   TileType t = GetEffectiveTileType(tile);
00308 
00309   if (t == MP_INDUSTRY) {
00310     /* If industry is allowed to be seen, use its colour on the map */
00311     if (_legend_from_industries[_industry_to_list_pos[Industry::GetByTile(tile)->type]].show_on_map) {
00312       return GetIndustrySpec(Industry::GetByTile(tile)->type)->map_colour * 0x01010101;
00313     } else {
00314       /* Otherwise, return the colour of the clear tiles, which will make it disappear */
00315       t = MP_CLEAR;
00316     }
00317   }
00318 
00319   return ApplyMask(_smallmap_industry_show_heightmap ? _map_height_bits[TileHeight(tile)] : MKCOLOUR(0x54545454), &_smallmap_vehicles_andor[t]);
00320 }
00321 
00328 static inline uint32 GetSmallMapRoutesPixels(TileIndex tile)
00329 {
00330   TileType t = GetEffectiveTileType(tile);
00331 
00332   if (t == MP_STATION) {
00333     switch (GetStationType(tile)) {
00334       case STATION_RAIL:    return MKCOLOUR(0x56565656);
00335       case STATION_AIRPORT: return MKCOLOUR(0xB8B8B8B8);
00336       case STATION_TRUCK:   return MKCOLOUR(0xC2C2C2C2);
00337       case STATION_BUS:     return MKCOLOUR(0xBFBFBFBF);
00338       case STATION_DOCK:    return MKCOLOUR(0x98989898);
00339       default:              return MKCOLOUR(0xFFFFFFFF);
00340     }
00341   }
00342 
00343   /* Ground colour */
00344   return ApplyMask(MKCOLOUR(0x54545454), &_smallmap_contours_andor[t]);
00345 }
00346 
00347 
00348 static const uint32 _vegetation_clear_bits[] = {
00349   MKCOLOUR(0x54545454), 
00350   MKCOLOUR(0x52525252), 
00351   MKCOLOUR(0x0A0A0A0A), 
00352   MKCOLOUR(0x25252525), 
00353   MKCOLOUR(0x98989898), 
00354   MKCOLOUR(0xC2C2C2C2), 
00355   MKCOLOUR(0x54545454), 
00356   MKCOLOUR(0x54545454), 
00357 };
00358 
00365 static inline uint32 GetSmallMapVegetationPixels(TileIndex tile)
00366 {
00367   TileType t = GetEffectiveTileType(tile);
00368 
00369   switch (t) {
00370     case MP_CLEAR:
00371       return (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) < 3) ? MKCOLOUR(0x37373737) : _vegetation_clear_bits[GetClearGround(tile)];
00372 
00373     case MP_INDUSTRY:
00374       return GetIndustrySpec(Industry::GetByTile(tile)->type)->check_proc == CHECK_FOREST ? MKCOLOUR(0xD0D0D0D0) : MKCOLOUR(0xB5B5B5B5);
00375 
00376     case MP_TREES:
00377       if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT || GetTreeGround(tile) == TREE_GROUND_ROUGH_SNOW) {
00378         return (_settings_game.game_creation.landscape == LT_ARCTIC) ? MKCOLOUR(0x98575798) : MKCOLOUR(0xC25757C2);
00379       }
00380       return MKCOLOUR(0x54575754);
00381 
00382     default:
00383       return ApplyMask(MKCOLOUR(0x54545454), &_smallmap_vehicles_andor[t]);
00384   }
00385 }
00386 
00387 
00388 static uint32 _owner_colours[OWNER_END + 1];
00389 
00396 static inline uint32 GetSmallMapOwnerPixels(TileIndex tile)
00397 {
00398   Owner o;
00399 
00400   switch (GetTileType(tile)) {
00401     case MP_INDUSTRY: o = OWNER_END;          break;
00402     case MP_HOUSE:    o = OWNER_TOWN;         break;
00403     default:          o = GetTileOwner(tile); break;
00404     /* FIXME: For MP_ROAD there are multiple owners.
00405      * GetTileOwner returns the rail owner (level crossing) resp. the owner of ROADTYPE_ROAD (normal road),
00406      * even if there are no ROADTYPE_ROAD bits on the tile.
00407      */
00408   }
00409 
00410   return _owner_colours[o];
00411 }
00412 
00413 /* Each tile has 4 x pixels and 1 y pixel */
00414 
00416 static GetSmallMapPixels * const _smallmap_draw_procs[] = {
00417   GetSmallMapContoursPixels,
00418   GetSmallMapVehiclesPixels,
00419   GetSmallMapIndustriesPixels,
00420   GetSmallMapRoutesPixels,
00421   GetSmallMapVegetationPixels,
00422   GetSmallMapOwnerPixels,
00423 };
00424 
00426 static const byte _vehicle_type_colours[6] = {
00427   184, 191, 152, 15, 215, 184
00428 };
00429 
00430 
00432 class SmallMapWindow : public Window {
00434   enum SmallMapType {
00435     SMT_CONTOUR,
00436     SMT_VEHICLES,
00437     SMT_INDUSTRY,
00438     SMT_ROUTES,
00439     SMT_VEGETATION,
00440     SMT_OWNER,
00441   };
00442 
00443   static SmallMapType map_type; 
00444   static bool show_towns;       
00445 
00446   static const uint LEGEND_BLOB_WIDTH = 8;              
00447   static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2; 
00448   uint min_number_of_columns;    
00449   uint min_number_of_fixed_rows; 
00450   uint column_width;             
00451 
00452   int32 scroll_x;  
00453   int32 scroll_y;  
00454   int32 subscroll; 
00455 
00456   static const uint8 FORCE_REFRESH_PERIOD = 0x1F; 
00457   uint8 refresh; 
00458 
00465   FORCEINLINE Point RemapTile(int tile_x, int tile_y) const
00466   {
00467     return RemapCoords(tile_x - this->scroll_x / TILE_SIZE,
00468         tile_y - this->scroll_y / TILE_SIZE, 0);
00469   }
00470 
00480   FORCEINLINE Point PixelToTile(int dx, int dy, int *sub) const
00481   {
00482     dx += this->subscroll;  // Total horizontal offset.
00483 
00484     /* For each two rows down, add a x and a y tile, and
00485      * For each four pixels to the right, move a tile to the right. */
00486     Point pt = {(dy >> 1) - (dx >> 2), (dy >> 1) + (dx >> 2)};
00487     dx &= 3;
00488 
00489     if (dy & 1) { // Odd number of rows, handle the 2 pixel shift.
00490       if (dx < 2) {
00491         pt.x++;
00492         dx += 2;
00493       } else {
00494         pt.y++;
00495         dx -= 2;
00496       }
00497     }
00498 
00499     *sub = dx;
00500     return pt;
00501   }
00502 
00519   void DrawSmallMapStuff(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter, GetSmallMapPixels *proc) const
00520   {
00521     void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height);
00522 
00523     do {
00524       /* Check if the tile (xc,yc) is within the map range */
00525       uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0;
00526       if (IsInsideMM(xc, min_xy, MapMaxX()) && IsInsideMM(yc, min_xy, MapMaxY())) {
00527         /* Check if the dst pointer points to a pixel inside the screen buffer */
00528         if (dst < _screen.dst_ptr) continue;
00529         if (dst >= dst_ptr_abs_end) continue;
00530 
00531         uint32 val = proc(TileXY(xc, yc));
00532         uint8 *val8 = (uint8 *)&val;
00533         int idx = max(0, -start_pos);
00534         for (int pos = max(0, start_pos); pos < end_pos; pos++) {
00535           blitter->SetPixel(dst, idx, 0, val8[idx]);
00536           idx++;
00537         }
00538       }
00539     /* Switch to next tile in the column */
00540     } while (xc++, yc++, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0);
00541   }
00542 
00548   void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const
00549   {
00550     const Vehicle *v;
00551     FOR_ALL_VEHICLES(v) {
00552       if (v->type == VEH_EFFECT) continue;
00553       if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue;
00554 
00555       /* Remap into flat coordinates. */
00556       Point pt = this->RemapTile(v->x_pos / TILE_SIZE, v->y_pos / TILE_SIZE);
00557 
00558       int y = pt.y - dpi->top;
00559       if (!IsInsideMM(y, 0, dpi->height)) continue; // y is out of bounds.
00560 
00561       bool skip = false; // Default is to draw both pixels.
00562       int x = pt.x - this->subscroll - 3 - dpi->left; // Offset X coordinate.
00563       if (x < 0) {
00564         /* if x+1 is 0, that means we're on the very left edge,
00565          * and should thus only draw a single pixel */
00566         if (++x != 0) continue;
00567         skip = true;
00568       } else if (x >= dpi->width - 1) {
00569         /* Check if we're at the very right edge, and if so draw only a single pixel */
00570         if (x != dpi->width - 1) continue;
00571         skip = true;
00572       }
00573 
00574       /* Calculate pointer to pixel and the colour */
00575       byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : 0xF;
00576 
00577       /* And draw either one or two pixels depending on clipping */
00578       blitter->SetPixel(dpi->dst_ptr, x, y, colour);
00579       if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour);
00580     }
00581   }
00582 
00587   void DrawTowns(const DrawPixelInfo *dpi) const
00588   {
00589     const Town *t;
00590     FOR_ALL_TOWNS(t) {
00591       /* Remap the town coordinate */
00592       Point pt = this->RemapTile(TileX(t->xy), TileY(t->xy));
00593       int x = pt.x - this->subscroll - (t->sign.width_small >> 1);
00594       int y = pt.y;
00595 
00596       /* Check if the town sign is within bounds */
00597       if (x + t->sign.width_small > dpi->left &&
00598           x < dpi->left + dpi->width &&
00599           y + FONT_HEIGHT_SMALL > dpi->top &&
00600           y < dpi->top + dpi->height) {
00601         /* And draw it. */
00602         SetDParam(0, t->index);
00603         DrawString(x, x + t->sign.width_small, y, STR_SMALLMAP_TOWN);
00604       }
00605     }
00606   }
00607 
00614   static inline void DrawVertMapIndicator(int x, int y, int y2)
00615   {
00616     GfxFillRect(x, y,      x, y + 3, 69);
00617     GfxFillRect(x, y2 - 3, x, y2,    69);
00618   }
00619 
00626   static inline void DrawHorizMapIndicator(int x, int x2, int y)
00627   {
00628     GfxFillRect(x,      y, x + 3, y, 69);
00629     GfxFillRect(x2 - 3, y, x2,    y, 69);
00630   }
00631 
00635   void DrawMapIndicators() const
00636   {
00637     /* Find main viewport. */
00638     const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
00639 
00640     Point pt = RemapCoords(this->scroll_x, this->scroll_y, 0);
00641 
00642     int x = vp->virtual_left - pt.x;
00643     int y = vp->virtual_top - pt.y;
00644     int x2 = (x + vp->virtual_width) / TILE_SIZE;
00645     int y2 = (y + vp->virtual_height) / TILE_SIZE;
00646     x /= TILE_SIZE;
00647     y /= TILE_SIZE;
00648 
00649     x -= this->subscroll;
00650     x2 -= this->subscroll;
00651 
00652     SmallMapWindow::DrawVertMapIndicator(x, y, y2);
00653     SmallMapWindow::DrawVertMapIndicator(x2, y, y2);
00654 
00655     SmallMapWindow::DrawHorizMapIndicator(x, x2, y);
00656     SmallMapWindow::DrawHorizMapIndicator(x, x2, y2);
00657   }
00658 
00670   void DrawSmallMap(DrawPixelInfo *dpi) const
00671   {
00672     Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
00673     DrawPixelInfo *old_dpi;
00674 
00675     old_dpi = _cur_dpi;
00676     _cur_dpi = dpi;
00677 
00678     /* Clear it */
00679     GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, 0);
00680 
00681     /* Setup owner table */
00682     if (this->map_type == SMT_OWNER) {
00683       const Company *c;
00684 
00685       /* Fill with some special colours */
00686       _owner_colours[OWNER_TOWN]  = MKCOLOUR(0xB4B4B4B4);
00687       _owner_colours[OWNER_NONE]  = MKCOLOUR(0x54545454);
00688       _owner_colours[OWNER_WATER] = MKCOLOUR(0xCACACACA);
00689       _owner_colours[OWNER_END]   = MKCOLOUR(0x20202020); // Industry
00690 
00691       /* Now fill with the company colours */
00692       FOR_ALL_COMPANIES(c) {
00693         _owner_colours[c->index] = _colour_gradient[c->colour][5] * 0x01010101;
00694       }
00695     }
00696 
00697     /* Which tile is displayed at (dpi->left, dpi->top)? */
00698     int dx;
00699     Point tile = this->PixelToTile(dpi->left, dpi->top, &dx);
00700     int tile_x = this->scroll_x / TILE_SIZE + tile.x;
00701     int tile_y = this->scroll_y / TILE_SIZE + tile.y;
00702 
00703     void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0);
00704     int x = - dx - 4;
00705     int y = 0;
00706 
00707     for (;;) {
00708       /* Distance from left edge */
00709       if (x >= -3) {
00710         if (x >= dpi->width) break; // Exit the loop.
00711 
00712         int end_pos = min(dpi->width, x + 4);
00713         int reps = (dpi->height - y + 1) / 2; // Number of lines.
00714         if (reps > 0) {
00715           this->DrawSmallMapStuff(ptr, tile_x, tile_y, dpi->pitch * 2, reps, x, end_pos, blitter, _smallmap_draw_procs[this->map_type]);
00716         }
00717       }
00718 
00719       if (y == 0) {
00720         tile_y++;
00721         y++;
00722         ptr = blitter->MoveTo(ptr, 0, 1);
00723       } else {
00724         tile_x--;
00725         y--;
00726         ptr = blitter->MoveTo(ptr, 0, -1);
00727       }
00728       ptr = blitter->MoveTo(ptr, 2, 0);
00729       x += 2;
00730     }
00731 
00732     /* Draw vehicles */
00733     if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter);
00734 
00735     /* Draw town names */
00736     if (this->show_towns) this->DrawTowns(dpi);
00737 
00738     /* Draw map indicators */
00739     this->DrawMapIndicators();
00740 
00741     _cur_dpi = old_dpi;
00742   }
00743 
00744 public:
00745   SmallMapWindow(const WindowDesc *desc, int window_number) : Window(), refresh(FORCE_REFRESH_PERIOD)
00746   {
00747     this->InitNested(desc, window_number);
00748     this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
00749 
00750     _smallmap_industry_show_heightmap = false;
00751     this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_industry_show_heightmap);
00752 
00753     this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
00754     this->GetWidget<NWidgetStacked>(SM_WIDGET_SELECTINDUSTRIES)->SetDisplayedPlane(this->map_type != SMT_INDUSTRY);
00755 
00756     this->SmallMapCenterOnCurrentPos();
00757   }
00758 
00762   inline uint GetMaxLegendHeight() const
00763   {
00764     uint num_rows = max(this->min_number_of_fixed_rows, (_smallmap_industry_count + this->min_number_of_columns - 1) / this->min_number_of_columns);
00765     return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
00766   }
00767 
00771   inline uint GetMinLegendWidth() const
00772   {
00773     return WD_FRAMERECT_LEFT + this->min_number_of_columns * this->column_width;
00774   }
00775 
00779   inline uint GetNumberColumnsLegend(uint width) const
00780   {
00781     return width / this->column_width;
00782   }
00783 
00787   uint GetLegendHeight(uint width) const
00788   {
00789     uint num_columns = this->GetNumberColumnsLegend(width);
00790     uint num_rows = max(this->min_number_of_fixed_rows, (_smallmap_industry_count + num_columns - 1) / num_columns);
00791     return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
00792   }
00793 
00794   virtual void SetStringParameters(int widget) const
00795   {
00796     switch (widget) {
00797       case SM_WIDGET_CAPTION:
00798         SetDParam(0, STR_SMALLMAP_TYPE_CONTOURS + this->map_type);
00799         break;
00800     }
00801   }
00802 
00803   virtual void OnInit()
00804   {
00805     uint min_width = 0;
00806     this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS;
00807     this->min_number_of_fixed_rows = 0;
00808     for (uint i = 0; i < lengthof(_legend_table); i++) {
00809       uint height = 0;
00810       uint num_columns = 1;
00811       for (const LegendAndColour *tbl = _legend_table[i]; !tbl->end; ++tbl) {
00812         StringID str;
00813         if (i == SMT_INDUSTRY) {
00814           SetDParam(0, tbl->legend);
00815           SetDParam(1, IndustryPool::MAX_SIZE);
00816           str = STR_SMALLMAP_INDUSTRY;
00817         } else {
00818           if (tbl->col_break) {
00819             this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
00820             height = 0;
00821             num_columns++;
00822           }
00823           height++;
00824           str = tbl->legend;
00825         }
00826         min_width = max(GetStringBoundingBox(str).width, min_width);
00827       }
00828       this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
00829       this->min_number_of_columns = max(this->min_number_of_columns, num_columns);
00830     }
00831 
00832     /* The width of a column is the minimum width of all texts + the size of the blob + some spacing */
00833     this->column_width = min_width + LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
00834   }
00835 
00836   virtual void DrawWidget(const Rect &r, int widget) const
00837   {
00838     switch (widget) {
00839       case SM_WIDGET_MAP: {
00840         DrawPixelInfo new_dpi;
00841         if (!FillDrawPixelInfo(&new_dpi, r.left + 1, r.top + 1, r.right - r.left - 1, r.bottom - r.top - 1)) return;
00842         this->DrawSmallMap(&new_dpi);
00843       } break;
00844 
00845       case SM_WIDGET_LEGEND: {
00846         uint columns = this->GetNumberColumnsLegend(r.right - r.left + 1);
00847         uint number_of_rows = max(this->map_type == SMT_INDUSTRY ? (_smallmap_industry_count + columns - 1) / columns : 0, this->min_number_of_fixed_rows);
00848         bool rtl = _dynlang.text_dir == TD_RTL;
00849         uint y_org = r.top + WD_FRAMERECT_TOP;
00850         uint x = rtl ? r.right - this->column_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT;
00851         uint y = y_org;
00852         uint i = 0; // Row counter for industry legend.
00853         uint row_height = FONT_HEIGHT_SMALL;
00854 
00855         uint text_left  = rtl ? 0 : LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT;
00856         uint text_right = this->column_width - 1 - (rtl ? LEGEND_BLOB_WIDTH + WD_FRAMERECT_RIGHT : 0);
00857         uint blob_left  = rtl ? this->column_width - 1 - LEGEND_BLOB_WIDTH : 0;
00858         uint blob_right = rtl ? this->column_width - 1 : LEGEND_BLOB_WIDTH;
00859 
00860         for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) {
00861           if (tbl->col_break || (this->map_type == SMT_INDUSTRY && i++ >= number_of_rows)) {
00862             /* Column break needed, continue at top, COLUMN_WIDTH pixels
00863              * (one "row") to the right. */
00864             x += rtl ? -(int)this->column_width : this->column_width;
00865             y = y_org;
00866             i = 1;
00867           }
00868 
00869           if (this->map_type == SMT_INDUSTRY) {
00870             /* Industry name must be formatted, since it's not in tiny font in the specs.
00871              * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font */
00872             SetDParam(0, tbl->legend);
00873             assert(tbl->type < NUM_INDUSTRYTYPES);
00874             SetDParam(1, _industry_counts[tbl->type]);
00875             if (!tbl->show_on_map) {
00876               /* Simply draw the string, not the black border of the legend colour.
00877                * This will enforce the idea of the disabled item */
00878               DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_GREY);
00879             } else {
00880               DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_BLACK);
00881               GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0); // Outer border of the legend colour
00882             }
00883           } else {
00884             /* Anything that is not an industry is using normal process */
00885             GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0);
00886             DrawString(x + text_left, x + text_right, y, tbl->legend);
00887           }
00888           GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + row_height - 2, tbl->colour); // Legend colour
00889 
00890           y += row_height;
00891         }
00892       }
00893     }
00894   }
00895 
00896   virtual void OnPaint()
00897   {
00898     this->DrawWidgets();
00899   }
00900 
00901   virtual void OnClick(Point pt, int widget, int click_count)
00902   {
00903     switch (widget) {
00904       case SM_WIDGET_MAP: { // Map window
00905         /*
00906          * XXX: scrolling with the left mouse button is done by subsequently
00907          * clicking with the left mouse button; clicking once centers the
00908          * large map at the selected point. So by unclicking the left mouse
00909          * button here, it gets reclicked during the next inputloop, which
00910          * would make it look like the mouse is being dragged, while it is
00911          * actually being (virtually) clicked every inputloop.
00912          */
00913         _left_button_clicked = false;
00914 
00915         const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
00916         Point pt = RemapCoords(this->scroll_x, this->scroll_y, 0);
00917         Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
00918         w->viewport->follow_vehicle = INVALID_VEHICLE;
00919         w->viewport->dest_scrollpos_x = pt.x + ((_cursor.pos.x - this->left + wid->pos_x) << 4) - (w->viewport->virtual_width  >> 1);
00920         w->viewport->dest_scrollpos_y = pt.y + ((_cursor.pos.y - this->top  - wid->pos_y) << 4) - (w->viewport->virtual_height >> 1);
00921 
00922         this->SetDirty();
00923       } break;
00924 
00925       case SM_WIDGET_CONTOUR:    // Show land contours
00926       case SM_WIDGET_VEHICLES:   // Show vehicles
00927       case SM_WIDGET_INDUSTRIES: // Show industries
00928       case SM_WIDGET_ROUTES:     // Show transport routes
00929       case SM_WIDGET_VEGETATION: // Show vegetation
00930       case SM_WIDGET_OWNERS:     // Show land owners
00931         this->RaiseWidget(this->map_type + SM_WIDGET_CONTOUR);
00932         this->map_type = (SmallMapType)(widget - SM_WIDGET_CONTOUR);
00933         this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
00934 
00935         /* Hide Enable all/Disable all buttons if is not industry type small map */
00936         this->GetWidget<NWidgetStacked>(SM_WIDGET_SELECTINDUSTRIES)->SetDisplayedPlane(this->map_type != SMT_INDUSTRY);
00937 
00938         this->SetDirty();
00939         SndPlayFx(SND_15_BEEP);
00940         break;
00941 
00942       case SM_WIDGET_CENTERMAP: // Center the smallmap again
00943         this->SmallMapCenterOnCurrentPos();
00944         this->HandleButtonClick(SM_WIDGET_CENTERMAP);
00945         SndPlayFx(SND_15_BEEP);
00946         break;
00947 
00948       case SM_WIDGET_TOGGLETOWNNAME: // Toggle town names
00949         this->show_towns = !this->show_towns;
00950         this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
00951 
00952         this->SetDirty();
00953         SndPlayFx(SND_15_BEEP);
00954         break;
00955 
00956       case SM_WIDGET_LEGEND: // Legend
00957         /* If industry type small map*/
00958         if (this->map_type == SMT_INDUSTRY) {
00959           /* If click on industries label, find right industry type and enable/disable it */
00960           const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_LEGEND); // Label panel
00961           uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL;
00962           uint columns = this->GetNumberColumnsLegend(wi->current_x);
00963           uint number_of_rows = max((_smallmap_industry_count + columns - 1) / columns, this->min_number_of_fixed_rows);
00964           if (line >= number_of_rows) break;
00965 
00966           bool rtl = _dynlang.text_dir == TD_RTL;
00967           int x = pt.x - wi->pos_x;
00968           if (rtl) x = wi->current_x - x;
00969           uint column = (x - WD_FRAMERECT_LEFT) / this->column_width;
00970 
00971           /* Check if click is on industry label*/
00972           int industry_pos = (column * number_of_rows) + line;
00973           if (industry_pos < _smallmap_industry_count) {
00974             _legend_from_industries[industry_pos].show_on_map = !_legend_from_industries[industry_pos].show_on_map;
00975           }
00976 
00977           /* Raise the two buttons "all", as we have done a specific choice */
00978           this->RaiseWidget(SM_WIDGET_ENABLEINDUSTRIES);
00979           this->RaiseWidget(SM_WIDGET_DISABLEINDUSTRIES);
00980           this->SetDirty();
00981         }
00982         break;
00983 
00984       case SM_WIDGET_ENABLEINDUSTRIES: // Enable all industries
00985         for (int i = 0; i != _smallmap_industry_count; i++) {
00986           _legend_from_industries[i].show_on_map = true;
00987         }
00988         /* Toggle appeareance indicating the choice */
00989         this->LowerWidget(SM_WIDGET_ENABLEINDUSTRIES);
00990         this->RaiseWidget(SM_WIDGET_DISABLEINDUSTRIES);
00991         this->SetDirty();
00992         break;
00993 
00994       case SM_WIDGET_DISABLEINDUSTRIES: // Disable all industries
00995         for (int i = 0; i != _smallmap_industry_count; i++) {
00996           _legend_from_industries[i].show_on_map = false;
00997         }
00998         /* Toggle appeareance indicating the choice */
00999         this->RaiseWidget(SM_WIDGET_ENABLEINDUSTRIES);
01000         this->LowerWidget(SM_WIDGET_DISABLEINDUSTRIES);
01001         this->SetDirty();
01002         break;
01003 
01004       case SM_WIDGET_SHOW_HEIGHT: // Enable/disable showing of heightmap.
01005         _smallmap_industry_show_heightmap = !_smallmap_industry_show_heightmap;
01006         this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_industry_show_heightmap);
01007         this->SetDirty();
01008         break;
01009     }
01010   }
01011 
01012   virtual void OnRightClick(Point pt, int widget)
01013   {
01014     if (widget == SM_WIDGET_MAP) {
01015       if (_scrolling_viewport) return;
01016       _scrolling_viewport = true;
01017     }
01018   }
01019 
01020   virtual void OnTick()
01021   {
01022     /* Update the window every now and then */
01023     if (--this->refresh != 0) return;
01024 
01025     this->refresh = FORCE_REFRESH_PERIOD;
01026     this->SetDirty();
01027   }
01028 
01029   virtual void OnScroll(Point delta)
01030   {
01031     _cursor.fix_at = true;
01032 
01033     /* While tile is at (delta.x, delta.y)? */
01034     int sub;
01035     Point pt = this->PixelToTile(delta.x, delta.y, &sub);
01036     int x = this->scroll_x + pt.x * TILE_SIZE;
01037     int y = this->scroll_y + pt.y * TILE_SIZE;
01038 
01039     const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01040     int hx = wi->current_x / 2;
01041     int hy = wi->current_y / 2;
01042     int hvx = hx * -4 + hy * 8;
01043     int hvy = hx *  4 + hy * 8;
01044     if (x < -hvx) {
01045       x = -hvx;
01046       sub = 0;
01047     }
01048     if (x > (int)MapMaxX() * TILE_SIZE - hvx) {
01049       x = MapMaxX() * TILE_SIZE - hvx;
01050       sub = 0;
01051     }
01052     if (y < -hvy) {
01053       y = -hvy;
01054       sub = 0;
01055     }
01056     if (y > (int)MapMaxY() * TILE_SIZE - hvy) {
01057       y = MapMaxY() * TILE_SIZE - hvy;
01058       sub = 0;
01059     }
01060 
01061     this->scroll_x = x;
01062     this->scroll_y = y;
01063     this->subscroll = sub;
01064 
01065     this->SetDirty();
01066   }
01067 
01068   void SmallMapCenterOnCurrentPos()
01069   {
01070     const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
01071     const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01072 
01073     int x = ((vp->virtual_width  - (int)wi->current_x * TILE_SIZE) / 2 + vp->virtual_left) / 4;
01074     int y = ((vp->virtual_height - (int)wi->current_y * TILE_SIZE) / 2 + vp->virtual_top ) / 2 - TILE_SIZE * 2;
01075     this->scroll_x = (y - x) & ~0xF;
01076     this->scroll_y = (x + y) & ~0xF;
01077     this->SetDirty();
01078   }
01079 };
01080 
01081 SmallMapWindow::SmallMapType SmallMapWindow::map_type = SMT_CONTOUR;
01082 bool SmallMapWindow::show_towns = true;
01083 
01092 class NWidgetSmallmapDisplay : public NWidgetContainer {
01093   const SmallMapWindow *smallmap_window; 
01094 public:
01095   NWidgetSmallmapDisplay() : NWidgetContainer(NWID_VERTICAL)
01096   {
01097     this->smallmap_window = NULL;
01098   }
01099 
01100   virtual void SetupSmallestSize(Window *w, bool init_array)
01101   {
01102     NWidgetBase *display = this->head;
01103     NWidgetBase *bar = display->next;
01104 
01105     display->SetupSmallestSize(w, init_array);
01106     bar->SetupSmallestSize(w, init_array);
01107 
01108     this->smallmap_window = dynamic_cast<SmallMapWindow *>(w);
01109     this->smallest_x = max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth());
01110     this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetMaxLegendHeight());
01111     this->fill_x = max(display->fill_x, bar->fill_x);
01112     this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : min(display->fill_y, bar->fill_y);
01113     this->resize_x = max(display->resize_x, bar->resize_x);
01114     this->resize_y = min(display->resize_y, bar->resize_y);
01115   }
01116 
01117   virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01118   {
01119     this->pos_x = x;
01120     this->pos_y = y;
01121     this->current_x = given_width;
01122     this->current_y = given_height;
01123 
01124     NWidgetBase *display = this->head;
01125     NWidgetBase *bar = display->next;
01126 
01127     if (sizing == ST_SMALLEST) {
01128       this->smallest_x = given_width;
01129       this->smallest_y = given_height;
01130       /* Make display and bar exactly equal to their minimal size. */
01131       display->AssignSizePosition(ST_SMALLEST, x, y, display->smallest_x, display->smallest_y, rtl);
01132       bar->AssignSizePosition(ST_SMALLEST, x, y + display->smallest_y, bar->smallest_x, bar->smallest_y, rtl);
01133     }
01134 
01135     uint bar_height = max(bar->smallest_y, this->smallmap_window->GetLegendHeight(given_width - bar->smallest_x));
01136     uint display_height = given_height - bar_height;
01137     display->AssignSizePosition(ST_RESIZE, x, y, given_width, display_height, rtl);
01138     bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl);
01139   }
01140 
01141   virtual NWidgetCore *GetWidgetFromPos(int x, int y)
01142   {
01143     if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
01144     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01145       NWidgetCore *widget = child_wid->GetWidgetFromPos(x, y);
01146       if (widget != NULL) return widget;
01147     }
01148     return NULL;
01149   }
01150 
01151   virtual void Draw(const Window *w)
01152   {
01153     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) child_wid->Draw(w);
01154   }
01155 };
01156 
01158 static const NWidgetPart _nested_smallmap_display[] = {
01159   NWidget(WWT_PANEL, COLOUR_BROWN, SM_WIDGET_MAP_BORDER),
01160     NWidget(WWT_INSET, COLOUR_BROWN, SM_WIDGET_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(),
01161   EndContainer(),
01162 };
01163 
01165 static const NWidgetPart _nested_smallmap_bar[] = {
01166   NWidget(WWT_PANEL, COLOUR_BROWN),
01167     NWidget(NWID_HORIZONTAL),
01168       NWidget(WWT_EMPTY, INVALID_COLOUR, SM_WIDGET_LEGEND), SetResize(1, 1),
01169       NWidget(NWID_VERTICAL),
01170         /* Top button row. */
01171         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01172           NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_CENTERMAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER),
01173           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_CONTOUR), SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP),
01174           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEHICLES), SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP),
01175           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_INDUSTRIES), SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP),
01176         EndContainer(),
01177         /* Bottom button row. */
01178         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01179           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_TOGGLETOWNNAME), SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF),
01180           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_ROUTES), SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON),
01181           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEGETATION), SetDataTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP),
01182           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_OWNERS), SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP),
01183         EndContainer(),
01184         NWidget(NWID_SPACER), SetResize(0, 1),
01185       EndContainer(),
01186     EndContainer(),
01187   EndContainer(),
01188 };
01189 
01190 static NWidgetBase *SmallMapDisplay(int *biggest_index)
01191 {
01192   NWidgetContainer *map_display = new NWidgetSmallmapDisplay;
01193 
01194   MakeNWidgets(_nested_smallmap_display, lengthof(_nested_smallmap_display), biggest_index, map_display);
01195   MakeNWidgets(_nested_smallmap_bar, lengthof(_nested_smallmap_bar), biggest_index, map_display);
01196   return map_display;
01197 }
01198 
01199 
01200 static const NWidgetPart _nested_smallmap_widgets[] = {
01201   NWidget(NWID_HORIZONTAL),
01202     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
01203     NWidget(WWT_CAPTION, COLOUR_BROWN, SM_WIDGET_CAPTION), SetDataTip(STR_SMALLMAP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01204     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
01205     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
01206   EndContainer(),
01207   NWidgetFunction(SmallMapDisplay), // Smallmap display and legend bar + image buttons.
01208   /* Bottom button row and resize box. */
01209   NWidget(NWID_HORIZONTAL),
01210     NWidget(WWT_PANEL, COLOUR_BROWN),
01211       NWidget(NWID_HORIZONTAL),
01212         NWidget(NWID_SELECTION, INVALID_COLOUR, SM_WIDGET_SELECTINDUSTRIES),
01213           NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01214             NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_ENABLEINDUSTRIES), SetDataTip(STR_SMALLMAP_ENABLE_ALL, STR_SMALLMAP_TOOLTIP_ENABLE_ALL),
01215             NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_DISABLEINDUSTRIES), SetDataTip(STR_SMALLMAP_DISABLE_ALL, STR_SMALLMAP_TOOLTIP_DISABLE_ALL),
01216             NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_SHOW_HEIGHT), SetDataTip(STR_SMALLMAP_SHOW_HEIGHT, STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT),
01217           EndContainer(),
01218           NWidget(NWID_SPACER), SetFill(1, 1),
01219         EndContainer(),
01220         NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
01221       EndContainer(),
01222     EndContainer(),
01223     NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
01224   EndContainer(),
01225 };
01226 
01227 static const WindowDesc _smallmap_desc(
01228   WDP_AUTO, 446, 314,
01229   WC_SMALLMAP, WC_NONE,
01230   WDF_UNCLICK_BUTTONS,
01231   _nested_smallmap_widgets, lengthof(_nested_smallmap_widgets)
01232 );
01233 
01234 void ShowSmallMap()
01235 {
01236   AllocateWindowDescFront<SmallMapWindow>(&_smallmap_desc, 0);
01237 }
01238 
01247 bool ScrollMainWindowTo(int x, int y, int z, bool instant)
01248 {
01249   bool res = ScrollWindowTo(x, y, z, FindWindowById(WC_MAIN_WINDOW, 0), instant);
01250 
01251   /* If a user scrolls to a tile (via what way what so ever) and already is on
01252    * that tile (e.g.: pressed twice), move the smallmap to that location,
01253    * so you directly see where you are on the smallmap. */
01254 
01255   if (res) return res;
01256 
01257   SmallMapWindow *w = dynamic_cast<SmallMapWindow*>(FindWindowById(WC_SMALLMAP, 0));
01258   if (w != NULL) w->SmallMapCenterOnCurrentPos();
01259 
01260   return res;
01261 }

Generated on Thu Feb 4 17:20:28 2010 for OpenTTD by  doxygen 1.5.6