From 2377ed35b071d596cff9d5b4c30071cecc590292 Mon Sep 17 00:00:00 2001 From: CrSjimo Date: Mon, 17 Nov 2025 02:26:38 +0800 Subject: [PATCH 001/181] Add icon --- src/libs/3rdparty/svscraft | 2 +- src/plugins/coreplugin/res/icons/config.json | 8 ++++++++ .../res/org.diffscope.visualeditor_actions.xml | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libs/3rdparty/svscraft b/src/libs/3rdparty/svscraft index c9c7d6c2..2daf0f1f 160000 --- a/src/libs/3rdparty/svscraft +++ b/src/libs/3rdparty/svscraft @@ -1 +1 @@ -Subproject commit c9c7d6c28a2564c4a0ee79f485a6a15b7b81dc69 +Subproject commit 2daf0f1fde05bd6444529af8de91f8270e782de9 diff --git a/src/plugins/coreplugin/res/icons/config.json b/src/plugins/coreplugin/res/icons/config.json index 4b8caa22..ad5a981b 100644 --- a/src/plugins/coreplugin/res/icons/config.json +++ b/src/plugins/coreplugin/res/icons/config.json @@ -11201,6 +11201,14 @@ { "id": "item_compare", "icon": "item_compare" + }, + { + "id": "options_vertical", + "icon": "options_vertical" + }, + { + "id": "playhead_panel_chevron_double", + "icon": "playhead_panel_chevron_double" } ] } diff --git a/src/plugins/visualeditor/res/org.diffscope.visualeditor_actions.xml b/src/plugins/visualeditor/res/org.diffscope.visualeditor_actions.xml index 460625fc..4b743a8a 100644 --- a/src/plugins/visualeditor/res/org.diffscope.visualeditor_actions.xml +++ b/src/plugins/visualeditor/res/org.diffscope.visualeditor_actions.xml @@ -21,7 +21,7 @@ - + From 316e30a7b689c5e203d25e75c0972223bd7dc437 Mon Sep 17 00:00:00 2001 From: CrSjimo Date: Mon, 17 Nov 2025 02:28:07 +0800 Subject: [PATCH 002/181] Fix bugs in workspace --- src/libs/3rdparty/svscraft | 2 +- src/plugins/coreplugin/qml/actions/WorkspaceAddOnActions.qml | 1 - src/plugins/coreplugin/qml/windows/WorkspaceAddOnHelper.qml | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libs/3rdparty/svscraft b/src/libs/3rdparty/svscraft index 2daf0f1f..1ff1feba 160000 --- a/src/libs/3rdparty/svscraft +++ b/src/libs/3rdparty/svscraft @@ -1 +1 @@ -Subproject commit 2daf0f1fde05bd6444529af8de91f8270e782de9 +Subproject commit 1ff1feba05489b96b4598a0647cfd38fde4d74c4 diff --git a/src/plugins/coreplugin/qml/actions/WorkspaceAddOnActions.qml b/src/plugins/coreplugin/qml/actions/WorkspaceAddOnActions.qml index 65f0e532..1aac4bfe 100644 --- a/src/plugins/coreplugin/qml/actions/WorkspaceAddOnActions.qml +++ b/src/plugins/coreplugin/qml/actions/WorkspaceAddOnActions.qml @@ -133,7 +133,6 @@ ActionCollection { readonly property QtObject currentPane: d.helper.dockingPanes[panelPosition] enabled: currentPane !== null readonly property string baseText: [ - "", qsTr("%1 (Left Top)"), qsTr("%1 (Left Bottom)"), qsTr("%1 (Right Top)"), diff --git a/src/plugins/coreplugin/qml/windows/WorkspaceAddOnHelper.qml b/src/plugins/coreplugin/qml/windows/WorkspaceAddOnHelper.qml index c0df9945..8894e3bf 100644 --- a/src/plugins/coreplugin/qml/windows/WorkspaceAddOnHelper.qml +++ b/src/plugins/coreplugin/qml/windows/WorkspaceAddOnHelper.qml @@ -28,7 +28,6 @@ QtObject { return dockingPanes[activePanel] ?? null } readonly property list dockingPanes: [ - null, window.leftDockingView.firstItem, window.leftDockingView.lastItem, window.rightDockingView.firstItem, From 9bc13c2150237bb97df107b35fec6430c0ae8dc3 Mon Sep 17 00:00:00 2001 From: CrSjimo Date: Mon, 17 Nov 2025 16:57:43 +0800 Subject: [PATCH 003/181] Update actions --- .../internal/actions/ActionHelper.h | 29 +++++ .../internal/actions/FindActionsModel.cpp | 100 ++++++++------- .../internal/actions/FindActionsModel.h | 6 + .../internal/addon/FindActionsAddOn.cpp | 2 +- .../addon/ProjectWindowNavigatorAddOn.cpp | 16 --- .../addon/ProjectWindowNavigatorAddOn.h | 2 - .../coreplugin/qml/actions/ProjectActions.qml | 2 +- .../ProjectWindowNavigatorAddOnActions.qml | 9 +- .../res/org.diffscope.core_actions.xml | 25 ++-- .../windows/ActionWindowInterfaceBase.cpp | 13 +- .../internal/addons/MaintenanceAddOn.cpp | 2 +- .../qml/actions/ArrangementAddOnActions.qml | 120 ++++++++---------- .../org.diffscope.visualeditor_actions.xml | 12 +- 13 files changed, 176 insertions(+), 162 deletions(-) diff --git a/src/plugins/coreplugin/internal/actions/ActionHelper.h b/src/plugins/coreplugin/internal/actions/ActionHelper.h index a5ced122..e411c804 100644 --- a/src/plugins/coreplugin/internal/actions/ActionHelper.h +++ b/src/plugins/coreplugin/internal/actions/ActionHelper.h @@ -14,6 +14,35 @@ namespace Core::Internal { public: static bool triggerAction(QAK::QuickActionContext *actionContext, const QString &id, QObject *source = nullptr); static QObject *createActionObject(QAK::QuickActionContext *actionContext, const QString &id, bool shouldBeQuickAction = true); + static inline QString removeMnemonic(const QString &s) { + QString text(s.size(), QChar::Null); + int idx = 0; + int pos = 0; + int len = s.size(); + while (len) { + if (s.at(pos) == QLatin1Char('&') && (len == 1 || s.at(pos + 1) != QLatin1Char('&'))) { + ++pos; + --len; + if (len == 0) + break; + } else if (s.at(pos) == QLatin1Char('(') && len >= 4 && s.at(pos + 1) == QLatin1Char('&') && s.at(pos + 2) != QLatin1Char('&') && s.at(pos + 3) == QLatin1Char(')')) { + // a mnemonic with format "\s*(&X)" + int n = 0; + while (idx > n && text.at(idx - n - 1).isSpace()) + ++n; + idx -= n; + pos += 4; + len -= 4; + continue; + } + text[idx] = s.at(pos); + ++pos; + ++idx; + --len; + } + text.truncate(idx); + return text; + } }; } diff --git a/src/plugins/coreplugin/internal/actions/FindActionsModel.cpp b/src/plugins/coreplugin/internal/actions/FindActionsModel.cpp index 39bf2340..d70ce2a2 100644 --- a/src/plugins/coreplugin/internal/actions/FindActionsModel.cpp +++ b/src/plugins/coreplugin/internal/actions/FindActionsModel.cpp @@ -4,9 +4,13 @@ #include #include +#include #include #include +#include +#include + #include #include @@ -14,9 +18,12 @@ #include #include #include +#include namespace Core::Internal { + Q_STATIC_LOGGING_CATEGORY(lcFindActionsModel, "diffscope.core.findactionsmodel") + FindActionsModel::FindActionsModel(QAK::QuickActionContext *actionContext, FindActionsAddOn *parent) : QAbstractItemModel(parent), m_actionContext(actionContext) { m_collator.setNumericMode(true); @@ -103,40 +110,11 @@ namespace Core::Internal { return result; } - static QString removeMnemonic(const QString &s) { - QString text(s.size(), QChar::Null); - int idx = 0; - int pos = 0; - int len = s.size(); - while (len) { - if (s.at(pos) == QLatin1Char('&') && (len == 1 || s.at(pos + 1) != QLatin1Char('&'))) { - ++pos; - --len; - if (len == 0) - break; - } else if (s.at(pos) == QLatin1Char('(') && len >= 4 && s.at(pos + 1) == QLatin1Char('&') && s.at(pos + 2) != QLatin1Char('&') && s.at(pos + 3) == QLatin1Char(')')) { - // a mnemonic with format "\s*(&X)" - int n = 0; - while (idx > n && text.at(idx - n - 1).isSpace()) - ++n; - idx -= n; - pos += 4; - len -= 4; - continue; - } - text[idx] = s.at(pos); - ++pos; - ++idx; - --len; - } - text.truncate(idx); - return text; - } - enum ActionInternalFlag { None, Checkable, Separator, + Menu, }; QVariant FindActionsModel::data(const QModelIndex &index, int role) const { @@ -150,9 +128,11 @@ namespace Core::Internal { case Qt::DisplayRole: return actionId; case SVS::SVSCraft::CP_TitleRole: { - auto text = removeMnemonic(getTextWithFallback(actionId, true)); + auto text = ActionHelper::removeMnemonic(getTextWithFallback(actionId, true)); if (flag == Checkable) { text = tr("Toggle \"%1\"").arg(text); + } else if (flag == Menu) { + text = tr("Open Menu \"%1\"...").arg(text); } auto clazz = getClassWithFallback(actionId, true); if (clazz.isEmpty()) @@ -183,11 +163,21 @@ namespace Core::Internal { } } + static bool includeActionPredicate(const QString &id) { + static const QString namespaceUri = "http://schemas.diffscope.org/diffscope/actions/diffscope"; + auto info = CoreInterface::actionRegistry()->actionInfo(id); + if (info.attributes().contains(QAK::ActionAttributeKey("excludeFromCommands", namespaceUri))) { + return false; + } + auto componentType = info.attributes().value(QAK::ActionAttributeKey("componentType", namespaceUri)); + if (!componentType.isEmpty() && componentType != "action" && componentType != "menu") { + return false; + } + return true; + } + void FindActionsModel::setActions(const QStringList &actions) { - auto v = actions | std::views::filter([](const QString &id) { - auto info = CoreInterface::actionRegistry()->actionInfo(id); - return !info.attributes().contains(QAK::ActionAttributeKey("excludeFromCommands", "http://schemas.diffscope.org/diffscope/actions/diffscope")); - }); + auto v = actions | std::views::filter(includeActionPredicate); m_actions = QStringList(v.begin(), v.end()); } @@ -199,6 +189,15 @@ namespace Core::Internal { updateActionList(); } + void FindActionsModel::trigger(int index, ActionWindowInterfaceBase *windowInterface) { + const auto &[actionId, flag] = m_actionList.at(index); + if (flag == Menu) { + windowInterface->execQuickPick(static_cast(getActionObject(actionId))); + } else { + windowInterface->triggerAction(actionId, windowInterface->window()->property("contentItem").value()); + } + } + void FindActionsModel::updateActionList() { beginResetModel(); @@ -215,15 +214,26 @@ namespace Core::Internal { // Sort remaining actions using local collator std::sort(remainingActions.begin(), remainingActions.end(), [this](const QString &a, const QString &b) { return m_collator.compare(a, b) < 0; }); - auto pipeline = std::views::transform([=](const QString &id) -> QPair { - // TODO avoid creating action object on each time updating action list - auto actionObject = getActionObject(id); - if (!actionObject || !actionObject->property("enabled").toBool()) { - return {}; - } - return {id, actionObject->property("checkable").toBool() ? Checkable : None}; - }) | - std::views::filter([](const auto &p) { return !p.first.isEmpty(); }); + auto getActionFlagPair = [this](const QString &id) -> QPair { + // TODO avoid creating action object on each time updating action list + auto actionObject = getActionObject(id); + if (auto action = qobject_cast(actionObject)) { + if (!action->isEnabled()) { + return {}; + } + return {id, action->isCheckable() ? Checkable : None}; + } + if (auto menu = qobject_cast(actionObject)) { + if (!menu->isEnabled()) { + return {}; + } + return {id, Menu}; + } + qCWarning(lcFindActionsModel) << "Action" << id << "is neither an action or a menu. Please declare `componentType` in the action manifest."; + return {}; + }; + + auto pipeline = std::views::transform(getActionFlagPair) | std::views::filter([](const auto &p) { return !p.first.isEmpty(); }); for (const auto &item : m_priorityActions | pipeline) { m_actionList.append(item); } @@ -240,7 +250,7 @@ namespace Core::Internal { if (m_actionObjects.value(id)) { return m_actionObjects.value(id); } else { - auto obj = ActionHelper::createActionObject(m_actionContext, id, true); + auto obj = ActionHelper::createActionObject(m_actionContext, id, false); if (!obj) return nullptr; auto window = static_cast(QObject::parent())->windowHandle()->window(); diff --git a/src/plugins/coreplugin/internal/actions/FindActionsModel.h b/src/plugins/coreplugin/internal/actions/FindActionsModel.h index aeea7d9c..3a200e98 100644 --- a/src/plugins/coreplugin/internal/actions/FindActionsModel.h +++ b/src/plugins/coreplugin/internal/actions/FindActionsModel.h @@ -9,6 +9,10 @@ namespace QAK { class QuickActionContext; } +namespace Core { + class ActionWindowInterfaceBase; +} + namespace Core::Internal { class FindActionsAddOn; @@ -29,6 +33,8 @@ namespace Core::Internal { void setPriorityActions(const QStringList &priorityActions); void refresh(); + void trigger(int index, ActionWindowInterfaceBase *windowInterface); + private: void updateActionList(); QObject *getActionObject(const QString &id); diff --git a/src/plugins/coreplugin/internal/addon/FindActionsAddOn.cpp b/src/plugins/coreplugin/internal/addon/FindActionsAddOn.cpp index c28eb745..66a67404 100644 --- a/src/plugins/coreplugin/internal/addon/FindActionsAddOn.cpp +++ b/src/plugins/coreplugin/internal/addon/FindActionsAddOn.cpp @@ -66,7 +66,7 @@ namespace Core::Internal { auto actionId = m_model->index(i, 0).data().toString(); qCInfo(lcFindActionsAddOn) << "Triggering action" << actionId; QTimer::singleShot(0, [=] { - windowInterface->triggerAction(actionId, windowInterface->window()->property("contentItem").value()); + m_model->trigger(i, windowInterface); }); m_priorityActions.removeOne(actionId); m_priorityActions.prepend(actionId); diff --git a/src/plugins/coreplugin/internal/addon/ProjectWindowNavigatorAddOn.cpp b/src/plugins/coreplugin/internal/addon/ProjectWindowNavigatorAddOn.cpp index 43804a14..4944e2b5 100644 --- a/src/plugins/coreplugin/internal/addon/ProjectWindowNavigatorAddOn.cpp +++ b/src/plugins/coreplugin/internal/addon/ProjectWindowNavigatorAddOn.cpp @@ -5,7 +5,6 @@ #include #include -#include #include #include @@ -20,7 +19,6 @@ namespace Core::Internal { Q_STATIC_LOGGING_CATEGORY(lcProjectWindowNavigatorAddOn, "diffscope.core.projectwindownavigatoraddon") ProjectWindowNavigatorAddOn::ProjectWindowNavigatorAddOn(QObject *parent) : WindowInterfaceAddOn(parent) { - m_quickPickCommandModel = new QStandardItemModel(this); } ProjectWindowNavigatorAddOn::~ProjectWindowNavigatorAddOn() = default; @@ -90,14 +88,6 @@ namespace Core::Internal { } } - void ProjectWindowNavigatorAddOn::showSwitchToProjectWindowCommand() const { - auto windowInterface = windowHandle()->cast(); - auto index = windowInterface->execQuickPick(m_quickPickCommandModel, "Switch to project window", 0); - if (index == -1) - return; - raiseWindow(m_projectWindows.at(index)); - } - void ProjectWindowNavigatorAddOn::updateProjectWindows() { m_projectWindows.clear(); auto windows = CoreInterface::windowSystem()->windows(); @@ -106,12 +96,6 @@ namespace Core::Internal { std::back_inserter(m_projectWindows), [](auto w) { return qobject_cast(w); } ); - m_quickPickCommandModel->clear(); - for (auto windowInterface : m_projectWindows) { - auto item = new QStandardItem; - item->setData(windowInterface->window()->property("documentName"), SVS::SVSCraft::CP_TitleRole); - m_quickPickCommandModel->appendRow(item); - } Q_EMIT projectWindowsChanged(); } diff --git a/src/plugins/coreplugin/internal/addon/ProjectWindowNavigatorAddOn.h b/src/plugins/coreplugin/internal/addon/ProjectWindowNavigatorAddOn.h index 06fc6793..8998d565 100644 --- a/src/plugins/coreplugin/internal/addon/ProjectWindowNavigatorAddOn.h +++ b/src/plugins/coreplugin/internal/addon/ProjectWindowNavigatorAddOn.h @@ -26,7 +26,6 @@ namespace Core::Internal { Q_INVOKABLE static void raiseWindow(ProjectWindowInterface *windowInterface); Q_INVOKABLE void navigateToWindow(int step) const; - Q_INVOKABLE void showSwitchToProjectWindowCommand() const; Q_SIGNALS: void projectWindowsChanged(); @@ -35,7 +34,6 @@ namespace Core::Internal { void updateProjectWindows(); QList m_projectWindows; - QStandardItemModel *m_quickPickCommandModel; }; } diff --git a/src/plugins/coreplugin/qml/actions/ProjectActions.qml b/src/plugins/coreplugin/qml/actions/ProjectActions.qml index bb357200..28b68695 100644 --- a/src/plugins/coreplugin/qml/actions/ProjectActions.qml +++ b/src/plugins/coreplugin/qml/actions/ProjectActions.qml @@ -33,7 +33,7 @@ ActionCollection { } ActionItem { - actionId: "org.diffscope.core.file.saveCopy" + actionId: "org.diffscope.core.file.saveCopyAs" Action { onTriggered: Qt.callLater(() => d.windowHandle.saveCopy()) } diff --git a/src/plugins/coreplugin/qml/actions/ProjectWindowNavigatorAddOnActions.qml b/src/plugins/coreplugin/qml/actions/ProjectWindowNavigatorAddOnActions.qml index 6ad624eb..c1a484d0 100644 --- a/src/plugins/coreplugin/qml/actions/ProjectWindowNavigatorAddOnActions.qml +++ b/src/plugins/coreplugin/qml/actions/ProjectWindowNavigatorAddOnActions.qml @@ -35,6 +35,7 @@ ActionCollection { actionId: "org.diffscope.core.window.projectWindows" Menu { id: menu + enabled: d.addOn.projectWindows.length !== 0 Instantiator { model: DelegateModel { model: d.addOn.projectWindows @@ -60,12 +61,4 @@ ActionCollection { } } - ActionItem { - actionId: "org.diffscope.core.window.switchToProjectWindow" - Action { - enabled: d.addOn.projectWindows.length !== 0 - onTriggered: d.addOn.showSwitchToProjectWindowCommand() - } - } - } \ No newline at end of file diff --git a/src/plugins/coreplugin/res/org.diffscope.core_actions.xml b/src/plugins/coreplugin/res/org.diffscope.core_actions.xml index 66917ae4..6fc2f67d 100644 --- a/src/plugins/coreplugin/res/org.diffscope.core_actions.xml +++ b/src/plugins/coreplugin/res/org.diffscope.core_actions.xml @@ -18,10 +18,10 @@ - + - + @@ -107,7 +107,7 @@ - + @@ -118,7 +118,7 @@ - + @@ -131,8 +131,7 @@ - - + @@ -153,13 +152,13 @@ - - - - - - - + + + + + + + diff --git a/src/plugins/coreplugin/windows/ActionWindowInterfaceBase.cpp b/src/plugins/coreplugin/windows/ActionWindowInterfaceBase.cpp index 04725e24..4279cd34 100644 --- a/src/plugins/coreplugin/windows/ActionWindowInterfaceBase.cpp +++ b/src/plugins/coreplugin/windows/ActionWindowInterfaceBase.cpp @@ -85,24 +85,29 @@ namespace Core { if (!action->isEnabled()) continue; auto item = new QStandardItem; - item->setData(action->isCheckable() ? tr("Toggle \"%1\"").arg(action->text()) : action->text(), SVS::SVSCraft::CP_TitleRole); + auto text = Internal::ActionHelper::removeMnemonic(action->text()); + item->setData(action->isCheckable() ? tr("Toggle \"%1\"").arg(text) : text, SVS::SVSCraft::CP_TitleRole); item->setData(QVariant::fromValue(action), Qt::DisplayRole); model.appendRow(item); } else if (auto subMenu = menu->menuAt(i)) { if (!subMenu->isEnabled()) continue; auto item = new QStandardItem; - item->setData(subMenu->title(), SVS::SVSCraft::CP_TitleRole); + item->setData(Internal::ActionHelper::removeMnemonic(tr("Open Menu \"%1\"...").arg(subMenu->title())), SVS::SVSCraft::CP_TitleRole); item->setData(QVariant::fromValue(subMenu), Qt::DisplayRole); model.appendRow(item); } } - int index = execQuickPick(&model, menu->title()); + int index = execQuickPick(&model, Internal::ActionHelper::removeMnemonic(menu->title())); if (index >= 0) { if (auto action = model.item(index)->data(Qt::DisplayRole).value()) { - return action->trigger(); + if (!action->isEnabled()) + return; + return action->trigger(window()->property("contentItem").value()); } if (auto subMenu = model.item(index)->data(Qt::DisplayRole).value()) { + if (!subMenu->isEnabled()) + return; return execQuickPick(subMenu); } } diff --git a/src/plugins/maintenance/internal/addons/MaintenanceAddOn.cpp b/src/plugins/maintenance/internal/addons/MaintenanceAddOn.cpp index d282c06b..e593e740 100644 --- a/src/plugins/maintenance/internal/addons/MaintenanceAddOn.cpp +++ b/src/plugins/maintenance/internal/addons/MaintenanceAddOn.cpp @@ -92,7 +92,7 @@ namespace Maintenance { SVS::MessageBox::information( Core::RuntimeInterface::qmlEngine(), windowInterface->window(), - tr("Important Notice"), + tr("Disclaimer"), tr( "

The diagnostic report may contain sensitive information (e.g., usernames, hostnames, network addresses, personalized configurations).

\n" "

If you do not wish to make such information public, please do not share this report on public platforms like GitHub Issues or online chat rooms.

\n" diff --git a/src/plugins/visualeditor/qml/actions/ArrangementAddOnActions.qml b/src/plugins/visualeditor/qml/actions/ArrangementAddOnActions.qml index ab956baf..be1a2f43 100644 --- a/src/plugins/visualeditor/qml/actions/ArrangementAddOnActions.qml +++ b/src/plugins/visualeditor/qml/actions/ArrangementAddOnActions.qml @@ -60,83 +60,73 @@ ActionCollection { } ActionItem { - actionId: "org.diffscope.visualeditor.arrangementPanel.snapDurationCommand" - Action { - id: commandAction - readonly property Menu menu: Menu { - id: menu - title: commandAction.text - Instantiator { - model: DelegateModel { - model: [ - { text: qsTr("Auto"), data: PositionAlignmentManipulator.Auto }, - { text: qsTr("None"), data: PositionAlignmentManipulator.Unset }, - { text: qsTr("Whole note"), data: PositionAlignmentManipulator.Note1st }, - { text: qsTr("Half note"), data: PositionAlignmentManipulator.Note2nd }, - { text: qsTr("Quarter note"), data: PositionAlignmentManipulator.Note4th }, - { text: qsTr("8th note"), data: PositionAlignmentManipulator.Note8th }, - { text: qsTr("16th note"), data: PositionAlignmentManipulator.Note16th }, - { text: qsTr("32nd note"), data: PositionAlignmentManipulator.Note32nd }, - { text: qsTr("64th note"), data: PositionAlignmentManipulator.Note64th }, - { text: qsTr("128th note"), data: PositionAlignmentManipulator.Note128th }, - ] - delegate: Action { - required property var modelData - text: modelData.text - checkable: true - checked: d.arrangementPanelInterface?.positionAlignmentManipulator.duration === modelData.data - onTriggered: () => { - d.arrangementPanelInterface.positionAlignmentManipulator.duration = modelData.data - Qt.callLater(() => GlobalHelper.setProperty(this, "checked", true)) - } + actionId: "org.diffscope.visualeditor.arrangementPanel.snapDuration" + Menu { + id: menu + Instantiator { + model: DelegateModel { + model: [ + { text: qsTr("Auto"), data: PositionAlignmentManipulator.Auto }, + { text: qsTr("None"), data: PositionAlignmentManipulator.Unset }, + { text: qsTr("Whole note"), data: PositionAlignmentManipulator.Note1st }, + { text: qsTr("Half note"), data: PositionAlignmentManipulator.Note2nd }, + { text: qsTr("Quarter note"), data: PositionAlignmentManipulator.Note4th }, + { text: qsTr("8th note"), data: PositionAlignmentManipulator.Note8th }, + { text: qsTr("16th note"), data: PositionAlignmentManipulator.Note16th }, + { text: qsTr("32nd note"), data: PositionAlignmentManipulator.Note32nd }, + { text: qsTr("64th note"), data: PositionAlignmentManipulator.Note64th }, + { text: qsTr("128th note"), data: PositionAlignmentManipulator.Note128th }, + ] + delegate: Action { + required property var modelData + text: modelData.text + checkable: true + checked: d.arrangementPanelInterface?.positionAlignmentManipulator.duration === modelData.data + onTriggered: () => { + d.arrangementPanelInterface.positionAlignmentManipulator.duration = modelData.data + Qt.callLater(() => GlobalHelper.setProperty(this, "checked", true)) } } - onObjectAdded: (index, object) => { - menu.insertAction(index, object) - } - onObjectRemoved: (index, object) => { - menu.removeAction(object) - } + } + onObjectAdded: (index, object) => { + menu.insertAction(index, object) + } + onObjectRemoved: (index, object) => { + menu.removeAction(object) } } - onTriggered: Qt.callLater(() => d.addOn.windowHandle.execQuickPick(menu)) } } ActionItem { - actionId: "org.diffscope.visualeditor.arrangementPanel.snapTupletCommand" - Action { - id: commandAction - readonly property Menu menu: Menu { - id: menu - title: commandAction.text - Instantiator { - model: DelegateModel { - model: [ - { text: qsTr("None"), data: PositionAlignmentManipulator.None }, - { text: qsTr("Triplet"), data: PositionAlignmentManipulator.Triplet }, - { text: qsTr("Quintuplet"), data: PositionAlignmentManipulator.Quintuplet }, - ] - delegate: Action { - required property var modelData - text: modelData.text - checkable: true - checked: d.arrangementPanelInterface?.positionAlignmentManipulator.tuplet === modelData.data - onTriggered: () => { - d.arrangementPanelInterface.positionAlignmentManipulator.tuplet = modelData.data - Qt.callLater(() => GlobalHelper.setProperty(this, "checked", true)) - } + actionId: "org.diffscope.visualeditor.arrangementPanel.snapTuplet" + Menu { + id: menu + Instantiator { + model: DelegateModel { + model: [ + { text: qsTr("None"), data: PositionAlignmentManipulator.None }, + { text: qsTr("Triplet"), data: PositionAlignmentManipulator.Triplet }, + { text: qsTr("Quintuplet"), data: PositionAlignmentManipulator.Quintuplet }, + ] + delegate: Action { + required property var modelData + text: modelData.text + checkable: true + checked: d.arrangementPanelInterface?.positionAlignmentManipulator.tuplet === modelData.data + onTriggered: () => { + d.arrangementPanelInterface.positionAlignmentManipulator.tuplet = modelData.data + Qt.callLater(() => GlobalHelper.setProperty(this, "checked", true)) } } - onObjectAdded: (index, object) => { - menu.insertAction(index, object) - } - onObjectRemoved: (index, object) => { - menu.removeAction(object) - } + } + onObjectAdded: (index, object) => { + menu.insertAction(index, object) + } + onObjectRemoved: (index, object) => { + menu.removeAction(object) } } - onTriggered: Qt.callLater(() => d.addOn.windowHandle.execQuickPick(menu)) } } diff --git a/src/plugins/visualeditor/res/org.diffscope.visualeditor_actions.xml b/src/plugins/visualeditor/res/org.diffscope.visualeditor_actions.xml index 4b743a8a..df5b2172 100644 --- a/src/plugins/visualeditor/res/org.diffscope.visualeditor_actions.xml +++ b/src/plugins/visualeditor/res/org.diffscope.visualeditor_actions.xml @@ -18,14 +18,14 @@ - - - + + + - - - + + + From 809581364f24fd4c578fc3c284df38513a3e9e61 Mon Sep 17 00:00:00 2001 From: CrSjimo Date: Mon, 17 Nov 2025 17:26:27 +0800 Subject: [PATCH 004/181] Update appearance --- src/libs/3rdparty/svscraft | 2 +- .../uishell/src/qml/ProjectWindow.qml | 26 +++++++++++++------ .../uishell/src/qml/SettingDialog.qml | 10 ++++--- .../colorscheme/ColorSchemeCollection.cpp | 6 ++++- .../qml/settings/ColorSchemePage.qml | 4 +++ 5 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/libs/3rdparty/svscraft b/src/libs/3rdparty/svscraft index 1ff1feba..147e1204 160000 --- a/src/libs/3rdparty/svscraft +++ b/src/libs/3rdparty/svscraft @@ -1 +1 @@ -Subproject commit 1ff1feba05489b96b4598a0647cfd38fde4d74c4 +Subproject commit 147e12049c7d4d628aa491a4770817c7dd38275d diff --git a/src/libs/application/uishell/src/qml/ProjectWindow.qml b/src/libs/application/uishell/src/qml/ProjectWindow.qml index e2c7271b..05f4e3ab 100644 --- a/src/libs/application/uishell/src/qml/ProjectWindow.qml +++ b/src/libs/application/uishell/src/qml/ProjectWindow.qml @@ -132,8 +132,13 @@ Window { } } ColumnLayout { - spacing: 1 + spacing: 0 anchors.fill: parent + component PaneSeparator: Rectangle { + color: Theme.paneSeparatorColor + implicitHeight: 1 + Layout.fillWidth: true + } Rectangle { // TODO macOS fullscreen transition id: titleBar Accessible.role: Accessible.TitleBar @@ -225,11 +230,7 @@ Window { color: parent.color } } - Item { - Layout.fillWidth: true - implicitHeight: 0 - visible: !titleBar.visible && separatedMenuParent.visible - } + PaneSeparator {} Rectangle { id: separatedMenuParent Layout.fillWidth: true @@ -238,6 +239,9 @@ Window { implicitHeight: menuBar.visualVisible ? 24 : 0 // FIXME remove spacing when visual invisible } + PaneSeparator { + visible: separatedMenuParent.visible && menuBar.visualVisible + } ToolBar { id: toolBar Layout.fillWidth: true @@ -304,6 +308,7 @@ Window { } } } + PaneSeparator {} Item { id: mainPane readonly property double minimumPanelSize: 64 @@ -312,11 +317,13 @@ Window { SplitView { anchors.fill: parent ThemedItem.splitHandleEnabled: rightDock.panelOpened + ThemedItem.dividerStroke: rightDock.panelOpened ? SVS.DS_Splitter : SVS.DS_PaneSeparator Accessible.ignored: true SplitView { SplitView.minimumWidth: leftDock.SplitView.minimumWidth + mainPane.minimumPanelSize SplitView.fillWidth: true ThemedItem.splitHandleEnabled: leftDock.panelOpened + ThemedItem.dividerStroke: leftDock.panelOpened ? SVS.DS_Splitter : SVS.DS_PaneSeparator Accessible.ignored: true DockingView { id: leftDock @@ -340,6 +347,8 @@ Window { SplitView.fillHeight: true SplitView.minimumWidth: mainPane.minimumPanelSize ThemedItem.splitHandleVisible: topDock.panelOpened || bottomDock.panelOpened + ThemedItem.splitHandleEnabled: topDock.panelOpened && bottomDock.panelOpened + ThemedItem.dividerStroke: topDock.panelOpened && bottomDock.panelOpened ? SVS.DS_Splitter : SVS.DS_PaneSeparator Accessible.ignored: true Item { SplitView.minimumHeight: !bottomDock.panelOpened ? middleSplitView.height - bottomDock.barSize - 1 : topDock.barSize + (topDock.panelOpened ? mainPane.minimumPanelSize : 0) @@ -364,7 +373,7 @@ Window { width: parent.width height: 1 anchors.top: topDock.bottom - color: Theme.splitterColor + color: Theme.paneSeparatorColor visible: !topDock.panelOpened } } @@ -386,7 +395,7 @@ Window { width: parent.width height: 1 anchors.bottom: bottomDock.top - color: Theme.splitterColor + color: Theme.paneSeparatorColor visible: !bottomDock.panelOpened } } @@ -411,6 +420,7 @@ Window { } } } + PaneSeparator {} ToolBar { id: statusBar Accessible.role: Accessible.StatusBar diff --git a/src/libs/application/uishell/src/qml/SettingDialog.qml b/src/libs/application/uishell/src/qml/SettingDialog.qml index c4cb3c13..cb9e22d1 100644 --- a/src/libs/application/uishell/src/qml/SettingDialog.qml +++ b/src/libs/application/uishell/src/qml/SettingDialog.qml @@ -212,13 +212,12 @@ Window { return mapFromSource(sourceModel.indexForPageId(id)) } } - Rectangle { + Item { anchors.fill: parent - color: Theme.backgroundQuaternaryColor Keys.onEscapePressed: dialog.close() ColumnLayout { anchors.fill: parent - spacing: 1 + spacing: 0 SplitView { Layout.fillWidth: true Layout.fillHeight: true @@ -425,6 +424,11 @@ Window { } } } + Rectangle { + color: Theme.paneSeparatorColor + implicitHeight: 1 + Layout.fillWidth: true + } Rectangle { color: Theme.backgroundSecondaryColor Layout.fillWidth: true diff --git a/src/plugins/coreplugin/internal/colorscheme/ColorSchemeCollection.cpp b/src/plugins/coreplugin/internal/colorscheme/ColorSchemeCollection.cpp index 2658b37f..efc04cfb 100644 --- a/src/plugins/coreplugin/internal/colorscheme/ColorSchemeCollection.cpp +++ b/src/plugins/coreplugin/internal/colorscheme/ColorSchemeCollection.cpp @@ -30,6 +30,7 @@ namespace Core::Internal { {"backgroundTertiaryColor", QVariant::fromValue(QColor(0x252629))}, {"backgroundQuaternaryColor", QVariant::fromValue(QColor(0x313235))}, {"splitterColor", QVariant::fromValue(QColor(0x121315))}, + {"paneSeparatorColor", QVariant::fromValue(QColor(0x343538))}, {"foregroundPrimaryColor", QVariant::fromValue(QColor(0xdadada))}, {"foregroundSecondaryColor", QVariant::fromValue(QColor::fromRgba(0xa0dadada))}, {"linkColor", QVariant::fromValue(QColor(0x5566ff))}, @@ -62,6 +63,7 @@ namespace Core::Internal { {"backgroundTertiaryColor", QVariant::fromValue(QColor(0xd6d9da))}, {"backgroundQuaternaryColor", QVariant::fromValue(QColor(0xcacdce))}, {"splitterColor", QVariant::fromValue(QColor(0xeaeced))}, + {"paneSeparatorColor", QVariant::fromValue(QColor(0xc7cacb))}, {"foregroundPrimaryColor", QVariant::fromValue(QColor(0x252525))}, {"foregroundSecondaryColor", QVariant::fromValue(QColor::fromRgba(0xa0252525))}, {"linkColor", QVariant::fromValue(QColor(0x5566ff))}, @@ -93,7 +95,8 @@ namespace Core::Internal { {"backgroundSecondaryColor", QVariant::fromValue(QColor(0x060606))}, {"backgroundTertiaryColor", QVariant::fromValue(QColor(0x0c0c0c))}, {"backgroundQuaternaryColor", QVariant::fromValue(QColor(0x121212))}, - {"splitterColor", QVariant::fromValue(QColor(0xcc00aa))}, + {"splitterColor", QVariant::fromValue(QColor(0x00aacc))}, + {"paneSeparatorColor", QVariant::fromValue(QColor(0x7f7f7f))}, {"foregroundPrimaryColor", QVariant::fromValue(QColor(0xffffff))}, {"foregroundSecondaryColor", QVariant::fromValue(QColor::fromRgba(0xa0ffffff))}, {"linkColor", QVariant::fromValue(QColor(0x5566ff))}, @@ -332,6 +335,7 @@ namespace Core::Internal { theme->setProperty("backgroundTertiaryColor", m_unsavedPreset.value("backgroundTertiaryColor")); theme->setProperty("backgroundQuaternaryColor", m_unsavedPreset.value("backgroundQuaternaryColor")); theme->setProperty("splitterColor", m_unsavedPreset.value("splitterColor")); + theme->setProperty("paneSeparatorColor", m_unsavedPreset.value("paneSeparatorColor")); theme->setProperty("foregroundPrimaryColor", m_unsavedPreset.value("foregroundPrimaryColor")); theme->setProperty("foregroundSecondaryColor", m_unsavedPreset.value("foregroundSecondaryColor")); theme->setProperty("linkColor", m_unsavedPreset.value("linkColor")); diff --git a/src/plugins/coreplugin/qml/settings/ColorSchemePage.qml b/src/plugins/coreplugin/qml/settings/ColorSchemePage.qml index 885294be..4cd83d3c 100644 --- a/src/plugins/coreplugin/qml/settings/ColorSchemePage.qml +++ b/src/plugins/coreplugin/qml/settings/ColorSchemePage.qml @@ -350,6 +350,10 @@ Item { name: "splitterColor" text: qsTr("Splitter color") } + ListElement { + name: "paneSeparatorColor" + text: qsTr("Pane separator color") + } ListElement { name: "foregroundPrimaryColor" text: qsTr("Primary foreground color") From f353aec8cbcdcc5691be087b565e9e29bdeb8a0b Mon Sep 17 00:00:00 2001 From: CrSjimo Date: Mon, 17 Nov 2025 17:50:47 +0800 Subject: [PATCH 005/181] Remove AutoOpenPreviousProjects option --- src/plugins/coreplugin/internal/BehaviorPreference.h | 3 +-- src/plugins/coreplugin/qml/settings/GeneralPage.qml | 12 ------------ 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/plugins/coreplugin/internal/BehaviorPreference.h b/src/plugins/coreplugin/internal/BehaviorPreference.h index 7ed3ca80..aecc332d 100644 --- a/src/plugins/coreplugin/internal/BehaviorPreference.h +++ b/src/plugins/coreplugin/internal/BehaviorPreference.h @@ -61,8 +61,7 @@ namespace Core::Internal { enum StartupBehaviorFlag { SB_CreateNewProject = 0x01, - SB_AutoOpenPreviousProjects = 0x02, - SB_CloseHomeWindowAfterOpeningProject = 0x04, + SB_CloseHomeWindowAfterOpeningProject = 0x02, }; Q_ENUM(StartupBehaviorFlag) Q_DECLARE_FLAGS(StartupBehavior, StartupBehaviorFlag) diff --git a/src/plugins/coreplugin/qml/settings/GeneralPage.qml b/src/plugins/coreplugin/qml/settings/GeneralPage.qml index e8dcb14c..5fc3b306 100644 --- a/src/plugins/coreplugin/qml/settings/GeneralPage.qml +++ b/src/plugins/coreplugin/qml/settings/GeneralPage.qml @@ -91,18 +91,6 @@ ScrollView { } } } - CheckBox { - text: qsTr("Open previous projects on startup automatically") - TextMatcherItem on text { matcher: page.matcher } - checked: page.startupBehavior & BehaviorPreference.SB_AutoOpenPreviousProjects - onClicked: () => { - if (checked) { - page.startupBehavior |= BehaviorPreference.SB_AutoOpenPreviousProjects - } else { - page.startupBehavior &= ~BehaviorPreference.SB_AutoOpenPreviousProjects - } - } - } CheckBox { text: qsTr("Close the home window after opening a project") TextMatcherItem on text { matcher: page.matcher } From 2fb2e0e22e751c6d1876a907039e343cb662d423 Mon Sep 17 00:00:00 2001 From: CrSjimo Date: Tue, 18 Nov 2025 09:28:38 +0800 Subject: [PATCH 006/181] Add converter classes --- .../core/ClipboardConverter.cpp | 67 +++++++++++++++++++ .../core/ClipboardConverter.h | 53 +++++++++++++++ .../core/ClipboardConverter_p.h | 21 ++++++ .../core/ConverterCollection.cpp | 31 +++++++++ .../core/ConverterCollection.h | 41 ++++++++++++ .../core/FileConverter.cpp | 65 ++++++++++++++++++ .../importexportmanager/core/FileConverter.h | 51 ++++++++++++++ .../core/FileConverter_p.h | 21 ++++++ 8 files changed, 350 insertions(+) create mode 100644 src/plugins/importexportmanager/core/ClipboardConverter.cpp create mode 100644 src/plugins/importexportmanager/core/ClipboardConverter.h create mode 100644 src/plugins/importexportmanager/core/ClipboardConverter_p.h create mode 100644 src/plugins/importexportmanager/core/ConverterCollection.cpp create mode 100644 src/plugins/importexportmanager/core/ConverterCollection.h create mode 100644 src/plugins/importexportmanager/core/FileConverter.cpp create mode 100644 src/plugins/importexportmanager/core/FileConverter.h create mode 100644 src/plugins/importexportmanager/core/FileConverter_p.h diff --git a/src/plugins/importexportmanager/core/ClipboardConverter.cpp b/src/plugins/importexportmanager/core/ClipboardConverter.cpp new file mode 100644 index 00000000..5c3ec2c5 --- /dev/null +++ b/src/plugins/importexportmanager/core/ClipboardConverter.cpp @@ -0,0 +1,67 @@ +#include "ClipboardConverter.h" +#include "ClipboardConverter_p.h" + +#include + +namespace ImportExportManager { + + ClipboardConverter::ClipboardConverter(QObject *parent) : QObject(parent), d_ptr(new ClipboardConverterPrivate) { + Q_D(ClipboardConverter); + d->q_ptr = this; + } + + ClipboardConverter::~ClipboardConverter() = default; + + QString ClipboardConverter::name() const { + Q_D(const ClipboardConverter); + return d->name; + } + + QString ClipboardConverter::description() const { + Q_D(const ClipboardConverter); + return d->description; + } + + QStringList ClipboardConverter::mimeTypes() const { + Q_D(const ClipboardConverter); + return d->mimeTypes; + } + + ClipboardConverter::Modes ClipboardConverter::modes() const { + Q_D(const ClipboardConverter); + return d->modes; + } + + bool ClipboardConverter::paste(const QMimeData *mimeData, QDspx::Model &model) { + Q_UNUSED(mimeData) + Q_UNUSED(model) + return false; + } + + bool ClipboardConverter::copy(QMimeData *mimeData, const QDspx::Model &model) { + Q_UNUSED(mimeData) + Q_UNUSED(model) + return false; + } + + void ClipboardConverter::setName(const QString &name) { + Q_D(ClipboardConverter); + d->name = name; + } + + void ClipboardConverter::setDescription(const QString &description) { + Q_D(ClipboardConverter); + d->description = description; + } + + void ClipboardConverter::setMimeTypes(const QStringList &mimeTypes) { + Q_D(ClipboardConverter); + d->mimeTypes = mimeTypes; + } + + void ClipboardConverter::setModes(Modes modes) { + Q_D(ClipboardConverter); + d->modes = modes; + } + +} diff --git a/src/plugins/importexportmanager/core/ClipboardConverter.h b/src/plugins/importexportmanager/core/ClipboardConverter.h new file mode 100644 index 00000000..233d2783 --- /dev/null +++ b/src/plugins/importexportmanager/core/ClipboardConverter.h @@ -0,0 +1,53 @@ +#ifndef DIFFSCOPE_IMPORT_EXPORT_MANAGER_CLIPBOARDCONVERTER_H +#define DIFFSCOPE_IMPORT_EXPORT_MANAGER_CLIPBOARDCONVERTER_H + +#include + +class QMimeData; + +namespace QDspx { + struct Model; +} + +namespace ImportExportManager { + + class ClipboardConverterPrivate; + + class ClipboardConverter : public QObject { + Q_OBJECT + Q_DECLARE_PRIVATE(ClipboardConverter) + public: + explicit ClipboardConverter(QObject *parent = nullptr); + ~ClipboardConverter() override; + + QString name() const; + QString description() const; + QStringList mimeTypes() const; + + enum Mode { + Paste = 0x1, + Copy = 0x2, + }; + Q_ENUM(Mode) + Q_DECLARE_FLAGS(Modes, Mode) + + Modes modes() const; + + virtual bool paste(const QMimeData *mimeData, QDspx::Model &model); + virtual bool copy(QMimeData *mimeData, const QDspx::Model &model); + + protected: + void setName(const QString &name); + void setDescription(const QString &description); + void setMimeTypes(const QStringList &mimeTypes); + void setModes(Modes modes); + + private: + QScopedPointer d_ptr; + }; + + Q_DECLARE_OPERATORS_FOR_FLAGS(ClipboardConverter::Modes) + +} + +#endif //DIFFSCOPE_IMPORT_EXPORT_MANAGER_CLIPBOARDCONVERTER_H diff --git a/src/plugins/importexportmanager/core/ClipboardConverter_p.h b/src/plugins/importexportmanager/core/ClipboardConverter_p.h new file mode 100644 index 00000000..3bafa983 --- /dev/null +++ b/src/plugins/importexportmanager/core/ClipboardConverter_p.h @@ -0,0 +1,21 @@ +#ifndef DIFFSCOPE_IMPORT_EXPORT_MANAGER_CLIPBOARDCONVERTER_P_H +#define DIFFSCOPE_IMPORT_EXPORT_MANAGER_CLIPBOARDCONVERTER_P_H + +#include + +namespace ImportExportManager { + + class ClipboardConverterPrivate { + Q_DECLARE_PUBLIC(ClipboardConverter) + public: + ClipboardConverter *q_ptr; + + QString name; + QString description; + QStringList mimeTypes; + ClipboardConverter::Modes modes{}; + }; + +} + +#endif //DIFFSCOPE_IMPORT_EXPORT_MANAGER_CLIPBOARDCONVERTER_P_H diff --git a/src/plugins/importexportmanager/core/ConverterCollection.cpp b/src/plugins/importexportmanager/core/ConverterCollection.cpp new file mode 100644 index 00000000..4c06eaaa --- /dev/null +++ b/src/plugins/importexportmanager/core/ConverterCollection.cpp @@ -0,0 +1,31 @@ +#include "ConverterCollection.h" + +#include +#include + +namespace ImportExportManager { + + ConverterCollection *m_instance = nullptr; + + ConverterCollection::ConverterCollection(QObject *parent) : Core::ObjectPool(parent) { + Q_ASSERT(!m_instance); + m_instance = this; + } + + ConverterCollection::~ConverterCollection() { + m_instance = nullptr; + } + + ConverterCollection * ConverterCollection::instance() { + return m_instance; + } + + QList ConverterCollection::fileConverters() const { + return getObjects(); + } + + QList ConverterCollection::clipboardConverters() const { + return getObjects(); + } + +} diff --git a/src/plugins/importexportmanager/core/ConverterCollection.h b/src/plugins/importexportmanager/core/ConverterCollection.h new file mode 100644 index 00000000..2991f1c9 --- /dev/null +++ b/src/plugins/importexportmanager/core/ConverterCollection.h @@ -0,0 +1,41 @@ +#ifndef CONVERTERCOLLECTION_H +#define CONVERTERCOLLECTION_H + +#include + +#include + +class QQmlEngine; +class QJSEngine; + +namespace ImportExportManager { + + class FileConverter; + class ClipboardConverter; + + class ConverterCollection : public Core::ObjectPool { + Q_OBJECT + QML_ELEMENT + QML_SINGLETON + Q_PROPERTY(QList fileConverters READ fileConverters CONSTANT) + Q_PROPERTY(QList clipboardConverters READ clipboardConverters CONSTANT) + public: + ~ConverterCollection() override; + + static ConverterCollection *instance(); + + static inline ConverterCollection *create(QQmlEngine *, QJSEngine *engine) { + return instance(); + } + + QList fileConverters() const; + QList clipboardConverters() const; + + private: + explicit ConverterCollection(QObject *parent); + + }; + +} + +#endif //CONVERTERCOLLECTION_H diff --git a/src/plugins/importexportmanager/core/FileConverter.cpp b/src/plugins/importexportmanager/core/FileConverter.cpp new file mode 100644 index 00000000..2c72cc86 --- /dev/null +++ b/src/plugins/importexportmanager/core/FileConverter.cpp @@ -0,0 +1,65 @@ +#include "FileConverter.h" +#include "FileConverter_p.h" + +namespace ImportExportManager { + + FileConverter::FileConverter(QObject *parent) : QObject(parent), d_ptr(new FileConverterPrivate) { + Q_D(FileConverter); + d->q_ptr = this; + } + + FileConverter::~FileConverter() = default; + + QString FileConverter::name() const { + Q_D(const FileConverter); + return d->name; + } + + QString FileConverter::description() const { + Q_D(const FileConverter); + return d->description; + } + + QStringList FileConverter::filters() const { + Q_D(const FileConverter); + return d->filters; + } + + FileConverter::Modes FileConverter::modes() const { + Q_D(const FileConverter); + return d->modes; + } + + bool FileConverter::execImport(const QString &filename, QDspx::Model &model) { + Q_UNUSED(filename) + Q_UNUSED(model) + return false; + } + + bool FileConverter::execExport(const QString &filename, const QDspx::Model &model) { + Q_UNUSED(filename) + Q_UNUSED(model) + return false; + } + + void FileConverter::setName(const QString &name) { + Q_D(FileConverter); + d->name = name; + } + + void FileConverter::setDescription(const QString &description) { + Q_D(FileConverter); + d->description = description; + } + + void FileConverter::setFilters(const QStringList &filters) { + Q_D(FileConverter); + d->filters = filters; + } + + void FileConverter::setModes(Modes modes) { + Q_D(FileConverter); + d->modes = modes; + } + +} diff --git a/src/plugins/importexportmanager/core/FileConverter.h b/src/plugins/importexportmanager/core/FileConverter.h new file mode 100644 index 00000000..41d7e783 --- /dev/null +++ b/src/plugins/importexportmanager/core/FileConverter.h @@ -0,0 +1,51 @@ +#ifndef DIFFSCOPE_IMPORT_EXPORT_MANAGER_FILECONVERTER_H +#define DIFFSCOPE_IMPORT_EXPORT_MANAGER_FILECONVERTER_H + +#include + +namespace QDspx { + struct Model; +} + +namespace ImportExportManager { + + class FileConverterPrivate; + + class FileConverter : public QObject { + Q_OBJECT + Q_DECLARE_PRIVATE(FileConverter) + public: + explicit FileConverter(QObject *parent = nullptr); + ~FileConverter() override; + + QString name() const; + QString description() const; + QStringList filters() const; + + enum Mode { + Import = 0x1, + Export = 0x2, + }; + Q_ENUM(Mode) + Q_DECLARE_FLAGS(Modes, Mode) + + Modes modes() const; + + virtual bool execImport(const QString &filename, QDspx::Model &model); + virtual bool execExport(const QString &filename, const QDspx::Model &model); + + protected: + void setName(const QString &name); + void setDescription(const QString &description); + void setFilters(const QStringList &filters); + void setModes(Modes modes); + + private: + QScopedPointer d_ptr; + }; + + Q_DECLARE_OPERATORS_FOR_FLAGS(FileConverter::Modes) + +} + +#endif //DIFFSCOPE_IMPORT_EXPORT_MANAGER_FILECONVERTER_H diff --git a/src/plugins/importexportmanager/core/FileConverter_p.h b/src/plugins/importexportmanager/core/FileConverter_p.h new file mode 100644 index 00000000..6abc49b8 --- /dev/null +++ b/src/plugins/importexportmanager/core/FileConverter_p.h @@ -0,0 +1,21 @@ +#ifndef DIFFSCOPE_IMPORT_EXPORT_MANAGER_FILECONVERTER_P_H +#define DIFFSCOPE_IMPORT_EXPORT_MANAGER_FILECONVERTER_P_H + +#include + +namespace ImportExportManager { + + class FileConverterPrivate { + Q_DECLARE_PUBLIC(FileConverter) + public: + FileConverter *q_ptr; + + QString name; + QString description; + QStringList filters; + FileConverter::Modes modes{}; + }; + +} + +#endif //DIFFSCOPE_IMPORT_EXPORT_MANAGER_FILECONVERTER_P_H From c9acfb3fc9ff1eb9ab429c31e3ab80f01b9d2ae1 Mon Sep 17 00:00:00 2001 From: CrSjimo Date: Tue, 18 Nov 2025 15:36:11 +0800 Subject: [PATCH 007/181] Add import export actions --- src/libs/3rdparty/choruskit | 2 +- .../qml/actions/EditActionsAddOnActions.qml | 7 -- .../res/org.diffscope.core_actions.xml | 1 - .../internal/ImportExportManagerPlugin.cpp | 8 +- .../internal/ImportExportManagerPlugin.h | 2 +- .../internal/addon/ImportAddOn.cpp | 35 ++++++++ .../internal/addon/ImportAddOn.h | 21 +++++ .../internal/addon/ProjectAddOn.cpp | 37 ++++++++ .../internal/addon/ProjectAddOn.h | 21 +++++ .../importexportmanager/qml/ImportDialog.qml | 84 +++++++++++++++++++ .../qml/actions/ImportAddOnActions.qml | 21 +++++ .../qml/actions/ProjectAddOnActions.qml | 47 +++++++++++ ....diffscope.importexportmanager_actions.xml | 32 ++++++- 13 files changed, 305 insertions(+), 13 deletions(-) create mode 100644 src/plugins/importexportmanager/internal/addon/ImportAddOn.cpp create mode 100644 src/plugins/importexportmanager/internal/addon/ImportAddOn.h create mode 100644 src/plugins/importexportmanager/internal/addon/ProjectAddOn.cpp create mode 100644 src/plugins/importexportmanager/internal/addon/ProjectAddOn.h create mode 100644 src/plugins/importexportmanager/qml/ImportDialog.qml create mode 100644 src/plugins/importexportmanager/qml/actions/ImportAddOnActions.qml create mode 100644 src/plugins/importexportmanager/qml/actions/ProjectAddOnActions.qml diff --git a/src/libs/3rdparty/choruskit b/src/libs/3rdparty/choruskit index 2aa4fed3..ead08258 160000 --- a/src/libs/3rdparty/choruskit +++ b/src/libs/3rdparty/choruskit @@ -1 +1 @@ -Subproject commit 2aa4fed3506d79bfc0f3d1dde6acc5b4e86deb2a +Subproject commit ead082581b7116763a27e29f733fa13e4edb963b diff --git a/src/plugins/coreplugin/qml/actions/EditActionsAddOnActions.qml b/src/plugins/coreplugin/qml/actions/EditActionsAddOnActions.qml index d1424908..6cf80cce 100644 --- a/src/plugins/coreplugin/qml/actions/EditActionsAddOnActions.qml +++ b/src/plugins/coreplugin/qml/actions/EditActionsAddOnActions.qml @@ -62,13 +62,6 @@ ActionCollection { } } - ActionItem { - actionId: "org.diffscope.core.edit.pasteSpecial" - EditAction { - flag: EditActionsHandler.PasteSpecial - } - } - ActionItem { actionId: "org.diffscope.core.edit.delete" EditAction { diff --git a/src/plugins/coreplugin/res/org.diffscope.core_actions.xml b/src/plugins/coreplugin/res/org.diffscope.core_actions.xml index 6fc2f67d..a12285cf 100644 --- a/src/plugins/coreplugin/res/org.diffscope.core_actions.xml +++ b/src/plugins/coreplugin/res/org.diffscope.core_actions.xml @@ -40,7 +40,6 @@ - diff --git a/src/plugins/importexportmanager/internal/ImportExportManagerPlugin.cpp b/src/plugins/importexportmanager/internal/ImportExportManagerPlugin.cpp index 18083e1a..52700d68 100644 --- a/src/plugins/importexportmanager/internal/ImportExportManagerPlugin.cpp +++ b/src/plugins/importexportmanager/internal/ImportExportManagerPlugin.cpp @@ -13,11 +13,14 @@ #include #include +#include +#include + static auto getImportExportManagerActionExtension() { return QAK_STATIC_ACTION_EXTENSION(importexportmanager); } -namespace ImportExportManager { +namespace ImportExportManager::Internal { ImportExportManagerPlugin::ImportExportManagerPlugin() { } @@ -27,6 +30,9 @@ namespace ImportExportManager { bool ImportExportManagerPlugin::initialize(const QStringList &arguments, QString *errorMessage) { Core::RuntimeInterface::translationManager()->addTranslationPath(pluginSpec()->location() + QStringLiteral("/translations")); Core::CoreInterface::actionRegistry()->addExtension(::getImportExportManagerActionExtension()); + Core::HomeWindowInterfaceRegistry::instance()->attach(); + Core::ProjectWindowInterfaceRegistry::instance()->attach(); + Core::ProjectWindowInterfaceRegistry::instance()->attach(); return true; } void ImportExportManagerPlugin::extensionsInitialized() { diff --git a/src/plugins/importexportmanager/internal/ImportExportManagerPlugin.h b/src/plugins/importexportmanager/internal/ImportExportManagerPlugin.h index 062e79c7..d94ae2d1 100644 --- a/src/plugins/importexportmanager/internal/ImportExportManagerPlugin.h +++ b/src/plugins/importexportmanager/internal/ImportExportManagerPlugin.h @@ -3,7 +3,7 @@ #include -namespace ImportExportManager { +namespace ImportExportManager::Internal { class ImportExportManagerPlugin : public ExtensionSystem::IPlugin { Q_OBJECT diff --git a/src/plugins/importexportmanager/internal/addon/ImportAddOn.cpp b/src/plugins/importexportmanager/internal/addon/ImportAddOn.cpp new file mode 100644 index 00000000..2d106a5b --- /dev/null +++ b/src/plugins/importexportmanager/internal/addon/ImportAddOn.cpp @@ -0,0 +1,35 @@ +#include "ImportAddOn.h" + +#include + +#include +#include + +namespace ImportExportManager::Internal { + ImportAddOn::ImportAddOn(QObject *parent) : WindowInterfaceAddOn(parent) { + } + + ImportAddOn::~ImportAddOn() = default; + + void ImportAddOn::initialize() { + auto windowInterface = windowHandle()->cast(); + + // Load and register ImportAddOnActions QML component + QQmlComponent component(Core::RuntimeInterface::qmlEngine(), "DiffScope.ImportExportManager", "ImportAddOnActions"); + if (component.isError()) { + qFatal() << component.errorString(); + } + auto o = component.createWithInitialProperties({}); + o->setParent(this); + QMetaObject::invokeMethod(o, "registerToContext", windowInterface->actionContext()); + } + + void ImportAddOn::extensionsInitialized() { + } + + bool ImportAddOn::delayedInitialize() { + return WindowInterfaceAddOn::delayedInitialize(); + } +} + +#include "moc_ImportAddOn.cpp" \ No newline at end of file diff --git a/src/plugins/importexportmanager/internal/addon/ImportAddOn.h b/src/plugins/importexportmanager/internal/addon/ImportAddOn.h new file mode 100644 index 00000000..32ea3955 --- /dev/null +++ b/src/plugins/importexportmanager/internal/addon/ImportAddOn.h @@ -0,0 +1,21 @@ +#ifndef DIFFSCOPE_IMPORT_EXPORT_MANAGER_IMPORTADDON_H +#define DIFFSCOPE_IMPORT_EXPORT_MANAGER_IMPORTADDON_H + +#include + +namespace ImportExportManager::Internal { + + class ImportAddOn : public Core::WindowInterfaceAddOn { + Q_OBJECT + public: + explicit ImportAddOn(QObject *parent = nullptr); + ~ImportAddOn() override; + + void initialize() override; + void extensionsInitialized() override; + bool delayedInitialize() override; + }; + +} + +#endif //DIFFSCOPE_IMPORT_EXPORT_MANAGER_IMPORTADDON_H \ No newline at end of file diff --git a/src/plugins/importexportmanager/internal/addon/ProjectAddOn.cpp b/src/plugins/importexportmanager/internal/addon/ProjectAddOn.cpp new file mode 100644 index 00000000..a6714ce9 --- /dev/null +++ b/src/plugins/importexportmanager/internal/addon/ProjectAddOn.cpp @@ -0,0 +1,37 @@ +#include "ProjectAddOn.h" + +#include + +#include +#include + +namespace ImportExportManager::Internal { + ProjectAddOn::ProjectAddOn(QObject *parent) : WindowInterfaceAddOn(parent) { + } + + ProjectAddOn::~ProjectAddOn() = default; + + void ProjectAddOn::initialize() { + auto windowInterface = windowHandle()->cast(); + + // Load and register ProjectAddOnActions QML component + QQmlComponent component(Core::RuntimeInterface::qmlEngine(), "DiffScope.ImportExportManager", "ProjectAddOnActions"); + if (component.isError()) { + qFatal() << component.errorString(); + } + auto o = component.createWithInitialProperties({ + {"addOn", QVariant::fromValue(this)}, + }); + o->setParent(this); + QMetaObject::invokeMethod(o, "registerToContext", windowInterface->actionContext()); + } + + void ProjectAddOn::extensionsInitialized() { + } + + bool ProjectAddOn::delayedInitialize() { + return WindowInterfaceAddOn::delayedInitialize(); + } +} + +#include "moc_ProjectAddOn.cpp" \ No newline at end of file diff --git a/src/plugins/importexportmanager/internal/addon/ProjectAddOn.h b/src/plugins/importexportmanager/internal/addon/ProjectAddOn.h new file mode 100644 index 00000000..bae8c484 --- /dev/null +++ b/src/plugins/importexportmanager/internal/addon/ProjectAddOn.h @@ -0,0 +1,21 @@ +#ifndef DIFFSCOPE_IMPORT_EXPORT_MANAGER_PROJECTADDON_H +#define DIFFSCOPE_IMPORT_EXPORT_MANAGER_PROJECTADDON_H + +#include + +namespace ImportExportManager::Internal { + + class ProjectAddOn : public Core::WindowInterfaceAddOn { + Q_OBJECT + public: + explicit ProjectAddOn(QObject *parent = nullptr); + ~ProjectAddOn() override; + + void initialize() override; + void extensionsInitialized() override; + bool delayedInitialize() override; + }; + +} + +#endif //DIFFSCOPE_IMPORT_EXPORT_MANAGER_PROJECTADDON_H \ No newline at end of file diff --git a/src/plugins/importexportmanager/qml/ImportDialog.qml b/src/plugins/importexportmanager/qml/ImportDialog.qml new file mode 100644 index 00000000..3786cfaf --- /dev/null +++ b/src/plugins/importexportmanager/qml/ImportDialog.qml @@ -0,0 +1,84 @@ +import QtQml +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +import SVSCraft +import SVSCraft.UIComponents + +Window { + id: window + width: 400 + height: 600 + title: qsTr("Import") + + property string path: "" + + function browseFile() { + + } + + ColumnLayout { + id: mainLayout + Rectangle { + color: Theme.backgroundQuaternaryColor + Layout.fillWidth: true + Layout.fillHeight: true + ColumnLayout { + id: contentLayout + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: 12 + Label { + text: qsTr("Select a file to import") + font.pixelSize: 20 + } + GridLayout { + columns: 2 + Label { + text: qsTr("Path") + } + RowLayout { + TextField { + text: window.path + onTextEdited: window.path = text + } + Button { + text: qsTr("Browse") + onClicked: window.browseFile() + } + } + Label { + text: qsTr("Format") + } + ComboBox {} + } + } + } + Rectangle { + color: Theme.backgroundSecondaryColor + Layout.fillWidth: true + height: 52 + RowLayout { + id: buttonLayout + anchors.fill: parent + anchors.margins: 12 + spacing: 12 + Item { + Layout.fillWidth: true + Layout.fillHeight: true + } + Button { + ThemedItem.controlType: SVS.CT_Accent + Layout.alignment: Qt.AlignVCenter + text: qsTr("Continue") + } + Button { + Layout.alignment: Qt.AlignVCenter + text: qsTr("Cancel") + } + } + } + } +} \ No newline at end of file diff --git a/src/plugins/importexportmanager/qml/actions/ImportAddOnActions.qml b/src/plugins/importexportmanager/qml/actions/ImportAddOnActions.qml new file mode 100644 index 00000000..b6189c4a --- /dev/null +++ b/src/plugins/importexportmanager/qml/actions/ImportAddOnActions.qml @@ -0,0 +1,21 @@ +import QtQml +import QtQuick +import QtQuick.Controls + +import SVSCraft.UIComponents + +import QActionKit + +import DiffScope.UIShell + +ActionCollection { + + ActionItem { + actionId: "org.diffscope.importexportmanager.file.import" + Action { + onTriggered: () => { + + } + } + } +} \ No newline at end of file diff --git a/src/plugins/importexportmanager/qml/actions/ProjectAddOnActions.qml b/src/plugins/importexportmanager/qml/actions/ProjectAddOnActions.qml new file mode 100644 index 00000000..f42f504b --- /dev/null +++ b/src/plugins/importexportmanager/qml/actions/ProjectAddOnActions.qml @@ -0,0 +1,47 @@ +import QtQml +import QtQuick +import QtQuick.Controls + +import SVSCraft.UIComponents + +import QActionKit + +import DiffScope.UIShell + +ActionCollection { + + required property QtObject addOn + + ActionItem { + actionId: "org.diffscope.importexportmanager.file.export" + Action { + onTriggered: () => { + + } + } + } + ActionItem { + actionId: "org.diffscope.importexportmanager.project.importAsTracks" + Action { + onTriggered: () => { + + } + } + } + ActionItem { + actionId: "org.diffscope.importexportmanager.edit.copySpecial" + Action { + onTriggered: () => { + + } + } + } + ActionItem { + actionId: "org.diffscope.importexportmanager.edit.pasteSpecial" + Action { + onTriggered: () => { + + } + } + } +} \ No newline at end of file diff --git a/src/plugins/importexportmanager/res/org.diffscope.importexportmanager_actions.xml b/src/plugins/importexportmanager/res/org.diffscope.importexportmanager_actions.xml index efed6d8c..6c843464 100644 --- a/src/plugins/importexportmanager/res/org.diffscope.importexportmanager_actions.xml +++ b/src/plugins/importexportmanager/res/org.diffscope.importexportmanager_actions.xml @@ -15,11 +15,39 @@ - + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 3631f58bd28bcfa70c10f4171a41a73e04b0114d Mon Sep 17 00:00:00 2001 From: CrSjimo Date: Tue, 18 Nov 2025 18:02:07 +0800 Subject: [PATCH 008/181] Update --- src/libs/3rdparty/qactionkit | 2 +- src/plugins/coreplugin/core/CoreInterface.cpp | 22 +++++++- src/plugins/coreplugin/core/CoreInterface.h | 2 + .../res/org.diffscope.core_actions.xml | 3 +- .../core/ConverterCollection.cpp | 2 + .../core/ConverterCollection.h | 5 ++ .../core/FileConverter.cpp | 8 +-- .../importexportmanager/core/FileConverter.h | 15 ++++- .../internal/ImportExportManagerPlugin.cpp | 2 + .../internal/addon/ImportAddOn.cpp | 49 ++++++++++++++++- .../internal/addon/ImportAddOn.h | 2 + ...mportDialog.qml => ImportExportDialog.qml} | 55 ++++++++++++++++--- .../qml/ImportExportHelper.qml | 13 +++++ .../qml/actions/ImportAddOnActions.qml | 7 ++- ....diffscope.importexportmanager_actions.xml | 12 ++-- 15 files changed, 167 insertions(+), 32 deletions(-) rename src/plugins/importexportmanager/qml/{ImportDialog.qml => ImportExportDialog.qml} (53%) create mode 100644 src/plugins/importexportmanager/qml/ImportExportHelper.qml diff --git a/src/libs/3rdparty/qactionkit b/src/libs/3rdparty/qactionkit index 5f075d0a..42b9cd90 160000 --- a/src/libs/3rdparty/qactionkit +++ b/src/libs/3rdparty/qactionkit @@ -1 +1 @@ -Subproject commit 5f075d0ac57c8316ed719f5ba077b4fa36eb626e +Subproject commit 42b9cd9053d76aeb8d66728a650827d97f40f11a diff --git a/src/plugins/coreplugin/core/CoreInterface.cpp b/src/plugins/coreplugin/core/CoreInterface.cpp index b9a4b51c..543dacbe 100644 --- a/src/plugins/coreplugin/core/CoreInterface.cpp +++ b/src/plugins/coreplugin/core/CoreInterface.cpp @@ -234,7 +234,7 @@ namespace Core { QQmlEngine::setObjectOwnership(windowInterface, QQmlEngine::CppOwnership); } - static ProjectWindowInterface *createProjectWindow(ProjectDocumentContext *projectDocumentContext) { + ProjectWindowInterface *CoreInterface::createProjectWindow(ProjectDocumentContext *projectDocumentContext) { Internal::ProjectStartupTimerAddOn::startTimer(); auto windowInterface = ProjectWindowInterfaceRegistry::instance()->create(projectDocumentContext); QQmlEngine::setObjectOwnership(windowInterface, QQmlEngine::CppOwnership); @@ -251,8 +251,24 @@ namespace Core { ProjectWindowInterface *CoreInterface::newFile(QWindow *parent) { static QDspx::Model defaultModel{ .version = QDspx::Model::V1, - .content = { - + .content { + .tracks { + { + .name = tr("Track 1"), + .clips = { + QDspx::SingingClipRef::create( + tr("Untitled clip"), + QDspx::BusControl{}, + QDspx::ClipTime{ + .start = 0, + .length = 48000, + .clipStart = 0, + .clipLen = 48000, + } + ) + } + } + } } }; qCInfo(lcCoreInterface) << "New file"; diff --git a/src/plugins/coreplugin/core/CoreInterface.h b/src/plugins/coreplugin/core/CoreInterface.h index 73eca27c..353fdee2 100644 --- a/src/plugins/coreplugin/core/CoreInterface.h +++ b/src/plugins/coreplugin/core/CoreInterface.h @@ -24,6 +24,7 @@ namespace Core { class ProjectWindowInterface; class DspxCheckerRegistry; + class ProjectDocumentContext; class CoreInterfacePrivate; @@ -55,6 +56,7 @@ namespace Core { Q_INVOKABLE static ProjectWindowInterface *newFile(QWindow *parent = nullptr); Q_INVOKABLE static ProjectWindowInterface *newFileFromTemplate(const QString &templateFilePath, QWindow *parent = nullptr); Q_INVOKABLE static ProjectWindowInterface *openFile(const QString &filePath, QWindow *parent = nullptr); + Q_INVOKABLE static ProjectWindowInterface *createProjectWindow(ProjectDocumentContext *projectDocumentContext); Q_SIGNALS: void resetAllDoNotShowAgainRequested(); diff --git a/src/plugins/coreplugin/res/org.diffscope.core_actions.xml b/src/plugins/coreplugin/res/org.diffscope.core_actions.xml index a12285cf..5e434616 100644 --- a/src/plugins/coreplugin/res/org.diffscope.core_actions.xml +++ b/src/plugins/coreplugin/res/org.diffscope.core_actions.xml @@ -172,7 +172,7 @@ - + @@ -189,7 +189,6 @@ - diff --git a/src/plugins/importexportmanager/core/ConverterCollection.cpp b/src/plugins/importexportmanager/core/ConverterCollection.cpp index 4c06eaaa..d07e3630 100644 --- a/src/plugins/importexportmanager/core/ConverterCollection.cpp +++ b/src/plugins/importexportmanager/core/ConverterCollection.cpp @@ -29,3 +29,5 @@ namespace ImportExportManager { } } + +#include "moc_ConverterCollection.cpp" \ No newline at end of file diff --git a/src/plugins/importexportmanager/core/ConverterCollection.h b/src/plugins/importexportmanager/core/ConverterCollection.h index 2991f1c9..c2ea0b09 100644 --- a/src/plugins/importexportmanager/core/ConverterCollection.h +++ b/src/plugins/importexportmanager/core/ConverterCollection.h @@ -10,6 +10,10 @@ class QJSEngine; namespace ImportExportManager { + namespace Internal { + class ImportExportManagerPlugin; + } + class FileConverter; class ClipboardConverter; @@ -32,6 +36,7 @@ namespace ImportExportManager { QList clipboardConverters() const; private: + friend class Internal::ImportExportManagerPlugin; explicit ConverterCollection(QObject *parent); }; diff --git a/src/plugins/importexportmanager/core/FileConverter.cpp b/src/plugins/importexportmanager/core/FileConverter.cpp index 2c72cc86..1488a9c1 100644 --- a/src/plugins/importexportmanager/core/FileConverter.cpp +++ b/src/plugins/importexportmanager/core/FileConverter.cpp @@ -30,15 +30,11 @@ namespace ImportExportManager { return d->modes; } - bool FileConverter::execImport(const QString &filename, QDspx::Model &model) { - Q_UNUSED(filename) - Q_UNUSED(model) + bool FileConverter::execImport(const QString &filename, QDspx::Model &model, QWindow *window) { return false; } - bool FileConverter::execExport(const QString &filename, const QDspx::Model &model) { - Q_UNUSED(filename) - Q_UNUSED(model) + bool FileConverter::execExport(const QString &filename, const QDspx::Model &model, QWindow *window) { return false; } diff --git a/src/plugins/importexportmanager/core/FileConverter.h b/src/plugins/importexportmanager/core/FileConverter.h index 41d7e783..847a42d6 100644 --- a/src/plugins/importexportmanager/core/FileConverter.h +++ b/src/plugins/importexportmanager/core/FileConverter.h @@ -2,6 +2,9 @@ #define DIFFSCOPE_IMPORT_EXPORT_MANAGER_FILECONVERTER_H #include +#include + +class QWindow; namespace QDspx { struct Model; @@ -13,9 +16,14 @@ namespace ImportExportManager { class FileConverter : public QObject { Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("") Q_DECLARE_PRIVATE(FileConverter) + Q_PROPERTY(QString name READ name CONSTANT) + Q_PROPERTY(QString description READ description CONSTANT) + Q_PROPERTY(QStringList filters READ filters CONSTANT) + Q_PROPERTY(Modes modes READ modes CONSTANT) public: - explicit FileConverter(QObject *parent = nullptr); ~FileConverter() override; QString name() const; @@ -31,10 +39,11 @@ namespace ImportExportManager { Modes modes() const; - virtual bool execImport(const QString &filename, QDspx::Model &model); - virtual bool execExport(const QString &filename, const QDspx::Model &model); + virtual bool execImport(const QString &filename, QDspx::Model &model, QWindow *window); + virtual bool execExport(const QString &filename, const QDspx::Model &model, QWindow *window); protected: + explicit FileConverter(QObject *parent = nullptr); void setName(const QString &name); void setDescription(const QString &description); void setFilters(const QStringList &filters); diff --git a/src/plugins/importexportmanager/internal/ImportExportManagerPlugin.cpp b/src/plugins/importexportmanager/internal/ImportExportManagerPlugin.cpp index 52700d68..5c6bf5e1 100644 --- a/src/plugins/importexportmanager/internal/ImportExportManagerPlugin.cpp +++ b/src/plugins/importexportmanager/internal/ImportExportManagerPlugin.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -30,6 +31,7 @@ namespace ImportExportManager::Internal { bool ImportExportManagerPlugin::initialize(const QStringList &arguments, QString *errorMessage) { Core::RuntimeInterface::translationManager()->addTranslationPath(pluginSpec()->location() + QStringLiteral("/translations")); Core::CoreInterface::actionRegistry()->addExtension(::getImportExportManagerActionExtension()); + new ConverterCollection(this); Core::HomeWindowInterfaceRegistry::instance()->attach(); Core::ProjectWindowInterfaceRegistry::instance()->attach(); Core::ProjectWindowInterfaceRegistry::instance()->attach(); diff --git a/src/plugins/importexportmanager/internal/addon/ImportAddOn.cpp b/src/plugins/importexportmanager/internal/addon/ImportAddOn.cpp index 2d106a5b..b912614c 100644 --- a/src/plugins/importexportmanager/internal/addon/ImportAddOn.cpp +++ b/src/plugins/importexportmanager/internal/addon/ImportAddOn.cpp @@ -1,11 +1,26 @@ #include "ImportAddOn.h" +#include #include +#include +#include #include + +#include + +#include + +#include #include +#include + +#include namespace ImportExportManager::Internal { + + Q_STATIC_LOGGING_CATEGORY(lcImportAddOn, "diffscope.importexportmanager.importaddon") + ImportAddOn::ImportAddOn(QObject *parent) : WindowInterfaceAddOn(parent) { } @@ -19,7 +34,9 @@ namespace ImportExportManager::Internal { if (component.isError()) { qFatal() << component.errorString(); } - auto o = component.createWithInitialProperties({}); + auto o = component.createWithInitialProperties({ + {"addOn", QVariant::fromValue(this)}, + }); o->setParent(this); QMetaObject::invokeMethod(o, "registerToContext", windowInterface->actionContext()); } @@ -30,6 +47,36 @@ namespace ImportExportManager::Internal { bool ImportAddOn::delayedInitialize() { return WindowInterfaceAddOn::delayedInitialize(); } + + void ImportAddOn::execImport() const { + qCInfo(lcImportAddOn) << "Exec import"; + QQmlComponent component(Core::RuntimeInterface::qmlEngine(), "DiffScope.ImportExportManager", "ImportExportDialog"); + if (component.isError()) { + qFatal() << component.errorString(); + } + auto o = component.createWithInitialProperties({ + {"isExport", QVariant::fromValue(false)}, + }); + std::unique_ptr dialog(qobject_cast(o)); + QEventLoop eventLoop; + connect(dialog.get(), SIGNAL(done()), &eventLoop, SLOT(quit())); + dialog->setTransientParent(windowHandle()->window()); + dialog->show(); + eventLoop.exec(); + if (!dialog->property("accepted").toBool()) + return; + auto path = dialog->property("path").toString(); + auto converter = dialog->property("selectedConverter").value(); + QDspx::Model model; + if (!converter->execImport(path, model, windowHandle()->window())) { + // Assume that the converter has already notified the user, so we don't need to show another message box here + qCCritical(lcImportAddOn) << "Import failed" << path << converter->name() << converter; + return; + } + auto projectDocumentContext = std::make_unique(); + projectDocumentContext->newFile(model, false); + Core::CoreInterface::createProjectWindow(projectDocumentContext.release()); + } } #include "moc_ImportAddOn.cpp" \ No newline at end of file diff --git a/src/plugins/importexportmanager/internal/addon/ImportAddOn.h b/src/plugins/importexportmanager/internal/addon/ImportAddOn.h index 32ea3955..959a753f 100644 --- a/src/plugins/importexportmanager/internal/addon/ImportAddOn.h +++ b/src/plugins/importexportmanager/internal/addon/ImportAddOn.h @@ -14,6 +14,8 @@ namespace ImportExportManager::Internal { void initialize() override; void extensionsInitialized() override; bool delayedInitialize() override; + + Q_INVOKABLE void execImport() const; }; } diff --git a/src/plugins/importexportmanager/qml/ImportDialog.qml b/src/plugins/importexportmanager/qml/ImportExportDialog.qml similarity index 53% rename from src/plugins/importexportmanager/qml/ImportDialog.qml rename to src/plugins/importexportmanager/qml/ImportExportDialog.qml index 3786cfaf..e0088f90 100644 --- a/src/plugins/importexportmanager/qml/ImportDialog.qml +++ b/src/plugins/importexportmanager/qml/ImportExportDialog.qml @@ -9,38 +9,55 @@ import SVSCraft.UIComponents Window { id: window width: 400 - height: 600 - title: qsTr("Import") + height: 500 + flags: Qt.Dialog + modality: Qt.ApplicationModal + title: isExport ? qsTr("Export") : qsTr("Import") + property bool isExport: false property string path: "" + property FileConverter selectedConverter: null + property bool accepted: false + + signal done() + + onClosing: done() function browseFile() { } + ImportExportHelper { + id: helper + } + ColumnLayout { id: mainLayout + anchors.fill: parent + spacing: 0 Rectangle { color: Theme.backgroundQuaternaryColor Layout.fillWidth: true Layout.fillHeight: true ColumnLayout { id: contentLayout - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right + anchors.fill: parent anchors.margins: 12 + spacing: 12 Label { - text: qsTr("Select a file to import") + text: window.isExport ? qsTr("Select a file to export") : qsTr("Select a file to import") font.pixelSize: 20 } GridLayout { columns: 2 + Layout.fillWidth: true Label { text: qsTr("Path") } RowLayout { + Layout.fillWidth: true TextField { + Layout.fillWidth: true text: window.path onTextEdited: window.path = text } @@ -52,10 +69,29 @@ Window { Label { text: qsTr("Format") } - ComboBox {} + ComboBox { + Layout.fillWidth: true + model: window.isExport ? helper.exportFormatComboBoxModel : helper.importFormatComboBoxModel + onCurrentIndexChanged: window.selectedConverter = currentValue ?? null + } + Item {} + Label { + Layout.fillWidth: true + ThemedItem.foregroundLevel: SVS.FL_Secondary + text: window.selectedConverter?.description ?? "" + } + } + Item { + Layout.fillWidth: true + Layout.fillHeight: true } } } + Rectangle { + color: Theme.paneSeparatorColor + implicitHeight: 1 + Layout.fillWidth: true + } Rectangle { color: Theme.backgroundSecondaryColor Layout.fillWidth: true @@ -73,6 +109,11 @@ Window { ThemedItem.controlType: SVS.CT_Accent Layout.alignment: Qt.AlignVCenter text: qsTr("Continue") + enabled: window.path !== "" && window.selectedConverter !== null + onClicked: { + window.accepted = true + window.done() + } } Button { Layout.alignment: Qt.AlignVCenter diff --git a/src/plugins/importexportmanager/qml/ImportExportHelper.qml b/src/plugins/importexportmanager/qml/ImportExportHelper.qml new file mode 100644 index 00000000..fd4a652e --- /dev/null +++ b/src/plugins/importexportmanager/qml/ImportExportHelper.qml @@ -0,0 +1,13 @@ +import QtQml + +QtObject { + + readonly property var importFormatComboBoxModel: [...ConverterCollection.fileConverters] + .filter(converter => converter.modes & FileConverter.Import) + .map(converter => ({text: converter.name, data: converter})) + + readonly property var exportFormatComboBoxModel: [...ConverterCollection.fileConverters] + .filter(converter => converter.modes & FileConverter.Export) + .map(converter => ({text: converter.name, data: converter})) + +} \ No newline at end of file diff --git a/src/plugins/importexportmanager/qml/actions/ImportAddOnActions.qml b/src/plugins/importexportmanager/qml/actions/ImportAddOnActions.qml index b6189c4a..e11f170b 100644 --- a/src/plugins/importexportmanager/qml/actions/ImportAddOnActions.qml +++ b/src/plugins/importexportmanager/qml/actions/ImportAddOnActions.qml @@ -9,13 +9,14 @@ import QActionKit import DiffScope.UIShell ActionCollection { + id: d + + required property QtObject addOn ActionItem { actionId: "org.diffscope.importexportmanager.file.import" Action { - onTriggered: () => { - - } + onTriggered: Qt.callLater(() => d.addOn.execImport()) } } } \ No newline at end of file diff --git a/src/plugins/importexportmanager/res/org.diffscope.importexportmanager_actions.xml b/src/plugins/importexportmanager/res/org.diffscope.importexportmanager_actions.xml index 6c843464..5e0358f6 100644 --- a/src/plugins/importexportmanager/res/org.diffscope.importexportmanager_actions.xml +++ b/src/plugins/importexportmanager/res/org.diffscope.importexportmanager_actions.xml @@ -15,8 +15,8 @@ - - + + @@ -36,16 +36,16 @@ - + - + - + - + From 40bbb13a87df30e394fdf9b0ac77d276bc8bbbcd Mon Sep 17 00:00:00 2001 From: CrSjimo Date: Wed, 26 Nov 2025 01:28:35 +0800 Subject: [PATCH 009/181] Add additional tracks in arrangement panel --- src/libs/3rdparty/scopicflow | 2 +- src/libs/3rdparty/svscraft | 2 +- .../core/ArrangementPanelInterface.cpp | 5 +- .../core/ArrangementPanelInterface.h | 2 +- .../core/ArrangementPanelInterface_p.h | 3 + .../internal/AdditionalTrackLoader.cpp | 153 +++++++++++++++ .../internal/AdditionalTrackLoader.h | 54 ++++++ .../internal/VisualEditorPlugin.cpp | 4 + .../internal/addon/ArrangementAddOn.cpp | 8 +- .../internal/addon/ArrangementAddOn.h | 8 + .../internal/addon/LabelTrackAddOn.cpp | 43 +++++ .../internal/addon/LabelTrackAddOn.h | 21 ++ .../internal/addon/TempoTrackAddOn.cpp | 43 +++++ .../internal/addon/TempoTrackAddOn.h | 21 ++ .../visualeditor/qml/ArrangementView.qml | 180 ++++++++++++++++++ .../qml/actions/ArrangementAddOnActions.qml | 29 +++ .../qml/additionaltracks/LabelTrack.qml | 25 +++ .../qml/additionaltracks/TempoTrack.qml | 25 +++ .../qml/panels/ArrangementPanel.qml | 30 +-- .../org.diffscope.visualeditor_actions.xml | 12 ++ 20 files changed, 641 insertions(+), 29 deletions(-) create mode 100644 src/plugins/visualeditor/internal/AdditionalTrackLoader.cpp create mode 100644 src/plugins/visualeditor/internal/AdditionalTrackLoader.h create mode 100644 src/plugins/visualeditor/internal/addon/LabelTrackAddOn.cpp create mode 100644 src/plugins/visualeditor/internal/addon/LabelTrackAddOn.h create mode 100644 src/plugins/visualeditor/internal/addon/TempoTrackAddOn.cpp create mode 100644 src/plugins/visualeditor/internal/addon/TempoTrackAddOn.h create mode 100644 src/plugins/visualeditor/qml/additionaltracks/LabelTrack.qml create mode 100644 src/plugins/visualeditor/qml/additionaltracks/TempoTrack.qml diff --git a/src/libs/3rdparty/scopicflow b/src/libs/3rdparty/scopicflow index 9ef06154..ca6e98cb 160000 --- a/src/libs/3rdparty/scopicflow +++ b/src/libs/3rdparty/scopicflow @@ -1 +1 @@ -Subproject commit 9ef0615400f9835b11179c5fdc6f593f048c102a +Subproject commit ca6e98cbbe30890493cbb6d55113ab99f24f2b53 diff --git a/src/libs/3rdparty/svscraft b/src/libs/3rdparty/svscraft index 147e1204..aac3bcac 160000 --- a/src/libs/3rdparty/svscraft +++ b/src/libs/3rdparty/svscraft @@ -1 +1 @@ -Subproject commit 147e12049c7d4d628aa491a4770817c7dd38275d +Subproject commit aac3bcace2e041303f4d7cf479155555f4366e63 diff --git a/src/plugins/visualeditor/core/ArrangementPanelInterface.cpp b/src/plugins/visualeditor/core/ArrangementPanelInterface.cpp index 9e3bc35f..d15be033 100644 --- a/src/plugins/visualeditor/core/ArrangementPanelInterface.cpp +++ b/src/plugins/visualeditor/core/ArrangementPanelInterface.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include namespace VisualEditor { @@ -105,12 +106,13 @@ namespace VisualEditor { }); } - ArrangementPanelInterface::ArrangementPanelInterface(Core::ProjectWindowInterface *windowHandle) : QObject(windowHandle), d_ptr(new ArrangementPanelInterfacePrivate) { + ArrangementPanelInterface::ArrangementPanelInterface(Internal::ArrangementAddOn *addOn, Core::ProjectWindowInterface *windowHandle) : QObject(windowHandle), d_ptr(new ArrangementPanelInterfacePrivate) { Q_D(ArrangementPanelInterface); Q_ASSERT(windowHandle->getObjects(staticMetaObject.className()).isEmpty()); windowHandle->addObject(staticMetaObject.className(), this); d->q_ptr = this; d->windowHandle = windowHandle; + d->addon = addOn; d->timeViewModel = new sflow::TimeViewModel(this); d->timeLayoutViewModel = new sflow::TimeLayoutViewModel(this); @@ -130,6 +132,7 @@ namespace VisualEditor { qFatal() << component.errorString(); } auto o = component.createWithInitialProperties({ + {"addOn", QVariant::fromValue(d->addon)}, {"arrangementPanelInterface", QVariant::fromValue(this)}, {"projectViewModelContext", QVariant::fromValue(ProjectViewModelContext::of(d->windowHandle))}, }); diff --git a/src/plugins/visualeditor/core/ArrangementPanelInterface.h b/src/plugins/visualeditor/core/ArrangementPanelInterface.h index 21f3757e..fb7adfcf 100644 --- a/src/plugins/visualeditor/core/ArrangementPanelInterface.h +++ b/src/plugins/visualeditor/core/ArrangementPanelInterface.h @@ -82,7 +82,7 @@ namespace VisualEditor { private: friend class Internal::ArrangementAddOn; QScopedPointer d_ptr; - explicit ArrangementPanelInterface(Core::ProjectWindowInterface *windowHandle); + explicit ArrangementPanelInterface(Internal::ArrangementAddOn *addOn, Core::ProjectWindowInterface *windowHandle); }; } diff --git a/src/plugins/visualeditor/core/ArrangementPanelInterface_p.h b/src/plugins/visualeditor/core/ArrangementPanelInterface_p.h index 3478fec7..038fdd74 100644 --- a/src/plugins/visualeditor/core/ArrangementPanelInterface_p.h +++ b/src/plugins/visualeditor/core/ArrangementPanelInterface_p.h @@ -12,6 +12,9 @@ namespace VisualEditor { ArrangementPanelInterface *q_ptr; Core::ProjectWindowInterface *windowHandle; + + Internal::ArrangementAddOn *addon; + sflow::TimeViewModel *timeViewModel; sflow::TimeLayoutViewModel *timeLayoutViewModel; sflow::TimelineInteractionController *timelineInteractionController; diff --git a/src/plugins/visualeditor/internal/AdditionalTrackLoader.cpp b/src/plugins/visualeditor/internal/AdditionalTrackLoader.cpp new file mode 100644 index 00000000..5dd9059e --- /dev/null +++ b/src/plugins/visualeditor/internal/AdditionalTrackLoader.cpp @@ -0,0 +1,153 @@ +#include "AdditionalTrackLoader.h" + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +namespace VisualEditor::Internal { + + Q_STATIC_LOGGING_CATEGORY(lcAdditionalTrackLoader, "diffscope.visualeditor.additionaltrackloader") + + AdditionalTrackLoader::AdditionalTrackLoader(const QString &categoryId, QObject *parent) + : QObject(parent), m_categoryId(categoryId) { + updateComponentIdList(); + } + + AdditionalTrackLoader::~AdditionalTrackLoader() = default; + + void AdditionalTrackLoader::setContextObject(QObject *contextObject) { + m_contextObject = contextObject; + } + + QStringList AdditionalTrackLoader::components() const { + return m_components; + } + + QStringList AdditionalTrackLoader::loadedComponents() const { + QStringList list; + list.reserve(m_loaded.size()); + std::ranges::transform(m_loaded, std::back_inserter(list), [](const auto &p) { + return p.first; + }); + return list; + } + + QList AdditionalTrackLoader::loadedItems() const { + QList list; + list.reserve(m_loaded.size()); + std::ranges::transform(m_loaded, std::back_inserter(list), [](const auto &p) { + return p.second; + }); + return list; + } + + void AdditionalTrackLoader::moveUp(const QString &id) { + auto it = std::ranges::find_if(m_loaded, [&id](const auto &p) { + return p.first == id; + }); + if (it == m_loaded.end()) + return; + int i = std::distance(m_loaded.begin(), it); + if (i == 0) + return; + m_loaded.swapItemsAt(i, i - 1); + Q_EMIT loadedComponentsChanged(); + Q_EMIT loadedItemsChanged(); + } + + void AdditionalTrackLoader::moveDown(const QString &id) { + auto it = std::ranges::find_if(m_loaded, [&id](const auto &p) { + return p.first == id; + }); + if (it == m_loaded.end()) + return; + int i = std::distance(m_loaded.begin(), it); + if (i == m_loaded.size() - 1) + return; + m_loaded.swapItemsAt(i, i + 1); + Q_EMIT loadedComponentsChanged(); + Q_EMIT loadedItemsChanged(); + } + + void AdditionalTrackLoader::loadItem(const QString &id) { + if (std::ranges::any_of(m_loaded, [&id](const auto &p) { return p.first == id; })) + return; + + QQuickItem *item = createItem(id); + if (!item) + return; + + m_loaded.emplaceBack(id, item); + Q_EMIT loadedComponentsChanged(); + Q_EMIT loadedItemsChanged(); + } + + void AdditionalTrackLoader::removeItem(const QString &id) { + auto it = std::ranges::find_if(m_loaded, [&id](const auto &p) { + return p.first == id; + }); + if (it == m_loaded.end()) + return; + auto item = it->second; + m_loaded.erase(it); + item->deleteLater(); + Q_EMIT loadedComponentsChanged(); + Q_EMIT loadedItemsChanged(); + } + + QString AdditionalTrackLoader::componentName(const QString &id) { + auto info = Core::CoreInterface::actionRegistry()->actionInfo(id); + auto t = info.text(true); + return t.isEmpty() ? info.text(false) : t; + } + QUrl AdditionalTrackLoader::componentIcon(const QString &id) { + auto icon = Core::CoreInterface::actionRegistry()->actionIcon("", id); + return icon.url(); + } + + void AdditionalTrackLoader::updateComponentIdList() { + m_components.clear(); + auto actions = Core::CoreInterface::actionRegistry()->catalog().children(m_categoryId); + m_components = actions; + } + + QQuickItem *AdditionalTrackLoader::createItem(const QString &id) { + Q_UNUSED(id) + if (!m_contextObject) + return nullptr; + auto windowInterface = m_contextObject->property("windowHandle").value(); + Q_ASSERT(windowInterface); + auto component = windowInterface->actionContext()->action(id); + if (!component) { + qCWarning(lcAdditionalTrackLoader) << "Component" << id << "not found"; + return nullptr; + } + std::unique_ptr object(component->createWithInitialProperties({ + {"contextObject", QVariant::fromValue(m_contextObject)}, + })); + if (!object) { + qCWarning(lcAdditionalTrackLoader) << "Failed to create component" << id << component->errorString(); + return nullptr; + } + windowInterface->actionContext()->attachActionInfo(id, object.get()); + if (!qobject_cast(object.get())) { + qCWarning(lcAdditionalTrackLoader) << "Component" << id << "is not a QuickItem"; + return nullptr; + } + auto item = qobject_cast(object.release()); + item->setParent(this); + return item; + } + +} + +#include "moc_AdditionalTrackLoader.cpp" diff --git a/src/plugins/visualeditor/internal/AdditionalTrackLoader.h b/src/plugins/visualeditor/internal/AdditionalTrackLoader.h new file mode 100644 index 00000000..a90b3fd8 --- /dev/null +++ b/src/plugins/visualeditor/internal/AdditionalTrackLoader.h @@ -0,0 +1,54 @@ +#ifndef DIFFSCOPE_VISUALEDITOR_ADDITIONALTRACKLOADER_H +#define DIFFSCOPE_VISUALEDITOR_ADDITIONALTRACKLOADER_H + +#include +#include +#include + +class QQuickItem; + +namespace VisualEditor::Internal { + + class AdditionalTrackLoader : public QObject { + Q_OBJECT + + Q_PROPERTY(QStringList components READ components CONSTANT) + Q_PROPERTY(QStringList loadedComponents READ loadedComponents NOTIFY loadedComponentsChanged) + Q_PROPERTY(QList loadedItems READ loadedItems NOTIFY loadedItemsChanged) + + public: + explicit AdditionalTrackLoader(const QString &categoryId, QObject *parent = nullptr); + ~AdditionalTrackLoader() override; + + void setContextObject(QObject *contextObject); + + QStringList components() const; + QStringList loadedComponents() const; + QList loadedItems() const; + + Q_INVOKABLE void moveUp(const QString &id); + Q_INVOKABLE void moveDown(const QString &id); + Q_INVOKABLE void loadItem(const QString &id); + Q_INVOKABLE void removeItem(const QString &id); + + Q_INVOKABLE static QString componentName(const QString &id); + Q_INVOKABLE static QUrl componentIcon(const QString &id); + + Q_SIGNALS: + void loadedComponentsChanged(); + void loadedItemsChanged(); + + private: + void updateComponentIdList(); + QQuickItem *createItem(const QString &id); + + private: + QStringList m_components; + QString m_categoryId; + QObject *m_contextObject{}; + QList> m_loaded; + }; + +} + +#endif // DIFFSCOPE_VISUALEDITOR_ADDITIONALTRACKLOADER_H diff --git a/src/plugins/visualeditor/internal/VisualEditorPlugin.cpp b/src/plugins/visualeditor/internal/VisualEditorPlugin.cpp index c630b091..d998082a 100644 --- a/src/plugins/visualeditor/internal/VisualEditorPlugin.cpp +++ b/src/plugins/visualeditor/internal/VisualEditorPlugin.cpp @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include static auto getVisualEditorActionExtension() { @@ -66,5 +68,7 @@ namespace VisualEditor::Internal { void VisualEditorPlugin::initializeWindows() { Core::ProjectWindowInterfaceRegistry::instance()->attach(); Core::ProjectWindowInterfaceRegistry::instance()->attach(); + Core::ProjectWindowInterfaceRegistry::instance()->attach(); + Core::ProjectWindowInterfaceRegistry::instance()->attach(); } } diff --git a/src/plugins/visualeditor/internal/addon/ArrangementAddOn.cpp b/src/plugins/visualeditor/internal/addon/ArrangementAddOn.cpp index ebf965d9..ae84690e 100644 --- a/src/plugins/visualeditor/internal/addon/ArrangementAddOn.cpp +++ b/src/plugins/visualeditor/internal/addon/ArrangementAddOn.cpp @@ -11,6 +11,7 @@ #include #include +#include namespace VisualEditor::Internal { ArrangementAddOn::ArrangementAddOn(QObject *parent) : WindowInterfaceAddOn(parent) { @@ -21,7 +22,9 @@ namespace VisualEditor::Internal { void ArrangementAddOn::initialize() { auto windowInterface = windowHandle()->cast(); windowInterface->window()->installEventFilter(this); - new ArrangementPanelInterface(windowInterface); + m_additionalTrackLoader = new AdditionalTrackLoader("org.diffscope.visualeditor.arrangementPanel.additionalTrackWidgets", this); + auto arrangementPanelInterface = new ArrangementPanelInterface(this, windowInterface); + m_additionalTrackLoader->setContextObject(arrangementPanelInterface); { QQmlComponent component(Core::RuntimeInterface::qmlEngine(), "DiffScope.VisualEditor", "ArrangementAddOnActions"); if (component.isError()) { @@ -61,6 +64,9 @@ namespace VisualEditor::Internal { ArrangementPanelInterface *ArrangementAddOn::arrangementPanelInterface() const { return ArrangementPanelInterface::of(windowHandle()->cast()); } + AdditionalTrackLoader *ArrangementAddOn::additionalTrackLoader() const { + return m_additionalTrackLoader; + } bool ArrangementAddOn::eventFilter(QObject *watched, QEvent *event) { if (watched == windowHandle()->window()) { switch (event->type()) { diff --git a/src/plugins/visualeditor/internal/addon/ArrangementAddOn.h b/src/plugins/visualeditor/internal/addon/ArrangementAddOn.h index 8b8262e5..9532a2ed 100644 --- a/src/plugins/visualeditor/internal/addon/ArrangementAddOn.h +++ b/src/plugins/visualeditor/internal/addon/ArrangementAddOn.h @@ -9,9 +9,12 @@ namespace VisualEditor { namespace VisualEditor::Internal { + class AdditionalTrackLoader; + class ArrangementAddOn : public Core::WindowInterfaceAddOn { Q_OBJECT Q_PROPERTY(VisualEditor::ArrangementPanelInterface *arrangementPanelInterface READ arrangementPanelInterface CONSTANT) + Q_PROPERTY(AdditionalTrackLoader *additionalTrackLoader READ additionalTrackLoader CONSTANT) public: explicit ArrangementAddOn(QObject *parent = nullptr); ~ArrangementAddOn() override; @@ -22,8 +25,13 @@ namespace VisualEditor::Internal { ArrangementPanelInterface *arrangementPanelInterface() const; + AdditionalTrackLoader *additionalTrackLoader() const; + bool eventFilter(QObject *watched, QEvent *event) override; + private: + AdditionalTrackLoader *m_additionalTrackLoader{}; + }; } diff --git a/src/plugins/visualeditor/internal/addon/LabelTrackAddOn.cpp b/src/plugins/visualeditor/internal/addon/LabelTrackAddOn.cpp new file mode 100644 index 00000000..646e526f --- /dev/null +++ b/src/plugins/visualeditor/internal/addon/LabelTrackAddOn.cpp @@ -0,0 +1,43 @@ +#include "LabelTrackAddOn.h" + +#include + +#include + +#include + +#include + +namespace VisualEditor::Internal { + LabelTrackAddOn::LabelTrackAddOn(QObject *parent) : WindowInterfaceAddOn(parent) { + } + + LabelTrackAddOn::~LabelTrackAddOn() = default; + + void LabelTrackAddOn::initialize() { + auto windowInterface = windowHandle()->cast(); + { + QQmlComponent component(Core::RuntimeInterface::qmlEngine(), "DiffScope.VisualEditor", "LabelTrack", this); + if (component.isError()) { + qFatal() << component.errorString(); + } + auto o = component.createWithInitialProperties({ + {"addOn", QVariant::fromValue(this)}, + }); + if (component.isError()) { + qFatal() << component.errorString(); + } + o->setParent(this); + windowInterface->actionContext()->addAction("org.diffscope.visualeditor.arrangementPanel.additionalTracks.label", o->property("labelTrackComponent").value()); + } + } + + void LabelTrackAddOn::extensionsInitialized() { + } + + bool LabelTrackAddOn::delayedInitialize() { + return WindowInterfaceAddOn::delayedInitialize(); + } +} + +#include "moc_LabelTrackAddOn.cpp" \ No newline at end of file diff --git a/src/plugins/visualeditor/internal/addon/LabelTrackAddOn.h b/src/plugins/visualeditor/internal/addon/LabelTrackAddOn.h new file mode 100644 index 00000000..c737bc74 --- /dev/null +++ b/src/plugins/visualeditor/internal/addon/LabelTrackAddOn.h @@ -0,0 +1,21 @@ +#ifndef DIFFSCOPE_VISUAL_EDITOR_LABELTRACKADDON_H +#define DIFFSCOPE_VISUAL_EDITOR_LABELTRACKADDON_H + +#include + +namespace VisualEditor::Internal { + + class LabelTrackAddOn : public Core::WindowInterfaceAddOn { + Q_OBJECT + public: + explicit LabelTrackAddOn(QObject *parent = nullptr); + ~LabelTrackAddOn() override; + + void initialize() override; + void extensionsInitialized() override; + bool delayedInitialize() override; + }; + +} + +#endif //DIFFSCOPE_VISUAL_EDITOR_LABELTRACKADDON_H \ No newline at end of file diff --git a/src/plugins/visualeditor/internal/addon/TempoTrackAddOn.cpp b/src/plugins/visualeditor/internal/addon/TempoTrackAddOn.cpp new file mode 100644 index 00000000..c68d26f6 --- /dev/null +++ b/src/plugins/visualeditor/internal/addon/TempoTrackAddOn.cpp @@ -0,0 +1,43 @@ +#include "TempoTrackAddOn.h" + +#include + +#include + +#include + +#include + +namespace VisualEditor::Internal { + TempoTrackAddOn::TempoTrackAddOn(QObject *parent) : WindowInterfaceAddOn(parent) { + } + + TempoTrackAddOn::~TempoTrackAddOn() = default; + + void TempoTrackAddOn::initialize() { + auto windowInterface = windowHandle()->cast(); + { + QQmlComponent component(Core::RuntimeInterface::qmlEngine(), "DiffScope.VisualEditor", "TempoTrack", this); + if (component.isError()) { + qFatal() << component.errorString(); + } + auto o = component.createWithInitialProperties({ + {"addOn", QVariant::fromValue(this)}, + }); + if (component.isError()) { + qFatal() << component.errorString(); + } + o->setParent(this); + windowInterface->actionContext()->addAction("org.diffscope.visualeditor.arrangementPanel.additionalTracks.tempo", o->property("tempoTrackComponent").value()); + } + } + + void TempoTrackAddOn::extensionsInitialized() { + } + + bool TempoTrackAddOn::delayedInitialize() { + return WindowInterfaceAddOn::delayedInitialize(); + } +} + +#include "moc_TempoTrackAddOn.cpp" \ No newline at end of file diff --git a/src/plugins/visualeditor/internal/addon/TempoTrackAddOn.h b/src/plugins/visualeditor/internal/addon/TempoTrackAddOn.h new file mode 100644 index 00000000..0a288c21 --- /dev/null +++ b/src/plugins/visualeditor/internal/addon/TempoTrackAddOn.h @@ -0,0 +1,21 @@ +#ifndef DIFFSCOPE_VISUAL_EDITOR_TEMPOTRACKADDON_H +#define DIFFSCOPE_VISUAL_EDITOR_TEMPOTRACKADDON_H + +#include + +namespace VisualEditor::Internal { + + class TempoTrackAddOn : public Core::WindowInterfaceAddOn { + Q_OBJECT + public: + explicit TempoTrackAddOn(QObject *parent = nullptr); + ~TempoTrackAddOn() override; + + void initialize() override; + void extensionsInitialized() override; + bool delayedInitialize() override; + }; + +} + +#endif //DIFFSCOPE_VISUAL_EDITOR_TEMPOTRACKADDON_H \ No newline at end of file diff --git a/src/plugins/visualeditor/qml/ArrangementView.qml b/src/plugins/visualeditor/qml/ArrangementView.qml index ee07cf64..f42523fc 100644 --- a/src/plugins/visualeditor/qml/ArrangementView.qml +++ b/src/plugins/visualeditor/qml/ArrangementView.qml @@ -3,16 +3,20 @@ import QtQml.Models import QtQuick import QtQuick.Controls import QtQuick.Layouts +import QtQuick.Controls.impl import SVSCraft import SVSCraft.UIComponents +import QActionKit + import dev.sjimo.ScopicFlow import dev.sjimo.ScopicFlow.Views Item { id: view + required property QtObject addOn required property ArrangementPanelInterface arrangementPanelInterface required property ProjectViewModelContext projectViewModelContext @@ -27,6 +31,147 @@ Item { Item { // TODO SplitView.preferredWidth: 200 + ColumnLayout { + anchors.fill: parent + spacing: 0 + ToolBar { + Layout.fillWidth: true + Layout.preferredHeight: timeline.height + padding: 2 + ToolBarContainer { + id: toolBar + anchors.fill: parent + property MenuActionInstantiator instantiator: MenuActionInstantiator { + actionId: "org.diffscope.visualeditor.arrangementPanelTimelineToolBar" + context: view.arrangementPanelInterface?.windowHandle.actionContext ?? null + separatorComponent: ToolBarContainerSeparator { + } + stretchComponent: ToolBarContainerStretch { + } + Component.onCompleted: forceUpdateLayouts() + } + toolButtonComponent: ToolButton { + implicitWidth: 20 + implicitHeight: 20 + display: icon.source.toString().length !== 0 ? AbstractButton.IconOnly : AbstractButton.TextBesideIcon + DescriptiveText.bindAccessibleDescription: true + } + } + } + Rectangle { + Layout.fillWidth: true + implicitHeight: 1 + color: Theme.paneSeparatorColor + } + ColumnLayout { + Layout.fillWidth: true + Layout.fillHeight: false + spacing: 0 + Repeater { + model: view.addOn?.additionalTrackLoader.loadedComponents ?? [] + ColumnLayout { + id: layout + required property string modelData + required property int index + readonly property Item item: additionalTrackRepeater.itemAt(index)?.item ?? null + readonly property double itemSize: 12 + Layout.fillWidth: true + spacing: 0 + Item { + id: container + Layout.fillWidth: true + Layout.preferredHeight: layout.item?.height ?? 0 + readonly property Action moveUpAction: Action { + enabled: layout.index !== 0 + text: qsTr("Move Up") + icon.source: "image://fluent-system-icons/arrow_up" + onTriggered: view.addOn.additionalTrackLoader.moveUp(layout.modelData) + } + readonly property Action moveDownAction: Action { + enabled: layout.index !== (view.addOn?.additionalTrackLoader.loadedComponents.length ?? 0) - 1 + text: qsTr("Move Down") + icon.source: "image://fluent-system-icons/arrow_down" + onTriggered: view.addOn.additionalTrackLoader.moveDown(layout.modelData) + } + readonly property Action removeAction: Action { + text: qsTr("Remove") + icon.source: "image://fluent-system-icons/dismiss" + onTriggered: view.addOn.additionalTrackLoader.removeItem(layout.modelData) + } + RowLayout { + anchors.fill: parent + anchors.margins: 2 + anchors.leftMargin: 4 + anchors.rightMargin: 4 + visible: (layout.item?.height ?? 0) >= 12 + IconLabel { + Layout.fillHeight: true + icon.height: layout.itemSize + icon.width: layout.itemSize + icon.source: layout.item.ActionInstantiator.icon.source + icon.color: layout.item.ActionInstantiator.icon.color.valid ? layout.item.ActionInstantiator.icon.color : Theme.foregroundPrimaryColor + text: view.addOn.additionalTrackLoader.componentName(layout.modelData) + color: Theme.foregroundPrimaryColor + font.pixelSize: layout.itemSize * 0.75 + } + Item { + Layout.fillWidth: true + Layout.fillHeight: true + } + ToolButton { + implicitWidth: layout.itemSize + implicitHeight: layout.itemSize + padding: 0 + visible: hoverHandler.hovered + display: AbstractButton.IconOnly + action: container.moveUpAction + } + ToolButton { + implicitWidth: layout.itemSize + implicitHeight: layout.itemSize + padding: 0 + visible: hoverHandler.hovered + display: AbstractButton.IconOnly + action: container.moveDownAction + } + ToolButton { + implicitWidth: layout.itemSize + implicitHeight: layout.itemSize + padding: 1 // its icon looks a bit larger, so we need to add some padding + visible: hoverHandler.hovered + display: AbstractButton.IconOnly + action: container.removeAction + } + } + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + Menu { + id: menu + contentData: [container.moveUpAction, container.moveDownAction, container.removeAction] + } + onClicked: menu.popup() + } + HoverHandler { + id: hoverHandler + } + DescriptiveText.activated: hoverHandler.hovered && (layout.item?.height ?? 0) < 12 + DescriptiveText.toolTip: view.addOn.additionalTrackLoader.componentName(layout.modelData) + } + Rectangle { + Layout.fillWidth: true + implicitHeight: 1 + color: Theme.paneSeparatorColor + } + } + } + } + Item { + id: trackListContainer + Layout.fillWidth: true + Layout.fillHeight: true + } + } } Item { SplitView.fillWidth: true @@ -42,11 +187,46 @@ Item { scrollBehaviorViewModel: view.arrangementPanelInterface?.scrollBehaviorViewModel ?? null timelineInteractionController: view.arrangementPanelInterface?.timelineInteractionController ?? null } + Rectangle { + Layout.fillWidth: true + implicitHeight: 1 + color: Theme.paneSeparatorColor + } + ColumnLayout { + Layout.fillWidth: true + spacing: 0 + Repeater { + id: additionalTrackRepeater + model: view.addOn?.additionalTrackLoader.loadedComponents ?? [] + ColumnLayout { + required property string modelData + required property int index + Layout.fillWidth: true + spacing: 0 + readonly property Item separator: Rectangle { + Layout.fillWidth: true + implicitHeight: 1 + color: Theme.paneSeparatorColor + } + readonly property Item item: view.addOn?.additionalTrackLoader.loadedItems[index] ?? null + data: [item, separator] + } + } + } Item { + id: clipViewContainer Layout.fillWidth: true Layout.fillHeight: true } } + PositionIndicators { + id: positionIndicators + anchors.fill: parent + anchors.topMargin: timeline.height + timeViewModel: view.arrangementPanelInterface?.timeViewModel ?? null + playbackViewModel: view.projectViewModelContext?.playbackViewModel ?? null + timeLayoutViewModel: view.arrangementPanelInterface?.timeLayoutViewModel ?? null + } } } diff --git a/src/plugins/visualeditor/qml/actions/ArrangementAddOnActions.qml b/src/plugins/visualeditor/qml/actions/ArrangementAddOnActions.qml index be1a2f43..6167899d 100644 --- a/src/plugins/visualeditor/qml/actions/ArrangementAddOnActions.qml +++ b/src/plugins/visualeditor/qml/actions/ArrangementAddOnActions.qml @@ -139,4 +139,33 @@ ActionCollection { } } + ActionItem { + actionId: "org.diffscope.visualeditor.arrangementPanel.additionalTracks" + Menu { + id: menu + Instantiator { + model: d.addOn?.additionalTrackLoader.components ?? null + delegate: Action { + required property string modelData + text: d.addOn.additionalTrackLoader.componentName(modelData) + checkable: true + checked: d.addOn.additionalTrackLoader.loadedComponents.indexOf(modelData) >= 0 + onTriggered: () => { + if (checked) { + d.addOn.additionalTrackLoader.loadItem(modelData) + } else { + d.addOn.additionalTrackLoader.removeItem(modelData) + } + } + } + onObjectAdded: (index, object) => { + menu.insertAction(index, object) + } + onObjectRemoved: (index, object) => { + menu.removeAction(object) + } + } + } + } + } \ No newline at end of file diff --git a/src/plugins/visualeditor/qml/additionaltracks/LabelTrack.qml b/src/plugins/visualeditor/qml/additionaltracks/LabelTrack.qml new file mode 100644 index 00000000..03df4222 --- /dev/null +++ b/src/plugins/visualeditor/qml/additionaltracks/LabelTrack.qml @@ -0,0 +1,25 @@ +import QtQml +import QtQuick +import QtQuick.Controls +import QtQuick.Templates as T +import QtQuick.Layouts + +import QActionKit + +import SVSCraft +import SVSCraft.UIComponents + +import DiffScope.UIShell + +QtObject { + id: d + required property QtObject addOn + + readonly property Component labelTrackComponent: Item { + required property QtObject contextObject + Layout.fillWidth: true + implicitHeight: 16 + // TODO + } + +} \ No newline at end of file diff --git a/src/plugins/visualeditor/qml/additionaltracks/TempoTrack.qml b/src/plugins/visualeditor/qml/additionaltracks/TempoTrack.qml new file mode 100644 index 00000000..a0933e89 --- /dev/null +++ b/src/plugins/visualeditor/qml/additionaltracks/TempoTrack.qml @@ -0,0 +1,25 @@ +import QtQml +import QtQuick +import QtQuick.Controls +import QtQuick.Templates as T +import QtQuick.Layouts + +import QActionKit + +import SVSCraft +import SVSCraft.UIComponents + +import DiffScope.UIShell + +QtObject { + id: d + required property QtObject addOn + + readonly property Component tempoTrackComponent: Item { + required property QtObject contextObject + Layout.fillWidth: true + implicitHeight: 16 + // TODO + } + +} \ No newline at end of file diff --git a/src/plugins/visualeditor/qml/panels/ArrangementPanel.qml b/src/plugins/visualeditor/qml/panels/ArrangementPanel.qml index 21c9f789..33cf3e8f 100644 --- a/src/plugins/visualeditor/qml/panels/ArrangementPanel.qml +++ b/src/plugins/visualeditor/qml/panels/ArrangementPanel.qml @@ -25,6 +25,9 @@ QtObject { arrangementPanelInterface.positionAlignmentManipulator.duration = state.duration arrangementPanelInterface.positionAlignmentManipulator.tuplet = state.tuplet arrangementPanelInterface.autoPageScrollingManipulator.enabled = state.isAutoPageScrollingEnabled + for (let id of state.additionalTracks) { + d.addOn.additionalTrackLoader.loadItem(id) + } } function saveState() { @@ -33,7 +36,8 @@ QtObject { tool: arrangementPanelInterface.tool, duration: arrangementPanelInterface.positionAlignmentManipulator.duration, tuplet: arrangementPanelInterface.positionAlignmentManipulator.tuplet, - isAutoPageScrollingEnabled: arrangementPanelInterface.autoPageScrollingManipulator.enabled + isAutoPageScrollingEnabled: arrangementPanelInterface.autoPageScrollingManipulator.enabled, + additionalTracks: d.addOn.additionalTrackLoader.loadedComponents } } @@ -44,7 +48,7 @@ QtObject { header: ToolBarContainer { id: toolBar anchors.fill: parent - property ActionInstantiator instantiator: ActionInstantiator { + property MenuActionInstantiator instantiator: MenuActionInstantiator { actionId: "org.diffscope.visualeditor.arrangementPanelToolBar" context: d.addOn?.windowHandle.actionContext ?? null separatorComponent: ToolBarContainerSeparator { @@ -52,28 +56,6 @@ QtObject { stretchComponent: ToolBarContainerStretch { } Component.onCompleted: forceUpdateLayouts() - onObjectAdded: (index, object) => { - if (object instanceof Item) { - toolBar.insertItem(index, object) - } else if (object instanceof T.Action) { - toolBar.insertAction(index, object) - } else if (object instanceof T.Menu) { - toolBar.insertMenu(index, object) - } else { - toolBar.insertItem(index, dummyItem.createObject(this)) - } - } - onObjectRemoved: (index, object) => { - if (object instanceof Item) { - toolBar.removeItem(object) - } else if (object instanceof Action) { - toolBar.removeAction(object) - } else if (object instanceof Menu) { - toolBar.removeMenu(object) - } else { - toolBar.removeItem(target.itemAt(index)) - } - } } } data: [d.addOn?.arrangementPanelInterface.arrangementView ?? null] diff --git a/src/plugins/visualeditor/res/org.diffscope.visualeditor_actions.xml b/src/plugins/visualeditor/res/org.diffscope.visualeditor_actions.xml index df5b2172..c58f5d83 100644 --- a/src/plugins/visualeditor/res/org.diffscope.visualeditor_actions.xml +++ b/src/plugins/visualeditor/res/org.diffscope.visualeditor_actions.xml @@ -22,10 +22,17 @@ + + + + + + + @@ -41,6 +48,11 @@ + + + + + From 4448d19931e2d253a24dcbd7280b02b3fe1f1a17 Mon Sep 17 00:00:00 2001 From: CrSjimo Date: Wed, 26 Nov 2025 12:24:16 +0800 Subject: [PATCH 010/181] Fix bugs in ArrangementView --- src/plugins/visualeditor/qml/ArrangementView.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/visualeditor/qml/ArrangementView.qml b/src/plugins/visualeditor/qml/ArrangementView.qml index f42523fc..49ea4114 100644 --- a/src/plugins/visualeditor/qml/ArrangementView.qml +++ b/src/plugins/visualeditor/qml/ArrangementView.qml @@ -175,6 +175,7 @@ Item { } Item { SplitView.fillWidth: true + clip: true ColumnLayout { anchors.fill: parent spacing: 0 From 6f8f1fbda2d1d5c5d30e61e5017b61179a98845d Mon Sep 17 00:00:00 2001 From: CrSjimo Date: Fri, 28 Nov 2025 02:01:04 +0800 Subject: [PATCH 011/181] Add super-item getters in dspxmodel --- .../application/dspxmodel/src/AnchorNode.cpp | 29 ++++---- .../application/dspxmodel/src/AnchorNode.h | 8 +++ .../dspxmodel/src/AnchorNodeSequence.cpp | 23 +++++-- .../dspxmodel/src/AnchorNodeSequence.h | 6 +- .../dspxmodel/src/AnchorNodeSequence_p.h | 19 ++++++ .../application/dspxmodel/src/AnchorNode_p.h | 27 ++++++++ src/libs/application/dspxmodel/src/Clip.cpp | 51 ++++++-------- src/libs/application/dspxmodel/src/Clip.h | 13 ++-- .../dspxmodel/src/ClipSequence.cpp | 35 ++-------- .../application/dspxmodel/src/ClipSequence.h | 4 +- .../dspxmodel/src/ClipSequence_p.h | 19 ++++++ src/libs/application/dspxmodel/src/Clip_p.h | 27 ++++++++ .../dspxmodel/src/FreeValueDataArray.cpp | 13 +++- .../dspxmodel/src/FreeValueDataArray.h | 7 +- src/libs/application/dspxmodel/src/Label.cpp | 26 ++++---- src/libs/application/dspxmodel/src/Label.h | 5 ++ .../dspxmodel/src/LabelSequence.cpp | 12 ++-- .../dspxmodel/src/LabelSequence_p.h | 17 +++++ src/libs/application/dspxmodel/src/Label_p.h | 24 +++++++ src/libs/application/dspxmodel/src/Model_p.h | 6 ++ src/libs/application/dspxmodel/src/Note.cpp | 66 ++++++------------- src/libs/application/dspxmodel/src/Note.h | 11 ++-- .../dspxmodel/src/NoteSequence.cpp | 34 ++-------- .../application/dspxmodel/src/NoteSequence.h | 4 +- .../dspxmodel/src/NoteSequence_p.h | 19 ++++++ src/libs/application/dspxmodel/src/Note_p.h | 42 ++++++++++++ src/libs/application/dspxmodel/src/Param.cpp | 30 +++++---- src/libs/application/dspxmodel/src/Param.h | 7 ++ .../application/dspxmodel/src/ParamCurve.cpp | 24 ++++--- .../application/dspxmodel/src/ParamCurve.h | 5 ++ .../dspxmodel/src/ParamCurveAnchor.cpp | 2 +- .../dspxmodel/src/ParamCurveFree.cpp | 2 +- .../dspxmodel/src/ParamCurveSequence.cpp | 21 ++++-- .../dspxmodel/src/ParamCurveSequence.h | 6 +- .../dspxmodel/src/ParamCurveSequence_p.h | 19 ++++++ .../application/dspxmodel/src/ParamCurve_p.h | 25 +++++++ .../application/dspxmodel/src/ParamMap.cpp | 18 ++++- src/libs/application/dspxmodel/src/ParamMap.h | 6 +- src/libs/application/dspxmodel/src/Param_p.h | 26 ++++++++ .../application/dspxmodel/src/Phoneme.cpp | 26 +++++--- src/libs/application/dspxmodel/src/Phoneme.h | 5 ++ .../application/dspxmodel/src/PhonemeInfo.cpp | 29 ++++---- .../application/dspxmodel/src/PhonemeInfo.h | 9 ++- .../application/dspxmodel/src/PhonemeInfo_p.h | 25 +++++++ .../application/dspxmodel/src/PhonemeList.cpp | 21 ++++-- .../application/dspxmodel/src/PhonemeList.h | 6 +- .../application/dspxmodel/src/PhonemeList_p.h | 19 ++++++ .../application/dspxmodel/src/Phoneme_p.h | 32 +++++++++ .../application/dspxmodel/src/SingingClip.cpp | 5 +- src/libs/application/dspxmodel/src/Tempo.cpp | 29 ++++---- src/libs/application/dspxmodel/src/Tempo.h | 5 ++ .../dspxmodel/src/TempoSequence.cpp | 12 ++-- .../dspxmodel/src/TempoSequence_p.h | 17 +++++ src/libs/application/dspxmodel/src/Tempo_p.h | 26 ++++++++ .../dspxmodel/src/TimeSignature.cpp | 37 +++++------ .../application/dspxmodel/src/TimeSignature.h | 5 ++ .../dspxmodel/src/TimeSignatureSequence.cpp | 12 ++-- .../dspxmodel/src/TimeSignatureSequence_p.h | 17 +++++ .../dspxmodel/src/TimeSignature_p.h | 29 ++++++++ src/libs/application/dspxmodel/src/Track.cpp | 34 +++++----- src/libs/application/dspxmodel/src/Track.h | 6 ++ .../application/dspxmodel/src/TrackList.cpp | 7 ++ src/libs/application/dspxmodel/src/Track_p.h | 24 +++++++ 63 files changed, 856 insertions(+), 319 deletions(-) create mode 100644 src/libs/application/dspxmodel/src/AnchorNodeSequence_p.h create mode 100644 src/libs/application/dspxmodel/src/AnchorNode_p.h create mode 100644 src/libs/application/dspxmodel/src/ClipSequence_p.h create mode 100644 src/libs/application/dspxmodel/src/Clip_p.h create mode 100644 src/libs/application/dspxmodel/src/LabelSequence_p.h create mode 100644 src/libs/application/dspxmodel/src/Label_p.h create mode 100644 src/libs/application/dspxmodel/src/NoteSequence_p.h create mode 100644 src/libs/application/dspxmodel/src/Note_p.h create mode 100644 src/libs/application/dspxmodel/src/ParamCurveSequence_p.h create mode 100644 src/libs/application/dspxmodel/src/ParamCurve_p.h create mode 100644 src/libs/application/dspxmodel/src/Param_p.h create mode 100644 src/libs/application/dspxmodel/src/PhonemeInfo_p.h create mode 100644 src/libs/application/dspxmodel/src/PhonemeList_p.h create mode 100644 src/libs/application/dspxmodel/src/Phoneme_p.h create mode 100644 src/libs/application/dspxmodel/src/TempoSequence_p.h create mode 100644 src/libs/application/dspxmodel/src/Tempo_p.h create mode 100644 src/libs/application/dspxmodel/src/TimeSignatureSequence_p.h create mode 100644 src/libs/application/dspxmodel/src/TimeSignature_p.h create mode 100644 src/libs/application/dspxmodel/src/Track_p.h diff --git a/src/libs/application/dspxmodel/src/AnchorNode.cpp b/src/libs/application/dspxmodel/src/AnchorNode.cpp index def64001..22eaba9f 100644 --- a/src/libs/application/dspxmodel/src/AnchorNode.cpp +++ b/src/libs/application/dspxmodel/src/AnchorNode.cpp @@ -1,29 +1,17 @@ #include "AnchorNode.h" +#include "AnchorNode_p.h" #include #include #include +#include #include #include namespace dspx { - class AnchorNodePrivate { - Q_DECLARE_PUBLIC(AnchorNode) - public: - AnchorNode *q_ptr; - AnchorNode::InterpolationMode interp; - int x; - int y; - - void setInterpUnchecked(AnchorNode::InterpolationMode interp_); - void setInterp(AnchorNode::InterpolationMode interp_); - void setXUnchecked(int x_); - void setX(int x_); - }; - void AnchorNodePrivate::setInterpUnchecked(AnchorNode::InterpolationMode interp_) { Q_Q(AnchorNode); q->model()->strategy()->setEntityProperty(q->handle(), ModelStrategy::P_Type, QVariant::fromValue(interp_)); @@ -52,6 +40,14 @@ namespace dspx { setXUnchecked(x_); } + void AnchorNodePrivate::setAnchorNodeSequence(AnchorNode *item, AnchorNodeSequence *anchorNodeSequence) { + auto d = item->d_func(); + if (d->anchorNodeSequence != anchorNodeSequence) { + d->anchorNodeSequence = anchorNodeSequence; + Q_EMIT item->anchorNodeSequenceChanged(); + } + } + AnchorNode::AnchorNode(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new AnchorNodePrivate) { Q_D(AnchorNode); @@ -112,6 +108,11 @@ namespace dspx { setY(node.y); } + AnchorNodeSequence *AnchorNode::anchorNodeSequence() const { + Q_D(const AnchorNode); + return d->anchorNodeSequence; + } + void AnchorNode::handleSetEntityProperty(int property, const QVariant &value) { Q_D(AnchorNode); switch (property) { diff --git a/src/libs/application/dspxmodel/src/AnchorNode.h b/src/libs/application/dspxmodel/src/AnchorNode.h index 7f7c7826..4eaef0e8 100644 --- a/src/libs/application/dspxmodel/src/AnchorNode.h +++ b/src/libs/application/dspxmodel/src/AnchorNode.h @@ -11,6 +11,10 @@ namespace QDspx { namespace dspx { + class AnchorNodeSequence; + + class AnchorNodeSequencePrivate; + class AnchorNodePrivate; class DSPX_MODEL_EXPORT AnchorNode : public EntityObject { @@ -21,6 +25,7 @@ namespace dspx { Q_PRIVATE_PROPERTY(d_func(), InterpolationMode interp MEMBER interp WRITE setInterp NOTIFY interpChanged) Q_PRIVATE_PROPERTY(d_func(), int x MEMBER x WRITE setX NOTIFY xChanged) Q_PROPERTY(int y READ y WRITE setY NOTIFY yChanged) + Q_PROPERTY(AnchorNodeSequence *anchorNodeSequence READ anchorNodeSequence NOTIFY anchorNodeSequenceChanged) public: enum InterpolationMode { @@ -44,10 +49,13 @@ namespace dspx { QDspx::AnchorNode toQDspx() const; void fromQDspx(const QDspx::AnchorNode &node); + AnchorNodeSequence *anchorNodeSequence() const; + Q_SIGNALS: void interpChanged(InterpolationMode interp); void xChanged(int x); void yChanged(int y); + void anchorNodeSequenceChanged(); protected: void handleSetEntityProperty(int property, const QVariant &value) override; diff --git a/src/libs/application/dspxmodel/src/AnchorNodeSequence.cpp b/src/libs/application/dspxmodel/src/AnchorNodeSequence.cpp index 2544e95e..7c14003c 100644 --- a/src/libs/application/dspxmodel/src/AnchorNodeSequence.cpp +++ b/src/libs/application/dspxmodel/src/AnchorNodeSequence.cpp @@ -1,4 +1,5 @@ #include "AnchorNodeSequence.h" +#include "AnchorNodeSequence_p.h" #include #include @@ -7,21 +8,24 @@ #include #include +#include #include -#include #include namespace dspx { - class AnchorNodeSequencePrivate : public PointSequenceData { - Q_DECLARE_PUBLIC(AnchorNodeSequence) - }; - - AnchorNodeSequence::AnchorNodeSequence(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new AnchorNodeSequencePrivate) { + AnchorNodeSequence::AnchorNodeSequence(ParamCurveAnchor *paramCurveAnchor, Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new AnchorNodeSequencePrivate) { Q_D(AnchorNodeSequence); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::ES_ParamCurveAnchorNodes); d->q_ptr = this; d->pModel = ModelPrivate::get(model); + d->paramCurveAnchor = paramCurveAnchor; + connect(this, &AnchorNodeSequence::itemInserted, this, [=](AnchorNode *item) { + AnchorNodePrivate::setAnchorNodeSequence(item, this); + }); + connect(this, &AnchorNodeSequence::itemRemoved, this, [=](AnchorNode *item) { + AnchorNodePrivate::setAnchorNodeSequence(item, nullptr); + }); } AnchorNodeSequence::~AnchorNodeSequence() = default; @@ -102,6 +106,13 @@ namespace dspx { d->handleTakeFromSequenceContainer(takenEntity, entity); } + ParamCurveAnchor *AnchorNodeSequence::paramCurveAnchor() const { + Q_D(const AnchorNodeSequence); + return d->paramCurveAnchor; + } + + + } #include "moc_AnchorNodeSequence.cpp" diff --git a/src/libs/application/dspxmodel/src/AnchorNodeSequence.h b/src/libs/application/dspxmodel/src/AnchorNodeSequence.h index adcf4727..b7976e06 100644 --- a/src/libs/application/dspxmodel/src/AnchorNodeSequence.h +++ b/src/libs/application/dspxmodel/src/AnchorNodeSequence.h @@ -12,6 +12,7 @@ namespace QDspx { namespace dspx { class AnchorNode; + class ParamCurveAnchor; class AnchorNodeSequencePrivate; @@ -23,6 +24,7 @@ namespace dspx { Q_PROPERTY(int size READ size NOTIFY sizeChanged) Q_PROPERTY(AnchorNode *firstItem READ firstItem NOTIFY firstItemChanged) Q_PROPERTY(AnchorNode *lastItem READ lastItem NOTIFY lastItemChanged) + Q_PROPERTY(ParamCurveAnchor *paramCurveAnchor READ paramCurveAnchor CONSTANT) Q_PRIVATE_PROPERTY(d_func(), QJSValue iterable READ iterable CONSTANT) public: ~AnchorNodeSequence() override; @@ -41,6 +43,8 @@ namespace dspx { QList toQDspx() const; void fromQDspx(const QList &nodes); + ParamCurveAnchor *paramCurveAnchor() const; + Q_SIGNALS: void itemAboutToInsert(AnchorNode *item); void itemInserted(AnchorNode *item); @@ -56,7 +60,7 @@ namespace dspx { private: friend class ModelPrivate; - explicit AnchorNodeSequence(Handle handle, Model *model); + explicit AnchorNodeSequence(ParamCurveAnchor *paramCurveAnchor, Handle handle, Model *model); QScopedPointer d_ptr; }; diff --git a/src/libs/application/dspxmodel/src/AnchorNodeSequence_p.h b/src/libs/application/dspxmodel/src/AnchorNodeSequence_p.h new file mode 100644 index 00000000..8b27bf67 --- /dev/null +++ b/src/libs/application/dspxmodel/src/AnchorNodeSequence_p.h @@ -0,0 +1,19 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_ANCHORNODESEQUENCE_P_H +#define DIFFSCOPE_DSPX_MODEL_ANCHORNODESEQUENCE_P_H + +#include + +#include +#include + +namespace dspx { + + class AnchorNodeSequencePrivate : public PointSequenceData { + Q_DECLARE_PUBLIC(AnchorNodeSequence) + public: + ParamCurveAnchor *paramCurveAnchor{}; + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_ANCHORNODESEQUENCE_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/AnchorNode_p.h b/src/libs/application/dspxmodel/src/AnchorNode_p.h new file mode 100644 index 00000000..3b2704b6 --- /dev/null +++ b/src/libs/application/dspxmodel/src/AnchorNode_p.h @@ -0,0 +1,27 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_ANCHORNODE_P_H +#define DIFFSCOPE_DSPX_MODEL_ANCHORNODE_P_H + +#include + +namespace dspx { + + class AnchorNodePrivate { + Q_DECLARE_PUBLIC(AnchorNode) + public: + AnchorNode *q_ptr; + AnchorNode::InterpolationMode interp; + int x; + int y; + AnchorNodeSequence *anchorNodeSequence{}; + + void setInterpUnchecked(AnchorNode::InterpolationMode interp_); + void setInterp(AnchorNode::InterpolationMode interp_); + void setXUnchecked(int x_); + void setX(int x_); + + static void setAnchorNodeSequence(AnchorNode *item, AnchorNodeSequence *anchorNodeSequence); + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_ANCHORNODE_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/Clip.cpp b/src/libs/application/dspxmodel/src/Clip.cpp index 5014cf63..4caf4492 100644 --- a/src/libs/application/dspxmodel/src/Clip.cpp +++ b/src/libs/application/dspxmodel/src/Clip.cpp @@ -1,4 +1,5 @@ #include "Clip.h" +#include "Clip_p.h" #include #include @@ -9,25 +10,27 @@ #include #include #include -#include +#include #include #include namespace dspx { - class ClipPrivate { - Q_DECLARE_PUBLIC(Clip) - public: - Clip *q_ptr; - ModelPrivate *pModel; - QString name; - BusControl *control; - ClipTime *time; - Clip::ClipType type; - Track *track{}; - Workspace *workspace; - bool overlapped{}; - }; + void ClipPrivate::setOverlapped(Clip *item, bool overlapped) { + auto d = item->d_func(); + if (d->overlapped != overlapped) { + d->overlapped = overlapped; + Q_EMIT item->overlappedChanged(overlapped); + } + } + + void ClipPrivate::setClipSequence(Clip *item, ClipSequence *clipSequence) { + auto d = item->d_func(); + if (d->clipSequence != clipSequence) { + d->clipSequence = clipSequence; + Q_EMIT item->clipSequenceChanged(); + } + } Clip::Clip(ClipType type, Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new ClipPrivate) { Q_D(Clip); @@ -107,9 +110,9 @@ namespace dspx { } } - Track *Clip::track() const { + ClipSequence *Clip::clipSequence() const { Q_D(const Clip); - return d->track; + return d->clipSequence; } int Clip::position() const { @@ -127,22 +130,6 @@ namespace dspx { return d->overlapped; } - void Clip::setOverlapped(bool overlapped) { - Q_D(Clip); - if (d->overlapped != overlapped) { - d->overlapped = overlapped; - Q_EMIT overlappedChanged(overlapped); - } - } - - void Clip::setTrack(Track *track) { - Q_D(Clip); - if (d->track != track) { - d->track = track; - Q_EMIT trackChanged(); - } - } - void Clip::handleSetEntityProperty(int property, const QVariant &value) { Q_D(Clip); switch (property) { diff --git a/src/libs/application/dspxmodel/src/Clip.h b/src/libs/application/dspxmodel/src/Clip.h index 5dbbcb69..c35024e9 100644 --- a/src/libs/application/dspxmodel/src/Clip.h +++ b/src/libs/application/dspxmodel/src/Clip.h @@ -15,9 +15,7 @@ namespace dspx { class BusControl; class ClipTime; class Workspace; - class Track; - - class ClipSequencePrivate; + class ClipSequence; class ClipPrivate; @@ -31,7 +29,7 @@ namespace dspx { Q_PROPERTY(ClipTime *time READ time CONSTANT) Q_PROPERTY(ClipType type READ type CONSTANT) Q_PROPERTY(Workspace *workspace READ workspace CONSTANT) - Q_PROPERTY(Track *track READ track NOTIFY trackChanged) + Q_PROPERTY(ClipSequence *clipSequence READ clipSequence NOTIFY clipSequenceChanged) Q_PROPERTY(bool overlapped READ isOverlapped NOTIFY overlappedChanged) public: enum ClipType { @@ -56,7 +54,7 @@ namespace dspx { QDspx::ClipRef toQDspx() const; void fromQDspx(const QDspx::ClipRef &clip); - Track *track() const; + ClipSequence *clipSequence() const; int position() const; @@ -66,7 +64,7 @@ namespace dspx { Q_SIGNALS: void nameChanged(const QString &name); - void trackChanged(); + void clipSequenceChanged(); void positionChanged(int position); void lengthChanged(int length); void overlappedChanged(bool overlapped); @@ -76,10 +74,7 @@ namespace dspx { void handleSetEntityProperty(int property, const QVariant &value) override; private: - friend class ClipSequencePrivate; QScopedPointer d_ptr; - void setTrack(Track *track); - void setOverlapped(bool overlapped); }; } // dspx diff --git a/src/libs/application/dspxmodel/src/ClipSequence.cpp b/src/libs/application/dspxmodel/src/ClipSequence.cpp index ddc52650..440dfa0a 100644 --- a/src/libs/application/dspxmodel/src/ClipSequence.cpp +++ b/src/libs/application/dspxmodel/src/ClipSequence.cpp @@ -1,4 +1,5 @@ #include "ClipSequence.h" +#include "ClipSequence_p.h" #include #include @@ -11,42 +12,21 @@ #include #include #include -#include -#include #include -#include -#include namespace dspx { - static void setClipOverlapped(Clip *item, bool overlapped); - - class ClipSequencePrivate : public RangeSequenceData { - Q_DECLARE_PUBLIC(ClipSequence) - public: - Track *track{}; - static void setOverlapped(Clip *item, bool overlapped) { - item->setOverlapped(overlapped); - } - static void setTrack(Clip *item, Track *track) { - item->setTrack(track); - } - }; - - void setClipOverlapped(Clip *item, bool overlapped) { - ClipSequencePrivate::setOverlapped(item, overlapped); - } - - ClipSequence::ClipSequence(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new ClipSequencePrivate) { + ClipSequence::ClipSequence(Track *track, Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new ClipSequencePrivate) { Q_D(ClipSequence); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::ES_Clips); d->q_ptr = this; d->pModel = ModelPrivate::get(model); + d->track = track; connect(this, &ClipSequence::itemInserted, this, [=](Clip *item) { - ClipSequencePrivate::setTrack(item, d->track); + ClipPrivate::setClipSequence(item, this); }); connect(this, &ClipSequence::itemRemoved, this, [=](Clip *item) { - ClipSequencePrivate::setTrack(item, nullptr); + ClipPrivate::setClipSequence(item, nullptr); }); } @@ -133,11 +113,6 @@ namespace dspx { } } - void ClipSequence::setTrack(Track *track) { - Q_D(ClipSequence); - d->track = track; - } - void ClipSequence::handleInsertIntoSequenceContainer(Handle entity) { Q_D(ClipSequence); d->handleInsertIntoSequenceContainer(entity); diff --git a/src/libs/application/dspxmodel/src/ClipSequence.h b/src/libs/application/dspxmodel/src/ClipSequence.h index bbd14f69..49a30619 100644 --- a/src/libs/application/dspxmodel/src/ClipSequence.h +++ b/src/libs/application/dspxmodel/src/ClipSequence.h @@ -61,9 +61,7 @@ namespace dspx { private: friend class ModelPrivate; - friend class Track; - explicit ClipSequence(Handle handle, Model *model); - void setTrack(Track *track); + explicit ClipSequence(Track *track, Handle handle, Model *model); QScopedPointer d_ptr; }; diff --git a/src/libs/application/dspxmodel/src/ClipSequence_p.h b/src/libs/application/dspxmodel/src/ClipSequence_p.h new file mode 100644 index 00000000..b6c27acb --- /dev/null +++ b/src/libs/application/dspxmodel/src/ClipSequence_p.h @@ -0,0 +1,19 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_CLIPSEQUENCE_P_H +#define DIFFSCOPE_DSPX_MODEL_CLIPSEQUENCE_P_H + +#include + +#include +#include + +namespace dspx { + + class ClipSequencePrivate : public RangeSequenceData { + Q_DECLARE_PUBLIC(ClipSequence) + public: + Track *track{}; + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_CLIPSEQUENCE_P_H diff --git a/src/libs/application/dspxmodel/src/Clip_p.h b/src/libs/application/dspxmodel/src/Clip_p.h new file mode 100644 index 00000000..e3a3c02c --- /dev/null +++ b/src/libs/application/dspxmodel/src/Clip_p.h @@ -0,0 +1,27 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_CLIP_P_H +#define DIFFSCOPE_DSPX_MODEL_CLIP_P_H + +#include + +namespace dspx { + + class ClipPrivate { + Q_DECLARE_PUBLIC(Clip) + public: + Clip *q_ptr; + ModelPrivate *pModel; + QString name; + BusControl *control; + ClipTime *time; + Clip::ClipType type; + ClipSequence *clipSequence{}; + Workspace *workspace; + bool overlapped{}; + + static void setOverlapped(Clip *item, bool overlapped); + static void setClipSequence(Clip *item, ClipSequence *clipSequence); + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_CLIP_P_H diff --git a/src/libs/application/dspxmodel/src/FreeValueDataArray.cpp b/src/libs/application/dspxmodel/src/FreeValueDataArray.cpp index 8c65fcb8..c4346561 100644 --- a/src/libs/application/dspxmodel/src/FreeValueDataArray.cpp +++ b/src/libs/application/dspxmodel/src/FreeValueDataArray.cpp @@ -1,19 +1,23 @@ #include "FreeValueDataArray.h" #include +#include #include namespace dspx { class FreeValueDataArrayPrivate : public DataArrayData { Q_DECLARE_PUBLIC(FreeValueDataArray) + public: + ParamCurveFree *paramCurveFree{}; }; - FreeValueDataArray::FreeValueDataArray(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new FreeValueDataArrayPrivate) { + FreeValueDataArray::FreeValueDataArray(ParamCurveFree *paramCurveFree, Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new FreeValueDataArrayPrivate) { Q_D(FreeValueDataArray); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::ED_ParamCurveFreeValues); d->q_ptr = this; d->pModel = ModelPrivate::get(model); + d->paramCurveFree = paramCurveFree; } FreeValueDataArray::~FreeValueDataArray() = default; @@ -65,6 +69,13 @@ namespace dspx { d->handleRotateDataArray(leftIndex, middleIndex, rightIndex); } + ParamCurveFree *FreeValueDataArray::paramCurveFree() const { + Q_D(const FreeValueDataArray); + return d->paramCurveFree; + } + + + } #include "moc_FreeValueDataArray.cpp" diff --git a/src/libs/application/dspxmodel/src/FreeValueDataArray.h b/src/libs/application/dspxmodel/src/FreeValueDataArray.h index f3dd0284..2c9a263a 100644 --- a/src/libs/application/dspxmodel/src/FreeValueDataArray.h +++ b/src/libs/application/dspxmodel/src/FreeValueDataArray.h @@ -7,6 +7,8 @@ namespace dspx { + class ParamCurveFree; + class FreeValueDataArrayPrivate; class DSPX_MODEL_EXPORT FreeValueDataArray : public EntityObject { @@ -15,6 +17,7 @@ namespace dspx { QML_UNCREATABLE("") Q_DECLARE_PRIVATE(FreeValueDataArray) Q_PROPERTY(int size READ size NOTIFY sizeChanged) + Q_PROPERTY(ParamCurveFree *paramCurveFree READ paramCurveFree CONSTANT) Q_PRIVATE_PROPERTY(d_func(), QJSValue iterable READ iterable CONSTANT) public: @@ -28,6 +31,8 @@ namespace dspx { QList toQDspx() const; void fromQDspx(const QList &values); + ParamCurveFree *paramCurveFree() const; + Q_SIGNALS: void sizeChanged(int size); void aboutToSplice(int index, int length, const QList &values); @@ -41,7 +46,7 @@ namespace dspx { private: friend class ModelPrivate; - explicit FreeValueDataArray(Handle handle, Model *model); + explicit FreeValueDataArray(ParamCurveFree *paramCurveFree, Handle handle, Model *model); QScopedPointer d_ptr; }; diff --git a/src/libs/application/dspxmodel/src/Label.cpp b/src/libs/application/dspxmodel/src/Label.cpp index c4b86312..7fdfecfe 100644 --- a/src/libs/application/dspxmodel/src/Label.cpp +++ b/src/libs/application/dspxmodel/src/Label.cpp @@ -1,26 +1,17 @@ #include "Label.h" +#include "Label_p.h" #include #include #include +#include #include #include namespace dspx { - class LabelPrivate { - Q_DECLARE_PUBLIC(Label) - public: - Label *q_ptr; - int pos; - QString text; - - void setPosUnchecked(int pos_); - void setPos(int pos_); - }; - void LabelPrivate::setPosUnchecked(int pos_) { Q_Q(Label); q->model()->strategy()->setEntityProperty(q->handle(), ModelStrategy::P_Position, pos_); @@ -35,6 +26,14 @@ namespace dspx { setPosUnchecked(pos_); } + void LabelPrivate::setLabelSequence(Label *item, LabelSequence *labelSequence) { + auto d = item->d_func(); + if (d->labelSequence != labelSequence) { + d->labelSequence = labelSequence; + Q_EMIT item->labelSequenceChanged(); + } + } + Label::Label(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new LabelPrivate) { Q_D(Label); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::EI_Label); @@ -66,6 +65,11 @@ namespace dspx { model()->strategy()->setEntityProperty(handle(), ModelStrategy::P_Text, text); } + LabelSequence *Label::labelSequence() const { + Q_D(const Label); + return d->labelSequence; + } + QDspx::Label Label::toQDspx() const { return { .pos = pos(), diff --git a/src/libs/application/dspxmodel/src/Label.h b/src/libs/application/dspxmodel/src/Label.h index a5b5cf8b..dd21eb3f 100644 --- a/src/libs/application/dspxmodel/src/Label.h +++ b/src/libs/application/dspxmodel/src/Label.h @@ -11,6 +11,7 @@ namespace QDspx { namespace dspx { + class LabelSequence; class LabelPrivate; class DSPX_MODEL_EXPORT Label : public EntityObject { @@ -20,6 +21,7 @@ namespace dspx { Q_DECLARE_PRIVATE(Label); Q_PRIVATE_PROPERTY(d_func(), int pos MEMBER pos WRITE setPos NOTIFY posChanged) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) + Q_PROPERTY(LabelSequence *labelSequence READ labelSequence NOTIFY labelSequenceChanged) public: ~Label() override; @@ -29,12 +31,15 @@ namespace dspx { QString text() const; void setText(const QString &text); + LabelSequence *labelSequence() const; + QDspx::Label toQDspx() const; void fromQDspx(const QDspx::Label &label); Q_SIGNALS: void posChanged(int pos); void textChanged(const QString &text); + void labelSequenceChanged(); protected: void handleSetEntityProperty(int property, const QVariant &value) override; diff --git a/src/libs/application/dspxmodel/src/LabelSequence.cpp b/src/libs/application/dspxmodel/src/LabelSequence.cpp index 27e6e19c..13e39f86 100644 --- a/src/libs/application/dspxmodel/src/LabelSequence.cpp +++ b/src/libs/application/dspxmodel/src/LabelSequence.cpp @@ -1,4 +1,5 @@ #include "LabelSequence.h" +#include "LabelSequence_p.h" #include #include @@ -8,20 +9,21 @@ #include #include #include -#include #include namespace dspx { - class LabelSequencePrivate : public PointSequenceData { - Q_DECLARE_PUBLIC(LabelSequence) - }; - LabelSequence::LabelSequence(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new LabelSequencePrivate) { Q_D(LabelSequence); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::ES_Labels); d->q_ptr = this; d->pModel = ModelPrivate::get(model); + connect(this, &LabelSequence::itemInserted, this, [=](Label *item) { + LabelPrivate::setLabelSequence(item, this); + }); + connect(this, &LabelSequence::itemRemoved, this, [=](Label *item) { + LabelPrivate::setLabelSequence(item, nullptr); + }); } LabelSequence::~LabelSequence() = default; diff --git a/src/libs/application/dspxmodel/src/LabelSequence_p.h b/src/libs/application/dspxmodel/src/LabelSequence_p.h new file mode 100644 index 00000000..fe03ee4a --- /dev/null +++ b/src/libs/application/dspxmodel/src/LabelSequence_p.h @@ -0,0 +1,17 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_LABELSEQUENCE_P_H +#define DIFFSCOPE_DSPX_MODEL_LABELSEQUENCE_P_H + +#include + +#include +#include + +namespace dspx { + + class LabelSequencePrivate : public PointSequenceData { + Q_DECLARE_PUBLIC(LabelSequence) + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_LABELSEQUENCE_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/Label_p.h b/src/libs/application/dspxmodel/src/Label_p.h new file mode 100644 index 00000000..0ef4b5b3 --- /dev/null +++ b/src/libs/application/dspxmodel/src/Label_p.h @@ -0,0 +1,24 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_LABEL_P_H +#define DIFFSCOPE_DSPX_MODEL_LABEL_P_H + +#include + +namespace dspx { + + class LabelPrivate { + Q_DECLARE_PUBLIC(Label) + public: + Label *q_ptr; + int pos; + QString text; + LabelSequence *labelSequence{}; + + void setPosUnchecked(int pos_); + void setPos(int pos_); + + static void setLabelSequence(Label *item, LabelSequence *labelSequence); + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_LABEL_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/Model_p.h b/src/libs/application/dspxmodel/src/Model_p.h index 56b8448e..607e5333 100644 --- a/src/libs/application/dspxmodel/src/Model_p.h +++ b/src/libs/application/dspxmodel/src/Model_p.h @@ -49,6 +49,12 @@ namespace dspx { EntityObject *mapToObject(Handle handle) const; Handle mapToHandle(EntityObject *object) const; + template + T *createObject(S *superItem, Handle handle) { + Q_Q(Model); + return new T(superItem, handle, q); + } + template T *createObject(Handle handle) { Q_Q(Model); diff --git a/src/libs/application/dspxmodel/src/Note.cpp b/src/libs/application/dspxmodel/src/Note.cpp index 9f127f29..9888c90c 100644 --- a/src/libs/application/dspxmodel/src/Note.cpp +++ b/src/libs/application/dspxmodel/src/Note.cpp @@ -1,4 +1,5 @@ #include "Note.h" +#include "Note_p.h" #include #include @@ -8,42 +9,13 @@ #include #include #include -#include +#include #include #include #include namespace dspx { - class NotePrivate { - Q_DECLARE_PUBLIC(Note) - public: - Note *q_ptr; - ModelPrivate *pModel; - - int centShift; - int keyNum; - QString language; - int length; - QString lyric; - PhonemeInfo *phonemes; - int pos; - Pronunciation *pronunciation; - Vibrato *vibrato; - Workspace *workspace; - SingingClip *singingClip{}; - bool overlapped{}; - - void setCentShiftUnchecked(int centShift_); - void setCentShift(int centShift_); - void setKeyNumUnchecked(int keyNum_); - void setKeyNum(int keyNum_); - void setLengthUnchecked(int length_); - void setLength(int length_); - void setPosUnchecked(int pos_); - void setPos(int pos_); - }; - void NotePrivate::setCentShiftUnchecked(int centShift_) { Q_Q(Note); pModel->strategy->setEntityProperty(q->handle(), ModelStrategy::P_CentShift, centShift_); @@ -100,6 +72,22 @@ namespace dspx { setPosUnchecked(pos_); } + void NotePrivate::setOverlapped(Note *item, bool overlapped) { + auto d = item->d_func(); + if (d->overlapped != overlapped) { + d->overlapped = overlapped; + Q_EMIT item->overlappedChanged(overlapped); + } + } + + void NotePrivate::setNoteSequence(Note *item, NoteSequence *noteSequence) { + auto d = item->d_func(); + if (d->noteSequence != noteSequence) { + d->noteSequence = noteSequence; + Q_EMIT item->noteSequenceChanged(); + } + } + Note::Note(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new NotePrivate) { Q_D(Note); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::EI_Note); @@ -111,7 +99,7 @@ namespace dspx { d->length = d->pModel->strategy->getEntityProperty(handle, ModelStrategy::P_Length).toInt(); d->lyric = d->pModel->strategy->getEntityProperty(handle, ModelStrategy::P_Text).toString(); d->pos = d->pModel->strategy->getEntityProperty(handle, ModelStrategy::P_Position).toInt(); - d->phonemes = d->pModel->createObject(handle); + d->phonemes = d->pModel->createObject(this, handle); d->pronunciation = d->pModel->createObject(handle); d->vibrato = d->pModel->createObject(handle); d->workspace = d->pModel->createObject(d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Workspace)); @@ -203,9 +191,9 @@ namespace dspx { return d->workspace; } - SingingClip *Note::singingClip() const { + NoteSequence *Note::noteSequence() const { Q_D(const Note); - return d->singingClip; + return d->noteSequence; } bool Note::isOverlapped() const { @@ -293,18 +281,6 @@ namespace dspx { } } - void Note::setSingingClip(SingingClip *singingClip) { - Q_D(Note); - d->singingClip = singingClip; - Q_EMIT singingClipChanged(); - } - - void Note::setOverlapped(bool overlapped) { - Q_D(Note); - d->overlapped = overlapped; - Q_EMIT overlappedChanged(overlapped); - } - } #include "moc_Note.cpp" diff --git a/src/libs/application/dspxmodel/src/Note.h b/src/libs/application/dspxmodel/src/Note.h index 71fb896f..e96311d5 100644 --- a/src/libs/application/dspxmodel/src/Note.h +++ b/src/libs/application/dspxmodel/src/Note.h @@ -15,7 +15,7 @@ namespace dspx { class Pronunciation; class Vibrato; class Workspace; - class SingingClip; + class NoteSequence; class NoteSequencePrivate; @@ -36,7 +36,7 @@ namespace dspx { Q_PROPERTY(Pronunciation *pronunciation READ pronunciation CONSTANT) Q_PROPERTY(Vibrato *vibrato READ vibrato CONSTANT) Q_PROPERTY(Workspace *workspace READ workspace CONSTANT) - Q_PROPERTY(SingingClip *singingClip READ singingClip NOTIFY singingClipChanged) + Q_PROPERTY(NoteSequence *noteSequence READ noteSequence NOTIFY noteSequenceChanged) Q_PROPERTY(bool overlapped READ isOverlapped NOTIFY overlappedChanged) public: @@ -68,7 +68,7 @@ namespace dspx { Workspace *workspace() const; - SingingClip *singingClip() const; + NoteSequence *noteSequence() const; bool isOverlapped() const; @@ -82,7 +82,7 @@ namespace dspx { void lengthChanged(int length); void lyricChanged(const QString &lyric); void posChanged(int pos); - void singingClipChanged(); + void noteSequenceChanged(); void overlappedChanged(bool overlapped); protected: @@ -90,11 +90,8 @@ namespace dspx { private: friend class ModelPrivate; - friend class NoteSequencePrivate; explicit Note(Handle handle, Model *model); QScopedPointer d_ptr; - void setSingingClip(SingingClip *singingClip); - void setOverlapped(bool overlapped); }; } diff --git a/src/libs/application/dspxmodel/src/NoteSequence.cpp b/src/libs/application/dspxmodel/src/NoteSequence.cpp index 8aed6974..387ca3d2 100644 --- a/src/libs/application/dspxmodel/src/NoteSequence.cpp +++ b/src/libs/application/dspxmodel/src/NoteSequence.cpp @@ -1,4 +1,5 @@ #include "NoteSequence.h" +#include "NoteSequence_p.h" #include #include @@ -9,41 +10,21 @@ #include #include #include -#include #include -#include -#include namespace dspx { - static void setNoteOverlapped(Note *item, bool overlapped); - - class NoteSequencePrivate : public RangeSequenceData { - Q_DECLARE_PUBLIC(NoteSequence) - public: - SingingClip *singingClip{}; - static void setOverlapped(Note *item, bool overlapped) { - item->setOverlapped(overlapped); - } - static void setSingingClip(Note *item, SingingClip *singingClip) { - item->setSingingClip(singingClip); - } - }; - - void setNoteOverlapped(Note *item, bool overlapped) { - NoteSequencePrivate::setOverlapped(item, overlapped); - } - - NoteSequence::NoteSequence(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new NoteSequencePrivate) { + NoteSequence::NoteSequence(SingingClip *singingClip, Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new NoteSequencePrivate) { Q_D(NoteSequence); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::ES_Notes); d->q_ptr = this; d->pModel = ModelPrivate::get(model); + d->singingClip = singingClip; connect(this, &NoteSequence::itemInserted, this, [=](Note *item) { - NoteSequencePrivate::setSingingClip(item, d->singingClip); + NotePrivate::setNoteSequence(item, this); }); connect(this, &NoteSequence::itemRemoved, this, [=](Note *item) { - NoteSequencePrivate::setSingingClip(item, nullptr); + NotePrivate::setNoteSequence(item, nullptr); }); } @@ -119,11 +100,6 @@ namespace dspx { } } - void NoteSequence::setSingingClip(SingingClip *singingClip) { - Q_D(NoteSequence); - d->singingClip = singingClip; - } - void NoteSequence::handleInsertIntoSequenceContainer(Handle entity) { Q_D(NoteSequence); d->handleInsertIntoSequenceContainer(entity); diff --git a/src/libs/application/dspxmodel/src/NoteSequence.h b/src/libs/application/dspxmodel/src/NoteSequence.h index 65cb4948..7bcb911b 100644 --- a/src/libs/application/dspxmodel/src/NoteSequence.h +++ b/src/libs/application/dspxmodel/src/NoteSequence.h @@ -61,9 +61,7 @@ namespace dspx { private: friend class ModelPrivate; - friend class SingingClip; - explicit NoteSequence(Handle handle, Model *model); - void setSingingClip(SingingClip *singingClip); + explicit NoteSequence(SingingClip *singingClip, Handle handle, Model *model); QScopedPointer d_ptr; }; diff --git a/src/libs/application/dspxmodel/src/NoteSequence_p.h b/src/libs/application/dspxmodel/src/NoteSequence_p.h new file mode 100644 index 00000000..950ff19b --- /dev/null +++ b/src/libs/application/dspxmodel/src/NoteSequence_p.h @@ -0,0 +1,19 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_NOTESEQUENCE_P_H +#define DIFFSCOPE_DSPX_MODEL_NOTESEQUENCE_P_H + +#include + +#include +#include + +namespace dspx { + + class NoteSequencePrivate : public RangeSequenceData { + Q_DECLARE_PUBLIC(NoteSequence) + public: + SingingClip *singingClip{}; + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_NOTESEQUENCE_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/Note_p.h b/src/libs/application/dspxmodel/src/Note_p.h new file mode 100644 index 00000000..c6a70912 --- /dev/null +++ b/src/libs/application/dspxmodel/src/Note_p.h @@ -0,0 +1,42 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_NOTE_P_H +#define DIFFSCOPE_DSPX_MODEL_NOTE_P_H + +#include + +namespace dspx { + + class NotePrivate { + Q_DECLARE_PUBLIC(Note) + public: + Note *q_ptr; + ModelPrivate *pModel; + + int centShift; + int keyNum; + QString language; + int length; + QString lyric; + PhonemeInfo *phonemes; + int pos; + Pronunciation *pronunciation; + Vibrato *vibrato; + Workspace *workspace; + NoteSequence *noteSequence{}; + bool overlapped{}; + + void setCentShiftUnchecked(int centShift_); + void setCentShift(int centShift_); + void setKeyNumUnchecked(int keyNum_); + void setKeyNum(int keyNum_); + void setLengthUnchecked(int length_); + void setLength(int length_); + void setPosUnchecked(int pos_); + void setPos(int pos_); + + static void setOverlapped(Note *item, bool overlapped); + static void setNoteSequence(Note *item, NoteSequence *noteSequence); + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_NOTE_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/Param.cpp b/src/libs/application/dspxmodel/src/Param.cpp index 7c46e1ac..b81c7f12 100644 --- a/src/libs/application/dspxmodel/src/Param.cpp +++ b/src/libs/application/dspxmodel/src/Param.cpp @@ -1,32 +1,33 @@ #include "Param.h" +#include "Param_p.h" #include #include #include +#include #include namespace dspx { - class ParamPrivate { - Q_DECLARE_PUBLIC(Param) - public: - Param *q_ptr; - ModelPrivate *pModel; - ParamCurveSequence *original; - ParamCurveSequence *transform; - ParamCurveSequence *edited; - }; + void ParamPrivate::setParamMap(Param *item, ParamMap *paramMap) { + auto d = item->d_func(); + if (d->paramMap != paramMap) { + d->paramMap = paramMap; + Q_EMIT item->paramMapChanged(); + } + } Param::Param(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new ParamPrivate) { Q_D(Param); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::EI_Param); d->q_ptr = this; d->pModel = ModelPrivate::get(model); + d->paramMap = nullptr; - d->original = d->pModel->createObject(d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_ParamCurvesOriginal)); - d->transform = d->pModel->createObject(d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_ParamCurvesTransform)); - d->edited = d->pModel->createObject(d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_ParamCurvesEdited)); + d->original = d->pModel->createObject(this, d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_ParamCurvesOriginal)); + d->transform = d->pModel->createObject(this, d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_ParamCurvesTransform)); + d->edited = d->pModel->createObject(this, d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_ParamCurvesEdited)); } Param::~Param() = default; @@ -62,6 +63,11 @@ namespace dspx { d->edited->fromQDspx(param.edited); } + ParamMap *Param::paramMap() const { + Q_D(const Param); + return d->paramMap; + } + } #include "moc_Param.cpp" diff --git a/src/libs/application/dspxmodel/src/Param.h b/src/libs/application/dspxmodel/src/Param.h index 46d26c4a..dbb04407 100644 --- a/src/libs/application/dspxmodel/src/Param.h +++ b/src/libs/application/dspxmodel/src/Param.h @@ -12,6 +12,7 @@ namespace QDspx { namespace dspx { class ParamCurveSequence; + class ParamMap; class ParamPrivate; class DSPX_MODEL_EXPORT Param : public EntityObject { @@ -22,6 +23,7 @@ namespace dspx { Q_PROPERTY(ParamCurveSequence *original READ original CONSTANT) Q_PROPERTY(ParamCurveSequence *transform READ transform CONSTANT) Q_PROPERTY(ParamCurveSequence *edited READ edited CONSTANT) + Q_PROPERTY(ParamMap *paramMap READ paramMap CONSTANT) public: ~Param() override; @@ -30,9 +32,14 @@ namespace dspx { ParamCurveSequence *transform() const; ParamCurveSequence *edited() const; + ParamMap *paramMap() const; + QDspx::Param toQDspx() const; void fromQDspx(const QDspx::Param ¶m); + Q_SIGNALS: + void paramMapChanged(); + private: friend class ModelPrivate; explicit Param(Handle handle, Model *model); diff --git a/src/libs/application/dspxmodel/src/ParamCurve.cpp b/src/libs/application/dspxmodel/src/ParamCurve.cpp index d1336bfc..1da88780 100644 --- a/src/libs/application/dspxmodel/src/ParamCurve.cpp +++ b/src/libs/application/dspxmodel/src/ParamCurve.cpp @@ -1,4 +1,5 @@ #include "ParamCurve.h" +#include "ParamCurve_p.h" #include #include @@ -7,18 +8,19 @@ #include #include #include +#include +#include #include namespace dspx { - class ParamCurvePrivate { - Q_DECLARE_PUBLIC(ParamCurve) - public: - ParamCurve *q_ptr; - ModelPrivate *pModel; - ParamCurve::CurveType type; - int start{}; - }; + void ParamCurvePrivate::setParamCurveSequence(ParamCurve *paramCurve, ParamCurveSequence *paramCurveSequence) { + auto d = paramCurve->d_func(); + if (d->paramCurveSequence == paramCurveSequence) + return; + d->paramCurveSequence = paramCurveSequence; + Q_EMIT paramCurve->paramCurveSequenceChanged(); + } ParamCurve::ParamCurve(CurveType type, Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new ParamCurvePrivate) { @@ -26,6 +28,7 @@ namespace dspx { d->q_ptr = this; d->pModel = ModelPrivate::get(model); d->type = type; + d->paramCurveSequence = nullptr; } ParamCurve::~ParamCurve() = default; @@ -45,6 +48,11 @@ namespace dspx { return d->type; } + ParamCurveSequence *ParamCurve::paramCurveSequence() const { + Q_D(const ParamCurve); + return d->paramCurveSequence; + } + QDspx::ParamCurveRef ParamCurve::toQDspx() const { Q_D(const ParamCurve); switch (d->type) { diff --git a/src/libs/application/dspxmodel/src/ParamCurve.h b/src/libs/application/dspxmodel/src/ParamCurve.h index d7b55439..7cff8619 100644 --- a/src/libs/application/dspxmodel/src/ParamCurve.h +++ b/src/libs/application/dspxmodel/src/ParamCurve.h @@ -12,6 +12,7 @@ namespace QDspx { namespace dspx { + class ParamCurveSequence; class ParamCurvePrivate; class DSPX_MODEL_EXPORT ParamCurve : public EntityObject { @@ -21,6 +22,7 @@ namespace dspx { Q_DECLARE_PRIVATE(ParamCurve) Q_PROPERTY(int start READ start WRITE setStart NOTIFY startChanged) Q_PROPERTY(CurveType type READ type CONSTANT) + Q_PROPERTY(ParamCurveSequence *paramCurveSequence READ paramCurveSequence NOTIFY paramCurveSequenceChanged) public: enum CurveType { @@ -36,11 +38,14 @@ namespace dspx { CurveType type() const; + ParamCurveSequence *paramCurveSequence() const; + QDspx::ParamCurveRef toQDspx() const; void fromQDspx(const QDspx::ParamCurveRef &curve); Q_SIGNALS: void startChanged(int start); + void paramCurveSequenceChanged(); protected: explicit ParamCurve(CurveType type, Handle handle, Model *model); diff --git a/src/libs/application/dspxmodel/src/ParamCurveAnchor.cpp b/src/libs/application/dspxmodel/src/ParamCurveAnchor.cpp index 348ffaa9..7e2bd226 100644 --- a/src/libs/application/dspxmodel/src/ParamCurveAnchor.cpp +++ b/src/libs/application/dspxmodel/src/ParamCurveAnchor.cpp @@ -23,7 +23,7 @@ namespace dspx { d->q_ptr = this; d->pModel = ModelPrivate::get(model); - d->nodes = d->pModel->createObject(d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Children)); + d->nodes = d->pModel->createObject(this, d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Children)); } ParamCurveAnchor::~ParamCurveAnchor() = default; diff --git a/src/libs/application/dspxmodel/src/ParamCurveFree.cpp b/src/libs/application/dspxmodel/src/ParamCurveFree.cpp index 5c82eaa5..ed94fdb1 100644 --- a/src/libs/application/dspxmodel/src/ParamCurveFree.cpp +++ b/src/libs/application/dspxmodel/src/ParamCurveFree.cpp @@ -23,7 +23,7 @@ namespace dspx { d->q_ptr = this; d->pModel = ModelPrivate::get(model); - d->values = d->pModel->createObject(d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Children)); + d->values = d->pModel->createObject(this, d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Children)); } ParamCurveFree::~ParamCurveFree() = default; diff --git a/src/libs/application/dspxmodel/src/ParamCurveSequence.cpp b/src/libs/application/dspxmodel/src/ParamCurveSequence.cpp index 65026885..12585b3e 100644 --- a/src/libs/application/dspxmodel/src/ParamCurveSequence.cpp +++ b/src/libs/application/dspxmodel/src/ParamCurveSequence.cpp @@ -1,4 +1,5 @@ #include "ParamCurveSequence.h" +#include "ParamCurveSequence_p.h" #include #include @@ -9,6 +10,7 @@ #include #include +#include #include #include #include @@ -17,15 +19,19 @@ namespace dspx { - class ParamCurveSequencePrivate : public PointSequenceData { - Q_DECLARE_PUBLIC(ParamCurveSequence) - }; - - ParamCurveSequence::ParamCurveSequence(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new ParamCurveSequencePrivate) { + ParamCurveSequence::ParamCurveSequence(Param *param, Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new ParamCurveSequencePrivate) { Q_D(ParamCurveSequence); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::ES_ParamCurves); d->q_ptr = this; d->pModel = ModelPrivate::get(model); + d->param = param; + + connect(this, &ParamCurveSequence::itemInserted, this, [this](ParamCurve *paramCurve) { + ParamCurvePrivate::setParamCurveSequence(paramCurve, this); + }); + connect(this, &ParamCurveSequence::itemRemoved, this, [this](ParamCurve *paramCurve) { + ParamCurvePrivate::setParamCurveSequence(paramCurve, nullptr); + }); } ParamCurveSequence::~ParamCurveSequence() = default; @@ -116,6 +122,11 @@ namespace dspx { d->handleTakeFromSequenceContainer(takenEntity, entity); } + Param *ParamCurveSequence::param() const { + Q_D(const ParamCurveSequence); + return d->param; + } + } #include "moc_ParamCurveSequence.cpp" diff --git a/src/libs/application/dspxmodel/src/ParamCurveSequence.h b/src/libs/application/dspxmodel/src/ParamCurveSequence.h index e2cb1779..b219d441 100644 --- a/src/libs/application/dspxmodel/src/ParamCurveSequence.h +++ b/src/libs/application/dspxmodel/src/ParamCurveSequence.h @@ -13,6 +13,7 @@ namespace QDspx { namespace dspx { class ParamCurve; + class Param; class ParamCurveSequencePrivate; @@ -24,6 +25,7 @@ namespace dspx { Q_PROPERTY(int size READ size NOTIFY sizeChanged) Q_PROPERTY(ParamCurve *firstItem READ firstItem NOTIFY firstItemChanged) Q_PROPERTY(ParamCurve *lastItem READ lastItem NOTIFY lastItemChanged) + Q_PROPERTY(Param *param READ param CONSTANT) Q_PRIVATE_PROPERTY(d_func(), QJSValue iterable READ iterable CONSTANT) public: ~ParamCurveSequence() override; @@ -42,6 +44,8 @@ namespace dspx { QList toQDspx() const; void fromQDspx(const QList &curves); + Param *param() const; + Q_SIGNALS: void itemAboutToInsert(ParamCurve *item); void itemInserted(ParamCurve *item); @@ -57,7 +61,7 @@ namespace dspx { private: friend class ModelPrivate; - explicit ParamCurveSequence(Handle handle, Model *model); + explicit ParamCurveSequence(Param *param, Handle handle, Model *model); QScopedPointer d_ptr; }; diff --git a/src/libs/application/dspxmodel/src/ParamCurveSequence_p.h b/src/libs/application/dspxmodel/src/ParamCurveSequence_p.h new file mode 100644 index 00000000..8ffb2c96 --- /dev/null +++ b/src/libs/application/dspxmodel/src/ParamCurveSequence_p.h @@ -0,0 +1,19 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_PARAMCURVESEQUENCE_P_H +#define DIFFSCOPE_DSPX_MODEL_PARAMCURVESEQUENCE_P_H + +#include + +#include +#include + +namespace dspx { + + class ParamCurveSequencePrivate : public PointSequenceData { + Q_DECLARE_PUBLIC(ParamCurveSequence) + public: + Param *param{}; + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_PARAMCURVESEQUENCE_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/ParamCurve_p.h b/src/libs/application/dspxmodel/src/ParamCurve_p.h new file mode 100644 index 00000000..f8478651 --- /dev/null +++ b/src/libs/application/dspxmodel/src/ParamCurve_p.h @@ -0,0 +1,25 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_PARAMCURVE_P_H +#define DIFFSCOPE_DSPX_MODEL_PARAMCURVE_P_H + +#include + +namespace dspx { + + class ParamCurveSequence; + class ModelPrivate; + + class ParamCurvePrivate { + Q_DECLARE_PUBLIC(ParamCurve) + public: + ParamCurve *q_ptr; + ModelPrivate *pModel; + ParamCurve::CurveType type; + int start{}; + ParamCurveSequence *paramCurveSequence{}; + + static void setParamCurveSequence(ParamCurve *item, ParamCurveSequence *paramCurveSequence); + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_PARAMCURVE_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/ParamMap.cpp b/src/libs/application/dspxmodel/src/ParamMap.cpp index 89df5c92..925bac88 100644 --- a/src/libs/application/dspxmodel/src/ParamMap.cpp +++ b/src/libs/application/dspxmodel/src/ParamMap.cpp @@ -4,20 +4,31 @@ #include #include +#include #include #include +#include namespace dspx { class ParamMapPrivate : public MapData { Q_DECLARE_PUBLIC(ParamMap) + public: + SingingClip *singingClip; }; - ParamMap::ParamMap(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new ParamMapPrivate) { + ParamMap::ParamMap(SingingClip *singingClip, Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new ParamMapPrivate) { Q_D(ParamMap); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::EM_Params); d->q_ptr = this; d->pModel = ModelPrivate::get(model); + d->singingClip = singingClip; + connect(this, &ParamMap::itemInserted, this, [this](const QString &, Param *item) { + ParamPrivate::setParamMap(item, this); + }); + connect(this, &ParamMap::itemRemoved, this, [this](const QString &, Param *item) { + ParamPrivate::setParamMap(item, nullptr); + }); } ParamMap::~ParamMap() = default; @@ -78,6 +89,11 @@ namespace dspx { } } + SingingClip *ParamMap::singingClip() const { + Q_D(const ParamMap); + return d->singingClip; + } + void ParamMap::handleInsertIntoMapContainer(Handle entity, const QString &key) { Q_D(ParamMap); d->handleInsertIntoMapContainer(entity, key); diff --git a/src/libs/application/dspxmodel/src/ParamMap.h b/src/libs/application/dspxmodel/src/ParamMap.h index e52f2f78..0338d524 100644 --- a/src/libs/application/dspxmodel/src/ParamMap.h +++ b/src/libs/application/dspxmodel/src/ParamMap.h @@ -12,6 +12,7 @@ namespace QDspx { namespace dspx { + class SingingClip; class Param; class ParamMapPrivate; @@ -23,6 +24,7 @@ namespace dspx { Q_PROPERTY(int size READ size NOTIFY sizeChanged) Q_PROPERTY(QStringList keys READ keys NOTIFY keysChanged) Q_PROPERTY(QList items READ items NOTIFY itemsChanged) + Q_PROPERTY(SingingClip *singingClip READ singingClip CONSTANT) Q_PRIVATE_PROPERTY(d_func(), QJSValue iterable READ iterable CONSTANT) public: @@ -39,6 +41,8 @@ namespace dspx { QDspx::Params toQDspx() const; void fromQDspx(const QDspx::Params ¶mMap); + SingingClip *singingClip() const; + Q_SIGNALS: void itemAboutToInsert(const QString &key, Param *item); void itemInserted(const QString &key, Param *item); @@ -54,7 +58,7 @@ namespace dspx { private: friend class ModelPrivate; - explicit ParamMap(Handle handle, Model *model); + explicit ParamMap(SingingClip *singingClip, Handle handle, Model *model); QScopedPointer d_ptr; }; diff --git a/src/libs/application/dspxmodel/src/Param_p.h b/src/libs/application/dspxmodel/src/Param_p.h new file mode 100644 index 00000000..a179fe4f --- /dev/null +++ b/src/libs/application/dspxmodel/src/Param_p.h @@ -0,0 +1,26 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_PARAM_P_H +#define DIFFSCOPE_DSPX_MODEL_PARAM_P_H + +#include + +namespace dspx { + + class ParamMap; + class ModelPrivate; + + class ParamPrivate { + Q_DECLARE_PUBLIC(Param) + public: + Param *q_ptr; + ModelPrivate *pModel; + ParamCurveSequence *original; + ParamCurveSequence *transform; + ParamCurveSequence *edited; + ParamMap *paramMap; + + static void setParamMap(Param *item, ParamMap *paramMap); + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_PARAM_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/Phoneme.cpp b/src/libs/application/dspxmodel/src/Phoneme.cpp index a025c6a5..32f6e792 100644 --- a/src/libs/application/dspxmodel/src/Phoneme.cpp +++ b/src/libs/application/dspxmodel/src/Phoneme.cpp @@ -1,4 +1,5 @@ #include "Phoneme.h" +#include "Phoneme_p.h" #include #include @@ -7,23 +8,25 @@ #include #include +#include +#include namespace dspx { - class PhonemePrivate { - Q_DECLARE_PUBLIC(Phoneme) - public: - Phoneme *q_ptr; - QString language; - int start; - QString token; - bool onset; - }; + void PhonemePrivate::setPhonemeList(Phoneme *item, PhonemeList *phonemeList) { + auto d = item->d_func(); + if (d->phonemeList != phonemeList) { + d->phonemeList = phonemeList; + Q_EMIT item->phonemeListChanged(); + } + } Phoneme::Phoneme(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new PhonemePrivate) { Q_D(Phoneme); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::EI_Phoneme); d->q_ptr = this; + d->pModel = ModelPrivate::get(model); + d->phonemeList = nullptr; d->language = model->strategy()->getEntityProperty(handle, ModelStrategy::P_Language).toString(); d->start = model->strategy()->getEntityProperty(handle, ModelStrategy::P_Position).toInt(); d->token = model->strategy()->getEntityProperty(handle, ModelStrategy::P_Text).toString(); @@ -116,6 +119,11 @@ namespace dspx { } } + PhonemeList *Phoneme::phonemeList() const { + Q_D(const Phoneme); + return d->phonemeList; + } + } #include "moc_Phoneme.cpp" diff --git a/src/libs/application/dspxmodel/src/Phoneme.h b/src/libs/application/dspxmodel/src/Phoneme.h index 527262f7..1698944c 100644 --- a/src/libs/application/dspxmodel/src/Phoneme.h +++ b/src/libs/application/dspxmodel/src/Phoneme.h @@ -11,6 +11,7 @@ namespace QDspx { namespace dspx { + class PhonemeList; class PhonemePrivate; class DSPX_MODEL_EXPORT Phoneme : public EntityObject { @@ -22,6 +23,7 @@ namespace dspx { Q_PROPERTY(int start READ start WRITE setStart NOTIFY startChanged) Q_PROPERTY(QString token READ token WRITE setToken NOTIFY tokenChanged) Q_PROPERTY(bool onset READ onset WRITE setOnset NOTIFY onsetChanged) + Q_PROPERTY(PhonemeList *phonemeList READ phonemeList NOTIFY phonemeListChanged) public: ~Phoneme() override; @@ -38,6 +40,8 @@ namespace dspx { bool onset() const; void setOnset(bool onset); + PhonemeList *phonemeList() const; + QDspx::Phoneme toQDspx() const; void fromQDspx(const QDspx::Phoneme &phoneme); @@ -46,6 +50,7 @@ namespace dspx { void startChanged(int start); void tokenChanged(const QString &token); void onsetChanged(bool onset); + void phonemeListChanged(); protected: void handleSetEntityProperty(int property, const QVariant &value) override; diff --git a/src/libs/application/dspxmodel/src/PhonemeInfo.cpp b/src/libs/application/dspxmodel/src/PhonemeInfo.cpp index 48bca837..40008544 100644 --- a/src/libs/application/dspxmodel/src/PhonemeInfo.cpp +++ b/src/libs/application/dspxmodel/src/PhonemeInfo.cpp @@ -1,4 +1,5 @@ #include "PhonemeInfo.h" +#include "PhonemeInfo_p.h" #include #include @@ -7,25 +8,26 @@ #include #include +#include #include namespace dspx { - class PhonemeInfoPrivate { - Q_DECLARE_PUBLIC(PhonemeInfo) - public: - PhonemeInfo *q_ptr; - ModelPrivate *pModel; - PhonemeList *edited; - PhonemeList *original; - }; + void PhonemeInfoPrivate::setNote(PhonemeInfo *item, Note *note) { + auto d = item->d_func(); + if (d->note != note) { + d->note = note; + Q_EMIT item->noteChanged(); + } + } - PhonemeInfo::PhonemeInfo(Handle handle, Model *model) : QObject(model), d_ptr(new PhonemeInfoPrivate) { + PhonemeInfo::PhonemeInfo(Note *note, Handle handle, Model *model) : QObject(model), d_ptr(new PhonemeInfoPrivate) { Q_D(PhonemeInfo); d->q_ptr = this; d->pModel = ModelPrivate::get(model); - d->edited = d->pModel->createObject(d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_PhonemesEdited)); - d->original = d->pModel->createObject(d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_PhonemesOriginal)); + d->note = note; + d->edited = d->pModel->createObject(this, d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_PhonemesEdited)); + d->original = d->pModel->createObject(this, d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_PhonemesOriginal)); } PhonemeInfo::~PhonemeInfo() = default; @@ -53,6 +55,11 @@ namespace dspx { edited()->fromQDspx(phonemeInfo.edited); } + Note *PhonemeInfo::note() const { + Q_D(const PhonemeInfo); + return d->note; + } + } #include "moc_PhonemeInfo.cpp" diff --git a/src/libs/application/dspxmodel/src/PhonemeInfo.h b/src/libs/application/dspxmodel/src/PhonemeInfo.h index b3305cd7..6ed2d4cd 100644 --- a/src/libs/application/dspxmodel/src/PhonemeInfo.h +++ b/src/libs/application/dspxmodel/src/PhonemeInfo.h @@ -16,6 +16,7 @@ namespace dspx { class Model; class ModelPrivate; class PhonemeList; + class Note; class PhonemeInfoPrivate; @@ -26,6 +27,7 @@ namespace dspx { Q_DECLARE_PRIVATE(PhonemeInfo) Q_PROPERTY(PhonemeList *edited READ edited CONSTANT) Q_PROPERTY(PhonemeList *original READ original CONSTANT) + Q_PROPERTY(Note *note READ note CONSTANT) public: ~PhonemeInfo() override; @@ -33,12 +35,17 @@ namespace dspx { PhonemeList *edited() const; PhonemeList *original() const; + Note *note() const; + QDspx::Phonemes toQDspx() const; void fromQDspx(const QDspx::Phonemes &phonemeInfo); + Q_SIGNALS: + void noteChanged(); + private: friend class ModelPrivate; - explicit PhonemeInfo(Handle handle, Model *model); + explicit PhonemeInfo(Note *note, Handle handle, Model *model); QScopedPointer d_ptr; }; diff --git a/src/libs/application/dspxmodel/src/PhonemeInfo_p.h b/src/libs/application/dspxmodel/src/PhonemeInfo_p.h new file mode 100644 index 00000000..987e3c7d --- /dev/null +++ b/src/libs/application/dspxmodel/src/PhonemeInfo_p.h @@ -0,0 +1,25 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_PHONEMEINFO_P_H +#define DIFFSCOPE_DSPX_MODEL_PHONEMEINFO_P_H + +#include + +namespace dspx { + + class Note; + class ModelPrivate; + + class PhonemeInfoPrivate { + Q_DECLARE_PUBLIC(PhonemeInfo) + public: + PhonemeInfo *q_ptr; + ModelPrivate *pModel; + PhonemeList *edited{}; + PhonemeList *original{}; + Note *note{}; + + static void setNote(PhonemeInfo *item, Note *note); + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_PHONEMEINFO_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/PhonemeList.cpp b/src/libs/application/dspxmodel/src/PhonemeList.cpp index 159d49b4..4dbab0fe 100644 --- a/src/libs/application/dspxmodel/src/PhonemeList.cpp +++ b/src/libs/application/dspxmodel/src/PhonemeList.cpp @@ -4,20 +4,26 @@ #include #include +#include #include #include +#include +#include namespace dspx { - class PhonemeListPrivate : public ListData { - Q_DECLARE_PUBLIC(PhonemeList) - }; - - PhonemeList::PhonemeList(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new PhonemeListPrivate) { + PhonemeList::PhonemeList(PhonemeInfo *phonemeInfo, Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new PhonemeListPrivate) { Q_D(PhonemeList); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::EL_Phonemes); d->q_ptr = this; d->pModel = ModelPrivate::get(model); + d->phonemeInfo = phonemeInfo; + connect(this, &PhonemeList::itemInserted, this, [this](int, Phoneme *item) { + PhonemePrivate::setPhonemeList(item, this); + }); + connect(this, &PhonemeList::itemRemoved, this, [this](int, Phoneme *item) { + PhonemePrivate::setPhonemeList(item, nullptr); + }); } PhonemeList::~PhonemeList() = default; @@ -88,6 +94,11 @@ namespace dspx { d->handleRotateListContainer(leftIndex, middleIndex, rightIndex); } + PhonemeInfo *PhonemeList::phonemeInfo() const { + Q_D(const PhonemeList); + return d->phonemeInfo; + } + } #include "moc_PhonemeList.cpp" diff --git a/src/libs/application/dspxmodel/src/PhonemeList.h b/src/libs/application/dspxmodel/src/PhonemeList.h index dfa9d019..504d4066 100644 --- a/src/libs/application/dspxmodel/src/PhonemeList.h +++ b/src/libs/application/dspxmodel/src/PhonemeList.h @@ -12,6 +12,7 @@ namespace QDspx { namespace dspx { class Phoneme; + class PhonemeInfo; class PhonemeListPrivate; @@ -22,6 +23,7 @@ namespace dspx { Q_DECLARE_PRIVATE(PhonemeList) Q_PROPERTY(int size READ size NOTIFY sizeChanged) Q_PROPERTY(QList items READ items NOTIFY itemsChanged) + Q_PROPERTY(PhonemeInfo *phonemeInfo READ phonemeInfo CONSTANT) Q_PRIVATE_PROPERTY(d_func(), QJSValue iterable READ iterable CONSTANT) public: @@ -37,6 +39,8 @@ namespace dspx { QList toQDspx() const; void fromQDspx(const QList &phonemeList); + PhonemeInfo *phonemeInfo() const; + Q_SIGNALS: void itemAboutToInsert(int index, Phoneme *item); void itemInserted(int index, Phoneme *item); @@ -54,7 +58,7 @@ namespace dspx { private: friend class ModelPrivate; - explicit PhonemeList(Handle handle, Model *model); + explicit PhonemeList(PhonemeInfo *phonemeInfo, Handle handle, Model *model); QScopedPointer d_ptr; }; diff --git a/src/libs/application/dspxmodel/src/PhonemeList_p.h b/src/libs/application/dspxmodel/src/PhonemeList_p.h new file mode 100644 index 00000000..5cb257c2 --- /dev/null +++ b/src/libs/application/dspxmodel/src/PhonemeList_p.h @@ -0,0 +1,19 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_PHONEMELIST_P_H +#define DIFFSCOPE_DSPX_MODEL_PHONEMELIST_P_H + +#include +#include + +namespace dspx { + + class PhonemeInfo; + + class PhonemeListPrivate : public ListData { + Q_DECLARE_PUBLIC(PhonemeList) + public: + PhonemeInfo *phonemeInfo{}; + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_PHONEMELIST_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/Phoneme_p.h b/src/libs/application/dspxmodel/src/Phoneme_p.h new file mode 100644 index 00000000..05010ae0 --- /dev/null +++ b/src/libs/application/dspxmodel/src/Phoneme_p.h @@ -0,0 +1,32 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_PHONEME_P_H +#define DIFFSCOPE_DSPX_MODEL_PHONEME_P_H + +#include + +namespace dspx { + + class PhonemeList; + class ModelPrivate; + + class PhonemePrivate { + Q_DECLARE_PUBLIC(Phoneme) + public: + Phoneme *q_ptr; + ModelPrivate *pModel; + QString language; + int start{}; + QString token; + bool onset{}; + PhonemeList *phonemeList{}; + + static void setPhonemeList(Phoneme *item, PhonemeList *phonemeList); + + void setLanguageUnchecked(const QString &language); + void setStartUnchecked(int start); + void setTokenUnchecked(const QString &token); + void setOnsetUnchecked(bool onset); + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_PHONEME_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/SingingClip.cpp b/src/libs/application/dspxmodel/src/SingingClip.cpp index 2115440f..17fb30c6 100644 --- a/src/libs/application/dspxmodel/src/SingingClip.cpp +++ b/src/libs/application/dspxmodel/src/SingingClip.cpp @@ -28,9 +28,8 @@ namespace dspx { Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::EI_SingingClip); d->q_ptr = this; d->pModel = ModelPrivate::get(model); - d->notes = d->pModel->createObject(d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Children)); - d->notes->setSingingClip(this); - d->params = d->pModel->createObject(d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Params)); + d->notes = d->pModel->createObject(this, d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Children)); + d->params = d->pModel->createObject(this, d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Params)); d->sources = d->pModel->createObject(d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Sources)); } diff --git a/src/libs/application/dspxmodel/src/Tempo.cpp b/src/libs/application/dspxmodel/src/Tempo.cpp index 178cc9ac..0da9844a 100644 --- a/src/libs/application/dspxmodel/src/Tempo.cpp +++ b/src/libs/application/dspxmodel/src/Tempo.cpp @@ -1,4 +1,5 @@ #include "Tempo.h" +#include "Tempo_p.h" #include #include @@ -7,23 +8,10 @@ #include #include +#include namespace dspx { - class TempoPrivate { - Q_DECLARE_PUBLIC(Tempo) - public: - Tempo *q_ptr; - int pos; - double value; - - void setPosUnchecked(int pos_); - void setPos(int pos_); - - void setValueUnchecked(double value_); - void setValue(double value_); - }; - void TempoPrivate::setPosUnchecked(int pos_) { Q_Q(Tempo); q->model()->strategy()->setEntityProperty(q->handle(), ModelStrategy::P_Position, pos_); @@ -52,6 +40,14 @@ namespace dspx { setValueUnchecked(value_); } + void TempoPrivate::setTempoSequence(Tempo *item, TempoSequence *tempoSequence) { + auto d = item->d_func(); + if (d->tempoSequence != tempoSequence) { + d->tempoSequence = tempoSequence; + Q_EMIT item->tempoSequenceChanged(); + } + } + Tempo::Tempo(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new TempoPrivate) { Q_D(Tempo); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::EI_Tempo); @@ -84,6 +80,11 @@ namespace dspx { d->setValueUnchecked(value); } + TempoSequence *Tempo::tempoSequence() const { + Q_D(const Tempo); + return d->tempoSequence; + } + QDspx::Tempo Tempo::toQDspx() const { return { .pos = pos(), diff --git a/src/libs/application/dspxmodel/src/Tempo.h b/src/libs/application/dspxmodel/src/Tempo.h index 4dd8254e..53b71fa7 100644 --- a/src/libs/application/dspxmodel/src/Tempo.h +++ b/src/libs/application/dspxmodel/src/Tempo.h @@ -11,6 +11,7 @@ namespace QDspx { namespace dspx { + class TempoSequence; class TempoPrivate; class DSPX_MODEL_EXPORT Tempo : public EntityObject { @@ -20,6 +21,7 @@ namespace dspx { Q_DECLARE_PRIVATE(Tempo); Q_PRIVATE_PROPERTY(d_func(), int pos MEMBER pos WRITE setPos NOTIFY posChanged) Q_PRIVATE_PROPERTY(d_func(), double value MEMBER value WRITE setValue NOTIFY valueChanged) + Q_PROPERTY(TempoSequence *tempoSequence READ tempoSequence NOTIFY tempoSequenceChanged) public: ~Tempo() override; @@ -29,12 +31,15 @@ namespace dspx { double value() const; void setValue(double value); + TempoSequence *tempoSequence() const; + QDspx::Tempo toQDspx() const; void fromQDspx(const QDspx::Tempo &tempo); Q_SIGNALS: void posChanged(int pos); void valueChanged(double value); + void tempoSequenceChanged(); protected: void handleSetEntityProperty(int property, const QVariant &value) override; diff --git a/src/libs/application/dspxmodel/src/TempoSequence.cpp b/src/libs/application/dspxmodel/src/TempoSequence.cpp index a6851599..acd17721 100644 --- a/src/libs/application/dspxmodel/src/TempoSequence.cpp +++ b/src/libs/application/dspxmodel/src/TempoSequence.cpp @@ -1,4 +1,5 @@ #include "TempoSequence.h" +#include "TempoSequence_p.h" #include #include @@ -8,20 +9,21 @@ #include #include #include -#include #include namespace dspx { - class TempoSequencePrivate : public PointSequenceData { - Q_DECLARE_PUBLIC(TempoSequence) - }; - TempoSequence::TempoSequence(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new TempoSequencePrivate) { Q_D(TempoSequence); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::ES_Tempos); d->q_ptr = this; d->pModel = ModelPrivate::get(model); + connect(this, &TempoSequence::itemInserted, this, [=](Tempo *item) { + TempoPrivate::setTempoSequence(item, this); + }); + connect(this, &TempoSequence::itemRemoved, this, [=](Tempo *item) { + TempoPrivate::setTempoSequence(item, nullptr); + }); } TempoSequence::~TempoSequence() = default; diff --git a/src/libs/application/dspxmodel/src/TempoSequence_p.h b/src/libs/application/dspxmodel/src/TempoSequence_p.h new file mode 100644 index 00000000..44435be5 --- /dev/null +++ b/src/libs/application/dspxmodel/src/TempoSequence_p.h @@ -0,0 +1,17 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_TEMPOSEQUENCE_P_H +#define DIFFSCOPE_DSPX_MODEL_TEMPOSEQUENCE_P_H + +#include + +#include +#include + +namespace dspx { + + class TempoSequencePrivate : public PointSequenceData { + Q_DECLARE_PUBLIC(TempoSequence) + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_TEMPOSEQUENCE_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/Tempo_p.h b/src/libs/application/dspxmodel/src/Tempo_p.h new file mode 100644 index 00000000..8bb93871 --- /dev/null +++ b/src/libs/application/dspxmodel/src/Tempo_p.h @@ -0,0 +1,26 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_TEMPO_P_H +#define DIFFSCOPE_DSPX_MODEL_TEMPO_P_H + +#include + +namespace dspx { + + class TempoPrivate { + Q_DECLARE_PUBLIC(Tempo) + public: + Tempo *q_ptr; + int pos; + double value; + TempoSequence *tempoSequence{}; + + void setPosUnchecked(int pos_); + void setPos(int pos_); + void setValueUnchecked(double value_); + void setValue(double value_); + + static void setTempoSequence(Tempo *item, TempoSequence *tempoSequence); + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_TEMPO_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/TimeSignature.cpp b/src/libs/application/dspxmodel/src/TimeSignature.cpp index 99fc0cb9..5148bf3d 100644 --- a/src/libs/application/dspxmodel/src/TimeSignature.cpp +++ b/src/libs/application/dspxmodel/src/TimeSignature.cpp @@ -1,4 +1,5 @@ #include "TimeSignature.h" +#include "TimeSignature_p.h" #include #include @@ -7,24 +8,13 @@ #include #include +#include namespace dspx { - class TimeSignaturePrivate { - Q_DECLARE_PUBLIC(TimeSignature) - public: - TimeSignature *q_ptr; - int index; - int numerator; - int denominator; - - void setIndexUnchecked(int index_); - void setIndex(int index_); - void setNumeratorUnchecked(int numerator_); - void setNumerator(int numerator_); - void setDenominatorUnchecked(int denominator_); - void setDenominator(int denominator_); - }; + static constexpr bool validateDenominator(int d) { + return d == 1 || d == 2 || d == 4 || d == 8 || d == 16 || d == 32 || d == 64 || d == 128 || d == 256; + } void TimeSignaturePrivate::setIndexUnchecked(int index_) { Q_Q(TimeSignature); @@ -59,10 +49,6 @@ namespace dspx { q->model()->strategy()->setEntityProperty(q->handle(), ModelStrategy::P_Denominator, denominator_); } - static constexpr bool validateDenominator(int d) { - return d == 1 || d == 2 || d == 4 || d == 8 || d == 16 || d == 32 || d == 64 || d == 128 || d == 256; - } - void TimeSignaturePrivate::setDenominator(int denominator_) { Q_Q(TimeSignature); if (auto engine = qjsEngine(q); engine) { @@ -74,6 +60,14 @@ namespace dspx { setDenominatorUnchecked(denominator_); } + void TimeSignaturePrivate::setTimeSignatureSequence(TimeSignature *item, TimeSignatureSequence *timeSignatureSequence) { + auto d = item->d_func(); + if (d->timeSignatureSequence != timeSignatureSequence) { + d->timeSignatureSequence = timeSignatureSequence; + Q_EMIT item->timeSignatureSequenceChanged(); + } + } + TimeSignature::TimeSignature(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new TimeSignaturePrivate) { Q_D(TimeSignature); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::EI_TimeSignature); @@ -118,6 +112,11 @@ namespace dspx { d->setDenominatorUnchecked(denominator); } + TimeSignatureSequence *TimeSignature::timeSignatureSequence() const { + Q_D(const TimeSignature); + return d->timeSignatureSequence; + } + QDspx::TimeSignature TimeSignature::toQDspx() const { return { .index = index(), diff --git a/src/libs/application/dspxmodel/src/TimeSignature.h b/src/libs/application/dspxmodel/src/TimeSignature.h index 25918a5a..99f23148 100644 --- a/src/libs/application/dspxmodel/src/TimeSignature.h +++ b/src/libs/application/dspxmodel/src/TimeSignature.h @@ -11,6 +11,7 @@ namespace QDspx { namespace dspx { + class TimeSignatureSequence; class TimeSignaturePrivate; class DSPX_MODEL_EXPORT TimeSignature : public EntityObject { @@ -21,6 +22,7 @@ namespace dspx { Q_PRIVATE_PROPERTY(d_func(), int index MEMBER index WRITE setIndex NOTIFY indexChanged) Q_PRIVATE_PROPERTY(d_func(), int numerator MEMBER numerator WRITE setNumerator NOTIFY numeratorChanged) Q_PRIVATE_PROPERTY(d_func(), int denominator MEMBER denominator WRITE setDenominator NOTIFY denominatorChanged) + Q_PROPERTY(TimeSignatureSequence *timeSignatureSequence READ timeSignatureSequence NOTIFY timeSignatureSequenceChanged) public: ~TimeSignature() override; @@ -33,6 +35,8 @@ namespace dspx { int denominator() const; void setDenominator(int denominator); + TimeSignatureSequence *timeSignatureSequence() const; + QDspx::TimeSignature toQDspx() const; void fromQDspx(const QDspx::TimeSignature &timeSignature); @@ -40,6 +44,7 @@ namespace dspx { void indexChanged(int index); void numeratorChanged(int numerator); void denominatorChanged(int denominator); + void timeSignatureSequenceChanged(); protected: void handleSetEntityProperty(int property, const QVariant &value) override; diff --git a/src/libs/application/dspxmodel/src/TimeSignatureSequence.cpp b/src/libs/application/dspxmodel/src/TimeSignatureSequence.cpp index ad817520..c423ad07 100644 --- a/src/libs/application/dspxmodel/src/TimeSignatureSequence.cpp +++ b/src/libs/application/dspxmodel/src/TimeSignatureSequence.cpp @@ -1,4 +1,5 @@ #include "TimeSignatureSequence.h" +#include "TimeSignatureSequence_p.h" #include #include @@ -8,20 +9,21 @@ #include #include #include -#include #include namespace dspx { - class TimeSignatureSequencePrivate : public PointSequenceData { - Q_DECLARE_PUBLIC(TimeSignatureSequence) - }; - TimeSignatureSequence::TimeSignatureSequence(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new TimeSignatureSequencePrivate) { Q_D(TimeSignatureSequence); Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::ES_TimeSignatures); d->q_ptr = this; d->pModel = ModelPrivate::get(model); + connect(this, &TimeSignatureSequence::itemInserted, this, [=](TimeSignature *item) { + TimeSignaturePrivate::setTimeSignatureSequence(item, this); + }); + connect(this, &TimeSignatureSequence::itemRemoved, this, [=](TimeSignature *item) { + TimeSignaturePrivate::setTimeSignatureSequence(item, nullptr); + }); } TimeSignatureSequence::~TimeSignatureSequence() = default; diff --git a/src/libs/application/dspxmodel/src/TimeSignatureSequence_p.h b/src/libs/application/dspxmodel/src/TimeSignatureSequence_p.h new file mode 100644 index 00000000..3cf31cbe --- /dev/null +++ b/src/libs/application/dspxmodel/src/TimeSignatureSequence_p.h @@ -0,0 +1,17 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_TIMESIGNATURESEQUENCE_P_H +#define DIFFSCOPE_DSPX_MODEL_TIMESIGNATURESEQUENCE_P_H + +#include + +#include +#include + +namespace dspx { + + class TimeSignatureSequencePrivate : public PointSequenceData { + Q_DECLARE_PUBLIC(TimeSignatureSequence) + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_TIMESIGNATURESEQUENCE_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/TimeSignature_p.h b/src/libs/application/dspxmodel/src/TimeSignature_p.h new file mode 100644 index 00000000..7a787946 --- /dev/null +++ b/src/libs/application/dspxmodel/src/TimeSignature_p.h @@ -0,0 +1,29 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_TIMESIGNATURE_P_H +#define DIFFSCOPE_DSPX_MODEL_TIMESIGNATURE_P_H + +#include + +namespace dspx { + + class TimeSignaturePrivate { + Q_DECLARE_PUBLIC(TimeSignature) + public: + TimeSignature *q_ptr; + int index; + int numerator; + int denominator; + TimeSignatureSequence *timeSignatureSequence{}; + + void setIndexUnchecked(int index_); + void setIndex(int index_); + void setNumeratorUnchecked(int numerator_); + void setNumerator(int numerator_); + void setDenominatorUnchecked(int denominator_); + void setDenominator(int denominator_); + + static void setTimeSignatureSequence(TimeSignature *item, TimeSignatureSequence *timeSignatureSequence); + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_TIMESIGNATURE_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/Track.cpp b/src/libs/application/dspxmodel/src/Track.cpp index 013b541d..954ded82 100644 --- a/src/libs/application/dspxmodel/src/Track.cpp +++ b/src/libs/application/dspxmodel/src/Track.cpp @@ -1,4 +1,5 @@ #include "Track.h" +#include "Track_p.h" #include #include @@ -9,27 +10,18 @@ #include #include #include +#include #include +#include namespace dspx { - class TrackPrivate { - Q_DECLARE_PUBLIC(Track) - public: - Track *q_ptr; - ModelPrivate *pModel; - ClipSequence *clips; - QString name; - TrackControl *control; - Workspace *workspace; - }; - - static QString colorToHex(const QColor &color) { - return color.isValid() ? color.name(QColor::HexRgb) : QString(); - } - - static QColor hexToColor(const QString &hex) { - return QColor::fromString(hex); + void TrackPrivate::setTrackList(Track *item, TrackList *trackList) { + auto d = item->d_func(); + if (d->trackList != trackList) { + d->trackList = trackList; + Q_EMIT item->trackListChanged(); + } } Track::Track(Handle handle, Model *model) : EntityObject(handle, model), d_ptr(new TrackPrivate) { @@ -40,8 +32,7 @@ namespace dspx { d->name = d->pModel->strategy->getEntityProperty(handle, ModelStrategy::P_Name).toString(); d->control = d->pModel->createObject(handle); d->workspace = d->pModel->createObject(d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Workspace)); - d->clips = d->pModel->createObject(d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Children)); - d->clips->setTrack(this); + d->clips = d->pModel->createObject(this, d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Children)); } Track::~Track() = default; @@ -87,6 +78,11 @@ namespace dspx { workspace()->fromQDspx(track.workspace); } + TrackList *Track::trackList() const { + Q_D(const Track); + return d->trackList; + } + void Track::handleSetEntityProperty(int property, const QVariant &value) { Q_D(Track); switch (property) { diff --git a/src/libs/application/dspxmodel/src/Track.h b/src/libs/application/dspxmodel/src/Track.h index 4f25a1d0..8f03adf3 100644 --- a/src/libs/application/dspxmodel/src/Track.h +++ b/src/libs/application/dspxmodel/src/Track.h @@ -15,6 +15,8 @@ namespace dspx { class TrackControl; class Workspace; + class TrackList; + class TrackPrivate; class DSPX_MODEL_EXPORT Track : public EntityObject { @@ -26,6 +28,7 @@ namespace dspx { Q_PROPERTY(TrackControl *control READ control CONSTANT) Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(Workspace *workspace READ workspace CONSTANT) + Q_PROPERTY(TrackList *trackList READ trackList CONSTANT) public: ~Track() override; @@ -42,8 +45,11 @@ namespace dspx { QDspx::Track toQDspx() const; void fromQDspx(const QDspx::Track &track); + TrackList *trackList() const; + Q_SIGNALS: void nameChanged(const QString &name); + void trackListChanged(); protected: void handleSetEntityProperty(int property, const QVariant &value) override; diff --git a/src/libs/application/dspxmodel/src/TrackList.cpp b/src/libs/application/dspxmodel/src/TrackList.cpp index 49011c19..28a9e05d 100644 --- a/src/libs/application/dspxmodel/src/TrackList.cpp +++ b/src/libs/application/dspxmodel/src/TrackList.cpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace dspx { @@ -18,6 +19,12 @@ namespace dspx { Q_ASSERT(model->strategy()->getEntityType(handle) == ModelStrategy::EL_Tracks); d->q_ptr = this; d->pModel = ModelPrivate::get(model); + connect(this, &TrackList::itemInserted, this, [this](int, Track *item) { + TrackPrivate::setTrackList(item, this); + }); + connect(this, &TrackList::itemRemoved, this, [this](int, Track *item) { + TrackPrivate::setTrackList(item, nullptr); + }); } TrackList::~TrackList() = default; diff --git a/src/libs/application/dspxmodel/src/Track_p.h b/src/libs/application/dspxmodel/src/Track_p.h new file mode 100644 index 00000000..83036dbc --- /dev/null +++ b/src/libs/application/dspxmodel/src/Track_p.h @@ -0,0 +1,24 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_TRACK_P_H +#define DIFFSCOPE_DSPX_MODEL_TRACK_P_H + +#include + +namespace dspx { + + class TrackPrivate { + Q_DECLARE_PUBLIC(Track) + public: + Track *q_ptr; + ModelPrivate *pModel; + ClipSequence *clips; + QString name; + TrackControl *control; + Workspace *workspace; + TrackList *trackList; + + static void setTrackList(Track *item, TrackList *trackList); + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_TRACK_P_H From 3bc062cd125091ce7edb6375e1edba15e2e83c70 Mon Sep 17 00:00:00 2001 From: CrSjimo Date: Fri, 28 Nov 2025 02:36:25 +0800 Subject: [PATCH 012/181] Add selection models --- .../AnchorNodeSelectionModel.cpp | 44 +++++ .../selectionmodel/AnchorNodeSelectionModel.h | 51 ++++++ .../AnchorNodeSelectionModel_p.h | 20 +++ .../src/selectionmodel/ClipSelectionModel.cpp | 38 ++++ .../src/selectionmodel/ClipSelectionModel.h | 47 +++++ .../src/selectionmodel/ClipSelectionModel_p.h | 18 ++ .../selectionmodel/LabelSelectionModel.cpp | 168 ++++++++++++++++++ .../src/selectionmodel/LabelSelectionModel.h | 45 +++++ .../selectionmodel/LabelSelectionModel_p.h | 30 ++++ .../src/selectionmodel/NoteSelectionModel.cpp | 38 ++++ .../src/selectionmodel/NoteSelectionModel.h | 47 +++++ .../src/selectionmodel/NoteSelectionModel_p.h | 19 ++ .../src/selectionmodel/SelectionModel.cpp | 73 ++++++++ .../src/selectionmodel/SelectionModel.h | 83 +++++++++ .../src/selectionmodel/SelectionModel_p.h | 26 +++ .../selectionmodel/TempoSelectionModel.cpp | 168 ++++++++++++++++++ .../src/selectionmodel/TempoSelectionModel.h | 47 +++++ .../selectionmodel/TempoSelectionModel_p.h | 28 +++ .../selectionmodel/TrackSelectionModel.cpp | 37 ++++ .../src/selectionmodel/TrackSelectionModel.h | 43 +++++ .../selectionmodel/TrackSelectionModel_p.h | 20 +++ 21 files changed, 1090 insertions(+) create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/AnchorNodeSelectionModel.cpp create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/AnchorNodeSelectionModel.h create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/AnchorNodeSelectionModel_p.h create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/ClipSelectionModel.cpp create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/ClipSelectionModel.h create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/ClipSelectionModel_p.h create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/LabelSelectionModel.cpp create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/LabelSelectionModel.h create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/LabelSelectionModel_p.h create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/NoteSelectionModel.cpp create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/NoteSelectionModel.h create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/NoteSelectionModel_p.h create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/SelectionModel.cpp create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/SelectionModel.h create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/SelectionModel_p.h create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/TempoSelectionModel.cpp create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/TempoSelectionModel.h create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/TempoSelectionModel_p.h create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/TrackSelectionModel.cpp create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/TrackSelectionModel.h create mode 100644 src/libs/application/dspxmodel/src/selectionmodel/TrackSelectionModel_p.h diff --git a/src/libs/application/dspxmodel/src/selectionmodel/AnchorNodeSelectionModel.cpp b/src/libs/application/dspxmodel/src/selectionmodel/AnchorNodeSelectionModel.cpp new file mode 100644 index 00000000..7d6fd145 --- /dev/null +++ b/src/libs/application/dspxmodel/src/selectionmodel/AnchorNodeSelectionModel.cpp @@ -0,0 +1,44 @@ +#include "AnchorNodeSelectionModel.h" +#include "AnchorNodeSelectionModel_p.h" + +#include +#include +#include + +namespace dspx { + + AnchorNodeSelectionModel::AnchorNodeSelectionModel(QObject *parent) : QObject(parent), d_ptr(new AnchorNodeSelectionModelPrivate) { + Q_D(AnchorNodeSelectionModel); + d->q_ptr = this; + } + + AnchorNodeSelectionModel::~AnchorNodeSelectionModel() = default; + + AnchorNode *AnchorNodeSelectionModel::currentItem() const { + Q_D(const AnchorNodeSelectionModel); + return d->currentItem; + } + + QList AnchorNodeSelectionModel::selectedItems() const { + Q_D(const AnchorNodeSelectionModel); + return d->selectedItems; + } + + int AnchorNodeSelectionModel::selectedCount() const { + Q_D(const AnchorNodeSelectionModel); + return d->selectedItems.size(); + } + + QList AnchorNodeSelectionModel::paramCurvesAnchorWithSelectedItems() const { + Q_D(const AnchorNodeSelectionModel); + return d->paramCurvesAnchorWithSelectedItems; + } + + ParamCurveSequence *AnchorNodeSelectionModel::paramCurveSequenceWithSelectedItems() const { + Q_D(const AnchorNodeSelectionModel); + return d->paramCurveSequenceWithSelectedItems; + } + +} + +#include "moc_AnchorNodeSelectionModel.cpp" diff --git a/src/libs/application/dspxmodel/src/selectionmodel/AnchorNodeSelectionModel.h b/src/libs/application/dspxmodel/src/selectionmodel/AnchorNodeSelectionModel.h new file mode 100644 index 00000000..ef3f03bb --- /dev/null +++ b/src/libs/application/dspxmodel/src/selectionmodel/AnchorNodeSelectionModel.h @@ -0,0 +1,51 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_ANCHORNODESELECTIONMODEL_H +#define DIFFSCOPE_DSPX_MODEL_ANCHORNODESELECTIONMODEL_H + +#include +#include +#include + +#include + +namespace dspx { + + class AnchorNode; + class ParamCurveAnchor; + class ParamCurveSequence; + class AnchorNodeSelectionModelPrivate; + + class DSPX_MODEL_EXPORT AnchorNodeSelectionModel : public QObject { + Q_OBJECT + QML_ELEMENT + Q_DECLARE_PRIVATE(AnchorNodeSelectionModel) + + Q_PROPERTY(AnchorNode *currentItem READ currentItem NOTIFY currentItemChanged) + Q_PROPERTY(QList selectedItems READ selectedItems NOTIFY selectedItemsChanged) + Q_PROPERTY(int selectedCount READ selectedCount NOTIFY selectedCountChanged) + Q_PROPERTY(QList paramCurvesAnchorWithSelectedItems READ paramCurvesAnchorWithSelectedItems NOTIFY paramCurvesAnchorWithSelectedItemsChanged) + Q_PROPERTY(ParamCurveSequence *paramCurveSequenceWithSelectedItems READ paramCurveSequenceWithSelectedItems NOTIFY paramCurveSequenceWithSelectedItemsChanged) + + public: + explicit AnchorNodeSelectionModel(QObject *parent = nullptr); + ~AnchorNodeSelectionModel() override; + + AnchorNode *currentItem() const; + QList selectedItems() const; + int selectedCount() const; + QList paramCurvesAnchorWithSelectedItems() const; + ParamCurveSequence *paramCurveSequenceWithSelectedItems() const; + + Q_SIGNALS: + void currentItemChanged(); + void selectedItemsChanged(); + void selectedCountChanged(); + void paramCurvesAnchorWithSelectedItemsChanged(); + void paramCurveSequenceWithSelectedItemsChanged(); + + private: + QScopedPointer d_ptr; + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_ANCHORNODESELECTIONMODEL_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/selectionmodel/AnchorNodeSelectionModel_p.h b/src/libs/application/dspxmodel/src/selectionmodel/AnchorNodeSelectionModel_p.h new file mode 100644 index 00000000..3023358e --- /dev/null +++ b/src/libs/application/dspxmodel/src/selectionmodel/AnchorNodeSelectionModel_p.h @@ -0,0 +1,20 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_ANCHORNODESELECTIONMODEL_P_H +#define DIFFSCOPE_DSPX_MODEL_ANCHORNODESELECTIONMODEL_P_H + +#include + +namespace dspx { + + class AnchorNodeSelectionModelPrivate { + Q_DECLARE_PUBLIC(AnchorNodeSelectionModel) + public: + AnchorNodeSelectionModel *q_ptr; + AnchorNode *currentItem = nullptr; + QList selectedItems; + QList paramCurvesAnchorWithSelectedItems; + ParamCurveSequence *paramCurveSequenceWithSelectedItems = nullptr; + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_ANCHORNODESELECTIONMODEL_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/selectionmodel/ClipSelectionModel.cpp b/src/libs/application/dspxmodel/src/selectionmodel/ClipSelectionModel.cpp new file mode 100644 index 00000000..736e8ae0 --- /dev/null +++ b/src/libs/application/dspxmodel/src/selectionmodel/ClipSelectionModel.cpp @@ -0,0 +1,38 @@ +#include "ClipSelectionModel.h" +#include "ClipSelectionModel_p.h" + +#include +#include + +namespace dspx { + + ClipSelectionModel::ClipSelectionModel(QObject *parent) : QObject(parent), d_ptr(new ClipSelectionModelPrivate) { + Q_D(ClipSelectionModel); + d->q_ptr = this; + } + + ClipSelectionModel::~ClipSelectionModel() = default; + + Clip *ClipSelectionModel::currentItem() const { + Q_D(const ClipSelectionModel); + return d->currentItem; + } + + QList ClipSelectionModel::selectedItems() const { + Q_D(const ClipSelectionModel); + return d->selectedItems; + } + + int ClipSelectionModel::selectedCount() const { + Q_D(const ClipSelectionModel); + return d->selectedItems.size(); + } + + QList ClipSelectionModel::tracksWithSelectedItems() const { + Q_D(const ClipSelectionModel); + return d->tracksWithSelectedItems; + } + +} + +#include "moc_ClipSelectionModel.cpp" diff --git a/src/libs/application/dspxmodel/src/selectionmodel/ClipSelectionModel.h b/src/libs/application/dspxmodel/src/selectionmodel/ClipSelectionModel.h new file mode 100644 index 00000000..66ed0361 --- /dev/null +++ b/src/libs/application/dspxmodel/src/selectionmodel/ClipSelectionModel.h @@ -0,0 +1,47 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_CLIPSELECTIONMODEL_H +#define DIFFSCOPE_DSPX_MODEL_CLIPSELECTIONMODEL_H + +#include +#include +#include + +#include + +namespace dspx { + + class Clip; + class Track; + class ClipSelectionModelPrivate; + + class DSPX_MODEL_EXPORT ClipSelectionModel : public QObject { + Q_OBJECT + QML_ELEMENT + Q_DECLARE_PRIVATE(ClipSelectionModel) + + Q_PROPERTY(Clip *currentItem READ currentItem NOTIFY currentItemChanged) + Q_PROPERTY(QList selectedItems READ selectedItems NOTIFY selectedItemsChanged) + Q_PROPERTY(int selectedCount READ selectedCount NOTIFY selectedCountChanged) + Q_PROPERTY(QList tracksWithSelectedItems READ tracksWithSelectedItems NOTIFY tracksWithSelectedItemsChanged) + + public: + explicit ClipSelectionModel(QObject *parent = nullptr); + ~ClipSelectionModel() override; + + Clip *currentItem() const; + QList selectedItems() const; + int selectedCount() const; + QList tracksWithSelectedItems() const; + + Q_SIGNALS: + void currentItemChanged(); + void selectedItemsChanged(); + void selectedCountChanged(); + void tracksWithSelectedItemsChanged(); + + private: + QScopedPointer d_ptr; + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_CLIPSELECTIONMODEL_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/selectionmodel/ClipSelectionModel_p.h b/src/libs/application/dspxmodel/src/selectionmodel/ClipSelectionModel_p.h new file mode 100644 index 00000000..70a380a3 --- /dev/null +++ b/src/libs/application/dspxmodel/src/selectionmodel/ClipSelectionModel_p.h @@ -0,0 +1,18 @@ +#ifndef DIFFSCOPE_DSPX_MODEL_CLIPSELECTIONMODEL_P_H +#define DIFFSCOPE_DSPX_MODEL_CLIPSELECTIONMODEL_P_H + +#include +namespace dspx { + + class ClipSelectionModelPrivate { + Q_DECLARE_PUBLIC(ClipSelectionModel) + public: + ClipSelectionModel *q_ptr; + Clip *currentItem = nullptr; + QList selectedItems; + QList tracksWithSelectedItems; + }; + +} + +#endif //DIFFSCOPE_DSPX_MODEL_CLIPSELECTIONMODEL_P_H \ No newline at end of file diff --git a/src/libs/application/dspxmodel/src/selectionmodel/LabelSelectionModel.cpp b/src/libs/application/dspxmodel/src/selectionmodel/LabelSelectionModel.cpp new file mode 100644 index 00000000..760e3f6d --- /dev/null +++ b/src/libs/application/dspxmodel/src/selectionmodel/LabelSelectionModel.cpp @@ -0,0 +1,168 @@ +#include "LabelSelectionModel.h" +#include "LabelSelectionModel_p.h" + +#include +#include +#include +#include + +namespace dspx { + + bool LabelSelectionModelPrivate::isAddedToModel(Label *item) const { + return item->labelSequence() == selectionModel->model()->timeline()->labels(); + } + void LabelSelectionModelPrivate::setCurrentItem(Label *item) { + Q_Q(LabelSelectionModel); + if (currentItem) { + if (!selectedItems.contains(currentItem)) { + QObject::disconnect(item, nullptr, q, nullptr); + } + } + currentItem = item; + if (currentItem) { + if (!selectedItems.contains(currentItem)) { + QObject::connect(item, &Label::labelSequenceChanged, q, [=, this] { + if (isAddedToModel(item)) + return; + updateOnItemRemoved(item); + }); + QObject::connect(item, &QObject::destroyed, q, [=, this] { + updateOnItemRemoved(item); + }); + } + } + } + void LabelSelectionModelPrivate::addToSelection(Label *item) { + Q_Q(LabelSelectionModel); + if (currentItem != item) { + QObject::connect(item, &Label::labelSequenceChanged, q, [=, this] { + if (isAddedToModel(item)) + return; + updateOnItemRemoved(item); + }); + QObject::connect(item, &QObject::destroyed, q, [=, this] { + updateOnItemRemoved(item); + }); + } + selectedItems.insert(item); + } + void LabelSelectionModelPrivate::removeFromSelection(Label *item) { + Q_Q(LabelSelectionModel); + if (currentItem != item) { + QObject::disconnect(item, nullptr, q, nullptr); + } + selectedItems.remove(item); + } + void LabelSelectionModelPrivate::clearSelection() { + Q_Q(LabelSelectionModel); + for (auto item : selectedItems) { + if (currentItem != item) { + QObject::disconnect(item, nullptr, q, nullptr); + } + } + selectedItems.clear(); + } + inline void LabelSelectionModelPrivate::updateOnItemRemoved(Label *item) { + Q_Q(LabelSelectionModel); + bool selectionUpdatedFlag = false; + bool currentItemUpdatedFlag = false; + if (currentItem == item) { + currentItemUpdatedFlag = true; + setCurrentItem(nullptr); + } + if (selectedItems.contains(item)) { + selectionUpdatedFlag = true; + removeFromSelection(item); + } + if (selectionUpdatedFlag) { + Q_EMIT q->selectedItemsChanged(); + } + if (currentItemUpdatedFlag) { + Q_EMIT q->currentItemChanged(); + } + } + + LabelSelectionModel::LabelSelectionModel(SelectionModel *parent) : QObject(parent), d_ptr(new LabelSelectionModelPrivate) { + Q_D(LabelSelectionModel); + d->q_ptr = this; + d->selectionModel = parent; + } + + LabelSelectionModel::~LabelSelectionModel() = default; + + Label *LabelSelectionModel::currentItem() const { + Q_D(const LabelSelectionModel); + return d->currentItem; + } + + QList