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