OpenTTD Source 20250218-master-g53dd1258a7
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"
22
23#include "engine_base.h"
24#include "industry.h"
25#include "object_base.h"
26#include "station_base.h"
27#include "town.h"
28#include "vehicle_base.h"
29#include "train.h"
30#include "roadveh.h"
31
32#include "newgrf_act5.h"
33#include "newgrf_airport.h"
34#include "newgrf_airporttiles.h"
35#include "newgrf_badge.h"
36#include "newgrf_debug.h"
37#include "newgrf_object.h"
38#include "newgrf_spritegroup.h"
39#include "newgrf_station.h"
40#include "newgrf_town.h"
41#include "newgrf_railtype.h"
42#include "newgrf_industries.h"
44
46
47#include "table/strings.h"
48
49#include "safeguards.h"
50
52NewGrfDebugSpritePicker _newgrf_debug_sprite_picker = { SPM_NONE, nullptr, std::vector<SpriteID>() };
53
59static inline uint GetFeatureIndex(uint window_number)
60{
61 return GB(window_number, 0, 24);
62}
63
71static inline uint GetInspectWindowNumber(GrfSpecFeature feature, uint index)
72{
73 assert((index >> 24) == 0);
74 return (feature << 24) | index;
75}
76
77static inline uint GetInspectWindowNumber(GrfSpecFeature feature, ConvertibleThroughBase auto index) { return GetInspectWindowNumber(feature, index.base()); }
78
83enum NIType : uint8_t {
86};
87
88typedef const void *NIOffsetProc(const void *b);
89
91struct NIProperty {
92 std::string_view name;
93 NIOffsetProc *offset_proc;
94 uint8_t read_size;
95 uint8_t prop;
96 uint8_t type;
97};
98
99
122
125 std::string_view name;
126 uint8_t var;
127};
128
130class NIHelper {
131public:
133 virtual ~NIHelper() = default;
134
140 virtual bool IsInspectable(uint index) const = 0;
141
147 virtual uint GetParent(uint index) const = 0;
148
154 virtual const void *GetInstance(uint index) const = 0;
155
161 virtual const void *GetSpec(uint index) const = 0;
162
167 virtual void SetStringParameters(uint index) const = 0;
168
174 virtual uint32_t GetGRFID(uint index) const = 0;
175
181 virtual std::span<const BadgeID> GetBadges(uint index) const = 0;
182
191 virtual uint Resolve(uint index, uint var, uint param, bool &avail) const = 0;
192
197 virtual bool PSAWithParameter() const
198 {
199 return false;
200 }
201
208 virtual const std::span<int32_t> GetPSA([[maybe_unused]] uint index, [[maybe_unused]] uint32_t grfid) const
209 {
210 return {};
211 }
212
213protected:
219 void SetSimpleStringParameters(StringID string, uint32_t index) const
220 {
221 SetDParam(0, string);
222 SetDParam(1, index);
223 }
224
225
232 void SetObjectAtStringParameters(StringID string, uint32_t index, TileIndex tile) const
233 {
234 SetDParam(0, STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT);
235 SetDParam(1, string);
236 SetDParam(2, index);
237 SetDParam(3, tile);
238 }
239
240 void SetObjectAtStringParameters(StringID string, ConvertibleThroughBase auto index, TileIndex tile) const
241 {
242 this->SetObjectAtStringParameters(string, index.base(), tile);
243 }
244};
245
246
248struct NIFeature {
249 std::span<const NIProperty> properties;
250 std::span<const NICallback> callbacks;
251 std::span<const NIVariable> variables;
252 std::unique_ptr<const NIHelper> helper;
253};
254
255/* Load all the NewGRF debug data; externalised as it is just a huge bunch of tables. */
257
263static inline GrfSpecFeature GetFeatureNum(uint window_number)
264{
265 return (GrfSpecFeature)GB(window_number, 24, 8);
266}
267
273static inline const NIFeature *GetFeature(uint window_number)
274{
275 GrfSpecFeature idx = GetFeatureNum(window_number);
276 return idx < GSF_FAKE_END ? _nifeatures[idx] : nullptr;
277}
278
285static inline const NIHelper &GetFeatureHelper(uint window_number)
286{
287 return *GetFeature(window_number)->helper;
288}
289
293 static uint32_t var60params[GSF_FAKE_END][0x20];
294
297
300
303
304 Scrollbar *vscroll;
305
311 static bool HasVariableParameter(uint variable)
312 {
313 return IsInsideBS(variable, 0x60, 0x20);
314 }
315
321 {
322 this->caller_grfid = grfid;
323 this->SetDirty();
324 }
325
329 bool HasChainIndex() const
330 {
332 return f == GSF_TRAINS || f == GSF_ROADVEHICLES;
333 }
334
339 uint GetFeatureIndex() const
340 {
341 uint index = ::GetFeatureIndex(this->window_number);
342 if (this->chain_index > 0) {
343 assert(this->HasChainIndex());
344 const Vehicle *v = Vehicle::Get(index);
345 v = v->Move(this->chain_index);
346 if (v != nullptr) index = v->index.base();
347 }
348 return index;
349 }
350
355 {
356 if (this->chain_index == 0) return;
357
358 assert(this->HasChainIndex());
359
361 v = v->Move(this->chain_index);
362 if (v == nullptr) this->chain_index = 0;
363 }
364
366 {
367 this->CreateNestedTree();
368 this->vscroll = this->GetScrollbar(WID_NGRFI_SCROLLBAR);
369 this->FinishInitNested(wno);
370
371 this->vscroll->SetCount(0);
373
374 this->OnInvalidateData(0, true);
375 }
376
377 void SetStringParameters(WidgetID widget) const override
378 {
379 if (widget != WID_NGRFI_CAPTION) return;
380
382 }
383
385 {
386 switch (widget) {
387 case WID_NGRFI_VEH_CHAIN: {
388 assert(this->HasChainIndex());
390 size.height = std::max(size.height, GetVehicleImageCellSize((VehicleType)(VEH_TRAIN + (f - GSF_TRAINS)), EIT_IN_DEPOT).height + 2 + WidgetDimensions::scaled.bevel.Vertical());
391 break;
392 }
393
395 resize.height = std::max(11, GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal);
396 resize.width = 1;
397
398 size.height = 5 * resize.height + WidgetDimensions::scaled.frametext.Vertical();
399 break;
400 }
401 }
402
409 void DrawString(const Rect &r, int offset, const std::string &string) const
410 {
411 offset -= this->vscroll->GetPosition();
412 if (offset < 0 || offset >= this->vscroll->GetCapacity()) return;
413
414 ::DrawString(r.Shrink(WidgetDimensions::scaled.frametext).Shrink(0, offset * this->resize.step_height, 0, 0), string, TC_BLACK);
415 }
416
421 void DrawVehicleChainWidget(const Rect &r) const
422 {
423 const Vehicle *v = Vehicle::Get(this->GetFeatureIndex());
424 int total_width = 0;
425 int sel_start = 0;
426 int sel_end = 0;
427 for (const Vehicle *u = v->First(); u != nullptr; u = u->Next()) {
428 if (u == v) sel_start = total_width;
429 switch (u->type) {
430 case VEH_TRAIN: total_width += Train::From(u)->GetDisplayImageWidth(); break;
431 case VEH_ROAD: total_width += RoadVehicle::From(u)->GetDisplayImageWidth(); break;
432 default: NOT_REACHED();
433 }
434 if (u == v) sel_end = total_width;
435 }
436
438 int width = br.Width();
439 int skip = 0;
440 if (total_width > width) {
441 int sel_center = (sel_start + sel_end) / 2;
442 if (sel_center > width / 2) skip = std::min(total_width - width, sel_center - width / 2);
443 }
444
446 int h = GetVehicleImageCellSize((VehicleType)(VEH_TRAIN + (f - GSF_TRAINS)), EIT_IN_DEPOT).height;
447 int y = CenterBounds(br.top, br.bottom, h);
448 DrawVehicleImage(v->First(), br, VehicleID::Invalid(), EIT_IN_DETAILS, skip);
449
450 /* Highlight the articulated part (this is different to the whole-vehicle highlighting of DrawVehicleImage */
451 if (_current_text_dir == TD_RTL) {
452 DrawFrameRect(r.right - sel_end + skip, y, r.right - sel_start + skip, y + h, COLOUR_WHITE, FrameFlag::BorderOnly);
453 } else {
454 DrawFrameRect(r.left + sel_start - skip, y, r.left + sel_end - skip, y + h, COLOUR_WHITE, FrameFlag::BorderOnly);
455 }
456 }
457
462 void DrawMainPanelWidget(const Rect &r) const
463 {
464 uint index = this->GetFeatureIndex();
465 const NIFeature *nif = GetFeature(this->window_number);
466 const NIHelper &nih = *nif->helper;
467 const void *base = nih.GetInstance(index);
468 const void *base_spec = nih.GetSpec(index);
469
470 uint i = 0;
471 if (!nif->variables.empty()) {
472 this->DrawString(r, i++, "Variables:");
473 for (const NIVariable &niv : nif->variables) {
474 bool avail = true;
476 uint value = nih.Resolve(index, niv.var, param, avail);
477
478 if (!avail) continue;
479
480 if (HasVariableParameter(niv.var)) {
481 this->DrawString(r, i++, fmt::format(" {:02x}[{:02x}]: {:08x} ({})", niv.var, param, value, niv.name));
482 } else {
483 this->DrawString(r, i++, fmt::format(" {:02x}: {:08x} ({})", niv.var, value, niv.name));
484 }
485 }
486 }
487
488 auto psa = nih.GetPSA(index, this->caller_grfid);
489 if (!psa.empty()) {
490 if (nih.PSAWithParameter()) {
491 this->DrawString(r, i++, fmt::format("Persistent storage [{:08X}]:", std::byteswap(this->caller_grfid)));
492 } else {
493 this->DrawString(r, i++, "Persistent storage:");
494 }
495 assert(psa.size() % 4 == 0);
496 for (size_t j = 0; j < psa.size(); j += 4) {
497 this->DrawString(r, i++, fmt::format(" {}: {} {} {} {}", j, psa[j], psa[j + 1], psa[j + 2], psa[j + 3]));
498 }
499 }
500
501 auto badges = nih.GetBadges(index);
502 if (!badges.empty()) {
503 this->DrawString(r, i++, "Badges:");
504 for (const BadgeID &badge_index : badges) {
505 const Badge *badge = GetBadge(badge_index);
506 this->DrawString(r, i++, fmt::format(" {}: {}", StrMakeValid(badge->label), GetString(badge->name)));
507 }
508 }
509
510 if (!nif->properties.empty()) {
511 this->DrawString(r, i++, "Properties:");
512 for (const NIProperty &nip : nif->properties) {
513 const void *ptr = nip.offset_proc(base);
514 uint value;
515 switch (nip.read_size) {
516 case 1: value = *(const uint8_t *)ptr; break;
517 case 2: value = *(const uint16_t *)ptr; break;
518 case 4: value = *(const uint32_t *)ptr; break;
519 default: NOT_REACHED();
520 }
521
522 StringID string;
523 SetDParam(0, value);
524 switch (nip.type) {
525 case NIT_INT:
526 string = STR_JUST_INT;
527 break;
528
529 case NIT_CARGO:
530 string = IsValidCargoType(value) ? CargoSpec::Get(value)->name : STR_QUANTITY_N_A;
531 break;
532
533 default:
534 NOT_REACHED();
535 }
536
537 this->DrawString(r, i++, fmt::format(" {:02x}: {} ({})", nip.prop, GetString(string), nip.name));
538 }
539 }
540
541 if (!nif->callbacks.empty()) {
542 this->DrawString(r, i++, "Callbacks:");
543 for (const NICallback &nic : nif->callbacks) {
544 if (!std::holds_alternative<std::monostate>(nic.cb_bit)) {
545 const void *ptr = nic.offset_proc(base_spec);
546 uint value;
547 switch (nic.read_size) {
548 case 1: value = *(const uint8_t *)ptr; break;
549 case 2: value = *(const uint16_t *)ptr; break;
550 case 4: value = *(const uint32_t *)ptr; break;
551 default: NOT_REACHED();
552 }
553
554 struct visitor {
555 uint value;
556
557 bool operator()(const std::monostate &) { return false; }
558 bool operator()(const VehicleCallbackMask &bit) { return static_cast<VehicleCallbackMasks>(this->value).Test(bit); }
559 bool operator()(const StationCallbackMask &bit) { return static_cast<StationCallbackMasks>(this->value).Test(bit); }
560 bool operator()(const RoadStopCallbackMask &bit) { return static_cast<RoadStopCallbackMasks>(this->value).Test(bit); }
561 bool operator()(const HouseCallbackMask &bit) { return static_cast<HouseCallbackMasks>(this->value).Test(bit); }
562 bool operator()(const CanalCallbackMask &bit) { return static_cast<CanalCallbackMasks>(this->value).Test(bit); }
563 bool operator()(const CargoCallbackMask &bit) { return static_cast<CargoCallbackMasks>(this->value).Test(bit); }
564 bool operator()(const IndustryCallbackMask &bit) { return static_cast<IndustryCallbackMasks>(this->value).Test(bit); }
565 bool operator()(const IndustryTileCallbackMask &bit) { return static_cast<IndustryTileCallbackMasks>(this->value).Test(bit); }
566 bool operator()(const ObjectCallbackMask &bit) { return static_cast<ObjectCallbackMasks>(this->value).Test(bit); }
567 bool operator()(const AirportTileCallbackMask &bit) { return static_cast<AirportTileCallbackMasks>(this->value).Test(bit); }
568 };
569
570 if (!std::visit(visitor{value}, nic.cb_bit)) continue;
571 this->DrawString(r, i++, fmt::format(" {:03x}: {}", nic.cb_id, nic.name));
572 } else {
573 this->DrawString(r, i++, fmt::format(" {:03x}: {} (unmasked)", nic.cb_id, nic.name));
574 }
575 }
576 }
577
578 /* Not nice and certainly a hack, but it beats duplicating
579 * this whole function just to count the actual number of
580 * elements. Especially because they need to be redrawn. */
581 const_cast<NewGRFInspectWindow*>(this)->vscroll->SetCount(i);
582 }
583
584 void DrawWidget(const Rect &r, WidgetID widget) const override
585 {
586 switch (widget) {
588 this->DrawVehicleChainWidget(r);
589 break;
590
592 this->DrawMainPanelWidget(r);
593 break;
594 }
595 }
596
597 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
598 {
599 switch (widget) {
600 case WID_NGRFI_PARENT: {
602 uint index = nih.GetParent(this->GetFeatureIndex());
603 ::ShowNewGRFInspectWindow(GetFeatureNum(index), ::GetFeatureIndex(index), nih.GetGRFID(this->GetFeatureIndex()));
604 break;
605 }
606
608 if (this->chain_index > 0) {
609 this->chain_index--;
610 this->InvalidateData();
611 }
612 break;
613
615 if (this->HasChainIndex()) {
616 uint index = this->GetFeatureIndex();
617 Vehicle *v = Vehicle::Get(index);
618 if (v != nullptr && v->Next() != nullptr) {
619 this->chain_index++;
620 this->InvalidateData();
621 }
622 }
623 break;
624
625 case WID_NGRFI_MAINPANEL: {
626 /* Does this feature have variables? */
627 const NIFeature *nif = GetFeature(this->window_number);
628 if (nif->variables.empty()) return;
629
630 /* Get the line, make sure it's within the boundaries. */
632 if (line == INT32_MAX) return;
633
634 /* Find the variable related to the line */
635 for (const NIVariable &niv : nif->variables) {
636 if (--line != 0) continue; // 0 because of the "Variables:" line
637
638 if (!HasVariableParameter(niv.var)) break;
639
640 this->current_edit_param = niv.var;
642 }
643 }
644 }
645 }
646
647 void OnQueryTextFinished(std::optional<std::string> str) override
648 {
649 if (!str.has_value() || str->empty()) return;
650
651 NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][this->current_edit_param - 0x60] = std::strtol(str->c_str(), nullptr, 16);
652 this->SetDirty();
653 }
654
655 void OnResize() override
656 {
657 this->vscroll->SetCapacityFromWidget(this, WID_NGRFI_MAINPANEL, WidgetDimensions::scaled.frametext.Vertical());
658 }
659
665 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
666 {
667 if (!gui_scope) return;
668 if (this->HasChainIndex()) {
669 this->ValidateChainIndex();
670 this->SetWidgetDisabledState(WID_NGRFI_VEH_PREV, this->chain_index == 0);
672 this->SetWidgetDisabledState(WID_NGRFI_VEH_NEXT, v == nullptr || v->Next() == nullptr);
673 }
674 }
675};
676
677/* static */ uint32_t NewGRFInspectWindow::var60params[GSF_FAKE_END][0x20] = { {0} }; // Use spec to have 0s in whole array
678
679static constexpr NWidgetPart _nested_newgrf_inspect_chain_widgets[] = {
681 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
682 NWidget(WWT_CAPTION, COLOUR_GREY, WID_NGRFI_CAPTION), SetStringTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
683 NWidget(WWT_SHADEBOX, COLOUR_GREY),
684 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
685 NWidget(WWT_STICKYBOX, COLOUR_GREY),
686 EndContainer(),
687 NWidget(WWT_PANEL, COLOUR_GREY),
691 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NGRFI_VEH_CHAIN), SetFill(1, 0), SetResize(1, 0),
692 EndContainer(),
693 EndContainer(),
698 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
699 EndContainer(),
700 EndContainer(),
701};
702
703static constexpr NWidgetPart _nested_newgrf_inspect_widgets[] = {
705 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
706 NWidget(WWT_CAPTION, COLOUR_GREY, WID_NGRFI_CAPTION), SetStringTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
707 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NGRFI_PARENT), SetStringTip(STR_NEWGRF_INSPECT_PARENT_BUTTON, STR_NEWGRF_INSPECT_PARENT_TOOLTIP),
708 NWidget(WWT_SHADEBOX, COLOUR_GREY),
709 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
710 NWidget(WWT_STICKYBOX, COLOUR_GREY),
711 EndContainer(),
716 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
717 EndContainer(),
718 EndContainer(),
719};
720
721static WindowDesc _newgrf_inspect_chain_desc(
722 WDP_AUTO, "newgrf_inspect_chain", 400, 300,
724 {},
725 _nested_newgrf_inspect_chain_widgets
726);
727
728static WindowDesc _newgrf_inspect_desc(
729 WDP_AUTO, "newgrf_inspect", 400, 300,
731 {},
732 _nested_newgrf_inspect_widgets
733);
734
744void ShowNewGRFInspectWindow(GrfSpecFeature feature, uint index, const uint32_t grfid)
745{
746 if (!IsNewGRFInspectable(feature, index)) return;
747
748 WindowNumber wno = GetInspectWindowNumber(feature, index);
749 WindowDesc &desc = (feature == GSF_TRAINS || feature == GSF_ROADVEHICLES) ? _newgrf_inspect_chain_desc : _newgrf_inspect_desc;
750 NewGRFInspectWindow *w = AllocateWindowDescFront<NewGRFInspectWindow, true>(desc, wno);
751 w->SetCallerGRFID(grfid);
752}
753
763{
764 if (feature == GSF_INVALID) return;
765
766 WindowNumber wno = GetInspectWindowNumber(feature, index);
768}
769
779{
780 if (feature == GSF_INVALID) return;
781
782 WindowNumber wno = GetInspectWindowNumber(feature, index);
784
785 /* Reinitialise the land information window to remove the "debug" sprite if needed.
786 * Note: Since we might be called from a command here, it is important to not execute
787 * the invalidation immediately. The landinfo window tests commands itself. */
789}
790
800bool IsNewGRFInspectable(GrfSpecFeature feature, uint index)
801{
802 const NIFeature *nif = GetFeature(GetInspectWindowNumber(feature, index));
803 if (nif == nullptr) return false;
804 return nif->helper->IsInspectable(index);
805}
806
813{
814 switch (GetTileType(tile)) {
815 default: return GSF_INVALID;
816 case MP_RAILWAY: return GSF_RAILTYPES;
817 case MP_ROAD: return IsLevelCrossing(tile) ? GSF_RAILTYPES : GSF_ROADTYPES;
818 case MP_HOUSE: return GSF_HOUSES;
819 case MP_INDUSTRY: return GSF_INDUSTRYTILES;
820 case MP_OBJECT: return GSF_OBJECTS;
821
822 case MP_STATION:
823 switch (GetStationType(tile)) {
824 case StationType::Rail: return GSF_STATIONS;
825 case StationType::Airport: return GSF_AIRPORTTILES;
826 case StationType::Bus: return GSF_ROADSTOPS;
827 case StationType::Truck: return GSF_ROADSTOPS;
828 default: return GSF_INVALID;
829 }
830 }
831}
832
839{
840 switch (type) {
841 case VEH_TRAIN: return GSF_TRAINS;
842 case VEH_ROAD: return GSF_ROADVEHICLES;
843 case VEH_SHIP: return GSF_SHIPS;
844 case VEH_AIRCRAFT: return GSF_AIRCRAFT;
845 default: return GSF_INVALID;
846 }
847}
848
849
850/**** Sprite Aligner ****/
851
854 typedef std::pair<int16_t, int16_t> XyOffs;
855
857 Scrollbar *vscroll;
858 std::map<SpriteID, XyOffs> offs_start_map;
859
860 static inline ZoomLevel zoom = ZOOM_LVL_END;
861 static bool centre;
862 static bool crosshair;
863 const Action5Type *act5_type = nullptr;
864
866 {
867 /* On first opening, set initial zoom to current zoom level. */
868 if (SpriteAlignerWindow::zoom == ZOOM_LVL_END) SpriteAlignerWindow::zoom = _gui_zoom;
869 SpriteAlignerWindow::zoom = Clamp(SpriteAlignerWindow::zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max);
870
871 /* Oh yes, we assume there is at least one normal sprite! */
872 while (GetSpriteType(this->current_sprite) != SpriteType::Normal) this->current_sprite++;
873 this->SelectAction5Type();
874
875 this->CreateNestedTree();
876 this->vscroll = this->GetScrollbar(WID_SA_SCROLLBAR);
877 this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.size());
878 this->FinishInitNested(wno);
879
880 this->SetWidgetLoweredState(WID_SA_CENTRE, SpriteAlignerWindow::centre);
881 this->SetWidgetLoweredState(WID_SA_CROSSHAIR, SpriteAlignerWindow::crosshair);
882
883 this->InvalidateData(0, true);
884 }
885
886 void SetStringParameters(WidgetID widget) const override
887 {
888 const Sprite *spr = GetSprite(this->current_sprite, SpriteType::Normal);
889 switch (widget) {
890 case WID_SA_CAPTION:
891 if (this->act5_type != nullptr) {
893 SetDParam(1, this->act5_type - GetAction5Types().data());
894 SetDParam(2, this->current_sprite - this->act5_type->sprite_base);
895 SetDParamStr(3, GetOriginFile(this->current_sprite)->GetSimplifiedFilename());
896 SetDParam(4, GetSpriteLocalID(this->current_sprite));
897 } else if (this->current_sprite < SPR_OPENTTD_BASE) {
899 SetDParam(1, this->current_sprite);
900 SetDParamStr(2, GetOriginFile(this->current_sprite)->GetSimplifiedFilename());
901 SetDParam(3, GetSpriteLocalID(this->current_sprite));
902 } else {
904 SetDParamStr(1, GetOriginFile(this->current_sprite)->GetSimplifiedFilename());
905 SetDParam(2, GetSpriteLocalID(this->current_sprite));
906 }
907 break;
908
910 SetDParam(0, UnScaleByZoom(spr->x_offs, SpriteAlignerWindow::zoom));
911 SetDParam(1, UnScaleByZoom(spr->y_offs, SpriteAlignerWindow::zoom));
912 break;
913
914 case WID_SA_OFFSETS_REL: {
915 /* Relative offset is new absolute offset - starting absolute offset.
916 * Show 0, 0 as the relative offsets if entry is not in the map (meaning they have not been changed yet).
917 */
918 const auto key_offs_pair = this->offs_start_map.find(this->current_sprite);
919 if (key_offs_pair != this->offs_start_map.end()) {
920 SetDParam(0, UnScaleByZoom(spr->x_offs - key_offs_pair->second.first, SpriteAlignerWindow::zoom));
921 SetDParam(1, UnScaleByZoom(spr->y_offs - key_offs_pair->second.second, SpriteAlignerWindow::zoom));
922 } else {
923 SetDParam(0, 0);
924 SetDParam(1, 0);
925 }
926 break;
927 }
928
929 default:
930 break;
931 }
932 }
933
935 {
936 switch (widget) {
937 case WID_SA_SPRITE:
938 size.height = ScaleGUITrad(200);
939 break;
940
941 case WID_SA_LIST: {
942 Dimension d = {};
943 for (const auto &spritefile : GetCachedSpriteFiles()) {
944 SetDParamStr(0, spritefile->GetSimplifiedFilename());
945 SetDParamMaxDigits(1, 6);
947 }
948 size.width = d.width + padding.width;
949 resize.height = GetCharacterHeight(FS_NORMAL) + padding.height;
950 resize.width = 1;
951 fill.height = resize.height;
952 break;
953 }
954
955 default:
956 break;
957 }
958 }
959
960 void DrawWidget(const Rect &r, WidgetID widget) const override
961 {
962 switch (widget) {
963 case WID_SA_SPRITE: {
964 /* Center the sprite ourselves */
965 const Sprite *spr = GetSprite(this->current_sprite, SpriteType::Normal);
967 int x;
968 int y;
969 if (SpriteAlignerWindow::centre) {
970 x = -UnScaleByZoom(spr->x_offs, SpriteAlignerWindow::zoom) + (ir.Width() - UnScaleByZoom(spr->width, SpriteAlignerWindow::zoom)) / 2;
971 y = -UnScaleByZoom(spr->y_offs, SpriteAlignerWindow::zoom) + (ir.Height() - UnScaleByZoom(spr->height, SpriteAlignerWindow::zoom)) / 2;
972 } else {
973 x = ir.Width() / 2;
974 y = ir.Height() / 2;
975 }
976
978 if (!FillDrawPixelInfo(&new_dpi, ir)) break;
980
981 DrawSprite(this->current_sprite, PAL_NONE, x, y, nullptr, SpriteAlignerWindow::zoom);
982
983 Rect outline = {0, 0, UnScaleByZoom(spr->width, SpriteAlignerWindow::zoom) - 1, UnScaleByZoom(spr->height, SpriteAlignerWindow::zoom) - 1};
984 outline = outline.Translate(x + UnScaleByZoom(spr->x_offs, SpriteAlignerWindow::zoom), y + UnScaleByZoom(spr->y_offs, SpriteAlignerWindow::zoom));
985 DrawRectOutline(outline.Expand(1), PC_LIGHT_BLUE, 1, 1);
986
987 if (SpriteAlignerWindow::crosshair) {
988 GfxDrawLine(x, 0, x, ir.Height() - 1, PC_WHITE, 1, 1);
989 GfxDrawLine(0, y, ir.Width() - 1, y, PC_WHITE, 1, 1);
990 }
991 break;
992 }
993
994 case WID_SA_LIST: {
995 /* Don't redraw sprite list while it is still being filled by picker. */
996 if (_newgrf_debug_sprite_picker.mode == SPM_REDRAW) break;
997
998 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget);
999 int step_size = nwid->resize_y;
1000
1001 const std::vector<SpriteID> &list = _newgrf_debug_sprite_picker.sprites;
1002
1004 auto [first, last] = this->vscroll->GetVisibleRangeIterators(list);
1005 for (auto it = first; it != last; ++it) {
1006 const SpriteFile *file = GetOriginFile(*it);
1007 if (file == nullptr) {
1008 SetDParam(0, *it);
1009 DrawString(ir, STR_JUST_COMMA, *it == this->current_sprite ? TC_WHITE : (TC_GREY | TC_NO_SHADE), SA_RIGHT | SA_FORCE);
1010 } else {
1012 SetDParam(1, GetSpriteLocalID(*it));
1013 DrawString(ir, STR_SPRITE_ALIGNER_SPRITE, *it == this->current_sprite ? TC_WHITE : TC_BLACK);
1014 }
1015 ir.top += step_size;
1016 }
1017 break;
1018 }
1019 }
1020 }
1021
1022 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1023 {
1024 switch (widget) {
1025 case WID_SA_PREVIOUS:
1026 do {
1027 this->current_sprite = (this->current_sprite == 0 ? GetMaxSpriteID() : this->current_sprite) - 1;
1028 } while (GetSpriteType(this->current_sprite) != SpriteType::Normal);
1029 this->SelectAction5Type();
1030 this->SetDirty();
1031 break;
1032
1033 case WID_SA_GOTO:
1035 break;
1036
1037 case WID_SA_NEXT:
1038 do {
1039 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
1040 } while (GetSpriteType(this->current_sprite) != SpriteType::Normal);
1041 this->SelectAction5Type();
1042 this->SetDirty();
1043 break;
1044
1045 case WID_SA_PICKER:
1047 _newgrf_debug_sprite_picker.mode = SPM_WAIT_CLICK;
1048 this->SetDirty();
1049 break;
1050
1051 case WID_SA_LIST: {
1052 auto it = this->vscroll->GetScrolledItemFromWidget(_newgrf_debug_sprite_picker.sprites, pt.y, this, widget);
1053 if (it != _newgrf_debug_sprite_picker.sprites.end()) {
1054 SpriteID spr = *it;
1055 if (GetSpriteType(spr) == SpriteType::Normal) this->current_sprite = spr;
1056 }
1057 this->SelectAction5Type();
1058 this->SetDirty();
1059 break;
1060 }
1061
1062 case WID_SA_UP:
1063 case WID_SA_DOWN:
1064 case WID_SA_LEFT:
1065 case WID_SA_RIGHT: {
1066 /*
1067 * Yes... this is a hack.
1068 *
1069 * No... I don't think it is useful to make this less of a hack.
1070 *
1071 * If you want to align sprites, you just need the number. Generally
1072 * the sprite caches are big enough to not remove the sprite from the
1073 * cache. If that's not the case, just let the NewGRF developer
1074 * increase the cache size instead of storing thousands of offsets
1075 * for the incredibly small chance that it's actually going to be
1076 * used by someone and the sprite cache isn't big enough for that
1077 * particular NewGRF developer.
1078 */
1079 Sprite *spr = const_cast<Sprite *>(GetSprite(this->current_sprite, SpriteType::Normal));
1080
1081 /* Remember the original offsets of the current sprite, if not already in mapping. */
1082 if (this->offs_start_map.count(this->current_sprite) == 0) {
1083 this->offs_start_map[this->current_sprite] = XyOffs(spr->x_offs, spr->y_offs);
1084 }
1085 int amt = ScaleByZoom(_ctrl_pressed ? 8 : 1, SpriteAlignerWindow::zoom);
1086 switch (widget) {
1087 /* Move eight units at a time if ctrl is pressed. */
1088 case WID_SA_UP: spr->y_offs -= amt; break;
1089 case WID_SA_DOWN: spr->y_offs += amt; break;
1090 case WID_SA_LEFT: spr->x_offs -= amt; break;
1091 case WID_SA_RIGHT: spr->x_offs += amt; break;
1092 }
1093 /* Of course, we need to redraw the sprite, but where is it used?
1094 * Everywhere is a safe bet. */
1096 break;
1097 }
1098
1099 case WID_SA_RESET_REL:
1100 /* Reset the starting offsets for the current sprite. */
1101 this->offs_start_map.erase(this->current_sprite);
1102 this->SetDirty();
1103 break;
1104
1105 case WID_SA_CENTRE:
1106 SpriteAlignerWindow::centre = !SpriteAlignerWindow::centre;
1107 this->SetWidgetLoweredState(widget, SpriteAlignerWindow::centre);
1108 this->SetDirty();
1109 break;
1110
1111 case WID_SA_CROSSHAIR:
1112 SpriteAlignerWindow::crosshair = !SpriteAlignerWindow::crosshair;
1113 this->SetWidgetLoweredState(widget, SpriteAlignerWindow::crosshair);
1114 this->SetDirty();
1115 break;
1116
1117 default:
1118 if (IsInsideBS(widget, WID_SA_ZOOM, ZOOM_LVL_END)) {
1119 SpriteAlignerWindow::zoom = ZoomLevel(widget - WID_SA_ZOOM);
1120 this->InvalidateData(0, true);
1121 }
1122 break;
1123 }
1124 }
1125
1126 void OnQueryTextFinished(std::optional<std::string> str) override
1127 {
1128 if (!str.has_value() || str->empty()) return;
1129
1130 this->current_sprite = atoi(str->c_str());
1131 if (this->current_sprite >= GetMaxSpriteID()) this->current_sprite = 0;
1132 while (GetSpriteType(this->current_sprite) != SpriteType::Normal) {
1133 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
1134 }
1135 this->SelectAction5Type();
1136 this->SetDirty();
1137 }
1138
1144 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1145 {
1146 if (!gui_scope) return;
1147 if (data == 1) {
1148 /* Sprite picker finished */
1150 this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.size());
1151 }
1152
1153 SpriteAlignerWindow::zoom = Clamp(SpriteAlignerWindow::zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max);
1154 for (ZoomLevel z = ZOOM_LVL_BEGIN; z < ZOOM_LVL_END; z++) {
1156 this->SetWidgetsLoweredState(SpriteAlignerWindow::zoom == z, WID_SA_ZOOM + z);
1157 }
1158 }
1159
1160 void OnResize() override
1161 {
1162 this->vscroll->SetCapacityFromWidget(this, WID_SA_LIST);
1163 }
1164
1165private:
1166 void SelectAction5Type()
1167 {
1168 const auto act5types = GetAction5Types();
1169 for (auto it = std::begin(act5types); it != std::end(act5types); ++it) {
1170 if (it->sprite_base <= this->current_sprite && this->current_sprite < it->sprite_base + it->max_sprites) {
1171 this->act5_type = &*it;
1172 return;
1173 }
1174 }
1175 this->act5_type = nullptr;
1176 }
1177};
1178
1179bool SpriteAlignerWindow::centre = true;
1180bool SpriteAlignerWindow::crosshair = true;
1181
1182static constexpr NWidgetPart _nested_sprite_aligner_widgets[] = {
1184 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1185 NWidget(WWT_CAPTION, COLOUR_GREY, WID_SA_CAPTION), SetStringTip(STR_JUST_STRING4, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1186 NWidget(WWT_SHADEBOX, COLOUR_GREY),
1187 NWidget(WWT_STICKYBOX, COLOUR_GREY),
1188 EndContainer(),
1189 NWidget(WWT_PANEL, COLOUR_GREY),
1193 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),
1194 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),
1195 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),
1196 EndContainer(),
1198 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1199 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_UP), SetSpriteTip(SPR_ARROW_UP, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1200 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1201 EndContainer(),
1204 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1205 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_LEFT), SetSpriteTip(SPR_ARROW_LEFT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1206 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1207 EndContainer(),
1208 NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_SA_SPRITE), SetToolTip(STR_SPRITE_ALIGNER_SPRITE_TOOLTIP), SetResize(1, 1), SetFill(1, 1),
1209 EndContainer(),
1211 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1212 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_RIGHT), SetSpriteTip(SPR_ARROW_RIGHT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1213 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1214 EndContainer(),
1215 EndContainer(),
1217 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1218 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_DOWN), SetSpriteTip(SPR_ARROW_DOWN, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1219 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1220 EndContainer(),
1221 NWidget(WWT_LABEL, INVALID_COLOUR, WID_SA_OFFSETS_ABS), SetStringTip(STR_SPRITE_ALIGNER_OFFSETS_ABS), SetFill(1, 0), SetResize(1, 0),
1222 NWidget(WWT_LABEL, INVALID_COLOUR, WID_SA_OFFSETS_REL), SetStringTip(STR_SPRITE_ALIGNER_OFFSETS_REL), SetFill(1, 0), SetResize(1, 0),
1224 NWidget(WWT_TEXTBTN_2, COLOUR_GREY, WID_SA_CENTRE), SetStringTip(STR_SPRITE_ALIGNER_CENTRE_OFFSET), SetFill(1, 0), SetResize(1, 0),
1225 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),
1226 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_CROSSHAIR), SetStringTip(STR_SPRITE_ALIGNER_CROSSHAIR), SetFill(1, 0), SetResize(1, 0),
1227 EndContainer(),
1228 EndContainer(),
1230 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_PICKER), SetStringTip(STR_SPRITE_ALIGNER_PICKER_BUTTON, STR_SPRITE_ALIGNER_PICKER_TOOLTIP), SetFill(1, 0),
1234 EndContainer(),
1236 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + ZOOM_LVL_IN_4X), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_MIN), SetFill(1, 0),
1237 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + ZOOM_LVL_IN_2X), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_IN_2X), SetFill(1, 0),
1238 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + ZOOM_LVL_NORMAL), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_NORMAL), SetFill(1, 0),
1239 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + ZOOM_LVL_OUT_2X), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X), SetFill(1, 0),
1240 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + ZOOM_LVL_OUT_4X), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X), SetFill(1, 0),
1241 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + ZOOM_LVL_OUT_8X), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X), SetFill(1, 0),
1242 EndContainer(),
1243 EndContainer(),
1244 EndContainer(),
1246 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
1247 NWidget(WWT_RESIZEBOX, COLOUR_GREY), SetResizeWidgetTypeTip(RWV_HIDE_BEVEL, STR_TOOLTIP_RESIZE),
1248 EndContainer(),
1249 EndContainer(),
1250};
1251
1252static WindowDesc _sprite_aligner_desc(
1253 WDP_AUTO, "sprite_aligner", 400, 300,
1255 {},
1256 _nested_sprite_aligner_widgets
1257);
1258
1263{
1264 AllocateWindowDescFront<SpriteAlignerWindow>(_sprite_aligner_desc, 0);
1265}
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 t)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:106
std::string label
Label of badge.
StringID name
Short name.
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.
void SetSimpleStringParameters(StringID string, uint32_t index) const
Helper to make setting the strings easier.
virtual bool PSAWithParameter() const
Used to decide if the PSA needs a parameter or not.
void SetObjectAtStringParameters(StringID string, uint32_t index, TileIndex tile) const
Helper to make setting the strings easier for objects at a specific tile.
virtual void SetStringParameters(uint index) const =0
Set the string parameters to write the right data for a STRINGn.
virtual uint GetParent(uint index) const =0
Get the parent "window_number" of a given instance.
Baseclass for nested widgets.
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:2459
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:2533
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:28
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:94
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.
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.
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:851
void DrawRectOutline(const Rect &r, int colour, int width, int dash)
Draw the outline of a Rect.
Definition gfx.cpp:456
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 DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition gfx.cpp:988
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:1548
int CenterBounds(int min, int max, int size)
Determine where to draw a centred object inside a widget.
Definition gfx_func.h:166
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:243
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:377
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
Definition gfx_type.h:387
@ TC_NO_SHADE
Do not add shading to this text colour.
Definition gfx_type.h:318
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:937
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1529
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.
std::span< const Action5Type > GetAction5Types()
Get list of all action 5 types.
Definition newgrf.cpp:6759
GrfSpecFeature
Definition newgrf.h:69
@ GSF_INVALID
An invalid spec feature.
Definition newgrf.h:97
@ GSF_FAKE_END
End of the fake features.
Definition newgrf.h:95
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 ZOOM_LVL_BEGIN to ZOOM_LVL_END).
@ 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:85
Road vehicle states.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:57
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(T &dst, const char *str, const char *last, StringValidationSettings settings)
Copies the valid (UTF-8) characters from str up to last to the dst.
Definition string.cpp:126
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
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:163
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition strings.cpp:420
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition strings.cpp:466
void SetDParamMaxDigits(size_t n, uint count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition strings.cpp:202
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:21
SpriteID sprite_base
Load the sprites starting from this sprite.
Definition newgrf_act5.h:23
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
StringID name
Name of this type of cargo.
Definition cargotype.h:91
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:156
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.
NIOffsetProc * offset_proc
Callback proc to get the actual variable address in memory.
std::string_view name
The human readable name of the callback.
uint16_t cb_id
The number of the callback.
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.
uint8_t read_size
The number of bytes (i.e. byte, word, dword etc) to read.
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.
uint8_t read_size
Number of bytes (i.e. byte, word, dword etc)
std::string_view name
A (human readable) name for the property.
NIOffsetProc * offset_proc
Callback proc to get the actual variable address in memory.
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.
void DrawVehicleChainWidget(const Rect &r) const
Helper function to draw the vehicle chain widget.
void SetStringParameters(WidgetID widget) const override
Initialize string parameters for a 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.
std::vector< SpriteID > sprites
Sprites found.
Coordinates of a point in 2D.
Tindex index
Index of this pool item.
static Titem * Get(auto index)
Returns Titem with given index.
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.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
static T * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
Window used for aligning sprites.
void SetStringParameters(WidgetID widget) const override
Initialize string parameters for a widget.
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.
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
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:168
Number to differentiate different windows of the same class.
Data structure for an opened window.
Definition window_gui.h:272
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1730
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3157
void RaiseWidget(WidgetID widget_index)
Marks a widget as raised.
Definition window_gui.h:468
virtual void ShowNewGRFInspectWindow() const
Show the NewGRF inspection window.
Definition window_gui.h:854
ResizeInfo resize
Resize information.
Definition window_gui.h:313
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition window_gui.h:514
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1720
void SetWidgetsLoweredState(bool lowered_stat, Args... widgets)
Sets the lowered/raised status of a list of widgets.
Definition window_gui.h:525
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:440
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:969
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
Definition window_gui.h:459
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:311
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:380
int height
Height of the window (number of pixels down in y direction)
Definition window_gui.h:311
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:310
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:301
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:283
static RectPadding ScaleGUITrad(const RectPadding &r)
Scale a RectPadding to GUI zoom level.
Definition widget.cpp:35
@ 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:48
@ NWID_SPACER
Invisible widget that takes some space.
Definition widget_type.h:70
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:46
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:41
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:57
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:50
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:55
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:52
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:76
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:68
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:60
@ WWT_TEXTBTN_2
(Toggle) Button with diff text when clicked
Definition widget_type.h:47
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:39
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:59
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:56
@ NWID_HORIZONTAL_LTR
Horizontal container that doesn't change the order of the widgets for RTL languages.
Definition widget_type.h:67
@ 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:22
@ AWV_INCREASE
Arrow to the right or in case of RTL to the left.
Definition widget_type.h:23
@ RWV_HIDE_BEVEL
Bevel of resize box is hidden.
Definition widget_type.h:31
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:1137
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:3217
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:145
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 > ZOOM_LVL_MIN) When shifting right,...
Definition zoom_func.h:22
int UnScaleByZoom(int value, ZoomLevel zoom)
Scale by zoom level, usually shift right (when zoom > ZOOM_LVL_MIN) When shifting right,...
Definition zoom_func.h:34
ZoomLevel
All zoom levels we know.
Definition zoom_type.h:16
@ ZOOM_LVL_NORMAL
The normal zoom level.
Definition zoom_type.h:21
@ ZOOM_LVL_BEGIN
Begin for iteration.
Definition zoom_type.h:18
@ ZOOM_LVL_OUT_4X
Zoomed 4 times out.
Definition zoom_type.h:23
@ ZOOM_LVL_OUT_2X
Zoomed 2 times out.
Definition zoom_type.h:22
@ ZOOM_LVL_OUT_8X
Zoomed 8 times out.
Definition zoom_type.h:24
@ ZOOM_LVL_IN_2X
Zoomed 2 times in.
Definition zoom_type.h:20
@ ZOOM_LVL_END
End for iteration.
Definition zoom_type.h:25
@ ZOOM_LVL_IN_4X
Zoomed 4 times in.
Definition zoom_type.h:19