00001
00002
00003
00004
00005
00006
00007
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 #include "station_base.h"
00030 #include "company_func.h"
00031 #include "cargotype.h"
00032 #include "core/smallmap_type.hpp"
00033
00034 #include "table/strings.h"
00035
00037 enum SmallMapWindowWidgets {
00038 SM_WIDGET_CAPTION,
00039 SM_WIDGET_MAP_BORDER,
00040 SM_WIDGET_MAP,
00041 SM_WIDGET_LEGEND,
00042 SM_WIDGET_ZOOM_IN,
00043 SM_WIDGET_ZOOM_OUT,
00044 SM_WIDGET_CONTOUR,
00045 SM_WIDGET_VEHICLES,
00046 SM_WIDGET_INDUSTRIES,
00047 SM_WIDGET_ROUTE_LINKS,
00048 SM_WIDGET_ROUTES,
00049 SM_WIDGET_VEGETATION,
00050 SM_WIDGET_OWNERS,
00051 SM_WIDGET_CENTERMAP,
00052 SM_WIDGET_TOGGLETOWNNAME,
00053 SM_WIDGET_SELECT_BUTTONS,
00054 SM_WIDGET_ENABLE_ALL,
00055 SM_WIDGET_DISABLE_ALL,
00056 SM_WIDGET_SHOW_HEIGHT,
00057 };
00058
00059 static int _smallmap_industry_count;
00060 static int _smallmap_company_count;
00061 static int _smallmap_cargo_count;
00062
00063 static const int NUM_NO_COMPANY_ENTRIES = 4;
00064
00065 static const uint8 PC_ROUGH_LAND = 0x52;
00066 static const uint8 PC_GRASS_LAND = 0x54;
00067 static const uint8 PC_BARE_LAND = 0x37;
00068 static const uint8 PC_FIELDS = 0x25;
00069 static const uint8 PC_TREES = 0x57;
00070 static const uint8 PC_WATER = 0xCA;
00071
00073 #define MK(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, false}
00074
00076 #define MC(height) {0, STR_TINY_BLACK_HEIGHT, INVALID_INDUSTRYTYPE, height, INVALID_COMPANY, true, false, false}
00077
00079 #define MO(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, false}
00080
00082 #define MOEND() {0, 0, INVALID_INDUSTRYTYPE, 0, OWNER_NONE, true, true, false}
00083
00085 #define MKEND() {0, STR_NULL, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, true, false}
00086
00091 #define MS(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, true}
00092
00094 struct LegendAndColour {
00095 uint8 colour;
00096 StringID legend;
00097 IndustryType type;
00098 uint8 height;
00099 CompanyID company;
00100 CargoID cid;
00101 bool show_on_map;
00102 bool end;
00103 bool col_break;
00104 };
00105
00107 static LegendAndColour _legend_land_contours[] = {
00108
00109 MC(0),
00110 MC(4),
00111 MC(8),
00112 MC(12),
00113 MC(14),
00114
00115 MS(PC_BLACK, STR_SMALLMAP_LEGENDA_ROADS),
00116 MK(PC_GREY, STR_SMALLMAP_LEGENDA_RAILROADS),
00117 MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS),
00118 MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00119 MK(PC_WHITE, STR_SMALLMAP_LEGENDA_VEHICLES),
00120 MKEND()
00121 };
00122
00123 static const LegendAndColour _legend_vehicles[] = {
00124 MK(PC_RED, STR_SMALLMAP_LEGENDA_TRAINS),
00125 MK(PC_YELLOW, STR_SMALLMAP_LEGENDA_ROAD_VEHICLES),
00126 MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_SHIPS),
00127 MK(PC_WHITE, STR_SMALLMAP_LEGENDA_AIRCRAFT),
00128
00129 MS(PC_BLACK, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES),
00130 MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00131 MKEND()
00132 };
00133
00134 static const LegendAndColour _legend_routes[] = {
00135 MK(PC_BLACK, STR_SMALLMAP_LEGENDA_ROADS),
00136 MK(PC_GREY, STR_SMALLMAP_LEGENDA_RAILROADS),
00137 MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00138
00139 MS(PC_VERY_DARK_BROWN, STR_SMALLMAP_LEGENDA_RAILROAD_STATION),
00140 MK(PC_ORANGE, STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY),
00141 MK(PC_YELLOW, STR_SMALLMAP_LEGENDA_BUS_STATION),
00142 MK(PC_RED, STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT),
00143 MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_DOCK),
00144 MKEND()
00145 };
00146
00147 static const LegendAndColour _legend_vegetation[] = {
00148 MK(PC_ROUGH_LAND, STR_SMALLMAP_LEGENDA_ROUGH_LAND),
00149 MK(PC_GRASS_LAND, STR_SMALLMAP_LEGENDA_GRASS_LAND),
00150 MK(PC_BARE_LAND, STR_SMALLMAP_LEGENDA_BARE_LAND),
00151 MK(PC_FIELDS, STR_SMALLMAP_LEGENDA_FIELDS),
00152 MK(PC_TREES, STR_SMALLMAP_LEGENDA_TREES),
00153 MK(PC_GREEN, STR_SMALLMAP_LEGENDA_FOREST),
00154
00155 MS(PC_GREY, STR_SMALLMAP_LEGENDA_ROCKS),
00156 MK(PC_ORANGE, STR_SMALLMAP_LEGENDA_DESERT),
00157 MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_SNOW),
00158 MK(PC_BLACK, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES),
00159 MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00160 MKEND()
00161 };
00162
00163 static LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1] = {
00164 MO(PC_WATER, STR_SMALLMAP_LEGENDA_WATER),
00165 MO(0x00, STR_SMALLMAP_LEGENDA_NO_OWNER),
00166 MO(PC_DARK_RED, STR_SMALLMAP_LEGENDA_TOWNS),
00167 MO(PC_DARK_GREY, STR_SMALLMAP_LEGENDA_INDUSTRIES),
00168
00169 MOEND(),
00170 };
00171
00172 #undef MK
00173 #undef MC
00174 #undef MS
00175 #undef MO
00176 #undef MOEND
00177 #undef MKEND
00178
00183 static LegendAndColour _legend_from_industries[NUM_INDUSTRYTYPES + 1];
00185 static uint _industry_to_list_pos[NUM_INDUSTRYTYPES];
00187 static LegendAndColour _legend_from_cargoes[NUM_CARGO + 1];
00189 static uint _cargotype_to_list_pos[NUM_CARGO];
00191 static bool _smallmap_show_heightmap = false;
00193 static uint _company_to_list_pos[MAX_COMPANIES];
00194
00198 void BuildIndustriesLegend()
00199 {
00200 uint j = 0;
00201
00202
00203 for (uint8 i = 0; i < NUM_INDUSTRYTYPES; i++) {
00204 IndustryType ind = _sorted_industry_types[i];
00205 const IndustrySpec *indsp = GetIndustrySpec(ind);
00206 if (indsp->enabled) {
00207 _legend_from_industries[j].legend = indsp->name;
00208 _legend_from_industries[j].colour = indsp->map_colour;
00209 _legend_from_industries[j].type = ind;
00210 _legend_from_industries[j].show_on_map = true;
00211 _legend_from_industries[j].col_break = false;
00212 _legend_from_industries[j].end = false;
00213
00214
00215 _industry_to_list_pos[ind] = j;
00216 j++;
00217 }
00218 }
00219
00220 _legend_from_industries[j].end = true;
00221
00222
00223 _smallmap_industry_count = j;
00224 }
00225
00227 void BuildCargoTypesLegend()
00228 {
00229 uint j = 0;
00230
00231
00232 const CargoSpec *cs;
00233 FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
00234 _legend_from_cargoes[j].legend = cs->name;
00235 _legend_from_cargoes[j].colour = cs->legend_colour;
00236 _legend_from_cargoes[j].cid = cs->Index();
00237 _legend_from_cargoes[j].show_on_map = true;
00238 _legend_from_cargoes[j].col_break = false;
00239 _legend_from_cargoes[j].end = false;
00240
00241
00242 _cargotype_to_list_pos[cs->Index()] = j;
00243 j++;
00244 }
00245
00246
00247 _legend_from_cargoes[j].end = true;
00248
00249
00250 _smallmap_cargo_count = j;
00251 }
00252
00253 static const LegendAndColour * const _legend_table[] = {
00254 _legend_land_contours,
00255 _legend_vehicles,
00256 _legend_from_industries,
00257 _legend_from_cargoes,
00258 _legend_routes,
00259 _legend_vegetation,
00260 _legend_land_owners,
00261 };
00262
00263 #define MKCOLOUR(x) TO_LE32X(x)
00264
00265 #define MKCOLOUR_XXXX(x) (MKCOLOUR(0x01010101) * (uint)(x))
00266 #define MKCOLOUR_X0X0(x) (MKCOLOUR(0x01000100) * (uint)(x))
00267 #define MKCOLOUR_0X0X(x) (MKCOLOUR(0x00010001) * (uint)(x))
00268 #define MKCOLOUR_0XX0(x) (MKCOLOUR(0x00010100) * (uint)(x))
00269 #define MKCOLOUR_X00X(x) (MKCOLOUR(0x01000001) * (uint)(x))
00270
00271 #define MKCOLOUR_XYXY(x, y) (MKCOLOUR_X0X0(x) | MKCOLOUR_0X0X(y))
00272 #define MKCOLOUR_XYYX(x, y) (MKCOLOUR_X00X(x) | MKCOLOUR_0XX0(y))
00273
00274 #define MKCOLOUR_0000 MKCOLOUR_XXXX(0x00)
00275 #define MKCOLOUR_0FF0 MKCOLOUR_0XX0(0xFF)
00276 #define MKCOLOUR_F00F MKCOLOUR_X00X(0xFF)
00277 #define MKCOLOUR_FFFF MKCOLOUR_XXXX(0xFF)
00278
00280 static const uint32 _green_map_heights[] = {
00281 MKCOLOUR_XXXX(0x5A),
00282 MKCOLOUR_XYXY(0x5A, 0x5B),
00283 MKCOLOUR_XXXX(0x5B),
00284 MKCOLOUR_XYXY(0x5B, 0x5C),
00285 MKCOLOUR_XXXX(0x5C),
00286 MKCOLOUR_XYXY(0x5C, 0x5D),
00287 MKCOLOUR_XXXX(0x5D),
00288 MKCOLOUR_XYXY(0x5D, 0x5E),
00289 MKCOLOUR_XXXX(0x5E),
00290 MKCOLOUR_XYXY(0x5E, 0x5F),
00291 MKCOLOUR_XXXX(0x5F),
00292 MKCOLOUR_XYXY(0x5F, 0x1F),
00293 MKCOLOUR_XXXX(0x1F),
00294 MKCOLOUR_XYXY(0x1F, 0x27),
00295 MKCOLOUR_XXXX(0x27),
00296 MKCOLOUR_XXXX(0x27),
00297 };
00298 assert_compile(lengthof(_green_map_heights) == MAX_TILE_HEIGHT + 1);
00299
00301 static const uint32 _dark_green_map_heights[] = {
00302 MKCOLOUR_XXXX(0x60),
00303 MKCOLOUR_XYXY(0x60, 0x61),
00304 MKCOLOUR_XXXX(0x61),
00305 MKCOLOUR_XYXY(0x61, 0x62),
00306 MKCOLOUR_XXXX(0x62),
00307 MKCOLOUR_XYXY(0x62, 0x63),
00308 MKCOLOUR_XXXX(0x63),
00309 MKCOLOUR_XYXY(0x63, 0x64),
00310 MKCOLOUR_XXXX(0x64),
00311 MKCOLOUR_XYXY(0x64, 0x65),
00312 MKCOLOUR_XXXX(0x65),
00313 MKCOLOUR_XYXY(0x65, 0x66),
00314 MKCOLOUR_XXXX(0x66),
00315 MKCOLOUR_XYXY(0x66, 0x67),
00316 MKCOLOUR_XXXX(0x67),
00317 MKCOLOUR_XXXX(0x67),
00318 };
00319 assert_compile(lengthof(_dark_green_map_heights) == MAX_TILE_HEIGHT + 1);
00320
00322 static const uint32 _violet_map_heights[] = {
00323 MKCOLOUR_XXXX(0x80),
00324 MKCOLOUR_XYXY(0x80, 0x81),
00325 MKCOLOUR_XXXX(0x81),
00326 MKCOLOUR_XYXY(0x81, 0x82),
00327 MKCOLOUR_XXXX(0x82),
00328 MKCOLOUR_XYXY(0x82, 0x83),
00329 MKCOLOUR_XXXX(0x83),
00330 MKCOLOUR_XYXY(0x83, 0x84),
00331 MKCOLOUR_XXXX(0x84),
00332 MKCOLOUR_XYXY(0x84, 0x85),
00333 MKCOLOUR_XXXX(0x85),
00334 MKCOLOUR_XYXY(0x85, 0x86),
00335 MKCOLOUR_XXXX(0x86),
00336 MKCOLOUR_XYXY(0x86, 0x87),
00337 MKCOLOUR_XXXX(0x87),
00338 MKCOLOUR_XXXX(0x87),
00339 };
00340 assert_compile(lengthof(_violet_map_heights) == MAX_TILE_HEIGHT + 1);
00341
00343 struct SmallMapColourScheme {
00344 const uint32 *height_colours;
00345 uint32 default_colour;
00346 };
00347
00349 static const SmallMapColourScheme _heightmap_schemes[] = {
00350 {_green_map_heights, MKCOLOUR_XXXX(0x54)},
00351 {_dark_green_map_heights, MKCOLOUR_XXXX(0x62)},
00352 {_violet_map_heights, MKCOLOUR_XXXX(0x82)},
00353 };
00354
00358 void BuildLandLegend()
00359 {
00360 for (LegendAndColour *lc = _legend_land_contours; lc->legend == STR_TINY_BLACK_HEIGHT; lc++) {
00361 lc->colour = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].height_colours[lc->height];
00362 }
00363 }
00364
00368 void BuildOwnerLegend()
00369 {
00370 _legend_land_owners[1].colour = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].default_colour;
00371
00372 int i = NUM_NO_COMPANY_ENTRIES;
00373 const Company *c;
00374 FOR_ALL_COMPANIES(c) {
00375 _legend_land_owners[i].colour = _colour_gradient[c->colour][5];
00376 _legend_land_owners[i].company = c->index;
00377 _legend_land_owners[i].show_on_map = true;
00378 _legend_land_owners[i].col_break = false;
00379 _legend_land_owners[i].end = false;
00380 _company_to_list_pos[c->index] = i;
00381 i++;
00382 }
00383
00384
00385 _legend_land_owners[i].end = true;
00386
00387
00388 _smallmap_company_count = i;
00389 }
00390
00391 struct AndOr {
00392 uint32 mor;
00393 uint32 mand;
00394 };
00395
00396 static inline uint32 ApplyMask(uint32 colour, const AndOr *mask)
00397 {
00398 return (colour & mask->mand) | mask->mor;
00399 }
00400
00401
00403 static const AndOr _smallmap_contours_andor[] = {
00404 {MKCOLOUR_0000 , MKCOLOUR_FFFF},
00405 {MKCOLOUR_0XX0(PC_GREY ), MKCOLOUR_F00F},
00406 {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F},
00407 {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F},
00408 {MKCOLOUR_0000 , MKCOLOUR_FFFF},
00409 {MKCOLOUR_XXXX(PC_LIGHT_BLUE), MKCOLOUR_0000},
00410 {MKCOLOUR_XXXX(PC_WATER ), MKCOLOUR_0000},
00411 {MKCOLOUR_0000 , MKCOLOUR_FFFF},
00412 {MKCOLOUR_XXXX(PC_DARK_RED ), MKCOLOUR_0000},
00413 {MKCOLOUR_0000 , MKCOLOUR_FFFF},
00414 {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F},
00415 {MKCOLOUR_0XX0(PC_GREY ), MKCOLOUR_F00F},
00416 };
00417
00419 static const AndOr _smallmap_vehicles_andor[] = {
00420 {MKCOLOUR_0000 , MKCOLOUR_FFFF},
00421 {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F},
00422 {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F},
00423 {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F},
00424 {MKCOLOUR_0000 , MKCOLOUR_FFFF},
00425 {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F},
00426 {MKCOLOUR_XXXX(PC_WATER ), MKCOLOUR_0000},
00427 {MKCOLOUR_0000 , MKCOLOUR_FFFF},
00428 {MKCOLOUR_XXXX(PC_DARK_RED ), MKCOLOUR_0000},
00429 {MKCOLOUR_0000 , MKCOLOUR_FFFF},
00430 {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F},
00431 {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F},
00432 };
00433
00435 static const byte _tiletype_importance[] = {
00436 2,
00437 8,
00438 7,
00439 5,
00440 2,
00441 9,
00442 2,
00443 1,
00444 6,
00445 8,
00446 2,
00447 0,
00448 };
00449
00450
00451 static inline TileType GetEffectiveTileType(TileIndex tile)
00452 {
00453 TileType t = GetTileType(tile);
00454
00455 if (t == MP_TUNNELBRIDGE) {
00456 TransportType tt = GetTunnelBridgeTransportType(tile);
00457
00458 switch (tt) {
00459 case TRANSPORT_RAIL: t = MP_RAILWAY; break;
00460 case TRANSPORT_ROAD: t = MP_ROAD; break;
00461 default: t = MP_WATER; break;
00462 }
00463 }
00464 return t;
00465 }
00466
00473 static inline uint32 GetSmallMapContoursPixels(TileIndex tile, TileType t)
00474 {
00475 const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00476 return ApplyMask(cs->height_colours[TileHeight(tile)], &_smallmap_contours_andor[t]);
00477 }
00478
00486 static inline uint32 GetSmallMapVehiclesPixels(TileIndex tile, TileType t)
00487 {
00488 const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00489 return ApplyMask(cs->default_colour, &_smallmap_vehicles_andor[t]);
00490 }
00491
00499 static inline uint32 GetSmallMapIndustriesPixels(TileIndex tile, TileType t)
00500 {
00501 if (t == MP_INDUSTRY) {
00502
00503 if (_legend_from_industries[_industry_to_list_pos[Industry::GetByTile(tile)->type]].show_on_map) {
00504 return GetIndustrySpec(Industry::GetByTile(tile)->type)->map_colour * 0x01010101;
00505 } else {
00506
00507 t = (IsTileOnWater(tile) ? MP_WATER : MP_CLEAR);
00508 }
00509 }
00510
00511 const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00512 return ApplyMask(_smallmap_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour, &_smallmap_vehicles_andor[t]);
00513 }
00514
00523 static inline uint32 GetSmallMapRoutesPixels(TileIndex tile, TileType t, bool show_height = false)
00524 {
00525 if (t == MP_STATION) {
00526 switch (GetStationType(tile)) {
00527 case STATION_RAIL: return MKCOLOUR_XXXX(PC_VERY_DARK_BROWN);
00528 case STATION_AIRPORT: return MKCOLOUR_XXXX(PC_RED);
00529 case STATION_TRUCK: return MKCOLOUR_XXXX(PC_ORANGE);
00530 case STATION_BUS: return MKCOLOUR_XXXX(PC_YELLOW);
00531 case STATION_DOCK: return MKCOLOUR_XXXX(PC_LIGHT_BLUE);
00532 default: return MKCOLOUR_FFFF;
00533 }
00534 } else if (t == MP_RAILWAY) {
00535 AndOr andor = {
00536 MKCOLOUR_0XX0(GetRailTypeInfo(GetRailType(tile))->map_colour),
00537 _smallmap_contours_andor[t].mand
00538 };
00539
00540 const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00541 return ApplyMask(cs->default_colour, &andor);
00542 }
00543
00544
00545 const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00546 return ApplyMask(show_height ? cs->height_colours[TileHeight(tile)] : cs->default_colour, &_smallmap_contours_andor[t]);
00547 }
00548
00549
00550 static const uint32 _vegetation_clear_bits[] = {
00551 MKCOLOUR_XXXX(PC_GRASS_LAND),
00552 MKCOLOUR_XXXX(PC_ROUGH_LAND),
00553 MKCOLOUR_XXXX(PC_GREY),
00554 MKCOLOUR_XXXX(PC_FIELDS),
00555 MKCOLOUR_XXXX(PC_LIGHT_BLUE),
00556 MKCOLOUR_XXXX(PC_ORANGE),
00557 MKCOLOUR_XXXX(PC_GRASS_LAND),
00558 MKCOLOUR_XXXX(PC_GRASS_LAND),
00559 };
00560
00568 static inline uint32 GetSmallMapVegetationPixels(TileIndex tile, TileType t)
00569 {
00570 switch (t) {
00571 case MP_CLEAR:
00572 return (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) < 3) ? MKCOLOUR_XXXX(PC_BARE_LAND) : _vegetation_clear_bits[GetClearGround(tile)];
00573
00574 case MP_INDUSTRY:
00575 return GetIndustrySpec(Industry::GetByTile(tile)->type)->check_proc == CHECK_FOREST ? MKCOLOUR_XXXX(PC_GREEN) : MKCOLOUR_XXXX(PC_DARK_RED);
00576
00577 case MP_TREES:
00578 if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT || GetTreeGround(tile) == TREE_GROUND_ROUGH_SNOW) {
00579 return (_settings_game.game_creation.landscape == LT_ARCTIC) ? MKCOLOUR_XYYX(PC_LIGHT_BLUE, PC_TREES) : MKCOLOUR_XYYX(PC_ORANGE, PC_TREES);
00580 }
00581 return MKCOLOUR_XYYX(PC_GRASS_LAND, PC_TREES);
00582
00583 default:
00584 return ApplyMask(MKCOLOUR_XXXX(PC_GRASS_LAND), &_smallmap_vehicles_andor[t]);
00585 }
00586 }
00587
00595 static inline uint32 GetSmallMapOwnerPixels(TileIndex tile, TileType t)
00596 {
00597 Owner o;
00598
00599 switch (t) {
00600 case MP_INDUSTRY: return MKCOLOUR_XXXX(PC_DARK_GREY);
00601 case MP_HOUSE: return MKCOLOUR_XXXX(PC_DARK_RED);
00602 default: o = GetTileOwner(tile); break;
00603
00604
00605
00606
00607 }
00608
00609 if ((o < MAX_COMPANIES && !_legend_land_owners[_company_to_list_pos[o]].show_on_map) || o == OWNER_NONE || o == OWNER_WATER) {
00610 if (t == MP_WATER) return MKCOLOUR_XXXX(PC_WATER);
00611 const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00612 return _smallmap_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour;
00613 } else if (o == OWNER_TOWN) {
00614 return MKCOLOUR_XXXX(PC_DARK_RED);
00615 }
00616
00617 return MKCOLOUR_XXXX(_legend_land_owners[_company_to_list_pos[o]].colour);
00618 }
00619
00621 static const byte _vehicle_type_colours[6] = {
00622 PC_RED, PC_YELLOW, PC_LIGHT_BLUE, PC_WHITE, PC_BLACK, PC_RED
00623 };
00624
00625
00627 class SmallMapWindow : public Window {
00629 enum SmallMapType {
00630 SMT_CONTOUR,
00631 SMT_VEHICLES,
00632 SMT_INDUSTRY,
00633 SMT_ROUTE_LINKS,
00634 SMT_ROUTES,
00635 SMT_VEGETATION,
00636 SMT_OWNER,
00637 };
00638
00640 enum ZoomLevelChange {
00641 ZLC_INITIALIZE,
00642 ZLC_ZOOM_OUT,
00643 ZLC_ZOOM_IN,
00644 };
00645
00646 static SmallMapType map_type;
00647 static bool show_towns;
00648
00649 static const uint LEGEND_BLOB_WIDTH = 8;
00650 static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2;
00651 uint min_number_of_fixed_rows;
00652 uint column_width;
00653
00654 int32 scroll_x;
00655 int32 scroll_y;
00656 int32 subscroll;
00657 int zoom;
00658
00659 static const uint8 FORCE_REFRESH_PERIOD = 0x1F;
00660 uint8 refresh;
00661
00668 FORCEINLINE Point RemapTile(int tile_x, int tile_y) const
00669 {
00670 int x_offset = tile_x - this->scroll_x / (int)TILE_SIZE;
00671 int y_offset = tile_y - this->scroll_y / (int)TILE_SIZE;
00672
00673 if (this->zoom == 1) return RemapCoords(x_offset, y_offset, 0);
00674
00675
00676 if (x_offset < 0) x_offset -= this->zoom - 1;
00677 if (y_offset < 0) y_offset -= this->zoom - 1;
00678
00679 return RemapCoords(x_offset / this->zoom, y_offset / this->zoom, 0);
00680 }
00681
00692 FORCEINLINE Point PixelToTile(int px, int py, int *sub, bool add_sub = true) const
00693 {
00694 if (add_sub) px += this->subscroll;
00695
00696
00697
00698 Point pt = {((py >> 1) - (px >> 2)) * this->zoom, ((py >> 1) + (px >> 2)) * this->zoom};
00699 px &= 3;
00700
00701 if (py & 1) {
00702 if (px < 2) {
00703 pt.x += this->zoom;
00704 px += 2;
00705 } else {
00706 pt.y += this->zoom;
00707 px -= 2;
00708 }
00709 }
00710
00711 *sub = px;
00712 return pt;
00713 }
00714
00724 Point ComputeScroll(int tx, int ty, int x, int y, int *sub)
00725 {
00726 assert(x >= 0 && y >= 0);
00727
00728 int new_sub;
00729 Point tile_xy = PixelToTile(x, y, &new_sub, false);
00730 tx -= tile_xy.x;
00731 ty -= tile_xy.y;
00732
00733 Point scroll;
00734 if (new_sub == 0) {
00735 *sub = 0;
00736 scroll.x = (tx + this->zoom) * TILE_SIZE;
00737 scroll.y = (ty - this->zoom) * TILE_SIZE;
00738 } else {
00739 *sub = 4 - new_sub;
00740 scroll.x = (tx + 2 * this->zoom) * TILE_SIZE;
00741 scroll.y = (ty - 2 * this->zoom) * TILE_SIZE;
00742 }
00743 return scroll;
00744 }
00745
00752 void SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt)
00753 {
00754 static const int zoomlevels[] = {1, 2, 4, 6, 8};
00755 static const int MIN_ZOOM_INDEX = 0;
00756 static const int MAX_ZOOM_INDEX = lengthof(zoomlevels) - 1;
00757
00758 int new_index, cur_index, sub;
00759 Point tile;
00760 switch (change) {
00761 case ZLC_INITIALIZE:
00762 cur_index = - 1;
00763 new_index = MIN_ZOOM_INDEX;
00764 break;
00765
00766 case ZLC_ZOOM_IN:
00767 case ZLC_ZOOM_OUT:
00768 for (cur_index = MIN_ZOOM_INDEX; cur_index <= MAX_ZOOM_INDEX; cur_index++) {
00769 if (this->zoom == zoomlevels[cur_index]) break;
00770 }
00771 assert(cur_index <= MAX_ZOOM_INDEX);
00772
00773 tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub);
00774 new_index = Clamp(cur_index + ((change == ZLC_ZOOM_IN) ? -1 : 1), MIN_ZOOM_INDEX, MAX_ZOOM_INDEX);
00775 break;
00776
00777 default: NOT_REACHED();
00778 }
00779
00780 if (new_index != cur_index) {
00781 this->zoom = zoomlevels[new_index];
00782 if (cur_index >= 0) {
00783 Point new_tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub);
00784 this->SetNewScroll(this->scroll_x + (tile.x - new_tile.x) * TILE_SIZE,
00785 this->scroll_y + (tile.y - new_tile.y) * TILE_SIZE, sub);
00786 }
00787 this->SetWidgetDisabledState(SM_WIDGET_ZOOM_IN, this->zoom == zoomlevels[MIN_ZOOM_INDEX]);
00788 this->SetWidgetDisabledState(SM_WIDGET_ZOOM_OUT, this->zoom == zoomlevels[MAX_ZOOM_INDEX]);
00789 this->SetDirty();
00790 }
00791 }
00792
00798 inline uint32 GetTileColours(const TileArea &ta) const
00799 {
00800 int importance = 0;
00801 TileIndex tile = INVALID_TILE;
00802 TileType et = MP_VOID;
00803
00804 TILE_AREA_LOOP(ti, ta) {
00805 TileType ttype = GetEffectiveTileType(ti);
00806 if (_tiletype_importance[ttype] > importance) {
00807 importance = _tiletype_importance[ttype];
00808 tile = ti;
00809 et = ttype;
00810 }
00811 }
00812
00813 switch (this->map_type) {
00814 case SMT_CONTOUR:
00815 return GetSmallMapContoursPixels(tile, et);
00816
00817 case SMT_VEHICLES:
00818 return GetSmallMapVehiclesPixels(tile, et);
00819
00820 case SMT_INDUSTRY:
00821 return GetSmallMapIndustriesPixels(tile, et);
00822
00823 case SMT_ROUTE_LINKS:
00824 return GetSmallMapRoutesPixels(tile, et, _smallmap_show_heightmap);
00825
00826 case SMT_ROUTES:
00827 return GetSmallMapRoutesPixels(tile, et);
00828
00829 case SMT_VEGETATION:
00830 return GetSmallMapVegetationPixels(tile, et);
00831
00832 case SMT_OWNER:
00833 return GetSmallMapOwnerPixels(tile, et);
00834
00835 default: NOT_REACHED();
00836 }
00837 }
00838
00853 void DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const
00854 {
00855 void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height);
00856 uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0;
00857
00858 do {
00859
00860 if (xc >= MapMaxX() || yc >= MapMaxY()) continue;
00861
00862
00863 if (dst < _screen.dst_ptr) continue;
00864 if (dst >= dst_ptr_abs_end) continue;
00865
00866
00867 TileArea ta;
00868 if (min_xy == 1 && (xc == 0 || yc == 0)) {
00869 if (this->zoom == 1) continue;
00870
00871 ta = TileArea(TileXY(max(min_xy, xc), max(min_xy, yc)), this->zoom - (xc == 0), this->zoom - (yc == 0));
00872 } else {
00873 ta = TileArea(TileXY(xc, yc), this->zoom, this->zoom);
00874 }
00875 ta.ClampToMap();
00876
00877 uint32 val = this->GetTileColours(ta);
00878 uint8 *val8 = (uint8 *)&val;
00879 int idx = max(0, -start_pos);
00880 for (int pos = max(0, start_pos); pos < end_pos; pos++) {
00881 blitter->SetPixel(dst, idx, 0, val8[idx]);
00882 idx++;
00883 }
00884
00885 } while (xc += this->zoom, yc += this->zoom, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0);
00886 }
00887
00893 void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const
00894 {
00895 const Vehicle *v;
00896 FOR_ALL_VEHICLES(v) {
00897 if (v->type == VEH_EFFECT) continue;
00898 if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue;
00899
00900
00901 Point pt = this->RemapTile(v->x_pos / TILE_SIZE, v->y_pos / TILE_SIZE);
00902
00903 int y = pt.y - dpi->top;
00904 if (!IsInsideMM(y, 0, dpi->height)) continue;
00905
00906 bool skip = false;
00907 int x = pt.x - this->subscroll - 3 - dpi->left;
00908 if (x < 0) {
00909
00910
00911 if (++x != 0) continue;
00912 skip = true;
00913 } else if (x >= dpi->width - 1) {
00914
00915 if (x != dpi->width - 1) continue;
00916 skip = true;
00917 }
00918
00919
00920 byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : PC_WHITE;
00921
00922
00923 blitter->SetPixel(dpi->dst_ptr, x, y, colour);
00924 if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour);
00925 }
00926 }
00927
00932 void DrawTowns(const DrawPixelInfo *dpi) const
00933 {
00934 const Town *t;
00935 FOR_ALL_TOWNS(t) {
00936
00937 Point pt = this->RemapTile(TileX(t->xy), TileY(t->xy));
00938 int x = pt.x - this->subscroll - (t->sign.width_small >> 1);
00939 int y = pt.y;
00940
00941
00942 if (x + t->sign.width_small > dpi->left &&
00943 x < dpi->left + dpi->width &&
00944 y + FONT_HEIGHT_SMALL > dpi->top &&
00945 y < dpi->top + dpi->height) {
00946
00947 SetDParam(0, t->index);
00948 DrawString(x, x + t->sign.width_small, y, STR_SMALLMAP_TOWN);
00949 }
00950 }
00951 }
00952
00956 void DrawRouteLinks() const
00957 {
00958
00959 for (int i = 0; i < _smallmap_cargo_count; i++) {
00960 if (_legend_from_cargoes[i].show_on_map) {
00961 CargoID cid = _legend_from_cargoes[i].cid;
00962
00963
00964 const Station *st;
00965 FOR_ALL_STATIONS(st) {
00966 Point src_pt = this->RemapTile(TileX(st->xy), TileY(st->xy));
00967 src_pt.x -= this->subscroll;
00968
00969
00970 std::map<StationID, uint> links;
00971 for (RouteLinkList::const_iterator l = st->goods[cid].routes.begin(); l != st->goods[cid].routes.end(); ++l) {
00972 if (IsInteractiveCompany((*l)->GetOwner())) links[(*l)->GetDestination()] += st->goods[cid].cargo.CountForNextHop((*l)->GetOriginOrderId());
00973 }
00974
00975
00976 for (std::map<StationID, uint>::iterator itr = links.begin(); itr != links.end(); ++itr) {
00977
00978 const Station *dest = Station::Get(itr->first);
00979 Point dest_pt = this->RemapTile(TileX(dest->xy), TileY(dest->xy));
00980 dest_pt.x -= this->subscroll;
00981
00982
00983 uint count = itr->second;
00984 for (RouteLinkList::const_iterator j = dest->goods[cid].routes.begin(); j != dest->goods[cid].routes.end(); ++j) {
00985 if ((*j)->GetDestination() == st->index && IsInteractiveCompany((*j)->GetOwner())) count += dest->goods[cid].cargo.CountForNextHop((*j)->GetOriginOrderId());
00986 }
00987
00988
00989 int size = 1;
00990 if (count >= 400) size++;
00991 if (count >= 800) size++;
00992 if (count >= 1600) size++;
00993 if (count >= 3200) size++;
00994
00995
00996 GfxDrawLine(src_pt.x, src_pt.y, dest_pt.x, dest_pt.y, PC_BLACK, size + 2);
00997 GfxDrawLine(src_pt.x, src_pt.y, dest_pt.x, dest_pt.y, _legend_from_cargoes[i].colour, size);
00998 }
00999 }
01000 }
01001 }
01002
01003
01004 const Station *st;
01005 FOR_ALL_STATIONS(st) {
01006
01007 uint total = 0;
01008 bool show = false;
01009 for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
01010 if (_legend_from_cargoes[_cargotype_to_list_pos[cid]].show_on_map) {
01011 total += st->goods[cid].cargo.Count();
01012 show |= !st->goods[cid].routes.empty();
01013 }
01014 }
01015
01016 if (!show) continue;
01017
01018
01019 int d = 1;
01020 if (total >= 200) d++;
01021 if (total >= 400) d++;
01022 if (total >= 800) d++;
01023 if (total >= 1600) d++;
01024 if (total >= 3200) d++;
01025 if (total >= 6400) d++;
01026
01027
01028 Point dest_pt = this->RemapTile(TileX(st->xy), TileY(st->xy));
01029 dest_pt.x -= this->subscroll + d/2;
01030 dest_pt.y -= d/2;
01031
01032
01033 byte colour = _colour_gradient[Company::IsValidID(st->owner) ? Company::Get(st->owner)->colour : COLOUR_GREY][6];
01034 GfxFillRect(dest_pt.x - 1, dest_pt.y - 1, dest_pt.x + d + 1, dest_pt.y + d + 1, PC_BLACK);
01035 GfxFillRect(dest_pt.x, dest_pt.y, dest_pt.x + d, dest_pt.y + d, colour);
01036 }
01037 }
01038
01045 static inline void DrawVertMapIndicator(int x, int y, int y2)
01046 {
01047 GfxFillRect(x, y, x, y + 3, PC_VERY_LIGHT_YELLOW);
01048 GfxFillRect(x, y2 - 3, x, y2, PC_VERY_LIGHT_YELLOW);
01049 }
01050
01057 static inline void DrawHorizMapIndicator(int x, int x2, int y)
01058 {
01059 GfxFillRect(x, y, x + 3, y, PC_VERY_LIGHT_YELLOW);
01060 GfxFillRect(x2 - 3, y, x2, y, PC_VERY_LIGHT_YELLOW);
01061 }
01062
01066 void DrawMapIndicators() const
01067 {
01068
01069 const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
01070
01071 Point tile = InverseRemapCoords(vp->virtual_left, vp->virtual_top);
01072 Point tl = this->RemapTile(tile.x >> 4, tile.y >> 4);
01073 tl.x -= this->subscroll;
01074
01075 tile = InverseRemapCoords(vp->virtual_left + vp->virtual_width, vp->virtual_top + vp->virtual_height);
01076 Point br = this->RemapTile(tile.x >> 4, tile.y >> 4);
01077 br.x -= this->subscroll;
01078
01079 SmallMapWindow::DrawVertMapIndicator(tl.x, tl.y, br.y);
01080 SmallMapWindow::DrawVertMapIndicator(br.x, tl.y, br.y);
01081
01082 SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, tl.y);
01083 SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, br.y);
01084 }
01085
01097 void DrawSmallMap(DrawPixelInfo *dpi) const
01098 {
01099 Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
01100 DrawPixelInfo *old_dpi;
01101
01102 old_dpi = _cur_dpi;
01103 _cur_dpi = dpi;
01104
01105
01106 GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, PC_BLACK);
01107
01108
01109 int dx;
01110 Point tile = this->PixelToTile(dpi->left, dpi->top, &dx);
01111 int tile_x = this->scroll_x / (int)TILE_SIZE + tile.x;
01112 int tile_y = this->scroll_y / (int)TILE_SIZE + tile.y;
01113
01114 void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0);
01115 int x = - dx - 4;
01116 int y = 0;
01117
01118 for (;;) {
01119
01120 if (x >= -3) {
01121 if (x >= dpi->width) break;
01122
01123 int end_pos = min(dpi->width, x + 4);
01124 int reps = (dpi->height - y + 1) / 2;
01125 if (reps > 0) {
01126 this->DrawSmallMapColumn(ptr, tile_x, tile_y, dpi->pitch * 2, reps, x, end_pos, blitter);
01127 }
01128 }
01129
01130 if (y == 0) {
01131 tile_y += this->zoom;
01132 y++;
01133 ptr = blitter->MoveTo(ptr, 0, 1);
01134 } else {
01135 tile_x -= this->zoom;
01136 y--;
01137 ptr = blitter->MoveTo(ptr, 0, -1);
01138 }
01139 ptr = blitter->MoveTo(ptr, 2, 0);
01140 x += 2;
01141 }
01142
01143
01144 if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter);
01145
01146
01147 if (this->map_type == SMT_ROUTE_LINKS) this->DrawRouteLinks();
01148
01149
01150 if (this->show_towns) this->DrawTowns(dpi);
01151
01152
01153 this->DrawMapIndicators();
01154
01155 _cur_dpi = old_dpi;
01156 }
01157
01161 void SetupWidgetData()
01162 {
01163 StringID legend_tooltip;
01164 StringID enable_all_tooltip;
01165 StringID disable_all_tooltip;
01166 int plane;
01167 switch (this->map_type) {
01168 case SMT_INDUSTRY:
01169 legend_tooltip = STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION;
01170 enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES;
01171 disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES;
01172 plane = 0;
01173 break;
01174
01175 case SMT_OWNER:
01176 legend_tooltip = STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION;
01177 enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES;
01178 disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES;
01179 plane = 0;
01180 break;
01181
01182 case SMT_ROUTE_LINKS:
01183 legend_tooltip = STR_SMALLMAP_TOOLTIP_ROUTELINK_SELECTION;
01184 enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_ROUTELINKS;
01185 disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_ROUTELINKS;
01186 plane = 0;
01187 break;
01188
01189 default:
01190 legend_tooltip = STR_NULL;
01191 enable_all_tooltip = STR_NULL;
01192 disable_all_tooltip = STR_NULL;
01193 plane = 1;
01194 break;
01195 }
01196
01197 this->GetWidget<NWidgetCore>(SM_WIDGET_LEGEND)->SetDataTip(STR_NULL, legend_tooltip);
01198 this->GetWidget<NWidgetCore>(SM_WIDGET_ENABLE_ALL)->SetDataTip(STR_SMALLMAP_ENABLE_ALL, enable_all_tooltip);
01199 this->GetWidget<NWidgetCore>(SM_WIDGET_DISABLE_ALL)->SetDataTip(STR_SMALLMAP_DISABLE_ALL, disable_all_tooltip);
01200 this->GetWidget<NWidgetStacked>(SM_WIDGET_SELECT_BUTTONS)->SetDisplayedPlane(plane);
01201 }
01202
01203 public:
01204 uint min_number_of_columns;
01205
01206 SmallMapWindow(const WindowDesc *desc, int window_number) : Window(), refresh(FORCE_REFRESH_PERIOD)
01207 {
01208 this->InitNested(desc, window_number);
01209 this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
01210
01211 BuildLandLegend();
01212 this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_show_heightmap);
01213
01214 this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
01215
01216 this->SetupWidgetData();
01217
01218 this->SetZoomLevel(ZLC_INITIALIZE, NULL);
01219 this->SmallMapCenterOnCurrentPos();
01220 }
01221
01226 inline uint GetMinLegendWidth() const
01227 {
01228 return WD_FRAMERECT_LEFT + this->min_number_of_columns * this->column_width;
01229 }
01230
01235 inline uint GetNumberColumnsLegend(uint width) const
01236 {
01237 return width / this->column_width;
01238 }
01239
01245 uint GetLegendHeight(uint num_columns) const
01246 {
01247 uint num_rows = max(this->min_number_of_fixed_rows, CeilDiv(max(_smallmap_company_count, _smallmap_industry_count), num_columns));
01248 return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
01249 }
01250
01251 virtual void SetStringParameters(int widget) const
01252 {
01253 switch (widget) {
01254 case SM_WIDGET_CAPTION:
01255 SetDParam(0, STR_SMALLMAP_TYPE_CONTOURS + this->map_type);
01256 break;
01257 }
01258 }
01259
01260 virtual void OnInit()
01261 {
01262 uint min_width = 0;
01263 this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS;
01264 this->min_number_of_fixed_rows = 0;
01265 for (uint i = 0; i < lengthof(_legend_table); i++) {
01266 uint height = 0;
01267 uint num_columns = 1;
01268 for (const LegendAndColour *tbl = _legend_table[i]; !tbl->end; ++tbl) {
01269 StringID str;
01270 if (i == SMT_INDUSTRY) {
01271 SetDParam(0, tbl->legend);
01272 SetDParam(1, IndustryPool::MAX_SIZE);
01273 str = STR_SMALLMAP_INDUSTRY;
01274 } else if (i == SMT_OWNER) {
01275 if (tbl->company != INVALID_COMPANY) {
01276 if (!Company::IsValidID(tbl->company)) {
01277
01278 BuildOwnerLegend();
01279 this->OnInit();
01280 return;
01281 }
01282
01283 SetDParam(0, tbl->company);
01284 str = STR_SMALLMAP_COMPANY;
01285 } else {
01286 str = tbl->legend;
01287 }
01288 } else if (i == SMT_ROUTE_LINKS) {
01289 SetDParam(0, tbl->legend);
01290 str = STR_SMALLMAP_CARGO;
01291 } else {
01292 if (tbl->col_break) {
01293 this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
01294 height = 0;
01295 num_columns++;
01296 }
01297 height++;
01298 str = tbl->legend;
01299 }
01300 min_width = max(GetStringBoundingBox(str).width, min_width);
01301 }
01302 this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
01303 this->min_number_of_columns = max(this->min_number_of_columns, num_columns);
01304 }
01305
01306
01307 this->column_width = min_width + LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
01308 }
01309
01310 virtual void OnPaint()
01311 {
01312 if (this->map_type == SMT_OWNER) {
01313 for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) {
01314 if (tbl->company != INVALID_COMPANY && !Company::IsValidID(tbl->company)) {
01315
01316 BuildOwnerLegend();
01317 this->InvalidateData(1);
01318 break;
01319 }
01320 }
01321 }
01322
01323 this->DrawWidgets();
01324 }
01325
01326 virtual void DrawWidget(const Rect &r, int widget) const
01327 {
01328 switch (widget) {
01329 case SM_WIDGET_MAP: {
01330 DrawPixelInfo new_dpi;
01331 if (!FillDrawPixelInfo(&new_dpi, r.left + 1, r.top + 1, r.right - r.left - 1, r.bottom - r.top - 1)) return;
01332 this->DrawSmallMap(&new_dpi);
01333 break;
01334 }
01335
01336 case SM_WIDGET_LEGEND: {
01337 uint columns = this->GetNumberColumnsLegend(r.right - r.left + 1);
01338 uint number_of_rows = max((this->map_type == SMT_INDUSTRY || this->map_type == SMT_OWNER || this->map_type == SMT_ROUTE_LINKS) ? CeilDiv(max(_smallmap_company_count, max(_smallmap_industry_count, _smallmap_cargo_count)), columns) : 0, this->min_number_of_fixed_rows);
01339 bool rtl = _current_text_dir == TD_RTL;
01340 uint y_org = r.top + WD_FRAMERECT_TOP;
01341 uint x = rtl ? r.right - this->column_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT;
01342 uint y = y_org;
01343 uint i = 0;
01344 uint row_height = FONT_HEIGHT_SMALL;
01345
01346 uint text_left = rtl ? 0 : LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT;
01347 uint text_right = this->column_width - 1 - (rtl ? LEGEND_BLOB_WIDTH + WD_FRAMERECT_RIGHT : 0);
01348 uint blob_left = rtl ? this->column_width - 1 - LEGEND_BLOB_WIDTH : 0;
01349 uint blob_right = rtl ? this->column_width - 1 : LEGEND_BLOB_WIDTH;
01350
01351 for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) {
01352 if (tbl->col_break || ((this->map_type == SMT_INDUSTRY || this->map_type == SMT_OWNER || this->map_type == SMT_ROUTE_LINKS) && i++ >= number_of_rows)) {
01353
01354
01355 x += rtl ? -(int)this->column_width : this->column_width;
01356 y = y_org;
01357 i = 1;
01358 }
01359
01360 if (this->map_type == SMT_INDUSTRY) {
01361
01362
01363 SetDParam(0, tbl->legend);
01364 SetDParam(1, Industry::GetIndustryTypeCount(tbl->type));
01365 if (!tbl->show_on_map) {
01366
01367
01368 DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_GREY);
01369 } else {
01370 DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_BLACK);
01371 GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK);
01372 }
01373 } else if (this->map_type == SMT_ROUTE_LINKS) {
01374
01375 SetDParam(0, tbl->legend);
01376 if (!tbl->show_on_map) {
01377
01378 DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_CARGO, TC_GREY);
01379 } else {
01380 DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_CARGO, TC_BLACK);
01381 GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK);
01382 }
01383 } else if (this->map_type == SMT_OWNER && tbl->company != INVALID_COMPANY) {
01384 SetDParam(0, tbl->company);
01385 if (!tbl->show_on_map) {
01386
01387
01388 DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_COMPANY, TC_GREY);
01389 } else {
01390 DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_COMPANY, TC_BLACK);
01391 GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK);
01392 }
01393 } else {
01394 if (this->map_type == SMT_CONTOUR) SetDParam(0, tbl->height * TILE_HEIGHT_STEP);
01395
01396
01397 GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK);
01398 DrawString(x + text_left, x + text_right, y, tbl->legend);
01399 }
01400 GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + row_height - 2, tbl->colour);
01401
01402 y += row_height;
01403 }
01404 }
01405 }
01406 }
01407
01412 void SwitchMapType(SmallMapType map_type)
01413 {
01414 this->RaiseWidget(this->map_type + SM_WIDGET_CONTOUR);
01415 this->map_type = map_type;
01416 this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
01417
01418 this->SetupWidgetData();
01419
01420 this->SetDirty();
01421 }
01422
01423 virtual void OnClick(Point pt, int widget, int click_count)
01424 {
01425
01426 InvalidateWindowClassesData(WC_INDUSTRY_CARGOES, NUM_INDUSTRYTYPES);
01427
01428 switch (widget) {
01429 case SM_WIDGET_MAP: {
01430
01431
01432
01433
01434
01435
01436
01437
01438 _left_button_clicked = false;
01439
01440 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01441 Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
01442 int sub;
01443 pt = this->PixelToTile(pt.x - wid->pos_x, pt.y - wid->pos_y, &sub);
01444 pt = RemapCoords(this->scroll_x + pt.x * TILE_SIZE + this->zoom * (TILE_SIZE - sub * TILE_SIZE / 4),
01445 this->scroll_y + pt.y * TILE_SIZE + sub * this->zoom * TILE_SIZE / 4, 0);
01446
01447 w->viewport->follow_vehicle = INVALID_VEHICLE;
01448 w->viewport->dest_scrollpos_x = pt.x - (w->viewport->virtual_width >> 1);
01449 w->viewport->dest_scrollpos_y = pt.y - (w->viewport->virtual_height >> 1);
01450
01451 this->SetDirty();
01452 break;
01453 }
01454
01455 case SM_WIDGET_ZOOM_IN:
01456 case SM_WIDGET_ZOOM_OUT: {
01457 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01458 Point pt = {wid->current_x / 2, wid->current_y / 2};
01459 this->SetZoomLevel((widget == SM_WIDGET_ZOOM_IN) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt);
01460 SndPlayFx(SND_15_BEEP);
01461 break;
01462 }
01463
01464 case SM_WIDGET_CONTOUR:
01465 case SM_WIDGET_VEHICLES:
01466 case SM_WIDGET_INDUSTRIES:
01467 case SM_WIDGET_ROUTE_LINKS:
01468 case SM_WIDGET_ROUTES:
01469 case SM_WIDGET_VEGETATION:
01470 case SM_WIDGET_OWNERS:
01471 this->SwitchMapType((SmallMapType)(widget - SM_WIDGET_CONTOUR));
01472 SndPlayFx(SND_15_BEEP);
01473 break;
01474
01475 case SM_WIDGET_CENTERMAP:
01476 this->SmallMapCenterOnCurrentPos();
01477 this->HandleButtonClick(SM_WIDGET_CENTERMAP);
01478 SndPlayFx(SND_15_BEEP);
01479 break;
01480
01481 case SM_WIDGET_TOGGLETOWNNAME:
01482 this->show_towns = !this->show_towns;
01483 this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
01484
01485 this->SetDirty();
01486 SndPlayFx(SND_15_BEEP);
01487 break;
01488
01489 case SM_WIDGET_LEGEND:
01490 if (this->map_type == SMT_INDUSTRY || this->map_type == SMT_OWNER || this->map_type == SMT_ROUTE_LINKS) {
01491 const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_LEGEND);
01492 uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL;
01493 uint columns = this->GetNumberColumnsLegend(wi->current_x);
01494 uint number_of_rows = max(CeilDiv(max(_smallmap_company_count, max(_smallmap_industry_count, _smallmap_cargo_count)), columns), this->min_number_of_fixed_rows);
01495 if (line >= number_of_rows) break;
01496
01497 bool rtl = _current_text_dir == TD_RTL;
01498 int x = pt.x - wi->pos_x;
01499 if (rtl) x = wi->current_x - x;
01500 uint column = (x - WD_FRAMERECT_LEFT) / this->column_width;
01501
01502
01503 if (this->map_type == SMT_INDUSTRY) {
01504
01505 int industry_pos = (column * number_of_rows) + line;
01506 if (industry_pos < _smallmap_industry_count) {
01507 if (_ctrl_pressed) {
01508
01509 bool changes = false;
01510 for (int i = 0; i != _smallmap_industry_count; i++) {
01511 bool new_state = i == industry_pos;
01512 if (_legend_from_industries[i].show_on_map != new_state) {
01513 changes = true;
01514 _legend_from_industries[i].show_on_map = new_state;
01515 }
01516 }
01517 if (!changes) {
01518
01519 for (int i = 0; i != _smallmap_industry_count; i++) {
01520 _legend_from_industries[i].show_on_map = true;
01521 }
01522 }
01523 } else {
01524 _legend_from_industries[industry_pos].show_on_map = !_legend_from_industries[industry_pos].show_on_map;
01525 }
01526 }
01527 } else if (this->map_type == SMT_OWNER) {
01528
01529 int company_pos = (column * number_of_rows) + line;
01530 if (company_pos < NUM_NO_COMPANY_ENTRIES) break;
01531 if (company_pos < _smallmap_company_count) {
01532 if (_ctrl_pressed) {
01533
01534 bool changes = false;
01535 for (int i = NUM_NO_COMPANY_ENTRIES; i != _smallmap_company_count; i++) {
01536 bool new_state = i == company_pos;
01537 if (_legend_land_owners[i].show_on_map != new_state) {
01538 changes = true;
01539 _legend_land_owners[i].show_on_map = new_state;
01540 }
01541 }
01542 if (!changes) {
01543
01544 for (int i = NUM_NO_COMPANY_ENTRIES; i != _smallmap_company_count; i++) {
01545 _legend_land_owners[i].show_on_map = true;
01546 }
01547 }
01548 } else {
01549 _legend_land_owners[company_pos].show_on_map = !_legend_land_owners[company_pos].show_on_map;
01550 }
01551 }
01552 } else if (this->map_type == SMT_ROUTE_LINKS) {
01553
01554 int cargo_pos = (column * number_of_rows) + line;
01555 if (cargo_pos < _smallmap_cargo_count) {
01556 if (_ctrl_pressed) {
01557
01558 bool changes = false;
01559 for (int i = 0; i != _smallmap_cargo_count; i++) {
01560 bool new_state = i == cargo_pos;
01561 if (_legend_from_cargoes[i].show_on_map != new_state) {
01562 changes = true;
01563 _legend_from_cargoes[i].show_on_map = new_state;
01564 }
01565 }
01566 if (!changes) {
01567
01568 for (int i = 0; i != _smallmap_cargo_count; i++) {
01569 _legend_from_cargoes[i].show_on_map = true;
01570 }
01571 }
01572 } else {
01573 _legend_from_cargoes[cargo_pos].show_on_map = !_legend_from_cargoes[cargo_pos].show_on_map;
01574 }
01575 }
01576 }
01577 this->SetDirty();
01578 }
01579 break;
01580
01581 case SM_WIDGET_ENABLE_ALL:
01582 if (this->map_type == SMT_INDUSTRY) {
01583 for (int i = 0; i != _smallmap_industry_count; i++) {
01584 _legend_from_industries[i].show_on_map = true;
01585 }
01586 } else if (this->map_type == SMT_OWNER) {
01587 for (int i = NUM_NO_COMPANY_ENTRIES; i != _smallmap_company_count; i++) {
01588 _legend_land_owners[i].show_on_map = true;
01589 }
01590 } else if (this->map_type == SMT_ROUTE_LINKS) {
01591 for (int i = 0; i != _smallmap_cargo_count; i++) {
01592 _legend_from_cargoes[i].show_on_map = true;
01593 }
01594 }
01595 this->SetDirty();
01596 break;
01597
01598 case SM_WIDGET_DISABLE_ALL:
01599 if (this->map_type == SMT_INDUSTRY) {
01600 for (int i = 0; i != _smallmap_industry_count; i++) {
01601 _legend_from_industries[i].show_on_map = false;
01602 }
01603 } else if (this->map_type == SMT_OWNER) {
01604 for (int i = NUM_NO_COMPANY_ENTRIES; i != _smallmap_company_count; i++) {
01605 _legend_land_owners[i].show_on_map = false;
01606 }
01607 } else if (this->map_type == SMT_ROUTE_LINKS) {
01608 for (int i = 0; i != _smallmap_cargo_count; i++) {
01609 _legend_from_cargoes[i].show_on_map = false;
01610 }
01611 }
01612 this->SetDirty();
01613 break;
01614
01615 case SM_WIDGET_SHOW_HEIGHT:
01616 _smallmap_show_heightmap = !_smallmap_show_heightmap;
01617 this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_show_heightmap);
01618 this->SetDirty();
01619 break;
01620 }
01621 }
01622
01630 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
01631 {
01632 if (!gui_scope) return;
01633 switch (data) {
01634 case 1:
01635
01636 this->ReInit();
01637 break;
01638
01639 case 0: {
01640 extern uint64 _displayed_industries;
01641 if (this->map_type != SMT_INDUSTRY) this->SwitchMapType(SMT_INDUSTRY);
01642
01643 for (int i = 0; i != _smallmap_industry_count; i++) {
01644 _legend_from_industries[i].show_on_map = HasBit(_displayed_industries, _legend_from_industries[i].type);
01645 }
01646 break;
01647 }
01648
01649 default: NOT_REACHED();
01650 }
01651 this->SetDirty();
01652 }
01653
01654 virtual bool OnRightClick(Point pt, int widget)
01655 {
01656 if (widget != SM_WIDGET_MAP || _scrolling_viewport) return false;
01657
01658 _scrolling_viewport = true;
01659 return true;
01660 }
01661
01662 virtual void OnMouseWheel(int wheel)
01663 {
01664 if (_settings_client.gui.scrollwheel_scrolling == 0) {
01665 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01666 int cursor_x = _cursor.pos.x - this->left - wid->pos_x;
01667 int cursor_y = _cursor.pos.y - this->top - wid->pos_y;
01668 if (IsInsideMM(cursor_x, 0, wid->current_x) && IsInsideMM(cursor_y, 0, wid->current_y)) {
01669 Point pt = {cursor_x, cursor_y};
01670 this->SetZoomLevel((wheel < 0) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt);
01671 }
01672 }
01673 }
01674
01675 virtual void OnTick()
01676 {
01677
01678 if (--this->refresh != 0) return;
01679
01680 this->refresh = FORCE_REFRESH_PERIOD;
01681 this->SetDirty();
01682 }
01683
01691 void SetNewScroll(int sx, int sy, int sub)
01692 {
01693 const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01694 Point hv = InverseRemapCoords(wi->current_x * TILE_SIZE / 2, wi->current_y * TILE_SIZE / 2);
01695 hv.x *= this->zoom;
01696 hv.y *= this->zoom;
01697
01698 if (sx < -hv.x) {
01699 sx = -hv.x;
01700 sub = 0;
01701 }
01702 if (sx > (int)(MapMaxX() * TILE_SIZE) - hv.x) {
01703 sx = MapMaxX() * TILE_SIZE - hv.x;
01704 sub = 0;
01705 }
01706 if (sy < -hv.y) {
01707 sy = -hv.y;
01708 sub = 0;
01709 }
01710 if (sy > (int)(MapMaxY() * TILE_SIZE) - hv.y) {
01711 sy = MapMaxY() * TILE_SIZE - hv.y;
01712 sub = 0;
01713 }
01714
01715 this->scroll_x = sx;
01716 this->scroll_y = sy;
01717 this->subscroll = sub;
01718 }
01719
01720 virtual void OnScroll(Point delta)
01721 {
01722 _cursor.fix_at = true;
01723
01724
01725 int sub;
01726 Point pt = this->PixelToTile(delta.x, delta.y, &sub);
01727 this->SetNewScroll(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, sub);
01728
01729 this->SetDirty();
01730 }
01731
01732 void SmallMapCenterOnCurrentPos()
01733 {
01734 const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
01735 Point pt = InverseRemapCoords(vp->virtual_left + vp->virtual_width / 2, vp->virtual_top + vp->virtual_height / 2);
01736
01737 int sub;
01738 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01739 Point sxy = this->ComputeScroll(pt.x / TILE_SIZE, pt.y / TILE_SIZE, max(0, (int)wid->current_x / 2 - 2), wid->current_y / 2, &sub);
01740 this->SetNewScroll(sxy.x, sxy.y, sub);
01741 this->SetDirty();
01742 }
01743 };
01744
01745 SmallMapWindow::SmallMapType SmallMapWindow::map_type = SMT_CONTOUR;
01746 bool SmallMapWindow::show_towns = true;
01747
01756 class NWidgetSmallmapDisplay : public NWidgetContainer {
01757 const SmallMapWindow *smallmap_window;
01758 public:
01759 NWidgetSmallmapDisplay() : NWidgetContainer(NWID_VERTICAL)
01760 {
01761 this->smallmap_window = NULL;
01762 }
01763
01764 virtual void SetupSmallestSize(Window *w, bool init_array)
01765 {
01766 NWidgetBase *display = this->head;
01767 NWidgetBase *bar = display->next;
01768
01769 display->SetupSmallestSize(w, init_array);
01770 bar->SetupSmallestSize(w, init_array);
01771
01772 this->smallmap_window = dynamic_cast<SmallMapWindow *>(w);
01773 this->smallest_x = max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth());
01774 this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetLegendHeight(smallmap_window->min_number_of_columns));
01775 this->fill_x = max(display->fill_x, bar->fill_x);
01776 this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : min(display->fill_y, bar->fill_y);
01777 this->resize_x = max(display->resize_x, bar->resize_x);
01778 this->resize_y = min(display->resize_y, bar->resize_y);
01779 }
01780
01781 virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01782 {
01783 this->pos_x = x;
01784 this->pos_y = y;
01785 this->current_x = given_width;
01786 this->current_y = given_height;
01787
01788 NWidgetBase *display = this->head;
01789 NWidgetBase *bar = display->next;
01790
01791 if (sizing == ST_SMALLEST) {
01792 this->smallest_x = given_width;
01793 this->smallest_y = given_height;
01794
01795 display->AssignSizePosition(ST_SMALLEST, x, y, display->smallest_x, display->smallest_y, rtl);
01796 bar->AssignSizePosition(ST_SMALLEST, x, y + display->smallest_y, bar->smallest_x, bar->smallest_y, rtl);
01797 }
01798
01799 uint bar_height = max(bar->smallest_y, this->smallmap_window->GetLegendHeight(this->smallmap_window->GetNumberColumnsLegend(given_width - bar->smallest_x)));
01800 uint display_height = given_height - bar_height;
01801 display->AssignSizePosition(ST_RESIZE, x, y, given_width, display_height, rtl);
01802 bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl);
01803 }
01804
01805 virtual NWidgetCore *GetWidgetFromPos(int x, int y)
01806 {
01807 if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
01808 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01809 NWidgetCore *widget = child_wid->GetWidgetFromPos(x, y);
01810 if (widget != NULL) return widget;
01811 }
01812 return NULL;
01813 }
01814
01815 virtual void Draw(const Window *w)
01816 {
01817 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) child_wid->Draw(w);
01818 }
01819 };
01820
01822 static const NWidgetPart _nested_smallmap_display[] = {
01823 NWidget(WWT_PANEL, COLOUR_BROWN, SM_WIDGET_MAP_BORDER),
01824 NWidget(WWT_INSET, COLOUR_BROWN, SM_WIDGET_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(),
01825 EndContainer(),
01826 };
01827
01829 static const NWidgetPart _nested_smallmap_bar[] = {
01830 NWidget(WWT_PANEL, COLOUR_BROWN),
01831 NWidget(NWID_HORIZONTAL),
01832 NWidget(WWT_EMPTY, INVALID_COLOUR, SM_WIDGET_LEGEND), SetResize(1, 1),
01833 NWidget(NWID_VERTICAL),
01834
01835 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01836 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_IN),
01837 SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), SetFill(1, 1),
01838 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_CENTERMAP),
01839 SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER), SetFill(1, 1),
01840 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_CONTOUR),
01841 SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP), SetFill(1, 1),
01842 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEHICLES),
01843 SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP), SetFill(1, 1),
01844 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_INDUSTRIES),
01845 SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP), SetFill(1, 1),
01846 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_ROUTE_LINKS),
01847 SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_ROUTE_LINKS_ON_MAP), SetFill(1, 1),
01848 EndContainer(),
01849
01850 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01851 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_OUT),
01852 SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), SetFill(1, 1),
01853 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_TOGGLETOWNNAME),
01854 SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF), SetFill(1, 1),
01855 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_ROUTES),
01856 SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON), SetFill(1, 1),
01857 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEGETATION),
01858 SetDataTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP), SetFill(1, 1),
01859 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_OWNERS),
01860 SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP), SetFill(1, 1),
01861 NWidget(NWID_SPACER), SetFill(1, 1),
01862 EndContainer(),
01863 NWidget(NWID_SPACER), SetResize(0, 1),
01864 EndContainer(),
01865 EndContainer(),
01866 EndContainer(),
01867 };
01868
01869 static NWidgetBase *SmallMapDisplay(int *biggest_index)
01870 {
01871 NWidgetContainer *map_display = new NWidgetSmallmapDisplay;
01872
01873 MakeNWidgets(_nested_smallmap_display, lengthof(_nested_smallmap_display), biggest_index, map_display);
01874 MakeNWidgets(_nested_smallmap_bar, lengthof(_nested_smallmap_bar), biggest_index, map_display);
01875 return map_display;
01876 }
01877
01878
01879 static const NWidgetPart _nested_smallmap_widgets[] = {
01880 NWidget(NWID_HORIZONTAL),
01881 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
01882 NWidget(WWT_CAPTION, COLOUR_BROWN, SM_WIDGET_CAPTION), SetDataTip(STR_SMALLMAP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01883 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
01884 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
01885 EndContainer(),
01886 NWidgetFunction(SmallMapDisplay),
01887
01888 NWidget(NWID_HORIZONTAL),
01889 NWidget(WWT_PANEL, COLOUR_BROWN),
01890 NWidget(NWID_HORIZONTAL),
01891 NWidget(NWID_SELECTION, INVALID_COLOUR, SM_WIDGET_SELECT_BUTTONS),
01892 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01893 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, SM_WIDGET_ENABLE_ALL), SetDataTip(STR_SMALLMAP_ENABLE_ALL, STR_NULL),
01894 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, SM_WIDGET_DISABLE_ALL), SetDataTip(STR_SMALLMAP_DISABLE_ALL, STR_NULL),
01895 NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_SHOW_HEIGHT), SetDataTip(STR_SMALLMAP_SHOW_HEIGHT, STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT),
01896 EndContainer(),
01897 NWidget(NWID_SPACER), SetFill(1, 1),
01898 EndContainer(),
01899 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
01900 EndContainer(),
01901 EndContainer(),
01902 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
01903 EndContainer(),
01904 };
01905
01906 static const WindowDesc _smallmap_desc(
01907 WDP_AUTO, 446, 314,
01908 WC_SMALLMAP, WC_NONE,
01909 WDF_UNCLICK_BUTTONS,
01910 _nested_smallmap_widgets, lengthof(_nested_smallmap_widgets)
01911 );
01912
01916 void ShowSmallMap()
01917 {
01918 AllocateWindowDescFront<SmallMapWindow>(&_smallmap_desc, 0);
01919 }
01920
01929 bool ScrollMainWindowTo(int x, int y, int z, bool instant)
01930 {
01931 bool res = ScrollWindowTo(x, y, z, FindWindowById(WC_MAIN_WINDOW, 0), instant);
01932
01933
01934
01935
01936
01937 if (res) return res;
01938
01939 SmallMapWindow *w = dynamic_cast<SmallMapWindow*>(FindWindowById(WC_SMALLMAP, 0));
01940 if (w != NULL) w->SmallMapCenterOnCurrentPos();
01941
01942 return res;
01943 }