diff --git a/share/qtcreator/qmldesigner/designsystem/Main.qml b/share/qtcreator/qmldesigner/designsystem/Main.qml index ffcffe81dd0..7182e04d06b 100644 --- a/share/qtcreator/qmldesigner/designsystem/Main.qml +++ b/share/qtcreator/qmldesigner/designsystem/Main.qml @@ -81,10 +81,190 @@ Rectangle { } function setValue(value: var, row: int, column: int, isBinding: bool): bool { - console.log("setValue(", value, row, column, isBinding, ")") - return tableView.model.setData(tableView.index(row, column), + let result = tableView.model.setData(tableView.index(row, column), DesignSystemBackend.dsInterface.createThemeProperty("", value, isBinding), Qt.EditRole) + + if (!result) + overlayInvalid.showData(row, column) + + return result + } + + function dismissInvalidOverlay() { + overlayInvalid.hide() + notification.visible = false + } + + Rectangle { + id: overlayInvalid + + property Item cellItem + + color: "transparent" + border { + width: StudioTheme.Values.border + color: StudioTheme.Values.themeAmberLight + } + + visible: false + z: 112 + + function show() { + overlayInvalid.visible = true + overlayInvalid.layout() + notification.visible = true + + notification.forceActiveFocus() + } + + function showData(row: int, column: int) { + overlayInvalid.parent = tableView.contentItem + overlayInvalid.cellItem = tableView.itemAtCell(Qt.point(column, row)) + + notification.message = qsTr("Invalid binding. Please use a valid non-cyclic binding.") + + overlayInvalid.show() + } + + function showHeaderData(section: int, orientation: var) { + if (orientation === Qt.Horizontal) { + overlayInvalid.parent = horizontalHeaderView.contentItem + overlayInvalid.cellItem = horizontalHeaderView.itemAtCell(Qt.point(overlay.section, 0)) + } else { + overlayInvalid.parent = verticalHeaderView.contentItem + overlayInvalid.cellItem = verticalHeaderView.itemAtCell(Qt.point(0, overlay.section)) + } + + notification.message = qsTr("This name is already in use, please use a different name.") + + overlayInvalid.show() + } + + function hide() { + overlayInvalid.visible = false + } + + function layout() { + if (!overlayInvalid.visible) + return + + if (overlayInvalid.cellItem !== null) { + overlayInvalid.x = overlayInvalid.cellItem.x + 1 + overlayInvalid.y = overlayInvalid.cellItem.y + 1 + overlayInvalid.width = overlayInvalid.cellItem.width - 2 + overlayInvalid.height = overlayInvalid.cellItem.height - 2 + } + } + + Connections { + target: tableView + + function onLayoutChanged() { overlayInvalid.layout() } + } + } + + Rectangle { + id: notification + + property alias message: contentItemText.text + + width: 260 + height: 78 + z: 666 + + visible: false + + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: 20 + + color: StudioTheme.Values.themePopoutBackground + border.color: "#636363" + border.width: StudioTheme.Values.border + + onActiveFocusChanged: { + if (!notification.activeFocus) + root.dismissInvalidOverlay() + } + + Column { + id: column + anchors.fill: parent + anchors.margins: StudioTheme.Values.border + + Item { + id: titleBarItem + width: parent.width + height: StudioTheme.Values.height + + Row { + id: row + anchors.fill: parent + anchors.leftMargin: 8 + anchors.rightMargin: 4 + spacing: 4 + + Item { + id: titleBarContent + width: row.width - row.spacing - closeIndicator.width + height: row.height + + Row { + anchors.fill: parent + spacing: 10 + + T.Label { + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: root.customStyle.mediumIconFontSize + text: StudioTheme.Constants.warning2_medium + font.family: StudioTheme.Constants.iconFont.family + color: StudioTheme.Values.themeAmberLight + } + + Text { + anchors.verticalCenter: parent.verticalCenter + text: qsTr("Warning") + color: StudioTheme.Values.themeTextColor + } + } + } + + StudioControls.IconIndicator { + id: closeIndicator + anchors.verticalCenter: parent.verticalCenter + icon: StudioTheme.Constants.colorPopupClose + pixelSize: StudioTheme.Values.myIconFontSize + onClicked: root.dismissInvalidOverlay() + } + } + } + + Item { + id: contentItem + width: parent.width + height: parent.height - titleBarItem.height + + Column { + anchors.fill: parent + anchors.margins: 8 + anchors.topMargin: 4 + + Item { + width: parent.width + height: parent.height + + Text { + id: contentItemText + anchors.fill: parent + wrapMode: Text.Wrap + elide: Text.ElideRight + color: StudioTheme.Values.themeTextColor + } + } + } + } + } } Connections { @@ -154,7 +334,7 @@ Rectangle { StudioControls.Dialog { id: createCollectionDialog - property alias newCollectionName: createCollectionTextField.text; + property alias newCollectionName: createCollectionTextField.text title: qsTr("Create collection") width: Math.min(300, root.width) closePolicy: Popup.CloseOnEscape @@ -318,7 +498,7 @@ Rectangle { StudioControls.MenuItem { text: qsTr("Create collection") onTriggered: { - createCollectionDialog.newCollectionName = DesignSystemBackend.dsInterface.generateCollectionName(qsTr("NewCollection")); + createCollectionDialog.newCollectionName = DesignSystemBackend.dsInterface.generateCollectionName(qsTr("NewCollection")) createCollectionDialog.open() } } @@ -338,10 +518,7 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter buttonIcon: StudioTheme.Constants.updateContent_medium tooltip: qsTr("Refresh") - onClicked: { - DesignSystemBackend.dsInterface.loadDesignSystem() - //root.loadModel(DesignSystemBackend.dsInterface.collections[0]) - } + onClicked: DesignSystemBackend.dsInterface.loadDesignSystem() } } } @@ -361,6 +538,7 @@ Rectangle { required property var propertyValue readonly property bool bindingEditor: cell.isBinding || tableView.model.editableOverride + readonly property bool isValid: cell.resolvedValue !== undefined color: root.backgroundColor implicitWidth: root.cellWidth @@ -377,10 +555,13 @@ Rectangle { HoverHandler { id: cellHoverHandler } DSC.BindingIndicator { - icon.text: dataCell.isBinding ? StudioTheme.Constants.actionIconBinding - : StudioTheme.Constants.actionIcon - icon.color: dataCell.isBinding ? StudioTheme.Values.themeInteraction - : StudioTheme.Values.themeTextColor + id: bindingIndicator + icon.text: !dataCell.isValid ? StudioTheme.Constants.warning2_medium + : dataCell.isBinding ? StudioTheme.Constants.actionIconBinding + : StudioTheme.Constants.actionIcon + icon.color: !dataCell.isValid ? StudioTheme.Values.themeAmberLight + : dataCell.isBinding ? StudioTheme.Values.themeInteraction + : StudioTheme.Values.themeTextColor anchors.verticalCenter: parent.verticalCenter anchors.right: parent.right @@ -391,9 +572,24 @@ Rectangle { tableView.closeEditor() menu.show(dataCell.row, dataCell.column) } + + onHoverChanged: { + if (dataCell.isValid) + return + + if (bindingIndicator.hover) + toolTipInvalid.showText(dataCell, + Qt.point(bindingIndicator.x + bindingIndicator.width, + bindingIndicator.y), + qsTr("Invalid binding. Cyclic binding is not allowed.")) + else + toolTipInvalid.hideText() + } } } + StudioControls.ToolTipExt { id: toolTipInvalid } + DelegateChooser { id: chooser role: "group" @@ -783,7 +979,7 @@ Rectangle { } text: qsTr("Reset") onTriggered: { - let data = tableView.model.data(menu.modelIndex, CollectionModel.ResolvedValueRole) + let data = tableView.model.data(menu.modelIndex, CollectionModel.ResolvedValueRole) ?? "" var prop = DesignSystemBackend.dsInterface.createThemeProperty("", data, false) let result = tableView.model.setData(menu.modelIndex, prop, Qt.EditRole) } @@ -895,6 +1091,10 @@ Rectangle { // Revoke active focus from text field by forcing active focus on another item tableView.forceActiveFocus() + + + if (!result) + overlayInvalid.showHeaderData(overlay.section, overlay.orientation) } Text { @@ -929,8 +1129,7 @@ Rectangle { } function show(section, orientation) { - // Close all currently visible edit delegates - tableView.closeEditor() + tableView.closeEditor() // Close all currently visible edit delegates if (orientation === Qt.Horizontal) overlay.parent = horizontalHeaderView.contentItem @@ -970,7 +1169,6 @@ Rectangle { let insideViewport = item !== null - //overlay.visible = insideViewport if (insideViewport) { overlay.x = item.x overlay.y = item.y diff --git a/share/qtcreator/qmldesigner/designsystem/imports/DesignSystemControls/BindingIndicator.qml b/share/qtcreator/qmldesigner/designsystem/imports/DesignSystemControls/BindingIndicator.qml index 096b639e246..0ce33472abd 100644 --- a/share/qtcreator/qmldesigner/designsystem/imports/DesignSystemControls/BindingIndicator.qml +++ b/share/qtcreator/qmldesigner/designsystem/imports/DesignSystemControls/BindingIndicator.qml @@ -11,7 +11,7 @@ Item { property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle property alias icon: icon - property bool hover: mouseArea.containsMouse//false + property bool hover: mouseArea.containsMouse property bool pressed: false property bool forceVisible: false @@ -19,6 +19,7 @@ Item { implicitHeight: control.style.actionIndicatorSize.height signal clicked + z: 10 T.Label { @@ -56,7 +57,6 @@ Item { id: mouseArea anchors.fill: parent hoverEnabled: true - //onContainsMouseChanged: control.hover = mouseArea.containsMouse onClicked: control.clicked() } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ToolTip.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ToolTip.qml index b39fb6881ce..8185edaaf6c 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ToolTip.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ToolTip.qml @@ -3,7 +3,7 @@ import QtQuick import QtQuick.Templates as T -import StudioTheme 1.0 as StudioTheme +import StudioTheme as StudioTheme T.ToolTip { id: control @@ -38,4 +38,3 @@ T.ToolTip { border.color: control.style.toolTip.border } } - diff --git a/src/plugins/qmldesigner/components/designsystemview/designsystemview.cpp b/src/plugins/qmldesigner/components/designsystemview/designsystemview.cpp index 77532f284f2..29e8cf49f49 100644 --- a/src/plugins/qmldesigner/components/designsystemview/designsystemview.cpp +++ b/src/plugins/qmldesigner/components/designsystemview/designsystemview.cpp @@ -53,8 +53,8 @@ WidgetInfo DesignSystemView::widgetInfo() return createWidgetInfo(m_designSystemWidget, "DesignSystemView", WidgetInfo::RightPane, - Tr::tr("Design System"), - Tr::tr("Design System view"), + Tr::tr("Design Tokens"), + Tr::tr("Design Tokens view"), DesignerWidgetFlags::IgnoreErrors); } diff --git a/src/plugins/qmldesigner/components/designsystemview/designsystemwidget.cpp b/src/plugins/qmldesigner/components/designsystemview/designsystemwidget.cpp index d843a4a20bb..1afc2b2a6de 100644 --- a/src/plugins/qmldesigner/components/designsystemview/designsystemwidget.cpp +++ b/src/plugins/qmldesigner/components/designsystemview/designsystemwidget.cpp @@ -62,7 +62,7 @@ DesignSystemWidget::DesignSystemWidget(DesignSystemView *view, DesignSystemInter Theme::setupTheme(engine()); - setWindowTitle(tr("Design System", "Title of Editor widget")); + setWindowTitle(tr("Design Tokens", "Title of Editor widget")); setMinimumSize(QSize(195, 195)); // init the first load of the QML UI elements