EffectComposer: Move code editor tabs to Qml side

Task-number: QDS-14141
Change-Id: I8edb70f7773723e4f87cbed7ed0e766362917a7d
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
This commit is contained in:
Ali Kianian
2024-11-27 19:55:36 +02:00
parent 76a99f5a66
commit 3bacff48ea
3 changed files with 208 additions and 12 deletions

View File

@@ -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
}
}
}

View File

@@ -28,7 +28,7 @@
#include <QPlainTextEdit>
#include <QSettings>
#include <QSplitter>
#include <QTabWidget>
#include <QStackedWidget>
#include <QVBoxLayout>
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;

View File

@@ -10,7 +10,7 @@
#include <utils/uniqueobjectptr.h>
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<StudioQuickWidget> m_headerWidget;
QPointer<QTabWidget> m_tabWidget;
QPointer<StudioQuickWidget> m_qmlTabWidget;
QPointer<QStackedWidget> m_stackedWidget;
QPointer<EffectComposerUniformsTableModel> m_defaultTableModel;
QPointer<EffectComposerEditableNodesModel> m_editableNodesModel;
ShaderEditorData *m_currentEditorData = nullptr;
bool m_liveUpdate = false;
bool m_opened = false;
QString m_selectedShaderName;
};
} // namespace EffectComposer