From 2e334303fef72fa0e146440ace99be3162bd8be4 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 23 Jan 2023 11:59:10 +0100 Subject: [PATCH] QmlDesigner: Add top level toolbar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added Designer\TopToolBar=true to .ini to enable toolbar * Added backend to CrumbleBar * Added crumble bar * Added QML toolbar * Disabled original toolbar in DesignModeWidget * Added callback to DesignerActionManager * Added id to ZoomPreviewAction * Dock Manager is exposed in DesignModeWidget * Added new version of icon font Change-Id: I8c8ad16137c84229854a1d0fa6dfdf498edf4253 Reviewed-by: Thomas Hartmann Reviewed-by: Henning Gründl --- .../qmldesigner/newstateseditor/Main.qml | 6 +- .../imports/StudioControls/AbstractButton.qml | 3 +- .../imports/StudioControls/ComboBox.qml | 9 +- .../imports/StudioControls/ComboBoxInput.qml | 3 +- .../StudioControls/TopLevelComboBox.qml | 230 ++++++++++ .../imports/StudioControls/qmldir | 1 + .../imports/StudioTheme/ControlStyle.qml | 4 +- .../imports/StudioTheme/ToolbarStyle.qml | 6 +- .../imports/StudioTheme/Values.qml | 25 ++ .../qtcreator/qmldesigner/statusbar/Main.qml | 21 + .../qmldesigner/toolbar/CrumbleBar.qml | 93 ++++ .../qmldesigner/toolbar/CrumbleBread.qml | 176 ++++++++ share/qtcreator/qmldesigner/toolbar/Main.qml | 223 ++++++++++ .../qmldesigner/toolbar/ToolbarButton.qml | 24 + src/plugins/qmldesigner/CMakeLists.txt | 9 + .../components/componentcore/crumblebar.cpp | 40 +- .../components/componentcore/crumblebar.h | 36 +- .../componentcore/designeractionmanager.cpp | 9 + .../componentcore/designeractionmanager.h | 6 + .../components/toolbar/toolbar.cpp | 126 ++++++ .../qmldesigner/components/toolbar/toolbar.h | 21 + .../components/toolbar/toolbarbackend.cpp | 409 ++++++++++++++++++ .../components/toolbar/toolbarbackend.h | 129 ++++++ src/plugins/qmldesigner/designmodewidget.cpp | 147 ++++--- src/plugins/qmldesigner/designmodewidget.h | 20 +- src/plugins/qmldesigner/qmldesignerplugin.cpp | 8 +- .../qmlpreviewplugin/qmlpreviewactions.cpp | 2 +- 27 files changed, 1698 insertions(+), 88 deletions(-) create mode 100644 share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml create mode 100644 share/qtcreator/qmldesigner/statusbar/Main.qml create mode 100644 share/qtcreator/qmldesigner/toolbar/CrumbleBar.qml create mode 100644 share/qtcreator/qmldesigner/toolbar/CrumbleBread.qml create mode 100644 share/qtcreator/qmldesigner/toolbar/Main.qml create mode 100644 share/qtcreator/qmldesigner/toolbar/ToolbarButton.qml create mode 100644 src/plugins/qmldesigner/components/toolbar/toolbar.cpp create mode 100644 src/plugins/qmldesigner/components/toolbar/toolbar.h create mode 100644 src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp create mode 100644 src/plugins/qmldesigner/components/toolbar/toolbarbackend.h diff --git a/share/qtcreator/qmldesigner/newstateseditor/Main.qml b/share/qtcreator/qmldesigner/newstateseditor/Main.qml index 0176cc79f60..66bd37baad8 100644 --- a/share/qtcreator/qmldesigner/newstateseditor/Main.qml +++ b/share/qtcreator/qmldesigner/newstateseditor/Main.qml @@ -307,7 +307,7 @@ Rectangle { } } - onCurrentStateInternalIdChanged: layoutTimer.start() + //onCurrentStateInternalIdChanged: layoutTimer.start() StudioControls.Dialog { id: editDialog @@ -573,6 +573,8 @@ Rectangle { y: scrollView.height - height width: scrollView.availableWidth orientation: Qt.Horizontal + active: frame.contentHeight > scrollView.height + visible: frame.contentHeight > scrollView.height } ScrollBar.vertical: StateScrollBar { @@ -582,6 +584,8 @@ Rectangle { y: scrollView.topPadding height: scrollView.availableHeight orientation: Qt.Vertical + active: frame.contentWidth > scrollView.width + visible: frame.contentWidth > scrollView.width } Flickable { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml index 782e35b5f37..3bc2ad52c13 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/AbstractButton.qml @@ -45,6 +45,7 @@ T.AbstractButton { color: control.style.background.idle border.color: control.style.border.idle border.width: control.style.borderWidth + radius: control.style.radius } indicator: Item { @@ -77,7 +78,7 @@ T.AbstractButton { when: control.enabled && control.pressed PropertyChanges { target: buttonIcon - color: control.style.icon.idle + color: control.style.icon.interaction } }, State { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml index ea2c430004c..bbb01e59efc 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml @@ -93,8 +93,8 @@ T.ComboBox { __parentPopup: control.popup x: comboBoxInput.x + comboBoxInput.width y: control.style.borderWidth - width: control.style.baseIconSize.width - control.style.borderWidth - height: control.style.baseIconSize.height - control.style.borderWidth * 2 + width: control.style.squareControlSize.width - control.style.borderWidth + height: control.style.squareControlSize.height - control.style.borderWidth * 2 } background: Rectangle { @@ -162,7 +162,7 @@ T.ComboBox { : control.style.text.idle font.family: StudioTheme.Constants.iconFont.family font.pixelSize: control.style.smallIconFontSize - visible: control.currentIndex === index ? true : false + visible: control.currentIndex === index anchors.fill: parent renderType: Text.NativeRendering horizontalAlignment: Text.AlignHCenter @@ -261,8 +261,7 @@ T.ComboBox { // tab focus. It is therefor possible to use the mouse wheel to scroll through the items. State { name: "focus" - when: control.enabled && control.activeFocus && !control.editable - && !control.open + when: control.enabled && control.activeFocus && !control.editable && !control.open PropertyChanges { target: control wheelEnabled: true diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml index ceb5565f276..a5d95e84d38 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBoxInput.qml @@ -87,7 +87,8 @@ TextInput { }, State { name: "dragHover" - when: control.__parentControl.enabled && control.__parentControl.hasActiveHoverDrag + when: control.__parentControl.enabled + && (control.__parentControl.hasActiveHoverDrag ?? false) PropertyChanges { target: background color: control.style.background.interaction diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml new file mode 100644 index 00000000000..00548dd12e4 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml @@ -0,0 +1,230 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Templates 2.12 as T +import StudioTheme 1.0 as StudioTheme + +T.ComboBox { + id: control + + property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle + + property bool hover: (comboBoxInput.hover || window.visible) && control.enabled + property bool edit: false + property bool open: window.visible + + editable: false + width: control.style.controlSize.width + height: control.style.controlSize.height + + leftPadding: control.style.borderWidth + rightPadding: popupIndicator.width + control.style.borderWidth + font.pixelSize: control.style.baseFontSize + + delegate: ItemDelegate { + required property int index + required property var modelData + + width: control.width + highlighted: control.highlightedIndex === index + contentItem: Text { + text: modelData + color: "#21be2b" + font: control.font + elide: Text.ElideRight + verticalAlignment: Text.AlignVCenter + } + } + + indicator: CheckIndicator { + id: popupIndicator + style: control.style + __parentControl: control + __parentPopup: comboBoxPopup + x: comboBoxInput.x + comboBoxInput.width + y: control.style.borderWidth + width: control.style.squareControlSize.width - control.style.borderWidth + height: control.style.squareControlSize.height - control.style.borderWidth * 2 + } + + contentItem: ComboBoxInput { + id: comboBoxInput + style: control.style + __parentControl: control + text: control.editText + } + + background: Rectangle { + id: comboBoxBackground + color: control.style.background.idle + border.color: control.style.border.idle + border.width: control.style.borderWidth + width: control.width + height: control.height + } + + popup: T.Popup { + id: comboBoxPopup + width: 0 + height: 0 + closePolicy: T.Popup.CloseOnEscape | T.Popup.CloseOnPressOutsideParent + onAboutToShow: { + control.menuDelegate.parent = window.contentItem + control.menuDelegate.visible = true + + window.show() + window.requestActivate() + window.x = control.mapToGlobal(0,0).x + window.y = control.mapToGlobal(0,0).y + control.height + control.menuDelegate.focus = true + } + + onAboutToHide: window.hide() + } + + // Close popup when application goes to background + Connections { + target: Qt.application + function onStateChanged() { + if (Qt.application.state === Qt.ApplicationInactive) + comboBoxPopup.close() + } + } + + Window { + id: window + width: control.menuDelegate.implicitWidth + height: control.menuDelegate.implicitHeight + visible: false + flags: Qt.Popup | Qt.NoDropShadowWindowHint + modality: Qt.NonModal + transientParent: control.Window.window + color: "transparent" + } + + property Menu menuDelegate: Menu { + id: textEditMenu + y: 0 + width: control.width + overlap: 0 + + Repeater { + model: control.model + + MenuItem { + id: menuItem + x: 0 + text: modelData + onTriggered: { + control.currentIndex = index + comboBoxPopup.close() + } + + background: Rectangle { + implicitWidth: textLabel.implicitWidth + menuItem.labelSpacing + + menuItem.leftPadding + menuItem.rightPadding + implicitHeight: control.style.controlSize.height + x: control.style.borderWidth + y: control.style.borderWidth + width: menuItem.menu.width - (control.style.borderWidth * 2) + height: menuItem.height - (control.style.borderWidth * 2) + color: menuItem.highlighted ? control.style.interaction + : "transparent" + } + + contentItem: Item { + Text { + id: textLabel + leftPadding: itemDelegateIconArea.width + text: menuItem.text + font: control.font + color: menuItem.highlighted ? control.style.text.selectedText + : control.style.text.idle + anchors.verticalCenter: parent.verticalCenter + } + + Item { + id: itemDelegateIconArea + width: menuItem.height + height: menuItem.height + + T.Label { + id: itemDelegateIcon + text: StudioTheme.Constants.tickIcon + color: textLabel.color + font.family: StudioTheme.Constants.iconFont.family + font.pixelSize: control.style.smallIconFontSize + visible: control.currentIndex === index + anchors.fill: parent + renderType: Text.NativeRendering + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + } + } + } + } + + states: [ + State { + name: "default" + when: control.enabled && !control.hover && !control.edit && !control.open + && !control.activeFocus && !control.hasActiveDrag + PropertyChanges { + target: control + wheelEnabled: false + } + PropertyChanges { + target: comboBoxInput + selectByMouse: false + } + PropertyChanges { + target: comboBoxBackground + color: control.style.background.idle + } + }, + // This state is intended for ComboBoxes which aren't editable, but have focus e.g. via + // tab focus. It is therefor possible to use the mouse wheel to scroll through the items. + State { + name: "focus" + when: control.enabled && control.activeFocus && !control.editable && !control.open + PropertyChanges { + target: control + wheelEnabled: true + } + PropertyChanges { + target: comboBoxInput + focus: true + } + }, + State { + name: "popup" + when: control.enabled && control.open + PropertyChanges { + target: control + wheelEnabled: true + } + PropertyChanges { + target: comboBoxInput + selectByMouse: false + readOnly: true + } + PropertyChanges { + target: comboBoxBackground + color: control.style.background.interaction + border.color: control.style.border.interaction + } + }, + State { + name: "disable" + when: !control.enabled + PropertyChanges { + target: comboBoxBackground + color: control.style.background.disabled + border.color: control.style.border.disabled + } + } + ] +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/qmldir b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/qmldir index fea940d8783..d6071b6ff2d 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/qmldir +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/qmldir @@ -49,3 +49,4 @@ TextField 1.0 TextField.qml ToolTip 1.0 ToolTip.qml TranslationIndicator 1.0 TranslationIndicator.qml VerticalScrollBar 1.0 VerticalScrollBar.qml +TopLevelComboBox 1.0 TopLevelComboBox.qml diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ControlStyle.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ControlStyle.qml index 18425baae3d..075d12b06b0 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ControlStyle.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ControlStyle.qml @@ -17,7 +17,7 @@ QtObject { property real bigIconFontSize: Values.bigIconFontSize property real borderWidth: Values.border - property real radius: 4 + property real radius: Values.radius property size smallControlSize: Qt.size(Values.smallRectWidth, Values.smallRectWidth) @@ -28,7 +28,6 @@ QtObject { property size smallIconSize: Qt.size(Values.spinControlIconSizeMulti, Values.spinControlIconSizeMulti) - property size baseIconSize: Qt.size(Values.height, Values.height) // TODO only used once property size spinBoxIndicatorSize: Qt.size(Values.spinBoxIndicatorWidth, @@ -92,6 +91,7 @@ QtObject { component BorderColors: QtObject { property color idle: Values.themeControlOutline property color interaction: Values.themeControlOutlineInteraction + property color hover: "red" property color disabled: Values.themeControlOutlineDisabled } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ToolbarStyle.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ToolbarStyle.qml index 993c2d1aa89..c399edf5ded 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ToolbarStyle.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/ToolbarStyle.qml @@ -4,7 +4,7 @@ import QtQuick ControlStyle { - background { - idle: "red" - } + controlSize: Qt.size(Values.topLevelComboWidth, Values.topLevelComboHeight) + baseIconFontSize: Values.topLevelComboIcon + smallIconFontSize: 10 } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml index 76f529a6b34..e8e52a4d7f8 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml @@ -10,6 +10,10 @@ QtObject { property real baseHeight: 29 + property real topLevelComboWidth: 210 + property real topLevelComboHeight: 36 + property real topLevelComboIcon: 20 + property real smallFont: 8 property real baseFont: 12 property real mediumFont: 14 @@ -77,6 +81,7 @@ QtObject { property real marginTopBottom: 4 property real border: 1 property real borderHover: 3 + property real radius: 0 property real maxComboBoxPopupHeight: Math.round(300 * values.scaleFactor) property real maxTextAreaPopupHeight: Math.round(150 * values.scaleFactor) @@ -350,4 +355,24 @@ QtObject { property ControlStyle controlStyle: DefaultStyle {} property ControlStyle toolbarStyle: ToolbarStyle {} + property ControlStyle primaryToolbarStyle: ToolbarStyle { + baseIconFontSize: values.baseFontSize + radius: 4 + + icon: ControlStyle.IconColors { + idle: values.themeTextSelectedTextColor + disabled: "#636363" + } + + background: ControlStyle.BackgroundColors { + idle: values.themeInteraction + } + + border: ControlStyle.BorderColors { + idle: values.themeInteraction + hover: "#000000" + interaction: "#DCDADA" + disabled: "#636363" + } + } } diff --git a/share/qtcreator/qmldesigner/statusbar/Main.qml b/share/qtcreator/qmldesigner/statusbar/Main.qml new file mode 100644 index 00000000000..adddd64bab8 --- /dev/null +++ b/share/qtcreator/qmldesigner/statusbar/Main.qml @@ -0,0 +1,21 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import StudioControls +import StudioTheme 1.0 as StudioTheme + +Item { + id: toolbarContainer + + height: 24 + width: 2024 + + Rectangle { + + color: "#2d2d2d" + anchors.fill: parent + + } +} diff --git a/share/qtcreator/qmldesigner/toolbar/CrumbleBar.qml b/share/qtcreator/qmldesigner/toolbar/CrumbleBar.qml new file mode 100644 index 00000000000..930bd4fa774 --- /dev/null +++ b/share/qtcreator/qmldesigner/toolbar/CrumbleBar.qml @@ -0,0 +1,93 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls + +ListView { + id: root + + property real crumbleWidth: 166 + property real crumbleHeight: 36 + + property real inset: 5 + property real strokeWidth: 1 + property real textLeftMargin: 18 + property real textTopMargin: 6 + property real textRightMargin: 6 + property real textBottomMargin: 6 + + property alias font: fontMetrics.font + + signal clicked(index: int) + + boundsBehavior: Flickable.StopAtBounds + flickableDirection: Flickable.HorizontalFlick + interactive: true + + orientation: ListView.Horizontal + clip: true + focus: true + + function updateContentX() { + root.contentX = (root.contentWidth < root.width) ? 0 : root.contentWidth - root.width + } + + onCountChanged: root.updateContentX() + onWidthChanged: root.updateContentX() + + visible: root.count > 1 && root.width > (root.crumbleWidth) - 24 + + delegate: CrumbleBread { + text: fileName + tooltip: fileAddress + + width: root.crumbleWidth + height: root.crumbleHeight + + inset: root.inset + strokeWidth: root.strokeWidth + textLeftMargin: root.textLeftMargin + textTopMargin: root.textTopMargin + textRightMargin: root.textRightMargin + textBottomMargin: root.textBottomMargin + + font: root.font + + modelSize: root.count + + onClicked: { + if (index + 1 < root.count) + root.clicked(index) + } + } + + add: Transition { + NumberAnimation { + property: "opacity" + from: 0 + to: 1.0 + duration: 400 + } + NumberAnimation { + property: "scale" + from: 0 + to: 1.0 + duration: 400 + } + } + + displaced: Transition { + NumberAnimation { + property: "x" + duration: 400 + easing.type: Easing.OutBack + } + } + + FontMetrics { + id: fontMetrics + font.pixelSize: 12 + font.family: "SF Pro" + } +} diff --git a/share/qtcreator/qmldesigner/toolbar/CrumbleBread.qml b/share/qtcreator/qmldesigner/toolbar/CrumbleBread.qml new file mode 100644 index 00000000000..27acf0c80b7 --- /dev/null +++ b/share/qtcreator/qmldesigner/toolbar/CrumbleBread.qml @@ -0,0 +1,176 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import QtQuick.Shapes + +Item { + id: root + antialiasing: true + + property int modelSize + + /* Colors might come from Theme */ + property color idleBackgroundColor: "#2e2f30" + property color idleStrokeColor: "#1f1f1f" + property color idleTextColor: "#ffffff" + property color hoverBackgroundColor: "#434343" + property color hoverStrokeColor: "#434343" + property color activeColor: "#57b9fc" + property color activeTextColor: "#1f1f1f" + + property string tooltip + + property alias text: label.text + property alias font: label.font + property alias inset: backgroundPath.inset + property alias strokeWidth: backgroundPath.strokeWidth + + property real textLeftMargin: 18 + property real textTopMargin: 6 + property real textRightMargin: 6 + property real textBottomMargin: 6 + + readonly property int itemIndex: index + readonly property bool isFirst: itemIndex === 0 + readonly property bool isLast: (itemIndex + 1) === modelSize + + signal clicked(int callIdx) + + width: 166 + height: 36 + + Shape { + id: backgroundShape + anchors.fill: root + + antialiasing: root.antialiasing + layer.enabled: antialiasing + layer.smooth: antialiasing + layer.samples: antialiasing ? 4 : 0 + + ShapePath { + id: backgroundPath + + joinStyle: ShapePath.MiterJoin + fillColor: root.idleBackgroundColor + strokeColor: root.idleStrokeColor + strokeWidth: 1 + + property real inset: 5 + property real rightOut: root.isLast ? 0 : root.inset + property real leftIn: root.isFirst ? 0 : root.inset + property real strokeOffset: backgroundPath.strokeWidth / 2 + + property real topY: backgroundPath.strokeOffset + property real bottomY: backgroundShape.height - backgroundPath.strokeOffset + property real halfY: (backgroundPath.topY + backgroundPath.bottomY) / 2 + + startX: backgroundPath.strokeOffset + startY: backgroundPath.topY + + PathLine { + x: backgroundShape.width - backgroundPath.strokeOffset - backgroundPath.rightOut + y: backgroundPath.topY + } + PathLine { + x: backgroundShape.width - backgroundPath.strokeOffset + y: backgroundPath.halfY + } + PathLine { + x: backgroundShape.width - backgroundPath.strokeOffset - backgroundPath.rightOut + y: backgroundPath.bottomY + } + PathLine { + x: backgroundPath.strokeOffset + y: backgroundPath.bottomY + } + PathLine { + x: backgroundPath.leftIn + backgroundPath.strokeOffset + y: backgroundPath.halfY + } + PathLine { + x: backgroundPath.strokeOffset + y: backgroundPath.topY + } + } + } + + Text { + id: label + + anchors.fill: parent + anchors.leftMargin: root.textLeftMargin + anchors.topMargin: root.textTopMargin + anchors.rightMargin: root.textRightMargin + anchors.bottomMargin: root.textBottomMargin + + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + + color: root.idleTextColor + + wrapMode: Text.Wrap + elide: Text.ElideRight + maximumLineCount: 1 + + text: "Crumble File" + font.pixelSize: 12 + font.family: "SF Pro" + + ToolTip.text: root.tooltip + ToolTip.visible: mouseArea.containsMouse + ToolTip.delay: 1000 + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + onClicked: root.clicked(root.itemIndex) + } + + states: [ + State { + name: "idle" + when: !mouseArea.containsMouse && !mouseArea.pressed && !root.isLast + + PropertyChanges { + target: backgroundPath + fillColor: root.idleBackgroundColor + strokeColor: root.idleStrokeColor + } + }, + State { + name: "active" + when: root.isLast + extend: "pressed" + }, + State { + name: "hover" + when: mouseArea.containsMouse && !mouseArea.pressed + + PropertyChanges { + target: backgroundPath + fillColor: root.hoverBackgroundColor + strokeColor: root.hoverStrokeColor + } + }, + State { + name: "pressed" + when: mouseArea.pressed + + PropertyChanges { + target: backgroundPath + strokeColor: root.activeColor + fillColor: root.activeColor + } + + PropertyChanges { + target: label + color: root.activeTextColor + } + } + ] +} diff --git a/share/qtcreator/qmldesigner/toolbar/Main.qml b/share/qtcreator/qmldesigner/toolbar/Main.qml new file mode 100644 index 00000000000..cba6f4e553e --- /dev/null +++ b/share/qtcreator/qmldesigner/toolbar/Main.qml @@ -0,0 +1,223 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 +import QtQuick 2.15 +import QtQuick.Controls 2.15 + +import StudioControls +import StudioTheme 1.0 as StudioTheme + +import ToolBar 1.0 + +Rectangle { + id: toolbarContainer + color: "#2d2d2d" + border.color: "#00000000" + + height: 56 + width: 2024 + + ToolBarBackend { + id: backend + } + + Item { + id: topToolbarOtherMode + anchors.fill: parent + visible: !backend.isInDesignMode + + ToolbarButton { + id: homeOther + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 10 + enabled: backend.isDesignModeEnabled + tooltip: qsTr("Switch to Design Mode") + buttonIcon: StudioTheme.Constants.topToolbar_designMode + + onClicked: backend.triggerModeChange() + } + } + + Item { + id: topToolbar + anchors.fill: parent + visible: backend.isInDesignMode + + ToolbarButton { + id: home + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: 10 + buttonIcon: StudioTheme.Constants.topToolbar_home + + onClicked: backend.triggerModeChange() + } + + ToolbarButton { + id: runProject + anchors.verticalCenter: parent.verticalCenter + anchors.left: home.right + anchors.leftMargin: 10 + buttonIcon: StudioTheme.Constants.topToolbar_runProject + style: StudioTheme.ToolbarStyle { + icon: StudioTheme.ControlStyle.IconColors { + idle: "#649a5d" + } + } + + onClicked: backend.runProject() + } + + ToolbarButton { + id: livePreviewButton + style: StudioTheme.Values.primaryToolbarStyle + width: 96 + anchors.verticalCenter: parent.verticalCenter + anchors.left: runProject.right + anchors.leftMargin: 10 + iconFont: StudioTheme.Constants.font + buttonIcon: qsTr("Live Preview") + + onClicked: livePreview.trigger() + + ActionSubscriber { + id: livePreview + actionId: "LivePreview" + } + } + + TopLevelComboBox { + id: currentFile + style: StudioTheme.Values.toolbarStyle + width: 320 + anchors.verticalCenter: parent.verticalCenter + anchors.left: livePreviewButton.right + anchors.leftMargin: 10 + model: backend.documentModel + currentIndex: backend.documentIndex + + onActivated: backend.openFileByIndex(index) + } + + ToolbarButton { + id: backButton + anchors.verticalCenter: parent.verticalCenter + anchors.left: currentFile.right + anchors.leftMargin: 10 + enabled: backend.canGoBack + tooltip: qsTr("Go Back") + buttonIcon: StudioTheme.Constants.topToolbar_navFile + iconRotation: 0 + + onClicked: backend.goBackward() + } + + ToolbarButton { + id: forwardButton + anchors.verticalCenter: parent.verticalCenter + anchors.left: backButton.right + anchors.leftMargin: 10 + enabled: backend.canGoForward + tooltip: qsTr("Go Forward") + buttonIcon: StudioTheme.Constants.topToolbar_navFile + iconRotation: 180 + + onClicked: backend.goForward() + } + + ToolbarButton { + id: closeButton + anchors.verticalCenter: parent.verticalCenter + anchors.left: forwardButton.right + anchors.leftMargin: 10 + tooltip: qsTr("Close") + buttonIcon: StudioTheme.Constants.topToolbar_closeFile + + onClicked: backend.closeCurrentDocument() + } + + CrumbleBar { + id: flickable + height: 36 + anchors.left: closeButton.right + anchors.leftMargin: 10 + anchors.right: createComponent.left + anchors.rightMargin: 10 + anchors.verticalCenter: parent.verticalCenter + model: CrumbleBarModel { + id: crumbleBarModel + } + + onClicked: crumbleBarModel.onCrumblePathElementClicked(index) + } + + ToolbarButton { + id: createComponent + anchors.verticalCenter: parent.verticalCenter + anchors.right: enterComponent.left + anchors.rightMargin: 10 + enabled: moveToComponentBackend.available + tooltip: moveToComponentBackend.tooltip + buttonIcon: StudioTheme.Constants.topToolbar_makeComponent + + onClicked: moveToComponentBackend.trigger() + + ActionSubscriber { + id: moveToComponentBackend + actionId: "MakeComponent" + } + } + + ToolbarButton { + id: enterComponent + anchors.verticalCenter: parent.verticalCenter + anchors.right: workspaces.left + anchors.rightMargin: 10 + enabled: goIntoComponentBackend.available + tooltip: goIntoComponentBackend.tooltip + buttonIcon: StudioTheme.Constants.topToolbar_enterComponent + + onClicked: goIntoComponentBackend.trigger() + + ActionSubscriber { + id: goIntoComponentBackend + actionId: "GoIntoComponent" + } + } + + TopLevelComboBox { + id: workspaces + style: StudioTheme.Values.toolbarStyle + width: 210 + anchors.verticalCenter: parent.verticalCenter + anchors.right: annotations.left + anchors.rightMargin: 10 + model: backend.workspaces + onCurrentTextChanged: backend.setCurrentWorkspace(workspaces.currentText) + } + + ToolbarButton { + id: annotations + anchors.verticalCenter: parent.verticalCenter + anchors.right: shareButton.left + anchors.rightMargin: 10 + tooltip: qsTr("Edit Annotations") + buttonIcon: StudioTheme.Constants.topToolbar_annotations + + onClicked: backend.editGlobalAnnoation() + } + + ToolbarButton { + id: shareButton + style: StudioTheme.Values.primaryToolbarStyle + width: 96 + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: 8 + iconFont: StudioTheme.Constants.font + buttonIcon: qsTr("Share") + + onClicked: backend.shareApplicationOnline() + } + } +} diff --git a/share/qtcreator/qmldesigner/toolbar/ToolbarButton.qml b/share/qtcreator/qmldesigner/toolbar/ToolbarButton.qml new file mode 100644 index 00000000000..af3ea57a412 --- /dev/null +++ b/share/qtcreator/qmldesigner/toolbar/ToolbarButton.qml @@ -0,0 +1,24 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +import QtQuick +import StudioControls 1.0 as StudioControls +import StudioTheme 1.0 as StudioTheme +import HelperWidgets 2.0 + +StudioControls.AbstractButton { + id: button + + property alias tooltip: toolTipArea.tooltip + + style: StudioTheme.Values.toolbarStyle + hover: toolTipArea.containsMouse + + ToolTipArea { + id: toolTipArea + anchors.fill: parent + // Without setting the acceptedButtons property the clicked event won't + // reach the AbstractButton, it will be consumed by the ToolTipArea + acceptedButtons: Qt.NoButton + } +} diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index fdb91f8e069..2e6c875e15b 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -1111,6 +1111,15 @@ extend_qtc_plugin(QmlDesigner shortcutwidget.cpp shortcutwidget.h ) +extend_qtc_plugin(QmlDesigner + SOURCES_PREFIX components/toolbar + SOURCES + toolbar.cpp + toolbar.h + toolbarbackend.cpp + toolbarbackend.h +) + extend_qtc_plugin(QmlDesigner CONDITION TARGET Nanotrace DEPENDS Nanotrace diff --git a/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp b/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp index c9dad6aa669..4310a7adfee 100644 --- a/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp +++ b/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp @@ -6,6 +6,7 @@ #include "qmldesignerplugin.h" #include +#include #include #include @@ -60,6 +61,7 @@ void CrumbleBar::pushFile(const Utils::FilePath &fileName) { if (!m_isInternalCalled) { crumblePath()->clear(); + m_pathes.clear(); } else { // If the path already exists in crumblePath, pop up to first instance of that to avoid // cyclical crumblePath @@ -71,8 +73,10 @@ void CrumbleBar::pushFile(const Utils::FilePath &fileName) } if (match != -1) { - for (int i = crumblePath()->length() - 1 - match; i > 0; --i) + for (int i = crumblePath()->length() - 1 - match; i > 0; --i) { crumblePath()->popElement(); + m_pathes.removeLast(); + } } } @@ -81,10 +85,13 @@ void CrumbleBar::pushFile(const Utils::FilePath &fileName) CrumbleBarInfo crumbleBarInfo; crumbleBarInfo.fileName = fileName; crumblePath()->pushElement(fileName.fileName(), QVariant::fromValue(crumbleBarInfo)); + m_pathes.append({fileName, fileName.fileName(), {}}); } m_isInternalCalled = false; updateVisibility(); + + emit pathChanged(); } void CrumbleBar::pushInFileComponent(const ModelNode &modelNode) @@ -97,10 +104,13 @@ void CrumbleBar::pushInFileComponent(const ModelNode &modelNode) crumblePath()->popElement(); crumblePath()->pushElement(crumbleBarInfo.displayName, QVariant::fromValue(crumbleBarInfo)); + m_pathes.append({{}, crumbleBarInfo.displayName, modelNode}); m_isInternalCalled = false; updateVisibility(); + + emit pathChanged(); } void CrumbleBar::nextFileIsCalledInternally() @@ -120,6 +130,21 @@ Utils::CrumblePath *CrumbleBar::crumblePath() return m_crumblePath; } +QStringList CrumbleBar::path() const +{ + QStringList list; + for (auto &path : m_pathes) { + list.append(path.displayName); + } + + return list; +} + +QList CrumbleBar::infos() const +{ + return m_pathes; +} + bool CrumbleBar::showSaveDialog() { bool canceled = false; @@ -151,11 +176,15 @@ void CrumbleBar::onCrumblePathElementClicked(const QVariant &data) if (!inlineComp && !showSaveDialog()) return; - while (clickedCrumbleBarInfo != crumblePath()->dataForLastIndex().value()) + while (clickedCrumbleBarInfo != crumblePath()->dataForLastIndex().value()) { crumblePath()->popElement(); + m_pathes.removeLast(); + } - if (crumblePath()->dataForLastIndex().value().modelNode.isValid()) + if (crumblePath()->dataForLastIndex().value().modelNode.isValid()) { crumblePath()->popElement(); + m_pathes.removeLast(); + } m_isInternalCalled = true; if (inlineComp) { @@ -164,6 +193,7 @@ void CrumbleBar::onCrumblePathElementClicked(const QVariant &data) QmlDesignerPlugin::instance()->viewManager().setComponentViewToMaster(); } else { crumblePath()->popElement(); + m_pathes.removeLast(); nextFileIsCalledInternally(); Core::EditorManager::openEditor(clickedCrumbleBarInfo.fileName, Utils::Id(), @@ -175,12 +205,14 @@ void CrumbleBar::onCrumblePathElementClicked(const QVariant &data) QmlDesignerPlugin::instance()->viewManager().setComponentViewToMaster(); } } + emit pathChanged(); updateVisibility(); } void CrumbleBar::updateVisibility() { - crumblePath()->setVisible(crumblePath()->length() > 1); + if (!ToolBar::isVisible()) + crumblePath()->setVisible(crumblePath()->length() > 1); } bool operator ==(const CrumbleBarInfo &first, const CrumbleBarInfo &second) diff --git a/src/plugins/qmldesigner/components/componentcore/crumblebar.h b/src/plugins/qmldesigner/components/componentcore/crumblebar.h index c3a7d2d937e..48a5552428a 100644 --- a/src/plugins/qmldesigner/components/componentcore/crumblebar.h +++ b/src/plugins/qmldesigner/components/componentcore/crumblebar.h @@ -10,6 +10,24 @@ namespace QmlDesigner { +class CrumbleBarInfo { +public: + + CrumbleBarInfo() = default; + + CrumbleBarInfo(Utils::FilePath f, + QString d, + ModelNode m) : + fileName(f), + displayName(d), + modelNode(m) + {} + + Utils::FilePath fileName; + QString displayName; + ModelNode modelNode; +}; + class CrumbleBar : public QObject { Q_OBJECT @@ -24,21 +42,23 @@ public: Utils::CrumblePath *crumblePath(); -private: + QStringList path() const; + + QList infos() const; + void onCrumblePathElementClicked(const QVariant &data); + +signals: + void pathChanged(); + +private: void updateVisibility(); bool showSaveDialog(); private: bool m_isInternalCalled = false; Utils::CrumblePath *m_crumblePath = nullptr; -}; - -class CrumbleBarInfo { -public: - Utils::FilePath fileName; - QString displayName; - ModelNode modelNode; + QList m_pathes; }; bool operator ==(const CrumbleBarInfo &first, const CrumbleBarInfo &second); diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index 10ce808b5aa..44feade5fce 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -293,6 +293,11 @@ QIcon DesignerActionManager::contextIcon(int contextId) const return m_designerIcons->icon(DesignerIcons::IconId(contextId), DesignerIcons::ContextMenuArea); } +void DesignerActionManager::addAddActionCallback(ActionAddedInterface callback) +{ + m_callBacks.append(callback); +} + class VisiblityModelNodeAction : public ModelNodeContextMenuAction { public: @@ -2051,6 +2056,10 @@ void DesignerActionManager::createDefaultModelNodePreviewImageHandlers() void DesignerActionManager::addDesignerAction(ActionInterface *newAction) { m_designerActions.append(QSharedPointer(newAction)); + + for (auto callback : m_callBacks) { + callback(newAction); + } } void DesignerActionManager::addCreatorCommand(Core::Command *command, const QByteArray &category, int priority, diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h index 41bf7b83876..72d708e9588 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h @@ -14,6 +14,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE class QGraphicsItem; class QGraphicsWidget; @@ -27,6 +29,7 @@ class DesignerIcons; using AddResourceOperation = std::function; using ModelNodePreviewImageOperation = std::function; +using ActionAddedInterface = std::function; struct AddResourceHandler { @@ -121,6 +124,8 @@ public: QHash handleExternalAssetsDrop(const QMimeData *data) const; QIcon contextIcon(int contextId) const; + void addAddActionCallback(ActionAddedInterface callback); + private: void addTransitionEffectAction(const TypeName &typeName); void addCustomTransitionEffectAction(); @@ -133,6 +138,7 @@ private: QList m_modelNodePreviewImageHandlers; ExternalDependenciesInterface &m_externalDependencies; QScopedPointer m_designerIcons; + QList m_callBacks; }; } //QmlDesigner diff --git a/src/plugins/qmldesigner/components/toolbar/toolbar.cpp b/src/plugins/qmldesigner/components/toolbar/toolbar.cpp new file mode 100644 index 00000000000..7410cc17a6a --- /dev/null +++ b/src/plugins/qmldesigner/components/toolbar/toolbar.cpp @@ -0,0 +1,126 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "toolbar.h" +#include "toolbarbackend.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include + +namespace QmlDesigner { + +QmlDesigner::ToolBar::ToolBar() +{ + +} + +static Utils::FilePath propertyEditorResourcesPath() +{ +#ifdef SHARE_QML_PATH + if (qEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) + return Utils::FilePath::fromString(QLatin1String(SHARE_QML_PATH) + "/propertyEditorQmlSources"); +#endif + return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources"); +} + +Utils::FilePath qmlSourcesStatusBarPath() +{ +#ifdef SHARE_QML_PATH + if (qEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) + return Utils::FilePath::fromString(QLatin1String(SHARE_QML_PATH) + "/statusbar"); +#endif + return Core::ICore::resourcePath("qmldesigner/statusbar"); +} + +Utils::FilePath qmlSourcesPath() +{ +#ifdef SHARE_QML_PATH + if (qEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) + return Utils::FilePath::fromString(QLatin1String(SHARE_QML_PATH) + "/toolbar"); +#endif + return Core::ICore::resourcePath("qmldesigner/toolbar"); +} + +void ToolBar::create() +{ + if (!isVisible()) + return; + + ToolBarBackend::registerDeclarativeType(); + + auto window = Core::ICore::mainWindow(); + + //Core::ICore::statusBar()->hide(); + + auto toolBar = new QToolBar; + + toolBar->setFloatable(false); + toolBar->setMovable(false); + + auto quickWidget = new QQuickWidget; + + quickWidget->setFixedHeight(48); + quickWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + quickWidget->setMinimumWidth(200); + quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + + quickWidget->engine()->addImportPath(propertyEditorResourcesPath().toString() + "/imports"); + + Utils::FilePath qmlFilePath = qmlSourcesPath() / "Main.qml"; + QTC_ASSERT(qmlFilePath.exists(), return ); + + Theme::setupTheme(quickWidget->engine()); + + quickWidget->setSource(QUrl::fromLocalFile(qmlFilePath.toFSPathString())); + + toolBar->addWidget(quickWidget); + window->addToolBar(toolBar); +} + +void ToolBar::createStatusBar() +{ + if (!isVisible()) + return; + + ToolBarBackend::registerDeclarativeType(); + + auto quickWidget = new QQuickWidget; + + quickWidget->setFixedHeight(24); + quickWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + quickWidget->setMinimumWidth(200); + quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + + quickWidget->engine()->addImportPath(propertyEditorResourcesPath().toString() + "/imports"); + + Utils::FilePath qmlFilePath = qmlSourcesStatusBarPath() + QStringLiteral("/Main.qml"); + QTC_ASSERT(qmlFilePath.exists(), return ); + + Theme::setupTheme(quickWidget->engine()); + + quickWidget->setSource(QUrl::fromLocalFile(qmlFilePath.toFSPathString())); + + for (QWidget *w : Core::ICore::statusBar()->findChildren(Qt::FindDirectChildrenOnly)) { + w->hide(); + } + + Core::ICore::statusBar()->addWidget(quickWidget); +} + +bool ToolBar::isVisible() +{ + QSettings *settings = Core::ICore::settings(); + const QString qdsToolbarEntry = "QML/Designer/TopToolBar"; + + return settings->value(qdsToolbarEntry, false).toBool(); +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/toolbar/toolbar.h b/src/plugins/qmldesigner/components/toolbar/toolbar.h new file mode 100644 index 00000000000..3a9dd53abaf --- /dev/null +++ b/src/plugins/qmldesigner/components/toolbar/toolbar.h @@ -0,0 +1,21 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace QmlDesigner { + +class ToolBar : public QQuickWidget +{ + Q_OBJECT + +public: + ToolBar(); + static void create(); + static void createStatusBar(); + static bool isVisible(); +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp new file mode 100644 index 00000000000..44e035f359e --- /dev/null +++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp @@ -0,0 +1,409 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#include "toolbarbackend.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +namespace QmlDesigner { + +static Internal::DesignModeWidget *designModeWidget() +{ + return QmlDesignerPlugin::instance()->mainWidget(); +} + +static DesignDocument *currentDesignDocument() +{ + return QmlDesignerPlugin::instance()->documentManager().currentDesignDocument(); +} + +static CrumbleBar *crumbleBar() +{ + return designModeWidget()->crumbleBar(); +} + +static Utils::FilePath getMainUiFile() +{ + auto project = ProjectExplorer::SessionManager::startupProject(); + if (!project) + return {}; + + if (!project->activeTarget()) + return {}; + + auto qmlBuildSystem = qobject_cast( + project->activeTarget()->buildSystem()); + return qmlBuildSystem->mainUiFilePath(); +} + +static void openUiFile() +{ + const Utils::FilePath mainUiFile = getMainUiFile(); + + if (mainUiFile.completeSuffix() == "ui.qml" && mainUiFile.exists()) + Core::EditorManager::openEditor(mainUiFile, Utils::Id()); +} + +void ToolBarBackend::triggerModeChange() +{ + QTimer::singleShot(0, []() { //Do not trigger mode change directly from QML + bool qmlFileOpen = false; + + auto document = Core::EditorManager::currentDocument(); + + if (document) + qmlFileOpen = document->filePath().fileName().endsWith(".qml"); + + if (Core::ModeManager::currentModeId() == Core::Constants::MODE_DESIGN) + Core::ModeManager::activateMode(Core::Constants::MODE_WELCOME); + else if (qmlFileOpen) + Core::ModeManager::activateMode(Core::Constants::MODE_DESIGN); + else if (Core::ModeManager::currentModeId() == Core::Constants::MODE_WELCOME) + openUiFile(); + else + Core::ModeManager::activateMode(Core::Constants::MODE_WELCOME); + }); +} + +void ToolBarBackend::runProject() +{ + ProjectExplorer::ProjectExplorerPlugin::runStartupProject( + ProjectExplorer::Constants::NORMAL_RUN_MODE); +} + +void ToolBarBackend::goForward() +{ + QTC_ASSERT(designModeWidget(), return ); + designModeWidget()->toolBarOnGoForwardClicked(); +} + +void ToolBarBackend::goBackward() +{ + QTC_ASSERT(designModeWidget(), return ); + designModeWidget()->toolBarOnGoBackClicked(); +} + +void ToolBarBackend::openFileByIndex(int i) +{ + auto fileName = Core::DocumentModel::entries().at(i)->fileName(); + + Core::EditorManager::openEditor(fileName, Utils::Id(), Core::EditorManager::DoNotMakeVisible); +} + +void ToolBarBackend::closeCurrentDocument() +{ + Core::EditorManager::slotCloseCurrentEditorOrDocument(); +} + +void ToolBarBackend::shareApplicationOnline() +{ + auto command = Core::ActionManager::command("QmlProject.ShareDesign"); + if (command) + command->action()->trigger(); +} + +void ToolBarBackend::setCurrentWorkspace(const QString &workspace) +{ + designModeWidget()->dockManager()->openWorkspace(workspace); +} + +void ToolBarBackend::editGlobalAnnoation() +{ + ModelNode node = currentDesignDocument()->rewriterView()->rootModelNode(); + + if (node.isValid()) { + designModeWidget()->globalAnnotationEditor().setModelNode(node); + designModeWidget()->globalAnnotationEditor().showWidget(); + } +} + +bool ToolBarBackend::canGoBack() const +{ + QTC_ASSERT(designModeWidget(), return false); + return designModeWidget()->canGoBack(); +} + +bool ToolBarBackend::canGoForward() const +{ + QTC_ASSERT(designModeWidget(), return false); + return designModeWidget()->canGoForward(); +} + +ToolBarBackend::ToolBarBackend(QObject *parent) + : QObject(parent) +{ + ActionAddedInterface callback = [this](ActionInterface *interface) { + if (interface->menuId() == "PreviewZoom") + m_zoomAction = interface; + }; + + QmlDesignerPlugin::instance()->viewManager().designerActionManager().addAddActionCallback(callback); + + connect(designModeWidget(), + &Internal::DesignModeWidget::navigationHistoryChanged, + this, + &ToolBarBackend::navigationHistoryChanged); + + connect(Core::DocumentModel::model(), + &QAbstractItemModel::rowsInserted, + this, + &ToolBarBackend::updateDocumentModel); + connect(Core::DocumentModel::model(), + &QAbstractItemModel::rowsRemoved, + this, + &ToolBarBackend::updateDocumentModel); + connect(Core::DocumentModel::model(), + &QAbstractItemModel::dataChanged, + this, + &ToolBarBackend::updateDocumentModel); + connect(Core::DocumentModel::model(), + &QAbstractItemModel::modelReset, + this, + &ToolBarBackend::updateDocumentModel); + + connect(Core::EditorManager::instance(), + &Core::EditorManager::currentEditorChanged, + this, + &ToolBarBackend::documentIndexChanged); + + connect(designModeWidget(), &Internal::DesignModeWidget::initialized, this, [this]() { + const auto dockManager = designModeWidget()->dockManager(); + + connect(dockManager, + &ADS::DockManager::workspaceListChanged, + this, + &ToolBarBackend::setupWorkspaces); + connect(dockManager, &ADS::DockManager::workspaceLoaded, this, [this](const QString &) { + emit currentWorkspaceChanged(); + }); + + setupWorkspaces(); + }); + + auto editorManager = Core::EditorManager::instance(); + + connect(editorManager, &Core::EditorManager::documentClosed, this, [this]() { + if (isInDesignMode() && Core::DocumentModel::entryCount() == 0) { + QTimer::singleShot(0, []() { /* The mode change has to happen from event loop. + Otherwise we and up in an invalid state */ + Core::ModeManager::activateMode(Core::Constants::MODE_WELCOME); + }); + } + }); + + connect(Core::ICore::instance(), &Core::ICore::coreAboutToOpen, this, [this] { + connect(Core::DesignMode::instance(), &Core::DesignMode::enabledStateChanged, this, [this] { + emit isDesignModeEnabledChanged(); + }); + }); + + connect(Core::ModeManager::instance(), &Core::ModeManager::currentModeChanged, this, [this]() { + emit isInDesignModeChanged(); + }); +} + +void ToolBarBackend::registerDeclarativeType() +{ + qmlRegisterType("ToolBar", 1, 0, "ToolBarBackend"); + qmlRegisterType("ToolBar", 1, 0, "ActionSubscriber"); + qmlRegisterType("ToolBar", 1, 0, "CrumbleBarModel"); +} + +QStringList ToolBarBackend::documentModel() const +{ + return m_openDocuments; +} + +void ToolBarBackend::updateDocumentModel() +{ + m_openDocuments.clear(); + for (auto &entry : Core::DocumentModel::entries()) + m_openDocuments.append(entry->displayName()); + + emit openDocumentsChanged(); +} + +int ToolBarBackend::documentIndex() const +{ + if (Core::EditorManager::currentDocument()) + return Core::DocumentModel::indexOfDocument(Core::EditorManager::currentDocument()).value(); + + return -1; +} + +QString ToolBarBackend::currentWorkspace() const +{ + return designModeWidget()->dockManager()->activeWorkspace(); +} + +QStringList ToolBarBackend::workspaces() const +{ + return m_workspaces; +} + +bool ToolBarBackend::isInDesignMode() const +{ + if (!Core::ModeManager::instance()) + return false; + + return Core::ModeManager::currentModeId() == Core::Constants::MODE_DESIGN; +} + +bool ToolBarBackend::isDesignModeEnabled() const +{ + if (Core::DesignMode::instance()) + return Core::DesignMode::instance()->isEnabled() || getMainUiFile().exists(); + + return false; +} + +void ToolBarBackend::setupWorkspaces() +{ + m_workspaces.clear(); + m_workspaces = designModeWidget()->dockManager()->workspaces(); + Utils::sort(m_workspaces); + emit workspacesChanged(); +} + +ActionSubscriber::ActionSubscriber(QObject *parent) + : QObject(parent) +{ + ActionAddedInterface callback = [this](ActionInterface *interface) { + if (interface->menuId() == m_actionId.toLatin1()) { + m_interface = interface; + setupNotifier(); + } + }; + + QmlDesignerPlugin::instance()->viewManager().designerActionManager().addAddActionCallback(callback); +} + +void ActionSubscriber::trigger() +{ + if (m_interface) + m_interface->action()->trigger(); +} + +bool ActionSubscriber::available() const +{ + if (m_interface) + return m_interface->action()->isEnabled(); + return false; +} + +bool ActionSubscriber::checked() const +{ + if (m_interface) + return m_interface->action()->isChecked(); + + return false; +} + +QString ActionSubscriber::actionId() const +{ + return m_actionId; +} + +void ActionSubscriber::setActionId(const QString &id) +{ + if (id == m_actionId) + return; + + m_actionId = id; + emit actionIdChanged(); + emit tooltipChanged(); +} + +QString ActionSubscriber::tooltip() const +{ + if (m_interface) + return m_interface->action()->text(); + return {}; +} + +void ActionSubscriber::setupNotifier() +{ + if (!m_interface) + return; + + connect(m_interface->action(), &QAction::enabledChanged, this, &ActionSubscriber::availableChanged); + + emit tooltipChanged(); +} + +CrumbleBarModel::CrumbleBarModel(QObject *) +{ + connect(crumbleBar(), &CrumbleBar::pathChanged, this, &CrumbleBarModel::handleCrumblePathChanged); +} + +int CrumbleBarModel::rowCount(const QModelIndex &) const +{ + return crumbleBar()->path().count(); +} + +QHash CrumbleBarModel::roleNames() const +{ + static QHash roleNames{{Qt::UserRole + 1, "fileName"}, + {Qt::UserRole + 2, "fileAddress"}}; + + return roleNames; +} + +QVariant CrumbleBarModel::data(const QModelIndex &index, int role) const +{ + if (index.isValid() && index.row() < rowCount()) { + auto info = crumbleBar()->infos().at(index.row()); + + if (role == Qt::UserRole + 1) { + return info.displayName; + } else if (role == Qt::UserRole + 2) { + return info.fileName.displayName(); + } else { + qWarning() << Q_FUNC_INFO << "invalid role"; + } + } else { + qWarning() << Q_FUNC_INFO << "invalid index"; + } + + return QVariant(); +} + +void CrumbleBarModel::handleCrumblePathChanged() +{ + beginResetModel(); + endResetModel(); +} + +void CrumbleBarModel::onCrumblePathElementClicked(int i) +{ + if (i < rowCount()) { + auto info = crumbleBar()->infos().at(i); + crumbleBar()->onCrumblePathElementClicked(QVariant::fromValue(info)); + } +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h new file mode 100644 index 00000000000..11695525673 --- /dev/null +++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h @@ -0,0 +1,129 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +namespace QmlDesigner { + +class ActionInterface; + +class CrumbleBarModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit CrumbleBarModel(QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + + QHash roleNames() const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + void handleCrumblePathChanged(); + + Q_INVOKABLE void onCrumblePathElementClicked(int i); + +private: +}; + +class ActionSubscriber : public QObject +{ + Q_OBJECT + +public: + ActionSubscriber(QObject *parent = nullptr); + + Q_PROPERTY(QString actionId READ actionId WRITE setActionId NOTIFY actionIdChanged) + Q_PROPERTY(bool available READ available NOTIFY availableChanged) + Q_PROPERTY(bool checked READ checked NOTIFY checkedChanged) + Q_PROPERTY(QString tooltip READ tooltip NOTIFY tooltipChanged) + + Q_INVOKABLE void trigger(); + + bool available() const; + bool checked() const; + + QString actionId() const; + void setActionId(const QString &id); + + QString tooltip() const; + +signals: + void actionIdChanged(); + void availableChanged(); + void checkedChanged(); + void tooltipChanged(); + +private: + void setupNotifier(); + + ActionInterface *m_interface = nullptr; + QString m_actionId; +}; + +class ToolBarBackend : public QObject +{ + Q_OBJECT + + Q_PROPERTY(bool canGoBack READ canGoBack NOTIFY navigationHistoryChanged) + Q_PROPERTY(bool canGoForward READ canGoForward NOTIFY navigationHistoryChanged) + Q_PROPERTY(QStringList documentModel READ documentModel NOTIFY openDocumentsChanged) + Q_PROPERTY(int documentIndex READ documentIndex NOTIFY documentIndexChanged) + Q_PROPERTY(QString currentWorkspace READ currentWorkspace NOTIFY currentWorkspaceChanged) + Q_PROPERTY(QStringList workspaces READ workspaces NOTIFY workspacesChanged) + Q_PROPERTY(bool isInDesignMode READ isInDesignMode NOTIFY isInDesignModeChanged) + Q_PROPERTY(bool isDesignModeEnabled READ isDesignModeEnabled NOTIFY isDesignModeEnabledChanged) + +public: + ToolBarBackend(QObject *parent = nullptr); + static void registerDeclarativeType(); + + Q_INVOKABLE void triggerModeChange(); + Q_INVOKABLE void runProject(); + Q_INVOKABLE void goForward(); + Q_INVOKABLE void goBackward(); + Q_INVOKABLE void openFileByIndex(int i); + Q_INVOKABLE void closeCurrentDocument(); + Q_INVOKABLE void shareApplicationOnline(); + Q_INVOKABLE void setCurrentWorkspace(const QString &workspace); + Q_INVOKABLE void editGlobalAnnoation(); + + bool canGoBack() const; + bool canGoForward() const; + + QStringList documentModel() const; + + void updateDocumentModel(); + int documentIndex() const; + + QString currentWorkspace() const; + QStringList workspaces() const; + + bool isInDesignMode() const; + bool isDesignModeEnabled() const; + +signals: + void navigationHistoryChanged(); + void openDocumentsChanged(); + void documentIndexChanged(); + void currentWorkspaceChanged(); + void workspacesChanged(); + void isInDesignModeChanged(); + void isDesignModeEnabledChanged(); + +private: + void setupWorkspaces(); + + ActionInterface *m_zoomAction; + ActionInterface *editAnnotation; + ActionInterface *goIntoComponent; + ActionInterface *moveToComponent; + + QStringList m_openDocuments; + QStringList m_workspaces; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp index 574c7cf3651..09483d31040 100644 --- a/src/plugins/qmldesigner/designmodewidget.cpp +++ b/src/plugins/qmldesigner/designmodewidget.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -341,27 +342,69 @@ void DesignModeWidget::setup() mviews->addAction(command); // Create toolbars - auto toolBar = new QToolBar(); + if (!ToolBar::isVisible()) { + auto toolBar = new QToolBar(); - toolBar->addAction(viewManager().componentViewAction()); - toolBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - DesignerActionToolBar *designerToolBar = QmlDesignerPlugin::instance()->viewManager().designerActionManager().createToolBar(m_toolBar); + toolBar->addAction(viewManager().componentViewAction()); + toolBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + DesignerActionToolBar *designerToolBar = QmlDesignerPlugin::instance()->viewManager().designerActionManager().createToolBar(m_toolBar); - designerToolBar->layout()->addWidget(toolBar); + designerToolBar->layout()->addWidget(toolBar); - m_toolBar->addCenterToolBar(designerToolBar); - m_toolBar->setMinimumWidth(320); - m_toolBar->setToolbarCreationFlags(Core::EditorToolBar::FlagsStandalone); - m_toolBar->setNavigationVisible(true); + m_toolBar->addCenterToolBar(designerToolBar); + m_toolBar->setMinimumWidth(320); + m_toolBar->setToolbarCreationFlags(Core::EditorToolBar::FlagsStandalone); + m_toolBar->setNavigationVisible(true); - connect(m_toolBar, &Core::EditorToolBar::goForwardClicked, this, &DesignModeWidget::toolBarOnGoForwardClicked); - connect(m_toolBar, &Core::EditorToolBar::goBackClicked, this, &DesignModeWidget::toolBarOnGoBackClicked); + connect(m_toolBar, &Core::EditorToolBar::goForwardClicked, this, &DesignModeWidget::toolBarOnGoForwardClicked); + connect(m_toolBar, &Core::EditorToolBar::goBackClicked, this, &DesignModeWidget::toolBarOnGoBackClicked); - QToolBar* toolBarWrapper = new QToolBar(); - toolBarWrapper->addWidget(m_toolBar); - toolBarWrapper->addWidget(createCrumbleBarFrame()); - toolBarWrapper->setMovable(false); - addToolBar(Qt::TopToolBarArea, toolBarWrapper); + + QToolBar* toolBarWrapper = new QToolBar(); + toolBarWrapper->addWidget(m_toolBar); + toolBarWrapper->addWidget(createCrumbleBarFrame()); + toolBarWrapper->setMovable(false); + addToolBar(Qt::TopToolBarArea, toolBarWrapper); + + + addSpacerToToolBar(toolBar); + + auto workspaceComboBox = new QComboBox(); + workspaceComboBox->setMinimumWidth(120); + workspaceComboBox->setToolTip(tr("Switch the active workspace.")); + auto sortedWorkspaces = m_dockManager->workspaces(); + Utils::sort(sortedWorkspaces); + workspaceComboBox->addItems(sortedWorkspaces); + workspaceComboBox->setCurrentText(m_dockManager->activeWorkspace()); + toolBar->addWidget(workspaceComboBox); + + connect(m_dockManager, &ADS::DockManager::workspaceListChanged, + workspaceComboBox, [this, workspaceComboBox]() { + workspaceComboBox->clear(); + auto sortedWorkspaces = m_dockManager->workspaces(); + Utils::sort(sortedWorkspaces); + workspaceComboBox->addItems(sortedWorkspaces); + workspaceComboBox->setCurrentText(m_dockManager->activeWorkspace()); + }); + connect(m_dockManager, &ADS::DockManager::workspaceLoaded, workspaceComboBox, &QComboBox::setCurrentText); + connect(workspaceComboBox, &QComboBox::activated, + m_dockManager, [this, workspaceComboBox]([[maybe_unused]] int index) { + m_dockManager->openWorkspace(workspaceComboBox->currentText()); + }); + + const QIcon gaIcon = Utils::StyleHelper::getIconFromIconFont( + fontName, Theme::getIconUnicode(Theme::Icon::annotationBubble), + 36, 36, Theme::getColor(Theme::IconsBaseColor)); + toolBar->addAction(gaIcon, tr("Edit global annotation for current file."), [&](){ + ModelNode node = currentDesignDocument()->rewriterView()->rootModelNode(); + + if (node.isValid()) { + m_globalAnnotationEditor.setModelNode(node); + m_globalAnnotationEditor.showWidget(); + } + }); + + } if (currentDesignDocument()) setupNavigatorHistory(currentDesignDocument()->textEditor()); @@ -392,43 +435,6 @@ void DesignModeWidget::setup() } }); - addSpacerToToolBar(toolBar); - - auto workspaceComboBox = new QComboBox(); - workspaceComboBox->setMinimumWidth(120); - workspaceComboBox->setToolTip(tr("Switch the active workspace.")); - auto sortedWorkspaces = m_dockManager->workspaces(); - Utils::sort(sortedWorkspaces); - workspaceComboBox->addItems(sortedWorkspaces); - workspaceComboBox->setCurrentText(m_dockManager->activeWorkspace()); - toolBar->addWidget(workspaceComboBox); - - connect(m_dockManager, &ADS::DockManager::workspaceListChanged, - workspaceComboBox, [this, workspaceComboBox]() { - workspaceComboBox->clear(); - auto sortedWorkspaces = m_dockManager->workspaces(); - Utils::sort(sortedWorkspaces); - workspaceComboBox->addItems(sortedWorkspaces); - workspaceComboBox->setCurrentText(m_dockManager->activeWorkspace()); - }); - connect(m_dockManager, &ADS::DockManager::workspaceLoaded, workspaceComboBox, &QComboBox::setCurrentText); - connect(workspaceComboBox, &QComboBox::activated, - m_dockManager, [this, workspaceComboBox]([[maybe_unused]] int index) { - m_dockManager->openWorkspace(workspaceComboBox->currentText()); - }); - - const QIcon gaIcon = Utils::StyleHelper::getIconFromIconFont( - fontName, Theme::getIconUnicode(Theme::Icon::annotationBubble), - 36, 36, Theme::getColor(Theme::IconsBaseColor)); - toolBar->addAction(gaIcon, tr("Edit global annotation for current file."), [&](){ - ModelNode node = currentDesignDocument()->rewriterView()->rootModelNode(); - - if (node.isValid()) { - m_globalAnnotationEditor.setModelNode(node); - m_globalAnnotationEditor.showWidget(); - } - }); - viewManager().enableWidgets(); @@ -500,6 +506,26 @@ void DesignModeWidget::toolBarOnGoForwardClicked() } } +bool DesignModeWidget::canGoForward() +{ + return m_canGoForward; +} + +bool DesignModeWidget::canGoBack() +{ + return m_canGoBack; +} + +ADS::DockManager *DesignModeWidget::dockManager() const +{ + return m_dockManager; +} + +GlobalAnnotationEditor &DesignModeWidget::globalAnnotationEditor() +{ + return m_globalAnnotationEditor; +} + DesignDocument *DesignModeWidget::currentDesignDocument() const { return QmlDesignerPlugin::instance()->documentManager().currentDesignDocument(); @@ -515,11 +541,14 @@ void DesignModeWidget::setupNavigatorHistory(Core::IEditor *editor) if (!m_keepNavigatorHistory) addNavigatorHistoryEntry(editor->document()->filePath()); - const bool canGoBack = m_navigatorHistoryCounter > 0; - const bool canGoForward = m_navigatorHistoryCounter < (m_navigatorHistory.size() - 1); - m_toolBar->setCanGoBack(canGoBack); - m_toolBar->setCanGoForward(canGoForward); - m_toolBar->setCurrentEditor(editor); + m_canGoBack = m_navigatorHistoryCounter > 0; + m_canGoForward = m_navigatorHistoryCounter < (m_navigatorHistory.size() - 1); + m_toolBar->setCanGoBack(m_canGoBack); + m_toolBar->setCanGoForward(m_canGoForward); + if (!ToolBar::isVisible()) + m_toolBar->setCurrentEditor(editor); + + emit navigationHistoryChanged(); } void DesignModeWidget::addNavigatorHistoryEntry(const Utils::FilePath &fileName) @@ -576,6 +605,8 @@ void DesignModeWidget::initialize() } m_initStatus = Initialized; + + emit initialized(); } } // namespace Internal diff --git a/src/plugins/qmldesigner/designmodewidget.h b/src/plugins/qmldesigner/designmodewidget.h index 5f1d44de4cb..14efd1e6d50 100644 --- a/src/plugins/qmldesigner/designmodewidget.h +++ b/src/plugins/qmldesigner/designmodewidget.h @@ -64,12 +64,23 @@ public: static QWidget *createProjectExplorerWidget(QWidget *parent); -private: - enum InitializeStatus { NotInitialized, Initializing, Initialized }; - void toolBarOnGoBackClicked(); void toolBarOnGoForwardClicked(); + bool canGoForward(); + bool canGoBack(); + + ADS::DockManager *dockManager() const; + + GlobalAnnotationEditor &globalAnnotationEditor(); + +signals: + void navigationHistoryChanged(); + void initialized(); + +private: + enum InitializeStatus { NotInitialized, Initializing, Initialized }; + void setup(); bool isInNodeDefinition(int nodeOffset, int nodeLength, int cursorPos) const; QmlDesigner::ModelNode nodeForPosition(int cursorPos) const; @@ -96,6 +107,9 @@ private: ADS::DockManager *m_dockManager = nullptr; ADS::DockWidget *m_outputPaneDockWidget = nullptr; GlobalAnnotationEditor m_globalAnnotationEditor; + + bool m_canGoForward = false; + bool m_canGoBack = false; }; } // namespace Internal diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index a472b1416cd..39194033a9d 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -15,6 +15,7 @@ #include "qmldesignerprojectmanager.h" #include "quick2propertyeditorview.h" #include "settingspage.h" +#include #include #include @@ -92,7 +93,7 @@ public: return {"QmlDesigner.Wizards.Enterprise"}; } QSet availablePlatforms() const override { return {}; } - QString displayNameForPlatform(Utils::Id id) const override { return {}; } + QString displayNameForPlatform(Utils::Id) const override { return {}; } }; QString normalizeIdentifier(const QString &string) @@ -270,6 +271,11 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e Core::AsynchronousMessageBox::warning(composedTitle, description.toString()); }); + if (QmlProjectManager::QmlProject::isQtDesignStudio()) { + ToolBar::create(); + ToolBar::createStatusBar(); + } + return true; } diff --git a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp index d7c314a085d..b47101b0aff 100644 --- a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp +++ b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewactions.cpp @@ -113,7 +113,7 @@ QByteArray ZoomPreviewAction::category() const QByteArray ZoomPreviewAction::menuId() const { - return QByteArray(); + return "PreviewZoom"; } int ZoomPreviewAction::priority() const