From 35b990f21f7a20f751b31fa93090f53ca7e297fb Mon Sep 17 00:00:00 2001 From: Anthony Rabine Date: Mon, 15 May 2023 15:22:23 +0200 Subject: [PATCH] (WIP) Code generation --- story-editor/scripts/media.asm | 32 +++++++++++ story-editor/src/code_editor.cpp | 30 +++-------- story-editor/src/main_window.cpp | 74 +++++++++++++++++++++----- story-editor/src/main_window.h | 10 +++- story-editor/src/media_node_model.cpp | 12 ++++- story-editor/src/ost-editor.qrc | 1 + story-editor/src/resource_model.cpp | 10 ++++ story-editor/src/resource_model.h | 2 + story-editor/src/resources_dock.cpp | 28 +--------- story-editor/src/resources_dock.h | 9 +--- story-editor/src/story_graph_model.cpp | 31 +++++++++-- story-editor/src/story_graph_model.h | 5 +- story-editor/src/story_node_base.h | 5 ++ story-editor/src/story_project.cpp | 4 +- story-editor/src/story_project.h | 4 +- 15 files changed, 176 insertions(+), 81 deletions(-) create mode 100644 story-editor/scripts/media.asm diff --git a/story-editor/scripts/media.asm b/story-editor/scripts/media.asm new file mode 100644 index 0000000..74d7c86 --- /dev/null +++ b/story-editor/scripts/media.asm @@ -0,0 +1,32 @@ +; Generic media choice manager +.media: + ; Les adresses des différents medias sont dans la stack +; Arguments: + ; r0: address d'une structure de type "media choice" +; Local: + ; t0: loop counter + ; t1: increment 1 + ; t2: increment 4 + ; t3: current media address + +.media_loop_start: + load t0, @r0, 4 ; Le premier élément est le nombre de choix possibles, t0 = 3 (exemple) + lcons t1, 1 + lcons t2, 4 + mov t3, r0 +.media_loop: + add t3, t2 ; @++ + + +; ------- On appelle un autre media node + push r0 ; save r0 + load r0, @t3, 4 ; r0 = content in ram at address in T4 + call r0 + pop r0 + ; TODO: wait for event + + sub t0, t1 ; i-- + skipnz t0 ; if (r0) goto start_loop; + jump .media_loop_start + jump .media_loop + diff --git a/story-editor/src/code_editor.cpp b/story-editor/src/code_editor.cpp index b26f88c..77c45c6 100644 --- a/story-editor/src/code_editor.cpp +++ b/story-editor/src/code_editor.cpp @@ -2,6 +2,7 @@ #include #include +#include //![constructor] @@ -13,14 +14,12 @@ CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(parent) connect(this, &CodeEditor::updateRequest, this, &CodeEditor::updateLineNumberArea); connect(this, &CodeEditor::cursorPositionChanged, this, &CodeEditor::highlightCurrentLine); + setTabStopDistance(QFontMetricsF(font()).horizontalAdvance(' ') * 4); + updateLineNumberAreaWidth(0); highlightCurrentLine(); } -//![constructor] - -//![extraAreaWidth] - int CodeEditor::lineNumberAreaWidth() { int digits = 1; @@ -35,18 +34,12 @@ int CodeEditor::lineNumberAreaWidth() return space; } -//![extraAreaWidth] - -//![slotUpdateExtraAreaWidth] void CodeEditor::updateLineNumberAreaWidth(int /* newBlockCount */) { setViewportMargins(lineNumberAreaWidth(), 0, 0, 0); } -//![slotUpdateExtraAreaWidth] - -//![slotUpdateRequest] void CodeEditor::updateLineNumberArea(const QRect &rect, int dy) { @@ -59,9 +52,7 @@ void CodeEditor::updateLineNumberArea(const QRect &rect, int dy) updateLineNumberAreaWidth(0); } -//![slotUpdateRequest] -//![resizeEvent] void CodeEditor::resizeEvent(QResizeEvent *e) { @@ -71,9 +62,6 @@ void CodeEditor::resizeEvent(QResizeEvent *e) lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height())); } -//![resizeEvent] - -//![cursorPositionChanged] void CodeEditor::highlightCurrentLine() { @@ -82,9 +70,10 @@ void CodeEditor::highlightCurrentLine() if (!isReadOnly()) { QTextEdit::ExtraSelection selection; - QColor lineColor = QColor(Qt::yellow).lighter(160); + QColor lineColor = QColor(Qt::darkGray).lighter(160); selection.format.setBackground(lineColor); + selection.format.setForeground(Qt::black); selection.format.setProperty(QTextFormat::FullWidthSelection, true); selection.cursor = textCursor(); selection.cursor.clearSelection(); @@ -94,25 +83,17 @@ void CodeEditor::highlightCurrentLine() setExtraSelections(extraSelections); } -//![cursorPositionChanged] - -//![extraAreaPaintEvent_0] void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event) { QPainter painter(lineNumberArea); painter.fillRect(event->rect(), Qt::lightGray); - //![extraAreaPaintEvent_0] - - //![extraAreaPaintEvent_1] QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); int top = qRound(blockBoundingGeometry(block).translated(contentOffset()).top()); int bottom = top + qRound(blockBoundingRect(block).height()); - //![extraAreaPaintEvent_1] - //![extraAreaPaintEvent_2] while (block.isValid() && top <= event->rect().bottom()) { if (block.isVisible() && bottom >= event->rect().top()) { QString number = QString::number(blockNumber + 1); @@ -126,5 +107,6 @@ void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event) bottom = top + qRound(blockBoundingRect(block).height()); ++blockNumber; } + } //![extraAreaPaintEvent_2] diff --git a/story-editor/src/main_window.cpp b/story-editor/src/main_window.cpp index 5ec8187..4a5dbd7 100644 --- a/story-editor/src/main_window.cpp +++ b/story-editor/src/main_window.cpp @@ -1,4 +1,5 @@ - +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023-2099 Anthony Rabine #include #include @@ -49,7 +50,8 @@ int nodeX = 0.0; typedef void (*message_output_t)(QtMsgType , const QMessageLogContext &, const QString &); MainWindow::MainWindow() - : m_model(m_project) + : m_resourceModel(m_project) + , m_model(m_project) , m_scene(m_model) , m_settings("OpenStoryTeller", "OpenStoryTellerEditor") { @@ -84,7 +86,7 @@ MainWindow::MainWindow() QCoreApplication::postEvent(this, new VmEvent(VmEvent::evOkButton)); }); - m_resourcesDock = new ResourcesDock(m_project); + m_resourcesDock = new ResourcesDock(m_project, m_resourceModel); addDockWidget(Qt::DockWidgetArea::RightDockWidgetArea, m_resourcesDock); m_toolbar->AddDockToMenu(m_resourcesDock->toggleViewAction()); @@ -97,8 +99,7 @@ MainWindow::MainWindow() m_toolbar->AddDockToMenu(m_vmDock->toggleViewAction()); connect(m_vmDock, &VmDock::sigCompile, [=]() { - m_resourcesDock->SaveToProject(); - m_scriptEditorDock->setScript(m_project.Compile()); + // m_scriptEditorDock->setScript(m_project.BuildResources()); }); connect(m_vmDock, &VmDock::sigStepInstruction, [=]() { @@ -124,7 +125,7 @@ MainWindow::MainWindow() m_chooseFileUi.setupUi(m_chooseFileDialog); m_chooseFileDialog->close(); - connect(&m_model, &StoryGraphModel::sigChooseFile, [&](NodeId id) { + connect(&m_model, &StoryGraphModel::sigChooseFile, [&](NodeId id, const QString &type) { m_chooseFileUi.tableView->setModel(&m_resourcesDock->getModel()); m_chooseFileDialog->exec(); @@ -138,9 +139,8 @@ MainWindow::MainWindow() Resource res; if (m_project.GetResourceAt(index.row(), res)) { - QJsonObject obj; - obj["image"] = res.file.c_str(); - m_model.setNodeData(id, NodeRole::InternalData, obj.toVariantMap()); + nlohmann::json obj = {{type.toStdString(), res.file}}; + m_model.SetInternalData(id, obj); } } }); @@ -197,6 +197,10 @@ MainWindow::MainWindow() OpenProject(recent); }); + connect(m_toolbar, &ToolBar::sigRun, this, [&]() { + BuildAndRun(); + }); + // Install event handler now that everythin is initialized Callback::func = std::bind(&MainWindow::MessageOutput, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); auto cb = static_cast(Callback::callback); @@ -209,10 +213,52 @@ MainWindow::MainWindow() qDebug() << "Welcome to StoryTeller Editor"; CloseProject(); + RefreshProjectInformation(); // QMetaObject::invokeMethod(this, "slotWelcome", Qt::QueuedConnection); } +void MainWindow::BuildAndRun() +{ + // 1. Check if the model can be compiled, check for errors and report + + // FIXME + + // 2. Generate the assembly code from the model + std::string code = m_project.BuildResources() + "\n"; + code += m_model.Build(); + + // Add global functions + code += ReadResourceFile(":/scripts/media.asm").toStdString(); + + code += "\thalt\r\n"; + + m_scriptEditorDock->setScript(code.c_str()); + + // 3. Compile the assembly to machine binary + // buildScript(); + +} + + +QString MainWindow::ReadResourceFile(const QString &fileName) +{ + QString data; + QFile file(fileName); + if(!file.open(QIODevice::ReadOnly)) { + qDebug() << "filenot opened"; + } + else + { + qDebug() << "file opened"; + data = file.readAll(); + } + + file.close(); + + return data; +} + void MainWindow::slotDefaultDocksPosition() { m_settings.clear(); @@ -562,6 +608,8 @@ void MainWindow::OpenProject(const QString &filePath) nlohmann::json model; + m_resourceModel.BeginChange(); + if (m_project.Load(filePath.toStdString(), model)) { m_model.Load(model); @@ -572,14 +620,16 @@ void MainWindow::OpenProject(const QString &filePath) qWarning() << errorMsg; QMessageBox::critical(this, tr("Open project error"), errorMsg); } + + m_resourceModel.EndChange(); + RefreshProjectInformation(); } void MainWindow::SaveProject() { - // QJsonObject jsonModel = m_model.save(); - - + nlohmann::json model = m_model.Save(); + m_project.Save(model); statusBar()->showMessage(tr("Saved '%1'").arg(m_project.GetProjectFilePath().c_str()), 2000); } diff --git a/story-editor/src/main_window.h b/story-editor/src/main_window.h index 37395f9..ee23027 100644 --- a/story-editor/src/main_window.h +++ b/story-editor/src/main_window.h @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2023-2099 Anthony Rabine + #ifndef MAIN_WINDOW_H #define MAIN_WINDOW_H @@ -44,7 +47,7 @@ using QtNodes::NodeDelegateModelRegistry; #include "log_dock.h" #include "toolbar.h" #include "new_project_dialog.h" - +#include "resource_model.h" struct DebugContext { @@ -116,6 +119,9 @@ class MainWindow : public QMainWindow public: MainWindow(); +protected: + void BuildAndRun(); + private slots: void stepInstruction(); void closeEvent(QCloseEvent *event); @@ -124,6 +130,7 @@ private slots: private: StoryProject m_project; + ResourceModel m_resourceModel; StoryGraphModel m_model; StoryGraphScene m_scene; GraphicsView *m_view{nullptr}; @@ -176,6 +183,7 @@ private: void ExitProgram(); void EnableProject(); void OpenProject(const QString &filePath); + QString ReadResourceFile(const QString &fileName); }; #endif // MAIN_WINDOW_H diff --git a/story-editor/src/media_node_model.cpp b/story-editor/src/media_node_model.cpp index fa39887..6052e20 100644 --- a/story-editor/src/media_node_model.cpp +++ b/story-editor/src/media_node_model.cpp @@ -43,8 +43,16 @@ MediaNodeModel::MediaNodeModel(StoryGraphModel &model) }); connect(m_ui.selectImageButton, &QPushButton::clicked, [&](bool enable) { - emit m_model.sigChooseFile(getNodeId()); + emit m_model.sigChooseFile(getNodeId(), "image"); }); + + // default model + m_mediaData = { + {"image", ""}, + {"sound", ""} + }; + + m_mediaData.merge_patch(StoryNodeBase::ToJson()); } nlohmann::json MediaNodeModel::ToJson() const @@ -58,7 +66,7 @@ nlohmann::json MediaNodeModel::ToJson() const void MediaNodeModel::FromJson(nlohmann::json &j) { - m_mediaData = j; + m_mediaData.merge_patch(j); // Display loaded image std::string imagePath = m_mediaData["image"].get(); diff --git a/story-editor/src/ost-editor.qrc b/story-editor/src/ost-editor.qrc index 67a9b1b..c4f9c51 100644 --- a/story-editor/src/ost-editor.qrc +++ b/story-editor/src/ost-editor.qrc @@ -10,5 +10,6 @@ ../assets/folder-open-outline.svg ../assets/welcome.png ../assets/play-circle-green.png + ../scripts/media.asm diff --git a/story-editor/src/resource_model.cpp b/story-editor/src/resource_model.cpp index a3501b0..861be64 100644 --- a/story-editor/src/resource_model.cpp +++ b/story-editor/src/resource_model.cpp @@ -58,6 +58,16 @@ void ResourceModel::Clear() endResetModel(); } +void ResourceModel::BeginChange() +{ + beginResetModel(); +} + +void ResourceModel::EndChange() +{ + endResetModel(); +} + // ------------------------------- PROXY MODEL ------------------------------- diff --git a/story-editor/src/resource_model.h b/story-editor/src/resource_model.h index 03ee802..52ed1dd 100644 --- a/story-editor/src/resource_model.h +++ b/story-editor/src/resource_model.h @@ -19,6 +19,8 @@ public: void append(const Resource & res); void Clear(); + void BeginChange(); + void EndChange(); private: StoryProject &m_project; diff --git a/story-editor/src/resources_dock.cpp b/story-editor/src/resources_dock.cpp index 7f1c155..00535ae 100644 --- a/story-editor/src/resources_dock.cpp +++ b/story-editor/src/resources_dock.cpp @@ -2,9 +2,9 @@ #include #include -ResourcesDock::ResourcesDock(StoryProject &project) +ResourcesDock::ResourcesDock(StoryProject &project, ResourceModel &model) : m_project(project) - , m_resourcesModel(project) + , m_resourcesModel(model) , DockWidgetBase(tr("Resources"), true) { setObjectName("ResourcesDock"); // used to save the state @@ -55,28 +55,4 @@ ResourcesDock::ResourcesDock(StoryProject &project) }); } -void ResourcesDock::Initialize() -{ - -} - -void ResourcesDock::Append(const Resource &res) -{ - m_resourcesModel.append(res); -} - -void ResourcesDock::SaveToProject() -{ - m_project.Clear(); -// for (auto & r : m_resourcesModel.GetData()) -// { -// m_project.m_images.push_back(r); - // } -} - -void ResourcesDock::Clear() -{ - m_resourcesModel.Clear(); -} - diff --git a/story-editor/src/resources_dock.h b/story-editor/src/resources_dock.h index 52cd2f8..50aecac 100644 --- a/story-editor/src/resources_dock.h +++ b/story-editor/src/resources_dock.h @@ -10,7 +10,7 @@ class ResourcesDock : public DockWidgetBase { Q_OBJECT public: - ResourcesDock(StoryProject &project); + ResourcesDock(StoryProject &project, ResourceModel &model); void Initialize(); @@ -19,15 +19,10 @@ public: void SetFilterType(const QString &type) { m_proxyModel.setFilterType(type); } - void Append(const Resource &res); - - void SaveToProject(); - void Clear(); - private: StoryProject &m_project; Ui::ostResources m_uiOstResources; - ResourceModel m_resourcesModel; + ResourceModel &m_resourcesModel; ResourceFilterProxyModel m_proxyModel; }; diff --git a/story-editor/src/story_graph_model.cpp b/story-editor/src/story_graph_model.cpp index ba4d96b..0aa2af6 100644 --- a/story-editor/src/story_graph_model.cpp +++ b/story-editor/src/story_graph_model.cpp @@ -327,9 +327,10 @@ namespace QtNodes { } void from_json(const nlohmann::json& j, ConnectionId& p) { -// j.at("name").get_to(p.name); -// j.at("address").get_to(p.address); -// j.at("age").get_to(p.age); + j.at("outNodeId").get_to(p.outNodeId); + j.at("outPortIndex").get_to(p.outPortIndex); + j.at("intNodeId").get_to(p.inNodeId); + j.at("inPortIndex").get_to(p.inPortIndex); } } // namespace QtNodes @@ -361,6 +362,8 @@ void StoryGraphModel::Load(const nlohmann::json &j) LoadNode(element); } + std::cout << j.dump(4) << std::endl; + nlohmann::json connectionJsonArray = j["connections"]; for (auto& connection : connectionJsonArray) { @@ -398,6 +401,18 @@ nlohmann::json StoryGraphModel::SaveNode(NodeId const nodeId) const return nodeJson; } +std::string StoryGraphModel::BuildNode(NodeId const nodeId) const +{ + std::string code; + + auto it = _models.find(nodeId); + if (it == _models.end()) + return ""; + + auto &model = it->second; + return model->Build(); +} + void StoryGraphModel::LoadNode(const nlohmann::json &nodeJson) { @@ -445,7 +460,17 @@ void StoryGraphModel::LoadNode(const nlohmann::json &nodeJson) } } +std::string StoryGraphModel::Build() +{ + std::string code; + nlohmann::json nodesJsonArray; + for (auto const nodeId : allNodeIds()) { + code = BuildNode(nodeId) + "\n"; + } + + return code; +} void StoryGraphModel::addPort(NodeId nodeId, PortType portType, PortIndex portIndex) { diff --git a/story-editor/src/story_graph_model.h b/story-editor/src/story_graph_model.h index 3df488f..e1550fa 100644 --- a/story-editor/src/story_graph_model.h +++ b/story-editor/src/story_graph_model.h @@ -127,8 +127,11 @@ public: nlohmann::json SaveNode(NodeId const) const; void LoadNode(const nlohmann::json &nodeJson); // Creates a new node + std::string Build(); + + std::string BuildNode(const NodeId nodeId) const; signals: - void sigChooseFile(NodeId id); + void sigChooseFile(NodeId id, const QString &type); private: StoryProject &m_project; diff --git a/story-editor/src/story_node_base.h b/story-editor/src/story_node_base.h index 5bd7d02..26461d1 100644 --- a/story-editor/src/story_node_base.h +++ b/story-editor/src/story_node_base.h @@ -48,8 +48,13 @@ public: // default impl } + virtual std::string Build() { + return ""; + } + NodeGeometryData &geometryData() { return m_geometryData; } + private: NodeId m_nodeId; NodeGeometryData m_geometryData; diff --git a/story-editor/src/story_project.cpp b/story-editor/src/story_project.cpp index 3ac2fe9..da31669 100644 --- a/story-editor/src/story_project.cpp +++ b/story-editor/src/story_project.cpp @@ -272,7 +272,7 @@ std::string StoryProject::GetFileExtension(const std::string &fileName) return ""; } -std::string StoryProject::Compile() +std::string StoryProject::BuildResources() { std::stringstream chip32; @@ -288,8 +288,6 @@ std::string StoryProject::Compile() } chip32 << ".entry:\r\n"; - chip32 << "\thalt\r\n"; - return chip32.str(); } diff --git a/story-editor/src/story_project.h b/story-editor/src/story_project.h index 6ee14b4..0206318 100644 --- a/story-editor/src/story_project.h +++ b/story-editor/src/story_project.h @@ -67,8 +67,8 @@ struct StoryProject m_resources.clear(); m_initialized = false; } - - std::string Compile(); + + std::string BuildResources(); void SetImageFormat(ImageFormat format); void SetSoundFormat(SoundFormat format); void SetDisplayFormat(int w, int h);