2013-02-12 19:39:20 +00:00
/*
2015-09-29 17:13:12 +00:00
* OpenClonk , http : //www.openclonk.org
*
2016-04-03 18:18:29 +00:00
* Copyright ( c ) 2014 - 2016 , The OpenClonk Team and contributors
2015-09-29 17:13:12 +00:00
*
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
*
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
*
* To redistribute this file separately , substitute the full license texts
* for the above references .
*/
2013-02-12 19:39:20 +00:00
/* a flexisble ingame menu system that can be composed out of multiple windows */
2014-10-13 16:48:03 +00:00
# ifndef INC_C4ScriptGuiWindow
# define INC_C4ScriptGuiWindow
2013-02-12 19:39:20 +00:00
2016-04-03 18:07:56 +00:00
# include "graphics/C4Surface.h"
# include "gui/C4Gui.h"
# include "script/C4Value.h"
2013-04-04 16:12:34 +00:00
2018-01-20 17:20:51 +00:00
namespace C4ScriptGuiWindowPropertyName {
enum type
{
left = 0 ,
top ,
right ,
bottom ,
relLeft ,
relRight ,
relTop ,
relBottom ,
leftMargin ,
topMargin ,
rightMargin ,
bottomMargin ,
relLeftMargin ,
relRightMargin ,
relTopMargin ,
relBottomMargin ,
backgroundColor ,
frameDecoration ,
symbolObject ,
symbolDef ,
symbolGraphicsName ,
text ,
onClickAction ,
onMouseInAction ,
onMouseOutAction ,
onCloseAction ,
style ,
priority ,
player ,
tooltip ,
_lastProp
} ;
}
namespace C4ScriptGuiWindowActionID {
enum type
{
SetTag = 1 ,
Call ,
} ;
}
2013-02-12 19:39:20 +00:00
2018-01-20 17:20:51 +00:00
namespace C4ScriptGuiWindowStyleFlag {
enum type
{
None = 0 ,
GridLayout = 1 ,
VerticalLayout = 2 ,
TextVCenter = 4 ,
TextHCenter = 8 ,
TextRight = 16 ,
TextBottom = 32 ,
FitChildren = 64 ,
Multiple = 128 ,
IgnoreMouse = 256 ,
NoCrop = 512 ,
TightGridLayout = 1024 ,
} ;
}
2013-04-04 16:12:34 +00:00
2014-10-13 16:48:03 +00:00
class C4ScriptGuiWindow ;
2013-02-12 19:39:20 +00:00
2014-10-13 16:48:03 +00:00
class C4ScriptGuiWindowAction
2013-02-12 19:39:20 +00:00
{
2014-10-13 16:48:03 +00:00
friend class C4ScriptGuiWindow ;
2013-02-12 19:39:20 +00:00
private :
2013-04-04 16:12:34 +00:00
// the ID is unique among all actions. It is used later to synchronize callbacks
2017-05-07 11:50:00 +00:00
int32_t id { 0 } ;
2013-04-04 16:12:34 +00:00
2017-05-07 11:50:00 +00:00
int32_t action { 0 } ;
C4ScriptGuiWindowAction * nextAction { nullptr } ; // a linked list of actions
2013-02-12 19:39:20 +00:00
// note: depending on the action not all of the following attributes always have values
2017-05-07 11:50:00 +00:00
C4PropList * target { nullptr } ; // contains a valid C4Object in case of SetTag, a generic proplist in case of Call
C4String * text { nullptr } ; // can be either a function name to call or a tag to set
2013-04-04 16:12:34 +00:00
C4Value value ; // arbitrary value used for Call
2017-05-07 11:50:00 +00:00
int32_t subwindowID { 0 } ;
2013-02-12 19:39:20 +00:00
public :
2017-05-07 11:50:00 +00:00
C4ScriptGuiWindowAction ( ) : value ( 0 ) { }
2014-10-13 16:48:03 +00:00
~ C4ScriptGuiWindowAction ( ) ;
2013-02-12 19:39:20 +00:00
void ClearPointers ( C4Object * pObj ) ;
2013-04-04 16:12:34 +00:00
bool Init ( C4ValueArray * array , int32_t index = 0 ) ; // index is the current action in an array of actions
// executes non-synced actions and syncs the others
2013-05-24 16:13:04 +00:00
// the action type parameters is only used to be able to sync commands
2014-10-13 16:48:03 +00:00
void Execute ( C4ScriptGuiWindow * parent , int32_t player , int32_t actionType ) ;
// used to execute synced commands, explanation see C4ScriptGuiWindow::ExecuteCommand
bool ExecuteCommand ( int32_t actionID , C4ScriptGuiWindow * parent , int32_t player ) ;
2014-02-15 17:30:21 +00:00
// used for serialization. The "first" parameter is used so that chained actions are stored correctly into an array
2013-05-23 14:29:14 +00:00
const C4Value ToC4Value ( bool first = true ) ;
2013-02-12 19:39:20 +00:00
} ;
2014-10-13 16:48:03 +00:00
class C4ScriptGuiWindowProperty
2013-02-12 19:39:20 +00:00
{
2014-10-13 16:48:03 +00:00
friend class C4ScriptGuiWindow ;
2013-02-12 19:39:20 +00:00
private :
typedef union
{
void * data ;
float f ;
int32_t d ;
C4Object * obj ;
C4Def * def ;
C4GUI : : FrameDecoration * deco ;
StdCopyStrBuf * strBuf ;
2014-10-13 16:48:03 +00:00
C4ScriptGuiWindowAction * action ;
2013-02-12 19:39:20 +00:00
} Prop ;
2017-05-07 11:50:00 +00:00
Prop * current { nullptr } ;
2013-04-04 16:12:34 +00:00
// the last tag is used to be able to call the correct action on re-synchronizing commands
2017-05-07 11:50:00 +00:00
C4String * currentTag { nullptr } ;
2013-04-04 16:12:34 +00:00
2013-05-24 16:13:04 +00:00
std : : map < C4String * , Prop > taggedProperties ;
2013-02-12 19:39:20 +00:00
void CleanUp ( Prop & prop ) ;
void CleanUpAll ( ) ;
2017-05-07 11:50:00 +00:00
int32_t type { - 1 } ; // which property do I stand for?
2014-02-15 17:30:21 +00:00
2014-02-17 14:46:36 +00:00
// the following methods directly set values (default Std tag)
// note that for int/floats no cleanup is necessary as it would be for the more general Set method
2017-05-07 11:50:00 +00:00
void SetInt ( int32_t to , C4String * tag = nullptr ) ;
void SetFloat ( float to , C4String * tag = nullptr ) ;
void SetNull ( C4String * tag = nullptr ) ;
2013-02-12 19:39:20 +00:00
public :
2014-10-13 16:48:03 +00:00
~ C4ScriptGuiWindowProperty ( ) ;
2017-05-07 11:50:00 +00:00
C4ScriptGuiWindowProperty ( ) = default ;
2013-05-24 16:13:04 +00:00
void Set ( const C4Value & value , C4String * tag ) ;
2013-02-12 19:39:20 +00:00
int32_t GetInt ( ) { return current - > d ; }
float GetFloat ( ) { return current - > f ; }
C4Object * GetObject ( ) { return current - > obj ; }
C4Def * GetDef ( ) { return current - > def ; }
C4GUI : : FrameDecoration * GetFrameDecoration ( ) { return current - > deco ; }
StdCopyStrBuf * GetStrBuf ( ) { return current - > strBuf ; }
2014-10-13 16:48:03 +00:00
C4ScriptGuiWindowAction * GetAction ( ) { return current - > action ; }
std : : list < C4ScriptGuiWindowAction * > GetAllActions ( ) ; // used to synchronize actions
2013-02-12 19:39:20 +00:00
2013-04-04 16:12:34 +00:00
bool SwitchTag ( C4String * tag ) ;
2013-05-24 16:13:04 +00:00
C4String * GetCurrentTag ( ) { return currentTag ; }
2014-02-15 17:30:21 +00:00
const C4Value ToC4Value ( ) ;
2013-02-12 19:39:20 +00:00
void ClearPointers ( C4Object * pObj ) ;
} ;
2014-10-13 16:48:03 +00:00
class C4ScriptGuiWindow : public C4GUI : : ScrollWindow
2013-02-12 19:39:20 +00:00
{
2014-10-13 16:48:03 +00:00
friend class C4ScriptGuiWindowAction ;
friend class C4ScriptGuiWindowScrollBar ;
2014-10-23 21:29:14 +00:00
public :
2015-03-27 10:33:57 +00:00
// the size of the screen that is covered by a centered "main menu"
static const float standardWidth ;
static const float standardHeight ;
2013-02-12 19:39:20 +00:00
private :
2014-10-11 09:29:02 +00:00
// the "main" menu ID is always unique, however the sub-menu IDs do NOT have to be unique
2013-02-12 19:39:20 +00:00
// they can be set from script and in combination with the target should suffice to identify windows
int32_t id ;
2014-10-11 09:29:02 +00:00
// The name of a window is used when updating a window to identify the correct child;
// however, it is NOT generally used to identify windows, f.e. to close them.
// 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;
// so separating the identifying property from the name hopefully reduces clashes - especially since names will often be "left"/"right" etc.
// 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).
C4String * name ;
2013-02-12 19:39:20 +00:00
// this is not only a window inside a menu but a top-level-window?
// this does not mean the ::WindowMenuRoot but rather a player-created submenu
bool isMainWindow ;
2014-10-11 09:29:02 +00:00
// whether this menu is the root of all script-created menus (aka of the isMainWindow windows)
bool IsRoot ( ) ;
2014-10-05 14:46:14 +00:00
bool mainWindowNeedsLayoutUpdate ;
2013-02-12 19:39:20 +00:00
2013-04-04 16:12:34 +00:00
bool wasRemoved ; // to notify the window that it should not inform its parent on Close() a second time
2013-05-09 11:28:45 +00:00
bool closeActionWasExecuted ; // to prevent a window from calling the close-callback twice even if f.e. closed in the close-callback..
2013-02-12 19:39:20 +00:00
C4Object * target ;
2013-04-04 16:12:34 +00:00
const C4Object * GetTarget ( ) { return target ; }
2013-02-12 19:39:20 +00:00
// properties are stored extra to make "tags" possible
2014-10-13 16:48:03 +00:00
C4ScriptGuiWindowProperty props [ C4ScriptGuiWindowPropertyName : : _lastProp ] ;
2013-02-12 19:39:20 +00:00
void Init ( ) ;
// ID is set by parent, parent gives unique IDs to children
void SetID ( int32_t to ) { id = to ; }
// to be used to generate the quick-access children map for main menus
2014-10-13 16:48:03 +00:00
void ChildGotID ( C4ScriptGuiWindow * child ) ;
void ChildWithIDRemoved ( C4ScriptGuiWindow * child ) ;
std : : multimap < int32_t , C4ScriptGuiWindow * > childrenIDMap ;
2013-04-28 14:41:04 +00:00
// should be called when the Priority property of a child changes
// will sort the child correctly into the children list
2014-10-13 16:48:03 +00:00
void ChildChangedPriority ( C4ScriptGuiWindow * child ) ;
2014-02-17 14:46:36 +00:00
// helper function to extract relative and absolute position values from a string
2018-01-20 17:20:51 +00:00
void SetPositionStringProperties ( const C4Value & property , C4ScriptGuiWindowPropertyName : : type relative , C4ScriptGuiWindowPropertyName : : type absolute , C4String * tag ) ;
C4Value PositionToC4Value ( C4ScriptGuiWindowPropertyName : : type relative , C4ScriptGuiWindowPropertyName : : type absolute ) ;
2014-02-26 21:37:02 +00:00
// sets all margins either from a string or from an array
void SetMarginProperties ( const C4Value & property , C4String * tag ) ;
2014-10-11 09:29:02 +00:00
C4Value MarginsToC4Value ( ) ;
2013-02-12 19:39:20 +00:00
2013-05-26 16:12:03 +00:00
// this is only supposed to be called at ::Game.GuiWindowRoot since it uses the "ID" property
2013-05-23 14:29:14 +00:00
// this is done to make saving easier. Since IDs do not need to be sequential, action&menu IDs can both be derived from "id"
2013-02-12 19:39:20 +00:00
int32_t GenerateMenuID ( ) { return + + id ; }
2013-04-04 16:12:34 +00:00
int32_t GenerateActionID ( ) { return + + id ; }
2014-10-05 14:46:14 +00:00
2013-04-07 20:52:45 +00:00
// children height should be set when enabling a scroll bar so that, with style FitChildren, the size can simply be changed
void EnableScrollBar ( bool enable = true , float childrenHeight = 0.0f ) ;
2013-04-04 16:12:34 +00:00
2013-02-12 19:39:20 +00:00
public :
// used by mouse input, this is in screen coordinates
2014-10-05 14:46:14 +00:00
/*struct _lastDrawPosition
2013-02-12 19:39:20 +00:00
{
float left , right ;
float top , bottom ;
float topMostChild , bottomMostChild ;
int32_t dirty ; // indicates wish to update topMostChild and bottomMostChild asap
2014-03-26 22:52:45 +00:00
bool needLayoutUpdate ;
_lastDrawPosition ( ) : left ( 0.0f ) , right ( 0.0f ) , top ( 0.0f ) , bottom ( 0.0f ) , topMostChild ( 0.0f ) , bottomMostChild ( 0.0f ) , dirty ( 2 ) , needLayoutUpdate ( false ) { }
2014-10-05 14:46:14 +00:00
} lastDrawPosition ; */
2013-02-12 19:39:20 +00:00
void SetTag ( C4String * tag ) ;
2014-10-13 16:48:03 +00:00
C4ScriptGuiWindow ( ) ;
2017-05-07 11:50:00 +00:00
~ C4ScriptGuiWindow ( ) override ;
2013-02-12 19:39:20 +00:00
int32_t GetID ( ) { return id ; }
// finds a child with a certain ID, usually called on ::MainWindowRoot to get submenus
2014-10-13 16:48:03 +00:00
C4ScriptGuiWindow * GetChildByID ( int32_t child ) ;
2014-10-11 09:29:02 +00:00
// finds a child by name, usually called when updating a window with a new proplist
2014-10-13 16:48:03 +00:00
C4ScriptGuiWindow * GetChildByName ( C4String * childName ) ;
2013-02-12 19:39:20 +00:00
// finds any fitting sub menu - not necessarily direct child
// has to be called on children of ::MainWindowRoot, uses the childrenIDMap
// note: always checks the target to avoid ambiguities, even if 0
2014-10-13 16:48:03 +00:00
C4ScriptGuiWindow * GetSubWindow ( int32_t childID , C4Object * childTarget ) ;
2013-02-12 19:39:20 +00:00
// pass a proplist to create a window + subwindows as specified
2013-04-07 20:52:45 +00:00
// you can call this function on a window more than once
// if isUpdate is true, all new children will have resetStdTag set
2013-05-26 16:12:03 +00:00
bool CreateFromPropList ( C4PropList * proplist , bool resetStdTag = false , bool isUpdate = false , bool isLoading = false ) ;
2014-02-15 17:30:21 +00:00
// constructs a C4Value (proplist) that contains everything that is needed for saving this window
const C4Value ToC4Value ( ) ;
2014-10-23 21:29:14 +00:00
// this MUST only be called when loading
void SetEnumeratedID ( int enumID ) { id = enumID ; }
void Denumerate ( C4ValueNumbers * numbers ) ;
2014-10-13 16:48:03 +00:00
// C4ScriptGuiWindow will delete its children on close. Make sure you don't delete anything twice
C4ScriptGuiWindow * AddChild ( C4ScriptGuiWindow * child ) ;
C4ScriptGuiWindow * AddChild ( ) { return AddChild ( new C4ScriptGuiWindow ( ) ) ; }
2013-02-12 19:39:20 +00:00
2013-04-04 16:12:34 +00:00
void ClearChildren ( bool close = true ) ; // close: whether to properly "Close" them, alias for RemoveChild
2015-09-05 01:07:20 +00:00
void RemoveChild ( C4ScriptGuiWindow * child , bool close = true , bool all = false ) ; // child = 0 & all = true to clear all. Also deletes the child(ren).
2013-02-12 19:39:20 +00:00
void Close ( ) ;
void ClearPointers ( C4Object * pObj ) ;
2015-01-20 19:44:13 +00:00
// calculate the width/height based on a certain property (f.e. leftMargin and relLeftMargin) and the parent's width/height
2018-01-20 17:20:51 +00:00
float CalculateRelativeSize ( float parentWidthOrHeight , C4ScriptGuiWindowPropertyName : : type absoluteProperty , C4ScriptGuiWindowPropertyName : : type relativeProperty ) ;
2015-01-20 19:44:13 +00:00
2015-08-02 21:19:28 +00:00
// schedules a layout update for the next drawing step
void RequestLayoutUpdate ( ) ;
2014-10-05 14:46:14 +00:00
// this updates the window's layout and also propagates to all children
bool UpdateLayout ( C4TargetFacet & cgo ) ;
bool UpdateLayout ( C4TargetFacet & cgo , float parentWidth , float parentHeight ) ;
bool UpdateChildLayout ( C4TargetFacet & cgo , float parentWidth , float parentHeight ) ;
// special layouts that are set by styles
void UpdateLayoutGrid ( ) ;
2016-11-05 14:21:29 +00:00
void UpdateLayoutTightGrid ( ) ;
2014-10-05 14:46:14 +00:00
void UpdateLayoutVertical ( ) ;
2014-10-11 09:29:02 +00:00
// the window will be drawn in the context of a viewport BY the viewport
// so just do nothing when TheScreen wants to draw the window
2017-05-07 11:50:00 +00:00
void Draw ( C4TargetFacet & cgo ) override { }
2013-02-12 19:39:20 +00:00
// Draw without parameters can be used for the root
2014-10-05 14:46:14 +00:00
bool DrawAll ( C4TargetFacet & cgo , int32_t player ) ;
2014-10-11 09:29:02 +00:00
// the clipping rectangle has already been set, but currentClippingRect must be passed to DrawChildren
bool Draw ( C4TargetFacet & cgo , int32_t player , C4Rect * currentClippingRect ) ;
2014-10-05 14:46:14 +00:00
bool GetClippingRect ( int32_t & left , int32_t & top , int32_t & right , int32_t & bottom ) ;
// withMultipleFlag is there to draw only the non-multiple or the multiple windows
// withMultipleFlag == -1: all windows are drawn (standard)
// withMultipleFlag == 0: only one non-Multiple window is drawn
// withMultipleFlag == 1: only Multiple windows are drawn
// returns whether at least one child was drawn
2014-10-11 09:29:02 +00:00
bool DrawChildren ( C4TargetFacet & cgo , int32_t player , int32_t withMultipleFlag = - 1 , C4Rect * currentClippingRect = nullptr ) ;
2013-04-04 16:12:34 +00:00
// used for commands that have been synchronized and are coming from the command queue
// attention: calls to this need to be synchronized!
2013-05-24 16:13:04 +00:00
bool ExecuteCommand ( int32_t actionID , int32_t player , int32_t subwindowID , int32_t actionType , C4Object * target ) ;
2014-10-05 14:46:14 +00:00
// virtual bool MouseInput(int32_t player, int32_t button, int32_t mouseX, int32_t mouseY, DWORD dwKeyParam);
// this is called only on the root menu
2015-09-04 03:17:22 +00:00
using C4GUI : : ScrollWindow : : MouseInput ;
2014-10-11 09:29:02 +00:00
virtual bool MouseInput ( int32_t iButton , int32_t iX , int32_t iY , DWORD dwKeyParam ) ;
2014-10-05 14:46:14 +00:00
// this is then called on the child windows, note the return value
2014-10-11 09:29:02 +00:00
virtual bool ProcessMouseInput ( int32_t iButton , int32_t iX , int32_t iY , DWORD dwKeyParam , int32_t parentOffsetX , int32_t parentOffsetY ) ;
2014-10-05 14:46:14 +00:00
// called when mouse cursor enters element region
2017-05-07 11:50:00 +00:00
void MouseEnter ( C4GUI : : CMouse & rMouse ) override ;
2014-10-05 14:46:14 +00:00
// called when mouse cursor leaves element region
2017-05-07 11:50:00 +00:00
void MouseLeave ( C4GUI : : CMouse & rMouse ) override ;
2016-02-07 09:42:55 +00:00
// This remembers whether the window currently has mouse focus and whether it has been mouse-down-ed.
// All windows with mouse focus set are remembered by their parents and notified when the mouse left.
// The state is also used to make sure that button-up events without button-downs are not caught by the UI.
2014-10-05 14:46:14 +00:00
enum MouseState // values of this enum will be bit-wise combined
{
None = 0 ,
Focus = 1 ,
MouseDown = 2
} ;
int32_t currentMouseState ; // this needs to be saved in savegames!!!
// OnMouseOut() called by this window, unsets the mouse focus
// must notify children, too!
void OnMouseOut ( int32_t player ) ;
2014-10-11 09:29:02 +00:00
// called by this window, sets the mouse focus; the offset is used to set the correct tooltip rectangle for ::MouseControl
void OnMouseIn ( int32_t player , int32_t parentOffsetX , int32_t parentOffsetY ) ;
2014-10-05 14:46:14 +00:00
bool HasMouseFocus ( ) { return currentMouseState & MouseState : : Focus ; }
2016-01-31 22:35:37 +00:00
// Returns whether the menu can be seen (and interacted with) by a player. This includes checking the target's visibility.
bool IsVisibleTo ( int32_t player ) ;
2014-02-17 14:46:36 +00:00
private :
2015-09-06 17:02:31 +00:00
// Use the currently loaded font to determine on-screen size of 1 EM.
static float Em2Pix ( float em ) ;
static float Pix2Em ( float pix ) ;
2013-02-12 19:39:20 +00:00
} ;
# endif