mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
save docks visibility, fix node, media node complete, vpfr generation (WIP)
This commit is contained in:
parent
35b990f21f
commit
416b6b2f43
24 changed files with 471 additions and 80 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -16,3 +16,7 @@ story-editor/CMakeLists.txt.user
|
|||
hardware/kicad/ost-pico-addon/ost-pico-addon-backups/
|
||||
|
||||
hardware/kicad/ost-pico-addon/fp-info-cache
|
||||
|
||||
*.kra~
|
||||
|
||||
*.png~
|
||||
|
|
|
|||
122
art/pack/LICENSE.md
Normal file
122
art/pack/LICENSE.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
Creative Commons Legal Code
|
||||
|
||||
CC0 1.0 Universal
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
HEREUNDER.
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without fear
|
||||
of later claims of infringement build upon, modify, incorporate in other
|
||||
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||
and for any purposes, including without limitation commercial purposes.
|
||||
These owners may contribute to the Commons to promote the ideal of a free
|
||||
culture and the further production of creative, cultural and scientific
|
||||
works, or to gain reputation or greater distribution for their Work in
|
||||
part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not
|
||||
limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
iii. publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work;
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
in a Work;
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation
|
||||
thereof, including any amended or successor version of such
|
||||
directive); and
|
||||
vii. other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||
of action, whether now known or unknown (including existing as well as
|
||||
future claims and causes of action), in the Work (i) in all territories
|
||||
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||
treaty (including future time extensions), (iii) in any current or future
|
||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||
including without limitation commercial, advertising or promotional
|
||||
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||
member of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal or
|
||||
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||
as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||
be judged legally invalid or ineffective under applicable law, then the
|
||||
Waiver shall be preserved to the maximum extent permitted taking into
|
||||
account Affirmer's express Statement of Purpose. In addition, to the
|
||||
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||
maximum duration provided by applicable law or treaty (including future
|
||||
time extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"License"). The License shall be deemed effective as of the date CC0 was
|
||||
applied by Affirmer to the Work. Should any part of the License for any
|
||||
reason be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||
of the License, and in such case Affirmer hereby affirms that he or she
|
||||
will not (i) exercise any of his or her remaining Copyright and Related
|
||||
Rights in the Work or (ii) assert any associated claims and causes of
|
||||
action with respect to the Work, in either case contrary to Affirmer's
|
||||
express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
b. Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy, or
|
||||
the present or absence of errors, whether or not discoverable, all to
|
||||
the greatest extent permissible under applicable law.
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without
|
||||
limitation any person's Copyright and Related Rights in the Work.
|
||||
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||
consents, permissions or other rights required for any use of the
|
||||
Work.
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to
|
||||
this CC0 or use of the Work.
|
||||
|
||||
2
art/pack/README.md
Normal file
2
art/pack/README.md
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
All arts in this directory are licensed under the Creative Commons CS0 PUBLIC DOMAIN.
|
||||
|
||||
BIN
art/pack/bird.kra
Normal file
BIN
art/pack/bird.kra
Normal file
Binary file not shown.
BIN
art/pack/bird.png
Normal file
BIN
art/pack/bird.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
BIN
art/pack/qui_sera_le_hero.m4a
Normal file
BIN
art/pack/qui_sera_le_hero.m4a
Normal file
Binary file not shown.
|
|
@ -9,11 +9,11 @@ set(CMAKE_AUTOMOC ON)
|
|||
set(CMAKE_AUTORCC ON)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets OpenGLWidgets OpenGL)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Widgets Gui OpenGL OpenGLWidgets)
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets OpenGLWidgets Multimedia OpenGL)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Widgets Gui OpenGLWidgets Multimedia OpenGL )
|
||||
|
||||
set(PROJECT_SOURCES
|
||||
src/main.cpp
|
||||
|
|
@ -113,6 +113,7 @@ target_link_libraries(${PROJECT_NAME} PUBLIC
|
|||
Qt${QT_VERSION_MAJOR}::Gui
|
||||
Qt${QT_VERSION_MAJOR}::OpenGLWidgets
|
||||
Qt${QT_VERSION_MAJOR}::OpenGL
|
||||
Qt${QT_VERSION_MAJOR}::Multimedia
|
||||
QtNodes
|
||||
QHexView
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 91a32d82b38e30459131307f3c23b88a5d4de331
|
||||
Subproject commit 3b9ae0777cd52d6037bdcc6e0b05b57c5eb8701e
|
||||
|
|
@ -43,4 +43,9 @@ void DockWidgetBase::Open()
|
|||
}
|
||||
}
|
||||
|
||||
void DockWidgetBase::SetPreferedVisibility(bool visibility)
|
||||
{
|
||||
m_visibility = visibility ? tribool::True : tribool::False;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ public:
|
|||
|
||||
void Close();
|
||||
void Open();
|
||||
|
||||
void SetPreferedVisibility(bool visibility);
|
||||
bool GetPreferedVisibility() const { return m_visibility; }
|
||||
private:
|
||||
enum tribool: uint8_t {False = 0, True = 1, Unknown = 2};
|
||||
tribool m_visibility{Unknown};
|
||||
|
|
|
|||
|
|
@ -76,11 +76,11 @@ MainWindow::MainWindow()
|
|||
|
||||
m_logDock = new LogDock();
|
||||
addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea, m_logDock);
|
||||
m_toolbar->AddDockToMenu(m_logDock->toggleViewAction());
|
||||
m_toolbar->AddDockToMenu(m_logDock->toggleViewAction(), m_logDock);
|
||||
|
||||
m_ostHmiDock = new OstHmiDock();
|
||||
addDockWidget(Qt::DockWidgetArea::RightDockWidgetArea, m_ostHmiDock);
|
||||
m_toolbar->AddDockToMenu(m_ostHmiDock->toggleViewAction());
|
||||
m_toolbar->AddDockToMenu(m_ostHmiDock->toggleViewAction(), m_ostHmiDock);
|
||||
|
||||
connect(m_ostHmiDock, &OstHmiDock::sigOkButton, [=]() {
|
||||
QCoreApplication::postEvent(this, new VmEvent(VmEvent::evOkButton));
|
||||
|
|
@ -88,15 +88,15 @@ MainWindow::MainWindow()
|
|||
|
||||
m_resourcesDock = new ResourcesDock(m_project, m_resourceModel);
|
||||
addDockWidget(Qt::DockWidgetArea::RightDockWidgetArea, m_resourcesDock);
|
||||
m_toolbar->AddDockToMenu(m_resourcesDock->toggleViewAction());
|
||||
m_toolbar->AddDockToMenu(m_resourcesDock->toggleViewAction(), m_resourcesDock);
|
||||
|
||||
m_scriptEditorDock = new ScriptEditorDock();
|
||||
addDockWidget(Qt::DockWidgetArea::LeftDockWidgetArea, m_scriptEditorDock);
|
||||
m_toolbar->AddDockToMenu(m_scriptEditorDock->toggleViewAction());
|
||||
m_toolbar->AddDockToMenu(m_scriptEditorDock->toggleViewAction(), m_scriptEditorDock);
|
||||
|
||||
m_vmDock = new VmDock(m_assembler);
|
||||
addDockWidget(Qt::DockWidgetArea::RightDockWidgetArea, m_vmDock);
|
||||
m_toolbar->AddDockToMenu(m_vmDock->toggleViewAction());
|
||||
m_toolbar->AddDockToMenu(m_vmDock->toggleViewAction(), m_vmDock);
|
||||
|
||||
connect(m_vmDock, &VmDock::sigCompile, [=]() {
|
||||
// m_scriptEditorDock->setScript(m_project.BuildResources());
|
||||
|
|
@ -112,11 +112,11 @@ MainWindow::MainWindow()
|
|||
|
||||
m_ramView = new MemoryViewDock("RamViewDock", "RAM");
|
||||
addDockWidget(Qt::DockWidgetArea::RightDockWidgetArea, m_ramView);
|
||||
m_toolbar->AddDockToMenu(m_ramView->toggleViewAction());
|
||||
m_toolbar->AddDockToMenu(m_ramView->toggleViewAction(), m_ramView);
|
||||
|
||||
m_romView = new MemoryViewDock("RomViewDock", "ROM");
|
||||
addDockWidget(Qt::DockWidgetArea::RightDockWidgetArea, m_romView);
|
||||
m_toolbar->AddDockToMenu(m_romView->toggleViewAction());
|
||||
m_toolbar->AddDockToMenu(m_romView->toggleViewAction(), m_romView);
|
||||
|
||||
tabifyDockWidget(m_vmDock, m_romView);
|
||||
tabifyDockWidget(m_romView, m_ramView);
|
||||
|
|
@ -208,7 +208,7 @@ MainWindow::MainWindow()
|
|||
|
||||
qInstallMessageHandler(cb);
|
||||
|
||||
readSettings();
|
||||
readSettings(); // restore all windows preferences
|
||||
qDebug() << "Settings location: " << m_settings.fileName();
|
||||
qDebug() << "Welcome to StoryTeller Editor";
|
||||
|
||||
|
|
@ -221,7 +221,6 @@ MainWindow::MainWindow()
|
|||
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
|
||||
|
|
@ -231,7 +230,7 @@ void MainWindow::BuildAndRun()
|
|||
// Add global functions
|
||||
code += ReadResourceFile(":/scripts/media.asm").toStdString();
|
||||
|
||||
code += "\thalt\r\n";
|
||||
// code += "\thalt\r\n";
|
||||
|
||||
m_scriptEditorDock->setScript(code.c_str());
|
||||
|
||||
|
|
@ -298,6 +297,9 @@ void MainWindow::readSettings()
|
|||
// Restore recent projects list
|
||||
m_recentProjects = m_settings.value("RecentProjects").toStringList();
|
||||
m_toolbar->GenerateRecentProjectsMenu(m_recentProjects);
|
||||
|
||||
// retore prefered visibility
|
||||
m_toolbar->SetDocksPreferences(m_settings.value("PreferedVisibility"));
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
|
|
@ -308,6 +310,9 @@ void MainWindow::closeEvent(QCloseEvent *event)
|
|||
// Memorize recent projects list
|
||||
m_settings.setValue("RecentProjects", m_recentProjects);
|
||||
|
||||
// Memorize all docks prefered visibiliy
|
||||
m_settings.setValue("PreferedVisibility", m_toolbar->GetDocksPreferences());
|
||||
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@
|
|||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
|
@ -59,9 +62,9 @@
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<widget class="QLabel" name="imageName">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -97,9 +100,9 @@
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<widget class="QLabel" name="soundName">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -111,7 +114,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_4">
|
||||
<widget class="QPushButton" name="playSoundButton">
|
||||
<property name="icon">
|
||||
<iconset resource="ost-editor.qrc">
|
||||
<normaloff>:/assets/play-circle.png</normaloff>:/assets/play-circle.png</iconset>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#include <QtCore/QEvent>
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QMenu>
|
||||
|
||||
#include <qdebug.h>
|
||||
|
||||
MediaNodeModel::MediaNodeModel(StoryGraphModel &model)
|
||||
: m_model(model)
|
||||
|
|
@ -46,6 +46,16 @@ MediaNodeModel::MediaNodeModel(StoryGraphModel &model)
|
|||
emit m_model.sigChooseFile(getNodeId(), "image");
|
||||
});
|
||||
|
||||
connect(m_ui.selectSoundButton, &QPushButton::clicked, [&](bool enable) {
|
||||
emit m_model.sigChooseFile(getNodeId(), "sound");
|
||||
});
|
||||
|
||||
connect(m_ui.playSoundButton, &QPushButton::clicked, [&](bool enable) {
|
||||
m_model.PlaySound(m_soundFilePath);
|
||||
});
|
||||
|
||||
m_ui.playSoundButton->setEnabled(false);
|
||||
|
||||
// default model
|
||||
m_mediaData = {
|
||||
{"image", ""},
|
||||
|
|
@ -55,6 +65,11 @@ MediaNodeModel::MediaNodeModel(StoryGraphModel &model)
|
|||
m_mediaData.merge_patch(StoryNodeBase::ToJson());
|
||||
}
|
||||
|
||||
QString MediaNodeModel::caption() const
|
||||
{
|
||||
return QString("Media Node " + QString::number(getNodeId()));
|
||||
}
|
||||
|
||||
nlohmann::json MediaNodeModel::ToJson() const
|
||||
{
|
||||
// Always start with generic
|
||||
|
|
@ -66,30 +81,23 @@ nlohmann::json MediaNodeModel::ToJson() const
|
|||
|
||||
void MediaNodeModel::FromJson(nlohmann::json &j)
|
||||
{
|
||||
m_mediaData.merge_patch(j);
|
||||
|
||||
// Display loaded image
|
||||
std::string imagePath = m_mediaData["image"].get<std::string>();
|
||||
|
||||
if (imagePath.size() > 0)
|
||||
{
|
||||
setImage(imagePath.c_str());
|
||||
}
|
||||
setInternalData(j); // Merge with SetInternalData ?
|
||||
}
|
||||
|
||||
void MediaNodeModel::setImage(const QString &imagePath)
|
||||
void MediaNodeModel::setImage(const QString &fileName)
|
||||
{
|
||||
QPixmap pix(imagePath);
|
||||
QPixmap pix(m_model.BuildFullImagePath(fileName));
|
||||
|
||||
if (pix.isNull())
|
||||
{
|
||||
std::cout << "!!!!!!! " << m_mediaData["image"].get<std::string>() << std::endl;
|
||||
qCritical() << "Can't find image: " << fileName;
|
||||
}
|
||||
|
||||
int w = m_ui.image->width();
|
||||
int h = m_ui.image->height();
|
||||
pix.scaled(w, h, Qt::KeepAspectRatio);
|
||||
m_ui.image->setPixmap(pix);
|
||||
m_ui.imageName->setText(fileName);
|
||||
}
|
||||
|
||||
void MediaNodeModel::setInternalData(const nlohmann::json &j)
|
||||
|
|
@ -98,10 +106,74 @@ void MediaNodeModel::setInternalData(const nlohmann::json &j)
|
|||
setImage(j["image"].get<std::string>().c_str());
|
||||
}
|
||||
|
||||
if (j.contains("sound")) {
|
||||
QString fileName = j["sound"].get<std::string>().c_str();
|
||||
m_soundFilePath = m_model.BuildFullSoundPath(fileName);
|
||||
m_ui.soundName->setText(fileName);
|
||||
m_ui.playSoundButton->setEnabled(true);
|
||||
}
|
||||
|
||||
// Merge new data into local object
|
||||
m_mediaData.merge_patch(j);
|
||||
}
|
||||
|
||||
std::string MediaNodeModel::GenerateConstants()
|
||||
{
|
||||
std::string s;
|
||||
|
||||
std::string image = m_mediaData["image"].get<std::string>();
|
||||
std::string sound = m_mediaData["sound"].get<std::string>();
|
||||
if (image.size() > 0)
|
||||
{
|
||||
s = StoryProject::FileToConstant(image);
|
||||
}
|
||||
if (sound.size() > 0)
|
||||
{
|
||||
s = StoryProject::FileToConstant(sound);
|
||||
}
|
||||
|
||||
// Generate choice table if needed (out ports > 1)
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string MediaNodeModel::Build()
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
ss << R"(; ---------------- )" << GetNodeTitle() << "\n";
|
||||
std::string image = m_mediaData["image"].get<std::string>();
|
||||
std::string sound = m_mediaData["sound"].get<std::string>();
|
||||
if (image.size() > 0)
|
||||
{
|
||||
ss << "lcons r0, $" << image << "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "lcons r0, 0\n";
|
||||
}
|
||||
|
||||
if (sound.size() > 0)
|
||||
{
|
||||
ss << "lcons r1, $" << sound << "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "lcons r1, 0\n";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
|
||||
syscall 1
|
||||
lcons r0, $ChoiceObject
|
||||
jump .media ; no return possible, so a jump is enough
|
||||
*/
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
unsigned int MediaNodeModel::nPorts(PortType portType) const
|
||||
{
|
||||
unsigned int result = 1;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: 2023-2099 Anthony Rabine <anthony@rabine.fr>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
|
|
@ -18,7 +21,6 @@ using QtNodes::PortType;
|
|||
|
||||
#include "story_graph_model.h"
|
||||
#include "story_node_base.h"
|
||||
#include "story_project.h"
|
||||
|
||||
/// The model dictates the number of inputs and outputs for the Node.
|
||||
/// In this example it has no logic.
|
||||
|
|
@ -31,7 +33,7 @@ public:
|
|||
~MediaNodeModel() = default;
|
||||
|
||||
public:
|
||||
QString caption() const override { return QString("Media Node"); }
|
||||
QString caption() const override;
|
||||
|
||||
QString name() const override { return QString("MediaNode"); }
|
||||
|
||||
|
|
@ -41,6 +43,9 @@ public:
|
|||
|
||||
void setInternalData(const nlohmann::json &j) override;
|
||||
|
||||
virtual std::string GenerateConstants() override;
|
||||
virtual std::string Build() override;
|
||||
|
||||
public:
|
||||
virtual QString modelName() const { return QString("MediaNode"); }
|
||||
|
||||
|
|
@ -66,6 +71,8 @@ private:
|
|||
unsigned int m_ports{1};
|
||||
QWidget *m_widget;
|
||||
|
||||
QString m_soundFilePath;
|
||||
|
||||
Ui::mediaNodeUi m_ui;
|
||||
std::shared_ptr<NodeData> m_nodeData;
|
||||
|
||||
|
|
|
|||
|
|
@ -45,12 +45,19 @@ QVariant ResourceModel::headerData(int section, Qt::Orientation orientation, int
|
|||
}
|
||||
}
|
||||
|
||||
void ResourceModel::append(const Resource &res) {
|
||||
void ResourceModel::Append(const Resource &res) {
|
||||
beginInsertRows({}, m_project.ResourcesSize(), m_project.ResourcesSize());
|
||||
m_project.AppendResource(res);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void ResourceModel::Delete(int row)
|
||||
{
|
||||
beginRemoveRows({}, row, row);
|
||||
m_project.DeleteResourceAt(row);
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
void ResourceModel::Clear()
|
||||
{
|
||||
beginResetModel();
|
||||
|
|
|
|||
|
|
@ -16,8 +16,9 @@ public:
|
|||
int columnCount(const QModelIndex &) const override;
|
||||
QVariant data(const QModelIndex &index, 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 Delete(int row);
|
||||
void Clear();
|
||||
void BeginChange();
|
||||
void EndChange();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ ResourcesDock::ResourcesDock(StoryProject &project, ResourceModel &model)
|
|||
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),
|
||||
".",
|
||||
tr("Images (*.bmp)"));
|
||||
tr("Images (*.bmp *.png *.jpg)"));
|
||||
|
||||
if (std::filesystem::exists(fileName.toStdString()))
|
||||
{
|
||||
|
|
@ -30,7 +30,7 @@ ResourcesDock::ResourcesDock(StoryProject &project, ResourceModel &model)
|
|||
res.format = "BMP";
|
||||
res.type = "image";
|
||||
res.file = p.filename();
|
||||
m_resourcesModel.append(res);
|
||||
m_resourcesModel.Append(res);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ ResourcesDock::ResourcesDock(StoryProject &project, ResourceModel &model)
|
|||
|
||||
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),
|
||||
".",
|
||||
tr("Sound files (*.wav, *.mp3, *.m4a)"));
|
||||
tr("Sound files (*.wav *.mp3 *.m4a)"));
|
||||
|
||||
if (std::filesystem::exists(fileName.toStdString()))
|
||||
{
|
||||
|
|
@ -50,7 +50,21 @@ ResourcesDock::ResourcesDock(StoryProject &project, ResourceModel &model)
|
|||
res.format = "WAV";
|
||||
res.type = "sound";
|
||||
res.file = p.filename();
|
||||
m_resourcesModel.append(res);
|
||||
m_resourcesModel.Append(res);
|
||||
}
|
||||
});
|
||||
|
||||
connect(m_uiOstResources.deleteButton, &QPushButton::clicked, [=](bool checked) {
|
||||
QItemSelectionModel *selectionModel = m_uiOstResources.resourcesView->selectionModel();
|
||||
// Récupération des lignes sélectionnées
|
||||
QModelIndexList selectedRows = selectionModel->selectedRows();
|
||||
|
||||
if (selectedRows.count() > 0)
|
||||
{
|
||||
for (int i = 0; i < selectedRows.count(); i++)
|
||||
{
|
||||
m_resourcesModel.Delete(selectedRows.at(i).row());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,14 @@
|
|||
#include <QtNodes/ConnectionIdUtils>
|
||||
#include <QJsonArray>
|
||||
#include <iterator>
|
||||
#include <QDir>
|
||||
|
||||
StoryGraphModel::StoryGraphModel(StoryProject &project)
|
||||
: m_project(project)
|
||||
{
|
||||
|
||||
m_player = new QMediaPlayer;
|
||||
m_audioOutput = new QAudioOutput;
|
||||
m_player->setAudioOutput(m_audioOutput);
|
||||
}
|
||||
|
||||
StoryGraphModel::~StoryGraphModel()
|
||||
|
|
@ -146,7 +149,7 @@ QVariant StoryGraphModel::nodeData(NodeId nodeId, NodeRole role) const
|
|||
break;
|
||||
|
||||
case NodeRole::Caption:
|
||||
result = QString("Node");
|
||||
result = model->caption();
|
||||
break;
|
||||
|
||||
case NodeRole::Style: {
|
||||
|
|
@ -168,7 +171,6 @@ QVariant StoryGraphModel::nodeData(NodeId nodeId, NodeRole role) const
|
|||
case NodeRole::Widget: {
|
||||
auto w = model->embeddedWidget();
|
||||
result = QVariant::fromValue(w);
|
||||
// result = QVariant::fromValue(widget(nodeId));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -321,7 +323,7 @@ namespace QtNodes {
|
|||
j = nlohmann::json{
|
||||
{"outNodeId", static_cast<qint64>(p.outNodeId)},
|
||||
{"outPortIndex", static_cast<qint64>(p.outPortIndex)},
|
||||
{"intNodeId", static_cast<qint64>(p.inNodeId)},
|
||||
{"inNodeId", static_cast<qint64>(p.inNodeId)},
|
||||
{"inPortIndex", static_cast<qint64>(p.inPortIndex)},
|
||||
};
|
||||
}
|
||||
|
|
@ -329,7 +331,7 @@ namespace QtNodes {
|
|||
void from_json(const nlohmann::json& j, ConnectionId& p) {
|
||||
j.at("outNodeId").get_to(p.outNodeId);
|
||||
j.at("outPortIndex").get_to(p.outPortIndex);
|
||||
j.at("intNodeId").get_to(p.inNodeId);
|
||||
j.at("inNodeId").get_to(p.inNodeId);
|
||||
j.at("inPortIndex").get_to(p.inPortIndex);
|
||||
}
|
||||
} // namespace QtNodes
|
||||
|
|
@ -401,16 +403,11 @@ nlohmann::json StoryGraphModel::SaveNode(NodeId const nodeId) const
|
|||
return nodeJson;
|
||||
}
|
||||
|
||||
std::string StoryGraphModel::BuildNode(NodeId const nodeId) const
|
||||
void StoryGraphModel::PlaySound(const QString &fileName)
|
||||
{
|
||||
std::string code;
|
||||
|
||||
auto it = _models.find(nodeId);
|
||||
if (it == _models.end())
|
||||
return "";
|
||||
|
||||
auto &model = it->second;
|
||||
return model->Build();
|
||||
m_player->setSource(QUrl::fromLocalFile(fileName));
|
||||
m_audioOutput->setVolume(50);
|
||||
m_player->play();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -460,16 +457,67 @@ void StoryGraphModel::LoadNode(const nlohmann::json &nodeJson)
|
|||
}
|
||||
}
|
||||
|
||||
std::string StoryGraphModel::Build()
|
||||
NodeId StoryGraphModel::FindFirstNode() const
|
||||
{
|
||||
std::string code;
|
||||
nlohmann::json nodesJsonArray;
|
||||
for (auto const nodeId : allNodeIds()) {
|
||||
NodeId id{InvalidNodeId};
|
||||
|
||||
code = BuildNode(nodeId) + "\n";
|
||||
// First node is the one without connection on its input port
|
||||
|
||||
for (auto const nodeId : allNodeIds())
|
||||
{
|
||||
bool foundConnection{false};
|
||||
for (auto& c : _connectivity)
|
||||
{
|
||||
if (c.outNodeId == nodeId)
|
||||
{
|
||||
foundConnection = true;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
if (!foundConnection)
|
||||
{
|
||||
id = nodeId;
|
||||
qDebug() << "First node is: " << id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
std::string StoryGraphModel::Build()
|
||||
{
|
||||
std::stringstream chip32;
|
||||
|
||||
FindFirstNode();
|
||||
|
||||
chip32 << "\tjump .entry\r\n";
|
||||
|
||||
// First generate all constants
|
||||
for (auto const nodeId : allNodeIds())
|
||||
{
|
||||
auto it = _models.find(nodeId);
|
||||
if (it != _models.end())
|
||||
{
|
||||
chip32 << it->second->GenerateConstants() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
chip32 << ".entry:\r\n";
|
||||
|
||||
nlohmann::json nodesJsonArray;
|
||||
for (auto const nodeId : allNodeIds())
|
||||
{
|
||||
auto it = _models.find(nodeId);
|
||||
if (it == _models.end())
|
||||
return "";
|
||||
|
||||
auto &model = it->second;
|
||||
chip32 << model->Build() << "\n";
|
||||
}
|
||||
|
||||
return chip32.str();
|
||||
}
|
||||
|
||||
void StoryGraphModel::addPort(NodeId nodeId, PortType portType, PortIndex portIndex)
|
||||
|
|
@ -497,6 +545,26 @@ void StoryGraphModel::removePort(NodeId nodeId, PortType portType, PortIndex por
|
|||
portsDeleted();
|
||||
}
|
||||
|
||||
QString StoryGraphModel::GetImagesDir() const
|
||||
{
|
||||
return QString(m_project.GetWorkingDir().c_str()) + QDir::separator() + "images";
|
||||
}
|
||||
|
||||
QString StoryGraphModel::BuildFullImagePath(const QString &fileName) const
|
||||
{
|
||||
return GetImagesDir() + QDir::separator() + fileName;
|
||||
}
|
||||
|
||||
QString StoryGraphModel::GetSoundsDir() const
|
||||
{
|
||||
return QString(m_project.GetWorkingDir().c_str()) + QDir::separator() + "sounds";
|
||||
}
|
||||
|
||||
QString StoryGraphModel::BuildFullSoundPath(const QString &fileName) const
|
||||
{
|
||||
return GetSoundsDir() + QDir::separator() + fileName;
|
||||
}
|
||||
|
||||
void StoryGraphModel::Clear()
|
||||
{
|
||||
_nodeIds.clear();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
// SPDX-FileCopyrightText: 2023-2099 Anthony Rabine <anthony@rabine.fr>
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "src/story_project.h"
|
||||
|
|
@ -10,6 +13,8 @@
|
|||
|
||||
#include <QtNodes/NodeDelegateModel>
|
||||
#include <QtNodes/NodeDelegateModelRegistry>
|
||||
#include <QAudioOutput>
|
||||
#include <QMediaPlayer>
|
||||
|
||||
using QtNodes::ConnectionStyle;
|
||||
using QtNodes::NodeRole;
|
||||
|
|
@ -118,6 +123,10 @@ public:
|
|||
}
|
||||
|
||||
StoryProject &GetProject() { return m_project; };
|
||||
QString GetImagesDir() const;
|
||||
QString GetSoundsDir() const;
|
||||
QString BuildFullImagePath(const QString &fileName) const;
|
||||
QString BuildFullSoundPath(const QString &fileName) const;
|
||||
void Clear();
|
||||
void SetInternalData(NodeId nodeId, nlohmann::json &j);
|
||||
|
||||
|
|
@ -129,7 +138,11 @@ public:
|
|||
|
||||
std::string Build();
|
||||
|
||||
std::string BuildNode(const NodeId nodeId) const;
|
||||
|
||||
// Centralized for wide usage
|
||||
void PlaySound(const QString &fileName);
|
||||
|
||||
NodeId FindFirstNode() const;
|
||||
signals:
|
||||
void sigChooseFile(NodeId id, const QString &type);
|
||||
|
||||
|
|
@ -164,4 +177,7 @@ private:
|
|||
|
||||
/// A convenience variable needed for generating unique node ids.
|
||||
unsigned int _nextNodeId{0};
|
||||
|
||||
QMediaPlayer *m_player{nullptr};
|
||||
QAudioOutput *m_audioOutput{nullptr};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public:
|
|||
}
|
||||
|
||||
void setNodeId(NodeId id) { m_nodeId = id; }
|
||||
NodeId getNodeId() { return m_nodeId; }
|
||||
NodeId getNodeId() const { return m_nodeId; }
|
||||
|
||||
virtual nlohmann::json ToJson() const {
|
||||
nlohmann::json j;
|
||||
|
|
@ -48,15 +48,21 @@ public:
|
|||
// default impl
|
||||
}
|
||||
|
||||
virtual std::string GenerateConstants() {
|
||||
return "";
|
||||
}
|
||||
|
||||
virtual std::string Build() {
|
||||
return "";
|
||||
}
|
||||
|
||||
NodeGeometryData &geometryData() { return m_geometryData; }
|
||||
|
||||
std::string GetNodeTitle() const { return m_nodeTitle; }
|
||||
|
||||
private:
|
||||
NodeId m_nodeId;
|
||||
std::string m_nodeTitle{"Media node"};
|
||||
NodeGeometryData m_geometryData;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,9 @@ bool StoryProject::Load(const std::string &file_path, nlohmann::json &model)
|
|||
m_name = projectData["name"].get<std::string>();
|
||||
m_uuid = projectData["uuid"].get<std::string>();
|
||||
|
||||
nlohmann::json resourcesData = projectData["resources"];
|
||||
if (j.contains("resources"))
|
||||
{
|
||||
nlohmann::json resourcesData = j["resources"];
|
||||
|
||||
for (const auto &obj : resourcesData)
|
||||
{
|
||||
|
|
@ -77,6 +79,7 @@ bool StoryProject::Load(const std::string &file_path, nlohmann::json &model)
|
|||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
|
@ -244,6 +247,15 @@ void StoryProject::ReplaceCharacter(std::string &theString, const std::string &t
|
|||
while (found != std::string::npos);
|
||||
}
|
||||
|
||||
std::string StoryProject::FileToConstant(const std::string &FileName)
|
||||
{
|
||||
std::string fileName = GetFileName(FileName);
|
||||
std::string ext = GetFileExtension(fileName);
|
||||
EraseString(fileName, "." + ext); // on retire l'extension du pack
|
||||
|
||||
return "$" + fileName + " DC8 \"" + fileName + "." + ext + "\", 8\r\n";
|
||||
}
|
||||
|
||||
void StoryProject::AppendResource(const Resource &res)
|
||||
{
|
||||
m_resources.push_back(res);
|
||||
|
|
@ -265,6 +277,14 @@ void StoryProject::ClearResources()
|
|||
m_resources.clear();
|
||||
}
|
||||
|
||||
void StoryProject::DeleteResourceAt(int index)
|
||||
{
|
||||
if ((index >= 0) && (index < m_resources.size()))
|
||||
{
|
||||
m_resources.erase(m_resources.begin() + index);
|
||||
}
|
||||
}
|
||||
|
||||
std::string StoryProject::GetFileExtension(const std::string &fileName)
|
||||
{
|
||||
if(fileName.find_last_of(".") != std::string::npos)
|
||||
|
|
|
|||
|
|
@ -86,12 +86,13 @@ struct StoryProject
|
|||
static std::string GetFileExtension(const std::string &FileName);
|
||||
static std::string GetFileName(const std::string &path);
|
||||
static void ReplaceCharacter(std::string &theString, const std::string &toFind, const std::string &toReplace);
|
||||
|
||||
static std::string FileToConstant(const std::string &FileName);
|
||||
|
||||
// ------------- Resources Management
|
||||
void AppendResource(const Resource &res);
|
||||
bool GetResourceAt(int index, Resource &resOut);
|
||||
void ClearResources();
|
||||
void DeleteResourceAt(int index);
|
||||
int ResourcesSize() const { return m_resources.size(); }
|
||||
|
||||
std::vector<Resource>::const_iterator Begin() const { return m_resources.begin(); }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "toolbar.h"
|
||||
#include "qmenubar.h"
|
||||
#include "src/dock_widget_base.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
|
|
@ -108,6 +109,33 @@ void ToolBar::GenerateRecentProjectsMenu(const QStringList &recents)
|
|||
}
|
||||
}
|
||||
|
||||
QVariant ToolBar::GetDocksPreferences() const
|
||||
{
|
||||
QMap<QString, QVariant> prefs;
|
||||
|
||||
for (auto d : m_docksList)
|
||||
{
|
||||
prefs[d->objectName()] = d->GetPreferedVisibility();
|
||||
}
|
||||
|
||||
return prefs;
|
||||
}
|
||||
|
||||
QVariant ToolBar::SetDocksPreferences(const QVariant &prefs)
|
||||
{
|
||||
QMap<QString, QVariant> p = prefs.toMap();
|
||||
|
||||
for (auto d : m_docksList)
|
||||
{
|
||||
if (p.contains(d->objectName()))
|
||||
{
|
||||
d->SetPreferedVisibility(p[d->objectName()].toBool());
|
||||
}
|
||||
}
|
||||
|
||||
return prefs;
|
||||
}
|
||||
|
||||
void ToolBar::SetActionsActive(bool enable)
|
||||
{
|
||||
for (auto d : m_actionDockList)
|
||||
|
|
@ -128,8 +156,12 @@ void ToolBar::slotAbout()
|
|||
"Build your own stories on an open source hardware."));
|
||||
}
|
||||
|
||||
void ToolBar::AddDockToMenu(QAction *action)
|
||||
void ToolBar::AddDockToMenu(QAction *action, DockWidgetBase *dock)
|
||||
{
|
||||
m_windowsMenu->addAction(action);
|
||||
m_actionDockList.push_back(action);
|
||||
m_docksList.push_back(dock);
|
||||
connect(action, &QAction::triggered, this, [dock](bool checked) {
|
||||
dock->SetPreferedVisibility(checked);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <QToolBar>
|
||||
#include <QMenuBar>
|
||||
#include "dock_widget_base.h"
|
||||
|
||||
class ToolBar : public QToolBar
|
||||
{
|
||||
|
|
@ -11,9 +12,11 @@ class ToolBar : public QToolBar
|
|||
public:
|
||||
ToolBar();
|
||||
void createActions(QMenuBar *menuBar);
|
||||
void AddDockToMenu(QAction *action);
|
||||
void AddDockToMenu(QAction *action, DockWidgetBase *dock);
|
||||
void SetActionsActive(bool enable);
|
||||
void GenerateRecentProjectsMenu(const QStringList &recents);
|
||||
QVariant GetDocksPreferences() const;
|
||||
QVariant SetDocksPreferences(const QVariant &prefs);
|
||||
|
||||
signals:
|
||||
void sigNew();
|
||||
|
|
@ -35,6 +38,7 @@ private:
|
|||
QAction *m_closeProjectAction{nullptr};
|
||||
QAction *m_runAction{nullptr};
|
||||
QList<QAction *> m_actionDockList;
|
||||
QList<DockWidgetBase *> m_docksList;
|
||||
};
|
||||
|
||||
#endif // TOOLBAR_H
|
||||
|
|
|
|||
Loading…
Reference in a new issue