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 = MP_CLEAR;
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 }
00423
00424
00425 const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour];
00426 return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]);
00427 }
00428
00429
00430 static const uint32 _vegetation_clear_bits[] = {
00431 MKCOLOUR(0x54545454),
00432 MKCOLOUR(0x52525252),
00433 MKCOLOUR(0x0A0A0A0A),
00434 MKCOLOUR(0x25252525),
00435 MKCOLOUR(0x98989898),
00436 MKCOLOUR(0xC2C2C2C2),
00437 MKCOLOUR(0x54545454),
00438 MKCOLOUR(0x54545454),
00439 };
00440
00448 static inline uint32 GetSmallMapVegetationPixels(TileIndex tile, TileType t)
00449 {
00450 switch (t) {
00451 case MP_CLEAR:
00452 return (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) < 3) ? MKCOLOUR(0x37373737) : _vegetation_clear_bits[GetClearGround(tile)];
00453
00454 case MP_INDUSTRY:
00455 return GetIndustrySpec(Industry::GetByTile(tile)->type)->check_proc == CHECK_FOREST ? MKCOLOUR(0xD0D0D0D0) : MKCOLOUR(0xB5B5B5B5);
00456
00457 case MP_TREES:
00458 if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT || GetTreeGround(tile) == TREE_GROUND_ROUGH_SNOW) {
00459 return (_settings_game.game_creation.landscape == LT_ARCTIC) ? MKCOLOUR(0x98575798) : MKCOLOUR(0xC25757C2);
00460 }
00461 return MKCOLOUR(0x54575754);
00462
00463 default:
00464 return ApplyMask(MKCOLOUR(0x54545454), &_smallmap_vehicles_andor[t]);
00465 }
00466 }
00467
00468
00469 static uint32 _owner_colours[OWNER_END + 1];
00470
00478 static inline uint32 GetSmallMapOwnerPixels(TileIndex tile, TileType t)
00479 {
00480 Owner o;
00481
00482 switch (t) {
00483 case MP_INDUSTRY: o = OWNER_END; break;
00484 case MP_HOUSE: o = OWNER_TOWN; break;
00485 default: o = GetTileOwner(tile); break;
00486
00487
00488
00489
00490 }
00491
00492 return _owner_colours[o];
00493 }
00494
00496 static const byte _vehicle_type_colours[6] = {
00497 184, 191, 152, 15, 215, 184
00498 };
00499
00500
00502 class SmallMapWindow : public Window {
00504 enum SmallMapType {
00505 SMT_CONTOUR,
00506 SMT_VEHICLES,
00507 SMT_INDUSTRY,
00508 SMT_ROUTES,
00509 SMT_VEGETATION,
00510 SMT_OWNER,
00511 };
00512
00514 enum ZoomLevelChange {
00515 ZLC_INITIALIZE,
00516 ZLC_ZOOM_OUT,
00517 ZLC_ZOOM_IN,
00518 };
00519
00520 static SmallMapType map_type;
00521 static bool show_towns;
00522
00523 static const uint LEGEND_BLOB_WIDTH = 8;
00524 static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2;
00525 uint min_number_of_columns;
00526 uint min_number_of_fixed_rows;
00527 uint column_width;
00528
00529 int32 scroll_x;
00530 int32 scroll_y;
00531 int32 subscroll;
00532 int zoom;
00533
00534 static const uint8 FORCE_REFRESH_PERIOD = 0x1F;
00535 uint8 refresh;
00536
00543 FORCEINLINE Point RemapTile(int tile_x, int tile_y) const
00544 {
00545 int x_offset = tile_x - this->scroll_x / TILE_SIZE;
00546 int y_offset = tile_y - this->scroll_y / TILE_SIZE;
00547
00548 if (this->zoom == 1) return RemapCoords(x_offset, y_offset, 0);
00549
00550
00551 if (x_offset < 0) x_offset -= this->zoom - 1;
00552 if (y_offset < 0) y_offset -= this->zoom - 1;
00553
00554 return RemapCoords(x_offset / this->zoom, y_offset / this->zoom, 0);
00555 }
00556
00567 FORCEINLINE Point PixelToTile(int px, int py, int *sub, bool add_sub = true) const
00568 {
00569 if (add_sub) px += this->subscroll;
00570
00571
00572
00573 Point pt = {((py >> 1) - (px >> 2)) * this->zoom, ((py >> 1) + (px >> 2)) * this->zoom};
00574 px &= 3;
00575
00576 if (py & 1) {
00577 if (px < 2) {
00578 pt.x += this->zoom;
00579 px += 2;
00580 } else {
00581 pt.y += this->zoom;
00582 px -= 2;
00583 }
00584 }
00585
00586 *sub = px;
00587 return pt;
00588 }
00589
00599 Point ComputeScroll(int tx, int ty, int x, int y, int *sub)
00600 {
00601 assert(x >= 0 && y >= 0);
00602
00603 int new_sub;
00604 Point tile_xy = PixelToTile(x, y, &new_sub, false);
00605 tx -= tile_xy.x;
00606 ty -= tile_xy.y;
00607
00608 Point scroll;
00609 if (new_sub == 0) {
00610 *sub = 0;
00611 scroll.x = (tx + this->zoom) * TILE_SIZE;
00612 scroll.y = (ty - this->zoom) * TILE_SIZE;
00613 } else {
00614 *sub = 4 - new_sub;
00615 scroll.x = (tx + 2 * this->zoom) * TILE_SIZE;
00616 scroll.y = (ty - 2 * this->zoom) * TILE_SIZE;
00617 }
00618 return scroll;
00619 }
00620
00626 void SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt)
00627 {
00628 static const int zoomlevels[] = {1, 2, 4, 6, 8};
00629 static const int MIN_ZOOM_INDEX = 0;
00630 static const int MAX_ZOOM_INDEX = lengthof(zoomlevels) - 1;
00631
00632 int new_index, cur_index, sub;
00633 Point tile;
00634 switch (change) {
00635 case ZLC_INITIALIZE:
00636 cur_index = - 1;
00637 new_index = MIN_ZOOM_INDEX;
00638 break;
00639
00640 case ZLC_ZOOM_IN:
00641 case ZLC_ZOOM_OUT:
00642 for (cur_index = MIN_ZOOM_INDEX; cur_index <= MAX_ZOOM_INDEX; cur_index++) {
00643 if (this->zoom == zoomlevels[cur_index]) break;
00644 }
00645 assert(cur_index <= MAX_ZOOM_INDEX);
00646
00647 tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub);
00648 new_index = Clamp(cur_index + ((change == ZLC_ZOOM_IN) ? -1 : 1), MIN_ZOOM_INDEX, MAX_ZOOM_INDEX);
00649 break;
00650
00651 default: NOT_REACHED();
00652 }
00653
00654 if (new_index != cur_index) {
00655 this->zoom = zoomlevels[new_index];
00656 if (cur_index >= 0) {
00657 Point new_tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub);
00658 this->SetNewScroll(this->scroll_x + (tile.x - new_tile.x) * TILE_SIZE,
00659 this->scroll_y + (tile.y - new_tile.y) * TILE_SIZE, sub);
00660 }
00661 this->SetWidgetDisabledState(SM_WIDGET_ZOOM_IN, this->zoom == zoomlevels[MIN_ZOOM_INDEX]);
00662 this->SetWidgetDisabledState(SM_WIDGET_ZOOM_OUT, this->zoom == zoomlevels[MAX_ZOOM_INDEX]);
00663 this->SetDirty();
00664 }
00665 }
00666
00672 inline uint32 GetTileColours(const TileArea &ta) const
00673 {
00674 int importance = 0;
00675 TileIndex tile = INVALID_TILE;
00676 TileType et = MP_VOID;
00677
00678 TILE_AREA_LOOP(ti, ta) {
00679 TileType ttype = GetEffectiveTileType(ti);
00680 if (_tiletype_importance[ttype] > importance) {
00681 importance = _tiletype_importance[ttype];
00682 tile = ti;
00683 et = ttype;
00684 }
00685 }
00686
00687 switch (this->map_type) {
00688 case SMT_CONTOUR:
00689 return GetSmallMapContoursPixels(tile, et);
00690
00691 case SMT_VEHICLES:
00692 return GetSmallMapVehiclesPixels(tile, et);
00693
00694 case SMT_INDUSTRY:
00695 return GetSmallMapIndustriesPixels(tile, et);
00696
00697 case SMT_ROUTES:
00698 return GetSmallMapRoutesPixels(tile, et);
00699
00700 case SMT_VEGETATION:
00701 return GetSmallMapVegetationPixels(tile, et);
00702
00703 case SMT_OWNER:
00704 return GetSmallMapOwnerPixels(tile, et);
00705
00706 default: NOT_REACHED();
00707 }
00708 }
00709
00724 void DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const
00725 {
00726 void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height);
00727 uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0;
00728
00729 do {
00730
00731 if (xc >= MapMaxX() || yc >= MapMaxY()) continue;
00732
00733
00734 if (dst < _screen.dst_ptr) continue;
00735 if (dst >= dst_ptr_abs_end) continue;
00736
00737
00738 TileArea ta;
00739 if (min_xy == 1 && (xc == 0 || yc == 0)) {
00740 if (this->zoom == 1) continue;
00741
00742 ta = TileArea(TileXY(max(min_xy, xc), max(min_xy, yc)), this->zoom - (xc == 0), this->zoom - (yc == 0));
00743 } else {
00744 ta = TileArea(TileXY(xc, yc), this->zoom, this->zoom);
00745 }
00746 ta.ClampToMap();
00747
00748 uint32 val = this->GetTileColours(ta);
00749 uint8 *val8 = (uint8 *)&val;
00750 int idx = max(0, -start_pos);
00751 for (int pos = max(0, start_pos); pos < end_pos; pos++) {
00752 blitter->SetPixel(dst, idx, 0, val8[idx]);
00753 idx++;
00754 }
00755
00756 } while (xc += this->zoom, yc += this->zoom, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0);
00757 }
00758
00764 void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const
00765 {
00766 const Vehicle *v;
00767 FOR_ALL_VEHICLES(v) {
00768 if (v->type == VEH_EFFECT) continue;
00769 if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue;
00770
00771
00772 Point pt = this->RemapTile(v->x_pos / TILE_SIZE, v->y_pos / TILE_SIZE);
00773
00774 int y = pt.y - dpi->top;
00775 if (!IsInsideMM(y, 0, dpi->height)) continue;
00776
00777 bool skip = false;
00778 int x = pt.x - this->subscroll - 3 - dpi->left;
00779 if (x < 0) {
00780
00781
00782 if (++x != 0) continue;
00783 skip = true;
00784 } else if (x >= dpi->width - 1) {
00785
00786 if (x != dpi->width - 1) continue;
00787 skip = true;
00788 }
00789
00790
00791 byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : 0xF;
00792
00793
00794 blitter->SetPixel(dpi->dst_ptr, x, y, colour);
00795 if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour);
00796 }
00797 }
00798
00803 void DrawTowns(const DrawPixelInfo *dpi) const
00804 {
00805 const Town *t;
00806 FOR_ALL_TOWNS(t) {
00807
00808 Point pt = this->RemapTile(TileX(t->xy), TileY(t->xy));
00809 int x = pt.x - this->subscroll - (t->sign.width_small >> 1);
00810 int y = pt.y;
00811
00812
00813 if (x + t->sign.width_small > dpi->left &&
00814 x < dpi->left + dpi->width &&
00815 y + FONT_HEIGHT_SMALL > dpi->top &&
00816 y < dpi->top + dpi->height) {
00817
00818 SetDParam(0, t->index);
00819 DrawString(x, x + t->sign.width_small, y, STR_SMALLMAP_TOWN);
00820 }
00821 }
00822 }
00823
00830 static inline void DrawVertMapIndicator(int x, int y, int y2)
00831 {
00832 GfxFillRect(x, y, x, y + 3, 69);
00833 GfxFillRect(x, y2 - 3, x, y2, 69);
00834 }
00835
00842 static inline void DrawHorizMapIndicator(int x, int x2, int y)
00843 {
00844 GfxFillRect(x, y, x + 3, y, 69);
00845 GfxFillRect(x2 - 3, y, x2, y, 69);
00846 }
00847
00851 void DrawMapIndicators() const
00852 {
00853
00854 const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
00855
00856 Point tile = InverseRemapCoords(vp->virtual_left, vp->virtual_top);
00857 Point tl = this->RemapTile(tile.x >> 4, tile.y >> 4);
00858 tl.x -= this->subscroll;
00859
00860 tile = InverseRemapCoords(vp->virtual_left + vp->virtual_width, vp->virtual_top + vp->virtual_height);
00861 Point br = this->RemapTile(tile.x >> 4, tile.y >> 4);
00862 br.x -= this->subscroll;
00863
00864 SmallMapWindow::DrawVertMapIndicator(tl.x, tl.y, br.y);
00865 SmallMapWindow::DrawVertMapIndicator(br.x, tl.y, br.y);
00866
00867 SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, tl.y);
00868 SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, br.y);
00869 }
00870
00882 void DrawSmallMap(DrawPixelInfo *dpi) const
00883 {
00884 Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
00885 DrawPixelInfo *old_dpi;
00886
00887 old_dpi = _cur_dpi;
00888 _cur_dpi = dpi;
00889
00890
00891 GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, 0);
00892
00893
00894 if (this->map_type == SMT_OWNER) {
00895 const Company *c;
00896
00897
00898 _owner_colours[OWNER_TOWN] = MKCOLOUR(0xB4B4B4B4);
00899 _owner_colours[OWNER_NONE] = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].default_colour;
00900 _owner_colours[OWNER_WATER] = MKCOLOUR(0xCACACACA);
00901 _owner_colours[OWNER_END] = MKCOLOUR(0x20202020);
00902
00903
00904 FOR_ALL_COMPANIES(c) {
00905 _owner_colours[c->index] = _colour_gradient[c->colour][5] * 0x01010101;
00906 }
00907 }
00908
00909
00910 int dx;
00911 Point tile = this->PixelToTile(dpi->left, dpi->top, &dx);
00912 int tile_x = this->scroll_x / TILE_SIZE + tile.x;
00913 int tile_y = this->scroll_y / TILE_SIZE + tile.y;
00914
00915 void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0);
00916 int x = - dx - 4;
00917 int y = 0;
00918
00919 for (;;) {
00920
00921 if (x >= -3) {
00922 if (x >= dpi->width) break;
00923
00924 int end_pos = min(dpi->width, x + 4);
00925 int reps = (dpi->height - y + 1) / 2;
00926 if (reps > 0) {
00927 this->DrawSmallMapColumn(ptr, tile_x, tile_y, dpi->pitch * 2, reps, x, end_pos, blitter);
00928 }
00929 }
00930
00931 if (y == 0) {
00932 tile_y += this->zoom;
00933 y++;
00934 ptr = blitter->MoveTo(ptr, 0, 1);
00935 } else {
00936 tile_x -= this->zoom;
00937 y--;
00938 ptr = blitter->MoveTo(ptr, 0, -1);
00939 }
00940 ptr = blitter->MoveTo(ptr, 2, 0);
00941 x += 2;
00942 }
00943
00944
00945 if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter);
00946
00947
00948 if (this->show_towns) this->DrawTowns(dpi);
00949
00950
00951 this->DrawMapIndicators();
00952
00953 _cur_dpi = old_dpi;
00954 }
00955
00956 public:
00957 SmallMapWindow(const WindowDesc *desc, int window_number) : Window(), refresh(FORCE_REFRESH_PERIOD)
00958 {
00959 this->InitNested(desc, window_number);
00960 this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
00961
00962 _smallmap_industry_show_heightmap = false;
00963 BuildLandLegend();
00964 this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_industry_show_heightmap);
00965
00966 this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
00967 this->GetWidget<NWidgetStacked>(SM_WIDGET_SELECTINDUSTRIES)->SetDisplayedPlane(this->map_type != SMT_INDUSTRY);
00968
00969 this->SetZoomLevel(ZLC_INITIALIZE, NULL);
00970 this->SmallMapCenterOnCurrentPos();
00971 }
00972
00976 inline uint GetMaxLegendHeight() const
00977 {
00978 uint num_rows = max(this->min_number_of_fixed_rows, (_smallmap_industry_count + this->min_number_of_columns - 1) / this->min_number_of_columns);
00979 return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
00980 }
00981
00985 inline uint GetMinLegendWidth() const
00986 {
00987 return WD_FRAMERECT_LEFT + this->min_number_of_columns * this->column_width;
00988 }
00989
00993 inline uint GetNumberColumnsLegend(uint width) const
00994 {
00995 return width / this->column_width;
00996 }
00997
01001 uint GetLegendHeight(uint width) const
01002 {
01003 uint num_columns = this->GetNumberColumnsLegend(width);
01004 uint num_rows = max(this->min_number_of_fixed_rows, (_smallmap_industry_count + num_columns - 1) / num_columns);
01005 return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
01006 }
01007
01008 virtual void SetStringParameters(int widget) const
01009 {
01010 switch (widget) {
01011 case SM_WIDGET_CAPTION:
01012 SetDParam(0, STR_SMALLMAP_TYPE_CONTOURS + this->map_type);
01013 break;
01014 }
01015 }
01016
01017 virtual void OnInit()
01018 {
01019 uint min_width = 0;
01020 this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS;
01021 this->min_number_of_fixed_rows = 0;
01022 for (uint i = 0; i < lengthof(_legend_table); i++) {
01023 uint height = 0;
01024 uint num_columns = 1;
01025 for (const LegendAndColour *tbl = _legend_table[i]; !tbl->end; ++tbl) {
01026 StringID str;
01027 if (i == SMT_INDUSTRY) {
01028 SetDParam(0, tbl->legend);
01029 SetDParam(1, IndustryPool::MAX_SIZE);
01030 str = STR_SMALLMAP_INDUSTRY;
01031 } else {
01032 if (tbl->col_break) {
01033 this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
01034 height = 0;
01035 num_columns++;
01036 }
01037 height++;
01038 str = tbl->legend;
01039 }
01040 min_width = max(GetStringBoundingBox(str).width, min_width);
01041 }
01042 this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
01043 this->min_number_of_columns = max(this->min_number_of_columns, num_columns);
01044 }
01045
01046
01047 this->column_width = min_width + LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
01048 }
01049
01050 virtual void DrawWidget(const Rect &r, int widget) const
01051 {
01052 switch (widget) {
01053 case SM_WIDGET_MAP: {
01054 DrawPixelInfo new_dpi;
01055 if (!FillDrawPixelInfo(&new_dpi, r.left + 1, r.top + 1, r.right - r.left - 1, r.bottom - r.top - 1)) return;
01056 this->DrawSmallMap(&new_dpi);
01057 } break;
01058
01059 case SM_WIDGET_LEGEND: {
01060 uint columns = this->GetNumberColumnsLegend(r.right - r.left + 1);
01061 uint number_of_rows = max(this->map_type == SMT_INDUSTRY ? (_smallmap_industry_count + columns - 1) / columns : 0, this->min_number_of_fixed_rows);
01062 bool rtl = _dynlang.text_dir == TD_RTL;
01063 uint y_org = r.top + WD_FRAMERECT_TOP;
01064 uint x = rtl ? r.right - this->column_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT;
01065 uint y = y_org;
01066 uint i = 0;
01067 uint row_height = FONT_HEIGHT_SMALL;
01068
01069 uint text_left = rtl ? 0 : LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT;
01070 uint text_right = this->column_width - 1 - (rtl ? LEGEND_BLOB_WIDTH + WD_FRAMERECT_RIGHT : 0);
01071 uint blob_left = rtl ? this->column_width - 1 - LEGEND_BLOB_WIDTH : 0;
01072 uint blob_right = rtl ? this->column_width - 1 : LEGEND_BLOB_WIDTH;
01073
01074 for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) {
01075 if (tbl->col_break || (this->map_type == SMT_INDUSTRY && i++ >= number_of_rows)) {
01076
01077
01078 x += rtl ? -(int)this->column_width : this->column_width;
01079 y = y_org;
01080 i = 1;
01081 }
01082
01083 if (this->map_type == SMT_INDUSTRY) {
01084
01085
01086 SetDParam(0, tbl->legend);
01087 assert(tbl->type < NUM_INDUSTRYTYPES);
01088 SetDParam(1, _industry_counts[tbl->type]);
01089 if (!tbl->show_on_map) {
01090
01091
01092 DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_GREY);
01093 } else {
01094 DrawString(x + text_left, x + text_right, y, STR_SMALLMAP_INDUSTRY, TC_BLACK);
01095 GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0);
01096 }
01097 } else {
01098
01099 GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, 0);
01100 DrawString(x + text_left, x + text_right, y, tbl->legend);
01101 }
01102 GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + row_height - 2, tbl->colour);
01103
01104 y += row_height;
01105 }
01106 }
01107 }
01108 }
01109
01110 virtual void OnPaint()
01111 {
01112 this->DrawWidgets();
01113 }
01114
01115 virtual void OnClick(Point pt, int widget, int click_count)
01116 {
01117 switch (widget) {
01118 case SM_WIDGET_MAP: {
01119
01120
01121
01122
01123
01124
01125
01126
01127 _left_button_clicked = false;
01128
01129 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01130 Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
01131 int sub;
01132 pt = this->PixelToTile(pt.x - wid->pos_x, pt.y - wid->pos_y, &sub);
01133 pt = RemapCoords(this->scroll_x + pt.x * TILE_SIZE + this->zoom * (TILE_SIZE - sub * TILE_SIZE / 4),
01134 this->scroll_y + pt.y * TILE_SIZE + sub * this->zoom * TILE_SIZE / 4, 0);
01135
01136 w->viewport->follow_vehicle = INVALID_VEHICLE;
01137 w->viewport->dest_scrollpos_x = pt.x - (w->viewport->virtual_width >> 1);
01138 w->viewport->dest_scrollpos_y = pt.y - (w->viewport->virtual_height >> 1);
01139
01140 this->SetDirty();
01141 } break;
01142
01143 case SM_WIDGET_ZOOM_IN:
01144 case SM_WIDGET_ZOOM_OUT: {
01145 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01146 Point pt = {wid->current_x / 2, wid->current_y / 2};
01147 this->SetZoomLevel((widget == SM_WIDGET_ZOOM_IN) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt);
01148 SndPlayFx(SND_15_BEEP);
01149 break;
01150 }
01151
01152 case SM_WIDGET_CONTOUR:
01153 case SM_WIDGET_VEHICLES:
01154 case SM_WIDGET_INDUSTRIES:
01155 case SM_WIDGET_ROUTES:
01156 case SM_WIDGET_VEGETATION:
01157 case SM_WIDGET_OWNERS:
01158 this->RaiseWidget(this->map_type + SM_WIDGET_CONTOUR);
01159 this->map_type = (SmallMapType)(widget - SM_WIDGET_CONTOUR);
01160 this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
01161
01162
01163 this->GetWidget<NWidgetStacked>(SM_WIDGET_SELECTINDUSTRIES)->SetDisplayedPlane(this->map_type != SMT_INDUSTRY);
01164
01165 this->SetDirty();
01166 SndPlayFx(SND_15_BEEP);
01167 break;
01168
01169 case SM_WIDGET_CENTERMAP:
01170 this->SmallMapCenterOnCurrentPos();
01171 this->HandleButtonClick(SM_WIDGET_CENTERMAP);
01172 SndPlayFx(SND_15_BEEP);
01173 break;
01174
01175 case SM_WIDGET_TOGGLETOWNNAME:
01176 this->show_towns = !this->show_towns;
01177 this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
01178
01179 this->SetDirty();
01180 SndPlayFx(SND_15_BEEP);
01181 break;
01182
01183 case SM_WIDGET_LEGEND:
01184
01185 if (this->map_type == SMT_INDUSTRY) {
01186
01187 const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_LEGEND);
01188 uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL;
01189 uint columns = this->GetNumberColumnsLegend(wi->current_x);
01190 uint number_of_rows = max((_smallmap_industry_count + columns - 1) / columns, this->min_number_of_fixed_rows);
01191 if (line >= number_of_rows) break;
01192
01193 bool rtl = _dynlang.text_dir == TD_RTL;
01194 int x = pt.x - wi->pos_x;
01195 if (rtl) x = wi->current_x - x;
01196 uint column = (x - WD_FRAMERECT_LEFT) / this->column_width;
01197
01198
01199 int industry_pos = (column * number_of_rows) + line;
01200 if (industry_pos < _smallmap_industry_count) {
01201 _legend_from_industries[industry_pos].show_on_map = !_legend_from_industries[industry_pos].show_on_map;
01202 }
01203
01204
01205 this->RaiseWidget(SM_WIDGET_ENABLEINDUSTRIES);
01206 this->RaiseWidget(SM_WIDGET_DISABLEINDUSTRIES);
01207 this->SetDirty();
01208 }
01209 break;
01210
01211 case SM_WIDGET_ENABLEINDUSTRIES:
01212 for (int i = 0; i != _smallmap_industry_count; i++) {
01213 _legend_from_industries[i].show_on_map = true;
01214 }
01215
01216 this->LowerWidget(SM_WIDGET_ENABLEINDUSTRIES);
01217 this->RaiseWidget(SM_WIDGET_DISABLEINDUSTRIES);
01218 this->SetDirty();
01219 break;
01220
01221 case SM_WIDGET_DISABLEINDUSTRIES:
01222 for (int i = 0; i != _smallmap_industry_count; i++) {
01223 _legend_from_industries[i].show_on_map = false;
01224 }
01225
01226 this->RaiseWidget(SM_WIDGET_ENABLEINDUSTRIES);
01227 this->LowerWidget(SM_WIDGET_DISABLEINDUSTRIES);
01228 this->SetDirty();
01229 break;
01230
01231 case SM_WIDGET_SHOW_HEIGHT:
01232 _smallmap_industry_show_heightmap = !_smallmap_industry_show_heightmap;
01233 this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_industry_show_heightmap);
01234 this->SetDirty();
01235 break;
01236 }
01237 }
01238
01239 virtual void OnRightClick(Point pt, int widget)
01240 {
01241 if (widget == SM_WIDGET_MAP) {
01242 if (_scrolling_viewport) return;
01243 _scrolling_viewport = true;
01244 }
01245 }
01246
01247 virtual void OnMouseWheel(int wheel)
01248 {
01249 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01250 int cursor_x = _cursor.pos.x - this->left - wid->pos_x;
01251 int cursor_y = _cursor.pos.y - this->top - wid->pos_y;
01252 if (IsInsideMM(cursor_x, 0, wid->current_x) && IsInsideMM(cursor_y, 0, wid->current_y)) {
01253 Point pt = {cursor_x, cursor_y};
01254 this->SetZoomLevel((wheel < 0) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt);
01255 }
01256 }
01257
01258 virtual void OnTick()
01259 {
01260
01261 if (--this->refresh != 0) return;
01262
01263 this->refresh = FORCE_REFRESH_PERIOD;
01264 this->SetDirty();
01265 }
01266
01274 void SetNewScroll(int sx, int sy, int sub)
01275 {
01276 const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01277 Point hv = InverseRemapCoords(wi->current_x * TILE_SIZE / 2, wi->current_y * TILE_SIZE / 2);
01278 hv.x *= this->zoom;
01279 hv.y *= this->zoom;
01280
01281 if (sx < -hv.x) {
01282 sx = -hv.x;
01283 sub = 0;
01284 }
01285 if (sx > (int)MapMaxX() * TILE_SIZE - hv.x) {
01286 sx = MapMaxX() * TILE_SIZE - hv.x;
01287 sub = 0;
01288 }
01289 if (sy < -hv.y) {
01290 sy = -hv.y;
01291 sub = 0;
01292 }
01293 if (sy > (int)MapMaxY() * TILE_SIZE - hv.y) {
01294 sy = MapMaxY() * TILE_SIZE - hv.y;
01295 sub = 0;
01296 }
01297
01298 this->scroll_x = sx;
01299 this->scroll_y = sy;
01300 this->subscroll = sub;
01301 }
01302
01303 virtual void OnScroll(Point delta)
01304 {
01305 _cursor.fix_at = true;
01306
01307
01308 int sub;
01309 Point pt = this->PixelToTile(delta.x, delta.y, &sub);
01310 this->SetNewScroll(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, sub);
01311
01312 this->SetDirty();
01313 }
01314
01315 void SmallMapCenterOnCurrentPos()
01316 {
01317 const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
01318 Point pt = InverseRemapCoords(vp->virtual_left + vp->virtual_width / 2, vp->virtual_top + vp->virtual_height / 2);
01319
01320 int sub;
01321 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
01322 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);
01323 this->SetNewScroll(sxy.x, sxy.y, sub);
01324 this->SetDirty();
01325 }
01326 };
01327
01328 SmallMapWindow::SmallMapType SmallMapWindow::map_type = SMT_CONTOUR;
01329 bool SmallMapWindow::show_towns = true;
01330
01339 class NWidgetSmallmapDisplay : public NWidgetContainer {
01340 const SmallMapWindow *smallmap_window;
01341 public:
01342 NWidgetSmallmapDisplay() : NWidgetContainer(NWID_VERTICAL)
01343 {
01344 this->smallmap_window = NULL;
01345 }
01346
01347 virtual void SetupSmallestSize(Window *w, bool init_array)
01348 {
01349 NWidgetBase *display = this->head;
01350 NWidgetBase *bar = display->next;
01351
01352 display->SetupSmallestSize(w, init_array);
01353 bar->SetupSmallestSize(w, init_array);
01354
01355 this->smallmap_window = dynamic_cast<SmallMapWindow *>(w);
01356 this->smallest_x = max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth());
01357 this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetMaxLegendHeight());
01358 this->fill_x = max(display->fill_x, bar->fill_x);
01359 this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : min(display->fill_y, bar->fill_y);
01360 this->resize_x = max(display->resize_x, bar->resize_x);
01361 this->resize_y = min(display->resize_y, bar->resize_y);
01362 }
01363
01364 virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01365 {
01366 this->pos_x = x;
01367 this->pos_y = y;
01368 this->current_x = given_width;
01369 this->current_y = given_height;
01370
01371 NWidgetBase *display = this->head;
01372 NWidgetBase *bar = display->next;
01373
01374 if (sizing == ST_SMALLEST) {
01375 this->smallest_x = given_width;
01376 this->smallest_y = given_height;
01377
01378 display->AssignSizePosition(ST_SMALLEST, x, y, display->smallest_x, display->smallest_y, rtl);
01379 bar->AssignSizePosition(ST_SMALLEST, x, y + display->smallest_y, bar->smallest_x, bar->smallest_y, rtl);
01380 }
01381
01382 uint bar_height = max(bar->smallest_y, this->smallmap_window->GetLegendHeight(given_width - bar->smallest_x));
01383 uint display_height = given_height - bar_height;
01384 display->AssignSizePosition(ST_RESIZE, x, y, given_width, display_height, rtl);
01385 bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl);
01386 }
01387
01388 virtual NWidgetCore *GetWidgetFromPos(int x, int y)
01389 {
01390 if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
01391 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01392 NWidgetCore *widget = child_wid->GetWidgetFromPos(x, y);
01393 if (widget != NULL) return widget;
01394 }
01395 return NULL;
01396 }
01397
01398 virtual void Draw(const Window *w)
01399 {
01400 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) child_wid->Draw(w);
01401 }
01402 };
01403
01405 static const NWidgetPart _nested_smallmap_display[] = {
01406 NWidget(WWT_PANEL, COLOUR_BROWN, SM_WIDGET_MAP_BORDER),
01407 NWidget(WWT_INSET, COLOUR_BROWN, SM_WIDGET_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(),
01408 EndContainer(),
01409 };
01410
01412 static const NWidgetPart _nested_smallmap_bar[] = {
01413 NWidget(WWT_PANEL, COLOUR_BROWN),
01414 NWidget(NWID_HORIZONTAL),
01415 NWidget(WWT_EMPTY, INVALID_COLOUR, SM_WIDGET_LEGEND), SetResize(1, 1),
01416 NWidget(NWID_VERTICAL),
01417
01418 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01419 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN),
01420 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_CENTERMAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER),
01421 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_CONTOUR), SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP),
01422 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEHICLES), SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP),
01423 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_INDUSTRIES), SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP),
01424 EndContainer(),
01425
01426 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01427 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT),
01428 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_TOGGLETOWNNAME), SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF),
01429 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_ROUTES), SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON),
01430 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEGETATION), SetDataTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP),
01431 NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_OWNERS), SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP),
01432 EndContainer(),
01433 NWidget(NWID_SPACER), SetResize(0, 1),
01434 EndContainer(),
01435 EndContainer(),
01436 EndContainer(),
01437 };
01438
01439 static NWidgetBase *SmallMapDisplay(int *biggest_index)
01440 {
01441 NWidgetContainer *map_display = new NWidgetSmallmapDisplay;
01442
01443 MakeNWidgets(_nested_smallmap_display, lengthof(_nested_smallmap_display), biggest_index, map_display);
01444 MakeNWidgets(_nested_smallmap_bar, lengthof(_nested_smallmap_bar), biggest_index, map_display);
01445 return map_display;
01446 }
01447
01448
01449 static const NWidgetPart _nested_smallmap_widgets[] = {
01450 NWidget(NWID_HORIZONTAL),
01451 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
01452 NWidget(WWT_CAPTION, COLOUR_BROWN, SM_WIDGET_CAPTION), SetDataTip(STR_SMALLMAP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01453 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
01454 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
01455 EndContainer(),
01456 NWidgetFunction(SmallMapDisplay),
01457
01458 NWidget(NWID_HORIZONTAL),
01459 NWidget(WWT_PANEL, COLOUR_BROWN),
01460 NWidget(NWID_HORIZONTAL),
01461 NWidget(NWID_SELECTION, INVALID_COLOUR, SM_WIDGET_SELECTINDUSTRIES),
01462 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01463 NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_ENABLEINDUSTRIES), SetDataTip(STR_SMALLMAP_ENABLE_ALL, STR_SMALLMAP_TOOLTIP_ENABLE_ALL),
01464 NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_DISABLEINDUSTRIES), SetDataTip(STR_SMALLMAP_DISABLE_ALL, STR_SMALLMAP_TOOLTIP_DISABLE_ALL),
01465 NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_SHOW_HEIGHT), SetDataTip(STR_SMALLMAP_SHOW_HEIGHT, STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT),
01466 EndContainer(),
01467 NWidget(NWID_SPACER), SetFill(1, 1),
01468 EndContainer(),
01469 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
01470 EndContainer(),
01471 EndContainer(),
01472 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
01473 EndContainer(),
01474 };
01475
01476 static const WindowDesc _smallmap_desc(
01477 WDP_AUTO, 446, 314,
01478 WC_SMALLMAP, WC_NONE,
01479 WDF_UNCLICK_BUTTONS,
01480 _nested_smallmap_widgets, lengthof(_nested_smallmap_widgets)
01481 );
01482
01483 void ShowSmallMap()
01484 {
01485 AllocateWindowDescFront<SmallMapWindow>(&_smallmap_desc, 0);
01486 }
01487
01496 bool ScrollMainWindowTo(int x, int y, int z, bool instant)
01497 {
01498 bool res = ScrollWindowTo(x, y, z, FindWindowById(WC_MAIN_WINDOW, 0), instant);
01499
01500
01501
01502
01503
01504 if (res) return res;
01505
01506 SmallMapWindow *w = dynamic_cast<SmallMapWindow*>(FindWindowById(WC_SMALLMAP, 0));
01507 if (w != NULL) w->SmallMapCenterOnCurrentPos();
01508
01509 return res;
01510 }