story run icon, save/load resources

This commit is contained in:
Anthony Rabine 2023-05-12 17:36:42 +02:00
parent 5ac03b8e8d
commit ca36d4ac32
14 changed files with 290 additions and 68 deletions

View file

@ -1,5 +1,7 @@
## Arduino MKR Zero (SAMD21G18A) ## Arduino MKR Zero (SAMD21G18A)
Current status: ON DEVELOPMENT
| Category | Maker | Name | Rounded Price | | Category | Maker | Name | Rounded Price |
| ------------------ | ------------------------------ | --------------------- | ------------- | | ------------------ | ------------------------------ | --------------------- | ------------- |
| Main CPU board | Arduino | MKR Zero | 30€ | | Main CPU board | Arduino | MKR Zero | 30€ |

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 24 24"
version="1.1"
id="svg4"
sodipodi:docname="play-circle-green.svg"
inkscape:export-filename="play-circle-green.png"
inkscape:export-xdpi="599.172"
inkscape:export-ydpi="599.172"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="38.514415"
inkscape:cx="8.0619166"
inkscape:cy="14.708779"
inkscape:window-width="1920"
inkscape:window-height="1136"
inkscape:window-x="3840"
inkscape:window-y="40"
inkscape:window-maximized="1"
inkscape:current-layer="svg4"
inkscape:showpageshadow="2"
inkscape:deskcolor="#d1d1d1" />
<path
d="M10,16.5V7.5L16,12M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2Z"
id="path2"
style="fill:#4e9a06" />
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -135,10 +135,13 @@ MainWindow::MainWindow()
{ {
// Take first // Take first
QModelIndex index = selection.at(0); QModelIndex index = selection.at(0);
QString fn = m_resourcesDock->getModel().GetFileName(index.row()); Resource res;
QJsonObject obj; if (m_project.GetResourceAt(index.row(), res))
obj["image"] = fn; {
m_model.setNodeData(id, NodeRole::InternalData, obj.toVariantMap()); QJsonObject obj;
obj["image"] = res.file.c_str();
m_model.setNodeData(id, NodeRole::InternalData, obj.toVariantMap());
}
} }
}); });
@ -268,7 +271,7 @@ void MainWindow::DisplayNode(StoryNode *m_tree, QtNodes::NodeId parentId)
if (m_tree->image >= 0) if (m_tree->image >= 0)
{ {
std::string imageFile = m_project.GetWorkingDir() + "/rf/" + m_project.m_images[m_tree->image].file + ".bmp"; std::string imageFile = ""; // FIXME m_project.GetWorkingDir() + "/rf/" + m_project.m_images[m_tree->image].file + ".bmp";
std::cout << "Node image: " << imageFile << std::endl; std::cout << "Node image: " << imageFile << std::endl;
nodeInternalData["image"] = imageFile.c_str(); nodeInternalData["image"] = imageFile.c_str();
} }
@ -575,6 +578,20 @@ void MainWindow::OpenProject(const QString &filePath)
m_project.SetName(projectData["name"].toString().toStdString()); m_project.SetName(projectData["name"].toString().toStdString());
m_project.SetUuid(projectData["uuid"].toString().toStdString()); m_project.SetUuid(projectData["uuid"].toString().toStdString());
QJsonArray resourcesData = projectData["resources"].toArray();
for (const auto &r : resourcesData)
{
Resource rData;
QJsonObject obj = r.toObject();
rData.type = obj["type"].toString().toStdString();
rData.format = obj["format"].toString().toStdString();
rData.description = obj["description"].toString().toStdString();
rData.file = obj["file"].toString().toStdString();
m_resourcesDock->Append(rData);
}
if (projectRoot.contains("nodegraph")) if (projectRoot.contains("nodegraph"))
{ {
QJsonObject nodeData = projectRoot["nodegraph"].toObject(); QJsonObject nodeData = projectRoot["nodegraph"].toObject();
@ -622,6 +639,21 @@ void MainWindow::SaveProject()
projectData["name"] = m_project.GetName().c_str(); projectData["name"] = m_project.GetName().c_str();
projectData["uuid"] = m_project.GetUuid().c_str(); projectData["uuid"] = m_project.GetUuid().c_str();
QJsonArray resourcesData;
for (std::vector<Resource>::const_iterator it = m_project.Begin(); it != m_project.End(); ++it)
{
auto &r = *it;
QJsonObject obj;
obj["type"] = r.type.c_str();
obj["format"] = r.format.c_str();
obj["description"] = r.description.c_str();
obj["file"] = r.file.c_str();
resourcesData.append(obj);
}
projectData["resources"] = resourcesData;
QJsonObject saveData; QJsonObject saveData;
saveData["project"] = projectData; saveData["project"] = projectData;
saveData["nodegraph"] = jsonModel; saveData["nodegraph"] = jsonModel;

View file

@ -42,7 +42,6 @@ MediaNodeModel::MediaNodeModel(StoryGraphModel &model)
}); });
connect(m_ui.selectImageButton, &QPushButton::clicked, [&](bool enable) { connect(m_ui.selectImageButton, &QPushButton::clicked, [&](bool enable) {
//m_contextMenu->exec(m_widget->mapFromGlobal(QCursor::pos()));
emit m_model.sigChooseFile(getNodeId()); emit m_model.sigChooseFile(getNodeId());
}); });
} }

