6 #include <unordered_set>
50 using std::make_unique;
53 using std::unique_ptr;
54 using std::unordered_set;
97 UIEditorTabView::UIEditorTabView(
EditorView* editorView,
const string& tabId,
GUIScreenNode* screenNode,
const string& fileName)
104 guiEngine = unique_ptr<Engine>(Engine::createOffScreenInstance(1920, 1080,
false,
false,
false));
105 guiEngine->setSceneColor(
Color4(39.0f / 255.0f, 39.0f / 255.0f, 39.0f / 255.0f, 1.0f));
124 vector<int> checkedGUIEngineMouseEventIndices;
125 vector<int> checkedEngineMouseEventIndices;
126 vector<int> unusedEngineMouseEventIndices;
128 auto modelEntity =
dynamic_cast<Object*
>(
engine->getEntity(
"model"));
129 if (modelEntity !=
nullptr &&
modelMeshNode.empty() ==
false && modelEntity->getModel()->getNodeById(
modelMeshNode) !=
nullptr) {
131 auto modelEntityModelImportMatrixInverted = modelEntity->getModel()->getImportTransformMatrix().
clone().
invert();
132 auto modelEntityWorldMatrixInverted = modelEntityWorldMatrix.
clone().
multiply(modelEntity->getTransformMatrix()).multiply(modelEntityModelImportMatrixInverted).invert();
134 const auto& engineMouseEvents =
engine->getGUI()->getMouseEvents();
135 auto& guiEngineMouseEvents =
guiEngine->getGUI()->getMouseEvents();
136 auto mouseEventIdx = 0;
137 for (
const auto& event:
engine->getGUI()->getMouseEvents()) {
138 if (event.isProcessed() ==
true) {
143 Vector3 mouseWorldCoordinate =
engine->computeWorldCoordinateByMousePosition(event.getXUnscaled(),
event.getYUnscaled());
144 auto bookLocalCoordinate = modelEntityWorldMatrixInverted.multiply(mouseWorldCoordinate);
145 auto clonedEvent = event;
148 clonedEvent.setXUnscaled(clonedEvent.getX());
149 clonedEvent.setYUnscaled(clonedEvent.getY());
150 if (clonedEvent.getX() >= 0 && clonedEvent.getX() <
guiEngine->getWidth() &&
151 clonedEvent.getY() >= 0 && clonedEvent.getY() <
guiEngine->getHeight()) {
152 checkedGUIEngineMouseEventIndices.push_back(guiEngineMouseEvents.size());
153 guiEngineMouseEvents.push_back(clonedEvent);
155 checkedEngineMouseEventIndices.push_back(mouseEventIdx);
158 unusedEngineMouseEventIndices.push_back(mouseEventIdx);
164 const auto& engineMouseEvents =
engine->getGUI()->getMouseEvents();
165 for (
auto i = 0; i < engineMouseEvents.size(); i++) unusedEngineMouseEventIndices.push_back(i);
168 guiEngine->getGUI()->handleEvents(
false);
170 auto engineMouseEvents =
engine->getGUI()->getMouseEvents();
171 const auto& guiEngineMouseEvents =
guiEngine->getGUI()->getMouseEvents();
172 engine->getGUI()->getMouseEvents().clear();
175 for (
auto i = 0; i < checkedEngineMouseEventIndices.size(); i++) {
176 if (guiEngineMouseEvents[checkedGUIEngineMouseEventIndices[i]].isProcessed() ==
false)
engine->getGUI()->getMouseEvents().push_back(engineMouseEvents[checkedEngineMouseEventIndices[i]]);
178 for (
auto i = 0; i < unusedEngineMouseEventIndices.size(); i++) {
179 engine->getGUI()->getMouseEvents().push_back(engineMouseEvents[unusedEngineMouseEventIndices[i]]);
182 guiEngine->getGUI()->getKeyboardEvents().clear();
183 guiEngine->getGUI()->getMouseEvents().clear();
187 engine->getGUI()->getMouseEvents().clear();
188 engine->getGUI()->getKeyboardEvents().clear();
209 Console::println(
"UIEditorTabView::initialize(): An error occurred: " +
string(exception.what()));
217 TextFormatter::getInstance()->format(
"xml",
textNode);
219 codeCompletion = TextFormatter::getInstance()->loadCodeCompletion(
"xml");
224 class TextChangeListener:
public GUIStyledTextNodeController::ChangeListener {
226 TextChangeListener(
UIEditorTabView* uiEditorTabView): uiEditorTabView(uiEditorTabView) {
229 virtual ~TextChangeListener() {
232 virtual void onRemoveText(
int idx,
int count)
override {
237 TextFormatter::getInstance()->format(
"xml", uiEditorTabView->
textNode, idx, idx +
count);
240 virtual void onInsertText(
int idx,
int count)
override {
245 TextFormatter::getInstance()->format(
"xml", uiEditorTabView->
textNode, idx, idx +
count);
258 class TextCodeCompletionListener:
public GUIStyledTextNodeController::CodeCompletionListener {
260 TextCodeCompletionListener(
UIEditorTabView* uiEditorTabView): uiEditorTabView(uiEditorTabView) {
263 virtual ~TextCodeCompletionListener() {
266 virtual void onCodeCompletion(
int idx)
override {
273 string search = StringTools::substring(uiEditorTabView->
textNode->
getText().
getString(), previousDelimiterPos == 0?0:previousDelimiterPos + 1, idx);
274 vector<CodeCompletionSymbol> codeCompletionSymbolCandidates;
275 #define MAX_ENTRIES 40
277 if (StringTools::startsWith(symbol.name, search) ==
true) {
278 if (symbol.overloadList.empty() ==
true) {
279 if (codeCompletionSymbolCandidates.size() ==
MAX_ENTRIES) {
280 codeCompletionSymbolCandidates.push_back(
291 codeCompletionSymbolCandidates.push_back(
294 .display = symbol.name,
302 for (
const auto& overload: symbol.overloadList) {
303 if (codeCompletionSymbolCandidates.size() ==
MAX_ENTRIES) {
304 codeCompletionSymbolCandidates.push_back(
316 for (
const auto& parameter: overload.parameters) {
317 if (parameters.empty() ==
false) parameters+=
", ";
318 parameters+= parameter;
320 codeCompletionSymbolCandidates.push_back(
323 .display = symbol.name +
"(" + parameters +
") = " + overload.returnValue,
325 .parameters = overload.parameters,
326 .returnValue = overload.returnValue
331 if (codeCompletionSymbolCandidates.size() ==
MAX_ENTRIES + 1)
break;
340 codeCompletionSymbolCandidates.begin(),
341 codeCompletionSymbolCandidates.begin() + (Math::min(codeCompletionSymbolCandidates.size(),
MAX_ENTRIES)),
343 return lhs.display < rhs.display;
349 for (
const auto& codeCompletionSymbolCandidate: codeCompletionSymbolCandidates) {
351 class OnCodeCompletionAction:
public virtual Action
355 void performAction()
override {
356 if (symbol.
name.empty() ==
true)
return;
362 if (withoutWhiteSpaceDelimiters.find(
' ') != string::npos) withoutWhiteSpaceDelimiters.erase(withoutWhiteSpaceDelimiters.find(
' '), 1);
363 if (withoutWhiteSpaceDelimiters.find(
'\t') != string::npos) withoutWhiteSpaceDelimiters.erase(withoutWhiteSpaceDelimiters.find(
'\t'), 1);
364 if (withoutWhiteSpaceDelimiters.find(
'\n') != string::npos) withoutWhiteSpaceDelimiters.erase(withoutWhiteSpaceDelimiters.find(
'\n'), 1);
367 string parameterString;
369 for (
const auto& parameter: symbol.
parameters) {
370 auto parameterTokenized = StringTools::tokenize(parameter,
" \t\n");
371 if (parameterString.empty() ==
false) parameterString+=
", ";
372 parameterString+= parameterTokenized[parameterTokenized.size() - 1];
374 parameterString =
"(" + parameterString +
")";
376 uiEditorTabView->
textNode->
removeText(previousDelimiterPos == 0?0:previousDelimiterPos + 1, nextDelimiterPos - (previousDelimiterPos == 0?0:previousDelimiterPos + 1));
377 uiEditorTabView->
textNode->
insertText(previousDelimiterPos == 0?0:previousDelimiterPos + 1, symbol.
name + parameterString);
378 TextFormatter::getInstance()->format(
"xml", uiEditorTabView->
textNode, previousDelimiterPos == 0?0:previousDelimiterPos + 1, (previousDelimiterPos == 0?0:previousDelimiterPos + 1) + symbol.
name.size() + parameterString.size());
390 if (codeCompletionSymbolCandidates.empty() ==
false) {
392 int left, top, width, height, offsetX, offsetY;
394 if (selectedTab !=
nullptr) {
395 uiEditorTabView->
getEditorView()->
getViewPort(selectedTab->getFrameBufferNode(), left, top, width, height, offsetX, offsetY);
457 .fileName = string(),
459 .screenNode =
nullptr,
468 if (screenIdx < 0 || screenIdx >=
uiScreenNodes.size())
return;
475 xml = FileSystem::getInstance()->getContentAsString(
476 Tools::getPathName(fileName),
477 Tools::getFileName(fileName)
480 Console::println(
"UIEditorTabView::setScreen(): an error occurred: " +
screenNode->
getFileName() +
": " +
string(exception.what()));
495 if (screenIdx < 0 || screenIdx >=
uiScreenNodes.size())
return;
508 if (screenIdx < 0 || screenIdx >=
uiScreenNodes.size())
return;
517 guiEngine->getGUI()->resetRenderScreens();
522 auto screensMaxWidth = -1;
523 auto screensMaxHeight = -1;
537 Console::println(
"UIEditorTabView::reAddScreens(): an error occurred: " +
string(exception.what()));
541 "resources/engine/gui/",
543 {{
"text", StringTools::replace(StringTools::replace(
"An error occurred: " +
string(exception.what()),
"[",
"\\["),
"]",
"\\]") }}
546 Console::println(
"UIEditorTabView::reAddScreens(): an error occurred: " +
string(exception2.what()));
549 if (xmlRootNode ==
"screen") {
559 Console::println(
"UIEditorTabView::reAddScreens(): an error occurred: " +
string(exception.what()));
563 "resources/engine/gui/",
565 {{
"text", StringTools::replace(StringTools::replace(
"An error occurred: " +
string(exception.what()),
"[",
"\\["),
"]",
"\\]") }}
568 Console::println(
"UIEditorTabView::reAddScreens(): an error occurred: " +
string(exception2.what()));
572 if (xmlRootNode ==
"template") {
581 unordered_map<string, string> templateAttributes;
584 templateAttributes = GUIParser::parseTemplateAttributes(
uiScreenNodes[i].xml);
586 Console::println(
"UIEditorTabView::reAddScreens(): an error occurred: " +
string(exception.what()));
589 if (templateAttributes.find(
"preview-id") == templateAttributes.end()) templateAttributes[
"preview-id"] =
"preview-id";
590 if (templateAttributes.find(
"preview-container-width") == templateAttributes.end()) templateAttributes[
"preview-container-width"] =
"100%";
591 if (templateAttributes.find(
"preview-container-height") == templateAttributes.end()) templateAttributes[
"preview-container-height"] =
"100%";
596 "<screen id='screen_template'>\n" +
597 " <layout width='{$preview-container-width}' height='{$preview-container-height}' alignment='none' horizontal-align='center' vertical-align='center'>\n" +
598 GUIParser::getInnerXml(StringTools::replace(
uiScreenNodes[i].xml,
"{$id}",
"{$preview-id}")) +
606 Console::println(
"UIEditorTabView::reAddScreens(): an error occurred: " +
string(exception.what()));
610 "resources/engine/gui/",
612 {{
"text", StringTools::replace(StringTools::replace(
"An error occurred: " +
string(exception.what()),
"[",
"\\["),
"]",
"\\]") }}
615 Console::println(
"UIEditorTabView::reAddScreens(): an error occurred: " +
string(exception2.what()));
641 if (screensMaxWidth == -1) screensMaxWidth = 1920;
642 if (screensMaxHeight == -1) screensMaxHeight = 1080;
643 if (
guiEngine->getWidth() != screensMaxWidth ||
guiEngine->getHeight() != screensMaxHeight) {
644 guiEngine->reshape(screensMaxWidth, screensMaxHeight);
659 prototype = unique_ptr<Prototype>(PrototypeReader::read(pathName, fileName));
661 Console::println(
"UIEditorTabView::loadPrototype(): An error occurred: " +
string(exception.what()));
669 engine = unique_ptr<Engine>(Engine::createOffScreenInstance(512, 512,
true,
true,
false));
671 engine->setShadowMapLightEyeDistanceScale(0.1f);
672 engine->setSceneColor(
Color4(39.0f / 255.0f, 39.0f / 255.0f, 39.0f / 255.0f, 1.0f));
681 auto modelEntity =
engine->getEntity(
"model");
682 if (modelEntity !=
nullptr) {
683 modelEntity->setScale(modelEntity->getScale() * 2.0f);
684 modelEntity->update();
686 static_cast<Object*
>(modelEntity)->setAnimation(modelMeshAnimation);
688 auto groundEntity =
engine->getEntity(
"ground");
689 if (groundEntity !=
nullptr) {
690 groundEntity->setScale(groundEntity->getScale() * 2.0f);
691 groundEntity->update();
704 auto modelEntity =
dynamic_cast<Object*
>(
engine->getEntity(
"model"));
705 if (modelEntity !=
nullptr) {
717 if (model ==
nullptr || model->getNodeById(
modelMeshNode) ==
nullptr)
return;
720 const auto& modelMeshNodeFacesEntities = model->getNodeById(
modelMeshNode)->getFacesEntities();
721 unordered_set<string> materialIds;
722 for (
const auto& facesEntity: modelMeshNodeFacesEntities) {
723 if (facesEntity.getMaterial() !=
nullptr) materialIds.insert(facesEntity.getMaterial()->getId());
724 for (
const auto& face: facesEntity.getFaces()) {
725 for (
auto i = 0; i < 3; i++) {
735 for (
const auto& materialId: materialIds) {
736 auto materialIt = model->getMaterials().find(materialId);
737 auto material = materialIt != model->getMaterials().end()?materialIt->second:
nullptr;
738 if (material ==
nullptr)
continue;
739 material->getSpecularMaterialProperties()->setDiffuseColor(
Color4(0.8f, 0.8f, 0.8f, 0.9999f));
740 if (material->getPBRMaterialProperties() !=
nullptr) material->getPBRMaterialProperties()->setBaseColorFactor(
Color4(1.0f, 1.0f, 1.0f, 0.9999f));
747 auto modelEntity =
dynamic_cast<Object*
>(
engine->getEntity(
"model"));
748 if (modelEntity !=
nullptr) {
764 guiEngine->setSceneColor(
Color4(39.0f / 255.0f, 39.0f / 255.0f, 39.0f / 255.0f, 1.0f));
777 if (screenIdx < 0 || screenIdx >=
uiScreenNodes.size())
return;
808 if (screenIdx < 0 || screenIdx >=
uiScreenNodes.size())
return;
812 TextFormatter::getInstance()->format(
"xml",
textNode);
816 auto textNodeController = required_dynamic_cast<GUIStyledTextNodeController*>(
textNode->
getController());
817 return textNodeController->getIndex();
820 bool UIEditorTabView::find(
const string& findString,
bool matchCase,
bool wholeWord,
bool selection,
bool firstSearch,
int& index) {
822 return TextTools::find(
textNode, findString, matchCase, wholeWord, selection, firstSearch, index);
828 return TextTools::count(
textNode, findString, matchCase, wholeWord, selection);
831 bool UIEditorTabView::replace(
const string& findString,
const string& replaceString,
bool matchCase,
bool wholeWord,
bool selection,
int& index) {
833 auto success = TextTools::replace(
textNode, findString, replaceString, matchCase, wholeWord, selection, index);
839 auto success = TextTools::replaceAll(
textNode, findString, replaceString, matchCase, wholeWord, selection);
Color 4 definition class.
Object to be used with engine class.
Bogus/Simple partition implementation.
Represents a model face, consisting of vertex, normal, tangent and bitangent vectors,...
Node faces entity A node can have multiple entities containing faces and a applied material.
Representation of a 3D model.
Represents specular material properties.
Represents specular material properties.
void setAnimation(const string &id, float speed=1.0f)
Sets up a base animation to play.
const Matrix4x4 getNodeTransformMatrix(const string &id)
Returns transform matrix for given node.
void unbindDiffuseTexture(const string &nodeId=string(), const string &facesEntityId=string())
Unbind dynamic texture to a node and faces entity of this object.
GUINodeConditions & getActiveConditions()
void set(const string &condition)
Set condition.
float computeParentChildrenRenderOffsetXTotal()
GUINodeController * getController()
float computeParentChildrenRenderOffsetYTotal()
GUI screen node that represents a screen that can be rendered via GUI system.
const string & getFileName()
void addTooltipRequestListener(GUITooltipRequestListener *listener)
Add tooltip request listener.
GUIScreenNode_SizeConstraints & getSizeConstraints()
GUINode * getInnerNodeById(const string &nodeId)
Get inner GUI node by id.
GUINode * getNodeById(const string &nodeId)
Get GUI node by id.
GUI styled text node controller.
int getNextDelimiter(int index, const string &delimiters)
Get next delimiter.
void insertText(int32_t idx, int c)
Insert character c at idx.
void setText(const MutableString &text)
Set text.
int getPreviousDelimiter(int index, const string &delimiters)
Get previous delimiter.
void removeText(int32_t idx, int32_t count)
Remove characters at idx with given length.
const MutableString & getText() const
Matrix4x4 clone() const
Clones this matrix.
Vector3 multiply(const Vector3 &vector3) const
Multiplies this matrix with vector3.
Matrix4x4 & invert()
Inverts this matrix.
Vector3 class representing vector3 mathematical structure and operations with x, y,...
File system singleton class.
Mutable utf8 aware string class.
char getCharAt(int32_t idx) const
Get char at given binary index.
const string & getString() const
std::exception Exception
Exception base class.