OpenTTD Source 20260108-master-g8ba1860eaa
smallmap_gui.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
10#include "stdafx.h"
11#include "core/backup_type.hpp"
12#include "clear_map.h"
13#include "industry.h"
14#include "station_map.h"
15#include "landscape.h"
16#include "tree_map.h"
17#include "viewport_func.h"
18#include "town.h"
19#include "tunnelbridge_map.h"
20#include "core/endian_func.hpp"
21#include "vehicle_base.h"
22#include "sound_func.h"
23#include "window_func.h"
24#include "company_base.h"
25#include "zoom_func.h"
26#include "strings_func.h"
27#include "blitter/factory.hpp"
29#include "timer/timer.h"
30#include "timer/timer_window.h"
31#include "smallmap_gui.h"
32
34
35#include "table/strings.h"
36
37#include <bitset>
38
39#include "safeguards.h"
40
44
56
58static const uint8_t _linkstat_colours_in_legenda[] = {0, 1, 3, 5, 7, 9, 11};
59
60static const int NUM_NO_COMPANY_ENTRIES = 4;
61
63#define MK(a, b) {b, a, IT_INVALID, 0, CompanyID::Invalid(), true, false, false}
64
66#define MC(col_break) {STR_TINY_BLACK_HEIGHT, {}, IT_INVALID, 0, CompanyID::Invalid(), true, false, col_break}
67
69#define MO(a, b) {b, a, IT_INVALID, 0, CompanyID::Invalid(), true, false, false}
70
72#define MOEND() {STR_NULL, {}, IT_INVALID, 0, OWNER_NONE, true, true, false}
73
75#define MKEND() {STR_NULL, {}, IT_INVALID, 0, CompanyID::Invalid(), true, true, false}
76
81#define MS(a, b) {b, a, IT_INVALID, 0, CompanyID::Invalid(), true, false, true}
82
85 MK(PC_BLACK, STR_SMALLMAP_LEGENDA_ROADS),
86 MK(PC_GREY, STR_SMALLMAP_LEGENDA_RAILROADS),
87 MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS),
88 MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
89 MK(PC_WHITE, STR_SMALLMAP_LEGENDA_VEHICLES),
90
91 /* Placeholders for the colours and heights of the legend.
92 * The following values are set at BuildLandLegend() based
93 * on each colour scheme and the maximum map height. */
94 MC(true),
95 MC(false),
96 MC(false),
97 MC(false),
98 MC(false),
99 MC(false),
100 MC(true),
101 MC(false),
102 MC(false),
103 MC(false),
104 MC(false),
105 MC(false),
106 MKEND()
107};
108
109static const LegendAndColour _legend_vehicles[] = {
110 MK(PC_RED, STR_SMALLMAP_LEGENDA_TRAINS),
111 MK(PC_YELLOW, STR_SMALLMAP_LEGENDA_ROAD_VEHICLES),
112 MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_SHIPS),
113 MK(PC_WHITE, STR_SMALLMAP_LEGENDA_AIRCRAFT),
114
115 MS(PC_BLACK, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES),
116 MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
117 MKEND()
118};
119
120static const LegendAndColour _legend_routes[] = {
121 MK(PC_BLACK, STR_SMALLMAP_LEGENDA_ROADS),
122 MK(PC_GREY, STR_SMALLMAP_LEGENDA_RAILROADS),
123 MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
124
125 MS(PC_VERY_DARK_BROWN, STR_SMALLMAP_LEGENDA_RAILROAD_STATION),
126 MK(PC_ORANGE, STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY),
127 MK(PC_YELLOW, STR_SMALLMAP_LEGENDA_BUS_STATION),
128 MK(PC_RED, STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT),
129 MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_DOCK),
130 MKEND()
131};
132
133static const LegendAndColour _legend_vegetation[] = {
134 MK(PC_ROUGH_LAND, STR_SMALLMAP_LEGENDA_ROUGH_LAND),
135 MK(PC_GRASS_LAND, STR_SMALLMAP_LEGENDA_GRASS_LAND),
136 MK(PC_BARE_LAND, STR_SMALLMAP_LEGENDA_BARE_LAND),
137 MK(PC_RAINFOREST, STR_SMALLMAP_LEGENDA_RAINFOREST),
138 MK(PC_FIELDS, STR_SMALLMAP_LEGENDA_FIELDS),
139 MK(PC_TREES, STR_SMALLMAP_LEGENDA_TREES),
140
141 MS(PC_GREEN, STR_SMALLMAP_LEGENDA_FOREST),
142 MK(PC_GREY, STR_SMALLMAP_LEGENDA_ROCKS),
143 MK(PC_ORANGE, STR_SMALLMAP_LEGENDA_DESERT),
144 MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_SNOW),
145 MK(PC_BLACK, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES),
146 MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
147 MKEND()
148};
149
150static LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1] = {
151 MO(PC_WATER, STR_SMALLMAP_LEGENDA_WATER),
152 MO({}, STR_SMALLMAP_LEGENDA_NO_OWNER), // This colour will vary depending on settings.
153 MO(PC_DARK_RED, STR_SMALLMAP_LEGENDA_TOWNS),
154 MO(PC_DARK_GREY, STR_SMALLMAP_LEGENDA_INDUSTRIES),
155 /* The legend will be terminated the first time it is used. */
156 MOEND(),
157};
158
159#undef MK
160#undef MC
161#undef MS
162#undef MO
163#undef MOEND
164#undef MKEND
165
178static bool _smallmap_show_heightmap = false;
180static IndustryType _smallmap_industry_highlight = IT_INVALID;
185
190{
191 uint j = 0;
192
193 /* Add each name */
194 for (IndustryType ind : _sorted_industry_types) {
195 const IndustrySpec *indsp = GetIndustrySpec(ind);
196 if (indsp->enabled) {
202 _legend_from_industries[j].end = false;
203
204 /* Store widget number for this industry type. */
205 _industry_to_list_pos[ind] = j;
206 j++;
207 }
208 }
209 /* Terminate the list */
211
212 /* Store number of enabled industries */
214}
215
220{
221 /* Clear the legend */
222 std::fill(std::begin(_legend_linkstats), std::end(_legend_linkstats), LegendAndColour{});
223
224 uint i = 0;
225 for (; i < _sorted_cargo_specs.size(); ++i) {
226 const CargoSpec *cs = _sorted_cargo_specs[i];
227
229 _legend_linkstats[i].colour = cs->legend_colour;
230 _legend_linkstats[i].type = cs->Index();
232 }
233
236
238 _legend_linkstats[i].legend = STR_EMPTY;
241 }
242
243 _legend_linkstats[_smallmap_cargo_count].legend = STR_LINKGRAPH_LEGEND_UNUSED;
244 _legend_linkstats[i - 1].legend = STR_LINKGRAPH_LEGEND_OVERLOADED;
245 _legend_linkstats[(_smallmap_cargo_count + i - 1) / 2].legend = STR_LINKGRAPH_LEGEND_SATURATED;
246 _legend_linkstats[i].end = true;
247}
248
249static const LegendAndColour * const _legend_table[] = {
251 _legend_vehicles,
254 _legend_routes,
255 _legend_vegetation,
256 _legend_land_owners,
257};
258
259#define MKCOLOUR(x) TO_LE32(x)
260
261#define MKCOLOUR_XXXX(x) (MKCOLOUR(0x01010101) * (uint)(x.p))
262#define MKCOLOUR_0XX0(x) (MKCOLOUR(0x00010100) * (uint)(x.p))
263#define MKCOLOUR_X00X(x) (MKCOLOUR(0x01000001) * (uint)(x.p))
264
265#define MKCOLOUR_XYYX(x, y) (MKCOLOUR_X00X(x) | MKCOLOUR_0XX0(y))
266
267#define MKCOLOUR_0000 MKCOLOUR_XXXX(PixelColour{0x00})
268#define MKCOLOUR_F00F MKCOLOUR_X00X(PixelColour{0xFF})
269#define MKCOLOUR_FFFF MKCOLOUR_XXXX(PixelColour{0xFF})
270
272
275 std::vector<uint32_t> height_colours;
276 std::span<const uint32_t> height_colours_base;
277 uint32_t default_colour;
278};
279
282 {{}, _green_map_heights, MKCOLOUR_XXXX(PixelColour{0x54})},
283 {{}, _dark_green_map_heights, MKCOLOUR_XXXX(PixelColour{0x62})},
284 {{}, _violet_map_heights, MKCOLOUR_XXXX(PixelColour{0x81})},
285};
286
291{
292 /* The smallmap window has never been initialized, so no need to change the legend. */
293 if (_heightmap_schemes[0].height_colours.empty()) return;
294
295 /*
296 * The general idea of this function is to fill the legend with an appropriate evenly spaced
297 * selection of height levels. All entries with STR_TINY_BLACK_HEIGHT are reserved for this.
298 * At the moment there are twelve of these.
299 *
300 * The table below defines up to which height level a particular delta in the legend should be
301 * used. One could opt for just dividing the maximum height and use that as delta, but that
302 * creates many "ugly" legend labels, e.g. once every 950 meter. As a result, this table will
303 * reduce the number of deltas to 7: every 100m, 200m, 300m, 500m, 750m, 1000m and 1250m. The
304 * deltas are closer together at the lower numbers because going from 12 entries to just 4, as
305 * would happen when replacing 200m and 300m by 250m, would mean the legend would be short and
306 * that might not be considered appropriate.
307 *
308 * The current method yields at least 7 legend entries and at most 12. It can be increased to
309 * 8 by adding a 150m and 400m option, but especially 150m creates ugly heights.
310 *
311 * It tries to evenly space the legend items over the two columns that are there for the legend.
312 */
313
314 /* Table for delta; if max_height is less than the first column, use the second column as value. */
315 uint deltas[][2] = { { 24, 2 }, { 48, 4 }, { 72, 6 }, { 120, 10 }, { 180, 15 }, { 240, 20 }, { MAX_TILE_HEIGHT + 1, 25 }};
316 uint i = 0;
317 for (; _settings_game.construction.map_height_limit >= deltas[i][0]; i++) {
318 /* Nothing to do here. */
319 }
320 uint delta = deltas[i][1];
321
322 int total_entries = (_settings_game.construction.map_height_limit / delta) + 1;
323 int rows = CeilDiv(total_entries, 2);
324 int j = 0;
325
326 for (i = 0; i < lengthof(_legend_land_contours) - 1 && j < total_entries; i++) {
327 if (_legend_land_contours[i].legend != STR_TINY_BLACK_HEIGHT) continue;
328
329 _legend_land_contours[i].col_break = j % rows == 0;
330 _legend_land_contours[i].end = false;
331 _legend_land_contours[i].height = j * delta;
333 j++;
334 }
335 _legend_land_contours[i].end = true;
336}
337
342{
343 _legend_land_owners[1].colour = PixelColour{static_cast<uint8_t>(_heightmap_schemes[_settings_client.gui.smallmap_land_colour].default_colour)};
344
346 for (const Company *c : Company::Iterate()) {
347 _legend_land_owners[i].colour = GetColourGradient(c->colour, SHADE_LIGHT);
348 _legend_land_owners[i].company = c->index;
349 _legend_land_owners[i].show_on_map = true;
350 _legend_land_owners[i].col_break = false;
351 _legend_land_owners[i].end = false;
352 _company_to_list_pos[c->index] = i;
353 i++;
354 }
355
356 /* Terminate the list */
357 _legend_land_owners[i].end = true;
358
359 /* Store maximum amount of owner legend entries. */
361}
362
363struct AndOr {
364 uint32_t mor;
365 uint32_t mand;
366};
367
368static inline uint32_t ApplyMask(uint32_t colour, const AndOr *mask)
369{
370 return (colour & mask->mand) | mask->mor;
371}
372
373
376 {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_CLEAR
377 {MKCOLOUR_0XX0(PC_GREY ), MKCOLOUR_F00F}, // MP_RAILWAY
378 {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_ROAD
379 {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_HOUSE
380 {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TREES
381 {MKCOLOUR_XXXX(PC_LIGHT_BLUE), MKCOLOUR_0000}, // MP_STATION
382 {MKCOLOUR_XXXX(PC_WATER ), MKCOLOUR_0000}, // MP_WATER
383 {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_VOID
384 {MKCOLOUR_XXXX(PC_DARK_RED ), MKCOLOUR_0000}, // MP_INDUSTRY
385 {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TUNNELBRIDGE
386 {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_OBJECT
387 {MKCOLOUR_0XX0(PC_GREY ), MKCOLOUR_F00F},
388};
389
392 {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_CLEAR
393 {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_RAILWAY
394 {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_ROAD
395 {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_HOUSE
396 {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TREES
397 {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_STATION
398 {MKCOLOUR_XXXX(PC_WATER ), MKCOLOUR_0000}, // MP_WATER
399 {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_VOID
400 {MKCOLOUR_XXXX(PC_DARK_RED ), MKCOLOUR_0000}, // MP_INDUSTRY
401 {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TUNNELBRIDGE
402 {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_OBJECT
403 {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F},
404};
405
407static const uint8_t _tiletype_importance[] = {
408 2, // MP_CLEAR
409 8, // MP_RAILWAY
410 7, // MP_ROAD
411 5, // MP_HOUSE
412 2, // MP_TREES
413 9, // MP_STATION
414 2, // MP_WATER
415 1, // MP_VOID
416 6, // MP_INDUSTRY
417 8, // MP_TUNNELBRIDGE
418 2, // MP_OBJECT
419 0,
420};
421
422
434
447
460
468static inline uint32_t GetSmallMapRoutesPixels(TileIndex tile, TileType t)
469{
470 switch (t) {
471 case MP_STATION:
472 switch (GetStationType(tile)) {
473 case StationType::Rail: return MKCOLOUR_XXXX(PC_VERY_DARK_BROWN);
474 case StationType::Airport: return MKCOLOUR_XXXX(PC_RED);
475 case StationType::Truck: return MKCOLOUR_XXXX(PC_ORANGE);
476 case StationType::Bus: return MKCOLOUR_XXXX(PC_YELLOW);
477 case StationType::Dock: return MKCOLOUR_XXXX(PC_LIGHT_BLUE);
478 default: return MKCOLOUR_FFFF;
479 }
480
481 case MP_RAILWAY: {
482 AndOr andor = {
483 MKCOLOUR_0XX0(GetRailTypeInfo(GetRailType(tile))->map_colour),
485 };
486
488 return ApplyMask(cs->default_colour, &andor);
489 }
490
491 case MP_ROAD: {
492 const RoadTypeInfo *rti = nullptr;
493 if (GetRoadTypeRoad(tile) != INVALID_ROADTYPE) {
494 rti = GetRoadTypeInfo(GetRoadTypeRoad(tile));
495 } else {
496 rti = GetRoadTypeInfo(GetRoadTypeTram(tile));
497 }
498 if (rti != nullptr) {
499 AndOr andor = {
500 MKCOLOUR_0XX0(rti->map_colour),
502 };
503
505 return ApplyMask(cs->default_colour, &andor);
506 }
507 [[fallthrough]];
508 }
509
510 default:
511 /* Ground colour */
513 return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]);
514 }
515}
516
524static inline uint32_t GetSmallMapLinkStatsPixels(TileIndex tile, TileType t)
525{
527}
528
529static const uint32_t _vegetation_clear_bits[] = {
530 MKCOLOUR_XXXX(PC_GRASS_LAND),
531 MKCOLOUR_XXXX(PC_ROUGH_LAND),
532 MKCOLOUR_XXXX(PC_GREY),
533 MKCOLOUR_XXXX(PC_FIELDS),
534 MKCOLOUR_XXXX(PC_LIGHT_BLUE),
535 MKCOLOUR_XXXX(PC_ORANGE),
536 MKCOLOUR_XXXX(PC_GRASS_LAND),
537 MKCOLOUR_XXXX(PC_GRASS_LAND),
538};
539
547static inline uint32_t GetSmallMapVegetationPixels(TileIndex tile, TileType t)
548{
549 switch (t) {
550 case MP_CLEAR:
551 if (IsClearGround(tile, CLEAR_GRASS)) {
552 if (GetClearDensity(tile) < 3) return MKCOLOUR_XXXX(PC_BARE_LAND);
553 if (GetTropicZone(tile) == TROPICZONE_RAINFOREST) return MKCOLOUR_XXXX(PC_RAINFOREST);
554 }
555 return _vegetation_clear_bits[IsSnowTile(tile) ? CLEAR_SNOW : GetClearGround(tile)];
556
557 case MP_INDUSTRY:
558 return IsTileForestIndustry(tile) ? MKCOLOUR_XXXX(PC_GREEN) : MKCOLOUR_XXXX(PC_DARK_RED);
559
560 case MP_TREES:
562 return (_settings_game.game_creation.landscape == LandscapeType::Arctic) ? MKCOLOUR_XYYX(PC_LIGHT_BLUE, PC_TREES) : MKCOLOUR_XYYX(PC_ORANGE, PC_TREES);
563 }
564 return (GetTropicZone(tile) == TROPICZONE_RAINFOREST) ? MKCOLOUR_XYYX(PC_RAINFOREST, PC_TREES) : MKCOLOUR_XYYX(PC_GRASS_LAND, PC_TREES);
565
566 default:
567 return ApplyMask(MKCOLOUR_XXXX(PC_GRASS_LAND), &_smallmap_vehicles_andor[t]);
568 }
569}
570
580uint32_t GetSmallMapOwnerPixels(TileIndex tile, TileType t, IncludeHeightmap include_heightmap)
581{
582 Owner o;
583
584 switch (t) {
585 case MP_VOID: return MKCOLOUR_XXXX(PC_BLACK);
586 case MP_INDUSTRY: return MKCOLOUR_XXXX(PC_DARK_GREY);
587 case MP_HOUSE: return MKCOLOUR_XXXX(PC_DARK_RED);
588 case MP_ROAD:
589 o = GetRoadOwner(tile, HasRoadTypeRoad(tile) ? RTT_ROAD : RTT_TRAM);
590 break;
591
592 default:
593 o = GetTileOwner(tile);
594 break;
595 }
596
597 if ((o < MAX_COMPANIES && !_legend_land_owners[_company_to_list_pos[o]].show_on_map) || o == OWNER_NONE || o == OWNER_WATER) {
598 if (t == MP_WATER) return MKCOLOUR_XXXX(PC_WATER);
600 return ((include_heightmap == IncludeHeightmap::IfEnabled && _smallmap_show_heightmap) || include_heightmap == IncludeHeightmap::Always)
601 ? cs->height_colours[TileHeight(tile)] : cs->default_colour;
602 } else if (o == OWNER_TOWN) {
603 return MKCOLOUR_XXXX(PC_DARK_RED);
604 }
605
606 return MKCOLOUR_XXXX(_legend_land_owners[_company_to_list_pos[o]].colour);
607}
608
613
615enum SmallMapType : uint8_t {
616 SMT_CONTOUR,
617 SMT_VEHICLES,
618 SMT_INDUSTRY,
619 SMT_LINKSTATS,
620 SMT_ROUTES,
621 SMT_VEGETATION,
622 SMT_OWNER,
623};
625
626
627class SmallMapWindow : public Window {
628protected:
635
637 static bool show_towns;
638 static bool show_ind_names;
639 static int map_height_limit;
640
641 static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2;
642
643 uint min_number_of_columns = 0;
644 uint min_number_of_fixed_rows = 0;
645 uint column_width = 0;
646 uint legend_width = 0;
647
648 int32_t scroll_x = 0;
649 int32_t scroll_y = 0;
650 int32_t subscroll = 0;
651 int zoom = 0;
652
653 std::unique_ptr<LinkGraphOverlay> overlay{};
654
660
661 static inline Point SmallmapRemapCoords(int x, int y)
662 {
663 Point pt;
664 pt.x = (y - x) * 2;
665 pt.y = y + x;
666 return pt;
667 }
668
675 static inline void DrawVertMapIndicator(int x, int y, int y2)
676 {
677 GfxFillRect(x, y, x, y + 3, PC_VERY_LIGHT_YELLOW);
678 GfxFillRect(x, y2 - 3, x, y2, PC_VERY_LIGHT_YELLOW);
679 }
680
687 static inline void DrawHorizMapIndicator(int x, int x2, int y)
688 {
689 GfxFillRect(x, y, x + 3, y, PC_VERY_LIGHT_YELLOW);
690 GfxFillRect(x2 - 3, y, x2, y, PC_VERY_LIGHT_YELLOW);
691 }
692
697 inline uint GetMinLegendWidth() const
698 {
699 return WidgetDimensions::scaled.framerect.left + this->min_number_of_columns * this->column_width;
700 }
701
706 inline uint GetNumberColumnsLegend(uint width) const
707 {
708 return width / this->column_width;
709 }
710
716 inline uint GetLegendHeight(uint num_columns) const
717 {
719 this->GetNumberRowsLegend(num_columns) * GetCharacterHeight(FS_SMALL);
720 }
721
731
733 const IntervalTimer<TimerWindow> blink_interval = {TIMER_BLINK_INTERVAL, [this](auto) {
734 Blink();
735 }};
736
738 const IntervalTimer<TimerWindow> refresh_interval = {std::chrono::milliseconds(930), [this](auto) {
739 ForceRefresh();
740 }};
741
746 {
747 /* Rebuild colour indices if necessary. */
749
750 for (auto &heightmap_scheme : _heightmap_schemes) {
751 /* The heights go from 0 up to and including maximum. */
752 size_t heights = _settings_game.construction.map_height_limit + 1;
753 heightmap_scheme.height_colours.resize(heights);
754
755 for (size_t z = 0; z < heights; z++) {
756 size_t access_index = (heightmap_scheme.height_colours_base.size() * z) / heights;
757
758 /* Choose colour by mapping the range (0..max heightlevel) on the complete colour table. */
759 heightmap_scheme.height_colours[z] = heightmap_scheme.height_colours_base[access_index];
760 }
761 }
762
765 }
766
775 uint GetNumberRowsLegend(uint columns) const
776 {
777 /* Reserve one column for link colours */
778 uint num_rows_linkstats = CeilDiv(_smallmap_cargo_count, columns - 1);
779 uint num_rows_others = CeilDiv(std::max(_smallmap_industry_count, _smallmap_company_count), columns);
780 return std::max({this->min_number_of_fixed_rows, num_rows_linkstats, num_rows_others});
781 }
782
794 void SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item = 0)
795 {
796 if (_ctrl_pressed) {
797 /* Disable all, except the clicked one */
798 bool changes = false;
799 for (int i = begin_legend_item; i != end_legend_item; i++) {
800 bool new_state = (i == click_pos);
801 if (legend[i].show_on_map != new_state) {
802 changes = true;
803 legend[i].show_on_map = new_state;
804 }
805 }
806 if (!changes) {
807 /* Nothing changed? Then show all (again). */
808 for (int i = begin_legend_item; i != end_legend_item; i++) {
809 legend[i].show_on_map = true;
810 }
811 }
812 } else {
813 legend[click_pos].show_on_map = !legend[click_pos].show_on_map;
814 }
815
816 if (this->map_type == SMT_INDUSTRY) this->BreakIndustryChainLink();
817 }
818
824 {
825 this->RaiseWidget(WID_SM_CONTOUR + this->map_type);
826 this->map_type = map_type;
827 this->LowerWidget(WID_SM_CONTOUR + this->map_type);
828
829 this->SetupWidgetData();
830
831 if (map_type == SMT_LINKSTATS) this->overlay->SetDirty();
832 if (map_type != SMT_INDUSTRY) this->BreakIndustryChainLink();
833 this->ReInit();
834 }
835
843 void SetNewScroll(int sx, int sy, int sub)
844 {
845 const NWidgetBase *wi = this->GetWidget<NWidgetBase>(WID_SM_MAP);
846 Point hv = InverseRemapCoords(wi->current_x * ZOOM_BASE * TILE_SIZE / 2, wi->current_y * ZOOM_BASE * TILE_SIZE / 2);
847 hv.x *= this->zoom;
848 hv.y *= this->zoom;
849
850 if (sx < -hv.x) {
851 sx = -hv.x;
852 sub = 0;
853 }
854 if (sx > (int)(Map::MaxX() * TILE_SIZE) - hv.x) {
855 sx = Map::MaxX() * TILE_SIZE - hv.x;
856 sub = 0;
857 }
858 if (sy < -hv.y) {
859 sy = -hv.y;
860 sub = 0;
861 }
862 if (sy > (int)(Map::MaxY() * TILE_SIZE) - hv.y) {
863 sy = Map::MaxY() * TILE_SIZE - hv.y;
864 sub = 0;
865 }
866
867 this->scroll_x = sx;
868 this->scroll_y = sy;
869 this->subscroll = sub;
870 if (this->map_type == SMT_LINKSTATS) this->overlay->SetDirty();
871 }
872
876 void DrawMapIndicators() const
877 {
878 /* Find main viewport. */
879 const Viewport &vp = *GetMainWindow()->viewport;
880
881 Point upper_left_smallmap_coord = InverseRemapCoords2(vp.virtual_left, vp.virtual_top);
882 Point lower_right_smallmap_coord = InverseRemapCoords2(vp.virtual_left + vp.virtual_width - 1, vp.virtual_top + vp.virtual_height - 1);
883
884 Point upper_left = this->RemapTile(upper_left_smallmap_coord.x / (int)TILE_SIZE, upper_left_smallmap_coord.y / (int)TILE_SIZE);
885 upper_left.x -= this->subscroll;
886
887 Point lower_right = this->RemapTile(lower_right_smallmap_coord.x / (int)TILE_SIZE, lower_right_smallmap_coord.y / (int)TILE_SIZE);
888 lower_right.x -= this->subscroll;
889
890 SmallMapWindow::DrawVertMapIndicator(upper_left.x, upper_left.y, lower_right.y);
891 SmallMapWindow::DrawVertMapIndicator(lower_right.x, upper_left.y, lower_right.y);
892
893 SmallMapWindow::DrawHorizMapIndicator(upper_left.x, lower_right.x, upper_left.y);
894 SmallMapWindow::DrawHorizMapIndicator(upper_left.x, lower_right.x, lower_right.y);
895 }
896
910 void DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const
911 {
912 void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height);
913 uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0;
914
915 do {
916 /* Check if the tile (xc,yc) is within the map range */
917 if (xc >= Map::MaxX() || yc >= Map::MaxY()) continue;
918
919 /* Check if the dst pointer points to a pixel inside the screen buffer */
920 if (dst < _screen.dst_ptr) continue;
921 if (dst >= dst_ptr_abs_end) continue;
922
923 /* Construct tilearea covered by (xc, yc, xc + this->zoom, yc + this->zoom) such that it is within min_xy limits. */
924 TileArea ta;
925 if (min_xy == 1 && (xc == 0 || yc == 0)) {
926 if (this->zoom == 1) continue; // The tile area is empty, don't draw anything.
927
928 ta = TileArea(TileXY(std::max(min_xy, xc), std::max(min_xy, yc)), this->zoom - (xc == 0), this->zoom - (yc == 0));
929 } else {
930 ta = TileArea(TileXY(xc, yc), this->zoom, this->zoom);
931 }
932 ta.ClampToMap(); // Clamp to map boundaries (may contain MP_VOID tiles!).
933
934 uint32_t val = this->GetTileColours(ta);
935 uint8_t *val8 = (uint8_t *)&val;
936 int idx = std::max(0, -start_pos);
937 for (int pos = std::max(0, start_pos); pos < end_pos; pos++) {
938 blitter->SetPixel(dst, idx, 0, PixelColour{val8[idx]});
939 idx++;
940 }
941 /* Switch to next tile in the column */
942 } while (xc += this->zoom, yc += this->zoom, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0);
943 }
944
950 void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const
951 {
952 for (const Vehicle *v : Vehicle::Iterate()) {
953 if (v->type == VEH_EFFECT) continue;
954 if (v->vehstatus.Any({VehState::Hidden, VehState::Unclickable})) continue;
955
956 /* Remap into flat coordinates. */
957 Point pt = this->RemapTile(v->x_pos / (int)TILE_SIZE, v->y_pos / (int)TILE_SIZE);
958
959 int y = pt.y - dpi->top;
960 if (!IsInsideMM(y, 0, dpi->height)) continue; // y is out of bounds.
961
962 bool skip = false; // Default is to draw both pixels.
963 int x = pt.x - this->subscroll - 3 - dpi->left; // Offset X coordinate.
964 if (x < 0) {
965 /* if x+1 is 0, that means we're on the very left edge,
966 * and should thus only draw a single pixel */
967 if (++x != 0) continue;
968 skip = true;
969 } else if (x >= dpi->width - 1) {
970 /* Check if we're at the very right edge, and if so draw only a single pixel */
971 if (x != dpi->width - 1) continue;
972 skip = true;
973 }
974
975 /* Calculate pointer to pixel and the colour */
976 PixelColour colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : PC_WHITE;
977
978 /* And draw either one or two pixels depending on clipping */
979 blitter->SetPixel(dpi->dst_ptr, x, y, colour);
980 if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour);
981 }
982 }
983
988 void DrawTowns(const DrawPixelInfo *dpi, const int vertical_padding) const
989 {
990 for (const Town *t : Town::Iterate()) {
991 /* Remap the town coordinate */
992 Point pt = this->RemapTile(TileX(t->xy), TileY(t->xy));
993 int x = pt.x - this->subscroll - (t->cache.sign.width_small >> 1);
994 int y = pt.y + vertical_padding;
995
996 /* Check if the town sign is within bounds */
997 if (x + t->cache.sign.width_small > dpi->left &&
998 x < dpi->left + dpi->width &&
999 y + GetCharacterHeight(FS_SMALL) > dpi->top &&
1000 y < dpi->top + dpi->height) {
1001 /* And draw it. */
1002 DrawString(x, x + t->cache.sign.width_small, y, GetString(STR_SMALLMAP_TOWN, t->index));
1003 }
1004 }
1005 }
1006
1011 void DrawIndustryNames(const DrawPixelInfo *dpi, const int vertical_padding) const
1012 {
1013 if (this->map_type != SMT_INDUSTRY) return;
1014
1015 for (const Industry *i : Industry::Iterate()) {
1017 if (!tbl.show_on_map) continue;
1018
1019 /* Industry names blink together with their blobs in the smallmap. */
1020 const bool is_blinking = i->type == _smallmap_industry_highlight && !_smallmap_industry_highlight_state;
1021 if (is_blinking) continue;
1022
1023 if (_industry_to_name_string_width[i->type] == 0) {
1025 }
1026 const uint16_t &legend_text_width = _industry_to_name_string_width[i->type];
1027
1028 /* Remap the industry coordinate */
1029 const TileIndex &tile = i->location.GetCenterTile();
1030 const Point pt = this->RemapTile(TileX(tile), TileY(tile));
1031 const int x = pt.x - this->subscroll - (legend_text_width / 2);
1032 const int y = pt.y + vertical_padding;
1033
1034 /* Check if the industry name is within bounds */
1035 if (x + legend_text_width > dpi->left &&
1036 x < dpi->left + dpi->width &&
1037 y + GetCharacterHeight(FS_SMALL) > dpi->top &&
1038 y < dpi->top + dpi->height) {
1039
1040 /* And draw it. */
1041 DrawString(x, x + legend_text_width, y, tbl.legend, TC_WHITE, SA_LEFT, false, FS_SMALL);
1042 }
1043 }
1044 }
1045
1058 {
1060 AutoRestoreBackup dpi_backup(_cur_dpi, dpi);
1061
1062 /* If freeform edges are off, draw infinite water off the edges of the map. */
1064 GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, map_clear_color);
1065
1066 /* Which tile is displayed at (dpi->left, dpi->top)? */
1067 int dx;
1068 Point tile = this->PixelToTile(dpi->left, dpi->top, &dx);
1069 int tile_x = this->scroll_x / (int)TILE_SIZE + tile.x;
1070 int tile_y = this->scroll_y / (int)TILE_SIZE + tile.y;
1071
1072 void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0);
1073 int x = - dx - 4;
1074 int y = 0;
1075
1076 for (;;) {
1077 /* Distance from left edge */
1078 if (x >= -3) {
1079 if (x >= dpi->width) break; // Exit the loop.
1080
1081 int end_pos = std::min(dpi->width, x + 4);
1082 int reps = (dpi->height - y + 1) / 2; // Number of lines.
1083 if (reps > 0) {
1084 this->DrawSmallMapColumn(ptr, tile_x, tile_y, dpi->pitch * 2, reps, x, end_pos, blitter);
1085 }
1086 }
1087
1088 if (y == 0) {
1089 tile_y += this->zoom;
1090 y++;
1091 ptr = blitter->MoveTo(ptr, 0, 1);
1092 } else {
1093 tile_x -= this->zoom;
1094 y--;
1095 ptr = blitter->MoveTo(ptr, 0, -1);
1096 }
1097 ptr = blitter->MoveTo(ptr, 2, 0);
1098 x += 2;
1099 }
1100
1101 /* Draw vehicles */
1102 if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter);
1103
1104 /* Draw link stat overlay */
1105 if (this->map_type == SMT_LINKSTATS) this->overlay->Draw(dpi);
1106
1107 const int map_labels_vertical_padding = ScaleGUITrad(2);
1108
1109 /* Draw town names */
1110 if (this->show_towns) this->DrawTowns(dpi, map_labels_vertical_padding);
1111
1112 /* Draw industry names */
1113 if (this->show_ind_names) this->DrawIndustryNames(dpi, map_labels_vertical_padding);
1114
1115 /* Draw map indicators */
1116 this->DrawMapIndicators();
1117 }
1118
1125 Point RemapTile(int tile_x, int tile_y) const
1126 {
1127 int x_offset = tile_x - this->scroll_x / (int)TILE_SIZE;
1128 int y_offset = tile_y - this->scroll_y / (int)TILE_SIZE;
1129
1130 if (this->zoom == 1) return SmallmapRemapCoords(x_offset, y_offset);
1131
1132 /* For negative offsets, round towards -inf. */
1133 if (x_offset < 0) x_offset -= this->zoom - 1;
1134 if (y_offset < 0) y_offset -= this->zoom - 1;
1135
1136 return SmallmapRemapCoords(x_offset / this->zoom, y_offset / this->zoom);
1137 }
1138
1149 Point PixelToTile(int px, int py, int *sub, bool add_sub = true) const
1150 {
1151 if (add_sub) px += this->subscroll; // Total horizontal offset.
1152
1153 /* For each two rows down, add a x and a y tile, and
1154 * For each four pixels to the right, move a tile to the right. */
1155 Point pt = {((py >> 1) - (px >> 2)) * this->zoom, ((py >> 1) + (px >> 2)) * this->zoom};
1156 px &= 3;
1157
1158 if (py & 1) { // Odd number of rows, handle the 2 pixel shift.
1159 if (px < 2) {
1160 pt.x += this->zoom;
1161 px += 2;
1162 } else {
1163 pt.y += this->zoom;
1164 px -= 2;
1165 }
1166 }
1167
1168 *sub = px;
1169 return pt;
1170 }
1171
1181 Point ComputeScroll(int tx, int ty, int x, int y, int *sub) const
1182 {
1183 assert(x >= 0 && y >= 0);
1184
1185 int new_sub;
1186 Point tile_xy = PixelToTile(x, y, &new_sub, false);
1187 tx -= tile_xy.x;
1188 ty -= tile_xy.y;
1189
1190 Point scroll;
1191 if (new_sub == 0) {
1192 *sub = 0;
1193 scroll.x = (tx + this->zoom) * TILE_SIZE;
1194 scroll.y = (ty - this->zoom) * TILE_SIZE;
1195 } else {
1196 *sub = 4 - new_sub;
1197 scroll.x = (tx + 2 * this->zoom) * TILE_SIZE;
1198 scroll.y = (ty - 2 * this->zoom) * TILE_SIZE;
1199 }
1200 return scroll;
1201 }
1202
1209 void SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt)
1210 {
1211 static const int zoomlevels[] = {1, 2, 4, 6, 8}; // Available zoom levels. Bigger number means more zoom-out (further away).
1212 static const int MIN_ZOOM_INDEX = 0;
1213 static const int MAX_ZOOM_INDEX = lengthof(zoomlevels) - 1;
1214
1215 int new_index, cur_index, sub;
1216 Point tile;
1217 switch (change) {
1218 case ZLC_INITIALIZE:
1219 cur_index = - 1; // Definitely different from new_index.
1220 new_index = MIN_ZOOM_INDEX;
1221 tile.x = tile.y = 0;
1222 break;
1223
1224 case ZLC_ZOOM_IN:
1225 case ZLC_ZOOM_OUT:
1226 for (cur_index = MIN_ZOOM_INDEX; cur_index <= MAX_ZOOM_INDEX; cur_index++) {
1227 if (this->zoom == zoomlevels[cur_index]) break;
1228 }
1229 assert(cur_index <= MAX_ZOOM_INDEX);
1230
1231 tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub);
1232 new_index = Clamp(cur_index + ((change == ZLC_ZOOM_IN) ? -1 : 1), MIN_ZOOM_INDEX, MAX_ZOOM_INDEX);
1233 break;
1234
1235 default: NOT_REACHED();
1236 }
1237
1238 if (new_index != cur_index) {
1239 this->zoom = zoomlevels[new_index];
1240 if (cur_index >= 0) {
1241 Point new_tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub);
1242 this->SetNewScroll(this->scroll_x + (tile.x - new_tile.x) * TILE_SIZE,
1243 this->scroll_y + (tile.y - new_tile.y) * TILE_SIZE, sub);
1244 } else if (this->map_type == SMT_LINKSTATS) {
1245 this->overlay->SetDirty();
1246 }
1247 this->SetWidgetDisabledState(WID_SM_ZOOM_IN, this->zoom == zoomlevels[MIN_ZOOM_INDEX]);
1248 this->SetWidgetDisabledState(WID_SM_ZOOM_OUT, this->zoom == zoomlevels[MAX_ZOOM_INDEX]);
1249 this->SetDirty();
1250 }
1251 }
1252
1257 {
1258 CargoTypes cargo_mask = 0;
1259 for (int i = 0; i != _smallmap_cargo_count; ++i) {
1260 if (_legend_linkstats[i].show_on_map) SetBit(cargo_mask, _legend_linkstats[i].type);
1261 }
1262 this->overlay->SetCargoMask(cargo_mask);
1263 }
1264
1269 {
1270 StringID legend_tooltip;
1271 StringID enable_all_tooltip;
1272 StringID disable_all_tooltip;
1273 int industry_names_select_plane;
1274 int select_buttons_plane;
1275 switch (this->map_type) {
1276 case SMT_INDUSTRY:
1277 legend_tooltip = STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION;
1278 enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES;
1279 disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES;
1280 industry_names_select_plane = 0;
1281 select_buttons_plane = 0;
1282 break;
1283
1284 case SMT_OWNER:
1285 legend_tooltip = STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION;
1286 enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES;
1287 disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES;
1288 industry_names_select_plane = SZSP_NONE;
1289 select_buttons_plane = 0;
1290 break;
1291
1292 case SMT_LINKSTATS:
1293 legend_tooltip = STR_SMALLMAP_TOOLTIP_CARGO_SELECTION;
1294 enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS;
1295 disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS;
1296 industry_names_select_plane = SZSP_NONE;
1297 select_buttons_plane = 0;
1298 break;
1299
1300 default:
1301 legend_tooltip = STR_NULL;
1302 enable_all_tooltip = STR_NULL;
1303 disable_all_tooltip = STR_NULL;
1304 industry_names_select_plane = SZSP_NONE;
1305 select_buttons_plane = 1;
1306 break;
1307 }
1308
1309 this->GetWidget<NWidgetCore>(WID_SM_LEGEND)->SetToolTip(legend_tooltip);
1310 this->GetWidget<NWidgetCore>(WID_SM_ENABLE_ALL)->SetStringTip(STR_SMALLMAP_ENABLE_ALL, enable_all_tooltip);
1311 this->GetWidget<NWidgetCore>(WID_SM_DISABLE_ALL)->SetStringTip(STR_SMALLMAP_DISABLE_ALL, disable_all_tooltip);
1312 this->GetWidget<NWidgetStacked>(WID_SM_SHOW_IND_NAMES_SEL)->SetDisplayedPlane(industry_names_select_plane);
1313 this->GetWidget<NWidgetStacked>(WID_SM_SELECT_BUTTONS)->SetDisplayedPlane(select_buttons_plane);
1314 }
1315
1321 uint32_t GetTileColours(const TileArea &ta) const
1322 {
1323 int importance = 0;
1324 TileIndex tile = INVALID_TILE; // Position of the most important tile.
1325 TileType et = MP_VOID; // Effective tile type at that position.
1326
1327 for (TileIndex ti : ta) {
1328 TileType ttype = GetTileType(ti);
1329
1330 switch (ttype) {
1331 case MP_TUNNELBRIDGE: {
1333
1334 switch (tt) {
1335 case TRANSPORT_RAIL: ttype = MP_RAILWAY; break;
1336 case TRANSPORT_ROAD: ttype = MP_ROAD; break;
1337 default: ttype = MP_WATER; break;
1338 }
1339 break;
1340 }
1341
1342 case MP_INDUSTRY:
1343 /* Special handling of industries while in "Industries" smallmap view. */
1344 if (this->map_type == SMT_INDUSTRY) {
1345 /* If industry is allowed to be seen, use its colour on the map.
1346 * This has the highest priority above any value in _tiletype_importance. */
1347 IndustryType type = Industry::GetByTile(ti)->type;
1348 if (_legend_from_industries[_industry_to_list_pos[type]].show_on_map) {
1349 if (type == _smallmap_industry_highlight) {
1350 if (_smallmap_industry_highlight_state) return MKCOLOUR_XXXX(PC_WHITE);
1351 } else {
1352 return GetIndustrySpec(type)->map_colour.p * 0x01010101;
1353 }
1354 }
1355 /* Otherwise make it disappear */
1356 ttype = IsTileOnWater(ti) ? MP_WATER : MP_CLEAR;
1357 }
1358 break;
1359
1360 default:
1361 break;
1362 }
1363
1364 if (_tiletype_importance[ttype] > importance) {
1365 importance = _tiletype_importance[ttype];
1366 tile = ti;
1367 et = ttype;
1368 }
1369 }
1370
1371 switch (this->map_type) {
1372 case SMT_CONTOUR:
1373 return GetSmallMapContoursPixels(tile, et);
1374
1375 case SMT_VEHICLES:
1376 return GetSmallMapVehiclesPixels(tile, et);
1377
1378 case SMT_INDUSTRY:
1379 return GetSmallMapIndustriesPixels(tile, et);
1380
1381 case SMT_LINKSTATS:
1382 return GetSmallMapLinkStatsPixels(tile, et);
1383
1384 case SMT_ROUTES:
1385 return GetSmallMapRoutesPixels(tile, et);
1386
1387 case SMT_VEGETATION:
1388 return GetSmallMapVegetationPixels(tile, et);
1389
1390 case SMT_OWNER:
1392
1393 default: NOT_REACHED();
1394 }
1395 }
1396
1403 {
1404 const NWidgetBase *wi = this->GetWidget<NWidgetBase>(WID_SM_LEGEND);
1405 uint line = (pt.y - wi->pos_y - WidgetDimensions::scaled.framerect.top) / GetCharacterHeight(FS_SMALL);
1406 uint columns = this->GetNumberColumnsLegend(wi->current_x);
1407 uint number_of_rows = this->GetNumberRowsLegend(columns);
1408 if (line >= number_of_rows) return -1;
1409
1410 bool rtl = _current_text_dir == TD_RTL;
1411 int x = pt.x - wi->pos_x;
1412 if (rtl) x = wi->current_x - x;
1413 uint column = (x - WidgetDimensions::scaled.framerect.left) / this->column_width;
1414
1415 return (column * number_of_rows) + line;
1416 }
1417
1420 {
1421 if (this->map_type == SMT_LINKSTATS) {
1422 CompanyMask company_mask = this->GetOverlayCompanyMask();
1423 if (this->overlay->GetCompanyMask() != company_mask) {
1424 this->overlay->SetCompanyMask(company_mask);
1425 } else {
1426 this->overlay->SetDirty();
1427 }
1428 }
1429 }
1430
1432 void Blink()
1433 {
1434 if (_smallmap_industry_highlight == IT_INVALID) return;
1435
1437
1438 this->UpdateLinks();
1439 this->SetDirty();
1440 }
1441
1444 {
1445 if (_smallmap_industry_highlight != IT_INVALID) return;
1446
1447 this->UpdateLinks();
1448 this->SetDirty();
1449 }
1450
1451public:
1452 friend class NWidgetSmallmapDisplay;
1453
1454 SmallMapWindow(WindowDesc &desc, int window_number) : Window(desc)
1455 {
1456 _smallmap_industry_highlight = IT_INVALID;
1457 this->overlay = std::make_unique<LinkGraphOverlay>(this, WID_SM_MAP, 0, this->GetOverlayCompanyMask(), 1);
1458 this->CreateNestedTree();
1459 this->LowerWidget(WID_SM_CONTOUR + this->map_type);
1460
1461 this->RebuildColourIndexIfNecessary();
1462
1463 this->SetWidgetLoweredState(WID_SM_SHOW_HEIGHT, _smallmap_show_heightmap);
1464
1465 this->SetWidgetLoweredState(WID_SM_TOGGLETOWNNAME, this->show_towns);
1466 this->SetWidgetLoweredState(WID_SM_SHOW_IND_NAMES, this->show_ind_names);
1467
1468 this->SetupWidgetData();
1469 this->FinishInitNested(window_number);
1470
1471 this->SetZoomLevel(ZLC_INITIALIZE, nullptr);
1472 this->SmallMapCenterOnCurrentPos();
1473 this->SetOverlayCargoMask();
1474 }
1475
1480 {
1481 const Viewport &vp = *GetMainWindow()->viewport;
1482 Point viewport_center = InverseRemapCoords2(vp.virtual_left + vp.virtual_width / 2, vp.virtual_top + vp.virtual_height / 2);
1483
1484 int sub;
1485 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SM_MAP);
1486 Point sxy = this->ComputeScroll(viewport_center.x / (int)TILE_SIZE, viewport_center.y / (int)TILE_SIZE,
1487 std::max(0, (int)wid->current_x / 2 - 2), wid->current_y / 2, &sub);
1488 this->SetNewScroll(sxy.x, sxy.y, sub);
1489 this->SetDirty();
1490 }
1491
1498 {
1499 int x = CentreBounds(st->rect.left, st->rect.right, 0);
1500 int y = CentreBounds(st->rect.top, st->rect.bottom, 0);
1501 Point ret = this->RemapTile(x, y);
1502
1503 /* Same magic 3 as in DrawVehicles; that's where I got it from.
1504 * No idea what it is, but without it the result looks bad.
1505 */
1506 ret.x -= 3 + this->subscroll;
1507 return ret;
1508 }
1509
1510 void Close([[maybe_unused]] int data) override
1511 {
1512 this->BreakIndustryChainLink();
1513 this->Window::Close();
1514 }
1515
1516 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
1517 {
1518 switch (widget) {
1519 case WID_SM_CAPTION:
1520 return GetString(STR_SMALLMAP_CAPTION, STR_SMALLMAP_TYPE_CONTOURS + this->map_type);
1521
1522 default:
1523 return this->Window::GetWidgetString(widget, stringid);
1524 }
1525 }
1526
1527 void OnInit() override
1528 {
1529 uint min_width = 0;
1530 this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS;
1531 this->min_number_of_fixed_rows = lengthof(_linkstat_colours_in_legenda);
1532 for (uint i = 0; i < lengthof(_legend_table); i++) {
1533 uint height = 0;
1534 uint num_columns = 1;
1535 for (const LegendAndColour *tbl = _legend_table[i]; !tbl->end; ++tbl) {
1536 std::string str;
1537 if (i == SMT_INDUSTRY) {
1538 str = GetString(STR_SMALLMAP_INDUSTRY, tbl->legend, IndustryPool::MAX_SIZE);
1539 } else if (i == SMT_LINKSTATS) {
1540 str = GetString(STR_SMALLMAP_LINKSTATS, tbl->legend);
1541 } else if (i == SMT_OWNER) {
1542 if (tbl->company != CompanyID::Invalid()) {
1543 if (!Company::IsValidID(tbl->company)) {
1544 /* Rebuild the owner legend. */
1546 this->OnInit();
1547 return;
1548 }
1549 /* Non-fixed legend entries for the owner view. */
1550 str = GetString(STR_SMALLMAP_COMPANY, tbl->company);
1551 } else {
1552 str = GetString(tbl->legend);
1553 }
1554 } else {
1555 if (tbl->col_break) {
1556 this->min_number_of_fixed_rows = std::max(this->min_number_of_fixed_rows, height);
1557 height = 0;
1558 num_columns++;
1559 }
1560 height++;
1561 if (i == SMT_CONTOUR) {
1562 str = GetString(tbl->legend, tbl->height * TILE_HEIGHT_STEP);
1563 } else {
1564 str = GetString(tbl->legend);
1565 }
1566 }
1567 min_width = std::max(GetStringBoundingBox(str).width, min_width);
1568 }
1569 this->min_number_of_fixed_rows = std::max(this->min_number_of_fixed_rows, height);
1570 this->min_number_of_columns = std::max(this->min_number_of_columns, num_columns);
1571 }
1572
1573 /* Width of the legend blob. */
1574 this->legend_width = GetCharacterHeight(FS_SMALL) * 9 / 6;
1575
1576 /* The width of a column is the minimum width of all texts + the size of the blob + some spacing */
1577 this->column_width = min_width + WidgetDimensions::scaled.hsep_normal + this->legend_width + WidgetDimensions::scaled.framerect.Horizontal();
1578
1579 /* Cached string widths of industry names in the smallmap. Calculation is deferred to DrawIndustryNames(). */
1580 std::fill(std::begin(_industry_to_name_string_width), std::end(_industry_to_name_string_width), 0);
1581 }
1582
1583 void OnPaint() override
1584 {
1585 if (this->map_type == SMT_OWNER) {
1586 for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) {
1587 if (tbl->company != CompanyID::Invalid() && !Company::IsValidID(tbl->company)) {
1588 /* Rebuild the owner legend. */
1590 this->InvalidateData(1);
1591 break;
1592 }
1593 }
1594 }
1595
1596 this->DrawWidgets();
1597 }
1598
1599 void DrawWidget(const Rect &r, WidgetID widget) const override
1600 {
1601 switch (widget) {
1602 case WID_SM_MAP: {
1603 Rect ir = r.Shrink(WidgetDimensions::scaled.bevel);
1604 DrawPixelInfo new_dpi;
1605 if (!FillDrawPixelInfo(&new_dpi, ir)) return;
1606 this->DrawSmallMap(&new_dpi);
1607 break;
1608 }
1609
1610 case WID_SM_LEGEND: {
1611 uint columns = this->GetNumberColumnsLegend(r.Width());
1612 uint number_of_rows = this->GetNumberRowsLegend(columns);
1613 bool rtl = _current_text_dir == TD_RTL;
1614 uint i = 0; // Row counter for industry legend.
1615 uint row_height = GetCharacterHeight(FS_SMALL);
1616 int padding = ScaleGUITrad(1);
1617
1618 Rect origin = r.WithWidth(this->column_width, rtl).Shrink(WidgetDimensions::scaled.framerect).WithHeight(row_height);
1619 Rect text = origin.Indent(this->legend_width + WidgetDimensions::scaled.hsep_normal, rtl);
1620 Rect icon = origin.WithWidth(this->legend_width, rtl).Shrink(0, padding, 0, 0);
1621
1622 StringID string = STR_NULL;
1623 switch (this->map_type) {
1624 case SMT_INDUSTRY:
1625 string = STR_SMALLMAP_INDUSTRY;
1626 break;
1627 case SMT_LINKSTATS:
1628 string = STR_SMALLMAP_LINKSTATS;
1629 break;
1630 case SMT_OWNER:
1631 string = STR_SMALLMAP_COMPANY;
1632 break;
1633 default:
1634 break;
1635 }
1636
1637 for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) {
1638 if (tbl->col_break || ((this->map_type == SMT_INDUSTRY || this->map_type == SMT_OWNER || this->map_type == SMT_LINKSTATS) && i++ >= number_of_rows)) {
1639 /* Column break needed, continue at top, COLUMN_WIDTH pixels
1640 * (one "row") to the right. */
1641 int x = rtl ? -(int)this->column_width : this->column_width;
1642 int y = origin.top - text.top;
1643 text = text.Translate(x, y);
1644 icon = icon.Translate(x, y);
1645 i = 1;
1646 }
1647
1648 PixelColour legend_colour = tbl->colour;
1649
1650 std::array<StringParameter, 2> params{};
1651 switch (this->map_type) {
1652 case SMT_INDUSTRY:
1653 /* Industry name must be formatted, since it's not in tiny font in the specs.
1654 * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font */
1655 params[0] = tbl->legend;
1656 params[1] = Industry::GetIndustryTypeCount(tbl->type);
1657 if (tbl->show_on_map && tbl->type == _smallmap_industry_highlight) {
1659 }
1660 [[fallthrough]];
1661
1662 case SMT_LINKSTATS:
1663 params[0] = tbl->legend;
1664 [[fallthrough]];
1665
1666 case SMT_OWNER:
1667 if (this->map_type != SMT_OWNER || tbl->company != CompanyID::Invalid()) {
1668 if (this->map_type == SMT_OWNER) params[0] = tbl->company;
1669 if (!tbl->show_on_map) {
1670 /* Simply draw the string, not the black border of the legend colour.
1671 * This will enforce the idea of the disabled item */
1672 DrawString(text, GetStringWithArgs(string, params), TC_GREY);
1673 } else {
1674 DrawString(text, GetStringWithArgs(string, params), TC_BLACK);
1675 GfxFillRect(icon, PC_BLACK); // Outer border of the legend colour
1676 }
1677 break;
1678 }
1679 [[fallthrough]];
1680
1681 default:
1682 /* Anything that is not an industry or a company is using normal process */
1683 GfxFillRect(icon, PC_BLACK);
1684 if (this->map_type == SMT_CONTOUR) {
1685 DrawString(text, GetString(tbl->legend, tbl->height * TILE_HEIGHT_STEP));
1686 } else {
1687 DrawString(text, tbl->legend);
1688 }
1689 break;
1690 }
1691 GfxFillRect(icon.Shrink(WidgetDimensions::scaled.bevel), legend_colour); // Legend colour
1692
1693 text = text.Translate(0, row_height);
1694 icon = icon.Translate(0, row_height);
1695 }
1696 }
1697 }
1698 }
1699
1700 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1701 {
1702 switch (widget) {
1703 case WID_SM_MAP: { // Map window
1704 if (click_count > 0) this->mouse_capture_widget = widget;
1705
1706 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SM_MAP);
1707 Window *w = GetMainWindow();
1708 int sub;
1709 pt = this->PixelToTile(pt.x - wid->pos_x, pt.y - wid->pos_y, &sub);
1710 ScrollWindowTo(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, -1, w);
1711
1712 this->SetDirty();
1713 break;
1714 }
1715
1716 case WID_SM_ZOOM_IN:
1717 case WID_SM_ZOOM_OUT: {
1718 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SM_MAP);
1719 Point zoom_pt = { (int)wid->current_x / 2, (int)wid->current_y / 2};
1720 this->SetZoomLevel((widget == WID_SM_ZOOM_IN) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &zoom_pt);
1721 SndClickBeep();
1722 break;
1723 }
1724
1725 case WID_SM_CONTOUR: // Show land contours
1726 case WID_SM_VEHICLES: // Show vehicles
1727 case WID_SM_INDUSTRIES: // Show industries
1728 case WID_SM_LINKSTATS: // Show route map
1729 case WID_SM_ROUTES: // Show transport routes
1730 case WID_SM_VEGETATION: // Show vegetation
1731 case WID_SM_OWNERS: // Show land owners
1732 this->SwitchMapType((SmallMapType)(widget - WID_SM_CONTOUR));
1733 SndClickBeep();
1734 break;
1735
1736 case WID_SM_CENTERMAP: // Center the smallmap again
1737 this->SmallMapCenterOnCurrentPos();
1738 this->HandleButtonClick(WID_SM_CENTERMAP);
1739 break;
1740
1741 case WID_SM_TOGGLETOWNNAME: // Toggle town names
1742 this->show_towns = !this->show_towns;
1743 this->SetWidgetLoweredState(WID_SM_TOGGLETOWNNAME, this->show_towns);
1744
1745 this->SetDirty();
1746 SndClickBeep();
1747 break;
1748
1749 case WID_SM_SHOW_IND_NAMES: // Toggle industry names
1750 this->show_ind_names = !this->show_ind_names;
1751 this->SetWidgetLoweredState(WID_SM_SHOW_IND_NAMES, this->show_ind_names);
1752
1753 this->SetDirty();
1754 SndClickBeep();
1755 break;
1756
1757 case WID_SM_LEGEND: // Legend
1758 if (this->map_type == SMT_INDUSTRY || this->map_type == SMT_LINKSTATS || this->map_type == SMT_OWNER) {
1759 int click_pos = this->GetPositionOnLegend(pt);
1760 if (click_pos < 0) break;
1761
1762 /* If industry type small map*/
1763 if (this->map_type == SMT_INDUSTRY) {
1764 /* If click on industries label, find right industry type and enable/disable it. */
1765 if (click_pos < _smallmap_industry_count) {
1766 this->SelectLegendItem(click_pos, _legend_from_industries, _smallmap_industry_count);
1767 }
1768 } else if (this->map_type == SMT_LINKSTATS) {
1769 if (click_pos < _smallmap_cargo_count) {
1770 this->SelectLegendItem(click_pos, _legend_linkstats, _smallmap_cargo_count);
1771 this->SetOverlayCargoMask();
1772 }
1773 } else if (this->map_type == SMT_OWNER) {
1774 if (click_pos < _smallmap_company_count) {
1775 this->SelectLegendItem(click_pos, _legend_land_owners, _smallmap_company_count, NUM_NO_COMPANY_ENTRIES);
1776 }
1777 }
1778 this->SetDirty();
1779 }
1780 break;
1781
1782 case WID_SM_ENABLE_ALL:
1783 case WID_SM_DISABLE_ALL: {
1784 LegendAndColour *tbl = nullptr;
1785 switch (this->map_type) {
1786 case SMT_INDUSTRY:
1788 this->BreakIndustryChainLink();
1789 break;
1790 case SMT_OWNER:
1791 tbl = &(_legend_land_owners[NUM_NO_COMPANY_ENTRIES]);
1792 break;
1793 case SMT_LINKSTATS:
1794 tbl = _legend_linkstats;
1795 break;
1796 default:
1797 NOT_REACHED();
1798 }
1799 for (;!tbl->end && tbl->legend != STR_LINKGRAPH_LEGEND_UNUSED; ++tbl) {
1800 tbl->show_on_map = (widget == WID_SM_ENABLE_ALL);
1801 }
1802 if (this->map_type == SMT_LINKSTATS) this->SetOverlayCargoMask();
1803 this->SetDirty();
1804 break;
1805 }
1806
1807 case WID_SM_SHOW_HEIGHT: // Enable/disable showing of heightmap.
1808 _smallmap_show_heightmap = !_smallmap_show_heightmap;
1809 this->SetWidgetLoweredState(WID_SM_SHOW_HEIGHT, _smallmap_show_heightmap);
1810 this->SetDirty();
1811 break;
1812 }
1813 }
1814
1823 void OnInvalidateData(int data = 0, bool gui_scope = true) override
1824 {
1825 if (!gui_scope) return;
1826
1827 switch (data) {
1828 case 1:
1829 /* The owner legend has already been rebuilt. */
1830 this->ReInit();
1831 break;
1832
1833 case 0: {
1834 extern std::bitset<NUM_INDUSTRYTYPES> _displayed_industries;
1835 if (this->map_type != SMT_INDUSTRY) this->SwitchMapType(SMT_INDUSTRY);
1836
1837 for (int i = 0; i != _smallmap_industry_count; i++) {
1839 }
1840 break;
1841 }
1842
1843 case 2:
1844 this->RebuildColourIndexIfNecessary();
1845 break;
1846
1847 default: NOT_REACHED();
1848 }
1849 this->SetDirty();
1850 }
1851
1852 bool OnRightClick(Point, WidgetID widget) override
1853 {
1854 if (widget != WID_SM_MAP || _scrolling_viewport) return false;
1855
1856 _scrolling_viewport = true;
1857 return true;
1858 }
1859
1860 void OnMouseWheel(int wheel, WidgetID widget) override
1861 {
1862 if (widget != WID_SM_MAP) return;
1864 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SM_MAP);
1865 int cursor_x = _cursor.pos.x - this->left - wid->pos_x;
1866 int cursor_y = _cursor.pos.y - this->top - wid->pos_y;
1867 Point pt = {cursor_x, cursor_y};
1868 this->SetZoomLevel((wheel < 0) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt);
1869 }
1870 }
1871
1872 void OnScroll(Point delta) override
1873 {
1875
1876 /* While tile is at (delta.x, delta.y)? */
1877 int sub;
1878 Point pt = this->PixelToTile(delta.x, delta.y, &sub);
1879 this->SetNewScroll(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, sub);
1880
1881 this->SetDirty();
1882 }
1883
1884 void OnMouseOver([[maybe_unused]] Point pt, WidgetID widget) override
1885 {
1886 IndustryType new_highlight = IT_INVALID;
1887 if (widget == WID_SM_LEGEND && this->map_type == SMT_INDUSTRY) {
1888 int industry_pos = GetPositionOnLegend(pt);
1889 if (industry_pos >= 0 && industry_pos < _smallmap_industry_count) {
1890 new_highlight = _legend_from_industries[industry_pos].type;
1891 }
1892 }
1893 if (new_highlight != _smallmap_industry_highlight) {
1894 _smallmap_industry_highlight = new_highlight;
1896 this->SetDirty();
1897 }
1898 }
1899
1900};
1901
1903bool SmallMapWindow::show_towns = true;
1906
1917public:
1919
1920 void SetupSmallestSize(Window *w) override
1921 {
1922 assert(this->children.size() == 2);
1923 NWidgetBase *display = this->children.front().get();
1924 NWidgetBase *bar = this->children.back().get();
1925
1926 display->SetupSmallestSize(w);
1927 bar->SetupSmallestSize(w);
1928
1929 this->smallmap_window = dynamic_cast<SmallMapWindow *>(w);
1930 assert(this->smallmap_window != nullptr);
1931 this->smallest_x = std::max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth());
1933 this->fill_x = std::max(display->fill_x, bar->fill_x);
1934 this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : std::min(display->fill_y, bar->fill_y);
1935 this->resize_x = std::max(display->resize_x, bar->resize_x);
1936 this->resize_y = std::min(display->resize_y, bar->resize_y);
1937 this->ApplyAspectRatio();
1938 }
1939
1940 void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
1941 {
1942 this->pos_x = x;
1943 this->pos_y = y;
1944 this->current_x = given_width;
1945 this->current_y = given_height;
1946
1947 assert(this->children.size() == 2);
1948 NWidgetBase *display = this->children.front().get();
1949 NWidgetBase *bar = this->children.back().get();
1950
1951 if (sizing == ST_SMALLEST) {
1952 this->smallest_x = given_width;
1953 this->smallest_y = given_height;
1954 /* Make display and bar exactly equal to their minimal size. */
1955 display->AssignSizePosition(ST_SMALLEST, x, y, display->smallest_x, display->smallest_y, rtl);
1956 bar->AssignSizePosition(ST_SMALLEST, x, y + display->smallest_y, bar->smallest_x, bar->smallest_y, rtl);
1957 }
1958
1959 uint bar_height = std::max(bar->smallest_y, this->smallmap_window->GetLegendHeight(this->smallmap_window->GetNumberColumnsLegend(given_width - bar->smallest_x)));
1960 uint display_height = given_height - bar_height;
1961 display->AssignSizePosition(ST_RESIZE, x, y, given_width, display_height, rtl);
1962 bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl);
1963 }
1964};
1965
1967static constexpr std::initializer_list<NWidgetPart> _nested_smallmap_display = {
1968 NWidget(WWT_PANEL, COLOUR_BROWN, WID_SM_MAP_BORDER),
1969 NWidget(WWT_INSET, COLOUR_BROWN, WID_SM_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(),
1970 EndContainer(),
1971};
1972
1974static constexpr std::initializer_list<NWidgetPart> _nested_smallmap_bar = {
1975 NWidget(WWT_PANEL, COLOUR_BROWN),
1977 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SM_LEGEND), SetResize(1, 1),
1979 /* Top button row. */
1981 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_ZOOM_IN),
1982 SetSpriteTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), SetFill(1, 1),
1983 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_CENTERMAP),
1984 SetSpriteTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER_TOOLTIP), SetFill(1, 1),
1985 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_BLANK),
1986 SetSpriteTip(SPR_EMPTY), SetFill(1, 1),
1987 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_CONTOUR),
1988 SetSpriteTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP), SetFill(1, 1),
1989 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_VEHICLES),
1990 SetSpriteTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP), SetFill(1, 1),
1991 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_INDUSTRIES),
1992 SetSpriteTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP), SetFill(1, 1),
1993 EndContainer(),
1994 /* Bottom button row. */
1996 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_ZOOM_OUT),
1997 SetSpriteTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), SetFill(1, 1),
1999 SetSpriteTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF), SetFill(1, 1),
2000 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_LINKSTATS),
2001 SetSpriteTip(SPR_IMG_CARGOFLOW, STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP), SetFill(1, 1),
2002 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_ROUTES),
2003 SetSpriteTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON), SetFill(1, 1),
2004 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_VEGETATION),
2005 SetSpriteTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP), SetFill(1, 1),
2006 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_OWNERS),
2007 SetSpriteTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP), SetFill(1, 1),
2008 EndContainer(),
2010 EndContainer(),
2011 EndContainer(),
2012 EndContainer(),
2013};
2014
2015static std::unique_ptr<NWidgetBase> SmallMapDisplay()
2016{
2017 std::unique_ptr<NWidgetBase> map_display = std::make_unique<NWidgetSmallmapDisplay>();
2018
2019 map_display = MakeNWidgets(_nested_smallmap_display, std::move(map_display));
2020 map_display = MakeNWidgets(_nested_smallmap_bar, std::move(map_display));
2021 return map_display;
2022}
2023
2024static constexpr std::initializer_list<NWidgetPart> _nested_smallmap_widgets = {
2026 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
2027 NWidget(WWT_CAPTION, COLOUR_BROWN, WID_SM_CAPTION),
2028 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
2029 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
2030 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
2031 EndContainer(),
2032 NWidgetFunction(SmallMapDisplay), // Smallmap display and legend bar + image buttons.
2033 /* Bottom button row and resize box. */
2037 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SM_ENABLE_ALL), SetStringTip(STR_SMALLMAP_ENABLE_ALL),
2038 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SM_DISABLE_ALL), SetStringTip(STR_SMALLMAP_DISABLE_ALL),
2039 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_SM_SHOW_HEIGHT), SetStringTip(STR_SMALLMAP_SHOW_HEIGHT, STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT),
2040
2041 /* 'show industry names' button and container. Only shown for the industry map type. */
2043 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_SM_SHOW_IND_NAMES), SetStringTip(STR_SMALLMAP_SHOW_INDUSTRY_NAMES, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRY_NAMES),
2044 EndContainer(),
2045
2046 NWidget(WWT_PANEL, COLOUR_BROWN), SetFill(1, 0), SetResize(1, 0),
2047 EndContainer(),
2048 EndContainer(),
2049 NWidget(WWT_PANEL, COLOUR_BROWN), SetFill(1, 0), SetResize(1, 0),
2050 EndContainer(),
2051 EndContainer(),
2052 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
2053 EndContainer(),
2054};
2055
2056static WindowDesc _smallmap_desc(
2057 WDP_AUTO, "smallmap", 484, 314,
2059 {},
2060 _nested_smallmap_widgets
2061);
2062
2067{
2068 AllocateWindowDescFront<SmallMapWindow>(_smallmap_desc, 0);
2069}
2070
2079bool ScrollMainWindowTo(int x, int y, int z, bool instant)
2080{
2081 bool res = ScrollWindowTo(x, y, z, GetMainWindow(), instant);
2082
2083 /* If a user scrolls to a tile (via what way what so ever) and already is on
2084 * that tile (e.g.: pressed twice), move the smallmap to that location,
2085 * so you directly see where you are on the smallmap. */
2086
2087 if (res) return res;
2088
2090 if (w != nullptr) w->SmallMapCenterOnCurrentPos();
2091
2092 return res;
2093}
2094
2101{
2102 return static_cast<const SmallMapWindow *>(w)->GetStationMiddle(st);
2103}
Class for backupping variables and making sure they are restored later.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
Definition cargo_type.h:73
std::vector< const CargoSpec * > _sorted_cargo_specs
Cargo specifications sorted alphabetically by name.
constexpr Timpl & Set()
Set all bits.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
Definition factory.hpp:136
How all blitters should look like.
Definition base.hpp:29
virtual void * MoveTo(void *video, int x, int y)=0
Move the destination pointer the requested amount x and y, keeping in mind any pitch and bpp of the r...
virtual void SetPixel(void *video, int x, int y, PixelColour colour)=0
Draw a pixel with a given colour on the video-buffer.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
static const PixelColour LINK_COLOURS[][12]
Colours for the various "load" states of links.
Baseclass for nested widgets.
virtual void SetupSmallestSize(Window *w)=0
Compute smallest size needed by the widget.
virtual void SetDirty(const Window *w) const
Mark the widget as 'dirty' (in need of repaint).
Definition widget.cpp:931
WidgetType type
Type of the widget / nested widget.
uint resize_x
Horizontal resize step (0 means not resizable).
uint fill_x
Horizontal fill stepsize (from initial size, 0 means not resizable).
uint smallest_x
Smallest horizontal size of the widget in a filled window.
uint current_x
Current horizontal size (after resizing).
int pos_y
Vertical position of top-left corner of the widget in the window.
int pos_x
Horizontal position of top-left corner of the widget in the window.
uint smallest_y
Smallest vertical size of the widget in a filled window.
virtual void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl)=0
Assign size and position to the widget.
uint fill_y
Vertical fill stepsize (from initial size, 0 means not resizable).
uint resize_y
Vertical resize step (0 means not resizable).
RectPadding padding
Padding added to the widget. Managed by parent container widget. (parent container may swap left and ...
uint current_y
Current vertical size (after resizing).
Baseclass for container widgets.
std::vector< std::unique_ptr< NWidgetBase > > children
Child widgets in container.
Custom container class for displaying smallmap with a vertically resizing legend panel.
void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
Assign size and position to the widget.
void SetupSmallestSize(Window *w) override
Compute smallest size needed by the widget.
const SmallMapWindow * smallmap_window
Window manager instance.
PixelColour map_colour
Colour on mini-map.
Definition road.h:131
Class managing the smallmap window.
void SmallMapCenterOnCurrentPos()
Center the small map on the current center of the viewport.
void SetOverlayCargoMask()
Set the link graph overlay cargo mask from the legend.
void Close(int data) override
Hide the window and all its child windows, and mark them for a later deletion.
static SmallMapType map_type
Currently displayed legends.
uint GetNumberColumnsLegend(uint width) const
Return number of columns that can be displayed in width pixels.
void SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item=0)
Select and toggle a legend item.
void SwitchMapType(SmallMapType map_type)
Select a new map type.
void DrawSmallMap(DrawPixelInfo *dpi) const
Draws the small map.
Point ComputeScroll(int tx, int ty, int x, int y, int *sub) const
Compute base parameters of the smallmap such that tile (tx, ty) starts at pixel (x,...
Point GetStationMiddle(const Station *st) const
Get the center of the given station as point on the screen in the smallmap window.
void ForceRefresh()
Force a full refresh of the map.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
uint GetMinLegendWidth() const
Compute minimal required width of the legends.
static bool show_towns
Display town names in the smallmap.
Point PixelToTile(int px, int py, int *sub, bool add_sub=true) const
Determine the tile relative to the base tile of the smallmap, and the pixel position at that tile for...
void Blink()
Blink the industries (if hover over an industry).
void DrawIndustryNames(const DrawPixelInfo *dpi, const int vertical_padding) const
Adds industry names to the smallmap.
static void DrawVertMapIndicator(int x, int y, int y2)
Draws vertical part of map indicator.
uint GetLegendHeight(uint num_columns) const
Compute height given a number of columns.
uint min_number_of_columns
Minimal number of columns in legends.
CompanyMask GetOverlayCompanyMask() const
Get a bitmask for company links to be displayed.
uint32_t GetTileColours(const TileArea &ta) const
Decide which colours to show to the user for a group of tiles.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
void DrawTowns(const DrawPixelInfo *dpi, const int vertical_padding) const
Adds town names to the smallmap.
void OnPaint() override
The window must be repainted.
void SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt)
Initialize or change the zoom level.
int GetPositionOnLegend(Point pt)
Determines the mouse position on the legend.
void OnMouseWheel(int wheel, WidgetID widget) override
The mouse wheel has been turned.
void OnMouseOver(Point pt, WidgetID widget) override
The mouse is currently moving over the window or has just moved outside of the window.
ZoomLevelChange
Available kinds of zoomlevel changes.
@ ZLC_ZOOM_IN
Zoom in.
@ ZLC_ZOOM_OUT
Zoom out.
@ ZLC_INITIALIZE
Initialize zoom level.
void SetupWidgetData()
Function to set up widgets depending on the information being shown on the smallmap.
static bool show_ind_names
Display industry names in the smallmap.
void RebuildColourIndexIfNecessary()
Rebuilds the colour indices used for fast access to the smallmap contour colours based on the heightl...
void DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const
Draws one column of tiles of the small map in a certain mode onto the screen buffer,...
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
static int map_height_limit
Currently used/cached map height limit.
Point RemapTile(int tile_x, int tile_y) const
Remap tile to location on this smallmap.
static void DrawHorizMapIndicator(int x, int x2, int y)
Draws horizontal part of map indicator.
void OnInit() override
Notification that the nested widget tree gets initialized.
void UpdateLinks()
Update all the links on the map.
void OnScroll(Point delta) override
Handle the request for (viewport) scrolling.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void DrawMapIndicators() const
Adds map indicators to the smallmap.
bool OnRightClick(Point, WidgetID widget) override
A click with the right mouse button has been made on the window.
void SetNewScroll(int sx, int sy, int sub)
Set new scroll_x, scroll_y, and subscroll values after limiting them such that the center of the smal...
uint GetNumberRowsLegend(uint columns) const
Get the number of rows in the legend from the number of columns.
void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const
Adds vehicles to the smallmap.
static void BreakIndustryChainLink()
Notify the industry chain window to stop sending newly selected industries.
A sort-of mixin that implements 'at(pos)' and 'operator[](pos)' only for a specific type.
RectPadding framerect
Standard padding inside many panels.
Definition window_gui.h:40
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
int hsep_normal
Normal horizontal spacing.
Definition window_gui.h:61
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition window_gui.h:38
Map accessors for 'clear' tiles.
bool IsClearGround(Tile t, ClearGround ct)
Set the type of clear tile.
Definition clear_map.h:59
@ CLEAR_GRASS
0-3
Definition clear_map.h:20
@ CLEAR_SNOW
0-3 (Not stored in map.)
Definition clear_map.h:24
ClearGround GetClearGround(Tile t)
Get the type of clear tile.
Definition clear_map.h:47
bool IsSnowTile(Tile t)
Test if a tile is covered with snow.
Definition clear_map.h:35
uint GetClearDensity(Tile t)
Get the density of a non-field clear tile.
Definition clear_map.h:71
Definition of stuff that is very close to a company, like the company struct itself.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
static constexpr Owner OWNER_TOWN
A town owns the tile, or a town is expanding.
static constexpr Owner OWNER_NONE
The tile has no ownership.
static constexpr Owner OWNER_WATER
The tile/execution is done by "water".
Function to handling different endian machines.
#define DECLARE_ENUM_AS_ADDABLE(EnumType)
Operator that allows this enumeration to be added to any other enumeration.
Factory to 'query' all available blitters.
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:87
int CentreBounds(int min, int max, int size)
Determine where to position a centred object.
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:897
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:668
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
void GfxFillRect(int left, int top, int right, int bottom, const std::variant< PixelColour, PaletteID > &colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition gfx.cpp:115
bool FillDrawPixelInfo(DrawPixelInfo *n, int left, int top, int width, int height)
Set up a clipping area for only drawing into a certain area.
Definition gfx.cpp:1568
@ FS_SMALL
Index of the small font in the font tables.
Definition gfx_type.h:250
@ SA_LEFT
Left align the text.
Definition gfx_type.h:388
constexpr NWidgetPart NWidgetFunction(NWidgetFunctionType *func_ptr)
Obtain a nested widget (sub)tree from an external source.
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetSpriteTip(SpriteID sprite, StringID tip={})
Widget part function for setting the sprite and tooltip.
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
std::unique_ptr< NWidgetBase > MakeNWidgets(std::span< const NWidgetPart > nwid_parts, std::unique_ptr< NWidgetBase > &&container)
Construct a nested widget tree from an array of parts.
Definition widget.cpp:3374
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=INVALID_WIDGET)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
The colour tables for heightmaps.
static const uint32_t _violet_map_heights[]
Height map colours for the violet colour scheme, ordered by height.
static const uint32_t _dark_green_map_heights[]
Height map colours for the dark green colour scheme, ordered by height.
static const uint32_t _green_map_heights[]
Height map colours for the green colour scheme, ordered by height.
Base of all industries.
bool IsTileForestIndustry(TileIndex tile)
Check whether the tile is a forest.
const IndustrySpec * GetIndustrySpec(IndustryType thistype)
Accessor for array _industry_specs.
std::array< IndustryType, NUM_INDUSTRYTYPES > _sorted_industry_types
Industry types sorted by name.
std::bitset< NUM_INDUSTRYTYPES > _displayed_industries
Communication from the industry chain window to the smallmap window about what industries to display.
static const IndustryType NUM_INDUSTRYTYPES
total number of industry types, new and old; limited to 240 because we need some special ids like IT_...
Point InverseRemapCoords2(int x, int y, bool clamp_to_map, bool *clamped)
Map 2D viewport or smallmap coordinate to 3D world or tile coordinate.
Functions related to OTTD's landscape.
Point InverseRemapCoords(int x, int y)
Map 2D viewport or smallmap coordinate to 3D world or tile coordinate.
Definition landscape.h:111
Declaration of linkgraph overlay GUI.
static TileIndex TileXY(uint x, uint y)
Returns the TileIndex of a coordinate.
Definition map_func.h:385
static uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:437
static uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:427
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
constexpr uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
PixelColour GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition palette.cpp:388
static constexpr PixelColour PC_TREES
Green palette colour for trees.
static constexpr PixelColour PC_VERY_LIGHT_YELLOW
Almost-white yellow palette colour.
static constexpr PixelColour PC_ROUGH_LAND
Dark green palette colour for rough land.
static constexpr PixelColour PC_YELLOW
Yellow palette colour.
static constexpr PixelColour PC_GREEN
Green palette colour.
static constexpr PixelColour PC_FIELDS
Light brown palette colour for fields.
static constexpr PixelColour PC_DARK_RED
Dark red palette colour.
static constexpr PixelColour PC_WATER
Dark blue palette colour for water.
static constexpr PixelColour PC_ORANGE
Orange palette colour.
static constexpr PixelColour PC_GRASS_LAND
Dark green palette colour for grass land.
static constexpr PixelColour PC_BARE_LAND
Brown palette colour for bare land.
static constexpr PixelColour PC_GREY
Grey palette colour.
static constexpr PixelColour PC_RED
Red palette colour.
static constexpr PixelColour PC_DARK_GREY
Dark grey palette colour.
static constexpr PixelColour PC_BLACK
Black palette colour.
static constexpr PixelColour PC_RAINFOREST
Pale green palette colour for rainforest.
static constexpr PixelColour PC_WHITE
White palette colour.
static constexpr PixelColour PC_VERY_DARK_BROWN
Almost-black brown palette colour.
static constexpr PixelColour PC_LIGHT_BLUE
Light blue palette colour.
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:300
RailType GetRailType(Tile t)
Gets the rail type of the given tile.
Definition rail_map.h:115
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:215
Owner GetRoadOwner(Tile t, RoadTramType rtt)
Get the owner of a specific road type.
Definition road_map.h:218
@ RTT_ROAD
Road road type.
Definition road_type.h:38
@ RTT_TRAM
Tram road type.
Definition road_type.h:39
@ INVALID_ROADTYPE
flag for invalid roadtype
Definition road_type.h:28
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
@ VSM_VIEWPORT_RMB_FIXED
Viewport moves with mouse movement on holding right mouse button, cursor position is fixed.
@ VSM_MAP_RMB_FIXED
Map moves with mouse movement on holding right mouse button, cursor position is fixed.
@ SWS_OFF
Scroll wheel has no effect.
#define MK(a, b)
Macro for ordinary entry of LegendAndColour.
void ShowSmallMap()
Show the smallmap window.
static const AndOr _smallmap_vehicles_andor[]
Colour masks for "Vehicles", "Industry", and "Vegetation" modes.
static uint32_t GetSmallMapLinkStatsPixels(TileIndex tile, TileType t)
Return the colour a tile would be displayed with in the small map in mode "link stats".
static uint32_t GetSmallMapContoursPixels(TileIndex tile, TileType t)
Return the colour a tile would be displayed with in the small map in mode "Contour".
void BuildLandLegend()
(Re)build the colour tables for the legends.
static LegendAndColour _legend_from_industries[NUM_INDUSTRYTYPES+1]
Allow room for all industries, plus a terminator entry This is required in order to have the industry...
#define MS(a, b)
Macro for break marker in arrays of LegendAndColour.
#define MC(col_break)
Macro for a height legend entry with configurable colour.
static const uint8_t _linkstat_colours_in_legenda[]
Link stat colours shown in legenda.
static uint _industry_to_list_pos[NUM_INDUSTRYTYPES]
For connecting industry type to position in industries list(small map legend)
static const uint8_t _tiletype_importance[]
Mapping of tile type to importance of the tile (higher number means more interesting to show).
static IndustryType _smallmap_industry_highlight
Highlight a specific industry type.
void BuildOwnerLegend()
Completes the array for the owned property legend.
static const int NUM_NO_COMPANY_ENTRIES
Number of entries in the owner legend that are not companies.
static int _smallmap_cargo_count
Number of cargos in the link stats legend.
uint32_t GetSmallMapOwnerPixels(TileIndex tile, TileType t, IncludeHeightmap include_heightmap)
Return the colour a tile would be displayed with in the small map in mode "Owner".
static int _smallmap_company_count
Number of entries in the owner legend.
static SmallMapColourScheme _heightmap_schemes[]
Available colour schemes for height maps.
static constexpr std::initializer_list< NWidgetPart > _nested_smallmap_display
Widget parts of the smallmap display.
static const PixelColour _vehicle_type_colours[6]
Vehicle colours in SMT_VEHICLES mode.
static uint32_t GetSmallMapVegetationPixels(TileIndex tile, TileType t)
Return the colour a tile would be displayed with in the smallmap in mode "Vegetation".
static constexpr std::initializer_list< NWidgetPart > _nested_smallmap_bar
Widget parts of the smallmap legend bar + image buttons.
static uint32_t GetSmallMapIndustriesPixels(TileIndex tile, TileType t)
Return the colour a tile would be displayed with in the small map in mode "Industries".
static LegendAndColour _legend_land_contours[]
Legend text giving the colours to look for on the minimap.
static bool _smallmap_show_heightmap
Show heightmap in industry and owner mode of smallmap window.
SmallMapType
Types of legends in the WID_SM_LEGEND widget.
static int _smallmap_industry_count
Number of used industries.
static bool _smallmap_industry_highlight_state
State of highlight blinking.
void BuildLinkStatsLegend()
Populate legend table for the link stat view.
static uint32_t GetSmallMapRoutesPixels(TileIndex tile, TileType t)
Return the colour a tile would be displayed with in the small map in mode "Routes".
static uint16_t _industry_to_name_string_width[NUM_INDUSTRYTYPES]
The string bounding box width for each industry type in the smallmap.
#define MKEND()
Macro for end of list marker in arrays of LegendAndColour.
static uint32_t GetSmallMapVehiclesPixels(TileIndex, TileType t)
Return the colour a tile would be displayed with in the small map in mode "Vehicles".
bool ScrollMainWindowTo(int x, int y, int z, bool instant)
Scrolls the main window to given coordinates.
static TypedIndexContainer< std::array< uint32_t, MAX_COMPANIES >, CompanyID > _company_to_list_pos
For connecting company ID to position in owner list (small map legend)
void BuildIndustriesLegend()
Fills an array for the industries legends.
static const AndOr _smallmap_contours_andor[]
Colour masks for "Contour" and "Routes" modes.
#define MOEND()
Macro used for forcing a rebuild of the owner legend the first time it is used.
static LegendAndColour _legend_linkstats[NUM_CARGO+lengthof(_linkstat_colours_in_legenda)+1]
Legend entries for the link stats view.
#define MO(a, b)
Macro for non-company owned property entry of LegendAndColour.
Point GetSmallMapStationMiddle(const Window *w, const Station *st)
Determine the middle of a station in the smallmap window.
Smallmap GUI functions.
IncludeHeightmap
Enum for how to include the heightmap pixels/colours in small map related functions.
@ Always
Always include the heightmap.
@ IfEnabled
Only include the heightmap if its enabled in the gui by the player.
Types related to the smallmap widgets.
@ WID_SM_OWNERS
Button to select the owners view.
@ WID_SM_VEHICLES
Button to select the vehicles view.
@ WID_SM_MAP_BORDER
Border around the smallmap.
@ WID_SM_CENTERMAP
Button to move smallmap center to main window center.
@ WID_SM_VEGETATION
Button to select the vegetation view.
@ WID_SM_TOGGLETOWNNAME
Toggle button to display town names.
@ WID_SM_CONTOUR
Button to select the contour view (height map).
@ WID_SM_ENABLE_ALL
Button to enable display of all legend entries.
@ WID_SM_SHOW_HEIGHT
Show heightmap toggle button.
@ WID_SM_ZOOM_OUT
Button to zoom out one step.
@ WID_SM_LEGEND
Bottom panel to display smallmap legends.
@ WID_SM_ZOOM_IN
Button to zoom in one step.
@ WID_SM_MAP
Panel containing the smallmap.
@ WID_SM_SHOW_IND_NAMES
Show industry names toggle button.
@ WID_SM_SELECT_BUTTONS
Selection widget for the buttons present in some smallmap modes.
@ WID_SM_BLANK
Empty button as placeholder.
@ WID_SM_LINKSTATS
Button to select the link stats view.
@ WID_SM_SHOW_IND_NAMES_SEL
Container for the 'show industry names' button, which can be hidden.
@ WID_SM_ROUTES
Button to select the routes view.
@ WID_SM_INDUSTRIES
Button to select the industries view.
@ WID_SM_CAPTION
Caption of the window.
@ WID_SM_DISABLE_ALL
Button to disable display of all legend entries.
void SndClickBeep()
Play a beep sound for a click event if enabled in settings.
Definition sound.cpp:253
Functions related to sound.
Maps accessors for stations.
StationType GetStationType(Tile t)
Get the station type of this tile.
Definition station_map.h:44
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:271
void GetStringWithArgs(StringBuilder &builder, StringID string, StringParameters &args, uint case_index, bool game_script)
Get a parsed string with most special stringcodes replaced by the string parameters.
Definition strings.cpp:336
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
@ TD_RTL
Text is written right-to-left by default.
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
StationRect rect
NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions.
Specification of a cargo type.
Definition cargotype.h:74
CargoType Index() const
Determines index of this cargospec.
Definition cargotype.h:108
StringID name
Name of this type of cargo.
Definition cargotype.h:91
GUISettings gui
settings related to the GUI
bool freeform_edges
allow terraforming the tiles at the map edges
uint8_t map_height_limit
the maximum allowed heightlevel
T y
Y coordinate.
T x
X coordinate.
bool fix_at
mouse is moving, but cursor is not (used for scrolling)
Definition gfx_type.h:128
Point pos
logical mouse position
Definition gfx_type.h:125
Data about how and where to blit pixels.
Definition gfx_type.h:157
uint8_t linkgraph_colours
linkgraph overlay colours
uint8_t scroll_mode
viewport scroll mode
uint8_t scrollwheel_scrolling
scrolling using the scroll wheel?
uint8_t smallmap_land_colour
colour used for land and heightmap at the smallmap
LandscapeType landscape
the landscape we're currently in
ConstructionSettings construction
construction of things in-game
GameCreationSettings game_creation
settings used during the creation of a game (map)
Defines the data structure for constructing industry.
StringID name
Displayed name of the industry.
bool enabled
entity still available (by default true).newgrf can disable it, though
PixelColour map_colour
colour used for the small map
Defines the internal data of a functional industry.
Definition industry.h:62
IndustryType type
type of industry.
Definition industry.h:115
static uint16_t GetIndustryTypeCount(IndustryType type)
Get the count of industries for this type.
Definition industry.h:264
static Industry * GetByTile(TileIndex tile)
Get the industry of the given tile.
Definition industry.h:251
Structure for holding relevant data for legends in small map.
PixelColour colour
Colour of the item on the map.
uint8_t height
Height in tiles. Only valid for height legend entries.
StringID legend
String corresponding to the coloured item.
bool show_on_map
For filtering industries, if true, industry is shown on the map in colour.
CompanyID company
Company to display. Only valid for company entries of the owner legend.
bool end
This is the end of the list.
bool col_break
Perform a column break and go further at the next column.
IndustryType type
Type of industry. Only valid for industry entries.
static uint MaxY()
Gets the maximum Y coordinate within the map, including MP_VOID.
Definition map_func.h:308
static uint MaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition map_func.h:299
Represents the covered area of e.g.
void ClampToMap()
Clamp the tile area to map borders.
Definition tilearea.cpp:142
Colour for pixel/line drawing.
Definition gfx_type.h:405
uint8_t p
Palette index.
Definition gfx_type.h:406
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static constexpr size_t MAX_SIZE
Make template parameter accessible from outside.
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
int Width() const
Get width of Rect.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Rect WithHeight(int height, bool end=false) const
Copy Rect and set its height.
Rect Indent(int indent, bool end) const
Copy Rect and indent it from its position.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
Colour scheme of the smallmap.
std::vector< uint32_t > height_colours
Cached colours for each level in a map.
uint32_t default_colour
Default colour of the land.
std::span< const uint32_t > height_colours_base
Base table for determining the colours.
Station data structure.
Town data structure.
Definition town.h:63
Vehicle data structure.
Data structure for viewport, display of a part of the world.
int virtual_top
Virtual top coordinate.
int virtual_left
Virtual left coordinate.
int virtual_width
width << zoom
int virtual_height
height << zoom
High level window description.
Definition window_gui.h:168
Data structure for an opened window.
Definition window_gui.h:274
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1104
std::unique_ptr< ViewportData > viewport
Pointer to viewport data, if present.
Definition window_gui.h:319
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:506
static uint TileHeight(Tile tile)
Returns the height of a tile.
Definition tile_map.h:29
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
TropicZone GetTropicZone(Tile tile)
Get the tropic zone.
Definition tile_map.h:238
static TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
static constexpr uint MAX_TILE_HEIGHT
Maximum allowed tile height.
Definition tile_type.h:24
@ TROPICZONE_RAINFOREST
Rainforest tile.
Definition tile_type.h:79
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
static constexpr uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
TileType
The different types of tiles.
Definition tile_type.h:47
@ MP_TREES
Tile got trees.
Definition tile_type.h:52
@ MP_ROAD
A tile with road (or tram tracks)
Definition tile_type.h:50
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
@ MP_TUNNELBRIDGE
Tunnel entry/exit and bridge heads.
Definition tile_type.h:57
@ MP_CLEAR
A tile without any structures, i.e. grass, rocks, farm fields etc.
Definition tile_type.h:48
@ MP_HOUSE
A house by a town.
Definition tile_type.h:51
@ MP_WATER
Water tile.
Definition tile_type.h:54
@ MP_RAILWAY
A railway.
Definition tile_type.h:49
@ MP_INDUSTRY
Part of an industry.
Definition tile_type.h:56
@ MP_VOID
Invisible tiles at the SW and SE border.
Definition tile_type.h:55
OrthogonalTileArea TileArea
Shorthand for the much more common orthogonal tile area.
Definition of Interval and OneShot timers.
Definition of the Window system.
static constexpr std::chrono::milliseconds TIMER_BLINK_INTERVAL
Interval used by blinking interface elements.
Base of the town class.
TransportType
Available types of transport.
@ TRANSPORT_RAIL
Transport by train.
@ TRANSPORT_ROAD
Transport by road vehicle.
Map accessors for tree tiles.
TreeGround GetTreeGround(Tile t)
Returns the groundtype for tree tiles.
Definition tree_map.h:102
@ TREE_GROUND_ROUGH_SNOW
A snow tile that is rough underneath.
Definition tree_map.h:57
@ TREE_GROUND_SNOW_DESERT
a desert or snow tile, depend on landscape
Definition tree_map.h:55
Functions that have tunnels and bridges in common.
TransportType GetTunnelBridgeTransportType(Tile t)
Tunnel: Get the transport type of the tunnel (road or rail) Bridge: Get the transport type of the bri...
Base class for all vehicles.
@ VEH_EFFECT
Effect vehicle type (smoke, explosions, sparks, bubbles)
bool ScrollWindowTo(int x, int y, int z, Window *w, bool instant)
Scrolls the viewport in a window to a given location.
Functions related to (drawing on) viewports.
static const int TILE_HEIGHT_STEP
One Z unit tile height difference is displayed as 50m.
bool IsTileOnWater(Tile t)
Tests if the tile was built on water.
Definition water_map.h:138
static RectPadding ScaleGUITrad(const RectPadding &r)
Scale a RectPadding to GUI zoom level.
Definition widget.cpp:49
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ WWT_INSET
Pressed (inset) panel, most commonly used as combo box text area.
Definition widget_type.h:40
@ WWT_IMGBTN
(Toggle) Button with image
Definition widget_type.h:41
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
@ NWID_SPACER
Invisible widget that takes some space.
Definition widget_type.h:70
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:44
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:39
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:57
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:55
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:52
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:68
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:60
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:37
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:59
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:56
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:71
@ SZSP_NONE
Display plane with zero size in both directions (none filling and resizing).
@ EqualSize
Containers should keep all their (resizing) children equally large.
SizingType
Different forms of sizing nested widgets, using NWidgetBase::AssignSizePosition()
@ ST_RESIZE
Resize the nested widget tree.
@ ST_SMALLEST
Initialize nested widget tree to smallest size. Also updates current_x and current_y.
Window * GetMainWindow()
Get the main window, i.e.
Definition window.cpp:1182
bool _scrolling_viewport
A viewport is being scrolled with the mouse.
Definition window.cpp:93
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1153
void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
Mark window data of all windows of a given class as invalid (in need of re-computing) Note that by de...
Definition window.cpp:3318
Window functions not directly related to making/drawing windows.
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:144
int WidgetID
Widget ID.
Definition window_type.h:20
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:50
@ WC_INDUSTRY_CARGOES
Industry cargoes chain; Window numbers:
@ WC_SMALLMAP
Small map; Window numbers:
Functions related to zooming.