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
import QtQuick
import QtQuick.Controls
import QtCore
import HelperWidgets
import StudioControls 1.0 as StudioControls
Item {
id: root
property string __previewEnv
property string __previewModel
width: 420
height: 420
@@ -16,23 +21,18 @@ Item {
signal previewModelChanged(string model)
// invoked from C++ to refresh material preview image
function refreshPreview()
{
itemPane.headerItem.refreshPreview()
}
signal refreshPreview()
// Called from C++ to close context menu on focus out
function closeContextMenu()
{
itemPane.headerItem.closeContextMenu()
Controller.closeContextMenu()
}
// Called from C++ to initialize preview menu checkmarks
function initPreviewData(env, model)
{
itemPane.headerItem.previewEnv = env
itemPane.headerItem.previewModel = model
function initPreviewData(env, model) {
root.__previewEnv = env
root.__previewModel = model
}
MaterialEditorToolBar {
@@ -47,56 +47,105 @@ Item {
id: settings
property var topSection
property bool dockMode
}
PropertyEditorPane {
id: itemPane
StudioControls.SplitView {
id: splitView
readonly property bool isHorizontal: splitView.orientation == Qt.Horizontal
anchors.top: toolbar.bottom
anchors.bottom: parent.bottom
width: parent.width
orientation: splitView.width > 1000 ? Qt.Horizontal : Qt.Vertical
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 {
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
visible: specificsTwo.theSource !== ""
sourceComponent: specificQmlComponent
active: splitView.isHorizontal
visible: leftSideView.active && leftSideView.item
onTheSourceChanged: {
specificsTwo.active = false
specificsTwo.active = true
sourceComponent: PreviewComponent {}
}
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
width: 1
height: 10
visible: specificsTwo.visible
}
component PreviewComponent : MaterialEditorPreview {
id: previewItem
Loader {
id: specificsOne
anchors.left: parent.left
anchors.right: parent.right
source: specificsUrl
onPreviewEnvChanged: root.previewEnvChanged(previewEnv)
onPreviewModelChanged: root.previewModelChanged(previewModel)
previewEnv: root.__previewEnv
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 StudioTheme as StudioTheme
SplitView {
StudioControls.SplitView {
id: root
property string previewEnv
property string previewModel
property alias showImage: previewLoader.active
property Component previewComponent: null
property real __spacing: 5
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
width: parent.width
implicitHeight: showImage ? previewLoader.implicitHeight + nameSection.implicitHeight : nameSection.implicitHeight
orientation: Qt.Vertical
handle: Rectangle {
implicitWidth: root.orientation === Qt.Horizontal ? StudioTheme.Values.splitterThickness : root.width
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
Loader {
id: previewLoader
SplitView.fillWidth: true
SplitView.minimumWidth: 152
SplitView.preferredHeight: Math.min(root.width * 0.75, 400)
SplitView.minimumHeight: 150
implicitHeight: materialPreview.height
SplitView.preferredHeight: previewLoader.visible ? Math.min(root.width * 0.75, 400) : 0
SplitView.minimumHeight: previewLoader.visible ? 150 : 0
SplitView.maximumHeight: previewLoader.visible ? 600 : 0
clip: true
color: "#000000"
visible: previewLoader.active && previewLoader.item
Image {
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()
}
}
}
}
sourceComponent: root.previewComponent
}
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
SpinBoxIndicator 1.0 SpinBoxIndicator.qml
SpinBoxInput 1.0 SpinBoxInput.qml
SplitView 1.0 SplitView.qml
Switch 1.0 Switch.qml
TabBar 1.0 TabBar.qml
TabButton 1.0 TabButton.qml

View File

@@ -863,10 +863,13 @@ void MaterialEditorView::propertiesAboutToBeRemoved(const QList<AbstractProperty
void MaterialEditorView::requestPreviewRender()
{
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,
{},
m_previewSize,
MATERIAL_EDITOR_IMAGE_REQUEST_ID);
m_previewRequestId);
}
}
@@ -955,11 +958,10 @@ void MaterialEditorView::modelNodePreviewPixmapChanged(const ModelNode &node,
const QPixmap &pixmap,
const QByteArray &requestId)
{
if (node != m_selectedMaterial)
if (node != m_selectedMaterial || requestId != m_previewRequestId)
return;
if (requestId == MATERIAL_EDITOR_IMAGE_REQUEST_ID)
m_qmlBackEnd->updateMaterialPreview(pixmap);
m_qmlBackEnd->updateMaterialPreview(pixmap);
}
void MaterialEditorView::importsChanged([[maybe_unused]] const Imports &addedImports,

View File

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