OpenTTD Source 20250524-master-gc366e6a48e
newgrf_debug_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"
13#include "window_gui.h"
14#include "window_func.h"
16#include "spritecache.h"
17#include "string_func.h"
18#include "strings_func.h"
19#include "textbuf_gui.h"
20#include "vehicle_gui.h"
21#include "zoom_func.h"
23
24#include "engine_base.h"
25#include "industry.h"
26#include "object_base.h"
27#include "station_base.h"
28#include "town.h"
29#include "vehicle_base.h"
30#include "train.h"
31#include "roadveh.h"
32
33#include "newgrf_act5.h"
34#include "newgrf_airport.h"
35#include "newgrf_airporttiles.h"
36#include "newgrf_badge.h"
37#include "newgrf_debug.h"
38#include "newgrf_object.h"
39#include "newgrf_spritegroup.h"
40#include "newgrf_station.h"
41#include "newgrf_town.h"
42#include "newgrf_railtype.h"
43#include "newgrf_industries.h"
45
47
48#include "table/strings.h"
49
50#include "safeguards.h"
51
54
60static inline uint GetFeatureIndex(uint window_number)
61{
62 return GB(window_number, 0, 24);
63}
64
72static inline uint GetInspectWindowNumber(GrfSpecFeature feature, uint index)
73{
74 assert((index >> 24) == 0);
75 return (feature << 24) | index;
76}
77
78static inline uint GetInspectWindowNumber(GrfSpecFeature feature, ConvertibleThroughBase auto index) { return GetInspectWindowNumber(feature, index.base()); }
79
84enum NIType : uint8_t {
87};
88
89using NIReadProc = uint32_t(const void *b);
90
92struct NIProperty {
93 std::string_view name;
94 NIReadProc *read_proc;
95 uint8_t prop;
96 uint8_t type;
97};
98
99
121
124 std::string_view name;
125 uint8_t var;
126};
127
129class NIHelper {
130public:
132 virtual ~NIHelper() = default;
133
139 virtual bool IsInspectable(uint index) const = 0;
140
146 virtual uint GetParent(uint index) const = 0;
147
153 virtual const void *GetInstance(uint index) const = 0;
154
160 virtual const void *GetSpec(uint index) const = 0;
161
166 virtual std::string GetName(uint index) const = 0;
167
173 virtual uint32_t GetGRFID(uint index) const = 0;
174
180 virtual std::span<const BadgeID> GetBadges(uint index) const = 0;
181
190 virtual uint Resolve(uint index, uint var, uint param, bool &avail) const = 0;
191
196 virtual bool PSAWithParameter() const
197 {
198 return false;
199 }
200
207 virtual const std::span<int32_t> GetPSA([[maybe_unused]] uint index, [[maybe_unused]] uint32_t grfid) const
208 {
209 return {};
210 }
211};
212
213
215struct NIFeature {
216 std::span<const NIProperty> properties;
217 std::span<const NICallback> callbacks;
218 std::span<const NIVariable> variables;
219 std::unique_ptr<const NIHelper> helper;
220};
221
222/* Load all the NewGRF debug data; externalised as it is just a huge bunch of tables. */
224
230static inline GrfSpecFeature GetFeatureNum(uint window_number)
231{
232 return (GrfSpecFeature)GB(window_number, 24, 8);
233}
234
240static inline const NIFeature *GetFeature(uint window_number)
241{
242 GrfSpecFeature idx = GetFeatureNum(window_number);
243 return idx < GSF_FAKE_END ? _nifeatures[idx] : nullptr;
244}
245
252static inline const NIHelper &GetFeatureHelper(uint window_number)
253{
254 return *GetFeature(window_number)->helper;
255}
256
260 static uint32_t var60params[GSF_FAKE_END][0x20];
261
263 uint32_t caller_grfid = 0;
264
266 uint chain_index = 0;
267
270
271 Scrollbar *vscroll = nullptr;
272
278 static bool HasVariableParameter(uint variable)
279 {
280 return IsInsideBS(variable, 0x60, 0x20);
281 }
282
287 void SetCallerGRFID(uint32_t grfid)
288 {
289 this->caller_grfid = grfid;
290 this->SetDirty();
291 }
292
296 bool HasChainIndex() const
297 {
299 return f == GSF_TRAINS || f == GSF_ROADVEHICLES;
300 }
301
306 uint GetFeatureIndex() const
307 {
308 uint index = ::GetFeatureIndex(this->window_number);
309 if (this->chain_index > 0) {
310 assert(this->HasChainIndex());
311 const Vehicle *v = Vehicle::Get(index);
312 v = v->Move(this->chain_index);
313 if (v != nullptr) index = v->index.base();
314 }
315 return index;
316 }
317
322 {
323 if (this->chain_index == 0) return;
324
325 assert(this->HasChainIndex());
326
328 v = v->Move(this->chain_index);
329 if (v == nullptr) this->chain_index = 0;
330 }
331
333 {
334 this->CreateNestedTree();
335 this->vscroll = this->GetScrollbar(WID_NGRFI_SCROLLBAR);
336 this->FinishInitNested(wno);
337
338 this->vscroll->SetCount(0);
339 this->SetWidgetDisabledState(WID_NGRFI_PARENT, GetFeatureHelper(this->window_number).GetParent(this->GetFeatureIndex()) == UINT32_MAX);
340
341 this->OnInvalidateData(0, true);
342 }
343
344 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
345 {
346 if (widget != WID_NGRFI_CAPTION) return this->Window::GetWidgetString(widget, stringid);
347
349 }
350
351 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
352 {
353 switch (widget) {
354 case WID_NGRFI_VEH_CHAIN: {
355 assert(this->HasChainIndex());
357 size.height = std::max(size.height, GetVehicleImageCellSize((VehicleType)(VEH_TRAIN + (f - GSF_TRAINS)), EIT_IN_DEPOT).height + 2 + WidgetDimensions::scaled.bevel.Vertical());
358 break;
359 }
360
362 resize.height = std::max(11, GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal);
363 resize.width = 1;
364
365 size.height = 5 * resize.height + WidgetDimensions::scaled.frametext.Vertical();
366 break;
367 }
368 }
369
376 void DrawString(const Rect &r, int offset, const std::string &string) const
377 {
378 offset -= this->vscroll->GetPosition();
379 if (offset < 0 || offset >= this->vscroll->GetCapacity()) return;
380
381 ::DrawString(r.Shrink(WidgetDimensions::scaled.frametext).Shrink(0, offset * this->resize.step_height, 0, 0), string, TC_BLACK);
382 }
383
388 void DrawVehicleChainWidget(const Rect &r) const
389 {
390 const Vehicle *v = Vehicle::Get(this->GetFeatureIndex());
391 int total_width = 0;
392 int sel_start = 0;
393 int sel_end = 0;
394 for (const Vehicle *u = v->First(); u != nullptr; u = u->Next()) {
395 if (u == v) sel_start = total_width;
396 switch (u->type) {
397 case VEH_TRAIN: total_width += Train::From(u)->GetDisplayImageWidth(); break;
398 case VEH_ROAD: total_width += RoadVehicle::From(u)->GetDisplayImageWidth(); break;
399 default: NOT_REACHED();
400 }
401 if (u == v) sel_end = total_width;
402 }
403
405 int width = br.Width();
406 int skip = 0;
407 if (total_width > width) {
408 int sel_center = (sel_start + sel_end) / 2;
409 if (sel_center > width / 2) skip = std::min(total_width - width, sel_center - width / 2);
410 }
411
413 int h = GetVehicleImageCellSize((VehicleType)(VEH_TRAIN + (f - GSF_TRAINS)), EIT_IN_DEPOT).height;
414 int y = CentreBounds(br.top, br.bottom, h);
415 DrawVehicleImage(v->First(), br, VehicleID::Invalid(), EIT_IN_DETAILS, skip);
416
417 /* Highlight the articulated part (this is different to the whole-vehicle highlighting of DrawVehicleImage */
418 if (_current_text_dir == TD_RTL) {
419 DrawFrameRect(r.right - sel_end + skip, y, r.right - sel_start + skip, y + h, COLOUR_WHITE, FrameFlag::BorderOnly);
420 } else {
421 DrawFrameRect(r.left + sel_start - skip, y, r.left + sel_end - skip, y + h, COLOUR_WHITE, FrameFlag::BorderOnly);
422 }
423 }
424
425 std::string GetPropertyString(const NIProperty &nip, uint value) const
426 {
427 switch (nip.type) {
428 case NIT_INT: return GetString(STR_JUST_INT, value);
429 case NIT_CARGO: return GetString(IsValidCargoType(value) ? CargoSpec::Get(value)->name : STR_QUANTITY_N_A);
430 default: NOT_REACHED();
431 }
432 }
433
438 void DrawMainPanelWidget(const Rect &r) const
439 {
440 uint index = this->GetFeatureIndex();
441 const NIFeature *nif = GetFeature(this->window_number);
442 const NIHelper &nih = *nif->helper;
443 const void *base = nih.GetInstance(index);
444 const void *base_spec = nih.GetSpec(index);
445
446 uint i = 0;
447 if (!nif->variables.empty()) {
448 this->DrawString(r, i++, "Variables:");
449 for (const NIVariable &niv : nif->variables) {
450 bool avail = true;
451 uint param = HasVariableParameter(niv.var) ? NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][niv.var - 0x60] : 0;
452 uint value = nih.Resolve(index, niv.var, param, avail);
453
454 if (!avail) continue;
455
456 if (HasVariableParameter(niv.var)) {
457 this->DrawString(r, i++, fmt::format(" {:02x}[{:02x}]: {:08x} ({})", niv.var, param, value, niv.name));
458 } else {
459 this->DrawString(r, i++, fmt::format(" {:02x}: {:08x} ({})", niv.var, value, niv.name));
460 }
461 }
462 }
463
464 auto psa = nih.GetPSA(index, this->caller_grfid);
465 if (!psa.empty()) {
466 if (nih.PSAWithParameter()) {
467 this->DrawString(r, i++, fmt::format("Persistent storage [{:08X}]:", std::byteswap(this->caller_grfid)));
468 } else {
469 this->DrawString(r, i++, "Persistent storage:");
470 }
471 assert(psa.size() % 4 == 0);
472 for (size_t j = 0; j < psa.size(); j += 4) {
473 this->DrawString(r, i++, fmt::format(" {}: {} {} {} {}", j, psa[j], psa[j + 1], psa[j + 2], psa[j + 3]));
474 }
475 }
476
477 auto badges = nih.GetBadges(index);
478 if (!badges.empty()) {
479 this->DrawString(r, i++, "Badges:");
480 for (const BadgeID &badge_index : badges) {
481 const Badge *badge = GetBadge(badge_index);
482 this->DrawString(r, i++, fmt::format(" {}: {}", StrMakeValid(badge->label), GetString(badge->name)));
483 }
484 }
485
486 if (!nif->properties.empty()) {
487 this->DrawString(r, i++, "Properties:");
488 for (const NIProperty &nip : nif->properties) {
489 uint32_t value = nip.read_proc(base);
490 this->DrawString(r, i++, fmt::format(" {:02x}: {} ({})", nip.prop, this->GetPropertyString(nip, value), nip.name));
491 }
492 }
493
494 if (!nif->callbacks.empty()) {
495 this->DrawString(r, i++, "Callbacks:");
496 for (const NICallback &nic : nif->callbacks) {
497 if (!std::holds_alternative<std::monostate>(nic.cb_bit)) {
498 uint32_t value = nic.read_proc(base_spec);
499
500 struct visitor {
501 uint32_t value;
502
503 bool operator()(const std::monostate &) { return false; }
504 bool operator()(const VehicleCallbackMask &bit) { return static_cast<VehicleCallbackMasks>(this->value).Test(bit); }
505 bool operator()(const StationCallbackMask &bit) { return static_cast<StationCallbackMasks>(this->value).Test(bit); }
506 bool operator()(const RoadStopCallbackMask &bit) { return static_cast<RoadStopCallbackMasks>(this->value).Test(bit); }
507 bool operator()(const HouseCallbackMask &bit) { return static_cast<HouseCallbackMasks>(this->value).Test(bit); }
508 bool operator()(const CanalCallbackMask &bit) { return static_cast<CanalCallbackMasks>(this->value).Test(bit); }
509 bool operator()(const CargoCallbackMask &bit) { return static_cast<CargoCallbackMasks>(this->value).Test(bit); }
510 bool operator()(const IndustryCallbackMask &bit) { return static_cast<IndustryCallbackMasks>(this->value).Test(bit); }
511 bool operator()(const IndustryTileCallbackMask &bit) { return static_cast<IndustryTileCallbackMasks>(this->value).Test(bit); }
512 bool operator()(const ObjectCallbackMask &bit) { return static_cast<ObjectCallbackMasks>(this->value).Test(bit); }
513 bool operator()(const AirportTileCallbackMask &bit) { return static_cast<AirportTileCallbackMasks>(this->value).Test(bit); }
514 };
515
516 if (!std::visit(visitor{value}, nic.cb_bit)) continue;
517 this->DrawString(r, i++, fmt::format(" {:03x}: {}", nic.cb_id, nic.name));
518 } else {
519 this->DrawString(r, i++, fmt::format(" {:03x}: {} (unmasked)", nic.cb_id, nic.name));
520 }
521 }
522 }
523
524 /* Not nice and certainly a hack, but it beats duplicating
525 * this whole function just to count the actual number of
526 * elements. Especially because they need to be redrawn. */
527 const_cast<NewGRFInspectWindow*>(this)->vscroll->SetCount(i);
528 }
529
530 void DrawWidget(const Rect &r, WidgetID widget) const override
531 {
532 switch (widget) {
534 this->DrawVehicleChainWidget(r);
535 break;
536
538 this->DrawMainPanelWidget(r);
539 break;
540 }
541 }
542
543 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
544 {
545 switch (widget) {
546 case WID_NGRFI_PARENT: {
547 const NIHelper &nih = GetFeatureHelper(this->window_number);
548 uint index = nih.GetParent(this->GetFeatureIndex());
549 ::ShowNewGRFInspectWindow(GetFeatureNum(index), ::GetFeatureIndex(index), nih.GetGRFID(this->GetFeatureIndex()));
550 break;
551 }
552
554 if (this->chain_index > 0) {
555 this->chain_index--;
556 this->InvalidateData();
557 }
558 break;
559
561 if (this->HasChainIndex()) {
562 uint index = this->GetFeatureIndex();
563 Vehicle *v = Vehicle::Get(index);
564 if (v != nullptr && v->Next() != nullptr) {
565 this->chain_index++;
566 this->InvalidateData();
567 }
568 }
569 break;
570
571 case WID_NGRFI_MAINPANEL: {
572 /* Does this feature have variables? */
573 const NIFeature *nif = GetFeature(this->window_number);
574 if (nif->variables.empty()) return;
575
576 /* Get the line, make sure it's within the boundaries. */
577 int32_t line = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NGRFI_MAINPANEL, WidgetDimensions::scaled.frametext.top);
578 if (line == INT32_MAX) return;
579
580 /* Find the variable related to the line */
581 for (const NIVariable &niv : nif->variables) {
582 if (--line != 0) continue; // 0 because of the "Variables:" line
583
584 if (!HasVariableParameter(niv.var)) break;
585
586 this->current_edit_param = niv.var;
587 ShowQueryString({}, STR_NEWGRF_INSPECT_QUERY_CAPTION, 9, this, CS_HEXADECIMAL, {});
588 }
589 }
590 }
591 }
592
593 void OnQueryTextFinished(std::optional<std::string> str) override
594 {
595 if (!str.has_value()) return;
596
597 auto val = ParseInteger<int32_t>(*str, 10, true);
598 if (!val.has_value()) return;
599 NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][this->current_edit_param - 0x60] = *val;
600 this->SetDirty();
601 }
602
603 void OnResize() override
604 {
605 this->vscroll->SetCapacityFromWidget(this, WID_NGRFI_MAINPANEL, WidgetDimensions::scaled.frametext.Vertical());
606 }
607
613 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
614 {
615 if (!gui_scope) return;
616 if (this->HasChainIndex()) {
617 this->ValidateChainIndex();
618 this->SetWidgetDisabledState(WID_NGRFI_VEH_PREV, this->chain_index == 0);
620 this->SetWidgetDisabledState(WID_NGRFI_VEH_NEXT, v == nullptr || v->Next() == nullptr);
621 }
622 }
623};
624
625/* static */ uint32_t NewGRFInspectWindow::var60params[GSF_FAKE_END][0x20] = { {0} }; // Use spec to have 0s in whole array
626
627static constexpr NWidgetPart _nested_newgrf_inspect_chain_widgets[] = {
629 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
630 NWidget(WWT_CAPTION, COLOUR_GREY, WID_NGRFI_CAPTION), SetStringTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
631 NWidget(WWT_SHADEBOX, COLOUR_GREY),
632 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
633 NWidget(WWT_STICKYBOX, COLOUR_GREY),
634 EndContainer(),
635 NWidget(WWT_PANEL, COLOUR_GREY),
639 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NGRFI_VEH_CHAIN), SetFill(1, 0), SetResize(1, 0),
640 EndContainer(),
641 EndContainer(),
646 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
647 EndContainer(),
648 EndContainer(),
649};
650
651static constexpr NWidgetPart _nested_newgrf_inspect_widgets[] = {
653 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
654 NWidget(WWT_CAPTION, COLOUR_GREY, WID_NGRFI_CAPTION), SetStringTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
655 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NGRFI_PARENT), SetStringTip(STR_NEWGRF_INSPECT_PARENT_BUTTON, STR_NEWGRF_INSPECT_PARENT_TOOLTIP),
656 NWidget(WWT_SHADEBOX, COLOUR_GREY),
657 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
658 NWidget(WWT_STICKYBOX, COLOUR_GREY),
659 EndContainer(),
664 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
665 EndContainer(),
666 EndContainer(),
667};
668
669static WindowDesc _newgrf_inspect_chain_desc(
670 WDP_AUTO, "newgrf_inspect_chain", 400, 300,
672 {},
673 _nested_newgrf_inspect_chain_widgets
674);
675
676static WindowDesc _newgrf_inspect_desc(
677 WDP_AUTO, "newgrf_inspect", 400, 300,
679 {},
680 _nested_newgrf_inspect_widgets
681);
682
692void ShowNewGRFInspectWindow(GrfSpecFeature feature, uint index, const uint32_t grfid)
693{
694 if (!IsNewGRFInspectable(feature, index)) return;
695
696 WindowNumber wno = GetInspectWindowNumber(feature, index);
697 WindowDesc &desc = (feature == GSF_TRAINS || feature == GSF_ROADVEHICLES) ? _newgrf_inspect_chain_desc : _newgrf_inspect_desc;
698 NewGRFInspectWindow *w = AllocateWindowDescFront<NewGRFInspectWindow, true>(desc, wno);
699 w->SetCallerGRFID(grfid);
700}
701
711{
712 if (feature == GSF_INVALID) return;
713
714 WindowNumber wno = GetInspectWindowNumber(feature, index);
716}
717
727{
728 if (feature == GSF_INVALID) return;
729
730 WindowNumber wno = GetInspectWindowNumber(feature, index);
732
733 /* Reinitialise the land information window to remove the "debug" sprite if needed.
734 * Note: Since we might be called from a command here, it is important to not execute
735 * the invalidation immediately. The landinfo window tests commands itself. */
737}
738
748bool IsNewGRFInspectable(GrfSpecFeature feature, uint index)
749{
750 const NIFeature *nif = GetFeature(GetInspectWindowNumber(feature, index));
751 if (nif == nullptr) return false;
752 return nif->helper->IsInspectable(index);
753}
754
761{
762 switch (GetTileType(tile)) {
763 default: return GSF_INVALID;
764 case MP_RAILWAY: return GSF_RAILTYPES;
765 case MP_ROAD: return IsLevelCrossing(tile) ? GSF_RAILTYPES : GSF_ROADTYPES;
766 case MP_HOUSE: return GSF_HOUSES;
767 case MP_INDUSTRY: return GSF_INDUSTRYTILES;
768 case MP_OBJECT: return GSF_OBJECTS;
769
770 case MP_STATION:
771 switch (GetStationType(tile)) {
772 case StationType::Rail: return GSF_STATIONS;
773 case StationType::Airport: return GSF_AIRPORTTILES;
774 case StationType::Bus: return GSF_ROADSTOPS;
775 case StationType::Truck: return GSF_ROADSTOPS;
776 default: return GSF_INVALID;
777 }
778 }
779}
780
787{
788 switch (type) {
789 case VEH_TRAIN: return GSF_TRAINS;
790 case VEH_ROAD: return GSF_ROADVEHICLES;
791 case VEH_SHIP: return GSF_SHIPS;
792 case VEH_AIRCRAFT: return GSF_AIRCRAFT;
793 default: return GSF_INVALID;
794 }
795}
796
797
798/**** Sprite Aligner ****/
799
802 typedef std::pair<int16_t, int16_t> XyOffs;
803
805 Scrollbar *vscroll = nullptr;
806 std::map<SpriteID, XyOffs> offs_start_map{};
807
808 static inline ZoomLevel zoom = ZoomLevel::End;
809 static bool centre;
810 static bool crosshair;
811 const Action5Type *act5_type = nullptr;
812
814 {
815 /* On first opening, set initial zoom to current zoom level. */
816 if (SpriteAlignerWindow::zoom == ZoomLevel::End) SpriteAlignerWindow::zoom = _gui_zoom;
817 SpriteAlignerWindow::zoom = Clamp(SpriteAlignerWindow::zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max);
818
819 /* Oh yes, we assume there is at least one normal sprite! */
821 this->SelectAction5Type();
822
823 this->CreateNestedTree();
824 this->vscroll = this->GetScrollbar(WID_SA_SCROLLBAR);
825 this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.size());
826 this->FinishInitNested(wno);
827
828 this->SetWidgetLoweredState(WID_SA_CENTRE, SpriteAlignerWindow::centre);
829 this->SetWidgetLoweredState(WID_SA_CROSSHAIR, SpriteAlignerWindow::crosshair);
830
831 this->InvalidateData(0, true);
832 }
833
834 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
835 {
836 const Sprite *spr = GetSprite(this->current_sprite, SpriteType::Normal);
837 switch (widget) {
838 case WID_SA_CAPTION:
839 if (this->act5_type != nullptr) {
840 return GetString(STR_SPRITE_ALIGNER_CAPTION_ACTION5,
841 this->act5_type - GetAction5Types().data(),
842 this->current_sprite - this->act5_type->sprite_base,
843 GetOriginFile(this->current_sprite)->GetSimplifiedFilename(),
845 }
846 if (this->current_sprite < SPR_OPENTTD_BASE) {
847 return GetString(STR_SPRITE_ALIGNER_CAPTION_ACTIONA,
848 this->current_sprite,
849 GetOriginFile(this->current_sprite)->GetSimplifiedFilename(),
851 }
852 return GetString(STR_SPRITE_ALIGNER_CAPTION_NO_ACTION,
853 GetOriginFile(this->current_sprite)->GetSimplifiedFilename(),
855
857 return GetString(STR_SPRITE_ALIGNER_OFFSETS_ABS, UnScaleByZoom(spr->x_offs, SpriteAlignerWindow::zoom), UnScaleByZoom(spr->y_offs, SpriteAlignerWindow::zoom));
858
859 case WID_SA_OFFSETS_REL: {
860 /* Relative offset is new absolute offset - starting absolute offset.
861 * Show 0, 0 as the relative offsets if entry is not in the map (meaning they have not been changed yet).
862 */
863 const auto key_offs_pair = this->offs_start_map.find(this->current_sprite);
864 if (key_offs_pair != this->offs_start_map.end()) {
865 return GetString(STR_SPRITE_ALIGNER_OFFSETS_REL,
866 UnScaleByZoom(spr->x_offs - key_offs_pair->second.first, SpriteAlignerWindow::zoom),
867 UnScaleByZoom(spr->y_offs - key_offs_pair->second.second, SpriteAlignerWindow::zoom));
868 }
869
870 return GetString(STR_SPRITE_ALIGNER_OFFSETS_REL, 0, 0);
871 }
872
873 default:
874 return this->Window::GetWidgetString(widget, stringid);
875 }
876 }
877
878 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
879 {
880 switch (widget) {
881 case WID_SA_SPRITE:
882 size.height = ScaleGUITrad(200);
883 break;
884
885 case WID_SA_LIST: {
886 Dimension d = {};
887 for (const auto &spritefile : GetCachedSpriteFiles()) {
888 d = maxdim(d, GetStringBoundingBox(GetString(STR_SPRITE_ALIGNER_SPRITE, spritefile->GetSimplifiedFilename(), GetParamMaxDigits(6))));
889 }
890 size.width = d.width + padding.width;
891 resize.height = GetCharacterHeight(FS_NORMAL) + padding.height;
892 resize.width = 1;
893 fill.height = resize.height;
894 break;
895 }
896
897 default:
898 break;
899 }
900 }
901
902 void DrawWidget(const Rect &r, WidgetID widget) const override
903 {
904 switch (widget) {
905 case WID_SA_SPRITE: {
906 /* Center the sprite ourselves */
907 const Sprite *spr = GetSprite(this->current_sprite, SpriteType::Normal);
909 int x;
910 int y;
911 if (SpriteAlignerWindow::centre) {
912 x = -UnScaleByZoom(spr->x_offs, SpriteAlignerWindow::zoom) + (ir.Width() - UnScaleByZoom(spr->width, SpriteAlignerWindow::zoom)) / 2;
913 y = -UnScaleByZoom(spr->y_offs, SpriteAlignerWindow::zoom) + (ir.Height() - UnScaleByZoom(spr->height, SpriteAlignerWindow::zoom)) / 2;
914 } else {
915 x = ir.Width() / 2;
916 y = ir.Height() / 2;
917 }
918
919 DrawPixelInfo new_dpi;
920 if (!FillDrawPixelInfo(&new_dpi, ir)) break;
921 AutoRestoreBackup dpi_backup(_cur_dpi, &new_dpi);
922
923 DrawSprite(this->current_sprite, PAL_NONE, x, y, nullptr, SpriteAlignerWindow::zoom);
924
925 Rect outline = {0, 0, UnScaleByZoom(spr->width, SpriteAlignerWindow::zoom) - 1, UnScaleByZoom(spr->height, SpriteAlignerWindow::zoom) - 1};
926 outline = outline.Translate(x + UnScaleByZoom(spr->x_offs, SpriteAlignerWindow::zoom), y + UnScaleByZoom(spr->y_offs, SpriteAlignerWindow::zoom));
927 DrawRectOutline(outline.Expand(1), PC_LIGHT_BLUE, 1, 1);
928
929 if (SpriteAlignerWindow::crosshair) {
930 GfxDrawLine(x, 0, x, ir.Height() - 1, PC_WHITE, 1, 1);
931 GfxDrawLine(0, y, ir.Width() - 1, y, PC_WHITE, 1, 1);
932 }
933 break;
934 }
935
936 case WID_SA_LIST: {
937 /* Don't redraw sprite list while it is still being filled by picker. */
938 if (_newgrf_debug_sprite_picker.mode == SPM_REDRAW) break;
939
940 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget);
941 int step_size = nwid->resize_y;
942
944
945 Rect ir = r.Shrink(WidgetDimensions::scaled.matrix);
946 auto [first, last] = this->vscroll->GetVisibleRangeIterators(list);
947 for (auto it = first; it != last; ++it) {
948 const SpriteFile *file = GetOriginFile(*it);
949 if (file == nullptr) {
950 DrawString(ir, GetString(STR_JUST_COMMA, *it), *it == this->current_sprite ? TC_WHITE : (TC_GREY | TC_NO_SHADE), SA_RIGHT | SA_FORCE);
951 } else {
952 DrawString(ir, GetString(STR_SPRITE_ALIGNER_SPRITE, file->GetSimplifiedFilename(), GetSpriteLocalID(*it)), *it == this->current_sprite ? TC_WHITE : TC_BLACK);
953 }
954 ir.top += step_size;
955 }
956 break;
957 }
958 }
959 }
960
961 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
962 {
963 switch (widget) {
964 case WID_SA_PREVIOUS:
965 do {
966 this->current_sprite = (this->current_sprite == 0 ? GetMaxSpriteID() : this->current_sprite) - 1;
968 this->SelectAction5Type();
969 this->SetDirty();
970 break;
971
972 case WID_SA_GOTO:
973 ShowQueryString({}, STR_SPRITE_ALIGNER_GOTO_CAPTION, 7, this, CS_NUMERAL, {});
974 break;
975
976 case WID_SA_NEXT:
977 do {
978 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
980 this->SelectAction5Type();
981 this->SetDirty();
982 break;
983
984 case WID_SA_PICKER:
986 _newgrf_debug_sprite_picker.mode = SPM_WAIT_CLICK;
987 this->SetDirty();
988 break;
989
990 case WID_SA_LIST: {
991 auto it = this->vscroll->GetScrolledItemFromWidget(_newgrf_debug_sprite_picker.sprites, pt.y, this, widget);
992 if (it != _newgrf_debug_sprite_picker.sprites.end()) {
993 SpriteID spr = *it;
994 if (GetSpriteType(spr) == SpriteType::Normal) this->current_sprite = spr;
995 }
996 this->SelectAction5Type();
997 this->SetDirty();
998 break;
999 }
1000
1001 case WID_SA_UP:
1002 case WID_SA_DOWN:
1003 case WID_SA_LEFT:
1004 case WID_SA_RIGHT: {
1005 /*
1006 * Yes... this is a hack.
1007 *
1008 * No... I don't think it is useful to make this less of a hack.
1009 *
1010 * If you want to align sprites, you just need the number. Generally
1011 * the sprite caches are big enough to not remove the sprite from the
1012 * cache. If that's not the case, just let the NewGRF developer
1013 * increase the cache size instead of storing thousands of offsets
1014 * for the incredibly small chance that it's actually going to be
1015 * used by someone and the sprite cache isn't big enough for that
1016 * particular NewGRF developer.
1017 */
1018 Sprite *spr = const_cast<Sprite *>(GetSprite(this->current_sprite, SpriteType::Normal));
1019
1020 /* Remember the original offsets of the current sprite, if not already in mapping. */
1021 if (this->offs_start_map.count(this->current_sprite) == 0) {
1022 this->offs_start_map[this->current_sprite] = XyOffs(spr->x_offs, spr->y_offs);
1023 }
1024 int amt = ScaleByZoom(_ctrl_pressed ? 8 : 1, SpriteAlignerWindow::zoom);
1025 switch (widget) {
1026 /* Move eight units at a time if ctrl is pressed. */
1027 case WID_SA_UP: spr->y_offs -= amt; break;
1028 case WID_SA_DOWN: spr->y_offs += amt; break;
1029 case WID_SA_LEFT: spr->x_offs -= amt; break;
1030 case WID_SA_RIGHT: spr->x_offs += amt; break;
1031 }
1032 /* Of course, we need to redraw the sprite, but where is it used?
1033 * Everywhere is a safe bet. */
1035 break;
1036 }
1037
1038 case WID_SA_RESET_REL:
1039 /* Reset the starting offsets for the current sprite. */
1040 this->offs_start_map.erase(this->current_sprite);
1041 this->SetDirty();
1042 break;
1043
1044 case WID_SA_CENTRE:
1045 SpriteAlignerWindow::centre = !SpriteAlignerWindow::centre;
1046 this->SetWidgetLoweredState(widget, SpriteAlignerWindow::centre);
1047 this->SetDirty();
1048 break;
1049
1050 case WID_SA_CROSSHAIR:
1051 SpriteAlignerWindow::crosshair = !SpriteAlignerWindow::crosshair;
1052 this->SetWidgetLoweredState(widget, SpriteAlignerWindow::crosshair);
1053 this->SetDirty();
1054 break;
1055
1056 default:
1058 SpriteAlignerWindow::zoom = static_cast<ZoomLevel>(widget - WID_SA_ZOOM);
1059 this->InvalidateData(0, true);
1060 }
1061 break;
1062 }
1063 }
1064
1065 void OnQueryTextFinished(std::optional<std::string> str) override
1066 {
1067 if (!str.has_value()) return;
1068
1069 auto value = ParseInteger(*str, 10, true);
1070 if (!value.has_value()) return;
1071 this->current_sprite = *value;
1072 if (this->current_sprite >= GetMaxSpriteID()) this->current_sprite = 0;
1074 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
1075 }
1076 this->SelectAction5Type();
1077 this->SetDirty();
1078 }
1079
1085 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1086 {
1087 if (!gui_scope) return;
1088 if (data == 1) {
1089 /* Sprite picker finished */
1091 this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.size());
1092 }
1093
1094 SpriteAlignerWindow::zoom = Clamp(SpriteAlignerWindow::zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max);
1095 for (ZoomLevel z = ZoomLevel::Begin; z < ZoomLevel::End; z++) {
1096 this->SetWidgetsDisabledState(z < _settings_client.gui.zoom_min || z > _settings_client.gui.zoom_max, WID_SA_ZOOM + to_underlying(z));
1097 this->SetWidgetsLoweredState(SpriteAlignerWindow::zoom == z, WID_SA_ZOOM + to_underlying(z));
1098 }
1099 }
1100
1101 void OnResize() override
1102 {
1103 this->vscroll->SetCapacityFromWidget(this, WID_SA_LIST);
1104 }
1105
1106private:
1107 void SelectAction5Type()
1108 {
1109 const auto act5types = GetAction5Types();
1110 for (auto it = std::begin(act5types); it != std::end(act5types); ++it) {
1111 if (it->sprite_base <= this->current_sprite && this->current_sprite < it->sprite_base + it->max_sprites) {
1112 this->act5_type = &*it;
1113 return;
1114 }
1115 }
1116 this->act5_type = nullptr;
1117 }
1118};
1119
1120bool SpriteAlignerWindow::centre = true;
1121bool SpriteAlignerWindow::crosshair = true;
1122
1123static constexpr NWidgetPart _nested_sprite_aligner_widgets[] = {
1125 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1126 NWidget(WWT_CAPTION, COLOUR_GREY, WID_SA_CAPTION),
1127 NWidget(WWT_SHADEBOX, COLOUR_GREY),
1128 NWidget(WWT_STICKYBOX, COLOUR_GREY),
1129 EndContainer(),
1130 NWidget(WWT_PANEL, COLOUR_GREY),
1134 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_PREVIOUS), SetStringTip(STR_SPRITE_ALIGNER_PREVIOUS_BUTTON, STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
1135 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_GOTO), SetStringTip(STR_SPRITE_ALIGNER_GOTO_BUTTON, STR_SPRITE_ALIGNER_GOTO_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
1136 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_NEXT), SetStringTip(STR_SPRITE_ALIGNER_NEXT_BUTTON, STR_SPRITE_ALIGNER_NEXT_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
1137 EndContainer(),
1139 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1140 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_UP), SetSpriteTip(SPR_ARROW_UP, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1141 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1142 EndContainer(),
1145 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1146 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_LEFT), SetSpriteTip(SPR_ARROW_LEFT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1147 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1148 EndContainer(),
1149 NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_SA_SPRITE), SetToolTip(STR_SPRITE_ALIGNER_SPRITE_TOOLTIP), SetResize(1, 1), SetFill(1, 1),
1150 EndContainer(),
1152 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1153 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_RIGHT), SetSpriteTip(SPR_ARROW_RIGHT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1154 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1155 EndContainer(),
1156 EndContainer(),
1158 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1159 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_DOWN), SetSpriteTip(SPR_ARROW_DOWN, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1160 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1161 EndContainer(),
1162 NWidget(WWT_LABEL, INVALID_COLOUR, WID_SA_OFFSETS_ABS), SetFill(1, 0), SetResize(1, 0),
1163 NWidget(WWT_LABEL, INVALID_COLOUR, WID_SA_OFFSETS_REL), SetFill(1, 0), SetResize(1, 0),
1165 NWidget(WWT_TEXTBTN_2, COLOUR_GREY, WID_SA_CENTRE), SetStringTip(STR_SPRITE_ALIGNER_CENTRE_OFFSET), SetFill(1, 0), SetResize(1, 0),
1166 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_RESET_REL), SetStringTip(STR_SPRITE_ALIGNER_RESET_BUTTON, STR_SPRITE_ALIGNER_RESET_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
1167 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_CROSSHAIR), SetStringTip(STR_SPRITE_ALIGNER_CROSSHAIR), SetFill(1, 0), SetResize(1, 0),
1168 EndContainer(),
1169 EndContainer(),
1171 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_PICKER), SetStringTip(STR_SPRITE_ALIGNER_PICKER_BUTTON, STR_SPRITE_ALIGNER_PICKER_TOOLTIP), SetFill(1, 0),
1175 EndContainer(),
1177 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + to_underlying(ZoomLevel::In4x)), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_MIN), SetFill(1, 0),
1178 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + to_underlying(ZoomLevel::In2x)), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_IN_2X), SetFill(1, 0),
1179 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + to_underlying(ZoomLevel::Normal)), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_NORMAL), SetFill(1, 0),
1180 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + to_underlying(ZoomLevel::Out2x)), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X), SetFill(1, 0),
1181 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + to_underlying(ZoomLevel::Out4x)), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X), SetFill(1, 0),
1182 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + to_underlying(ZoomLevel::Out8x)), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X), SetFill(1, 0),
1183 EndContainer(),
1184 EndContainer(),
1185 EndContainer(),
1187 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
1188 NWidget(WWT_RESIZEBOX, COLOUR_GREY), SetResizeWidgetTypeTip(RWV_HIDE_BEVEL, STR_TOOLTIP_RESIZE),
1189 EndContainer(),
1190 EndContainer(),
1191};
1192
1193static WindowDesc _sprite_aligner_desc(
1194 WDP_AUTO, "sprite_aligner", 400, 300,
1196 {},
1197 _nested_sprite_aligner_widgets
1198);
1199
1204{
1205 AllocateWindowDescFront<SpriteAlignerWindow>(_sprite_aligner_desc, 0);
1206}
Class for backupping variables and making sure they are restored later.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:106
std::string label
Label of badge.
StringID name
Short name.
Flat set implementation that uses a sorted vector for storage.
Helper class to wrap some functionality/queries in.
virtual std::span< const BadgeID > GetBadges(uint index) const =0
Get the list of badges of this item.
virtual uint Resolve(uint index, uint var, uint param, bool &avail) const =0
Resolve (action2) variable for a given index.
virtual const void * GetSpec(uint index) const =0
Get (NewGRF) specs given an index.
virtual bool IsInspectable(uint index) const =0
Is the item with the given index inspectable?
virtual uint32_t GetGRFID(uint index) const =0
Get the GRFID of the file that includes this item.
virtual const void * GetInstance(uint index) const =0
Get the instance given an index.
virtual const std::span< int32_t > GetPSA(uint index, uint32_t grfid) const
Gets the span containing the persistent storage.
virtual ~NIHelper()=default
Silence a warning.
virtual std::string GetName(uint index) const =0
Get the name of this item.
virtual bool PSAWithParameter() const
Used to decide if the PSA needs a parameter or not.
virtual uint GetParent(uint index) const =0
Get the parent "window_number" of a given instance.
Baseclass for nested widgets.
uint resize_y
Vertical resize step (0 means not resizable).
const std::string & GetSimplifiedFilename() const
Get the simplified filename of the opened file.
Scrollbar data structure.
size_type GetCapacity() const
Gets the number of visible elements of the scrollbar.
void SetCount(size_t num)
Sets the number of elements in the list.
auto GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Return an iterator pointing to the element of a scrolled widget that a user clicked in.
size_type GetScrolledRowFromWidget(int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Compute the row of a scrolled widget that a user clicked in.
Definition widget.cpp:2482
void SetCapacityFromWidget(Window *w, WidgetID widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget.
Definition widget.cpp:2556
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
size_type GetPosition() const
Gets the position of the first visible element in the list.
RandomAccessFile with some extra information specific for sprite files.
RectPadding frametext
Padding inside frame with text.
Definition window_gui.h:41
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:93
A type is considered 'convertible through base()' when it has a 'base()' function that returns someth...
VehicleCellSize GetVehicleImageCellSize(VehicleType type, EngineImageType image_type)
Get the GUI cell size for a vehicle image.
Base class for engines.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:77
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
int CentreBounds(int min, int max, int size)
Determine where to position a centred object.
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:887
void DrawRectOutline(const Rect &r, int colour, int width, int dash)
Draw the outline of a Rect.
Definition gfx.cpp:457
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:658
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition gfx.cpp:1024
ZoomLevel _gui_zoom
GUI Zoom level.
Definition gfx.cpp:61
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:1554
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
@ Normal
The most basic (normal) sprite.
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:251
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:385
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
Definition gfx_type.h:395
@ TC_NO_SHADE
Do not add shading to this text colour.
Definition gfx_type.h:326
constexpr NWidgetPart SetMatrixDataTip(uint32_t cols, uint32_t rows, StringID tip={})
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetSpriteTip(SpriteID sprite, StringID tip={})
Widget part function for setting the sprite and tooltip.
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart SetResizeWidgetTypeTip(ResizeWidgetValues widget_type, StringID tip)
Widget part function for setting the resize widget type and tooltip.
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetToolTip(StringID tip)
Widget part function for setting tooltip and clearing the widget data.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart SetArrowWidgetTypeTip(ArrowWidgetValues widget_type, StringID tip={})
Widget part function for setting the arrow widget type and tooltip.
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition window.cpp:955
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1535
Base of all industries.
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
void ShowQueryString(std::string_view str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
GrfSpecFeature
Definition newgrf.h:69
@ GSF_INVALID
An invalid spec feature.
Definition newgrf.h:100
@ GSF_FAKE_END
End of the fake features.
Definition newgrf.h:96
std::span< const Action5Type > GetAction5Types()
Get list of all action 5 types.
Information about NewGRF Action 5.
NewGRF handling of airports.
NewGRF handling of airport tiles.
Badge * GetBadge(BadgeID index)
Get a badge if it exists.
Functions related to NewGRF badges.
AirportTileCallbackMask
Callback masks for airport tiles.
StationCallbackMask
Callback masks for stations.
VehicleCallbackMask
Callback masks for vehicles, indicates which callbacks are used by a vehicle.
CargoCallbackMask
Callback masks for cargoes.
IndustryCallbackMask
Callback masks for Industries.
CanalCallbackMask
Callback masks for canals.
ObjectCallbackMask
Callback masks for objects.
RoadStopCallbackMask
Callback masks for road stops.
IndustryTileCallbackMask
Callback masks for industry tiles.
HouseCallbackMask
Callback masks for houses.
Functions/types related to NewGRF debugging.
Data 'tables' for NewGRF debugging.
static const NIFeature *const _nifeatures[]
Table with all NIFeatures.
static uint GetInspectWindowNumber(GrfSpecFeature feature, uint index)
Get the window number for the inspect window given a feature and index.
NIType
The type of a property to show.
@ NIT_INT
The property is a simple integer.
@ NIT_CARGO
The property is a cargo.
void ShowSpriteAlignerWindow()
Show the window for aligning sprites.
GrfSpecFeature GetGrfSpecFeature(TileIndex tile)
Get the GrfSpecFeature associated with the tile.
void InvalidateNewGRFInspectWindow(GrfSpecFeature feature, uint index)
Invalidate the inspect window for a given feature and index.
static const NIFeature * GetFeature(uint window_number)
Get the NIFeature related to the window number.
void ShowNewGRFInspectWindow(GrfSpecFeature feature, uint index, const uint32_t grfid)
Show the inspect window for a given feature and index.
bool IsNewGRFInspectable(GrfSpecFeature feature, uint index)
Can we inspect the data given a certain feature and index.
static const NIHelper & GetFeatureHelper(uint window_number)
Get the NIHelper related to the window number.
static uint GetFeatureIndex(uint window_number)
Get the feature index related to the window number.
void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index)
Delete inspect window for a given feature and index.
static GrfSpecFeature GetFeatureNum(uint window_number)
Get the feature number related to the window number.
NewGrfDebugSpritePicker _newgrf_debug_sprite_picker
The sprite picker.
Types related to the newgrf debug widgets.
@ WID_NGRFI_VEH_CHAIN
Display for vehicle chain.
@ WID_NGRFI_PARENT
Inspect the parent.
@ WID_NGRFI_MAINPANEL
Panel widget containing the actual data.
@ WID_NGRFI_VEH_NEXT
Go to next vehicle in chain.
@ WID_NGRFI_CAPTION
The caption bar of course.
@ WID_NGRFI_VEH_PREV
Go to previous vehicle in chain.
@ WID_NGRFI_SCROLLBAR
Scrollbar.
@ WID_SA_NEXT
Skip to the next sprite.
@ WID_SA_CAPTION
Caption of the window.
@ WID_SA_SPRITE
The actual sprite.
@ WID_SA_PICKER
Sprite picker.
@ WID_SA_SCROLLBAR
Scrollbar for sprite list.
@ WID_SA_OFFSETS_ABS
The sprite offsets (absolute).
@ WID_SA_PREVIOUS
Skip to the previous sprite.
@ WID_SA_OFFSETS_REL
The sprite offsets (relative).
@ WID_SA_CROSSHAIR
Toggle crosshair.
@ WID_SA_GOTO
Go to a given sprite.
@ WID_SA_DOWN
Move the sprite down.
@ WID_SA_ZOOM
Zoom level buttons (from ZoomLevel::Begin to ZoomLevel::Max).
@ WID_SA_UP
Move the sprite up.
@ WID_SA_RESET_REL
Reset relative sprite offset.
@ WID_SA_LIST
Queried sprite list.
@ WID_SA_RIGHT
Move the sprite to the right.
@ WID_SA_LEFT
Move the sprite to the left.
@ WID_SA_CENTRE
Toggle centre sprite.
Functions for NewGRF industries.
NewGRF handling of industry tiles.
Functions related to NewGRF objects.
NewGRF handling of rail types.
Action 2 handling.
Header file for NewGRF stations.
Functions to handle the town part of NewGRF towns.
Base for all objects.
static const uint8_t PC_WHITE
White palette colour.
static const uint8_t PC_LIGHT_BLUE
Light blue palette colour.
Class related to random access to files.
bool IsLevelCrossing(Tile t)
Return whether a tile is a level crossing.
Definition road_map.h:69
Road vehicle states.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:59
SpriteType GetSpriteType(SpriteID sprite)
Get the sprite type of a given sprite.
SpriteID GetMaxSpriteID()
Get a reasonable (upper bound) estimate of the maximum SpriteID used in OpenTTD; there will be no spr...
std::span< const std::unique_ptr< SpriteFile > > GetCachedSpriteFiles()
Get the list of cached SpriteFiles.
SpriteFile * GetOriginFile(SpriteID sprite)
Get the SpriteFile of a given sprite.
uint32_t GetSpriteLocalID(SpriteID sprite)
Get the GRF-local sprite id of a given sprite.
Functions to cache sprites in memory.
static const SpriteID SPR_OPENTTD_BASE
Extra graphic spritenumbers.
Definition sprites.h:56
Base classes/functions 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.
static void StrMakeValid(Builder &builder, StringConsumer &consumer, StringValidationSettings settings)
Copies the valid (UTF-8) characters from consumer to the builder.
Definition string.cpp:117
Parse strings.
static std::optional< T > ParseInteger(std::string_view arg, int base=10, bool clamp=false)
Change a string into its number representation.
Functions related to low-level strings.
@ CS_HEXADECIMAL
Only hexadecimal characters.
Definition string_type.h:30
@ CS_NUMERAL
Only numeric ones.
Definition string_type.h:26
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:415
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:57
uint64_t GetParamMaxDigits(uint count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:219
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
@ TD_RTL
Text is written right-to-left by default.
Information about a single action 5 type.
Definition newgrf_act5.h:23
SpriteID sprite_base
Load the sprites starting from this sprite.
Definition newgrf_act5.h:25
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
Definition cargotype.h:137
GUISettings gui
settings related to the GUI
Dimensions (a width and height) of a rectangle in 2D.
Data about how and where to blit pixels.
Definition gfx_type.h:158
ZoomLevel zoom_min
minimum zoom out level
ZoomLevel zoom_max
maximum zoom out level
Representation of the available callbacks with information on when they actually apply.
std::string_view name
The human readable name of the callback.
uint16_t cb_id
The number of the callback.
NIReadProc * read_proc
Callback proc to get the actual variable from memory.
std::variant< std::monostate, VehicleCallbackMask, StationCallbackMask, RoadStopCallbackMask, HouseCallbackMask, CanalCallbackMask, CargoCallbackMask, IndustryCallbackMask, IndustryTileCallbackMask, ObjectCallbackMask, AirportTileCallbackMask > cb_bit
The bit that needs to be set for this callback to be enabled.
Container for all information for a given feature.
std::span< const NICallback > callbacks
The callbacks associated with this feature.
std::span< const NIVariable > variables
The variables associated with this feature.
std::span< const NIProperty > properties
The properties associated with this feature.
std::unique_ptr< const NIHelper > helper
The class container all helper functions.
Representation of the data from a NewGRF property.
NIReadProc * read_proc
Callback proc to get the actual variable from memory.
std::string_view name
A (human readable) name for the property.
uint8_t prop
The number of the property.
Representation on the NewGRF variables.
Partial widget specification to allow NWidgets to be written nested.
Window used for inspecting NewGRFs.
static bool HasVariableParameter(uint variable)
Check whether the given variable has a parameter.
static uint32_t var60params[GSF_FAKE_END][0x20]
The value for the variable 60 parameters.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
void DrawMainPanelWidget(const Rect &r) const
Helper function to draw the main panel widget.
void ValidateChainIndex()
Ensure that this->chain_index is in range.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
void DrawString(const Rect &r, int offset, const std::string &string) const
Helper function to draw a string (line) in the window.
bool HasChainIndex() const
Check whether this feature has chain index, i.e.
uint32_t caller_grfid
GRFID of the caller of this window, 0 if it has no caller.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
void DrawVehicleChainWidget(const Rect &r) const
Helper function to draw the vehicle chain widget.
uint GetFeatureIndex() const
Get the feature index.
void SetCallerGRFID(uint32_t grfid)
Set the GRFID of the item opening this window.
uint8_t current_edit_param
The currently edited parameter, to update the right one.
void OnResize() override
Called after the window got resized.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
uint chain_index
For ground vehicles: Index in vehicle chain.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
Spritepicker of SpriteAligner.
NewGrfDebugSpritePickerMode mode
Current state.
FlatSet< SpriteID > sprites
Sprites found.
Coordinates of a point in 2D.
static Titem * Get(auto index)
Returns Titem with given index.
Tindex index
Index of this pool item.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
int Width() const
Get width of Rect.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
int Height() const
Get height of Rect.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
Rect Expand(int s) const
Copy and expand Rect by s pixels.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
Window used for aligning sprites.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
std::pair< int16_t, int16_t > XyOffs
Pair for x and y offsets of the sprite before alignment. First value contains the x offset,...
const Action5Type * act5_type
Sprite Area of current selected sprite.
void OnResize() override
Called after the window got resized.
SpriteID current_sprite
The currently shown sprite.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
std::map< SpriteID, XyOffs > offs_start_map
Mapping of starting offsets for the sprites which have been aligned in the sprite aligner window.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
Data structure describing a sprite.
Definition spritecache.h:17
uint16_t width
Width of the sprite.
Definition spritecache.h:19
uint16_t height
Height of the sprite.
Definition spritecache.h:18
int16_t y_offs
Number of pixels to shift the sprite downwards.
Definition spritecache.h:21
int16_t x_offs
Number of pixels to shift the sprite to the right.
Definition spritecache.h:20
uint height
Vehicle cell height.
Definition vehicle_gui.h:84
Vehicle data structure.
Vehicle * Move(int n)
Get the vehicle at offset n of this vehicle chain.
Vehicle * First() const
Get the first vehicle of this vehicle chain.
Vehicle * Next() const
Get the next vehicle of this vehicle.
High level window description.
Definition window_gui.h:167
Number to differentiate different windows of the same class.
Data structure for an opened window.
Definition window_gui.h:273
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1778
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3205
void RaiseWidget(WidgetID widget_index)
Marks a widget as raised.
Definition window_gui.h:469
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:503
virtual void ShowNewGRFInspectWindow() const
Show the NewGRF inspection window.
Definition window_gui.h:867
ResizeInfo resize
Resize information.
Definition window_gui.h:314
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition window_gui.h:515
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1768
void SetWidgetsLoweredState(bool lowered_stat, Args... widgets)
Sets the lowered/raised status of a list of widgets.
Definition window_gui.h:526
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:441
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
Definition window_gui.h:460
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:312
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:381
int height
Height of the window (number of pixels down in y direction)
Definition window_gui.h:312
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:311
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:302
Stuff related to the text buffer GUI.
static debug_inline TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
@ 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_HOUSE
A house by a town.
Definition tile_type.h:51
@ MP_RAILWAY
A railway.
Definition tile_type.h:49
@ MP_INDUSTRY
Part of an industry.
Definition tile_type.h:56
@ MP_OBJECT
Contains objects such as transmitters and owned land.
Definition tile_type.h:58
Base of the town class.
Base for the train class.
Base class for all vehicles.
void DrawVehicleImage(const Vehicle *v, const Rect &r, VehicleID selection, EngineImageType image_type, int skip)
Draws an image of a vehicle chain.
Functions related to the vehicle's GUIs.
@ EIT_IN_DEPOT
Vehicle drawn in depot.
@ EIT_IN_DETAILS
Vehicle drawn in vehicle details, refit window, ...
VehicleType
Available vehicle types.
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition widget.cpp:298
static RectPadding ScaleGUITrad(const RectPadding &r)
Scale a RectPadding to GUI zoom level.
Definition widget.cpp:49
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
@ WWT_PUSHARROWBTN
Normal push-button (no toggle button) with arrow caption.
@ WWT_LABEL
Centered label.
Definition widget_type.h:49
@ NWID_SPACER
Invisible widget that takes some space.
Definition widget_type.h:71
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:67
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:45
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:40
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:58
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:51
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:56
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:53
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:77
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:69
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:61
@ WWT_TEXTBTN_2
(Toggle) Button with diff text when clicked
Definition widget_type.h:46
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:38
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:60
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:57
@ NWID_HORIZONTAL_LTR
Horizontal container that doesn't change the order of the widgets for RTL languages.
Definition widget_type.h:68
@ EqualSize
Containers should keep all their (resizing) children equally large.
@ AWV_DECREASE
Arrow to the left or in case of RTL to the right.
Definition widget_type.h:21
@ AWV_INCREASE
Arrow to the right or in case of RTL to the left.
Definition widget_type.h:22
@ RWV_HIDE_BEVEL
Bevel of resize box is hidden.
Definition widget_type.h:30
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition window.cpp:1182
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition window.cpp:3265
Window functions not directly related to making/drawing windows.
Functions, definitions and such used only by the GUI.
@ BorderOnly
Draw border only, no background.
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:144
int WidgetID
Widget ID.
Definition window_type.h:20
@ WC_LAND_INFO
Land info window; Window numbers:
@ WC_SPRITE_ALIGNER
Sprite aligner (debug); Window numbers:
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:47
@ WC_NEWGRF_INSPECT
NewGRF inspect (debug); Window numbers:
Functions related to zooming.
int ScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift left (when zoom > ZoomLevel::Min) When shifting right,...
Definition zoom_func.h:22
int UnScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift right (when zoom > ZoomLevel::Min) When shifting right,...
Definition zoom_func.h:34
ZoomLevel
All zoom levels we know.
Definition zoom_type.h:16
@ Begin
Begin for iteration.
@ In2x
Zoomed 2 times in.
@ End
End for iteration.
@ Out2x
Zoomed 2 times out.
@ Normal
The normal zoom level.
@ In4x
Zoomed 4 times in.
@ Out8x
Zoomed 8 times out.
@ Out4x
Zoomed 4 times out.