OpenTTD Source 20241224-master-gf74b0cf984
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_debug.h"
36#include "newgrf_object.h"
37#include "newgrf_spritegroup.h"
38#include "newgrf_station.h"
39#include "newgrf_town.h"
40#include "newgrf_railtype.h"
41#include "newgrf_industries.h"
43
45
46#include "table/strings.h"
47
48#include "safeguards.h"
49
51NewGrfDebugSpritePicker _newgrf_debug_sprite_picker = { SPM_NONE, nullptr, std::vector<SpriteID>() };
52
58static inline uint GetFeatureIndex(uint window_number)
59{
60 return GB(window_number, 0, 24);
61}
62
70static inline uint GetInspectWindowNumber(GrfSpecFeature feature, uint index)
71{
72 assert((index >> 24) == 0);
73 return (feature << 24) | index;
74}
75
84
85typedef const void *NIOffsetProc(const void *b);
86
88struct NIProperty {
89 const char *name;
90 NIOffsetProc *offset_proc;
91 uint8_t read_size;
92 uint8_t prop;
93 uint8_t type;
94};
95
96
102 const char *name;
103 NIOffsetProc *offset_proc;
104 uint8_t read_size;
105 uint8_t cb_bit;
106 uint16_t cb_id;
107};
109static const int CBM_NO_BIT = UINT8_MAX;
110
113 const char *name;
114 uint8_t var;
115};
116
118class NIHelper {
119public:
121 virtual ~NIHelper() = default;
122
128 virtual bool IsInspectable(uint index) const = 0;
129
135 virtual uint GetParent(uint index) const = 0;
136
142 virtual const void *GetInstance(uint index) const = 0;
143
149 virtual const void *GetSpec(uint index) const = 0;
150
155 virtual void SetStringParameters(uint index) const = 0;
156
162 virtual uint32_t GetGRFID(uint index) const = 0;
163
172 virtual uint Resolve(uint index, uint var, uint param, bool &avail) const = 0;
173
178 virtual bool PSAWithParameter() const
179 {
180 return false;
181 }
182
189 virtual const std::span<int32_t> GetPSA([[maybe_unused]] uint index, [[maybe_unused]] uint32_t grfid) const
190 {
191 return {};
192 }
193
194protected:
200 void SetSimpleStringParameters(StringID string, uint32_t index) const
201 {
202 SetDParam(0, string);
203 SetDParam(1, index);
204 }
205
206
213 void SetObjectAtStringParameters(StringID string, uint32_t index, TileIndex tile) const
214 {
215 SetDParam(0, STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT);
216 SetDParam(1, string);
217 SetDParam(2, index);
218 SetDParam(3, tile);
219 }
220};
221
222
230
231/* Load all the NewGRF debug data; externalised as it is just a huge bunch of tables. */
233
239static inline GrfSpecFeature GetFeatureNum(uint window_number)
240{
241 return (GrfSpecFeature)GB(window_number, 24, 8);
242}
243
249static inline const NIFeature *GetFeature(uint window_number)
250{
251 GrfSpecFeature idx = GetFeatureNum(window_number);
252 return idx < GSF_FAKE_END ? _nifeatures[idx] : nullptr;
253}
254
261static inline const NIHelper *GetFeatureHelper(uint window_number)
262{
263 return GetFeature(window_number)->helper;
264}
265
269 static uint32_t var60params[GSF_FAKE_END][0x20];
270
273
276
279
280 Scrollbar *vscroll;
281
287 static bool HasVariableParameter(uint variable)
288 {
289 return IsInsideBS(variable, 0x60, 0x20);
290 }
291
297 {
298 this->caller_grfid = grfid;
299 this->SetDirty();
300 }
301
305 bool HasChainIndex() const
306 {
308 return f == GSF_TRAINS || f == GSF_ROADVEHICLES;
309 }
310
315 uint GetFeatureIndex() const
316 {
317 uint index = ::GetFeatureIndex(this->window_number);
318 if (this->chain_index > 0) {
319 assert(this->HasChainIndex());
320 const Vehicle *v = Vehicle::Get(index);
321 v = v->Move(this->chain_index);
322 if (v != nullptr) index = v->index;
323 }
324 return index;
325 }
326
331 {
332 if (this->chain_index == 0) return;
333
334 assert(this->HasChainIndex());
335
337 v = v->Move(this->chain_index);
338 if (v == nullptr) this->chain_index = 0;
339 }
340
342 {
343 this->CreateNestedTree();
344 this->vscroll = this->GetScrollbar(WID_NGRFI_SCROLLBAR);
345 this->FinishInitNested(wno);
346
347 this->vscroll->SetCount(0);
349
350 this->OnInvalidateData(0, true);
351 }
352
353 void SetStringParameters(WidgetID widget) const override
354 {
355 if (widget != WID_NGRFI_CAPTION) return;
356
358 }
359
361 {
362 switch (widget) {
363 case WID_NGRFI_VEH_CHAIN: {
364 assert(this->HasChainIndex());
366 size.height = std::max(size.height, GetVehicleImageCellSize((VehicleType)(VEH_TRAIN + (f - GSF_TRAINS)), EIT_IN_DEPOT).height + 2 + WidgetDimensions::scaled.bevel.Vertical());
367 break;
368 }
369
371 resize.height = std::max(11, GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.vsep_normal);
372 resize.width = 1;
373
374 size.height = 5 * resize.height + WidgetDimensions::scaled.frametext.Vertical();
375 break;
376 }
377 }
378
385 void DrawString(const Rect &r, int offset, const std::string &string) const
386 {
387 offset -= this->vscroll->GetPosition();
388 if (offset < 0 || offset >= this->vscroll->GetCapacity()) return;
389
390 ::DrawString(r.Shrink(WidgetDimensions::scaled.frametext).Shrink(0, offset * this->resize.step_height, 0, 0), string, TC_BLACK);
391 }
392
397 void DrawVehicleChainWidget(const Rect &r) const
398 {
399 const Vehicle *v = Vehicle::Get(this->GetFeatureIndex());
400 int total_width = 0;
401 int sel_start = 0;
402 int sel_end = 0;
403 for (const Vehicle *u = v->First(); u != nullptr; u = u->Next()) {
404 if (u == v) sel_start = total_width;
405 switch (u->type) {
406 case VEH_TRAIN: total_width += Train::From(u)->GetDisplayImageWidth(); break;
407 case VEH_ROAD: total_width += RoadVehicle::From(u)->GetDisplayImageWidth(); break;
408 default: NOT_REACHED();
409 }
410 if (u == v) sel_end = total_width;
411 }
412
414 int width = br.Width();
415 int skip = 0;
416 if (total_width > width) {
417 int sel_center = (sel_start + sel_end) / 2;
418 if (sel_center > width / 2) skip = std::min(total_width - width, sel_center - width / 2);
419 }
420
422 int h = GetVehicleImageCellSize((VehicleType)(VEH_TRAIN + (f - GSF_TRAINS)), EIT_IN_DEPOT).height;
423 int y = CenterBounds(br.top, br.bottom, h);
425
426 /* Highlight the articulated part (this is different to the whole-vehicle highlighting of DrawVehicleImage */
427 if (_current_text_dir == TD_RTL) {
428 DrawFrameRect(r.right - sel_end + skip, y, r.right - sel_start + skip, y + h, COLOUR_WHITE, FR_BORDERONLY);
429 } else {
430 DrawFrameRect(r.left + sel_start - skip, y, r.left + sel_end - skip, y + h, COLOUR_WHITE, FR_BORDERONLY);
431 }
432 }
433
438 void DrawMainPanelWidget(const Rect &r) const
439 {
440 uint index = this->GetFeatureIndex();
441 const NIFeature *nif = GetFeature(this->window_number);
442 const NIHelper *nih = nif->helper;
443 const void *base = nih->GetInstance(index);
444 const void *base_spec = nih->GetSpec(index);
445
446 uint i = 0;
447 if (nif->variables != nullptr) {
448 this->DrawString(r, i++, "Variables:");
449 for (const NIVariable *niv = nif->variables; niv->name != nullptr; niv++) {
450 bool avail = true;
451 uint param = HasVariableParameter(niv->var) ? NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][niv->var - 0x60] : 0;
452 uint value = nih->Resolve(index, niv->var, param, avail);
453
454 if (!avail) continue;
455
456 if (HasVariableParameter(niv->var)) {
457 this->DrawString(r, i++, fmt::format(" {:02x}[{:02x}]: {:08x} ({})", niv->var, param, value, niv->name));
458 } else {
459 this->DrawString(r, i++, fmt::format(" {:02x}: {:08x} ({})", niv->var, value, niv->name));
460 }
461 }
462 }
463
464 auto psa = nih->GetPSA(index, this->caller_grfid);
465 if (!psa.empty()) {
466 if (nih->PSAWithParameter()) {
467 this->DrawString(r, i++, fmt::format("Persistent storage [{:08X}]:", BSWAP32(this->caller_grfid)));
468 } else {
469 this->DrawString(r, i++, "Persistent storage:");
470 }
471 assert(psa.size() % 4 == 0);
472 for (size_t j = 0; j < psa.size(); j += 4) {
473 this->DrawString(r, i++, fmt::format(" {}: {} {} {} {}", j, psa[j], psa[j + 1], psa[j + 2], psa[j + 3]));
474 }
475 }
476
477 if (nif->properties != nullptr) {
478 this->DrawString(r, i++, "Properties:");
479 for (const NIProperty *nip = nif->properties; nip->name != nullptr; nip++) {
480 const void *ptr = nip->offset_proc(base);
481 uint value;
482 switch (nip->read_size) {
483 case 1: value = *(const uint8_t *)ptr; break;
484 case 2: value = *(const uint16_t *)ptr; break;
485 case 4: value = *(const uint32_t *)ptr; break;
486 default: NOT_REACHED();
487 }
488
489 StringID string;
490 SetDParam(0, value);
491 switch (nip->type) {
492 case NIT_INT:
493 string = STR_JUST_INT;
494 break;
495
496 case NIT_CARGO:
497 string = IsValidCargoID(value) ? CargoSpec::Get(value)->name : STR_QUANTITY_N_A;
498 break;
499
500 default:
501 NOT_REACHED();
502 }
503
504 this->DrawString(r, i++, fmt::format(" {:02x}: {} ({})", nip->prop, GetString(string), nip->name));
505 }
506 }
507
508 if (nif->callbacks != nullptr) {
509 this->DrawString(r, i++, "Callbacks:");
510 for (const NICallback *nic = nif->callbacks; nic->name != nullptr; nic++) {
511 if (nic->cb_bit != CBM_NO_BIT) {
512 const void *ptr = nic->offset_proc(base_spec);
513 uint value;
514 switch (nic->read_size) {
515 case 1: value = *(const uint8_t *)ptr; break;
516 case 2: value = *(const uint16_t *)ptr; break;
517 case 4: value = *(const uint32_t *)ptr; break;
518 default: NOT_REACHED();
519 }
520
521 if (!HasBit(value, nic->cb_bit)) continue;
522 this->DrawString(r, i++, fmt::format(" {:03x}: {}", nic->cb_id, nic->name));
523 } else {
524 this->DrawString(r, i++, fmt::format(" {:03x}: {} (unmasked)", nic->cb_id, nic->name));
525 }
526 }
527 }
528
529 /* Not nice and certainly a hack, but it beats duplicating
530 * this whole function just to count the actual number of
531 * elements. Especially because they need to be redrawn. */
532 const_cast<NewGRFInspectWindow*>(this)->vscroll->SetCount(i);
533 }
534
535 void DrawWidget(const Rect &r, WidgetID widget) const override
536 {
537 switch (widget) {
539 this->DrawVehicleChainWidget(r);
540 break;
541
543 this->DrawMainPanelWidget(r);
544 break;
545 }
546 }
547
548 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
549 {
550 switch (widget) {
551 case WID_NGRFI_PARENT: {
553 uint index = nih->GetParent(this->GetFeatureIndex());
554 ::ShowNewGRFInspectWindow(GetFeatureNum(index), ::GetFeatureIndex(index), nih->GetGRFID(this->GetFeatureIndex()));
555 break;
556 }
557
559 if (this->chain_index > 0) {
560 this->chain_index--;
561 this->InvalidateData();
562 }
563 break;
564
566 if (this->HasChainIndex()) {
567 uint index = this->GetFeatureIndex();
568 Vehicle *v = Vehicle::Get(index);
569 if (v != nullptr && v->Next() != nullptr) {
570 this->chain_index++;
571 this->InvalidateData();
572 }
573 }
574 break;
575
576 case WID_NGRFI_MAINPANEL: {
577 /* Does this feature have variables? */
578 const NIFeature *nif = GetFeature(this->window_number);
579 if (nif->variables == nullptr) return;
580
581 /* Get the line, make sure it's within the boundaries. */
583 if (line == INT32_MAX) return;
584
585 /* Find the variable related to the line */
586 for (const NIVariable *niv = nif->variables; niv->name != nullptr; niv++, line--) {
587 if (line != 1) continue; // 1 because of the "Variables:" line
588
589 if (!HasVariableParameter(niv->var)) break;
590
591 this->current_edit_param = niv->var;
593 }
594 }
595 }
596 }
597
598 void OnQueryTextFinished(std::optional<std::string> str) override
599 {
600 if (!str.has_value() || str->empty()) return;
601
602 NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][this->current_edit_param - 0x60] = std::strtol(str->c_str(), nullptr, 16);
603 this->SetDirty();
604 }
605
606 void OnResize() override
607 {
608 this->vscroll->SetCapacityFromWidget(this, WID_NGRFI_MAINPANEL, WidgetDimensions::scaled.frametext.Vertical());
609 }
610
616 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
617 {
618 if (!gui_scope) return;
619 if (this->HasChainIndex()) {
620 this->ValidateChainIndex();
621 this->SetWidgetDisabledState(WID_NGRFI_VEH_PREV, this->chain_index == 0);
623 this->SetWidgetDisabledState(WID_NGRFI_VEH_NEXT, v == nullptr || v->Next() == nullptr);
624 }
625 }
626};
627
628/* static */ uint32_t NewGRFInspectWindow::var60params[GSF_FAKE_END][0x20] = { {0} }; // Use spec to have 0s in whole array
629
630static constexpr NWidgetPart _nested_newgrf_inspect_chain_widgets[] = {
632 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
633 NWidget(WWT_CAPTION, COLOUR_GREY, WID_NGRFI_CAPTION), SetDataTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
634 NWidget(WWT_SHADEBOX, COLOUR_GREY),
635 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
636 NWidget(WWT_STICKYBOX, COLOUR_GREY),
637 EndContainer(),
638 NWidget(WWT_PANEL, COLOUR_GREY),
642 NWidget(WWT_EMPTY, COLOUR_GREY, WID_NGRFI_VEH_CHAIN), SetFill(1, 0), SetResize(1, 0),
643 EndContainer(),
644 EndContainer(),
649 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
650 EndContainer(),
651 EndContainer(),
652};
653
654static constexpr NWidgetPart _nested_newgrf_inspect_widgets[] = {
656 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
657 NWidget(WWT_CAPTION, COLOUR_GREY, WID_NGRFI_CAPTION), SetDataTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
658 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NGRFI_PARENT), SetDataTip(STR_NEWGRF_INSPECT_PARENT_BUTTON, STR_NEWGRF_INSPECT_PARENT_TOOLTIP),
659 NWidget(WWT_SHADEBOX, COLOUR_GREY),
660 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
661 NWidget(WWT_STICKYBOX, COLOUR_GREY),
662 EndContainer(),
667 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
668 EndContainer(),
669 EndContainer(),
670};
671
672static WindowDesc _newgrf_inspect_chain_desc(
673 WDP_AUTO, "newgrf_inspect_chain", 400, 300,
675 0,
676 _nested_newgrf_inspect_chain_widgets
677);
678
679static WindowDesc _newgrf_inspect_desc(
680 WDP_AUTO, "newgrf_inspect", 400, 300,
682 0,
683 _nested_newgrf_inspect_widgets
684);
685
695void ShowNewGRFInspectWindow(GrfSpecFeature feature, uint index, const uint32_t grfid)
696{
697 if (!IsNewGRFInspectable(feature, index)) return;
698
699 WindowNumber wno = GetInspectWindowNumber(feature, index);
700 WindowDesc &desc = (feature == GSF_TRAINS || feature == GSF_ROADVEHICLES) ? _newgrf_inspect_chain_desc : _newgrf_inspect_desc;
701 NewGRFInspectWindow *w = AllocateWindowDescFront<NewGRFInspectWindow>(desc, wno, true);
702 w->SetCallerGRFID(grfid);
703}
704
714{
715 if (feature == GSF_INVALID) return;
716
717 WindowNumber wno = GetInspectWindowNumber(feature, index);
719}
720
730{
731 if (feature == GSF_INVALID) return;
732
733 WindowNumber wno = GetInspectWindowNumber(feature, index);
735
736 /* Reinitialise the land information window to remove the "debug" sprite if needed.
737 * Note: Since we might be called from a command here, it is important to not execute
738 * the invalidation immediately. The landinfo window tests commands itself. */
740}
741
751bool IsNewGRFInspectable(GrfSpecFeature feature, uint index)
752{
753 const NIFeature *nif = GetFeature(GetInspectWindowNumber(feature, index));
754 if (nif == nullptr) return false;
755 return nif->helper->IsInspectable(index);
756}
757
764{
765 switch (GetTileType(tile)) {
766 default: return GSF_INVALID;
767 case MP_RAILWAY: return GSF_RAILTYPES;
768 case MP_ROAD: return IsLevelCrossing(tile) ? GSF_RAILTYPES : GSF_ROADTYPES;
769 case MP_HOUSE: return GSF_HOUSES;
770 case MP_INDUSTRY: return GSF_INDUSTRYTILES;
771 case MP_OBJECT: return GSF_OBJECTS;
772
773 case MP_STATION:
774 switch (GetStationType(tile)) {
775 case STATION_RAIL: return GSF_STATIONS;
776 case STATION_AIRPORT: return GSF_AIRPORTTILES;
777 case STATION_BUS: return GSF_ROADSTOPS;
778 case STATION_TRUCK: return GSF_ROADSTOPS;
779 default: return GSF_INVALID;
780 }
781 }
782}
783
790{
791 switch (type) {
792 case VEH_TRAIN: return GSF_TRAINS;
793 case VEH_ROAD: return GSF_ROADVEHICLES;
794 case VEH_SHIP: return GSF_SHIPS;
795 case VEH_AIRCRAFT: return GSF_AIRCRAFT;
796 default: return GSF_INVALID;
797 }
798}
799
800
801/**** Sprite Aligner ****/
802
805 typedef std::pair<int16_t, int16_t> XyOffs;
806
808 Scrollbar *vscroll;
809 std::map<SpriteID, XyOffs> offs_start_map;
810
811 static inline ZoomLevel zoom = ZOOM_LVL_END;
812 static bool centre;
813 static bool crosshair;
814 const Action5Type *act5_type = nullptr;
815
817 {
818 /* On first opening, set initial zoom to current zoom level. */
819 if (SpriteAlignerWindow::zoom == ZOOM_LVL_END) SpriteAlignerWindow::zoom = _gui_zoom;
820 SpriteAlignerWindow::zoom = Clamp(SpriteAlignerWindow::zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max);
821
822 /* Oh yes, we assume there is at least one normal sprite! */
823 while (GetSpriteType(this->current_sprite) != SpriteType::Normal) this->current_sprite++;
824 this->SelectAction5Type();
825
826 this->CreateNestedTree();
827 this->vscroll = this->GetScrollbar(WID_SA_SCROLLBAR);
828 this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.size());
829 this->FinishInitNested(wno);
830
831 this->SetWidgetLoweredState(WID_SA_CENTRE, SpriteAlignerWindow::centre);
832 this->SetWidgetLoweredState(WID_SA_CROSSHAIR, SpriteAlignerWindow::crosshair);
833
834 this->InvalidateData(0, true);
835 }
836
837 void SetStringParameters(WidgetID widget) const override
838 {
839 const Sprite *spr = GetSprite(this->current_sprite, SpriteType::Normal);
840 switch (widget) {
841 case WID_SA_CAPTION:
842 if (this->act5_type != nullptr) {
844 SetDParam(1, this->act5_type - GetAction5Types().data());
845 SetDParam(2, this->current_sprite - this->act5_type->sprite_base);
846 SetDParamStr(3, GetOriginFile(this->current_sprite)->GetSimplifiedFilename());
847 SetDParam(4, GetSpriteLocalID(this->current_sprite));
848 } else if (this->current_sprite < SPR_OPENTTD_BASE) {
850 SetDParam(1, this->current_sprite);
851 SetDParamStr(2, GetOriginFile(this->current_sprite)->GetSimplifiedFilename());
852 SetDParam(3, GetSpriteLocalID(this->current_sprite));
853 } else {
855 SetDParamStr(1, GetOriginFile(this->current_sprite)->GetSimplifiedFilename());
856 SetDParam(2, GetSpriteLocalID(this->current_sprite));
857 }
858 break;
859
861 SetDParam(0, UnScaleByZoom(spr->x_offs, SpriteAlignerWindow::zoom));
862 SetDParam(1, UnScaleByZoom(spr->y_offs, SpriteAlignerWindow::zoom));
863 break;
864
865 case WID_SA_OFFSETS_REL: {
866 /* Relative offset is new absolute offset - starting absolute offset.
867 * Show 0, 0 as the relative offsets if entry is not in the map (meaning they have not been changed yet).
868 */
869 const auto key_offs_pair = this->offs_start_map.find(this->current_sprite);
870 if (key_offs_pair != this->offs_start_map.end()) {
871 SetDParam(0, UnScaleByZoom(spr->x_offs - key_offs_pair->second.first, SpriteAlignerWindow::zoom));
872 SetDParam(1, UnScaleByZoom(spr->y_offs - key_offs_pair->second.second, SpriteAlignerWindow::zoom));
873 } else {
874 SetDParam(0, 0);
875 SetDParam(1, 0);
876 }
877 break;
878 }
879
880 default:
881 break;
882 }
883 }
884
886 {
887 switch (widget) {
888 case WID_SA_SPRITE:
889 size.height = ScaleGUITrad(200);
890 break;
891
892 case WID_SA_LIST: {
893 Dimension d = {};
894 for (const auto &spritefile : GetCachedSpriteFiles()) {
895 SetDParamStr(0, spritefile->GetSimplifiedFilename());
896 SetDParamMaxDigits(1, 6);
898 }
899 size.width = d.width + padding.width;
900 resize.height = GetCharacterHeight(FS_NORMAL) + padding.height;
901 resize.width = 1;
902 fill.height = resize.height;
903 break;
904 }
905
906 default:
907 break;
908 }
909 }
910
911 void DrawWidget(const Rect &r, WidgetID widget) const override
912 {
913 switch (widget) {
914 case WID_SA_SPRITE: {
915 /* Center the sprite ourselves */
916 const Sprite *spr = GetSprite(this->current_sprite, SpriteType::Normal);
918 int x;
919 int y;
920 if (SpriteAlignerWindow::centre) {
921 x = -UnScaleByZoom(spr->x_offs, SpriteAlignerWindow::zoom) + (ir.Width() - UnScaleByZoom(spr->width, SpriteAlignerWindow::zoom)) / 2;
922 y = -UnScaleByZoom(spr->y_offs, SpriteAlignerWindow::zoom) + (ir.Height() - UnScaleByZoom(spr->height, SpriteAlignerWindow::zoom)) / 2;
923 } else {
924 x = ir.Width() / 2;
925 y = ir.Height() / 2;
926 }
927
929 if (!FillDrawPixelInfo(&new_dpi, ir)) break;
931
932 DrawSprite(this->current_sprite, PAL_NONE, x, y, nullptr, SpriteAlignerWindow::zoom);
933
934 Rect outline = {0, 0, UnScaleByZoom(spr->width, SpriteAlignerWindow::zoom) - 1, UnScaleByZoom(spr->height, SpriteAlignerWindow::zoom) - 1};
935 outline = outline.Translate(x + UnScaleByZoom(spr->x_offs, SpriteAlignerWindow::zoom), y + UnScaleByZoom(spr->y_offs, SpriteAlignerWindow::zoom));
936 DrawRectOutline(outline.Expand(1), PC_LIGHT_BLUE, 1, 1);
937
938 if (SpriteAlignerWindow::crosshair) {
939 GfxDrawLine(x, 0, x, ir.Height() - 1, PC_WHITE, 1, 1);
940 GfxDrawLine(0, y, ir.Width() - 1, y, PC_WHITE, 1, 1);
941 }
942 break;
943 }
944
945 case WID_SA_LIST: {
946 /* Don't redraw sprite list while it is still being filled by picker. */
947 if (_newgrf_debug_sprite_picker.mode == SPM_REDRAW) break;
948
949 const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget);
950 int step_size = nwid->resize_y;
951
952 const std::vector<SpriteID> &list = _newgrf_debug_sprite_picker.sprites;
953
955 auto [first, last] = this->vscroll->GetVisibleRangeIterators(list);
956 for (auto it = first; it != last; ++it) {
957 const SpriteFile *file = GetOriginFile(*it);
958 if (file == nullptr) {
959 SetDParam(0, *it);
960 DrawString(ir, STR_JUST_COMMA, *it == this->current_sprite ? TC_WHITE : (TC_GREY | TC_NO_SHADE), SA_RIGHT | SA_FORCE);
961 } else {
964 DrawString(ir, STR_SPRITE_ALIGNER_SPRITE, *it == this->current_sprite ? TC_WHITE : TC_BLACK);
965 }
966 ir.top += step_size;
967 }
968 break;
969 }
970 }
971 }
972
973 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
974 {
975 switch (widget) {
976 case WID_SA_PREVIOUS:
977 do {
978 this->current_sprite = (this->current_sprite == 0 ? GetMaxSpriteID() : this->current_sprite) - 1;
979 } while (GetSpriteType(this->current_sprite) != SpriteType::Normal);
980 this->SelectAction5Type();
981 this->SetDirty();
982 break;
983
984 case WID_SA_GOTO:
986 break;
987
988 case WID_SA_NEXT:
989 do {
990 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
991 } while (GetSpriteType(this->current_sprite) != SpriteType::Normal);
992 this->SelectAction5Type();
993 this->SetDirty();
994 break;
995
996 case WID_SA_PICKER:
998 _newgrf_debug_sprite_picker.mode = SPM_WAIT_CLICK;
999 this->SetDirty();
1000 break;
1001
1002 case WID_SA_LIST: {
1003 auto it = this->vscroll->GetScrolledItemFromWidget(_newgrf_debug_sprite_picker.sprites, pt.y, this, widget);
1004 if (it != _newgrf_debug_sprite_picker.sprites.end()) {
1005 SpriteID spr = *it;
1006 if (GetSpriteType(spr) == SpriteType::Normal) this->current_sprite = spr;
1007 }
1008 this->SelectAction5Type();
1009 this->SetDirty();
1010 break;
1011 }
1012
1013 case WID_SA_UP:
1014 case WID_SA_DOWN:
1015 case WID_SA_LEFT:
1016 case WID_SA_RIGHT: {
1017 /*
1018 * Yes... this is a hack.
1019 *
1020 * No... I don't think it is useful to make this less of a hack.
1021 *
1022 * If you want to align sprites, you just need the number. Generally
1023 * the sprite caches are big enough to not remove the sprite from the
1024 * cache. If that's not the case, just let the NewGRF developer
1025 * increase the cache size instead of storing thousands of offsets
1026 * for the incredibly small chance that it's actually going to be
1027 * used by someone and the sprite cache isn't big enough for that
1028 * particular NewGRF developer.
1029 */
1030 Sprite *spr = const_cast<Sprite *>(GetSprite(this->current_sprite, SpriteType::Normal));
1031
1032 /* Remember the original offsets of the current sprite, if not already in mapping. */
1033 if (this->offs_start_map.count(this->current_sprite) == 0) {
1034 this->offs_start_map[this->current_sprite] = XyOffs(spr->x_offs, spr->y_offs);
1035 }
1036 int amt = ScaleByZoom(_ctrl_pressed ? 8 : 1, SpriteAlignerWindow::zoom);
1037 switch (widget) {
1038 /* Move eight units at a time if ctrl is pressed. */
1039 case WID_SA_UP: spr->y_offs -= amt; break;
1040 case WID_SA_DOWN: spr->y_offs += amt; break;
1041 case WID_SA_LEFT: spr->x_offs -= amt; break;
1042 case WID_SA_RIGHT: spr->x_offs += amt; break;
1043 }
1044 /* Of course, we need to redraw the sprite, but where is it used?
1045 * Everywhere is a safe bet. */
1047 break;
1048 }
1049
1050 case WID_SA_RESET_REL:
1051 /* Reset the starting offsets for the current sprite. */
1052 this->offs_start_map.erase(this->current_sprite);
1053 this->SetDirty();
1054 break;
1055
1056 case WID_SA_CENTRE:
1057 SpriteAlignerWindow::centre = !SpriteAlignerWindow::centre;
1058 this->SetWidgetLoweredState(widget, SpriteAlignerWindow::centre);
1059 this->SetDirty();
1060 break;
1061
1062 case WID_SA_CROSSHAIR:
1063 SpriteAlignerWindow::crosshair = !SpriteAlignerWindow::crosshair;
1064 this->SetWidgetLoweredState(widget, SpriteAlignerWindow::crosshair);
1065 this->SetDirty();
1066 break;
1067
1068 default:
1069 if (IsInsideBS(widget, WID_SA_ZOOM, ZOOM_LVL_END)) {
1070 SpriteAlignerWindow::zoom = ZoomLevel(widget - WID_SA_ZOOM);
1071 this->InvalidateData(0, true);
1072 }
1073 break;
1074 }
1075 }
1076
1077 void OnQueryTextFinished(std::optional<std::string> str) override
1078 {
1079 if (!str.has_value() || str->empty()) return;
1080
1081 this->current_sprite = atoi(str->c_str());
1082 if (this->current_sprite >= GetMaxSpriteID()) this->current_sprite = 0;
1083 while (GetSpriteType(this->current_sprite) != SpriteType::Normal) {
1084 this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID();
1085 }
1086 this->SelectAction5Type();
1087 this->SetDirty();
1088 }
1089
1095 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1096 {
1097 if (!gui_scope) return;
1098 if (data == 1) {
1099 /* Sprite picker finished */
1101 this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.size());
1102 }
1103
1104 SpriteAlignerWindow::zoom = Clamp(SpriteAlignerWindow::zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max);
1105 for (ZoomLevel z = ZOOM_LVL_BEGIN; z < ZOOM_LVL_END; z++) {
1107 this->SetWidgetsLoweredState(SpriteAlignerWindow::zoom == z, WID_SA_ZOOM + z);
1108 }
1109 }
1110
1111 void OnResize() override
1112 {
1113 this->vscroll->SetCapacityFromWidget(this, WID_SA_LIST);
1114 }
1115
1116private:
1117 void SelectAction5Type()
1118 {
1119 const auto act5types = GetAction5Types();
1120 for (auto it = std::begin(act5types); it != std::end(act5types); ++it) {
1121 if (it->sprite_base <= this->current_sprite && this->current_sprite < it->sprite_base + it->max_sprites) {
1122 this->act5_type = &*it;
1123 return;
1124 }
1125 }
1126 this->act5_type = nullptr;
1127 }
1128};
1129
1130bool SpriteAlignerWindow::centre = true;
1131bool SpriteAlignerWindow::crosshair = true;
1132
1133static constexpr NWidgetPart _nested_sprite_aligner_widgets[] = {
1135 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1136 NWidget(WWT_CAPTION, COLOUR_GREY, WID_SA_CAPTION), SetDataTip(STR_JUST_STRING4, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1137 NWidget(WWT_SHADEBOX, COLOUR_GREY),
1138 NWidget(WWT_STICKYBOX, COLOUR_GREY),
1139 EndContainer(),
1140 NWidget(WWT_PANEL, COLOUR_GREY),
1144 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_PREVIOUS), SetDataTip(STR_SPRITE_ALIGNER_PREVIOUS_BUTTON, STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
1145 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_GOTO), SetDataTip(STR_SPRITE_ALIGNER_GOTO_BUTTON, STR_SPRITE_ALIGNER_GOTO_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
1146 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_NEXT), SetDataTip(STR_SPRITE_ALIGNER_NEXT_BUTTON, STR_SPRITE_ALIGNER_NEXT_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
1147 EndContainer(),
1149 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1150 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_UP), SetDataTip(SPR_ARROW_UP, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1151 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1152 EndContainer(),
1155 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1156 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_LEFT), SetDataTip(SPR_ARROW_LEFT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1157 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1158 EndContainer(),
1159 NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_SA_SPRITE), SetDataTip(STR_NULL, STR_SPRITE_ALIGNER_SPRITE_TOOLTIP), SetResize(1, 1), SetFill(1, 1),
1160 EndContainer(),
1162 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1163 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_RIGHT), SetDataTip(SPR_ARROW_RIGHT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1164 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1165 EndContainer(),
1166 EndContainer(),
1168 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1169 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_DOWN), SetDataTip(SPR_ARROW_DOWN, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), SetMinimalSize(11, 11),
1170 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(1, 0),
1171 EndContainer(),
1172 NWidget(WWT_LABEL, COLOUR_GREY, WID_SA_OFFSETS_ABS), SetDataTip(STR_SPRITE_ALIGNER_OFFSETS_ABS, STR_NULL), SetFill(1, 0), SetResize(1, 0),
1173 NWidget(WWT_LABEL, COLOUR_GREY, WID_SA_OFFSETS_REL), SetDataTip(STR_SPRITE_ALIGNER_OFFSETS_REL, STR_NULL), SetFill(1, 0), SetResize(1, 0),
1175 NWidget(WWT_TEXTBTN_2, COLOUR_GREY, WID_SA_CENTRE), SetDataTip(STR_SPRITE_ALIGNER_CENTRE_OFFSET, STR_NULL), SetFill(1, 0), SetResize(1, 0),
1176 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_RESET_REL), SetDataTip(STR_SPRITE_ALIGNER_RESET_BUTTON, STR_SPRITE_ALIGNER_RESET_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
1177 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_CROSSHAIR), SetDataTip(STR_SPRITE_ALIGNER_CROSSHAIR, STR_NULL), SetFill(1, 0), SetResize(1, 0),
1178 EndContainer(),
1179 EndContainer(),
1181 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_PICKER), SetDataTip(STR_SPRITE_ALIGNER_PICKER_BUTTON, STR_SPRITE_ALIGNER_PICKER_TOOLTIP), SetFill(1, 0),
1183 NWidget(WWT_MATRIX, COLOUR_GREY, WID_SA_LIST), SetResize(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetFill(1, 1), SetScrollbar(WID_SA_SCROLLBAR),
1185 EndContainer(),
1187 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + ZOOM_LVL_IN_4X), SetDataTip(STR_CONFIG_SETTING_ZOOM_LVL_MIN, STR_NULL), SetFill(1, 0),
1188 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + ZOOM_LVL_IN_2X), SetDataTip(STR_CONFIG_SETTING_ZOOM_LVL_IN_2X, STR_NULL), SetFill(1, 0),
1189 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + ZOOM_LVL_NORMAL), SetDataTip(STR_CONFIG_SETTING_ZOOM_LVL_NORMAL, STR_NULL), SetFill(1, 0),
1190 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + ZOOM_LVL_OUT_2X), SetDataTip(STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X, STR_NULL), SetFill(1, 0),
1191 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + ZOOM_LVL_OUT_4X), SetDataTip(STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X, STR_NULL), SetFill(1, 0),
1192 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_ZOOM + ZOOM_LVL_OUT_8X), SetDataTip(STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X, STR_NULL), SetFill(1, 0),
1193 EndContainer(),
1194 EndContainer(),
1195 EndContainer(),
1197 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
1198 NWidget(WWT_RESIZEBOX, COLOUR_GREY), SetDataTip(RWV_HIDE_BEVEL, STR_TOOLTIP_RESIZE),
1199 EndContainer(),
1200 EndContainer(),
1201};
1202
1203static WindowDesc _sprite_aligner_desc(
1204 WDP_AUTO, "sprite_aligner", 400, 300,
1206 0,
1207 _nested_sprite_aligner_widgets
1208);
1209
1214{
1215 AllocateWindowDescFront<SpriteAlignerWindow>(_sprite_aligner_desc, 0);
1216}
Class for backupping variables and making sure they are restored later.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
static uint32_t BSWAP32(uint32_t x)
Perform a 32 bits endianness bitswap on x.
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 IsValidCargoID(CargoID t)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:107
Helper class to wrap some functionality/queries in.
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:2377
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:2451
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:43
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:96
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:18
@ Normal
The most basic (normal) sprite.
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:345
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
Definition gfx_type.h:355
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:209
@ TC_NO_SHADE
Do not add shading to this text colour.
Definition gfx_type.h:284
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
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 SetDataTip(uint32_t data, StringID tip)
Widget part function for setting the data and tooltip.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetMatrixDataTip(uint8_t cols, uint8_t rows, StringID tip)
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
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:940
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(StringID 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:6467
GrfSpecFeature
Definition newgrf.h:67
@ GSF_INVALID
An invalid spec feature.
Definition newgrf.h:94
@ GSF_FAKE_END
End of the fake features.
Definition newgrf.h:92
Information about NewGRF Action 5.
NewGRF handling of airports.
NewGRF handling of airport tiles.
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.
static const int CBM_NO_BIT
Mask to show no bit needs to be enabled for the callback.
static const NIHelper * GetFeatureHelper(uint window_number)
Get the NIHelper related to the window number.
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 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:56
SpriteType GetSpriteType(SpriteID sprite)
Get the sprite type of a given sprite.
std::span< const std::unique_ptr< SpriteFile > > GetCachedSpriteFiles()
Get the list of cached SpriteFiles.
uint GetMaxSpriteID()
Get a reasonable (upper bound) estimate of the maximum SpriteID used in OpenTTD; there will be no spr...
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.
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:104
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition strings.cpp:333
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:371
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:143
Functions related to OTTD's strings.
@ TD_RTL
Text is written right-to-left by default.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
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 ID.
Definition cargotype.h:139
StringID name
Name of this type of cargo.
Definition cargotype.h:93
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:157
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.
const char * name
The human readable name of the callback.
uint8_t cb_bit
The bit that needs to be set for this callback to be enabled.
uint16_t cb_id
The number of the callback.
uint8_t read_size
The number of bytes (i.e. byte, word, dword etc) to read.
Container for all information for a given feature.
const NIHelper * helper
The class container all helper functions.
const NICallback * callbacks
The callbacks associated with this feature.
const NIVariable * variables
The variables associated with this feature.
const NIProperty * properties
The properties associated with this feature.
Representation of the data from a NewGRF property.
uint8_t read_size
Number of bytes (i.e. byte, word, dword etc)
const char * 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(size_t 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:159
Data structure for an opened window.
Definition window_gui.h:273
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1733
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3159
void RaiseWidget(WidgetID widget_index)
Marks a widget as raised.
Definition window_gui.h:475
virtual void ShowNewGRFInspectWindow() const
Show the NewGRF inspection window.
Definition window_gui.h:861
ResizeInfo resize
Resize information.
Definition window_gui.h:314
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition window_gui.h:521
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1723
void SetWidgetsLoweredState(bool lowered_stat, Args... widgets)
Sets the lowered/raised status of a list of widgets.
Definition window_gui.h:532
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:447
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:977
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
Definition window_gui.h:466
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:314
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:387
int height
Height of the window (number of pixels down in y direction)
Definition window_gui.h:312
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:311
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:302
Stuff related to the text buffer GUI.
static debug_inline TileType GetTileType(Tile tile)
Get the tiletype of a given tile.
Definition tile_map.h:96
@ MP_ROAD
A tile with road (or tram tracks)
Definition tile_type.h:50
@ MP_STATION
A tile of a station.
Definition tile_type.h:53
@ MP_HOUSE
A house by a town.
Definition tile_type.h:51
@ MP_RAILWAY
A railway.
Definition tile_type.h:49
@ MP_INDUSTRY
Part of an industry.
Definition tile_type.h:56
@ MP_OBJECT
Contains objects such as transmitters and owned land.
Definition tile_type.h:58
Base of the town class.
Base for the train class.
Base class for all vehicles.
void DrawVehicleImage(const Vehicle *v, const Rect &r, VehicleID selection, EngineImageType image_type, int skip)
Draws an image of a vehicle chain.
Functions related to the vehicle's GUIs.
@ EIT_IN_DEPOT
Vehicle drawn in depot.
@ EIT_IN_DETAILS
Vehicle drawn in vehicle details, refit window, ...
VehicleType
Available vehicle types.
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
static const VehicleID INVALID_VEHICLE
Constant representing a non-existing vehicle.
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
@ AWV_DECREASE
Arrow to the left or in case of RTL to the right.
Definition widget_type.h:31
@ AWV_INCREASE
Arrow to the right or in case of RTL to the left.
Definition widget_type.h:32
@ NC_EQUALSIZE
Value of the NCB_EQUALSIZE flag.
@ 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:57
@ NWID_SPACER
Invisible widget that takes some space.
Definition widget_type.h:79
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:75
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:55
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:50
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:66
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:59
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:64
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:61
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:85
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:77
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:69
@ WWT_TEXTBTN_2
(Toggle) Button with diff text when clicked
Definition widget_type.h:56
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:48
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:68
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:65
@ NWID_HORIZONTAL_LTR
Horizontal container that doesn't change the order of the widgets for RTL languages.
Definition widget_type.h:76
@ RWV_HIDE_BEVEL
Bevel of resize box is hidden.
Definition widget_type.h:40
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:1140
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:3219
Window functions not directly related to making/drawing windows.
Functions, definitions and such used only by the GUI.
@ FR_BORDERONLY
Draw border only, no background.
Definition window_gui.h:27
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:147
int WidgetID
Widget ID.
Definition window_type.h:18
int32_t WindowNumber
Number to differentiate different windows of the same class.
@ 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:45
@ 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