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
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_ZOOM_IN,
00040 SM_WIDGET_ZOOM_OUT,
00041 SM_WIDGET_CONTOUR,
00042 SM_WIDGET_VEHICLES,
00043 SM_WIDGET_INDUSTRIES,
00044 SM_WIDGET_ROUTES,
00045 SM_WIDGET_VEGETATION,
00046 SM_WIDGET_OWNERS,
00047 SM_WIDGET_CENTERMAP,
00048 SM_WIDGET_TOGGLETOWNNAME,
00049 SM_WIDGET_SELECTINDUSTRIES,
00050 SM_WIDGET_ENABLEINDUSTRIES,
00051 SM_WIDGET_DISABLEINDUSTRIES,
00052 SM_WIDGET_SHOW_HEIGHT,
00053 };
00054
00055 static int _smallmap_industry_count;
00056
00058 #define MK(a, b) {a, b, INVALID_INDUSTRYTYPE, true, false, false}
00059
00060 #define MC(b) MK(0, b)
00061
00062 #define MKEND() {0, STR_NULL, INVALID_INDUSTRYTYPE, true, true, false}
00063
00065 #define MS(a, b) {a, b, INVALID_INDUSTRYTYPE, true, false, true}
00066
00068 struct LegendAndColour {
00069 uint8 colour;
00070 StringID legend;
00071 IndustryType type;
00072 bool show_on_map;
00073 bool end;
00074 bool col_break;
00075 };
00076
00078 static LegendAndColour _legend_land_contours[] = {
00079
00080 MC(STR_SMALLMAP_LEGENDA_100M),
00081 MC(STR_SMALLMAP_LEGENDA_200M),
00082 MC(STR_SMALLMAP_LEGENDA_300M),
00083 MC(STR_SMALLMAP_LEGENDA_400M),
00084 MC(STR_SMALLMAP_LEGENDA_500M),
00085
00086 MS(0xD7, STR_SMALLMAP_LEGENDA_ROADS),
00087 MK(0x0A, STR_SMALLMAP_LEGENDA_RAILROADS),
00088 MK(0x98, STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS),
00089 MK(0xB5, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00090 MK(0x0F, STR_SMALLMAP_LEGENDA_VEHICLES),
00091 MKEND()
00092 };
00093
00094 static const LegendAndColour _legend_vehicles[] = {
00095 MK(0xB8, STR_SMALLMAP_LEGENDA_TRAINS),
00096 MK(0xBF, STR_SMALLMAP_LEGENDA_ROAD_VEHICLES),
00097 MK(0x98, STR_SMALLMAP_LEGENDA_SHIPS),
00098 MK(0x0F, STR_SMALLMAP_LEGENDA_AIRCRAFT),
00099
00100 MS(0xD7, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES),
00101 MK(0xB5, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00102 MKEND()
00103 };
00104
00105 static const LegendAndColour _legend_routes[] = {
00106 MK(0xD7, STR_SMALLMAP_LEGENDA_ROADS),
00107 MK(0x0A, STR_SMALLMAP_LEGENDA_RAILROADS),
00108 MK(0xB5, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00109
00110 MS(0x56, STR_SMALLMAP_LEGENDA_RAILROAD_STATION),
00111 MK(0xC2, STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY),
00112 MK(0xBF, STR_SMALLMAP_LEGENDA_BUS_STATION),
00113 MK(0xB8, STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT),
00114 MK(0x98, STR_SMALLMAP_LEGENDA_DOCK),
00115 MKEND()
00116 };
00117
00118 static const LegendAndColour _legend_vegetation[] = {
00119 MK(0x52, STR_SMALLMAP_LEGENDA_ROUGH_LAND),
00120 MK(0x54, STR_SMALLMAP_LEGENDA_GRASS_LAND),
00121 MK(0x37, STR_SMALLMAP_LEGENDA_BARE_LAND),
00122 MK(0x25, STR_SMALLMAP_LEGENDA_FIELDS),
00123 MK(0x57, STR_SMALLMAP_LEGENDA_TREES),
00124 MK(0xD0, STR_SMALLMAP_LEGENDA_FOREST),
00125
00126 MS(0x0A, STR_SMALLMAP_LEGENDA_ROCKS),
00127 MK(0xC2, STR_SMALLMAP_LEGENDA_DESERT),
00128 MK(0x98, STR_SMALLMAP_LEGENDA_SNOW),
00129 MK(0xD7, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES),
00130 MK(0xB5, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00131 MKEND()
00132 };
00133
00134 static const LegendAndColour _legend_land_owners[] = {
00135 MK(0xCA, STR_SMALLMAP_LEGENDA_WATER),
00136 MK(0x54, STR_SMALLMAP_LEGENDA_NO_OWNER),
00137 MK(0xB4, STR_SMALLMAP_LEGENDA_TOWNS),
00138 MK(0x20, STR_SMALLMAP_LEGENDA_INDUSTRIES),
00139 MKEND()
00140 };
00141 #undef MK
00142 #undef MC
00143 #undef MS
00144 #undef MKEND
00145
00148 static LegendAndColour _legend_from_industries[NUM_INDUSTRYTYPES + 1];
00149
00150 static uint _industry_to_list_pos[NUM_INDUSTRYTYPES];
00152 static bool _smallmap_industry_show_heightmap;
00153
00157 void BuildIndustriesLegend()
00158 {
00159 uint j = 0;
00160
00161
00162 for (IndustryType i = 0; i < NUM_INDUSTRYTYPES; i++) {
00163 const IndustrySpec *indsp = GetIndustrySpec(i);
00164 if (indsp->enabled) {
00165 _legend_from_industries[j].legend = indsp->name;
00166 _legend_from_industries[j].colour = indsp->map_colour;
00167 _legend_from_industries[j].type = i;
00168 _legend_from_industries[j].show_on_map = true;
00169 _legend_from_industries[j].col_break = false;
00170 _legend_from_industries[j].end = false;
00171
00172
00173 _industry_to_list_pos[i] = j;
00174 j++;
00175 }
00176 }
00177
00178 _legend_from_industries[j].end = true;
00179
00180
00181 _smallmap_industry_count = j;
00182 }
00183
00184 static const LegendAndColour * const _legend_table[] = {
00185 _legend_land_contours,
00186 _legend_vehicles,
00187 _legend_from_industries,
00188 _legend_routes,
00189 _legend_vegetation,
00190 _legend_land_owners,
00191 };
00192
00193 #define MKCOLOUR(x) TO_LE32X(x)
00194
00196 static const uint32 _green_map_heights[] = {
00197 MKCOLOUR(0x5A5A5A5A),
00198 MKCOLOUR(0x5A5B5A5B),
00199 MKCOLOUR(0x5B5B5B5B),
00200 MKCOLOUR(0x5B5C5B5C),
00201 MKCOLOUR(0x5C5C5C5C),
00202 MKCOLOUR(0x5C5D5C5D),
00203 MKCOLOUR(0x5D5D5D5D),
00204 MKCOLOUR(0x5D5E5D5E),
00205 MKCOLOUR(0x5E5E5E5E),
00206 MKCOLOUR(0x5E5F5E5F),
00207 MKCOLOUR(0x5F5F5F5F),
00208 MKCOLOUR(0x5F1F5F1F),
00209 MKCOLOUR(0x1F1F1F1F),
00210 MKCOLOUR(0x1F271F27),
00211 MKCOLOUR(0x27272727),
00212 MKCOLOUR(0x27272727),
00213 };
00214 assert_compile(lengthof(_green_map_heights) == MAX_TILE_HEIGHT + 1);
00215
00217 static const uint32 _dark_green_map_heights[] = {
00218 MKCOLOUR(0x60606060),
00219 MKCOLOUR(0x60616061),
00220 MKCOLOUR(0x61616161),
00221 MKCOLOUR(0x61626162),
00222 MKCOLOUR(0x62626262),
00223 MKCOLOUR(0x62636263),
00224 MKCOLOUR(0x63636363),
00225 MKCOLOUR(0x63646364),
00226 MKCOLOUR(0x64646464),
00227 MKCOLOUR(0x64656465),
00228 MKCOLOUR(0x65656565),
00229 MKCOLOUR(0x65666566),
00230 MKCOLOUR(0x66666666),
00231 MKCOLOUR(0x66676667),
00232 MKCOLOUR(0x67676767),
00233 MKCOLOUR(0x67676767),
00234 };
00235 assert_compile(lengthof(_dark_green_map_heights) == MAX_TILE_HEIGHT + 1);
00236
00238 static const uint32 _violet_map_heights[] = {
00239 MKCOLOUR(0x80808080),
00240 MKCOLOUR(0x80818081),
00241 MKCOLOUR(0x81818181),
00242 MKCOLOUR(0x81828182),
00243 MKCOLOUR(0x82828282),
00244 MKCOLOUR(0x82838283),
00245 MKCOLOUR(0x83838383),
00246 MKCOLOUR(0x83848384),
00247 MKCOLOUR(0x84848484),
00248 MKCOLOUR(0x84858485),
00249 MKCOLOUR(0x85858585),
00250 MKCOLOUR(0x85868586),
00251 MKCOLOUR(0x86868686),
00252 MKCOLOUR(0x86878687),
00253 MKCOLOUR(0x87878787),
00254 MKCOLOUR(0x87878787),
00255 };
00256 assert_compile(lengthof(_violet_map_heights) == MAX_TILE_HEIGHT + 1);
00257
00259 struct SmallMapColourScheme {
00260 const uint32 *height_colours;
00261 uint32 default_colour;
00262 };
00263
00265 static const SmallMapColourScheme _heightmap_schemes[] = {
00266 {_green_map_heights, MKCOLOUR(0x54545454)},
00267 {_dark_green_map_heights, MKCOLOUR(0x62626262)},
00268 {_violet_map_heights, MKCOLOUR(0x82828282)},
00269 };
00270
00271 void BuildLandLegend()
00272 {
00273 _legend_land_contours[0].colour = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].height_colours[0];
00274 _legend_land_contours[1].colour = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].height_colours[4];
00275 _legend_land_contours[2].colour = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].height_colours[8];
00276 _legend_land_contours[3].colour = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].height_colours[12];
00277 _legend_land_contours[4].colour = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].height_colours[14];
00278 }
00279
00280 struct AndOr {
00281 uint32 mor;
00282 uint32 mand;
00283 };
00284
00285 static inline uint32 ApplyMask(uint32 colour, const AndOr *mask)
00286 {
00287 return (colour & mask->mand) | mask->mor;
00288 }
00289
00290
00292 static const AndOr _smallmap_contours_andor[] = {
00293 {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00294 {MKCOLOUR(0x000A0A00), MKCOLOUR(0xFF0000FF)},
00295 {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)},
00296 {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)},
00297 {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00298 {MKCOLOUR(0x98989898), MKCOLOUR(0x00000000)},
00299 {MKCOLOUR(0xCACACACA), MKCOLOUR(0x00000000)},
00300 {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00301 {MKCOLOUR(0xB5B5B5B5), MKCOLOUR(0x00000000)},
00302 {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00303 {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)},
00304 {MKCOLOUR(0x000A0A00), MKCOLOUR(0xFF0000FF)},
00305 };
00306
00308 static const AndOr _smallmap_vehicles_andor[] = {
00309 {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00310 {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)},
00311 {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)},
00312 {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)},
00313 {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00314 {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)},
00315 {MKCOLOUR(0xCACACACA), MKCOLOUR(0x00000000)},
00316 {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00317 {MKCOLOUR(0xB5B5B5B5), MKCOLOUR(0x00000000)},
00318 {MKCOLOUR(0x00000000), MKCOLOUR(0xFFFFFFFF)},
00319 {MKCOLOUR(0x00B5B500), MKCOLOUR(0xFF0000FF)},
00320 {MKCOLOUR(0x00D7D700), MKCOLOUR(0xFF0000FF)},
00321 };
00322
00324 static const byte _tiletype_importance[] = {
00325 2,
00326 8,
00327 7,
00328 5,
00329 2,
00330 9,
00331 2,
00332 1,
00333 6,
00334 8,
00335 2,
00336 0,
00337 };
00338
00339
00340 static inline TileType GetEffectiveTileType(TileIndex tile)
00341 {
00342 TileType t = GetTileType(tile);
00343
00344 if (t == MP_TUNNELBRIDGE) {
00345 TransportType tt = GetTunnelBridgeTransportType(tile);
00346
00347 switch (tt) {
00348 case TRANSPORT_RAIL: t = MP_RAILWAY; break;
00349 case TRANSPORT_ROAD: t = MP_ROAD; break;
00350 default: t = MP_WATER; break;
00351 }
00352 }
00353 return t;
00354 }
00355
00362 static inline uint32 GetSmallMapContoursPixels(TileIndex tile, TileType t)
00363 {
00364 const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00365 return ApplyMask(cs->height_colours[TileHeight(tile)], &_smallmap_contours_andor[t]);
00366 }
00367
00375 static inline uint32 GetSmallMapVehiclesPixels(TileIndex tile, TileType t)
00376 {
00377 const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00378 return ApplyMask(cs->default_colour, &_smallmap_vehicles_andor[t]);
00379 }
00380
00388 static inline uint32 GetSmallMapIndustriesPixels(TileIndex tile, TileType t)
00389 {
00390 if (t == MP_INDUSTRY) {
00391
00392 if (_legend_from_industries[_industry_to_list_pos[Industry::GetByTile(tile)->type]].show_on_map) {
00393 return GetIndustrySpec(Industry::GetByTile(tile)->type)->map_colour * 0x01010101;
00394 } else {
00395
00396 t = (GetWaterClass(tile) == WATER_CLASS_INVALID) ? MP_CLEAR : MP_WATER;
00397 }
00398 }
00399
00400 const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00401 return ApplyMask(_smallmap_industry_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour, &_smallmap_vehicles_andor[t]);
00402 }
00403
00411 static inline uint32 GetSmallMapRoutesPixels(TileIndex tile, TileType t)
00412 {
00413 if (t == MP_STATION) {
00414 switch (GetStationType(tile)) {
00415 case STATION_RAIL: return MKCOLOUR(0x56565656);
00416 case STATION_AIRPORT: return MKCOLOUR(0xB8B8B8B8);
00417 case STATION_TRUCK: return MKCOLOUR(0xC2C2C2C2);
00418 case STATION_BUS: return MKCOLOUR(0xBFBFBFBF);
00419 case STATION_DOCK: return MKCOLOUR(0x98989898);
00420 default: return MKCOLOUR(0xFFFFFFFF);
00421 }
00422 } else if (t == MP_RAILWAY) {
00423 AndOr andor = {
00424 GetRailTypeInfo(GetRailType(tile))->map_colour * MKCOLOUR(0x00010100),
00425 _smallmap_contours_andor[t].mand
00426 };
00427
00428 const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00429 return ApplyMask(cs->default_colour, &andor);
00430 }
00431
00432
00433 const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00434 return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]);
00435 }
00436
00437
00438 static const uint32 _vegetation_clear_bits[] = {
00439 MKCOLOUR(0x54545454),
00440 MKCOLOUR(0x52525252),
00441 MKCOLOUR(0x0A0A0A0A),
00442 MKCOLOUR(0x25252525),
00443 MKCOLOUR(0x98989898),
00444 MKCOLOUR(0xC2C2C2C2),
00445 MKCOLOUR(0x54545454),
00446 MKCOLOUR(0x54545454),
00447 };
00448
00456 static inline uint32 GetSmallMapVegetationPixels(TileIndex tile, TileType t)
00457 {
00458 switch (t) {
00459 case MP_CLEAR:
00460 return (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) < 3) ? MKCOLOUR(0x37373737) : _vegetation_clear_bits[GetClearGround(tile)];
00461
00462 case MP_INDUSTRY:
00463 return GetIndustrySpec(Industry::GetByTile(tile)->type)->check_proc == CHECK_FOREST ? MKCOLOUR(0xD0D0D0D0) : MKCOLOUR(0xB5B5B5B5);
00464
00465 case MP_TREES:
00466 if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT || GetTreeGround(tile) == TREE_GROUND_ROUGH_SNOW) {
00467 return (_settings_game.game_creation.landscape == LT_ARCTIC) ? MKCOLOUR(0x98575798) : MKCOLOUR(0xC25757C2);
00468 }
00469 return MKCOLOUR(0x54575754);
00470
00471 default:
00472 return ApplyMask(MKCOLOUR(0x54545454), &_smallmap_vehicles_andor[t]);
00473 }
00474 }
00475
00476
00477 static uint32 _owner_colours[OWNER_END + 1];
00478
00486 static inline uint32 GetSmallMapOwnerPixels(TileIndex tile, TileType t)
00487 {
00488 Owner o;
00489
00490 switch (t) {
00491 case MP_INDUSTRY: o = OWNER_END; break;
00492 case MP_HOUSE: o = OWNER_TOWN; break;
00493 default: o = GetTileOwner(tile); break;
00494
00495
00496
00497
00498 }
00499
00500 return _owner_colours[o];
00501 }
00502
00504 static const byte _vehicle_type_colours[6] = {
00505 184, 191, 152, 15, 215, 184
00506 };
00507
00508
00510 class SmallMapWindow : public Window {
00512 enum SmallMapType {
00513 SMT_CONTOUR,
00514 SMT_VEHICLES,
00515 SMT_INDUSTRY,
00516 SMT_ROUTES,
00517 SMT_VEGETATION,
00518 SMT_OWNER,
00519 };
00520
00522 enum ZoomLevelChange {
00523 ZLC_INITIALIZE,
00524 ZLC_ZOOM_OUT,
00525 ZLC_ZOOM_IN,
00526 };
00527
00528 static SmallMapType map_type;
00529 static bool show_towns;
00530
00531 static const uint LEGEND_BLOB_WIDTH = 8;
00532 static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2;
00533 uint min_number_of_columns;
00534 uint min_number_of_fixed_rows;
00535 uint column_width;
00536
00537 int32 scroll_x;
00538 int32 scroll_y;
00539 int32 subscroll;
00540 int zoom;
00541
00542 static const uint8 FORCE_REFRESH_PERIOD = 0x1F;
00543 uint8 refresh;
00544
00551 FORCEINLINE Point RemapTile(int tile_x, int tile_y) const
00552 {
00553 int x_offset = tile_x - this->scroll_x / TILE_SIZE;
00554 int y_offset = tile_y - this->scroll_y / TILE_SIZE;
00555
00556 if (this->zoom == 1) return RemapCoords(x_offset, y_offset, 0);
00557
00558
00559 if (x_offset < 0) x_offset -= this->zoom - 1;
00560 if (y_offset < 0) y_offset -= this->zoom - 1;
00561
00562 return RemapCoords(x_offset / this->zoom, y_offset / this->zoom, 0);
00563 }
00564
00575 FORCEINLINE Point PixelToTile(int px, int py, int *sub, bool add_sub = true) const
00576 {
00577 if (add_sub) px += this->subscroll;
00578
00579
00580
00581 Point pt = {((py >> 1) - (px >> 2)) * this->zoom, ((py >> 1) + (px >> 2)) * this->zoom};
00582 px &= 3;
00583
00584 if (py & 1) {
00585 if (px < 2) {
00586 pt.x += this->zoom;
00587 px += 2;
00588 } else {
00589 pt.y += this->zoom;
00590 px -= 2;
00591 }
00592 }
00593
00594 *sub = px;
00595 return pt;
00596 }
00597
00607 Point ComputeScroll(int tx, int ty, int x, int y, int *sub)
00608 {
00609 assert(x >= 0 && y >= 0);
00610
00611 int new_sub;
00612 Point tile_xy = PixelToTile(x, y, &new_sub, false);
00613 tx -= tile_xy.x;
00614 ty -= tile_xy.y;
00615
00616 Point scroll;
00617 if (new_sub == 0) {
00618 *sub = 0;
00619 scroll.x = (tx + this->zoom) * TILE_SIZE;
00620 scroll.y = (ty - this->zoom) * TILE_SIZE;
00621 } else {
00622 *sub = 4 - new_sub;
00623 scroll.x = (tx + 2 * this->zoom) * TILE_SIZE;
00624 scroll.y = (ty - 2 * this->zoom) * TILE_SIZE;
00625 }
00626 return scroll;
00627 }
00628
00634 void SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt)
00635 {
00636 static const int zoomlevels[] = {1, 2, 4, 6, 8};
00637 static const int MIN_ZOOM_INDEX = 0;
00638 static const int MAX_ZOOM_INDEX = lengthof(zoomlevels) - 1;
00639
00640 int new_index, cur_index, sub;
00641 Point tile;
00642 switch (change) {
00643 case ZLC_INITIALIZE:
00644 cur_index = - 1;
00645 new_index = MIN_ZOOM_INDEX;
00646 break;
00647
00648 case ZLC_ZOOM_IN:
00649 case ZLC_ZOOM_OUT:
00650 for (cur_index = MIN_ZOOM_INDEX; cur_index <= MAX_ZOOM_INDEX; cur_index++) {
00651 if (this->zoom == zoomlevels[cur_index]) break;
00652 }
00653 assert(cur_index <= MAX_ZOOM_INDEX);
00654
00655 tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub);
00656 new_index = Clamp(cur_index + ((change == ZLC_ZOOM_IN) ? -1 : 1), MIN_ZOOM_INDEX, MAX_ZOOM_INDEX);
00657 break;
00658
00659 default: NOT_REACHED();
00660 }
00661
00662 if (new_index != cur_index) {
00663 this->zoom = zoomlevels[new_index];
00664 if (cur_index >= 0) {
00665 Point new_tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub);
00666 this->SetNewScroll(this->scroll_x + (tile.x - new_tile.x) * TILE_SIZE,
00667 this->scroll_y + (tile.y - new_tile.y) * TILE_SIZE, sub);
00668 }
00669 this->SetWidgetDisabledState(SM_WIDGET_ZOOM_IN, this->zoom == zoomlevels[MIN_ZOOM_INDEX]);
00670 this->SetWidgetDisabledState(SM_WIDGET_ZOOM_OUT, this->zoom == zoomlevels[MAX_ZOOM_INDEX]);
00671 this->SetDirty();
00672 }
00673 }
00674
00680 inline uint32 GetTileColours(const TileArea &ta) const
00681 {
00682 int importance = 0;
00683 TileIndex tile = INVALID_TILE;
00684 TileType et = MP_VOID;
00685
00686 TILE_AREA_LOOP(ti, ta) {
00687 TileType ttype = GetEffectiveTileType(ti);
00688 if (_tiletype_importance[ttype] > importance) {
00689 importance = _tiletype_importance[ttype];
00690 tile = ti;
00691 et = ttype;
00692 }
00693 }
00694
00695 switch (this->map_type) {
00696 case SMT_CONTOUR:
00697 return GetSmallMapContoursPixels(tile, et);
00698
00699 case SMT_VEHICLES:
00700 return GetSmallMapVehiclesPixels(tile, et);
00701
00702 case SMT_INDUSTRY:
00703 return GetSmallMapIndustriesPixels(tile, et);
00704
00705 case SMT_ROUTES:
00706 return GetSmallMapRoutesPixels(tile, et);
00707
00708 case SMT_VEGETATION:
00709 return GetSmallMapVegetationPixels(tile, et);
00710
00711 case SMT_OWNER:
00712 return GetSmallMapOwnerPixels(tile, et);
00713
00714 default: NOT_REACHED();
00715 }
00716 }
00717
00732 void DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const
00733 {
00734 void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height);
00735 uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0;
00736
00737 do {
00738
00739 if (xc >= MapMaxX() || yc >= MapMaxY()) continue;
00740
00741
00742 if (dst < _screen.dst_ptr) continue;
00743 if (dst >= dst_ptr_abs_end) continue;
00744
00745
00746 TileArea ta;
00747 if (min_xy == 1 && (xc == 0 || yc == 0)) {
00748 if (this->zoom == 1) continue;
00749
00750 ta = TileArea(TileXY(max(min_xy, xc), max(min_xy, yc)), this->zoom - (xc == 0), this->zoom - (yc == 0));
00751 } else {
00752 ta = TileArea(TileXY(xc, yc), this->zoom, this->zoom);
00753 }
00754 ta.ClampToMap();
00755
00756 uint32 val = this->GetTileColours(ta);
00757 uint8 *val8 = (uint8 *)&val;
00758 int idx = max(0, -start_pos);
00759 for (int pos = max(0, start_pos); pos < end_pos; pos++) {
00760 blitter->SetPixel(dst, idx, 0, val8[idx]);
00761 idx++;
00762 }
00763
00764 } while (xc += this->zoom, yc += this->zoom, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0);
00765 }
00766
00772 void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const
00773 {
00774 const Vehicle *v;
00775 FOR_ALL_VEHICLES(v) {
00776 if (v->type == VEH_EFFECT) continue;
00777 if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue;
00778
00779
00780 Point pt = this->RemapTile(v->x_pos / TILE_SIZE, v->y_pos / TILE_SIZE);
00781
00782 int y = pt.y - dpi->top;
00783 if (!IsInsideMM(y, 0, dpi->height)) continue;
00784
00785 bool skip = false;
00786 int x = pt.x - this->subscroll - 3 - dpi->left;
00787 if (x < 0) {
00788
00789
00790 if (++x != 0) continue;
00791 skip = true;
00792 } else if (x >= dpi->width - 1) {
00793
00794 if (x != dpi->width - 1) continue;
00795 skip = true;
00796 }
00797
00798
00799 byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : 0xF;
00800
00801
00802 blitter->SetPixel(dpi->dst_ptr, x, y, colour);
00803 if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour);
00804 }
00805 }
00806
00811 void DrawTowns(const DrawPixelInfo *dpi) const
00812 {
00813 const Town *t;
00814 FOR_ALL_TOWNS(t) {
00815
00816 Point pt = this->RemapTile(TileX(t->xy), TileY(t->xy));
00817 int x = pt.x - this->subscroll - (t->sign.width_small >> 1);
00818 int y = pt.y;
00819
00820
00821 if (x + t->sign.width_small > dpi->left &&
00822 x < dpi->left + dpi->width &&
00823 y + FONT_HEIGHT_SMALL > dpi->top &&
00824 y < dpi->top + dpi->height) {
00825
00826 SetDParam(0, t->index);
00827 DrawString(x, x + t->sign.width_small, y, STR_SMALLMAP_TOWN);
00828 }
00829 }
00830 }
00831
00838 static inline void DrawVertMapIndicator(int x, int y, int y2)
00839 {
00840 GfxFillRect(x, y, x, y + 3, 69);
00841 GfxFillRect(x, y2 - 3, x, y2, 69);
00842 }
00843
00850 static inline void DrawHorizMapIndicator(int x, int x2, int y)
00851 {
00852 GfxFillRect(x, y, x + 3, y, 69);
00853 GfxFillRect(x2 - 3, y, x2, y, 69);
00854 }
00855
00859 void DrawMapIndicators() const
00860 {
00861
00862 const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
00863
00864 Point tile = InverseRemapCoords(vp->virtual_left, vp->virtual_top);
00865 Point tl = this->RemapTile(tile.x >> 4, tile.y >> 4);
00866 tl.x -= this->subscroll;
00867
00868 tile = InverseRemapCoords(vp->virtual_left + vp->virtual_width, vp->virtual_top + vp->virtual_height);
00869 Point br = this->RemapTile(tile.x >> 4, tile.y >> 4);
00870 br.x -= this->subscroll;
00871
00872 SmallMapWindow::DrawVertMapIndicator(tl.x, tl.y, br.y);
00873 SmallMapWindow::DrawVertMapIndicator(br.x, tl.y, br.y);
00874
00875 SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, tl.y);
00876 SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, br.y);
00877 }
00878
00890 void DrawSmallMap(DrawPixelInfo *dpi) const
00891 {
00892 Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
00893 DrawPixelInfo *old_dpi;
00894
00895 old_dpi = _cur_dpi;
00896 _cur_dpi = dpi;
00897
00898
00899 GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, 0);
00900
00901
00902 if (this->map_type == SMT_OWNER) {
00903 const Company *c;
00904
00905
00906 _owner_colours[OWNER_TOWN] = MKCOLOUR(0xB4B4B4B4);
00907 _owner_colours[OWNER_NONE] = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].default_colour;
00908 _owner_colours[OWNER_WATER] = MKCOLOUR(0xCACACACA);
00909 _owner_colours[OWNER_END] = MKCOLOUR(0x20202020);
00910
00911
00912 FOR_ALL_COMPANIES(c) {
00913 _owner_colours[c->index] = _colour_gradient[c->colour][5] * 0x01010101;
00914 }
00915 }
00916
00917
00918 int dx;
00919 Point tile = this->PixelToTile(dpi->left, dpi->top, &dx);
00920 int tile_x = this->scroll_x / TILE_SIZE + tile.x;
00921 int tile_y = this->scroll_y / TILE_SIZE + tile.y;
00922
00923 void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0);
00924 int x = - dx - 4;
00925 int y = 0;
00926
00927 for (;;) {
00928
00929 if (x >= -3) {
00930 if (x >= dpi->width) break;
00931
00932 int end_pos = min(dpi->width, x + 4);
00933 int reps = (dpi->height - y + 1) / 2;
00934 if (reps > 0) {
00935 this->DrawSmallMapColumn(ptr, tile_x, tile_y, dpi->pitch * 2, reps, x, end_pos, blitter);
00936 }
00937 }
00938
00939 if (y == 0) {
00940 tile_y += this->zoom;
00941 y++;
00942 ptr = blitter->MoveTo(ptr, 0, 1);
00943 } else {
00944 tile_x -= this->zoom;
00945 y--;
00946 ptr = blitter->MoveTo(ptr, 0, -1);
00947 }
00948 ptr = blitter->MoveTo(ptr, 2, 0);
00949 x += 2;
00950 }
00951
00952
00953 if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter);
00954
00955
00956 if (this->show_towns) this->DrawTowns(dpi);
00957
00958
00959 this->DrawMapIndicators();
00960
00961 _cur_dpi = old_dpi;
00962 }
00963
00964 public:
00965 SmallMapWindow(const WindowDesc *desc, int window_number) : Window(), refresh(FORCE_REFRESH_PERIOD)
00966 {
00967 this->InitNested(desc, window_number);
00968 this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
00969
00970 _smallmap_industry_show_heightmap = false;
00971 BuildLandLegend();
00972 this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_industry_show_heightmap);
00973
00974 this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
00975 this->GetWidget<NWidgetStacked>(SM_WIDGET_SELECTINDUSTRIES)->SetDisplayedPlane(this->map_type != SMT_INDUSTRY);
00976
00977 this->SetZoomLevel(ZLC_INITIALIZE, NULL);
00978 this->SmallMapCenterOnCurrentPos();
00979 }
00980
00984 inline uint GetMaxLegendHeight() const
00985 {
00986 uint num_rows = max(this->min_number_of_fixed_rows, (_smallmap_industry_count + this->min_number_of_columns - 1) / this->min_number_of_columns);
00987 return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
00988 }
00989
00993 inline uint GetMinLegendWidth() const
00994 {
00995 return WD_FRAMERECT_LEFT + this->min_number_of_columns * this->column_width;
00996 }
00997
01001 inline uint GetNumberColumnsLegend(uint width) const
01002 {
01003 return width / this->column_width;
01004 }
01005
01009 uint GetLegendHeight(uint width) const
01010 {
01011 uint num_columns = this->GetNumberColumnsLegend(width);
01012 uint num_rows = max(this->min_number_of_fixed_rows, (_smallmap_industry_count + num_columns - 1) / num_columns);
01013 return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
01014 }
01015
01016 virtual void SetStringParameters(int widget) const
01017 {
01018 switch (widget) {
01019 case SM_WIDGET_CAPTION:
01020 SetDParam(0, STR_SMALLMAP_TYPE_CONTOURS + this->map_type);
01021 break;
01022 }
01023 }
01024
01025 virtual void OnInit()
01026 {
01027 uint min_width = 0;
01028 this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS;
01029 this->min_number_of_fixed_rows = 0;
01030 for (uint i = 0; i < lengthof(_legend_table); i++) {
01031 uint height = 0;
01032 uint num_columns = 1;
01033 for (const LegendAndColour *tbl = _legend_table[i]; !tbl->end; ++tbl) {
01034 StringID str;
01035 if (i == SMT_INDUSTRY) {
01036 SetDParam(0, tbl->legend);
01037 SetDParam(1, IndustryPool::MAX_SIZE);
01038 str = STR_SMALLMAP_INDUSTRY;
01039 } else {
01040 if (tbl->col_break) {
01041 this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
01042 height = 0;
01043 num_columns++;
01044 }
01045 height++;
01046 str = tbl->legend;
01047 }
01048 min_width = max(GetStringBoundingBox(str).width, min_width);
01049 }
01050 this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
01051 this->min_number_of_columns = max(this->min_number_of_columns, num_columns);
01052 }
01053
01054
01055 this->column_width = min_width + LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
01056 }
01057
01058 virtual void DrawWidget(const Rect &r, int widget) const
01059 {
01060 switch (widget) {
01061 case SM_WIDGET_MAP: {
01062 DrawPixelInfo new_dpi;
01063 if (!FillDrawPixelInfo(&new_dpi, r.left + 1, r.top + 1, r.right - r.left - 1, r.bottom - r.top - 1)) return;
01064 this->DrawSmallMap(&new_dpi);
01065 } break;
01066
01067 case SM_WIDGET_LEGEND: {
01068 uint columns = this->GetNumberColumnsLegend(r.right - r.left + 1);
01069 uint number_of_rows = max(this->map_type == SMT_INDUSTRY ? (_smallmap_industry_count + columns - 1) / columns : 0, this->min_number_of_fixed_rows);
01070 bool rtl = _dynlang.text_dir == TD_RTL;
01071 uint y_org = r.top + WD_FRAMERECT_TOP;
01072 uint x = rtl ? r.right - this->column_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT;
01073 uint y = y_org;
01074 uint i = 0;
01075 uint row_height = FONT_HEIGHT_SMALL;
01076
01077 uint text_left = rtl ? 0 : LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT;
01078 uint text_right = this->column_width - 1 - (rtl ? LEGEND_BLOB_WIDTH + WD_FRAMERECT_RIGHT : 0);
01079 uint blob_left = rtl ? this->column_width - 1 - LEGEND_BLOB_WIDTH : 0;
01080 uint blob_right = rtl ? this->column_width - 1 : LEGEND_BLOB_WIDTH;
01081
01082 for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) {
01083 if (tbl->col_break || (this->map_type == SMT_INDUSTRY && i++ >= number_of_rows)) {
01084
01085
01086 x += rtl ? -(int)this->column_width : this->column_width;
01087 y = y_org;
01088 i = 1;
01089 }
01090
01091 if (this->map_type == SMT_INDUSTRY) {
01092
01093
01094 SetDParam(0, tbl->legend);
01095 assert(tbl->type < NUM_INDUSTRYTYPES);
01096 SetDParam(1, _industry_counts[tbl->type]);
01097 if (!tbl->show_on_map) {
01098
01099
01100 DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_GREY);
01101 } else {
01102 DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_BLACK);
01103 GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0);
01104 }
01105 } else {
01106
01107 GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0);
01108 DrawString(x + text_left, x + text_right, y, tbl->legend);
01109 }
01110 GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + row_height - 2, tbl->colour);
01111
01112 y += row_height;
01113 }
01114 }
01115 }
01116 }
01117
01118 virtual void OnPaint()
01119 {
01120 this->DrawWidgets();
01121 }
01122
01123 virtual void OnClick(Point pt, int widget, int click_count)
01124 {
01125 switch (widget) {
01126 case SM_WIDGET_MAP: {
01127
01128
01129
01130
01131
01132
01133
01134
01135 _left_button_clicked = false;
01136
01137 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01138 Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
01139 int sub;
01140 pt = this->PixelToTile(pt.x - wid->pos_x, pt.y - wid->pos_y, &sub);
01141 pt = RemapCoords(this->scroll_x + pt.x * TILE_SIZE + this->zoom * (TILE_SIZE - sub * TILE_SIZE / 4),
01142 this->scroll_y + pt.y * TILE_SIZE + sub * this->zoom * TILE_SIZE / 4, 0);
01143
01144 w->viewport->follow_vehicle = INVALID_VEHICLE;
01145 w->viewport->dest_scrollpos_x = pt.x - (w->viewport->virtual_width >> 1);
01146 w->viewport->dest_scrollpos_y = pt.y - (w->viewport->virtual_height >> 1);
01147
01148 this->SetDirty();
01149 } break;
01150
01151 case SM_WIDGET_ZOOM_IN:
01152 case SM_WIDGET_ZOOM_OUT: {
01153 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01154 Point pt = {wid->current_x / 2, wid->current_y / 2};
01155 this->SetZoomLevel((widget == SM_WIDGET_ZOOM_IN) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt);
01156 SndPlayFx(SND_15_BEEP);
01157 break;
01158 }
01159
01160 case SM_WIDGET_CONTOUR:
01161 case SM_WIDGET_VEHICLES:
01162 case SM_WIDGET_INDUSTRIES:
01163 case SM_WIDGET_ROUTES:
01164 case SM_WIDGET_VEGETATION:
01165 case SM_WIDGET_OWNERS:
01166 this->RaiseWidget(this->map_type + SM_WIDGET_CONTOUR);
01167 this->map_type = (SmallMapType)(widget - SM_WIDGET_CONTOUR);
01168 this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
01169
01170
01171 this->GetWidget<NWidgetStacked>(SM_WIDGET_SELECTINDUSTRIES)->SetDisplayedPlane(this->map_type != SMT_INDUSTRY);
01172
01173 this->SetDirty();
01174 SndPlayFx(SND_15_BEEP);
01175 break;
01176
01177 case SM_WIDGET_CENTERMAP:
01178 this->SmallMapCenterOnCurrentPos();
01179 this->HandleButtonClick(SM_WIDGET_CENTERMAP);
01180 SndPlayFx(SND_15_BEEP);
01181 break;
01182
01183 case SM_WIDGET_TOGGLETOWNNAME:
01184 this->show_towns = !this->show_towns;
01185 this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
01186
01187 this->SetDirty();
01188 SndPlayFx(SND_15_BEEP);
01189 break;
01190
01191 case SM_WIDGET_LEGEND:
01192
01193 if (this->map_type == SMT_INDUSTRY) {
01194
01195 const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_LEGEND);
01196 uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL;
01197 uint columns = this->GetNumberColumnsLegend(wi->current_x);
01198 uint number_of_rows = max((_smallmap_industry_count + columns - 1) / columns, this->min_number_of_fixed_rows);
01199 if (line >= number_of_rows) break;
01200
01201 bool rtl = _dynlang.text_dir == TD_RTL;
01202 int x = pt.x - wi->pos_x;
01203 if (rtl) x = wi->current_x - x;
01204 uint column = (x - WD_FRAMERECT_LEFT) / this->column_width;
01205
01206
01207 int industry_pos = (column * number_of_rows) + line;
01208 if (industry_pos < _smallmap_industry_count) {
01209 _legend_from_industries[industry_pos].show_on_map = !_legend_from_industries[industry_pos].show_on_map;
01210 }
01211
01212
01213 this->RaiseWidget(SM_WIDGET_ENABLEINDUSTRIES);
01214 this->RaiseWidget(SM_WIDGET_DISABLEINDUSTRIES);
01215 this->SetDirty();
01216 }
01217 break;
01218
01219 case SM_WIDGET_ENABLEINDUSTRIES:
01220 for (int i = 0; i != _smallmap_industry_count; i++) {
01221 _legend_from_industries[i].show_on_map = true;
01222 }
01223
01224 this->LowerWidget(SM_WIDGET_ENABLEINDUSTRIES);
01225 this->RaiseWidget(SM_WIDGET_DISABLEINDUSTRIES);
01226 this->SetDirty();
01227 break;
01228
01229 case SM_WIDGET_DISABLEINDUSTRIES:
01230 for (int i = 0; i != _smallmap_industry_count; i++) {
01231 _legend_from_industries[i].show_on_map = false;
01232 }
01233
01234 this->RaiseWidget(SM_WIDGET_ENABLEINDUSTRIES);
01235 this->LowerWidget(SM_WIDGET_DISABLEINDUSTRIES);
01236 this->SetDirty();
01237 break;
01238
01239 case SM_WIDGET_SHOW_HEIGHT:
01240 _smallmap_industry_show_heightmap = !_smallmap_industry_show_heightmap;
01241 this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_industry_show_heightmap);
01242 this->SetDirty();
01243 break;
01244 }
01245 }
01246
01247 virtual void OnRightClick(Point pt, int widget)
01248 {
01249 if (widget == SM_WIDGET_MAP) {
01250 if (_scrolling_viewport) return;
01251 _scrolling_viewport = true;
01252 }
01253 }
01254
01255 virtual void OnMouseWheel(int wheel)
01256 {
01257 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01258 int cursor_x = _cursor.pos.x - this->left - wid->pos_x;
01259 int cursor_y = _cursor.pos.y - this->top - wid->pos_y;
01260 if (IsInsideMM(cursor_x, 0, wid->current_x) && IsInsideMM(cursor_y, 0, wid->current_y)) {
01261 Point pt = {cursor_x, cursor_y};
01262 this->SetZoomLevel((wheel < 0) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt);
01263 }
01264 }
01265
01266 virtual void OnTick()
01267 {
01268
01269 if (--this->refresh != 0) return;
01270
01271 this->refresh = FORCE_REFRESH_PERIOD;
01272 this->SetDirty();
01273 }
01274
01282 void SetNewScroll(int sx, int sy, int sub)
01283 {
01284 const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01285 Point hv = InverseRemapCoords(wi->current_x * TILE_SIZE / 2, wi->current_y * TILE_SIZE / 2);
01286 hv.x *= this->zoom;
01287 hv.y *= this->zoom;
01288
01289 if (sx < -hv.x) {
01290 sx = -hv.x;
01291 sub = 0;
01292 }
01293 if (sx > (int)MapMaxX() * TILE_SIZE - hv.x) {
01294 sx = MapMaxX() * TILE_SIZE - hv.x;
01295 sub = 0;
01296 }
01297 if (sy < -hv.y) {
01298 sy = -hv.y;
01299 sub = 0;
01300 }
01301 if (sy > (int)MapMaxY() * TILE_SIZE - hv.y) {
01302 sy = MapMaxY() * TILE_SIZE - hv.y;
01303 sub = 0;
01304 }
01305
01306 this->scroll_x = sx;
01307 this->scroll_y = sy;
01308 this->subscroll = sub;
01309 }
01310
01311 virtual void OnScroll(Point delta)
01312 {
01313 _cursor.fix_at = true;
01314
01315
01316 int sub;
01317 Point pt = this->PixelToTile(delta.x, delta.y, &sub);
01318 this->SetNewScroll(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, sub);
01319
01320 this->SetDirty();
01321 }
01322
01323 void SmallMapCenterOnCurrentPos()
01324 {
01325 const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
01326 Point pt = InverseRemapCoords(vp->virtual_left + vp->virtual_width / 2, vp->virtual_top + vp->virtual_height / 2);
01327
01328 int sub;
01329 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01330 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);
01331 this->SetNewScroll(sxy.x, sxy.y, sub);
01332 this->SetDirty();
01333 }
01334 };
01335
01336 SmallMapWindow::SmallMapType SmallMapWindow::map_type = SMT_CONTOUR;
01337 bool SmallMapWindow::show_towns = true;
01338
01347 class NWidgetSmallmapDisplay : public NWidgetContainer {
01348 const SmallMapWindow *smallmap_window;
01349 public:
01350 NWidgetSmallmapDisplay() : NWidgetContainer(NWID_VERTICAL)
01351 {
01352 this->smallmap_window = NULL;
01353 }
01354
01355 virtual void SetupSmallestSize(Window *w, bool init_array)
01356 {
01357 NWidgetBase *display = this->head;
01358 NWidgetBase *bar = display->next;
01359
01360 display->SetupSmallestSize(w, init_array);
01361 bar->SetupSmallestSize(w, init_array);
01362
01363 this->smallmap_window = dynamic_cast<SmallMapWindow *>(w);
01364 this->smallest_x = max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth());
01365 this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetMaxLegendHeight());
01366 this->fill_x = max(display->fill_x, bar->fill_x);
01367 this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : min(display->fill_y, bar->fill_y);
01368 this->resize_x = max(display->resize_x, bar->resize_x);
01369 this->resize_y = min(display->resize_y, bar->resize_y);
01370 }
01371
01372 virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01373 {
01374 this->pos_x = x;
01375 this->pos_y = y;
01376 this->current_x = given_width;
01377 this->current_y = given_height;
01378
01379 NWidgetBase *display = this->head;
01380 NWidgetBase *bar = display->next;
01381
01382 if (sizing == ST_SMALLEST) {
01383 this->smallest_x = given_width;
01384 this->smallest_y = given_height;
01385
01386 display->AssignSizePosition(ST_SMALLEST, x, y, display->smallest_x, display->smallest_y, rtl);
01387 bar->AssignSizePosition(ST_SMALLEST, x, y + display->smallest_y, bar->smallest_x, bar->smallest_y, rtl);
01388 }
01389
01390 uint bar_height = max(bar->smallest_y, this->smallmap_window->GetLegendHeight(given_width - bar->smallest_x));
01391 uint display_height = given_height - bar_height;
01392 display->AssignSizePosition(ST_RESIZE, x, y, given_width, display_height, rtl);
01393 bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl);
01394 }
01395
01396 virtual NWidgetCore *GetWidgetFromPos(int x, int y)
01397 {
01398 if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
01399 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01400 NWidgetCore *widget = child_wid->GetWidgetFromPos(x, y);
01401 if (widget != NULL) return widget;
01402 }
01403 return NULL;
01404 }
01405
01406 virtual void Draw(const Window *w)
01407 {
01408 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) child_wid->Draw(w);
01409 }
01410 };
01411
01413 static const NWidgetPart _nested_smallmap_display[] = {
01414 NWidget(WWT_PANEL, COLOUR_BROWN, SM_WIDGET_MAP_BORDER),
01415 NWidget(WWT_INSET, COLOUR_BROWN, SM_WIDGET_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(),
01416 EndContainer(),
01417 };
01418
01420 static const NWidgetPart _nested_smallmap_bar[] = {
01421 NWidget(WWT_PANEL, COLOUR_BROWN),
01422 NWidget(NWID_HORIZONTAL),
01423 NWidget(WWT_EMPTY, INVALID_COLOUR, SM_WIDGET_LEGEND), SetResize(1, 1),
01424 NWidget(NWID_VERTICAL),
01425
01426 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01427 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN),
01428 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_CENTERMAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER),
01429 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_CONTOUR), SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP),
01430 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEHICLES), SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP),
01431 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_INDUSTRIES), SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP),
01432 EndContainer(),
01433
01434 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01435 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT),
01436 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_TOGGLETOWNNAME), SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF),
01437 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_ROUTES), SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON),
01438 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEGETATION), SetDataTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP),
01439 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_OWNERS), SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP),
01440 EndContainer(),
01441 NWidget(NWID_SPACER), SetResize(0, 1),
01442 EndContainer(),
01443 EndContainer(),
01444 EndContainer(),
01445 };
01446
01447 static NWidgetBase *SmallMapDisplay(int *biggest_index)
01448 {
01449 NWidgetContainer *map_display = new NWidgetSmallmapDisplay;
01450
01451 MakeNWidgets(_nested_smallmap_display, lengthof(_nested_smallmap_display), biggest_index, map_display);
01452 MakeNWidgets(_nested_smallmap_bar, lengthof(_nested_smallmap_bar), biggest_index, map_display);
01453 return map_display;
01454 }
01455
01456
01457 static const NWidgetPart _nested_smallmap_widgets[] = {
01458 NWidget(NWID_HORIZONTAL),
01459 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
01460 NWidget(WWT_CAPTION, COLOUR_BROWN, SM_WIDGET_CAPTION), SetDataTip(STR_SMALLMAP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01461 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
01462 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
01463 EndContainer(),
01464 NWidgetFunction(SmallMapDisplay),
01465
01466 NWidget(NWID_HORIZONTAL),
01467 NWidget(WWT_PANEL, COLOUR_BROWN),
01468 NWidget(NWID_HORIZONTAL),
01469 NWidget(NWID_SELECTION, INVALID_COLOUR, SM_WIDGET_SELECTINDUSTRIES),
01470 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01471 NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_ENABLEINDUSTRIES), SetDataTip(STR_SMALLMAP_ENABLE_ALL, STR_SMALLMAP_TOOLTIP_ENABLE_ALL),
01472 NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_DISABLEINDUSTRIES), SetDataTip(STR_SMALLMAP_DISABLE_ALL, STR_SMALLMAP_TOOLTIP_DISABLE_ALL),
01473 NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_SHOW_HEIGHT), SetDataTip(STR_SMALLMAP_SHOW_HEIGHT, STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT),
01474 EndContainer(),
01475 NWidget(NWID_SPACER), SetFill(1, 1),
01476 EndContainer(),
01477 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
01478 EndContainer(),
01479 EndContainer(),
01480 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
01481 EndContainer(),
01482 };
01483
01484 static const WindowDesc _smallmap_desc(
01485 WDP_AUTO, 446, 314,
01486 WC_SMALLMAP, WC_NONE,
01487 WDF_UNCLICK_BUTTONS,
01488 _nested_smallmap_widgets, lengthof(_nested_smallmap_widgets)
01489 );
01490
01491 void ShowSmallMap()
01492 {
01493 AllocateWindowDescFront<SmallMapWindow>(&_smallmap_desc, 0);
01494 }
01495
01504 bool ScrollMainWindowTo(int x, int y, int z, bool instant)
01505 {
01506 bool res = ScrollWindowTo(x, y, z, FindWindowById(WC_MAIN_WINDOW, 0), instant);
01507
01508
01509
01510
01511
01512 if (res) return res;
01513
01514 SmallMapWindow *w = dynamic_cast<SmallMapWindow*>(FindWindowById(WC_SMALLMAP, 0));
01515 if (w != NULL) w->SmallMapCenterOnCurrentPos();
01516
01517 return res;
01518 }