OpenTTD Source 20260421-master-gc2fbc6fdeb
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
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 (to_underlying(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
167 virtual std::string GetName(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};
213
214
216struct NIFeature {
217 std::span<const NIProperty> properties;
218 std::span<const NICallback> callbacks;
219 std::span<const NIVariable> variables;
220 std::unique_ptr<const NIHelper> helper;
221};
222
223/* Load all the NewGRF debug data; externalised as it is just a huge bunch of tables. */
225
231static inline GrfSpecFeature GetFeatureNum(uint window_number)
232{
233 return (GrfSpecFeature)GB(window_number, 24, 8);
234}
235
241static inline const NIFeature *GetFeature(uint window_number)
242{
243 GrfSpecFeature idx = GetFeatureNum(window_number);
244 return idx < GrfSpecFeature::FakeEnd ? _nifeatures[idx] : nullptr;
245}
246
253static inline const NIHelper &GetFeatureHelper(uint window_number)
254{
255 return *GetFeature(window_number)->helper;
256}
257
259struct NewGRFInspectWindow : Window {
262
264 uint32_t caller_grfid = 0;
265
267 uint chain_index = 0;
268
271
272 Scrollbar *vscroll = nullptr;
273
279 static bool HasVariableParameter(uint variable)
280 {
281 return IsInsideBS(variable, 0x60, 0x20);
282 }
283
288 void SetCallerGRFID(uint32_t grfid)
289 {
290 this->caller_grfid = grfid;
291 this->SetDirty();
292 }
293
298 bool HasChainIndex() const
299 {
302 }
303
309 {
310 switch (GetFeatureNum(this->window_number)) {
313 case GrfSpecFeature::Ships: return VEH_SHIP;
315 default: NOT_REACHED();
316 }
317 }
318
323 uint GetFeatureIndex() const
324 {
325 uint index = ::GetFeatureIndex(this->window_number);
326 if (this->chain_index > 0) {
327 assert(this->HasChainIndex());
328 const Vehicle *v = Vehicle::Get(index);
329 v = v->Move(this->chain_index);
330 if (v != nullptr) index = v->index.base();
331 }
332 return index;
333 }
334
339 {
340 if (this->chain_index == 0) return;
341
342 assert(this->HasChainIndex());
343
345 v = v->Move(this->chain_index);
346 if (v == nullptr) this->chain_index = 0;
347 }
348
350 {
351 this->CreateNestedTree();
352 this->vscroll = this->GetScrollbar(WID_NGRFI_SCROLLBAR);
353 this->FinishInitNested(wno);
354
355 this->vscroll->SetCount(0);
356 this->SetWidgetDisabledState(WID_NGRFI_PARENT, GetFeatureHelper(this->window_number).GetParent(this->GetFeatureIndex()) == UINT32_MAX);
357
358 this->OnInvalidateData(0, true);
359 }
360
361 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
362 {
363 if (widget != WID_NGRFI_CAPTION) return this->Window::GetWidgetString(widget, stringid);
364
366 }
367
368 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
369 {
370 switch (widget) {
372 assert(this->HasChainIndex());
373 size.height = std::max(size.height, GetVehicleImageCellSize(this->GetVehicleTypeForWindow(), EIT_IN_DEPOT).height + 2 + WidgetDimensions::scaled.bevel.Vertical());
374 break;
375
377 fill.height = resize.height = std::max(11, GetCharacterHeight(FontSize::Normal) + WidgetDimensions::scaled.vsep_normal);
378 resize.width = 1;
379
380 size.height = 5 * resize.height + WidgetDimensions::scaled.frametext.Vertical();
381 break;
382 }
383 }
384
391 void DrawString(const Rect &r, int offset, const std::string &string) const
392 {
393 offset -= this->vscroll->GetPosition();
394 if (offset < 0 || offset >= this->vscroll->GetCapacity()) return;
395
396 ::DrawString(r.Shrink(WidgetDimensions::scaled.frametext).Shrink(0, offset * this->resize.step_height, 0, 0), string, TC_BLACK);
397 }
398
403 void DrawVehicleChainWidget(const Rect &r) const
404 {
405 const Vehicle *v = Vehicle::Get(this->GetFeatureIndex());
406 int total_width = 0;
407 int sel_start = 0;
408 int sel_end = 0;
409 for (const Vehicle *u = v->First(); u != nullptr; u = u->Next()) {
410 if (u == v) sel_start = total_width;
411 switch (u->type) {
412 case VEH_TRAIN: total_width += Train::From(u)->GetDisplayImageWidth(); break;
413 case VEH_ROAD: total_width += RoadVehicle::From(u)->GetDisplayImageWidth(); break;
414 default: NOT_REACHED();
415 }
416 if (u == v) sel_end = total_width;
417 }
418
420 int width = br.Width();
421 int skip = 0;
422 if (total_width > width) {
423 int sel_center = (sel_start + sel_end) / 2;
424 if (sel_center > width / 2) skip = std::min(total_width - width, sel_center - width / 2);
425 }
426
428 int y = CentreBounds(br.top, br.bottom, h);
429 DrawVehicleImage(v->First(), br, VehicleID::Invalid(), EIT_IN_DETAILS, skip);
430
431 /* Highlight the articulated part (this is different to the whole-vehicle highlighting of DrawVehicleImage */
432 if (_current_text_dir == TD_RTL) {
433 DrawFrameRect(r.right - sel_end + skip, y, r.right - sel_start + skip, y + h, Colours::White, FrameFlag::BorderOnly);
434 } else {
435 DrawFrameRect(r.left + sel_start - skip, y, r.left + sel_end - skip, y + h, Colours::White, FrameFlag::BorderOnly);
436 }
437 }
438
439 std::string GetPropertyString(const NIProperty &nip, uint value) const
440 {
441 switch (nip.type) {
442 case NIT_INT: return GetString(STR_JUST_INT, value);
443 case NIT_CARGO: return GetString(IsValidCargoType(value) ? CargoSpec::Get(value)->name : STR_QUANTITY_N_A);
444 default: NOT_REACHED();
445 }
446 }
447
452 void DrawMainPanelWidget(const Rect &r) const
453 {
454 uint index = this->GetFeatureIndex();
455 const NIFeature *nif = GetFeature(this->window_number);
456 const NIHelper &nih = *nif->helper;
457 const void *base = nih.GetInstance(index);
458 const void *base_spec = nih.GetSpec(index);
459
460 uint i = 0;
461 if (!nif->variables.empty()) {
462 this->DrawString(r, i++, "Variables:");
463 for (const NIVariable &niv : nif->variables) {
464 bool avail = true;
465 uint param = HasVariableParameter(niv.var) ? NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][niv.var - 0x60] : 0;
466 uint value = nih.Resolve(index, niv.var, param, avail);
467
468 if (!avail) continue;
469
470 if (HasVariableParameter(niv.var)) {
471 this->DrawString(r, i++, fmt::format(" {:02x}[{:02x}]: {:08x} ({})", niv.var, param, value, niv.name));
472 } else {
473 this->DrawString(r, i++, fmt::format(" {:02x}: {:08x} ({})", niv.var, value, niv.name));
474 }
475 }
476 }
477
478 auto psa = nih.GetPSA(index, this->caller_grfid);
479 if (!psa.empty()) {
480 if (nih.PSAWithParameter()) {
481 this->DrawString(r, i++, fmt::format("Persistent storage [{:08X}]:", std::byteswap(this->caller_grfid)));
482 } else {
483 this->DrawString(r, i++, "Persistent storage:");
484 }
485 assert(psa.size() % 4 == 0);
486 for (size_t j = 0; j < psa.size(); j += 4) {
487 this->DrawString(r, i++, fmt::format(" {}: {} {} {} {}", j, psa[j], psa[j + 1], psa[j + 2], psa[j + 3]));
488 }
489 }
490
491 auto badges = nih.GetBadges(index);
492 if (!badges.empty()) {
493 this->DrawString(r, i++, "Badges:");
494 for (const BadgeID &badge_index : badges) {
495 const Badge *badge = GetBadge(badge_index);
496 this->DrawString(r, i++, fmt::format(" {}: {}", StrMakeValid(badge->label), GetString(badge->name)));
497 }
498 }
499
500 if (!nif->properties.empty()) {
501 this->DrawString(r, i++, "Properties:");
502 for (const NIProperty &nip : nif->properties) {
503 uint32_t value = nip.read_proc(base);
504 this->DrawString(r, i++, fmt::format(" {:02x}: {} ({})", nip.prop, this->GetPropertyString(nip, value), nip.name));
505 }
506 }
507
508 if (!nif->callbacks.empty()) {
509 this->DrawString(r, i++, "Callbacks:");
510 for (const NICallback &nic : nif->callbacks) {
511 if (!std::holds_alternative<std::monostate>(nic.cb_bit)) {
512 uint32_t value = nic.read_proc(base_spec);
513
514 struct visitor {
515 uint32_t value;
516
517 bool operator()(const std::monostate &) { return false; }
518 bool operator()(const VehicleCallbackMask &bit) { return static_cast<VehicleCallbackMasks>(this->value).Test(bit); }
519 bool operator()(const StationCallbackMask &bit) { return static_cast<StationCallbackMasks>(this->value).Test(bit); }
520 bool operator()(const RoadStopCallbackMask &bit) { return static_cast<RoadStopCallbackMasks>(this->value).Test(bit); }
521 bool operator()(const HouseCallbackMask &bit) { return static_cast<HouseCallbackMasks>(this->value).Test(bit); }
522 bool operator()(const CanalCallbackMask &bit) { return static_cast<CanalCallbackMasks>(this->value).Test(bit); }
523 bool operator()(const CargoCallbackMask &bit) { return static_cast<CargoCallbackMasks>(this->value).Test(bit); }
524 bool operator()(const IndustryCallbackMask &bit) { return static_cast<IndustryCallbackMasks>(this->value).Test(bit); }
525 bool operator()(const IndustryTileCallbackMask &bit) { return static_cast<IndustryTileCallbackMasks>(this->value).Test(bit); }
526 bool operator()(const ObjectCallbackMask &bit) { return static_cast<ObjectCallbackMasks>(this->value).Test(bit); }
527 bool operator()(const AirportTileCallbackMask &bit) { return static_cast<AirportTileCallbackMasks>(this->value).Test(bit); }
528 };
529
530 if (!std::visit(visitor{value}, nic.cb_bit)) continue;
531 this->DrawString(r, i++, fmt::format(" {:03x}: {}", nic.cb_id, nic.name));
532 } else {
533 this->DrawString(r, i++, fmt::format(" {:03x}: {} (unmasked)", nic.cb_id, nic.name));
534 }
535 }
536 }
537
538 /* Not nice and certainly a hack, but it beats duplicating
539 * this whole function just to count the actual number of
540 * elements. Especially because they need to be redrawn. */
541 const_cast<NewGRFInspectWindow*>(this)->vscroll->SetCount(i);
542 }
543
544 void DrawWidget(const Rect &r, WidgetID widget) const override
545 {
546 switch (widget) {
548 this->DrawVehicleChainWidget(r);
549 break;
550
552 this->DrawMainPanelWidget(r);
553 break;
554 }
555 }
556
557 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
558 {
559 switch (widget) {
560 case WID_NGRFI_PARENT: {
561 const NIHelper &nih = GetFeatureHelper(this->window_number);
562 uint index = nih.GetParent(this->GetFeatureIndex());
563 ::ShowNewGRFInspectWindow(GetFeatureNum(index), ::GetFeatureIndex(index), nih.GetGRFID(this->GetFeatureIndex()));
564 break;
565 }
566
568 if (this->chain_index > 0) {
569 this->chain_index--;
570 this->InvalidateData();
571 }
572 break;
573
575 if (this->HasChainIndex()) {
576 uint index = this->GetFeatureIndex();
577 Vehicle *v = Vehicle::Get(index);
578 if (v != nullptr && v->Next() != nullptr) {
579 this->chain_index++;
580 this->InvalidateData();
581 }
582 }
583 break;
584
585 case WID_NGRFI_MAINPANEL: {
586 /* Does this feature have variables? */
587 const NIFeature *nif = GetFeature(this->window_number);
588 if (nif->variables.empty()) return;
589
590 /* Get the line, make sure it's within the boundaries. */
591 int32_t line = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NGRFI_MAINPANEL, WidgetDimensions::scaled.frametext.top);
592 if (line == INT32_MAX) return;
593
594 /* Find the variable related to the line */
595 for (const NIVariable &niv : nif->variables) {
596 if (--line != 0) continue; // 0 because of the "Variables:" line
597
598 if (!HasVariableParameter(niv.var)) break;
599
600 this->current_edit_param = niv.var;
601 ShowQueryString({}, STR_NEWGRF_INSPECT_QUERY_CAPTION, 9, this, CS_HEXADECIMAL, {});
602 }
603 }
604 }
605 }
606
607 void OnQueryTextFinished(std::optional<std::string> str) override
608 {
609 if (!str.has_value()) return;
610
611 auto val = ParseInteger<uint32_t>(*str, 16, true);
612 if (!val.has_value()) return;
613 NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][this->current_edit_param - 0x60] = *val;
614 this->SetDirty();
615 }
616
617 void OnResize() override
618 {
619 this->vscroll->SetCapacityFromWidget(this, WID_NGRFI_MAINPANEL, WidgetDimensions::scaled.frametext.Vertical());
620 }
621
627 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
628 {
629 if (!gui_scope) return;
630 if (this->HasChainIndex()) {
631 this->ValidateChainIndex();
632 this->SetWidgetDisabledState(WID_NGRFI_VEH_PREV, this->chain_index == 0);
634 this->SetWidgetDisabledState(WID_NGRFI_VEH_NEXT, v == nullptr || v->Next() == nullptr);
635 }
636 }
637};
638
639static constexpr std::initializer_list<NWidgetPart> _nested_newgrf_inspect_chain_widgets = {
642 NWidget(WWT_CAPTION, Colours::Grey, WID_NGRFI_CAPTION), SetStringTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
646 EndContainer(),
652 EndContainer(),
653 EndContainer(),
659 EndContainer(),
660 EndContainer(),
661};
662
663static constexpr std::initializer_list<NWidgetPart> _nested_newgrf_inspect_widgets = {
666 NWidget(WWT_CAPTION, Colours::Grey, WID_NGRFI_CAPTION), SetStringTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
667 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_NGRFI_PARENT), SetStringTip(STR_NEWGRF_INSPECT_PARENT_BUTTON, STR_NEWGRF_INSPECT_PARENT_TOOLTIP),
671 EndContainer(),
677 EndContainer(),
678 EndContainer(),
679};
680
681static WindowDesc _newgrf_inspect_chain_desc(
682 WDP_AUTO, "newgrf_inspect_chain", 400, 300,
684 {},
685 _nested_newgrf_inspect_chain_widgets
686);
687
688static WindowDesc _newgrf_inspect_desc(
689 WDP_AUTO, "newgrf_inspect", 400, 300,
691 {},
692 _nested_newgrf_inspect_widgets
693);
694
704void ShowNewGRFInspectWindow(GrfSpecFeature feature, uint index, const uint32_t grfid)
705{
706 if (!IsNewGRFInspectable(feature, index)) return;
707
708 WindowNumber wno = GetInspectWindowNumber(feature, index);
709 WindowDesc &desc = (feature == GrfSpecFeature::Trains || feature == GrfSpecFeature::RoadVehicles) ? _newgrf_inspect_chain_desc : _newgrf_inspect_desc;
711 w->SetCallerGRFID(grfid);
712}
713
723{
724 if (feature == GrfSpecFeature::Invalid) return;
725
726 WindowNumber wno = GetInspectWindowNumber(feature, index);
728}
729
739{
740 if (feature == GrfSpecFeature::Invalid) return;
741
742 WindowNumber wno = GetInspectWindowNumber(feature, index);
744
745 /* Reinitialise the land information window to remove the "debug" sprite if needed.
746 * Note: Since we might be called from a command here, it is important to not execute
747 * the invalidation immediately. The landinfo window tests commands itself. */
749}
750
760bool IsNewGRFInspectable(GrfSpecFeature feature, uint index)
761{
762 const NIFeature *nif = GetFeature(GetInspectWindowNumber(feature, index));
763 if (nif == nullptr) return false;
764 return nif->helper->IsInspectable(index);
765}
766
792
793
794/**** Sprite Aligner ****/
795
797struct SpriteAlignerWindow : Window {
798 typedef std::pair<int16_t, int16_t> XyOffs;
799
801 Scrollbar *vscroll = nullptr;
802 std::map<SpriteID, XyOffs> offs_start_map{};
803
804 static inline ZoomLevel zoom = ZoomLevel::End;
805 static bool centre;
806 static bool crosshair;
807 const Action5Type *act5_type = nullptr;
808
809 SpriteAlignerWindow(WindowDesc &desc, WindowNumber wno) : Window(desc)
810 {
811 /* On first opening, set initial zoom to current zoom level. */
812 if (SpriteAlignerWindow::zoom == ZoomLevel::End) SpriteAlignerWindow::zoom = _gui_zoom;
813 SpriteAlignerWindow::zoom = Clamp(SpriteAlignerWindow::zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max);
814
815 /* Oh yes, we assume there is at least one normal sprite! */
816 while (GetSpriteType(this->current_sprite) != SpriteType::Normal) this->current_sprite++;
817 this->SelectAction5Type();
818
819 this->CreateNestedTree();
820 this->vscroll = this->GetScrollbar(WID_SA_SCROLLBAR);
821 this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.size());
822 this->FinishInitNested(wno);
823
824 this->SetWidgetLoweredState(WID_SA_CENTRE, SpriteAlignerWindow::centre);
825 this->SetWidgetLoweredState(WID_SA_CROSSHAIR, SpriteAlignerWindow::crosshair);
826
827 this->InvalidateData(0, true);
828 }
829
830 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
831 {
832 const Sprite *spr = GetSprite(this->current_sprite, SpriteType::Normal);
833 switch (widget) {
834 case WID_SA_CAPTION:
835 if (this->act5_type != nullptr) {
836 return GetString(STR_SPRITE_ALIGNER_CAPTION_ACTION5,
837 this->act5_type - GetAction5Types().data(),
838 this->current_sprite - this->act5_type->sprite_base,
839 GetOriginFile(this->current_sprite)->GetSimplifiedFilename(),
840 GetSpriteLocalID(this->current_sprite));
841 }
842 if (this->current_sprite < SPR_OPENTTD_BASE) {
843 return GetString(STR_SPRITE_ALIGNER_CAPTION_ACTIONA,
844 this->current_sprite,
845 GetOriginFile(this->current_sprite)->GetSimplifiedFilename(),
846 GetSpriteLocalID(this->current_sprite));
847 }
848 return GetString(STR_SPRITE_ALIGNER_CAPTION_NO_ACTION,
849 GetOriginFile(this->current_sprite)->GetSimplifiedFilename(),
850 GetSpriteLocalID(this->current_sprite));
851
853 return GetString(STR_SPRITE_ALIGNER_OFFSETS_ABS, UnScaleByZoom(spr->x_offs, SpriteAlignerWindow::zoom), UnScaleByZoom(spr->y_offs, SpriteAlignerWindow::zoom));
854
855 case WID_SA_OFFSETS_REL: {
856 /* Relative offset is new absolute offset - starting absolute offset.
857 * Show 0, 0 as the relative offsets if entry is not in the map (meaning they have not been changed yet).
858 */
859 const auto key_offs_pair = this->offs_start_map.find(this->current_sprite);
860 if (key_offs_pair != this->offs_start_map.end()) {
861 return GetString(STR_SPRITE_ALIGNER_OFFSETS_REL,
862 UnScaleByZoom(spr->x_offs - key_offs_pair->second.first, SpriteAlignerWindow::zoom),
863 UnScaleByZoom(spr->y_offs - key_offs_pair->second.second, SpriteAlignerWindow::zoom));
864 }
865
866 return GetString(STR_SPRITE_ALIGNER_OFFSETS_REL, 0, 0);
867 }
868
869 default:
870 return this->Window::GetWidgetString(widget, stringid);
871 }
872 }
873
874 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
875 {
876 switch (widget) {
877 case WID_SA_SPRITE:
878 size.height = ScaleGUITrad(200);
879 break;
880
881 case WID_SA_LIST: {
882 Dimension d = {};
883 for (const auto &spritefile : GetCachedSpriteFiles()) {
884 d = maxdim(d, GetStringBoundingBox(GetString(STR_SPRITE_ALIGNER_SPRITE, spritefile->GetSimplifiedFilename(), GetParamMaxDigits(6))));
885 }
886 size.width = d.width + padding.width;
887 fill.height = resize.height = GetCharacterHeight(FontSize::Normal) + padding.height;
888 resize.width = 1;
889 break;
890 }
891
892 default:
893 break;
894 }
895 }
896
897 void DrawWidget(const Rect &r, WidgetID widget) const override
898 {
899 switch (widget) {
900 case WID_SA_SPRITE: {
901 /* Center the sprite ourselves */
902 const Sprite *spr = GetSprite(this->current_sprite, SpriteType::Normal);
904 int x;
905 int y;
906 if (SpriteAlignerWindow::centre) {
907 x = -UnScaleByZoom(spr->x_offs, SpriteAlignerWindow::zoom) + (ir.Width() - UnScaleByZoom(spr->width, SpriteAlignerWindow::zoom)) / 2;
908 y = -UnScaleByZoom(spr->y_offs, SpriteAlignerWindow::zoom) + (ir.Height() - UnScaleByZoom(spr->height, SpriteAlignerWindow::zoom)) / 2;
909 } else {
910 x = ir.Width() / 2;
911 y = ir.Height() / 2;
912 }
913
914 DrawPixelInfo new_dpi;
915 if (!FillDrawPixelInfo(&new_dpi, ir)) break;
916 AutoRestoreBackup dpi_backup(_cur_dpi, &new_dpi);
917
918 DrawSprite(this->current_sprite, PAL_NONE, x, y, nullptr, SpriteAlignerWindow::zoom);
919
920 Rect outline = {0, 0, UnScaleByZoom(spr->width, SpriteAlignerWindow::zoom) - 1, UnScaleByZoom(spr->height, SpriteAlignerWindow::zoom) - 1};
921 outline = outline.Translate(x + UnScaleByZoom(spr->x_offs, SpriteAlignerWindow::zoom), y + UnScaleByZoom(spr->y_offs, SpriteAlignerWindow::zoom));
922 DrawRectOutline(outline.Expand(1), PC_LIGHT_BLUE, 1, 1);
923
924 if (SpriteAlignerWindow::crosshair) {
925 GfxDrawLine(x, 0, x, ir.Height() - 1, PC_WHITE, 1, 1);
926 GfxDrawLine(0, y, ir.Width() - 1, y, PC_WHITE, 1, 1);
927 }
928 break;
929 }
930
931 case WID_SA_LIST: {
932 /* Don't redraw sprite list while it is still being filled by picker. */
933 if (_newgrf_debug_sprite_picker.mode == SPM_REDRAW) break;
934
935 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget);
936 int step_size = nwid->resize_y;
937
939
940 Rect ir = r.Shrink(WidgetDimensions::scaled.matrix);
941 auto [first, last] = this->vscroll->GetVisibleRangeIterators(list);
942 for (auto it = first; it != last; ++it) {
943 const SpriteFile *file = GetOriginFile(*it);
944 if (file == nullptr) {
945 DrawString(ir, GetString(STR_JUST_COMMA, *it), *it == this->current_sprite ? TC_WHITE : (TC_GREY | TC_NO_SHADE), SA_RIGHT | SA_FORCE);
946 } else {
947 DrawString(ir, GetString(STR_SPRITE_ALIGNER_SPRITE, file->GetSimplifiedFilename(), GetSpriteLocalID(*it)), *it == this->current_sprite ? TC_WHITE : TC_BLACK);
948 }
949 ir.top += step_size;
950 }
951 break;
952 }
953 }
954 }
955
956 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
957 {
958 switch (widget) {
959 case WID_SA_PREVIOUS:
960 do {
961 this->current_sprite = (this->current_sprite == 0 ? GetMaxSpriteID() : this->current_sprite) - 1;
962 } while (GetSpriteType(this->current_sprite) != SpriteType::Normal);
963 this->SelectAction5Type();
964 this->SetDirty();
965 break;
966
967 case WID_SA_GOTO:
968 ShowQueryString({}, STR_SPRITE_ALIGNER_GOTO_CAPTION, 7, this, CS_NUMERAL, {});
969 break;
970
971 case WID_SA_NEXT:
972 do {
973 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
974 } while (GetSpriteType(this->current_sprite) != SpriteType::Normal);
975 this->SelectAction5Type();
976 this->SetDirty();
977 break;
978
979 case WID_SA_PICKER:
981 _newgrf_debug_sprite_picker.mode = SPM_WAIT_CLICK;
982 this->SetDirty();
983 break;
984
985 case WID_SA_LIST: {
986 auto it = this->vscroll->GetScrolledItemFromWidget(_newgrf_debug_sprite_picker.sprites, pt.y, this, widget);
987 if (it != _newgrf_debug_sprite_picker.sprites.end()) {
988 SpriteID spr = *it;
989 if (GetSpriteType(spr) == SpriteType::Normal) this->current_sprite = spr;
990 }
991 this->SelectAction5Type();
992 this->SetDirty();
993 break;
994 }
995
996 case WID_SA_UP:
997 case WID_SA_DOWN:
998 case WID_SA_LEFT:
999 case WID_SA_RIGHT: {
1000 /*
1001 * Yes... this is a hack.
1002 *
1003 * No... I don't think it is useful to make this less of a hack.
1004 *
1005 * If you want to align sprites, you just need the number. Generally
1006 * the sprite caches are big enough to not remove the sprite from the
1007 * cache. If that's not the case, just let the NewGRF developer
1008 * increase the cache size instead of storing thousands of offsets
1009 * for the incredibly small chance that it's actually going to be
1010 * used by someone and the sprite cache isn't big enough for that
1011 * particular NewGRF developer.
1012 */
1013 Sprite *spr = const_cast<Sprite *>(GetSprite(this->current_sprite, SpriteType::Normal));
1014
1015 /* Remember the original offsets of the current sprite, if not already in mapping. */
1016 if (this->offs_start_map.count(this->current_sprite) == 0) {
1017 this->offs_start_map[this->current_sprite] = XyOffs(spr->x_offs, spr->y_offs);
1018 }
1019 int amt = ScaleByZoom(_ctrl_pressed ? 8 : 1, SpriteAlignerWindow::zoom);
1020 switch (widget) {
1021 /* Move eight units at a time if ctrl is pressed. */
1022 case WID_SA_UP: spr->y_offs -= amt; break;
1023 case WID_SA_DOWN: spr->y_offs += amt; break;
1024 case WID_SA_LEFT: spr->x_offs -= amt; break;
1025 case WID_SA_RIGHT: spr->x_offs += amt; break;
1026 }
1027 /* Of course, we need to redraw the sprite, but where is it used?
1028 * Everywhere is a safe bet. */
1030 break;
1031 }
1032
1033 case WID_SA_RESET_REL:
1034 /* Reset the starting offsets for the current sprite. */
1035 this->offs_start_map.erase(this->current_sprite);
1036 this->SetDirty();
1037 break;
1038
1039 case WID_SA_CENTRE:
1040 SpriteAlignerWindow::centre = !SpriteAlignerWindow::centre;
1041 this->SetWidgetLoweredState(widget, SpriteAlignerWindow::centre);
1042 this->SetDirty();
1043 break;
1044
1045 case WID_SA_CROSSHAIR:
1046 SpriteAlignerWindow::crosshair = !SpriteAlignerWindow::crosshair;
1047 this->SetWidgetLoweredState(widget, SpriteAlignerWindow::crosshair);
1048 this->SetDirty();
1049 break;
1050
1051 default:
1053 SpriteAlignerWindow::zoom = static_cast<ZoomLevel>(widget - WID_SA_ZOOM);
1054 this->InvalidateData(0, true);
1055 }
1056 break;
1057 }
1058 }
1059
1060 void OnQueryTextFinished(std::optional<std::string> str) override
1061 {
1062 if (!str.has_value()) return;
1063
1064 auto value = ParseInteger(*str, 10, true);
1065 if (!value.has_value()) return;
1066 this->current_sprite = *value;
1067 if (this->current_sprite >= GetMaxSpriteID()) this->current_sprite = 0;
1068 while (GetSpriteType(this->current_sprite) != SpriteType::Normal) {
1069 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
1070 }
1071 this->SelectAction5Type();
1072 this->SetDirty();
1073 }
1074
1080 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1081 {
1082 if (!gui_scope) return;
1083 if (data == 1) {
1084 /* Sprite picker finished */
1086 this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.size());
1087 }
1088
1089 SpriteAlignerWindow::zoom = Clamp(SpriteAlignerWindow::zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max);
1090 for (ZoomLevel z = ZoomLevel::Begin; z < ZoomLevel::End; z++) {
1091 this->SetWidgetsDisabledState(z < _settings_client.gui.zoom_min || z > _settings_client.gui.zoom_max, WID_SA_ZOOM + to_underlying(z));
1092 this->SetWidgetsLoweredState(SpriteAlignerWindow::zoom == z, WID_SA_ZOOM + to_underlying(z));
1093 }
1094 }
1095
1096 void OnResize() override
1097 {
1098 this->vscroll->SetCapacityFromWidget(this, WID_SA_LIST);
1099 }
1100
1101private:
1102 void SelectAction5Type()
1103 {
1104 const auto act5types = GetAction5Types();
1105 for (auto it = std::begin(act5types); it != std::end(act5types); ++it) {
1106 if (it->sprite_base <= this->current_sprite && this->current_sprite < it->sprite_base + it->max_sprites) {
1107 this->act5_type = &*it;
1108 return;
1109 }
1110 }
1111 this->act5_type = nullptr;
1112 }
1113};
1114
1115bool SpriteAlignerWindow::centre = true;
1116bool SpriteAlignerWindow::crosshair = true;
1117
1118static constexpr std::initializer_list<NWidgetPart> _nested_sprite_aligner_widgets = {
1124 EndContainer(),
1129 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SA_PREVIOUS), SetStringTip(STR_SPRITE_ALIGNER_PREVIOUS_BUTTON, STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
1130 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SA_GOTO), SetStringTip(STR_SPRITE_ALIGNER_GOTO_BUTTON, STR_SPRITE_ALIGNER_GOTO_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
1131 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SA_NEXT), SetStringTip(STR_SPRITE_ALIGNER_NEXT_BUTTON, STR_SPRITE_ALIGNER_NEXT_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
1132 EndContainer(),
1134 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1135 NWidget(WWT_PUSHIMGBTN, Colours::Grey, WID_SA_UP), SetSpriteTip(SPR_ARROW_UP, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1136 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1137 EndContainer(),
1140 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1141 NWidget(WWT_PUSHIMGBTN, Colours::Grey, WID_SA_LEFT), SetSpriteTip(SPR_ARROW_LEFT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1142 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1143 EndContainer(),
1144 NWidget(WWT_PANEL, Colours::DarkBlue, WID_SA_SPRITE), SetToolTip(STR_SPRITE_ALIGNER_SPRITE_TOOLTIP), SetResize(1, 1), SetFill(1, 1),
1145 EndContainer(),
1147 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1148 NWidget(WWT_PUSHIMGBTN, Colours::Grey, WID_SA_RIGHT), SetSpriteTip(SPR_ARROW_RIGHT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1149 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1150 EndContainer(),
1151 EndContainer(),
1153 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1154 NWidget(WWT_PUSHIMGBTN, Colours::Grey, WID_SA_DOWN), SetSpriteTip(SPR_ARROW_DOWN, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1155 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1156 EndContainer(),
1160 NWidget(WWT_TEXTBTN_2, Colours::Grey, WID_SA_CENTRE), SetStringTip(STR_SPRITE_ALIGNER_CENTRE_OFFSET), SetFill(1, 0), SetResize(1, 0),
1161 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SA_RESET_REL), SetStringTip(STR_SPRITE_ALIGNER_RESET_BUTTON, STR_SPRITE_ALIGNER_RESET_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
1162 NWidget(WWT_TEXTBTN, Colours::Grey, WID_SA_CROSSHAIR), SetStringTip(STR_SPRITE_ALIGNER_CROSSHAIR), SetFill(1, 0), SetResize(1, 0),
1163 EndContainer(),
1164 EndContainer(),
1166 NWidget(WWT_TEXTBTN, Colours::Grey, WID_SA_PICKER), SetStringTip(STR_SPRITE_ALIGNER_PICKER_BUTTON, STR_SPRITE_ALIGNER_PICKER_TOOLTIP), SetFill(1, 0),
1170 EndContainer(),
1172 NWidget(WWT_TEXTBTN, Colours::Grey, WID_SA_ZOOM + to_underlying(ZoomLevel::In4x)), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_MIN), SetFill(1, 0),
1173 NWidget(WWT_TEXTBTN, Colours::Grey, WID_SA_ZOOM + to_underlying(ZoomLevel::In2x)), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_IN_2X), SetFill(1, 0),
1174 NWidget(WWT_TEXTBTN, Colours::Grey, WID_SA_ZOOM + to_underlying(ZoomLevel::Normal)), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_NORMAL), SetFill(1, 0),
1175 NWidget(WWT_TEXTBTN, Colours::Grey, WID_SA_ZOOM + to_underlying(ZoomLevel::Out2x)), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X), SetFill(1, 0),
1176 NWidget(WWT_TEXTBTN, Colours::Grey, WID_SA_ZOOM + to_underlying(ZoomLevel::Out4x)), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X), SetFill(1, 0),
1177 NWidget(WWT_TEXTBTN, Colours::Grey, WID_SA_ZOOM + to_underlying(ZoomLevel::Out8x)), SetStringTip(STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X), SetFill(1, 0),
1178 EndContainer(),
1179 EndContainer(),
1180 EndContainer(),
1182 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
1184 EndContainer(),
1185 EndContainer(),
1186};
1187
1188static WindowDesc _sprite_aligner_desc(
1189 WDP_AUTO, "sprite_aligner", 400, 300,
1191 {},
1192 _nested_sprite_aligner_widgets
1193);
1194
1199{
1200 AllocateWindowDescFront<SpriteAlignerWindow>(_sprite_aligner_desc, 0);
1201}
Class for backupping variables and making sure they are restored later.
static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr enable_if_t< is_integral_v< T >, T > byteswap(T x) noexcept
Custom implementation of std::byteswap; remove once we build with C++23.
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:108
std::string label
Label of badge.
StringID name
Short name.
A sort-of mixin that implements 'at(pos)' and 'operator[](pos)' only for a specific enum class.
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
Ensure the destructor of the sub classes are called as well.
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:2458
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:2532
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.
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:21
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:88
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:900
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:669
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:39
void DrawRectOutline(const Rect &r, PixelColour colour, int width, int dash)
Draw the outline of a Rect.
Definition gfx.cpp:464
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:1038
ZoomLevel _gui_zoom
GUI Zoom level.
Definition gfx.cpp:62
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:1573
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
@ Normal
The most basic (normal) sprite.
Definition gfx_type.h:358
@ Normal
Index of the normal font in the font tables.
Definition gfx_type.h:249
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:390
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
Definition gfx_type.h:400
@ White
White.
Definition gfx_type.h:300
@ Invalid
Invalid marker.
Definition gfx_type.h:302
@ DarkBlue
Dark blue.
Definition gfx_type.h:285
@ Grey
Grey.
Definition gfx_type.h:299
@ TC_NO_SHADE
Do not add shading to this text colour.
Definition gfx_type.h:331
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 SetResizeWidgetTypeTip(ResizeWidgetType widget_type, StringID tip)
Widget part function for setting the resize widget type 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 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 NWidget(WidgetType tp, Colours col, WidgetID idx=INVALID_WIDGET)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetArrowWidgetTypeTip(ArrowWidgetType 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:980
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1554
Base of all industries.
#define Point
Macro that prevents name conflicts between included headers.
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:72
@ RoadStops
Road stops feature.
Definition newgrf.h:93
@ RailTypes
Rail types feature.
Definition newgrf.h:89
@ Trains
Trains feature.
Definition newgrf.h:73
@ RoadVehicles
Road vehicles feature.
Definition newgrf.h:74
@ RoadTypes
Road types feature.
Definition newgrf.h:91
@ Invalid
An invalid spec feature.
Definition newgrf.h:103
@ Ships
Ships feature.
Definition newgrf.h:75
@ Houses
Houses feature.
Definition newgrf.h:80
@ FakeEnd
End of the fake features.
Definition newgrf.h:99
@ Stations
Stations feature.
Definition newgrf.h:77
@ Aircraft
Aircraft feature.
Definition newgrf.h:76
@ IndustryTiles
Industry tiles feature.
Definition newgrf.h:82
@ Objects
Objects feature.
Definition newgrf.h:88
@ AirportTiles
Airport tiles feature.
Definition newgrf.h:90
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.
NewGrfDebugSpritePicker _newgrf_debug_sprite_picker
The sprite picker.
Data 'tables' for NewGRF debugging.
static const EnumClassIndexContainer< std::array< const NIFeature *, to_underlying(GrfSpecFeature::FakeEnd)>, GrfSpecFeature > _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 constexpr PixelColour PC_WHITE
White palette colour.
static constexpr PixelColour 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:60
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
@ Rail
Railways/train station.
@ Bus
Road stop for busses.
@ Truck
Road stop for trucks.
@ Airport
Airports and heliports, excluding the ones on oil rigs.
Definition of base types and functions in a cross-platform compatible way.
static void StrMakeValid(Builder &builder, StringConsumer &consumer, StringValidationSettings settings)
Copies the valid (UTF-8) characters from consumer to the builder.
Definition string.cpp:119
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:424
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
uint64_t GetParamMaxDigits(uint count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:218
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:139
Dimensions (a width and height) of a rectangle in 2D.
Data about how and where to blit pixels.
Definition gfx_type.h:157
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.
Window used for inspecting NewGRFs.
static bool HasVariableParameter(uint variable)
Check whether the given variable has a parameter.
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.
static EnumClassIndexContainer< std::array< std::array< uint32_t, 0x20 >, to_underlying(GrfSpecFeature::FakeEnd)>, GrfSpecFeature > var60params
The value for the variable 60 parameters.
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.
VehicleType GetVehicleTypeForWindow() const
Get the vehicle type corresponding to the grf feature for this window.
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.
static Vehicle * Get(auto index)
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.
int GetDisplayImageWidth(Point *offset=nullptr) const
Get the width of a road vehicle image in the GUI.
static Train * From(Vehicle *v)
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.
uint16_t width
Width of the sprite.
uint16_t height
Height of the sprite.
int16_t y_offs
Number of pixels to shift the sprite downwards.
int16_t x_offs
Number of pixels to shift the sprite to the right.
int GetDisplayImageWidth(Point *offset=nullptr) const
Get the width of a train vehicle image in the GUI.
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:274
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1822
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing).
Definition window.cpp:3262
void RaiseWidget(WidgetID widget_index)
Marks a widget as raised.
Definition window_gui.h:470
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:518
virtual void ShowNewGRFInspectWindow() const
Show the NewGRF inspection window.
Definition window_gui.h:875
ResizeInfo resize
Resize information.
Definition window_gui.h:315
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition window_gui.h:516
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1812
void SetWidgetsLoweredState(bool lowered_stat, Args... widgets)
Sets the lowered/raised status of a list of widgets.
Definition window_gui.h:527
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:442
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition window.cpp:1846
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:990
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
Definition window_gui.h:461
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:327
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:382
int height
Height of the window (number of pixels down in y direction).
Definition window_gui.h:313
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:312
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:303
Stuff related to the text buffer GUI.
static TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
@ Station
A tile of a station or airport.
Definition tile_type.h:54
@ Object
Contains objects such as transmitters and owned land.
Definition tile_type.h:59
@ Industry
Part of an industry.
Definition tile_type.h:57
@ Railway
A tile with railway.
Definition tile_type.h:50
@ House
A house by a town.
Definition tile_type.h:52
@ Road
A tile with road and/or tram tracks.
Definition tile_type.h:51
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:309
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: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:44
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:39
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX).
Definition widget_type.h:57
@ WWT_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:45
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:37
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window).
Definition widget_type.h:59
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX).
Definition widget_type.h:56
@ NWID_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.
@ Decrease
Arrow to the left or in case of RTL to the right.
Definition widget_type.h:20
@ Increase
Arrow to the right or in case of RTL to the left.
Definition widget_type.h:21
@ HideBevel
Bevel of resize box is hidden.
Definition widget_type.h:29
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:1209
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:3322
Window functions not directly related to making/drawing windows.
Functions, definitions and such used only by the GUI.
@ BorderOnly
Draw border only, no background.
Definition window_gui.h:26
Twindow * AllocateWindowDescFront(WindowDesc &desc, WindowNumber window_number, Targs... extra_arguments)
Open a new window.
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:144
int WidgetID
Widget ID.
Definition window_type.h:21
@ 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:51
@ 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:20
@ Begin
Begin for iteration.
Definition zoom_type.h:22
@ In2x
Zoomed 2 times in.
Definition zoom_type.h:25
@ End
End for iteration.
Definition zoom_type.h:31
@ Out2x
Zoomed 2 times out.
Definition zoom_type.h:27
@ Normal
The normal zoom level.
Definition zoom_type.h:26
@ In4x
Zoomed 4 times in.
Definition zoom_type.h:24
@ Out8x
Zoomed 8 times out.
Definition zoom_type.h:29
@ Out4x
Zoomed 4 times out.
Definition zoom_type.h:28