smallmap_gui.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "clear_map.h"
00014 #include "industry.h"
00015 #include "station_map.h"
00016 #include "landscape.h"
00017 #include "window_gui.h"
00018 #include "tree_map.h"
00019 #include "viewport_func.h"
00020 #include "gfx_func.h"
00021 #include "town.h"
00022 #include "blitter/factory.hpp"
00023 #include "tunnelbridge_map.h"
00024 #include "strings_func.h"
00025 #include "core/endian_func.hpp"
00026 #include "vehicle_base.h"
00027 #include "sound_func.h"
00028 #include "window_func.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 
00223 static const AndOr _smallmap_contours_andor[] = {
00224   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00225   {MKCOLOUR(0x000A0A00), MKCOLOUR(0xFF0000FF)},
00226   {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)},
00227   {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)},
00228   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00229   {MKCOLOUR(0x98989898), MKCOLOUR(0x00000000)},
00230   {MKCOLOUR(0xCACACACA), MKCOLOUR(0x00000000)},
00231   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00232   {MKCOLOUR(0xB5B5B5B5), MKCOLOUR(0x00000000)},
00233   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00234   {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)},
00235   {MKCOLOUR(0x000A0A00), MKCOLOUR(0xFF0000FF)},
00236 };
00237 
00238 static const AndOr _smallmap_vehicles_andor[] = {
00239   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00240   {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)},
00241   {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)},
00242   {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)},
00243   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00244   {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)},
00245   {MKCOLOUR(0xCACACACA), MKCOLOUR(0x00000000)},
00246   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00247   {MKCOLOUR(0xB5B5B5B5), MKCOLOUR(0x00000000)},
00248   {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00249   {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)},
00250   {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)},
00251 };
00252 
00253 typedef uint32 GetSmallMapPixels(TileIndex tile); 
00254 
00255 
00256 static inline TileType GetEffectiveTileType(TileIndex tile)
00257 {
00258   TileType t = GetTileType(tile);
00259 
00260   if (t == MP_TUNNELBRIDGE) {
00261     TransportType tt = GetTunnelBridgeTransportType(tile);
00262 
00263     switch (tt) {
00264       case TRANSPORT_RAIL: t = MP_RAILWAY; break;
00265       case TRANSPORT_ROAD: t = MP_ROAD;    break;
00266       default:             t = MP_WATER;   break;
00267     }
00268   }
00269   return t;
00270 }
00271 
00277 static inline uint32 GetSmallMapContoursPixels(TileIndex tile)
00278 {
00279   TileType t = GetEffectiveTileType(tile);
00280 
00281   return ApplyMask(_map_height_bits[TileHeight(tile)], &_smallmap_contours_andor[t]);
00282 }
00283 
00290 static inline uint32 GetSmallMapVehiclesPixels(TileIndex tile)
00291 {
00292   TileType t = GetEffectiveTileType(tile);
00293 
00294   return ApplyMask(MKCOLOUR(0x54545454), &_smallmap_vehicles_andor[t]);
00295 }
00296 
00303 static inline uint32 GetSmallMapIndustriesPixels(TileIndex tile)
00304 {
00305   TileType t = GetEffectiveTileType(tile);
00306 
00307   if (t == MP_INDUSTRY) {
00308     /* If industry is allowed to be seen, use its colour on the map */
00309     if (_legend_from_industries[_industry_to_list_pos[Industry::GetByTile(tile)->type]].show_on_map) {
00310       return GetIndustrySpec(Industry::GetByTile(tile)->type)->map_colour * 0x01010101;
00311     } else {
00312       /* Otherwise, return the colour of the clear tiles, which will make it disappear */
00313       t = MP_CLEAR;
00314     }
00315   }
00316 
00317   return ApplyMask(_smallmap_industry_show_heightmap ? _map_height_bits[TileHeight(tile)] : MKCOLOUR(0x54545454), &_smallmap_vehicles_andor[t]);
00318 }
00319 
00326 static inline uint32 GetSmallMapRoutesPixels(TileIndex tile)
00327 {
00328   TileType t = GetEffectiveTileType(tile);
00329 
00330   if (t == MP_STATION) {
00331     switch (GetStationType(tile)) {
00332       case STATION_RAIL:    return MKCOLOUR(0x56565656);
00333       case STATION_AIRPORT: return MKCOLOUR(0xB8B8B8B8);
00334       case STATION_TRUCK:   return MKCOLOUR(0xC2C2C2C2);
00335       case STATION_BUS:     return MKCOLOUR(0xBFBFBFBF);
00336       case STATION_DOCK:    return MKCOLOUR(0x98989898);
00337       default:              return MKCOLOUR(0xFFFFFFFF);
00338     }
00339   }
00340 
00341   /* Ground colour */
00342   return ApplyMask(MKCOLOUR(0x54545454), &_smallmap_contours_andor[t]);
00343 }
00344 
00345 
00346 static const uint32 _vegetation_clear_bits[] = {
00347   MKCOLOUR(0x54545454), 
00348   MKCOLOUR(0x52525252), 
00349   MKCOLOUR(0x0A0A0A0A), 
00350   MKCOLOUR(0x25252525), 
00351   MKCOLOUR(0x98989898), 
00352   MKCOLOUR(0xC2C2C2C2), 
00353   MKCOLOUR(0x54545454), 
00354   MKCOLOUR(0x54545454), 
00355 };
00356 
00357 static inline uint32 GetSmallMapVegetationPixels(TileIndex tile)
00358 {
00359   TileType t = GetEffectiveTileType(tile);
00360 
00361   switch (t) {
00362     case MP_CLEAR:
00363       return (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) < 3) ? MKCOLOUR(0x37373737) : _vegetation_clear_bits[GetClearGround(tile)];
00364 
00365     case MP_INDUSTRY:
00366       return GetIndustrySpec(Industry::GetByTile(tile)->type)->check_proc == CHECK_FOREST ? MKCOLOUR(0xD0D0D0D0) : MKCOLOUR(0xB5B5B5B5);
00367 
00368     case MP_TREES:
00369       if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT) {
00370         return (_settings_game.game_creation.landscape == LT_ARCTIC) ? MKCOLOUR(0x98575798) : MKCOLOUR(0xC25757C2);
00371       }
00372       return MKCOLOUR(0x54575754);
00373 
00374     default:
00375       return ApplyMask(MKCOLOUR(0x54545454), &_smallmap_vehicles_andor[t]);
00376   }
00377 }
00378 
00379 
00380 static uint32 _owner_colours[OWNER_END + 1];
00381 
00388 static inline uint32 GetSmallMapOwnerPixels(TileIndex tile)
00389 {
00390   Owner o;
00391 
00392   switch (GetTileType(tile)) {
00393     case MP_INDUSTRY: o = OWNER_END;          break;
00394     case MP_HOUSE:    o = OWNER_TOWN;         break;
00395     default:          o = GetTileOwner(tile); break;
00396     /* FIXME: For MP_ROAD there are multiple owners.
00397      * GetTileOwner returns the rail owner (level crossing) resp. the owner of ROADTYPE_ROAD (normal road),
00398      * even if there are no ROADTYPE_ROAD bits on the tile.
00399      */
00400   }
00401 
00402   return _owner_colours[o];
00403 }
00404 
00405 
00406 static const uint32 _smallmap_mask_left[3] = {
00407   MKCOLOUR(0xFF000000),
00408   MKCOLOUR(0xFFFF0000),
00409   MKCOLOUR(0xFFFFFF00),
00410 };
00411 
00412 static const uint32 _smallmap_mask_right[] = {
00413   MKCOLOUR(0x000000FF),
00414   MKCOLOUR(0x0000FFFF),
00415   MKCOLOUR(0x00FFFFFF),
00416 };
00417 
00418 /* Each tile has 4 x pixels and 1 y pixel */
00419 
00420 static GetSmallMapPixels * const _smallmap_draw_procs[] = {
00421   GetSmallMapContoursPixels,
00422   GetSmallMapVehiclesPixels,
00423   GetSmallMapIndustriesPixels,
00424   GetSmallMapRoutesPixels,
00425   GetSmallMapVegetationPixels,
00426   GetSmallMapOwnerPixels,
00427 };
00428 
00429 static const byte _vehicle_type_colours[6] = {
00430   184, 191, 152, 15, 215, 184
00431 };
00432 
00433 
00435 class SmallMapWindow : public Window {
00437   enum SmallMapType {
00438     SMT_CONTOUR,
00439     SMT_VEHICLES,
00440     SMT_INDUSTRY,
00441     SMT_ROUTES,
00442     SMT_VEGETATION,
00443     SMT_OWNER,
00444   };
00445 
00446   static SmallMapType map_type; 
00447   static bool show_towns;       
00448 
00449   static const uint LEGEND_BLOB_WIDTH = 8;              
00450   static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2; 
00451   uint min_number_of_columns;    
00452   uint min_number_of_fixed_rows; 
00453   uint column_width;             
00454 
00455   int32 scroll_x;
00456   int32 scroll_y;
00457   int32 subscroll;
00458 
00459   static const uint8 FORCE_REFRESH_PERIOD = 0x1F; 
00460   uint8 refresh; 
00461 
00468   inline int RemapX(int tile_x) const
00469   {
00470     return tile_x - this->scroll_x / TILE_SIZE;
00471   }
00472 
00479   inline int RemapY(int tile_y) const
00480   {
00481     return tile_y - this->scroll_y / TILE_SIZE;
00482   }
00483 
00498   void DrawSmallMapStuff(void *dst, uint xc, uint yc, int pitch, int reps, uint32 mask, Blitter *blitter, GetSmallMapPixels *proc) const
00499   {
00500     void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height);
00501     void *dst_ptr_end = blitter->MoveTo(dst_ptr_abs_end, -4, 0);
00502 
00503     do {
00504       /* Check if the tile (xc,yc) is within the map range */
00505       uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0;
00506       if (IsInsideMM(xc, min_xy, MapMaxX()) && IsInsideMM(yc, min_xy, MapMaxY())) {
00507         /* Check if the dst pointer points to a pixel inside the screen buffer */
00508         if (dst < _screen.dst_ptr) continue;
00509         if (dst >= dst_ptr_abs_end) continue;
00510 
00511         uint32 val = proc(TileXY(xc, yc)) & mask;
00512         uint8 *val8 = (uint8 *)&val;
00513 
00514         if (dst <= dst_ptr_end) {
00515           blitter->SetPixelIfEmpty(dst, 0, 0, val8[0]);
00516           blitter->SetPixelIfEmpty(dst, 1, 0, val8[1]);
00517           blitter->SetPixelIfEmpty(dst, 2, 0, val8[2]);
00518           blitter->SetPixelIfEmpty(dst, 3, 0, val8[3]);
00519         } else {
00520           /* It happens that there are only 1, 2 or 3 pixels left to fill, so
00521            * in that special case, write till the end of the video-buffer */
00522           int i = 0;
00523           do {
00524             blitter->SetPixelIfEmpty(dst, 0, 0, val8[i]);
00525           } while (i++, dst = blitter->MoveTo(dst, 1, 0), dst < dst_ptr_abs_end);
00526         }
00527       }
00528     /* Switch to next tile in the column */
00529     } while (xc++, yc++, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0);
00530   }
00531 
00537   void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const
00538   {
00539     const Vehicle *v;
00540     FOR_ALL_VEHICLES(v) {
00541       if (v->type == VEH_EFFECT) continue;
00542       if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue;
00543 
00544       /* Remap into flat coordinates. */
00545       Point pt = RemapCoords(
00546           this->RemapX(v->x_pos / TILE_SIZE),
00547           this->RemapY(v->y_pos / TILE_SIZE),
00548           0);
00549       int x = pt.x;
00550       int y = pt.y;
00551 
00552       /* Check if y is out of bounds? */
00553       y -= dpi->top;
00554       if (!IsInsideMM(y, 0, dpi->height)) continue;
00555 
00556       /* Default is to draw both pixels. */
00557       bool skip = false;
00558 
00559       /* Offset X coordinate */
00560       x -= this->subscroll + 3 + dpi->left;
00561 
00562       if (x < 0) {
00563         /* if x+1 is 0, that means we're on the very left edge,
00564          * and should thus only draw a single pixel */
00565         if (++x != 0) continue;
00566         skip = true;
00567       } else if (x >= dpi->width - 1) {
00568         /* Check if we're at the very right edge, and if so draw only a single pixel */
00569         if (x != dpi->width - 1) continue;
00570         skip = true;
00571       }
00572 
00573       /* Calculate pointer to pixel and the colour */
00574       byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : 0xF;
00575 
00576       /* And draw either one or two pixels depending on clipping */
00577       blitter->SetPixel(dpi->dst_ptr, x, y, colour);
00578       if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour);
00579     }
00580   }
00581 
00586   void DrawTowns(const DrawPixelInfo *dpi) const
00587   {
00588     const Town *t;
00589     FOR_ALL_TOWNS(t) {
00590       /* Remap the town coordinate */
00591       Point pt = RemapCoords(
00592           this->RemapX(TileX(t->xy)),
00593           this->RemapY(TileY(t->xy)),
00594           0);
00595       int x = pt.x - this->subscroll - (t->sign.width_small >> 1);
00596       int y = pt.y;
00597 
00598       /* Check if the town sign is within bounds */
00599       if (x + t->sign.width_small > dpi->left &&
00600           x < dpi->left + dpi->width &&
00601           y + FONT_HEIGHT_SMALL > dpi->top &&
00602           y < dpi->top + dpi->height) {
00603         /* And draw it. */
00604         SetDParam(0, t->index);
00605         DrawString(x, x + t->sign.width_small, y, STR_SMALLMAP_TOWN);
00606       }
00607     }
00608   }
00609 
00616   static inline void DrawVertMapIndicator(int x, int y, int y2)
00617   {
00618     GfxFillRect(x, y,      x, y + 3, 69);
00619     GfxFillRect(x, y2 - 3, x, y2,    69);
00620   }
00621 
00628   static inline void DrawHorizMapIndicator(int x, int x2, int y)
00629   {
00630     GfxFillRect(x,      y, x + 3, y, 69);
00631     GfxFillRect(x2 - 3, y, x2,    y, 69);
00632   }
00633 
00637   void DrawMapIndicators() const
00638   {
00639     /* Find main viewport. */
00640     const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
00641 
00642     Point pt = RemapCoords(this->scroll_x, this->scroll_y, 0);
00643 
00644     int x = vp->virtual_left - pt.x;
00645     int y = vp->virtual_top - pt.y;
00646     int x2 = (x + vp->virtual_width) / TILE_SIZE;
00647     int y2 = (y + vp->virtual_height) / TILE_SIZE;
00648     x /= TILE_SIZE;
00649     y /= TILE_SIZE;
00650 
00651     x -= this->subscroll;
00652     x2 -= this->subscroll;
00653 
00654     SmallMapWindow::DrawVertMapIndicator(x, y, y2);
00655     SmallMapWindow::DrawVertMapIndicator(x2, y, y2);
00656 
00657     SmallMapWindow::DrawHorizMapIndicator(x, x2, y);
00658     SmallMapWindow::DrawHorizMapIndicator(x, x2, y2);
00659   }
00660 
00672   void DrawSmallMap(DrawPixelInfo *dpi) const
00673   {
00674     Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
00675     DrawPixelInfo *old_dpi;
00676 
00677     old_dpi = _cur_dpi;
00678     _cur_dpi = dpi;
00679 
00680     /* Clear it */
00681     GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, 0);
00682 
00683     /* Setup owner table */
00684     if (this->map_type == SMT_OWNER) {
00685       const Company *c;
00686 
00687       /* Fill with some special colours */
00688       _owner_colours[OWNER_TOWN]  = MKCOLOUR(0xB4B4B4B4);
00689       _owner_colours[OWNER_NONE]  = MKCOLOUR(0x54545454);
00690       _owner_colours[OWNER_WATER] = MKCOLOUR(0xCACACACA);
00691       _owner_colours[OWNER_END]   = MKCOLOUR(0x20202020); // Industry
00692 
00693       /* Now fill with the company colours */
00694       FOR_ALL_COMPANIES(c) {
00695         _owner_colours[c->index] = _colour_gradient[c->colour][5] * 0x01010101;
00696       }
00697     }
00698 
00699     int tile_x = this->scroll_x / TILE_SIZE;
00700     int tile_y = this->scroll_y / TILE_SIZE;
00701 
00702     int dx = dpi->left + this->subscroll;
00703     tile_x -= dx / 4;
00704     tile_y += dx / 4;
00705     dx &= 3;
00706 
00707     int dy = dpi->top;
00708     tile_x += dy / 2;
00709     tile_y += dy / 2;
00710 
00711     if (dy & 1) {
00712       tile_x++;
00713       dx += 2;
00714       if (dx > 3) {
00715         dx -= 4;
00716         tile_x--;
00717         tile_y++;
00718       }
00719     }
00720 
00721     void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0);
00722     int x = - dx - 4;
00723     int y = 0;
00724 
00725     for (;;) {
00726       uint32 mask = 0xFFFFFFFF;
00727 
00728       /* Distance from left edge */
00729       if (x >= -3) {
00730         if (x < 0) {
00731           /* Mask to use at the left edge */
00732           mask = _smallmap_mask_left[x + 3];
00733         }
00734 
00735         /* Distance from right edge */
00736         int t = dpi->width - x;
00737         if (t < 4) {
00738           if (t <= 0) break; // Exit loop
00739           /* Mask to use at the right edge */
00740           mask &= _smallmap_mask_right[t - 1];
00741         }
00742 
00743         /* Number of lines */
00744         int reps = (dpi->height - y + 1) / 2;
00745         if (reps > 0) {
00746           this->DrawSmallMapStuff(ptr, tile_x, tile_y, dpi->pitch * 2, reps, mask, blitter, _smallmap_draw_procs[this->map_type]);
00747         }
00748       }
00749 
00750       if (y == 0) {
00751         tile_y++;
00752         y++;
00753         ptr = blitter->MoveTo(ptr, 0, 1);
00754       } else {
00755         tile_x--;
00756         y--;
00757         ptr = blitter->MoveTo(ptr, 0, -1);
00758       }
00759       ptr = blitter->MoveTo(ptr, 2, 0);
00760       x += 2;
00761     }
00762 
00763     /* Draw vehicles */
00764     if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter);
00765 
00766     /* Draw town names */
00767     if (this->show_towns) this->DrawTowns(dpi);
00768 
00769     /* Draw map indicators */
00770     this->DrawMapIndicators();
00771 
00772     _cur_dpi = old_dpi;
00773   }
00774 
00775 public:
00776   SmallMapWindow(const WindowDesc *desc, int window_number) : Window(), refresh(FORCE_REFRESH_PERIOD)
00777   {
00778     this->InitNested(desc, window_number);
00779     this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
00780 
00781     _smallmap_industry_show_heightmap = false;
00782     this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_industry_show_heightmap);
00783 
00784     this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
00785     this->GetWidget<NWidgetStacked>(SM_WIDGET_SELECTINDUSTRIES)->SetDisplayedPlane(this->map_type != SMT_INDUSTRY);
00786 
00787     this->SmallMapCenterOnCurrentPos();
00788   }
00789 
00793   inline uint GetMaxLegendHeight() const
00794   {
00795     uint num_rows = max(this->min_number_of_fixed_rows, (_smallmap_industry_count + this->min_number_of_columns - 1) / this->min_number_of_columns);
00796     return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
00797   }
00798 
00802   inline uint GetMinLegendWidth() const
00803   {
00804     return WD_FRAMERECT_LEFT + this->min_number_of_columns * this->column_width;
00805   }
00806 
00810   inline uint GetNumberColumnsLegend(uint width) const
00811   {
00812     return width / this->column_width;
00813   }
00814 
00818   uint GetLegendHeight(uint width) const
00819   {
00820     uint num_columns = this->GetNumberColumnsLegend(width);
00821     uint num_rows = max(this->min_number_of_fixed_rows, (_smallmap_industry_count + num_columns - 1) / num_columns);
00822     return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
00823   }
00824 
00825   virtual void SetStringParameters(int widget) const
00826   {
00827     switch (widget) {
00828       case SM_WIDGET_CAPTION:
00829         SetDParam(0, STR_SMALLMAP_TYPE_CONTOURS + this->map_type);
00830         break;
00831     }
00832   }
00833 
00834   virtual void OnInit()
00835   {
00836     uint min_width = 0;
00837     this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS;
00838     this->min_number_of_fixed_rows = 0;
00839     for (uint i = 0; i < lengthof(_legend_table); i++) {
00840       uint height = 0;
00841       uint num_columns = 1;
00842       for (const LegendAndColour *tbl = _legend_table[i]; !tbl->end; ++tbl) {
00843         StringID str;
00844         if (i == SMT_INDUSTRY) {
00845           SetDParam(0, tbl->legend);
00846           SetDParam(1, IndustryPool::MAX_SIZE);
00847           str = STR_SMALLMAP_INDUSTRY;
00848         } else {
00849           if (tbl->col_break) {
00850             this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
00851             height = 0;
00852             num_columns++;
00853           }
00854           height++;
00855           str = tbl->legend;
00856         }
00857         min_width = max(GetStringBoundingBox(str).width, min_width);
00858       }
00859       this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
00860       this->min_number_of_columns = max(this->min_number_of_columns, num_columns);
00861     }
00862 
00863     /* The width of a column is the minimum width of all texts + the size of the blob + some spacing */
00864     this->column_width = min_width + LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
00865   }
00866 
00867   virtual void DrawWidget(const Rect &r, int widget) const
00868   {
00869     switch (widget) {
00870       case SM_WIDGET_MAP: {
00871         DrawPixelInfo new_dpi;
00872         if (!FillDrawPixelInfo(&new_dpi, r.left + 1, r.top + 1, r.right - r.left - 1, r.bottom - r.top - 1)) return;
00873         this->DrawSmallMap(&new_dpi);
00874       } break;
00875 
00876       case SM_WIDGET_LEGEND: {
00877         uint columns = this->GetNumberColumnsLegend(r.right - r.left + 1);
00878         uint number_of_rows = max(this->map_type == SMT_INDUSTRY ? (_smallmap_industry_count + columns - 1) / columns : 0, this->min_number_of_fixed_rows);
00879         bool rtl = _dynlang.text_dir == TD_RTL;
00880         uint y_org = r.top + WD_FRAMERECT_TOP;
00881         uint x = rtl ? r.right - this->column_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT;
00882         uint y = y_org;
00883         uint i = 0; // Row counter for industry legend.
00884         uint row_height = FONT_HEIGHT_SMALL;
00885 
00886         uint text_left  = rtl ? 0 : LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT;
00887         uint text_right = this->column_width - 1 - (rtl ? LEGEND_BLOB_WIDTH + WD_FRAMERECT_RIGHT : 0);
00888         uint blob_left  = rtl ? this->column_width - 1 - LEGEND_BLOB_WIDTH : 0;
00889         uint blob_right = rtl ? this->column_width - 1 : LEGEND_BLOB_WIDTH;
00890 
00891         for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) {
00892           if (tbl->col_break || (this->map_type == SMT_INDUSTRY && i++ >= number_of_rows)) {
00893             /* Column break needed, continue at top, COLUMN_WIDTH pixels
00894              * (one "row") to the right. */
00895             x += rtl ? -(int)this->column_width : this->column_width;
00896             y = y_org;
00897             i = 1;
00898           }
00899 
00900           if (this->map_type == SMT_INDUSTRY) {
00901             /* Industry name must be formatted, since it's not in tiny font in the specs.
00902              * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font */
00903             SetDParam(0, tbl->legend);
00904             assert(tbl->type < NUM_INDUSTRYTYPES);
00905             SetDParam(1, _industry_counts[tbl->type]);
00906             if (!tbl->show_on_map) {
00907               /* Simply draw the string, not the black border of the legend colour.
00908                * This will enforce the idea of the disabled item */
00909               DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_GREY);
00910             } else {
00911               DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_BLACK);
00912               GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0); // Outer border of the legend colour
00913             }
00914           } else {
00915             /* Anything that is not an industry is using normal process */
00916             GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0);
00917             DrawString(x + text_left, x + text_right, y, tbl->legend);
00918           }
00919           GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + row_height - 2, tbl->colour); // Legend colour
00920 
00921           y += row_height;
00922         }
00923       }
00924     }
00925   }
00926 
00927   virtual void OnPaint()
00928   {
00929     this->DrawWidgets();
00930   }
00931 
00932   virtual void OnClick(Point pt, int widget)
00933   {
00934     switch (widget) {
00935       case SM_WIDGET_MAP: { // Map window
00936         /*
00937          * XXX: scrolling with the left mouse button is done by subsequently
00938          * clicking with the left mouse button; clicking once centers the
00939          * large map at the selected point. So by unclicking the left mouse
00940          * button here, it gets reclicked during the next inputloop, which
00941          * would make it look like the mouse is being dragged, while it is
00942          * actually being (virtually) clicked every inputloop.
00943          */
00944         _left_button_clicked = false;
00945 
00946         Point pt = RemapCoords(this->scroll_x, this->scroll_y, 0);
00947         Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
00948         w->viewport->follow_vehicle = INVALID_VEHICLE;
00949         w->viewport->dest_scrollpos_x = pt.x + ((_cursor.pos.x - this->left + 2) << 4) - (w->viewport->virtual_width >> 1);
00950         w->viewport->dest_scrollpos_y = pt.y + ((_cursor.pos.y - this->top - 16) << 4) - (w->viewport->virtual_height >> 1);
00951 
00952         this->SetDirty();
00953       } break;
00954 
00955       case SM_WIDGET_CONTOUR:    // Show land contours
00956       case SM_WIDGET_VEHICLES:   // Show vehicles
00957       case SM_WIDGET_INDUSTRIES: // Show industries
00958       case SM_WIDGET_ROUTES:     // Show transport routes
00959       case SM_WIDGET_VEGETATION: // Show vegetation
00960       case SM_WIDGET_OWNERS:     // Show land owners
00961         this->RaiseWidget(this->map_type + SM_WIDGET_CONTOUR);
00962         this->map_type = (SmallMapType)(widget - SM_WIDGET_CONTOUR);
00963         this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
00964 
00965         /* Hide Enable all/Disable all buttons if is not industry type small map */
00966         this->GetWidget<NWidgetStacked>(SM_WIDGET_SELECTINDUSTRIES)->SetDisplayedPlane(this->map_type != SMT_INDUSTRY);
00967 
00968         this->SetDirty();
00969         SndPlayFx(SND_15_BEEP);
00970         break;
00971 
00972       case SM_WIDGET_CENTERMAP: // Center the smallmap again
00973         this->SmallMapCenterOnCurrentPos();
00974         this->HandleButtonClick(SM_WIDGET_CENTERMAP);
00975         SndPlayFx(SND_15_BEEP);
00976         break;
00977 
00978       case SM_WIDGET_TOGGLETOWNNAME: // Toggle town names
00979         this->show_towns = !this->show_towns;
00980         this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
00981 
00982         this->SetDirty();
00983         SndPlayFx(SND_15_BEEP);
00984         break;
00985 
00986       case SM_WIDGET_LEGEND: // Legend
00987         /* If industry type small map*/
00988         if (this->map_type == SMT_INDUSTRY) {
00989           /* If click on industries label, find right industry type and enable/disable it */
00990           const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_LEGEND); // Label panel
00991           uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL;
00992           uint columns = this->GetNumberColumnsLegend(wi->current_x);
00993           uint number_of_rows = max((_smallmap_industry_count + columns - 1) / columns, this->min_number_of_fixed_rows);
00994           if (line >= number_of_rows) break;
00995 
00996           bool rtl = _dynlang.text_dir == TD_RTL;
00997           int x = pt.x - wi->pos_x;
00998           if (rtl) x = wi->current_x - x;
00999           uint column = (x - WD_FRAMERECT_LEFT) / this->column_width;
01000 
01001           /* Check if click is on industry label*/
01002           int industry_pos = (column * number_of_rows) + line;
01003           if (industry_pos < _smallmap_industry_count) {
01004             _legend_from_industries[industry_pos].show_on_map = !_legend_from_industries[industry_pos].show_on_map;
01005           }
01006 
01007           /* Raise the two buttons "all", as we have done a specific choice */
01008           this->RaiseWidget(SM_WIDGET_ENABLEINDUSTRIES);
01009           this->RaiseWidget(SM_WIDGET_DISABLEINDUSTRIES);
01010           this->SetDirty();
01011         }
01012         break;
01013 
01014       case SM_WIDGET_ENABLEINDUSTRIES: // Enable all industries
01015         for (int i = 0; i != _smallmap_industry_count; i++) {
01016           _legend_from_industries[i].show_on_map = true;
01017         }
01018         /* Toggle appeareance indicating the choice */
01019         this->LowerWidget(SM_WIDGET_ENABLEINDUSTRIES);
01020         this->RaiseWidget(SM_WIDGET_DISABLEINDUSTRIES);
01021         this->SetDirty();
01022         break;
01023 
01024       case SM_WIDGET_DISABLEINDUSTRIES: // Disable all industries
01025         for (int i = 0; i != _smallmap_industry_count; i++) {
01026           _legend_from_industries[i].show_on_map = false;
01027         }
01028         /* Toggle appeareance indicating the choice */
01029         this->RaiseWidget(SM_WIDGET_ENABLEINDUSTRIES);
01030         this->LowerWidget(SM_WIDGET_DISABLEINDUSTRIES);
01031         this->SetDirty();
01032         break;
01033 
01034       case SM_WIDGET_SHOW_HEIGHT: // Enable/disable showing of heightmap.
01035         _smallmap_industry_show_heightmap = !_smallmap_industry_show_heightmap;
01036         this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_industry_show_heightmap);
01037         this->SetDirty();
01038         break;
01039     }
01040   }
01041 
01042   virtual void OnRightClick(Point pt, int widget)
01043   {
01044     if (widget == SM_WIDGET_MAP) {
01045       if (_scrolling_viewport) return;
01046       _scrolling_viewport = true;
01047     }
01048   }
01049 
01050   virtual void OnTick()
01051   {
01052     /* Update the window every now and then */
01053     if (--this->refresh != 0) return;
01054 
01055     this->refresh = FORCE_REFRESH_PERIOD;
01056     this->SetDirty();
01057   }
01058 
01059   virtual void OnScroll(Point delta)
01060   {
01061     _cursor.fix_at = true;
01062 
01063     int x = this->scroll_x;
01064     int y = this->scroll_y;
01065 
01066     int sub = this->subscroll + delta.x;
01067 
01068     x -= (sub >> 2) << 4;
01069     y += (sub >> 2) << 4;
01070     sub &= 3;
01071 
01072     x += (delta.y >> 1) << 4;
01073     y += (delta.y >> 1) << 4;
01074 
01075     if (delta.y & 1) {
01076       x += TILE_SIZE;
01077       sub += 2;
01078       if (sub > 3) {
01079         sub -= 4;
01080         x -= TILE_SIZE;
01081         y += TILE_SIZE;
01082       }
01083     }
01084 
01085     const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01086     int hx = wi->current_x / 2;
01087     int hy = wi->current_y / 2;
01088     int hvx = hx * -4 + hy * 8;
01089     int hvy = hx *  4 + hy * 8;
01090     if (x < -hvx) {
01091       x = -hvx;
01092       sub = 0;
01093     }
01094     if (x > (int)MapMaxX() * TILE_SIZE - hvx) {
01095       x = MapMaxX() * TILE_SIZE - hvx;
01096       sub = 0;
01097     }
01098     if (y < -hvy) {
01099       y = -hvy;
01100       sub = 0;
01101     }
01102     if (y > (int)MapMaxY() * TILE_SIZE - hvy) {
01103       y = MapMaxY() * TILE_SIZE - hvy;
01104       sub = 0;
01105     }
01106 
01107     this->scroll_x = x;
01108     this->scroll_y = y;
01109     this->subscroll = sub;
01110 
01111     this->SetDirty();
01112   }
01113 
01114   void SmallMapCenterOnCurrentPos()
01115   {
01116     const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
01117     const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01118 
01119     int x = ((vp->virtual_width  - (int)wi->current_x * TILE_SIZE) / 2 + vp->virtual_left) / 4;
01120     int y = ((vp->virtual_height - (int)wi->current_y * TILE_SIZE) / 2 + vp->virtual_top ) / 2 - TILE_SIZE * 2;
01121     this->scroll_x = (y - x) & ~0xF;
01122     this->scroll_y = (x + y) & ~0xF;
01123     this->SetDirty();
01124   }
01125 };
01126 
01127 SmallMapWindow::SmallMapType SmallMapWindow::map_type = SMT_CONTOUR;
01128 bool SmallMapWindow::show_towns = true;
01129 
01138 class NWidgetSmallmapDisplay : public NWidgetContainer {
01139   const SmallMapWindow *smallmap_window; 
01140 public:
01141   NWidgetSmallmapDisplay() : NWidgetContainer(NWID_VERTICAL)
01142   {
01143     this->smallmap_window = NULL;
01144   }
01145 
01146   virtual void SetupSmallestSize(Window *w, bool init_array)
01147   {
01148     NWidgetBase *display = this->head;
01149     NWidgetBase *bar = display->next;
01150 
01151     display->SetupSmallestSize(w, init_array);
01152     bar->SetupSmallestSize(w, init_array);
01153 
01154     this->smallmap_window = dynamic_cast<SmallMapWindow *>(w);
01155     this->smallest_x = max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth());
01156     this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetMaxLegendHeight());
01157     this->fill_x = max(display->fill_x, bar->fill_x);
01158     this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : min(display->fill_y, bar->fill_y);
01159     this->resize_x = max(display->resize_x, bar->resize_x);
01160     this->resize_y = min(display->resize_y, bar->resize_y);
01161   }
01162 
01163   virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01164   {
01165     this->pos_x = x;
01166     this->pos_y = y;
01167     this->current_x = given_width;
01168     this->current_y = given_height;
01169 
01170     NWidgetBase *display = this->head;
01171     NWidgetBase *bar = display->next;
01172 
01173     if (sizing == ST_SMALLEST) {
01174       this->smallest_x = given_width;
01175       this->smallest_y = given_height;
01176       /* Make display and bar exactly equal to their minimal size. */
01177       display->AssignSizePosition(ST_SMALLEST, x, y, display->smallest_x, display->smallest_y, rtl);
01178       bar->AssignSizePosition(ST_SMALLEST, x, y + display->smallest_y, bar->smallest_x, bar->smallest_y, rtl);
01179     }
01180 
01181     uint bar_height = max(bar->smallest_y, this->smallmap_window->GetLegendHeight(given_width - bar->smallest_x));
01182     uint display_height = given_height - bar_height;
01183     display->AssignSizePosition(ST_RESIZE, x, y, given_width, display_height, rtl);
01184     bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl);
01185   }
01186 
01187   virtual NWidgetCore *GetWidgetFromPos(int x, int y)
01188   {
01189     if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
01190     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01191       NWidgetCore *widget = child_wid->GetWidgetFromPos(x, y);
01192       if (widget != NULL) return widget;
01193     }
01194     return NULL;
01195   }
01196 
01197   virtual void Draw(const Window *w)
01198   {
01199     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) child_wid->Draw(w);
01200   }
01201 };
01202 
01204 static const NWidgetPart _nested_smallmap_display[] = {
01205   NWidget(WWT_PANEL, COLOUR_BROWN, SM_WIDGET_MAP_BORDER),
01206     NWidget(WWT_INSET, COLOUR_BROWN, SM_WIDGET_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(),
01207   EndContainer(),
01208 };
01209 
01211 static const NWidgetPart _nested_smallmap_bar[] = {
01212   NWidget(WWT_PANEL, COLOUR_BROWN),
01213     NWidget(NWID_HORIZONTAL),
01214       NWidget(WWT_EMPTY, INVALID_COLOUR, SM_WIDGET_LEGEND), SetResize(1, 1),
01215       NWidget(NWID_VERTICAL),
01216         /* Top button row. */
01217         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01218           NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_CENTERMAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER),
01219           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_CONTOUR), SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP),
01220           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEHICLES), SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP),
01221           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_INDUSTRIES), SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP),
01222         EndContainer(),
01223         /* Bottom button row. */
01224         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01225           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_TOGGLETOWNNAME), SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF),
01226           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_ROUTES), SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON),
01227           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEGETATION), SetDataTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP),
01228           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_OWNERS), SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP),
01229         EndContainer(),
01230         NWidget(NWID_SPACER), SetResize(0, 1),
01231       EndContainer(),
01232     EndContainer(),
01233   EndContainer(),
01234 };
01235 
01236 static NWidgetBase *SmallMapDisplay(int *biggest_index)
01237 {
01238   NWidgetContainer *map_display = new NWidgetSmallmapDisplay;
01239 
01240   MakeNWidgets(_nested_smallmap_display, lengthof(_nested_smallmap_display), biggest_index, map_display);
01241   MakeNWidgets(_nested_smallmap_bar, lengthof(_nested_smallmap_bar), biggest_index, map_display);
01242   return map_display;
01243 }
01244 
01245 
01246 static const NWidgetPart _nested_smallmap_widgets[] = {
01247   NWidget(NWID_HORIZONTAL),
01248     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
01249     NWidget(WWT_CAPTION, COLOUR_BROWN, SM_WIDGET_CAPTION), SetDataTip(STR_SMALLMAP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01250     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
01251     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
01252   EndContainer(),
01253   NWidgetFunction(SmallMapDisplay), // Smallmap display and legend bar + image buttons.
01254   /* Bottom button row and resize box. */
01255   NWidget(NWID_HORIZONTAL),
01256     NWidget(WWT_PANEL, COLOUR_BROWN),
01257       NWidget(NWID_HORIZONTAL),
01258         NWidget(NWID_SELECTION, INVALID_COLOUR, SM_WIDGET_SELECTINDUSTRIES),
01259           NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01260             NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_ENABLEINDUSTRIES), SetDataTip(STR_SMALLMAP_ENABLE_ALL, STR_SMALLMAP_TOOLTIP_ENABLE_ALL),
01261             NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_DISABLEINDUSTRIES), SetDataTip(STR_SMALLMAP_DISABLE_ALL, STR_SMALLMAP_TOOLTIP_DISABLE_ALL),
01262             NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_SHOW_HEIGHT), SetDataTip(STR_SMALLMAP_SHOW_HEIGHT, STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT),
01263           EndContainer(),
01264           NWidget(NWID_SPACER), SetFill(1, 1),
01265         EndContainer(),
01266         NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
01267       EndContainer(),
01268     EndContainer(),
01269     NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
01270   EndContainer(),
01271 };
01272 
01273 static const WindowDesc _smallmap_desc(
01274   WDP_AUTO, 446, 314,
01275   WC_SMALLMAP, WC_NONE,
01276   WDF_UNCLICK_BUTTONS,
01277   _nested_smallmap_widgets, lengthof(_nested_smallmap_widgets)
01278 );
01279 
01280 void ShowSmallMap()
01281 {
01282   AllocateWindowDescFront<SmallMapWindow>(&_smallmap_desc, 0);
01283 }
01284 
01293 bool ScrollMainWindowTo(int x, int y, int z, bool instant)
01294 {
01295   bool res = ScrollWindowTo(x, y, z, FindWindowById(WC_MAIN_WINDOW, 0), instant);
01296 
01297   /* If a user scrolls to a tile (via what way what so ever) and already is on
01298    * that tile (e.g.: pressed twice), move the smallmap to that location,
01299    * so you directly see where you are on the smallmap. */
01300 
01301   if (res) return res;
01302 
01303   SmallMapWindow *w = dynamic_cast<SmallMapWindow*>(FindWindowById(WC_SMALLMAP, 0));
01304   if (w != NULL) w->SmallMapCenterOnCurrentPos();
01305 
01306   return res;
01307 }

Generated on Wed Dec 30 20:40:06 2009 for OpenTTD by  doxygen 1.5.6