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