QmlDesigner: Update StateEditor layout

* Add alias properties to StudioControls AbstractButton
* Add color to StudioControls theme
* Update StateEditor layout due to issue with default label placement

Task-number: QDS-2623
Task-number: QDS-2615
Change-Id: If46daab2293d42dff7d73c4cf9a0c370442c5694
Reviewed-by: Brook Cronin <brook.cronin@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Henning Gruendl
2020-08-28 16:10:50 +02:00
committed by Thomas Hartmann
parent 72406c69ce
commit 431667925e
4 changed files with 189 additions and 121 deletions

View File

@@ -33,6 +33,9 @@ T.AbstractButton {
property alias buttonIcon: buttonIcon.text property alias buttonIcon: buttonIcon.text
property alias iconColor: buttonIcon.color property alias iconColor: buttonIcon.color
property alias iconFont: buttonIcon.font.family property alias iconFont: buttonIcon.font.family
property alias iconSize: buttonIcon.font.pixelSize
property alias iconItalic: buttonIcon.font.italic
property alias iconBold: buttonIcon.font.bold
property alias backgroundVisible: buttonBackground.visible property alias backgroundVisible: buttonBackground.visible
property alias backgroundRadius: buttonBackground.radius property alias backgroundRadius: buttonBackground.radius

View File

@@ -122,6 +122,8 @@ QtObject {
property string themeTabDark: Theme.color(Theme.QmlDesigner_TabDark) property string themeTabDark: Theme.color(Theme.QmlDesigner_TabDark)
property string themeTabLight: Theme.color(Theme.QmlDesigner_TabLight) property string themeTabLight: Theme.color(Theme.QmlDesigner_TabLight)
property string themeStateDefaultHighlight: "#ffe400"
// Taken out of Constants.js // Taken out of Constants.js
property string themeChangedStateText: Theme.color(Theme.DSchangedStateText) property string themeChangedStateText: Theme.color(Theme.DSchangedStateText)

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -24,6 +24,7 @@
****************************************************************************/ ****************************************************************************/
import QtQuick 2.15 import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuickDesignerTheme 1.0 import QtQuickDesignerTheme 1.0
import HelperWidgets 2.0 import HelperWidgets 2.0
import StudioControls 1.0 as StudioControls import StudioControls 1.0 as StudioControls
@@ -32,7 +33,8 @@ import StudioTheme 1.0 as StudioTheme
Rectangle { Rectangle {
id: myRoot id: myRoot
border.width: 1 color: baseColor
property bool isBaseState property bool isBaseState
property bool isCurrentState property bool isCurrentState
property color baseColor property color baseColor
@@ -42,13 +44,19 @@ Rectangle {
property bool delegateHasWhenCondition property bool delegateHasWhenCondition
property string delegateWhenConditionString property string delegateWhenConditionString
property bool hasAnnotation: checkAnnotation() property bool hasAnnotation: checkAnnotation()
property int topAreaHeight
property int bottomAreaHeight
property int stateMargin
property int previewMargin
property int columnSpacing
readonly property bool isDefaultState: isDefault readonly property bool isDefaultState: isDefault
signal delegateInteraction property int closeButtonMargin: 6
property int textFieldMargin: 4
property int highlightBorderWidth: 2
color: baseColor signal delegateInteraction
border.color: Theme.qmlDesignerBorderColor()
function autoComplete(text, pos, explicitComplete, filter) { function autoComplete(text, pos, explicitComplete, filter) {
var stringList = statesEditorModel.autoComplete(text, pos, explicitComplete) var stringList = statesEditorModel.autoComplete(text, pos, explicitComplete)
@@ -62,7 +70,6 @@ Rectangle {
MouseArea { MouseArea {
id: mouseArea id: mouseArea
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
onClicked: { onClicked: {
focus = true focus = true
@@ -74,11 +81,15 @@ Rectangle {
StudioControls.AbstractButton { StudioControls.AbstractButton {
id: removeStateButton id: removeStateButton
buttonIcon: StudioTheme.Constants.closeCross buttonIcon: StudioTheme.Constants.closeCross
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 4 anchors.rightMargin: myRoot.closeButtonMargin
anchors.verticalCenter: stateNameField.verticalCenter anchors.top: parent.top
visible: !isBaseState anchors.topMargin: myRoot.closeButtonMargin
visible: !isBaseState && isCurrentState
onClicked: { onClicked: {
myRoot.delegateInteraction() myRoot.delegateInteraction()
@@ -156,9 +167,49 @@ Rectangle {
} }
Rectangle {
anchors.margins: (isDefaultState || (isBaseState && !modelHasDefaultState)) ? -myRoot.highlightBorderWidth : 0
anchors.fill: column
color: Theme.color(Theme.DSsliderActiveTrackFocus)
border.color: StudioTheme.Values.themeStateDefaultHighlight
border.width: (isDefaultState || (isBaseState && !modelHasDefaultState)) ? myRoot.highlightBorderWidth : 0
}
Column {
id: column
anchors.margins: myRoot.stateMargin
anchors.fill: parent
spacing: expanded ? myRoot.columnSpacing : 0
Rectangle {
width: myRoot.width - 2 * myRoot.stateMargin
height: myRoot.topAreaHeight
color: Theme.color(Theme.DShoverHighlight)
StudioControls.TextField { StudioControls.TextField {
id: stateNameField id: stateNameField
property string oldValue
width: StudioTheme.Values.height * 7
anchors.top: parent.top
anchors.topMargin: myRoot.textFieldMargin
anchors.left: parent.left
anchors.leftMargin: myRoot.textFieldMargin
translationIndicatorVisible: false
readOnly: isBaseState
actionIndicator.icon.text: delegateHasWhenCondition
? StudioTheme.Constants.actionIconBinding
: StudioTheme.Constants.actionIcon
actionIndicator.onClicked: { actionIndicator.onClicked: {
stateNameField.actionIndicator.forceVisible = true stateNameField.actionIndicator.forceVisible = true
contextMenu.popup() contextMenu.popup()
@@ -169,85 +220,82 @@ Rectangle {
contextMenu.dismiss() contextMenu.dismiss()
} }
actionIndicator.icon.text: delegateHasWhenCondition
? StudioTheme.Constants.actionIconBinding : StudioTheme.Constants.actionIcon
translationIndicatorVisible: false
y: 4
anchors.left: parent.left
// use the spacing which the image to the delegate rectangle has
anchors.leftMargin: 4
anchors.right: removeStateButton.left
anchors.rightMargin: 2
readOnly: isBaseState
onActiveFocusChanged: { onActiveFocusChanged: {
if (activeFocus) if (activeFocus)
root.currentStateInternalId = internalNodeId root.currentStateInternalId = internalNodeId
} }
Component.onCompleted: {
text = delegateStateName
}
property string oldValue
onEditingFinished: { onEditingFinished: {
if (stateNameField.oldValue === stateNameField.text) if (stateNameField.oldValue === stateNameField.text)
return return
stateNameField.oldValue = stateNameField.text stateNameField.oldValue = stateNameField.text
if (stateNameField.text !== delegateStateName) if (stateNameField.text !== myRoot.delegateStateName)
statesEditorModel.renameState(internalNodeId, stateNameField.text) statesEditorModel.renameState(internalNodeId, stateNameField.text)
} }
}
Item { Component.onCompleted: {
id: stateImageArea text = myRoot.delegateStateName
anchors.topMargin: 2
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: stateNameField.bottom
height: delegateStateImageSize + 2
width: delegateStateImageSize + 2
visible: expanded
Rectangle {
anchors.margins: -1
anchors.fill: stateImage
border.width: 1
border.color: Theme.qmlDesignerBackgroundColorDarker()
}
Image {
id: stateImage
anchors.centerIn: parent
source: delegateStateImageSource
sourceSize.width: delegateStateImageSize
sourceSize.height: delegateStateImageSize
} }
} }
Text { Text {
id: stateDefaultIndicator id: stateDefaultIndicator
anchors.left: parent.left
anchors.leftMargin: StudioTheme.Values.height
anchors.right: removeStateButton.left
anchors.rightMargin: 4
anchors.bottom: parent.bottom
anchors.bottomMargin: 4
color: Theme.color(Theme.PanelTextColorLight) anchors.right: parent.right
anchors.rightMargin: myRoot.previewMargin
anchors.verticalCenter: stateNameField.verticalCenter
color: Theme.color(Theme.DStextColor)
font.italic: true font.italic: true
font.pixelSize: Theme.smallFontPixelSize() font.pixelSize: StudioTheme.Values.myFontSize
font.family: StudioTheme.Constants.font
visible: expanded && (isDefaultState || (isBaseState && !modelHasDefaultState)) visible: (isDefaultState || (isBaseState && !modelHasDefaultState))
text: ("* " + qsTr("Default")) text: qsTr("Default")
}
}
Rectangle {
id: stateImageArea
width: myRoot.width - 2 * myRoot.stateMargin
height: myRoot.bottomAreaHeight
color: Theme.color(Theme.DShoverHighlight)
visible: expanded
Rectangle {
border.width: StudioTheme.Values.border
border.color: Theme.color(Theme.DSsliderActiveTrackFocus)
color: Theme.color(Theme.DSsliderInactiveTrack)
anchors.centerIn: parent
width: Math.round(stateImage.paintedWidth) + 2 * StudioTheme.Values.border
height: Math.round(stateImage.paintedHeight) + 2 * StudioTheme.Values.border
}
Image {
id: stateImage
anchors.margins: myRoot.previewMargin
anchors.centerIn: parent
anchors.fill: parent
source: delegateStateImageSource
sourceSize.width: delegateStateImageSize
sourceSize.height: delegateStateImageSize
fillMode: Image.PreserveAspectFit
}
}
} }
BindingEditor { BindingEditor {
id: bindingEditor
property string newWhenCondition property string newWhenCondition
property Timer timer: Timer { property Timer timer: Timer {
@@ -258,8 +306,6 @@ Rectangle {
onTriggered: statesEditorModel.setWhenCondition(internalNodeId, bindingEditor.newWhenCondition) onTriggered: statesEditorModel.setWhenCondition(internalNodeId, bindingEditor.newWhenCondition)
} }
id: bindingEditor
stateModelNodeProperty: statesEditorModel.stateModelNode() stateModelNodeProperty: statesEditorModel.stateModelNode()
onRejected: { onRejected: {

View File

@@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of Qt Creator. ** This file is part of Qt Creator.
@@ -33,16 +33,29 @@ import StudioTheme 1.0 as StudioTheme
FocusScope { FocusScope {
id: root id: root
height: (root.expanded ? 192 : 40) + StudioTheme.Values.scrollBarThickness property int delegateTopAreaHeight: 30
property int delegateBottomAreaHeight: 200
property int delegateColumnSpacing: 2
property int delegateStateMargin: 16
property int delegatePreviewMargin: 16
height: (root.expanded ? (root.delegateTopAreaHeight + root.delegateBottomAreaHeight + root.delegateColumnSpacing)
: root.delegateTopAreaHeight)
+ StudioTheme.Values.scrollBarThickness
+ 2 * (root.delegateStateMargin + StudioTheme.Values.border + root.padding)
signal createNewState signal createNewState
signal deleteState(int internalNodeId) signal deleteState(int internalNodeId)
signal duplicateCurrentState signal duplicateCurrentState
property int stateImageSize: 180 property int stateImageSize: 200
property int padding: 2 property int padding: 2
property int delegateWidth: root.stateImageSize + 44 property int delegateWidth: root.stateImageSize
property int delegateHeight: root.height - StudioTheme.Values.scrollBarThickness - root.padding * 2 + 1 + 2 * (root.delegateStateMargin + root.delegatePreviewMargin)
property int innerSpacing: 0 property int delegateHeight: root.height
- StudioTheme.Values.scrollBarThickness
- 2 * (root.padding + StudioTheme.Values.border)
property int innerSpacing: 2
property int currentStateInternalId: 0 property int currentStateInternalId: 0
property bool expanded: true property bool expanded: true
@@ -59,7 +72,7 @@ FocusScope {
Rectangle { Rectangle {
id: background id: background
anchors.fill: parent anchors.fill: parent
color: Theme.qmlDesignerBackgroundColorDarkAlternate() color: Theme.color(Theme.QmlDesigner_BackgroundColorDarkAlternate)
} }
MouseArea { MouseArea {
@@ -103,35 +116,33 @@ FocusScope {
AbstractButton { AbstractButton {
id: addStateButton id: addStateButton
visible: canAddNewStates
buttonIcon: root.expanded ? qsTr("Create New State") : StudioTheme.Constants.plus
iconFont: root.expanded ? StudioTheme.Constants.font : StudioTheme.Constants.iconFont
iconSize: root.expanded ? StudioTheme.Values.myFontSize : StudioTheme.Values.myIconFontSize
iconItalic: root.expanded ? true : false
tooltip: qsTr("Add a new state.") tooltip: qsTr("Add a new state.")
visible: canAddNewStates
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 8 anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: Math.max(parent.height / 2 - 8, 18) width: Math.max(parent.height / 2 - 8, 18)
height: width height: root.expanded ? 80 : width
onClicked: { onClicked: {
root.closeContextMenu() root.closeContextMenu()
root.createNewState() root.createNewState()
} }
}
}
background: Rectangle { Rectangle {
property color buttonBaseColor: Qt.darker(Theme.qmlDesignerBackgroundColorDarkAlternate(), 1.1) color: Theme.color(Theme.DSsliderActiveTrackFocus)
color: addStateButton.hovered ? Qt.lighter(buttonBaseColor, 1.2) : buttonBaseColor x: root.padding
border.color: Theme.qmlDesignerBorderColor() y: root.padding
border.width: 1 width: Math.min((root.delegateWidth * flickable.count) + (2 * (flickable.count - 1)),
Image { flickable.width)
source: "image://icons/plus" height: root.delegateHeight
width: 16
height: 16
anchors.centerIn: parent
smooth: false
}
}
}
} }
ListView { ListView {
@@ -155,15 +166,21 @@ FocusScope {
id: statesDelegate id: statesDelegate
width: root.delegateWidth width: root.delegateWidth
height: root.delegateHeight height: root.delegateHeight
isBaseState: 0 == internalNodeId isBaseState: 0 === internalNodeId
isCurrentState: root.currentStateInternalId == internalNodeId isCurrentState: root.currentStateInternalId === internalNodeId
baseColor: isCurrentState ? Theme.color(Theme.QmlDesigner_HighlightColor) : background.color baseColor: isCurrentState ? Theme.color(Theme.DSinteraction) : background.color
delegateStateName: stateName delegateStateName: stateName
delegateStateImageSource: stateImageSource delegateStateImageSource: stateImageSource
delegateStateImageSize: stateImageSize delegateStateImageSize: stateImageSize
delegateHasWhenCondition: hasWhenCondition delegateHasWhenCondition: hasWhenCondition
delegateWhenConditionString: whenConditionString delegateWhenConditionString: whenConditionString
onDelegateInteraction: root.closeContextMenu() onDelegateInteraction: root.closeContextMenu()
columnSpacing: root.delegateColumnSpacing
topAreaHeight: root.delegateTopAreaHeight
bottomAreaHeight: root.delegateBottomAreaHeight
stateMargin: root.delegateStateMargin
previewMargin: root.delegatePreviewMargin
} }
property bool bothVisible: horizontal.scrollBarVisible && vertical.scrollBarVisible property bool bothVisible: horizontal.scrollBarVisible && vertical.scrollBarVisible