View file

@ -9,5 +9,6 @@
<file>../assets/close-outline.svg</file> <file>../assets/close-outline.svg</file>
<file>../assets/folder-open-outline.svg</file> <file>../assets/folder-open-outline.svg</file>
<file>../assets/welcome.png</file> <file>../assets/welcome.png</file>
<file>../assets/play-circle-green.png</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -1,15 +1,37 @@
#include "resource_model.h" #include "resource_model.h"
ResourceModel::ResourceModel(StoryProject &project, QObject *parent)
: QAbstractTableModel{parent}
, m_project(project)
{
}
int ResourceModel::rowCount(const QModelIndex &) const
{
return m_project.ResourcesSize();
}
int ResourceModel::columnCount(const QModelIndex &) const
{
return 4;
}
QVariant ResourceModel::data(const QModelIndex &index, int role) const { QVariant ResourceModel::data(const QModelIndex &index, int role) const {
if (role != Qt::DisplayRole && role != Qt::EditRole) return {}; if (role != Qt::DisplayRole && role != Qt::EditRole) return {};
const auto & res = m_data[index.row()]; Resource res;
switch (index.column()) { if (m_project.GetResourceAt(index.row(), res))
case 0: return res.file.c_str(); {
case 1: return res.format.c_str(); switch (index.column()) {
case 2: return res.description.c_str(); case 0: return res.file.c_str();
default: return {}; case 1: return res.format.c_str();
}; case 2: return res.description.c_str();
case 3: return res.type.c_str();
default: ;
};
}
return {};
} }
QVariant ResourceModel::headerData(int section, Qt::Orientation orientation, int role) const { QVariant ResourceModel::headerData(int section, Qt::Orientation orientation, int role) const {
@ -18,30 +40,76 @@ QVariant ResourceModel::headerData(int section, Qt::Orientation orientation, int
case 0: return "File"; case 0: return "File";
case 1: return "Format"; case 1: return "Format";
case 2: return "Description"; case 2: return "Description";
case 3: return "Type";
default: return {}; default: return {};
} }
} }
void ResourceModel::append(const Resource &res) { void ResourceModel::append(const Resource &res) {
beginInsertRows({}, m_data.count(), m_data.count()); beginInsertRows({}, m_project.ResourcesSize(), m_project.ResourcesSize());
m_data.append(res); m_project.AppendResource(res);
endInsertRows(); endInsertRows();
} }
void ResourceModel::Clear() void ResourceModel::Clear()
{ {
beginResetModel(); beginResetModel();
m_data.clear(); m_project.ClearResources();
endResetModel(); endResetModel();
} }
QString ResourceModel::GetFileName(int row) {
QString n;
if (row < m_data.size()) // ------------------------------- PROXY MODEL -------------------------------
{
n = m_data.at(row).file.c_str();
}
return n;
ResourceFilterProxyModel::ResourceFilterProxyModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
} }
void ResourceFilterProxyModel::setFilterType(const QString & type)
{
m_typeFilter = type;
invalidateFilter();
}
bool ResourceFilterProxyModel::filterAcceptsRow(int sourceRow,
const QModelIndex &sourceParent) const
{
QModelIndex indexType = sourceModel()->index(sourceRow, 3, sourceParent);
return (sourceModel()->data(indexType).toString() == m_typeFilter);
}
/*
bool ResourceFilterProxyModel::lessThan(const QModelIndex &left,
const QModelIndex &right) const
{
QVariant leftData = sourceModel()->data(left);
QVariant rightData = sourceModel()->data(right);
if (leftData.userType() == QMetaType::QDateTime) {
return leftData.toDateTime() < rightData.toDateTime();
} else {
static const QRegularExpression emailPattern("[\\w\\.]*@[\\w\\.]*");
QString leftString = leftData.toString();
if (left.column() == 1) {
const QRegularExpressionMatch match = emailPattern.match(leftString);
if (match.hasMatch())
leftString = match.captured(0);
}
QString rightString = rightData.toString();
if (right.column() == 1) {
const QRegularExpressionMatch match = emailPattern.match(rightString);
if (match.hasMatch())
rightString = match.captured(0);
}
return QString::localeAwareCompare(leftString, rightString) < 0;
}
}
*/

