From 3bacff48ea070c617c515c22de03f7d57a991bb6 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Wed, 27 Nov 2024 19:55:36 +0200 Subject: [PATCH] EffectComposer: Move code editor tabs to Qml side Task-number: QDS-14141 Change-Id: I8edb70f7773723e4f87cbed7ed0e766362917a7d Reviewed-by: Mahmoud Badri Reviewed-by: Miikka Heikkinen --- .../CodeEditorTabs.qml | 104 ++++++++++++++++++ .../effectshaderscodeeditor.cpp | 98 +++++++++++++++-- .../effectcomposer/effectshaderscodeeditor.h | 18 ++- 3 files changed, 208 insertions(+), 12 deletions(-) create mode 100644 share/qtcreator/qmldesigner/effectComposerQmlSources/CodeEditorTabs.qml diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/CodeEditorTabs.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/CodeEditorTabs.qml new file mode 100644 index 00000000000..897023a1715 --- /dev/null +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/CodeEditorTabs.qml @@ -0,0 +1,104 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import StudioTheme as StudioTheme + +Rectangle { + id: root + + property var rootEditor: shaderEditor + property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle + + color: StudioTheme.Values.themeToolbarBackground + height: rowLayout.height + + RowLayout { + id: rowLayout + + width: parent.width + anchors.verticalCenter: parent.verticalCenter + spacing: StudioTheme.Values.controlGap + + TabButton { + text: qsTr("Fragment Shader") + tabId: "FRAGMENT" + } + + TabButton { + text: qsTr("Vertex Shader") + tabId: "VERTEX" + } + + Item { + Layout.fillWidth: true + Layout.preferredHeight: 1 + } + } + + component TabButton: Label { + id: tabButton + + required property string tabId + readonly property bool selected: rootEditor.selectedShader === tabId + + Layout.preferredHeight: 40 + Layout.preferredWidth: 120 + + font.pixelSize: StudioTheme.Values.mediumFont + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + padding: 10 + + color: { + if (!tabButton.enabled) + return root.style.text.disabled + + if (tabButton.selected) + return root.style.text.selectedText + + return root.style.text.idle + } + + background: Rectangle { + color: { + if (!tabButton.enabled) + return "transparent" + + if (tabItemMouseArea.containsMouse && tabButton.selected) + return root.style.interactionHover + + if (tabButton.selected) + return root.style.interaction + + if (tabItemMouseArea.containsMouse) + return root.style.background.hover + + return root.style.background.idle + } + + border.width: 1 + border.color: { + if (!tabButton.enabled) + return "transparent" + + if (tabButton.selected) + return root.style.border.interaction + + if (tabItemMouseArea.containsMouse) + return root.style.border.hover + + return root.style.border.idle + } + } + + MouseArea { + id: tabItemMouseArea + hoverEnabled: true + anchors.fill: parent + onClicked: rootEditor.selectedShader = tabButton.tabId + } + } +} diff --git a/src/plugins/effectcomposer/effectshaderscodeeditor.cpp b/src/plugins/effectcomposer/effectshaderscodeeditor.cpp index a229d9e6d25..b38c495a9a0 100644 --- a/src/plugins/effectcomposer/effectshaderscodeeditor.cpp +++ b/src/plugins/effectcomposer/effectshaderscodeeditor.cpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include namespace { @@ -36,6 +36,11 @@ namespace { inline constexpr char EFFECTCOMPOSER_LIVE_UPDATE_KEY[] = "EffectComposer/CodeEditor/LiveUpdate"; inline constexpr char OBJECT_NAME_EFFECTCOMPOSER_SHADER_HEADER[] = "QQuickWidgetEffectComposerCodeEditorHeader"; +inline constexpr char OBJECT_NAME_EFFECTCOMPOSER_SHADER_EDITOR_TABS[] + = "QQuickWidgetEffectComposerCodeEditorTabs"; + +inline constexpr char EFFECTCOMPOSER_VERTEX_ID[] = "VERTEX"; +inline constexpr char EFFECTCOMPOSER_FRAGMENT_ID[] = "FRAGMENT"; QString propertyEditorResourcesPath() { @@ -71,6 +76,7 @@ EffectShadersCodeEditor::~EffectShadersCodeEditor() close(); m_headerWidget->setSource({}); + m_qmlTabWidget->setSource({}); } void EffectShadersCodeEditor::showWidget() @@ -121,12 +127,12 @@ void EffectShadersCodeEditor::setupShader(ShaderEditorData *data) if (m_currentEditorData == data) return; - while (m_tabWidget->count()) - m_tabWidget->removeTab(0); + auto oldEditorData = m_currentEditorData; + m_currentEditorData = data; if (data) { - m_tabWidget->addTab(data->fragmentEditor.get(), tr("Fragment Shader")); - m_tabWidget->addTab(data->vertexEditor.get(), tr("Vertex Shader")); + m_stackedWidget->addWidget(data->fragmentEditor.get()); + m_stackedWidget->addWidget(data->vertexEditor.get()); selectNonEmptyShader(data); setUniformsModel(data->tableModel); @@ -134,7 +140,10 @@ void EffectShadersCodeEditor::setupShader(ShaderEditorData *data) setUniformsModel(nullptr); } - m_currentEditorData = data; + if (oldEditorData) { + m_stackedWidget->removeWidget(oldEditorData->fragmentEditor.get()); + m_stackedWidget->removeWidget(oldEditorData->vertexEditor.get()); + } } void EffectShadersCodeEditor::cleanFromData(ShaderEditorData *data) @@ -143,6 +152,20 @@ void EffectShadersCodeEditor::cleanFromData(ShaderEditorData *data) setupShader(nullptr); } +void EffectShadersCodeEditor::selectShader(const QString &shaderName) +{ + using namespace Qt::StringLiterals; + if (!m_currentEditorData) + return; + EffectCodeEditorWidget *editor = nullptr; + if (shaderName == EFFECTCOMPOSER_FRAGMENT_ID) + editor = m_currentEditorData->fragmentEditor.get(); + else if (shaderName == EFFECTCOMPOSER_VERTEX_ID) + editor = m_currentEditorData->vertexEditor.get(); + + m_stackedWidget->setCurrentWidget(editor); +} + ShaderEditorData *EffectShadersCodeEditor::createEditorData( const QString &fragmentDocument, const QString &vertexDocument, @@ -229,20 +252,32 @@ void EffectShadersCodeEditor::setupUIComponents() { QVBoxLayout *verticalLayout = new QVBoxLayout(this); QSplitter *splitter = new QSplitter(this); - m_tabWidget = new QTabWidget(this); + QWidget *tabComplexWidget = new QWidget(this); + QVBoxLayout *tabsLayout = new QVBoxLayout(tabComplexWidget); + m_stackedWidget = new QStackedWidget(tabComplexWidget); splitter->setOrientation(Qt::Vertical); createHeader(); + createQmlTabs(); verticalLayout->setContentsMargins(0, 0, 0, 0); verticalLayout->addWidget(splitter); + tabsLayout->addWidget(m_qmlTabWidget); + tabsLayout->addWidget(m_stackedWidget); + splitter->addWidget(m_headerWidget.get()); - splitter->addWidget(m_tabWidget); + splitter->addWidget(tabComplexWidget); splitter->setCollapsible(0, false); splitter->setCollapsible(1, false); + connect( + m_stackedWidget.get(), + &QStackedWidget::currentChanged, + this, + &EffectShadersCodeEditor::onEditorWidgetChanged); + this->resize(660, 240); } @@ -291,11 +326,30 @@ void EffectShadersCodeEditor::createHeader() "editableCompositionsModel", QVariant::fromValue(m_editableNodesModel.get())); } +void EffectShadersCodeEditor::createQmlTabs() +{ + m_qmlTabWidget = new StudioQuickWidget(this); + m_qmlTabWidget->quickWidget()->setObjectName(OBJECT_NAME_EFFECTCOMPOSER_SHADER_EDITOR_TABS); + m_qmlTabWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + QmlDesigner::Theme::setupTheme(m_qmlTabWidget->engine()); + m_qmlTabWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); + m_qmlTabWidget->engine()->addImportPath(EffectUtils::nodesSourcesPath() + "/common"); + m_qmlTabWidget->setClearColor(QmlDesigner::Theme::getColor( + QmlDesigner::Theme::Color::QmlDesigner_BackgroundColorDarkAlternate)); + m_qmlTabWidget->rootContext()->setContextProperty("shaderEditor", QVariant::fromValue(this)); + m_qmlTabWidget->setFixedHeight(43); +} + void EffectShadersCodeEditor::loadQml() { const QString headerQmlPath = EffectComposerWidget::qmlSourcesPath() + "/CodeEditorHeader.qml"; QTC_ASSERT(QFileInfo::exists(headerQmlPath), return); m_headerWidget->setSource(QUrl::fromLocalFile(headerQmlPath)); + + const QString editorTabsQmlPath = EffectComposerWidget::qmlSourcesPath() + + "/CodeEditorTabs.qml"; + QTC_ASSERT(QFileInfo::exists(editorTabsQmlPath), return); + m_qmlTabWidget->setSource(QUrl::fromLocalFile(editorTabsQmlPath)); } void EffectShadersCodeEditor::setUniformsModel(EffectComposerUniformsTableModel *uniformsTable) @@ -316,13 +370,37 @@ void EffectShadersCodeEditor::selectNonEmptyShader(ShaderEditorData *data) ? data->fragmentEditor.get() : data->vertexEditor.get(); - m_tabWidget->setCurrentWidget(widgetToSelect); + m_stackedWidget->setCurrentWidget(widgetToSelect); widgetToSelect->setFocus(); } +void EffectShadersCodeEditor::setSelectedShaderName(const QString &shaderName) +{ + if (m_selectedShaderName == shaderName) + return; + m_selectedShaderName = shaderName; + emit selectedShaderChanged(m_selectedShaderName); +} + +void EffectShadersCodeEditor::onEditorWidgetChanged() +{ + QWidget *currentWidget = m_stackedWidget->currentWidget(); + if (!m_currentEditorData || !currentWidget) { + setSelectedShaderName({}); + return; + } + + if (currentWidget == m_currentEditorData->fragmentEditor.get()) + setSelectedShaderName(EFFECTCOMPOSER_FRAGMENT_ID); + else if (currentWidget == m_currentEditorData->vertexEditor.get()) + setSelectedShaderName(EFFECTCOMPOSER_VERTEX_ID); + else + setSelectedShaderName({}); +} + EffectCodeEditorWidget *EffectShadersCodeEditor::currentEditor() const { - QWidget *currentTab = m_tabWidget->currentWidget(); + QWidget *currentTab = m_stackedWidget->currentWidget(); if (!m_currentEditorData || !currentTab) return nullptr; diff --git a/src/plugins/effectcomposer/effectshaderscodeeditor.h b/src/plugins/effectcomposer/effectshaderscodeeditor.h index 218ab58046b..afb63bf77dd 100644 --- a/src/plugins/effectcomposer/effectshaderscodeeditor.h +++ b/src/plugins/effectcomposer/effectshaderscodeeditor.h @@ -10,7 +10,7 @@ #include QT_FORWARD_DECLARE_CLASS(QSettings) -QT_FORWARD_DECLARE_CLASS(QTabWidget) +QT_FORWARD_DECLARE_CLASS(QStackedWidget) class StudioQuickWidget; @@ -42,6 +42,12 @@ class EffectShadersCodeEditor : public QWidget Q_OBJECT Q_PROPERTY(bool liveUpdate READ liveUpdate WRITE setLiveUpdate NOTIFY liveUpdateChanged) + Q_PROPERTY( + QString selectedShader + MEMBER m_selectedShaderName + WRITE selectShader + NOTIFY selectedShaderChanged) + public: EffectShadersCodeEditor(const QString &title = tr("Untitled Editor"), QWidget *parent = nullptr); ~EffectShadersCodeEditor() override; @@ -59,6 +65,8 @@ public: void setupShader(ShaderEditorData *data); void cleanFromData(ShaderEditorData *data); + void selectShader(const QString &shaderName); + ShaderEditorData *createEditorData( const QString &fragmentDocument, const QString &vertexDocument, @@ -73,6 +81,7 @@ signals: void liveUpdateChanged(bool); void rebakeRequested(); void openedChanged(bool); + void selectedShaderChanged(const QString &); protected: using QWidget::show; @@ -86,21 +95,26 @@ private: void writeLiveUpdateSettings(); void readAndApplyLiveUpdateSettings(); void createHeader(); + void createQmlTabs(); void loadQml(); void setUniformsModel(EffectComposerUniformsTableModel *uniforms); void selectNonEmptyShader(ShaderEditorData *data); + void setSelectedShaderName(const QString &shaderName); + void onEditorWidgetChanged(); EffectCodeEditorWidget *currentEditor() const; QSettings *m_settings = nullptr; QPointer m_headerWidget; - QPointer m_tabWidget; + QPointer m_qmlTabWidget; + QPointer m_stackedWidget; QPointer m_defaultTableModel; QPointer m_editableNodesModel; ShaderEditorData *m_currentEditorData = nullptr; bool m_liveUpdate = false; bool m_opened = false; + QString m_selectedShaderName; }; } // namespace EffectComposer