OpenTTD Source  1.11.2
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 "date_func.h"
14 #include "gui.h"
15 #include "story_base.h"
16 #include "core/geometry_func.hpp"
17 #include "company_func.h"
18 #include "command_func.h"
19 #include "widgets/dropdown_type.h"
20 #include "widgets/dropdown_func.h"
21 #include "sortlist_type.h"
22 #include "goal_base.h"
23 #include "viewport_func.h"
24 #include "window_func.h"
25 #include "company_base.h"
26 #include "tilehighlight_func.h"
27 #include "vehicle_base.h"
28 
29 #include "widgets/story_widget.h"
30 
31 #include "table/strings.h"
32 #include "table/sprites.h"
33 
34 #include <numeric>
35 
36 #include "safeguards.h"
37 
38 static CursorID TranslateStoryPageButtonCursor(StoryPageButtonCursor cursor);
39 
42 
44 protected:
46  const StoryPageElement *pe;
47  Rect bounds;
48  };
49  typedef std::vector<LayoutCacheElement> LayoutCache;
50 
51  enum class ElementFloat {
52  None,
53  Left,
54  Right,
55  };
56 
58  mutable LayoutCache layout_cache;
59 
64 
66 
67  static GUIStoryPageList::SortFunction * const page_sorter_funcs[];
68  static GUIStoryPageElementList::SortFunction * const page_element_sorter_funcs[];
69 
72  {
73  if (this->story_pages.NeedRebuild()) {
74  this->story_pages.clear();
75 
76  for (const StoryPage *p : StoryPage::Iterate()) {
77  if (this->IsPageAvailable(p)) {
78  this->story_pages.push_back(p);
79  }
80  }
81 
82  this->story_pages.shrink_to_fit();
83  this->story_pages.RebuildDone();
84  }
85 
86  this->story_pages.Sort();
87  }
88 
90  static bool PageOrderSorter(const StoryPage * const &a, const StoryPage * const &b)
91  {
92  return a->sort_value < b->sort_value;
93  }
94 
97  {
98  if (this->story_page_elements.NeedRebuild()) {
99  this->story_page_elements.clear();
100 
101  const StoryPage *p = GetSelPage();
102  if (p != nullptr) {
103  for (const StoryPageElement *pe : StoryPageElement::Iterate()) {
104  if (pe->page == p->index) {
105  this->story_page_elements.push_back(pe);
106  }
107  }
108  }
109 
110  this->story_page_elements.shrink_to_fit();
111  this->story_page_elements.RebuildDone();
112  }
113 
114  this->story_page_elements.Sort();
116  }
117 
119  static bool PageElementOrderSorter(const StoryPageElement * const &a, const StoryPageElement * const &b)
120  {
121  return a->sort_value < b->sort_value;
122  }
123 
124  /*
125  * Checks if a given page should be visible in the story book.
126  * @param page The page to check.
127  * @return True if the page should be visible, otherwise false.
128  */
129  bool IsPageAvailable(const StoryPage *page) const
130  {
131  return page->company == INVALID_COMPANY || page->company == this->window_number;
132  }
133 
139  {
140  if (!_story_page_pool.IsValidID(selected_page_id)) return nullptr;
141  return _story_page_pool.Get(selected_page_id);
142  }
143 
148  int GetSelPageNum() const
149  {
150  int page_number = 0;
151  for (const StoryPage *p : this->story_pages) {
152  if (p->index == this->selected_page_id) {
153  return page_number;
154  }
155  page_number++;
156  }
157  return -1;
158  }
159 
164  {
165  /* Verify that the selected page exist. */
166  if (!_story_page_pool.IsValidID(this->selected_page_id)) return false;
167 
168  return this->story_pages.front()->index == this->selected_page_id;
169  }
170 
175  {
176  /* Verify that the selected page exist. */
177  if (!_story_page_pool.IsValidID(this->selected_page_id)) return false;
178 
179  if (this->story_pages.size() <= 1) return true;
180  const StoryPage *last = this->story_pages.back();
181  return last->index == this->selected_page_id;
182  }
183 
188  {
189  /* Generate generic title if selected page have no custom title. */
190  StoryPage *page = this->GetSelPage();
191  if (page != nullptr && page->title == nullptr) {
192  SetDParam(0, GetSelPageNum() + 1);
193  GetString(selected_generic_title, STR_STORY_BOOK_GENERIC_PAGE_ITEM, lastof(selected_generic_title));
194  }
195 
196  this->story_page_elements.ForceRebuild();
198 
199  if (this->active_button_id != INVALID_STORY_PAGE_ELEMENT) ResetObjectToPlace();
200 
201  this->vscroll->SetCount(this->GetContentHeight());
205  }
206 
211  {
212  if (!_story_page_pool.IsValidID(this->selected_page_id)) return;
213 
214  /* Find the last available page which is previous to the current selected page. */
215  const StoryPage *last_available;
216  last_available = nullptr;
217  for (const StoryPage *p : this->story_pages) {
218  if (p->index == this->selected_page_id) {
219  if (last_available == nullptr) return; // No previous page available.
220  this->SetSelectedPage(last_available->index);
221  return;
222  }
223  last_available = p;
224  }
225  }
226 
231  {
232  if (!_story_page_pool.IsValidID(this->selected_page_id)) return;
233 
234  /* Find selected page. */
235  for (auto iter = this->story_pages.begin(); iter != this->story_pages.end(); iter++) {
236  const StoryPage *p = *iter;
237  if (p->index == this->selected_page_id) {
238  /* Select the page after selected page. */
239  iter++;
240  if (iter != this->story_pages.end()) {
241  this->SetSelectedPage((*iter)->index);
242  }
243  return;
244  }
245  }
246  }
247 
252  {
253  DropDownList list;
254  uint16 page_num = 1;
255  for (const StoryPage *p : this->story_pages) {
256  bool current_page = p->index == this->selected_page_id;
257  DropDownListStringItem *item = nullptr;
258  if (p->title != nullptr) {
259  item = new DropDownListCharStringItem(p->title, p->index, current_page);
260  } else {
261  /* No custom title => use a generic page title with page number. */
262  DropDownListParamStringItem *str_item =
263  new DropDownListParamStringItem(STR_STORY_BOOK_GENERIC_PAGE_ITEM, p->index, current_page);
264  str_item->SetParam(0, page_num);
265  item = str_item;
266  }
267 
268  list.emplace_back(item);
269  page_num++;
270  }
271 
272  return list;
273  }
274 
279  {
280  return this->GetWidget<NWidgetCore>(WID_SB_PAGE_PANEL)->current_x - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT - 1;
281  }
282 
290  uint GetHeadHeight(int max_width) const
291  {
292  StoryPage *page = this->GetSelPage();
293  if (page == nullptr) return 0;
294  int height = 0;
295 
296  /* Title lines */
297  height += FONT_HEIGHT_NORMAL; // Date always use exactly one line.
298  SetDParamStr(0, page->title != nullptr ? page->title : this->selected_generic_title);
299  height += GetStringHeight(STR_STORY_BOOK_TITLE, max_width);
300 
301  return height;
302  }
303 
311  {
312  switch (pe.type) {
313  case SPET_GOAL: {
314  Goal *g = Goal::Get((GoalID) pe.referenced_id);
315  if (g == nullptr) return SPR_IMG_GOAL_BROKEN_REF;
316  return g->completed ? SPR_IMG_GOAL_COMPLETED : SPR_IMG_GOAL;
317  }
318  case SPET_LOCATION:
319  return SPR_IMG_VIEW_LOCATION;
320  default:
321  NOT_REACHED();
322  }
323  }
324 
331  uint GetPageElementHeight(const StoryPageElement &pe, int max_width) const
332  {
333  switch (pe.type) {
334  case SPET_TEXT:
335  SetDParamStr(0, pe.text);
336  return GetStringHeight(STR_BLACK_RAW_STRING, max_width);
337 
338  case SPET_GOAL:
339  case SPET_LOCATION: {
340  Dimension sprite_dim = GetSpriteSize(GetPageElementSprite(pe));
341  return sprite_dim.height;
342  }
343 
344  case SPET_BUTTON_PUSH:
345  case SPET_BUTTON_TILE:
346  case SPET_BUTTON_VEHICLE: {
349  }
350 
351  default:
352  NOT_REACHED();
353  }
354  return 0;
355  }
356 
362  ElementFloat GetPageElementFloat(const StoryPageElement &pe) const
363  {
364  switch (pe.type) {
365  case SPET_BUTTON_PUSH:
366  case SPET_BUTTON_TILE:
367  case SPET_BUTTON_VEHICLE: {
369  if (flags & SPBF_FLOAT_LEFT) return ElementFloat::Left;
370  if (flags & SPBF_FLOAT_RIGHT) return ElementFloat::Right;
371  return ElementFloat::None;
372  }
373 
374  default:
375  return ElementFloat::None;
376  }
377  }
378 
385  {
386  switch (pe.type) {
387  case SPET_BUTTON_PUSH:
388  case SPET_BUTTON_TILE:
389  case SPET_BUTTON_VEHICLE: {
392  }
393 
394  default:
395  NOT_REACHED(); // only buttons can float
396  }
397  }
398 
401  {
402  this->layout_cache.clear();
403  }
404 
407  {
408  /* Assume if the layout cache has contents it is valid */
409  if (!this->layout_cache.empty()) return;
410 
411  StoryPage *page = this->GetSelPage();
412  if (page == nullptr) return;
413  int max_width = GetAvailablePageContentWidth();
414  int element_dist = FONT_HEIGHT_NORMAL;
415 
416  /* Make space for the header */
417  int main_y = GetHeadHeight(max_width) + element_dist;
418 
419  /* Current bottom of left/right column */
420  int left_y = main_y;
421  int right_y = main_y;
422  /* Current width of left/right column, 0 indicates no content in column */
423  int left_width = 0;
424  int right_width = 0;
425  /* Indexes into element cache for yet unresolved floats */
426  std::vector<size_t> left_floats;
427  std::vector<size_t> right_floats;
428 
429  /* Build layout */
430  for (const StoryPageElement *pe : this->story_page_elements) {
431  ElementFloat fl = this->GetPageElementFloat(*pe);
432 
433  if (fl == ElementFloat::None) {
434  /* Verify available width */
435  const int min_required_width = 10 * FONT_HEIGHT_NORMAL;
436  int left_offset = (left_width == 0) ? 0 : (left_width + element_dist);
437  int right_offset = (right_width == 0) ? 0 : (right_width + element_dist);
438  if (left_offset + right_offset + min_required_width >= max_width) {
439  /* Width of floats leave too little for main content, push down */
440  main_y = std::max(main_y, left_y);
441  main_y = std::max(main_y, right_y);
442  left_width = right_width = 0;
443  left_offset = right_offset = 0;
444  /* Do not add element_dist here, to keep together elements which were supposed to float besides each other. */
445  }
446  /* Determine height */
447  const int available_width = max_width - left_offset - right_offset;
448  const int height = GetPageElementHeight(*pe, available_width);
449  /* Check for button that needs extra margin */
450  if (left_offset == 0 && right_offset == 0) {
451  switch (pe->type) {
452  case SPET_BUTTON_PUSH:
453  case SPET_BUTTON_TILE:
454  case SPET_BUTTON_VEHICLE:
455  left_offset = right_offset = available_width / 5;
456  break;
457  default:
458  break;
459  }
460  }
461  /* Position element in main column */
462  LayoutCacheElement ce{ pe, {} };
463  ce.bounds.left = left_offset;
464  ce.bounds.right = max_width - right_offset;
465  ce.bounds.top = main_y;
466  main_y += height;
467  ce.bounds.bottom = main_y;
468  this->layout_cache.push_back(ce);
469  main_y += element_dist;
470  /* Clear all floats */
471  left_width = right_width = 0;
472  left_y = right_y = main_y = std::max({main_y, left_y, right_y});
473  left_floats.clear();
474  right_floats.clear();
475  } else {
476  /* Prepare references to correct column */
477  int &cur_width = (fl == ElementFloat::Left) ? left_width : right_width;
478  int &cur_y = (fl == ElementFloat::Left) ? left_y : right_y;
479  std::vector<size_t> &cur_floats = (fl == ElementFloat::Left) ? left_floats : right_floats;
480  /* Position element */
481  cur_width = std::max(cur_width, this->GetPageElementFloatWidth(*pe));
482  LayoutCacheElement ce{ pe, {} };
483  ce.bounds.left = (fl == ElementFloat::Left) ? 0 : (max_width - cur_width);
484  ce.bounds.right = (fl == ElementFloat::Left) ? cur_width : max_width;
485  ce.bounds.top = cur_y;
486  cur_y += GetPageElementHeight(*pe, cur_width);
487  ce.bounds.bottom = cur_y;
488  cur_floats.push_back(this->layout_cache.size());
489  this->layout_cache.push_back(ce);
490  cur_y += element_dist;
491  /* Update floats in column to all have the same width */
492  for (size_t index : cur_floats) {
493  LayoutCacheElement &ce = this->layout_cache[index];
494  ce.bounds.left = (fl == ElementFloat::Left) ? 0 : (max_width - cur_width);
495  ce.bounds.right = (fl == ElementFloat::Left) ? cur_width : max_width;
496  }
497  }
498  }
499  }
500 
506  {
508 
509  /* The largest bottom coordinate of any element is the height of the content */
510  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); });
511 
512  return max_y;
513  }
514 
526  void DrawActionElement(int &y_offset, int width, int line_height, SpriteID action_sprite, StringID string_id = STR_JUST_RAW_STRING) const
527  {
528  Dimension sprite_dim = GetSpriteSize(action_sprite);
529  uint element_height = std::max(sprite_dim.height, (uint)line_height);
530 
531  uint sprite_top = y_offset + (element_height - sprite_dim.height) / 2;
532  uint text_top = y_offset + (element_height - line_height) / 2;
533 
534  DrawSprite(action_sprite, PAL_NONE, 0, sprite_top);
535  DrawString(sprite_dim.width + WD_FRAMETEXT_LEFT, width, text_top, string_id, TC_BLACK);
536 
537  y_offset += element_height;
538  }
539 
545  {
546  switch (pe.type) {
547  case SPET_TEXT:
548  /* Do nothing. */
549  break;
550 
551  case SPET_LOCATION:
552  if (_ctrl_pressed) {
554  } else {
556  }
557  break;
558 
559  case SPET_GOAL:
561  break;
562 
563  case SPET_BUTTON_PUSH:
564  if (this->active_button_id != INVALID_STORY_PAGE_ELEMENT) ResetObjectToPlace();
565  this->active_button_id = pe.index;
566  this->SetTimeout();
568 
570  break;
571 
572  case SPET_BUTTON_TILE:
573  if (this->active_button_id == pe.index) {
575  this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
576  } else {
577  CursorID cursor = TranslateStoryPageButtonCursor(StoryPageButtonData{ pe.referenced_id }.GetCursor());
578  SetObjectToPlaceWnd(cursor, PAL_NONE, HT_RECT, this);
579  this->active_button_id = pe.index;
580  }
582  break;
583 
584  case SPET_BUTTON_VEHICLE:
585  if (this->active_button_id == pe.index) {
587  this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
588  } else {
589  CursorID cursor = TranslateStoryPageButtonCursor(StoryPageButtonData{ pe.referenced_id }.GetCursor());
590  SetObjectToPlaceWnd(cursor, PAL_NONE, HT_VEHICLE, this);
591  this->active_button_id = pe.index;
592  }
594  break;
595 
596  default:
597  NOT_REACHED();
598  }
599  }
600 
601 public:
603  {
604  this->CreateNestedTree();
605  this->vscroll = this->GetScrollbar(WID_SB_SCROLLBAR);
606  this->vscroll->SetStepSize(FONT_HEIGHT_NORMAL);
607 
608  /* Initialize page sort. */
609  this->story_pages.SetSortFuncs(StoryBookWindow::page_sorter_funcs);
610  this->story_pages.ForceRebuild();
611  this->BuildStoryPageList();
612  this->story_page_elements.SetSortFuncs(StoryBookWindow::page_element_sorter_funcs);
613  /* story_page_elements will get built by SetSelectedPage */
614 
615  this->FinishInitNested(window_number);
616  this->owner = (Owner)this->window_number;
617 
618  /* Initialize selected vars. */
619  this->selected_generic_title[0] = '\0';
620  this->selected_page_id = INVALID_STORY_PAGE;
621 
622  this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
623 
624  this->OnInvalidateData(-1);
625  }
626 
631  {
632  this->SetWidgetDisabledState(WID_SB_PREV_PAGE, story_pages.size() == 0 || this->IsFirstPageSelected());
633  this->SetWidgetDisabledState(WID_SB_NEXT_PAGE, story_pages.size() == 0 || this->IsLastPageSelected());
636  }
637 
642  void SetSelectedPage(uint16 page_index)
643  {
644  if (this->selected_page_id != page_index) {
645  if (this->active_button_id) ResetObjectToPlace();
646  this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
647  this->selected_page_id = page_index;
648  this->RefreshSelectedPage();
650  }
651  }
652 
653  void SetStringParameters(int widget) const override
654  {
655  switch (widget) {
656  case WID_SB_SEL_PAGE: {
657  StoryPage *page = this->GetSelPage();
658  SetDParamStr(0, page != nullptr && page->title != nullptr ? page->title : this->selected_generic_title);
659  break;
660  }
661  case WID_SB_CAPTION:
662  if (this->window_number == INVALID_COMPANY) {
663  SetDParam(0, STR_STORY_BOOK_SPECTATOR_CAPTION);
664  } else {
665  SetDParam(0, STR_STORY_BOOK_CAPTION);
666  SetDParam(1, this->window_number);
667  }
668  break;
669  }
670  }
671 
672  void OnPaint() override
673  {
674  /* Detect if content has changed height. This can happen if a
675  * multi-line text contains eg. {COMPANY} and that company is
676  * renamed.
677  */
678  if (this->vscroll->GetCount() != this->GetContentHeight()) {
679  this->vscroll->SetCount(this->GetContentHeight());
682  }
683 
684  this->DrawWidgets();
685  }
686 
687  void DrawWidget(const Rect &r, int widget) const override
688  {
689  if (widget != WID_SB_PAGE_PANEL) return;
690 
691  StoryPage *page = this->GetSelPage();
692  if (page == nullptr) return;
693 
694  const int x = r.left + WD_FRAMETEXT_LEFT;
695  const int y = r.top + WD_FRAMETEXT_TOP;
696  const int right = r.right - WD_FRAMETEXT_RIGHT;
697  const int bottom = r.bottom - WD_FRAMETEXT_BOTTOM;
698 
699  /* Set up a clipping region for the panel. */
700  DrawPixelInfo tmp_dpi;
701  if (!FillDrawPixelInfo(&tmp_dpi, x, y, right - x + 1, bottom - y + 1)) return;
702 
703  DrawPixelInfo *old_dpi = _cur_dpi;
704  _cur_dpi = &tmp_dpi;
705 
706  /* Draw content (now coordinates given to Draw** are local to the new clipping region). */
707  int line_height = FONT_HEIGHT_NORMAL;
708  const int scrollpos = this->vscroll->GetPosition();
709  int y_offset = -scrollpos;
710 
711  /* Date */
712  if (page->date != INVALID_DATE) {
713  SetDParam(0, page->date);
714  DrawString(0, right - x, y_offset, STR_JUST_DATE_LONG, TC_BLACK);
715  }
716  y_offset += line_height;
717 
718  /* Title */
719  SetDParamStr(0, page->title != nullptr ? page->title : this->selected_generic_title);
720  y_offset = DrawStringMultiLine(0, right - x, y_offset, bottom - y, STR_STORY_BOOK_TITLE, TC_BLACK, SA_TOP | SA_HOR_CENTER);
721 
722  /* Page elements */
724  for (const LayoutCacheElement &ce : this->layout_cache) {
725  y_offset = ce.bounds.top - scrollpos;
726  switch (ce.pe->type) {
727  case SPET_TEXT:
728  SetDParamStr(0, ce.pe->text);
729  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);
730  break;
731 
732  case SPET_GOAL: {
733  Goal *g = Goal::Get((GoalID) ce.pe->referenced_id);
734  StringID string_id = g == nullptr ? STR_STORY_BOOK_INVALID_GOAL_REF : STR_JUST_RAW_STRING;
735  if (g != nullptr) SetDParamStr(0, g->text);
736  DrawActionElement(y_offset, ce.bounds.right - ce.bounds.left, line_height, GetPageElementSprite(*ce.pe), string_id);
737  break;
738  }
739 
740  case SPET_LOCATION:
741  SetDParamStr(0, ce.pe->text);
742  DrawActionElement(y_offset, ce.bounds.right - ce.bounds.left, line_height, GetPageElementSprite(*ce.pe));
743  break;
744 
745  case SPET_BUTTON_PUSH:
746  case SPET_BUTTON_TILE:
747  case SPET_BUTTON_VEHICLE: {
748  const int tmargin = WD_BEVEL_TOP + WD_FRAMETEXT_TOP;
749  const FrameFlags frame = this->active_button_id == ce.pe->index ? FR_LOWERED : FR_NONE;
750  const Colours bgcolour = StoryPageButtonData{ ce.pe->referenced_id }.GetColour();
751 
752  DrawFrameRect(ce.bounds.left, ce.bounds.top - scrollpos, ce.bounds.right, ce.bounds.bottom - scrollpos - 1, bgcolour, frame);
753 
754  SetDParamStr(0, ce.pe->text);
755  DrawString(ce.bounds.left + WD_BEVEL_LEFT, ce.bounds.right - WD_BEVEL_RIGHT, ce.bounds.top + tmargin - scrollpos, STR_JUST_RAW_STRING, TC_WHITE, SA_CENTER);
756  break;
757  }
758 
759  default: NOT_REACHED();
760  }
761  }
762 
763  /* Restore clipping region. */
764  _cur_dpi = old_dpi;
765  }
766 
767  void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
768  {
769  if (widget != WID_SB_SEL_PAGE && widget != WID_SB_PAGE_PANEL) return;
770 
771  Dimension d;
772  d.height = FONT_HEIGHT_NORMAL;
773  d.width = 0;
774 
775  switch (widget) {
776  case WID_SB_SEL_PAGE: {
777 
778  /* Get max title width. */
779  for (uint16 i = 0; i < this->story_pages.size(); i++) {
780  const StoryPage *s = this->story_pages[i];
781 
782  if (s->title != nullptr) {
783  SetDParamStr(0, s->title);
784  } else {
785  SetDParamStr(0, this->selected_generic_title);
786  }
787  Dimension title_d = GetStringBoundingBox(STR_BLACK_RAW_STRING);
788 
789  if (title_d.width > d.width) {
790  d.width = title_d.width;
791  }
792  }
793 
794  d.width += padding.width;
795  d.height += padding.height;
796  *size = maxdim(*size, d);
797  break;
798  }
799 
800  case WID_SB_PAGE_PANEL: {
801  d.height *= 5;
802  d.height += padding.height + WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM;
803  *size = maxdim(*size, d);
804  break;
805  }
806  }
807 
808  }
809 
810  void OnResize() override
811  {
814  this->vscroll->SetCount(this->GetContentHeight());
815  }
816 
817  void OnClick(Point pt, int widget, int click_count) override
818  {
819  switch (widget) {
820  case WID_SB_SEL_PAGE: {
821  DropDownList list = this->BuildDropDownList();
822  if (!list.empty()) {
823  /* Get the index of selected page. */
824  int selected = 0;
825  for (uint16 i = 0; i < this->story_pages.size(); i++) {
826  const StoryPage *p = this->story_pages[i];
827  if (p->index == this->selected_page_id) break;
828  selected++;
829  }
830 
831  ShowDropDownList(this, std::move(list), selected, widget);
832  }
833  break;
834  }
835 
836  case WID_SB_PREV_PAGE:
837  this->SelectPrevPage();
838  break;
839 
840  case WID_SB_NEXT_PAGE:
841  this->SelectNextPage();
842  break;
843 
844  case WID_SB_PAGE_PANEL: {
845  int clicked_y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SB_PAGE_PANEL, WD_FRAMETEXT_TOP);
847 
848  for (const LayoutCacheElement &ce : this->layout_cache) {
849  if (clicked_y >= ce.bounds.top && clicked_y < ce.bounds.bottom && pt.x >= ce.bounds.left && pt.x < ce.bounds.right) {
850  this->OnPageElementClick(*ce.pe);
851  return;
852  }
853  }
854  }
855  }
856  }
857 
858  void OnDropdownSelect(int widget, int index) override
859  {
860  if (widget != WID_SB_SEL_PAGE) return;
861 
862  /* index (which is set in BuildDropDownList) is the page id. */
863  this->SetSelectedPage(index);
864  }
865 
873  void OnInvalidateData(int data = 0, bool gui_scope = true) override
874  {
875  if (!gui_scope) return;
876 
877  /* If added/removed page, force rebuild. Sort order never change so just a
878  * re-sort is never needed.
879  */
880  if (data == -1) {
881  this->story_pages.ForceRebuild();
882  this->BuildStoryPageList();
883 
884  /* Was the last page removed? */
885  if (this->story_pages.size() == 0) {
886  this->selected_generic_title[0] = '\0';
887  }
888 
889  /* Verify page selection. */
890  if (!_story_page_pool.IsValidID(this->selected_page_id)) {
891  this->selected_page_id = INVALID_STORY_PAGE;
892  }
893  if (this->selected_page_id == INVALID_STORY_PAGE && this->story_pages.size() > 0) {
894  /* No page is selected, but there exist at least one available.
895  * => Select first page.
896  */
897  this->SetSelectedPage(this->story_pages[0]->index);
898  }
899 
900  this->SetWidgetDisabledState(WID_SB_SEL_PAGE, this->story_pages.size() == 0);
903  } else if (data >= 0 && this->selected_page_id == data) {
904  this->RefreshSelectedPage();
905  }
906  }
907 
908  void OnTimeout() override
909  {
910  this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
912  }
913 
914  void OnPlaceObject(Point pt, TileIndex tile) override
915  {
916  const StoryPageElement *const pe = StoryPageElement::GetIfValid(this->active_button_id);
917  if (pe == nullptr || pe->type != SPET_BUTTON_TILE) {
919  this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
921  return;
922  }
923 
924  DoCommandP(tile, pe->index, 0, CMD_STORY_PAGE_BUTTON);
926  }
927 
928  bool OnVehicleSelect(const Vehicle *v) override
929  {
930  const StoryPageElement *const pe = StoryPageElement::GetIfValid(this->active_button_id);
931  if (pe == nullptr || pe->type != SPET_BUTTON_VEHICLE) {
933  this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
935  return false;
936  }
937 
938  /* Check that the vehicle matches the requested type */
940  VehicleType wanted_vehtype = data.GetVehicleType();
941  if (wanted_vehtype != VEH_INVALID && wanted_vehtype != v->type) return false;
942 
945  return true;
946  }
947 
948  void OnPlaceObjectAbort() override
949  {
950  this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
952  }
953 };
954 
955 GUIStoryPageList::SortFunction * const StoryBookWindow::page_sorter_funcs[] = {
956  &PageOrderSorter,
957 };
958 
959 GUIStoryPageElementList::SortFunction * const StoryBookWindow::page_element_sorter_funcs[] = {
960  &PageElementOrderSorter,
961 };
962 
963 static const NWidgetPart _nested_story_book_widgets[] = {
965  NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
966  NWidget(WWT_CAPTION, COLOUR_BROWN, WID_SB_CAPTION), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
967  NWidget(WWT_SHADEBOX, COLOUR_BROWN),
968  NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
969  NWidget(WWT_STICKYBOX, COLOUR_BROWN),
970  EndContainer(),
972  NWidget(NWID_VERTICAL), SetFill(1, 1),
975  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),
976  NWidget(NWID_BUTTON_DROPDOWN, COLOUR_BROWN, WID_SB_SEL_PAGE), SetMinimalSize(93, 12), SetFill(1, 0),
977  SetDataTip(STR_BLACK_RAW_STRING, STR_STORY_BOOK_SEL_PAGE_TOOLTIP), SetResize(1, 0),
978  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),
979  EndContainer(),
980  EndContainer(),
981  NWidget(NWID_VERTICAL), SetFill(0, 1),
982  NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_SB_SCROLLBAR),
983  NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
984  EndContainer(),
985  EndContainer(),
986 };
987 
988 static WindowDesc _story_book_desc(
989  WDP_CENTER, "view_story", 400, 300,
991  0,
992  _nested_story_book_widgets, lengthof(_nested_story_book_widgets)
993 );
994 
995 static CursorID TranslateStoryPageButtonCursor(StoryPageButtonCursor cursor)
996 {
997  switch (cursor) {
998  case SPBC_MOUSE: return SPR_CURSOR_MOUSE;
999  case SPBC_ZZZ: return SPR_CURSOR_ZZZ;
1000  case SPBC_BUOY: return SPR_CURSOR_BUOY;
1001  case SPBC_QUERY: return SPR_CURSOR_QUERY;
1002  case SPBC_HQ: return SPR_CURSOR_HQ;
1003  case SPBC_SHIP_DEPOT: return SPR_CURSOR_SHIP_DEPOT;
1004  case SPBC_SIGN: return SPR_CURSOR_SIGN;
1005  case SPBC_TREE: return SPR_CURSOR_TREE;
1006  case SPBC_BUY_LAND: return SPR_CURSOR_BUY_LAND;
1007  case SPBC_LEVEL_LAND: return SPR_CURSOR_LEVEL_LAND;
1008  case SPBC_TOWN: return SPR_CURSOR_TOWN;
1009  case SPBC_INDUSTRY: return SPR_CURSOR_INDUSTRY;
1010  case SPBC_ROCKY_AREA: return SPR_CURSOR_ROCKY_AREA;
1011  case SPBC_DESERT: return SPR_CURSOR_DESERT;
1012  case SPBC_TRANSMITTER: return SPR_CURSOR_TRANSMITTER;
1013  case SPBC_AIRPORT: return SPR_CURSOR_AIRPORT;
1014  case SPBC_DOCK: return SPR_CURSOR_DOCK;
1015  case SPBC_CANAL: return SPR_CURSOR_CANAL;
1016  case SPBC_LOCK: return SPR_CURSOR_LOCK;
1017  case SPBC_RIVER: return SPR_CURSOR_RIVER;
1018  case SPBC_AQUEDUCT: return SPR_CURSOR_AQUEDUCT;
1019  case SPBC_BRIDGE: return SPR_CURSOR_BRIDGE;
1020  case SPBC_RAIL_STATION: return SPR_CURSOR_RAIL_STATION;
1021  case SPBC_TUNNEL_RAIL: return SPR_CURSOR_TUNNEL_RAIL;
1022  case SPBC_TUNNEL_ELRAIL: return SPR_CURSOR_TUNNEL_ELRAIL;
1023  case SPBC_TUNNEL_MONO: return SPR_CURSOR_TUNNEL_MONO;
1024  case SPBC_TUNNEL_MAGLEV: return SPR_CURSOR_TUNNEL_MAGLEV;
1025  case SPBC_AUTORAIL: return SPR_CURSOR_AUTORAIL;
1026  case SPBC_AUTOELRAIL: return SPR_CURSOR_AUTOELRAIL;
1027  case SPBC_AUTOMONO: return SPR_CURSOR_AUTOMONO;
1028  case SPBC_AUTOMAGLEV: return SPR_CURSOR_AUTOMAGLEV;
1029  case SPBC_WAYPOINT: return SPR_CURSOR_WAYPOINT;
1030  case SPBC_RAIL_DEPOT: return SPR_CURSOR_RAIL_DEPOT;
1031  case SPBC_ELRAIL_DEPOT: return SPR_CURSOR_ELRAIL_DEPOT;
1032  case SPBC_MONO_DEPOT: return SPR_CURSOR_MONO_DEPOT;
1033  case SPBC_MAGLEV_DEPOT: return SPR_CURSOR_MAGLEV_DEPOT;
1034  case SPBC_CONVERT_RAIL: return SPR_CURSOR_CONVERT_RAIL;
1035  case SPBC_CONVERT_ELRAIL: return SPR_CURSOR_CONVERT_ELRAIL;
1036  case SPBC_CONVERT_MONO: return SPR_CURSOR_CONVERT_MONO;
1037  case SPBC_CONVERT_MAGLEV: return SPR_CURSOR_CONVERT_MAGLEV;
1038  case SPBC_AUTOROAD: return SPR_CURSOR_AUTOROAD;
1039  case SPBC_AUTOTRAM: return SPR_CURSOR_AUTOTRAM;
1040  case SPBC_ROAD_DEPOT: return SPR_CURSOR_ROAD_DEPOT;
1041  case SPBC_BUS_STATION: return SPR_CURSOR_BUS_STATION;
1042  case SPBC_TRUCK_STATION: return SPR_CURSOR_TRUCK_STATION;
1043  case SPBC_ROAD_TUNNEL: return SPR_CURSOR_ROAD_TUNNEL;
1044  case SPBC_CLONE_TRAIN: return SPR_CURSOR_CLONE_TRAIN;
1045  case SPBC_CLONE_ROADVEH: return SPR_CURSOR_CLONE_ROADVEH;
1046  case SPBC_CLONE_SHIP: return SPR_CURSOR_CLONE_SHIP;
1047  case SPBC_CLONE_AIRPLANE: return SPR_CURSOR_CLONE_AIRPLANE;
1048  case SPBC_DEMOLISH: return ANIMCURSOR_DEMOLISH;
1049  case SPBC_LOWERLAND: return ANIMCURSOR_LOWERLAND;
1050  case SPBC_RAISELAND: return ANIMCURSOR_RAISELAND;
1051  case SPBC_PICKSTATION: return ANIMCURSOR_PICKSTATION;
1052  case SPBC_BUILDSIGNALS: return ANIMCURSOR_BUILDSIGNALS;
1053  default: return SPR_CURSOR_QUERY;
1054  }
1055 }
1056 
1062 void ShowStoryBook(CompanyID company, uint16 page_id)
1063 {
1064  if (!Company::IsValidID(company)) company = (CompanyID)INVALID_COMPANY;
1065 
1066  StoryBookWindow *w = AllocateWindowDescFront<StoryBookWindow>(&_story_book_desc, company, true);
1067  if (page_id != INVALID_STORY_PAGE) w->SetSelectedPage(page_id);
1068 }
StoryPageElement::sort_value
uint32 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:140
Pool::IsValidID
bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:120
Window::SetTimeout
void SetTimeout()
Set the timeout flag of the window and initiate the timer.
Definition: window_gui.h:367
SPET_TEXT
@ SPET_TEXT
A text element.
Definition: story_base.h:31
TileIndex
uint32 TileIndex
The index/ID of a Tile.
Definition: tile_type.h:83
Goal
Struct about goals, current and completed.
Definition: goal_base.h:21
StoryBookWindow::OnClick
void OnClick(Point pt, int widget, int click_count) override
A click with the left mouse button has been made on the window.
Definition: story_gui.cpp:817
StoryBookWindow::GetSelPageNum
int GetSelPageNum() const
Get the page number of selected page.
Definition: story_gui.cpp:148
Pool::PoolItem<&_goal_pool >::Get
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:329
ScrollMainWindowToTile
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition: viewport.cpp:2443
ShowGoalsList
void ShowGoalsList(CompanyID company)
Open a goal list window.
Definition: goal_gui.cpp:320
DropDownListParamStringItem
String list item with parameters.
Definition: dropdown_type.h:56
SetScrollbar
static NWidgetPart SetScrollbar(int index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1104
ShowExtraViewportWindow
void ShowExtraViewportWindow(TileIndex tile=INVALID_TILE)
Show a new Extra Viewport window.
Definition: viewport_gui.cpp:168
Dimension
Dimensions (a width and height) of a rectangle in 2D.
Definition: geometry_type.hpp:27
command_func.h
WWT_STICKYBOX
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition: widget_type.h:64
Pool::PoolItem<&_story_page_element_pool >::GetIfValid
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:340
GUIList::Sort
bool Sort(Comp compare)
Sort the list.
Definition: sortlist_type.h:247
Window::GetScrollbar
const Scrollbar * GetScrollbar(uint widnum) const
Return the Scrollbar to a widget index.
Definition: window.cpp:309
dropdown_func.h
StoryBookWindow::SetStringParameters
void SetStringParameters(int widget) const override
Initialize string parameters for a widget.
Definition: story_gui.cpp:653
StoryBookWindow::DrawWidget
void DrawWidget(const Rect &r, int widget) const override
Draw the contents of a nested widget.
Definition: story_gui.cpp:687
company_base.h
ANIMCURSOR_RAISELAND
static const CursorID ANIMCURSOR_RAISELAND
696 - 698 - raise land tool
Definition: sprites.h:1494
StoryPageButtonFlags
StoryPageButtonFlags
Flags available for buttons.
Definition: story_base.h:45
WWT_CAPTION
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:59
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:384
WID_SB_NEXT_PAGE
@ WID_SB_NEXT_PAGE
Next button.
Definition: story_widget.h:21
Scrollbar::GetScrolledRowFromWidget
int GetScrolledRowFromWidget(int clickpos, const Window *const w, int widget, int padding=0, int line_height=-1) const
Compute the row of a scrolled widget that a user clicked in.
Definition: widget.cpp:1972
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:99
StoryBookWindow::GetPageElementSprite
SpriteID GetPageElementSprite(const StoryPageElement &pe) const
Decides which sprite to display for a given page element.
Definition: story_gui.cpp:310
StoryBookWindow::GetAvailablePageContentWidth
uint GetAvailablePageContentWidth() const
Get the width available for displaying content on the page panel.
Definition: story_gui.cpp:278
WWT_DEFSIZEBOX
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition: widget_type.h:63
StoryBookWindow::BuildDropDownList
DropDownList BuildDropDownList() const
Builds the page selector drop down list.
Definition: story_gui.cpp:251
FrameFlags
FrameFlags
Flags to describe the look of the frame.
Definition: window_gui.h:25
Window::CreateNestedTree
void CreateNestedTree(bool fill_nested=true)
Perform the first part of the initialization of a nested widget tree.
Definition: window.cpp:1832
SA_LEFT
@ SA_LEFT
Left align the text.
Definition: gfx_func.h:96
Pool::PoolItem::index
Tindex index
Index of this pool item.
Definition: pool_type.hpp:227
NWID_HORIZONTAL
@ NWID_HORIZONTAL
Horizontal container.
Definition: widget_type.h:73
DropDownListCharStringItem
List item containing a C char string.
Definition: dropdown_type.h:70
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:1496
SPET_BUTTON_PUSH
@ SPET_BUTTON_PUSH
A push button that triggers an immediate event.
Definition: story_base.h:34
StoryBookWindow::layout_cache
LayoutCache layout_cache
Cached element layout.
Definition: story_gui.cpp:58
Scrollbar::SetCount
void SetCount(int num)
Sets the number of elements in the list.
Definition: widget_type.h:679
_ctrl_pressed
bool _ctrl_pressed
Is Ctrl pressed?
Definition: gfx.cpp:35
vehicle_base.h
SetResize
static NWidgetPart SetResize(int16 dx, int16 dy)
Widget part function for setting the resize step.
Definition: widget_type.h:939
WD_FRAMETEXT_TOP
@ WD_FRAMETEXT_TOP
Top offset of the text of the frame.
Definition: window_gui.h:72
StoryBookWindow::SelectNextPage
void SelectNextPage()
Selects the next available page after the currently selected page.
Definition: story_gui.cpp:230
goal_base.h
DrawString
int DrawString(int left, int right, int top, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition: gfx.cpp:640
story_widget.h
SPET_GOAL
@ SPET_GOAL
An element that references a goal.
Definition: story_base.h:33
INVALID_STORY_PAGE_ELEMENT
static const StoryPageElementID INVALID_STORY_PAGE_ELEMENT
Constant representing a non-existing story page element.
Definition: story_type.h:22
ANIMCURSOR_DEMOLISH
static const CursorID ANIMCURSOR_DEMOLISH
704 - 707 - demolish dynamite
Definition: sprites.h:1492
StoryPage::sort_value
uint32 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:160
Window::owner
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition: window_gui.h:325
WindowNumber
int32 WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:711
FR_LOWERED
@ FR_LOWERED
If set the frame is lowered and the background colour brighter (ie. buttons when pressed)
Definition: window_gui.h:29
SA_CENTER
@ SA_CENTER
Center both horizontally and vertically.
Definition: gfx_func.h:106
Vehicle
Vehicle data structure.
Definition: vehicle_base.h:222
SA_HOR_CENTER
@ SA_HOR_CENTER
Horizontally center the text.
Definition: gfx_func.h:97
Owner
Owner
Enum for all companies/owners.
Definition: company_type.h:18
Scrollbar
Scrollbar data structure.
Definition: widget_type.h:598
StoryBookWindow::OnTimeout
void OnTimeout() override
Called when this window's timeout has been reached.
Definition: story_gui.cpp:908
WD_FRAMETEXT_LEFT
@ WD_FRAMETEXT_LEFT
Left offset of the text of the frame.
Definition: window_gui.h:70
SetDParam
static void SetDParam(uint n, uint64 v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings_func.h:199
NWidgetPart
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:919
SetDataTip
static NWidgetPart SetDataTip(uint32 data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1023
WID_SB_PAGE_PANEL
@ WID_SB_PAGE_PANEL
Page body.
Definition: story_widget.h:18
GetStringBoundingBox
Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:842
StoryPageElement::referenced_id
uint32 referenced_id
Id of referenced object (location, goal etc.)
Definition: story_base.h:144
DrawStringMultiLine
int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition: gfx.cpp:763
StoryBookWindow::selected_generic_title
char selected_generic_title[255]
If the selected page doesn't have a custom title, this buffer is used to store a generic page title.
Definition: story_gui.cpp:63
SpriteID
uint32 SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:17
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
WindowDesc
High level window description.
Definition: window_gui.h:166
WC_STORY_BOOK
@ WC_STORY_BOOK
Story book; Window numbers:
Definition: window_type.h:289
SA_TOP
@ SA_TOP
Top align the text.
Definition: gfx_func.h:101
window_gui.h
ANIMCURSOR_PICKSTATION
static const CursorID ANIMCURSOR_PICKSTATION
716 - 718 - goto-order icon
Definition: sprites.h:1495
StoryBookWindow::vscroll
Scrollbar * vscroll
Scrollbar of the page text.
Definition: story_gui.cpp:57
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
Window::resize
ResizeInfo resize
Resize information.
Definition: window_gui.h:323
StoryPageElement::type
StoryPageElementType type
Type of page element.
Definition: story_base.h:142
Scrollbar::GetCount
uint16 GetCount() const
Gets the number of elements in the list.
Definition: widget_type.h:622
tilehighlight_func.h
CursorID
uint32 CursorID
The number of the cursor (sprite)
Definition: gfx_type.h:19
DoCommandP
bool DoCommandP(const CommandContainer *container, bool my_cmd)
Shortcut for the long DoCommandP when having a container with the data.
Definition: command.cpp:541
FS_NORMAL
@ FS_NORMAL
Index of the normal font in the font tables.
Definition: gfx_type.h:207
StoryBookWindow::story_page_elements
GUIStoryPageElementList story_page_elements
Sorted list of page elements that belong to the current page.
Definition: story_gui.cpp:61
Window::height
int height
Height of the window (number of pixels down in y direction)
Definition: window_gui.h:321
StoryPageID
uint16 StoryPageID
ID of a story page.
Definition: story_type.h:16
GUIList< const StoryPage * >::SortFunction
bool SortFunction(const const StoryPage * &, const const StoryPage * &)
Signature of sort function.
Definition: sortlist_type.h:48
StoryBookWindow::SelectPrevPage
void SelectPrevPage()
Selects the previous available page before the currently selected page.
Definition: story_gui.cpp:210
StoryBookWindow::GetSelPage
StoryPage * GetSelPage() const
Get instance of selected page.
Definition: story_gui.cpp:138
WD_FRAMETEXT_BOTTOM
@ WD_FRAMETEXT_BOTTOM
Bottom offset of the text of the frame.
Definition: window_gui.h:73
ShowDropDownList
void ShowDropDownList(Window *w, DropDownList &&list, int selected, int button, uint width, bool auto_width, bool instant_close)
Show a drop down list.
Definition: dropdown.cpp:447
StoryBookWindow
Definition: story_gui.cpp:43
StoryBookWindow::InvalidateStoryPageElementLayout
void InvalidateStoryPageElementLayout()
Invalidate the current page layout.
Definition: story_gui.cpp:400
StoryPage
Struct about stories, current and completed.
Definition: story_base.h:159
dropdown_type.h
StoryBookWindow::RefreshSelectedPage
void RefreshSelectedPage()
Updates the content of selected page.
Definition: story_gui.cpp:187
Window::SetWidgetDisabledState
void SetWidgetDisabledState(byte widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition: window_gui.h:393
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:290
WID_SB_CAPTION
@ WID_SB_CAPTION
Caption of the window.
Definition: story_widget.h:16
DropDownListStringItem
Common string list item.
Definition: dropdown_type.h:39
StoryBookWindow::OnPageElementClick
void OnPageElementClick(const StoryPageElement &pe)
Internal event handler for when a page element is clicked.
Definition: story_gui.cpp:544
safeguards.h
StoryBookWindow::OnPlaceObjectAbort
void OnPlaceObjectAbort() override
The user cancelled a tile highlight mode that has been set.
Definition: story_gui.cpp:948
sortlist_type.h
Window::flags
WindowFlags flags
Window flags.
Definition: window_gui.h:311
VEH_INVALID
@ VEH_INVALID
Non-existing type of vehicle.
Definition: vehicle_type.h:35
StoryBookWindow::selected_page_id
StoryPageID selected_page_id
Pool index of selected page.
Definition: story_gui.cpp:62
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:978
CMD_STORY_PAGE_BUTTON
@ CMD_STORY_PAGE_BUTTON
selection via story page button
Definition: command_type.h:299
StoryBookWindow::SetSelectedPage
void SetSelectedPage(uint16 page_index)
Sets the selected page.
Definition: story_gui.cpp:642
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:53
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:331
date_func.h
WD_FRAMETEXT_RIGHT
@ WD_FRAMETEXT_RIGHT
Right offset of the text of the frame.
Definition: window_gui.h:71
stdafx.h
Window::window_number
WindowNumber window_number
Window number within the window class.
Definition: window_gui.h:313
VehicleType
VehicleType
Available vehicle types.
Definition: vehicle_type.h:21
StoryPage::title
char * title
Title of story page.
Definition: story_base.h:164
Pool::Get
Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:109
ShowStoryBook
void ShowStoryBook(CompanyID company, uint16 page_id)
Raise or create the story book window for company, at page page_id.
Definition: story_gui.cpp:1062
viewport_func.h
WC_NONE
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:38
StoryBookWindow::OnDropdownSelect
void OnDropdownSelect(int widget, int index) override
A dropdown option associated to this window has been selected.
Definition: story_gui.cpp:858
NWID_VERTICAL
@ NWID_VERTICAL
Vertical container.
Definition: widget_type.h:75
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:1616
GetStringHeight
int GetStringHeight(const char *str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition: gfx.cpp:689
GetSpriteSize
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition: gfx.cpp:913
WWT_CLOSEBOX
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition: widget_type.h:67
WWT_RESIZEBOX
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:66
GUIList::NeedRebuild
bool NeedRebuild() const
Check if a rebuild is needed.
Definition: sortlist_type.h:362
StoryBookWindow::IsFirstPageSelected
bool IsFirstPageSelected()
Check if the selected page is also the first available page.
Definition: story_gui.cpp:163
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:526
StringID
uint32 StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
EndContainer
static NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
Definition: widget_type.h:1008
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:378
strings_func.h
NWID_VSCROLLBAR
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition: widget_type.h:82
StoryBookWindow::PageElementOrderSorter
static bool PageElementOrderSorter(const StoryPageElement *const &a, const StoryPageElement *const &b)
Sort story page elements by order value.
Definition: story_gui.cpp:119
INVALID_DATE
static const Date INVALID_DATE
Representation of an invalid date.
Definition: date_type.h:110
WD_BEVEL_RIGHT
@ WD_BEVEL_RIGHT
Width of right bevel border.
Definition: window_gui.h:55
FONT_HEIGHT_NORMAL
#define FONT_HEIGHT_NORMAL
Height of characters in the normal (FS_NORMAL) font.
Definition: gfx_func.h:179
NWidget
static NWidgetPart NWidget(WidgetType tp, Colours col, int16 idx=-1)
Widget part function for starting a new 'real' widget.
Definition: widget_type.h:1123
Goal::completed
bool completed
Is the goal completed or not?
Definition: goal_base.h:27
WID_SB_PREV_PAGE
@ WID_SB_PREV_PAGE
Prev button.
Definition: story_widget.h:20
geometry_func.hpp
StoryBookWindow::OnResize
void OnResize() override
Called after the window got resized.
Definition: story_gui.cpp:810
SetMinimalSize
static NWidgetPart SetMinimalSize(int16 x, int16 y)
Widget part function for setting the minimal size.
Definition: widget_type.h:956
WWT_PANEL
@ WWT_PANEL
Simple depressed panel.
Definition: widget_type.h:48
StoryBookWindow::story_pages
GUIStoryPageList story_pages
Sorted list of pages.
Definition: story_gui.cpp:60
StoryBookWindow::UpdateWidgetSize
void UpdateWidgetSize(int 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:767
StoryPageElementID
uint16 StoryPageElementID
ID of a story page element.
Definition: story_type.h:15
HT_RECT
@ HT_RECT
rectangle (stations, depots, ...)
Definition: tilehighlight_type.h:21
Scrollbar::GetPosition
uint16 GetPosition() const
Gets the position of the first visible element in the list.
Definition: widget_type.h:640
StoryPageElement
Struct about story page elements.
Definition: story_base.h:139
Window::FinishInitNested
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition: window.cpp:1848
company_func.h
DrawFrameRect
void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags)
Draw frame rectangle.
Definition: widget.cpp:175
WD_BEVEL_TOP
@ WD_BEVEL_TOP
Height of top bevel border.
Definition: window_gui.h:56
WD_BEVEL_LEFT
@ WD_BEVEL_LEFT
Width of left bevel border.
Definition: window_gui.h:54
window_func.h
GUIList::ForceRebuild
void ForceRebuild()
Force that a rebuild is needed.
Definition: sortlist_type.h:370
lengthof
#define lengthof(x)
Return the length of an fixed size array.
Definition: stdafx.h:369
Window::width
int width
width of the window (number of pixels to the right in x direction)
Definition: window_gui.h:320
Scrollbar::SetCapacityFromWidget
void SetCapacityFromWidget(Window *w, int widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget.
Definition: widget.cpp:1986
INVALID_STORY_PAGE
static const StoryPageID INVALID_STORY_PAGE
Constant representing a non-existing story page.
Definition: story_type.h:23
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:914
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:3358
Scrollbar::SetStepSize
void SetStepSize(uint16 stepsize)
Set the distance to scroll when using the buttons or the wheel.
Definition: widget_type.h:668
INVALID_COMPANY
@ INVALID_COMPANY
An invalid company.
Definition: company_type.h:30
StoryPageElement::text
char * text
Static content text of page element.
Definition: story_base.h:145
SetFill
static NWidgetPart SetFill(uint fill_x, uint fill_y)
Widget part function for setting filling.
Definition: widget_type.h:992
gui.h
SPR_CURSOR_MOUSE
static const CursorID SPR_CURSOR_MOUSE
Cursor sprite numbers.
Definition: sprites.h:1374
StoryPageButtonData
Helper to construct packed "id" values for button-type StoryPageElement.
Definition: story_base.h:117
StoryBookWindow::PageOrderSorter
static bool PageOrderSorter(const StoryPage *const &a, const StoryPage *const &b)
Sort story pages by order value.
Definition: story_gui.cpp:90
Window
Data structure for an opened window.
Definition: window_gui.h:277
GUIList::RebuildDone
void RebuildDone()
Notify the sortlist that the rebuild is done.
Definition: sortlist_type.h:380
WID_SB_SEL_PAGE
@ WID_SB_SEL_PAGE
Page selector.
Definition: story_widget.h:17
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:318
BaseVehicle::type
VehicleType type
Type of vehicle.
Definition: vehicle_type.h:52
Window::DrawWidgets
void DrawWidgets() const
Paint all widgets of a window.
Definition: widget.cpp:602
StoryBookWindow::UpdatePrevNextDisabledState
void UpdatePrevNextDisabledState()
Updates the disabled state of the prev/next buttons.
Definition: story_gui.cpp:630
StoryBookWindow::LayoutCacheElement
Definition: story_gui.cpp:45
StoryBookWindow::OnInvalidateData
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Definition: story_gui.cpp:873
StoryBookWindow::BuildStoryPageList
void BuildStoryPageList()
(Re)Build story page list.
Definition: story_gui.cpp:71
story_base.h
Window::SetWidgetDirty
void SetWidgetDirty(byte widget_index) const
Invalidate a widget, i.e.
Definition: window.cpp:597
WID_SB_SCROLLBAR
@ WID_SB_SCROLLBAR
Scrollbar of the goal list.
Definition: story_widget.h:19
GoalID
uint16 GoalID
ID of a goal.
Definition: goal_type.h:38
Rect
Specification of a rectangle with absolute coordinates of all edges.
Definition: geometry_type.hpp:47
StoryBookWindow::GetContentHeight
uint GetContentHeight()
Get the total height of the content displayed in this window.
Definition: story_gui.cpp:505
StoryPage::date
Date date
Date when the page was created.
Definition: story_base.h:161
WD_BEVEL_BOTTOM
@ WD_BEVEL_BOTTOM
Height of bottom bevel border.
Definition: window_gui.h:57
lastof
#define lastof(x)
Get the last element of an fixed size array.
Definition: stdafx.h:385
StoryPage::company
CompanyID company
StoryPage is for a specific company; INVALID_COMPANY if it is global.
Definition: story_base.h:162
StoryBookWindow::IsLastPageSelected
bool IsLastPageSelected()
Check if the selected page is also the last available page.
Definition: story_gui.cpp:174
ResetObjectToPlace
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
Definition: viewport.cpp:3421
WDP_CENTER
@ WDP_CENTER
Center the window.
Definition: window_gui.h:155
StoryBookWindow::OnPaint
void OnPaint() override
The window must be repainted.
Definition: story_gui.cpp:672
StoryBookWindow::GetPageElementFloat
ElementFloat GetPageElementFloat(const StoryPageElement &pe) const
Get the float style of a page element.
Definition: story_gui.cpp:362
Goal::text
char * text
Text of the goal.
Definition: goal_base.h:25
SetDParamStr
void SetDParamStr(uint n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition: strings.cpp:286
WWT_TEXTBTN
@ WWT_TEXTBTN
(Toggle) Button with text
Definition: widget_type.h:53
StoryBookWindow::BuildStoryPageElementList
void BuildStoryPageElementList()
(Re)Build story page element list.
Definition: story_gui.cpp:96
NWID_BUTTON_DROPDOWN
@ NWID_BUTTON_DROPDOWN
Button with a drop-down.
Definition: widget_type.h:80
GUIList::SetSortFuncs
void SetSortFuncs(SortFunction *const *n_funcs)
Hand the array of sort function pointers to the sort list.
Definition: sortlist_type.h:270
DrawPixelInfo
Data about how and where to blit pixels.
Definition: gfx_type.h:155
StoryBookWindow::EnsureStoryPageElementLayout
void EnsureStoryPageElementLayout() const
Create the page layout if it is missing.
Definition: story_gui.cpp:406
StoryBookWindow::active_button_id
StoryPageElementID active_button_id
Which button element the player is currently using.
Definition: story_gui.cpp:65
ANIMCURSOR_LOWERLAND
static const CursorID ANIMCURSOR_LOWERLAND
699 - 701 - lower land tool
Definition: sprites.h:1493
WWT_SHADEBOX
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition: widget_type.h:62