OpenTTD Source: src/story_gui.cpp Source File

OpenTTD Source 14.0-beta1

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 <http://www.gnu.org/licenses/>.
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 "widgets/dropdown_type.h"
19 #include "widgets/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
36 static CursorID TranslateStoryPageButtonCursor(StoryPageButtonCursor cursor);
37
38 typedef GUIList<const StoryPage*> GUIStoryPageList;
39 typedef GUIList<const StoryPageElement*> GUIStoryPageElementList;
40
41 struct StoryBookWindow : Window {
42 protected:
43 struct LayoutCacheElement {
44 const StoryPageElement *pe;
45 Rect bounds;
46 };
47 typedef std::vector<LayoutCacheElement> LayoutCache;
48
49 enum class ElementFloat {
50 None,
51 Left,
52 Right,
53 };
54
55 Scrollbar *vscroll;
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 GUIStoryPageList::SortFunction * const page_sorter_funcs[];
66 static 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.shrink_to_fit();
81 this->story_pages.RebuildDone();
82 }
83
84 this->story_pages.Sort();
85 }
86
88 static bool PageOrderSorter(const StoryPage * const &a, const StoryPage * const &b)
89 {
90 return a->sort_value < b->sort_value;
91 }
92
94 void BuildStoryPageElementList()
95 {
96 if (this->story_page_elements.NeedRebuild()) {
97 this->story_page_elements.clear();
98
99 const StoryPage *p = GetSelPage();
100 if (p != nullptr) {
101 for (const StoryPageElement *pe : StoryPageElement::Iterate()) {
102 if (pe->page == p->index) {
103 this->story_page_elements.push_back(pe);
104 }
105 }
106 }
107
108 this->story_page_elements.shrink_to_fit();
109 this->story_page_elements.RebuildDone();
110 }
111
112 this->story_page_elements.Sort();
113 this->InvalidateStoryPageElementLayout();
114 }
115
117 static bool PageElementOrderSorter(const StoryPageElement * const &a, const StoryPageElement * const &b)
118 {
119 return a->sort_value < b->sort_value;
120 }
121
122 /*
123 * Checks if a given page should be visible in the story book.
124 * @param page The page to check.
125 * @return True if the page should be visible, otherwise false.
126 */
127 bool IsPageAvailable(const StoryPage *page) const
128 {
129 return page->company == INVALID_COMPANY || page->company == this->window_number;
130 }
131
136 StoryPage *GetSelPage() const
137 {
138 if (!_story_page_pool.IsValidID(selected_page_id)) return nullptr;
139 return _story_page_pool.Get(selected_page_id);
140 }
141
146 int GetSelPageNum() const
147 {
148 int page_number = 0;
149 for (const StoryPage *p : this->story_pages) {
150 if (p->index == this->selected_page_id) {
151 return page_number;
152 }
153 page_number++;
154 }
155 return -1;
156 }
157
161 bool IsFirstPageSelected()
162 {
163 /* Verify that the selected page exist. */
164 if (!_story_page_pool.IsValidID(this->selected_page_id)) return false;
165
166 return this->story_pages.front()->index == this->selected_page_id;
167 }
168
172 bool IsLastPageSelected()
173 {
174 /* Verify that the selected page exist. */
175 if (!_story_page_pool.IsValidID(this->selected_page_id)) return false;
176
177 if (this->story_pages.size() <= 1) return true;
178 const StoryPage *last = this->story_pages.back();
179 return last->index == this->selected_page_id;
180 }
181
185 void RefreshSelectedPage()
186 {
187 /* Generate generic title if selected page have no custom title. */
188 StoryPage *page = this->GetSelPage();
189 if (page != nullptr && page->title.empty()) {
190 SetDParam(0, GetSelPageNum() + 1);
191 selected_generic_title = GetString(STR_STORY_BOOK_GENERIC_PAGE_ITEM);
192 }
193
194 this->story_page_elements.ForceRebuild();
195 this->BuildStoryPageElementList();
196
197 if (this->active_button_id != INVALID_STORY_PAGE_ELEMENT) ResetObjectToPlace();
198
199 this->vscroll->SetCount(this->GetContentHeight());
200 this->SetWidgetDirty(WID_SB_SCROLLBAR);
201 this->SetWidgetDirty(WID_SB_SEL_PAGE);
202 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
203 }
204
208 void SelectPrevPage()
209 {
210 if (!_story_page_pool.IsValidID(this->selected_page_id)) return;
211
212 /* Find the last available page which is previous to the current selected page. */
213 const StoryPage *last_available;
214 last_available = nullptr;
215 for (const StoryPage *p : this->story_pages) {
216 if (p->index == this->selected_page_id) {
217 if (last_available == nullptr) return; // No previous page available.
218 this->SetSelectedPage(last_available->index);
219 return;
220 }
221 last_available = p;
222 }
223 }
224
228 void SelectNextPage()
229 {
230 if (!_story_page_pool.IsValidID(this->selected_page_id)) return;
231
232 /* Find selected page. */
233 for (auto iter = this->story_pages.begin(); iter != this->story_pages.end(); iter++) {
234 const StoryPage *p = *iter;
235 if (p->index == this->selected_page_id) {
236 /* Select the page after selected page. */
237 iter++;
238 if (iter != this->story_pages.end()) {
239 this->SetSelectedPage((*iter)->index);
240 }
241 return;
242 }
243 }
244 }
245
249 DropDownList BuildDropDownList() const
250 {
251 DropDownList list;
252 uint16_t page_num = 1;
253 for (const StoryPage *p : this->story_pages) {
254 bool current_page = p->index == this->selected_page_id;
255 if (!p->title.empty()) {
256 list.push_back(std::make_unique<DropDownListStringItem>(p->title, p->index, current_page));
257 } else {
258 /* No custom title => use a generic page title with page number. */
259 SetDParam(0, page_num);
260 list.push_back(std::make_unique<DropDownListStringItem>(STR_STORY_BOOK_GENERIC_PAGE_ITEM, p->index, current_page));
261 }
262 page_num++;
263 }
264
265 return list;
266 }
267
271 uint GetAvailablePageContentWidth() const
272 {
273 return this->GetWidget<NWidgetCore>(WID_SB_PAGE_PANEL)->current_x - WidgetDimensions::scaled.frametext.Horizontal() - 1;
274 }
275
283 uint GetHeadHeight(int max_width) const
284 {
285 StoryPage *page = this->GetSelPage();
286 if (page == nullptr) return 0;
287 int height = 0;
288
289 /* Title lines */
290 height += GetCharacterHeight(FS_NORMAL); // Date always use exactly one line.
291 SetDParamStr(0, !page->title.empty() ? page->title : this->selected_generic_title);
292 height += GetStringHeight(STR_STORY_BOOK_TITLE, max_width);
293
294 return height;
295 }
296
303 SpriteID GetPageElementSprite(const StoryPageElement &pe) const
304 {
305 switch (pe.type) {
306 case SPET_GOAL: {
307 Goal *g = Goal::Get((GoalID) pe.referenced_id);
308 if (g == nullptr) return SPR_IMG_GOAL_BROKEN_REF;
309 return g->completed ? SPR_IMG_GOAL_COMPLETED : SPR_IMG_GOAL;
310 }
311 case SPET_LOCATION:
312 return SPR_IMG_VIEW_LOCATION;
313 default:
314 NOT_REACHED();
315 }
316 }
317
324 uint GetPageElementHeight(const StoryPageElement &pe, int max_width) const
325 {
326 switch (pe.type) {
327 case SPET_TEXT:
328 SetDParamStr(0, pe.text);
329 return GetStringHeight(STR_JUST_RAW_STRING, max_width);
330
331 case SPET_GOAL:
332 case SPET_LOCATION: {
333 Dimension sprite_dim = GetSpriteSize(GetPageElementSprite(pe));
334 return sprite_dim.height;
335 }
336
337 case SPET_BUTTON_PUSH:
338 case SPET_BUTTON_TILE:
339 case SPET_BUTTON_VEHICLE: {
340 Dimension dim = GetStringBoundingBox(pe.text, FS_NORMAL);
341 return dim.height + WidgetDimensions::scaled.framerect.Vertical() + WidgetDimensions::scaled.frametext.Vertical();
342 }
343
344 default:
345 NOT_REACHED();
346 }
347 return 0;
348 }
349
355 ElementFloat GetPageElementFloat(const StoryPageElement &pe) const
356 {
357 switch (pe.type) {
358 case SPET_BUTTON_PUSH:
359 case SPET_BUTTON_TILE:
360 case SPET_BUTTON_VEHICLE: {
361 StoryPageButtonFlags flags = StoryPageButtonData{ pe.referenced_id }.GetFlags();
362 if (flags & SPBF_FLOAT_LEFT) return ElementFloat::Left;
363 if (flags & SPBF_FLOAT_RIGHT) return ElementFloat::Right;
364 return ElementFloat::None;
365 }
366
367 default:
368 return ElementFloat::None;
369 }
370 }
371
377 int GetPageElementFloatWidth(const StoryPageElement &pe) const
378 {
379 switch (pe.type) {
380 case SPET_BUTTON_PUSH:
381 case SPET_BUTTON_TILE:
382 case SPET_BUTTON_VEHICLE: {
383 Dimension dim = GetStringBoundingBox(pe.text, FS_NORMAL);
384 return dim.width + WidgetDimensions::scaled.framerect.Vertical() + WidgetDimensions::scaled.frametext.Vertical();
385 }
386
387 default:
388 NOT_REACHED(); // only buttons can float
389 }
390 }
391
393 void InvalidateStoryPageElementLayout()
394 {
395 this->layout_cache.clear();
396 }
397
399 void EnsureStoryPageElementLayout() const
400 {
401 /* Assume if the layout cache has contents it is valid */
402 if (!this->layout_cache.empty()) return;
403
404 StoryPage *page = this->GetSelPage();
405 if (page == nullptr) return;
406 int max_width = GetAvailablePageContentWidth();
407 int element_dist = GetCharacterHeight(FS_NORMAL);
408
409 /* Make space for the header */
410 int main_y = GetHeadHeight(max_width) + element_dist;
411
412 /* Current bottom of left/right column */
413 int left_y = main_y;
414 int right_y = main_y;
415 /* Current width of left/right column, 0 indicates no content in column */
416 int left_width = 0;
417 int right_width = 0;
418 /* Indexes into element cache for yet unresolved floats */
419 std::vector<size_t> left_floats;
420 std::vector<size_t> right_floats;
421
422 /* Build layout */
423 for (const StoryPageElement *pe : this->story_page_elements) {
424 ElementFloat fl = this->GetPageElementFloat(*pe);
425
426 if (fl == ElementFloat::None) {
427 /* Verify available width */
428 const int min_required_width = 10 * GetCharacterHeight(FS_NORMAL);
429 int left_offset = (left_width == 0) ? 0 : (left_width + element_dist);
430 int right_offset = (right_width == 0) ? 0 : (right_width + element_dist);
431 if (left_offset + right_offset + min_required_width >= max_width) {
432 /* Width of floats leave too little for main content, push down */
433 main_y = std::max(main_y, left_y);
434 main_y = std::max(main_y, right_y);
435 left_width = right_width = 0;
436 left_offset = right_offset = 0;
437 /* Do not add element_dist here, to keep together elements which were supposed to float besides each other. */
438 }
439 /* Determine height */
440 const int available_width = max_width - left_offset - right_offset;
441 const int height = GetPageElementHeight(*pe, available_width);
442 /* Check for button that needs extra margin */
443 if (left_offset == 0 && right_offset == 0) {
444 switch (pe->type) {
445 case SPET_BUTTON_PUSH:
446 case SPET_BUTTON_TILE:
447 case SPET_BUTTON_VEHICLE:
448 left_offset = right_offset = available_width / 5;
449 break;
450 default:
451 break;
452 }
453 }
454 /* Position element in main column */
455 LayoutCacheElement ce{ pe, {} };
456 ce.bounds.left = left_offset;
457 ce.bounds.right = max_width - right_offset;
458 ce.bounds.top = main_y;
459 main_y += height;
460 ce.bounds.bottom = main_y;
461 this->layout_cache.push_back(ce);
462 main_y += element_dist;
463 /* Clear all floats */
464 left_width = right_width = 0;
465 left_y = right_y = main_y = std::max({main_y, left_y, right_y});
466 left_floats.clear();
467 right_floats.clear();
468 } else {
469 /* Prepare references to correct column */
470 int &cur_width = (fl == ElementFloat::Left) ? left_width : right_width;
471 int &cur_y = (fl == ElementFloat::Left) ? left_y : right_y;
472 std::vector<size_t> &cur_floats = (fl == ElementFloat::Left) ? left_floats : right_floats;
473 /* Position element */
474 cur_width = std::max(cur_width, this->GetPageElementFloatWidth(*pe));
475 LayoutCacheElement ce{ pe, {} };
476 ce.bounds.left = (fl == ElementFloat::Left) ? 0 : (max_width - cur_width);
477 ce.bounds.right = (fl == ElementFloat::Left) ? cur_width : max_width;
478 ce.bounds.top = cur_y;
479 cur_y += GetPageElementHeight(*pe, cur_width);
480 ce.bounds.bottom = cur_y;
481 cur_floats.push_back(this->layout_cache.size());
482 this->layout_cache.push_back(ce);
483 cur_y += element_dist;
484 /* Update floats in column to all have the same width */
485 for (size_t index : cur_floats) {
486 LayoutCacheElement &ce = this->layout_cache[index];
487 ce.bounds.left = (fl == ElementFloat::Left) ? 0 : (max_width - cur_width);
488 ce.bounds.right = (fl == ElementFloat::Left) ? cur_width : max_width;
489 }
490 }
491 }
492 }
493
498 uint GetContentHeight()
499 {
500 this->EnsureStoryPageElementLayout();
501
502 /* The largest bottom coordinate of any element is the height of the content */
503 uint max_y = std::accumulate(this->layout_cache.begin(), this->layout_cache.end(), 0, [](uint max_y, const LayoutCacheElement &ce) -> uint { return std::max<uint>(max_y, ce.bounds.bottom); });
504
505 return max_y;
506 }
507
519 void DrawActionElement(int &y_offset, int width, int line_height, SpriteID action_sprite, StringID string_id = STR_JUST_RAW_STRING) const
520 {
521 Dimension sprite_dim = GetSpriteSize(action_sprite);
522 uint element_height = std::max(sprite_dim.height, (uint)line_height);
523
524 uint sprite_top = y_offset + (element_height - sprite_dim.height) / 2;
525 uint text_top = y_offset + (element_height - line_height) / 2;
526
527 DrawSprite(action_sprite, PAL_NONE, 0, sprite_top);
528 DrawString(sprite_dim.width + WidgetDimensions::scaled.frametext.left, width, text_top, string_id, TC_BLACK);
529
530 y_offset += element_height;
531 }
532
537 void OnPageElementClick(const StoryPageElement &pe)
538 {
539 switch (pe.type) {
540 case SPET_TEXT:
541 /* Do nothing. */
542 break;
543
544 case SPET_LOCATION:
545 if (_ctrl_pressed) {
546 ShowExtraViewportWindow((TileIndex)pe.referenced_id);
547 } else {
548 ScrollMainWindowToTile((TileIndex)pe.referenced_id);
549 }
550 break;
551
552 case SPET_GOAL:
553 ShowGoalsList((CompanyID)this->window_number);
554 break;
555
556 case SPET_BUTTON_PUSH:
557 if (this->active_button_id != INVALID_STORY_PAGE_ELEMENT) ResetObjectToPlace();
558 this->active_button_id = pe.index;
559 this->SetTimeout();
560 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
561
562 Command<CMD_STORY_PAGE_BUTTON>::Post(0, pe.index, 0);
563 break;
564
565 case SPET_BUTTON_TILE:
566 if (this->active_button_id == pe.index) {
567 ResetObjectToPlace();
568 this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
569 } else {
570 CursorID cursor = TranslateStoryPageButtonCursor(StoryPageButtonData{ pe.referenced_id }.GetCursor());
571 SetObjectToPlaceWnd(cursor, PAL_NONE, HT_RECT, this);
572 this->active_button_id = pe.index;
573 }
574 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
575 break;
576
577 case SPET_BUTTON_VEHICLE:
578 if (this->active_button_id == pe.index) {
579 ResetObjectToPlace();
580 this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
581 } else {
582 CursorID cursor = TranslateStoryPageButtonCursor(StoryPageButtonData{ pe.referenced_id }.GetCursor());
583 SetObjectToPlaceWnd(cursor, PAL_NONE, HT_VEHICLE, this);
584 this->active_button_id = pe.index;
585 }
586 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
587 break;
588
589 default:
590 NOT_REACHED();
591 }
592 }
593
594 public:
595 StoryBookWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
596 {
597 this->CreateNestedTree();
598 this->vscroll = this->GetScrollbar(WID_SB_SCROLLBAR);
599 this->vscroll->SetStepSize(GetCharacterHeight(FS_NORMAL));
600
601 /* Initialize page sort. */
602 this->story_pages.SetSortFuncs(StoryBookWindow::page_sorter_funcs);
603 this->story_pages.ForceRebuild();
604 this->BuildStoryPageList();
605 this->story_page_elements.SetSortFuncs(StoryBookWindow::page_element_sorter_funcs);
606 /* story_page_elements will get built by SetSelectedPage */
607
608 this->FinishInitNested(window_number);
609 this->owner = (Owner)this->window_number;
610
611 /* Initialize selected vars. */
612 this->selected_generic_title.clear();
613 this->selected_page_id = INVALID_STORY_PAGE;
614
615 this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
616
617 this->OnInvalidateData(-1);
618 }
619
623 void UpdatePrevNextDisabledState()
624 {
625 this->SetWidgetDisabledState(WID_SB_PREV_PAGE, story_pages.empty() || this->IsFirstPageSelected());
626 this->SetWidgetDisabledState(WID_SB_NEXT_PAGE, story_pages.empty() || this->IsLastPageSelected());
627 this->SetWidgetDirty(WID_SB_PREV_PAGE);
628 this->SetWidgetDirty(WID_SB_NEXT_PAGE);
629 }
630
635 void SetSelectedPage(uint16_t page_index)
636 {
637 if (this->selected_page_id != page_index) {
638 if (this->active_button_id) ResetObjectToPlace();
639 this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
640 this->selected_page_id = page_index;
641 this->RefreshSelectedPage();
642 this->UpdatePrevNextDisabledState();
643 }
644 }
645
646 void SetStringParameters(WidgetID widget) const override
647 {
648 switch (widget) {
649 case WID_SB_SEL_PAGE: {
650 StoryPage *page = this->GetSelPage();
651 SetDParamStr(0, page != nullptr && !page->title.empty() ? page->title : this->selected_generic_title);
652 break;
653 }
654 case WID_SB_CAPTION:
655 if (this->window_number == INVALID_COMPANY) {
656 SetDParam(0, STR_STORY_BOOK_SPECTATOR_CAPTION);
657 } else {
658 SetDParam(0, STR_STORY_BOOK_CAPTION);
659 SetDParam(1, this->window_number);
660 }
661 break;
662 }
663 }
664
665 void OnPaint() override
666 {
667 /* Detect if content has changed height. This can happen if a
668 * multi-line text contains eg. {COMPANY} and that company is
669 * renamed.
670 */
671 if (this->vscroll->GetCount() != this->GetContentHeight()) {
672 this->vscroll->SetCount(this->GetContentHeight());
673 this->SetWidgetDirty(WID_SB_SCROLLBAR);
674 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
675 }
676
677 this->DrawWidgets();
678 }
679
680 void DrawWidget(const Rect &r, WidgetID widget) const override
681 {
682 if (widget != WID_SB_PAGE_PANEL) return;
683
684 StoryPage *page = this->GetSelPage();
685 if (page == nullptr) return;
686
687 Rect fr = r.Shrink(WidgetDimensions::scaled.frametext);
688
689 /* Set up a clipping region for the panel. */
690 DrawPixelInfo tmp_dpi;
691 if (!FillDrawPixelInfo(&tmp_dpi, fr)) return;
692
693 AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi);
694
695 /* Draw content (now coordinates given to Draw** are local to the new clipping region). */
696 fr = fr.Translate(-fr.left, -fr.top);
697 int line_height = GetCharacterHeight(FS_NORMAL);
698 const int scrollpos = this->vscroll->GetPosition();
699 int y_offset = -scrollpos;
700
701 /* Date */
702 if (page->date != CalendarTime::INVALID_DATE) {
703 SetDParam(0, page->date);
704 DrawString(0, fr.right, y_offset, STR_JUST_DATE_LONG, TC_BLACK);
705 }
706 y_offset += line_height;
707
708 /* Title */
709 SetDParamStr(0, !page->title.empty() ? page->title : this->selected_generic_title);
710 y_offset = DrawStringMultiLine(0, fr.right, y_offset, fr.bottom, STR_STORY_BOOK_TITLE, TC_BLACK, SA_TOP | SA_HOR_CENTER);
711
712 /* Page elements */
713 this->EnsureStoryPageElementLayout();
714 for (const LayoutCacheElement &ce : this->layout_cache) {
715 y_offset = ce.bounds.top - scrollpos;
716 switch (ce.pe->type) {
717 case SPET_TEXT:
718 SetDParamStr(0, ce.pe->text);
719 y_offset = DrawStringMultiLine(ce.bounds.left, ce.bounds.right, ce.bounds.top - scrollpos, ce.bounds.bottom - scrollpos, STR_JUST_RAW_STRING, TC_BLACK, SA_TOP | SA_LEFT);
720 break;
721
722 case SPET_GOAL: {
723 Goal *g = Goal::Get((GoalID) ce.pe->referenced_id);
724 StringID string_id = g == nullptr ? STR_STORY_BOOK_INVALID_GOAL_REF : STR_JUST_RAW_STRING;
725 if (g != nullptr) SetDParamStr(0, g->text);
726 DrawActionElement(y_offset, ce.bounds.right - ce.bounds.left, line_height, GetPageElementSprite(*ce.pe), string_id);
727 break;
728 }
729
730 case SPET_LOCATION:
731 SetDParamStr(0, ce.pe->text);
732 DrawActionElement(y_offset, ce.bounds.right - ce.bounds.left, line_height, GetPageElementSprite(*ce.pe));
733 break;
734
735 case SPET_BUTTON_PUSH:
736 case SPET_BUTTON_TILE:
737 case SPET_BUTTON_VEHICLE: {
738 const int tmargin = WidgetDimensions::scaled.bevel.top + WidgetDimensions::scaled.frametext.top;
739 const FrameFlags frame = this->active_button_id == ce.pe->index ? FR_LOWERED : FR_NONE;
740 const Colours bgcolour = StoryPageButtonData{ ce.pe->referenced_id }.GetColour();
741
742 DrawFrameRect(ce.bounds.left, ce.bounds.top - scrollpos, ce.bounds.right, ce.bounds.bottom - scrollpos - 1, bgcolour, frame);
743
744 SetDParamStr(0, ce.pe->text);
745 DrawString(ce.bounds.left + WidgetDimensions::scaled.bevel.left, ce.bounds.right - WidgetDimensions::scaled.bevel.right, ce.bounds.top + tmargin - scrollpos, STR_JUST_RAW_STRING, TC_WHITE, SA_CENTER);
746 break;
747 }
748
749 default: NOT_REACHED();
750 }
751 }
752 }
753
754 void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
755 {
756 if (widget != WID_SB_SEL_PAGE && widget != WID_SB_PAGE_PANEL) return;
757
758 Dimension d;
759 d.height = GetCharacterHeight(FS_NORMAL);
760 d.width = 0;
761
762 switch (widget) {
763 case WID_SB_SEL_PAGE: {
764
765 /* Get max title width. */
766 for (size_t i = 0; i < this->story_pages.size(); i++) {
767 const StoryPage *s = this->story_pages[i];
768
769 if (!s->title.empty()) {
770 SetDParamStr(0, s->title);
771 } else {
772 SetDParamStr(0, this->selected_generic_title);
773 }
774 Dimension title_d = GetStringBoundingBox(STR_JUST_RAW_STRING);
775
776 if (title_d.width > d.width) {
777 d.width = title_d.width;
778 }
779 }
780
781 d.width += padding.width;
782 d.height += padding.height;
783 *size = maxdim(*size, d);
784 break;
785 }
786
787 case WID_SB_PAGE_PANEL: {
788 d.height *= 5;
789 d.height += padding.height + WidgetDimensions::scaled.frametext.Vertical();
790 *size = maxdim(*size, d);
791 break;
792 }
793 }
794
795 }
796
797 void OnResize() override
798 {
799 this->InvalidateStoryPageElementLayout();
800 this->vscroll->SetCapacityFromWidget(this, WID_SB_PAGE_PANEL, WidgetDimensions::scaled.frametext.Vertical());
801 this->vscroll->SetCount(this->GetContentHeight());
802 }
803
804 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
805 {
806 switch (widget) {
807 case WID_SB_SEL_PAGE: {
808 DropDownList list = this->BuildDropDownList();
809 if (!list.empty()) {
810 /* Get the index of selected page. */
811 int selected = 0;
812 for (size_t i = 0; i < this->story_pages.size(); i++) {
813 const StoryPage *p = this->story_pages[i];
814 if (p->index == this->selected_page_id) break;
815 selected++;
816 }
817
818 ShowDropDownList(this, std::move(list), selected, widget);
819 }
820 break;
821 }
822
823 case WID_SB_PREV_PAGE:
824 this->SelectPrevPage();
825 break;
826
827 case WID_SB_NEXT_PAGE:
828 this->SelectNextPage();
829 break;
830
831 case WID_SB_PAGE_PANEL: {
832 int clicked_y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SB_PAGE_PANEL, WidgetDimensions::scaled.frametext.top);
833 this->EnsureStoryPageElementLayout();
834
835 for (const LayoutCacheElement &ce : this->layout_cache) {
836 if (clicked_y >= ce.bounds.top && clicked_y < ce.bounds.bottom && pt.x >= ce.bounds.left && pt.x < ce.bounds.right) {
837 this->OnPageElementClick(*ce.pe);
838 return;
839 }
840 }
841 }
842 }
843 }
844
845 void OnDropdownSelect(WidgetID widget, int index) override
846 {
847 if (widget != WID_SB_SEL_PAGE) return;
848
849 /* index (which is set in BuildDropDownList) is the page id. */
850 this->SetSelectedPage(index);
851 }
852
860 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
861 {
862 if (!gui_scope) return;
863
864 /* If added/removed page, force rebuild. Sort order never change so just a
865 * re-sort is never needed.
866 */
867 if (data == -1) {
868 this->story_pages.ForceRebuild();
869 this->BuildStoryPageList();
870
871 /* Was the last page removed? */
872 if (this->story_pages.empty()) {
873 this->selected_generic_title.clear();
874 }
875
876 /* Verify page selection. */
877 if (!_story_page_pool.IsValidID(this->selected_page_id)) {
878 this->selected_page_id = INVALID_STORY_PAGE;
879 }
880 if (this->selected_page_id == INVALID_STORY_PAGE && !this->story_pages.empty()) {
881 /* No page is selected, but there exist at least one available.
882 * => Select first page.
883 */
884 this->SetSelectedPage(this->story_pages[0]->index);
885 }
886
887 this->SetWidgetDisabledState(WID_SB_SEL_PAGE, this->story_pages.empty());
888 this->SetWidgetDirty(WID_SB_SEL_PAGE);
889 this->UpdatePrevNextDisabledState();
890 } else if (data >= 0 && this->selected_page_id == data) {
891 this->RefreshSelectedPage();
892 }
893 }
894
895 void OnTimeout() override
896 {
897 this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
898 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
899 }
900
901 void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
902 {
903 const StoryPageElement *const pe = StoryPageElement::GetIfValid(this->active_button_id);
904 if (pe == nullptr || pe->type != SPET_BUTTON_TILE) {
905 ResetObjectToPlace();
906 this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
907 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
908 return;
909 }
910
911 Command<CMD_STORY_PAGE_BUTTON>::Post(tile, pe->index, 0);
912 ResetObjectToPlace();
913 }
914
915 bool OnVehicleSelect(const Vehicle *v) override
916 {
917 const StoryPageElement *const pe = StoryPageElement::GetIfValid(this->active_button_id);
918 if (pe == nullptr || pe->type != SPET_BUTTON_VEHICLE) {
919 ResetObjectToPlace();
920 this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
921 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
922 return false;
923 }
924
925 /* Check that the vehicle matches the requested type */
926 StoryPageButtonData data{ pe->referenced_id };
927 VehicleType wanted_vehtype = data.GetVehicleType();
928 if (wanted_vehtype != VEH_INVALID && wanted_vehtype != v->type) return false;
929
930 Command<CMD_STORY_PAGE_BUTTON>::Post(0, pe->index, v->index);
931 ResetObjectToPlace();
932 return true;
933 }
934
935 void OnPlaceObjectAbort() override
936 {
937 this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
938 this->SetWidgetDirty(WID_SB_PAGE_PANEL);
939 }
940 };
941
942 GUIStoryPageList::SortFunction * const StoryBookWindow::page_sorter_funcs[] = {
943 &PageOrderSorter,
944 };
945
946 GUIStoryPageElementList::SortFunction * const StoryBookWindow::page_element_sorter_funcs[] = {
947 &PageElementOrderSorter,
948 };
949
950 static constexpr NWidgetPart _nested_story_book_widgets[] = {
951 NWidget(NWID_HORIZONTAL),
952 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
953 NWidget(WWT_CAPTION, COLOUR_BROWN, WID_SB_CAPTION), SetDataTip(STR_JUST_STRING1, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
954 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
955 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
956 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
957 EndContainer(),
958 NWidget(NWID_HORIZONTAL),
959 NWidget(WWT_PANEL, COLOUR_BROWN, WID_SB_PAGE_PANEL), SetResize(1, 1), SetScrollbar(WID_SB_SCROLLBAR), EndContainer(),
960 NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_SB_SCROLLBAR),
961 EndContainer(),
962 NWidget(NWID_HORIZONTAL),
963 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_SB_PREV_PAGE), SetMinimalSize(100, 0), SetFill(0, 0), SetDataTip(STR_STORY_BOOK_PREV_PAGE, STR_STORY_BOOK_PREV_PAGE_TOOLTIP),
964 NWidget(NWID_BUTTON_DROPDOWN, COLOUR_BROWN, WID_SB_SEL_PAGE), SetMinimalSize(93, 12), SetFill(1, 0),
965 SetDataTip(STR_JUST_RAW_STRING, STR_STORY_BOOK_SEL_PAGE_TOOLTIP), SetResize(1, 0),
966 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_SB_NEXT_PAGE), SetMinimalSize(100, 0), SetFill(0, 0), SetDataTip(STR_STORY_BOOK_NEXT_PAGE, STR_STORY_BOOK_NEXT_PAGE_TOOLTIP),
967 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
968 EndContainer(),
969 };
970
971 static WindowDesc _story_book_desc(__FILE__, __LINE__,
972 WDP_AUTO, "view_story", 400, 300,
973 WC_STORY_BOOK, WC_NONE,
974 0,
975 std::begin(_nested_story_book_widgets), std::end(_nested_story_book_widgets)
976 );
977
978 static WindowDesc _story_book_gs_desc(__FILE__, __LINE__,
979 WDP_CENTER, "view_story_gs", 400, 300,
980 WC_STORY_BOOK, WC_NONE,
981 0,
982 std::begin(_nested_story_book_widgets), std::end(_nested_story_book_widgets)
983 );
984
985 static CursorID TranslateStoryPageButtonCursor(StoryPageButtonCursor cursor)
986 {
987 switch (cursor) {
988 case SPBC_MOUSE: return SPR_CURSOR_MOUSE;
989 case SPBC_ZZZ: return SPR_CURSOR_ZZZ;
990 case SPBC_BUOY: return SPR_CURSOR_BUOY;
991 case SPBC_QUERY: return SPR_CURSOR_QUERY;
992 case SPBC_HQ: return SPR_CURSOR_HQ;
993 case SPBC_SHIP_DEPOT: return SPR_CURSOR_SHIP_DEPOT;
994 case SPBC_SIGN: return SPR_CURSOR_SIGN;
995 case SPBC_TREE: return SPR_CURSOR_TREE;
996 case SPBC_BUY_LAND: return SPR_CURSOR_BUY_LAND;
997 case SPBC_LEVEL_LAND: return SPR_CURSOR_LEVEL_LAND;
998 case SPBC_TOWN: return SPR_CURSOR_TOWN;
999 case SPBC_INDUSTRY: return SPR_CURSOR_INDUSTRY;
1000 case SPBC_ROCKY_AREA: return SPR_CURSOR_ROCKY_AREA;
1001 case SPBC_DESERT: return SPR_CURSOR_DESERT;
1002 case SPBC_TRANSMITTER: return SPR_CURSOR_TRANSMITTER;
1003 case SPBC_AIRPORT: return SPR_CURSOR_AIRPORT;
1004 case SPBC_DOCK: return SPR_CURSOR_DOCK;
1005 case SPBC_CANAL: return SPR_CURSOR_CANAL;
1006 case SPBC_LOCK: return SPR_CURSOR_LOCK;
1007 case SPBC_RIVER: return SPR_CURSOR_RIVER;
1008 case SPBC_AQUEDUCT: return SPR_CURSOR_AQUEDUCT;
1009 case SPBC_BRIDGE: return SPR_CURSOR_BRIDGE;
1010 case SPBC_RAIL_STATION: return SPR_CURSOR_RAIL_STATION;
1011 case SPBC_TUNNEL_RAIL: return SPR_CURSOR_TUNNEL_RAIL;
1012 case SPBC_TUNNEL_ELRAIL: return SPR_CURSOR_TUNNEL_ELRAIL;
1013 case SPBC_TUNNEL_MONO: return SPR_CURSOR_TUNNEL_MONO;
1014 case SPBC_TUNNEL_MAGLEV: return SPR_CURSOR_TUNNEL_MAGLEV;
1015 case SPBC_AUTORAIL: return SPR_CURSOR_AUTORAIL;
1016 case SPBC_AUTOELRAIL: return SPR_CURSOR_AUTOELRAIL;
1017 case SPBC_AUTOMONO: return SPR_CURSOR_AUTOMONO;
1018 case SPBC_AUTOMAGLEV: return SPR_CURSOR_AUTOMAGLEV;
1019 case SPBC_WAYPOINT: return SPR_CURSOR_WAYPOINT;
1020 case SPBC_RAIL_DEPOT: return SPR_CURSOR_RAIL_DEPOT;
1021 case SPBC_ELRAIL_DEPOT: return SPR_CURSOR_ELRAIL_DEPOT;
1022 case SPBC_MONO_DEPOT: return SPR_CURSOR_MONO_DEPOT;
1023 case SPBC_MAGLEV_DEPOT: return SPR_CURSOR_MAGLEV_DEPOT;
1024 case SPBC_CONVERT_RAIL: return SPR_CURSOR_CONVERT_RAIL;
1025 case SPBC_CONVERT_ELRAIL: return SPR_CURSOR_CONVERT_ELRAIL;
1026 case SPBC_CONVERT_MONO: return SPR_CURSOR_CONVERT_MONO;
1027 case SPBC_CONVERT_MAGLEV: return SPR_CURSOR_CONVERT_MAGLEV;
1028 case SPBC_AUTOROAD: return SPR_CURSOR_AUTOROAD;
1029 case SPBC_AUTOTRAM: return SPR_CURSOR_AUTOTRAM;
1030 case SPBC_ROAD_DEPOT: return SPR_CURSOR_ROAD_DEPOT;
1031 case SPBC_BUS_STATION: return SPR_CURSOR_BUS_STATION;
1032 case SPBC_TRUCK_STATION: return SPR_CURSOR_TRUCK_STATION;
1033 case SPBC_ROAD_TUNNEL: return SPR_CURSOR_ROAD_TUNNEL;
1034 case SPBC_CLONE_TRAIN: return SPR_CURSOR_CLONE_TRAIN;
1035 case SPBC_CLONE_ROADVEH: return SPR_CURSOR_CLONE_ROADVEH;
1036 case SPBC_CLONE_SHIP: return SPR_CURSOR_CLONE_SHIP;
1037 case SPBC_CLONE_AIRPLANE: return SPR_CURSOR_CLONE_AIRPLANE;
1038 case SPBC_DEMOLISH: return ANIMCURSOR_DEMOLISH;
1039 case SPBC_LOWERLAND: return ANIMCURSOR_LOWERLAND;
1040 case SPBC_RAISELAND: return ANIMCURSOR_RAISELAND;
1041 case SPBC_PICKSTATION: return ANIMCURSOR_PICKSTATION;
1042 case SPBC_BUILDSIGNALS: return ANIMCURSOR_BUILDSIGNALS;
1043 default: return SPR_CURSOR_QUERY;
1044 }
1045 }
1046
1053 void ShowStoryBook(CompanyID company, uint16_t page_id, bool centered)
1054 {
1055 if (!Company::IsValidID(company)) company = (CompanyID)INVALID_COMPANY;
1056
1057 StoryBookWindow *w = AllocateWindowDescFront<StoryBookWindow>(centered ? &_story_book_gs_desc : &_story_book_desc, company, true);
1058 if (page_id != INVALID_STORY_PAGE) w->SetSelectedPage(page_id);
1059 }
SetFill
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
Definition: widget_type.h:1141
Pool::IsValidID
bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:119
Window::SetTimeout
void SetTimeout()
Set the timeout flag of the window and initiate the timer.
Definition: window_gui.h:355
ShowStoryBook
void ShowStoryBook(CompanyID company, uint16_t page_id, bool centered)
Raise or create the story book window for company, at page page_id.
Definition: story_gui.cpp:1053
SPET_TEXT
@ SPET_TEXT
A text element.
Definition: story_base.h:31
Goal
Struct about goals, current and completed.
Definition: goal_base.h:21
StoryBookWindow::GetSelPageNum
int GetSelPageNum() const
Get the page number of selected page.
Definition: story_gui.cpp:146
Pool::PoolItem<&_goal_pool >::Get
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:335
ScrollMainWindowToTile
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition: viewport.cpp:2509
StoryPage::title
std::string title
Title of story page.
Definition: story_base.h:169
ShowGoalsList
void ShowGoalsList(CompanyID company)
Open a goal list window.
Definition: goal_gui.cpp:316
ShowExtraViewportWindow
void ShowExtraViewportWindow(TileIndex tile=INVALID_TILE)
Show a new Extra Viewport window.
Definition: viewport_gui.cpp:156
WID_SB_PAGE_PANEL
@ WID_SB_PAGE_PANEL
Page body.
Definition: story_widget.h:18
Dimension
Dimensions (a width and height) of a rectangle in 2D.
Definition: geometry_type.hpp:30
command_func.h
WidgetDimensions::scaled
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition: window_gui.h:68
WWT_STICKYBOX
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition: widget_type.h:68
Pool::PoolItem<&_story_page_element_pool >::GetIfValid
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:346
dropdown_func.h
StoryPage::date
TimerGameCalendar::Date date
Date when the page was created.
Definition: story_base.h:166
Rect::Shrink
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Definition: geometry_type.hpp:98
company_base.h
ANIMCURSOR_RAISELAND
static const CursorID ANIMCURSOR_RAISELAND
696 - 698 - raise land tool
Definition: sprites.h:1502
StoryPageButtonFlags
StoryPageButtonFlags
Flags available for buttons.
Definition: story_base.h:42
WWT_CAPTION
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:63
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:377
Window::SetWidgetDirty
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition: window.cpp:552
StringID
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
GUIList< const StoryPage * >
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:210
StoryBookWindow::GetPageElementSprite
SpriteID GetPageElementSprite(const StoryPageElement &pe) const
Decides which sprite to display for a given page element.
Definition: story_gui.cpp:303
StoryBookWindow::GetAvailablePageContentWidth
uint GetAvailablePageContentWidth() const
Get the width available for displaying content on the page panel.
Definition: story_gui.cpp:271
WWT_DEFSIZEBOX
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition: widget_type.h:67
StoryBookWindow::BuildDropDownList
DropDownList BuildDropDownList() const
Builds the page selector drop down list.
Definition: story_gui.cpp:249
FrameFlags
FrameFlags
Flags to describe the look of the frame.
Definition: window_gui.h:24
Pool::PoolItem::index
Tindex index
Index of this pool item.
Definition: pool_type.hpp:234
WID_SB_PREV_PAGE
@ WID_SB_PREV_PAGE
Prev button.
Definition: story_widget.h:20
NWID_HORIZONTAL
@ NWID_HORIZONTAL
Horizontal container.
Definition: widget_type.h:77
maxdim
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Definition: geometry_func.cpp:22
ANIMCURSOR_BUILDSIGNALS
static const CursorID ANIMCURSOR_BUILDSIGNALS
1292 - 1293 - build signal
Definition: sprites.h:1504
SPET_BUTTON_PUSH
@ SPET_BUTTON_PUSH
A push button that triggers an immediate event.
Definition: story_base.h:34
StoryPageElementID
uint16_t StoryPageElementID
ID of a story page element.
Definition: story_type.h:15
EndContainer
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
Definition: widget_type.h:1151
StoryBookWindow::layout_cache
LayoutCache layout_cache
Cached element layout.
Definition: story_gui.cpp:56
Scrollbar::SetStepSize
void SetStepSize(size_t stepsize)
Set the distance to scroll when using the buttons or the wheel.
Definition: widget_type.h:748
_ctrl_pressed
bool _ctrl_pressed
Is Ctrl pressed?
Definition: gfx.cpp:37
vehicle_base.h
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:2334
StoryBookWindow::SelectNextPage
void SelectNextPage()
Selects the next available page after the currently selected page.
Definition: story_gui.cpp:228
goal_base.h
story_widget.h
SPET_GOAL
@ SPET_GOAL
An element that references a goal.
Definition: story_base.h:33
ANIMCURSOR_DEMOLISH
static const CursorID ANIMCURSOR_DEMOLISH
704 - 707 - demolish dynamite
Definition: sprites.h:1500
Window::owner
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition: window_gui.h:310
RectPadding::Vertical
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Definition: geometry_type.hpp:69
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > >
FR_LOWERED
@ FR_LOWERED
If set the frame is lowered and the background colour brighter (ie. buttons when pressed)
Definition: window_gui.h:28
Vehicle
Vehicle data structure.
Definition: vehicle_base.h:240
Owner
Owner
Enum for all companies/owners.
Definition: company_type.h:18
Scrollbar
Scrollbar data structure.
Definition: widget_type.h:678
Window::GetScrollbar
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition: window.cpp:315
StoryBookWindow::OnTimeout
void OnTimeout() override
Called when this window's timeout has been reached.
Definition: story_gui.cpp:895
NWidgetPart
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:1038
GUIList::NeedRebuild
bool NeedRebuild() const
Check if a rebuild is needed.
Definition: sortlist_type.h:387
Scrollbar::GetPosition
uint16_t GetPosition() const
Gets the position of the first visible element in the list.
Definition: widget_type.h:720
Scrollbar::GetCount
uint16_t GetCount() const
Gets the number of elements in the list.
Definition: widget_type.h:702
SPET_BUTTON_VEHICLE
@ SPET_BUTTON_VEHICLE
A button that allows the player to select a vehicle, and triggers an event wih the vehicle.
Definition: story_base.h:36
StoryBookWindow::OnInvalidateData
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
Definition: story_gui.cpp:860
WindowDesc
High level window description.
Definition: window_gui.h:153
WidgetID
int WidgetID
Widget ID.
Definition: window_type.h:18
RectPadding::Horizontal
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
Definition: geometry_type.hpp:63
WC_STORY_BOOK
@ WC_STORY_BOOK
Story book; Window numbers:
Definition: window_type.h:296
window_gui.h
ANIMCURSOR_PICKSTATION
static const CursorID ANIMCURSOR_PICKSTATION
716 - 718 - goto-order icon
Definition: sprites.h:1503
StoryBookWindow::vscroll
Scrollbar * vscroll
Scrollbar of the page text.
Definition: story_gui.cpp:55
SetResize
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
Definition: widget_type.h:1086
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:35
WDP_AUTO
@ WDP_AUTO
Find a place automatically.
Definition: window_gui.h:141
Window::resize
ResizeInfo resize
Resize information.
Definition: window_gui.h:308
StoryPageElement::type
StoryPageElementType type
Type of page element.
Definition: story_base.h:147
tilehighlight_func.h
WindowNumber
int32_t WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:732
FS_NORMAL
@ FS_NORMAL
Index of the normal font in the font tables.
Definition: gfx_type.h:203
SA_TOP
@ SA_TOP
Top align the text.
Definition: gfx_type.h:343
Rect::Translate
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
Definition: geometry_type.hpp:174
SetScrollbar
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1244
StoryBookWindow::story_page_elements
GUIStoryPageElementList story_page_elements
Sorted list of page elements that belong to the current page.
Definition: story_gui.cpp:59
Window::height
int height
Height of the window (number of pixels down in y direction)
Definition: window_gui.h:306
GUIList< const StoryPage * >::SortFunction
std::conditional_t< std::is_same_v< std::nullptr_t, std::nullptr_t >, bool(const const StoryPage * &, const const StoryPage * &), bool(const const StoryPage * &, const const StoryPage * &, const std::nullptr_t)> SortFunction
Signature of sort function.
Definition: sortlist_type.h:49
StoryBookWindow::SelectPrevPage
void SelectPrevPage()
Selects the previous available page before the currently selected page.
Definition: story_gui.cpp:208
StoryBookWindow::GetSelPage
StoryPage * GetSelPage() const
Get instance of selected page.
Definition: story_gui.cpp:136
StoryBookWindow
Definition: story_gui.cpp:41
StoryBookWindow::InvalidateStoryPageElementLayout
void InvalidateStoryPageElementLayout()
Invalidate the current page layout.
Definition: story_gui.cpp:393
StoryPage
Struct about stories, current and completed.
Definition: story_base.h:164
dropdown_type.h
StoryBookWindow::RefreshSelectedPage
void RefreshSelectedPage()
Updates the content of selected page.
Definition: story_gui.cpp:185
EngineDisplayFlags::None
@ None
No flag set.
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:283
NWidget
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
Definition: widget_type.h:1258
StoryBookWindow::OnPageElementClick
void OnPageElementClick(const StoryPageElement &pe)
Internal event handler for when a page element is clicked.
Definition: story_gui.cpp:537
safeguards.h
StoryBookWindow::OnPlaceObjectAbort
void OnPlaceObjectAbort() override
The user cancelled a tile highlight mode that has been set.
Definition: story_gui.cpp:935
sortlist_type.h
Window::flags
WindowFlags flags
Window flags.
Definition: window_gui.h:294
VEH_INVALID
@ VEH_INVALID
Non-existing type of vehicle.
Definition: vehicle_type.h:35
CursorID
uint32_t CursorID
The number of the cursor (sprite)
Definition: gfx_type.h:19
GetStringHeight
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition: gfx.cpp:705
StoryBookWindow::selected_page_id
StoryPageID selected_page_id
Pool index of selected page.
Definition: story_gui.cpp:60
SPET_LOCATION
@ SPET_LOCATION
An element that references a tile along with a one-line text.
Definition: story_base.h:32
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:1007
sprites.h
Point
Coordinates of a point in 2D.
Definition: geometry_type.hpp:21
StoryPageButtonCursor
StoryPageButtonCursor
Mouse cursors usable by story page buttons.
Definition: story_base.h:50
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:324
stdafx.h
GoalID
uint16_t GoalID
ID of a goal.
Definition: goal_type.h:37
Window::window_number
WindowNumber window_number
Window number within the window class.
Definition: window_gui.h:296
VehicleType
VehicleType
Available vehicle types.
Definition: vehicle_type.h:21
SpriteID
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:17
Pool::Get
Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:108
viewport_func.h
WC_NONE
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:45
SA_HOR_CENTER
@ SA_HOR_CENTER
Horizontally center the text.
Definition: gfx_type.h:339
HT_VEHICLE
@ HT_VEHICLE
vehicle is accepted as target as well (bitmask)
Definition: tilehighlight_type.h:27
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:1571
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
Scrollbar::GetScrolledRowFromWidget
int 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:2260
Window::SetWidgetDisabledState
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition: window_gui.h:381
GetSpriteSize
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition: gfx.cpp:941
WWT_CLOSEBOX
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition: widget_type.h:71
WWT_RESIZEBOX
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:70
StoryBookWindow::IsFirstPageSelected
bool IsFirstPageSelected()
Check if the selected page is also the first available page.
Definition: story_gui.cpp:161
StoryBookWindow::DrawActionElement
void DrawActionElement(int &y_offset, int width, int line_height, SpriteID action_sprite, StringID string_id=STR_JUST_RAW_STRING) 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:519
WID_SB_SEL_PAGE
@ WID_SB_SEL_PAGE
Page selector.
Definition: story_widget.h:17
GUIList::ForceRebuild
void ForceRebuild()
Force that a rebuild is needed.
Definition: sortlist_type.h:395
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:775
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:384
Window::CreateNestedTree
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition: window.cpp:1724
strings_func.h
NWID_VSCROLLBAR
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition: widget_type.h:86
ShowDropDownList
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, bool instant_close)
Show a drop down list.
Definition: dropdown.cpp:349
WID_SB_CAPTION
@ WID_SB_CAPTION
Caption of the window.
Definition: story_widget.h:16
StoryBookWindow::PageElementOrderSorter
static bool PageElementOrderSorter(const StoryPageElement *const &a, const StoryPageElement *const &b)
Sort story page elements by order value.
Definition: story_gui.cpp:117
WID_SB_SCROLLBAR
@ WID_SB_SCROLLBAR
Scrollbar of the goal list.
Definition: story_widget.h:19
SetDParam
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings.cpp:104
Goal::completed
bool completed
Is the goal completed or not?
Definition: goal_base.h:27
geometry_func.hpp
StoryBookWindow::OnResize
void OnResize() override
Called after the window got resized.
Definition: story_gui.cpp:797
StoryPageElement::referenced_id
uint32_t referenced_id
Id of referenced object (location, goal etc.)
Definition: story_base.h:149
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:165
story_cmd.h
WWT_PANEL
@ WWT_PANEL
Simple depressed panel.
Definition: widget_type.h:52
StoryBookWindow::story_pages
GUIStoryPageList story_pages
Sorted list of pages.
Definition: story_gui.cpp:58
AutoRestoreBackup
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
Definition: backup_type.hpp:153
Scrollbar::SetCount
void SetCount(size_t num)
Sets the number of elements in the list.
Definition: widget_type.h:760
TimerGameConst< struct Calendar >::INVALID_DATE
static constexpr TimerGame< struct Calendar >::Date INVALID_DATE
Representation of an invalid date.
Definition: timer_game_common.h:193
GetString
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
Definition: strings.cpp:327
HT_RECT
@ HT_RECT
rectangle (stations, depots, ...)
Definition: tilehighlight_type.h:21
StoryPageElement::text
std::string text
Static content text of page element.
Definition: story_base.h:150
StoryPageElement
Struct about story page elements.
Definition: story_base.h:144
SetDParamStr
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition: strings.cpp:352
Window::FinishInitNested
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition: window.cpp:1734
company_func.h
SA_LEFT
@ SA_LEFT
Left align the text.
Definition: gfx_type.h:338
DrawFrameRect
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition: widget.cpp:281
CommandHelper
Definition: command_func.h:93
window_func.h
SA_CENTER
@ SA_CENTER
Center both horizontally and vertically.
Definition: gfx_type.h:348
GetCharacterHeight
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition: fontcache.cpp:78
Window::width
int width
width of the window (number of pixels to the right in x direction)
Definition: window_gui.h:305
SetMinimalSize
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
Definition: widget_type.h:1097
StoryBookWindow::SetSelectedPage
void SetSelectedPage(uint16_t page_index)
Sets the selected page.
Definition: story_gui.cpp:635
GUIList::SetSortFuncs
void SetSortFuncs(SortFunction *const *n_funcs)
Hand the array of sort function pointers to the sort list.
Definition: sortlist_type.h:295
GUIList::RebuildDone
void RebuildDone()
Notify the sortlist that the rebuild is done.
Definition: sortlist_type.h:405
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:658
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:3420
INVALID_COMPANY
@ INVALID_COMPANY
An invalid company.
Definition: company_type.h:30
Goal::text
std::string text
Text of the goal.
Definition: goal_base.h:25
WidgetDimensions::bevel
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition: window_gui.h:40
gui.h
SPR_CURSOR_MOUSE
static const CursorID SPR_CURSOR_MOUSE
Cursor sprite numbers.
Definition: sprites.h:1382
WidgetDimensions::frametext
RectPadding frametext
Padding inside frame with text.
Definition: window_gui.h:43
StoryPageButtonData
Helper to construct packed "id" values for button-type StoryPageElement.
Definition: story_base.h:122
StoryBookWindow::PageOrderSorter
static bool PageOrderSorter(const StoryPage *const &a, const StoryPage *const &b)
Sort story pages by order value.
Definition: story_gui.cpp:88
Window
Data structure for an opened window.
Definition: window_gui.h:267
Pool::PoolItem<&_company_pool >::IsValidID
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:324
BaseVehicle::type
VehicleType type
Type of vehicle.
Definition: vehicle_type.h:51
Window::DrawWidgets
void DrawWidgets() const
Paint all widgets of a window.
Definition: widget.cpp:731
StoryBookWindow::UpdatePrevNextDisabledState
void UpdatePrevNextDisabledState()
Updates the disabled state of the prev/next buttons.
Definition: story_gui.cpp:623
WID_SB_NEXT_PAGE
@ WID_SB_NEXT_PAGE
Next button.
Definition: story_widget.h:21
StoryBookWindow::LayoutCacheElement
Definition: story_gui.cpp:43
SetDataTip
constexpr NWidgetPart SetDataTip(uint32_t data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1162
StoryBookWindow::BuildStoryPageList
void BuildStoryPageList()
(Re)Build story page list.
Definition: story_gui.cpp:69
story_base.h
StoryPageID
uint16_t StoryPageID
ID of a story page.
Definition: story_type.h:16
Rect
Specification of a rectangle with absolute coordinates of all edges.
Definition: geometry_type.hpp:75
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:145
GUIList::Sort
bool Sort(Comp compare)
Sort the list.
Definition: sortlist_type.h:268
StoryBookWindow::GetContentHeight
uint GetContentHeight()
Get the total height of the content displayed in this window.
Definition: story_gui.cpp:498
StoryPage::company
CompanyID company
StoryPage is for a specific company; INVALID_COMPANY if it is global.
Definition: story_base.h:167
WidgetDimensions::framerect
RectPadding framerect
Standard padding inside many panels.
Definition: window_gui.h:42
StoryBookWindow::IsLastPageSelected
bool IsLastPageSelected()
Check if the selected page is also the last available page.
Definition: story_gui.cpp:172
ResetObjectToPlace
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
Definition: viewport.cpp:3483
WDP_CENTER
@ WDP_CENTER
Center the window.
Definition: window_gui.h:142
StoryBookWindow::OnPaint
void OnPaint() override
The window must be repainted.
Definition: story_gui.cpp:665
StoryBookWindow::GetPageElementFloat
ElementFloat GetPageElementFloat(const StoryPageElement &pe) const
Get the float style of a page element.
Definition: story_gui.cpp:355
GetStringBoundingBox
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:852
WWT_TEXTBTN
@ WWT_TEXTBTN
(Toggle) Button with text
Definition: widget_type.h:57
StoryBookWindow::BuildStoryPageElementList
void BuildStoryPageElementList()
(Re)Build story page element list.
Definition: story_gui.cpp:94
NWID_BUTTON_DROPDOWN
@ NWID_BUTTON_DROPDOWN
Button with a drop-down.
Definition: widget_type.h:84
DrawPixelInfo
Data about how and where to blit pixels.
Definition: gfx_type.h:151
StoryBookWindow::EnsureStoryPageElementLayout
void EnsureStoryPageElementLayout() const
Create the page layout if it is missing.
Definition: story_gui.cpp:399
StoryBookWindow::active_button_id
StoryPageElementID active_button_id
Which button element the player is currently using.
Definition: story_gui.cpp:63
ANIMCURSOR_LOWERLAND
static const CursorID ANIMCURSOR_LOWERLAND
699 - 701 - lower land tool
Definition: sprites.h:1501
WWT_SHADEBOX
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition: widget_type.h:66