View file

@ -10,22 +10,36 @@ class ResourceModel : public QAbstractTableModel
{ {
public: public:
ResourceModel(QObject * parent = {}) : QAbstractTableModel{parent} {} ResourceModel(StoryProject &project, QObject * parent = {});
int rowCount(const QModelIndex &) const override { return m_data.count(); } int rowCount(const QModelIndex &) const override;
int columnCount(const QModelIndex &) const override { return 3; } int columnCount(const QModelIndex &) const override;
QVariant data(const QModelIndex &index, int role) const override; QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
void append(const Resource & res); void append(const Resource & res);
void Clear(); void Clear();
QString GetFileName(int row); private:
StoryProject &m_project;
};
QList<Resource> GetData() const { return m_data; } class ResourceFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
ResourceFilterProxyModel(QObject *parent = nullptr);
void setFilterType(const QString &type);
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
// bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
private: private:
QList<Resource> m_data;
QString m_typeFilter;
}; };
#endif // RESOURCE_MODEL_H #endif // RESOURCE_MODEL_H

View file

@ -4,6 +4,7 @@
ResourcesDock::ResourcesDock(StoryProject &project) ResourcesDock::ResourcesDock(StoryProject &project)
: m_project(project) : m_project(project)
, m_resourcesModel(project)
, DockWidgetBase(tr("Resources"), true) , DockWidgetBase(tr("Resources"), true)
{ {
setObjectName("ResourcesDock"); // used to save the state setObjectName("ResourcesDock"); // used to save the state
@ -11,37 +12,46 @@ ResourcesDock::ResourcesDock(StoryProject &project)
m_uiOstResources.setupUi(this); m_uiOstResources.setupUi(this);
m_uiOstResources.resourcesView->setModel(&m_resourcesModel); m_uiOstResources.resourcesView->setModel(&m_resourcesModel);
m_proxyModel.setSourceModel(&m_resourcesModel);
connect(m_uiOstResources.addImageButton, &QPushButton::clicked, [=](bool checked) { connect(m_uiOstResources.addImageButton, &QPushButton::clicked, [=](bool checked) {
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),
".", ".",
tr("Images (*.bmp)")); tr("Images (*.bmp)"));
std::filesystem::path p(fileName.toStdString()); if (std::filesystem::exists(fileName.toStdString()))
std::filesystem::path p2 = m_project.ImagesPath() / p.filename().generic_string(); {
std::filesystem::copy(p, p2); std::filesystem::path p(fileName.toStdString());
std::filesystem::path p2 = m_project.ImagesPath() / p.filename().generic_string();
Resource res; std::filesystem::copy(p, p2, std::filesystem::copy_options::overwrite_existing);
res.format = "BMP";
res.file = p.filename();
m_resourcesModel.append(res);
Resource res;
res.format = "BMP";
res.type = "image";
res.file = p.filename();
m_resourcesModel.append(res);
}
}); });
connect(m_uiOstResources.addSoundButton, &QPushButton::clicked, [=](bool checked) { connect(m_uiOstResources.addSoundButton, &QPushButton::clicked, [=](bool checked) {
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),
".", ".",
tr("Sounds (*.wav)")); tr("Sound files (*.wav, *.mp3, *.m4a)"));
std::filesystem::path p(fileName.toStdString()); if (std::filesystem::exists(fileName.toStdString()))
std::filesystem::path p2 = m_project.SoundsPath() / p.filename().generic_string(); {
std::filesystem::copy(p, p2); std::filesystem::path p(fileName.toStdString());
std::filesystem::path p2 = m_project.SoundsPath() / p.filename().generic_string();
std::filesystem::copy(p, p2, std::filesystem::copy_options::overwrite_existing);
Resource res; Resource res;
res.format = "WAV"; res.format = "WAV";
res.file = p.filename(); res.type = "sound";
m_resourcesModel.append(res); res.file = p.filename();
m_resourcesModel.append(res);
}
}); });
} }
@ -50,16 +60,21 @@ void ResourcesDock::Initialize()
} }
void ResourcesDock::Append(const Resource &res)
{
m_resourcesModel.append(res);
}
void ResourcesDock::SaveToProject() void ResourcesDock::SaveToProject()
{ {
m_project.Clear(); m_project.Clear();
for (auto & r : m_resourcesModel.GetData()) // for (auto & r : m_resourcesModel.GetData())
{ // {
m_project.m_images.push_back(r); // m_project.m_images.push_back(r);
} // }
} }
void ResourcesDock::slotClear() void ResourcesDock::Clear()
{ {
m_resourcesModel.Clear(); m_resourcesModel.Clear();
} }

