OpenTTD Source 20260129-master-g2bb01bd0e4
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#include "core/enum_type.hpp"
33
35
36#include "table/strings.h"
37
38#include <bitset>
39
40#include "safeguards.h"
41
45
57
59static const uint8_t _linkstat_colours_in_legenda[] = {0, 1, 3, 5, 7, 9, 11};
60
61static const int NUM_NO_COMPANY_ENTRIES = 4;
62
64#define MK(a, b) {b, a, IT_INVALID, 0, CompanyID::Invalid(), true, false, false}
65
67#define MC(col_break) {STR_TINY_BLACK_HEIGHT, {}, IT_INVALID, 0, CompanyID::Invalid(), true, false, col_break}
68
70#define MO(a, b) {b, a, IT_INVALID, 0, CompanyID::Invalid(), true, false, false}
71
73#define MOEND() {STR_NULL, {}, IT_INVALID, 0, OWNER_NONE, true, true, false}
74
76#define MKEND() {STR_NULL, {}, IT_INVALID, 0, CompanyID::Invalid(), true, true, false}
77
82#define MS(a, b) {b, a, IT_INVALID, 0, CompanyID::Invalid(), true, false, true}
83
86 MK(PC_BLACK, STR_SMALLMAP_LEGENDA_ROADS),
87 MK(PC_GREY, STR_SMALLMAP_LEGENDA_RAILROADS),
88 MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS),
89 MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
90 MK(PC_WHITE, STR_SMALLMAP_LEGENDA_VEHICLES),
91
92 /* Placeholders for the colours and heights of the legend.
93 * The following values are set at BuildLandLegend() based
94 * on each colour scheme and the maximum map height. */
95 MC(true),
96 MC(false),
97 MC(false),
98 MC(false),
99 MC(false),
100 MC(false),
101 MC(true),
102 MC(false),
103 MC(false),
104 MC(false),
105 MC(false),
106 MC(false),
107 MKEND()
108};
109
110static const LegendAndColour _legend_vehicles[] = {
111 MK(PC_RED, STR_SMALLMAP_LEGENDA_TRAINS),
112 MK(PC_YELLOW, STR_SMALLMAP_LEGENDA_ROAD_VEHICLES),
113 MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_SHIPS),
114 MK(PC_WHITE, STR_SMALLMAP_LEGENDA_AIRCRAFT),
115
116 MS(PC_BLACK, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES),
117 MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
118 MKEND()
119};
120
121static const LegendAndColour _legend_routes[] = {
122 MK(PC_BLACK, STR_SMALLMAP_LEGENDA_ROADS),
123 MK(PC_GREY, STR_SMALLMAP_LEGENDA_RAILROADS),
124 MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
125
126 MS(PC_VERY_DARK_BROWN, STR_SMALLMAP_LEGENDA_RAILROAD_STATION),
127 MK(PC_ORANGE, STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY),
128 MK(PC_YELLOW, STR_SMALLMAP_LEGENDA_BUS_STATION),
129 MK(PC_RED, STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT),
130 MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_DOCK),
131 MKEND()
132};
133
134static const LegendAndColour _legend_vegetation[] = {
135 MK(PC_ROUGH_LAND, STR_SMALLMAP_LEGENDA_ROUGH_LAND),
136 MK(PC_GRASS_LAND, STR_SMALLMAP_LEGENDA_GRASS_LAND),
137 MK(PC_BARE_LAND, STR_SMALLMAP_LEGENDA_BARE_LAND),
138 MK(PC_RAINFOREST, STR_SMALLMAP_LEGENDA_RAINFOREST),
139 MK(PC_FIELDS, STR_SMALLMAP_LEGENDA_FIELDS),
140 MK(PC_TREES, STR_SMALLMAP_LEGENDA_TREES),
141
142 MS(PC_GREEN, STR_SMALLMAP_LEGENDA_FOREST),
143 MK(PC_GREY, STR_SMALLMAP_LEGENDA_ROCKS),
144 MK(PC_ORANGE, STR_SMALLMAP_LEGENDA_DESERT),
145 MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_SNOW),
146 MK(PC_BLACK, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES),
147 MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
148 MKEND()
149};
150
151static LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1] = {
152 MO(PC_WATER, STR_SMALLMAP_LEGENDA_WATER),
153 MO({}, STR_SMALLMAP_LEGENDA_NO_OWNER), // This colour will vary depending on settings.
154 MO(PC_DARK_RED, STR_SMALLMAP_LEGENDA_TOWNS),
155 MO(PC_DARK_GREY, STR_SMALLMAP_LEGENDA_INDUSTRIES),
156 /* The legend will be terminated the first time it is used. */
157 MOEND(),
158};
159
160#undef MK
161#undef MC
162#undef MS
163#undef MO
164#undef MOEND
165#undef MKEND
166
179static bool _smallmap_show_heightmap = false;
181static IndustryType _smallmap_industry_highlight = IT_INVALID;
186
191{
192 uint j = 0;
193
194 /* Add each name */
195 for (IndustryType ind : _sorted_industry_types) {
196 const IndustrySpec *indsp = GetIndustrySpec(ind);
197 if (indsp->enabled) {
203 _legend_from_industries[j].end = false;
204
205 /* Store widget number for this industry type. */
206 _industry_to_list_pos[ind] = j;
207 j++;
208 }
209 }
210 /* Terminate the list */
212
213 /* Store number of enabled industries */
215}
216
221{
222 /* Clear the legend */
223 std::fill(std::begin(_legend_linkstats), std::end(_legend_linkstats), LegendAndColour{});
224
225 uint i = 0;
226 for (; i < _sorted_cargo_specs.size(); ++i) {
227 const CargoSpec *cs = _sorted_cargo_specs[i];
228
230 _legend_linkstats[i].colour = cs->legend_colour;
231 _legend_linkstats[i].type = cs->Index();
233 }
234
237
239 _legend_linkstats[i].legend = STR_EMPTY;
242 }
243
244 _legend_linkstats[_smallmap_cargo_count].legend = STR_LINKGRAPH_LEGEND_UNUSED;
245 _legend_linkstats[i - 1].legend = STR_LINKGRAPH_LEGEND_OVERLOADED;
246 _legend_linkstats[(_smallmap_cargo_count + i - 1) / 2].legend = STR_LINKGRAPH_LEGEND_SATURATED;
247 _legend_linkstats[i].end = true;
248}
249
250static const LegendAndColour * const _legend_table[] = {
252 _legend_vehicles,
255 _legend_routes,
256 _legend_vegetation,
257 _legend_land_owners,
258};
259
260#define MKCOLOUR(x) TO_LE32(x)
261
262#define MKCOLOUR_XXXX(x) (MKCOLOUR(0x01010101) * (uint)(x.p))
263#define MKCOLOUR_0XX0(x) (MKCOLOUR(0x00010100) * (uint)(x.p))
264#define MKCOLOUR_X00X(x) (MKCOLOUR(0x01000001) * (uint)(x.p))
265
266#define MKCOLOUR_XYYX(x, y) (MKCOLOUR_X00X(x) | MKCOLOUR_0XX0(y))
267
268#define MKCOLOUR_0000 MKCOLOUR_XXXX(PixelColour{0x00})
269#define MKCOLOUR_F00F MKCOLOUR_X00X(PixelColour{0xFF})
270#define MKCOLOUR_FFFF MKCOLOUR_XXXX(PixelColour{0xFF})
271
273
276 std::vector<uint32_t> height_colours;
277 std::span<const uint32_t> height_colours_base;
278 uint32_t default_colour;
279};
280
283 {{}, _green_map_heights, MKCOLOUR_XXXX(PixelColour{0x54})},
284 {{}, _dark_green_map_heights, MKCOLOUR_XXXX(PixelColour{0x62})},
285 {{}, _violet_map_heights, MKCOLOUR_XXXX(PixelColour{0x81})},
286};
287
292{
293 /* The smallmap window has never been initialized, so no need to change the legend. */
294 if (_heightmap_schemes[0].height_colours.empty()) return;
295
296 /*
297 * The general idea of this function is to fill the legend with an appropriate evenly spaced
298 * selection of height levels. All entries with STR_TINY_BLACK_HEIGHT are reserved for this.
299 * At the moment there are twelve of these.
300 *
301 * The table below defines up to which height level a particular delta in the legend should be
302 * used. One could opt for just dividing the maximum height and use that as delta, but that
303 * creates many "ugly" legend labels, e.g. once every 950 meter. As a result, this table will
304 * reduce the number of deltas to 7: every 100m, 200m, 300m, 500m, 750m, 1000m and 1250m. The
305 * deltas are closer together at the lower numbers because going from 12 entries to just 4, as
306 * would happen when replacing 200m and 300m by 250m, would mean the legend would be short and
307 * that might not be considered appropriate.
308 *
309 * The current method yields at least 7 legend entries and at most 12. It can be increased to
310 * 8 by adding a 150m and 400m option, but especially 150m creates ugly heights.
311 *
312 * It tries to evenly space the legend items over the two columns that are there for the legend.
313 */
314
315 /* Table for delta; if max_height is less than the first column, use the second column as value. */
316 uint deltas[][2] = { { 24, 2 }, { 48, 4 }, { 72, 6 }, { 120, 10 }, { 180, 15 }, { 240, 20 }, { MAX_TILE_HEIGHT + 1, 25 }};
317 uint i = 0;
318 for (; _settings_game.construction.map_height_limit >= deltas[i][0]; i++) {
319 /* Nothing to do here. */
320 }
321 uint delta = deltas[i][1];
322
323 int total_entries = (_settings_game.construction.map_height_limit / delta) + 1;
324 int rows = CeilDiv(total_entries, 2);
325 int j = 0;
326
327 for (i = 0; i < lengthof(_legend_land_contours) - 1 && j < total_entries; i++) {
328 if (_legend_land_contours[i].legend != STR_TINY_BLACK_HEIGHT) continue;
329
330 _legend_land_contours[i].col_break = j % rows == 0;
331 _legend_land_contours[i].end = false;
332 _legend_land_contours[i].height = j * delta;
334 j++;
335 }
336 _legend_land_contours[i].end = true;
337}
338
343{
344 _legend_land_owners[1].colour = PixelColour{static_cast<uint8_t>(_heightmap_schemes[_settings_client.gui.smallmap_land_colour].default_colour)};
345
347 for (const Company *c : Company::Iterate()) {
348 _legend_land_owners[i].colour = GetColourGradient(c->colour, SHADE_LIGHT);
349 _legend_land_owners[i].company = c->index;
350 _legend_land_owners[i].show_on_map = true;
351 _legend_land_owners[i].col_break = false;
352 _legend_land_owners[i].end = false;
353 _company_to_list_pos[c->index] = i;
354 i++;
355 }
356
357 /* Terminate the list */
358 _legend_land_owners[i].end = true;
359
360 /* Store maximum amount of owner legend entries. */
362}
363
364struct AndOr {
365 uint32_t mor;
366 uint32_t mand;
367};
368
369static inline uint32_t ApplyMask(uint32_t colour, const AndOr *mask)
370{
371 return (colour & mask->mand) | mask->mor;
372}
373
374
377 AndOr(MKCOLOUR_0000, MKCOLOUR_FFFF), // TileType::Clear
378 AndOr(MKCOLOUR_0XX0(PC_GREY), MKCOLOUR_F00F), // TileType::Railway
379 AndOr(MKCOLOUR_0XX0(PC_BLACK), MKCOLOUR_F00F), // TileType::Road
380 AndOr(MKCOLOUR_0XX0(PC_DARK_RED), MKCOLOUR_F00F), // TileType::House
381 AndOr(MKCOLOUR_0000, MKCOLOUR_FFFF), // TileType::Trees
382 AndOr(MKCOLOUR_XXXX(PC_LIGHT_BLUE), MKCOLOUR_0000), // TileType::Station
383 AndOr(MKCOLOUR_XXXX(PC_WATER), MKCOLOUR_0000), // TileType::Water
384 AndOr(MKCOLOUR_0000, MKCOLOUR_FFFF), // TileType::Void
385 AndOr(MKCOLOUR_XXXX(PC_DARK_RED), MKCOLOUR_0000), // TileType::Industry
386 AndOr(MKCOLOUR_0000, MKCOLOUR_FFFF), // TileType::TunnelBridge
387 AndOr(MKCOLOUR_0XX0(PC_DARK_RED), MKCOLOUR_F00F), // TileType::Object
388 AndOr(MKCOLOUR_0XX0(PC_GREY), MKCOLOUR_F00F),
389};
390
393 AndOr(MKCOLOUR_0000, MKCOLOUR_FFFF), // TileType::Clear
394 AndOr(MKCOLOUR_0XX0(PC_BLACK), MKCOLOUR_F00F), // TileType::Railway
395 AndOr(MKCOLOUR_0XX0(PC_BLACK), MKCOLOUR_F00F), // TileType::Road
396 AndOr(MKCOLOUR_0XX0(PC_DARK_RED), MKCOLOUR_F00F), // TileType::House
397 AndOr(MKCOLOUR_0000, MKCOLOUR_FFFF), // TileType::Trees
398 AndOr(MKCOLOUR_0XX0(PC_BLACK), MKCOLOUR_F00F), // TileType::Station
399 AndOr(MKCOLOUR_XXXX(PC_WATER), MKCOLOUR_0000), // TileType::Water
400 AndOr(MKCOLOUR_0000, MKCOLOUR_FFFF), // TileType::Void
401 AndOr(MKCOLOUR_XXXX(PC_DARK_RED), MKCOLOUR_0000), // TileType::Industry
402 AndOr(MKCOLOUR_0000, MKCOLOUR_FFFF), // TileType::TunnelBridge
403 AndOr(MKCOLOUR_0XX0(PC_DARK_RED), MKCOLOUR_F00F), // TileType::Object
404 AndOr(MKCOLOUR_0XX0(PC_BLACK), MKCOLOUR_F00F),
405};
406
409 2, // TileType::Clear
410 8, // TileType::Railway
411 7, // TileType::Road
412 5, // TileType::House
413 2, // TileType::Trees
414 9, // TileType::Station
415 2, // TileType::Water
416 1, // TileType::Void
417 6, // TileType::Industry
418 8, // TileType::TunnelBridge
419 2, // TileType::Object
420 0,
421};
422
423
435
448
461
469static inline uint32_t GetSmallMapRoutesPixels(TileIndex tile, TileType t)
470{
471 switch (t) {
473 switch (GetStationType(tile)) {
474 case StationType::Rail: return MKCOLOUR_XXXX(PC_VERY_DARK_BROWN);
475 case StationType::Airport: return MKCOLOUR_XXXX(PC_RED);
476 case StationType::Truck: return MKCOLOUR_XXXX(PC_ORANGE);
477 case StationType::Bus: return MKCOLOUR_XXXX(PC_YELLOW);
478 case StationType::Dock: return MKCOLOUR_XXXX(PC_LIGHT_BLUE);
479 default: return MKCOLOUR_FFFF;
480 }
481
482 case TileType::Railway: {
483 AndOr andor = {
484 MKCOLOUR_0XX0(GetRailTypeInfo(GetRailType(tile))->map_colour),
486 };
487
489 return ApplyMask(cs->default_colour, &andor);
490 }
491
492 case TileType::Road: {
493 const RoadTypeInfo *rti = nullptr;
494 if (GetRoadTypeRoad(tile) != INVALID_ROADTYPE) {
495 rti = GetRoadTypeInfo(GetRoadTypeRoad(tile));
496 } else {
497 rti = GetRoadTypeInfo(GetRoadTypeTram(tile));
498 }
499 if (rti != nullptr) {
500 AndOr andor = {
501 MKCOLOUR_0XX0(rti->map_colour),
503 };
504
506 return ApplyMask(cs->default_colour, &andor);
507 }
508 [[fallthrough]];
509 }
510
511 default:
512 /* Ground colour */
514 return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]);
515 }
516}
517
525static inline uint32_t GetSmallMapLinkStatsPixels(TileIndex tile, TileType t)
526{
528}
529
530static const uint32_t _vegetation_clear_bits[] = {
531 MKCOLOUR_XXXX(PC_GRASS_LAND),
532 MKCOLOUR_XXXX(PC_ROUGH_LAND),
533 MKCOLOUR_XXXX(PC_GREY),
534 MKCOLOUR_XXXX(PC_FIELDS),
535 MKCOLOUR_XXXX(PC_GRASS_LAND),
536 MKCOLOUR_XXXX(PC_ORANGE),
537 MKCOLOUR_XXXX(PC_GRASS_LAND),
538 MKCOLOUR_XXXX(PC_GRASS_LAND),
539};
540
548static inline uint32_t GetSmallMapVegetationPixels(TileIndex tile, TileType t)
549{
550 switch (t) {
551 case TileType::Clear:
552 if (IsSnowTile(tile)) return MKCOLOUR_XXXX(PC_LIGHT_BLUE);
553 if (IsClearGround(tile, CLEAR_GRASS)) {
554 if (GetClearDensity(tile) < 3) return MKCOLOUR_XXXX(PC_BARE_LAND);
555 if (GetTropicZone(tile) == TROPICZONE_RAINFOREST) return MKCOLOUR_XXXX(PC_RAINFOREST);
556 }
557 return _vegetation_clear_bits[GetClearGround(tile)];
558
560 return IsTileForestIndustry(tile) ? MKCOLOUR_XXXX(PC_GREEN) : MKCOLOUR_XXXX(PC_DARK_RED);
561
562 case TileType::Trees:
565 }
566 return (GetTropicZone(tile) == TROPICZONE_RAINFOREST) ? MKCOLOUR_XYYX(PC_RAINFOREST, PC_TREES) : MKCOLOUR_XYYX(PC_GRASS_LAND, PC_TREES);
567
568 default:
569 return ApplyMask(MKCOLOUR_XXXX(PC_GRASS_LAND), &_smallmap_vehicles_andor[t]);
570 }
571}
572
582uint32_t GetSmallMapOwnerPixels(TileIndex tile, TileType t, IncludeHeightmap include_heightmap)
583{
584 Owner o;
585
586 switch (t) {
587 case TileType::Void: return MKCOLOUR_XXXX(PC_BLACK);
588 case TileType::Industry: return MKCOLOUR_XXXX(PC_DARK_GREY);
589 case TileType::House: return MKCOLOUR_XXXX(PC_DARK_RED);
590 case TileType::Road:
591 o = GetRoadOwner(tile, HasRoadTypeRoad(tile) ? RTT_ROAD : RTT_TRAM);
592 break;
593
594 default:
595 o = GetTileOwner(tile);
596 break;
597 }
598
599 if ((o < MAX_COMPANIES && !_legend_land_owners[_company_to_list_pos[o]].show_on_map) || o == OWNER_NONE || o == OWNER_WATER) {
600 if (t == TileType::Water) return MKCOLOUR_XXXX(PC_WATER);
602 return ((include_heightmap == IncludeHeightmap::IfEnabled && _smallmap_show_heightmap) || include_heightmap == IncludeHeightmap::Always)
603 ? cs->height_colours[TileHeight(tile)] : cs->default_colour;
604 } else if (o == OWNER_TOWN) {
605 return MKCOLOUR_XXXX(PC_DARK_RED);
606 }
607
608 return MKCOLOUR_XXXX(_legend_land_owners[_company_to_list_pos[o]].colour);
609}
610
615
617enum SmallMapType : uint8_t {
618 SMT_CONTOUR,
619 SMT_VEHICLES,
620 SMT_INDUSTRY,
621 SMT_LINKSTATS,
622 SMT_ROUTES,
623 SMT_VEGETATION,
624 SMT_OWNER,
625};
627
628
629class SmallMapWindow : public Window {
630protected:
637
639 static bool show_towns;
640 static bool show_ind_names;
641 static int map_height_limit;
642
643 static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2;
644
645 uint min_number_of_columns = 0;
646 uint min_number_of_fixed_rows = 0;
647 uint column_width = 0;
648 uint legend_width = 0;
649
650 int32_t scroll_x = 0;
651 int32_t scroll_y = 0;
652 int32_t subscroll = 0;
653 int zoom = 0;
654
655 std::unique_ptr<LinkGraphOverlay> overlay{};
656
662
663 static inline Point SmallmapRemapCoords(int x, int y)
664 {
665 Point pt;
666 pt.x = (y - x) * 2;
667 pt.y = y + x;
668 return pt;
669 }
670
677 static inline void DrawVertMapIndicator(int x, int y, int y2)
678 {
679 GfxFillRect(x, y, x, y + 3, PC_VERY_LIGHT_YELLOW);
680 GfxFillRect(x, y2 - 3, x, y2, PC_VERY_LIGHT_YELLOW);
681 }
682
689 static inline void DrawHorizMapIndicator(int x, int x2, int y)
690 {
691 GfxFillRect(x, y, x + 3, y, PC_VERY_LIGHT_YELLOW);
692 GfxFillRect(x2 - 3, y, x2, y, PC_VERY_LIGHT_YELLOW);
693 }
694
699 inline uint GetMinLegendWidth() const
700 {
701 return WidgetDimensions::scaled.framerect.left + this->min_number_of_columns * this->column_width;
702 }
703
708 inline uint GetNumberColumnsLegend(uint width) const
709 {
710 return width / this->column_width;
711 }
712
718 inline uint GetLegendHeight(uint num_columns) const
719 {
721 this->GetNumberRowsLegend(num_columns) * GetCharacterHeight(FS_SMALL);
722 }
723
733
735 const IntervalTimer<TimerWindow> blink_interval = {TIMER_BLINK_INTERVAL, [this](auto) {
736 Blink();
737 }};
738
740 const IntervalTimer<TimerWindow> refresh_interval = {std::chrono::milliseconds(930), [this](auto) {
741 ForceRefresh();
742 }};
743
748 {
749 /* Rebuild colour indices if necessary. */
751
752 for (auto &heightmap_scheme : _heightmap_schemes) {
753 /* The heights go from 0 up to and including maximum. */
754 size_t heights = _settings_game.construction.map_height_limit + 1;
755 heightmap_scheme.height_colours.resize(heights);
756
757 for (size_t z = 0; z < heights; z++) {
758 size_t access_index = (heightmap_scheme.height_colours_base.size() * z) / heights;
759
760 /* Choose colour by mapping the range (0..max heightlevel) on the complete colour table. */
761 heightmap_scheme.height_colours[z] = heightmap_scheme.height_colours_base[access_index];
762 }
763 }
764
767 }
768
777 uint GetNumberRowsLegend(uint columns) const
778 {
779 /* Reserve one column for link colours */
780 uint num_rows_linkstats = CeilDiv(_smallmap_cargo_count, columns - 1);
781 uint num_rows_others = CeilDiv(std::max(_smallmap_industry_count, _smallmap_company_count), columns);
782 return std::max({this->min_number_of_fixed_rows, num_rows_linkstats, num_rows_others});
783 }
784
796 void SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item = 0)
797 {
798 if (_ctrl_pressed) {
799 /* Disable all, except the clicked one */
800 bool changes = false;
801 for (int i = begin_legend_item; i != end_legend_item; i++) {
802 bool new_state = (i == click_pos);
803 if (legend[i].show_on_map != new_state) {
804 changes = true;
805 legend[i].show_on_map = new_state;
806 }
807 }
808 if (!changes) {
809 /* Nothing changed? Then show all (again). */
810 for (int i = begin_legend_item; i != end_legend_item; i++) {
811 legend[i].show_on_map = true;
812 }
813 }
814 } else {
815 legend[click_pos].show_on_map = !legend[click_pos].show_on_map;
816 }
817
818 if (this->map_type == SMT_INDUSTRY) this->BreakIndustryChainLink();
819 }
820
826 {
827 this->RaiseWidget(WID_SM_CONTOUR + this->map_type);
828 this->map_type = map_type;
829 this->LowerWidget(WID_SM_CONTOUR + this->map_type);
830
831 this->SetupWidgetData();
832
833 if (map_type == SMT_LINKSTATS) this->overlay->SetDirty();
834 if (map_type != SMT_INDUSTRY) this->BreakIndustryChainLink();
835 this->ReInit();
836 }
837
845 void SetNewScroll(int sx, int sy, int sub)
846 {
847 const NWidgetBase *wi = this->GetWidget<NWidgetBase>(WID_SM_MAP);
848 Point hv = InverseRemapCoords(wi->current_x * ZOOM_BASE * TILE_SIZE / 2, wi->current_y * ZOOM_BASE * TILE_SIZE / 2);
849 hv.x *= this->zoom;
850 hv.y *= this->zoom;
851
852 if (sx < -hv.x) {
853 sx = -hv.x;
854 sub = 0;
855 }
856 if (sx > (int)(Map::MaxX() * TILE_SIZE) - hv.x) {
857 sx = Map::MaxX() * TILE_SIZE - hv.x;
858 sub = 0;
859 }
860 if (sy < -hv.y) {
861 sy = -hv.y;
862 sub = 0;
863 }
864 if (sy > (int)(Map::MaxY() * TILE_SIZE) - hv.y) {
865 sy = Map::MaxY() * TILE_SIZE - hv.y;
866 sub = 0;
867 }
868
869 this->scroll_x = sx;
870 this->scroll_y = sy;
871 this->subscroll = sub;
872 if (this->map_type == SMT_LINKSTATS) this->overlay->SetDirty();
873 }
874
878 void DrawMapIndicators() const
879 {
880 /* Find main viewport. */
881 const Viewport &vp = *GetMainWindow()->viewport;
882
883 Point upper_left_smallmap_coord = InverseRemapCoords2(vp.virtual_left, vp.virtual_top);
884 Point lower_right_smallmap_coord = InverseRemapCoords2(vp.virtual_left + vp.virtual_width - 1, vp.virtual_top + vp.virtual_height - 1);
885
886 Point upper_left = this->RemapTile(upper_left_smallmap_coord.x / (int)TILE_SIZE, upper_left_smallmap_coord.y / (int)TILE_SIZE);
887 upper_left.x -= this->subscroll;
888
889 Point lower_right = this->RemapTile(lower_right_smallmap_coord.x / (int)TILE_SIZE, lower_right_smallmap_coord.y / (int)TILE_SIZE);
890 lower_right.x -= this->subscroll;
891
892 SmallMapWindow::DrawVertMapIndicator(upper_left.x, upper_left.y, lower_right.y);
893 SmallMapWindow::DrawVertMapIndicator(lower_right.x, upper_left.y, lower_right.y);
894
895 SmallMapWindow::DrawHorizMapIndicator(upper_left.x, lower_right.x, upper_left.y);
896 SmallMapWindow::DrawHorizMapIndicator(upper_left.x, lower_right.x, lower_right.y);
897 }
898
912 void DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const
913 {
914 void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height);
915 uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0;
916
917 do {
918 /* Check if the tile (xc,yc) is within the map range */
919 if (xc >= Map::MaxX() || yc >= Map::MaxY()) continue;
920
921 /* Check if the dst pointer points to a pixel inside the screen buffer */
922 if (dst < _screen.dst_ptr) continue;
923 if (dst >= dst_ptr_abs_end) continue;
924
925 /* Construct tilearea covered by (xc, yc, xc + this->zoom, yc + this->zoom) such that it is within min_xy limits. */
926 TileArea ta;
927 if (min_xy == 1 && (xc == 0 || yc == 0)) {
928 if (this->zoom == 1) continue; // The tile area is empty, don't draw anything.
929
930 ta = TileArea(TileXY(std::max(min_xy, xc), std::max(min_xy, yc)), this->zoom - (xc == 0), this->zoom - (yc == 0));
931 } else {
932 ta = TileArea(TileXY(xc, yc), this->zoom, this->zoom);
933 }
934 ta.ClampToMap(); // Clamp to map boundaries (may contain TileType::Void tiles!).
935
936 uint32_t val = this->GetTileColours(ta);
937 uint8_t *val8 = (uint8_t *)&val;
938 int idx = std::max(0, -start_pos);
939 for (int pos = std::max(0, start_pos); pos < end_pos; pos++) {
940 blitter->SetPixel(dst, idx, 0, PixelColour{val8[idx]});
941 idx++;
942 }
943 /* Switch to next tile in the column */
944 } while (xc += this->zoom, yc += this->zoom, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0);
945 }
946
952 void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const
953 {
954 for (const Vehicle *v : Vehicle::Iterate()) {
955 if (v->type == VEH_EFFECT) continue;
956 if (v->vehstatus.Any({VehState::Hidden, VehState::Unclickable})) continue;
957
958 /* Remap into flat coordinates. */
959 Point pt = this->RemapTile(v->x_pos / (int)TILE_SIZE, v->y_pos / (int)TILE_SIZE);
960
961 int y = pt.y - dpi->top;
962 if (!IsInsideMM(y, 0, dpi->height)) continue; // y is out of bounds.
963
964 bool skip = false; // Default is to draw both pixels.
965 int x = pt.x - this->subscroll - 3 - dpi->left; // Offset X coordinate.
966 if (x < 0) {
967 /* if x+1 is 0, that means we're on the very left edge,
968 * and should thus only draw a single pixel */
969 if (++x != 0) continue;
970 skip = true;
971 } else if (x >= dpi->width - 1) {
972 /* Check if we're at the very right edge, and if so draw only a single pixel */
973 if (x != dpi->width - 1) continue;
974 skip = true;
975 }
976
977 /* Calculate pointer to pixel and the colour */
978 PixelColour colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : PC_WHITE;
979
980 /* And draw either one or two pixels depending on clipping */
981 blitter->SetPixel(dpi->dst_ptr, x, y, colour);
982 if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour);
983 }
984 }
985
990 void DrawTowns(const DrawPixelInfo *dpi, const int vertical_padding) const
991 {
992 for (const Town *t : Town::Iterate()) {
993 /* Remap the town coordinate */
994 Point pt = this->RemapTile(TileX(t->xy), TileY(t->xy));
995 int x = pt.x - this->subscroll - (t->cache.sign.width_small >> 1);
996 int y = pt.y + vertical_padding;
997
998 /* Check if the town sign is within bounds */
999 if (x + t->cache.sign.width_small > dpi->left &&
1000 x < dpi->left + dpi->width &&
1001 y + GetCharacterHeight(FS_SMALL) > dpi->top &&
1002 y < dpi->top + dpi->height) {
1003 /* And draw it. */
1004 DrawString(x, x + t->cache.sign.width_small, y, GetString(STR_SMALLMAP_TOWN, t->index));
1005 }
1006 }
1007 }
1008
1013 void DrawIndustryNames(const DrawPixelInfo *dpi, const int vertical_padding) const
1014 {
1015 if (this->map_type != SMT_INDUSTRY) return;
1016
1017 for (const Industry *i : Industry::Iterate()) {
1019 if (!tbl.show_on_map) continue;
1020
1021 /* Industry names blink together with their blobs in the smallmap. */
1022 const bool is_blinking = i->type == _smallmap_industry_highlight && !_smallmap_industry_highlight_state;
1023 if (is_blinking) continue;
1024
1025 if (_industry_to_name_string_width[i->type] == 0) {
1027 }
1028 const uint16_t &legend_text_width = _industry_to_name_string_width[i->type];
1029
1030 /* Remap the industry coordinate */
1031 const TileIndex &tile = i->location.GetCenterTile();
1032 const Point pt = this->RemapTile(TileX(tile), TileY(tile));
1033 const int x = pt.x - this->subscroll - (legend_text_width / 2);
1034 const int y = pt.y + vertical_padding;
1035
1036 /* Check if the industry name is within bounds */
1037 if (x + legend_text_width > dpi->left &&
1038 x < dpi->left + dpi->width &&
1039 y + GetCharacterHeight(FS_SMALL) > dpi->top &&
1040 y < dpi->top + dpi->height) {
1041
1042 /* And draw it. */
1043 DrawString(x, x + legend_text_width, y, tbl.legend, TC_WHITE, SA_LEFT, false, FS_SMALL);
1044 }
1045 }
1046 }
1047
1060 {
1062 AutoRestoreBackup dpi_backup(_cur_dpi, dpi);
1063
1064 /* If freeform edges are off, draw infinite water off the edges of the map. */
1066 GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, map_clear_color);
1067
1068 /* Which tile is displayed at (dpi->left, dpi->top)? */
1069 int dx;
1070 Point tile = this->PixelToTile(dpi->left, dpi->top, &dx);
1071 int tile_x = this->scroll_x / (int)TILE_SIZE + tile.x;
1072 int tile_y = this->scroll_y / (int)TILE_SIZE + tile.y;
1073
1074 void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0);
1075 int x = - dx - 4;
1076 int y = 0;
1077
1078 for (;;) {
1079 /* Distance from left edge */
1080 if (x >= -3) {
1081 if (x >= dpi->width) break; // Exit the loop.
1082
1083 int end_pos = std::min(dpi->width, x + 4);
1084 int reps = (dpi->height - y + 1) / 2; // Number of lines.
1085 if (reps > 0) {
1086 this->DrawSmallMapColumn(ptr, tile_x, tile_y, dpi->pitch * 2, reps, x, end_pos, blitter);
1087 }
1088 }
1089
1090 if (y == 0) {
1091 tile_y += this->zoom;
1092 y++;
1093 ptr = blitter->MoveTo(ptr, 0, 1);
1094 } else {
1095 tile_x -= this->zoom;
1096 y--;
1097 ptr = blitter->MoveTo(ptr, 0, -1);
1098 }
1099 ptr = blitter->MoveTo(ptr, 2, 0);
1100 x += 2;
1101 }
1102
1103 /* Draw vehicles */
1104 if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter);
1105
1106 /* Draw link stat overlay */
1107 if (this->map_type == SMT_LINKSTATS) this->overlay->Draw(dpi);
1108
1109 const int map_labels_vertical_padding = ScaleGUITrad(2);
1110
1111 /* Draw town names */
1112 if (this->show_towns) this->DrawTowns(dpi, map_labels_vertical_padding);
1113
1114 /* Draw industry names */
1115 if (this->show_ind_names) this->DrawIndustryNames(dpi, map_labels_vertical_padding);
1116
1117 /* Draw map indicators */
1118 this->DrawMapIndicators();
1119 }
1120
1127 Point RemapTile(int tile_x, int tile_y) const
1128 {
1129 int x_offset = tile_x - this->scroll_x / (int)TILE_SIZE;
1130 int y_offset = tile_y - this->scroll_y / (int)TILE_SIZE;
1131
1132 if (this->zoom == 1) return SmallmapRemapCoords(x_offset, y_offset);
1133
1134 /* For negative offsets, round towards -inf. */
1135 if (x_offset < 0) x_offset -= this->zoom - 1;
1136 if (y_offset < 0) y_offset -= this->zoom - 1;
1137
1138 return SmallmapRemapCoords(x_offset / this->zoom, y_offset / this->zoom);
1139 }
1140
1151 Point PixelToTile(int px, int py, int *sub, bool add_sub = true) const
1152 {
1153 if (add_sub) px += this->subscroll; // Total horizontal offset.
1154
1155 /* For each two rows down, add a x and a y tile, and
1156 * For each four pixels to the right, move a tile to the right. */
1157 Point pt = {((py >> 1) - (px >> 2)) * this->zoom, ((py >> 1) + (px >> 2)) * this->zoom};
1158 px &= 3;
1159
1160 if (py & 1) { // Odd number of rows, handle the 2 pixel shift.
1161 if (px < 2) {
1162 pt.x += this->zoom;
1163 px += 2;
1164 } else {
1165 pt.y += this->zoom;
1166 px -= 2;
1167 }
1168 }
1169
1170 *sub = px;
1171 return pt;
1172 }
1173
1183 Point ComputeScroll(int tx, int ty, int x, int y, int *sub) const
1184 {
1185 assert(x >= 0 && y >= 0);
1186
1187 int new_sub;
1188 Point tile_xy = PixelToTile(x, y, &new_sub, false);
1189 tx -= tile_xy.x;
1190 ty -= tile_xy.y;
1191
1192 Point scroll;
1193 if (new_sub == 0) {
1194 *sub = 0;
1195 scroll.x = (tx + this->zoom) * TILE_SIZE;
1196 scroll.y = (ty - this->zoom) * TILE_SIZE;
1197 } else {
1198 *sub = 4 - new_sub;
1199 scroll.x = (tx + 2 * this->zoom) * TILE_SIZE;
1200 scroll.y = (ty - 2 * this->zoom) * TILE_SIZE;
1201 }
1202 return scroll;
1203 }
1204
1211 void SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt)
1212 {
1213 static const int zoomlevels[] = {1, 2, 4, 6, 8}; // Available zoom levels. Bigger number means more zoom-out (further away).
1214 static const int MIN_ZOOM_INDEX = 0;
1215 static const int MAX_ZOOM_INDEX = lengthof(zoomlevels) - 1;
1216
1217 int new_index, cur_index, sub;
1218 Point tile;
1219 switch (change) {
1220 case ZLC_INITIALIZE:
1221 cur_index = - 1; // Definitely different from new_index.
1222 new_index = MIN_ZOOM_INDEX;
1223 tile.x = tile.y = 0;
1224 break;
1225
1226 case ZLC_ZOOM_IN:
1227 case ZLC_ZOOM_OUT:
1228 for (cur_index = MIN_ZOOM_INDEX; cur_index <= MAX_ZOOM_INDEX; cur_index++) {
1229 if (this->zoom == zoomlevels[cur_index]) break;
1230 }
1231 assert(cur_index <= MAX_ZOOM_INDEX);
1232
1233 tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub);
1234 new_index = Clamp(cur_index + ((change == ZLC_ZOOM_IN) ? -1 : 1), MIN_ZOOM_INDEX, MAX_ZOOM_INDEX);
1235 break;
1236
1237 default: NOT_REACHED();
1238 }
1239
1240 if (new_index != cur_index) {
1241 this->zoom = zoomlevels[new_index];
1242 if (cur_index >= 0) {
1243 Point new_tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub);
1244 this->SetNewScroll(this->scroll_x + (tile.x - new_tile.x) * TILE_SIZE,
1245 this->scroll_y + (tile.y - new_tile.y) * TILE_SIZE, sub);
1246 } else if (this->map_type == SMT_LINKSTATS) {
1247 this->overlay->SetDirty();
1248 }
1249 this->SetWidgetDisabledState(WID_SM_ZOOM_IN, this->zoom == zoomlevels[MIN_ZOOM_INDEX]);
1250 this->SetWidgetDisabledState(WID_SM_ZOOM_OUT, this->zoom == zoomlevels[MAX_ZOOM_INDEX]);
1251 this->SetDirty();
1252 }
1253 }
1254
1259 {
1260 CargoTypes cargo_mask = 0;
1261 for (int i = 0; i != _smallmap_cargo_count; ++i) {
1262 if (_legend_linkstats[i].show_on_map) SetBit(cargo_mask, _legend_linkstats[i].type);
1263 }
1264 this->overlay->SetCargoMask(cargo_mask);
1265 }
1266
1271 {
1272 StringID legend_tooltip;
1273 StringID enable_all_tooltip;
1274 StringID disable_all_tooltip;
1275 int industry_names_select_plane;
1276 int select_buttons_plane;
1277 switch (this->map_type) {
1278 case SMT_INDUSTRY:
1279 legend_tooltip = STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION;
1280 enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES;
1281 disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES;
1282 industry_names_select_plane = 0;
1283 select_buttons_plane = 0;
1284 break;
1285
1286 case SMT_OWNER:
1287 legend_tooltip = STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION;
1288 enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES;
1289 disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES;
1290 industry_names_select_plane = SZSP_NONE;
1291 select_buttons_plane = 0;
1292 break;
1293
1294 case SMT_LINKSTATS:
1295 legend_tooltip = STR_SMALLMAP_TOOLTIP_CARGO_SELECTION;
1296 enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS;
1297 disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS;
1298 industry_names_select_plane = SZSP_NONE;
1299 select_buttons_plane = 0;
1300 break;
1301
1302 default:
1303 legend_tooltip = STR_NULL;
1304 enable_all_tooltip = STR_NULL;
1305 disable_all_tooltip = STR_NULL;
1306 industry_names_select_plane = SZSP_NONE;
1307 select_buttons_plane = 1;
1308 break;
1309 }
1310
1311 this->GetWidget<NWidgetCore>(WID_SM_LEGEND)->SetToolTip(legend_tooltip);
1312 this->GetWidget<NWidgetCore>(WID_SM_ENABLE_ALL)->SetStringTip(STR_SMALLMAP_ENABLE_ALL, enable_all_tooltip);
1313 this->GetWidget<NWidgetCore>(WID_SM_DISABLE_ALL)->SetStringTip(STR_SMALLMAP_DISABLE_ALL, disable_all_tooltip);
1314 this->GetWidget<NWidgetStacked>(WID_SM_SHOW_IND_NAMES_SEL)->SetDisplayedPlane(industry_names_select_plane);
1315 this->GetWidget<NWidgetStacked>(WID_SM_SELECT_BUTTONS)->SetDisplayedPlane(select_buttons_plane);
1316 }
1317
1323 uint32_t GetTileColours(const TileArea &ta) const
1324 {
1325 int importance = 0;
1326 TileIndex tile = INVALID_TILE; // Position of the most important tile.
1327 TileType et = TileType::Void; // Effective tile type at that position.
1328
1329 for (TileIndex ti : ta) {
1330 TileType ttype = GetTileType(ti);
1331
1332 switch (ttype) {
1335
1336 switch (tt) {
1337 case TRANSPORT_RAIL: ttype = TileType::Railway; break;
1338 case TRANSPORT_ROAD: ttype = TileType::Road; break;
1339 default: ttype = TileType::Water; break;
1340 }
1341 break;
1342 }
1343
1344 case TileType::Industry:
1345 /* Special handling of industries while in "Industries" smallmap view. */
1346 if (this->map_type == SMT_INDUSTRY) {
1347 /* If industry is allowed to be seen, use its colour on the map.
1348 * This has the highest priority above any value in _tiletype_importance. */
1349 IndustryType type = Industry::GetByTile(ti)->type;
1350 if (_legend_from_industries[_industry_to_list_pos[type]].show_on_map) {
1351 if (type == _smallmap_industry_highlight) {
1352 if (_smallmap_industry_highlight_state) return MKCOLOUR_XXXX(PC_WHITE);
1353 } else {
1354 return GetIndustrySpec(type)->map_colour.p * 0x01010101;
1355 }
1356 }
1357 /* Otherwise make it disappear */
1359 }
1360 break;
1361
1362 default:
1363 break;
1364 }
1365
1366 if (_tiletype_importance[ttype] > importance) {
1367 importance = _tiletype_importance[ttype];
1368 tile = ti;
1369 et = ttype;
1370 }
1371 }
1372
1373 switch (this->map_type) {
1374 case SMT_CONTOUR:
1375 return GetSmallMapContoursPixels(tile, et);
1376
1377 case SMT_VEHICLES:
1378 return GetSmallMapVehiclesPixels(tile, et);
1379
1380 case SMT_INDUSTRY:
1381 return GetSmallMapIndustriesPixels(tile, et);
1382
1383 case SMT_LINKSTATS:
1384 return GetSmallMapLinkStatsPixels(tile, et);
1385
1386 case SMT_ROUTES:
1387 return GetSmallMapRoutesPixels(tile, et);
1388
1389 case SMT_VEGETATION:
1390 return GetSmallMapVegetationPixels(tile, et);
1391
1392 case SMT_OWNER:
1394
1395 default: NOT_REACHED();
1396 }
1397 }
1398
1405 {
1406 const NWidgetBase *wi = this->GetWidget<NWidgetBase>(WID_SM_LEGEND);
1407 uint line = (pt.y - wi->pos_y - WidgetDimensions::scaled.framerect.top) / GetCharacterHeight(FS_SMALL);
1408 uint columns = this->GetNumberColumnsLegend(wi->current_x);
1409 uint number_of_rows = this->GetNumberRowsLegend(columns);
1410 if (line >= number_of_rows) return -1;
1411
1412 bool rtl = _current_text_dir == TD_RTL;
1413 int x = pt.x - wi->pos_x;
1414 if (rtl) x = wi->current_x - x;
1415 uint column = (x - WidgetDimensions::scaled.framerect.left) / this->column_width;
1416
1417 return (column * number_of_rows) + line;
1418 }
1419
1422 {
1423 if (this->map_type == SMT_LINKSTATS) {
1424 CompanyMask company_mask = this->GetOverlayCompanyMask();
1425 if (this->overlay->GetCompanyMask() != company_mask) {
1426 this->overlay->SetCompanyMask(company_mask);
1427 } else {
1428 this->overlay->SetDirty();
1429 }
1430 }
1431 }
1432
1434 void Blink()
1435 {
1436 if (_smallmap_industry_highlight == IT_INVALID) return;
1437
1439
1440 this->UpdateLinks();
1441 this->SetDirty();
1442 }
1443
1446 {
1447 if (_smallmap_industry_highlight != IT_INVALID) return;
1448
1449 this->UpdateLinks();
1450 this->SetDirty();
1451 }
1452
1453public:
1454 friend class NWidgetSmallmapDisplay;
1455
1456 SmallMapWindow(WindowDesc &desc, int window_number) : Window(desc)
1457 {
1458 _smallmap_industry_highlight = IT_INVALID;
1459 this->overlay = std::make_unique<LinkGraphOverlay>(this, WID_SM_MAP, 0, this->GetOverlayCompanyMask(), 1);
1460 this->CreateNestedTree();
1461 this->LowerWidget(WID_SM_CONTOUR + this->map_type);
1462
1463 this->RebuildColourIndexIfNecessary();
1464
1465 this->SetWidgetLoweredState(WID_SM_SHOW_HEIGHT, _smallmap_show_heightmap);
1466
1467 this->SetWidgetLoweredState(WID_SM_TOGGLETOWNNAME, this->show_towns);
1468 this->SetWidgetLoweredState(WID_SM_SHOW_IND_NAMES, this->show_ind_names);
1469
1470 this->SetupWidgetData();
1471 this->FinishInitNested(window_number);
1472
1473 this->SetZoomLevel(ZLC_INITIALIZE, nullptr);
1474 this->SmallMapCenterOnCurrentPos();
1475 this->SetOverlayCargoMask();
1476 }
1477
1482 {
1483 const Viewport &vp = *GetMainWindow()->viewport;
1484 Point viewport_center = InverseRemapCoords2(vp.virtual_left + vp.virtual_width / 2, vp.virtual_top + vp.virtual_height / 2);
1485
1486 int sub;
1487 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SM_MAP);
1488 Point sxy = this->ComputeScroll(viewport_center.x / (int)TILE_SIZE, viewport_center.y / (int)TILE_SIZE,
1489 std::max(0, (int)wid->current_x / 2 - 2), wid->current_y / 2, &sub);
1490 this->SetNewScroll(sxy.x, sxy.y, sub);
1491 this->SetDirty();
1492 }
1493
1500 {
1501 int x = CentreBounds(st->rect.left, st->rect.right, 0);
1502 int y = CentreBounds(st->rect.top, st->rect.bottom, 0);
1503 Point ret = this->RemapTile(x, y);
1504
1505 /* Same magic 3 as in DrawVehicles; that's where I got it from.
1506 * No idea what it is, but without it the result looks bad.
1507 */
1508 ret.x -= 3 + this->subscroll;
1509 return ret;
1510 }
1511
1512 void Close([[maybe_unused]] int data) override
1513 {
1514 this->BreakIndustryChainLink();
1515 this->Window::Close();
1516 }
1517
1518 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
1519 {
1520 switch (widget) {
1521 case WID_SM_CAPTION:
1522 return GetString(STR_SMALLMAP_CAPTION, STR_SMALLMAP_TYPE_CONTOURS + this->map_type);
1523
1524 default:
1525 return this->Window::GetWidgetString(widget, stringid);
1526 }
1527 }
1528
1529 void OnInit() override
1530 {
1531 uint min_width = 0;
1532 this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS;
1533 this->min_number_of_fixed_rows = lengthof(_linkstat_colours_in_legenda);
1534 for (uint i = 0; i < lengthof(_legend_table); i++) {
1535 uint height = 0;
1536 uint num_columns = 1;
1537 for (const LegendAndColour *tbl = _legend_table[i]; !tbl->end; ++tbl) {
1538 std::string str;
1539 if (i == SMT_INDUSTRY) {
1540 str = GetString(STR_SMALLMAP_INDUSTRY, tbl->legend, IndustryPool::MAX_SIZE);
1541 } else if (i == SMT_LINKSTATS) {
1542 str = GetString(STR_SMALLMAP_LINKSTATS, tbl->legend);
1543 } else if (i == SMT_OWNER) {
1544 if (tbl->company != CompanyID::Invalid()) {
1545 if (!Company::IsValidID(tbl->company)) {
1546 /* Rebuild the owner legend. */
1548 this->OnInit();
1549 return;
1550 }
1551 /* Non-fixed legend entries for the owner view. */
1552 str = GetString(STR_SMALLMAP_COMPANY, tbl->company);
1553 } else {
1554 str = GetString(tbl->legend);
1555 }
1556 } else {
1557 if (tbl->col_break) {
1558 this->min_number_of_fixed_rows = std::max(this->min_number_of_fixed_rows, height);
1559 height = 0;
1560 num_columns++;
1561 }
1562 height++;
1563 if (i == SMT_CONTOUR) {
1564 str = GetString(tbl->legend, tbl->height * TILE_HEIGHT_STEP);
1565 } else {
1566 str = GetString(tbl->legend);
1567 }
1568 }
1569 min_width = std::max(GetStringBoundingBox(str).width, min_width);
1570 }
1571 this->min_number_of_fixed_rows = std::max(this->min_number_of_fixed_rows, height);
1572 this->min_number_of_columns = std::max(this->min_number_of_columns, num_columns);
1573 }
1574
1575 /* Width of the legend blob. */
1576 this->legend_width = GetCharacterHeight(FS_SMALL) * 9 / 6;
1577
1578 /* The width of a column is the minimum width of all texts + the size of the blob + some spacing */
1579 this->column_width = min_width + WidgetDimensions::scaled.hsep_normal + this->legend_width + WidgetDimensions::scaled.framerect.Horizontal();
1580
1581 /* Cached string widths of industry names in the smallmap. Calculation is deferred to DrawIndustryNames(). */
1582 std::fill(std::begin(_industry_to_name_string_width), std::end(_industry_to_name_string_width), 0);
1583 }
1584
1585 void OnPaint() override
1586 {
1587 if (this->map_type == SMT_OWNER) {
1588 for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) {
1589 if (tbl->company != CompanyID::Invalid() && !Company::IsValidID(tbl->company)) {
1590 /* Rebuild the owner legend. */
1592 this->InvalidateData(1);
1593 break;
1594 }
1595 }
1596 }
1597
1598 this->DrawWidgets();
1599 }
1600
1601 void DrawWidget(const Rect &r, WidgetID widget) const override
1602 {
1603 switch (widget) {
1604 case WID_SM_MAP: {
1605 Rect ir = r.Shrink(WidgetDimensions::scaled.bevel);
1606 DrawPixelInfo new_dpi;
1607 if (!FillDrawPixelInfo(&new_dpi, ir)) return;
1608 this->DrawSmallMap(&new_dpi);
1609 break;
1610 }
1611
1612 case WID_SM_LEGEND: {
1613 uint columns = this->GetNumberColumnsLegend(r.Width());
1614 uint number_of_rows = this->GetNumberRowsLegend(columns);
1615 bool rtl = _current_text_dir == TD_RTL;
1616 uint i = 0; // Row counter for industry legend.
1617 uint row_height = GetCharacterHeight(FS_SMALL);
1618 int padding = ScaleGUITrad(1);
1619
1620 Rect origin = r.WithWidth(this->column_width, rtl).Shrink(WidgetDimensions::scaled.framerect).WithHeight(row_height);
1621 Rect text = origin.Indent(this->legend_width + WidgetDimensions::scaled.hsep_normal, rtl);
1622 Rect icon = origin.WithWidth(this->legend_width, rtl).Shrink(0, padding, 0, 0);
1623
1624 StringID string = STR_NULL;
1625 switch (this->map_type) {
1626 case SMT_INDUSTRY:
1627 string = STR_SMALLMAP_INDUSTRY;
1628 break;
1629 case SMT_LINKSTATS:
1630 string = STR_SMALLMAP_LINKSTATS;
1631 break;
1632 case SMT_OWNER:
1633 string = STR_SMALLMAP_COMPANY;
1634 break;
1635 default:
1636 break;
1637 }
1638
1639 for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) {
1640 if (tbl->col_break || ((this->map_type == SMT_INDUSTRY || this->map_type == SMT_OWNER || this->map_type == SMT_LINKSTATS) && i++ >= number_of_rows)) {
1641 /* Column break needed, continue at top, COLUMN_WIDTH pixels
1642 * (one "row") to the right. */
1643 int x = rtl ? -(int)this->column_width : this->column_width;
1644 int y = origin.top - text.top;
1645 text = text.Translate(x, y);
1646 icon = icon.Translate(x, y);
1647 i = 1;
1648 }
1649
1650 PixelColour legend_colour = tbl->colour;
1651
1652 std::array<StringParameter, 2> params{};
1653 switch (this->map_type) {
1654 case SMT_INDUSTRY:
1655 /* Industry name must be formatted, since it's not in tiny font in the specs.
1656 * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font */
1657 params[0] = tbl->legend;
1658 params[1] = Industry::GetIndustryTypeCount(tbl->type);
1659 if (tbl->show_on_map && tbl->type == _smallmap_industry_highlight) {
1661 }
1662 [[fallthrough]];
1663
1664 case SMT_LINKSTATS:
1665 params[0] = tbl->legend;
1666 [[fallthrough]];
1667
1668 case SMT_OWNER:
1669 if (this->map_type != SMT_OWNER || tbl->company != CompanyID::Invalid()) {
1670 if (this->map_type == SMT_OWNER) params[0] = tbl->company;
1671 if (!tbl->show_on_map) {
1672 /* Simply draw the string, not the black border of the legend colour.
1673 * This will enforce the idea of the disabled item */
1674 DrawString(text, GetStringWithArgs(string, params), TC_GREY);
1675 } else {
1676 DrawString(text, GetStringWithArgs(string, params), TC_BLACK);
1677 GfxFillRect(icon, PC_BLACK); // Outer border of the legend colour
1678 }
1679 break;
1680 }
1681 [[fallthrough]];
1682
1683 default:
1684 /* Anything that is not an industry or a company is using normal process */
1685 GfxFillRect(icon, PC_BLACK);
1686 if (this->map_type == SMT_CONTOUR) {
1687 DrawString(text, GetString(tbl->legend, tbl->height * TILE_HEIGHT_STEP));
1688 } else {
1689 DrawString(text, tbl->legend);
1690 }
1691 break;
1692 }
1693 GfxFillRect(icon.Shrink(WidgetDimensions::scaled.bevel), legend_colour); // Legend colour
1694
1695 text = text.Translate(0, row_height);
1696 icon = icon.Translate(0, row_height);
1697 }
1698 }
1699 }
1700 }
1701
1702 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1703 {
1704 switch (widget) {
1705 case WID_SM_MAP: { // Map window
1706 if (click_count > 0) this->mouse_capture_widget = widget;
1707
1708 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SM_MAP);
1709 Window *w = GetMainWindow();
1710 int sub;
1711 pt = this->PixelToTile(pt.x - wid->pos_x, pt.y - wid->pos_y, &sub);
1712 ScrollWindowTo(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, -1, w);
1713
1714 this->SetDirty();
1715 break;
1716 }
1717
1718 case WID_SM_ZOOM_IN:
1719 case WID_SM_ZOOM_OUT: {
1720 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SM_MAP);
1721 Point zoom_pt = { (int)wid->current_x / 2, (int)wid->current_y / 2};
1722 this->SetZoomLevel((widget == WID_SM_ZOOM_IN) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &zoom_pt);
1723 SndClickBeep();
1724 break;
1725 }
1726
1727 case WID_SM_CONTOUR: // Show land contours
1728 case WID_SM_VEHICLES: // Show vehicles
1729 case WID_SM_INDUSTRIES: // Show industries
1730 case WID_SM_LINKSTATS: // Show route map
1731 case WID_SM_ROUTES: // Show transport routes
1732 case WID_SM_VEGETATION: // Show vegetation
1733 case WID_SM_OWNERS: // Show land owners
1734 this->SwitchMapType((SmallMapType)(widget - WID_SM_CONTOUR));
1735 SndClickBeep();
1736 break;
1737
1738 case WID_SM_CENTERMAP: // Center the smallmap again
1739 this->SmallMapCenterOnCurrentPos();
1740 this->HandleButtonClick(WID_SM_CENTERMAP);
1741 break;
1742
1743 case WID_SM_TOGGLETOWNNAME: // Toggle town names
1744 this->show_towns = !this->show_towns;
1745 this->SetWidgetLoweredState(WID_SM_TOGGLETOWNNAME, this->show_towns);
1746
1747 this->SetDirty();
1748 SndClickBeep();
1749 break;
1750
1751 case WID_SM_SHOW_IND_NAMES: // Toggle industry names
1752 this->show_ind_names = !this->show_ind_names;
1753 this->SetWidgetLoweredState(WID_SM_SHOW_IND_NAMES, this->show_ind_names);
1754
1755 this->SetDirty();
1756 SndClickBeep();
1757 break;
1758
1759 case WID_SM_LEGEND: // Legend
1760 if (this->map_type == SMT_INDUSTRY || this->map_type == SMT_LINKSTATS || this->map_type == SMT_OWNER) {
1761 int click_pos = this->GetPositionOnLegend(pt);
1762 if (click_pos < 0) break;
1763
1764 /* If industry type small map*/
1765 if (this->map_type == SMT_INDUSTRY) {
1766 /* If click on industries label, find right industry type and enable/disable it. */
1767 if (click_pos < _smallmap_industry_count) {
1768 this->SelectLegendItem(click_pos, _legend_from_industries, _smallmap_industry_count);
1769 }
1770 } else if (this->map_type == SMT_LINKSTATS) {
1771 if (click_pos < _smallmap_cargo_count) {
1772 this->SelectLegendItem(click_pos, _legend_linkstats, _smallmap_cargo_count);
1773 this->SetOverlayCargoMask();
1774 }
1775 } else if (this->map_type == SMT_OWNER) {
1776 if (click_pos < _smallmap_company_count) {
1777 this->SelectLegendItem(click_pos, _legend_land_owners, _smallmap_company_count, NUM_NO_COMPANY_ENTRIES);
1778 }
1779 }
1780 this->SetDirty();
1781 }
1782 break;
1783
1784 case WID_SM_ENABLE_ALL:
1785 case WID_SM_DISABLE_ALL: {
1786 LegendAndColour *tbl = nullptr;
1787 switch (this->map_type) {
1788 case SMT_INDUSTRY:
1790 this->BreakIndustryChainLink();
1791 break;
1792 case SMT_OWNER:
1793 tbl = &(_legend_land_owners[NUM_NO_COMPANY_ENTRIES]);
1794 break;
1795 case SMT_LINKSTATS:
1796 tbl = _legend_linkstats;
1797 break;
1798 default:
1799 NOT_REACHED();
1800 }
1801 for (;!tbl->end && tbl->legend != STR_LINKGRAPH_LEGEND_UNUSED; ++tbl) {
1802 tbl->show_on_map = (widget == WID_SM_ENABLE_ALL);
1803 }
1804 if (this->map_type == SMT_LINKSTATS) this->SetOverlayCargoMask();
1805 this->SetDirty();
1806 break;
1807 }
1808
1809 case WID_SM_SHOW_HEIGHT: // Enable/disable showing of heightmap.
1810 _smallmap_show_heightmap = !_smallmap_show_heightmap;
1811 this->SetWidgetLoweredState(WID_SM_SHOW_HEIGHT, _smallmap_show_heightmap);
1812 this->SetDirty();
1813 break;
1814 }
1815 }
1816
1825 void OnInvalidateData(int data = 0, bool gui_scope = true) override
1826 {
1827 if (!gui_scope) return;
1828
1829 switch (data) {
1830 case 1:
1831 /* The owner legend has already been rebuilt. */
1832 this->ReInit();
1833 break;
1834
1835 case 0: {
1836 extern std::bitset<NUM_INDUSTRYTYPES> _displayed_industries;
1837 if (this->map_type != SMT_INDUSTRY) this->SwitchMapType(SMT_INDUSTRY);
1838
1839 for (int i = 0; i != _smallmap_industry_count; i++) {
1841 }
1842 break;
1843 }
1844
1845 case 2:
1846 this->RebuildColourIndexIfNecessary();
1847 break;
1848
1849 default: NOT_REACHED();
1850 }
1851 this->SetDirty();
1852 }
1853
1854 bool OnRightClick(Point, WidgetID widget) override
1855 {
1856 if (widget != WID_SM_MAP || _scrolling_viewport) return false;
1857
1858 _scrolling_viewport = true;
1859 return true;
1860 }
1861
1862 void OnMouseWheel(int wheel, WidgetID widget) override
1863 {
1864 if (widget != WID_SM_MAP) return;
1866 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SM_MAP);
1867 int cursor_x = _cursor.pos.x - this->left - wid->pos_x;
1868 int cursor_y = _cursor.pos.y - this->top - wid->pos_y;
1869 Point pt = {cursor_x, cursor_y};
1870 this->SetZoomLevel((wheel < 0) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt);
1871 }
1872 }
1873
1874 void OnScroll(Point delta) override
1875 {
1877
1878 /* While tile is at (delta.x, delta.y)? */
1879 int sub;
1880 Point pt = this->PixelToTile(delta.x, delta.y, &sub);
1881 this->SetNewScroll(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, sub);
1882
1883 this->SetDirty();
1884 }
1885
1886 void OnMouseOver([[maybe_unused]] Point pt, WidgetID widget) override
1887 {
1888 IndustryType new_highlight = IT_INVALID;
1889 if (widget == WID_SM_LEGEND && this->map_type == SMT_INDUSTRY) {
1890 int industry_pos = GetPositionOnLegend(pt);
1891 if (industry_pos >= 0 && industry_pos < _smallmap_industry_count) {
1892 new_highlight = _legend_from_industries[industry_pos].type;
1893 }
1894 }
1895 if (new_highlight != _smallmap_industry_highlight) {
1896 _smallmap_industry_highlight = new_highlight;
1898 this->SetDirty();
1899 }
1900 }
1901
1902};
1903
1905bool SmallMapWindow::show_towns = true;
1908
1919public:
1921
1922 void SetupSmallestSize(Window *w) override
1923 {
1924 assert(this->children.size() == 2);
1925 NWidgetBase *display = this->children.front().get();
1926 NWidgetBase *bar = this->children.back().get();
1927
1928 display->SetupSmallestSize(w);
1929 bar->SetupSmallestSize(w);
1930
1931 this->smallmap_window = dynamic_cast<SmallMapWindow *>(w);
1932 assert(this->smallmap_window != nullptr);
1933 this->smallest_x = std::max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth());
1935 this->fill_x = std::max(display->fill_x, bar->fill_x);
1936 this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : std::min(display->fill_y, bar->fill_y);
1937 this->resize_x = std::max(display->resize_x, bar->resize_x);
1938 this->resize_y = std::min(display->resize_y, bar->resize_y);
1939 this->ApplyAspectRatio();
1940 }
1941
1942 void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
1943 {
1944 this->pos_x = x;
1945 this->pos_y = y;
1946 this->current_x = given_width;
1947 this->current_y = given_height;
1948
1949 assert(this->children.size() == 2);
1950 NWidgetBase *display = this->children.front().get();
1951 NWidgetBase *bar = this->children.back().get();
1952
1953 if (sizing == ST_SMALLEST) {
1954 this->smallest_x = given_width;
1955 this->smallest_y = given_height;
1956 /* Make display and bar exactly equal to their minimal size. */
1957 display->AssignSizePosition(ST_SMALLEST, x, y, display->smallest_x, display->smallest_y, rtl);
1958 bar->AssignSizePosition(ST_SMALLEST, x, y + display->smallest_y, bar->smallest_x, bar->smallest_y, rtl);
1959 }
1960
1961 uint bar_height = std::max(bar->smallest_y, this->smallmap_window->GetLegendHeight(this->smallmap_window->GetNumberColumnsLegend(given_width - bar->smallest_x)));
1962 uint display_height = given_height - bar_height;
1963 display->AssignSizePosition(ST_RESIZE, x, y, given_width, display_height, rtl);
1964 bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl);
1965 }
1966};
1967
1969static constexpr std::initializer_list<NWidgetPart> _nested_smallmap_display = {
1970 NWidget(WWT_PANEL, COLOUR_BROWN, WID_SM_MAP_BORDER),
1971 NWidget(WWT_INSET, COLOUR_BROWN, WID_SM_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(),
1972 EndContainer(),
1973};
1974
1976static constexpr std::initializer_list<NWidgetPart> _nested_smallmap_bar = {
1977 NWidget(WWT_PANEL, COLOUR_BROWN),
1979 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SM_LEGEND), SetResize(1, 1),
1981 /* Top button row. */
1983 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_ZOOM_IN),
1984 SetSpriteTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), SetFill(1, 1),
1985 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_CENTERMAP),
1986 SetSpriteTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER_TOOLTIP), SetFill(1, 1),
1987 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_BLANK),
1988 SetSpriteTip(SPR_EMPTY), SetFill(1, 1),
1989 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_CONTOUR),
1990 SetSpriteTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP), SetFill(1, 1),
1991 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_VEHICLES),
1992 SetSpriteTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP), SetFill(1, 1),
1993 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_INDUSTRIES),
1994 SetSpriteTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP), SetFill(1, 1),
1995 EndContainer(),
1996 /* Bottom button row. */
1998 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_ZOOM_OUT),
1999 SetSpriteTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), SetFill(1, 1),
2001 SetSpriteTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF), SetFill(1, 1),
2002 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_LINKSTATS),
2003 SetSpriteTip(SPR_IMG_CARGOFLOW, STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP), SetFill(1, 1),
2004 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_ROUTES),
2005 SetSpriteTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON), SetFill(1, 1),
2006 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_VEGETATION),
2007 SetSpriteTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP), SetFill(1, 1),
2008 NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_OWNERS),
2009 SetSpriteTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP), SetFill(1, 1),
2010 EndContainer(),
2012 EndContainer(),
2013 EndContainer(),
2014 EndContainer(),
2015};
2016
2017static std::unique_ptr<NWidgetBase> SmallMapDisplay()
2018{
2019 std::unique_ptr<NWidgetBase> map_display = std::make_unique<NWidgetSmallmapDisplay>();
2020
2021 map_display = MakeNWidgets(_nested_smallmap_display, std::move(map_display));
2022 map_display = MakeNWidgets(_nested_smallmap_bar, std::move(map_display));
2023 return map_display;
2024}
2025
2026static constexpr std::initializer_list<NWidgetPart> _nested_smallmap_widgets = {
2028 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
2029 NWidget(WWT_CAPTION, COLOUR_BROWN, WID_SM_CAPTION),
2030 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
2031 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
2032 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
2033 EndContainer(),
2034 NWidgetFunction(SmallMapDisplay), // Smallmap display and legend bar + image buttons.
2035 /* Bottom button row and resize box. */
2039 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SM_ENABLE_ALL), SetStringTip(STR_SMALLMAP_ENABLE_ALL),
2040 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SM_DISABLE_ALL), SetStringTip(STR_SMALLMAP_DISABLE_ALL),
2041 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_SM_SHOW_HEIGHT), SetStringTip(STR_SMALLMAP_SHOW_HEIGHT, STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT),
2042
2043 /* 'show industry names' button and container. Only shown for the industry map type. */
2045 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_SM_SHOW_IND_NAMES), SetStringTip(STR_SMALLMAP_SHOW_INDUSTRY_NAMES, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRY_NAMES),
2046 EndContainer(),
2047
2048 NWidget(WWT_PANEL, COLOUR_BROWN), SetFill(1, 0), SetResize(1, 0),
2049 EndContainer(),
2050 EndContainer(),
2051 NWidget(WWT_PANEL, COLOUR_BROWN), SetFill(1, 0), SetResize(1, 0),
2052 EndContainer(),
2053 EndContainer(),
2054 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
2055 EndContainer(),
2056};
2057
2058static WindowDesc _smallmap_desc(
2059 WDP_AUTO, "smallmap", 484, 314,
2061 {},
2062 _nested_smallmap_widgets
2063);
2064
2069{
2070 AllocateWindowDescFront<SmallMapWindow>(_smallmap_desc, 0);
2071}
2072
2081bool ScrollMainWindowTo(int x, int y, int z, bool instant)
2082{
2083 bool res = ScrollWindowTo(x, y, z, GetMainWindow(), instant);
2084
2085 /* If a user scrolls to a tile (via what way what so ever) and already is on
2086 * that tile (e.g.: pressed twice), move the smallmap to that location,
2087 * so you directly see where you are on the smallmap. */
2088
2089 if (res) return res;
2090
2092 if (w != nullptr) w->SmallMapCenterOnCurrentPos();
2093
2094 return res;
2095}
2096
2103{
2104 return static_cast<const SmallMapWindow *>(w)->GetStationMiddle(st);
2105}
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.
A sort-of mixin that implements 'at(pos)' and 'operator[](pos)' only for a specific enum class.
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:58
@ CLEAR_GRASS
0-3
Definition clear_map.h:20
ClearGround GetClearGround(Tile t)
Get the type of clear tile.
Definition clear_map.h:46
bool IsSnowTile(Tile t)
Test if a tile is covered with snow.
Definition clear_map.h:34
uint GetClearDensity(Tile t)
Get the density of a non-field clear tile.
Definition clear_map.h:70
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.
Type (helpers) for enums.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
#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
@ Arctic
Landscape with snow levels.
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
@ MapRMBFixed
Map moves with mouse movement on holding right mouse button, cursor position is fixed.
@ ViewportRMBFixed
Viewport moves with mouse movement on holding right mouse button, cursor position is fixed.
@ Off
Scroll wheel has no effect.
#define MK(a, b)
Macro for ordinary entry of LegendAndColour.
void ShowSmallMap()
Show the smallmap window.
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 const EnumClassIndexContainer< std::array< AndOr, to_underlying(TileType::End)+1 >, TileType > _smallmap_contours_andor
Colour masks for "Contour" and "Routes" modes.
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 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.
static const EnumClassIndexContainer< std::array< uint8_t, to_underlying(TileType::End)+1 >, TileType > _tiletype_importance
Mapping of tile type to importance of the tile (higher number means more interesting to show).
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)
static const EnumClassIndexContainer< std::array< AndOr, to_underlying(TileType::End)+1 >, TileType > _smallmap_vehicles_andor
Colour masks for "Vehicles", "Industry", and "Vegetation" modes.
void BuildIndustriesLegend()
Fills an array for the industries legends.
#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
@ Dock
Ship port.
@ Rail
Railways/train station.
@ Bus
Road stop for busses.
@ Truck
Road stop for trucks.
@ Airport
Airports and heliports, excluding the ones on oil rigs.
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
ViewportScrollMode scroll_mode
viewport scroll mode
ScrollWheelScrolling 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 TileType::Void.
Definition map_func.h:308
static uint MaxX()
Gets the maximum X coordinate within the map, including TileType::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:84
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
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:48
@ TunnelBridge
Tunnel entry/exit and bridge heads.
@ Water
Water tile.
@ Station
A tile of a station or airport.
@ Industry
Part of an industry.
@ Railway
A tile with railway.
@ Void
Invisible tiles at the SW and SE border.
@ End
End marker.
@ Trees
Tile with one or more trees.
@ House
A house by a town.
@ Road
A tile with road and/or tram tracks.
@ Clear
A tile without any structures, i.e. grass, rocks, farm fields etc.
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.