mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
Build binary, code display, errors management
This commit is contained in:
parent
83d8542002
commit
09aab7241a
32 changed files with 657 additions and 522 deletions
|
|
@ -94,15 +94,13 @@ static inline void leu16_put(std::vector<std::uint8_t> &container, uint16_t data
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GET_REG(name, ra) if (!GetRegister(name, ra)) {\
|
#define GET_REG(name, ra) if (!GetRegister(name, ra)) {\
|
||||||
std::stringstream ss; \
|
m_lastError.line -1; \
|
||||||
ss << "ERROR! Bad register name: " << name << std::endl;\
|
m_lastError.message = "ERROR! Bad register name: " + name; \
|
||||||
m_lastError = ss.str(); \
|
|
||||||
return false; }
|
return false; }
|
||||||
|
|
||||||
#define CHIP32_CHECK(instr, cond, error) if (!(cond)) { \
|
#define CHIP32_CHECK(instr, cond, error) if (!(cond)) { \
|
||||||
std::stringstream ss; \
|
m_lastError.line = instr.line; \
|
||||||
ss << "error line: " << instr.line << ": " << error << std::endl; \
|
m_lastError.message = error; \
|
||||||
m_lastError = ss.str(); \
|
|
||||||
return false; } \
|
return false; } \
|
||||||
|
|
||||||
std::vector<std::string> Split(std::string line)
|
std::vector<std::string> Split(std::string line)
|
||||||
|
|
@ -242,7 +240,7 @@ bool Assembler::CompileMnemonicArguments(Instr &instr)
|
||||||
instr.compiledArgs.push_back(static_cast<uint32_t>(strtol(instr.args[2].c_str(), NULL, 0)));
|
instr.compiledArgs.push_back(static_cast<uint32_t>(strtol(instr.args[2].c_str(), NULL, 0)));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
CHIP32_CHECK(instr, false, "Unsupported mnemonic: " << instr.mnemonic);
|
CHIP32_CHECK(instr, false, "Unsupported mnemonic: " + instr.mnemonic);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -286,7 +284,7 @@ bool Assembler::CompileConstantArgument(Instr &instr, const std::string &a)
|
||||||
((intVal <= UINT32_MAX) && (instr.dataTypeSize == 32))) {
|
((intVal <= UINT32_MAX) && (instr.dataTypeSize == 32))) {
|
||||||
sizeOk = true;
|
sizeOk = true;
|
||||||
}
|
}
|
||||||
CHIP32_CHECK(instr, sizeOk, "integer too high: " << intVal);
|
CHIP32_CHECK(instr, sizeOk, "integer too high: " + std::to_string(intVal));
|
||||||
if (instr.dataTypeSize == 8) {
|
if (instr.dataTypeSize == 8) {
|
||||||
instr.compiledArgs.push_back(intVal);
|
instr.compiledArgs.push_back(intVal);
|
||||||
} else if (instr.dataTypeSize == 16) {
|
} else if (instr.dataTypeSize == 16) {
|
||||||
|
|
@ -362,7 +360,7 @@ bool Assembler::Parse(const std::string &data)
|
||||||
instr.mnemonic = opcode;
|
instr.mnemonic = opcode;
|
||||||
instr.isLabel = true;
|
instr.isLabel = true;
|
||||||
instr.addr = code_addr;
|
instr.addr = code_addr;
|
||||||
CHIP32_CHECK(instr, m_labels.count(opcode) == 0, "duplicated label : " << opcode);
|
CHIP32_CHECK(instr, m_labels.count(opcode) == 0, "duplicated label : " + opcode);
|
||||||
m_labels[opcode] = instr;
|
m_labels[opcode] = instr;
|
||||||
m_instructions.push_back(instr);
|
m_instructions.push_back(instr);
|
||||||
}
|
}
|
||||||
|
|
@ -383,7 +381,7 @@ bool Assembler::Parse(const std::string &data)
|
||||||
{
|
{
|
||||||
instr.args.insert(instr.args.begin(), lineParts.begin() + 1, lineParts.end());
|
instr.args.insert(instr.args.begin(), lineParts.begin() + 1, lineParts.end());
|
||||||
CHIP32_CHECK(instr, instr.args.size() == instr.code.nbAargs,
|
CHIP32_CHECK(instr, instr.args.size() == instr.code.nbAargs,
|
||||||
"Bad number of parameters. Required: " << static_cast<int>(instr.code.nbAargs) << ", got: " << instr.args.size());
|
"Bad number of parameters. Required: " + std::to_string(static_cast<int>(instr.code.nbAargs)) + ", got: " + std::to_string(instr.args.size()));
|
||||||
nbArgsSuccess = true;
|
nbArgsSuccess = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -412,7 +410,7 @@ bool Assembler::Parse(const std::string &data)
|
||||||
|
|
||||||
CHIP32_CHECK(instr, (type.size() >= 3), "bad data type size");
|
CHIP32_CHECK(instr, (type.size() >= 3), "bad data type size");
|
||||||
CHIP32_CHECK(instr, (type[0] == 'D') && ((type[1] == 'C') || (type[1] == 'V')), "bad data type (must be DCxx or DVxx");
|
CHIP32_CHECK(instr, (type[0] == 'D') && ((type[1] == 'C') || (type[1] == 'V')), "bad data type (must be DCxx or DVxx");
|
||||||
CHIP32_CHECK(instr, m_labels.count(opcode) == 0, "duplicated label : " << opcode);
|
CHIP32_CHECK(instr, m_labels.count(opcode) == 0, "duplicated label : " + opcode);
|
||||||
|
|
||||||
instr.isRomData = type[1] == 'C' ? true : false;
|
instr.isRomData = type[1] == 'C' ? true : false;
|
||||||
instr.isRamData = type[1] == 'V' ? true : false;
|
instr.isRamData = type[1] == 'V' ? true : false;
|
||||||
|
|
@ -445,7 +443,8 @@ bool Assembler::Parse(const std::string &data)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_lastError = "Unknown mnemonic or bad formatted line: " + std::to_string(lineNum);
|
m_lastError.message = "Unknown mnemonic or badly formatted line";
|
||||||
|
m_lastError.line = lineNum;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -458,7 +457,7 @@ bool Assembler::Parse(const std::string &data)
|
||||||
// label is the first argument for jump, second position for LCONS
|
// label is the first argument for jump, second position for LCONS
|
||||||
uint16_t argsIndex = instr.code.opcode == OP_LCONS ? 1 : 0;
|
uint16_t argsIndex = instr.code.opcode == OP_LCONS ? 1 : 0;
|
||||||
std::string label = instr.args[argsIndex];
|
std::string label = instr.args[argsIndex];
|
||||||
CHIP32_CHECK(instr, m_labels.count(label) > 0, "label not found: " << label);
|
CHIP32_CHECK(instr, m_labels.count(label) > 0, "label not found: " + label);
|
||||||
uint16_t addr = m_labels[label].addr;
|
uint16_t addr = m_labels[label].addr;
|
||||||
std::cout << "LABEL: " << label << " , addr: " << addr << std::endl;
|
std::cout << "LABEL: " << label << " , addr: " << addr << std::endl;
|
||||||
instr.compiledArgs[argsIndex] = addr & 0xFF;
|
instr.compiledArgs[argsIndex] = addr & 0xFF;
|
||||||
|
|
|
||||||
|
|
@ -83,10 +83,16 @@ struct Result
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Assembler
|
class Assembler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
struct Error {
|
||||||
|
std::string message;
|
||||||
|
int line;
|
||||||
|
std::string ToString() const { return "Error line " + std::to_string(line) + ", " + message; }
|
||||||
|
};
|
||||||
|
|
||||||
// Separated parser to allow only code check
|
// Separated parser to allow only code check
|
||||||
bool Parse(const std::string &data);
|
bool Parse(const std::string &data);
|
||||||
// Generate the executable binary after the parse pass
|
// Generate the executable binary after the parse pass
|
||||||
|
|
@ -104,7 +110,7 @@ public:
|
||||||
bool GetRegister(const std::string ®Name, uint8_t ®);
|
bool GetRegister(const std::string ®Name, uint8_t ®);
|
||||||
bool GetRegisterName(uint8_t reg, std::string ®Name);
|
bool GetRegisterName(uint8_t reg, std::string ®Name);
|
||||||
|
|
||||||
std::string GetLastError() { return m_lastError; }
|
Error GetLastError() { return m_lastError; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool CompileMnemonicArguments(Instr &instr);
|
bool CompileMnemonicArguments(Instr &instr);
|
||||||
|
|
@ -112,7 +118,7 @@ private:
|
||||||
// label, address
|
// label, address
|
||||||
std::map<std::string, Instr> m_labels;
|
std::map<std::string, Instr> m_labels;
|
||||||
|
|
||||||
std::string m_lastError;
|
Error m_lastError;
|
||||||
|
|
||||||
std::vector<Instr> m_instructions;
|
std::vector<Instr> m_instructions;
|
||||||
bool CompileConstantArgument(Instr &instr, const std::string &a);
|
bool CompileConstantArgument(Instr &instr, const std::string &a);
|
||||||
|
|
|
||||||
|
|
@ -119,8 +119,8 @@ set(SRCS
|
||||||
src/resources_window.cpp
|
src/resources_window.cpp
|
||||||
src/resources_window.h
|
src/resources_window.h
|
||||||
|
|
||||||
src/node_properties_window.cpp
|
src/properties_window.cpp
|
||||||
src/node_properties_window.h
|
src/properties_window.h
|
||||||
|
|
||||||
src/gui.h
|
src/gui.h
|
||||||
src/gui.cpp
|
src/gui.cpp
|
||||||
|
|
@ -128,6 +128,9 @@ set(SRCS
|
||||||
src/code_editor.cpp
|
src/code_editor.cpp
|
||||||
src/code_editor.h
|
src/code_editor.h
|
||||||
|
|
||||||
|
src/connection.cpp
|
||||||
|
src/connection.h
|
||||||
|
|
||||||
src/uuid.h
|
src/uuid.h
|
||||||
src/resource_manager.h
|
src/resource_manager.h
|
||||||
src/i_story_project.h
|
src/i_story_project.h
|
||||||
|
|
|
||||||
1
story-editor/icon.rc
Normal file
1
story-editor/icon.rc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
IDI_ICON1 ICON DISCARDABLE "story-editor-logo.ico"
|
||||||
53
story-editor/nsis-installer.nsi
Normal file
53
story-editor/nsis-installer.nsi
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
# define installer name
|
||||||
|
!define APPNAME "StoryEditor"
|
||||||
|
!define COMPANYNAME "OpenStoryTeller"
|
||||||
|
!define DESCRIPTION "A story editor using graphical nodes, for the OpenStoryTeller project. http://openstoryteller.org"
|
||||||
|
|
||||||
|
!define VERSIONMAJOR 1
|
||||||
|
!define VERSIONMINOR 3
|
||||||
|
!define VERSIONBUILD 4
|
||||||
|
OutFile "build/story-editor-setup.exe"
|
||||||
|
|
||||||
|
# set desktop as install directory
|
||||||
|
InstallDir "$PROGRAMFILES64\${APPNAME}"
|
||||||
|
Name "${COMPANYNAME} - ${APPNAME}"
|
||||||
|
|
||||||
|
# default section start
|
||||||
|
Section
|
||||||
|
|
||||||
|
# define output path
|
||||||
|
SetOutPath $INSTDIR
|
||||||
|
|
||||||
|
# specify file to go in output path
|
||||||
|
File /r "build/story-editor\*"
|
||||||
|
File "story-editor-logo.ico"
|
||||||
|
|
||||||
|
# define uninstaller name
|
||||||
|
WriteUninstaller $INSTDIR\uninstaller.exe
|
||||||
|
|
||||||
|
# Create shortcut
|
||||||
|
SetShellVarContext all
|
||||||
|
CreateDirectory "$SMPROGRAMS\${COMPANYNAME}"
|
||||||
|
CreateShortCut "$SMPROGRAMS\${COMPANYNAME}\${APPNAME}.lnk" "$INSTDIR\story-editor.exe" "" "$INSTDIR\story-editor-logo.ico"
|
||||||
|
SetShellVarContext current
|
||||||
|
|
||||||
|
|
||||||
|
#-------
|
||||||
|
# default section end
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
# create a section to define what the uninstaller does.
|
||||||
|
# the section will always be named "Uninstall"
|
||||||
|
Section "Uninstall"
|
||||||
|
|
||||||
|
# Always delete uninstaller first
|
||||||
|
Delete $INSTDIR\uninstaller.exe
|
||||||
|
Delete "$SMPROGRAMS\${COMPANYNAME}\${APPNAME}.lnk"
|
||||||
|
Delete $INSTDIR\story-editor-logo.ico
|
||||||
|
|
||||||
|
# now delete installed file
|
||||||
|
Delete $INSTDIR\*
|
||||||
|
|
||||||
|
# Delete the directory
|
||||||
|
RMDir /r $INSTDIR
|
||||||
|
SectionEnd
|
||||||
|
|
@ -105,8 +105,10 @@ public:
|
||||||
|
|
||||||
|
|
||||||
virtual void Draw() = 0;
|
virtual void Draw() = 0;
|
||||||
|
|
||||||
virtual void DrawProperties() = 0;
|
virtual void DrawProperties() = 0;
|
||||||
|
virtual std::string GenerateConstants() = 0;
|
||||||
|
virtual std::string Build() = 0;
|
||||||
|
virtual std::string GetEntryLabel() = 0;
|
||||||
|
|
||||||
void SetPosition(float x, float y);
|
void SetPosition(float x, float y);
|
||||||
|
|
||||||
|
|
@ -135,8 +137,8 @@ public:
|
||||||
unsigned long GetId() const { return m_id; }
|
unsigned long GetId() const { return m_id; }
|
||||||
unsigned long GetInternalId() const { return m_node->ID.Get(); }
|
unsigned long GetInternalId() const { return m_node->ID.Get(); }
|
||||||
|
|
||||||
void seTitle(const std::string &title) { m_title = title; }
|
void SeTitle(const std::string &title) { m_title = title; }
|
||||||
std::string getTitle() const { return m_title; }
|
std::string GetTitle() const { return m_title; }
|
||||||
|
|
||||||
virtual void FromJson(const nlohmann::json &) = 0;
|
virtual void FromJson(const nlohmann::json &) = 0;
|
||||||
virtual void ToJson(nlohmann::json &) = 0;
|
virtual void ToJson(nlohmann::json &) = 0;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "code_editor.h"
|
#include "code_editor.h"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
CodeEditor::CodeEditor()
|
CodeEditor::CodeEditor()
|
||||||
: WindowBase("Code editor")
|
: WindowBase("Code editor")
|
||||||
|
|
@ -11,27 +12,32 @@ CodeEditor::CodeEditor()
|
||||||
void CodeEditor::Initialize()
|
void CodeEditor::Initialize()
|
||||||
{
|
{
|
||||||
// error markers
|
// error markers
|
||||||
TextEditor::ErrorMarkers markers;
|
|
||||||
markers.insert(std::make_pair<int, std::string>(6, "Example error here:\nInclude file not found: \"TextEditor.h\""));
|
//
|
||||||
markers.insert(std::make_pair<int, std::string>(41, "Another example error"));
|
// markers.insert(std::make_pair<int, std::string>(41, "Another example error"));
|
||||||
mEditor.SetErrorMarkers(markers);
|
|
||||||
|
|
||||||
// "breakpoint" markers
|
// "breakpoint" markers
|
||||||
//TextEditor::Breakpoints bpts;
|
m_breakPoints.insert(42);
|
||||||
//bpts.insert(24);
|
mEditor.SetBreakpoints(m_breakPoints);
|
||||||
//bpts.insert(47);
|
|
||||||
//editor.SetBreakpoints(bpts);
|
|
||||||
|
|
||||||
mFileToEdit = "test/test_zebra7500.js";
|
}
|
||||||
|
|
||||||
{
|
void CodeEditor::ClearErrors()
|
||||||
std::ifstream t(mFileToEdit);
|
{
|
||||||
if (t.good())
|
m_markers.clear();
|
||||||
{
|
}
|
||||||
std::string str((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
|
|
||||||
mEditor.SetText(str);
|
void CodeEditor::AddError(int line, const std::string &text)
|
||||||
}
|
{
|
||||||
}
|
m_markers.insert(std::make_pair(line, text));
|
||||||
|
mEditor.SetErrorMarkers(m_markers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CodeEditor::SetScript(const std::string &txt)
|
||||||
|
{
|
||||||
|
mEditor.SetText(txt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeEditor::Draw()
|
void CodeEditor::Draw()
|
||||||
|
|
@ -99,10 +105,9 @@ void CodeEditor::Draw()
|
||||||
ImGui::EndMenuBar();
|
ImGui::EndMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Text("%6d/%-6d %6d lines | %s | %s | %s | %s", cpos.mLine + 1, cpos.mColumn + 1, mEditor.GetTotalLines(),
|
ImGui::Text("%6d/%-6d %6d lines | %s | %s ", cpos.mLine + 1, cpos.mColumn + 1, mEditor.GetTotalLines(),
|
||||||
mEditor.IsOverwrite() ? "Ovr" : "Ins",
|
mEditor.IsOverwrite() ? "Ovr" : "Ins",
|
||||||
mEditor.CanUndo() ? "*" : " ",
|
mEditor.CanUndo() ? "*" : " ");
|
||||||
mEditor.GetLanguageDefinition().mName.c_str(), mFileToEdit.c_str());
|
|
||||||
|
|
||||||
mEditor.Render("TextEditor");
|
mEditor.Render("TextEditor");
|
||||||
WindowBase::EndDraw();
|
WindowBase::EndDraw();
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,12 @@ public:
|
||||||
virtual void Draw() override;
|
virtual void Draw() override;
|
||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
|
|
||||||
|
void SetScript(const std::string &txt);
|
||||||
|
void ClearErrors();
|
||||||
|
void AddError(int line, const std::string &text);
|
||||||
private:
|
private:
|
||||||
TextEditor mEditor;
|
TextEditor mEditor;
|
||||||
std::string mFileToEdit;
|
TextEditor::Breakpoints m_breakPoints;
|
||||||
|
TextEditor::ErrorMarkers m_markers;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
17
story-editor/src/connection.cpp
Normal file
17
story-editor/src/connection.cpp
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include "connection.h"
|
||||||
|
|
||||||
|
void to_json(nlohmann::json &j, const Connection &p) {
|
||||||
|
j = nlohmann::json{
|
||||||
|
{"outNodeId", static_cast<int64_t>(p.outNodeId)},
|
||||||
|
{"outPortIndex", static_cast<int64_t>(p.outPortIndex)},
|
||||||
|
{"inNodeId", static_cast<int64_t>(p.inNodeId)},
|
||||||
|
{"inPortIndex", static_cast<int64_t>(p.inPortIndex)},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void from_json(const nlohmann::json &j, Connection &p) {
|
||||||
|
j.at("outNodeId").get_to(p.outNodeId);
|
||||||
|
j.at("outPortIndex").get_to(p.outPortIndex);
|
||||||
|
j.at("inNodeId").get_to(p.inNodeId);
|
||||||
|
j.at("inPortIndex").get_to(p.inPortIndex);
|
||||||
|
}
|
||||||
53
story-editor/src/connection.h
Normal file
53
story-editor/src/connection.h
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include "json.hpp"
|
||||||
|
|
||||||
|
struct Connection
|
||||||
|
{
|
||||||
|
Connection()
|
||||||
|
: outNodeId(0)
|
||||||
|
, outPortIndex(0)
|
||||||
|
, inNodeId(0)
|
||||||
|
, inPortIndex(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
unsigned int outNodeId{0};
|
||||||
|
unsigned int outPortIndex{0};
|
||||||
|
unsigned int inNodeId{0};
|
||||||
|
unsigned int inPortIndex{0};
|
||||||
|
|
||||||
|
Connection& operator=(const Connection& other) {
|
||||||
|
this->outNodeId = other.outNodeId;
|
||||||
|
this->outPortIndex = other.outPortIndex;
|
||||||
|
this->inNodeId = other.inNodeId;
|
||||||
|
this->inPortIndex = other.inPortIndex;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool operator==(Connection const &a, Connection const &b)
|
||||||
|
{
|
||||||
|
return a.outNodeId == b.outNodeId && a.outPortIndex == b.outPortIndex
|
||||||
|
&& a.inNodeId == b.inNodeId && a.inPortIndex == b.inPortIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(Connection const &a, Connection const &b)
|
||||||
|
{
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void invertConnection(Connection &id)
|
||||||
|
{
|
||||||
|
std::swap(id.outNodeId, id.inNodeId);
|
||||||
|
std::swap(id.outPortIndex, id.inPortIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void to_json(nlohmann::json& j, const Connection& p);
|
||||||
|
|
||||||
|
void from_json(const nlohmann::json& j, Connection& p);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -8,13 +8,7 @@ ConsoleWindow::ConsoleWindow()
|
||||||
{
|
{
|
||||||
ClearLog();
|
ClearLog();
|
||||||
memset(InputBuf, 0, sizeof(InputBuf));
|
memset(InputBuf, 0, sizeof(InputBuf));
|
||||||
HistoryPos = -1;
|
|
||||||
|
|
||||||
// "CLASSIFY" is here to provide the test case where "C"+[tab] completes to "CL" and display multiple matches.
|
|
||||||
Commands.push_back("HELP");
|
|
||||||
Commands.push_back("HISTORY");
|
|
||||||
Commands.push_back("CLEAR");
|
|
||||||
Commands.push_back("CLASSIFY");
|
|
||||||
AutoScroll = true;
|
AutoScroll = true;
|
||||||
ScrollToBottom = false;
|
ScrollToBottom = false;
|
||||||
}
|
}
|
||||||
|
|
@ -22,8 +16,6 @@ ConsoleWindow::ConsoleWindow()
|
||||||
ConsoleWindow::~ConsoleWindow()
|
ConsoleWindow::~ConsoleWindow()
|
||||||
{
|
{
|
||||||
ClearLog();
|
ClearLog();
|
||||||
for (int i = 0; i < History.Size; i++)
|
|
||||||
free(History[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConsoleWindow::ClearLog()
|
void ConsoleWindow::ClearLog()
|
||||||
|
|
@ -113,7 +105,16 @@ void ConsoleWindow::Draw()
|
||||||
{
|
{
|
||||||
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
|
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
|
||||||
{
|
{
|
||||||
ImGui::TextUnformatted(Items[i].c_str());
|
if (Items[i].type > 0)
|
||||||
|
{
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255,0,0,255));
|
||||||
|
}
|
||||||
|
ImGui::TextUnformatted(Items[i].text.c_str());
|
||||||
|
|
||||||
|
if (Items[i].type > 0)
|
||||||
|
{
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
@ -168,151 +169,3 @@ void ConsoleWindow::Draw()
|
||||||
WindowBase::EndDraw();
|
WindowBase::EndDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConsoleWindow::ExecCommand(const char *command_line)
|
|
||||||
{
|
|
||||||
AddLog("# %s\n", command_line);
|
|
||||||
|
|
||||||
// Insert into history. First find match and delete it so it can be pushed to the back.
|
|
||||||
// This isn't trying to be smart or optimal.
|
|
||||||
HistoryPos = -1;
|
|
||||||
for (int i = History.Size - 1; i >= 0; i--)
|
|
||||||
if (Stricmp(History[i], command_line) == 0)
|
|
||||||
{
|
|
||||||
free(History[i]);
|
|
||||||
History.erase(History.begin() + i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
History.push_back(Strdup(command_line));
|
|
||||||
|
|
||||||
// Process command
|
|
||||||
if (Stricmp(command_line, "CLEAR") == 0)
|
|
||||||
{
|
|
||||||
ClearLog();
|
|
||||||
}
|
|
||||||
else if (Stricmp(command_line, "HELP") == 0)
|
|
||||||
{
|
|
||||||
AddLog("Commands:");
|
|
||||||
for (int i = 0; i < Commands.Size; i++)
|
|
||||||
AddLog("- %s", Commands[i]);
|
|
||||||
}
|
|
||||||
else if (Stricmp(command_line, "HISTORY") == 0)
|
|
||||||
{
|
|
||||||
int first = History.Size - 10;
|
|
||||||
for (int i = first > 0 ? first : 0; i < History.Size; i++)
|
|
||||||
AddLog("%3d: %s\n", i, History[i]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddLog("Unknown command: '%s'\n", command_line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// On command input, we scroll to bottom even if AutoScroll==false
|
|
||||||
ScrollToBottom = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ConsoleWindow::TextEditCallbackStub(ImGuiInputTextCallbackData *data)
|
|
||||||
{
|
|
||||||
ConsoleWindow* console = (ConsoleWindow*)data->UserData;
|
|
||||||
return console->TextEditCallback(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ConsoleWindow::TextEditCallback(ImGuiInputTextCallbackData *data)
|
|
||||||
{
|
|
||||||
//AddLog("cursor: %d, selection: %d-%d", data->CursorPos, data->SelectionStart, data->SelectionEnd);
|
|
||||||
switch (data->EventFlag)
|
|
||||||
{
|
|
||||||
case ImGuiInputTextFlags_CallbackCompletion:
|
|
||||||
{
|
|
||||||
// Example of TEXT COMPLETION
|
|
||||||
|
|
||||||
// Locate beginning of current word
|
|
||||||
const char* word_end = data->Buf + data->CursorPos;
|
|
||||||
const char* word_start = word_end;
|
|
||||||
while (word_start > data->Buf)
|
|
||||||
{
|
|
||||||
const char c = word_start[-1];
|
|
||||||
if (c == ' ' || c == '\t' || c == ',' || c == ';')
|
|
||||||
break;
|
|
||||||
word_start--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build a list of candidates
|
|
||||||
ImVector<const char*> candidates;
|
|
||||||
for (int i = 0; i < Commands.Size; i++)
|
|
||||||
if (Strnicmp(Commands[i], word_start, (int)(word_end - word_start)) == 0)
|
|
||||||
candidates.push_back(Commands[i]);
|
|
||||||
|
|
||||||
if (candidates.Size == 0)
|
|
||||||
{
|
|
||||||
// No match
|
|
||||||
AddLog("No match for \"%.*s\"!\n", (int)(word_end - word_start), word_start);
|
|
||||||
}
|
|
||||||
else if (candidates.Size == 1)
|
|
||||||
{
|
|
||||||
// Single match. Delete the beginning of the word and replace it entirely so we've got nice casing.
|
|
||||||
data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
|
|
||||||
data->InsertChars(data->CursorPos, candidates[0]);
|
|
||||||
data->InsertChars(data->CursorPos, " ");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Multiple matches. Complete as much as we can..
|
|
||||||
// So inputing "C"+Tab will complete to "CL" then display "CLEAR" and "CLASSIFY" as matches.
|
|
||||||
int match_len = (int)(word_end - word_start);
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
int c = 0;
|
|
||||||
bool all_candidates_matches = true;
|
|
||||||
for (int i = 0; i < candidates.Size && all_candidates_matches; i++)
|
|
||||||
if (i == 0)
|
|
||||||
c = toupper(candidates[i][match_len]);
|
|
||||||
else if (c == 0 || c != toupper(candidates[i][match_len]))
|
|
||||||
all_candidates_matches = false;
|
|
||||||
if (!all_candidates_matches)
|
|
||||||
break;
|
|
||||||
match_len++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match_len > 0)
|
|
||||||
{
|
|
||||||
data->DeleteChars((int)(word_start - data->Buf), (int)(word_end - word_start));
|
|
||||||
data->InsertChars(data->CursorPos, candidates[0], candidates[0] + match_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// List matches
|
|
||||||
AddLog("Possible matches:\n");
|
|
||||||
for (int i = 0; i < candidates.Size; i++)
|
|
||||||
AddLog("- %s\n", candidates[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ImGuiInputTextFlags_CallbackHistory:
|
|
||||||
{
|
|
||||||
// Example of HISTORY
|
|
||||||
const int prev_history_pos = HistoryPos;
|
|
||||||
if (data->EventKey == ImGuiKey_UpArrow)
|
|
||||||
{
|
|
||||||
if (HistoryPos == -1)
|
|
||||||
HistoryPos = History.Size - 1;
|
|
||||||
else if (HistoryPos > 0)
|
|
||||||
HistoryPos--;
|
|
||||||
}
|
|
||||||
else if (data->EventKey == ImGuiKey_DownArrow)
|
|
||||||
{
|
|
||||||
if (HistoryPos != -1)
|
|
||||||
if (++HistoryPos >= History.Size)
|
|
||||||
HistoryPos = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A better implementation would preserve the data on the current input line along with cursor position.
|
|
||||||
if (prev_history_pos != HistoryPos)
|
|
||||||
{
|
|
||||||
const char* history_str = (HistoryPos >= 0) ? History[HistoryPos] : "";
|
|
||||||
data->DeleteChars(0, data->BufTextLen);
|
|
||||||
data->InsertChars(0, history_str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -25,42 +25,34 @@ public:
|
||||||
|
|
||||||
void ClearLog();
|
void ClearLog();
|
||||||
|
|
||||||
void AddMessage(const std::string &message) { AddLog("%s", message.c_str()); }
|
void AddLog(const std::string &text, uint32_t type)
|
||||||
|
|
||||||
virtual void Draw() override;
|
|
||||||
|
|
||||||
void ExecCommand(const char* command_line);
|
|
||||||
|
|
||||||
// In C++11 you'd be better off using lambdas for this sort of forwarding callbacks
|
|
||||||
static int TextEditCallbackStub(ImGuiInputTextCallbackData* data);
|
|
||||||
|
|
||||||
int TextEditCallback(ImGuiInputTextCallbackData* data);
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
void AddLog(const char* fmt, ...) IM_FMTARGS(2)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
// FIXME-OPT
|
// FIXME-OPT
|
||||||
char buf[1024];
|
Entry e{text, type};
|
||||||
va_list args;
|
|
||||||
va_start(args, fmt);
|
|
||||||
vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
|
|
||||||
buf[IM_ARRAYSIZE(buf)-1] = 0;
|
|
||||||
va_end(args);
|
|
||||||
std::scoped_lock<std::mutex> mutex(mLogMutex);
|
std::scoped_lock<std::mutex> mutex(mLogMutex);
|
||||||
Items.push_back(Strdup(buf));
|
Items.push_back(e);
|
||||||
if (Items.size() > 100)
|
if (Items.size() > 100)
|
||||||
{
|
{
|
||||||
Items.erase(Items.begin());
|
Items.erase(Items.begin());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void Draw() override;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct Entry {
|
||||||
|
std::string text;
|
||||||
|
uint32_t type;
|
||||||
|
};
|
||||||
|
|
||||||
std::mutex mLogMutex;
|
std::mutex mLogMutex;
|
||||||
char InputBuf[256];
|
char InputBuf[256];
|
||||||
std::vector<std::string> Items;
|
std::vector<Entry> Items;
|
||||||
ImVector<const char*> Commands;
|
|
||||||
ImVector<char*> History;
|
|
||||||
int HistoryPos; // -1: new line, 0..History.Size-1 browsing history.
|
|
||||||
ImGuiTextFilter Filter;
|
ImGuiTextFilter Filter;
|
||||||
bool AutoScroll;
|
bool AutoScroll;
|
||||||
bool ScrollToBottom;
|
bool ScrollToBottom;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
#include "emulator_window.h"
|
#include "emulator_window.h"
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
#include "IconsMaterialDesignIcons.h"
|
||||||
|
|
||||||
EmulatorWindow::EmulatorWindow()
|
EmulatorWindow::EmulatorWindow(IStoryProject &proj)
|
||||||
: WindowBase("Emulator")
|
: WindowBase("Emulator")
|
||||||
|
, m_project(proj)
|
||||||
{
|
{
|
||||||
|
|
||||||
Gui::LoadRawImage("assets/play.png", m_playImage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmulatorWindow::Initialize() {
|
void EmulatorWindow::Initialize()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
int my_image_width = 0;
|
|
||||||
int my_image_height = 0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,8 +34,32 @@ void EmulatorWindow::Draw()
|
||||||
ImVec2 p = ImGui::GetCursorScreenPos();
|
ImVec2 p = ImGui::GetCursorScreenPos();
|
||||||
ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 320, p.y + 240), ImGui::GetColorU32(ImVec4(1.0, 1.0, 1.0, 1.0)));
|
ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 320, p.y + 240), ImGui::GetColorU32(ImVec4(1.0, 1.0, 1.0, 1.0)));
|
||||||
|
|
||||||
ImGui::SetCursorScreenPos(ImVec2(p.x, p.y + 240));
|
ImGui::SetCursorScreenPos(ImVec2(p.x, p.y + 244));
|
||||||
ImGui::ImageButton("play", m_playImage.texture, ImVec2(45, 45));
|
|
||||||
|
float old_size = ImGui::GetFont()->Scale;
|
||||||
|
ImGui::GetFont()->Scale *= 2;
|
||||||
|
|
||||||
|
ImGui::PushFont(ImGui::GetFont());
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::Button(ICON_MDI_PLAY_CIRCLE_OUTLINE, ImVec2(50, 50));
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Button(ICON_MDI_STOP_CIRCLE_OUTLINE, ImVec2(50, 50));
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Button(ICON_MDI_ARROW_LEFT_BOLD_CIRCLE_OUTLINE, ImVec2(50, 50));
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Button(ICON_MDI_ARROW_RIGHT_BOLD_CIRCLE_OUTLINE, ImVec2(50, 50));
|
||||||
|
|
||||||
|
ImGui::GetFont()->Scale = old_size;
|
||||||
|
ImGui::PopFont();
|
||||||
|
|
||||||
|
ImGui::SeparatorText("Script control and debug");
|
||||||
|
|
||||||
|
if (ImGui::Button("Build"))
|
||||||
|
{
|
||||||
|
m_project.Build();
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
WindowBase::EndDraw();
|
WindowBase::EndDraw();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "window_base.h"
|
#include "window_base.h"
|
||||||
#include "gui.h"
|
#include "i_story_project.h"
|
||||||
|
|
||||||
class EmulatorWindow : public WindowBase
|
class EmulatorWindow : public WindowBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EmulatorWindow();
|
EmulatorWindow(IStoryProject &proj);
|
||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
virtual void Draw() override;
|
virtual void Draw() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Gui::Image m_playImage;
|
IStoryProject &m_project;
|
||||||
Gui::Image m_pauseImage;
|
|
||||||
Gui::Image m_homeImage;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,17 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
|
#include "connection.h"
|
||||||
|
|
||||||
class IStoryProject
|
class IStoryProject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IStoryProject() {}
|
virtual ~IStoryProject() {}
|
||||||
|
|
||||||
|
virtual void Log(const std::string &txt, bool critical = false) = 0;
|
||||||
virtual void PlaySoundFile(const std::string &fileName) = 0;
|
virtual void PlaySoundFile(const std::string &fileName) = 0;
|
||||||
virtual std::string BuildFullAssetsPath(const std::string &fileName) const = 0;
|
virtual std::string BuildFullAssetsPath(const std::string &fileName) const = 0;
|
||||||
|
|
||||||
|
|
@ -22,7 +25,12 @@ public:
|
||||||
virtual std::pair<FilterIterator, FilterIterator> Resources() = 0;
|
virtual std::pair<FilterIterator, FilterIterator> Resources() = 0;
|
||||||
virtual void AddResource(std::shared_ptr<Resource> res) = 0;
|
virtual void AddResource(std::shared_ptr<Resource> res) = 0;
|
||||||
virtual void ClearResources() = 0;
|
virtual void ClearResources() = 0;
|
||||||
|
virtual void DeleteResource(FilterIterator &it) = 0;
|
||||||
|
|
||||||
|
// Node interaction
|
||||||
|
virtual void Build() = 0;
|
||||||
|
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(unsigned long nodeId) = 0;
|
||||||
|
virtual std::string GetNodeEntryLabel(unsigned long nodeId) = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,10 @@
|
||||||
#include "ImGuiFileDialog.h"
|
#include "ImGuiFileDialog.h"
|
||||||
|
|
||||||
MainWindow::MainWindow()
|
MainWindow::MainWindow()
|
||||||
: m_resourcesWindow(*this)
|
: m_emulatorWindow(*this)
|
||||||
|
, m_resourcesWindow(*this)
|
||||||
, m_nodeEditorWindow(*this)
|
, m_nodeEditorWindow(*this)
|
||||||
|
|
||||||
{
|
{
|
||||||
m_project.Clear();
|
m_project.Clear();
|
||||||
}
|
}
|
||||||
|
|
@ -168,109 +170,15 @@ void MainWindow::Initialize()
|
||||||
gui.Initialize();
|
gui.Initialize();
|
||||||
// gui.ApplyTheme();
|
// gui.ApplyTheme();
|
||||||
|
|
||||||
editor.Initialize();
|
m_editor.Initialize();
|
||||||
m_emulatorWindow.Initialize();
|
m_emulatorWindow.Initialize();
|
||||||
m_nodeEditorWindow.Initialize();
|
m_nodeEditorWindow.Initialize();
|
||||||
m_nodePropertiesWindow.Initialize();
|
m_PropertiesWindow.Initialize();
|
||||||
|
|
||||||
LoadParams();
|
LoadParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MainWindow::ShowOptionsWindow()
|
|
||||||
{
|
|
||||||
static int pingState = 0;
|
|
||||||
|
|
||||||
// Always center this window when appearing
|
|
||||||
ImVec2 center = ImGui::GetMainViewport()->GetCenter();
|
|
||||||
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
|
|
||||||
ImGui::SetNextWindowSize(ImVec2(600, 0.0f));
|
|
||||||
if (ImGui::BeginPopupModal("Options", NULL, ImGuiWindowFlags_AlwaysAutoResize))
|
|
||||||
{
|
|
||||||
ImGui::PushItemWidth(-1.0f);
|
|
||||||
|
|
||||||
ImGui::Text("Adresse du serveur");
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::InputText("##addr", mBufAddress, sizeof(mBufAddress));
|
|
||||||
|
|
||||||
ImGui::Text("Chemin de récupération");
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::InputText("##rec_path", mBufReceivePath, sizeof(mBufReceivePath));
|
|
||||||
|
|
||||||
ImGui::Text("Chemin d'envoi des données");
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::InputText("##send_path", mBufSendPath, sizeof(mBufSendPath));
|
|
||||||
|
|
||||||
ImGui::PushItemWidth(100);
|
|
||||||
ImGui::Text("Port");
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::InputText("##port", mBufPort, sizeof(mBufPort), ImGuiInputTextFlags_CharsDecimal);
|
|
||||||
|
|
||||||
float width = 50;
|
|
||||||
ImGui::BeginGroup();
|
|
||||||
ImGui::PushID("Zebra7500");
|
|
||||||
ImGui::TextUnformatted("Adresse IP Zebra7500");
|
|
||||||
ImGui::SameLine();
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
ImGui::PushItemWidth(width);
|
|
||||||
ImGui::PushID(i);
|
|
||||||
bool invalid_octet = false;
|
|
||||||
if (octets[i] > 255) {
|
|
||||||
// Make values over 255 red, and when focus is lost reset it to 255.
|
|
||||||
octets[i] = 255;
|
|
||||||
invalid_octet = true;
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
|
|
||||||
}
|
|
||||||
if (octets[i] < 0) {
|
|
||||||
// Make values below 0 yellow, and when focus is lost reset it to 0.
|
|
||||||
octets[i] = 0;
|
|
||||||
invalid_octet = true;
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.0f, 1.0f));
|
|
||||||
}
|
|
||||||
ImGui::InputInt("##v", &octets[i], 0, 0, ImGuiInputTextFlags_CharsDecimal);
|
|
||||||
if (invalid_octet) {
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::PopID();
|
|
||||||
ImGui::PopItemWidth();
|
|
||||||
}
|
|
||||||
ImGui::PopID();
|
|
||||||
ImGui::EndGroup();
|
|
||||||
|
|
||||||
// Example action button and way to build the IP string
|
|
||||||
ImGui::SameLine();
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (pingState == 1)
|
|
||||||
{
|
|
||||||
ImGui::TextUnformatted("Ping en cours...");
|
|
||||||
}
|
|
||||||
else if (pingState == 2)
|
|
||||||
{
|
|
||||||
ImGui::TextUnformatted("Ping succès!");
|
|
||||||
}
|
|
||||||
else if (pingState == 3)
|
|
||||||
{
|
|
||||||
ImGui::TextUnformatted("Ping erreur :(");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ImGui::TextUnformatted("");
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
|
|
||||||
ImGui::SetItemDefaultFocus();
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Cancel", ImVec2(120, 0)))
|
|
||||||
{
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MainWindow::ShowQuitConfirm()
|
bool MainWindow::ShowQuitConfirm()
|
||||||
{
|
{
|
||||||
|
|
@ -319,13 +227,13 @@ void MainWindow::OpenProjectDialog()
|
||||||
|
|
||||||
if (m_project.Load(filePathName, model, m_resources))
|
if (m_project.Load(filePathName, model, m_resources))
|
||||||
{
|
{
|
||||||
m_consoleWindow.AddMessage("Open project success");
|
Log("Open project success");
|
||||||
m_nodeEditorWindow.Load(model);
|
m_nodeEditorWindow.Load(model);
|
||||||
EnableProject();
|
EnableProject();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_consoleWindow.AddMessage("Open project error");
|
Log("Open project error");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -600,14 +508,12 @@ void MainWindow::Loop()
|
||||||
// ------------ Draw all windows
|
// ------------ Draw all windows
|
||||||
m_consoleWindow.Draw();
|
m_consoleWindow.Draw();
|
||||||
m_emulatorWindow.Draw();
|
m_emulatorWindow.Draw();
|
||||||
editor.Draw();
|
m_editor.Draw();
|
||||||
m_resourcesWindow.Draw();
|
m_resourcesWindow.Draw();
|
||||||
m_nodeEditorWindow.Draw();
|
m_nodeEditorWindow.Draw();
|
||||||
|
|
||||||
m_nodePropertiesWindow.SetSelectedNode(m_nodeEditorWindow.GetSelectedNode());
|
m_PropertiesWindow.SetSelectedNode(m_nodeEditorWindow.GetSelectedNode());
|
||||||
m_nodePropertiesWindow.Draw();
|
m_PropertiesWindow.Draw();
|
||||||
|
|
||||||
ShowOptionsWindow();
|
|
||||||
|
|
||||||
NewProjectPopup();
|
NewProjectPopup();
|
||||||
OpenProjectDialog();
|
OpenProjectDialog();
|
||||||
|
|
@ -629,9 +535,14 @@ void MainWindow::Loop()
|
||||||
gui.Destroy();
|
gui.Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::Log(const std::string &txt, bool critical)
|
||||||
|
{
|
||||||
|
m_consoleWindow.AddLog(txt, critical ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::PlaySoundFile(const std::string &fileName)
|
void MainWindow::PlaySoundFile(const std::string &fileName)
|
||||||
{
|
{
|
||||||
m_consoleWindow.AddMessage("Play sound file: " + fileName);
|
Log("Play sound file: " + fileName);
|
||||||
m_project.PlaySoundFile(fileName);
|
m_project.PlaySoundFile(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -665,6 +576,112 @@ std::pair<FilterIterator, FilterIterator> MainWindow::Resources()
|
||||||
return m_resources.Items();
|
return m_resources.Items();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::DeleteResource(FilterIterator &it)
|
||||||
|
{
|
||||||
|
return m_resources.Delete(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::Build()
|
||||||
|
{
|
||||||
|
// 1. First compile nodes to assembly
|
||||||
|
CompileToAssembler();
|
||||||
|
|
||||||
|
// 2. Compile the assembly to machine binary
|
||||||
|
GenerateBinary();
|
||||||
|
|
||||||
|
// 3. Convert all media to desired type format
|
||||||
|
ConvertResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MainWindow::GetNodeEntryLabel(unsigned long nodeId)
|
||||||
|
{
|
||||||
|
return m_nodeEditorWindow.GetNodeEntryLabel(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<std::shared_ptr<Connection>> MainWindow::GetNodeConnections(unsigned long nodeId)
|
||||||
|
{
|
||||||
|
return m_nodeEditorWindow.GetNodeConnections(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::CompileToAssembler()
|
||||||
|
{
|
||||||
|
// 1. Check if the model can be compiled, check for errors and report
|
||||||
|
// FIXME
|
||||||
|
|
||||||
|
// 2. Generate the assembly code from the model
|
||||||
|
m_currentCode = m_nodeEditorWindow.Build();
|
||||||
|
|
||||||
|
// Add global functions
|
||||||
|
{
|
||||||
|
std::string buffer;
|
||||||
|
|
||||||
|
std::ifstream f("scripts/media.asm");
|
||||||
|
f.seekg(0, std::ios::end);
|
||||||
|
buffer.resize(f.tellg());
|
||||||
|
f.seekg(0);
|
||||||
|
f.read(buffer.data(), buffer.size());
|
||||||
|
m_currentCode += buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_editor.SetScript(m_currentCode);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::GenerateBinary()
|
||||||
|
{
|
||||||
|
m_dbg.run_result = VM_FINISHED;
|
||||||
|
m_dbg.free_run = false;
|
||||||
|
|
||||||
|
if (m_assembler.Parse(m_currentCode) == true )
|
||||||
|
{
|
||||||
|
if (m_assembler.BuildBinary(m_program, m_result) == true)
|
||||||
|
{
|
||||||
|
m_result.Print();
|
||||||
|
|
||||||
|
Log("Binary successfully generated.");
|
||||||
|
|
||||||
|
// Update ROM memory
|
||||||
|
std::copy(m_program.begin(), m_program.end(), m_rom_data);
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
// m_ramView->SetMemory(m_ram_data, sizeof(m_ram_data));
|
||||||
|
// m_romView->SetMemory(m_rom_data, m_program.size());
|
||||||
|
m_project.SaveStory(m_program);
|
||||||
|
chip32_initialize(&m_chip32_ctx);
|
||||||
|
m_dbg.run_result = VM_OK;
|
||||||
|
UpdateVmView();
|
||||||
|
// DebugContext::DumpCodeAssembler(m_assembler);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Chip32::Assembler::Error err = m_assembler.GetLastError();
|
||||||
|
Log(err.ToString(), true);
|
||||||
|
m_editor.AddError(err.line, err.message); // show also the error in the code editor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Chip32::Assembler::Error err = m_assembler.GetLastError();
|
||||||
|
Log(err.ToString(), true);
|
||||||
|
m_editor.AddError(err.line, err.message); // show also the error in the code editor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::UpdateVmView()
|
||||||
|
{
|
||||||
|
// FIXME
|
||||||
|
// m_vmDock->updateRegistersView(m_chip32_ctx);
|
||||||
|
// highlightNextLine();
|
||||||
|
// Refresh RAM content
|
||||||
|
// m_ramView->SetMemory(m_ram_data, m_chip32_ctx.ram.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::ConvertResources()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::SaveParams()
|
void MainWindow::SaveParams()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
#include "emulator_window.h"
|
#include "emulator_window.h"
|
||||||
#include "resources_window.h"
|
#include "resources_window.h"
|
||||||
#include "node_editor_window.h"
|
#include "node_editor_window.h"
|
||||||
#include "node_properties_window.h"
|
#include "properties_window.h"
|
||||||
|
|
||||||
#include "chip32_assembler.h"
|
#include "chip32_assembler.h"
|
||||||
#include "chip32_vm.h"
|
#include "chip32_vm.h"
|
||||||
|
|
@ -92,7 +92,8 @@ private:
|
||||||
std::vector<uint8_t> m_program;
|
std::vector<uint8_t> m_program;
|
||||||
Chip32::Assembler m_assembler;
|
Chip32::Assembler m_assembler;
|
||||||
Chip32::Result m_result;
|
Chip32::Result m_result;
|
||||||
// DebugContext m_dbg;
|
DebugContext m_dbg;
|
||||||
|
std::string m_currentCode;
|
||||||
|
|
||||||
std::vector<std::string> m_recentProjects;
|
std::vector<std::string> m_recentProjects;
|
||||||
|
|
||||||
|
|
@ -101,29 +102,17 @@ private:
|
||||||
Gui gui;
|
Gui gui;
|
||||||
EmulatorWindow m_emulatorWindow;
|
EmulatorWindow m_emulatorWindow;
|
||||||
ConsoleWindow m_consoleWindow;
|
ConsoleWindow m_consoleWindow;
|
||||||
CodeEditor editor;
|
CodeEditor m_editor;
|
||||||
|
|
||||||
ResourcesWindow m_resourcesWindow;
|
ResourcesWindow m_resourcesWindow;
|
||||||
|
|
||||||
NodeEditorWindow m_nodeEditorWindow;
|
NodeEditorWindow m_nodeEditorWindow;
|
||||||
|
|
||||||
NodePropertiesWindow m_nodePropertiesWindow;
|
PropertiesWindow m_PropertiesWindow;
|
||||||
|
|
||||||
|
|
||||||
char mBufAddress[200];
|
|
||||||
char mBufReceivePath[200];
|
|
||||||
char mBufSendPath[200];
|
|
||||||
char mBufPort[10];
|
|
||||||
|
|
||||||
int octets[4];
|
|
||||||
|
|
||||||
std::string mServerAddr;
|
|
||||||
std::string mServerRecUrl;
|
|
||||||
std::string mServerSndUrl;
|
|
||||||
int mServerPort;
|
|
||||||
|
|
||||||
|
|
||||||
// From IStoryProject (proxy to StoryProject class)
|
// From IStoryProject (proxy to StoryProject class)
|
||||||
|
virtual void Log(const std::string &txt, bool critical = false) override;
|
||||||
virtual void PlaySoundFile(const std::string &fileName) override;;
|
virtual void PlaySoundFile(const std::string &fileName) override;;
|
||||||
virtual std::string BuildFullAssetsPath(const std::string &fileName) const override;
|
virtual std::string BuildFullAssetsPath(const std::string &fileName) const override;
|
||||||
virtual std::pair<FilterIterator, FilterIterator> Images() override;
|
virtual std::pair<FilterIterator, FilterIterator> Images() override;
|
||||||
|
|
@ -132,13 +121,15 @@ private:
|
||||||
virtual void AddResource(std::shared_ptr<Resource> res) override;
|
virtual void AddResource(std::shared_ptr<Resource> res) override;
|
||||||
virtual void ClearResources() override;
|
virtual void ClearResources() override;
|
||||||
virtual std::pair<FilterIterator, FilterIterator> Resources() override;
|
virtual std::pair<FilterIterator, FilterIterator> Resources() override;
|
||||||
|
virtual void DeleteResource(FilterIterator &it) override;
|
||||||
|
virtual void Build() override;
|
||||||
|
virtual std::list<std::shared_ptr<Connection>> GetNodeConnections(unsigned long nodeId) override;
|
||||||
|
virtual std::string GetNodeEntryLabel(unsigned long nodeId) override;
|
||||||
|
|
||||||
void SaveParams();
|
void SaveParams();
|
||||||
void LoadParams();
|
void LoadParams();
|
||||||
|
|
||||||
void DrawMainMenuBar();
|
void DrawMainMenuBar();
|
||||||
void ShowOptionsWindow();
|
|
||||||
bool ShowQuitConfirm();
|
bool ShowQuitConfirm();
|
||||||
|
|
||||||
void NewProjectPopup();
|
void NewProjectPopup();
|
||||||
|
|
@ -147,6 +138,11 @@ private:
|
||||||
void CloseProject();
|
void CloseProject();
|
||||||
void OpenProjectDialog();
|
void OpenProjectDialog();
|
||||||
void DrawStatusBar();
|
void DrawStatusBar();
|
||||||
|
|
||||||
|
bool CompileToAssembler();
|
||||||
|
void ConvertResources();
|
||||||
|
void GenerateBinary();
|
||||||
|
void UpdateVmView();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace ed = ax::NodeEditor;
|
namespace ed = ax::NodeEditor;
|
||||||
#include "IconsMaterialDesignIcons.h"
|
#include "IconsMaterialDesignIcons.h"
|
||||||
|
#include "story_project.h"
|
||||||
|
|
||||||
MediaNode::MediaNode(const std::string &title, IStoryProject &proj)
|
MediaNode::MediaNode(const std::string &title, IStoryProject &proj)
|
||||||
: BaseNode(title, proj)
|
: BaseNode(title, proj)
|
||||||
|
|
@ -128,6 +128,11 @@ void MediaNode::DrawProperties()
|
||||||
ImGui::OpenPopup("popup_button");
|
ImGui::OpenPopup("popup_button");
|
||||||
isImage = true;
|
isImage = true;
|
||||||
}
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button(ICON_MDI_CLOSE_BOX_OUTLINE "##delimage")) {
|
||||||
|
SetImage("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
ImGui::Text("Sound");
|
ImGui::Text("Sound");
|
||||||
|
|
@ -149,6 +154,11 @@ void MediaNode::DrawProperties()
|
||||||
isImage = false;
|
isImage = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button(ICON_MDI_CLOSE_BOX_OUTLINE "##delsound")) {
|
||||||
|
SetSound("");
|
||||||
|
}
|
||||||
|
|
||||||
// This is the actual popup Gui drawing section.
|
// This is the actual popup Gui drawing section.
|
||||||
if (ImGui::BeginPopup("popup_button")) {
|
if (ImGui::BeginPopup("popup_button")) {
|
||||||
ImGui::SeparatorText(isImage ? "Images" : "Sounds");
|
ImGui::SeparatorText(isImage ? "Images" : "Sounds");
|
||||||
|
|
@ -189,38 +199,36 @@ void MediaNode::SetSound(const std::string &f)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
std::string NodeEditorWindow::ChoiceLabel() const
|
std::string MediaNode::ChoiceLabel() const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "mediaChoice" << std::setw(4) << std::setfill('0') << GetId();
|
ss << "mediaChoice" << std::setw(4) << std::setfill('0') << GetId();
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string NodeEditorWindow::EntryLabel() const
|
std::string MediaNode::GetEntryLabel()
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << ".mediaEntry" << std::setw(4) << std::setfill('0') << getNodeId();
|
ss << ".mediaEntry" << std::setw(4) << std::setfill('0') << GetId();
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string NodeEditorWindow::GenerateConstants()
|
std::string MediaNode::GenerateConstants()
|
||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
|
|
||||||
std::string image = m_mediaData["image"].get<std::string>();
|
if (m_image.name.size() > 0)
|
||||||
std::string sound = m_mediaData["sound"].get<std::string>();
|
|
||||||
if (image.size() > 0)
|
|
||||||
{
|
{
|
||||||
s = StoryProject::FileToConstant(image, ".qoi"); // FIXME: Generate the extension setup in user option of output format
|
s = StoryProject::FileToConstant(m_image.name, ".qoi"); // FIXME: Generate the extension setup in user option of output format
|
||||||
}
|
}
|
||||||
if (sound.size() > 0)
|
if (m_soundName.size() > 0)
|
||||||
{
|
{
|
||||||
s += StoryProject::FileToConstant(sound, ".wav"); // FIXME: Generate the extension setup in user option of output format
|
s += StoryProject::FileToConstant(m_soundName, ".wav"); // FIXME: Generate the extension setup in user option of output format
|
||||||
}
|
}
|
||||||
|
|
||||||
int nb_out_conns = ComputeOutputConnections();
|
int nb_out_conns = Outputs();
|
||||||
if (nb_out_conns > 1)
|
if (nb_out_conns > 1)
|
||||||
{
|
{
|
||||||
// Generate choice table if needed (out ports > 1)
|
// Generate choice table if needed (out ports > 1)
|
||||||
|
|
@ -230,14 +238,14 @@ std::string NodeEditorWindow::GenerateConstants()
|
||||||
<< " DC32, "
|
<< " DC32, "
|
||||||
<< nb_out_conns << ", ";
|
<< nb_out_conns << ", ";
|
||||||
|
|
||||||
std::unordered_set<ConnectionId> conns = m_model.allConnectionIds(getNodeId());
|
std::list<std::shared_ptr<Connection>> conns = m_project.GetNodeConnections(GetId());
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto & c : conns)
|
for (auto & c : conns)
|
||||||
{
|
{
|
||||||
std::stringstream ssChoice;
|
std::stringstream ssChoice;
|
||||||
|
|
||||||
// On va chercher le label d'entrée du noeud connecté à l'autre bout
|
// On va chercher le label d'entrée du noeud connecté à l'autre bout
|
||||||
ss << m_model.GetNodeEntryLabel(c.inNodeId);
|
ss << m_project.GetNodeEntryLabel(c->inNodeId);
|
||||||
if (i < (nb_out_conns - 1))
|
if (i < (nb_out_conns - 1))
|
||||||
{
|
{
|
||||||
ss << ", ";
|
ss << ", ";
|
||||||
|
|
@ -255,22 +263,22 @@ std::string NodeEditorWindow::GenerateConstants()
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string NodeEditorWindow::Build()
|
std::string MediaNode::Build()
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
int nb_out_conns = ComputeOutputConnections();
|
int nb_out_conns = Outputs();
|
||||||
|
|
||||||
ss << R"(; ---------------------------- )"
|
ss << R"(; ---------------------------- )"
|
||||||
<< GetNodeTitle()
|
<< GetTitle()
|
||||||
<< " Type: "
|
<< " Type: "
|
||||||
<< (nb_out_conns == 0 ? "End" : nb_out_conns == 1 ? "Transition" : "Choice")
|
<< (nb_out_conns == 0 ? "End" : nb_out_conns == 1 ? "Transition" : "Choice")
|
||||||
<< "\n";
|
<< "\n";
|
||||||
std::string image = StoryProject::RemoveFileExtension(m_mediaData["image"].get<std::string>());
|
std::string image = StoryProject::RemoveFileExtension(m_image.name);
|
||||||
std::string sound = StoryProject::RemoveFileExtension(m_mediaData["sound"].get<std::string>());
|
std::string sound = StoryProject::RemoveFileExtension(m_soundName);
|
||||||
|
|
||||||
// Le label de ce noeud est généré de la façon suivante :
|
// Le label de ce noeud est généré de la façon suivante :
|
||||||
// "media" + Node ID + id du noeud parent. Si pas de noeud parent, alors rien
|
// "media" + Node ID + id du noeud parent. Si pas de noeud parent, alors rien
|
||||||
ss << EntryLabel() << ":\n";
|
ss << GetEntryLabel() << ":\n";
|
||||||
|
|
||||||
if (image.size() > 0)
|
if (image.size() > 0)
|
||||||
{
|
{
|
||||||
|
|
@ -301,18 +309,18 @@ std::string NodeEditorWindow::Build()
|
||||||
{
|
{
|
||||||
ss << "halt\n";
|
ss << "halt\n";
|
||||||
}
|
}
|
||||||
else if (nb_out_conns == 1) // Transition node
|
else if (nb_out_conns == 1) // it is a transition node
|
||||||
{
|
{
|
||||||
std::unordered_set<ConnectionId> conns = m_model.allConnectionIds(getNodeId());
|
std::list<std::shared_ptr<Connection>> conns = m_project.GetNodeConnections(GetId());
|
||||||
|
|
||||||
|
|
||||||
for (auto c : conns)
|
for (auto c : conns)
|
||||||
{
|
{
|
||||||
if (c.outNodeId == getNodeId())
|
if (c->outNodeId == GetId())
|
||||||
{
|
{
|
||||||
// On place dans R0 le prochain noeud à exécuter en cas de OK
|
// On place dans R0 le prochain noeud à exécuter en cas de OK
|
||||||
ss << "lcons r0, "
|
ss << "lcons r0, "
|
||||||
<< m_model.GetNodeEntryLabel(c.inNodeId) << "\n"
|
<< m_project.GetNodeEntryLabel(c->inNodeId) << "\n"
|
||||||
<< "ret\n";
|
<< "ret\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -325,4 +333,4 @@ std::string NodeEditorWindow::Build()
|
||||||
}
|
}
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,10 @@ public:
|
||||||
|
|
||||||
virtual void FromJson(const nlohmann::json &j) override;
|
virtual void FromJson(const nlohmann::json &j) override;
|
||||||
virtual void ToJson(nlohmann::json &j) override;
|
virtual void ToJson(nlohmann::json &j) override;
|
||||||
|
|
||||||
virtual void DrawProperties() override;
|
virtual void DrawProperties() override;
|
||||||
|
virtual std::string Build() override;
|
||||||
|
virtual std::string GetEntryLabel() override;
|
||||||
|
virtual std::string GenerateConstants() override;
|
||||||
private:
|
private:
|
||||||
IStoryProject &m_project;
|
IStoryProject &m_project;
|
||||||
Gui::Image m_image;
|
Gui::Image m_image;
|
||||||
|
|
@ -34,4 +35,5 @@ private:
|
||||||
std::string m_buttonUniqueName;
|
std::string m_buttonUniqueName;
|
||||||
void SetImage(const std::string &f);
|
void SetImage(const std::string &f);
|
||||||
void SetSound(const std::string &f);
|
void SetSound(const std::string &f);
|
||||||
|
std::string ChoiceLabel() const;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ void NodeEditorWindow::LoadNode(const nlohmann::json &nodeJson)
|
||||||
n->SetPosition(posJson["x"].get<float>(), posJson["y"].get<float>());
|
n->SetPosition(posJson["x"].get<float>(), posJson["y"].get<float>());
|
||||||
n->FromJson(internalDataJson);
|
n->FromJson(internalDataJson);
|
||||||
|
|
||||||
m_nodes[n->GetInternalId()] = n;
|
m_nodes.push_back(n);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -78,9 +78,9 @@ ed::PinId NodeEditorWindow::GetInputPin(unsigned long modelNodeId, int pinIndex)
|
||||||
|
|
||||||
for (auto & n : m_nodes)
|
for (auto & n : m_nodes)
|
||||||
{
|
{
|
||||||
if (n.second->GetId() == modelNodeId)
|
if (n->GetId() == modelNodeId)
|
||||||
{
|
{
|
||||||
id = n.second->GetInputPinAt(pinIndex);
|
id = n->GetInputPinAt(pinIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,9 +98,9 @@ ed::PinId NodeEditorWindow::GetOutputPin(unsigned long modelNodeId, int pinIndex
|
||||||
|
|
||||||
for (auto & n : m_nodes)
|
for (auto & n : m_nodes)
|
||||||
{
|
{
|
||||||
if (n.second->GetId() == modelNodeId)
|
if (n->GetId() == modelNodeId)
|
||||||
{
|
{
|
||||||
id = n.second->GetOutputPinAt(pinIndex);
|
id = n->GetOutputPinAt(pinIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,13 +133,13 @@ void NodeEditorWindow::Load(const nlohmann::json &model)
|
||||||
auto conn = std::make_shared<LinkInfo>();
|
auto conn = std::make_shared<LinkInfo>();
|
||||||
|
|
||||||
// our model
|
// our model
|
||||||
conn->model = connection.get<Connection>();
|
*conn->model = connection.get<Connection>();
|
||||||
|
|
||||||
|
|
||||||
// ImGui stuff for links
|
// ImGui stuff for links
|
||||||
conn->Id = BaseNode::GetNextId();
|
conn->ed_link->Id = BaseNode::GetNextId();
|
||||||
conn->InputId = GetInputPin(conn->model.inNodeId, conn->model.inPortIndex);
|
conn->ed_link->InputId = GetInputPin(conn->model->inNodeId, conn->model->inPortIndex);
|
||||||
conn->OutputId = GetOutputPin(conn->model.outNodeId, conn->model.outPortIndex);
|
conn->ed_link->OutputId = GetOutputPin(conn->model->outNodeId, conn->model->outPortIndex);
|
||||||
|
|
||||||
// Since we accepted new link, lets add one to our list of links.
|
// Since we accepted new link, lets add one to our list of links.
|
||||||
m_links.push_back(conn);
|
m_links.push_back(conn);
|
||||||
|
|
@ -155,18 +155,18 @@ void NodeEditorWindow::Save(nlohmann::json &model)
|
||||||
for (const auto & n : m_nodes)
|
for (const auto & n : m_nodes)
|
||||||
{
|
{
|
||||||
nlohmann::json node;
|
nlohmann::json node;
|
||||||
node["id"] = n.second->GetId();
|
node["id"] = n->GetId();
|
||||||
node["type"] = n.second->GetType();
|
node["type"] = n->GetType();
|
||||||
node["outPortCount"] = n.second->Outputs();
|
node["outPortCount"] = n->Outputs();
|
||||||
node["inPortCount"] = n.second->Inputs();
|
node["inPortCount"] = n->Inputs();
|
||||||
|
|
||||||
nlohmann::json position;
|
nlohmann::json position;
|
||||||
position["x"] = n.second->GetX();
|
position["x"] = n->GetX();
|
||||||
position["y"] = n.second->GetY();
|
position["y"] = n->GetY();
|
||||||
|
|
||||||
nlohmann::json internalData;
|
nlohmann::json internalData;
|
||||||
|
|
||||||
n.second->ToJson(internalData);
|
n->ToJson(internalData);
|
||||||
|
|
||||||
node["position"] = position;
|
node["position"] = position;
|
||||||
node["internal-data"] = internalData;
|
node["internal-data"] = internalData;
|
||||||
|
|
@ -185,27 +185,116 @@ void NodeEditorWindow::Save(nlohmann::json &model)
|
||||||
int index;
|
int index;
|
||||||
for (const auto & n : m_nodes)
|
for (const auto & n : m_nodes)
|
||||||
{
|
{
|
||||||
if (n.second->HasOnputPinId(linkInfo->OutputId, index))
|
if (n->HasOnputPinId(linkInfo->ed_link->OutputId, index))
|
||||||
{
|
{
|
||||||
c["outNodeId"] = n.second->GetId();
|
c["outNodeId"] = n->GetId();
|
||||||
c["outPortIndex"] = index;
|
c["outPortIndex"] = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n.second->HasInputPinId(linkInfo->InputId, index))
|
if (n->HasInputPinId(linkInfo->ed_link->InputId, index))
|
||||||
{
|
{
|
||||||
c["inNodeId"] = n.second->GetId();
|
c["inNodeId"] = n->GetId();
|
||||||
c["inPortIndex"] = index;
|
c["inPortIndex"] = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connections.push_back(c);
|
connections.push_back(c);
|
||||||
ed::Link(linkInfo->Id, linkInfo->OutputId, linkInfo->InputId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
model["connections"] = connections;
|
model["connections"] = connections;
|
||||||
ed::SetCurrentEditor(nullptr);
|
ed::SetCurrentEditor(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t NodeEditorWindow::FindFirstNode() const
|
||||||
|
{
|
||||||
|
uint32_t id = 0;
|
||||||
|
|
||||||
|
// First node is the one without connection on its input port
|
||||||
|
|
||||||
|
for (const auto & n : m_nodes)
|
||||||
|
{
|
||||||
|
bool foundConnection = false;
|
||||||
|
for (const auto& l : m_links)
|
||||||
|
{
|
||||||
|
if (l->model->inNodeId == n->GetId())
|
||||||
|
{
|
||||||
|
foundConnection = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundConnection)
|
||||||
|
{
|
||||||
|
id = n->GetId();
|
||||||
|
m_project.Log("First node is: " + std::to_string(id));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NodeEditorWindow::Build()
|
||||||
|
{
|
||||||
|
std::stringstream code;
|
||||||
|
ed::SetCurrentEditor(m_context);
|
||||||
|
|
||||||
|
|
||||||
|
std::stringstream chip32;
|
||||||
|
|
||||||
|
uint32_t firstNode = FindFirstNode();
|
||||||
|
|
||||||
|
code << "\tjump " << GetNodeEntryLabel(firstNode) << "\r\n";
|
||||||
|
|
||||||
|
// First generate all constants
|
||||||
|
for (const auto & n : m_nodes)
|
||||||
|
{
|
||||||
|
code << n->GenerateConstants() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto & n : m_nodes)
|
||||||
|
{
|
||||||
|
code << n->Build() << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
ed::SetCurrentEditor(nullptr);
|
||||||
|
return code.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<std::shared_ptr<Connection>> NodeEditorWindow::GetNodeConnections(unsigned long nodeId)
|
||||||
|
{
|
||||||
|
std::list<std::shared_ptr<Connection>> c;
|
||||||
|
ed::SetCurrentEditor(m_context);
|
||||||
|
|
||||||
|
for (const auto & l : m_links)
|
||||||
|
{
|
||||||
|
if (l->model->outNodeId == nodeId)
|
||||||
|
{
|
||||||
|
c.push_back(l->model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ed::SetCurrentEditor(nullptr);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string NodeEditorWindow::GetNodeEntryLabel(unsigned long nodeId)
|
||||||
|
{
|
||||||
|
std::string label;
|
||||||
|
ed::SetCurrentEditor(m_context);
|
||||||
|
|
||||||
|
for (const auto & n : m_nodes)
|
||||||
|
{
|
||||||
|
if (n->GetId() == nodeId)
|
||||||
|
{
|
||||||
|
label = n->GetEntryLabel();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ed::SetCurrentEditor(nullptr);
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<BaseNode> NodeEditorWindow::GetSelectedNode()
|
std::shared_ptr<BaseNode> NodeEditorWindow::GetSelectedNode()
|
||||||
{
|
{
|
||||||
|
|
@ -219,9 +308,12 @@ std::shared_ptr<BaseNode> NodeEditorWindow::GetSelectedNode()
|
||||||
|
|
||||||
if (nodeCount > 0)
|
if (nodeCount > 0)
|
||||||
{
|
{
|
||||||
if (m_nodes.contains(nId.Get()))
|
for (auto & n : m_nodes)
|
||||||
{
|
{
|
||||||
selected = m_nodes[nId.Get()];
|
if (n->GetInternalId() == nId.Get())
|
||||||
|
{
|
||||||
|
selected = n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -242,14 +334,14 @@ void NodeEditorWindow::Draw()
|
||||||
|
|
||||||
for (const auto & n : m_nodes)
|
for (const auto & n : m_nodes)
|
||||||
{
|
{
|
||||||
ImGui::PushID(n.first);
|
ImGui::PushID(n->GetInternalId());
|
||||||
n.second->Draw();
|
n->Draw();
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& linkInfo : m_links)
|
for (const auto& linkInfo : m_links)
|
||||||
{
|
{
|
||||||
ed::Link(linkInfo->Id, linkInfo->OutputId, linkInfo->InputId);
|
ed::Link(linkInfo->ed_link->Id, linkInfo->ed_link->OutputId, linkInfo->ed_link->InputId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle creation action, returns true if editor want to create new object (node or link)
|
// Handle creation action, returns true if editor want to create new object (node or link)
|
||||||
|
|
@ -304,7 +396,10 @@ void NodeEditorWindow::Draw()
|
||||||
|
|
||||||
m_links.erase(std::remove_if(m_links.begin(),
|
m_links.erase(std::remove_if(m_links.begin(),
|
||||||
m_links.end(),
|
m_links.end(),
|
||||||
[deletedLinkId](std::shared_ptr<LinkInfo> inf) { return inf->Id == deletedLinkId; }));
|
[deletedLinkId](std::shared_ptr<LinkInfo> inf)
|
||||||
|
{
|
||||||
|
return inf->ed_link->Id == deletedLinkId;
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// You may reject link deletion by calling:
|
// You may reject link deletion by calling:
|
||||||
|
|
|
||||||
|
|
@ -28,15 +28,24 @@ namespace ed = ax::NodeEditor;
|
||||||
class NodeEditorWindow : public WindowBase
|
class NodeEditorWindow : public WindowBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct LinkInfo
|
struct EditorLink {
|
||||||
{
|
|
||||||
// Stuff from ImGuiNodeEditor
|
|
||||||
ed::LinkId Id;
|
ed::LinkId Id;
|
||||||
ed::PinId InputId;
|
ed::PinId InputId;
|
||||||
ed::PinId OutputId;
|
ed::PinId OutputId;
|
||||||
|
};
|
||||||
|
|
||||||
// Stuff from the project.json file, our model
|
// Stuff from ImGuiNodeEditor, each element has a unique ID within one editor
|
||||||
Connection model;
|
struct LinkInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
LinkInfo()
|
||||||
|
{
|
||||||
|
ed_link = std::make_shared<EditorLink>();
|
||||||
|
model = std::make_shared<Connection>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<EditorLink> ed_link;
|
||||||
|
std::shared_ptr<Connection> model;
|
||||||
};
|
};
|
||||||
|
|
||||||
NodeEditorWindow(IStoryProject &proj);
|
NodeEditorWindow(IStoryProject &proj);
|
||||||
|
|
@ -47,17 +56,20 @@ public:
|
||||||
void Clear();
|
void Clear();
|
||||||
void Load(const nlohmann::json &model);
|
void Load(const nlohmann::json &model);
|
||||||
void Save(nlohmann::json &model);
|
void Save(nlohmann::json &model);
|
||||||
|
std::string Build();
|
||||||
|
std::list<std::shared_ptr<Connection> > GetNodeConnections(unsigned long nodeId);
|
||||||
|
std::string GetNodeEntryLabel(unsigned long nodeId);
|
||||||
|
|
||||||
std::shared_ptr<BaseNode> GetSelectedNode();
|
std::shared_ptr<BaseNode> GetSelectedNode();
|
||||||
std::string GenerateConstants();
|
|
||||||
private:
|
private:
|
||||||
IStoryProject &m_project;
|
IStoryProject &m_project;
|
||||||
|
|
||||||
ed::EditorContext* m_context = nullptr;
|
ed::EditorContext* m_context = nullptr;
|
||||||
|
|
||||||
// key: Id
|
// key: Id
|
||||||
std::map<unsigned long, std::shared_ptr<BaseNode>> m_nodes;
|
std::list<std::shared_ptr<BaseNode>> m_nodes;
|
||||||
std::vector<std::shared_ptr<LinkInfo>> m_links; // List of live links. It is dynamic unless you want to create read-only view over nodes.
|
std::list<std::shared_ptr<LinkInfo>> m_links; // List of live links. It is dynamic unless you want to create read-only view over nodes.
|
||||||
void ToolbarUI();
|
void ToolbarUI();
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -104,7 +116,6 @@ private:
|
||||||
void LoadNode(const nlohmann::json &nodeJson);
|
void LoadNode(const nlohmann::json &nodeJson);
|
||||||
ed::PinId GetInputPin(unsigned long modelNodeId, int pinIndex);
|
ed::PinId GetInputPin(unsigned long modelNodeId, int pinIndex);
|
||||||
ed::PinId GetOutputPin(unsigned long modelNodeId, int pinIndex);
|
ed::PinId GetOutputPin(unsigned long modelNodeId, int pinIndex);
|
||||||
std::string ChoiceLabel() const;
|
uint32_t FindFirstNode() const;
|
||||||
std::string EntryLabel() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
#include "node_properties_window.h"
|
|
||||||
#include "gui.h"
|
|
||||||
|
|
||||||
NodePropertiesWindow::NodePropertiesWindow()
|
|
||||||
: WindowBase("Properties")
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodePropertiesWindow::Initialize() {
|
|
||||||
|
|
||||||
int my_image_width = 0;
|
|
||||||
int my_image_height = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodePropertiesWindow::Draw()
|
|
||||||
{
|
|
||||||
// if (!IsVisible())
|
|
||||||
// {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
WindowBase::BeginDraw();
|
|
||||||
ImGui::SetWindowSize(ImVec2(626, 744), ImGuiCond_FirstUseEver);
|
|
||||||
|
|
||||||
|
|
||||||
static char buf1[32] = ""; ImGui::InputText("Title", buf1, 32);
|
|
||||||
|
|
||||||
if (m_selectedNode)
|
|
||||||
{
|
|
||||||
m_selectedNode->DrawProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
WindowBase::EndDraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
void NodePropertiesWindow::SetSelectedNode(std::shared_ptr<BaseNode> node)
|
|
||||||
{
|
|
||||||
m_selectedNode = node;
|
|
||||||
}
|
|
||||||
47
story-editor/src/properties_window.cpp
Normal file
47
story-editor/src/properties_window.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include "properties_window.h"
|
||||||
|
#include "gui.h"
|
||||||
|
|
||||||
|
PropertiesWindow::PropertiesWindow()
|
||||||
|
: WindowBase("Properties")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertiesWindow::Initialize() {
|
||||||
|
|
||||||
|
int my_image_width = 0;
|
||||||
|
int my_image_height = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertiesWindow::Draw()
|
||||||
|
{
|
||||||
|
// if (!IsVisible())
|
||||||
|
// {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
WindowBase::BeginDraw();
|
||||||
|
ImGui::SetWindowSize(ImVec2(626, 744), ImGuiCond_FirstUseEver);
|
||||||
|
|
||||||
|
|
||||||
|
ImGui::SeparatorText("Project");
|
||||||
|
|
||||||
|
ImGui::SeparatorText("Selected node");
|
||||||
|
|
||||||
|
|
||||||
|
if (m_selectedNode)
|
||||||
|
{
|
||||||
|
static char buf1[32] = ""; ImGui::InputText("Title", buf1, 32);
|
||||||
|
ImGui::Text("Node ID: %lu", m_selectedNode->GetId());
|
||||||
|
m_selectedNode->DrawProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowBase::EndDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertiesWindow::SetSelectedNode(std::shared_ptr<BaseNode> node)
|
||||||
|
{
|
||||||
|
m_selectedNode = node;
|
||||||
|
}
|
||||||
|
|
@ -5,10 +5,10 @@
|
||||||
|
|
||||||
#include "base_node.h"
|
#include "base_node.h"
|
||||||
|
|
||||||
class NodePropertiesWindow : public WindowBase
|
class PropertiesWindow : public WindowBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NodePropertiesWindow();
|
PropertiesWindow();
|
||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
virtual void Draw() override;
|
virtual void Draw() override;
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
struct Resource
|
struct Resource
|
||||||
{
|
{
|
||||||
|
|
@ -20,11 +21,8 @@ struct Resource
|
||||||
|
|
||||||
// Itérateur pour parcourir les éléments filtrés
|
// Itérateur pour parcourir les éléments filtrés
|
||||||
class FilterIterator {
|
class FilterIterator {
|
||||||
private:
|
public:
|
||||||
using Iterator = std::vector<std::shared_ptr<Resource>>::const_iterator;
|
using Iterator = std::list<std::shared_ptr<Resource>>::const_iterator;
|
||||||
Iterator current;
|
|
||||||
Iterator end;
|
|
||||||
std::string filterType;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FilterIterator(Iterator start, Iterator end, const std::string &type)
|
FilterIterator(Iterator start, Iterator end, const std::string &type)
|
||||||
|
|
@ -37,6 +35,10 @@ public:
|
||||||
return *current;
|
return *current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Iterator Current() const {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
// Surcharge de l'opérateur d'incrémentation
|
// Surcharge de l'opérateur d'incrémentation
|
||||||
FilterIterator& operator++() {
|
FilterIterator& operator++() {
|
||||||
++current;
|
++current;
|
||||||
|
|
@ -55,6 +57,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Iterator current;
|
||||||
|
Iterator end;
|
||||||
|
std::string filterType;
|
||||||
|
|
||||||
// Fonction pour trouver le prochain élément qui correspond au filtre
|
// Fonction pour trouver le prochain élément qui correspond au filtre
|
||||||
void searchNext() {
|
void searchNext() {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,11 @@ public:
|
||||||
UpdateIterators();
|
UpdateIterators();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Delete(FilterIterator &it)
|
||||||
|
{
|
||||||
|
m_items.erase(it.Current());
|
||||||
|
}
|
||||||
|
|
||||||
void Clear()
|
void Clear()
|
||||||
{
|
{
|
||||||
m_items.clear();
|
m_items.clear();
|
||||||
|
|
@ -61,7 +66,7 @@ public:
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::shared_ptr<Resource>> m_items;
|
std::list<std::shared_ptr<Resource>> m_items;
|
||||||
std::pair<FilterIterator, FilterIterator> m_images;
|
std::pair<FilterIterator, FilterIterator> m_images;
|
||||||
std::pair<FilterIterator, FilterIterator> m_sounds;
|
std::pair<FilterIterator, FilterIterator> m_sounds;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,6 +109,7 @@ void ResourcesWindow::Draw()
|
||||||
int id = 1000;
|
int id = 1000;
|
||||||
for (auto it = b; it != e; ++it)
|
for (auto it = b; it != e; ++it)
|
||||||
{
|
{
|
||||||
|
bool quitLoop = false;
|
||||||
ImGui::PushID(id);
|
ImGui::PushID(id);
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::Text("%s", (*it)->file.c_str());
|
ImGui::Text("%s", (*it)->file.c_str());
|
||||||
|
|
@ -132,7 +133,6 @@ void ResourcesWindow::Draw()
|
||||||
strncpy(description, (*it)->description.c_str(), sizeof(description));
|
strncpy(description, (*it)->description.c_str(), sizeof(description));
|
||||||
init = false;
|
init = false;
|
||||||
}
|
}
|
||||||
// ImGui::PushID(id);
|
|
||||||
ImGui::InputText("Description", description, sizeof(description));
|
ImGui::InputText("Description", description, sizeof(description));
|
||||||
if (ImGui::Button("Close"))
|
if (ImGui::Button("Close"))
|
||||||
{
|
{
|
||||||
|
|
@ -140,7 +140,6 @@ void ResourcesWindow::Draw()
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
// ImGui::PopID();
|
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Text("%s", (*it)->description.c_str());
|
ImGui::Text("%s", (*it)->description.c_str());
|
||||||
|
|
@ -153,9 +152,16 @@ void ResourcesWindow::Draw()
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
if (ImGui::SmallButton("Delete"))
|
if (ImGui::SmallButton("Delete"))
|
||||||
{
|
{
|
||||||
|
m_project.DeleteResource(it);
|
||||||
|
quitLoop = true;
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
id++;
|
id++;
|
||||||
|
|
||||||
|
if (quitLoop)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
|
|
|
||||||
|
|
@ -422,18 +422,4 @@ std::string StoryProject::BuildFullAssetsPath(const std::string &fileName) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void to_json(nlohmann::json &j, const Connection &p) {
|
|
||||||
j = nlohmann::json{
|
|
||||||
{"outNodeId", static_cast<int64_t>(p.outNodeId)},
|
|
||||||
{"outPortIndex", static_cast<int64_t>(p.outPortIndex)},
|
|
||||||
{"inNodeId", static_cast<int64_t>(p.inNodeId)},
|
|
||||||
{"inPortIndex", static_cast<int64_t>(p.inPortIndex)},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void from_json(const nlohmann::json &j, Connection &p) {
|
|
||||||
j.at("outNodeId").get_to(p.outNodeId);
|
|
||||||
j.at("outPortIndex").get_to(p.outPortIndex);
|
|
||||||
j.at("inNodeId").get_to(p.inNodeId);
|
|
||||||
j.at("inPortIndex").get_to(p.inPortIndex);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -48,35 +48,6 @@ struct AudioCommand {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Connection
|
|
||||||
{
|
|
||||||
int outNodeId;
|
|
||||||
int outPortIndex;
|
|
||||||
int inNodeId;
|
|
||||||
int inPortIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline bool operator==(Connection const &a, Connection const &b)
|
|
||||||
{
|
|
||||||
return a.outNodeId == b.outNodeId && a.outPortIndex == b.outPortIndex
|
|
||||||
&& a.inNodeId == b.inNodeId && a.inPortIndex == b.inPortIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool operator!=(Connection const &a, Connection const &b)
|
|
||||||
{
|
|
||||||
return !(a == b);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void invertConnection(Connection &id)
|
|
||||||
{
|
|
||||||
std::swap(id.outNodeId, id.inNodeId);
|
|
||||||
std::swap(id.outPortIndex, id.inPortIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void to_json(nlohmann::json& j, const Connection& p);
|
|
||||||
|
|
||||||
void from_json(const nlohmann::json& j, Connection& p);
|
|
||||||
|
|
||||||
|
|
||||||
// FIXME : Structure très Lunii style, à utiliser pour la conversion peut-être ...
|
// FIXME : Structure très Lunii style, à utiliser pour la conversion peut-être ...
|
||||||
struct StoryNode
|
struct StoryNode
|
||||||
|
|
|
||||||
BIN
story-editor/story-editor-logo.ico
Normal file
BIN
story-editor/story-editor-logo.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 220 KiB |
BIN
story-editor/story-editor-logo.png
Normal file
BIN
story-editor/story-editor-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
8
story-editor/story-editor.desktop
Normal file
8
story-editor/story-editor.desktop
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=StoryEditor
|
||||||
|
Comment=A tool to create stories with graphical nodes (OpenStoryTeller project)
|
||||||
|
Exec=story-editor
|
||||||
|
Icon=story-editor-logo
|
||||||
|
Categories=Graphics;2DGraphics;
|
||||||
|
|
||||||
Loading…
Reference in a new issue