mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
Open/load project
This commit is contained in:
parent
85bf8d8e32
commit
fc46659e42
19 changed files with 361 additions and 225 deletions
96
story-editor/example.asm
Normal file
96
story-editor/example.asm
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
; jump over the data, to our entry label
|
||||
jump .entry
|
||||
|
||||
; Constant elements are separated by commas
|
||||
$imageBird DC8, "example.bmp", 8 ; string of chars, followed by one byte
|
||||
$soundChoice DC8, "choose1.snd"
|
||||
$yaya DC8, "yaya.bmp"
|
||||
$rabbit DC8, "rabbit.bmp"
|
||||
$someConstant DC32, 12456789
|
||||
|
||||
; Liste des noeuds à appeler
|
||||
$ChoiceObject DC32, 2, .MEDIA_02, .MEDIA_03
|
||||
|
||||
; DVsxx to declare a variable in RAM, followed by the number of elements
|
||||
$MyArray DV8, 10 ; array of 10 bytes
|
||||
$RamData1 DV32, 1 ; one 32-bit integer
|
||||
$ChoiceMem DV32, 10 ; 10 elements for the choices, to be generated
|
||||
|
||||
; label definition
|
||||
.entry: ;; comment here should work
|
||||
|
||||
|
||||
; Syscall test: show image and play sound
|
||||
lcons r0, $imageBird ; image name address in ROM located in R0 (null terminated)
|
||||
lcons r1, $soundChoice ; set to 0 if no sound
|
||||
syscall 1
|
||||
lcons r0, $ChoiceObject
|
||||
jump .media ; no return possible, so a jump is enough
|
||||
|
||||
; 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
|
||||
|
||||
.MEDIA_02:
|
||||
lcons r0, $yaya ; image name address in ROM located in R0 (null terminated)
|
||||
lcons r1, $soundChoice ; set to 0 if no sound
|
||||
syscall 1
|
||||
ret
|
||||
|
||||
.MEDIA_03:
|
||||
lcons r0, $rabbit
|
||||
lcons r1, $soundChoice
|
||||
syscall 1
|
||||
ret
|
||||
|
||||
.SYSCALL_TEST:
|
||||
; syscall test: wait for event
|
||||
lcons r0, 0xFF ; wait for all event, blocking
|
||||
syscall 2
|
||||
|
||||
; We create a stupid loop just for RAM variable testing
|
||||
|
||||
lcons r0, 4 ; prepare loop: 4 iterations
|
||||
lcons r6, $RamData1 ; store address to R6
|
||||
store @r6, r0, 4 ; save R0 in RAM
|
||||
lcons r1, 1
|
||||
.loop:
|
||||
load r0, @r6, 4 ; load this variable
|
||||
sub r0, r1
|
||||
store @r6, r0, 4 ; save R0 in RAM
|
||||
skipz r0 ; skip loop if R0 == 0
|
||||
jump .loop
|
||||
|
||||
|
||||
mov r0, r2 ; copy R2 into R0 (blank space between , and R2)
|
||||
mov R0,R2 ; copy R2 into R0 (NO blank space between , and R2)
|
||||
|
||||
halt
|
||||
|
|
@ -17,9 +17,30 @@ bool EventFilter::eventFilter( QObject *obj, QEvent *event )
|
|||
}
|
||||
|
||||
|
||||
DockWidgetBase::DockWidgetBase(const QString &title)
|
||||
DockWidgetBase::DockWidgetBase(const QString &title, bool visibility)
|
||||
: QDockWidget(title)
|
||||
, m_visibility(visibility ? tribool::True : tribool::False)
|
||||
{
|
||||
EventFilter* filter = new EventFilter( this );
|
||||
installEventFilter( filter );
|
||||
setAllowedAreas(Qt::AllDockWidgetAreas);
|
||||
}
|
||||
|
||||
void DockWidgetBase::Close()
|
||||
{
|
||||
// Memorize prefered visibility
|
||||
// m_visibility = isVisible() ? tribool::True : tribool::False;
|
||||
hide();
|
||||
}
|
||||
|
||||
void DockWidgetBase::Open()
|
||||
{
|
||||
// Restore prefered visibility
|
||||
if (m_visibility) {
|
||||
show();
|
||||
} else {
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,14 @@ class DockWidgetBase : public QDockWidget
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DockWidgetBase(const QString &title);
|
||||
DockWidgetBase(const QString &title, bool visibility);
|
||||
|
||||
void Close();
|
||||
void Open();
|
||||
|
||||
private:
|
||||
enum tribool: uint8_t {False = 0, True = 1, Unknown = 2};
|
||||
tribool m_visibility{Unknown};
|
||||
};
|
||||
|
||||
#endif // DOCK_WIDGET_BASE_H
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#include "log_dock.h"
|
||||
|
||||
LogDock::LogDock()
|
||||
: DockWidgetBase(tr("Logs"))
|
||||
: DockWidgetBase(tr("Logs"), true)
|
||||
{
|
||||
setObjectName("OstHmiDock"); // used to save the state
|
||||
setObjectName("LogsDock"); // used to save the state
|
||||
m_logUi.setupUi(this);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -51,12 +51,12 @@ typedef void (*message_output_t)(QtMsgType , const QMessageLogContext &, const Q
|
|||
MainWindow::MainWindow()
|
||||
: m_model(m_project)
|
||||
, m_scene(m_model)
|
||||
, m_settings("D8S", "OpenStoryTeller")
|
||||
, m_settings("OpenStoryTeller", "OpenStoryTellerEditor")
|
||||
{
|
||||
m_project.Clear();
|
||||
// SetupTemporaryProject();
|
||||
|
||||
// RefreshProjectInformation();
|
||||
m_scene.setDropShadowEffect(false);
|
||||
m_scene.nodeGeometry().setMarginsRatio(0.02);
|
||||
|
||||
m_view = new GraphicsView(&m_scene);
|
||||
m_view->setScaleRange(0, 0);
|
||||
|
|
@ -64,10 +64,9 @@ MainWindow::MainWindow()
|
|||
setCentralWidget(m_view);
|
||||
|
||||
m_toolbar = new ToolBar();
|
||||
m_scene.setDropShadowEffect(false);
|
||||
m_scene.nodeGeometry().setMarginsRatio(0.02);
|
||||
m_toolbar->createActions(menuBar());
|
||||
addToolBar(m_toolbar);
|
||||
addToolBar(Qt::LeftToolBarArea, m_toolbar);
|
||||
m_toolbar->setVisible(true);
|
||||
|
||||
connect(m_toolbar, &ToolBar::sigDefaultDocksPosition, this, &MainWindow::slotDefaultDocksPosition);
|
||||
|
||||
|
|
@ -118,6 +117,9 @@ MainWindow::MainWindow()
|
|||
addDockWidget(Qt::DockWidgetArea::RightDockWidgetArea, m_romView);
|
||||
m_toolbar->AddDockToMenu(m_romView->toggleViewAction());
|
||||
|
||||
tabifyDockWidget(m_vmDock, m_romView);
|
||||
tabifyDockWidget(m_romView, m_ramView);
|
||||
|
||||
m_chooseFileDialog = new QDialog(this);
|
||||
m_chooseFileUi.setupUi(m_chooseFileDialog);
|
||||
m_chooseFileDialog->close();
|
||||
|
|
@ -167,8 +169,6 @@ MainWindow::MainWindow()
|
|||
Callback<uint8_t(uint8_t)>::func = std::bind(&MainWindow::Syscall, this, std::placeholders::_1);
|
||||
m_chip32_ctx.syscall = static_cast<syscall_t>(Callback<uint8_t(uint8_t)>::callback);
|
||||
|
||||
readSettings();
|
||||
|
||||
connect(m_toolbar, &ToolBar::sigNew, this, [&]() {
|
||||
NewProject();
|
||||
});
|
||||
|
|
@ -178,7 +178,7 @@ MainWindow::MainWindow()
|
|||
});
|
||||
|
||||
connect(m_toolbar, &ToolBar::sigOpen, this, [&]() {
|
||||
OpenProject();
|
||||
OpenProjectDialog();
|
||||
});
|
||||
|
||||
connect(m_toolbar, &ToolBar::sigClose, this, [&]() {
|
||||
|
|
@ -189,14 +189,21 @@ MainWindow::MainWindow()
|
|||
ExitProgram();
|
||||
});
|
||||
|
||||
connect(m_toolbar, &ToolBar::sigOpenRecent, this, [&](const QString &recent) {
|
||||
CloseProject();
|
||||
OpenProject(recent);
|
||||
});
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
qInstallMessageHandler(cb);
|
||||
|
||||
qDebug() << "Started StoryTeller Editor";
|
||||
readSettings();
|
||||
qDebug() << "Settings location: " << m_settings.fileName();
|
||||
qDebug() << "Welcome to StoryTeller Editor";
|
||||
|
||||
CloseProject();
|
||||
|
||||
|
|
@ -216,26 +223,6 @@ void MainWindow::slotWelcome()
|
|||
msgBox.exec();
|
||||
}
|
||||
|
||||
void MainWindow::SetupTemporaryProject()
|
||||
{
|
||||
/*
|
||||
QString appDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
|
||||
// Look at any previous workspace used
|
||||
// Generate a project unique ID name if no any
|
||||
m_settings.setValue("project/workspace", m_project.uuid.c_str());
|
||||
|
||||
m_project.working_dir = QString(appDir + QDir::separator() + m_project.uuid.c_str()).toStdString();
|
||||
m_project.name = "Untitled project";
|
||||
m_project.Initialize(m_settings.value("project/workspace", QUuid::createUuid().toString()).toString().toStdString()
|
||||
);
|
||||
|
||||
// m_resourcesDock->Initialize();
|
||||
|
||||
qDebug() << "Working dir is: " << m_project.working_dir.c_str();
|
||||
*/
|
||||
}
|
||||
|
||||
void MainWindow::ExitProgram()
|
||||
{
|
||||
// FIXME: warn if project not saved
|
||||
|
|
@ -243,7 +230,7 @@ void MainWindow::ExitProgram()
|
|||
|
||||
void MainWindow::RefreshProjectInformation()
|
||||
{
|
||||
setWindowTitle(QString("StoryTeller Editor - ") + m_project.GetWorkingDir().c_str());
|
||||
setWindowTitle(QString("StoryTeller Editor - ") + m_project.GetProjectFilePath().c_str());
|
||||
}
|
||||
|
||||
void MainWindow::MessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||
|
|
@ -258,12 +245,20 @@ void MainWindow::readSettings()
|
|||
|
||||
restoreGeometry(m_settings.value("MainWindow/geometry").toByteArray());
|
||||
restoreState(m_settings.value("MainWindow/windowState").toByteArray());
|
||||
|
||||
// Restore recent projects list
|
||||
m_recentProjects = m_settings.value("RecentProjects").toStringList();
|
||||
m_toolbar->GenerateRecentProjectsMenu(m_recentProjects);
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
m_settings.setValue("MainWindow/geometry", saveGeometry());
|
||||
m_settings.setValue("MainWindow/windowState", saveState());
|
||||
|
||||
// Memorize recent projects list
|
||||
m_settings.setValue("RecentProjects", m_recentProjects);
|
||||
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
|
|
@ -485,11 +480,11 @@ void MainWindow::NewProject()
|
|||
m_project.SetDisplayFormat(s.width(), s.height());
|
||||
m_project.SetImageFormat(m_newProjectDialog->GetImageFormat());
|
||||
m_project.SetSoundFormat(m_newProjectDialog->GetSoundFormat());
|
||||
m_project.SetName(m_newProjectDialog->GetProjectName().toStdString());
|
||||
m_project.SetUuid(QUuid::createUuid().toString().toStdString());
|
||||
|
||||
m_toolbar->SetAllDocks(true);
|
||||
m_toolbar->SetActionsActive(true);
|
||||
m_toolbar->ShowAllDocks(true);
|
||||
m_view->setEnabled(true);
|
||||
SaveProject();
|
||||
EnableProject();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -497,51 +492,124 @@ void MainWindow::CloseProject()
|
|||
{
|
||||
m_project.Clear();
|
||||
|
||||
m_toolbar->SetAllDocks(false);
|
||||
m_model.Clear();
|
||||
|
||||
m_ostHmiDock->Close();
|
||||
m_resourcesDock->Close();
|
||||
m_scriptEditorDock->Close();
|
||||
m_vmDock->Close();
|
||||
m_ramView->Close();
|
||||
m_romView->Close();
|
||||
m_logDock->Close();
|
||||
|
||||
m_toolbar->SetActionsActive(false);
|
||||
m_view->setEnabled(false);
|
||||
}
|
||||
|
||||
void MainWindow::OpenProject()
|
||||
void MainWindow::EnableProject()
|
||||
{
|
||||
QString fn = QFileDialog::getOpenFileName(this, tr("Open project file"),
|
||||
QDir::homePath(),
|
||||
tr("StoryEditor Project (project.json)"));
|
||||
// Add to recent if not exists
|
||||
if (!m_recentProjects.contains(m_project.GetProjectFilePath().c_str()))
|
||||
{
|
||||
m_recentProjects.push_front(m_project.GetProjectFilePath().c_str());
|
||||
// Limit to 10 recent projects
|
||||
if (m_recentProjects.size() > 10) {
|
||||
m_recentProjects.pop_back();
|
||||
}
|
||||
m_toolbar->GenerateRecentProjectsMenu(m_recentProjects);
|
||||
}
|
||||
|
||||
m_project.Initialize(fn.toStdString());
|
||||
m_ostHmiDock->Open();
|
||||
m_resourcesDock->Open();
|
||||
m_scriptEditorDock->Open();
|
||||
m_vmDock->Open();
|
||||
m_ramView->Open();
|
||||
m_romView->Open();
|
||||
m_logDock->Open();
|
||||
|
||||
m_toolbar->SetActionsActive(true);
|
||||
m_view->setEnabled(true);
|
||||
}
|
||||
|
||||
void MainWindow::OpenProjectDialog()
|
||||
{
|
||||
QFileDialog dialog(this);
|
||||
|
||||
dialog.setNameFilter(tr("StoryEditor Project (project.json)"));
|
||||
dialog.setFileMode(QFileDialog::ExistingFile);
|
||||
dialog.setDirectory(QDir::homePath());
|
||||
|
||||
if (dialog.exec())
|
||||
{
|
||||
QStringList fileNames = dialog.selectedFiles();
|
||||
|
||||
if (fileNames.size() == 1)
|
||||
{
|
||||
OpenProject(fileNames.at(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::OpenProject(const QString &filePath)
|
||||
{
|
||||
bool success = false;
|
||||
QString errorMsg;
|
||||
|
||||
m_project.Initialize(filePath.toStdString());
|
||||
|
||||
QFile loadFile(m_project.GetProjectFilePath().c_str());
|
||||
|
||||
if (!loadFile.open(QIODevice::ReadOnly)) {
|
||||
qWarning("Couldn't open project file.");
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonParseError err;
|
||||
QJsonDocument loadDoc = QJsonDocument::fromJson(loadFile.readAll(), &err);
|
||||
|
||||
if (err.error == QJsonParseError::NoError)
|
||||
if (loadFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QJsonObject projectRoot = loadDoc.object();
|
||||
QString errorString;
|
||||
QJsonParseError err;
|
||||
QJsonDocument loadDoc = QJsonDocument::fromJson(loadFile.readAll(), &err);
|
||||
|
||||
if (projectRoot.contains("project"))
|
||||
if (err.error == QJsonParseError::NoError)
|
||||
{
|
||||
QJsonObject projectData = projectRoot["project"].toObject();
|
||||
QJsonObject projectRoot = loadDoc.object();
|
||||
|
||||
m_project.name = projectData["name"].toString().toStdString();
|
||||
// m_project.uuid = projectData["uuid"].toString().toStdString();
|
||||
if (projectRoot.contains("project"))
|
||||
{
|
||||
QJsonObject projectData = projectRoot["project"].toObject();
|
||||
|
||||
m_project.SetName(projectData["name"].toString().toStdString());
|
||||
m_project.SetUuid(projectData["uuid"].toString().toStdString());
|
||||
|
||||
if (projectRoot.contains("nodegraph"))
|
||||
{
|
||||
QJsonObject nodeData = projectRoot["nodegraph"].toObject();
|
||||
m_model.load(nodeData);
|
||||
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMsg = tr("Missing nodegraph section in JSON file.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMsg = tr("Missing project section in JSON file.");
|
||||
}
|
||||
}
|
||||
|
||||
if (projectRoot.contains("nodegraph"))
|
||||
else
|
||||
{
|
||||
QJsonObject nodeData = projectRoot["nodegraph"].toObject();
|
||||
m_model.load(nodeData);
|
||||
errorMsg = err.errorString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Open project error"), err.errorString());
|
||||
errorMsg = tr("Could not open project file.");
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
EnableProject();
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << errorMsg;
|
||||
QMessageBox::critical(this, tr("Open project error"), errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -551,8 +619,8 @@ void MainWindow::SaveProject()
|
|||
QJsonObject jsonModel = m_model.save();
|
||||
|
||||
QJsonObject projectData;
|
||||
projectData["name"] = m_project.name.c_str();
|
||||
// projectData["uuid"] = m_project.uuid.c_str();
|
||||
projectData["name"] = m_project.GetName().c_str();
|
||||
projectData["uuid"] = m_project.GetUuid().c_str();
|
||||
|
||||
QJsonObject saveData;
|
||||
saveData["project"] = projectData;
|
||||
|
|
@ -572,12 +640,4 @@ void MainWindow::SaveProject()
|
|||
statusBar()->showMessage(tr("Saved '%1'").arg(m_project.GetProjectFilePath().c_str()), 2000);
|
||||
}
|
||||
|
||||
void MainWindow::about()
|
||||
{
|
||||
QMessageBox::about(this, tr("About OST Editor"),
|
||||
tr("OpenStoryTeller node editor."
|
||||
"Build your own stories on an open source hardware."));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ private:
|
|||
QDialog *m_chooseFileDialog;
|
||||
Ui::chooseFileDIalog m_chooseFileUi;
|
||||
NewProjectDialog *m_newProjectDialog{nullptr};
|
||||
QStringList m_recentProjects;
|
||||
|
||||
// VM
|
||||
uint8_t m_rom_data[16*1024];
|
||||
|
|
@ -158,7 +159,6 @@ private:
|
|||
void createStatusBar();
|
||||
void SaveProject();
|
||||
void DisplayNode(StoryNode *m_tree, QtNodes::NodeId parentId);
|
||||
void about();
|
||||
void buildScript();
|
||||
void highlightNextLine();
|
||||
void readSettings();
|
||||
|
|
@ -170,11 +170,12 @@ private:
|
|||
void MessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
|
||||
void NewProject();
|
||||
|
||||
void SetupTemporaryProject();
|
||||
void RefreshProjectInformation();
|
||||
void CloseProject();
|
||||
void OpenProject();
|
||||
void OpenProjectDialog();
|
||||
void ExitProgram();
|
||||
void EnableProject();
|
||||
void OpenProject(const QString &filePath);
|
||||
};
|
||||
|
||||
#endif // MAIN_WINDOW_H
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "model/buffer/qmemorybuffer.h"
|
||||
|
||||
MemoryViewDock::MemoryViewDock(const QString &objectName, const QString &title)
|
||||
: DockWidgetBase(title)
|
||||
: DockWidgetBase(title, false)
|
||||
{
|
||||
setObjectName(objectName);
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
<enum>QFrame::Box</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include <QPixmap>
|
||||
|
||||
OstHmiDock::OstHmiDock()
|
||||
: DockWidgetBase(tr("StoryTeller HMI"))
|
||||
: DockWidgetBase(tr("StoryTeller HMI"), true)
|
||||
{
|
||||
setObjectName("OstHmiDock"); // used to save the state
|
||||
m_uiOstDisplay.setupUi(this);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
ResourcesDock::ResourcesDock(StoryProject &project)
|
||||
: m_project(project)
|
||||
, DockWidgetBase(tr("Resources"))
|
||||
, DockWidgetBase(tr("Resources"), true)
|
||||
{
|
||||
setObjectName("ResourcesDock"); // used to save the state
|
||||
|
||||
|
|
|
|||
|
|
@ -1,114 +1,12 @@
|
|||
#include "script_editor_dock.h"
|
||||
|
||||
static const std::string test1 = R"(
|
||||
; jump over the data, to our entry label
|
||||
jump .entry
|
||||
|
||||
; Constant elements are separated by commas
|
||||
$imageBird DC8, "example.bmp", 8 ; string of chars, followed by one byte
|
||||
$soundChoice DC8, "choose1.snd"
|
||||
$yaya DC8, "yaya.bmp"
|
||||
$rabbit DC8, "rabbit.bmp"
|
||||
$someConstant DC32, 12456789
|
||||
|
||||
; Liste des noeuds à appeler
|
||||
$ChoiceObject DC32, 2, .MEDIA_02, .MEDIA_03
|
||||
|
||||
; DVsxx to declare a variable in RAM, followed by the number of elements
|
||||
$MyArray DV8, 10 ; array of 10 bytes
|
||||
$RamData1 DV32, 1 ; one 32-bit integer
|
||||
$ChoiceMem DV32, 10 ; 10 elements for the choices, to be generated
|
||||
|
||||
; label definition
|
||||
.entry: ;; comment here should work
|
||||
|
||||
|
||||
; Syscall test: show image and play sound
|
||||
lcons r0, $imageBird ; image name address in ROM located in R0 (null terminated)
|
||||
lcons r1, $soundChoice ; set to 0 if no sound
|
||||
syscall 1
|
||||
lcons r0, $ChoiceObject
|
||||
jump .media ; no return possible, so a jump is enough
|
||||
|
||||
; 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
|
||||
|
||||
.MEDIA_02:
|
||||
lcons r0, $yaya ; image name address in ROM located in R0 (null terminated)
|
||||
lcons r1, $soundChoice ; set to 0 if no sound
|
||||
syscall 1
|
||||
ret
|
||||
|
||||
.MEDIA_03:
|
||||
lcons r0, $rabbit
|
||||
lcons r1, $soundChoice
|
||||
syscall 1
|
||||
ret
|
||||
|
||||
.SYSCALL_TEST:
|
||||
; syscall test: wait for event
|
||||
lcons r0, 0xFF ; wait for all event, blocking
|
||||
syscall 2
|
||||
|
||||
; We create a stupid loop just for RAM variable testing
|
||||
|
||||
lcons r0, 4 ; prepare loop: 4 iterations
|
||||
lcons r6, $RamData1 ; store address to R6
|
||||
store @r6, r0, 4 ; save R0 in RAM
|
||||
lcons r1, 1
|
||||
.loop:
|
||||
load r0, @r6, 4 ; load this variable
|
||||
sub r0, r1
|
||||
store @r6, r0, 4 ; save R0 in RAM
|
||||
skipz r0 ; skip loop if R0 == 0
|
||||
jump .loop
|
||||
|
||||
|
||||
mov r0, r2 ; copy R2 into R0 (blank space between , and R2)
|
||||
mov R0,R2 ; copy R2 into R0 (NO blank space between , and R2)
|
||||
|
||||
halt
|
||||
|
||||
)";
|
||||
|
||||
|
||||
ScriptEditorDock::ScriptEditorDock()
|
||||
: DockWidgetBase(tr("Script editor"))
|
||||
: DockWidgetBase(tr("Script editor"), false)
|
||||
{
|
||||
setObjectName("ScriptEditorDock"); // used to save the state
|
||||
|
||||
m_editor = new CodeEditor(this);
|
||||
|
||||
m_editor->setPlainText(test1.c_str());
|
||||
m_highlighter = new Highlighter(m_editor->document());
|
||||
setWidget(m_editor);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -310,11 +310,15 @@ bool StoryGraphModel::deleteNode(NodeId const nodeId)
|
|||
QJsonObject StoryGraphModel::saveNode(NodeId const nodeId) const
|
||||
{
|
||||
QJsonObject nodeJson;
|
||||
|
||||
|
||||
nodeJson["id"] = static_cast<qint64>(nodeId);
|
||||
|
||||
nodeJson["internal-data"] = _models.at(nodeId)->save();
|
||||
auto it = _models.find(nodeId);
|
||||
if (it == _models.end())
|
||||
return nodeJson;
|
||||
|
||||
auto &model = it->second;
|
||||
|
||||
nodeJson["internal-data"] = model->save();
|
||||
|
||||
{
|
||||
QPointF const pos = nodeData(nodeId, NodeRole::Position).value<QPointF>();
|
||||
|
|
@ -352,27 +356,49 @@ QJsonObject StoryGraphModel::save() const
|
|||
|
||||
void StoryGraphModel::loadNode(QJsonObject const &nodeJson)
|
||||
{
|
||||
NodeId restoredNodeId = static_cast<NodeId>(nodeJson["id"].toInt());
|
||||
// Possibility of the id clash when reading it from json and not generating a
|
||||
// new value.
|
||||
// 1. When restoring a scene from a file.
|
||||
// Conflict is not possible because the scene must be cleared by the time of
|
||||
// loading.
|
||||
// 2. When undoing the deletion command. Conflict is not possible
|
||||
// because all the new ids were created past the removed nodes.
|
||||
NodeId restoredNodeId = nodeJson["id"].toInt();
|
||||
|
||||
_nextNodeId = std::max(_nextNodeId, restoredNodeId + 1);
|
||||
|
||||
// Create new node.
|
||||
_nodeIds.insert(restoredNodeId);
|
||||
QJsonObject const internalDataJson = nodeJson["internal-data"].toObject();
|
||||
|
||||
setNodeData(restoredNodeId, NodeRole::InPortCount, nodeJson["inPortCount"].toString().toUInt());
|
||||
QString delegateModelName = internalDataJson["model-name"].toString();
|
||||
|
||||
setNodeData(restoredNodeId,
|
||||
NodeRole::OutPortCount,
|
||||
nodeJson["outPortCount"].toString().toUInt());
|
||||
// std::unique_ptr<NodeDelegateModel> model = _registry->create(delegateModelName);
|
||||
|
||||
auto model = createNode(delegateModelName.toStdString());
|
||||
|
||||
if (model) {
|
||||
// connect(model.get(),
|
||||
// &NodeDelegateModel::dataUpdated,
|
||||
// [restoredNodeId, this](PortIndex const portIndex) {
|
||||
// onOutPortDataUpdated(restoredNodeId, portIndex);
|
||||
// });
|
||||
|
||||
|
||||
_models[restoredNodeId] = model;
|
||||
model->setNodeId(restoredNodeId);
|
||||
_nodeIds.insert(restoredNodeId);
|
||||
|
||||
Q_EMIT nodeCreated(restoredNodeId);
|
||||
|
||||
{
|
||||
QJsonObject posJson = nodeJson["position"].toObject();
|
||||
QPointF const pos(posJson["x"].toDouble(), posJson["y"].toDouble());
|
||||
|
||||
setNodeData(restoredNodeId, NodeRole::Position, pos);
|
||||
}
|
||||
|
||||
Q_EMIT nodeCreated(restoredNodeId);
|
||||
_models[restoredNodeId]->load(internalDataJson);
|
||||
} else {
|
||||
throw std::logic_error(std::string("No registered model with name ")
|
||||
+ delegateModelName.toLocal8Bit().data());
|
||||
}
|
||||
}
|
||||
|
||||
void StoryGraphModel::load(QJsonObject const &jsonDocument)
|
||||
|
|
@ -419,3 +445,11 @@ void StoryGraphModel::removePort(NodeId nodeId, PortType portType, PortIndex por
|
|||
|
||||
portsDeleted();
|
||||
}
|
||||
|
||||
void StoryGraphModel::Clear()
|
||||
{
|
||||
_nodeIds.clear();
|
||||
_connectivity.clear();
|
||||
_models.clear();
|
||||
emit modelReset();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ public:
|
|||
}
|
||||
|
||||
StoryProject &GetProject() { return m_project; };
|
||||
void Clear();
|
||||
|
||||
signals:
|
||||
void sigChooseFile(NodeId id);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ public:
|
|||
QPointF pos;
|
||||
};
|
||||
|
||||
~StoryNodeBase() {
|
||||
std::cout << "Delete node: " << m_nodeId << std::endl;
|
||||
}
|
||||
|
||||
void setNodeId(NodeId id) { m_nodeId = id; }
|
||||
NodeId getNodeId() { return m_nodeId; }
|
||||
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ bool StoryProject::Load(const std::string &file_path)
|
|||
|
||||
m_type = j["type"];
|
||||
m_code = j["code"];
|
||||
name = j["name"];
|
||||
m_name = j["name"];
|
||||
|
||||
success = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -47,8 +47,6 @@ struct StoryProject
|
|||
enum ImageFormat { IMG_FORMAT_BMP_4BITS, IMG_FORMAT_QOIF, IMG_FORMAT_COUNT };
|
||||
enum SoundFormat { SND_FORMAT_WAV, SND_FORMAT_QOAF, SND_FORMAT_COUNT };
|
||||
|
||||
// Project properties and location
|
||||
std::string name; /// human readable name
|
||||
std::vector<StoryNode> m_nodes;
|
||||
|
||||
std::string m_type;
|
||||
|
|
@ -75,9 +73,13 @@ struct StoryProject
|
|||
void SetImageFormat(ImageFormat format);
|
||||
void SetSoundFormat(SoundFormat format);
|
||||
void SetDisplayFormat(int w, int h);
|
||||
void SetName(const std::string &name) { m_name = name; }
|
||||
void SetUuid(const std::string &uuid) { m_uuid = uuid; }
|
||||
|
||||
std::string GetProjectFilePath() const;
|
||||
std::string GetWorkingDir() const;
|
||||
std::string GetName() const { return m_name; }
|
||||
std::string GetUuid() const { return m_uuid; }
|
||||
|
||||
std::filesystem::path ImagesPath() const { return m_imagesPath; }
|
||||
std::filesystem::path SoundsPath() const { return m_soundsPath; }
|
||||
|
|
@ -95,6 +97,8 @@ public:
|
|||
static std::string ToUpper(const std::string &input);
|
||||
|
||||
private:
|
||||
// Project properties and location
|
||||
std::string m_name; /// human readable name
|
||||
std::string m_uuid;
|
||||
std::filesystem::path m_imagesPath;
|
||||
std::filesystem::path m_soundsPath;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
#include "toolbar.h"
|
||||
#include "qmenubar.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
ToolBar::ToolBar()
|
||||
{
|
||||
setObjectName("MainToolBar");
|
||||
|
||||
// setIconSize(QSize(10, 10));
|
||||
// setFixedHeight(36);
|
||||
}
|
||||
|
||||
void ToolBar::createActions(QMenuBar *menuBar)
|
||||
|
|
@ -14,7 +19,7 @@ void ToolBar::createActions(QMenuBar *menuBar)
|
|||
{
|
||||
QIcon icon(":/assets/file-document-plus-outline.svg");
|
||||
QAction *act = new QAction(icon, tr("&New project"), this);
|
||||
act->setShortcuts(QKeySequence::Save);
|
||||
act->setShortcuts(QKeySequence::New);
|
||||
act->setStatusTip(tr("Create a new project"));
|
||||
connect(act, &QAction::triggered, this, &ToolBar::sigNew);
|
||||
fileMenu->addAction(act);
|
||||
|
|
@ -51,6 +56,9 @@ void ToolBar::createActions(QMenuBar *menuBar)
|
|||
addAction(m_closeProjectAction);
|
||||
}
|
||||
|
||||
m_recentProjectsMenu = new QMenu(tr("Recent projects"));
|
||||
fileMenu->addMenu(m_recentProjectsMenu);
|
||||
|
||||
fileMenu->addSeparator();
|
||||
|
||||
QAction *quitAct = fileMenu->addAction(tr("&Quit"), this, &ToolBar::sigExit);
|
||||
|
|
@ -64,20 +72,27 @@ void ToolBar::createActions(QMenuBar *menuBar)
|
|||
auto act = m_windowsMenu->addAction(tr("Reset docks position"));
|
||||
connect(act, &QAction::triggered, this, &ToolBar::sigDefaultDocksPosition);
|
||||
|
||||
m_closeAllDocksAction = m_windowsMenu->addAction(tr("Show/Hide all docks"));
|
||||
m_closeAllDocksAction->setCheckable(true);
|
||||
connect(m_closeAllDocksAction, &QAction::triggered, this, [=] (bool checked) {
|
||||
SetAllDocks(checked);
|
||||
});
|
||||
|
||||
m_windowsMenu->addSeparator();
|
||||
|
||||
QMenu *helpMenu = menuBar->addMenu(tr("&Help"));
|
||||
|
||||
QAction *aboutAct = helpMenu->addAction(tr("&About"), this, &ToolBar::sigAbout);
|
||||
QAction *aboutAct = helpMenu->addAction(tr("&About"), this, &ToolBar::slotAbout);
|
||||
aboutAct->setStatusTip(tr("Show the application's About box"));
|
||||
}
|
||||
|
||||
void ToolBar::GenerateRecentProjectsMenu(const QStringList &recents)
|
||||
{
|
||||
m_recentProjectsMenu->clear();
|
||||
|
||||
for (auto &r: recents)
|
||||
{
|
||||
auto act = m_recentProjectsMenu->addAction(r);
|
||||
connect(act, &QAction::triggered, this, [&, r]() {
|
||||
emit sigOpenRecent(r);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ToolBar::SetActionsActive(bool enable)
|
||||
{
|
||||
for (auto d : m_actionDockList)
|
||||
|
|
@ -89,19 +104,12 @@ void ToolBar::SetActionsActive(bool enable)
|
|||
m_saveProjectAction->setEnabled(enable);
|
||||
}
|
||||
|
||||
void ToolBar::ShowAllDocks(bool enable)
|
||||
{
|
||||
m_closeAllDocksAction->setEnabled(enable);
|
||||
m_closeAllDocksAction->trigger();
|
||||
}
|
||||
|
||||
void ToolBar::SetAllDocks(bool enable)
|
||||
void ToolBar::slotAbout()
|
||||
{
|
||||
for (auto d : m_actionDockList)
|
||||
{
|
||||
d->setChecked(!enable);
|
||||
d->trigger();
|
||||
}
|
||||
QMessageBox::about(this, tr("About OST Editor"),
|
||||
tr("OpenStoryTeller node editor."
|
||||
"Build your own stories on an open source hardware."));
|
||||
}
|
||||
|
||||
void ToolBar::AddDockToMenu(QAction *action)
|
||||
|
|
|
|||
|
|
@ -12,9 +12,8 @@ public:
|
|||
ToolBar();
|
||||
void createActions(QMenuBar *menuBar);
|
||||
void AddDockToMenu(QAction *action);
|
||||
void SetAllDocks(bool enable);
|
||||
void SetActionsActive(bool enable);
|
||||
void ShowAllDocks(bool enable);
|
||||
void GenerateRecentProjectsMenu(const QStringList &recents);
|
||||
|
||||
signals:
|
||||
void sigNew();
|
||||
|
|
@ -22,12 +21,15 @@ signals:
|
|||
void sigOpen();
|
||||
void sigClose();
|
||||
void sigExit();
|
||||
void sigAbout();
|
||||
void sigDefaultDocksPosition();
|
||||
void sigOpenRecent(const QString &project);
|
||||
|
||||
private slots:
|
||||
void slotAbout();
|
||||
|
||||
private:
|
||||
QMenu *m_windowsMenu;
|
||||
QAction *m_closeAllDocksAction;
|
||||
QMenu *m_recentProjectsMenu;
|
||||
QAction *m_saveProjectAction;
|
||||
QAction *m_closeProjectAction;
|
||||
QList<QAction *> m_actionDockList;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include "vm_dock.h"
|
||||
|
||||
VmDock::VmDock(Chip32::Assembler &assembler)
|
||||
: DockWidgetBase(tr("Virtual Machine"))
|
||||
: DockWidgetBase(tr("Virtual Machine"), false)
|
||||
{
|
||||
setObjectName("VirtualMachineDock"); // used to save the state
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue