OpenTTD
widget_type.h
Go to the documentation of this file.
1 /* $Id: widget_type.h 27900 2017-08-27 11:48:38Z frosch $ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * 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.
6  * 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.
7  * 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/>.
8  */
9 
12 #ifndef WIDGET_TYPE_H
13 #define WIDGET_TYPE_H
14 
15 #include "core/alloc_type.hpp"
16 #include "core/bitmath_func.hpp"
17 #include "core/math_func.hpp"
18 #include "strings_type.h"
19 #include "gfx_type.h"
20 #include "window_type.h"
21 
22 static const int WIDGET_LIST_END = -1;
23 
26  /* Number of column bits of the WWT_MATRIX widget data. */
29 
30  /* Number of row bits of the WWT_MATRIX widget data. */
33 };
34 
41 };
42 
46 enum WidgetType {
47  /* Window widget types. */
49 
62 
67 
73 
74  /* Nested widget types. */
85 
86  /* Nested widget part types. */
97 
98  /* Pushable window widget types. */
99  WWT_MASK = 0x7F,
100 
101  WWB_PUSHBUTTON = 1 << 7,
102 
103  WWT_PUSHBTN = WWT_PANEL | WWB_PUSHBUTTON,
104  WWT_PUSHTXTBTN = WWT_TEXTBTN | WWB_PUSHBUTTON,
105  WWT_PUSHIMGBTN = WWT_IMGBTN | WWB_PUSHBUTTON,
106  WWT_PUSHARROWBTN = WWT_ARROWBTN | WWB_PUSHBUTTON,
107  NWID_PUSHBUTTON_DROPDOWN = NWID_BUTTON_DROPDOWN | WWB_PUSHBUTTON,
108 };
109 
114 };
115 
116 /* Forward declarations. */
117 class NWidgetCore;
118 class Scrollbar;
119 
127 public:
129 
130  virtual void SetupSmallestSize(Window *w, bool init_array) = 0;
131  virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) = 0;
132 
133  virtual void FillNestedArray(NWidgetBase **array, uint length) = 0;
134 
135  virtual NWidgetCore *GetWidgetFromPos(int x, int y) = 0;
137 
138  virtual bool IsHighlighted() const { return false; }
139  virtual TextColour GetHighlightColour() const { return TC_INVALID; }
140  virtual void SetHighlighted(TextColour highlight_colour) {}
141 
149  inline void SetPadding(uint8 top, uint8 right, uint8 bottom, uint8 left)
150  {
151  this->padding_top = top;
152  this->padding_right = right;
153  this->padding_bottom = bottom;
154  this->padding_left = left;
155  }
156 
157  inline uint GetHorizontalStepSize(SizingType sizing) const;
158  inline uint GetVerticalStepSize(SizingType sizing) const;
159 
160  virtual void Draw(const Window *w) = 0;
161  virtual void SetDirty(const Window *w) const;
162 
164  uint fill_x;
165  uint fill_y;
166  uint resize_x;
167  uint resize_y;
168  /* Size of the widget in the smallest window possible.
169  * Computed by #SetupSmallestSize() followed by #AssignSizePosition().
170  */
171  uint smallest_x;
172  uint smallest_y;
173  /* Current widget size (that is, after resizing). */
174  uint current_x;
175  uint current_y;
176 
177  uint pos_x;
178  uint pos_y;
179 
182 
183  uint8 padding_top;
186  uint8 padding_left;
187 
188 protected:
189  inline void StoreSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height);
190 };
191 
197 {
198  return (sizing == ST_RESIZE) ? this->resize_x : this->fill_x;
199 }
200 
206 {
207  return (sizing == ST_RESIZE) ? this->resize_y : this->fill_y;
208 }
209 
218 inline void NWidgetBase::StoreSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height)
219 {
220  this->pos_x = x;
221  this->pos_y = y;
222  if (sizing == ST_SMALLEST) {
223  this->smallest_x = given_width;
224  this->smallest_y = given_height;
225  }
226  this->current_x = given_width;
227  this->current_y = given_height;
228 }
229 
230 
236 public:
237  NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y);
238 
239  void SetMinimalSize(uint min_x, uint min_y);
240  void SetMinimalTextLines(uint8 min_lines, uint8 spacing, FontSize size);
241  void SetFill(uint fill_x, uint fill_y);
242  void SetResize(uint resize_x, uint resize_y);
243 
244  void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl);
245 
246  uint min_x;
247  uint min_y;
248 };
249 
252  /* Generic. */
255  /* Viewport widget. */
259  /* Button dropdown widget. */
261  /* Scrollbar widget. */
264  /* Generic. */
266 
277 };
279 
280 
285 public:
286  NWidgetCore(WidgetType tp, Colours colour, uint fill_x, uint fill_y, uint32 widget_data, StringID tool_tip);
287 
288  void SetIndex(int index);
289  void SetDataTip(uint32 widget_data, StringID tool_tip);
290 
291  inline void SetLowered(bool lowered);
292  inline bool IsLowered() const;
293  inline void SetDisabled(bool disabled);
294  inline bool IsDisabled() const;
295 
296  /* virtual */ void FillNestedArray(NWidgetBase **array, uint length);
297  /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y);
298  /* virtual */ bool IsHighlighted() const;
299  /* virtual */ TextColour GetHighlightColour() const;
300  /* virtual */ void SetHighlighted(TextColour highlight_colour);
301 
303  Colours colour;
304  int index;
305  uint32 widget_data;
309 };
310 
315 inline void NWidgetCore::SetHighlighted(TextColour highlight_colour)
316 {
317  this->disp_flags = highlight_colour != TC_INVALID ? SETBITS(this->disp_flags, ND_HIGHLIGHT) : CLRBITS(this->disp_flags, ND_HIGHLIGHT);
318  this->highlight_colour = highlight_colour;
319 }
320 
322 inline bool NWidgetCore::IsHighlighted() const
323 {
324  return HasBit(this->disp_flags, NDB_HIGHLIGHT);
325 }
326 
329 {
330  return this->highlight_colour;
331 }
332 
337 inline void NWidgetCore::SetLowered(bool lowered)
338 {
339  this->disp_flags = lowered ? SETBITS(this->disp_flags, ND_LOWERED) : CLRBITS(this->disp_flags, ND_LOWERED);
340 }
341 
343 inline bool NWidgetCore::IsLowered() const
344 {
345  return HasBit(this->disp_flags, NDB_LOWERED);
346 }
347 
352 inline void NWidgetCore::SetDisabled(bool disabled)
353 {
354  this->disp_flags = disabled ? SETBITS(this->disp_flags, ND_DISABLED) : CLRBITS(this->disp_flags, ND_DISABLED);
355 }
356 
358 inline bool NWidgetCore::IsDisabled() const
359 {
360  return HasBit(this->disp_flags, NDB_DISABLED);
361 }
362 
363 
369 public:
371  ~NWidgetContainer();
372 
373  void Add(NWidgetBase *wid);
374  /* virtual */ void FillNestedArray(NWidgetBase **array, uint length);
375 
377  inline bool IsEmpty() { return head == NULL; }
378 
379  /* virtual */ NWidgetBase *GetWidgetOfType(WidgetType tp);
380 
381 protected:
384 };
385 
388  SZSP_VERTICAL = INT_MAX / 2,
391 
393 };
394 
406 public:
407  NWidgetStacked();
408 
409  void SetIndex(int index);
410 
411  void SetupSmallestSize(Window *w, bool init_array);
412  void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl);
413  /* virtual */ void FillNestedArray(NWidgetBase **array, uint length);
414 
415  /* virtual */ void Draw(const Window *w);
416  /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y);
417 
418  void SetDisplayedPlane(int plane);
419 
421  int index;
422 };
423 
427 
428  NC_NONE = 0,
430 };
432 
433 
435 public:
437 
438  void SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post);
439 
440  /* virtual */ void Draw(const Window *w);
441  /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y);
442 
443 protected:
445  uint8 pip_pre;
446  uint8 pip_inter;
447  uint8 pip_post;
448 };
449 
455 public:
457 
458  void SetupSmallestSize(Window *w, bool init_array);
459  void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl);
460 };
461 
467 public:
469 
470  void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl);
471 };
472 
478 public:
480 
481  void SetupSmallestSize(Window *w, bool init_array);
482  void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl);
483 };
484 
494 public:
495  NWidgetMatrix();
496 
497  void SetIndex(int index);
498  void SetColour(Colours colour);
499  void SetClicked(int clicked);
500  void SetCount(int count);
501  void SetScrollbar(Scrollbar *sb);
502 
503  void SetupSmallestSize(Window *w, bool init_array);
504  void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl);
505  /* virtual */ void FillNestedArray(NWidgetBase **array, uint length);
506 
507  /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y);
508  /* virtual */ void Draw(const Window *w);
509 protected:
510  int index;
511  Colours colour;
512  int clicked;
513  int count;
515 private:
516  int widget_w;
517  int widget_h;
518  int widgets_x;
519  int widgets_y;
520 
521  void GetScrollOffsets(int &start_x, int &start_y, int &base_offs_x, int &base_offs_y);
522 };
523 
524 
530 public:
531  NWidgetSpacer(int length, int height);
532 
533  void SetupSmallestSize(Window *w, bool init_array);
534  /* virtual */ void FillNestedArray(NWidgetBase **array, uint length);
535 
536  /* virtual */ void Draw(const Window *w);
537  /* virtual */ void SetDirty(const Window *w) const;
538  /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y);
539 };
540 
546 public:
549 
550  void Add(NWidgetBase *nwid);
551  void SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post);
552 
553  void SetupSmallestSize(Window *w, bool init_array);
554  void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl);
555 
556  /* virtual */ void FillNestedArray(NWidgetBase **array, uint length);
557 
558  /* virtual */ void Draw(const Window *w);
559  /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y);
560  /* virtual */ NWidgetBase *GetWidgetOfType(WidgetType tp);
561 
562 private:
564 };
565 
575 class NWidgetViewport : public NWidgetCore {
576 public:
577  NWidgetViewport(int index);
578 
579  /* virtual */ void SetupSmallestSize(Window *w, bool init_array);
580  /* virtual */ void Draw(const Window *w);
581 
582  void InitializeViewport(Window *w, uint32 follow_flags, ZoomLevel zoom);
584 };
585 
589 class Scrollbar {
590 private:
591  const bool is_vertical;
592  uint16 count;
593  uint16 cap;
594  uint16 pos;
595  uint16 stepsize;
596 
597 public:
603  };
604 
605  Scrollbar(bool is_vertical) : is_vertical(is_vertical), stepsize(1)
606  {
607  }
608 
613  inline uint16 GetCount() const
614  {
615  return this->count;
616  }
617 
622  inline uint16 GetCapacity() const
623  {
624  return this->cap;
625  }
626 
631  inline uint16 GetPosition() const
632  {
633  return this->pos;
634  }
635 
641  inline bool IsVisible(uint16 item) const
642  {
643  return IsInsideBS(item, this->GetPosition(), this->GetCapacity());
644  }
645 
650  inline bool IsVertical() const
651  {
652  return this->is_vertical;
653  }
654 
659  void SetStepSize(uint16 stepsize)
660  {
661  assert(stepsize > 0);
662  this->stepsize = stepsize;
663  }
664 
670  void SetCount(int num)
671  {
672  assert(num >= 0);
673  assert(num <= MAX_UVALUE(uint16));
674 
675  this->count = num;
676  num -= this->cap;
677  if (num < 0) num = 0;
678  if (num < this->pos) this->pos = num;
679  }
680 
686  void SetCapacity(int capacity)
687  {
688  assert(capacity > 0);
689  assert(capacity <= MAX_UVALUE(uint16));
690 
691  this->cap = capacity;
692  if (this->cap + this->pos > this->count) this->pos = max(0, this->count - this->cap);
693  }
694 
695  void SetCapacityFromWidget(Window *w, int widget, int padding = 0);
696 
701  void SetPosition(int position)
702  {
703  assert(position >= 0);
704  assert(this->count <= this->cap ? (position == 0) : (position + this->cap <= this->count));
705  this->pos = position;
706  }
707 
714  void UpdatePosition(int difference, ScrollbarStepping unit = SS_SMALL)
715  {
716  if (difference == 0) return;
717  switch (unit) {
718  case SS_SMALL: difference *= this->stepsize; break;
719  case SS_BIG: difference *= this->cap; break;
720  default: break;
721  }
722  this->SetPosition(Clamp(this->pos + difference, 0, max(this->count - this->cap, 0)));
723  }
724 
731  void ScrollTowards(int position)
732  {
733  if (position < this->GetPosition()) {
734  /* scroll up to the item */
735  this->SetPosition(position);
736  } else if (position >= this->GetPosition() + this->GetCapacity()) {
737  /* scroll down so that the item is at the bottom */
738  this->SetPosition(position - this->GetCapacity() + 1);
739  }
740  }
741 
742  int GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding = 0, int line_height = -1) const;
743 };
744 
750 class NWidgetScrollbar : public NWidgetCore, public Scrollbar {
751 public:
752  NWidgetScrollbar(WidgetType tp, Colours colour, int index);
753 
754  /* virtual */ void SetupSmallestSize(Window *w, bool init_array);
755  /* virtual */ void Draw(const Window *w);
756 
757  static void InvalidateDimensionCache();
758  static Dimension GetVerticalDimension();
759  static Dimension GetHorizontalDimension();
760 
761 private:
764 };
765 
770 class NWidgetLeaf : public NWidgetCore {
771 public:
772  NWidgetLeaf(WidgetType tp, Colours colour, int index, uint32 data, StringID tip);
773 
774  /* virtual */ void SetupSmallestSize(Window *w, bool init_array);
775  /* virtual */ void Draw(const Window *w);
776 
777  bool ButtonHit(const Point &pt);
778 
779  static void InvalidateDimensionCache();
780 
784 private:
789 };
790 
798 static inline uint ComputeMaxSize(uint base, uint max_space, uint step)
799 {
800  if (base >= max_space || step == 0) return base;
801  if (step == 1) return max_space;
802  uint increment = max_space - base;
803  increment -= increment % step;
804  return base + increment;
805 }
806 
859  uint32 data;
861 };
862 
868  Colours colour;
869  int16 index;
870 };
871 
877  uint8 top, right, bottom, left;
878 };
879 
885  uint8 pre, inter, post;
886 };
887 
893  uint8 lines;
894  uint8 spacing;
896 };
897 
904 typedef NWidgetBase *NWidgetFunctionType(int *biggest_index);
905 
910 struct NWidgetPart {
912  union {
921  } u;
922 };
923 
930 static inline NWidgetPart SetResize(int16 dx, int16 dy)
931 {
932  NWidgetPart part;
933 
934  part.type = WPT_RESIZE;
935  part.u.xy.x = dx;
936  part.u.xy.y = dy;
937 
938  return part;
939 }
940 
947 static inline NWidgetPart SetMinimalSize(int16 x, int16 y)
948 {
949  NWidgetPart part;
950 
951  part.type = WPT_MINSIZE;
952  part.u.xy.x = x;
953  part.u.xy.y = y;
954 
955  return part;
956 }
957 
965 static inline NWidgetPart SetMinimalTextLines(uint8 lines, uint8 spacing, FontSize size = FS_NORMAL)
966 {
967  NWidgetPart part;
968 
969  part.type = WPT_MINTEXTLINES;
970  part.u.text_lines.lines = lines;
971  part.u.text_lines.spacing = spacing;
972  part.u.text_lines.size = size;
973 
974  return part;
975 }
976 
983 static inline NWidgetPart SetFill(uint fill_x, uint fill_y)
984 {
985  NWidgetPart part;
986 
987  part.type = WPT_FILL;
988  part.u.xy.x = fill_x;
989  part.u.xy.y = fill_y;
990 
991  return part;
992 }
993 
999 static inline NWidgetPart EndContainer()
1000 {
1001  NWidgetPart part;
1002 
1003  part.type = WPT_ENDCONTAINER;
1004 
1005  return part;
1006 }
1007 
1014 static inline NWidgetPart SetDataTip(uint32 data, StringID tip)
1015 {
1016  NWidgetPart part;
1017 
1018  part.type = WPT_DATATIP;
1019  part.u.data_tip.data = data;
1020  part.u.data_tip.tooltip = tip;
1021 
1022  return part;
1023 }
1024 
1032 static inline NWidgetPart SetMatrixDataTip(uint8 cols, uint8 rows, StringID tip)
1033 {
1034  return SetDataTip((rows << MAT_ROW_START) | (cols << MAT_COL_START), tip);
1035 }
1036 
1046 static inline NWidgetPart SetPadding(uint8 top, uint8 right, uint8 bottom, uint8 left)
1047 {
1048  NWidgetPart part;
1049 
1050  part.type = WPT_PADDING;
1051  part.u.padding.top = top;
1052  part.u.padding.right = right;
1053  part.u.padding.bottom = bottom;
1054  part.u.padding.left = left;
1055 
1056  return part;
1057 }
1058 
1064 static inline NWidgetPart SetPadding(uint8 padding)
1065 {
1066  return SetPadding(padding, padding, padding, padding);
1067 }
1068 
1076 static inline NWidgetPart SetPIP(uint8 pre, uint8 inter, uint8 post)
1077 {
1078  NWidgetPart part;
1079 
1080  part.type = WPT_PIPSPACE;
1081  part.u.pip.pre = pre;
1082  part.u.pip.inter = inter;
1083  part.u.pip.post = post;
1084 
1085  return part;
1086 }
1087 
1095 static inline NWidgetPart SetScrollbar(int index)
1096 {
1097  NWidgetPart part;
1098 
1099  part.type = WPT_SCROLLBAR;
1100  part.u.widget.index = index;
1101 
1102  return part;
1103 }
1104 
1114 static inline NWidgetPart NWidget(WidgetType tp, Colours col, int16 idx = -1)
1115 {
1116  NWidgetPart part;
1117 
1118  part.type = tp;
1119  part.u.widget.colour = col;
1120  part.u.widget.index = idx;
1121 
1122  return part;
1123 }
1124 
1132 {
1133  NWidgetPart part;
1134 
1135  part.type = tp;
1136  part.u.cont_flags = cont_flags;
1137 
1138  return part;
1139 }
1140 
1147 {
1148  NWidgetPart part;
1149 
1150  part.type = WPT_FUNCTION;
1151  part.u.func_ptr = func_ptr;
1152 
1153  return part;
1154 }
1155 
1156 NWidgetContainer *MakeNWidgets(const NWidgetPart *parts, int count, int *biggest_index, NWidgetContainer *container);
1157 NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *parts, int count, int *biggest_index, NWidgetStacked **shade_select);
1158 
1159 NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int widget_last, int max_length, StringID button_tooltip);
1160 
1161 #endif /* WIDGET_TYPE_H */