From 7e8d64e65a4efbe0ac42b58e17b6cab40602b17c Mon Sep 17 00:00:00 2001 From: Ghabry Date: Sat, 25 Apr 2026 12:39:53 +0200 Subject: [PATCH 1/8] Fix whitespace --- src/ui/common/CheckBox.qml | 16 ++++++++-------- src/ui/database/DatabaseEntryListPage.qml | 4 ++-- src/ui/database/ItemPage.qml | 20 ++++++++++---------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/ui/common/CheckBox.qml b/src/ui/common/CheckBox.qml index 34ffa7e..979c059 100644 --- a/src/ui/common/CheckBox.qml +++ b/src/ui/common/CheckBox.qml @@ -12,9 +12,9 @@ Controls.CheckBox { property Ez.JsonView jsonData onToggled: { - if (jsonData !== null && key !== "") { - jsonData.set(key, checked); - } + if (jsonData !== null && key !== "") { + jsonData.set(key, checked); + } } Component.onCompleted: { @@ -22,10 +22,10 @@ Controls.CheckBox { } function onDataChanged() { - if (jsonData !== null && key !== "") { - checked = jsonData.boolean(key); - } else { - checked = false; - } + if (jsonData !== null && key !== "") { + checked = jsonData.boolean(key); + } else { + checked = false; + } } } diff --git a/src/ui/database/DatabaseEntryListPage.qml b/src/ui/database/DatabaseEntryListPage.qml index 6161fde..339103d 100644 --- a/src/ui/database/DatabaseEntryListPage.qml +++ b/src/ui/database/DatabaseEntryListPage.qml @@ -26,7 +26,7 @@ Kirigami.ScrollablePage { ListView { id: entryList - model: root.jsonData + model: root.jsonData onCurrentIndexChanged: { root.selectEntry(currentIndex) @@ -36,7 +36,7 @@ Kirigami.ScrollablePage { required property int index required property string name - width: ListView.view.width + width: ListView.view.width text: (index+1).toString().padStart(4, '0') + ": " + name highlighted: entryList.currentIndex === index diff --git a/src/ui/database/ItemPage.qml b/src/ui/database/ItemPage.qml index cdb8788..6106a21 100644 --- a/src/ui/database/ItemPage.qml +++ b/src/ui/database/ItemPage.qml @@ -15,16 +15,16 @@ DatabaseEntryPage { Kirigami.FormLayout { anchors.fill: parent - Ez.TextField { - jsonData: root.jsonData - key: "name" - Kirigami.FormData.label: "Name:" - } + Ez.TextField { + jsonData: root.jsonData + key: "name" + Kirigami.FormData.label: "Name:" + } - Ez.TextField { - jsonData: root.jsonData - key: "description" - Kirigami.FormData.label: "Description:" - } + Ez.TextField { + jsonData: root.jsonData + key: "description" + Kirigami.FormData.label: "Description:" + } } } From 26e6824239a3ae8ea08776e134fb5ae7769e565d Mon Sep 17 00:00:00 2001 From: Ghabry Date: Sat, 25 Apr 2026 12:40:51 +0200 Subject: [PATCH 2/8] TextField: Improve event and error handling --- src/ui/common/TextField.qml | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/ui/common/TextField.qml b/src/ui/common/TextField.qml index b0c60e1..9f29aec 100644 --- a/src/ui/common/TextField.qml +++ b/src/ui/common/TextField.qml @@ -11,19 +11,27 @@ Controls.TextField { property string key property Ez.JsonView jsonData - onTextChanged: { - //console.log("Text changed to:", key, jsonData, text) - if (jsonData !== null && key !== "") { - jsonData.set(key, text) - } + onKeyChanged: updateData() + onJsonDataChanged: updateData() + + onTextEdited: { + if (jsonData !== null && key !== "") { + jsonData.set(key, text) + } } Component.onCompleted: { - onDataChanged() + updateData() } - function onDataChanged() { - //console.log("data changed", jsonData.str(key)) - text = jsonData.str(key) + function updateData() { + if (jsonData !== null && key !== "") { + let jsonText = jsonData.str(key); + if (text !== jsonText) { + text = jsonText; + } + } else { + text = ""; + } } } From 62d690ce8cd5b761ee20cb772fc4395096c45d58 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Tue, 28 Apr 2026 21:17:14 +0200 Subject: [PATCH 3/8] JSON: Support std::string --- src/qmlbinding/json_internals/json_t_impl.h | 30 ++++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/qmlbinding/json_internals/json_t_impl.h b/src/qmlbinding/json_internals/json_t_impl.h index d1a2a62..9147e03 100644 --- a/src/qmlbinding/json_internals/json_t_impl.h +++ b/src/qmlbinding/json_internals/json_t_impl.h @@ -35,12 +35,16 @@ JsonT::JsonT(QObject* parent) : Json(parent) {} template QString JsonT::str(QString jsonPtr) const { auto res = glz::get(*m_data, jsonPtr.toStdString()); - if (res) { return ToQString(res.value()); } - qDebug() << "Json::str: Not pointing to DBString: " << jsonPtr; + auto res2 = glz::get(*m_data, jsonPtr.toStdString()); + if (res2) { + return ToQString(res2.value()); + } + + qDebug() << "Json::str: Not pointing to String: " << jsonPtr; return "!BAD POINTER!"; } @@ -85,26 +89,38 @@ bool JsonT::boolean(QString jsonPtr) const { template void JsonT::set(QString jsonPtr, const QVariant& value) { + bool ok = true; + std::string ptr = jsonPtr.toStdString(); + switch (value.typeId()) { case QMetaType::Int: - glz::set(m_data, jsonPtr.toStdString(), value.toInt()); + ok = glz::set(m_data, ptr, value.toInt()); break; case QMetaType::Double: - glz::set(m_data, jsonPtr.toStdString(), value.toDouble()); + ok = glz::set(m_data, ptr, value.toDouble()); break; case QMetaType::QString: { lcf::DBString s = ToDBString(value.value()); - glz::set(m_data, jsonPtr.toStdString(), s); + ok = glz::set(m_data, ptr, s); + + if (!ok) { + std::string s2 = value.value().toStdString(); + ok = glz::set(m_data, ptr, s2); + } break; } case QMetaType::Bool: { - glz::set(m_data, jsonPtr.toStdString(), value.toBool()); + ok = glz::set(m_data, ptr, value.toBool()); break; } default: - qDebug() << "Json::set: Type unsupported: " << value.typeName(); + qDebug() << QString("Json::set: Type %1 unsupported for path %2").arg(value.typeName()).arg(jsonPtr); break; } + + if (!ok) { + qDebug() << QString("Json::set: Assignment of type %1 failed for path %2").arg(value.typeName()).arg(jsonPtr); + } } template From 45f45d7c4e28a4f7325efe828bcd654b26108c68 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Tue, 28 Apr 2026 21:23:34 +0200 Subject: [PATCH 4/8] Add Music and Sound Picker and System Page The Picker is a column layout that contains: - A file list (left side) - A configuration (right side) The Viewer lists e.g. the filename and has a ... button that opens the picker For the file listing a directory model was added --- CMakeLists.txt | 10 ++ src/common/filefinder.cpp | 48 +++---- src/common/filefinder.h | 2 + src/qmlbinding/directory_model.cpp | 118 +++++++++++++++++ src/qmlbinding/directory_model.h | 70 +++++++++++ src/ui/common/PickerData.qml | 41 ++++++ src/ui/common/SpinBox.qml | 13 +- src/ui/database/DatabaseEntryListPage.qml | 2 +- src/ui/database/DatabasePage.qml | 8 +- src/ui/database/SystemPage.qml | 147 ++++++++++++++++++++++ src/ui/picker/MusicPicker.qml | 45 +++++++ src/ui/picker/PickerBase.qml | 94 ++++++++++++++ src/ui/picker/SoundPicker.qml | 38 ++++++ src/ui/viewer/FileViewerBase.qml | 42 +++++++ src/ui/viewer/MusicViewer.qml | 16 +++ src/ui/viewer/SoundViewer.qml | 16 +++ 16 files changed, 684 insertions(+), 26 deletions(-) create mode 100644 src/qmlbinding/directory_model.cpp create mode 100644 src/qmlbinding/directory_model.h create mode 100644 src/ui/common/PickerData.qml create mode 100644 src/ui/database/SystemPage.qml create mode 100644 src/ui/picker/MusicPicker.qml create mode 100644 src/ui/picker/PickerBase.qml create mode 100644 src/ui/picker/SoundPicker.qml create mode 100644 src/ui/viewer/FileViewerBase.qml create mode 100644 src/ui/viewer/MusicViewer.qml create mode 100644 src/ui/viewer/SoundViewer.qml diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c2b2db..af26225 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -325,6 +325,7 @@ set(EDITOR_SOURCES set(EDITOR_QML_UI src/ui/common/CheckBox.qml src/ui/common/ComboBox.qml + src/ui/common/PickerData.qml src/ui/common/RadioButton.qml src/ui/common/SpinBox.qml src/ui/common/TextField.qml @@ -337,10 +338,19 @@ set(EDITOR_QML_UI src/ui/database/DatabaseWindow.qml src/ui/database/ItemPage.qml src/ui/database/SkillPage.qml + src/ui/database/SystemPage.qml src/ui/database/VocabularyPage.qml + src/ui/picker/PickerBase.qml + src/ui/picker/MusicPicker.qml + src/ui/picker/SoundPicker.qml + src/ui/viewer/FileViewerBase.qml + src/ui/viewer/MusicViewer.qml + src/ui/viewer/SoundViewer.qml ) set(EDITOR_QML_INTERFACE + src/qmlbinding/directory_model.cpp + src/qmlbinding/directory_model.h src/qmlbinding/json_internals/json_t_database.cpp src/qmlbinding/json_internals/json_t_impl.h src/qmlbinding/json_internals/json_t_map.cpp diff --git a/src/common/filefinder.cpp b/src/common/filefinder.cpp index 1c4ad44..5be52ad 100644 --- a/src/common/filefinder.cpp +++ b/src/common/filefinder.cpp @@ -19,10 +19,10 @@ #include "defines.h" #include "filefinder.h" -QString FileFinder::Find(const QDir& dir, const QString& filename, FileType type, QDir::Filter filter) { - auto fn = [&](std::initializer_list exts) -> QString { - for (const std::string& ext: exts) { - QString file_to_find = filename + ToQString(ext); +QString FileFinder::Find(const QDir& dir, const QString& filename, FileFinder::FileType type, QDir::Filter filter) { + auto fn = [&](QStringList exts) -> QString { + for (const QString& ext: exts) { + QString file_to_find = filename + ext; const auto& list = dir.entryList(filter); for (const QString& item: list) { if (item.compare(file_to_find, Qt::CaseInsensitive) == 0) { @@ -33,23 +33,7 @@ QString FileFinder::Find(const QDir& dir, const QString& filename, FileType type return nullptr; }; - switch (type) { - case FileType::Default: - return fn({""}); - case FileType::Image: - return fn({ ".bmp", ".png", ".xyz"}); - case FileType::Sound: - return fn({".opus", ".oga", ".ogg", ".wav", ".mp3"}); - case FileType::Music: - return fn({".opus", ".oga", ".ogg", ".wav", ".mid", ".midi", ".mp3"}); - case FileType::Video: - return fn({".webm", ".mp4", ".avi"}); - case FileType::Font: - return fn({".ttf", ".ttc", ".otf", ".fon"}); - } - - assert(false); - return nullptr; + return fn(GetFiltersForType(type)); } QString FileFinder::Find(const QDir& baseDir, const QString& subDir, const QString& filename, FileType type, QDir::Filter filter) { @@ -77,3 +61,25 @@ bool FileFinder::IsEasyRpgProject(const QDir& directory) { QString FileFinder::CombinePath(const QString& path1, const QString& path2) { return path1 + QDir::separator() + path2; } + +QStringList FileFinder::GetFiltersForType(FileType type) { + switch (type) { + case FileType::Default: + return {""}; + case FileType::Image: + return {".bmp", ".png", ".xyz"}; + case FileType::Sound: + return {".opus", ".oga", ".ogg", ".wav", ".mp3"}; + case FileType::Music: + return {".opus", ".oga", ".ogg", ".wav", ".mid", ".midi", ".mp3"}; + case FileType::Video: + return {".webm", ".mp4", ".avi"}; + case FileType::Font: + return {".ttf", ".ttc", ".otf", ".fon"}; + default: + assert(false); + break; + } + + return {}; +} diff --git a/src/common/filefinder.h b/src/common/filefinder.h index a56af66..2711cc9 100644 --- a/src/common/filefinder.h +++ b/src/common/filefinder.h @@ -47,5 +47,7 @@ namespace FileFinder { bool IsEasyRpgProject(const QDir& directory); QString CombinePath(const QString& path1, const QString& path2); + + QStringList GetFiltersForType(FileType type); }; diff --git a/src/qmlbinding/directory_model.cpp b/src/qmlbinding/directory_model.cpp new file mode 100644 index 0000000..856de25 --- /dev/null +++ b/src/qmlbinding/directory_model.cpp @@ -0,0 +1,118 @@ +/* + * This file is part of EasyRPG Editor. + * + * EasyRPG Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EasyRPG Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EasyRPG Editor. If not, see . + */ + +#include "directory_model.h" +#include "common/filefinder.h" + +DirectoryModel::DirectoryModel(QObject* parent) : QAbstractListModel(parent) {} + +int DirectoryModel::rowCount(const QModelIndex& parent) const { + Q_UNUSED(parent) + return m_fileList.count(); +} + +QVariant DirectoryModel::data(const QModelIndex& index, int role) const { + if (!index.isValid() || index.row() < 0 || + index.row() >= m_fileList.count()) + return QVariant(); + + const QString& filename = m_fileList.at(index.row()); + + switch (role) { + case FileNameRole: + return filename; + case FullPathRole: + return QString("%1/%2").arg(m_path).arg(filename); + case BaseNameRole: + return filename.left(filename.lastIndexOf(".")); + case Qt::DisplayRole: + return filename; + default: + return QVariant(); + } +} + +QHash DirectoryModel::roleNames() const { + QHash roles; + roles[FileNameRole] = "fileName"; + roles[FullPathRole] = "fullPath"; + roles[BaseNameRole] = "baseName"; + return roles; +} + +QString DirectoryModel::path() const { return m_path; } + +void DirectoryModel::setPath(const QString& path) { + if (m_path == path) + return; + + m_path = path; + refreshModel(); + emit pathChanged(); +} + +FileFinder::FileType DirectoryModel::fileType() const { return m_fileType; } + +void DirectoryModel::setFileType(FileFinder::FileType fileType) { + if (m_fileType == fileType) + return; + + m_fileType = fileType; + refreshModel(); + emit fileTypeChanged(); +} + +void DirectoryModel::refreshModel() { + beginResetModel(); + + m_fileList.clear(); + + if (!m_path.isEmpty()) { + QDir dir(m_path); + if (dir.exists()) { + auto entries = dir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name); + + // Apply filters based on file type + QStringList filters = FileFinder::GetFiltersForType(m_fileType); + + for (const QString& entry : entries) { + if (matchesFilter(entry, filters)) { + m_fileList.append(entry); + } + } + } + } + + endResetModel(); + emit countChanged(); +} + +bool DirectoryModel::matchesFilter(const QString& fileName, + const QStringList& filters) const { + if (filters.isEmpty() || filters.contains("")) + return true; + + QString fileLower = fileName.toLower(); + + for (const QString& filter : filters) { + if (fileLower.endsWith(filter.toLower())) { + return true; + } + } + + return false; +} diff --git a/src/qmlbinding/directory_model.h b/src/qmlbinding/directory_model.h new file mode 100644 index 0000000..f17aed4 --- /dev/null +++ b/src/qmlbinding/directory_model.h @@ -0,0 +1,70 @@ +/* + * This file is part of EasyRPG Editor. + * + * EasyRPG Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EasyRPG Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EasyRPG Editor. If not, see . + */ + +#pragma once + +#include "common/filefinder.h" +#include +#include +#include +#include +#include + +class DirectoryModel : public QAbstractListModel { + Q_OBJECT + QML_ELEMENT + Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged) + Q_PROPERTY(int count READ rowCount NOTIFY countChanged) + Q_PROPERTY(FileFinder::FileType fileType READ fileType WRITE setFileType NOTIFY + fileTypeChanged) + +public: + enum Roles { + FileNameRole = Qt::UserRole + 1, + FullPathRole, + BaseNameRole + }; + + explicit DirectoryModel(QObject* parent = nullptr); + + // QAbstractItemModel interface + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, + int role = Qt::DisplayRole) const override; + Q_INVOKABLE QHash roleNames() const override; + + // Property accessors + QString path() const; + void setPath(const QString& path); + + FileFinder::FileType fileType() const; + void setFileType(FileFinder::FileType fileType); + +signals: + void pathChanged(); + void countChanged(); + void fileTypeChanged(); + +private: + void refreshModel(); + bool matchesFilter(const QString& fileName, + const QStringList& filters) const; + + QString m_path; + FileFinder::FileType m_fileType = FileFinder::FileType::Default; + QList m_fileList; +}; diff --git a/src/ui/common/PickerData.qml b/src/ui/common/PickerData.qml new file mode 100644 index 0000000..643ed44 --- /dev/null +++ b/src/ui/common/PickerData.qml @@ -0,0 +1,41 @@ +import QtQuick + +QtObject { + id: root + + property string filename + property int index: 0 + + property int fadein: 0 + property int volume: 100 + property int tempo: 100 + property int balance: 50 + + function fromMusic(jsonData) { + fromSound(jsonData) + fadein = jsonData.num("fadein") + return root + } + + function fromSound(jsonData) { + filename = jsonData.str("name") + volume = jsonData.num("volume") + tempo = jsonData.num("tempo") + balance = jsonData.num("balance") + return root + } + + function toMusic(jsonData) { + toSound(jsonData) + jsonData.set("fadein", fadein) + return root + } + + function toSound(jsonData) { + jsonData.set("name", filename) + jsonData.set("volume", volume) + jsonData.set("tempo", tempo) + jsonData.set("balance", balance) + return root + } +} diff --git a/src/ui/common/SpinBox.qml b/src/ui/common/SpinBox.qml index d71c316..132a0d5 100644 --- a/src/ui/common/SpinBox.qml +++ b/src/ui/common/SpinBox.qml @@ -11,6 +11,9 @@ Controls.SpinBox { property string key property Ez.JsonView jsonData + onKeyChanged: updateData() + onJsonDataChanged: updateData() + property string prefix: "" property string suffix: "" @@ -21,11 +24,15 @@ Controls.SpinBox { } Component.onCompleted: { - onDataChanged() + updateData() } - function onDataChanged() { - value = jsonData.num(key) + function updateData() { + if (jsonData !== null && key !== "") { + value = jsonData.num(key) + } else { + value = 0; + } } textFromValue: function(value, locale) { diff --git a/src/ui/database/DatabaseEntryListPage.qml b/src/ui/database/DatabaseEntryListPage.qml index 339103d..941cffa 100644 --- a/src/ui/database/DatabaseEntryListPage.qml +++ b/src/ui/database/DatabaseEntryListPage.qml @@ -65,7 +65,7 @@ Kirigami.ScrollablePage { //console.log("Pushing:", root.targetPage); pageStack.push(Qt.resolvedUrl(root.targetPage), { // Use the index passed to the function - jsonData: jsonData.subtree("/" + index), + jsonData: jsonData.subtree(index), objIndex: index }); } diff --git a/src/ui/database/DatabasePage.qml b/src/ui/database/DatabasePage.qml index 4d21926..f1b415b 100644 --- a/src/ui/database/DatabasePage.qml +++ b/src/ui/database/DatabasePage.qml @@ -46,11 +46,17 @@ Kirigami.ScrollablePage { key: "attributes" targetPage: "AttributePage.qml" } + ListElement { + name: "System" + key: "system" + targetPage: "SystemPage.qml" + single: true + } ListElement { name: "Vocabulary" key: "terms" - single: true targetPage: "VocabularyPage.qml" + single: true } } diff --git a/src/ui/database/SystemPage.qml b/src/ui/database/SystemPage.qml new file mode 100644 index 0000000..1f74106 --- /dev/null +++ b/src/ui/database/SystemPage.qml @@ -0,0 +1,147 @@ +// SPDX-FileCopyrightText: EasyRPG Editor Authors +// SPDX-License-Identifier: GPL-3.0-or-later + +import Qt.labs.folderlistmodel 2.11 +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls as Controls +import QtQml.Models as Models +import org.kde.kirigami as Kirigami +import org.easyrpg.editor as Ez + +DatabaseEntryPage { + id: root + + component JsonMusicViewer : Ez.MusicViewer { + property string key + readonly property var musicData: root.jsonData.subtree(key) + pickerData: Ez.PickerData { + Component.onCompleted: fromMusic(musicData) + } + onAccepted: pickerData.toMusic(musicData) + } + + component JsonSoundViewer : Ez.SoundViewer { + property string key + readonly property var soundData: root.jsonData.subtree(key) + pickerData: Ez.PickerData { + Component.onCompleted: fromMusic(soundData) + } + onAccepted: pickerData.toMusic(soundData) + } + + Kirigami.FormLayout { + anchors.fill: parent + + Kirigami.Separator { + Kirigami.FormData.isSection: true + Kirigami.FormData.label: "Music" + } + + JsonMusicViewer { + key: "title_music" + Kirigami.FormData.label: "Title:" + } + + JsonMusicViewer { + key: "gameover_music" + Kirigami.FormData.label: "Game Over:" + } + + JsonMusicViewer { + key: "inn_music" + Kirigami.FormData.label: "Inn:" + } + + JsonMusicViewer { + key: "boat_music" + Kirigami.FormData.label: "Boat:" + } + + JsonMusicViewer { + key: "ship_music" + Kirigami.FormData.label: "Ship:" + } + + JsonMusicViewer { + key: "airship_music" + Kirigami.FormData.label: "Airship:" + } + + JsonMusicViewer { + key: "battle_music" + Kirigami.FormData.label: "Battle:" + } + + JsonMusicViewer { + key: "battle_end_music" + Kirigami.FormData.label: "Battle End:" + } + + Kirigami.Separator { + Kirigami.FormData.isSection: true + Kirigami.FormData.label: "Sound" + } + + + JsonSoundViewer { + key: "cursor_se" + Kirigami.FormData.label: "Cursor:" + } + + JsonSoundViewer { + key: "decision_se" + Kirigami.FormData.label: "Decision:" + } + + JsonSoundViewer { + key: "cancel_se" + Kirigami.FormData.label: "Cancel:" + } + + JsonSoundViewer { + key: "buzzer_se" + Kirigami.FormData.label: "Buzzer:" + } + + JsonSoundViewer { + key: "battle_se" + Kirigami.FormData.label: "Battle:" + } + + JsonSoundViewer { + key: "escape_se" + Kirigami.FormData.label: "Escape:" + } + + JsonSoundViewer { + key: "enemy_attack_se" + Kirigami.FormData.label: "Enemy Attack:" + } + + JsonSoundViewer { + key: "enemy_damaged_se" + Kirigami.FormData.label: "Enemy Damaged:" + } + + JsonSoundViewer { + key: "actor_damaged_se" + Kirigami.FormData.label: "Actor Damaged:" + } + + JsonSoundViewer { + key: "dodge_se" + Kirigami.FormData.label: "Dodge:" + } + + JsonSoundViewer { + key: "enemy_death_se" + Kirigami.FormData.label: "Enemy Death:" + } + + JsonSoundViewer { + key: "item_se" + Kirigami.FormData.label: "Item:" + } + } +} diff --git a/src/ui/picker/MusicPicker.qml b/src/ui/picker/MusicPicker.qml new file mode 100644 index 0000000..a2982a4 --- /dev/null +++ b/src/ui/picker/MusicPicker.qml @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: EasyRPG Editor Authors +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls as Controls +import org.kde.kirigami as Kirigami +import org.easyrpg.editor as Ez + +PickerBase { + id: root + + directoryName: "Music" + + Controls.SpinBox { + id: fadeinInput + value: root.pickerData.fadein + Kirigami.FormData.label: "Fade In:" + } + + Controls.SpinBox { + id: volumeInput + value: root.pickerData.volume + Kirigami.FormData.label: "Volume:" + } + + Controls.SpinBox { + id: tempoInput + value: root.pickerData.tempo + Kirigami.FormData.label: "Pitch:" + } + + Controls.SpinBox { + id: balanceInput + value: root.pickerData.balance + Kirigami.FormData.label: "Balance:" + } + + onAccepted: { + root.pickerData.fadein = fadeinInput.value + root.pickerData.volume = volumeInput.value + root.pickerData.tempo = tempoInput.value + root.pickerData.balance = balanceInput.value + } +} diff --git a/src/ui/picker/PickerBase.qml b/src/ui/picker/PickerBase.qml new file mode 100644 index 0000000..bc7bf35 --- /dev/null +++ b/src/ui/picker/PickerBase.qml @@ -0,0 +1,94 @@ +// SPDX-FileCopyrightText: EasyRPG Editor Authors +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls as Controls +import org.kde.kirigami as Kirigami +import org.easyrpg.editor as Ez + +Kirigami.Page { + id: root + + required property Ez.PickerData pickerData + + property string directoryName + + default property alias formContent: formLayout.data + + /** Signal emitted when confirming */ + signal accepted(); + + actions: [ + Kirigami.Action { + text: "Cancel" + icon.name: "cancel" + onTriggered: { + Kirigami.PageStack.closeDialog() + } + }, + Kirigami.Action { + text: "Select" + icon.name: "confirm" + onTriggered: { + root.pickerData.filename = nameInput.text + root.accepted() + Kirigami.PageStack.closeDialog() + } + } + ] + + RowLayout { + anchors.fill: parent + + Controls.ScrollView { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.preferredWidth: parent.width * 0.25 + + background: Rectangle { + //color: Kirigami.Theme.viewBackgroundColor + } + + ListView { + id: dirList + clip: true + + model: Ez.DirectoryModel { + path: Ez.ProjectData.findDirectory(root.directoryName) + } + + delegate: Controls.ItemDelegate { + width: ListView.view.width + text: baseName + + highlighted: baseName === nameInput.text + + action: Controls.Action { + onTriggered: { + nameInput.text = baseName + } + } + + Component.onCompleted: { + if (highlighted) { + dirList.positionViewAtIndex(index, ListView.Center) + } + } + } + } + } + + Kirigami.FormLayout { + id: formLayout + Layout.alignment: Qt.AlignTop + + Controls.TextField { + id: nameInput + text: root.pickerData.filename + Kirigami.FormData.label: "Name:" + visible: false + } + } + } +} diff --git a/src/ui/picker/SoundPicker.qml b/src/ui/picker/SoundPicker.qml new file mode 100644 index 0000000..d83b3ac --- /dev/null +++ b/src/ui/picker/SoundPicker.qml @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: EasyRPG Editor Authors +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls as Controls +import org.kde.kirigami as Kirigami +import org.easyrpg.editor as Ez + +PickerBase { + id: root + + directoryName: "Sound" + + Controls.SpinBox { + id: volumeInput + value: root.pickerData.volume + Kirigami.FormData.label: "Volume:" + } + + Controls.SpinBox { + id: tempoInput + value: root.pickerData.tempo + Kirigami.FormData.label: "Pitch:" + } + + Controls.SpinBox { + id: balanceInput + value: root.pickerData.balance + Kirigami.FormData.label: "Balance:" + } + + onAccepted: { + root.pickerData.volume = volumeInput.value + root.pickerData.tempo = tempoInput.value + root.pickerData.balance = balanceInput.value + } +} diff --git a/src/ui/viewer/FileViewerBase.qml b/src/ui/viewer/FileViewerBase.qml new file mode 100644 index 0000000..d8fba7e --- /dev/null +++ b/src/ui/viewer/FileViewerBase.qml @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: EasyRPG Editor Authors +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls as Controls +import org.kde.kirigami as Kirigami +import org.easyrpg.editor as Ez + +RowLayout { + id: root + + property alias value: component.text + + property Ez.PickerData pickerData + + property Component pickerComponent + + /** Signal emitted when confirming in the picker dialog */ + signal accepted() + + Controls.TextField { + id: component + text: pickerData.filename + onTextEdited: { + pickerData.filename = text + root.accepted() + } + } + + Controls.Button { + //icon.name: "document-open" + text: "..." + + onClicked: { + applicationWindow().pageStack.pushDialogLayer(root.pickerComponent, { + pickerData: root.pickerData + }); + } + } +} + diff --git a/src/ui/viewer/MusicViewer.qml b/src/ui/viewer/MusicViewer.qml new file mode 100644 index 0000000..cce7f50 --- /dev/null +++ b/src/ui/viewer/MusicViewer.qml @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: EasyRPG Editor Authors +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import org.easyrpg.editor as Ez + +FileViewerBase { + id: root + + pickerComponent: Component { + Ez.MusicPicker { + onAccepted: root.accepted() + } + } +} + diff --git a/src/ui/viewer/SoundViewer.qml b/src/ui/viewer/SoundViewer.qml new file mode 100644 index 0000000..ad96c0a --- /dev/null +++ b/src/ui/viewer/SoundViewer.qml @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: EasyRPG Editor Authors +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import org.easyrpg.editor as Ez + +FileViewerBase { + id: root + + pickerComponent: Component { + Ez.SoundPicker { + onAccepted: root.accepted() + } + } +} + From 651404225a9c2a651a2cada09a31adb871801033 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Tue, 28 Apr 2026 23:56:33 +0200 Subject: [PATCH 5/8] Add ImagePicker Like Music/SoundPicker but for images The rendering is done through SpritePaintedItem --- CMakeLists.txt | 4 ++ src/qmlbinding/project_data_gadget.cpp | 10 +++ src/qmlbinding/project_data_gadget.h | 3 + src/qmlbinding/sprite_painted_item.cpp | 85 ++++++++++++++++++++++++++ src/qmlbinding/sprite_painted_item.h | 58 ++++++++++++++++++ src/ui/database/SystemPage.qml | 61 +++++++++++++++++- src/ui/picker/ImagePicker.qml | 22 +++++++ src/ui/picker/MusicPicker.qml | 2 +- src/ui/picker/PickerBase.qml | 7 ++- src/ui/picker/SoundPicker.qml | 2 +- src/ui/viewer/ImageViewer.qml | 47 ++++++++++++++ 11 files changed, 294 insertions(+), 7 deletions(-) create mode 100644 src/qmlbinding/sprite_painted_item.cpp create mode 100644 src/qmlbinding/sprite_painted_item.h create mode 100644 src/ui/picker/ImagePicker.qml create mode 100644 src/ui/viewer/ImageViewer.qml diff --git a/CMakeLists.txt b/CMakeLists.txt index af26225..a3cbecc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -340,10 +340,12 @@ set(EDITOR_QML_UI src/ui/database/SkillPage.qml src/ui/database/SystemPage.qml src/ui/database/VocabularyPage.qml + src/ui/picker/ImagePicker.qml src/ui/picker/PickerBase.qml src/ui/picker/MusicPicker.qml src/ui/picker/SoundPicker.qml src/ui/viewer/FileViewerBase.qml + src/ui/viewer/ImageViewer.qml src/ui/viewer/MusicViewer.qml src/ui/viewer/SoundViewer.qml ) @@ -364,6 +366,8 @@ set(EDITOR_QML_INTERFACE src/qmlbinding/lcf_glaze.h src/qmlbinding/project_data_gadget.cpp src/qmlbinding/project_data_gadget.h + src/qmlbinding/sprite_painted_item.cpp + src/qmlbinding/sprite_painted_item.h ) # Dependencies diff --git a/src/qmlbinding/project_data_gadget.cpp b/src/qmlbinding/project_data_gadget.cpp index 930a372..55b45ba 100644 --- a/src/qmlbinding/project_data_gadget.cpp +++ b/src/qmlbinding/project_data_gadget.cpp @@ -16,6 +16,7 @@ */ #include "project_data_gadget.h" +#include "common/image_loader.h" #include "model/actor.h" #include "model/project.h" #include "json_view.h" @@ -65,6 +66,15 @@ QString ProjectDataGadget::findDirectory(const QString& baseDir, const QString& return m_data->project().findDirectory(baseDir, dir); } +QPixmap ProjectDataGadget::loadImage(const QString& dir, const QString& filename) const { + QString file = findFile(dir, filename, FileFinder::FileType::Image); + if (file.isEmpty()) { + return {}; + } + + return ImageLoader::Load(file); +} + ActorModel ProjectDataGadget::actorModel(int actor_index) { return ActorModel(*m_data, m_data->database().actors[actor_index]); } diff --git a/src/qmlbinding/project_data_gadget.h b/src/qmlbinding/project_data_gadget.h index 3c585a4..dfed9d6 100644 --- a/src/qmlbinding/project_data_gadget.h +++ b/src/qmlbinding/project_data_gadget.h @@ -22,6 +22,7 @@ #include "model/project_data.h" #include #include +#include class ActorModel; class JsonView; @@ -50,6 +51,8 @@ class ProjectDataGadget : public QObject Q_INVOKABLE QString findDirectory(const QString& dir) const; Q_INVOKABLE QString findDirectory(const QString& baseDir, const QString& dir) const; + Q_INVOKABLE QPixmap loadImage(const QString& dir, const QString& filename) const; + Q_INVOKABLE ActorModel actorModel(int actor_index); QString projectPath() const; diff --git a/src/qmlbinding/sprite_painted_item.cpp b/src/qmlbinding/sprite_painted_item.cpp new file mode 100644 index 0000000..0e0b37b --- /dev/null +++ b/src/qmlbinding/sprite_painted_item.cpp @@ -0,0 +1,85 @@ +/* + * This file is part of EasyRPG Editor. + * + * EasyRPG Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EasyRPG Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EasyRPG Editor. If not, see . + */ + +#include "sprite_painted_item.h" +#include + +SpritePaintedItem::SpritePaintedItem(QQuickItem *parent) { + +} + +QString SpritePaintedItem::filename() const { + return m_filename; +} + +void SpritePaintedItem::setFilename(const QString& filename) { + if (m_filename == filename) { + return; + } + m_filename = filename; + m_image = {}; + emit filenameChanged(); + reload(); +} + +QString SpritePaintedItem::directory() const { + return m_directory; +} + +void SpritePaintedItem::setDirectory(const QString& directory) { + if (m_directory == directory) { + return; + } + m_directory = directory; + m_image = {}; + emit filenameChanged(); + reload(); +} + +ProjectDataGadget* SpritePaintedItem::projectData() const { return m_projectData; } + +void SpritePaintedItem::setProjectData(ProjectDataGadget* projectData) { + m_projectData = projectData; + m_image = {}; + emit projectDataChanged(); + reload(); +} + +void SpritePaintedItem::paint(QPainter* painter) { + const QSize targetSize(qMax(1, int(width())), qMax(1, int(height()))); + const QPixmap scaled = m_image.scaled(targetSize, Qt::KeepAspectRatio, Qt::FastTransformation); + + painter->drawPixmap(0, 0, scaled); +} + +void SpritePaintedItem::reload() { + if (!projectData()) { + return; + } + + if (m_image.isNull()) { + m_image = projectData()->loadImage(m_directory, m_filename); + + if (!m_image.isNull()) { + setImplicitSize(m_image.width(), m_image.height()); + } else { + return; + } + } + + update(); +} diff --git a/src/qmlbinding/sprite_painted_item.h b/src/qmlbinding/sprite_painted_item.h new file mode 100644 index 0000000..4bdbb6a --- /dev/null +++ b/src/qmlbinding/sprite_painted_item.h @@ -0,0 +1,58 @@ +/* + * This file is part of EasyRPG Editor. + * + * EasyRPG Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EasyRPG Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EasyRPG Editor. If not, see . + */ + +#pragma once + +#include +#include +#include "project_data_gadget.h" + +class SpritePaintedItem : public QQuickPaintedItem { + Q_OBJECT + QML_ELEMENT + Q_PROPERTY(QString filename READ filename WRITE setFilename NOTIFY filenameChanged) + Q_PROPERTY(QString directory READ directory WRITE setDirectory NOTIFY directoryChanged) + Q_PROPERTY(ProjectDataGadget* projectData READ projectData WRITE setProjectData NOTIFY projectDataChanged) + +public: + explicit SpritePaintedItem(QQuickItem* parent = nullptr); + + QString filename() const; + void setFilename(const QString& filename); + + QString directory() const; + void setDirectory(const QString& directory); + + ProjectDataGadget* projectData() const; + void setProjectData(ProjectDataGadget* projectData); + + void paint(QPainter* painter) override; + +signals: + void filenameChanged(); + void directoryChanged(); + void projectDataChanged(); + +private: + void reload(); + + QString m_filename; + QString m_directory; + ProjectDataGadget* m_projectData = nullptr; + QPixmap m_image; +}; + diff --git a/src/ui/database/SystemPage.qml b/src/ui/database/SystemPage.qml index 1f74106..3f7571e 100644 --- a/src/ui/database/SystemPage.qml +++ b/src/ui/database/SystemPage.qml @@ -12,6 +12,23 @@ import org.easyrpg.editor as Ez DatabaseEntryPage { id: root + component JsonImageViewer : Ez.ImageViewer { + id: imageViewer + + Layout.fillWidth: true + + property string key + filename: root.jsonData.str(key) + + pickerData: Ez.PickerData { + Component.onCompleted: filename = imageViewer.filename + } + onAccepted: { + imageViewer.filename = pickerData.filename + jsonData.set(key, pickerData.filename) + } + } + component JsonMusicViewer : Ez.MusicViewer { property string key readonly property var musicData: root.jsonData.subtree(key) @@ -25,14 +42,54 @@ DatabaseEntryPage { property string key readonly property var soundData: root.jsonData.subtree(key) pickerData: Ez.PickerData { - Component.onCompleted: fromMusic(soundData) + Component.onCompleted: fromSound(soundData) } - onAccepted: pickerData.toMusic(soundData) + onAccepted: pickerData.toSound(soundData) } Kirigami.FormLayout { anchors.fill: parent + Kirigami.Separator { + Kirigami.FormData.isSection: true + Kirigami.FormData.label: "Title" + } + + JsonImageViewer { + directory: "Title" + key: "title_name" + } + + Kirigami.Separator { + Kirigami.FormData.isSection: true + Kirigami.FormData.label: "Game Over" + } + + JsonImageViewer { + directory: "GameOver" + key: "gameover_name" + } + + Kirigami.Separator { + Kirigami.FormData.isSection: true + Kirigami.FormData.label: "System" + } + + JsonImageViewer { + directory: "System" + key: "system_name" + } + + Kirigami.Separator { + Kirigami.FormData.isSection: true + Kirigami.FormData.label: "System 2" + } + + JsonImageViewer { + directory: "System 2" + key: "system2_name" + } + Kirigami.Separator { Kirigami.FormData.isSection: true Kirigami.FormData.label: "Music" diff --git a/src/ui/picker/ImagePicker.qml b/src/ui/picker/ImagePicker.qml new file mode 100644 index 0000000..7c382b1 --- /dev/null +++ b/src/ui/picker/ImagePicker.qml @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: EasyRPG Editor Authors +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls as Controls +import org.kde.kirigami as Kirigami +import org.easyrpg.editor as Ez + +PickerBase { + id: root + + Ez.SpritePaintedItem { + id: sprite + + directory: root.directory + filename: root.filename + projectData: Ez.ProjectData + + Layout.fillWidth: true + } +} diff --git a/src/ui/picker/MusicPicker.qml b/src/ui/picker/MusicPicker.qml index a2982a4..c6af630 100644 --- a/src/ui/picker/MusicPicker.qml +++ b/src/ui/picker/MusicPicker.qml @@ -10,7 +10,7 @@ import org.easyrpg.editor as Ez PickerBase { id: root - directoryName: "Music" + directory: "Music" Controls.SpinBox { id: fadeinInput diff --git a/src/ui/picker/PickerBase.qml b/src/ui/picker/PickerBase.qml index bc7bf35..54341c0 100644 --- a/src/ui/picker/PickerBase.qml +++ b/src/ui/picker/PickerBase.qml @@ -12,12 +12,13 @@ Kirigami.Page { required property Ez.PickerData pickerData - property string directoryName + readonly property alias filename: nameInput.text + property string directory default property alias formContent: formLayout.data /** Signal emitted when confirming */ - signal accepted(); + signal accepted() actions: [ Kirigami.Action { @@ -55,7 +56,7 @@ Kirigami.Page { clip: true model: Ez.DirectoryModel { - path: Ez.ProjectData.findDirectory(root.directoryName) + path: Ez.ProjectData.findDirectory(root.directory) } delegate: Controls.ItemDelegate { diff --git a/src/ui/picker/SoundPicker.qml b/src/ui/picker/SoundPicker.qml index d83b3ac..0b4ca09 100644 --- a/src/ui/picker/SoundPicker.qml +++ b/src/ui/picker/SoundPicker.qml @@ -10,7 +10,7 @@ import org.easyrpg.editor as Ez PickerBase { id: root - directoryName: "Sound" + directory: "Sound" Controls.SpinBox { id: volumeInput diff --git a/src/ui/viewer/ImageViewer.qml b/src/ui/viewer/ImageViewer.qml new file mode 100644 index 0000000..ce98ac0 --- /dev/null +++ b/src/ui/viewer/ImageViewer.qml @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: EasyRPG Editor Authors +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import QtQuick.Dialogs +import QtQuick.Controls +import org.kde.kirigami as Kirigami +import org.easyrpg.editor as Ez + +Item { + id: root + + implicitWidth: sprite.implicitWidth + implicitHeight: sprite.implicitHeight + + property Ez.PickerData pickerData + + property Component pickerComponent: Ez.ImagePicker { + onAccepted: root.accepted() + } + + /** Signal emitted when confirming in the picker dialog */ + signal accepted() + + property alias directory: sprite.directory + property alias filename: sprite.filename + + Ez.SpritePaintedItem { + id: sprite + + anchors.fill: parent + + projectData: Ez.ProjectData + + MouseArea { + id: mouseArea + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onClicked: { + applicationWindow().pageStack.pushDialogLayer(root.pickerComponent, { + pickerData: root.pickerData, + directory: sprite.directory + }); + } + } + } +} From 2a640a22e5f628e4ab429b64d81a827e61279461 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Tue, 26 May 2026 21:01:41 +0200 Subject: [PATCH 6/8] Add Picker and Viewer for FaceSet and CharSet The Sprite Painted Item class is now more advanced and can e.g. skip cells (used by the CharSet) and play animations (also CharSet) --- CMakeLists.txt | 20 +- src/qmlbinding/sprite_painted_item.cpp | 85 ------ src/qmlbinding/sprite_painted_item.h | 58 ----- src/ui/common/PickerData.qml | 1 + src/ui/database/ActorPage.qml | 77 +++++- src/ui/database/DatabaseEntryPage.qml | 3 + src/ui/database/SystemPage.qml | 50 ++++ src/ui/picker/CharSetPicker.qml | 94 +++++++ src/ui/picker/FaceSetPicker.qml | 27 ++ src/ui/picker/charset_painted_item.cpp | 142 ++++++++++ src/ui/picker/charset_painted_item.h | 86 +++++++ src/ui/picker/faceset_painted_item.cpp | 27 ++ src/ui/picker/faceset_painted_item.h | 33 +++ src/ui/picker/sprite_painted_item.cpp | 341 +++++++++++++++++++++++++ src/ui/picker/sprite_painted_item.h | 128 ++++++++++ src/ui/viewer/CharSetViewer.qml | 34 +++ src/ui/viewer/FaceSetViewer.qml | 29 +++ src/ui/viewer/ViewerBase.qml | 34 +++ 18 files changed, 1119 insertions(+), 150 deletions(-) delete mode 100644 src/qmlbinding/sprite_painted_item.cpp delete mode 100644 src/qmlbinding/sprite_painted_item.h create mode 100644 src/ui/picker/CharSetPicker.qml create mode 100644 src/ui/picker/FaceSetPicker.qml create mode 100644 src/ui/picker/charset_painted_item.cpp create mode 100644 src/ui/picker/charset_painted_item.h create mode 100644 src/ui/picker/faceset_painted_item.cpp create mode 100644 src/ui/picker/faceset_painted_item.h create mode 100644 src/ui/picker/sprite_painted_item.cpp create mode 100644 src/ui/picker/sprite_painted_item.h create mode 100644 src/ui/viewer/CharSetViewer.qml create mode 100644 src/ui/viewer/FaceSetViewer.qml create mode 100644 src/ui/viewer/ViewerBase.qml diff --git a/CMakeLists.txt b/CMakeLists.txt index a3cbecc..0143623 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -329,7 +329,6 @@ set(EDITOR_QML_UI src/ui/common/RadioButton.qml src/ui/common/SpinBox.qml src/ui/common/TextField.qml - src/ui/MainWindow.qml src/ui/database/ActorPage.qml src/ui/database/AttributePage.qml src/ui/database/DatabaseEntryListPage.qml @@ -340,14 +339,20 @@ set(EDITOR_QML_UI src/ui/database/SkillPage.qml src/ui/database/SystemPage.qml src/ui/database/VocabularyPage.qml + src/ui/MainWindow.qml + src/ui/picker/CharSetPicker.qml + src/ui/picker/FaceSetPicker.qml src/ui/picker/ImagePicker.qml - src/ui/picker/PickerBase.qml src/ui/picker/MusicPicker.qml + src/ui/picker/PickerBase.qml src/ui/picker/SoundPicker.qml + src/ui/viewer/CharSetViewer.qml + src/ui/viewer/FaceSetViewer.qml src/ui/viewer/FileViewerBase.qml src/ui/viewer/ImageViewer.qml src/ui/viewer/MusicViewer.qml src/ui/viewer/SoundViewer.qml + src/ui/viewer/ViewerBase.qml ) set(EDITOR_QML_INTERFACE @@ -357,17 +362,21 @@ set(EDITOR_QML_INTERFACE src/qmlbinding/json_internals/json_t_impl.h src/qmlbinding/json_internals/json_t_map.cpp src/qmlbinding/json_internals/json_t_treemap.cpp - src/qmlbinding/json.h src/qmlbinding/json_list_view.cpp src/qmlbinding/json_list_view.h src/qmlbinding/json_t.h src/qmlbinding/json_view.cpp src/qmlbinding/json_view.h + src/qmlbinding/json.h src/qmlbinding/lcf_glaze.h src/qmlbinding/project_data_gadget.cpp src/qmlbinding/project_data_gadget.h - src/qmlbinding/sprite_painted_item.cpp - src/qmlbinding/sprite_painted_item.h + src/ui/picker/charset_painted_item.cpp + src/ui/picker/charset_painted_item.h + src/ui/picker/faceset_painted_item.cpp + src/ui/picker/faceset_painted_item.h + src/ui/picker/sprite_painted_item.cpp + src/ui/picker/sprite_painted_item.h ) # Dependencies @@ -437,6 +446,7 @@ target_include_directories(${EXE_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/src/qmlbinding # Required by QML build step + ${CMAKE_CURRENT_SOURCE_DIR}/src/ui/picker # QML painted items INTERFACE $ ) diff --git a/src/qmlbinding/sprite_painted_item.cpp b/src/qmlbinding/sprite_painted_item.cpp deleted file mode 100644 index 0e0b37b..0000000 --- a/src/qmlbinding/sprite_painted_item.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * This file is part of EasyRPG Editor. - * - * EasyRPG Editor is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * EasyRPG Editor is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with EasyRPG Editor. If not, see . - */ - -#include "sprite_painted_item.h" -#include - -SpritePaintedItem::SpritePaintedItem(QQuickItem *parent) { - -} - -QString SpritePaintedItem::filename() const { - return m_filename; -} - -void SpritePaintedItem::setFilename(const QString& filename) { - if (m_filename == filename) { - return; - } - m_filename = filename; - m_image = {}; - emit filenameChanged(); - reload(); -} - -QString SpritePaintedItem::directory() const { - return m_directory; -} - -void SpritePaintedItem::setDirectory(const QString& directory) { - if (m_directory == directory) { - return; - } - m_directory = directory; - m_image = {}; - emit filenameChanged(); - reload(); -} - -ProjectDataGadget* SpritePaintedItem::projectData() const { return m_projectData; } - -void SpritePaintedItem::setProjectData(ProjectDataGadget* projectData) { - m_projectData = projectData; - m_image = {}; - emit projectDataChanged(); - reload(); -} - -void SpritePaintedItem::paint(QPainter* painter) { - const QSize targetSize(qMax(1, int(width())), qMax(1, int(height()))); - const QPixmap scaled = m_image.scaled(targetSize, Qt::KeepAspectRatio, Qt::FastTransformation); - - painter->drawPixmap(0, 0, scaled); -} - -void SpritePaintedItem::reload() { - if (!projectData()) { - return; - } - - if (m_image.isNull()) { - m_image = projectData()->loadImage(m_directory, m_filename); - - if (!m_image.isNull()) { - setImplicitSize(m_image.width(), m_image.height()); - } else { - return; - } - } - - update(); -} diff --git a/src/qmlbinding/sprite_painted_item.h b/src/qmlbinding/sprite_painted_item.h deleted file mode 100644 index 4bdbb6a..0000000 --- a/src/qmlbinding/sprite_painted_item.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of EasyRPG Editor. - * - * EasyRPG Editor is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * EasyRPG Editor is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with EasyRPG Editor. If not, see . - */ - -#pragma once - -#include -#include -#include "project_data_gadget.h" - -class SpritePaintedItem : public QQuickPaintedItem { - Q_OBJECT - QML_ELEMENT - Q_PROPERTY(QString filename READ filename WRITE setFilename NOTIFY filenameChanged) - Q_PROPERTY(QString directory READ directory WRITE setDirectory NOTIFY directoryChanged) - Q_PROPERTY(ProjectDataGadget* projectData READ projectData WRITE setProjectData NOTIFY projectDataChanged) - -public: - explicit SpritePaintedItem(QQuickItem* parent = nullptr); - - QString filename() const; - void setFilename(const QString& filename); - - QString directory() const; - void setDirectory(const QString& directory); - - ProjectDataGadget* projectData() const; - void setProjectData(ProjectDataGadget* projectData); - - void paint(QPainter* painter) override; - -signals: - void filenameChanged(); - void directoryChanged(); - void projectDataChanged(); - -private: - void reload(); - - QString m_filename; - QString m_directory; - ProjectDataGadget* m_projectData = nullptr; - QPixmap m_image; -}; - diff --git a/src/ui/common/PickerData.qml b/src/ui/common/PickerData.qml index 643ed44..6c1970d 100644 --- a/src/ui/common/PickerData.qml +++ b/src/ui/common/PickerData.qml @@ -5,6 +5,7 @@ QtObject { property string filename property int index: 0 + property bool transparent: false property int fadein: 0 property int volume: 100 diff --git a/src/ui/database/ActorPage.qml b/src/ui/database/ActorPage.qml index 8c0eaa5..c7ca14a 100644 --- a/src/ui/database/ActorPage.qml +++ b/src/ui/database/ActorPage.qml @@ -21,19 +21,41 @@ DatabaseEntryPage { Models.ListElement { key: "accessory_id"; label: "Accessory:"; type: 5 } } + /*property Ez.PickerData charsetPickerData: Ez.PickerData { + index: charsetViewer.characterIndex + Component.onCompleted: filename = charsetViewer.filename + } + + property Component charsetPickerComponent: Ez.ImagePicker { + onAccepted: { + charsetViewer.filename = pickerData.filename + charsetViewer.characterIndex = pickerData.index + root.jsonData.set("character_name", pickerData.filename) + root.jsonData.set("character_index", pickerData.index) + } + }*/ + Kirigami.FormLayout { - anchors.fill: parent + id: form1 + Layout.fillWidth: true + + Kirigami.Separator { + Kirigami.FormData.isSection: true + Kirigami.FormData.label: "General" + } Ez.TextField { jsonData: root.jsonData key: "name" Kirigami.FormData.label: "Name:" + Layout.fillWidth: true } Ez.TextField { jsonData: root.jsonData key: "title" Kirigami.FormData.label: "Title:" + Layout.fillWidth: true } RowLayout { @@ -78,6 +100,57 @@ DatabaseEntryPage { } } + Kirigami.Separator { + Kirigami.FormData.isSection: true + Kirigami.FormData.label: "Graphics" + } + + Ez.FaceSetViewer { + id: faceViewer + Kirigami.FormData.label: "Face:" + + filename: root.jsonData.str("face_name") + cellIndex: root.jsonData.num("face_index") + + pickerData: Ez.PickerData { + index: faceViewer.cellIndex + Component.onCompleted: filename = faceViewer.filename + } + + onAccepted: { + faceViewer.filename = pickerData.filename + faceViewer.cellIndex = pickerData.index + root.jsonData.set("face_name", pickerData.filename) + root.jsonData.set("face_index", pickerData.index) + } + } + + Ez.CharSetViewer { + id: charViewer + Kirigami.FormData.label: "Character:" + + spin: true + walk: true + filename: root.jsonData.str("character_name") + cellIndex: root.jsonData.num("character_index") + transparent: root.jsonData.boolean("transparent") + + pickerData: Ez.PickerData { + index: charViewer.cellIndex + transparent: charViewer.transparent + Component.onCompleted: filename = charViewer.filename + } + + onAccepted: { + charViewer.filename = pickerData.filename + charViewer.cellIndex = pickerData.index + charViewer.transparent = pickerData.transparent + root.jsonData.set("character_name", pickerData.filename) + root.jsonData.set("character_index", pickerData.index) + root.jsonData.set("transparent", pickerData.transparent) + } + } + Kirigami.Separator { Kirigami.FormData.isSection: true Kirigami.FormData.label: "Equipment" @@ -89,7 +162,7 @@ DatabaseEntryPage { Ez.ComboBox { readonly property var repdata: equipmentRepeater.model.get(index) - + Layout.fillWidth: true jsonData: root.jsonData key: "initial_equipment/" + repdata.key Kirigami.FormData.label: repdata.label diff --git a/src/ui/database/DatabaseEntryPage.qml b/src/ui/database/DatabaseEntryPage.qml index f5523e7..fd24903 100644 --- a/src/ui/database/DatabaseEntryPage.qml +++ b/src/ui/database/DatabaseEntryPage.qml @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later import QtQuick +import QtQuick.Layouts import org.kde.kirigami as Kirigami import org.easyrpg.editor as Ez @@ -24,6 +25,8 @@ Kirigami.ScrollablePage { // TODO: Not used. Just for testing property bool showActions: false + Layout.fillWidth: true + actions: [ Kirigami.Action { text: "Cancel" diff --git a/src/ui/database/SystemPage.qml b/src/ui/database/SystemPage.qml index 3f7571e..4e3a208 100644 --- a/src/ui/database/SystemPage.qml +++ b/src/ui/database/SystemPage.qml @@ -47,6 +47,30 @@ DatabaseEntryPage { onAccepted: pickerData.toSound(soundData) } + component JsonCharSetViewer : Ez.CharSetViewer { + id: charViewer + property string nameKey + property string indexKey + + spin: true + walk: true + + filename: root.jsonData.str(nameKey) + cellIndex: root.jsonData.num(indexKey) + + pickerData: Ez.PickerData { + index: charViewer.cellIndex + Component.onCompleted: filename = charViewer.filename + } + + onAccepted: { + charViewer.filename = pickerData.filename + charViewer.cellIndex = pickerData.index + root.jsonData.set(nameKey, pickerData.filename) + root.jsonData.set(indexKey, pickerData.index) + } + } + Kirigami.FormLayout { anchors.fill: parent @@ -200,5 +224,31 @@ DatabaseEntryPage { key: "item_se" Kirigami.FormData.label: "Item:" } + + Kirigami.Separator { + Kirigami.FormData.isSection: true + Kirigami.FormData.label: "Vehicles" + } + + JsonCharSetViewer { + Kirigami.FormData.label: "Boat:" + nameKey: "boat_name" + indexKey: "boat_index" + showTransparency: false + } + + JsonCharSetViewer { + Kirigami.FormData.label: "Ship:" + nameKey: "ship_name" + indexKey: "ship_index" + showTransparency: false + } + + JsonCharSetViewer { + Kirigami.FormData.label: "Airship:" + nameKey: "airship_name" + indexKey: "airship_index" + showTransparency: false + } } } diff --git a/src/ui/picker/CharSetPicker.qml b/src/ui/picker/CharSetPicker.qml new file mode 100644 index 0000000..53205bc --- /dev/null +++ b/src/ui/picker/CharSetPicker.qml @@ -0,0 +1,94 @@ +// SPDX-FileCopyrightText: EasyRPG Editor Authors +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls as Controls +import org.kde.kirigami as Kirigami +import org.easyrpg.editor as Ez + +PickerBase { + id: root + + directory: "CharSet" + property bool showTransparency: true + + Ez.CharSetPaintedItem { + id: charsetPainted + pickerMode: true + projectData: Ez.ProjectData + filename: root.filename + cellIndex: root.pickerData.index + transparent: root.pickerData.transparent + onCellIndexChanged: { + root.pickerData.index = cellIndex + } + Layout.fillWidth: true + implicitWidth: 192 + implicitHeight: 192 + } + + Kirigami.Separator { + visible: root.showTransparency + Kirigami.FormData.isSection: true + Kirigami.FormData.label: "Options" + } + + Controls.CheckBox { + visible: root.showTransparency + text: "Transparent" + checked: root.pickerData.transparent + onClicked: root.pickerData.transparent = checked + } + + Kirigami.Separator { + Kirigami.FormData.isSection: true + Kirigami.FormData.label: "Facing (Preview Only)" + } + + ColumnLayout { + Controls.RadioButton { + text: "Up" + checked: charsetPainted.facing === Ez.CharSetPaintedItem.Direction_up + onClicked: charsetPainted.facing = Ez.CharSetPaintedItem.Direction_up + } + Controls.RadioButton { + text: "Right" + checked: charsetPainted.facing === Ez.CharSetPaintedItem.Direction_right + onClicked: charsetPainted.facing = Ez.CharSetPaintedItem.Direction_right + } + Controls.RadioButton { + text: "Down" + checked: charsetPainted.facing === Ez.CharSetPaintedItem.Direction_down + onClicked: charsetPainted.facing = Ez.CharSetPaintedItem.Direction_down + } + Controls.RadioButton { + text: "Left" + checked: charsetPainted.facing === Ez.CharSetPaintedItem.Direction_left + onClicked: charsetPainted.facing = Ez.CharSetPaintedItem.Direction_left + } + } + + Kirigami.Separator { + Kirigami.FormData.isSection: true + Kirigami.FormData.label: "Pattern (Preview Only)" + } + + ColumnLayout { + Controls.RadioButton { + text: "Left" + checked: charsetPainted.frame === Ez.CharSetPaintedItem.Frame_left + onClicked: charsetPainted.frame = Ez.CharSetPaintedItem.Frame_left + } + Controls.RadioButton { + text: "Middle" + checked: charsetPainted.frame === Ez.CharSetPaintedItem.Frame_middle + onClicked: charsetPainted.frame = Ez.CharSetPaintedItem.Frame_middle + } + Controls.RadioButton { + text: "Right" + checked: charsetPainted.frame === Ez.CharSetPaintedItem.Frame_right + onClicked: charsetPainted.frame = Ez.CharSetPaintedItem.Frame_right + } + } +} diff --git a/src/ui/picker/FaceSetPicker.qml b/src/ui/picker/FaceSetPicker.qml new file mode 100644 index 0000000..7c3dfc3 --- /dev/null +++ b/src/ui/picker/FaceSetPicker.qml @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: EasyRPG Editor Authors +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import QtQuick.Layouts +import org.kde.kirigami as Kirigami +import org.easyrpg.editor as Ez + +PickerBase { + id: root + + directory: "FaceSet" + + Ez.FaceSetPaintedItem { + id: facesetGrid + pickerMode: true + projectData: Ez.ProjectData + filename: root.filename + cellIndex: root.pickerData.index + onCellIndexChanged: { + root.pickerData.index = cellIndex + } + Layout.fillWidth: true + implicitWidth: 192 + implicitHeight: 192 + } +} diff --git a/src/ui/picker/charset_painted_item.cpp b/src/ui/picker/charset_painted_item.cpp new file mode 100644 index 0000000..4986196 --- /dev/null +++ b/src/ui/picker/charset_painted_item.cpp @@ -0,0 +1,142 @@ +/* + * This file is part of EasyRPG Editor. + * + * EasyRPG Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EasyRPG Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EasyRPG Editor. If not, see . + */ + +#include "charset_painted_item.h" + +CharSetPaintedItem::CharSetPaintedItem(QQuickItem *parent) : SpritePaintedItem(parent) { + m_directory = QStringLiteral("CharSet"); + m_cellWidth = 24; + m_cellHeight = 32; + m_skipCellsX = 2; // block width is 3 cells, so skip 2 + m_skipCellsY = 3; // block height is 4 cells, so skip 3 + setCellOffsetX(m_frame * m_cellWidth); + setCellOffsetY(m_facing * m_cellHeight); + + // Animation timer ~30 fps + m_timer.setInterval(1000 / 30); + QObject::connect(&m_timer, &QTimer::timeout, this, &CharSetPaintedItem::tick); +} + +int CharSetPaintedItem::facing() const { + return m_facing; +} + +void CharSetPaintedItem::setFacing(int facing) { + if (m_facing == facing) { + return; + } + m_facing = facing; + setCellOffsetY(m_facing * m_cellHeight); + emit facingChanged(); + update(); +} + +int CharSetPaintedItem::frame() const { + return m_frame; +} + +void CharSetPaintedItem::setFrame(int frame) { + if (m_frame == frame) { + return; + } + m_frame = frame; + setCellOffsetX(m_frame * m_cellWidth); + emit frameChanged(); + update(); +} + +bool CharSetPaintedItem::spin() const { + return m_spin; +} + +void CharSetPaintedItem::setSpin(bool spin) { + if (m_spin == spin) { + return; + } + m_spin = spin; + emit spinChanged(); + + if (m_spin || m_walk) { + m_timer.start(); + } else { + m_timer.stop(); + } +} + +bool CharSetPaintedItem::walk() const { + return m_walk; +} + +void CharSetPaintedItem::setWalk(bool walk) { + if (m_walk == walk) { + return; + } + m_walk = walk; + emit walkChanged(); + + if (m_spin || m_walk) { + m_timer.start(); + } else { + m_timer.stop(); + } +} + +QRectF CharSetPaintedItem::sourceRect() const { + if (pickerMode()) { + return SpritePaintedItem::sourceRect(); + } + + const int blockSizeX = 72; + const int blockSizeY = 128; + const int colsPerRow = 4; + + const int blockX = (m_cellIndex % colsPerRow) * blockSizeX; + const int blockY = (m_cellIndex / colsPerRow) * blockSizeY; + + const int x = blockX + m_frame * m_cellWidth; + const int y = blockY + m_facing * m_cellHeight; + + return QRectF(x, y, m_cellWidth, m_cellHeight); +} + +void CharSetPaintedItem::tick() { + static const int walkPatterns[4] = {Frame_middle, Frame_right, Frame_middle, Frame_left}; + + frame_count++; + + if (frame_count == 90) { + frame_count = 0; + if (m_spin) { + m_facing++; + if (m_facing > Direction_left) { + m_facing = Direction_up; + } + emit facingChanged(); + } + } + + if (m_walk) { + m_frame = walkPatterns[m_pattern]; + emit frameChanged(); + + if (frame_count % 6 == 0) { + m_pattern = (m_pattern + 1) % 4; + } + } + + update(); +} diff --git a/src/ui/picker/charset_painted_item.h b/src/ui/picker/charset_painted_item.h new file mode 100644 index 0000000..4421971 --- /dev/null +++ b/src/ui/picker/charset_painted_item.h @@ -0,0 +1,86 @@ +/* + * This file is part of EasyRPG Editor. + * + * EasyRPG Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EasyRPG Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EasyRPG Editor. If not, see . + */ + +#pragma once + +#include "sprite_painted_item.h" +#include + +/** + * Displays an animated character from a CharSet spritesheet. + */ +class CharSetPaintedItem : public SpritePaintedItem { + Q_OBJECT + QML_ELEMENT + Q_PROPERTY(int facing READ facing WRITE setFacing NOTIFY facingChanged) + Q_PROPERTY(int frame READ frame WRITE setFrame NOTIFY frameChanged) + Q_PROPERTY(bool spin READ spin WRITE setSpin NOTIFY spinChanged) + Q_PROPERTY(bool walk READ walk WRITE setWalk NOTIFY walkChanged) + +public: + enum Direction { + Direction_up = 0, + Direction_right = 1, + Direction_down = 2, + Direction_left = 3 + }; + Q_ENUM(Direction) + + enum Frame { + Frame_left = 0, + Frame_middle = 1, + Frame_right = 2 + }; + Q_ENUM(Frame) + + explicit CharSetPaintedItem(QQuickItem* parent = nullptr); + + int facing() const; + void setFacing(int facing); + + int frame() const; + void setFrame(int frame); + + bool spin() const; + void setSpin(bool spin); + + bool walk() const; + void setWalk(bool walk); + +signals: + void characterIndexChanged(); + void facingChanged(); + void frameChanged(); + void spinChanged(); + void walkChanged(); + +protected: + QRectF sourceRect() const override; + +private: + void tick(); + + QTimer m_timer; + + int m_facing = Direction_down; + int m_frame = Frame_middle; + bool m_spin = false; + bool m_walk = false; + + int m_pattern = 0; + int frame_count = 0; +}; diff --git a/src/ui/picker/faceset_painted_item.cpp b/src/ui/picker/faceset_painted_item.cpp new file mode 100644 index 0000000..a4cd3f0 --- /dev/null +++ b/src/ui/picker/faceset_painted_item.cpp @@ -0,0 +1,27 @@ +/* + * This file is part of EasyRPG Editor. + * + * EasyRPG Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EasyRPG Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EasyRPG Editor. If not, see . + */ + +#include "faceset_painted_item.h" +#include +#include + +FaceSetPaintedItem::FaceSetPaintedItem(QQuickItem* parent) : SpritePaintedItem(parent) { + setDirectory(QStringLiteral("FaceSet")); + setCellWidth(48); + setCellHeight(48); +} + diff --git a/src/ui/picker/faceset_painted_item.h b/src/ui/picker/faceset_painted_item.h new file mode 100644 index 0000000..812b432 --- /dev/null +++ b/src/ui/picker/faceset_painted_item.h @@ -0,0 +1,33 @@ +/* + * This file is part of EasyRPG Editor. + * + * EasyRPG Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EasyRPG Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EasyRPG Editor. If not, see . + */ + +#pragma once + +#include "sprite_painted_item.h" + +/** + * Displays or picks faces from a FaceSet spritesheet. + */ +class FaceSetPaintedItem : public SpritePaintedItem { + Q_OBJECT + QML_ELEMENT + +public: + explicit FaceSetPaintedItem(QQuickItem* parent = nullptr); + +protected: +}; diff --git a/src/ui/picker/sprite_painted_item.cpp b/src/ui/picker/sprite_painted_item.cpp new file mode 100644 index 0000000..5f4f7d8 --- /dev/null +++ b/src/ui/picker/sprite_painted_item.cpp @@ -0,0 +1,341 @@ +/* + * This file is part of EasyRPG Editor. + * + * EasyRPG Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EasyRPG Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EasyRPG Editor. If not, see . + */ + +#include "sprite_painted_item.h" +#include + +SpritePaintedItem::SpritePaintedItem(QQuickItem *parent) : QQuickPaintedItem(parent) { + setAcceptedMouseButtons(Qt::LeftButton); +} + +QString SpritePaintedItem::filename() const { + return m_filename; +} + +void SpritePaintedItem::setFilename(const QString& filename) { + if (m_filename == filename) { + return; + } + m_filename = filename; + m_image = {}; + emit filenameChanged(); + reload(); +} + +QString SpritePaintedItem::directory() const { + return m_directory; +} + +void SpritePaintedItem::setDirectory(const QString& directory) { + if (m_directory == directory) { + return; + } + m_directory = directory; + m_image = {}; + emit directoryChanged(); + reload(); +} + +ProjectDataGadget* SpritePaintedItem::projectData() const { return m_projectData; } + +void SpritePaintedItem::setProjectData(ProjectDataGadget* projectData) { + m_projectData = projectData; + m_image = {}; + emit projectDataChanged(); + reload(); +} + +bool SpritePaintedItem::pickerMode() const { + return m_pickerMode; +} + +void SpritePaintedItem::setPickerMode(bool pickerMode) { + if (m_pickerMode == pickerMode) { + return; + } + m_pickerMode = pickerMode; + emit pickerModeChanged(); + update(); +} + +int SpritePaintedItem::cellIndex() const { + return m_cellIndex; +} + +void SpritePaintedItem::setCellIndex(int cellIndex) { + if (m_cellIndex == cellIndex) { + return; + } + m_cellIndex = cellIndex; + emit cellIndexChanged(); + update(); +} + +int SpritePaintedItem::cellWidth() const { + return m_cellWidth; +} + +void SpritePaintedItem::setCellWidth(int cellWidth) { + if (m_cellWidth == cellWidth) { + return; + } + m_cellWidth = cellWidth; + emit cellWidthChanged(); + update(); +} + +int SpritePaintedItem::cellHeight() const { + return m_cellHeight; +} + +void SpritePaintedItem::setCellHeight(int cellHeight) { + if (m_cellHeight == cellHeight) { + return; + } + m_cellHeight = cellHeight; + emit cellHeightChanged(); + update(); +} + +bool SpritePaintedItem::transparent() const { + return m_transparent; +} + +void SpritePaintedItem::setTransparent(bool transparent) { + if (m_transparent == transparent) { + return; + } + m_transparent = transparent; + emit transparentChanged(); + update(); +} + +int SpritePaintedItem::cellOffsetX() const { + return m_cellOffsetX; +} + +void SpritePaintedItem::setCellOffsetX(int cellOffsetX) { + if (m_cellOffsetX == cellOffsetX) { + return; + } + m_cellOffsetX = cellOffsetX; + emit cellOffsetXChanged(); + update(); +} + +int SpritePaintedItem::cellOffsetY() const { + return m_cellOffsetY; +} + +void SpritePaintedItem::setCellOffsetY(int cellOffsetY) { + if (m_cellOffsetY == cellOffsetY) { + return; + } + m_cellOffsetY = cellOffsetY; + emit cellOffsetYChanged(); + update(); +} + +int SpritePaintedItem::skipCellsX() const { + return m_skipCellsX; +} + +void SpritePaintedItem::setSkipCellsX(int skipCellsX) { + if (m_skipCellsX == skipCellsX) { + return; + } + m_skipCellsX = skipCellsX; + emit skipCellsXChanged(); + update(); +} + +int SpritePaintedItem::skipCellsY() const { + return m_skipCellsY; +} + +void SpritePaintedItem::setSkipCellsY(int skipCellsY) { + if (m_skipCellsY == skipCellsY) { + return; + } + m_skipCellsY = skipCellsY; + emit skipCellsYChanged(); + update(); +} + +int SpritePaintedItem::gridColumns() const { + return m_gridColumns; +} + +void SpritePaintedItem::setGridColumns(int gridColumns) { + if (m_gridColumns == gridColumns) { + return; + } + m_gridColumns = gridColumns; + emit gridColumnsChanged(); + update(); +} + +QRectF SpritePaintedItem::sourceRect() const { + if (m_cellWidth <= 0 || m_cellHeight <= 0) { + return m_image.rect(); + } + const int pitchX = m_cellWidth * (m_skipCellsX + 1); + const int pitchY = m_cellHeight * (m_skipCellsY + 1); + const int col = m_cellIndex % m_gridColumns; + const int row = m_cellIndex / m_gridColumns; + return QRectF(col * pitchX + m_cellOffsetX, row * pitchY + m_cellOffsetY, m_cellWidth, m_cellHeight); +} + +void SpritePaintedItem::paint(QPainter* painter) { + if (m_image.isNull()) { + return; + } + + if (m_transparent) { + painter->setOpacity(0.5); + } + + if (m_pickerMode) { + if (m_cellWidth <= 0 || m_cellHeight <= 0) { + const QSize targetSize(qMax(1, int(width())), qMax(1, int(height()))); + const QPixmap scaled = m_image.scaled(targetSize, Qt::KeepAspectRatio, Qt::FastTransformation); + painter->drawPixmap(QRectF(0, 0, scaled.width(), scaled.height()), scaled, scaled.rect()); + } else { + // Picker mode: draw only the non-skipped cells sequentially + const int pitchX = m_cellWidth * (m_skipCellsX + 1); + const int pitchY = m_cellHeight * (m_skipCellsY + 1); + const int cols = qMax(1, m_image.width() / pitchX); + const int rows = qMax(1, m_image.height() / pitchY); + const int packedWidth = cols * m_cellWidth; + const int packedHeight = rows * m_cellHeight; + + const QSize targetSize(qMax(1, int(width())), qMax(1, int(height()))); + const QSize scaledSize = QSize(packedWidth, packedHeight).scaled(targetSize, Qt::KeepAspectRatio); + + const qreal scaleX = static_cast(scaledSize.width()) / packedWidth; + const qreal scaleY = static_cast(scaledSize.height()) / packedHeight; + + for (int row = 0; row < rows; ++row) { + for (int col = 0; col < cols; ++col) { + const QRectF srcRect(col * pitchX + m_cellOffsetX, row * pitchY + m_cellOffsetY, m_cellWidth, m_cellHeight); + const QRectF destRect(col * m_cellWidth * scaleX, row * m_cellHeight * scaleY, m_cellWidth * scaleX, m_cellHeight * scaleY); + painter->drawPixmap(destRect, m_image, srcRect); + } + } + + // Draw selection rectangle + const int selCol = m_cellIndex % m_gridColumns; + const int selRow = m_cellIndex / m_gridColumns; + const QRectF selRect( + selCol * m_cellWidth * scaleX, + selRow * m_cellHeight * scaleY, + m_cellWidth * scaleX, + m_cellHeight * scaleY + ); + + if (m_transparent) { + painter->setOpacity(1.0); + } + + QPen selPen(Qt::white); + selPen.setWidth(2); + selPen.setCosmetic(true); + + painter->setPen(selPen); + painter->setBrush(Qt::NoBrush); + painter->drawRect(selRect); + } + } else { + // Viewer mode: Draw the selected cell from the original image + // Scaled to fill the widget + const QRectF src = sourceRect(); + painter->drawPixmap(QRectF(0, 0, width(), height()), m_image, src); + } + + if (m_transparent && !m_pickerMode) { + painter->setOpacity(1.0); + } +} + +void SpritePaintedItem::mousePressEvent(QMouseEvent* event) { + if (m_image.isNull()) { + return; + } + + if (!m_pickerMode) { + return; + } + + if (m_cellWidth <= 0 || m_cellHeight <= 0) { + return; + } + + const int pitchX = m_cellWidth * (m_skipCellsX + 1); + const int pitchY = m_cellHeight * (m_skipCellsY + 1); + const int cols = qMax(1, m_image.width() / pitchX); + const int rows = qMax(1, m_image.height() / pitchY); + const int packedWidth = cols * m_cellWidth; + const int packedHeight = rows * m_cellHeight; + + const QSize targetSize(qMax(1, int(width())), qMax(1, int(height()))); + const QSize scaledSize = QSize(packedWidth, packedHeight).scaled(targetSize, Qt::KeepAspectRatio); + + const qreal scaleX = static_cast(scaledSize.width()) / packedWidth; + const qreal scaleY = static_cast(scaledSize.height()) / packedHeight; + + const int col = static_cast(event->pos().x() / (m_cellWidth * scaleX)); + const int row = static_cast(event->pos().y() / (m_cellHeight * scaleY)); + + if (col >= 0 && col < cols && row >= 0 && row < rows) { + const int index = row * m_gridColumns + col; + setCellIndex(index); + } +} + +void SpritePaintedItem::reload() { + if (!projectData()) { + return; + } + + if (m_image.isNull()) { + m_image = projectData()->loadImage(m_directory, m_filename); + } + + if (!m_image.isNull()) { + if (pickerMode()) { + if (m_cellWidth > 0 && m_cellHeight > 0) { + const int pitchX = m_cellWidth * (m_skipCellsX + 1); + const int pitchY = m_cellHeight * (m_skipCellsY + 1); + const int cols = qMax(1, m_image.width() / pitchX); + const int rows = qMax(1, m_image.height() / pitchY); + setImplicitSize(cols * m_cellWidth, rows * m_cellHeight); + } else { + setImplicitSize(m_image.width(), m_image.height()); + } + } else { + if (m_cellWidth > 0 && m_cellHeight > 0) { + setImplicitSize(m_cellWidth, m_cellHeight); + } else { + setImplicitSize(m_image.width(), m_image.height()); + } + } + } else { + setImplicitSize(m_cellWidth, m_cellHeight); + } + + update(); +} diff --git a/src/ui/picker/sprite_painted_item.h b/src/ui/picker/sprite_painted_item.h new file mode 100644 index 0000000..d6b633f --- /dev/null +++ b/src/ui/picker/sprite_painted_item.h @@ -0,0 +1,128 @@ +/* + * This file is part of EasyRPG Editor. + * + * EasyRPG Editor is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EasyRPG Editor is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EasyRPG Editor. If not, see . + */ + +#pragma once + +#include +#include +#include "project_data_gadget.h" + +/** + * Base class for spritesheet based painted items. + * + * The picker mode decides whether it displays a single item (false) or is used + * in a picker context (true). + */ +class SpritePaintedItem : public QQuickPaintedItem { + Q_OBJECT + QML_ELEMENT + Q_PROPERTY(QString filename READ filename WRITE setFilename NOTIFY filenameChanged) + Q_PROPERTY(QString directory READ directory WRITE setDirectory NOTIFY directoryChanged) + Q_PROPERTY(ProjectDataGadget* projectData READ projectData WRITE setProjectData NOTIFY projectDataChanged) + Q_PROPERTY(bool pickerMode READ pickerMode WRITE setPickerMode NOTIFY pickerModeChanged) + Q_PROPERTY(int cellIndex READ cellIndex WRITE setCellIndex NOTIFY cellIndexChanged) + Q_PROPERTY(int cellWidth READ cellWidth WRITE setCellWidth NOTIFY cellWidthChanged) + Q_PROPERTY(int cellHeight READ cellHeight WRITE setCellHeight NOTIFY cellHeightChanged) + Q_PROPERTY(bool transparent READ transparent WRITE setTransparent NOTIFY transparentChanged) + Q_PROPERTY(int skipCellsX READ skipCellsX WRITE setSkipCellsX NOTIFY skipCellsXChanged) + Q_PROPERTY(int skipCellsY READ skipCellsY WRITE setSkipCellsY NOTIFY skipCellsYChanged) + Q_PROPERTY(int gridColumns READ gridColumns WRITE setGridColumns NOTIFY gridColumnsChanged) + +public: + explicit SpritePaintedItem(QQuickItem* parent = nullptr); + + QString filename() const; + void setFilename(const QString& filename); + + QString directory() const; + void setDirectory(const QString& directory); + + ProjectDataGadget* projectData() const; + void setProjectData(ProjectDataGadget* projectData); + + bool pickerMode() const; + void setPickerMode(bool pickerMode); + + int cellIndex() const; + void setCellIndex(int cellIndex); + + int cellWidth() const; + void setCellWidth(int cellWidth); + + int cellHeight() const; + void setCellHeight(int cellHeight); + + bool transparent() const; + void setTransparent(bool transparent); + + int cellOffsetX() const; + void setCellOffsetX(int cellOffsetX); + + int cellOffsetY() const; + void setCellOffsetY(int cellOffsetY); + + int skipCellsX() const; + void setSkipCellsX(int skipCellsX); + + int skipCellsY() const; + void setSkipCellsY(int skipCellsY); + + int gridColumns() const; + void setGridColumns(int gridColumns); + + void paint(QPainter* painter) override; + +signals: + void filenameChanged(); + void directoryChanged(); + void projectDataChanged(); + void pickerModeChanged(); + void cellIndexChanged(); + void cellWidthChanged(); + void cellHeightChanged(); + void transparentChanged(); + void cellOffsetXChanged(); + void cellOffsetYChanged(); + void skipCellsXChanged(); + void skipCellsYChanged(); + void gridColumnsChanged(); + +protected: + /** Compute the source rectangle in image coordinates for the current cell. */ + virtual QRectF sourceRect() const; + + void mousePressEvent(QMouseEvent *event) override; + + virtual void reload(); + + QString m_filename; + QString m_directory; + ProjectDataGadget* m_projectData = nullptr; + bool m_pickerMode = false; + bool m_transparent = false; + QPixmap m_image; + + int m_cellIndex = 0; + int m_cellWidth = 0; + int m_cellHeight = 0; + int m_cellOffsetX = 0; + int m_cellOffsetY = 0; + int m_skipCellsX = 0; + int m_skipCellsY = 0; + int m_gridColumns = 4; +}; + diff --git a/src/ui/viewer/CharSetViewer.qml b/src/ui/viewer/CharSetViewer.qml new file mode 100644 index 0000000..0a659a4 --- /dev/null +++ b/src/ui/viewer/CharSetViewer.qml @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: EasyRPG Editor Authors +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import org.kde.kirigami as Kirigami +import org.easyrpg.editor as Ez + +ViewerBase { + id: root + + implicitWidth: 48 + implicitHeight: 64 + + pickerComponent: Ez.CharSetPicker { + onAccepted: root.accepted() + } + + property alias filename: paintedItem.filename + property alias cellIndex: paintedItem.cellIndex + property alias spin: paintedItem.spin + property alias walk: paintedItem.walk + property alias transparent: paintedItem.transparent + property bool showTransparency: true + + pickerProperties: { "showTransparency": root.showTransparency } + + Ez.CharSetPaintedItem { + id: paintedItem + + anchors.fill: parent + + projectData: Ez.ProjectData + } +} diff --git a/src/ui/viewer/FaceSetViewer.qml b/src/ui/viewer/FaceSetViewer.qml new file mode 100644 index 0000000..4824dfe --- /dev/null +++ b/src/ui/viewer/FaceSetViewer.qml @@ -0,0 +1,29 @@ +// SPDX-FileCopyrightText: EasyRPG Editor Authors +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import QtQuick.Layouts +import org.kde.kirigami as Kirigami +import org.easyrpg.editor as Ez + +ViewerBase { + id: root + + implicitWidth: 48 + implicitHeight: 48 + + pickerComponent: Ez.FaceSetPicker { + onAccepted: root.accepted() + } + + property alias filename: paintedItem.filename + property alias cellIndex: paintedItem.cellIndex + + Ez.FaceSetPaintedItem { + id: paintedItem + + anchors.fill: parent + + projectData: Ez.ProjectData + } +} diff --git a/src/ui/viewer/ViewerBase.qml b/src/ui/viewer/ViewerBase.qml new file mode 100644 index 0000000..521e827 --- /dev/null +++ b/src/ui/viewer/ViewerBase.qml @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: EasyRPG Editor Authors +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import org.kde.kirigami as Kirigami +import org.easyrpg.editor as Ez + +Item { + id: root + + property Ez.PickerData pickerData + property Component pickerComponent + property var pickerProperties: ({}) + + /** Signal emitted when confirming in the picker dialog */ + signal accepted() + + default property alias viewerContent: container.data + + Item { + id: container + anchors.fill: parent + } + + MouseArea { + id: mouseArea + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onClicked: { + let props = Object.assign({ pickerData: root.pickerData }, root.pickerProperties); + applicationWindow().pageStack.pushDialogLayer(root.pickerComponent, props); + } + } +} From 122ac475ef5231081ff67608b6f88961aaf97d21 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Fri, 29 May 2026 22:05:25 +0200 Subject: [PATCH 7/8] Add value changed handler to the JSON objects to allow detecting modified values in the UI layer Currently used to update the list view and the title when the name changes --- src/qmlbinding/json.h | 3 ++ src/qmlbinding/json_internals/json_t_impl.h | 2 ++ src/qmlbinding/json_list_view.cpp | 18 ++++++++++++ src/qmlbinding/json_list_view.h | 7 +++++ src/qmlbinding/json_view.cpp | 32 ++++++++++++++++----- src/qmlbinding/json_view.h | 6 +++- src/ui/common/CheckBox.qml | 3 ++ src/ui/common/ComboBox.qml | 13 ++++++--- src/ui/common/RadioButton.qml | 3 ++ src/ui/database/DatabaseEntryListPage.qml | 13 ++++----- src/ui/database/DatabaseEntryPage.qml | 17 +++++++++++ src/ui/database/DatabasePage.qml | 8 ++++-- 12 files changed, 103 insertions(+), 22 deletions(-) diff --git a/src/qmlbinding/json.h b/src/qmlbinding/json.h index 0f0f0fb..81c01c8 100644 --- a/src/qmlbinding/json.h +++ b/src/qmlbinding/json.h @@ -83,4 +83,7 @@ class Json : public QObject { * @return JSON string */ Q_INVOKABLE virtual QString toJson(QString jsonPtr) const = 0; + +signals: + void valueChanged(QString jsonPtr); }; diff --git a/src/qmlbinding/json_internals/json_t_impl.h b/src/qmlbinding/json_internals/json_t_impl.h index 9147e03..4675cdd 100644 --- a/src/qmlbinding/json_internals/json_t_impl.h +++ b/src/qmlbinding/json_internals/json_t_impl.h @@ -120,6 +120,8 @@ void JsonT::set(QString jsonPtr, const QVariant& value) { if (!ok) { qDebug() << QString("Json::set: Assignment of type %1 failed for path %2").arg(value.typeName()).arg(jsonPtr); + } else { + emit valueChanged(jsonPtr); } } diff --git a/src/qmlbinding/json_list_view.cpp b/src/qmlbinding/json_list_view.cpp index 369ec12..6a91275 100644 --- a/src/qmlbinding/json_list_view.cpp +++ b/src/qmlbinding/json_list_view.cpp @@ -26,6 +26,24 @@ QHash JsonListView::roleNames() const { roles[IndexRole] = "index"; return roles; } +void JsonListView::onValueChanged(QString jsonPtr) { + // No filtering required as the JsonView we listen on already does this + // ptr looks like this: /INDEX/VALUE/ + // extract the index and notify a row change + + int slash_idx = jsonPtr.indexOf('/', 1); + if (slash_idx != -1) { + bool ok; + int row = jsonPtr.mid(1, slash_idx - 1).toInt(&ok); + if (ok) { + if (hasFallback()) { + row++; + } + QModelIndex idx = index(row, 0); + emit QAbstractListModel::dataChanged(idx, idx); + } + } +} QString JsonListView::str(QString jsonPtr) const { return m_view->str(jsonPtr); diff --git a/src/qmlbinding/json_list_view.h b/src/qmlbinding/json_list_view.h index 5970297..065b6f2 100644 --- a/src/qmlbinding/json_list_view.h +++ b/src/qmlbinding/json_list_view.h @@ -65,6 +65,9 @@ class JsonListView : public QAbstractListModel { return !m_fallbackString.isEmpty(); } +public slots: + void onValueChanged(QString jsonPtr); + signals: void dataChanged(); void fallbackValueChanged(); @@ -82,6 +85,10 @@ class JsonListViewT : public JsonListView { explicit JsonListViewT(QObject* parent, std::vector* data, JsonView* view) : JsonListView(parent), m_data(data) { m_view = view; + assert(view); + + // Listen to all changes in the attached JsonView object + connect(view, &JsonView::valueChanged, this, &JsonListView::onValueChanged); } // QAbstractListModel overrides diff --git a/src/qmlbinding/json_view.cpp b/src/qmlbinding/json_view.cpp index 5798442..a7efd87 100644 --- a/src/qmlbinding/json_view.cpp +++ b/src/qmlbinding/json_view.cpp @@ -48,32 +48,42 @@ namespace { } } +JsonView::JsonView(QObject* parent) : QObject(parent) { + assert(parent); + auto json_parent = qobject_cast(parent); + assert(json_parent); + + // Listen to all changes in the parent Json object + // Filtering of irrelevant changes happens in the slot + connect(json_parent, &Json::valueChanged, this, &JsonView::onValueChanged); +} + QString JsonView::str(QString jsonPtr) const { - return static_cast(parent())->str(makePath(m_pathPrefix, jsonPtr)); + return qobject_cast(parent())->str(makePath(m_pathPrefix, jsonPtr)); } int JsonView::num(QString jsonPtr) const { - return static_cast(parent())->num(makePath(m_pathPrefix, jsonPtr)); + return qobject_cast(parent())->num(makePath(m_pathPrefix, jsonPtr)); } bool JsonView::boolean(QString jsonPtr) const { - return static_cast(parent())->boolean(makePath(m_pathPrefix, jsonPtr)); + return qobject_cast(parent())->boolean(makePath(m_pathPrefix, jsonPtr)); } void JsonView::set(QString jsonPtr, const QVariant& value) { - static_cast(parent())->set(makePath(m_pathPrefix, jsonPtr), value); + qobject_cast(parent())->set(makePath(m_pathPrefix, jsonPtr), value); } JsonView* JsonView::subtree(QString jsonPtr) { - return qvariant_cast(static_cast(parent())->subtree(makePath(m_pathPrefix, jsonPtr))); + return qvariant_cast(qobject_cast(parent())->subtree(makePath(m_pathPrefix, jsonPtr))); } JsonListView* JsonView::list(QString jsonPtr) { - return qvariant_cast(static_cast(parent())->list(makePath(m_pathPrefix, jsonPtr))); + return qvariant_cast(qobject_cast(parent())->list(makePath(m_pathPrefix, jsonPtr))); } QString JsonView::toJson(QString jsonPtr) const { - return static_cast(parent())->toJson(makePath(m_pathPrefix, jsonPtr)); + return qobject_cast(parent())->toJson(makePath(m_pathPrefix, jsonPtr)); } QString JsonView::pathPrefix() const { @@ -95,3 +105,11 @@ void JsonView::setPathPrefix(QString prefix) { m_pathPrefix = prefix; } + +void JsonView::onValueChanged(QString jsonPtr) { + if (jsonPtr.startsWith(pathPrefix() + "/")) { + // Pointer only contains the path relative to the view + QString trimmedPtr = jsonPtr.mid(pathPrefix().length()); + emit valueChanged(trimmedPtr); + } +} diff --git a/src/qmlbinding/json_view.h b/src/qmlbinding/json_view.h index 9640596..9c03ef2 100644 --- a/src/qmlbinding/json_view.h +++ b/src/qmlbinding/json_view.h @@ -34,7 +34,7 @@ class JsonView : public QObject { Q_PROPERTY(QString pathPrefix READ pathPrefix WRITE setPathPrefix NOTIFY pathPrefixChanged) public: - explicit JsonView(QObject* parent = nullptr) : QObject(parent) {} + explicit JsonView(QObject* parent = nullptr); // documentation: see json.h @@ -93,6 +93,10 @@ class JsonView : public QObject { signals: void pathPrefixChanged(); + void valueChanged(QString jsonPtr); + +public slots: + void onValueChanged(QString jsonPtr); private: QString m_pathPrefix; diff --git a/src/ui/common/CheckBox.qml b/src/ui/common/CheckBox.qml index 979c059..90acc14 100644 --- a/src/ui/common/CheckBox.qml +++ b/src/ui/common/CheckBox.qml @@ -11,6 +11,9 @@ Controls.CheckBox { property string key property Ez.JsonView jsonData + onKeyChanged: onDataChanged() + onJsonDataChanged: onDataChanged() + onToggled: { if (jsonData !== null && key !== "") { jsonData.set(key, checked); diff --git a/src/ui/common/ComboBox.qml b/src/ui/common/ComboBox.qml index 8fb908e..8028ffc 100644 --- a/src/ui/common/ComboBox.qml +++ b/src/ui/common/ComboBox.qml @@ -9,10 +9,15 @@ Controls.ComboBox { id: root property string key - property var jsonData + property Ez.JsonView jsonData + + onKeyChanged: onDataChanged() + onJsonDataChanged: onDataChanged() + onModelChanged: onDataChanged() + onCountChanged: onDataChanged() textRole: "text" // In a JsonListView this is "ID: NAME", e.g. "0001: Aina" - valueRole: "value" // In a JsonListView is the "ID" + valueRole: "value" // In a JsonListView this is the "ID" onActivated: { if (jsonData !== null && key !== "") { @@ -27,13 +32,13 @@ Controls.ComboBox { function onDataChanged() { if (jsonData !== null && key !== "") { currentIndex = indexOfValue(jsonData.num(key)) - if (currentIndex === -1) { + if (currentIndex === -1 && root.model) { console.log(`ComboBox: ${jsonData.num(key)} not found for ${key}`); let isProxy = (root.model.sourceModel !== undefined); let model = isProxy ? root.model.sourceModel : root.model; - if (model.fallbackString !== "") { + if (model && model.fallbackString !== "") { currentIndex = indexOfValue(model.fallbackValue); } } diff --git a/src/ui/common/RadioButton.qml b/src/ui/common/RadioButton.qml index 806f469..9be5bab 100644 --- a/src/ui/common/RadioButton.qml +++ b/src/ui/common/RadioButton.qml @@ -13,6 +13,9 @@ Controls.RadioButton { property int value + onKeyChanged: onDataChanged() + onJsonDataChanged: onDataChanged() + onCheckedChanged: { if (checked && jsonData !== null && key !== "") { jsonData.set(key, value) diff --git a/src/ui/database/DatabaseEntryListPage.qml b/src/ui/database/DatabaseEntryListPage.qml index 941cffa..874d6f0 100644 --- a/src/ui/database/DatabaseEntryListPage.qml +++ b/src/ui/database/DatabaseEntryListPage.qml @@ -54,14 +54,11 @@ Kirigami.ScrollablePage { var pageStack = applicationWindow().pageStack - // Reuse the already loaded Ui when item type (key) stays the same - if (pageStack.lastItem.key !== root.key) { - while (pageStack.depth > 2) { - pageStack.pop(); - } - } - - if (pageStack.depth <= 2) { + // Reuse the already loaded Ui + if (pageStack.depth > 2) { + pageStack.lastItem.jsonData = jsonData.subtree(index); + pageStack.lastItem.objIndex = index; + } else { //console.log("Pushing:", root.targetPage); pageStack.push(Qt.resolvedUrl(root.targetPage), { // Use the index passed to the function diff --git a/src/ui/database/DatabaseEntryPage.qml b/src/ui/database/DatabaseEntryPage.qml index fd24903..60aa2d7 100644 --- a/src/ui/database/DatabaseEntryPage.qml +++ b/src/ui/database/DatabaseEntryPage.qml @@ -22,6 +22,23 @@ Kirigami.ScrollablePage { /** When the object comes from a list, contains the index. Otherwise -1. */ property int objIndex: -1 + // Update the Page title when the name changes + Connections { + target: jsonData + function onValueChanged(jsonPtr) { + if (objIndex >= 0 && jsonPtr.endsWith("/name")) { + console.log(jsonPtr); + root.title = jsonData.str("name"); + } + } + } + + onJsonDataChanged: { + if (objIndex >= 0) { + root.title = jsonData.str("name"); + } + } + // TODO: Not used. Just for testing property bool showActions: false diff --git a/src/ui/database/DatabasePage.qml b/src/ui/database/DatabasePage.qml index f1b415b..09afcd4 100644 --- a/src/ui/database/DatabasePage.qml +++ b/src/ui/database/DatabasePage.qml @@ -18,6 +18,8 @@ Kirigami.ScrollablePage { /** Database of the current project */ property Ez.JsonView jsonData + title: "Database" + /** * name: Text shown to the user * key: JSON pointer to access the list items of this category @@ -94,12 +96,14 @@ Kirigami.ScrollablePage { if (item.single === true) { pageStack.push(Qt.resolvedUrl(item.targetPage), { - "jsonData": jsonData.subtree(item.key) + "jsonData": jsonData.subtree(item.key), + "title": item.name }) } else { pageStack.push(Qt.resolvedUrl("DatabaseEntryListPage.qml"), { "jsonData": jsonData.list(item.key), - "targetPage": item.targetPage + "targetPage": item.targetPage, + "title": item.name }) } } From 88331705a4f1237b9f676ae5458ba7c44330dfcd Mon Sep 17 00:00:00 2001 From: Ghabry Date: Fri, 29 May 2026 22:06:52 +0200 Subject: [PATCH 8/8] Fix all Wall/Wextra compiler warnings and replace whitespace with tab --- src/main.cpp | 4 ++-- src/model/actor.cpp | 4 ++-- src/qmlbinding/json_list_view.cpp | 9 +++++---- src/qmlbinding/json_list_view.h | 6 +++--- src/qmlbinding/project_data_gadget.cpp | 18 +++++++++--------- src/qmlbinding/project_data_gadget.h | 22 +++++++++++----------- src/ui/common/operand_widget.cpp | 4 ++-- src/ui/database/DatabaseEntryPage.qml | 3 +-- src/ui/database/DatabaseWindow.qml | 6 +++--- src/ui/database/actor_widget.cpp | 8 ++++---- src/ui/database/attribute_widget.cpp | 2 -- src/ui/database/common_event_widget.cpp | 2 +- src/ui/event/event_command_base_widget.cpp | 18 +++++++++--------- src/ui/main_window.cpp | 14 +++++++------- src/ui/other/open_project_dialog.cpp | 2 +- 15 files changed, 60 insertions(+), 62 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0af50b1..c8b8360 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,7 +43,7 @@ int main(int argc, char *argv[]) { // Kirigami only loads a custom style when using a static build // Lets wait for upstream to improve this #if defined(KIRIGAMI_STATIC) - // Default to org.kde.breeze style (from qqc2-breeze style) + // Default to org.kde.breeze style (from qqc2-breeze style) if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE")) { const char* fstyle = "KIRIGAMI_FORCE_STYLE"; if (qEnvironmentVariableIsEmpty(fstyle) || qEnvironmentVariableIntValue(fstyle) > 0) { @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { #endif // setup qml engine - auto engine = core().qmlEngine(); + //auto engine = core().qmlEngine(); /*engine->loadFromModule("org.easyrpg.editor", "MainWindow"); if (engine->rootObjects().isEmpty()) { diff --git a/src/model/actor.cpp b/src/model/actor.cpp index 64c10b2..46e890e 100644 --- a/src/model/actor.cpp +++ b/src/model/actor.cpp @@ -84,8 +84,8 @@ QAbstractItemModel* ActorModel::CreateEquipmentFilter(lcf::rpg::Item::Type type, auto filter = new SortFilterProxyModelIdFilter(indices, parent); if (!parent) { - QQmlEngine::setObjectOwnership(filter, QQmlEngine::JavaScriptOwnership); - } + QQmlEngine::setObjectOwnership(filter, QQmlEngine::JavaScriptOwnership); + } return filter; } diff --git a/src/qmlbinding/json_list_view.cpp b/src/qmlbinding/json_list_view.cpp index 6a91275..924afd0 100644 --- a/src/qmlbinding/json_list_view.cpp +++ b/src/qmlbinding/json_list_view.cpp @@ -18,14 +18,15 @@ #include "json_list_view.h" QHash JsonListView::roleNames() const { - QHash roles; + QHash roles; roles[Qt::DisplayRole] = "text"; - roles[NameRole] = "name"; - roles[TitleRole] = "title"; + roles[NameRole] = "name"; + roles[TitleRole] = "title"; roles[IdRole] = "value"; roles[IndexRole] = "index"; - return roles; + return roles; } + void JsonListView::onValueChanged(QString jsonPtr) { // No filtering required as the JsonView we listen on already does this // ptr looks like this: /INDEX/VALUE/ diff --git a/src/qmlbinding/json_list_view.h b/src/qmlbinding/json_list_view.h index 065b6f2..8503e8f 100644 --- a/src/qmlbinding/json_list_view.h +++ b/src/qmlbinding/json_list_view.h @@ -104,12 +104,12 @@ class JsonListViewT : public JsonListView { }; template -inline int JsonListViewT::rowCount(const QModelIndex &parent) const { +inline int JsonListViewT::rowCount(const QModelIndex& /*parent*/) const { return m_data->size() + (hasFallback() ? 1 : 0); } template -inline QVariant JsonListViewT::data(const QModelIndex &index, int role) const { +inline QVariant JsonListViewT::data(const QModelIndex& index, int role) const { if (!index.isValid() || index.row() >= rowCount(index)) { return QVariant(); } @@ -171,7 +171,7 @@ inline QVariant JsonListViewT::data(const QModelIndex &index, int role) } template -inline bool JsonListViewT::insertRows(int row, int count, const QModelIndex &parent) { +inline bool JsonListViewT::insertRows(int row, int /*count*/, const QModelIndex& /*parent*/) { if (row < 0 || row > rowCount()) { return false; } diff --git a/src/qmlbinding/project_data_gadget.cpp b/src/qmlbinding/project_data_gadget.cpp index 55b45ba..c367fc6 100644 --- a/src/qmlbinding/project_data_gadget.cpp +++ b/src/qmlbinding/project_data_gadget.cpp @@ -26,24 +26,24 @@ ProjectDataGadget::ProjectDataGadget(QObject* parent) : QObject(parent) { } void ProjectDataGadget::setProjectData(ProjectData* data) { - if (m_data == data) return; + if (m_data == data) return; - m_data = data; + m_data = data; - if (m_data) { - m_database_json.setData(&m_data->database()); - m_treemap_json.setData(&m_data->treeMap()); - } + if (m_data) { + m_database_json.setData(&m_data->database()); + m_treemap_json.setData(&m_data->treeMap()); + } - emit projectDataChanged(); + emit projectDataChanged(); } JsonView* ProjectDataGadget::database() { - return m_data ? qvariant_cast(m_database_json.subtree("/")) : nullptr; + return m_data ? qvariant_cast(m_database_json.subtree("/")) : nullptr; } JsonView* ProjectDataGadget::treeMap() { - return m_data ? qvariant_cast(m_treemap_json.subtree("/")) : nullptr; + return m_data ? qvariant_cast(m_treemap_json.subtree("/")) : nullptr; } QString ProjectDataGadget::findFile(const QString& filename, FileFinder::FileType type) const { diff --git a/src/qmlbinding/project_data_gadget.h b/src/qmlbinding/project_data_gadget.h index dfed9d6..9e3db09 100644 --- a/src/qmlbinding/project_data_gadget.h +++ b/src/qmlbinding/project_data_gadget.h @@ -38,27 +38,27 @@ class ProjectDataGadget : public QObject Q_PROPERTY(QString projectPath READ projectPath) public: - explicit ProjectDataGadget(QObject* parent = nullptr); + explicit ProjectDataGadget(QObject* parent = nullptr); - void setProjectData(ProjectData* data); + void setProjectData(ProjectData* data); - Q_INVOKABLE JsonView* database(); - Q_INVOKABLE JsonView* treeMap(); + Q_INVOKABLE JsonView* database(); + Q_INVOKABLE JsonView* treeMap(); - Q_INVOKABLE QString findFile(const QString& filename, FileFinder::FileType type = FileFinder::FileType::Default) const; - Q_INVOKABLE QString findFile(const QString& dir, const QString& filename, FileFinder::FileType type = FileFinder::FileType::Default) const; - Q_INVOKABLE QString findFileOrDefault(const QString& filename); - Q_INVOKABLE QString findDirectory(const QString& dir) const; - Q_INVOKABLE QString findDirectory(const QString& baseDir, const QString& dir) const; + Q_INVOKABLE QString findFile(const QString& filename, FileFinder::FileType type = FileFinder::FileType::Default) const; + Q_INVOKABLE QString findFile(const QString& dir, const QString& filename, FileFinder::FileType type = FileFinder::FileType::Default) const; + Q_INVOKABLE QString findFileOrDefault(const QString& filename); + Q_INVOKABLE QString findDirectory(const QString& dir) const; + Q_INVOKABLE QString findDirectory(const QString& baseDir, const QString& dir) const; - Q_INVOKABLE QPixmap loadImage(const QString& dir, const QString& filename) const; + Q_INVOKABLE QPixmap loadImage(const QString& dir, const QString& filename) const; Q_INVOKABLE ActorModel actorModel(int actor_index); QString projectPath() const; signals: - void projectDataChanged(); + void projectDataChanged(); private: ProjectData* m_data = nullptr; diff --git a/src/ui/common/operand_widget.cpp b/src/ui/common/operand_widget.cpp index 9013686..fd39723 100644 --- a/src/ui/common/operand_widget.cpp +++ b/src/ui/common/operand_widget.cpp @@ -171,13 +171,13 @@ void TimerOperandWidget::attach(EventCommandBaseWidget& base_widget, ProjectData base_widget.connectParameterHandler(m_comboVar, idx_value, op == 1); connect(m_spinSec, qOverload(&QSpinBox::valueChanged), this, - [=] (int new_value) { + [=, this] (int new_value) { int seconds = m_spinMin->value() * 60 + new_value; parameterChanged(m_operation.value, seconds); }); connect(m_spinMin, qOverload(&QSpinBox::valueChanged), this, - [=] (int new_value) { + [=, this] (int new_value) { int seconds = new_value * 60 + m_spinSec->value(); parameterChanged(m_operation.value, seconds); }); diff --git a/src/ui/database/DatabaseEntryPage.qml b/src/ui/database/DatabaseEntryPage.qml index 60aa2d7..1e3f1d3 100644 --- a/src/ui/database/DatabaseEntryPage.qml +++ b/src/ui/database/DatabaseEntryPage.qml @@ -26,8 +26,7 @@ Kirigami.ScrollablePage { Connections { target: jsonData function onValueChanged(jsonPtr) { - if (objIndex >= 0 && jsonPtr.endsWith("/name")) { - console.log(jsonPtr); + if (objIndex >= 0 && jsonPtr == "/name") { root.title = jsonData.str("name"); } } diff --git a/src/ui/database/DatabaseWindow.qml b/src/ui/database/DatabaseWindow.qml index 68b3e6d..9cf8f15 100644 --- a/src/ui/database/DatabaseWindow.qml +++ b/src/ui/database/DatabaseWindow.qml @@ -16,12 +16,12 @@ import org.easyrpg.editor as Ez Kirigami.ApplicationWindow { id: root - width: 1024 - height: 600 + width: Kirigami.Units.gridUnit * 74 + height: Kirigami.Units.gridUnit * 41 title: "EasyRPG Editor - Database" - pageStack.defaultColumnWidth: 200 + pageStack.defaultColumnWidth: Kirigami.Units.gridUnit * 11 /** Database of the current project */ property Ez.JsonView jsonData: Ez.ProjectData.database() diff --git a/src/ui/database/actor_widget.cpp b/src/ui/database/actor_widget.cpp index 9a18f11..b562ebd 100644 --- a/src/ui/database/actor_widget.cpp +++ b/src/ui/database/actor_widget.cpp @@ -345,7 +345,7 @@ void ActorWidget::on_listStatusRanks_clicked() { } int index = ui->listStatusRanks->currentRow(); - if (m_current->state_ranks.size() <= index) { + if (static_cast(m_current->state_ranks.size()) <= index) { for (int i = m_current->state_ranks.size(); i <= index; i++) { m_current->state_ranks.push_back(2); } @@ -355,7 +355,7 @@ void ActorWidget::on_listStatusRanks_clicked() { m_current->state_ranks[index] = rank; ui->listStatusRanks->item(index)->setIcon(QIcon(QString(":/ranks/rank%1").arg(rank))); - if (index == m_current->state_ranks.size() - 1 && rank == 2) { + if (index == static_cast(m_current->state_ranks.size()) - 1 && rank == 2) { m_current->state_ranks.pop_back(); for (int i = m_current->state_ranks.size() - 1; i >= 0; i--) { if (m_current->state_ranks[i] == 2) { @@ -373,7 +373,7 @@ void ActorWidget::on_listAttributeRanks_clicked() { } int index = ui->listAttributeRanks->currentRow(); - if (m_current->attribute_ranks.size() <= index) { + if (static_cast(m_current->attribute_ranks.size()) <= index) { for (int i = m_current->attribute_ranks.size(); i <= index; i++) { m_current->attribute_ranks.push_back(2); } @@ -383,7 +383,7 @@ void ActorWidget::on_listAttributeRanks_clicked() { m_current->attribute_ranks[index] = rank; ui->listAttributeRanks->item(index)->setIcon(QIcon(QString(":/ranks/rank%1").arg(rank))); - if (index == m_current->attribute_ranks.size() - 1 && rank == 2) { + if (index == static_cast(m_current->attribute_ranks.size()) - 1 && rank == 2) { m_current->attribute_ranks.pop_back(); for (int i = m_current->attribute_ranks.size() - 1; i >= 0; i--) { if (m_current->attribute_ranks[i] == 2) { diff --git a/src/ui/database/attribute_widget.cpp b/src/ui/database/attribute_widget.cpp index 1fc69b3..f29ab1d 100644 --- a/src/ui/database/attribute_widget.cpp +++ b/src/ui/database/attribute_widget.cpp @@ -69,8 +69,6 @@ void AttributeWidget::on_currentAttributeChanged(lcf::rpg::Attribute *attribute) } m_current = attribute; - auto& database = m_project.database(); - LcfWidgetBinding::bind(ui->lineName, attribute->name); LcfWidgetBinding::bind(m_buttonGroupType, attribute->type); LcfWidgetBinding::bind(ui->spinA, attribute->a_rate); diff --git a/src/ui/database/common_event_widget.cpp b/src/ui/database/common_event_widget.cpp index 64808b3..36ea6b7 100644 --- a/src/ui/database/common_event_widget.cpp +++ b/src/ui/database/common_event_widget.cpp @@ -56,7 +56,7 @@ void CommonEventWidget::setData(lcf::rpg::CommonEvent* common_event) { updateComboSwitchEnabled(); } -void CommonEventWidget::on_comboTrigger_currentIndexChanged(int index) { +void CommonEventWidget::on_comboTrigger_currentIndexChanged(int /*index*/) { updateComboSwitchEnabled(); } diff --git a/src/ui/event/event_command_base_widget.cpp b/src/ui/event/event_command_base_widget.cpp index 8a52024..7984dca 100644 --- a/src/ui/event/event_command_base_widget.cpp +++ b/src/ui/event/event_command_base_widget.cpp @@ -39,7 +39,7 @@ void EventCommandBaseWidget::setData(lcf::rpg::EventCommand* cmd) { auto idx = widget->objectName().indexOf("_argX"); if (idx != -1) { connect(widget, &QLineEdit::textEdited, this, - [=] (auto text) { + [=, this] (auto text) { cmd->string = lcf::DBString(ToDBString(text)); stringParameterChanged(text); }); @@ -150,7 +150,7 @@ void EventCommandBaseWidget::connectParameterHandler(QButtonGroup* group, int in Q_ASSERT_X(button, "connectParameterHandler", "No AbstractButton with this parameter value"); connect(group, QOverload::of(&QButtonGroup::buttonToggled), this, - [=](QAbstractButton*, bool checked) { + [=, this](QAbstractButton*, bool checked) { if (checked) { int id = group->checkedId(); @@ -169,7 +169,7 @@ void EventCommandBaseWidget::connectParameterHandler(RpgComboBoxBase* combo, int resizeCommandList(index); connect(combo->comboBox(), QOverload::of(&QComboBox::currentIndexChanged), this, - [=](int selected_index){ + [=, this](int selected_index){ m_cmd->parameters[index] = selected_index + 1; emit parameterChanged(index, selected_index + 1); }); @@ -183,7 +183,7 @@ void EventCommandBaseWidget::connectParameterHandler(QSpinBox *spin, int index, resizeCommandList(index); connect(spin, qOverload(&QSpinBox::valueChanged), this, - [=] (int new_value) { + [=, this] (int new_value) { m_cmd->parameters[index] = new_value; emit parameterChanged(index, new_value); }); @@ -196,10 +196,10 @@ void EventCommandBaseWidget::connectParameterHandler(QSpinBox *spin, int index, void EventCommandBaseWidget::connectParameterHandler(QCheckBox* check, int index, bool set_value) { resizeCommandList(index); - connect(check, qOverload(&QCheckBox::stateChanged), this, - [=] (int new_value) { - m_cmd->parameters[index] = new_value; - emit parameterChanged(index, new_value); + connect(check, &QCheckBox::checkStateChanged, this, + [=, this] (Qt::CheckState state) { + m_cmd->parameters[index] = (state == Qt::Checked ? 1 : 0); + emit parameterChanged(index, (state == Qt::Checked ? 1 : 0)); }); if (set_value) { @@ -211,7 +211,7 @@ void EventCommandBaseWidget::connectParameterHandler(QSlider* slider, int index, resizeCommandList(index); connect(slider, qOverload(&QSlider::valueChanged), this, - [=] (int new_value) { + [=, this] (int new_value) { m_cmd->parameters[index] = new_value; emit parameterChanged(index, new_value); }); diff --git a/src/ui/main_window.cpp b/src/ui/main_window.cpp index d968ebb..ae78a18 100644 --- a/src/ui/main_window.cpp +++ b/src/ui/main_window.cpp @@ -354,8 +354,8 @@ void MainWindow::ImportProject(const QDir& src_dir, QDir& target_dir, bool conve if (convert_xyz && info.dir().dirName() != MUSIC && info.dir().dirName() != SOUND) { QFile file(dest_file); - file.open(QIODevice::ReadOnly); - if (file.read(4) == "XYZ1") + bool success = file.open(QIODevice::ReadOnly); + if (success && file.read(4) == "XYZ1") { QString conv_path = target_dir.path() + "/" + info.dir().dirName() + "/" + info.completeBaseName() + ".png"; if (convertXYZtoPNG(file, conv_path)) @@ -494,9 +494,9 @@ void MainWindow::on_actionDatabaseNew_triggered() { auto engine = core().qmlEngine(); // Inject ProjectData into the QML - auto* projectGadget = engine->singletonInstance( - "org.easyrpg.editor", "ProjectData" - ); + auto* projectGadget = engine->singletonInstance( + "org.easyrpg.editor", "ProjectData" + ); projectGadget->setProjectData(&core().project()->projectData()); @@ -686,7 +686,7 @@ bool MainWindow::removeDir(const QString & dirName, const QString &root) QMessageBox::warning(this, tr("An error ocurred"), QString(tr("Could't delete %1")).arg(info.absoluteFilePath()), - QMessageBox::Ok, 0); + QMessageBox::Ok); return false; } } @@ -817,7 +817,7 @@ void MainWindow::on_actionProjectOpen_triggered() m_settings.setValue(DEFAULT_DIR_KEY,dlg.getDefaultDir()); } -void MainWindow::on_actionJukebox_triggered(bool disconnect) +void MainWindow::on_actionJukebox_triggered(bool) { } diff --git a/src/ui/other/open_project_dialog.cpp b/src/ui/other/open_project_dialog.cpp index 19532bd..adefa05 100644 --- a/src/ui/other/open_project_dialog.cpp +++ b/src/ui/other/open_project_dialog.cpp @@ -112,7 +112,7 @@ bool OpenProjectDialog::removeDir(const QString & dirName) QMessageBox::warning(this, tr("An error ocurred"), QString(tr("Could't delete %1")).arg(info.absoluteFilePath()), - QMessageBox::Ok, 0); + QMessageBox::Ok); return false; } }