Open/load project

This commit is contained in:
Anthony Rabine 2023-05-11 12:16:59 +02:00
parent 85bf8d8e32
commit fc46659e42
19 changed files with 361 additions and 225 deletions

96
story-editor/example.asm Normal file
View 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

View file

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

View file

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

View file

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

View file

@ -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;
}
if (loadFile.open(QIODevice::ReadOnly))
{
QJsonParseError err;
QJsonDocument loadDoc = QJsonDocument::fromJson(loadFile.readAll(), &err);
if (err.error == QJsonParseError::NoError)
{
QJsonObject projectRoot = loadDoc.object();
QString errorString;
if (projectRoot.contains("project"))
{
QJsonObject projectData = projectRoot["project"].toObject();
m_project.name = projectData["name"].toString().toStdString();
// m_project.uuid = projectData["uuid"].toString().toStdString();
}
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
{
QMessageBox::critical(this, tr("Open project error"), err.errorString());
errorMsg = tr("Missing project section in JSON file.");
}
}
else
{
errorMsg = err.errorString();
}
}
else
{
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."));
}

View file

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

View file

@ -2,7 +2,7 @@
#include "model/buffer/qmemorybuffer.h"
MemoryViewDock::MemoryViewDock(const QString &objectName, const QString &title)
: DockWidgetBase(title)
: DockWidgetBase(title, false)
{
setObjectName(objectName);

View file

@ -33,7 +33,7 @@
<enum>QFrame::Box</enum>
</property>
<property name="text">
<string>TextLabel</string>
<string/>
</property>
</widget>
</item>

View file

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

View file

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

View file

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

View file

@ -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.
QJsonObject const internalDataJson = nodeJson["internal-data"].toObject();
QString delegateModelName = internalDataJson["model-name"].toString();
// 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);
setNodeData(restoredNodeId, NodeRole::InPortCount, nodeJson["inPortCount"].toString().toUInt());
Q_EMIT nodeCreated(restoredNodeId);
setNodeData(restoredNodeId,
NodeRole::OutPortCount,
nodeJson["outPortCount"].toString().toUInt());
{
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();
}

View file

@ -131,6 +131,7 @@ public:
}
StoryProject &GetProject() { return m_project; };
void Clear();
signals:
void sigChooseFile(NodeId id);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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