8 #include <unordered_map>
9 #include <unordered_set>
48 using std::make_unique;
55 using std::unique_ptr;
56 using std::unordered_map;
57 using std::unordered_set;
96 GUIScreenNode::GUIScreenNode(
97 const string& fileName,
98 const string& applicationRootPathName,
99 const string& applicationSubPathName,
107 const string& backgroundImage,
109 const GUIColor& backgroundImageEffectColorMul,
110 const GUIColor& backgroundImageEffectColorAdd,
116 const string& tooltip,
119 const string& scriptFileName,
120 const EngineMiniScript::ScriptVariable& miniScriptArguments,
123 GUIParentNode(this, nullptr, id, flow, overflowX, overflowY, alignments, requestedConstraints, backgroundColor, backgroundImage, backgroundImageScale9Grid, backgroundImageEffectColorMul, backgroundImageEffectColorAdd, border, padding, showOn, hideOn, tooltip)
139 if (scriptFileName.empty() ==
false) {
140 this->
script = make_unique<GUIMiniScript>(
this);
142 string projectScriptPathName;
143 string projectScriptFileName;
146 this->
script->parseScript(
147 projectScriptPathName,
148 projectScriptFileName
151 if (this->
script->isValid() ==
false) {
153 Console::println(
"GUIScreenNode::GUIScreenNode(): " + projectScriptFileName +
": script not valid. Not using it.");
157 Console::println(this->
script->getInformation());
174 Console::println(
"Available event script handler functions:");
196 for (
auto i = 0; i <
subNodes.size(); i++) {
205 for (
const auto& [fontId, font]:
fontCache) {
210 for (
const auto& [imageId, image]:
imageCache) {
211 image->releaseReference();
218 if (
script !=
nullptr &&
script->hasFunction(
"initialize") ==
true) {
220 span argumentValuesSpan(argumentValues);
221 EngineMiniScript::ScriptVariable returnValue;
222 script->call(
"initialize", argumentValuesSpan, returnValue);
238 if (this->enabled ==
enabled)
return;
240 if (
gui !=
nullptr &&
277 for (
auto i = 0; i <
subNodes.size(); i++) {
284 if (
controller !=
nullptr && node->layouted ==
true) {
294 while (_node !=
nullptr) {
295 if (_node->conditionsMet ==
false) {
307 while (_node !=
nullptr) {
308 if (_node->layouted ==
false) __node = _node;
315 for (__node = node; __node != _node; __node = __node->
parentNode) {
321 _node->parentNode !=
nullptr &&
328 (_node->layouted ==
false &&
334 (_node->layouted ==
false &&
339 _node->layouted =
false;
340 _node = _node->parentNode;
344 _node->layouted =
false;
357 map<string, GUINode*> nodesToForceLayout;
360 if (node ==
nullptr)
continue;
362 if (layoutNode ==
nullptr)
continue;
363 nodesToForceLayout[layoutNode->getHierarchicalId()] = layoutNode;
368 for (
const auto& [nodeHierarchicalId, node]: nodesToForceLayout) {
370 auto parentNodeLayouted =
false;
371 auto _node = node->parentNode;
373 while (_node !=
nullptr) {
374 if (nodesToForceLayout.find(_node->getHierarchicalId()) != nodesToForceLayout.end()) {
375 parentNodeLayouted =
true;
378 _node = _node->parentNode;
381 if (parentNodeLayouted ==
true)
continue;
391 auto parentNode = required_dynamic_cast<GUIParentNode*>(node);
398 auto childController = childNode->getController();
399 if (childController !=
nullptr) childController->postLayout();
406 if (nodeController !=
nullptr) nodeController->
postLayout();
463 if (node ==
nullptr) {
464 Console::println(
"GUIScreenNode::removeNodeById(): node not found: " + nodeId);
467 if (node->parentNode !=
nullptr) node->parentNode->removeSubNode(node, resetScrollOffsets);
474 const auto& nodeId = node->
getId();
477 nodeIds.erase(nodeId);
483 auto parentNode = required_dynamic_cast<GUIParentNode*>(node);
513 auto skipFloatingNode =
false;
514 auto _floatingNode = floatingNode;
516 if (_floatingNode->conditionsMet ==
false) {
517 skipFloatingNode =
true;
520 _floatingNode = _floatingNode->parentNode;
521 }
while (_floatingNode !=
nullptr);
522 if (skipFloatingNode ==
true)
continue;
538 auto parentElementNode = required_dynamic_cast<GUIElementNode*>(
parentNode);
539 if (parentElementNode->focusable ==
true && (parentElementNode->getController() ==
nullptr || parentElementNode->getController()->isDisabled() ==
false)) {
540 focusableNodes.push_back(required_dynamic_cast<GUIElementNode*>(
parentNode));
698 if (listener->accept(node) ==
true)
return true;
772 auto now = Time::getCurrentMillis();
773 vector<int64_t> timedExpressionsToRemove;
774 for (
const auto& [timedExpressionsTime, timedExpressionsExpression]:
timedExpressions) {
775 if (now >= timedExpressionsTime) {
776 timedExpressionsToRemove.push_back(timedExpressionsTime);
780 for (
const auto& timedExpressionToRemove: timedExpressionsToRemove) {
784 for (
const auto& [nodeId, node]: _tickNodesById) {
785 if (node->controller !=
nullptr) node->controller->tick();
789 vector<EngineMiniScript::ScriptVariable> argumentValues(0);
790 span argumentValuesSpan(argumentValues);
791 EngineMiniScript::ScriptVariable returnValue;
792 script->call(
"onTick", argumentValuesSpan, returnValue);
802 if (
dynamic_cast<GUIElementNode*
>(childControllerNode) !=
nullptr ==
false)
805 auto guiElementNode = required_dynamic_cast<GUIElementNode*>(childControllerNode);
806 auto guiElementNodeController = guiElementNode->getController();
807 if (guiElementNodeController->hasValue()) {
808 const auto& name = guiElementNode->getName();
809 const auto& value = guiElementNodeController->getValue();
810 auto currentValueIt = values.find(name);
811 if (currentValueIt == values.end() || currentValueIt->second.size() == 0) {
812 values[name] = value;
823 if (
dynamic_cast<GUIElementNode*
>(childControllerNode) !=
nullptr ==
false)
826 auto guiElementNode = required_dynamic_cast<GUIElementNode*>(childControllerNode);
827 auto guiElementNodeController = guiElementNode->getController();
828 if (guiElementNodeController->hasValue()) {
829 auto name = guiElementNode->getName();
830 auto newValueIt = values.find(name);
831 if (newValueIt == values.end())
833 guiElementNodeController->setValue(newValueIt->second);
841 constraints.
minWidth = minWidth.empty() ==
true?-1:Integer::parse(minWidth);
842 constraints.
minHeight = minHeight.empty() ==
true?-1:Integer::parse(minHeight);
843 constraints.
maxWidth = maxWidth.empty() ==
true?-1:Integer::parse(maxWidth);
844 constraints.
maxHeight = maxHeight.empty() ==
true?-1:Integer::parse(maxHeight);
856 auto cacheId = fontPathName +
"/" + fontFileName +
":" + to_string(size);
857 auto fontCacheIt =
fontCache.find(cacheId);
858 auto font = fontCacheIt !=
fontCache.end()?fontCacheIt->second:
nullptr;
859 if (font ==
nullptr) {
861 font = GUIFont::parse(fontPathName, fontFileName, size);
863 Console::print(
"GUIScreenNode::getFont(): An error occurred: " +
id +
": " + cacheId +
": " +
string(exception.what()));
875 string imagePathName;
876 string imageFileName;
880 auto cacheId = imagePathName +
"/" + imageFileName;
882 auto image = imageCacheIt !=
imageCache.end()?imageCacheIt->second:
nullptr;
883 if (image ==
nullptr) {
885 image = TextureReader::read(imagePathName, imageFileName,
false,
false,
"tdme.gui." +
screenNode->
getId() +
".");
886 if (image !=
nullptr) {
887 image->setUseCompression(
false);
888 image->setUseMipMap(
false);
889 image->setRepeat(
false);
890 image->setClampMode(Texture::CLAMPMODE_TRANSPARENTPIXEL);
893 Console::print(
"GUIScreenNode::getImage(): An error occurred: " +
id +
": " + cacheId +
": " +
string(exception.what()));
896 if (image !=
nullptr)
imageCache[cacheId] = image;
902 auto forwardEventCount = 0;
906 for (
const auto& event: forwardEventListCopy) {
907 switch(event.eventType) {
912 if (elementNode ==
nullptr)
break;
918 vector<EngineMiniScript::ScriptVariable> argumentValues {
919 static_cast<int64_t
>(
event.type),
922 span argumentValuesSpan(argumentValues);
923 EngineMiniScript::ScriptVariable returnValue;
924 script->call(
"onAction", argumentValuesSpan, returnValue);
932 if (elementNode ==
nullptr)
break;
938 vector<EngineMiniScript::ScriptVariable> argumentValues {
941 span argumentValuesSpan(argumentValues);
942 EngineMiniScript::ScriptVariable returnValue;
943 script->call(
"onChange", argumentValuesSpan, returnValue);
951 if (elementNode ==
nullptr)
break;
957 vector<EngineMiniScript::ScriptVariable> argumentValues {
960 span argumentValuesSpan(argumentValues);
961 EngineMiniScript::ScriptVariable returnValue;
962 script->call(
"onMouseOver", argumentValuesSpan, returnValue);
970 if (elementNode ==
nullptr)
break;
976 vector<EngineMiniScript::ScriptVariable> argumentValues {
978 static_cast<int64_t
>(
event.mouseX),
979 static_cast<int64_t
>(event.mouseY)
981 span argumentValuesSpan(argumentValues);
982 EngineMiniScript::ScriptVariable returnValue;
983 script->call(
"onContextMenuRequest", argumentValuesSpan, returnValue);
991 if (elementNode ==
nullptr)
break;
997 vector<EngineMiniScript::ScriptVariable> argumentValues {
1000 span argumentValuesSpan(argumentValues);
1001 EngineMiniScript::ScriptVariable returnValue;
1002 script->call(
"onFocus", argumentValuesSpan, returnValue);
1010 if (elementNode ==
nullptr)
break;
1016 vector<EngineMiniScript::ScriptVariable> argumentValues {
1019 span argumentValuesSpan(argumentValues);
1020 EngineMiniScript::ScriptVariable returnValue;
1021 script->call(
"onUnfocus", argumentValuesSpan, returnValue);
1029 if (node ==
nullptr)
break;
1035 vector<EngineMiniScript::ScriptVariable> argumentValues {
1038 span argumentValuesSpan(argumentValues);
1039 EngineMiniScript::ScriptVariable returnValue;
1040 script->call(
"onMove", argumentValuesSpan, returnValue);
1048 if (node ==
nullptr)
break;
1049 moveListener[i]->onRelease(node, event.mouseX, event.mouseY);
1054 vector<EngineMiniScript::ScriptVariable> argumentValues {
1056 static_cast<int64_t
>(
event.mouseX),
1057 static_cast<int64_t
>(event.mouseY)
1059 span argumentValuesSpan(argumentValues);
1060 EngineMiniScript::ScriptVariable returnValue;
1061 script->call(
"onMoveRelease", argumentValuesSpan, returnValue);
1069 if (node ==
nullptr)
break;
1075 vector<EngineMiniScript::ScriptVariable> argumentValues {
1077 static_cast<int64_t
>(
event.mouseX),
1078 static_cast<int64_t
>(event.mouseY)
1080 span argumentValuesSpan(argumentValues);
1081 EngineMiniScript::ScriptVariable returnValue;
1082 script->call(
"onTooltipShowRequest", argumentValuesSpan, returnValue);
1094 vector<EngineMiniScript::ScriptVariable> argumentValues(0);
1095 span argumentValuesSpan(argumentValues);
1096 EngineMiniScript::ScriptVariable returnValue;
1097 script->call(
"onTooltipCloseRequest", argumentValuesSpan, returnValue);
1106 if (elementNode ==
nullptr)
break;
1112 vector<EngineMiniScript::ScriptVariable> argumentValues {
1114 static_cast<int64_t
>(
event.mouseX),
1115 static_cast<int64_t
>(event.mouseY)
1117 span argumentValuesSpan(argumentValues);
1118 EngineMiniScript::ScriptVariable returnValue;
1119 script->call(
"onDragRequest", argumentValuesSpan, returnValue);
1130 string projectFileCanonicalFileName;
1131 if (FileSystem::getInstance()->exists(
fileName) ==
true) {
1132 projectFileCanonicalFileName =
fileName;
1136 projectFilePathName = FileSystem::getInstance()->getPathName(projectFileCanonicalFileName);
1137 projectFileFileName = FileSystem::getInstance()->getFileName(projectFileCanonicalFileName);
1139 Console::print(
"GUIScreenNode::getProjectFilePathNameAndFileName(): An error occurred: " +
string(exception.what()));
static const Properties * getEngineThemeProperties()
static const Properties * getProjectThemeProperties()
GUIElementNode * getFocussedNode()
void unsetMouseStates()
Render screens change.
void invalidateFocussedNode()
Invalidate focussed node.
void executeOnChangeExpression()
Execute on change expression.
static void executeExpression(GUIScreenNode *screenNode, const string &expression)
Execute expression.
GUI element node conditions.
GUI node controller base class.
virtual void postLayout()=0
Post layout event.
static STATIC_DLL_IMPEXT GUINode_Flow * FLOATING
GUI node requested constraints requested constraints type enum.
static STATIC_DLL_IMPEXT GUINode_RequestedConstraints_RequestedConstraintsType * PERCENT
static STATIC_DLL_IMPEXT GUINode_RequestedConstraints_RequestedConstraintsType * STAR
static STATIC_DLL_IMPEXT GUINode_RequestedConstraints_RequestedConstraintsType * PIXEL
static STATIC_DLL_IMPEXT GUINode_RequestedConstraints_RequestedConstraintsType * AUTO
virtual void layoutOnDemand()
Layout on demand.
void _scrollToNodeX(GUIParentNode *toNode=nullptr)
Scroll to node X.
virtual void computeContentAlignment()
Do content alignment.
unique_ptr< GUINodeController > controller
GUIParentNode * parentNode
void _scrollToNodeY(GUIParentNode *toNode=nullptr)
Scroll to node Y.
virtual void undoEffects(GUIRenderer *guiRenderer)
Undo effects.
GUINode_ComputedConstraints computedConstraints
GUINodeController * getController()
GUIScreenNode * screenNode
GUINode_RequestedConstraints requestedConstraints
virtual void dispose()
Dispose node.
GUIScreenNode * getScreenNode()
virtual void applyEffects(GUIRenderer *guiRenderer)
Apply effects.
virtual void layout()
Layout.
GUI parent node overflow enum.
GUI parent node base class thats supporting child nodes.
void getChildControllerNodes(vector< GUINode * > &childControllerNodes, bool requireConditionsMet=false)
Get child controller nodes.
void determineMouseEventNodes(GUIMouseEvent *event, bool floatingNode, unordered_set< string > &eventNodeIds, unordered_set< string > &eventFloatingNodeIds, int flags=DETERMINEMOUSEEVENTNODES_FLAG_NONE) override
Determine mouse event nodes.
void render(GUIRenderer *guiRenderer) override
Render.
virtual void layoutSubNodes()
Layout sub nodes.
vector< GUINode * > subNodes
void invalidateRenderCaches()
Invalidate render caches.
GUI screen node that represents a screen that can be rendered via GUI system.
GUIInputEventHandler * inputEventHandler
void setInputEventHandler(GUIInputEventHandler *inputEventHandler)
Set input event handler.
void getProjectFilePathNameAndFileName(const string &fileName, string &projectFilePathName, string &projectFileFileName)
Get project path and filename of given file name.
bool scriptOnFocusAvailable
~GUIScreenNode()
Destructor.
const string getNodeType() override
void determineFocussedNodes(GUIParentNode *parentNode, vector< GUIElementNode * > &focusableNodes)
Determine focussed nodes.
int getContentWidth() override
bool removeNode(GUINode *node)
Add node.
vector< ForwardEvent > forwardEventList
void scrollToNodeX(const string &node, const string &toNode)
Register deferred scroll to node X.
void forwardEvents()
Forward events.
bool scriptOnDragRequestAvailable
bool scriptOnTickAvailable
void removeDragRequestListener(GUIDragRequestListener *listener)
Remove drag request listener.
void scrollToNodeY(const string &node, const string &toNode)
Register deferred scroll to node Y.
void setEnabled(bool enabled)
Set enabled.
GUIInputEventHandler * getInputEventHandler()
bool scriptOnUnfocusAvailable
int getContentHeight() override
bool scriptOnTooltipCloseRequestAvailable
unordered_map< string, GUINode * > tickNodesById
void forwardChange(GUIElementNode *node)
Forward change event.
void addContextMenuRequestListener(GUIContextMenuRequestListener *listener)
Add context menu request listener.
void addMoveListener(GUIMoveListener *listener)
Add move listener.
vector< GUIMouseOverListener * > mouseOverListener
void forwardContextMenuRequest(GUIElementNode *node, int mouseX, int mouseY)
Forward context menu request event.
vector< GUINode * > childControllerNodes
void forwardTooltipShowRequest(GUINode *node, int mouseX, int mouseY)
Forward tooltip show request event.
void addDragRequestListener(GUIDragRequestListener *listener)
Add drag request listener.
GUIColor foccussedBorderColor
void scrollToNodes()
Scroll to nodes.
void addChangeListener(GUIChangeListener *listener)
Add change listener.
void removeContextMenuRequestListener(GUIContextMenuRequestListener *listener)
Remove context menu request listener.
void setPopUp(bool popUp)
Set pop up.
void addTooltipRequestListener(GUITooltipRequestListener *listener)
Add tooltip request listener.
vector< GUIChangeListener * > changeListener
void setValues(const unordered_map< string, MutableString > &values)
Set values.
GUINode * forceInvalidateLayout(GUINode *node)
Actually do the invalidate layout.
void removeChangeListener(GUIChangeListener *listener)
Remove change listener.
void removeTooltipRequestListener(GUITooltipRequestListener *listener)
Remove tooltip request listener.
void removeNodeById(const string &nodeId, bool resetScrollOffsets)
Remove GUI node by id.
bool scriptOnMoveReleaseAvailable
void layout() override
Layout.
void removeActionListener(GUIActionListener *listener)
Remove action listener.
void removeFocusListener(GUIFocusListener *listener)
Remove focus listener.
void removeMouseOverListener(GUIMouseOverListener *listener)
Remove mouse over listener.
bool scriptOnTooltipShowRequestAvailable
void removeMoveListener(GUIMoveListener *listener)
Remove move listener.
void forwardAction(GUIActionListenerType type, GUIElementNode *node)
Forward action event.
bool scriptOnMoveAvailable
vector< GUIFocusListener * > focusListener
bool isMoveAccepted(GUINode *node)
Returns if move is accepted by move listener.
static GUIScreenNode_SizeConstraints createSizeConstraints(const string &minWidth, const string &minHeight, const string &maxWidth, const string &maxHeight)
Create size constraints.
void tick()
Calls registered tick nodes controller tick method.
void addMouseOverListener(GUIMouseOverListener *listener)
Add mouse over listener.
void renderFloatingNodes(GUIRenderer *guiRenderer)
Render floating nodes.
void determineMouseEventNodes(GUIMouseEvent *event, bool floatingNode, unordered_set< string > &eventNodeIds, unordered_set< string > &eventFloatingNodeIds, int flags=DETERMINEMOUSEEVENTNODES_FLAG_NONE) override
Determine mouse event nodes.
unique_ptr< GUIMiniScript > script
unordered_map< string, Texture * > imageCache
GUIScreenNode_SizeConstraints sizeConstraints
vector< ScrollToNodeStruct > scrollToNodesY
void setScreenSize(int width, int height)
Set screen size.
GUIFont * getFont(const string &fileName, int size)
Get font.
void getValues(unordered_map< string, MutableString > &values)
Get values.
vector< GUIActionListener * > actionListener
bool scriptOnChangeAvailable
void render(GUIRenderer *guiRenderer) override
Render screen.
void addActionListener(GUIActionListener *listener)
Add action listener.
void initializeMiniScript()
Initialize mini script.
string applicationSubPathName
void forwardMove(GUINode *node)
Forward move event.
unordered_map< string, GUINode * > nodesById
vector< GUIDragRequestListener * > dragRequestListener
void forwardMouseOver(GUIElementNode *node)
Forward mouse over event.
void forwardUnfocus(GUIElementNode *node)
Forward unfocus event.
string applicationRootPathName
vector< GUINode * > floatingNodes
bool isContentNode() override
bool addNode(GUINode *node)
Add node.
void invalidateLayouts()
Actually do the nodes marked for layout invalidation.
unordered_map< int64_t, string > timedExpressions
unordered_map< string, unordered_set< string > > elementNodeToNodeMapping
void setGUI(GUI *gui)
Set GUI.
void forwardTooltipCloseRequest()
Forward tooltip close request event.
vector< GUIMoveListener * > moveListener
void forwardMoveRelease(GUINode *node, int mouseX, int mouseY)
Forward move release event.
unordered_map< string, GUIFont * > fontCache
bool scriptOnContextMenuRequestAvailable
void forwardFocus(GUIElementNode *node)
Forward focus event.
EngineMiniScript::ScriptVariable miniScriptArguments
vector< ScrollToNodeStruct > scrollToNodesX
vector< GUITooltipRequestListener * > tooltipRequestListener
void addFocusListener(GUIFocusListener *listener)
Add focus listener.
unordered_set< string > invalidateLayoutNodeIds
Texture * getImage(const string &fileName)
Get image.
void forceLayout(GUINode *node)
Force layout node content (e.g.
void forwardDragRequest(GUIElementNode *node, int mouseX, int mouseY)
Forward drag request event.
vector< GUIContextMenuRequestListener * > contextMenuRequestListener
GUINode * getNodeById(const string &nodeId)
Get GUI node by id.
bool scriptOnActionAvailable
const vector< GUINode * > & getFloatingNodes()
bool scriptOnMouseOverAvailable
void setRenderAreaLeft(float renderAreaLeft)
Set up render area left.
void initScreen(GUIScreenNode *screenNode)
Init screen.
void doneScreen()
Done screen.
void setRenderAreaRight(float renderAreaRight)
Set up render area right.
void setRenderAreaTop(float renderAreaTop)
Set up render area top.
void setRenderAreaBottom(float renderAreaBottom)
Set up render area bottom.
File system singleton class.
Mutable utf8 aware string class.
Properties class, which helps out with storeing or loading key value pairs from/to property files.
std::exception Exception
Exception base class.
GUI action listener interface.
GUI change listener interface.
GUI drag request listener.
GUI focus listener interface.
GUI move listener interface.
GUI node computed constraints.
GUI node requested constraints entity.
GUINode_RequestedConstraints_RequestedConstraintsType * widthType
GUINode_RequestedConstraints_RequestedConstraintsType * heightType
GUI node scale 9 grid entity.
@ EVENTTYPE_CONTEXTMENUREQUEST
@ EVENTTYPE_TOOLTIPCLOSEREQUEST
@ EVENTTYPE_TOOLTIPSHOWREQUEST
GUI screen node size constraints entity.