OpenTTD Source 20260218-master-g2123fca5ea
story_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 "window_gui.h"
12#include "strings_func.h"
13#include "gui.h"
14#include "story_base.h"
16#include "company_func.h"
17#include "command_func.h"
18#include "dropdown_type.h"
19#include "dropdown_func.h"
20#include "sortlist_type.h"
21#include "goal_base.h"
22#include "viewport_func.h"
23#include "window_func.h"
24#include "company_base.h"
25#include "tilehighlight_func.h"
26#include "vehicle_base.h"
27#include "story_cmd.h"
28
30
31#include "table/strings.h"
32#include "table/sprites.h"
33
34#include "safeguards.h"
35
36static CursorID TranslateStoryPageButtonCursor(StoryPageButtonCursor cursor);
37
38typedef GUIList<const StoryPage*> GUIStoryPageList;
39typedef GUIList<const StoryPageElement*> GUIStoryPageElementList;
40
41struct StoryBookWindow : Window {
42protected:
44 const StoryPageElement *pe;
45 Rect bounds;
46 };
47 typedef std::vector<LayoutCacheElement> LayoutCache;
48
49 enum class ElementFloat : uint8_t {
50 None,
51 Left,
52 Right,
53 };
54
55 Scrollbar *vscroll = nullptr;
56 mutable LayoutCache layout_cache{};
57
58 GUIStoryPageList story_pages{};
59 GUIStoryPageElementList story_page_elements{};
61 std::string selected_generic_title{};
62
64
65 static const std::initializer_list<GUIStoryPageList::SortFunction * const> page_sorter_funcs;
66 static const std::initializer_list<GUIStoryPageElementList::SortFunction * const> page_element_sorter_funcs;
67
70 {
71 if (this->story_pages.NeedRebuild()) {
72 this->story_pages.clear();
73
74 for (const StoryPage *p : StoryPage::Iterate()) {
75 if (this->IsPageAvailable(p)) {
76 this->story_pages.push_back(p);
77 }
78 }
79
80 this->story_pages.RebuildDone();
81 }
82
83 this->story_pages.Sort();
84 }
85
87 static bool PageOrderSorter(const StoryPage * const &a, const StoryPage * const &b)
88 {
89 return a->sort_value < b->sort_value;
90 }
91
94 {
95 if (this->story_page_elements.NeedRebuild()) {
96 this->story_page_elements.clear();
97
98 const StoryPage *p = GetSelPage();
99 if (p != nullptr) {
100 for (const StoryPageElement *pe : StoryPageElement::Iterate()) {
101 if (pe->page == p->index) {
102 this->story_page_elements.push_back(pe);
103 }
104 }
105 }
106
107 this->story_page_elements.RebuildDone();
108 }
109
110 this->story_page_elements.Sort();
112 }
113
115 static bool PageElementOrderSorter(const StoryPageElement * const &a, const StoryPageElement * const &b)
116 {
117 return a->sort_value < b->sort_value;
118 }
119
120 /*
121 * Checks if a given page should be visible in the story book.
122 * @param page The page to check.
123 * @return True if the page should be visible, otherwise false.
124 */
125 bool IsPageAvailable(const StoryPage *page) const
126 {
127 return page->company == CompanyID::Invalid() || page->company == this->window_number;
128 }
129
135 {
136 if (!StoryPage::IsValidID(selected_page_id)) return nullptr;
138 }
139
144 int GetSelPageNum() const
145 {
146 int page_number = 0;
147 for (const StoryPage *p : this->story_pages) {
148 if (p->index == this->selected_page_id) {
149 return page_number;
150 }
151 page_number++;
152 }
153 return -1;
154 }
155
160 {
161 /* Verify that the selected page exist. */
162 if (!StoryPage::IsValidID(this->selected_page_id)) return false;
163
164 return this->story_pages.front()->index == this->selected_page_id;
165 }
166
171 {
172 /* Verify that the selected page exist. */
173 if (!StoryPage::IsValidID(this->selected_page_id)) return false;
174
175 if (this->story_pages.size() <= 1) return true;
176 const StoryPage *last = this->story_pages.back();
177 return last->index == this->selected_page_id;
178 }
179
184 {
185 /* Generate generic title if selected page have no custom title. */
186 StoryPage *page = this->GetSelPage();
187 if (page != nullptr && page->title.empty()) {
188 selected_generic_title = GetString(STR_STORY_BOOK_GENERIC_PAGE_ITEM, GetSelPageNum() + 1);
189 }
190
191 this->story_page_elements.ForceRebuild();
193
194 if (this->active_button_id != StoryPageElementID::Invalid()) ResetObjectToPlace();
195
196 this->vscroll->SetCount(this->GetContentHeight());
200 }
201
206 {
207 if (!StoryPage::IsValidID(this->selected_page_id)) return;
208
209 /* Find the last available page which is previous to the current selected page. */
210 const StoryPage *last_available;
211 last_available = nullptr;
212 for (const StoryPage *p : this->story_pages) {
213 if (p->index == this->selected_page_id) {
214 if (last_available == nullptr) return; // No previous page available.
215 this->SetSelectedPage(last_available->index);
216 return;
217 }
218 last_available = p;
219 }
220 }
221
226 {
227 if (!StoryPage::IsValidID(this->selected_page_id)) return;
228
229 /* Find selected page. */
230 for (auto iter = this->story_pages.begin(); iter != this->story_pages.end(); iter++) {
231 const StoryPage *p = *iter;
232 if (p->index == this->selected_page_id) {
233 /* Select the page after selected page. */
234 iter++;
235 if (iter != this->story_pages.end()) {
236 this->SetSelectedPage((*iter)->index);
237 }
238 return;
239 }
240 }
241 }
242
247 {
248 DropDownList list;
249 uint16_t page_num = 1;
250 for (const StoryPage *p : this->story_pages) {
251 bool current_page = p->index == this->selected_page_id;
252 if (!p->title.empty()) {
253 list.push_back(MakeDropDownListStringItem(p->title.GetDecodedString(), p->index.base(), current_page));
254 } else {
255 /* No custom title => use a generic page title with page number. */
256 list.push_back(MakeDropDownListStringItem(GetString(STR_STORY_BOOK_GENERIC_PAGE_ITEM, page_num), p->index.base(), current_page));
257 }
258 page_num++;
259 }
260
261 return list;
262 }
263
268 {
269 return this->GetWidget<NWidgetCore>(WID_SB_PAGE_PANEL)->current_x - WidgetDimensions::scaled.frametext.Horizontal() - 1;
270 }
271
279 uint GetHeadHeight(int max_width) const
280 {
281 StoryPage *page = this->GetSelPage();
282 if (page == nullptr) return 0;
283 int height = 0;
284
285 /* Title lines */
286 height += GetCharacterHeight(FS_NORMAL); // Date always use exactly one line.
287 height += GetStringHeight(GetString(STR_STORY_BOOK_TITLE, !page->title.empty() ? page->title.GetDecodedString() : this->selected_generic_title), max_width);
288
289 return height;
290 }
291
299 {
300 switch (pe.type) {
301 case SPET_GOAL: {
303 if (g == nullptr) return SPR_IMG_GOAL_BROKEN_REF;
304 return g->completed ? SPR_IMG_GOAL_COMPLETED : SPR_IMG_GOAL;
305 }
306 case SPET_LOCATION:
307 return SPR_IMG_VIEW_LOCATION;
308 default:
309 NOT_REACHED();
310 }
311 }
312
319 uint GetPageElementHeight(const StoryPageElement &pe, int max_width) const
320 {
321 switch (pe.type) {
322 case SPET_TEXT:
323 return GetStringHeight(pe.text.GetDecodedString(), max_width);
324
325 case SPET_GOAL:
326 case SPET_LOCATION: {
328 return sprite_dim.height;
329 }
330
331 case SPET_BUTTON_PUSH:
332 case SPET_BUTTON_TILE:
333 case SPET_BUTTON_VEHICLE: {
335 return dim.height + WidgetDimensions::scaled.framerect.Vertical() + WidgetDimensions::scaled.frametext.Vertical();
336 }
337
338 default:
339 NOT_REACHED();
340 }
341 return 0;
342 }
343
349 ElementFloat GetPageElementFloat(const StoryPageElement &pe) const
350 {
351 switch (pe.type) {
352 case SPET_BUTTON_PUSH:
353 case SPET_BUTTON_TILE:
354 case SPET_BUTTON_VEHICLE: {
356 if (flags & SPBF_FLOAT_LEFT) return ElementFloat::Left;
357 if (flags & SPBF_FLOAT_RIGHT) return ElementFloat::Right;
358 return ElementFloat::None;
359 }
360
361 default:
362 return ElementFloat::None;
363 }
364 }
365
372 {
373 switch (pe.type) {
374 case SPET_BUTTON_PUSH:
375 case SPET_BUTTON_TILE:
376 case SPET_BUTTON_VEHICLE: {
378 return dim.width + WidgetDimensions::scaled.framerect.Vertical() + WidgetDimensions::scaled.frametext.Vertical();
379 }
380
381 default:
382 NOT_REACHED(); // only buttons can float
383 }
384 }
385
388 {
389 this->layout_cache.clear();
390 }
391
394 {
395 /* Assume if the layout cache has contents it is valid */
396 if (!this->layout_cache.empty()) return;
397
398 StoryPage *page = this->GetSelPage();
399 if (page == nullptr) return;
400 int max_width = GetAvailablePageContentWidth();
401 int element_dist = GetCharacterHeight(FS_NORMAL);
402
403 /* Make space for the header */
404 int main_y = GetHeadHeight(max_width) + element_dist;
405
406 /* Current bottom of left/right column */
407 int left_y = main_y;
408 int right_y = main_y;
409 /* Current width of left/right column, 0 indicates no content in column */
410 int left_width = 0;
411 int right_width = 0;
412 /* Indexes into element cache for yet unresolved floats */
413 std::vector<size_t> left_floats;
414 std::vector<size_t> right_floats;
415
416 /* Build layout */
417 for (const StoryPageElement *pe : this->story_page_elements) {
418 ElementFloat fl = this->GetPageElementFloat(*pe);
419
420 if (fl == ElementFloat::None) {
421 /* Verify available width */
422 const int min_required_width = 10 * GetCharacterHeight(FS_NORMAL);
423 int left_offset = (left_width == 0) ? 0 : (left_width + element_dist);
424 int right_offset = (right_width == 0) ? 0 : (right_width + element_dist);
425 if (left_offset + right_offset + min_required_width >= max_width) {
426 /* Width of floats leave too little for main content, push down */
427 main_y = std::max(main_y, left_y);
428 main_y = std::max(main_y, right_y);
429 left_width = right_width = 0;
430 left_offset = right_offset = 0;
431 /* Do not add element_dist here, to keep together elements which were supposed to float besides each other. */
432 }
433 /* Determine height */
434 const int available_width = max_width - left_offset - right_offset;
435 const int height = GetPageElementHeight(*pe, available_width);
436 /* Check for button that needs extra margin */
437 if (left_offset == 0 && right_offset == 0) {
438 switch (pe->type) {
439 case SPET_BUTTON_PUSH:
440 case SPET_BUTTON_TILE:
442 left_offset = right_offset = available_width / 5;
443 break;
444 default:
445 break;
446 }
447 }
448 /* Position element in main column */
449 LayoutCacheElement ce{ pe, {} };
450 ce.bounds.left = left_offset;
451 ce.bounds.right = max_width - right_offset;
452 ce.bounds.top = main_y;
453 main_y += height;
454 ce.bounds.bottom = main_y;
455 this->layout_cache.push_back(ce);
456 main_y += element_dist;
457 /* Clear all floats */
458 left_width = right_width = 0;
459 left_y = right_y = main_y = std::max({main_y, left_y, right_y});
460 left_floats.clear();
461 right_floats.clear();
462 } else {
463 /* Prepare references to correct column */
464 int &cur_width = (fl == ElementFloat::Left) ? left_width : right_width;
465 int &cur_y = (fl == ElementFloat::Left) ? left_y : right_y;
466 std::vector<size_t> &cur_floats = (fl == ElementFloat::Left) ? left_floats : right_floats;
467 /* Position element */
468 cur_width = std::max(cur_width, this->GetPageElementFloatWidth(*pe));
469 LayoutCacheElement ce{ pe, {} };
470 ce.bounds.left = (fl == ElementFloat::Left) ? 0 : (max_width - cur_width);
471 ce.bounds.right = (fl == ElementFloat::Left) ? cur_width : max_width;
472 ce.bounds.top = cur_y;
473 cur_y += GetPageElementHeight(*pe, cur_width);
474 ce.bounds.bottom = cur_y;
475 cur_floats.push_back(this->layout_cache.size());
476 this->layout_cache.push_back(ce);
477 cur_y += element_dist;
478 /* Update floats in column to all have the same width */
479 for (size_t index : cur_floats) {
480 LayoutCacheElement &ce = this->layout_cache[index];
481 ce.bounds.left = (fl == ElementFloat::Left) ? 0 : (max_width - cur_width);
482 ce.bounds.right = (fl == ElementFloat::Left) ? cur_width : max_width;
483 }
484 }
485 }
486 }
487
493 {
495
496 /* The largest bottom coordinate of any element is the height of the content */
497 int32_t max_y = std::accumulate(this->layout_cache.begin(), this->layout_cache.end(), 0, [](int32_t max_y, const LayoutCacheElement &ce) -> int32_t { return std::max<int32_t>(max_y, ce.bounds.bottom); });
498
499 return max_y;
500 }
501
512 void DrawActionElement(int &y_offset, int width, int line_height, SpriteID action_sprite, const std::string &text) const
513 {
514 Dimension sprite_dim = GetSpriteSize(action_sprite);
515 uint element_height = std::max(sprite_dim.height, (uint)line_height);
516
517 uint sprite_top = y_offset + (element_height - sprite_dim.height) / 2;
518 uint text_top = y_offset + (element_height - line_height) / 2;
519
520 DrawSprite(action_sprite, PAL_NONE, 0, sprite_top);
521 DrawString(sprite_dim.width + WidgetDimensions::scaled.frametext.left, width, text_top, text, TC_BLACK);
522
523 y_offset += element_height;
524 }
525
531 {
532 switch (pe.type) {
533 case SPET_TEXT:
534 /* Do nothing. */
535 break;
536
537 case SPET_LOCATION:
538 if (_ctrl_pressed) {
540 } else {
542 }
543 break;
544
545 case SPET_GOAL:
547 break;
548
549 case SPET_BUTTON_PUSH:
550 if (this->active_button_id != StoryPageElementID::Invalid()) ResetObjectToPlace();
551 this->active_button_id = pe.index;
552 this->SetTimeout();
554
555 Command<Commands::StoryPageButton>::Post(TileIndex{}, pe.index, VehicleID::Invalid());
556 break;
557
558 case SPET_BUTTON_TILE:
559 if (this->active_button_id == pe.index) {
561 this->active_button_id = StoryPageElementID::Invalid();
562 } else {
563 CursorID cursor = TranslateStoryPageButtonCursor(StoryPageButtonData{ pe.referenced_id }.GetCursor());
564 SetObjectToPlaceWnd(cursor, PAL_NONE, HT_RECT, this);
565 this->active_button_id = pe.index;
566 }
568 break;
569
571 if (this->active_button_id == pe.index) {
573 this->active_button_id = StoryPageElementID::Invalid();
574 } else {
575 CursorID cursor = TranslateStoryPageButtonCursor(StoryPageButtonData{ pe.referenced_id }.GetCursor());
576 SetObjectToPlaceWnd(cursor, PAL_NONE, HT_VEHICLE, this);
577 this->active_button_id = pe.index;
578 }
580 break;
581
582 default:
583 NOT_REACHED();
584 }
585 }
586
587public:
589 {
590 this->CreateNestedTree();
591 this->vscroll = this->GetScrollbar(WID_SB_SCROLLBAR);
593
594 /* Initialize page sort. */
595 this->story_pages.SetSortFuncs(StoryBookWindow::page_sorter_funcs);
596 this->story_pages.ForceRebuild();
597 this->BuildStoryPageList();
598 this->story_page_elements.SetSortFuncs(StoryBookWindow::page_element_sorter_funcs);
599 /* story_page_elements will get built by SetSelectedPage */
600
601 this->FinishInitNested(window_number);
602 this->owner = this->window_number;
603
604 /* Initialize selected vars. */
605 this->selected_generic_title.clear();
606 this->selected_page_id = StoryPageID::Invalid();
607
608 this->active_button_id = StoryPageElementID::Invalid();
609
610 this->OnInvalidateData(-1);
611 }
612
617 {
618 this->SetWidgetDisabledState(WID_SB_PREV_PAGE, story_pages.empty() || this->IsFirstPageSelected());
619 this->SetWidgetDisabledState(WID_SB_NEXT_PAGE, story_pages.empty() || this->IsLastPageSelected());
622 }
623
629 {
630 if (this->selected_page_id != page_index) {
631 if (this->active_button_id != 0) ResetObjectToPlace();
632 this->active_button_id = StoryPageElementID::Invalid();
633 this->selected_page_id = page_index;
634 this->RefreshSelectedPage();
636 }
637 }
638
639 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
640 {
641 switch (widget) {
642 case WID_SB_SEL_PAGE: {
643 const StoryPage *page = this->GetSelPage();
644 return page != nullptr && !page->title.empty() ? page->title.GetDecodedString() : this->selected_generic_title;
645 }
646
647 case WID_SB_CAPTION:
648 if (this->window_number == CompanyID::Invalid()) {
649 return GetString(STR_STORY_BOOK_SPECTATOR_CAPTION);
650 }
651 return GetString(STR_STORY_BOOK_CAPTION, this->window_number);
652
653 default:
654 return this->Window::GetWidgetString(widget, stringid);
655 }
656 }
657
658 void OnPaint() override
659 {
660 /* Detect if content has changed height. This can happen if a
661 * multi-line text contains eg. {COMPANY} and that company is
662 * renamed.
663 */
664 if (this->vscroll->GetCount() != this->GetContentHeight()) {
665 this->vscroll->SetCount(this->GetContentHeight());
668 }
669
670 this->DrawWidgets();
671 }
672
673 void DrawWidget(const Rect &r, WidgetID widget) const override
674 {
675 if (widget != WID_SB_PAGE_PANEL) return;
676
677 StoryPage *page = this->GetSelPage();
678 if (page == nullptr) return;
679
680 Rect fr = r.Shrink(WidgetDimensions::scaled.frametext);
681
682 /* Set up a clipping region for the panel. */
683 DrawPixelInfo tmp_dpi;
684 if (!FillDrawPixelInfo(&tmp_dpi, fr)) return;
685
686 AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi);
687
688 /* Draw content (now coordinates given to Draw** are local to the new clipping region). */
689 fr = fr.Translate(-fr.left, -fr.top);
690 int line_height = GetCharacterHeight(FS_NORMAL);
691 const int scrollpos = this->vscroll->GetPosition();
692 int y_offset = -scrollpos;
693
694 /* Date */
695 if (page->date != CalendarTime::INVALID_DATE) {
696 DrawString(0, fr.right, y_offset, GetString(STR_JUST_DATE_LONG, page->date), TC_BLACK);
697 }
698 y_offset += line_height;
699
700 /* Title */
701 y_offset = DrawStringMultiLine(0, fr.right, y_offset, fr.bottom,
702 GetString(STR_STORY_BOOK_TITLE, !page->title.empty() ? page->title.GetDecodedString() : this->selected_generic_title), TC_BLACK, SA_TOP | SA_HOR_CENTER);
703
704 /* Page elements */
706 for (const LayoutCacheElement &ce : this->layout_cache) {
707 if (ce.bounds.bottom - scrollpos < fr.top) continue;
708
709 y_offset = ce.bounds.top - scrollpos;
710 if (y_offset > fr.bottom) return;
711
712 switch (ce.pe->type) {
713 case SPET_TEXT:
714 DrawStringMultiLineWithClipping(ce.bounds.left, ce.bounds.right, ce.bounds.top - scrollpos, ce.bounds.bottom - scrollpos,
715 ce.pe->text.GetDecodedString(), TC_BLACK, SA_TOP | SA_LEFT);
716 break;
717
718 case SPET_GOAL: {
719 Goal *g = Goal::Get((GoalID) ce.pe->referenced_id);
720 DrawActionElement(y_offset, ce.bounds.right - ce.bounds.left, line_height, GetPageElementSprite(*ce.pe),
721 g == nullptr ? GetString(STR_STORY_BOOK_INVALID_GOAL_REF) : g->text.GetDecodedString());
722 break;
723 }
724
725 case SPET_LOCATION:
726 DrawActionElement(y_offset, ce.bounds.right - ce.bounds.left, line_height, GetPageElementSprite(*ce.pe),
727 ce.pe->text.GetDecodedString());
728 break;
729
730 case SPET_BUTTON_PUSH:
731 case SPET_BUTTON_TILE:
732 case SPET_BUTTON_VEHICLE: {
733 const int tmargin = WidgetDimensions::scaled.bevel.top + WidgetDimensions::scaled.frametext.top;
734 const FrameFlags frame = this->active_button_id == ce.pe->index ? FrameFlag::Lowered : FrameFlags{};
735 const Colours bgcolour = StoryPageButtonData{ ce.pe->referenced_id }.GetColour();
736
737 DrawFrameRect(ce.bounds.left, ce.bounds.top - scrollpos, ce.bounds.right, ce.bounds.bottom - scrollpos - 1, bgcolour, frame);
738
739 DrawString(ce.bounds.left + WidgetDimensions::scaled.bevel.left, ce.bounds.right - WidgetDimensions::scaled.bevel.right, ce.bounds.top + tmargin - scrollpos,
740 ce.pe->text.GetDecodedString(), TC_WHITE, SA_CENTER);
741 break;
742 }
743
744 default: NOT_REACHED();
745 }
746 }
747 }
748
749 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
750 {
751 if (widget != WID_SB_SEL_PAGE && widget != WID_SB_PAGE_PANEL) return;
752
753 Dimension d;
754 d.height = GetCharacterHeight(FS_NORMAL);
755 d.width = 0;
756
757 switch (widget) {
758 case WID_SB_SEL_PAGE: {
759
760 /* Get max title width. */
761 for (size_t i = 0; i < this->story_pages.size(); i++) {
762 const StoryPage *s = this->story_pages[i];
763 Dimension title_d = GetStringBoundingBox(s->title.empty() ? this->selected_generic_title : s->title.GetDecodedString());
764
765 if (title_d.width > d.width) {
766 d.width = title_d.width;
767 }
768 }
769
770 d.width += padding.width;
771 d.height += padding.height;
772 size = maxdim(size, d);
773 break;
774 }
775
776 case WID_SB_PAGE_PANEL: {
777 d.height *= 5;
778 d.height += padding.height + WidgetDimensions::scaled.frametext.Vertical();
779 size = maxdim(size, d);
780 break;
781 }
782 }
783
784 }
785
786 void OnResize() override
787 {
789 this->vscroll->SetCapacityFromWidget(this, WID_SB_PAGE_PANEL, WidgetDimensions::scaled.frametext.Vertical());
790 this->vscroll->SetCount(this->GetContentHeight());
791 }
792
793 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
794 {
795 switch (widget) {
796 case WID_SB_SEL_PAGE: {
797 DropDownList list = this->BuildDropDownList();
798 if (!list.empty()) {
799 /* Get the index of selected page. */
800 int selected = 0;
801 for (size_t i = 0; i < this->story_pages.size(); i++) {
802 const StoryPage *p = this->story_pages[i];
803 if (p->index == this->selected_page_id) break;
804 selected++;
805 }
806
807 ShowDropDownList(this, std::move(list), selected, widget);
808 }
809 break;
810 }
811
812 case WID_SB_PREV_PAGE:
813 this->SelectPrevPage();
814 break;
815
816 case WID_SB_NEXT_PAGE:
817 this->SelectNextPage();
818 break;
819
820 case WID_SB_PAGE_PANEL: {
821 int clicked_y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SB_PAGE_PANEL, WidgetDimensions::scaled.frametext.top);
823
824 for (const LayoutCacheElement &ce : this->layout_cache) {
825 if (clicked_y >= ce.bounds.top && clicked_y < ce.bounds.bottom && pt.x >= ce.bounds.left && pt.x < ce.bounds.right) {
826 this->OnPageElementClick(*ce.pe);
827 return;
828 }
829 }
830 }
831 }
832 }
833
834 void OnDropdownSelect(WidgetID widget, int index, int) override
835 {
836 if (widget != WID_SB_SEL_PAGE) return;
837
838 /* index (which is set in BuildDropDownList) is the page id. */
839 this->SetSelectedPage(static_cast<StoryPageID>(index));
840 }
841
849 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
850 {
851 if (!gui_scope) return;
852
853 /* If added/removed page, force rebuild. Sort order never change so just a
854 * re-sort is never needed.
855 */
856 if (data == -1) {
857 this->story_pages.ForceRebuild();
858 this->BuildStoryPageList();
859
860 /* Was the last page removed? */
861 if (this->story_pages.empty()) {
862 this->selected_generic_title.clear();
863 }
864
865 /* Verify page selection. */
866 if (!StoryPage::IsValidID(this->selected_page_id)) {
867 this->selected_page_id = StoryPageID::Invalid();
868 }
869 if (this->selected_page_id == StoryPageID::Invalid() && !this->story_pages.empty()) {
870 /* No page is selected, but there exist at least one available.
871 * => Select first page.
872 */
873 this->SetSelectedPage(this->story_pages[0]->index);
874 }
875
876 this->SetWidgetDisabledState(WID_SB_SEL_PAGE, this->story_pages.empty());
879 } else if (data >= 0 && this->selected_page_id == data) {
880 this->RefreshSelectedPage();
881 }
882 }
883
884 void OnTimeout() override
885 {
886 this->active_button_id = StoryPageElementID::Invalid();
888 }
889
890 void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
891 {
892 const StoryPageElement *const pe = StoryPageElement::GetIfValid(this->active_button_id);
893 if (pe == nullptr || pe->type != SPET_BUTTON_TILE) {
895 this->active_button_id = StoryPageElementID::Invalid();
897 return;
898 }
899
900 Command<Commands::StoryPageButton>::Post(tile, pe->index, VehicleID::Invalid());
902 }
903
904 bool OnVehicleSelect(const Vehicle *v) override
905 {
906 const StoryPageElement *const pe = StoryPageElement::GetIfValid(this->active_button_id);
907 if (pe == nullptr || pe->type != SPET_BUTTON_VEHICLE) {
909 this->active_button_id = StoryPageElementID::Invalid();
911 return false;
912 }
913
914 /* Check that the vehicle matches the requested type */
915 StoryPageButtonData data{ pe->referenced_id };
916 VehicleType wanted_vehtype = data.GetVehicleType();
917 if (wanted_vehtype != VEH_INVALID && wanted_vehtype != v->type) return false;
918
919 Command<Commands::StoryPageButton>::Post(TileIndex{}, pe->index, v->index);
921 return true;
922 }
923
924 void OnPlaceObjectAbort() override
925 {
926 this->active_button_id = StoryPageElementID::Invalid();
928 }
929};
930
931const std::initializer_list<GUIStoryPageList::SortFunction * const> StoryBookWindow::page_sorter_funcs = {
932 &PageOrderSorter,
933};
934
935const std::initializer_list<GUIStoryPageElementList::SortFunction * const> StoryBookWindow::page_element_sorter_funcs = {
936 &PageElementOrderSorter,
937};
938
939static constexpr std::initializer_list<NWidgetPart> _nested_story_book_widgets = {
941 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
942 NWidget(WWT_CAPTION, COLOUR_BROWN, WID_SB_CAPTION),
943 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
944 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
945 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
946 EndContainer(),
950 EndContainer(),
952 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_SB_PREV_PAGE), SetMinimalSize(100, 0), SetFill(0, 0), SetStringTip(STR_STORY_BOOK_PREV_PAGE, STR_STORY_BOOK_PREV_PAGE_TOOLTIP),
953 NWidget(NWID_BUTTON_DROPDOWN, COLOUR_BROWN, WID_SB_SEL_PAGE), SetMinimalSize(93, 12), SetFill(1, 0),
954 SetToolTip(STR_STORY_BOOK_SEL_PAGE_TOOLTIP), SetResize(1, 0),
955 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_SB_NEXT_PAGE), SetMinimalSize(100, 0), SetFill(0, 0), SetStringTip(STR_STORY_BOOK_NEXT_PAGE, STR_STORY_BOOK_NEXT_PAGE_TOOLTIP),
956 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
957 EndContainer(),
958};
959
960static WindowDesc _story_book_desc(
961 WDP_AUTO, "view_story", 400, 300,
963 {},
964 _nested_story_book_widgets
965);
966
967static WindowDesc _story_book_gs_desc(
968 WDP_CENTER, "view_story_gs", 400, 300,
970 {},
971 _nested_story_book_widgets
972);
973
974static CursorID TranslateStoryPageButtonCursor(StoryPageButtonCursor cursor)
975{
976 switch (cursor) {
977 case SPBC_MOUSE: return SPR_CURSOR_MOUSE;
978 case SPBC_ZZZ: return SPR_CURSOR_ZZZ;
979 case SPBC_BUOY: return SPR_CURSOR_BUOY;
980 case SPBC_QUERY: return SPR_CURSOR_QUERY;
981 case SPBC_HQ: return SPR_CURSOR_HQ;
982 case SPBC_SHIP_DEPOT: return SPR_CURSOR_SHIP_DEPOT;
983 case SPBC_SIGN: return SPR_CURSOR_SIGN;
984 case SPBC_TREE: return SPR_CURSOR_TREE;
985 case SPBC_BUY_LAND: return SPR_CURSOR_BUY_LAND;
986 case SPBC_LEVEL_LAND: return SPR_CURSOR_LEVEL_LAND;
987 case SPBC_TOWN: return SPR_CURSOR_TOWN;
988 case SPBC_INDUSTRY: return SPR_CURSOR_INDUSTRY;
989 case SPBC_ROCKY_AREA: return SPR_CURSOR_ROCKY_AREA;
990 case SPBC_DESERT: return SPR_CURSOR_DESERT;
991 case SPBC_TRANSMITTER: return SPR_CURSOR_TRANSMITTER;
992 case SPBC_AIRPORT: return SPR_CURSOR_AIRPORT;
993 case SPBC_DOCK: return SPR_CURSOR_DOCK;
994 case SPBC_CANAL: return SPR_CURSOR_CANAL;
995 case SPBC_LOCK: return SPR_CURSOR_LOCK;
996 case SPBC_RIVER: return SPR_CURSOR_RIVER;
997 case SPBC_AQUEDUCT: return SPR_CURSOR_AQUEDUCT;
998 case SPBC_BRIDGE: return SPR_CURSOR_BRIDGE;
999 case SPBC_RAIL_STATION: return SPR_CURSOR_RAIL_STATION;
1000 case SPBC_TUNNEL_RAIL: return SPR_CURSOR_TUNNEL_RAIL;
1001 case SPBC_TUNNEL_ELRAIL: return SPR_CURSOR_TUNNEL_ELRAIL;
1002 case SPBC_TUNNEL_MONO: return SPR_CURSOR_TUNNEL_MONO;
1003 case SPBC_TUNNEL_MAGLEV: return SPR_CURSOR_TUNNEL_MAGLEV;
1004 case SPBC_AUTORAIL: return SPR_CURSOR_AUTORAIL;
1005 case SPBC_AUTOELRAIL: return SPR_CURSOR_AUTOELRAIL;
1006 case SPBC_AUTOMONO: return SPR_CURSOR_AUTOMONO;
1007 case SPBC_AUTOMAGLEV: return SPR_CURSOR_AUTOMAGLEV;
1008 case SPBC_WAYPOINT: return SPR_CURSOR_WAYPOINT;
1009 case SPBC_RAIL_DEPOT: return SPR_CURSOR_RAIL_DEPOT;
1010 case SPBC_ELRAIL_DEPOT: return SPR_CURSOR_ELRAIL_DEPOT;
1011 case SPBC_MONO_DEPOT: return SPR_CURSOR_MONO_DEPOT;
1012 case SPBC_MAGLEV_DEPOT: return SPR_CURSOR_MAGLEV_DEPOT;
1013 case SPBC_CONVERT_RAIL: return SPR_CURSOR_CONVERT_RAIL;
1014 case SPBC_CONVERT_ELRAIL: return SPR_CURSOR_CONVERT_ELRAIL;
1015 case SPBC_CONVERT_MONO: return SPR_CURSOR_CONVERT_MONO;
1016 case SPBC_CONVERT_MAGLEV: return SPR_CURSOR_CONVERT_MAGLEV;
1017 case SPBC_AUTOROAD: return SPR_CURSOR_AUTOROAD;
1018 case SPBC_AUTOTRAM: return SPR_CURSOR_AUTOTRAM;
1019 case SPBC_ROAD_DEPOT: return SPR_CURSOR_ROAD_DEPOT;
1020 case SPBC_BUS_STATION: return SPR_CURSOR_BUS_STATION;
1021 case SPBC_TRUCK_STATION: return SPR_CURSOR_TRUCK_STATION;
1022 case SPBC_ROAD_TUNNEL: return SPR_CURSOR_ROAD_TUNNEL;
1023 case SPBC_CLONE_TRAIN: return SPR_CURSOR_CLONE_TRAIN;
1024 case SPBC_CLONE_ROADVEH: return SPR_CURSOR_CLONE_ROADVEH;
1025 case SPBC_CLONE_SHIP: return SPR_CURSOR_CLONE_SHIP;
1026 case SPBC_CLONE_AIRPLANE: return SPR_CURSOR_CLONE_AIRPLANE;
1027 case SPBC_DEMOLISH: return ANIMCURSOR_DEMOLISH;
1028 case SPBC_LOWERLAND: return ANIMCURSOR_LOWERLAND;
1029 case SPBC_RAISELAND: return ANIMCURSOR_RAISELAND;
1030 case SPBC_PICKSTATION: return ANIMCURSOR_PICKSTATION;
1031 case SPBC_BUILDSIGNALS: return ANIMCURSOR_BUILDSIGNALS;
1032 default: return SPR_CURSOR_QUERY;
1033 }
1034}
1035
1042void ShowStoryBook(CompanyID company, StoryPageID page_id, bool centered)
1043{
1044 if (!Company::IsValidID(company)) company = (CompanyID)CompanyID::Invalid();
1045
1046 StoryBookWindow *w = AllocateWindowDescFront<StoryBookWindow, true>(centered ? _story_book_gs_desc : _story_book_desc, company);
1047 if (page_id != StoryPageID::Invalid()) w->SetSelectedPage(page_id);
1048}
@ None
Tile is not animated.
std::string GetDecodedString() const
Decode the encoded string.
Definition strings.cpp:207
List template of 'things' T to sort in a GUI.
void RebuildDone()
Notify the sortlist that the rebuild is done.
bool NeedRebuild() const
Check if a rebuild is needed.
void ForceRebuild()
Force that a rebuild is needed.
bool Sort(Comp compare)
Sort the list.
void SetSortFuncs(std::span< SortFunction *const > n_funcs)
Hand the sort function pointers to the GUIList.
Scrollbar data structure.
void SetCount(size_t num)
Sets the number of elements in the list.
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:2426
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:2500
size_type GetCount() const
Gets the number of elements in the list.
void SetStepSize(size_t stepsize)
Set the distance to scroll when using the buttons or the wheel.
size_type GetPosition() const
Gets the position of the first visible element in the list.
static constexpr TimerGame< struct Calendar >::Date INVALID_DATE
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
Functions related to commands.
Definition of stuff that is very close to a company, like the company struct itself.
Functions related to companies.
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, DropDownOptions options)
Show a drop down list.
Definition dropdown.cpp:419
Functions related to the drop down widget.
Types related to the drop down widget.
std::vector< std::unique_ptr< const DropDownListItem > > DropDownList
A drop down list is a collection of drop down list items.
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:87
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition gfx.cpp:717
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:972
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 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
bool DrawStringMultiLineWithClipping(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw a multiline string, possibly over multiple lines, if the region is within the current display cl...
Definition gfx.cpp:873
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition gfx.cpp:788
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
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:249
uint32_t CursorID
The number of the cursor (sprite).
Definition gfx_type.h:19
@ SA_TOP
Top align the text.
Definition gfx_type.h:393
@ SA_LEFT
Left align the text.
Definition gfx_type.h:388
@ SA_HOR_CENTER
Horizontally center the text.
Definition gfx_type.h:389
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:398
Goal base class.
void ShowGoalsList(CompanyID company)
Open a goal list window.
Definition goal_gui.cpp:310
PoolID< uint16_t, struct GoalIDTag, 64000, 0xFFFF > GoalID
ID of a goal.
Definition goal_type.h:38
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to 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 SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
GUI functions that shouldn't be here.
void ShowExtraViewportWindow(TileIndex tile=INVALID_TILE)
Show a new Extra Viewport window.
#define Point
Macro that prevents name conflicts between included headers.
A number of safeguards to prevent using unsafe methods.
Base types for having sorted lists in GUIs.
This file contains all sprite-related enums and defines.
static const CursorID ANIMCURSOR_PICKSTATION
716 - 718 - goto-order icon
Definition sprites.h:1525
static const CursorID ANIMCURSOR_BUILDSIGNALS
1292 - 1293 - build signal
Definition sprites.h:1526
static const CursorID SPR_CURSOR_MOUSE
Cursor sprite numbers.
Definition sprites.h:1404
static const CursorID ANIMCURSOR_DEMOLISH
704 - 707 - demolish dynamite
Definition sprites.h:1522
static const CursorID ANIMCURSOR_LOWERLAND
699 - 701 - lower land tool
Definition sprites.h:1523
static const CursorID ANIMCURSOR_RAISELAND
696 - 698 - raise land tool
Definition sprites.h:1524
Definition of base types and functions in a cross-platform compatible way.
StoryPage base class.
StoryPageButtonFlags
Flags available for buttons.
Definition story_base.h:43
@ SPET_LOCATION
An element that references a tile along with a one-line text.
Definition story_base.h:33
@ SPET_GOAL
An element that references a goal.
Definition story_base.h:34
@ SPET_BUTTON_PUSH
A push button that triggers an immediate event.
Definition story_base.h:35
@ SPET_BUTTON_TILE
A button that allows the player to select a tile, and triggers an event with the tile.
Definition story_base.h:36
@ SPET_TEXT
A text element.
Definition story_base.h:32
@ SPET_BUTTON_VEHICLE
A button that allows the player to select a vehicle, and triggers an event with the vehicle.
Definition story_base.h:37
StoryPageButtonCursor
Mouse cursors usable by story page buttons.
Definition story_base.h:51
Command definitions related to stories.
void ShowStoryBook(CompanyID company, StoryPageID page_id, bool centered)
Raise or create the story book window for company, at page page_id.
PoolID< uint16_t, struct StoryPageIDTag, 64000, 0xFFFF > StoryPageID
ID of a story page.
Definition story_type.h:16
PoolID< uint16_t, struct StoryPageElementIDTag, 64000, 0xFFFF > StoryPageElementID
ID of a story page element.
Definition story_type.h:15
Types related to the story widgets.
@ WID_SB_PAGE_PANEL
Page body.
@ WID_SB_SEL_PAGE
Page selector.
@ WID_SB_SCROLLBAR
Scrollbar of the goal list.
@ WID_SB_CAPTION
Caption of the window.
@ WID_SB_PREV_PAGE
Prev button.
@ WID_SB_NEXT_PAGE
Next button.
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
VehicleType type
Type of vehicle.
Dimensions (a width and height) of a rectangle in 2D.
Data about how and where to blit pixels.
Definition gfx_type.h:157
Struct about goals, current and completed.
Definition goal_base.h:22
EncodedString text
Text of the goal.
Definition goal_base.h:26
bool completed
Is the goal completed or not?
Definition goal_base.h:28
static Pool::IterateWrapper< StoryPage > Iterate(size_t from=0)
static StoryPage * Get(auto index)
static StoryPageElement * GetIfValid(auto index)
Specification of a rectangle with absolute coordinates of all edges.
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.
void OnTimeout() override
Called when this window's timeout has been reached.
void BuildStoryPageList()
(Re)Build story page list.
Definition story_gui.cpp:69
void OnPlaceObjectAbort() override
The user cancelled a tile highlight mode that has been set.
std::string selected_generic_title
If the selected page doesn't have a custom title, this buffer is used to store a generic page title.
Definition story_gui.cpp:61
void OnPageElementClick(const StoryPageElement &pe)
Internal event handler for when a page element is clicked.
void OnResize() override
Called after the window got resized.
static bool PageElementOrderSorter(const StoryPageElement *const &a, const StoryPageElement *const &b)
Sort story page elements by order value.
uint GetAvailablePageContentWidth() const
Get the width available for displaying content on the page panel.
void OnPaint() override
The window must be repainted.
void SetSelectedPage(StoryPageID page_index)
Sets the selected page.
bool IsFirstPageSelected()
Check if the selected page is also the first available page.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
DropDownList BuildDropDownList() const
Builds the page selector drop down list.
int GetPageElementFloatWidth(const StoryPageElement &pe) const
Get the width a page element would use if it was floating left or right.
LayoutCache layout_cache
Cached element layout.
Definition story_gui.cpp:56
void UpdatePrevNextDisabledState()
Updates the disabled state of the prev/next buttons.
Scrollbar * vscroll
Scrollbar of the page text.
Definition story_gui.cpp:55
void OnDropdownSelect(WidgetID widget, int index, int) override
A dropdown option associated to this window has been selected.
void SelectNextPage()
Selects the next available page after the currently selected page.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
void SelectPrevPage()
Selects the previous available page before the currently selected page.
void RefreshSelectedPage()
Updates the content of selected page.
StoryPageID selected_page_id
Pool index of selected page.
Definition story_gui.cpp:60
bool IsLastPageSelected()
Check if the selected page is also the last available page.
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.
GUIStoryPageList story_pages
Sorted list of pages.
Definition story_gui.cpp:58
void InvalidateStoryPageElementLayout()
Invalidate the current page layout.
void DrawActionElement(int &y_offset, int width, int line_height, SpriteID action_sprite, const std::string &text) const
Draws a page element that is composed of a sprite to the left and a single line of text after that.
void BuildStoryPageElementList()
(Re)Build story page element list.
Definition story_gui.cpp:93
StoryPage * GetSelPage() const
Get instance of selected page.
static bool PageOrderSorter(const StoryPage *const &a, const StoryPage *const &b)
Sort story pages by order value.
Definition story_gui.cpp:87
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
StoryPageElementID active_button_id
Which button element the player is currently using.
Definition story_gui.cpp:63
int32_t GetContentHeight()
Get the total height of the content displayed in this window.
uint GetHeadHeight(int max_width) const
Counts how many pixels of height that are used by Date and Title (excluding marginal after Title,...
uint GetPageElementHeight(const StoryPageElement &pe, int max_width) const
Get the height in pixels used by a page element.
int GetSelPageNum() const
Get the page number of selected page.
void OnPlaceObject(Point pt, TileIndex tile) override
The user clicked some place on the map when a tile highlight mode has been set.
SpriteID GetPageElementSprite(const StoryPageElement &pe) const
Decides which sprite to display for a given page element.
void EnsureStoryPageElementLayout() const
Create the page layout if it is missing.
GUIStoryPageElementList story_page_elements
Sorted list of page elements that belong to the current page.
Definition story_gui.cpp:59
ElementFloat GetPageElementFloat(const StoryPageElement &pe) const
Get the float style of a page element.
Helper to construct packed "id" values for button-type StoryPageElement.
Definition story_base.h:123
Colours GetColour() const
Get the button background colour.
Definition story.cpp:172
VehicleType GetVehicleType() const
Get the type of vehicles that are accepted by the button.
Definition story.cpp:203
StoryPageButtonFlags GetFlags() const
Get the button flags.
Definition story.cpp:183
StoryPageButtonCursor GetCursor() const
Get the mouse cursor used while waiting for input for the button.
Definition story.cpp:192
Struct about story page elements.
Definition story_base.h:145
uint32_t referenced_id
Id of referenced object (location, goal etc.).
Definition story_base.h:150
EncodedString text
Static content text of page element.
Definition story_base.h:151
uint32_t sort_value
A number that increases for every created story page element. Used for sorting. The id of a story pag...
Definition story_base.h:146
StoryPageElementType type
Type of page element.
Definition story_base.h:148
Struct about stories, current and completed.
Definition story_base.h:164
EncodedString title
Title of story page.
Definition story_base.h:169
uint32_t sort_value
A number that increases for every created story page. Used for sorting. The id of a story page is the...
Definition story_base.h:165
CompanyID company
StoryPage is for a specific company; CompanyID::Invalid() if it is global.
Definition story_base.h:167
TimerGameCalendar::Date date
Date when the page was created.
Definition story_base.h:166
Vehicle data structure.
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:1809
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:766
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:557
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:505
ResizeInfo resize
Resize information.
Definition window_gui.h:315
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1799
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition window_gui.h:317
void SetTimeout()
Set the timeout flag of the window and initiate the timer.
Definition window_gui.h:356
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition window.cpp:1832
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:986
WindowFlags flags
Window flags.
Definition window_gui.h:301
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: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
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
Functions related to tile highlights.
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w)
Change the cursor and mouse click/drag handling to a mode for performing special operations like tile...
@ HT_RECT
rectangle (stations, depots, ...)
@ HT_VEHICLE
vehicle is accepted as target as well (bitmask)
Base class for all vehicles.
VehicleType
Available vehicle types.
@ VEH_INVALID
Non-existing type of vehicle.
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Functions related to (drawing on) viewports.
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition widget.cpp:289
@ NWID_BUTTON_DROPDOWN
Button with a drop-down.
Definition widget_type.h:74
@ 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_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
@ WWT_CLOSEBOX
Close box (at top-left of a window).
Definition widget_type.h:60
@ 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
Window functions not directly related to making/drawing windows.
Functions, definitions and such used only by the GUI.
@ Lowered
If set the frame is lowered and the background colour brighter (ie. buttons when pressed).
Definition window_gui.h:27
Twindow * AllocateWindowDescFront(WindowDesc &desc, WindowNumber window_number, Targs... extra_arguments)
Open a new window.
@ WDP_CENTER
Center the window.
Definition window_gui.h:145
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:144
int WidgetID
Widget ID.
Definition window_type.h:20
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:50
@ WC_STORY_BOOK
Story book; Window numbers: