(WIP) Code generation

This commit is contained in:
Anthony Rabine 2023-05-15 15:22:23 +02:00
parent 868d4fdc8e
commit 35b990f21f
15 changed files with 176 additions and 81 deletions

View 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

View file

@ -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]

View file

@ -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);
}

View file

@ -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

View file

@ -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>();

View file

@ -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>

View file

@ -58,6 +58,16 @@ void ResourceModel::Clear()
endResetModel();
}
void ResourceModel::BeginChange()
{
beginResetModel();
}
void ResourceModel::EndChange()
{
endResetModel();
}
// ------------------------------- PROXY MODEL -------------------------------

View file

@ -19,6 +19,8 @@ public:
void append(const Resource & res);
void Clear();
void BeginChange();
void EndChange();
private:
StoryProject &m_project;

View file

@ -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();
}

View file

@ -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;
};

View file

@ -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)
{

View file

@ -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;

View file

@ -48,8 +48,13 @@ public:
// default impl
}
virtual std::string Build() {
return "";
}
NodeGeometryData &geometryData() { return m_geometryData; }
private:
NodeId m_nodeId;
NodeGeometryData m_geometryData;

View file

@ -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();
}

View file

@ -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);