QmlDesigner: Make MaterialEditor FullScreen

Task-number: QDS-12368
Change-Id: Ia65ca2cb5c89507b5290a32f1829551cec236192
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
Ali Kianian
2024-06-10 13:24:52 +03:00
parent d90b3cb0bc
commit 5084165703
7 changed files with 317 additions and 231 deletions

View File

@@ -2,12 +2,17 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
import QtQuick import QtQuick
import QtQuick.Controls
import QtCore import QtCore
import HelperWidgets import HelperWidgets
import StudioControls 1.0 as StudioControls
Item { Item {
id: root id: root
property string __previewEnv
property string __previewModel
width: 420 width: 420
height: 420 height: 420
@@ -16,23 +21,18 @@ Item {
signal previewModelChanged(string model) signal previewModelChanged(string model)
// invoked from C++ to refresh material preview image // invoked from C++ to refresh material preview image
function refreshPreview() signal refreshPreview()
{
itemPane.headerItem.refreshPreview()
}
// Called from C++ to close context menu on focus out // Called from C++ to close context menu on focus out
function closeContextMenu() function closeContextMenu()
{ {
itemPane.headerItem.closeContextMenu()
Controller.closeContextMenu() Controller.closeContextMenu()
} }
// Called from C++ to initialize preview menu checkmarks // Called from C++ to initialize preview menu checkmarks
function initPreviewData(env, model) function initPreviewData(env, model) {
{ root.__previewEnv = env
itemPane.headerItem.previewEnv = env root.__previewModel = model
itemPane.headerItem.previewModel = model
} }
MaterialEditorToolBar { MaterialEditorToolBar {
@@ -47,56 +47,105 @@ Item {
id: settings id: settings
property var topSection property var topSection
property bool dockMode
} }
PropertyEditorPane { StudioControls.SplitView {
id: itemPane id: splitView
readonly property bool isHorizontal: splitView.orientation == Qt.Horizontal
anchors.top: toolbar.bottom anchors.top: toolbar.bottom
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
width: parent.width width: parent.width
orientation: splitView.width > 1000 ? Qt.Horizontal : Qt.Vertical
clip: true clip: true
headerComponent: MaterialEditorTopSection {
id: topSection
onPreviewEnvChanged: root.previewEnvChanged(previewEnv)
onPreviewModelChanged: root.previewModelChanged(previewModel)
Component.onCompleted: topSection.restoreState(settings.topSection)
Component.onDestruction: settings.topSection = topSection.saveState()
}
DynamicPropertiesSection {
propertiesModel: MaterialEditorDynamicPropertiesModel {}
}
Loader { Loader {
id: specificsTwo id: leftSideView
property string theSource: specificQmlData SplitView.fillWidth: leftSideView.visible
SplitView.fillHeight: leftSideView.visible
SplitView.minimumWidth: leftSideView.visible ? 300 : 0
SplitView.minimumHeight: leftSideView.visible ? 300 : 0
width: parent.width active: splitView.isHorizontal
visible: specificsTwo.theSource !== "" visible: leftSideView.active && leftSideView.item
sourceComponent: specificQmlComponent
onTheSourceChanged: { sourceComponent: PreviewComponent {}
specificsTwo.active = false }
specificsTwo.active = true
PropertyEditorPane {
id: itemPane
clip: true
SplitView.fillWidth: !leftSideView.visible
SplitView.fillHeight: true
SplitView.minimumWidth: leftSideView.visible ? 400 : 0
SplitView.maximumWidth: leftSideView.visible ? 800 : -1
headerDocked: !leftSideView.visible && settings.dockMode
headerComponent: MaterialEditorTopSection {
id: topSection
Component.onCompleted: topSection.restoreState(settings.topSection)
Component.onDestruction: settings.topSection = topSection.saveState()
previewComponent: PreviewComponent {}
showImage: !splitView.isHorizontal
}
DynamicPropertiesSection {
propertiesModel: MaterialEditorDynamicPropertiesModel {}
}
Loader {
id: specificsTwo
property string theSource: specificQmlData
width: itemPane.width
visible: specificsTwo.theSource !== ""
sourceComponent: specificQmlComponent
onTheSourceChanged: {
specificsTwo.active = false
specificsTwo.active = true
}
}
Item { // spacer
width: 1
height: 10
visible: specificsTwo.visible
}
Loader {
id: specificsOne
width: itemPane.width
source: specificsUrl
} }
} }
}
Item { // spacer component PreviewComponent : MaterialEditorPreview {
width: 1 id: previewItem
height: 10
visible: specificsTwo.visible
}
Loader { onPreviewEnvChanged: root.previewEnvChanged(previewEnv)
id: specificsOne onPreviewModelChanged: root.previewModelChanged(previewModel)
anchors.left: parent.left
anchors.right: parent.right previewEnv: root.__previewEnv
source: specificsUrl previewModel: root.__previewModel
pinned: settings.dockMode
showPinButton: !leftSideView.visible
onPinnedChanged: settings.dockMode = previewItem.pinned
Connections {
target: root
function onRefreshPreview() {
previewItem.refreshPreview()
}
} }
} }
} }

View File

@@ -0,0 +1,185 @@
// 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 HelperWidgets as HelperWidgets
import StudioControls as StudioControls
import StudioTheme as StudioTheme
Rectangle {
id: root
property string previewEnv
property string previewModel
property alias pinned: pinButton.checked
property alias showPinButton: pinButton.visible
property StudioTheme.ControlStyle buttonStyle: StudioTheme.ViewBarButtonStyle {
// This is how you can override stuff from the control styles
baseIconFontSize: StudioTheme.Values.bigIconFontSize
}
Connections {
target: HelperWidgets.Controller
function onCloseContextMenu() {
root.closeContextMenu()
}
}
implicitHeight: image.height
clip: true
color: "#000000"
// Called from C++ to close context menu on focus out
function closeContextMenu()
{
modelMenu.close()
envMenu.close()
}
function refreshPreview()
{
image.source = ""
image.source = "image://materialEditor/preview"
}
Image {
id: image
anchors.fill: parent
fillMode: Image.PreserveAspectFit
source: "image://materialEditor/preview"
cache: false
smooth: true
sourceSize.width: image.width
sourceSize.height: image.height
Rectangle {
id: toolbarRect
radius: 10
color: StudioTheme.Values.themeToolbarBackground
width: optionsToolbar.width + 2 * toolbarRect.radius
height: optionsToolbar.height + toolbarRect.radius
anchors.left: parent.left
anchors.leftMargin: -toolbarRect.radius
anchors.verticalCenter: parent.verticalCenter
Column {
id: optionsToolbar
spacing: 5
anchors.centerIn: parent
anchors.horizontalCenterOffset: optionsToolbar.spacing
HelperWidgets.AbstractButton {
id: pinButton
style: root.buttonStyle
buttonIcon: pinButton.checked ? StudioTheme.Constants.pin : StudioTheme.Constants.unpin
checkable: true
}
HelperWidgets.AbstractButton {
id: previewEnvMenuButton
style: root.buttonStyle
buttonIcon: StudioTheme.Constants.textures_medium
tooltip: qsTr("Select preview environment.")
onClicked: envMenu.popup()
}
HelperWidgets.AbstractButton {
id: previewModelMenuButton
style: root.buttonStyle
buttonIcon: StudioTheme.Constants.cube_medium
tooltip: qsTr("Select preview model.")
onClicked: modelMenu.popup()
}
}
}
}
StudioControls.Menu {
id: modelMenu
closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside
ListModel {
id: modelMenuModel
ListElement {
modelName: qsTr("Cone")
modelStr: "#Cone"
}
ListElement {
modelName: qsTr("Cube")
modelStr: "#Cube"
}
ListElement {
modelName: qsTr("Cylinder")
modelStr: "#Cylinder"
}
ListElement {
modelName: qsTr("Sphere")
modelStr: "#Sphere"
}
}
Repeater {
model: modelMenuModel
StudioControls.MenuItemWithIcon {
text: modelName
onClicked: {
// Force property change notifications to keep check mark when reselected
root.previewModel = ""
root.previewModel = modelStr
}
checkable: true
checked: root.previewModel === modelStr
}
}
}
StudioControls.Menu {
id: envMenu
closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside
ListModel {
id: envMenuModel
ListElement {
envName: qsTr("Basic")
envStr: "Basic"
}
ListElement {
envName: qsTr("Color")
envStr: "Color"
}
ListElement {
envName: qsTr("Studio")
envStr: "SkyBox=preview_studio"
}
ListElement {
envName: qsTr("Landscape")
envStr: "SkyBox=preview_landscape"
}
}
Repeater {
model: envMenuModel
StudioControls.MenuItemWithIcon {
text: envName
onClicked: {
// Force property change notifications to keep check mark when reselected
root.previewEnv = ""
root.previewEnv = envStr
}
checkable: true
checked: root.previewEnv === envStr
}
}
}
}

View File

@@ -8,201 +8,29 @@ import HelperWidgets as HelperWidgets
import StudioControls as StudioControls import StudioControls as StudioControls
import StudioTheme as StudioTheme import StudioTheme as StudioTheme
SplitView { StudioControls.SplitView {
id: root id: root
property string previewEnv property alias showImage: previewLoader.active
property string previewModel property Component previewComponent: null
property real __spacing: 5 width: parent.width
implicitHeight: showImage ? previewLoader.implicitHeight + nameSection.implicitHeight : nameSection.implicitHeight
property StudioTheme.ControlStyle buttonStyle: StudioTheme.ViewBarButtonStyle {
//This is how you can override stuff from the control styles
baseIconFontSize: StudioTheme.Values.bigIconFontSize
}
function refreshPreview()
{
materialPreview.source = ""
materialPreview.source = "image://materialEditor/preview"
}
// Called from C++ to close context menu on focus out
function closeContextMenu()
{
modelMenu.close()
envMenu.close()
}
anchors.left: parent.left
anchors.right: parent.right
implicitHeight: previewRect.implicitHeight + nameSection.implicitHeight
orientation: Qt.Vertical orientation: Qt.Vertical
handle: Rectangle { Loader {
implicitWidth: root.orientation === Qt.Horizontal ? StudioTheme.Values.splitterThickness : root.width id: previewLoader
implicitHeight: root.orientation === Qt.Horizontal ? root.height : StudioTheme.Values.splitterThickness
color: SplitHandle.pressed ? StudioTheme.Values.themeSliderHandleInteraction
: (SplitHandle.hovered ? StudioTheme.Values.themeSliderHandleHover
: "transparent")
}
StudioControls.Menu {
id: modelMenu
closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside
ListModel {
id: modelMenuModel
ListElement {
modelName: qsTr("Cone")
modelStr: "#Cone"
}
ListElement {
modelName: qsTr("Cube")
modelStr: "#Cube"
}
ListElement {
modelName: qsTr("Cylinder")
modelStr: "#Cylinder"
}
ListElement {
modelName: qsTr("Sphere")
modelStr: "#Sphere"
}
}
Repeater {
model: modelMenuModel
StudioControls.MenuItemWithIcon {
text: modelName
onClicked: {
// Force property change notifications to keep check mark when reselected
root.previewModel = ""
root.previewModel = modelStr
}
checkable: true
checked: root.previewModel === modelStr
}
}
}
StudioControls.Menu {
id: envMenu
closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside
ListModel {
id: envMenuModel
ListElement {
envName: qsTr("Basic")
envStr: "Basic"
}
ListElement {
envName: qsTr("Color")
envStr: "Color"
}
ListElement {
envName: qsTr("Studio")
envStr: "SkyBox=preview_studio"
}
ListElement {
envName: qsTr("Landscape")
envStr: "SkyBox=preview_landscape"
}
}
Repeater {
model: envMenuModel
StudioControls.MenuItemWithIcon {
text: envName
onClicked: {
// Force property change notifications to keep check mark when reselected
root.previewEnv = ""
root.previewEnv = envStr
}
checkable: true
checked: root.previewEnv === envStr
}
}
}
Rectangle {
id: previewRect
SplitView.fillWidth: true SplitView.fillWidth: true
SplitView.minimumWidth: 152 SplitView.minimumWidth: 152
SplitView.preferredHeight: Math.min(root.width * 0.75, 400) SplitView.preferredHeight: previewLoader.visible ? Math.min(root.width * 0.75, 400) : 0
SplitView.minimumHeight: 150 SplitView.minimumHeight: previewLoader.visible ? 150 : 0
implicitHeight: materialPreview.height SplitView.maximumHeight: previewLoader.visible ? 600 : 0
clip: true visible: previewLoader.active && previewLoader.item
color: "#000000"
Image { sourceComponent: root.previewComponent
id: materialPreview
width: root.width
height: previewRect.height
anchors.centerIn: parent
fillMode: Image.PreserveAspectFit
source: "image://materialEditor/preview"
cache: false
smooth: true
sourceSize.width: materialPreview.width
sourceSize.height: materialPreview.height
Rectangle {
id: toolbarRect
radius: 10
color: StudioTheme.Values.themeToolbarBackground
width: optionsToolbar.width + 2 * toolbarRect.radius
height: optionsToolbar.height + toolbarRect.radius
anchors.left: parent.left
anchors.leftMargin: -toolbarRect.radius
anchors.verticalCenter: parent.verticalCenter
Column {
id: optionsToolbar
spacing: root.__spacing
anchors.centerIn: parent
anchors.horizontalCenterOffset: root.__spacing
HelperWidgets.AbstractButton {
id: pinButton
style: buttonStyle
buttonIcon: pinButton.checked ? StudioTheme.Constants.pin : StudioTheme.Constants.unpin
checkable: true
checked: itemPane.headerDocked
onCheckedChanged: itemPane.headerDocked = pinButton.checked
}
HelperWidgets.AbstractButton {
id: previewEnvMenuButton
style: buttonStyle
buttonIcon: StudioTheme.Constants.textures_medium
tooltip: qsTr("Select preview environment.")
onClicked: envMenu.popup()
}
HelperWidgets.AbstractButton {
id: previewModelMenuButton
style: buttonStyle
buttonIcon: StudioTheme.Constants.cube_medium
tooltip: qsTr("Select preview model.")
onClicked: modelMenu.popup()
}
}
}
}
} }
HelperWidgets.Section { HelperWidgets.Section {

View File

@@ -0,0 +1,20 @@
// 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 as QuickControls
import StudioTheme 1.0 as StudioTheme
QuickControls.SplitView {
id: control
property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
handle: Rectangle {
implicitWidth: control.orientation === Qt.Horizontal ? StudioTheme.Values.splitterThickness : control.width
implicitHeight: control.orientation === Qt.Horizontal ? control.height : StudioTheme.Values.splitterThickness
color: QuickControls.SplitHandle.pressed ? control.style.slider.handleInteraction
: (QuickControls.SplitHandle.hovered ? control.style.slider.handleHover
: "transparent")
}
}

View File

@@ -51,6 +51,7 @@ SortFilterModel 1.0 SortFilterModel.qml
SpinBox 1.0 SpinBox.qml SpinBox 1.0 SpinBox.qml
SpinBoxIndicator 1.0 SpinBoxIndicator.qml SpinBoxIndicator 1.0 SpinBoxIndicator.qml
SpinBoxInput 1.0 SpinBoxInput.qml SpinBoxInput 1.0 SpinBoxInput.qml
SplitView 1.0 SplitView.qml
Switch 1.0 Switch.qml Switch 1.0 Switch.qml
TabBar 1.0 TabBar.qml TabBar 1.0 TabBar.qml
TabButton 1.0 TabButton.qml TabButton 1.0 TabButton.qml

View File

@@ -863,10 +863,13 @@ void MaterialEditorView::propertiesAboutToBeRemoved(const QList<AbstractProperty
void MaterialEditorView::requestPreviewRender() void MaterialEditorView::requestPreviewRender()
{ {
if (model() && model()->nodeInstanceView() && m_selectedMaterial.isValid()) { if (model() && model()->nodeInstanceView() && m_selectedMaterial.isValid()) {
static int requestId = 0;
m_previewRequestId = QByteArray(MATERIAL_EDITOR_IMAGE_REQUEST_ID)
+ QByteArray::number(++requestId);
model()->nodeInstanceView()->previewImageDataForGenericNode(m_selectedMaterial, model()->nodeInstanceView()->previewImageDataForGenericNode(m_selectedMaterial,
{}, {},
m_previewSize, m_previewSize,
MATERIAL_EDITOR_IMAGE_REQUEST_ID); m_previewRequestId);
} }
} }
@@ -955,11 +958,10 @@ void MaterialEditorView::modelNodePreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap, const QPixmap &pixmap,
const QByteArray &requestId) const QByteArray &requestId)
{ {
if (node != m_selectedMaterial) if (node != m_selectedMaterial || requestId != m_previewRequestId)
return; return;
if (requestId == MATERIAL_EDITOR_IMAGE_REQUEST_ID) m_qmlBackEnd->updateMaterialPreview(pixmap);
m_qmlBackEnd->updateMaterialPreview(pixmap);
} }
void MaterialEditorView::importsChanged([[maybe_unused]] const Imports &addedImports, void MaterialEditorView::importsChanged([[maybe_unused]] const Imports &addedImports,

View File

@@ -129,6 +129,7 @@ private:
bool m_hasMaterialRoot = false; bool m_hasMaterialRoot = false;
bool m_initializingPreviewData = false; bool m_initializingPreviewData = false;
QSize m_previewSize; QSize m_previewSize;
QByteArray m_previewRequestId;
QPointer<QColorDialog> m_colorDialog; QPointer<QColorDialog> m_colorDialog;
QPointer<ItemLibraryInfo> m_itemLibraryInfo; QPointer<ItemLibraryInfo> m_itemLibraryInfo;