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