1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/********************************************************************
*
*	Created:	17/3/2014   10:37
*
*	File:		fsIGuiComponent.h
*
*	Author:		Mick Waites
*	
*	Purpose:	Base class for all menus/GUIs.
*
*********************************************************************/

#ifndef fsIGuiComponenthdr
#define fsIGuiComponenthdr

#include <map>

#include <fsCore/fsStr.h>

#include "../../../src/fsCEntity.h"
#include "../fsIComponent.h"
#include "fsCGuiParseTree.h"

class fsCResourceName;
class fsCUniqueId;
class fsCVariableTable;
class fsCButtonComponent;
class fsINode;


class fsIGuiComponent : public fsIComponent
{
public:

	template <typename TComponent>
	TComponent* siblingEntityComponentGet() const;
	template <typename TComponent>
	TComponent* siblingEntityFamilyComponentGet() const;

	static void flush();

	void listenerComponentsRegister(fsCEntity* const pRoot) const;
	void listenerComponentsDeRegister(fsCEntity* const pRoot) const;

	static fsCEntity* guiCreateFromCommands(fsStr& pCommands, fsCEntity* pParent = nullptr, fsBool pModal = true,
	                                        fsBool pNewGrammarMode = false);
	static fsCEntity* guiCreateFromFile(const fsCResourceName& pGuiLayoutFileName, fsCEntity* pParent = nullptr,
	                                    fsBool pModal = true);

	// Pure parse (no engine calls) and construction-from-tree, split out of
	// guiCreateFromCommands so the parse side can be snapshot-tested on its own.
	// pNewGrammarMode selects which file-format signal (.gui vs legacy .txt)
	// was resolved for this parse; see newGrammarFileNameResolve. Gates:
	// `key: value` as an alternate to legacy `key = value` (see colonKeyGet);
	// explicit `use NAME` mixins alongside the legacy
	// bare-identifier-if-recognised-style heuristic (see commandProcess);
	// typed `(x, y)`/`[elem, ...]` values (see newGrammarValueRead); and
	// contiguous-include-at-top-of-file enforcement (in parseToTree itself).
	static fsCGuiParseTree parseToTree(fsStr& pCommands, fsBool pNewGrammarMode = false);
	static fsCEntity* constructFromTree(const fsCGuiParseTree& pTree, fsCEntity* pParent = nullptr,
	                                    fsBool pModal = true);

	// Resolves pLegacyFileName to its .gui sibling if one exists next to it
	// (existence-check dispatch, not content-sniffing - mirrors the
	// coords.txt/Spine.json pattern in level.rs), leaving pOutResolvedFileName
	// as pLegacyFileName unchanged otherwise. Returns whether new-grammar mode
	// was selected. Public so the running-order loader can share the one
	// resolver (fsIRunningOrder), no drift.
	static fsBool newGrammarFileNameResolve(const fsStr& pLegacyFileName, fsStr& pOutResolvedFileName);

	virtual fsBool onButtonClicked(fsCButtonComponent* pButtonComp);

	static fsIGuiComponent* guiParentGetFromComponent(const fsIComponent* pComponent);
	static fsBool entityHasGuiComponentGet(const fsINode* pNode);

protected:

	void layoutFileProcess();

	void initialiseFromVariableTableDo(const fsCVariableTable& pVars) override;

	fsIGuiComponent(fsCEntity* pParent);
	virtual ~fsIGuiComponent();<--- Destructor in derived class

private:

	static std::map<fsStr, fsStr> mStyles;
	static std::vector<fsStr> mStylesIncluded;

	static fsStr* mGuiLayoutFileName;

	static void unknownCommandProcess(const fsStr& pCommand, fsStr& pCommands);
	static fsBool commandProcess(const fsStr& pCommand, fsStr& pCommands, std::map<fsStr, fsStr>& pStyles,
	                             fsBool pNewGrammarMode);
	static void newGrammarIncludeContiguityCheck(fsStr pCommands);

	static fsS32 styleCharacterCountGet(fsStr& pCommands);

	static std::unique_ptr<fsCGuiParseNode> guiElementParse(const fsCUniqueId& pComponentId,
	                                                        const fsStr& pComponentTypeName, fsStr& pCommands,
	                                                        std::map<fsStr, fsStr>& pStyles,
	                                                        fsCGuiParseNode* pParentNode, fsBool pNewGrammarMode);
	static fsBool colonKeyGet(fsStr& pCommands, fsStr& pOutKey);
	static fsCEntity* constructFromTree(const fsCGuiParseNode& pNode, fsCEntity* pParent, fsBool pMakeModal);
	static fsStr newGrammarValueRead(fsStr& pCommands);
	static void variableInsertIntoTree(const fsStr& pVariable, fsStr& pCommands, std::map<fsStr, fsStr>& pParams,
	                                   fsBool pNewGrammarMode);
	static fsBool fileContentsInclude(fsStr& pCommands);
	static void styleDefinitionAdd(fsStr& pCommands, std::map<fsStr, fsStr>& pStyles);
	static fsBool styleDefinitionDecodeAndInsertIntoCommands(const fsStr& pStyleName, fsStr& pCommands,
	                                                         std::map<fsStr, fsStr>& pStyles);
};

template <typename TComponent>
TComponent* fsIGuiComponent::siblingEntityComponentGet() const
{
	fsCEntity* const guiRootEnt = this->parentGet();
	std::vector<fsCEntity*> canditates = guiRootEnt->childEntitiesWithComponentsOfFamilyType<TComponent>();
	if (!canditates.empty())
	{
		return canditates.front()->componentGet<TComponent>();
	}
	return nullptr;
}

template <typename TComponent>
TComponent* fsIGuiComponent::siblingEntityFamilyComponentGet() const
{
	fsCEntity* const guiRootEnt = this->parentGet();
	std::vector<fsCEntity*> canditates = guiRootEnt->childEntitiesWithComponentsOfFamilyType<TComponent>();
	if (!canditates.empty())
	{
		return canditates.front()->firstComponentOfFamilyType<TComponent>();
	}
	return nullptr;
}

#endif