OpenClonk
C4ScriptGuiWindow.h
Go to the documentation of this file.
1 /*
2 * OpenClonk, http://www.openclonk.org
3 *
4 * Copyright (c) 2014-2016, The OpenClonk Team and contributors
5 *
6 * Distributed under the terms of the ISC license; see accompanying file
7 * "COPYING" for details.
8 *
9 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
10 * See accompanying file "TRADEMARK" for details.
11 *
12 * To redistribute this file separately, substitute the full license texts
13 * for the above references.
14 */
15 
16 /* a flexisble ingame menu system that can be composed out of multiple windows */
17 
18 #ifndef INC_C4ScriptGuiWindow
19 #define INC_C4ScriptGuiWindow
20 
21 #include "graphics/C4Surface.h"
22 #include "gui/C4Gui.h"
23 #include "script/C4Value.h"
24 
26  enum type
27  {
28  left = 0,
29  top,
32 
37 
42 
47 
63  };
64 }
65 
67  enum type
68  {
69  SetTag = 1,
71  };
72 }
73 
75  enum type
76  {
77  None = 0,
82  TextRight = 16,
83  TextBottom = 32,
85  Multiple = 128,
86  IgnoreMouse = 256,
87  NoCrop = 512,
89  };
90 }
91 
92 class C4ScriptGuiWindow;
93 
95 {
96  friend class C4ScriptGuiWindow;
97 
98  private:
99  // the ID is unique among all actions. It is used later to synchronize callbacks
100  int32_t id{0};
101 
102  int32_t action{0};
103  C4ScriptGuiWindowAction *nextAction{nullptr}; // a linked list of actions
104  // note: depending on the action not all of the following attributes always have values
105  C4PropList *target{nullptr}; // contains a valid C4Object in case of SetTag, a generic proplist in case of Call
106  C4String *text{nullptr}; // can be either a function name to call or a tag to set
107  C4Value value; // arbitrary value used for Call
108  int32_t subwindowID{0};
109 
110  public:
111  C4ScriptGuiWindowAction() : value(0) { }
113  void ClearPointers(C4Object *pObj);
114  bool Init(C4ValueArray *array, int32_t index = 0); // index is the current action in an array of actions
115  // executes non-synced actions and syncs the others
116  // the action type parameters is only used to be able to sync commands
117  void Execute(C4ScriptGuiWindow *parent, int32_t player, int32_t actionType);
118  // used to execute synced commands, explanation see C4ScriptGuiWindow::ExecuteCommand
119  bool ExecuteCommand(int32_t actionID, C4ScriptGuiWindow *parent, int32_t player);
120  // used for serialization. The "first" parameter is used so that chained actions are stored correctly into an array
121  const C4Value ToC4Value(bool first = true);
122 };
123 
125 {
126  friend class C4ScriptGuiWindow;
127 
128  private:
129  typedef union
130  {
131  void *data;
132  float f;
133  int32_t d;
134  C4Object *obj;
135  C4Def *def;
137  StdCopyStrBuf *strBuf;
138  C4ScriptGuiWindowAction *action;
139  } Prop;
140 
141  Prop *current{nullptr};
142  // the last tag is used to be able to call the correct action on re-synchronizing commands
143  C4String* currentTag{nullptr};
144 
145  std::map<C4String*, Prop> taggedProperties;
146  void CleanUp(Prop &prop);
147  void CleanUpAll();
148 
149  int32_t type{-1}; // which property do I stand for?
150 
151  // the following methods directly set values (default Std tag)
152  // note that for int/floats no cleanup is necessary as it would be for the more general Set method
153  void SetInt(int32_t to, C4String *tag = nullptr);
154  void SetFloat(float to, C4String *tag = nullptr);
155  void SetNull(C4String *tag = nullptr);
156 
157  public:
159  C4ScriptGuiWindowProperty() = default;
160  void Set(const C4Value &value, C4String *tag);
161 
162  int32_t GetInt() { return current->d; }
163  float GetFloat() { return current->f; }
164  C4Object *GetObject() { return current->obj; }
165  C4Def *GetDef() { return current->def; }
166  C4GUI::FrameDecoration *GetFrameDecoration() { return current->deco; }
167  StdCopyStrBuf *GetStrBuf() { return current->strBuf; }
168  C4ScriptGuiWindowAction *GetAction() { return current->action; }
169  std::list<C4ScriptGuiWindowAction*> GetAllActions(); // used to synchronize actions
170 
171  bool SwitchTag(C4String *tag);
172  C4String *GetCurrentTag() { return currentTag; }
173 
174  const C4Value ToC4Value();
175 
176  void ClearPointers(C4Object *pObj);
177 };
178 
180 {
182  friend class C4ScriptGuiWindowScrollBar;
183 public:
184  // the size of the screen that is covered by a centered "main menu"
185  static const float standardWidth;
186  static const float standardHeight;
187 
188  private:
189  // the "main" menu ID is always unique, however the sub-menu IDs do NOT have to be unique
190  // they can be set from script and in combination with the target should suffice to identify windows
191  int32_t id;
192  // The name of a window is used when updating a window to identify the correct child;
193  // however, it is NOT generally used to identify windows, f.e. to close them.
194  // The reasoning behind that is that EVERY window needs a name (in the defining proplist) but only windows that need to be addressed later need an ID;
195  // so separating the identifying property from the name hopefully reduces clashes - especially since names will often be "left"/"right" etc.
196  // Note that a window does not necessarily have a name and names starting with an underscore are never saved (to be able to f.e. add new windows without knowing the names of the existing windows).
197  C4String *name;
198  // this is not only a window inside a menu but a top-level-window?
199  // this does not mean the ::WindowMenuRoot but rather a player-created submenu
200  bool isMainWindow;
201  // whether this menu is the root of all script-created menus (aka of the isMainWindow windows)
202  bool IsRoot();
203  bool mainWindowNeedsLayoutUpdate;
204 
205  bool wasRemoved; // to notify the window that it should not inform its parent on Close() a second time
206  bool closeActionWasExecuted; // to prevent a window from calling the close-callback twice even if f.e. closed in the close-callback..
207  C4Object *target;
208  const C4Object *GetTarget() { return target; }
209 
210  // properties are stored extra to make "tags" possible
212  void Init();
213  // ID is set by parent, parent gives unique IDs to children
214  void SetID(int32_t to) { id = to; }
215  // to be used to generate the quick-access children map for main menus
216  void ChildGotID(C4ScriptGuiWindow *child);
217  void ChildWithIDRemoved(C4ScriptGuiWindow *child);
218  std::multimap<int32_t, C4ScriptGuiWindow *> childrenIDMap;
219  // should be called when the Priority property of a child changes
220  // will sort the child correctly into the children list
221  void ChildChangedPriority(C4ScriptGuiWindow *child);
222  // helper function to extract relative and absolute position values from a string
223  void SetPositionStringProperties(const C4Value &property, C4ScriptGuiWindowPropertyName::type relative, C4ScriptGuiWindowPropertyName::type absolute, C4String *tag);
225  // sets all margins either from a string or from an array
226  void SetMarginProperties(const C4Value &property, C4String *tag);
227  C4Value MarginsToC4Value();
228 
229  // this is only supposed to be called at ::Game.GuiWindowRoot since it uses the "ID" property
230  // this is done to make saving easier. Since IDs do not need to be sequential, action&menu IDs can both be derived from "id"
231  int32_t GenerateMenuID() { return ++id; }
232  int32_t GenerateActionID() { return ++id; }
233 
234 
235  // children height should be set when enabling a scroll bar so that, with style FitChildren, the size can simply be changed
236  void EnableScrollBar(bool enable = true, float childrenHeight = 0.0f);
237 
238  public:
239  // used by mouse input, this is in screen coordinates
240  /*struct _lastDrawPosition
241  {
242  float left, right;
243  float top, bottom;
244 
245  float topMostChild, bottomMostChild;
246  int32_t dirty; // indicates wish to update topMostChild and bottomMostChild asap
247  bool needLayoutUpdate;
248  _lastDrawPosition() : left(0.0f), right(0.0f), top(0.0f), bottom(0.0f), topMostChild(0.0f), bottomMostChild(0.0f), dirty(2), needLayoutUpdate(false){}
249  } lastDrawPosition;*/
250 
251  void SetTag(C4String *tag);
252 
254  ~C4ScriptGuiWindow() override;
255 
256  int32_t GetID() { return id; }
257  // finds a child with a certain ID, usually called on ::MainWindowRoot to get submenus
258  C4ScriptGuiWindow *GetChildByID(int32_t child);
259  // finds a child by name, usually called when updating a window with a new proplist
260  C4ScriptGuiWindow *GetChildByName(C4String *childName);
261  // finds any fitting sub menu - not necessarily direct child
262  // has to be called on children of ::MainWindowRoot, uses the childrenIDMap
263  // note: always checks the target to avoid ambiguities, even if 0
264  C4ScriptGuiWindow *GetSubWindow(int32_t childID, C4Object *childTarget);
265 
266 
267 
268  // pass a proplist to create a window + subwindows as specified
269  // you can call this function on a window more than once
270  // if isUpdate is true, all new children will have resetStdTag set
271  bool CreateFromPropList(C4PropList *proplist, bool resetStdTag = false, bool isUpdate = false, bool isLoading = false);
272 
273  // constructs a C4Value (proplist) that contains everything that is needed for saving this window
274  const C4Value ToC4Value();
275  // this MUST only be called when loading
276  void SetEnumeratedID(int enumID) { id = enumID; }
277  void Denumerate(C4ValueNumbers *numbers);
278  // C4ScriptGuiWindow will delete its children on close. Make sure you don't delete anything twice
279  C4ScriptGuiWindow *AddChild(C4ScriptGuiWindow *child);
281 
282  void ClearChildren(bool close = true); // close: whether to properly "Close" them, alias for RemoveChild
283  void RemoveChild(C4ScriptGuiWindow *child, bool close = true, bool all = false); // child = 0 & all = true to clear all. Also deletes the child(ren).
284  void Close();
285  void ClearPointers(C4Object *pObj);
286 
287  // calculate the width/height based on a certain property (f.e. leftMargin and relLeftMargin) and the parent's width/height
288  float CalculateRelativeSize(float parentWidthOrHeight, C4ScriptGuiWindowPropertyName::type absoluteProperty, C4ScriptGuiWindowPropertyName::type relativeProperty);
289 
290  // schedules a layout update for the next drawing step
291  void RequestLayoutUpdate();
292  // this updates the window's layout and also propagates to all children
293  bool UpdateLayout(C4TargetFacet &cgo);
294  bool UpdateLayout(C4TargetFacet &cgo, float parentWidth, float parentHeight);
295  bool UpdateChildLayout(C4TargetFacet &cgo, float parentWidth, float parentHeight);
296  // special layouts that are set by styles
297  void UpdateLayoutGrid();
298  void UpdateLayoutTightGrid();
299  void UpdateLayoutVertical();
300  // the window will be drawn in the context of a viewport BY the viewport
301  // so just do nothing when TheScreen wants to draw the window
302  void Draw(C4TargetFacet &cgo) override {}
303  // Draw without parameters can be used for the root
304  bool DrawAll(C4TargetFacet &cgo, int32_t player);
305  // the clipping rectangle has already been set, but currentClippingRect must be passed to DrawChildren
306  bool Draw(C4TargetFacet &cgo, int32_t player, C4Rect *currentClippingRect);
307  bool GetClippingRect(int32_t &left, int32_t &top, int32_t &right, int32_t &bottom);
308 
309  // withMultipleFlag is there to draw only the non-multiple or the multiple windows
310  // withMultipleFlag == -1: all windows are drawn (standard)
311  // withMultipleFlag == 0: only one non-Multiple window is drawn
312  // withMultipleFlag == 1: only Multiple windows are drawn
313  // returns whether at least one child was drawn
314  bool DrawChildren(C4TargetFacet &cgo, int32_t player, int32_t withMultipleFlag = -1, C4Rect *currentClippingRect = nullptr);
315 
316  // used for commands that have been synchronized and are coming from the command queue
317  // attention: calls to this need to be synchronized!
318  bool ExecuteCommand(int32_t actionID, int32_t player, int32_t subwindowID, int32_t actionType, C4Object *target);
319 
320  // virtual bool MouseInput(int32_t player, int32_t button, int32_t mouseX, int32_t mouseY, DWORD dwKeyParam);
321  // this is called only on the root menu
323  virtual bool MouseInput(int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam);
324  // this is then called on the child windows, note the return value
325  virtual bool ProcessMouseInput(int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam, int32_t parentOffsetX, int32_t parentOffsetY);
326  // called when mouse cursor enters element region
327  void MouseEnter(C4GUI::CMouse &rMouse) override;
328  // called when mouse cursor leaves element region
329  void MouseLeave(C4GUI::CMouse &rMouse) override;
330  // This remembers whether the window currently has mouse focus and whether it has been mouse-down-ed.
331  // All windows with mouse focus set are remembered by their parents and notified when the mouse left.
332  // The state is also used to make sure that button-up events without button-downs are not caught by the UI.
333  enum MouseState // values of this enum will be bit-wise combined
334  {
335  None = 0,
336  Focus = 1,
337  MouseDown = 2
338  };
339  int32_t currentMouseState; // this needs to be saved in savegames!!!
340  // OnMouseOut() called by this window, unsets the mouse focus
341  // must notify children, too!
342  void OnMouseOut(int32_t player);
343  // called by this window, sets the mouse focus; the offset is used to set the correct tooltip rectangle for ::MouseControl
344  void OnMouseIn(int32_t player, int32_t parentOffsetX, int32_t parentOffsetY);
345  bool HasMouseFocus() { return currentMouseState & MouseState::Focus; }
346  // Returns whether the menu can be seen (and interacted with) by a player. This includes checking the target's visibility.
347  bool IsVisibleTo(int32_t player);
348 private:
349  // Use the currently loaded font to determine on-screen size of 1 EM.
350  static float Em2Pix(float em);
351  static float Pix2Em(float pix);
352 };
353 
354 #endif
bool ExecuteCommand(int32_t actionID, int32_t player, int32_t subwindowID, int32_t actionType, C4Object *target)
void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override
static const float standardHeight
Definition: C4Rect.h:27
void ClearPointers(C4Object *pObj)
void SetEnumeratedID(int enumID)
C4GUI::FrameDecoration * GetFrameDecoration()
void Draw(C4TargetFacet &cgo) override
Definition: C4Def.h:98
C4ScriptGuiWindowAction * GetAction()
C4ScriptGuiWindow * AddChild()
static const float standardWidth
uint32_t DWORD
const C4Value ToC4Value()