mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
(WIP) Code generation
This commit is contained in:
parent
868d4fdc8e
commit
35b990f21f
15 changed files with 176 additions and 81 deletions
32
story-editor/scripts/media.asm
Normal file
32
story-editor/scripts/media.asm
Normal file
|
|
@ -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
|
||||
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <QPainter>
|
||||
#include <QTextBlock>
|
||||
#include <QFontMetrics>
|
||||
|
||||
//![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]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: 2023-2099 Anthony Rabine <anthony@rabine.fr>
|
||||
|
||||
#include <QAction>
|
||||
#include <QScreen>
|
||||
|
|
@ -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<void(QtMsgType , const QMessageLogContext &, const QString &)>::func = std::bind(&MainWindow::MessageOutput, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
auto cb = static_cast<message_output_t>(Callback<void(QtMsgType , const QMessageLogContext &, const QString &)>::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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: 2023-2099 Anthony Rabine <anthony@rabine.fr>
|
||||
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -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<std::string>();
|
||||
|
|
|
|||
|
|
@ -10,5 +10,6 @@
|
|||
<file>../assets/folder-open-outline.svg</file>
|
||||
<file>../assets/welcome.png</file>
|
||||
<file>../assets/play-circle-green.png</file>
|
||||
<file>../scripts/media.asm</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
|||
|
|
@ -58,6 +58,16 @@ void ResourceModel::Clear()
|
|||
endResetModel();
|
||||
}
|
||||
|
||||
void ResourceModel::BeginChange()
|
||||
{
|
||||
beginResetModel();
|
||||
}
|
||||
|
||||
void ResourceModel::EndChange()
|
||||
{
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------- PROXY MODEL -------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ public:
|
|||
void append(const Resource & res);
|
||||
|
||||
void Clear();
|
||||
void BeginChange();
|
||||
void EndChange();
|
||||
|
||||
private:
|
||||
StoryProject &m_project;
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
#include <QFileDialog>
|
||||
#include <QStandardPaths>
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -48,8 +48,13 @@ public:
|
|||
// default impl
|
||||
}
|
||||
|
||||
virtual std::string Build() {
|
||||
return "";
|
||||
}
|
||||
|
||||
NodeGeometryData &geometryData() { return m_geometryData; }
|
||||
|
||||
|
||||
private:
|
||||
NodeId m_nodeId;
|
||||
NodeGeometryData m_geometryData;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue