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