OpenTTD Source: src/story_gui.cpp Source File

OpenTTD Source 15.3

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
10#include "stdafx.h"
11#include "window_gui.h"
12#include "strings_func.h"
13#include "gui.h"
14#include "story_base.h"
15#include "core/geometry_func.hpp"
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
29#include "widgets/story_widget.h"
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
41 struct StoryBookWindow : Window {
42protected:
43 struct LayoutCacheElement {
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{};
60 StoryPageID selected_page_id{};
61 std::string selected_generic_title{};
62
63 StoryPageElementID active_button_id{};
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
69 void BuildStoryPageList()
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
93 void BuildStoryPageElementList()
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();
111 this->InvalidateStoryPageElementLayout();
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
134 StoryPage *GetSelPage() const
135 {
136 if (!StoryPage::IsValidID(selected_page_id)) return nullptr;
137 return StoryPage::Get(selected_page_id);
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
159 bool IsFirstPageSelected()
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
170 bool IsLastPageSelected()
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
183 void RefreshSelectedPage()
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();
192 this->BuildStoryPageElementList();
193
194 if (this->active_button_id != StoryPageElementID::Invalid()) ResetObjectToPlace();
195
196 this->vscroll->SetCount(this->GetContentHeight());
197 this->SetWidgetDirty(WID_SB_SCROLLBAR);
198 this->SetWidgetDirty(WID_SB_SEL_PAGE);
199 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
200 }
201
205 void SelectPrevPage()
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
225 void SelectNextPage()
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
246 DropDownList BuildDropDownList() const
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
267 uint GetAvailablePageContentWidth() const
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
298 SpriteID GetPageElementSprite(const StoryPageElement &pe) const
299 {
300 switch (pe.type) {
301 case SPET_GOAL: {
302 Goal *g = Goal::Get((GoalID) pe.referenced_id);
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: {
327 Dimension sprite_dim = GetSpriteSize(GetPageElementSprite(pe));
328 return sprite_dim.height;
329 }
330
331 case SPET_BUTTON_PUSH:
332 case SPET_BUTTON_TILE:
333 case SPET_BUTTON_VEHICLE: {
334 Dimension dim = GetStringBoundingBox(pe.text.GetDecodedString(), FS_NORMAL);
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: {
355 StoryPageButtonFlags flags = StoryPageButtonData{ pe.referenced_id }.GetFlags();
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
371 int GetPageElementFloatWidth(const StoryPageElement &pe) const
372 {
373 switch (pe.type) {
374 case SPET_BUTTON_PUSH:
375 case SPET_BUTTON_TILE:
376 case SPET_BUTTON_VEHICLE: {
377 Dimension dim = GetStringBoundingBox(pe.text.GetDecodedString(), FS_NORMAL);
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
387 void InvalidateStoryPageElementLayout()
388 {
389 this->layout_cache.clear();
390 }
391
393 void EnsureStoryPageElementLayout() const
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:
441 case SPET_BUTTON_VEHICLE:
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
492 int32_t GetContentHeight()
493 {
494 this->EnsureStoryPageElementLayout();
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
513 void DrawActionElement(int &y_offset, int width, int line_height, SpriteID action_sprite, const std::string &text) const
514 {
515 Dimension sprite_dim = GetSpriteSize(action_sprite);
516 uint element_height = std::max(sprite_dim.height, (uint)line_height);
517
518 uint sprite_top = y_offset + (element_height - sprite_dim.height) / 2;
519 uint text_top = y_offset + (element_height - line_height) / 2;
520
521 DrawSprite(action_sprite, PAL_NONE, 0, sprite_top);
522 DrawString(sprite_dim.width + WidgetDimensions::scaled.frametext.left, width, text_top, text, TC_BLACK);
523
524 y_offset += element_height;
525 }
526
531 void OnPageElementClick(const StoryPageElement &pe)
532 {
533 switch (pe.type) {
534 case SPET_TEXT:
535 /* Do nothing. */
536 break;
537
538 case SPET_LOCATION:
539 if (_ctrl_pressed) {
540 ShowExtraViewportWindow((TileIndex)pe.referenced_id);
541 } else {
542 ScrollMainWindowToTile((TileIndex)pe.referenced_id);
543 }
544 break;
545
546 case SPET_GOAL:
547 ShowGoalsList(this->window_number);
548 break;
549
550 case SPET_BUTTON_PUSH:
551 if (this->active_button_id != StoryPageElementID::Invalid()) ResetObjectToPlace();
552 this->active_button_id = pe.index;
553 this->SetTimeout();
554 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
555
556 Command<CMD_STORY_PAGE_BUTTON>::Post(TileIndex{}, pe.index, VehicleID::Invalid());
557 break;
558
559 case SPET_BUTTON_TILE:
560 if (this->active_button_id == pe.index) {
561 ResetObjectToPlace();
562 this->active_button_id = StoryPageElementID::Invalid();
563 } else {
564 CursorID cursor = TranslateStoryPageButtonCursor(StoryPageButtonData{ pe.referenced_id }.GetCursor());
565 SetObjectToPlaceWnd(cursor, PAL_NONE, HT_RECT, this);
566 this->active_button_id = pe.index;
567 }
568 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
569 break;
570
571 case SPET_BUTTON_VEHICLE:
572 if (this->active_button_id == pe.index) {
573 ResetObjectToPlace();
574 this->active_button_id = StoryPageElementID::Invalid();
575 } else {
576 CursorID cursor = TranslateStoryPageButtonCursor(StoryPageButtonData{ pe.referenced_id }.GetCursor());
577 SetObjectToPlaceWnd(cursor, PAL_NONE, HT_VEHICLE, this);
578 this->active_button_id = pe.index;
579 }
580 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
581 break;
582
583 default:
584 NOT_REACHED();
585 }
586 }
587
588public:
589 StoryBookWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
590 {
591 this->CreateNestedTree();
592 this->vscroll = this->GetScrollbar(WID_SB_SCROLLBAR);
593 this->vscroll->SetStepSize(GetCharacterHeight(FS_NORMAL));
594
595 /* Initialize page sort. */
596 this->story_pages.SetSortFuncs(StoryBookWindow::page_sorter_funcs);
597 this->story_pages.ForceRebuild();
598 this->BuildStoryPageList();
599 this->story_page_elements.SetSortFuncs(StoryBookWindow::page_element_sorter_funcs);
600 /* story_page_elements will get built by SetSelectedPage */
601
602 this->FinishInitNested(window_number);
603 this->owner = this->window_number;
604
605 /* Initialize selected vars. */
606 this->selected_generic_title.clear();
607 this->selected_page_id = StoryPageID::Invalid();
608
609 this->active_button_id = StoryPageElementID::Invalid();
610
611 this->OnInvalidateData(-1);
612 }
613
617 void UpdatePrevNextDisabledState()
618 {
619 this->SetWidgetDisabledState(WID_SB_PREV_PAGE, story_pages.empty() || this->IsFirstPageSelected());
620 this->SetWidgetDisabledState(WID_SB_NEXT_PAGE, story_pages.empty() || this->IsLastPageSelected());
621 this->SetWidgetDirty(WID_SB_PREV_PAGE);
622 this->SetWidgetDirty(WID_SB_NEXT_PAGE);
623 }
624
629 void SetSelectedPage(StoryPageID page_index)
630 {
631 if (this->selected_page_id != page_index) {
632 if (this->active_button_id != 0) ResetObjectToPlace();
633 this->active_button_id = StoryPageElementID::Invalid();
634 this->selected_page_id = page_index;
635 this->RefreshSelectedPage();
636 this->UpdatePrevNextDisabledState();
637 }
638 }
639
640 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
641 {
642 switch (widget) {
643 case WID_SB_SEL_PAGE: {
644 const StoryPage *page = this->GetSelPage();
645 return page != nullptr && !page->title.empty() ? page->title.GetDecodedString() : this->selected_generic_title;
646 }
647
648 case WID_SB_CAPTION:
649 if (this->window_number == CompanyID::Invalid()) {
650 return GetString(STR_STORY_BOOK_SPECTATOR_CAPTION);
651 }
652 return GetString(STR_STORY_BOOK_CAPTION, this->window_number);
653
654 default:
655 return this->Window::GetWidgetString(widget, stringid);
656 }
657 }
658
659 void OnPaint() override
660 {
661 /* Detect if content has changed height. This can happen if a
662 * multi-line text contains eg. {COMPANY} and that company is
663 * renamed.
664 */
665 if (this->vscroll->GetCount() != this->GetContentHeight()) {
666 this->vscroll->SetCount(this->GetContentHeight());
667 this->SetWidgetDirty(WID_SB_SCROLLBAR);
668 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
669 }
670
671 this->DrawWidgets();
672 }
673
674 void DrawWidget(const Rect &r, WidgetID widget) const override
675 {
676 if (widget != WID_SB_PAGE_PANEL) return;
677
678 StoryPage *page = this->GetSelPage();
679 if (page == nullptr) return;
680
681 Rect fr = r.Shrink(WidgetDimensions::scaled.frametext);
682
683 /* Set up a clipping region for the panel. */
684 DrawPixelInfo tmp_dpi;
685 if (!FillDrawPixelInfo(&tmp_dpi, fr)) return;
686
687 AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi);
688
689 /* Draw content (now coordinates given to Draw** are local to the new clipping region). */
690 fr = fr.Translate(-fr.left, -fr.top);
691 int line_height = GetCharacterHeight(FS_NORMAL);
692 const int scrollpos = this->vscroll->GetPosition();
693 int y_offset = -scrollpos;
694
695 /* Date */
696 if (page->date != CalendarTime::INVALID_DATE) {
697 DrawString(0, fr.right, y_offset, GetString(STR_JUST_DATE_LONG, page->date), TC_BLACK);
698 }
699 y_offset += line_height;
700
701 /* Title */
702 y_offset = DrawStringMultiLine(0, fr.right, y_offset, fr.bottom,
703 GetString(STR_STORY_BOOK_TITLE, !page->title.empty() ? page->title.GetDecodedString() : this->selected_generic_title), TC_BLACK, SA_TOP | SA_HOR_CENTER);
704
705 /* Page elements */
706 this->EnsureStoryPageElementLayout();
707 for (const LayoutCacheElement &ce : this->layout_cache) {
708 if (ce.bounds.bottom - scrollpos < fr.top) continue;
709
710 y_offset = ce.bounds.top - scrollpos;
711 if (y_offset > fr.bottom) return;
712
713 switch (ce.pe->type) {
714 case SPET_TEXT:
715 DrawStringMultiLineWithClipping(ce.bounds.left, ce.bounds.right, ce.bounds.top - scrollpos, ce.bounds.bottom - scrollpos,
716 ce.pe->text.GetDecodedString(), TC_BLACK, SA_TOP | SA_LEFT);
717 break;
718
719 case SPET_GOAL: {
720 Goal *g = Goal::Get((GoalID) ce.pe->referenced_id);
721 DrawActionElement(y_offset, ce.bounds.right - ce.bounds.left, line_height, GetPageElementSprite(*ce.pe),
722 g == nullptr ? GetString(STR_STORY_BOOK_INVALID_GOAL_REF) : g->text.GetDecodedString());
723 break;
724 }
725
726 case SPET_LOCATION:
727 DrawActionElement(y_offset, ce.bounds.right - ce.bounds.left, line_height, GetPageElementSprite(*ce.pe),
728 ce.pe->text.GetDecodedString());
729 break;
730
731 case SPET_BUTTON_PUSH:
732 case SPET_BUTTON_TILE:
733 case SPET_BUTTON_VEHICLE: {
734 const int tmargin = WidgetDimensions::scaled.bevel.top + WidgetDimensions::scaled.frametext.top;
735 const FrameFlags frame = this->active_button_id == ce.pe->index ? FrameFlag::Lowered : FrameFlags{};
736 const Colours bgcolour = StoryPageButtonData{ ce.pe->referenced_id }.GetColour();
737
738 DrawFrameRect(ce.bounds.left, ce.bounds.top - scrollpos, ce.bounds.right, ce.bounds.bottom - scrollpos - 1, bgcolour, frame);
739
740 DrawString(ce.bounds.left + WidgetDimensions::scaled.bevel.left, ce.bounds.right - WidgetDimensions::scaled.bevel.right, ce.bounds.top + tmargin - scrollpos,
741 ce.pe->text.GetDecodedString(), TC_WHITE, SA_CENTER);
742 break;
743 }
744
745 default: NOT_REACHED();
746 }
747 }
748 }
749
750 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
751 {
752 if (widget != WID_SB_SEL_PAGE && widget != WID_SB_PAGE_PANEL) return;
753
754 Dimension d;
755 d.height = GetCharacterHeight(FS_NORMAL);
756 d.width = 0;
757
758 switch (widget) {
759 case WID_SB_SEL_PAGE: {
760
761 /* Get max title width. */
762 for (size_t i = 0; i < this->story_pages.size(); i++) {
763 const StoryPage *s = this->story_pages[i];
764 Dimension title_d = GetStringBoundingBox(s->title.empty() ? this->selected_generic_title : s->title.GetDecodedString());
765
766 if (title_d.width > d.width) {
767 d.width = title_d.width;
768 }
769 }
770
771 d.width += padding.width;
772 d.height += padding.height;
773 size = maxdim(size, d);
774 break;
775 }
776
777 case WID_SB_PAGE_PANEL: {
778 d.height *= 5;
779 d.height += padding.height + WidgetDimensions::scaled.frametext.Vertical();
780 size = maxdim(size, d);
781 break;
782 }
783 }
784
785 }
786
787 void OnResize() override
788 {
789 this->InvalidateStoryPageElementLayout();
790 this->vscroll->SetCapacityFromWidget(this, WID_SB_PAGE_PANEL, WidgetDimensions::scaled.frametext.Vertical());
791 this->vscroll->SetCount(this->GetContentHeight());
792 }
793
794 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
795 {
796 switch (widget) {
797 case WID_SB_SEL_PAGE: {
798 DropDownList list = this->BuildDropDownList();
799 if (!list.empty()) {
800 /* Get the index of selected page. */
801 int selected = 0;
802 for (size_t i = 0; i < this->story_pages.size(); i++) {
803 const StoryPage *p = this->story_pages[i];
804 if (p->index == this->selected_page_id) break;
805 selected++;
806 }
807
808 ShowDropDownList(this, std::move(list), selected, widget);
809 }
810 break;
811 }
812
813 case WID_SB_PREV_PAGE:
814 this->SelectPrevPage();
815 break;
816
817 case WID_SB_NEXT_PAGE:
818 this->SelectNextPage();
819 break;
820
821 case WID_SB_PAGE_PANEL: {
822 int clicked_y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SB_PAGE_PANEL, WidgetDimensions::scaled.frametext.top);
823 this->EnsureStoryPageElementLayout();
824
825 for (const LayoutCacheElement &ce : this->layout_cache) {
826 if (clicked_y >= ce.bounds.top && clicked_y < ce.bounds.bottom && pt.x >= ce.bounds.left && pt.x < ce.bounds.right) {
827 this->OnPageElementClick(*ce.pe);
828 return;
829 }
830 }
831 }
832 }
833 }
834
835 void OnDropdownSelect(WidgetID widget, int index, int) override
836 {
837 if (widget != WID_SB_SEL_PAGE) return;
838
839 /* index (which is set in BuildDropDownList) is the page id. */
840 this->SetSelectedPage(static_cast<StoryPageID>(index));
841 }
842
850 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
851 {
852 if (!gui_scope) return;
853
854 /* If added/removed page, force rebuild. Sort order never change so just a
855 * re-sort is never needed.
856 */
857 if (data == -1) {
858 this->story_pages.ForceRebuild();
859 this->BuildStoryPageList();
860
861 /* Was the last page removed? */
862 if (this->story_pages.empty()) {
863 this->selected_generic_title.clear();
864 }
865
866 /* Verify page selection. */
867 if (!StoryPage::IsValidID(this->selected_page_id)) {
868 this->selected_page_id = StoryPageID::Invalid();
869 }
870 if (this->selected_page_id == StoryPageID::Invalid() && !this->story_pages.empty()) {
871 /* No page is selected, but there exist at least one available.
872 * => Select first page.
873 */
874 this->SetSelectedPage(this->story_pages[0]->index);
875 }
876
877 this->SetWidgetDisabledState(WID_SB_SEL_PAGE, this->story_pages.empty());
878 this->SetWidgetDirty(WID_SB_SEL_PAGE);
879 this->UpdatePrevNextDisabledState();
880 } else if (data >= 0 && this->selected_page_id == data) {
881 this->RefreshSelectedPage();
882 }
883 }
884
885 void OnTimeout() override
886 {
887 this->active_button_id = StoryPageElementID::Invalid();
888 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
889 }
890
891 void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
892 {
893 const StoryPageElement *const pe = StoryPageElement::GetIfValid(this->active_button_id);
894 if (pe == nullptr || pe->type != SPET_BUTTON_TILE) {
895 ResetObjectToPlace();
896 this->active_button_id = StoryPageElementID::Invalid();
897 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
898 return;
899 }
900
901 Command<CMD_STORY_PAGE_BUTTON>::Post(tile, pe->index, VehicleID::Invalid());
902 ResetObjectToPlace();
903 }
904
905 bool OnVehicleSelect(const Vehicle *v) override
906 {
907 const StoryPageElement *const pe = StoryPageElement::GetIfValid(this->active_button_id);
908 if (pe == nullptr || pe->type != SPET_BUTTON_VEHICLE) {
909 ResetObjectToPlace();
910 this->active_button_id = StoryPageElementID::Invalid();
911 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
912 return false;
913 }
914
915 /* Check that the vehicle matches the requested type */
916 StoryPageButtonData data{ pe->referenced_id };
917 VehicleType wanted_vehtype = data.GetVehicleType();
918 if (wanted_vehtype != VEH_INVALID && wanted_vehtype != v->type) return false;
919
920 Command<CMD_STORY_PAGE_BUTTON>::Post(TileIndex{}, pe->index, v->index);
921 ResetObjectToPlace();
922 return true;
923 }
924
925 void OnPlaceObjectAbort() override
926 {
927 this->active_button_id = StoryPageElementID::Invalid();
928 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
929 }
930};
931
932const std::initializer_list<GUIStoryPageList::SortFunction * const> StoryBookWindow::page_sorter_funcs = {
933 &PageOrderSorter,
934};
935
936const std::initializer_list<GUIStoryPageElementList::SortFunction * const> StoryBookWindow::page_element_sorter_funcs = {
937 &PageElementOrderSorter,
938};
939
940static constexpr std::initializer_list<NWidgetPart> _nested_story_book_widgets = {
941 NWidget(NWID_HORIZONTAL),
942 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
943 NWidget(WWT_CAPTION, COLOUR_BROWN, WID_SB_CAPTION),
944 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
945 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
946 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
947 EndContainer(),
948 NWidget(NWID_HORIZONTAL),
949 NWidget(WWT_PANEL, COLOUR_BROWN, WID_SB_PAGE_PANEL), SetResize(1, 1), SetScrollbar(WID_SB_SCROLLBAR), EndContainer(),
950 NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_SB_SCROLLBAR),
951 EndContainer(),
952 NWidget(NWID_HORIZONTAL),
953 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),
954 NWidget(NWID_BUTTON_DROPDOWN, COLOUR_BROWN, WID_SB_SEL_PAGE), SetMinimalSize(93, 12), SetFill(1, 0),
955 SetToolTip(STR_STORY_BOOK_SEL_PAGE_TOOLTIP), SetResize(1, 0),
956 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),
957 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
958 EndContainer(),
959};
960
961static WindowDesc _story_book_desc(
962 WDP_AUTO, "view_story", 400, 300,
963 WC_STORY_BOOK, WC_NONE,
964 {},
965 _nested_story_book_widgets
966);
967
968static WindowDesc _story_book_gs_desc(
969 WDP_CENTER, "view_story_gs", 400, 300,
970 WC_STORY_BOOK, WC_NONE,
971 {},
972 _nested_story_book_widgets
973);
974
975static CursorID TranslateStoryPageButtonCursor(StoryPageButtonCursor cursor)
976{
977 switch (cursor) {
978 case SPBC_MOUSE: return SPR_CURSOR_MOUSE;
979 case SPBC_ZZZ: return SPR_CURSOR_ZZZ;
980 case SPBC_BUOY: return SPR_CURSOR_BUOY;
981 case SPBC_QUERY: return SPR_CURSOR_QUERY;
982 case SPBC_HQ: return SPR_CURSOR_HQ;
983 case SPBC_SHIP_DEPOT: return SPR_CURSOR_SHIP_DEPOT;
984 case SPBC_SIGN: return SPR_CURSOR_SIGN;
985 case SPBC_TREE: return SPR_CURSOR_TREE;
986 case SPBC_BUY_LAND: return SPR_CURSOR_BUY_LAND;
987 case SPBC_LEVEL_LAND: return SPR_CURSOR_LEVEL_LAND;
988 case SPBC_TOWN: return SPR_CURSOR_TOWN;
989 case SPBC_INDUSTRY: return SPR_CURSOR_INDUSTRY;
990 case SPBC_ROCKY_AREA: return SPR_CURSOR_ROCKY_AREA;
991 case SPBC_DESERT: return SPR_CURSOR_DESERT;
992 case SPBC_TRANSMITTER: return SPR_CURSOR_TRANSMITTER;
993 case SPBC_AIRPORT: return SPR_CURSOR_AIRPORT;
994 case SPBC_DOCK: return SPR_CURSOR_DOCK;
995 case SPBC_CANAL: return SPR_CURSOR_CANAL;
996 case SPBC_LOCK: return SPR_CURSOR_LOCK;
997 case SPBC_RIVER: return SPR_CURSOR_RIVER;
998 case SPBC_AQUEDUCT: return SPR_CURSOR_AQUEDUCT;
999 case SPBC_BRIDGE: return SPR_CURSOR_BRIDGE;
1000 case SPBC_RAIL_STATION: return SPR_CURSOR_RAIL_STATION;
1001 case SPBC_TUNNEL_RAIL: return SPR_CURSOR_TUNNEL_RAIL;
1002 case SPBC_TUNNEL_ELRAIL: return SPR_CURSOR_TUNNEL_ELRAIL;
1003 case SPBC_TUNNEL_MONO: return SPR_CURSOR_TUNNEL_MONO;
1004 case SPBC_TUNNEL_MAGLEV: return SPR_CURSOR_TUNNEL_MAGLEV;
1005 case SPBC_AUTORAIL: return SPR_CURSOR_AUTORAIL;
1006 case SPBC_AUTOELRAIL: return SPR_CURSOR_AUTOELRAIL;
1007 case SPBC_AUTOMONO: return SPR_CURSOR_AUTOMONO;
1008 case SPBC_AUTOMAGLEV: return SPR_CURSOR_AUTOMAGLEV;
1009 case SPBC_WAYPOINT: return SPR_CURSOR_WAYPOINT;
1010 case SPBC_RAIL_DEPOT: return SPR_CURSOR_RAIL_DEPOT;
1011 case SPBC_ELRAIL_DEPOT: return SPR_CURSOR_ELRAIL_DEPOT;
1012 case SPBC_MONO_DEPOT: return SPR_CURSOR_MONO_DEPOT;
1013 case SPBC_MAGLEV_DEPOT: return SPR_CURSOR_MAGLEV_DEPOT;
1014 case SPBC_CONVERT_RAIL: return SPR_CURSOR_CONVERT_RAIL;
1015 case SPBC_CONVERT_ELRAIL: return SPR_CURSOR_CONVERT_ELRAIL;
1016 case SPBC_CONVERT_MONO: return SPR_CURSOR_CONVERT_MONO;
1017 case SPBC_CONVERT_MAGLEV: return SPR_CURSOR_CONVERT_MAGLEV;
1018 case SPBC_AUTOROAD: return SPR_CURSOR_AUTOROAD;
1019 case SPBC_AUTOTRAM: return SPR_CURSOR_AUTOTRAM;
1020 case SPBC_ROAD_DEPOT: return SPR_CURSOR_ROAD_DEPOT;
1021 case SPBC_BUS_STATION: return SPR_CURSOR_BUS_STATION;
1022 case SPBC_TRUCK_STATION: return SPR_CURSOR_TRUCK_STATION;
1023 case SPBC_ROAD_TUNNEL: return SPR_CURSOR_ROAD_TUNNEL;
1024 case SPBC_CLONE_TRAIN: return SPR_CURSOR_CLONE_TRAIN;
1025 case SPBC_CLONE_ROADVEH: return SPR_CURSOR_CLONE_ROADVEH;
1026 case SPBC_CLONE_SHIP: return SPR_CURSOR_CLONE_SHIP;
1027 case SPBC_CLONE_AIRPLANE: return SPR_CURSOR_CLONE_AIRPLANE;
1028 case SPBC_DEMOLISH: return ANIMCURSOR_DEMOLISH;
1029 case SPBC_LOWERLAND: return ANIMCURSOR_LOWERLAND;
1030 case SPBC_RAISELAND: return ANIMCURSOR_RAISELAND;
1031 case SPBC_PICKSTATION: return ANIMCURSOR_PICKSTATION;
1032 case SPBC_BUILDSIGNALS: return ANIMCURSOR_BUILDSIGNALS;
1033 default: return SPR_CURSOR_QUERY;
1034 }
1035}
1036
1043 void ShowStoryBook(CompanyID company, StoryPageID page_id, bool centered)
1044{
1045 if (!Company::IsValidID(company)) company = (CompanyID)CompanyID::Invalid();
1046
1047 StoryBookWindow *w = AllocateWindowDescFront<StoryBookWindow, true>(centered ? _story_book_gs_desc : _story_book_desc, company);
1048 if (page_id != StoryPageID::Invalid()) w->SetSelectedPage(page_id);
1049}
AnimatedTileState::None
@ None
Tile is not animated.
EncodedString::GetDecodedString
std::string GetDecodedString() const
Decode the encoded string.
Definition strings.cpp:207
EnumBitSet
Enum-as-bit-set wrapper.
Definition enum_type.hpp:177
GUIList
List template of 'things' T to sort in a GUI.
Definition sortlist_type.h:43
GUIList::RebuildDone
void RebuildDone()
Notify the sortlist that the rebuild is done.
Definition sortlist_type.h:405
GUIList::NeedRebuild
bool NeedRebuild() const
Check if a rebuild is needed.
Definition sortlist_type.h:387
GUIList::ForceRebuild
void ForceRebuild()
Force that a rebuild is needed.
Definition sortlist_type.h:395
GUIList::Sort
bool Sort(Comp compare)
Sort the list.
Definition sortlist_type.h:266
GUIList::SetSortFuncs
void SetSortFuncs(std::span< SortFunction *const > n_funcs)
Hand the sort function pointers to the GUIList.
Definition sortlist_type.h:293
Scrollbar
Scrollbar data structure.
Definition widget_type.h:711
Scrollbar::SetCount
void SetCount(size_t num)
Sets the number of elements in the list.
Definition widget_type.h:795
Scrollbar::GetScrolledRowFromWidget
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:2453
Scrollbar::SetCapacityFromWidget
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:2527
Scrollbar::GetCount
size_type GetCount() const
Gets the number of elements in the list.
Definition widget_type.h:737
Scrollbar::SetStepSize
void SetStepSize(size_t stepsize)
Set the distance to scroll when using the buttons or the wheel.
Definition widget_type.h:783
Scrollbar::GetPosition
size_type GetPosition() const
Gets the position of the first visible element in the list.
Definition widget_type.h:755
TimerGameConst< struct Calendar >::INVALID_DATE
static constexpr TimerGame< struct Calendar >::Date INVALID_DATE
Representation of an invalid date.
Definition timer_game_common.h:193
WidgetDimensions::framerect
RectPadding framerect
Standard padding inside many panels.
Definition window_gui.h:40
WidgetDimensions::frametext
RectPadding frametext
Padding inside frame with text.
Definition window_gui.h:41
WidgetDimensions::scaled
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
WidgetDimensions::bevel
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition window_gui.h:38
command_func.h
Functions related to commands.
company_base.h
Definition of stuff that is very close to a company, like the company struct itself.
company_func.h
Functions related to companies.
ShowDropDownList
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, DropDownOptions options)
Show a drop down list.
Definition dropdown.cpp:418
dropdown_func.h
Functions related to the drop down widget.
dropdown_type.h
Types related to the drop down widget.
DropDownList
std::vector< std::unique_ptr< const DropDownListItem > > DropDownList
A drop down list is a collection of drop down list items.
Definition dropdown_type.h:56
GetCharacterHeight
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:87
maxdim
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Definition geometry_func.cpp:22
geometry_func.hpp
Geometry functions.
GetStringHeight
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition gfx.cpp:715
GetSpriteSize
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:968
GetStringBoundingBox
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:897
DrawString
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:668
_ctrl_pressed
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
DrawSprite
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:1034
DrawStringMultiLineWithClipping
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:870
DrawStringMultiLine
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:785
FillDrawPixelInfo
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:1568
SpriteID
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
FS_NORMAL
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:249
CursorID
uint32_t CursorID
The number of the cursor (sprite)
Definition gfx_type.h:19
SA_TOP
@ SA_TOP
Top align the text.
Definition gfx_type.h:393
SA_LEFT
@ SA_LEFT
Left align the text.
Definition gfx_type.h:388
SA_HOR_CENTER
@ SA_HOR_CENTER
Horizontally center the text.
Definition gfx_type.h:389
SA_CENTER
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:398
goal_base.h
Goal base class.
ShowGoalsList
void ShowGoalsList(CompanyID company)
Open a goal list window.
Definition goal_gui.cpp:311
SetFill
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
Definition widget_type.h:1222
SetScrollbar
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
Definition widget_type.h:1402
SetStringTip
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
Definition widget_type.h:1243
SetMinimalSize
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
Definition widget_type.h:1159
SetToolTip
constexpr NWidgetPart SetToolTip(StringID tip)
Widget part function for setting tooltip and clearing the widget data.
Definition widget_type.h:1321
EndContainer
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
Definition widget_type.h:1232
NWidget
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=INVALID_WIDGET)
Widget part function for starting a new 'real' widget.
Definition widget_type.h:1427
SetResize
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
Definition widget_type.h:1148
gui.h
GUI functions that shouldn't be here.
ShowExtraViewportWindow
void ShowExtraViewportWindow(TileIndex tile=INVALID_TILE)
Show a new Extra Viewport window.
Definition viewport_gui.cpp:159
safeguards.h
A number of safeguards to prevent using unsafe methods.
sortlist_type.h
Base types for having sorted lists in GUIs.
sprites.h
This file contains all sprite-related enums and defines.
ANIMCURSOR_PICKSTATION
static const CursorID ANIMCURSOR_PICKSTATION
716 - 718 - goto-order icon
Definition sprites.h:1525
ANIMCURSOR_BUILDSIGNALS
static const CursorID ANIMCURSOR_BUILDSIGNALS
1292 - 1293 - build signal
Definition sprites.h:1526
SPR_CURSOR_MOUSE
static const CursorID SPR_CURSOR_MOUSE
Cursor sprite numbers.
Definition sprites.h:1404
ANIMCURSOR_DEMOLISH
static const CursorID ANIMCURSOR_DEMOLISH
704 - 707 - demolish dynamite
Definition sprites.h:1522
ANIMCURSOR_LOWERLAND
static const CursorID ANIMCURSOR_LOWERLAND
699 - 701 - lower land tool
Definition sprites.h:1523
ANIMCURSOR_RAISELAND
static const CursorID ANIMCURSOR_RAISELAND
696 - 698 - raise land tool
Definition sprites.h:1524
stdafx.h
Definition of base types and functions in a cross-platform compatible way.
story_base.h
StoryPage base class.
StoryPageButtonFlags
StoryPageButtonFlags
Flags available for buttons.
Definition story_base.h:43
SPET_LOCATION
@ SPET_LOCATION
An element that references a tile along with a one-line text.
Definition story_base.h:33
SPET_GOAL
@ SPET_GOAL
An element that references a goal.
Definition story_base.h:34
SPET_BUTTON_PUSH
@ SPET_BUTTON_PUSH
A push button that triggers an immediate event.
Definition story_base.h:35
SPET_BUTTON_TILE
@ 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
@ SPET_TEXT
A text element.
Definition story_base.h:32
SPET_BUTTON_VEHICLE
@ 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
StoryPageButtonCursor
Mouse cursors usable by story page buttons.
Definition story_base.h:51
story_cmd.h
Command definitions related to stories.
ShowStoryBook
void ShowStoryBook(CompanyID company, StoryPageID page_id, bool centered)
Raise or create the story book window for company, at page page_id.
Definition story_gui.cpp:1043
story_widget.h
Types related to the story widgets.
WID_SB_PAGE_PANEL
@ WID_SB_PAGE_PANEL
Page body.
Definition story_widget.h:18
WID_SB_SEL_PAGE
@ WID_SB_SEL_PAGE
Page selector.
Definition story_widget.h:17
WID_SB_SCROLLBAR
@ WID_SB_SCROLLBAR
Scrollbar of the goal list.
Definition story_widget.h:19
WID_SB_CAPTION
@ WID_SB_CAPTION
Caption of the window.
Definition story_widget.h:16
WID_SB_PREV_PAGE
@ WID_SB_PREV_PAGE
Prev button.
Definition story_widget.h:20
WID_SB_NEXT_PAGE
@ WID_SB_NEXT_PAGE
Next button.
Definition story_widget.h:21
GetString
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
strings_func.h
Functions related to OTTD's strings.
StringID
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition strings_type.h:19
AutoRestoreBackup
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
Definition backup_type.hpp:150
BaseVehicle::type
VehicleType type
Type of vehicle.
Definition vehicle_type.h:51
CommandHelper
Definition command_func.h:84
Coord2D< int >
Dimension
Dimensions (a width and height) of a rectangle in 2D.
Definition geometry_type.hpp:56
DrawPixelInfo
Data about how and where to blit pixels.
Definition gfx_type.h:157
Goal
Struct about goals, current and completed.
Definition goal_base.h:22
Goal::text
EncodedString text
Text of the goal.
Definition goal_base.h:26
Goal::completed
bool completed
Is the goal completed or not?
Definition goal_base.h:28
PoolID< uint16_t, struct StoryPageIDTag, 64000, 0xFFFF >
Pool::PoolItem<&_story_page_pool >::Iterate
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition pool_type.hpp:436
Pool::PoolItem<&_story_page_pool >::Get
static Titem * Get(auto index)
Returns Titem with given index.
Definition pool_type.hpp:387
Pool::PoolItem::index
Tindex index
Index of this pool item.
Definition pool_type.hpp:286
Pool::PoolItem<&_story_page_pool >::IsValidID
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition pool_type.hpp:376
Pool::PoolItem<&_story_page_element_pool >::GetIfValid
static Titem * GetIfValid(auto index)
Returns Titem with given index.
Definition pool_type.hpp:398
RectPadding::Horizontal
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
Definition geometry_type.hpp:89
RectPadding::Vertical
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Definition geometry_type.hpp:95
Rect
Specification of a rectangle with absolute coordinates of all edges.
Definition geometry_type.hpp:101
Rect::Shrink
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Definition geometry_type.hpp:124
Rect::Translate
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
Definition geometry_type.hpp:200
StoryBookWindow::LayoutCacheElement
Definition story_gui.cpp:43
StoryBookWindow
Definition story_gui.cpp:41
StoryBookWindow::OnTimeout
void OnTimeout() override
Called when this window's timeout has been reached.
Definition story_gui.cpp:885
StoryBookWindow::BuildStoryPageList
void BuildStoryPageList()
(Re)Build story page list.
Definition story_gui.cpp:69
StoryBookWindow::OnPlaceObjectAbort
void OnPlaceObjectAbort() override
The user cancelled a tile highlight mode that has been set.
Definition story_gui.cpp:925
StoryBookWindow::selected_generic_title
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
StoryBookWindow::OnPageElementClick
void OnPageElementClick(const StoryPageElement &pe)
Internal event handler for when a page element is clicked.
Definition story_gui.cpp:531
StoryBookWindow::OnResize
void OnResize() override
Called after the window got resized.
Definition story_gui.cpp:787
StoryBookWindow::PageElementOrderSorter
static bool PageElementOrderSorter(const StoryPageElement *const &a, const StoryPageElement *const &b)
Sort story page elements by order value.
Definition story_gui.cpp:115
StoryBookWindow::GetAvailablePageContentWidth
uint GetAvailablePageContentWidth() const
Get the width available for displaying content on the page panel.
Definition story_gui.cpp:267
StoryBookWindow::OnPaint
void OnPaint() override
The window must be repainted.
Definition story_gui.cpp:659
StoryBookWindow::SetSelectedPage
void SetSelectedPage(StoryPageID page_index)
Sets the selected page.
Definition story_gui.cpp:629
StoryBookWindow::IsFirstPageSelected
bool IsFirstPageSelected()
Check if the selected page is also the first available page.
Definition story_gui.cpp:159
StoryBookWindow::GetWidgetString
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
Definition story_gui.cpp:640
StoryBookWindow::DrawWidget
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Definition story_gui.cpp:674
StoryBookWindow::BuildDropDownList
DropDownList BuildDropDownList() const
Builds the page selector drop down list.
Definition story_gui.cpp:246
StoryBookWindow::GetPageElementFloatWidth
int GetPageElementFloatWidth(const StoryPageElement &pe) const
Get the width a page element would use if it was floating left or right.
Definition story_gui.cpp:371
StoryBookWindow::layout_cache
LayoutCache layout_cache
Cached element layout.
Definition story_gui.cpp:56
StoryBookWindow::UpdatePrevNextDisabledState
void UpdatePrevNextDisabledState()
Updates the disabled state of the prev/next buttons.
Definition story_gui.cpp:617
StoryBookWindow::vscroll
Scrollbar * vscroll
Scrollbar of the page text.
Definition story_gui.cpp:55
StoryBookWindow::OnDropdownSelect
void OnDropdownSelect(WidgetID widget, int index, int) override
A dropdown option associated to this window has been selected.
Definition story_gui.cpp:835
StoryBookWindow::SelectNextPage
void SelectNextPage()
Selects the next available page after the currently selected page.
Definition story_gui.cpp:225
StoryBookWindow::OnInvalidateData
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Definition story_gui.cpp:850
StoryBookWindow::SelectPrevPage
void SelectPrevPage()
Selects the previous available page before the currently selected page.
Definition story_gui.cpp:205
StoryBookWindow::RefreshSelectedPage
void RefreshSelectedPage()
Updates the content of selected page.
Definition story_gui.cpp:183
StoryBookWindow::selected_page_id
StoryPageID selected_page_id
Pool index of selected page.
Definition story_gui.cpp:60
StoryBookWindow::IsLastPageSelected
bool IsLastPageSelected()
Check if the selected page is also the last available page.
Definition story_gui.cpp:170
StoryBookWindow::UpdateWidgetSize
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.
Definition story_gui.cpp:750
StoryBookWindow::story_pages
GUIStoryPageList story_pages
Sorted list of pages.
Definition story_gui.cpp:58
StoryBookWindow::InvalidateStoryPageElementLayout
void InvalidateStoryPageElementLayout()
Invalidate the current page layout.
Definition story_gui.cpp:387
StoryBookWindow::DrawActionElement
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.
Definition story_gui.cpp:513
StoryBookWindow::BuildStoryPageElementList
void BuildStoryPageElementList()
(Re)Build story page element list.
Definition story_gui.cpp:93
StoryBookWindow::GetSelPage
StoryPage * GetSelPage() const
Get instance of selected page.
Definition story_gui.cpp:134
StoryBookWindow::PageOrderSorter
static bool PageOrderSorter(const StoryPage *const &a, const StoryPage *const &b)
Sort story pages by order value.
Definition story_gui.cpp:87
StoryBookWindow::OnClick
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
Definition story_gui.cpp:794
StoryBookWindow::active_button_id
StoryPageElementID active_button_id
Which button element the player is currently using.
Definition story_gui.cpp:63
StoryBookWindow::GetContentHeight
int32_t GetContentHeight()
Get the total height of the content displayed in this window.
Definition story_gui.cpp:492
StoryBookWindow::GetHeadHeight
uint GetHeadHeight(int max_width) const
Counts how many pixels of height that are used by Date and Title (excluding marginal after Title,...
Definition story_gui.cpp:279
StoryBookWindow::GetPageElementHeight
uint GetPageElementHeight(const StoryPageElement &pe, int max_width) const
Get the height in pixels used by a page element.
Definition story_gui.cpp:319
StoryBookWindow::GetSelPageNum
int GetSelPageNum() const
Get the page number of selected page.
Definition story_gui.cpp:144
StoryBookWindow::OnPlaceObject
void OnPlaceObject(Point pt, TileIndex tile) override
The user clicked some place on the map when a tile highlight mode has been set.
Definition story_gui.cpp:891
StoryBookWindow::GetPageElementSprite
SpriteID GetPageElementSprite(const StoryPageElement &pe) const
Decides which sprite to display for a given page element.
Definition story_gui.cpp:298
StoryBookWindow::EnsureStoryPageElementLayout
void EnsureStoryPageElementLayout() const
Create the page layout if it is missing.
Definition story_gui.cpp:393
StoryBookWindow::story_page_elements
GUIStoryPageElementList story_page_elements
Sorted list of page elements that belong to the current page.
Definition story_gui.cpp:59
StoryBookWindow::GetPageElementFloat
ElementFloat GetPageElementFloat(const StoryPageElement &pe) const
Get the float style of a page element.
Definition story_gui.cpp:349
StoryPageButtonData
Helper to construct packed "id" values for button-type StoryPageElement.
Definition story_base.h:123
StoryPageElement
Struct about story page elements.
Definition story_base.h:145
StoryPageElement::referenced_id
uint32_t referenced_id
Id of referenced object (location, goal etc.)
Definition story_base.h:150
StoryPageElement::text
EncodedString text
Static content text of page element.
Definition story_base.h:151
StoryPageElement::sort_value
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
StoryPageElement::type
StoryPageElementType type
Type of page element.
Definition story_base.h:148
StoryPage
Struct about stories, current and completed.
Definition story_base.h:167
StoryPage::title
EncodedString title
Title of story page.
Definition story_base.h:172
StoryPage::sort_value
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:168
StoryPage::company
CompanyID company
StoryPage is for a specific company; CompanyID::Invalid() if it is global.
Definition story_base.h:170
StoryPage::date
TimerGameCalendar::Date date
Date when the page was created.
Definition story_base.h:169
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > >
Vehicle
Vehicle data structure.
Definition vehicle_base.h:205
WindowDesc
High level window description.
Definition window_gui.h:168
WindowNumber
Number to differentiate different windows of the same class.
Definition window_type.h:760
Window
Data structure for an opened window.
Definition window_gui.h:274
Window::FinishInitNested
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1809
Window::DrawWidgets
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:784
Window::SetWidgetDirty
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:558
Window::GetWidgetString
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:506
Window::resize
ResizeInfo resize
Resize information.
Definition window_gui.h:315
Window::CreateNestedTree
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1799
Window::owner
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition window_gui.h:317
Window::SetTimeout
void SetTimeout()
Set the timeout flag of the window and initiate the timer.
Definition window_gui.h:356
Window::flags
WindowFlags flags
Window flags.
Definition window_gui.h:301
Window::GetScrollbar
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:315
Window::SetWidgetDisabledState
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:382
Window::height
int height
Height of the window (number of pixels down in y direction)
Definition window_gui.h:313
Window::width
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:312
Window::window_number
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:303
tilehighlight_func.h
Functions related to tile highlights.
ResetObjectToPlace
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
Definition viewport.cpp:3573
SetObjectToPlaceWnd
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...
Definition viewport.cpp:3510
HT_RECT
@ HT_RECT
rectangle (stations, depots, ...)
Definition tilehighlight_type.h:21
HT_VEHICLE
@ HT_VEHICLE
vehicle is accepted as target as well (bitmask)
Definition tilehighlight_type.h:27
vehicle_base.h
Base class for all vehicles.
VehicleType
VehicleType
Available vehicle types.
Definition vehicle_type.h:22
VEH_INVALID
@ VEH_INVALID
Non-existing type of vehicle.
Definition vehicle_type.h:36
ScrollMainWindowToTile
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition viewport.cpp:2592
viewport_func.h
Functions related to (drawing on) viewports.
DrawFrameRect
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition widget.cpp:307
NWID_BUTTON_DROPDOWN
@ NWID_BUTTON_DROPDOWN
Button with a drop-down.
Definition widget_type.h:74
NWID_HORIZONTAL
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
WWT_TEXTBTN
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:44
WWT_PANEL
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:39
WWT_STICKYBOX
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:57
WWT_SHADEBOX
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:55
WWT_CAPTION
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:52
NWID_VSCROLLBAR
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:76
WWT_CLOSEBOX
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:60
WWT_RESIZEBOX
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:59
WWT_DEFSIZEBOX
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:56
window_func.h
Window functions not directly related to making/drawing windows.
window_gui.h
Functions, definitions and such used only by the GUI.
FrameFlag::Lowered
@ Lowered
If set the frame is lowered and the background colour brighter (ie. buttons when pressed)
WDP_CENTER
@ WDP_CENTER
Center the window.
Definition window_gui.h:145
WDP_AUTO
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:144
WidgetID
int WidgetID
Widget ID.
Definition window_type.h:20
WC_NONE
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:50
WC_STORY_BOOK
@ WC_STORY_BOOK
Story book; Window numbers:
Definition window_type.h:301