From 17c938a38562aa51c9624ce4fc4fe36c110f45dd Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 15 May 2025 15:18:02 +0300 Subject: [PATCH] QmlDesigner: Remember 3D view splitter positions Splitter positions for each split preset in 3D view are stored in tool state of 3D scene, so they are remembered like all other tool states in 3D view. Refactored split presets to use enums instead of strings to facilitate tool state handling. It should also be slightly more efficient. Fixes: QDS-15343 Change-Id: I25619f2df2530875f73762bb6f65a133e326bff3 Reviewed-by: Mahmoud Badri --- .../components/edit3d/edit3dview.cpp | 30 +- .../components/edit3d/edit3dview.h | 10 +- .../qmlpuppet/mockfiles/qt6/EditView3D.qml | 271 ++++++++++-------- .../mockfiles/qt6/ViewportResizer.qml | 1 - 4 files changed, 173 insertions(+), 139 deletions(-) diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index 3555a4bc3df..c5f44999f0f 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -274,9 +274,9 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState) m_syncEnvBackgroundAction->action()->setChecked(false); if (sceneState.contains(activePresetKey)) - syncActivePresetCheckedState(sceneState[activePresetKey].toString()); + syncActivePresetCheckedState(static_cast(sceneState[activePresetKey].toInt())); else - syncActivePresetCheckedState("Single"); + syncActivePresetCheckedState(ViewPreset::Single); // Selection context change updates visible and enabled states SelectionContext selectionContext(this); @@ -729,14 +729,14 @@ void Edit3DView::createViewportPresetActions() auto createViewportPresetAction = [this](std::unique_ptr &targetAction, const QByteArray &id, const QString &label, - const QString &opCode, + const ViewPreset &opCode, const QIcon &icon, bool isChecked) { auto operation = [this, &targetAction, opCode](const SelectionContext &) { for (Edit3DAction *action : std::as_const(m_viewportPresetActions)) action->action()->setChecked(action->menuId() == targetAction->menuId()); - emitView3DAction(View3DActionType::ViewportPreset, opCode); + emitView3DAction(View3DActionType::ViewportPreset, int(opCode)); }; targetAction = std::make_unique( @@ -752,15 +752,15 @@ void Edit3DView::createViewportPresetActions() }; createViewportPresetAction(m_viewportPresetSingleAction, Constants::EDIT3D_PRESET_SINGLE, - Tr::tr("Single"), "Single", contextIcon(DesignerIcons::MultiViewPort1Icon), true); + Tr::tr("Single"), ViewPreset::Single, contextIcon(DesignerIcons::MultiViewPort1Icon), true); createViewportPresetAction(m_viewportPresetQuadAction, Constants::EDIT3D_PRESET_QUAD, - Tr::tr("Quad"), "Quad", contextIcon(DesignerIcons::MultiViewPort2x2Icon), false); + Tr::tr("Quad"), ViewPreset::Quad, contextIcon(DesignerIcons::MultiViewPort2x2Icon), false); createViewportPresetAction(m_viewportPreset3Left1RightAction, Constants::EDIT3D_PRESET_3LEFT1RIGHT, - Tr::tr("3 Left 1 Right"), "3Left1Right", contextIcon(DesignerIcons::MultiViewPort3plus1Icon), false); + Tr::tr("3 Left 1 Right"), ViewPreset::ThreeLeftOneRight, contextIcon(DesignerIcons::MultiViewPort3plus1Icon), false); createViewportPresetAction(m_viewportPreset2HorizontalAction, Constants::EDIT3D_PRESET_2HORIZONTAL, - Tr::tr("2 Horizontal"), "2Horizontal", contextIcon(DesignerIcons::MultiViewPort2hlIcon), false); + Tr::tr("2 Horizontal"), ViewPreset::TwoHorizontal, contextIcon(DesignerIcons::MultiViewPort2hlIcon), false); createViewportPresetAction(m_viewportPreset2VerticalAction, Constants::EDIT3D_PRESET_2VERTICAL, - Tr::tr("2 Vertical"), "2Vertical", contextIcon(DesignerIcons::MultiViewPort2vlIcon), false); + Tr::tr("2 Vertical"), ViewPreset::TwoVertical, contextIcon(DesignerIcons::MultiViewPort2vlIcon), false); m_viewportPresetActions << m_viewportPresetSingleAction.get(); m_viewportPresetActions << m_viewportPresetQuadAction.get(); @@ -921,13 +921,13 @@ void Edit3DView::syncCameraSpeedToNewView() setCameraSpeedAuxData(speed, multiplier); } -void Edit3DView::syncActivePresetCheckedState(const QString &preset) +void Edit3DView::syncActivePresetCheckedState(ViewPreset preset) { - m_viewportPresetSingleAction->action()->setChecked(preset == "Single"); - m_viewportPresetQuadAction->action()->setChecked(preset == "Quad"); - m_viewportPreset3Left1RightAction->action()->setChecked(preset == "3Left1Right"); - m_viewportPreset2HorizontalAction->action()->setChecked(preset == "2Horizontal"); - m_viewportPreset2VerticalAction->action()->setChecked(preset == "2Vertical"); + m_viewportPresetSingleAction->action()->setChecked(preset == ViewPreset::Single); + m_viewportPresetQuadAction->action()->setChecked(preset == ViewPreset::Quad); + m_viewportPreset3Left1RightAction->action()->setChecked(preset == ViewPreset::ThreeLeftOneRight); + m_viewportPreset2HorizontalAction->action()->setChecked(preset == ViewPreset::TwoHorizontal); + m_viewportPreset2VerticalAction->action()->setChecked(preset == ViewPreset::TwoVertical); } QmlObjectNode Edit3DView::currentSceneEnv() diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index fa1da27db36..2179506406f 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -135,6 +135,14 @@ private: None }; + enum class ViewPreset { + Single, + Quad, + ThreeLeftOneRight, + TwoHorizontal, + TwoVertical + }; + void registerEdit3DAction(Edit3DAction *action); void createEdit3DWidget(); @@ -151,7 +159,7 @@ private: void createViewportPresetActions(); void createSeekerSliderAction(); void syncCameraSpeedToNewView(); - void syncActivePresetCheckedState(const QString &preset); + void syncActivePresetCheckedState(ViewPreset preset); QmlObjectNode currentSceneEnv(); void storeCurrentSceneEnvironment(); diff --git a/src/tools/qmlpuppet/mockfiles/qt6/EditView3D.qml b/src/tools/qmlpuppet/mockfiles/qt6/EditView3D.qml index d99301ae3a2..8b24af5631a 100644 --- a/src/tools/qmlpuppet/mockfiles/qt6/EditView3D.qml +++ b/src/tools/qmlpuppet/mockfiles/qt6/EditView3D.qml @@ -11,6 +11,14 @@ Item { height: 768 visible: true + enum ViewPreset { + Single, + Quad, + ThreeLeftOneRight, + TwoHorizontal, + TwoVertical + } + property Node activeScene: null property int activeViewport: 0 property var editViews: [null, null, null, null] @@ -39,53 +47,40 @@ Item { property color gridColor: "#cccccc" property color viewportBorderColor: "#aaaaaaaa" property bool syncEnvBackground: true - property string activePreset: "Single" + property int activePreset: EditView3D.ViewPreset.Single property bool flyMode: false property bool showCameraSpeed: false property string cameraViewMode property int mouseCursor: -1 // The presets used to customize the display of the viewports - property var viewportPresets: { - "Single": { - numViewports: 1, - viewRects: [ - { x: 0.0, y: 0.0, width: 1.0, height: 1.0 } - ] - }, - "Quad": { - numViewports: 4, - viewRects: [ - { x: 0.0, y: 0.0, width: 0.5, height: 0.5 }, - { x: 0.5, y: 0.0, width: 0.5, height: 0.5 }, - { x: 0.0, y: 0.5, width: 0.5, height: 0.5 }, - { x: 0.5, y: 0.5, width: 0.5, height: 0.5 } - ] - }, - "3Left1Right": { - numViewports: 4, - viewRects: [ - { x: 0.25, y: 0.0, width: 0.75, height: 1.0 }, - { x: 0.0, y: 0.0, width: 0.25, height: 0.33 }, - { x: 0.0, y: 0.3333, width: 0.25, height: 0.34 }, - { x: 0.0, y: 0.6667, width: 0.25, height: 0.33 } - ] - }, - "2Horizontal": { - numViewports: 2, - viewRects: [ - { x: 0.0, y: 0.0, width: 1.0, height: 0.5 }, - { x: 0.0, y: 0.5, width: 1.0, height: 0.5 } - ] - }, - "2Vertical": { - numViewports: 2, - viewRects: [ - { x: 0.0, y: 0.0, width: 0.5, height: 1.0 }, - { x: 0.5, y: 0.0, width: 0.5, height: 1.0 } - ] - } - }; + readonly property var viewportPresets: [ + [ // Single + { x: 0.0, y: 0.0, width: 1.0, height: 1.0 } + ], + [ // Quad + { x: 0.0, y: 0.0, width: 0.5, height: 0.5 }, + { x: 0.5, y: 0.0, width: 0.5, height: 0.5 }, + { x: 0.0, y: 0.5, width: 0.5, height: 0.5 }, + { x: 0.5, y: 0.5, width: 0.5, height: 0.5 } + ], + [ // ThreeLeftOneRight + { x: 0.25, y: 0.0, width: 0.75, height: 1.0 }, + { x: 0.0, y: 0.0, width: 0.25, height: 0.33 }, + { x: 0.0, y: 0.3333, width: 0.25, height: 0.34 }, + { x: 0.0, y: 0.6667, width: 0.25, height: 0.33 } + ], + [ // TwoHorizontal + { x: 0.0, y: 0.0, width: 1.0, height: 0.5 }, + { x: 0.0, y: 0.5, width: 1.0, height: 0.5 } + ], + [ // TwoVertical + { x: 0.0, y: 0.0, width: 0.5, height: 1.0 }, + { x: 0.5, y: 0.0, width: 0.5, height: 1.0 } + ] + ] + + property var activeDividers: defaultDividers() enum SelectionMode { Item, Group } enum TransformMode { Move, Rotate, Scale } @@ -102,13 +97,9 @@ Item { property Node activeParticleSystem: null property bool shuttingDown: false - // Always normalized [0.0…1.0] - property real dividerX: 0.5 // Vertical split (left & right) - property real dividerY: 0.5 // Horizontal split (top & bottom) - - // Only used in “3Left1Right” - property real dividerY1: 0.3333 // first horizontal in left column - property real dividerY2: 0.6667 // secnd horizontal in left column + // Only used with ThreeLeftOneRight, never change + readonly property real dividerY1: 0.3333 // first horizontal in left column + readonly property real dividerY2: 0.6667 // secnd horizontal in left column property real fps: 0 @@ -451,10 +442,24 @@ Item { else if (resetToDefault) activeViewport = 0; - if ("activePreset" in toolStates) - activePreset = toolStates.activePreset; - else if (resetToDefault) - activePreset = "Single"; + if ("activePreset" in toolStates) { + if (toolStates.activePreset < 0 || toolStates.activePreset > 4) + activePreset = EditView3D.ViewPreset.Single; + else + activePreset = toolStates.activePreset; + } else if (resetToDefault) { + activePreset = EditView3D.ViewPreset.Single; + } + + if ("activeDividers" in toolStates) { + activeDividers = toolStates.activeDividers; + updateViewRects() + updateSplitResizers() + } else if (resetToDefault) { + activeDividers = defaultDividers() + updateViewRects() + updateSplitResizers() + } if ("showWireframe" in toolStates) showWireframes = toolStates.showWireframe; @@ -483,6 +488,7 @@ Item { _generalHelper.storeToolState(sceneId, "selectionMode", selectionMode); _generalHelper.storeToolState(sceneId, "transformMode", transformMode); _generalHelper.storeToolState(sceneId, "activePreset", activePreset) + _generalHelper.storeToolState(sceneId, "activeDividers", activeDividers) _generalHelper.storeToolState(sceneId, "activeViewport", activeViewport) _generalHelper.storeToolState(sceneId, "showWireframe", showWireframes) _generalHelper.storeToolState(sceneId, "matOverride", materialOverrides) @@ -725,14 +731,8 @@ Item { function updateSplitResizers() { - verticalResizer.x = dividerX * viewContainer.width - verticalResizer.grabSize - horizontalResizer.y = dividerY * viewContainer.height - horizontalResizer.grabSize - } - - function resetDividers() - { - dividerX = activePreset === "3Left1Right" ? 0.25 : 0.5 - dividerY = 0.5 + verticalResizer.x = activeDividers[activePreset].x * viewContainer.width - verticalResizer.grabSize + horizontalResizer.y = activeDividers[activePreset].y * viewContainer.height - horizontalResizer.grabSize } // Update viewports based on selected preset @@ -742,23 +742,20 @@ Item { if (!preset) return; - let count = preset.numViewports; - - if (activeViewport >= count) + if (activeViewport >= preset.length) activeViewport = 0; for (let i = 0; i < 4; ++i) { - if (i < count) { + if (i < preset.length) { viewRects[i].visible = true; - viewRects[i].x = preset.viewRects[i].x * viewContainer.width; - viewRects[i].y = preset.viewRects[i].y * viewContainer.height; - viewRects[i].width = preset.viewRects[i].width * viewContainer.width; - viewRects[i].height = preset.viewRects[i].height * viewContainer.height; + viewRects[i].x = preset[i].x * viewContainer.width; + viewRects[i].y = preset[i].y * viewContainer.height; + viewRects[i].width = preset[i].width * viewContainer.width; + viewRects[i].height = preset[i].height * viewContainer.height; } else { viewRects[i].visible = false; } } - resetDividers(); updateViewRects(); updateSplitResizers(); @@ -769,35 +766,18 @@ Item { // viewport preset and resizer(s) position. function updateViewRects() { - var w = viewContainer.width, h = viewContainer.height + var w = viewContainer.width + var h = viewContainer.height + var dividerX = activeDividers[activePreset].x + var dividerY = activeDividers[activePreset].y + switch (activePreset) { - case "Single": + case EditView3D.ViewPreset.Single: viewRect0.width = w; viewRect0.height = h; break; - case "2Vertical": - viewRect0.width = dividerX * w; - viewRect0.height = h; - viewRect1.x = dividerX * w; - viewRect1.width = (1 - dividerX) * w; - viewRect1.height = h; - - splitBorderV.x = dividerX * w; - break; - - case "2Horizontal": - viewRect0.width = w; - viewRect0.height = dividerY * h; - viewRect1.y = dividerY * h; - viewRect1.width = w; - viewRect1.height = (1 - dividerY) * h; - - splitBorderH1.y = dividerY * h; - splitBorderH1.width = w; - break; - - case "Quad": + case EditView3D.ViewPreset.Quad: // top‑left viewRect0.width = dividerX * w; viewRect0.height = dividerY * h; @@ -820,7 +800,7 @@ Item { splitBorderH1.width = w; break; - case "3Left1Right": + case EditView3D.ViewPreset.ThreeLeftOneRight: // big right view viewRect0.x = dividerX * w; viewRect0.width = (1 - dividerX) * w; @@ -843,12 +823,44 @@ Item { splitBorderH1.width = dividerX * w; splitBorderH2.y = dividerY2 * h; break; + + case EditView3D.ViewPreset.TwoHorizontal: + viewRect0.width = w; + viewRect0.height = dividerY * h; + viewRect1.y = dividerY * h; + viewRect1.width = w; + viewRect1.height = (1 - dividerY) * h; + + splitBorderH1.y = dividerY * h; + splitBorderH1.width = w; + break; + + case EditView3D.ViewPreset.TwoVertical: + viewRect0.width = dividerX * w; + viewRect0.height = h; + viewRect1.x = dividerX * w; + viewRect1.width = (1 - dividerX) * w; + viewRect1.height = h; + + splitBorderV.x = dividerX * w; + break; + } // Request overlays to redraw _generalHelper.requestOverlayUpdate(); } + function defaultDividers() { + return [ + { x: 0.0, y: 0.0 }, + { x: 0.5, y: 0.5 }, + { x: 0.25, y: 0.0 }, + { x: 0.0, y: 0.5 }, + { x: 0.5, y: 0.0 } + ] + } + function updateMouseCursor() { if (verticalResizer.containsMouse || verticalResizer.dragActive) @@ -1038,9 +1050,9 @@ Item { Rectangle { id: splitBorderV - visible: viewRoot.activePreset === "2Vertical" - || viewRoot.activePreset === "3Left1Right" - || viewRoot.activePreset === "Quad" + visible: viewRoot.activePreset === EditView3D.ViewPreset.TwoVertical + || viewRoot.activePreset === EditView3D.ViewPreset.ThreeLeftOneRight + || viewRoot.activePreset === EditView3D.ViewPreset.Quad y: 0 width: 1 height: parent.height @@ -1050,9 +1062,9 @@ Item { Rectangle { id: splitBorderH1 - visible: viewRoot.activePreset === "2Horizontal" - || viewRoot.activePreset === "3Left1Right" - || viewRoot.activePreset === "Quad" + visible: viewRoot.activePreset === EditView3D.ViewPreset.TwoHorizontal + || viewRoot.activePreset === EditView3D.ViewPreset.ThreeLeftOneRight + || viewRoot.activePreset === EditView3D.ViewPreset.Quad x: 0 height: 1 border.width: 1 @@ -1061,7 +1073,7 @@ Item { Rectangle { id: splitBorderH2 - visible: viewRoot.activePreset === "3Left1Right" + visible: viewRoot.activePreset === EditView3D.ViewPreset.ThreeLeftOneRight x: 0 height: 1 width: splitBorderH1.width @@ -1071,7 +1083,8 @@ Item { // Active viewport highlight Rectangle { - visible: activePreset !== "Single" && viewRects[viewRoot.activeViewport].visible + visible: activePreset !== EditView3D.ViewPreset.Single + && viewRects[viewRoot.activeViewport].visible x: viewRects[viewRoot.activeViewport].x y: viewRects[viewRoot.activeViewport].y width: viewRects[viewRoot.activeViewport].width @@ -1086,19 +1099,26 @@ Item { ViewportResizer { id: verticalResizer orientation: Qt.Vertical - divider: dividerX containerSize: viewContainer.width y: 0 height: viewContainer.height - visible: viewRoot.activePreset === "2Vertical" - || viewRoot.activePreset === "3Left1Right" - || viewRoot.activePreset === "Quad" + visible: viewRoot.activePreset === EditView3D.ViewPreset.TwoVertical + || viewRoot.activePreset === EditView3D.ViewPreset.ThreeLeftOneRight + || viewRoot.activePreset === EditView3D.ViewPreset.Quad onCurrentDividerChanged: (value) => { - dividerX = value; + viewRoot.activeDividers[viewRoot.activePreset] + = { x: value, + y: viewRoot.activeDividers[viewRoot.activePreset].y}; updateViewRects(); } onContainsMouseChanged: viewRoot.updateMouseCursor() - onDragActiveChanged: viewRoot.updateMouseCursor() + onDragActiveChanged: { + viewRoot.updateMouseCursor() + if (!dragActive) { + _generalHelper.storeToolState(viewRoot.sceneId, "activeDividers", + viewRoot.activeDividers) + } + } } // Horizontal divider (top/bottom) @@ -1106,18 +1126,25 @@ Item { id: horizontalResizer orientation: Qt.Horizontal - divider: dividerY containerSize: viewContainer.height x: 0 width: viewContainer.width - visible: viewRoot.activePreset === "2Horizontal" - || viewRoot.activePreset === "Quad" + visible: viewRoot.activePreset === EditView3D.ViewPreset.TwoHorizontal + || viewRoot.activePreset === EditView3D.ViewPreset.Quad onCurrentDividerChanged: (value) => { - dividerY = value; + viewRoot.activeDividers[viewRoot.activePreset] + = { x: viewRoot.activeDividers[viewRoot.activePreset].x, + y: value}; updateViewRects(); } onContainsMouseChanged: viewRoot.updateMouseCursor() - onDragActiveChanged: viewRoot.updateMouseCursor() + onDragActiveChanged: { + viewRoot.updateMouseCursor() + if (!dragActive) { + _generalHelper.storeToolState(viewRoot.sceneId, "activeDividers", + viewRoot.activeDividers) + } + } } MouseArea { @@ -1340,21 +1367,21 @@ Item { function updateSnapping() { switch (viewRoot.activePreset) { - case "Single": + case EditView3D.ViewPreset.Single: cameraView.snapLeft = true break - case "2Vertical": - cameraView.snapLeft = viewRoot.activeViewport == 1 - break - case "2Horizontal": - cameraView.snapLeft = true - break - case "Quad": + case EditView3D.ViewPreset.Quad: cameraView.snapLeft = viewRoot.activeViewport != 2 break - case "3Left1Right": + case EditView3D.ViewPreset.ThreeLeftOneRight: cameraView.snapLeft = false break + case EditView3D.ViewPreset.TwoHorizontal: + cameraView.snapLeft = true + break + case EditView3D.ViewPreset.TwoVertical: + cameraView.snapLeft = viewRoot.activeViewport == 1 + break } } } diff --git a/src/tools/qmlpuppet/mockfiles/qt6/ViewportResizer.qml b/src/tools/qmlpuppet/mockfiles/qt6/ViewportResizer.qml index 795ca303506..9861b8b8bbe 100644 --- a/src/tools/qmlpuppet/mockfiles/qt6/ViewportResizer.qml +++ b/src/tools/qmlpuppet/mockfiles/qt6/ViewportResizer.qml @@ -7,7 +7,6 @@ import QtQuick Item { id: root - property real divider property real containerSize property int orientation readonly property alias containsMouse: mouseArea.containsMouse