smallmap_gui.cpp

Go to the documentation of this file.
00001 /* $Id: smallmap_gui.cpp 18827 2010-01-16 15:24:00Z alberth $ */
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 
00414 static const uint32 _smallmap_mask_left[3] = {
00415   MKCOLOUR(0xFF000000),
00416   MKCOLOUR(0xFFFF0000),
00417   MKCOLOUR(0xFFFFFF00),
00418 };
00419 
00420 static const uint32 _smallmap_mask_right[] = {
00421   MKCOLOUR(0x000000FF),
00422   MKCOLOUR(0x0000FFFF),
00423   MKCOLOUR(0x00FFFFFF),
00424 };
00425 
00426 /* Each tile has 4 x pixels and 1 y pixel */
00427 
00429 static GetSmallMapPixels * const _smallmap_draw_procs[] = {
00430   GetSmallMapContoursPixels,
00431   GetSmallMapVehiclesPixels,
00432   GetSmallMapIndustriesPixels,
00433   GetSmallMapRoutesPixels,
00434   GetSmallMapVegetationPixels,
00435   GetSmallMapOwnerPixels,
00436 };
00437 
00439 static const byte _vehicle_type_colours[6] = {
00440   184, 191, 152, 15, 215, 184
00441 };
00442 
00443 
00445 class SmallMapWindow : public Window {
00447   enum SmallMapType {
00448     SMT_CONTOUR,
00449     SMT_VEHICLES,
00450     SMT_INDUSTRY,
00451     SMT_ROUTES,
00452     SMT_VEGETATION,
00453     SMT_OWNER,
00454   };
00455 
00456   static SmallMapType map_type; 
00457   static bool show_towns;       
00458 
00459   static const uint LEGEND_BLOB_WIDTH = 8;              
00460   static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2; 
00461   uint min_number_of_columns;    
00462   uint min_number_of_fixed_rows; 
00463   uint column_width;             
00464 
00465   int32 scroll_x;
00466   int32 scroll_y;
00467   int32 subscroll;
00468 
00469   static const uint8 FORCE_REFRESH_PERIOD = 0x1F; 
00470   uint8 refresh; 
00471 
00478   inline int RemapX(int tile_x) const
00479   {
00480     return tile_x - this->scroll_x / TILE_SIZE;
00481   }
00482 
00489   inline int RemapY(int tile_y) const
00490   {
00491     return tile_y - this->scroll_y / TILE_SIZE;
00492   }
00493 
00508   void DrawSmallMapStuff(void *dst, uint xc, uint yc, int pitch, int reps, uint32 mask, Blitter *blitter, GetSmallMapPixels *proc) const
00509   {
00510     void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height);
00511     void *dst_ptr_end = blitter->MoveTo(dst_ptr_abs_end, -4, 0);
00512 
00513     do {
00514       /* Check if the tile (xc,yc) is within the map range */
00515       uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0;
00516       if (IsInsideMM(xc, min_xy, MapMaxX()) && IsInsideMM(yc, min_xy, MapMaxY())) {
00517         /* Check if the dst pointer points to a pixel inside the screen buffer */
00518         if (dst < _screen.dst_ptr) continue;
00519         if (dst >= dst_ptr_abs_end) continue;
00520 
00521         uint32 val = proc(TileXY(xc, yc)) & mask;
00522         uint8 *val8 = (uint8 *)&val;
00523 
00524         if (dst <= dst_ptr_end) {
00525           blitter->SetPixelIfEmpty(dst, 0, 0, val8[0]);
00526           blitter->SetPixelIfEmpty(dst, 1, 0, val8[1]);
00527           blitter->SetPixelIfEmpty(dst, 2, 0, val8[2]);
00528           blitter->SetPixelIfEmpty(dst, 3, 0, val8[3]);
00529         } else {
00530           /* It happens that there are only 1, 2 or 3 pixels left to fill, so
00531            * in that special case, write till the end of the video-buffer */
00532           int i = 0;
00533           do {
00534             blitter->SetPixelIfEmpty(dst, 0, 0, val8[i]);
00535           } while (i++, dst = blitter->MoveTo(dst, 1, 0), dst < dst_ptr_abs_end);
00536         }
00537       }
00538     /* Switch to next tile in the column */
00539     } while (xc++, yc++, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0);
00540   }
00541 
00547   void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const
00548   {
00549     const Vehicle *v;
00550     FOR_ALL_VEHICLES(v) {
00551       if (v->type == VEH_EFFECT) continue;
00552       if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue;
00553 
00554       /* Remap into flat coordinates. */
00555       Point pt = RemapCoords(
00556           this->RemapX(v->x_pos / TILE_SIZE),
00557           this->RemapY(v->y_pos / TILE_SIZE),
00558           0);
00559       int x = pt.x;
00560       int y = pt.y;
00561 
00562       /* Check if y is out of bounds? */
00563       y -= dpi->top;
00564       if (!IsInsideMM(y, 0, dpi->height)) continue;
00565 
00566       /* Default is to draw both pixels. */
00567       bool skip = false;
00568 
00569       /* Offset X coordinate */
00570       x -= this->subscroll + 3 + dpi->left;
00571 
00572       if (x < 0) {
00573         /* if x+1 is 0, that means we're on the very left edge,
00574          * and should thus only draw a single pixel */
00575         if (++x != 0) continue;
00576         skip = true;
00577       } else if (x >= dpi->width - 1) {
00578         /* Check if we're at the very right edge, and if so draw only a single pixel */
00579         if (x != dpi->width - 1) continue;
00580         skip = true;
00581       }
00582 
00583       /* Calculate pointer to pixel and the colour */
00584       byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : 0xF;
00585 
00586       /* And draw either one or two pixels depending on clipping */
00587       blitter->SetPixel(dpi->dst_ptr, x, y, colour);
00588       if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour);
00589     }
00590   }
00591 
00596   void DrawTowns(const DrawPixelInfo *dpi) const
00597   {
00598     const Town *t;
00599     FOR_ALL_TOWNS(t) {
00600       /* Remap the town coordinate */
00601       Point pt = RemapCoords(
00602           this->RemapX(TileX(t->xy)),
00603           this->RemapY(TileY(t->xy)),
00604           0);
00605       int x = pt.x - this->subscroll - (t->sign.width_small >> 1);
00606       int y = pt.y;
00607 
00608       /* Check if the town sign is within bounds */
00609       if (x + t->sign.width_small > dpi->left &&
00610           x < dpi->left + dpi->width &&
00611           y + FONT_HEIGHT_SMALL > dpi->top &&
00612           y < dpi->top + dpi->height) {
00613         /* And draw it. */
00614         SetDParam(0, t->index);
00615         DrawString(x, x + t->sign.width_small, y, STR_SMALLMAP_TOWN);
00616       }
00617     }
00618   }
00619 
00626   static inline void DrawVertMapIndicator(int x, int y, int y2)
00627   {
00628     GfxFillRect(x, y,      x, y + 3, 69);
00629     GfxFillRect(x, y2 - 3, x, y2,    69);
00630   }
00631 
00638   static inline void DrawHorizMapIndicator(int x, int x2, int y)
00639   {
00640     GfxFillRect(x,      y, x + 3, y, 69);
00641     GfxFillRect(x2 - 3, y, x2,    y, 69);
00642   }
00643 
00647   void DrawMapIndicators() const
00648   {
00649     /* Find main viewport. */
00650     const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
00651 
00652     Point pt = RemapCoords(this->scroll_x, this->scroll_y, 0);
00653 
00654     int x = vp->virtual_left - pt.x;
00655     int y = vp->virtual_top - pt.y;
00656     int x2 = (x + vp->virtual_width) / TILE_SIZE;
00657     int y2 = (y + vp->virtual_height) / TILE_SIZE;
00658     x /= TILE_SIZE;
00659     y /= TILE_SIZE;
00660 
00661     x -= this->subscroll;
00662     x2 -= this->subscroll;
00663 
00664     SmallMapWindow::DrawVertMapIndicator(x, y, y2);
00665     SmallMapWindow::DrawVertMapIndicator(x2, y, y2);
00666 
00667     SmallMapWindow::DrawHorizMapIndicator(x, x2, y);
00668     SmallMapWindow::DrawHorizMapIndicator(x, x2, y2);
00669   }
00670 
00682   void DrawSmallMap(DrawPixelInfo *dpi) const
00683   {
00684     Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
00685     DrawPixelInfo *old_dpi;
00686 
00687     old_dpi = _cur_dpi;
00688     _cur_dpi = dpi;
00689 
00690     /* Clear it */
00691     GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, 0);
00692 
00693     /* Setup owner table */
00694     if (this->map_type == SMT_OWNER) {
00695       const Company *c;
00696 
00697       /* Fill with some special colours */
00698       _owner_colours[OWNER_TOWN]  = MKCOLOUR(0xB4B4B4B4);
00699       _owner_colours[OWNER_NONE]  = MKCOLOUR(0x54545454);
00700       _owner_colours[OWNER_WATER] = MKCOLOUR(0xCACACACA);
00701       _owner_colours[OWNER_END]   = MKCOLOUR(0x20202020); // Industry
00702 
00703       /* Now fill with the company colours */
00704       FOR_ALL_COMPANIES(c) {
00705         _owner_colours[c->index] = _colour_gradient[c->colour][5] * 0x01010101;
00706       }
00707     }
00708 
00709     int tile_x = this->scroll_x / TILE_SIZE;
00710     int tile_y = this->scroll_y / TILE_SIZE;
00711 
00712     int dx = dpi->left + this->subscroll;
00713     tile_x -= dx / 4;
00714     tile_y += dx / 4;
00715     dx &= 3;
00716 
00717     int dy = dpi->top;
00718     tile_x += dy / 2;
00719     tile_y += dy / 2;
00720 
00721     if (dy & 1) {
00722       tile_x++;
00723       dx += 2;
00724       if (dx > 3) {
00725         dx -= 4;
00726         tile_x--;
00727         tile_y++;
00728       }
00729     }
00730 
00731     void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0);
00732     int x = - dx - 4;
00733     int y = 0;
00734 
00735     for (;;) {
00736       uint32 mask = 0xFFFFFFFF;
00737 
00738       /* Distance from left edge */
00739       if (x >= -3) {
00740         if (x < 0) {
00741           /* Mask to use at the left edge */
00742           mask = _smallmap_mask_left[x + 3];
00743         }
00744 
00745         /* Distance from right edge */
00746         int t = dpi->width - x;
00747         if (t < 4) {
00748           if (t <= 0) break; // Exit loop
00749           /* Mask to use at the right edge */
00750           mask &= _smallmap_mask_right[t - 1];
00751         }
00752 
00753         /* Number of lines */
00754         int reps = (dpi->height - y + 1) / 2;
00755         if (reps > 0) {
00756           this->DrawSmallMapStuff(ptr, tile_x, tile_y, dpi->pitch * 2, reps, mask, blitter, _smallmap_draw_procs[this->map_type]);
00757         }
00758       }
00759 
00760       if (y == 0) {
00761         tile_y++;
00762         y++;
00763         ptr = blitter->MoveTo(ptr, 0, 1);
00764       } else {
00765         tile_x--;
00766         y--;
00767         ptr = blitter->MoveTo(ptr, 0, -1);
00768       }
00769       ptr = blitter->MoveTo(ptr, 2, 0);
00770       x += 2;
00771     }
00772 
00773     /* Draw vehicles */
00774     if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter);
00775 
00776     /* Draw town names */
00777     if (this->show_towns) this->DrawTowns(dpi);
00778 
00779     /* Draw map indicators */
00780     this->DrawMapIndicators();
00781 
00782     _cur_dpi = old_dpi;
00783   }
00784 
00785 public:
00786   SmallMapWindow(const WindowDesc *desc, int window_number) : Window(), refresh(FORCE_REFRESH_PERIOD)
00787   {
00788     this->InitNested(desc, window_number);
00789     this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
00790 
00791     _smallmap_industry_show_heightmap = false;
00792     this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_industry_show_heightmap);
00793 
00794     this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
00795     this->GetWidget<NWidgetStacked>(SM_WIDGET_SELECTINDUSTRIES)->SetDisplayedPlane(this->map_type != SMT_INDUSTRY);
00796 
00797     this->SmallMapCenterOnCurrentPos();
00798   }
00799 
00803   inline uint GetMaxLegendHeight() const
00804   {
00805     uint num_rows = max(this->min_number_of_fixed_rows, (_smallmap_industry_count + this->min_number_of_columns - 1) / this->min_number_of_columns);
00806     return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
00807   }
00808 
00812   inline uint GetMinLegendWidth() const
00813   {
00814     return WD_FRAMERECT_LEFT + this->min_number_of_columns * this->column_width;
00815   }
00816 
00820   inline uint GetNumberColumnsLegend(uint width) const
00821   {
00822     return width / this->column_width;
00823   }
00824 
00828   uint GetLegendHeight(uint width) const
00829   {
00830     uint num_columns = this->GetNumberColumnsLegend(width);
00831     uint num_rows = max(this->min_number_of_fixed_rows, (_smallmap_industry_count + num_columns - 1) / num_columns);
00832     return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
00833   }
00834 
00835   virtual void SetStringParameters(int widget) const
00836   {
00837     switch (widget) {
00838       case SM_WIDGET_CAPTION:
00839         SetDParam(0, STR_SMALLMAP_TYPE_CONTOURS + this->map_type);
00840         break;
00841     }
00842   }
00843 
00844   virtual void OnInit()
00845   {
00846     uint min_width = 0;
00847     this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS;
00848     this->min_number_of_fixed_rows = 0;
00849     for (uint i = 0; i < lengthof(_legend_table); i++) {
00850       uint height = 0;
00851       uint num_columns = 1;
00852       for (const LegendAndColour *tbl = _legend_table[i]; !tbl->end; ++tbl) {
00853         StringID str;
00854         if (i == SMT_INDUSTRY) {
00855           SetDParam(0, tbl->legend);
00856           SetDParam(1, IndustryPool::MAX_SIZE);
00857           str = STR_SMALLMAP_INDUSTRY;
00858         } else {
00859           if (tbl->col_break) {
00860             this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
00861             height = 0;
00862             num_columns++;
00863           }
00864           height++;
00865           str = tbl->legend;
00866         }
00867         min_width = max(GetStringBoundingBox(str).width, min_width);
00868       }
00869       this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
00870       this->min_number_of_columns = max(this->min_number_of_columns, num_columns);
00871     }
00872 
00873     /* The width of a column is the minimum width of all texts + the size of the blob + some spacing */
00874     this->column_width = min_width + LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
00875   }
00876 
00877   virtual void DrawWidget(const Rect &r, int widget) const
00878   {
00879     switch (widget) {
00880       case SM_WIDGET_MAP: {
00881         DrawPixelInfo new_dpi;
00882         if (!FillDrawPixelInfo(&new_dpi, r.left + 1, r.top + 1, r.right - r.left - 1, r.bottom - r.top - 1)) return;
00883         this->DrawSmallMap(&new_dpi);
00884       } break;
00885 
00886       case SM_WIDGET_LEGEND: {
00887         uint columns = this->GetNumberColumnsLegend(r.right - r.left + 1);
00888         uint number_of_rows = max(this->map_type == SMT_INDUSTRY ? (_smallmap_industry_count + columns - 1) / columns : 0, this->min_number_of_fixed_rows);
00889         bool rtl = _dynlang.text_dir == TD_RTL;
00890         uint y_org = r.top + WD_FRAMERECT_TOP;
00891         uint x = rtl ? r.right - this->column_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT;
00892         uint y = y_org;
00893         uint i = 0; // Row counter for industry legend.
00894         uint row_height = FONT_HEIGHT_SMALL;
00895 
00896         uint text_left  = rtl ? 0 : LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT;
00897         uint text_right = this->column_width - 1 - (rtl ? LEGEND_BLOB_WIDTH + WD_FRAMERECT_RIGHT : 0);
00898         uint blob_left  = rtl ? this->column_width - 1 - LEGEND_BLOB_WIDTH : 0;
00899         uint blob_right = rtl ? this->column_width - 1 : LEGEND_BLOB_WIDTH;
00900 
00901         for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) {
00902           if (tbl->col_break || (this->map_type == SMT_INDUSTRY && i++ >= number_of_rows)) {
00903             /* Column break needed, continue at top, COLUMN_WIDTH pixels
00904              * (one "row") to the right. */
00905             x += rtl ? -(int)this->column_width : this->column_width;
00906             y = y_org;
00907             i = 1;
00908           }
00909 
00910           if (this->map_type == SMT_INDUSTRY) {
00911             /* Industry name must be formatted, since it's not in tiny font in the specs.
00912              * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font */
00913             SetDParam(0, tbl->legend);
00914             assert(tbl->type < NUM_INDUSTRYTYPES);
00915             SetDParam(1, _industry_counts[tbl->type]);
00916             if (!tbl->show_on_map) {
00917               /* Simply draw the string, not the black border of the legend colour.
00918                * This will enforce the idea of the disabled item */
00919               DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_GREY);
00920             } else {
00921               DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_BLACK);
00922               GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0); // Outer border of the legend colour
00923             }
00924           } else {
00925             /* Anything that is not an industry is using normal process */
00926             GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0);
00927             DrawString(x + text_left, x + text_right, y, tbl->legend);
00928           }
00929           GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + row_height - 2, tbl->colour); // Legend colour
00930 
00931           y += row_height;
00932         }
00933       }
00934     }
00935   }
00936 
00937   virtual void OnPaint()
00938   {
00939     this->DrawWidgets();
00940   }
00941 
00942   virtual void OnClick(Point pt, int widget)
00943   {
00944     switch (widget) {
00945       case SM_WIDGET_MAP: { // Map window
00946         /*
00947          * XXX: scrolling with the left mouse button is done by subsequently
00948          * clicking with the left mouse button; clicking once centers the
00949          * large map at the selected point. So by unclicking the left mouse
00950          * button here, it gets reclicked during the next inputloop, which
00951          * would make it look like the mouse is being dragged, while it is
00952          * actually being (virtually) clicked every inputloop.
00953          */
00954         _left_button_clicked = false;
00955 
00956         const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
00957         Point pt = RemapCoords(this->scroll_x, this->scroll_y, 0);
00958         Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
00959         w->viewport->follow_vehicle = INVALID_VEHICLE;
00960         w->viewport->dest_scrollpos_x = pt.x + ((_cursor.pos.x - this->left + wid->pos_x) << 4) - (w->viewport->virtual_width  >> 1);
00961         w->viewport->dest_scrollpos_y = pt.y + ((_cursor.pos.y - this->top  - wid->pos_y) << 4) - (w->viewport->virtual_height >> 1);
00962 
00963         this->SetDirty();
00964       } break;
00965 
00966       case SM_WIDGET_CONTOUR:    // Show land contours
00967       case SM_WIDGET_VEHICLES:   // Show vehicles
00968       case SM_WIDGET_INDUSTRIES: // Show industries
00969       case SM_WIDGET_ROUTES:     // Show transport routes
00970       case SM_WIDGET_VEGETATION: // Show vegetation
00971       case SM_WIDGET_OWNERS:     // Show land owners
00972         this->RaiseWidget(this->map_type + SM_WIDGET_CONTOUR);
00973         this->map_type = (SmallMapType)(widget - SM_WIDGET_CONTOUR);
00974         this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
00975 
00976         /* Hide Enable all/Disable all buttons if is not industry type small map */
00977         this->GetWidget<NWidgetStacked>(SM_WIDGET_SELECTINDUSTRIES)->SetDisplayedPlane(this->map_type != SMT_INDUSTRY);
00978 
00979         this->SetDirty();
00980         SndPlayFx(SND_15_BEEP);
00981         break;
00982 
00983       case SM_WIDGET_CENTERMAP: // Center the smallmap again
00984         this->SmallMapCenterOnCurrentPos();
00985         this->HandleButtonClick(SM_WIDGET_CENTERMAP);
00986         SndPlayFx(SND_15_BEEP);
00987         break;
00988 
00989       case SM_WIDGET_TOGGLETOWNNAME: // Toggle town names
00990         this->show_towns = !this->show_towns;
00991         this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
00992 
00993         this->SetDirty();
00994         SndPlayFx(SND_15_BEEP);
00995         break;
00996 
00997       case SM_WIDGET_LEGEND: // Legend
00998         /* If industry type small map*/
00999         if (this->map_type == SMT_INDUSTRY) {
01000           /* If click on industries label, find right industry type and enable/disable it */
01001           const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_LEGEND); // Label panel
01002           uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL;
01003           uint columns = this->GetNumberColumnsLegend(wi->current_x);
01004           uint number_of_rows = max((_smallmap_industry_count + columns - 1) / columns, this->min_number_of_fixed_rows);
01005           if (line >= number_of_rows) break;
01006 
01007           bool rtl = _dynlang.text_dir == TD_RTL;
01008           int x = pt.x - wi->pos_x;
01009           if (rtl) x = wi->current_x - x;
01010           uint column = (x - WD_FRAMERECT_LEFT) / this->column_width;
01011 
01012           /* Check if click is on industry label*/
01013           int industry_pos = (column * number_of_rows) + line;
01014           if (industry_pos < _smallmap_industry_count) {
01015             _legend_from_industries[industry_pos].show_on_map = !_legend_from_industries[industry_pos].show_on_map;
01016           }
01017 
01018           /* Raise the two buttons "all", as we have done a specific choice */
01019           this->RaiseWidget(SM_WIDGET_ENABLEINDUSTRIES);
01020           this->RaiseWidget(SM_WIDGET_DISABLEINDUSTRIES);
01021           this->SetDirty();
01022         }
01023         break;
01024 
01025       case SM_WIDGET_ENABLEINDUSTRIES: // Enable all industries
01026         for (int i = 0; i != _smallmap_industry_count; i++) {
01027           _legend_from_industries[i].show_on_map = true;
01028         }
01029         /* Toggle appeareance indicating the choice */
01030         this->LowerWidget(SM_WIDGET_ENABLEINDUSTRIES);
01031         this->RaiseWidget(SM_WIDGET_DISABLEINDUSTRIES);
01032         this->SetDirty();
01033         break;
01034 
01035       case SM_WIDGET_DISABLEINDUSTRIES: // Disable all industries
01036         for (int i = 0; i != _smallmap_industry_count; i++) {
01037           _legend_from_industries[i].show_on_map = false;
01038         }
01039         /* Toggle appeareance indicating the choice */
01040         this->RaiseWidget(SM_WIDGET_ENABLEINDUSTRIES);
01041         this->LowerWidget(SM_WIDGET_DISABLEINDUSTRIES);
01042         this->SetDirty();
01043         break;
01044 
01045       case SM_WIDGET_SHOW_HEIGHT: // Enable/disable showing of heightmap.
01046         _smallmap_industry_show_heightmap = !_smallmap_industry_show_heightmap;
01047         this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_industry_show_heightmap);
01048         this->SetDirty();
01049         break;
01050     }
01051   }
01052 
01053   virtual void OnRightClick(Point pt, int widget)
01054   {
01055     if (widget == SM_WIDGET_MAP) {
01056       if (_scrolling_viewport) return;
01057       _scrolling_viewport = true;
01058     }
01059   }
01060 
01061   virtual void OnTick()
01062   {
01063     /* Update the window every now and then */
01064     if (--this->refresh != 0) return;
01065 
01066     this->refresh = FORCE_REFRESH_PERIOD;
01067     this->SetDirty();
01068   }
01069 
01070   virtual void OnScroll(Point delta)
01071   {
01072     _cursor.fix_at = true;
01073 
01074     int x = this->scroll_x;
01075     int y = this->scroll_y;
01076 
01077     int sub = this->subscroll + delta.x;
01078 
01079     x -= (sub >> 2) << 4;
01080     y += (sub >> 2) << 4;
01081     sub &= 3;
01082 
01083     x += (delta.y >> 1) << 4;
01084     y += (delta.y >> 1) << 4;
01085 
01086     if (delta.y & 1) {
01087       x += TILE_SIZE;
01088       sub += 2;
01089       if (sub > 3) {
01090         sub -= 4;
01091         x -= TILE_SIZE;
01092         y += TILE_SIZE;
01093       }
01094     }
01095 
01096     const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01097     int hx = wi->current_x / 2;
01098     int hy = wi->current_y / 2;
01099     int hvx = hx * -4 + hy * 8;
01100     int hvy = hx *  4 + hy * 8;
01101     if (x < -hvx) {
01102       x = -hvx;
01103       sub = 0;
01104     }
01105     if (x > (int)MapMaxX() * TILE_SIZE - hvx) {
01106       x = MapMaxX() * TILE_SIZE - hvx;
01107       sub = 0;
01108     }
01109     if (y < -hvy) {
01110       y = -hvy;
01111       sub = 0;
01112     }
01113     if (y > (int)MapMaxY() * TILE_SIZE - hvy) {
01114       y = MapMaxY() * TILE_SIZE - hvy;
01115       sub = 0;
01116     }
01117 
01118     this->scroll_x = x;
01119     this->scroll_y = y;
01120     this->subscroll = sub;
01121 
01122     this->SetDirty();
01123   }
01124 
01125   void SmallMapCenterOnCurrentPos()
01126   {
01127     const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
01128     const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01129 
01130     int x = ((vp->virtual_width  - (int)wi->current_x * TILE_SIZE) / 2 + vp->virtual_left) / 4;
01131     int y = ((vp->virtual_height - (int)wi->current_y * TILE_SIZE) / 2 + vp->virtual_top ) / 2 - TILE_SIZE * 2;
01132     this->scroll_x = (y - x) & ~0xF;
01133     this->scroll_y = (x + y) & ~0xF;
01134     this->SetDirty();
01135   }
01136 };
01137 
01138 SmallMapWindow::SmallMapType SmallMapWindow::map_type = SMT_CONTOUR;
01139 bool SmallMapWindow::show_towns = true;
01140 
01149 class NWidgetSmallmapDisplay : public NWidgetContainer {
01150   const SmallMapWindow *smallmap_window; 
01151 public:
01152   NWidgetSmallmapDisplay() : NWidgetContainer(NWID_VERTICAL)
01153   {
01154     this->smallmap_window = NULL;
01155   }
01156 
01157   virtual void SetupSmallestSize(Window *w, bool init_array)
01158   {
01159     NWidgetBase *display = this->head;
01160     NWidgetBase *bar = display->next;
01161 
01162     display->SetupSmallestSize(w, init_array);
01163     bar->SetupSmallestSize(w, init_array);
01164 
01165     this->smallmap_window = dynamic_cast<SmallMapWindow *>(w);
01166     this->smallest_x = max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth());
01167     this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetMaxLegendHeight());
01168     this->fill_x = max(display->fill_x, bar->fill_x);
01169     this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : min(display->fill_y, bar->fill_y);
01170     this->resize_x = max(display->resize_x, bar->resize_x);
01171     this->resize_y = min(display->resize_y, bar->resize_y);
01172   }
01173 
01174   virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01175   {
01176     this->pos_x = x;
01177     this->pos_y = y;
01178     this->current_x = given_width;
01179     this->current_y = given_height;
01180 
01181     NWidgetBase *display = this->head;
01182     NWidgetBase *bar = display->next;
01183 
01184     if (sizing == ST_SMALLEST) {
01185       this->smallest_x = given_width;
01186       this->smallest_y = given_height;
01187       /* Make display and bar exactly equal to their minimal size. */
01188       display->AssignSizePosition(ST_SMALLEST, x, y, display->smallest_x, display->smallest_y, rtl);
01189       bar->AssignSizePosition(ST_SMALLEST, x, y + display->smallest_y, bar->smallest_x, bar->smallest_y, rtl);
01190     }
01191 
01192     uint bar_height = max(bar->smallest_y, this->smallmap_window->GetLegendHeight(given_width - bar->smallest_x));
01193     uint display_height = given_height - bar_height;
01194     display->AssignSizePosition(ST_RESIZE, x, y, given_width, display_height, rtl);
01195     bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl);
01196   }
01197 
01198   virtual NWidgetCore *GetWidgetFromPos(int x, int y)
01199   {
01200     if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
01201     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01202       NWidgetCore *widget = child_wid->GetWidgetFromPos(x, y);
01203       if (widget != NULL) return widget;
01204     }
01205     return NULL;
01206   }
01207 
01208   virtual void Draw(const Window *w)
01209   {
01210     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) child_wid->Draw(w);
01211   }
01212 };
01213 
01215 static const NWidgetPart _nested_smallmap_display[] = {
01216   NWidget(WWT_PANEL, COLOUR_BROWN, SM_WIDGET_MAP_BORDER),
01217     NWidget(WWT_INSET, COLOUR_BROWN, SM_WIDGET_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(),
01218   EndContainer(),
01219 };
01220 
01222 static const NWidgetPart _nested_smallmap_bar[] = {
01223   NWidget(WWT_PANEL, COLOUR_BROWN),
01224     NWidget(NWID_HORIZONTAL),
01225       NWidget(WWT_EMPTY, INVALID_COLOUR, SM_WIDGET_LEGEND), SetResize(1, 1),
01226       NWidget(NWID_VERTICAL),
01227         /* Top button row. */
01228         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01229           NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_CENTERMAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER),
01230           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_CONTOUR), SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP),
01231           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEHICLES), SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP),
01232           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_INDUSTRIES), SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP),
01233         EndContainer(),
01234         /* Bottom button row. */
01235         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01236           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_TOGGLETOWNNAME), SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF),
01237           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_ROUTES), SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON),
01238           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEGETATION), SetDataTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP),
01239           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_OWNERS), SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP),
01240         EndContainer(),
01241         NWidget(NWID_SPACER), SetResize(0, 1),
01242       EndContainer(),
01243     EndContainer(),
01244   EndContainer(),
01245 };
01246 
01247 static NWidgetBase *SmallMapDisplay(int *biggest_index)
01248 {
01249   NWidgetContainer *map_display = new NWidgetSmallmapDisplay;
01250 
01251   MakeNWidgets(_nested_smallmap_display, lengthof(_nested_smallmap_display), biggest_index, map_display);
01252   MakeNWidgets(_nested_smallmap_bar, lengthof(_nested_smallmap_bar), biggest_index, map_display);
01253   return map_display;
01254 }
01255 
01256 
01257 static const NWidgetPart _nested_smallmap_widgets[] = {
01258   NWidget(NWID_HORIZONTAL),
01259     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
01260     NWidget(WWT_CAPTION, COLOUR_BROWN, SM_WIDGET_CAPTION), SetDataTip(STR_SMALLMAP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01261     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
01262     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
01263   EndContainer(),
01264   NWidgetFunction(SmallMapDisplay), // Smallmap display and legend bar + image buttons.
01265   /* Bottom button row and resize box. */
01266   NWidget(NWID_HORIZONTAL),
01267     NWidget(WWT_PANEL, COLOUR_BROWN),
01268       NWidget(NWID_HORIZONTAL),
01269         NWidget(NWID_SELECTION, INVALID_COLOUR, SM_WIDGET_SELECTINDUSTRIES),
01270           NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01271             NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_ENABLEINDUSTRIES), SetDataTip(STR_SMALLMAP_ENABLE_ALL, STR_SMALLMAP_TOOLTIP_ENABLE_ALL),
01272             NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_DISABLEINDUSTRIES), SetDataTip(STR_SMALLMAP_DISABLE_ALL, STR_SMALLMAP_TOOLTIP_DISABLE_ALL),
01273             NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_SHOW_HEIGHT), SetDataTip(STR_SMALLMAP_SHOW_HEIGHT, STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT),
01274           EndContainer(),
01275           NWidget(NWID_SPACER), SetFill(1, 1),
01276         EndContainer(),
01277         NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
01278       EndContainer(),
01279     EndContainer(),
01280     NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
01281   EndContainer(),
01282 };
01283 
01284 static const WindowDesc _smallmap_desc(
01285   WDP_AUTO, 446, 314,
01286   WC_SMALLMAP, WC_NONE,
01287   WDF_UNCLICK_BUTTONS,
01288   _nested_smallmap_widgets, lengthof(_nested_smallmap_widgets)
01289 );
01290 
01291 void ShowSmallMap()
01292 {
01293   AllocateWindowDescFront<SmallMapWindow>(&_smallmap_desc, 0);
01294 }
01295 
01304 bool ScrollMainWindowTo(int x, int y, int z, bool instant)
01305 {
01306   bool res = ScrollWindowTo(x, y, z, FindWindowById(WC_MAIN_WINDOW, 0), instant);
01307 
01308   /* If a user scrolls to a tile (via what way what so ever) and already is on
01309    * that tile (e.g.: pressed twice), move the smallmap to that location,
01310    * so you directly see where you are on the smallmap. */
01311 
01312   if (res) return res;
01313 
01314   SmallMapWindow *w = dynamic_cast<SmallMapWindow*>(FindWindowById(WC_SMALLMAP, 0));
01315   if (w != NULL) w->SmallMapCenterOnCurrentPos();
01316 
01317   return res;
01318 }

Generated on Wed Jan 20 23:38:39 2010 for OpenTTD by  doxygen 1.5.6