From a2d1d92dbacc351af398707e7151d4a817bf1c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Micha=C3=ABl=20Celerier?= Date: Sat, 10 Jan 2026 22:15:22 -0500 Subject: [PATCH 1/3] window: make the right side also a tab list --- src/lib/core/view/FixedTabWidget.cpp | 42 ++++++++-- src/lib/core/view/FixedTabWidget.hpp | 3 +- src/lib/core/view/Window.cpp | 119 +++++++++++++++++++-------- src/lib/core/view/Window.hpp | 6 ++ 4 files changed, 128 insertions(+), 42 deletions(-) diff --git a/src/lib/core/view/FixedTabWidget.cpp b/src/lib/core/view/FixedTabWidget.cpp index fdfe3885ba..bdbafaafca 100644 --- a/src/lib/core/view/FixedTabWidget.cpp +++ b/src/lib/core/view/FixedTabWidget.cpp @@ -18,8 +18,9 @@ namespace score FixedTabWidget::FixedTabWidget() noexcept : m_buttons{new QToolBar} { - m_layout.setContentsMargins(10, 10, 10, 10); - m_layout.setSpacing(6); + setContentsMargins(0, 0, 0, 0); + m_layout.setContentsMargins(0, 0, 0, 0); + m_layout.setSpacing(1); this->setLayout(&m_layout); auto layout = new score::MarginLess; @@ -97,16 +98,43 @@ struct DragOverToolButton final : public QToolButton int m_tm = 0; }; -std::pair FixedTabWidget::addTab(QWidget* widg, const PanelStatus& v) +std::pair +FixedTabWidget::addTab(QWidget* widg, const PanelStatus& v, int index) { - int idx = m_stack.addWidget(widg); + int idx = index >= 0 ? m_stack.insertWidget(index, widg) : m_stack.addWidget(widg); auto bbtn = new DragOverToolButton{}; bbtn->setAutoRaise(true); bbtn->setFocusPolicy(Qt::NoFocus); bbtn->setIconSize(m_buttons->iconSize()); - auto btn = m_buttons->addWidget(bbtn); + QAction* btn{}; + if(index < 0) + { + btn = m_buttons->addWidget(bbtn); + } + else + { + const auto& acts = m_buttons->actions(); + int k = 0; + QAction* before{}; + for(QAction* act : acts) + { + if(k++ == index) + { + before = act; + break; + } + } + if(before) + { + btn = m_buttons->insertWidget(before, bbtn); + } + else + { + btn = m_buttons->addWidget(bbtn); + } + } bbtn->setDefaultAction(btn); btn->setIcon(v.icon); btn->setText(v.prettyName); @@ -121,8 +149,8 @@ std::pair FixedTabWidget::addTab(QWidget* widg, const PanelStatus btn->setWhatsThis(widg->whatsThis()); btn->setStatusTip(widg->statusTip()); - connect(btn, &QAction::triggered, &m_stack, [this, btn, idx](bool checked) { - m_stack.setCurrentIndex(idx); + connect(btn, &QAction::triggered, &m_stack, [this, btn, widg](bool checked) { + m_stack.setCurrentWidget(widg); actionTriggered(btn, checked); }); diff --git a/src/lib/core/view/FixedTabWidget.hpp b/src/lib/core/view/FixedTabWidget.hpp index ae122ebea7..7116b3dfc6 100644 --- a/src/lib/core/view/FixedTabWidget.hpp +++ b/src/lib/core/view/FixedTabWidget.hpp @@ -25,7 +25,8 @@ class FixedTabWidget : public QWidget QSize sizeHint() const override; void setTab(int index); - std::pair addTab(QWidget* widg, const score::PanelStatus& v); + std::pair + addTab(QWidget* widg, const score::PanelStatus& v, int index = -1); QAction* addAction(QWidget* widg, const PanelStatus& v); QAction* addAction(QAction* act); diff --git a/src/lib/core/view/Window.cpp b/src/lib/core/view/Window.cpp index 511c5d12df..3b1e65f787 100644 --- a/src/lib/core/view/Window.cpp +++ b/src/lib/core/view/Window.cpp @@ -154,15 +154,17 @@ View::View(QObject* parent) topleftToolbar = new QWidget; topleftToolbar->setLayout(new score::MarginLess); - auto leftLabel = new TitleBar; - leftTabs = new FixedTabWidget; - connect(leftTabs, &FixedTabWidget::actionTriggered, this, [=](QAction* act, bool b) { - leftLabel->setText(act->iconText()); - }); - ((QVBoxLayout*)leftTabs->layout())->insertWidget(0, topleftToolbar); - ((QVBoxLayout*)leftTabs->layout())->insertWidget(1, leftLabel); - rightSplitter = new RectSplitter{Qt::Vertical}; + { + auto leftLabel = new TitleBar; + leftTabs = new FixedTabWidget; + connect(leftTabs, &FixedTabWidget::actionTriggered, this, [=](QAction* act, bool b) { + leftLabel->setText(act->iconText()); + }); + ((QVBoxLayout*)leftTabs->layout())->insertWidget(0, topleftToolbar); + ((QVBoxLayout*)leftTabs->layout())->insertWidget(1, leftLabel); + } + auto rect = QGuiApplication::primaryScreen()->availableGeometry(); this->resize( static_cast(rect.width() * 0.75), static_cast(rect.height() * 0.75)); @@ -230,7 +232,20 @@ View::View(QObject* parent) } }); } - totalWidg->addWidget(rightSplitter); + + { + auto rightLabel = new TitleBar; + rightTabs = new FixedTabWidget; + + rightSplitter = new RectSplitter{Qt::Vertical}; + rightSplitter->setContentsMargins(0, 0, 0, 0); + + connect( + rightTabs, &FixedTabWidget::actionTriggered, this, + [=](QAction* act, bool b) { rightLabel->setText(act->iconText()); }); + ((QVBoxLayout*)rightTabs->layout())->insertWidget(0, rightLabel); + } + totalWidg->addWidget(rightTabs); setCentralWidget(totalWidg); connect( @@ -302,7 +317,24 @@ void View::setupPanel(PanelDelegate* v) break; } case Qt::RightDockWidgetArea: { - rightSplitter->insertWidget(0, w); + auto status = v->defaultPanelStatus(); + if(status.prettyName == QObject::tr("Inspector")) + { + m_inspectorPanel = v; + } + else if(status.prettyName == QObject::tr("Objects")) + { + m_objectPanel = v; + } + else if(status.prettyName == QObject::tr("Info")) + { + m_infoPanel = v; + } + else + { + auto [idx, act] = rightTabs->addTab(w, v->defaultPanelStatus()); + toggle = act; + } break; } @@ -331,38 +363,57 @@ void View::setupPanel(PanelDelegate* v) void View::allPanelsAdded() { auto splitter = (RectSplitter*)centralWidget(); + std::map inspectorPanels; for(auto& panel : score::GUIAppContext().panels()) { - if(panel.defaultPanelStatus().prettyName == QObject::tr("Inspector")) + // rightTabs->addTab(panel.widget(), panel.defaultPanelStatus()); + //rightSplitter->insertWidget(1, panel.widget()); + + // auto act + // = bottomTabs->addAction(rightSplitter->widget(1), panel.defaultPanelStatus()); + // bottomTabs->actionGroup()->removeAction(act); + // act->setChecked(true); + // connect(act, &QAction::toggled, this, [splitter](bool ok) { + // QList sz = splitter->sizes(); + // if(ok) + // { + // if(sz[2] <= 1) + // { + // sz[2] = 200; + // splitter->setSizes(sz); + // } + // } + // else + // { + // sz[2] = 0; + // splitter->setSizes(sz); + // } + // }); + } + + rightSplitter->addWidget(m_objectPanel->widget()); + rightSplitter->addWidget(m_inspectorPanel->widget()); + rightSplitter->addWidget(m_infoPanel->widget()); + { + auto [idx, toggle] + = rightTabs->addTab(rightSplitter, m_inspectorPanel->defaultPanelStatus(), 0); + + if(toggle) { - rightSplitter->insertWidget(1, panel.widget()); - - auto act - = bottomTabs->addAction(rightSplitter->widget(1), panel.defaultPanelStatus()); - bottomTabs->actionGroup()->removeAction(act); - act->setChecked(true); - connect(act, &QAction::toggled, this, [splitter](bool ok) { - QList sz = splitter->sizes(); - if(ok) - { - if(sz[2] <= 1) - { - sz[2] = 200; - splitter->setSizes(sz); - } - } - else - { - sz[2] = 0; - splitter->setSizes(sz); - } - }); - break; + auto& mw = m_inspectorPanel->context().menus.get().at(score::Menus::Windows()); + addAction(toggle); + mw.menu()->addAction(toggle); + + // Maybe show the panel + if(m_inspectorPanel->defaultPanelStatus().shown) + toggle->toggle(); } } // Show the device explorer first leftTabs->toolbar()->actions().front()->trigger(); + // Show the inspector first + rightTabs->toolbar()->actions().front()->trigger(); QTimer::singleShot(100, this, [=] { int w = splitter->width(); { diff --git a/src/lib/core/view/Window.hpp b/src/lib/core/view/Window.hpp index 20948b92c5..167228e4fc 100644 --- a/src/lib/core/view/Window.hpp +++ b/src/lib/core/view/Window.hpp @@ -72,7 +72,9 @@ class SCORE_LIB_BASE_EXPORT View final : public QMainWindow QWidget* centralDocumentWidget{}; QSplitter* rightSplitter{}; QWidget* topleftToolbar{}; + QWidget* topRightToolbar{}; FixedTabWidget* leftTabs{}; + FixedTabWidget* rightTabs{}; // QTabWidget* rightTabs{}; FixedTabWidget* bottomTabs{}; QTabWidget* centralTabs{}; @@ -89,6 +91,10 @@ class SCORE_LIB_BASE_EXPORT View final : public QMainWindow Presenter* m_presenter{}; QLabel* m_status{}; + + PanelDelegate* m_objectPanel{}; + PanelDelegate* m_inspectorPanel{}; + PanelDelegate* m_infoPanel{}; }; } From ed8a1a18c378c8134a7d7f06994eb4acbfe0995f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Micha=C3=ABl=20Celerier?= Date: Sat, 10 Jan 2026 22:43:20 -0500 Subject: [PATCH 2/3] script: dock script editors inside the right pane --- src/lib/core/view/FixedTabWidget.hpp | 2 +- src/lib/core/view/Window.cpp | 19 ++++++----- src/lib/core/view/Window.hpp | 9 ++--- .../score-lib-process/Effect/EffectLayer.cpp | 33 +++++++++++++++++-- .../score-plugin-js/JS/ConsolePanel.cpp | 2 +- 5 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/lib/core/view/FixedTabWidget.hpp b/src/lib/core/view/FixedTabWidget.hpp index 7116b3dfc6..0412f014f3 100644 --- a/src/lib/core/view/FixedTabWidget.hpp +++ b/src/lib/core/view/FixedTabWidget.hpp @@ -14,7 +14,7 @@ class QActionGroup; namespace score { -class FixedTabWidget : public QWidget +class SCORE_LIB_BASE_EXPORT FixedTabWidget : public QWidget { W_OBJECT(FixedTabWidget) public: diff --git a/src/lib/core/view/Window.cpp b/src/lib/core/view/Window.cpp index 3b1e65f787..67e0189117 100644 --- a/src/lib/core/view/Window.cpp +++ b/src/lib/core/view/Window.cpp @@ -1,6 +1,7 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include "HelperPanelDelegate.hpp" +#include "ScriptPanelDelegate.hpp" #include #include @@ -320,15 +321,15 @@ void View::setupPanel(PanelDelegate* v) auto status = v->defaultPanelStatus(); if(status.prettyName == QObject::tr("Inspector")) { - m_inspectorPanel = v; + inspectorPanel = v; } else if(status.prettyName == QObject::tr("Objects")) { - m_objectPanel = v; + objectPanel = v; } else if(status.prettyName == QObject::tr("Info")) { - m_infoPanel = v; + infoPanel = v; } else { @@ -391,21 +392,21 @@ void View::allPanelsAdded() // }); } - rightSplitter->addWidget(m_objectPanel->widget()); - rightSplitter->addWidget(m_inspectorPanel->widget()); - rightSplitter->addWidget(m_infoPanel->widget()); + rightSplitter->addWidget(objectPanel->widget()); + rightSplitter->addWidget(inspectorPanel->widget()); + rightSplitter->addWidget(infoPanel->widget()); { auto [idx, toggle] - = rightTabs->addTab(rightSplitter, m_inspectorPanel->defaultPanelStatus(), 0); + = rightTabs->addTab(rightSplitter, inspectorPanel->defaultPanelStatus(), 0); if(toggle) { - auto& mw = m_inspectorPanel->context().menus.get().at(score::Menus::Windows()); + auto& mw = inspectorPanel->context().menus.get().at(score::Menus::Windows()); addAction(toggle); mw.menu()->addAction(toggle); // Maybe show the panel - if(m_inspectorPanel->defaultPanelStatus().shown) + if(inspectorPanel->defaultPanelStatus().shown) toggle->toggle(); } } diff --git a/src/lib/core/view/Window.hpp b/src/lib/core/view/Window.hpp index 167228e4fc..9c2ef0b69b 100644 --- a/src/lib/core/view/Window.hpp +++ b/src/lib/core/view/Window.hpp @@ -80,6 +80,11 @@ class SCORE_LIB_BASE_EXPORT View final : public QMainWindow QTabWidget* centralTabs{}; QWidget* transportBar{}; + PanelDelegate* objectPanel{}; + PanelDelegate* inspectorPanel{}; + PanelDelegate* infoPanel{}; + PanelDelegate* scriptPanel{}; + private: bool event(QEvent* event) override; void changeEvent(QEvent*) override; @@ -91,10 +96,6 @@ class SCORE_LIB_BASE_EXPORT View final : public QMainWindow Presenter* m_presenter{}; QLabel* m_status{}; - - PanelDelegate* m_objectPanel{}; - PanelDelegate* m_inspectorPanel{}; - PanelDelegate* m_infoPanel{}; }; } diff --git a/src/plugins/score-lib-process/Effect/EffectLayer.cpp b/src/plugins/score-lib-process/Effect/EffectLayer.cpp index 7bbd134f6f..16e640fdad 100644 --- a/src/plugins/score-lib-process/Effect/EffectLayer.cpp +++ b/src/plugins/score-lib-process/Effect/EffectLayer.cpp @@ -1,5 +1,10 @@ #include "EffectLayer.hpp" +#include "core/view/FixedTabWidget.hpp" +#include "core/view/Window.hpp" +#include "score/actions/MenuManager.hpp" +#include "score/plugins/panel/PanelDelegate.hpp" + #include #include #include @@ -17,10 +22,12 @@ #include #include +#include #include #include +#include #include W_OBJECT_IMPL(Process::EffectLayerPresenter) @@ -123,14 +130,36 @@ void setupScriptUI( if(auto win = fact.makeScriptUI(proc, ctx, nullptr)) { const_cast(proc.scriptUI) = win; - win->show(); + + if(auto score_view = static_cast(score::GUIAppContext().mainWindow)) + { + auto [idx, toggle] = score_view->rightTabs->addTab( + win, score::PanelStatus{ + false, true, Qt::RightDockWidgetArea, -100000, proc.prettyName(), + "script", QKeySequence{}}); + + auto& mw = ctx.app.menus.get().at(score::Menus::Windows()); + score_view->addAction(toggle); + mw.menu()->addAction(toggle); + toggle->toggle(); + + score_view->rightTabs->toolbar()->actions().back()->trigger(); + + QObject::connect( + win, &QWidget::destroyed, score_view, [&ctx, score_view, toggle] { + auto& mw = ctx.app.menus.get().at(score::Menus::Windows()); + mw.menu()->removeAction(toggle); + score_view->removeAction(toggle); + score_view->rightTabs->toolbar()->removeAction(toggle); + score_view->rightTabs->toolbar()->actions().front()->trigger(); + }); + } } } else { if(auto win = proc.scriptUI) { - win->close(); delete win; const_cast(proc.scriptUI) = nullptr; } diff --git a/src/plugins/score-plugin-js/JS/ConsolePanel.cpp b/src/plugins/score-plugin-js/JS/ConsolePanel.cpp index 64daab87bf..73c600b267 100644 --- a/src/plugins/score-plugin-js/JS/ConsolePanel.cpp +++ b/src/plugins/score-plugin-js/JS/ConsolePanel.cpp @@ -209,7 +209,7 @@ const score::PanelStatus& PanelDelegate::defaultPanelStatus() const static const score::PanelStatus status{ false, false, - Qt::BottomDockWidgetArea, + Qt::RightDockWidgetArea, 0, QObject::tr("Console"), "console", From cec5c3154659f2eb96af968ad4d9c7b3d61c4c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Micha=C3=ABl=20Celerier?= Date: Sat, 10 Jan 2026 22:43:35 -0500 Subject: [PATCH 3/3] gfx: use default prettyName implementation --- src/lib/core/view/ScriptPanelDelegate.hpp | 30 +++++++++++++++++++ src/lib/core/view/Window.cpp | 1 - .../score-plugin-gfx/Gfx/Filter/Process.cpp | 5 ---- .../score-plugin-gfx/Gfx/Filter/Process.hpp | 1 - 4 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 src/lib/core/view/ScriptPanelDelegate.hpp diff --git a/src/lib/core/view/ScriptPanelDelegate.hpp b/src/lib/core/view/ScriptPanelDelegate.hpp new file mode 100644 index 0000000000..3cc2d3bb94 --- /dev/null +++ b/src/lib/core/view/ScriptPanelDelegate.hpp @@ -0,0 +1,30 @@ +#pragma once +#include + +#include +#include + +namespace score +{ + +class ScriptPanelDelegate : public PanelDelegate +{ +public: + ScriptPanelDelegate(const score::GUIApplicationContext& ctx) + : PanelDelegate{ctx} + { + widg = new QWidget; + } + + QWidget* widget() override { return widg; } + + const PanelStatus& defaultPanelStatus() const override + { + static const PanelStatus stat{ + false, true, Qt::RightDockWidgetArea, -100000, + "Script", "script", QKeySequence("Ctrl+Shift+S")}; + return stat; + } + QWidget* widg{}; +}; +} diff --git a/src/lib/core/view/Window.cpp b/src/lib/core/view/Window.cpp index 67e0189117..3cc32813af 100644 --- a/src/lib/core/view/Window.cpp +++ b/src/lib/core/view/Window.cpp @@ -1,7 +1,6 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include "HelperPanelDelegate.hpp" -#include "ScriptPanelDelegate.hpp" #include #include diff --git a/src/plugins/score-plugin-gfx/Gfx/Filter/Process.cpp b/src/plugins/score-plugin-gfx/Gfx/Filter/Process.cpp index a1737472bd..5dd85036b5 100644 --- a/src/plugins/score-plugin-gfx/Gfx/Filter/Process.cpp +++ b/src/plugins/score-plugin-gfx/Gfx/Filter/Process.cpp @@ -176,11 +176,6 @@ Process::Preset Model::savePreset() const noexcept return p; } -QString Model::prettyName() const noexcept -{ - return tr("GFX Filter"); -} - Process::Descriptor ProcessFactory::descriptor(QString path) const noexcept { return ISFHelpers::descriptorFromISFFile(path); diff --git a/src/plugins/score-plugin-gfx/Gfx/Filter/Process.hpp b/src/plugins/score-plugin-gfx/Gfx/Filter/Process.hpp index a6e04b48c2..2d34084b84 100644 --- a/src/plugins/score-plugin-gfx/Gfx/Filter/Process.hpp +++ b/src/plugins/score-plugin-gfx/Gfx/Filter/Process.hpp @@ -69,7 +69,6 @@ class Model final : public Process::ProcessModel private: void loadPreset(const Process::Preset& preset) override; Process::Preset savePreset() const noexcept override; - QString prettyName() const noexcept override; ShaderSource m_program; ProcessedProgram m_processedProgram;