View file

@ -14,18 +14,21 @@ public:
void Initialize(); void Initialize();
QList<Resource> GetResources() const { return m_resourcesModel.GetData(); }
ResourceModel &getModel() { return m_resourcesModel; } ResourceModel &getModel() { return m_resourcesModel; }
ResourceFilterProxyModel &getFilteredModel() { return m_proxyModel; }
void SetFilterType(const QString &type) { m_proxyModel.setFilterType(type); }
void Append(const Resource &res);
void SaveToProject(); void SaveToProject();
void Clear();
public slots:
void slotClear();
private: private:
StoryProject &m_project; StoryProject &m_project;
Ui::ostResources m_uiOstResources; Ui::ostResources m_uiOstResources;
ResourceModel m_resourcesModel; ResourceModel m_resourcesModel;
ResourceFilterProxyModel m_proxyModel;
}; };
#endif // RESOURCESDOCK_H #endif // RESOURCESDOCK_H

View file

@ -35,9 +35,10 @@ void StoryProject::Initialize(const std::string &file_path)
bool StoryProject::Load(const std::string &file_path) bool StoryProject::Load(const std::string &file_path)
{ {
std::ifstream f(file_path); std::ifstream f(file_path);
bool success = false; bool success = false;
/*
std::filesystem::path p(file_path); std::filesystem::path p(file_path);
m_working_dir= p.parent_path(); m_working_dir= p.parent_path();
@ -116,7 +117,7 @@ bool StoryProject::Load(const std::string &file_path)
{ {
CreateTree(); CreateTree();
} }
*/
return success; return success;
} }
@ -191,6 +192,27 @@ void StoryProject::ReplaceCharacter(std::string &theString, const std::string &t
while (found != std::string::npos); while (found != std::string::npos);
} }
void StoryProject::AppendResource(const Resource &res)
{
m_resources.push_back(res);
}
bool StoryProject::GetResourceAt(int index, Resource &resOut)
{
bool success = false;
if ((index >= 0) && (index < m_resources.size()))
{
resOut = m_resources[index];
success = true;
}
return success;
}
void StoryProject::ClearResources()
{
m_resources.clear();
}
std::string StoryProject::GetFileExtension(const std::string &fileName) std::string StoryProject::GetFileExtension(const std::string &fileName)
{ {
if(fileName.find_last_of(".") != std::string::npos) if(fileName.find_last_of(".") != std::string::npos)
@ -204,7 +226,7 @@ std::string StoryProject::Compile()
chip32 << "\tjump .entry\r\n"; chip32 << "\tjump .entry\r\n";
for (auto & r : m_images) for (auto & r : m_resources)
{ {
std::string fileName = GetFileName(r.file); std::string fileName = GetFileName(r.file);
std::string ext = GetFileExtension(fileName); std::string ext = GetFileExtension(fileName);

View file

@ -40,6 +40,7 @@ struct Resource
std::string file; std::string file;
std::string description; std::string description;
std::string format; std::string format;
std::string type;
}; };
struct StoryProject struct StoryProject
@ -52,20 +53,14 @@ struct StoryProject
std::string m_type; std::string m_type;
std::string m_code; std::string m_code;
std::vector<Resource> m_images;
std::vector<Resource> m_sounds;
StoryNode *m_tree; StoryNode *m_tree;
bool Load(const std::string &file_path); bool Load(const std::string &file_path);
void CreateTree(); void CreateTree();
void Clear() { void Clear() {
m_uuid = ""; m_uuid = "";
m_working_dir = ""; m_working_dir = "";
m_images.clear(); m_resources.clear();
m_sounds.clear();
m_initialized = false; m_initialized = false;
} }
@ -88,6 +83,17 @@ struct StoryProject
static std::string GetFileName(const std::string &path); static std::string GetFileName(const std::string &path);
static void ReplaceCharacter(std::string &theString, const std::string &toFind, const std::string &toReplace); static void ReplaceCharacter(std::string &theString, const std::string &toFind, const std::string &toReplace);
// ------------- Resources Management
void AppendResource(const Resource &res);
bool GetResourceAt(int index, Resource &resOut);
void ClearResources();
int ResourcesSize() const { return m_resources.size(); }
std::vector<Resource>::const_iterator Begin() const { return m_resources.begin(); }
std::vector<Resource>::const_iterator End() const { return m_resources.end(); }
public: public:
// Initialize with an existing project // Initialize with an existing project
void Initialize(const std::string &file_path); void Initialize(const std::string &file_path);
@ -104,6 +110,7 @@ private:
std::filesystem::path m_soundsPath; std::filesystem::path m_soundsPath;
bool m_initialized{false}; bool m_initialized{false};
std::vector<Resource> m_resources;
std::string m_working_dir; /// Temporary folder based on the uuid, where the archive is unzipped std::string m_working_dir; /// Temporary folder based on the uuid, where the archive is unzipped
std::string m_project_path; /// JSON project file std::string m_project_path; /// JSON project file

View file

@ -67,6 +67,21 @@ void ToolBar::createActions(QMenuBar *menuBar)
menuBar->addSeparator(); menuBar->addSeparator();
// -------------------------------- DEBUG STORY
QMenu *storyMenu = menuBar->addMenu(tr("&Story"));
// ------------ Run
{
QIcon icon(":/assets/play-circle-green.png");
m_runAction = new QAction(icon, tr("&Close project"), this);
m_runAction->setStatusTip(tr("Build and run current project"));
connect(m_runAction, &QAction::triggered, this, &ToolBar::sigRun);
storyMenu->addAction(m_runAction);
addSeparator();
addAction(m_runAction);
}
// -------------------------------- WINDOWS MENU
m_windowsMenu = menuBar->addMenu(tr("&Windows")); m_windowsMenu = menuBar->addMenu(tr("&Windows"));
auto act = m_windowsMenu->addAction(tr("Reset docks position")); auto act = m_windowsMenu->addAction(tr("Reset docks position"));
@ -102,6 +117,7 @@ void ToolBar::SetActionsActive(bool enable)
m_windowsMenu->setEnabled(enable); m_windowsMenu->setEnabled(enable);
m_closeProjectAction->setEnabled(enable); m_closeProjectAction->setEnabled(enable);
m_saveProjectAction->setEnabled(enable); m_saveProjectAction->setEnabled(enable);
m_runAction->setEnabled(enable);
} }

View file

@ -23,15 +23,17 @@ signals:
void sigExit(); void sigExit();
void sigDefaultDocksPosition(); void sigDefaultDocksPosition();
void sigOpenRecent(const QString &project); void sigOpenRecent(const QString &project);
void sigRun();
private slots: private slots:
void slotAbout(); void slotAbout();
private: private:
QMenu *m_windowsMenu; QMenu *m_windowsMenu{nullptr};
QMenu *m_recentProjectsMenu; QMenu *m_recentProjectsMenu{nullptr};
QAction *m_saveProjectAction; QAction *m_saveProjectAction{nullptr};
QAction *m_closeProjectAction; QAction *m_closeProjectAction{nullptr};
QAction *m_runAction{nullptr};
QList<QAction *> m_actionDockList; QList<QAction *> m_actionDockList;
}; };