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 iconColor: buttonIcon.color
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 backgroundRadius: buttonBackground.radius

View File

@@ -122,6 +122,8 @@ QtObject {
property string themeTabDark: Theme.color(Theme.QmlDesigner_TabDark)
property string themeTabLight: Theme.color(Theme.QmlDesigner_TabLight)
property string themeStateDefaultHighlight: "#ffe400"
// Taken out of Constants.js
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/
**
** This file is part of Qt Creator.
@@ -24,6 +24,7 @@
****************************************************************************/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuickDesignerTheme 1.0
import HelperWidgets 2.0
import StudioControls 1.0 as StudioControls
@@ -32,7 +33,8 @@ import StudioTheme 1.0 as StudioTheme
Rectangle {
id: myRoot
border.width: 1
color: baseColor
property bool isBaseState
property bool isCurrentState
property color baseColor
@@ -42,13 +44,19 @@ Rectangle {
property bool delegateHasWhenCondition
property string delegateWhenConditionString
property bool hasAnnotation: checkAnnotation()
property int topAreaHeight
property int bottomAreaHeight
property int stateMargin
property int previewMargin
property int columnSpacing
readonly property bool isDefaultState: isDefault
signal delegateInteraction
property int closeButtonMargin: 6
property int textFieldMargin: 4
property int highlightBorderWidth: 2
color: baseColor
border.color: Theme.qmlDesignerBorderColor()
signal delegateInteraction
function autoComplete(text, pos, explicitComplete, filter) {
var stringList = statesEditorModel.autoComplete(text, pos, explicitComplete)
@@ -62,7 +70,6 @@ Rectangle {
MouseArea {
id: mouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton
onClicked: {
focus = true
@@ -74,11 +81,15 @@ Rectangle {
StudioControls.AbstractButton {
id: removeStateButton
buttonIcon: StudioTheme.Constants.closeCross
anchors.right: parent.right
anchors.rightMargin: 4
anchors.verticalCenter: stateNameField.verticalCenter
visible: !isBaseState
anchors.rightMargin: myRoot.closeButtonMargin
anchors.top: parent.top
anchors.topMargin: myRoot.closeButtonMargin
visible: !isBaseState && isCurrentState
onClicked: {
myRoot.delegateInteraction()
@@ -156,98 +167,135 @@ Rectangle {
}
StudioControls.TextField {
id: stateNameField
actionIndicator.onClicked: {
stateNameField.actionIndicator.forceVisible = true
contextMenu.popup()
}
onEditChanged: {
if (contextMenu.open && stateNameField.edit)
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: {
if (activeFocus)
root.currentStateInternalId = internalNodeId
}
Component.onCompleted: {
text = delegateStateName
}
property string oldValue
onEditingFinished: {
if (stateNameField.oldValue === stateNameField.text)
return
stateNameField.oldValue = stateNameField.text
if (stateNameField.text !== delegateStateName)
statesEditorModel.renameState(internalNodeId, stateNameField.text)
}
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
}
Item {
id: stateImageArea
anchors.topMargin: 2
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: stateNameField.bottom
height: delegateStateImageSize + 2
width: delegateStateImageSize + 2
Column {
id: column
anchors.margins: myRoot.stateMargin
anchors.fill: parent
spacing: expanded ? myRoot.columnSpacing : 0
visible: expanded
Rectangle {
anchors.margins: -1
anchors.fill: stateImage
border.width: 1
border.color: Theme.qmlDesignerBackgroundColorDarker()
width: myRoot.width - 2 * myRoot.stateMargin
height: myRoot.topAreaHeight
color: Theme.color(Theme.DShoverHighlight)
StudioControls.TextField {
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: {
stateNameField.actionIndicator.forceVisible = true
contextMenu.popup()
}
onEditChanged: {
if (contextMenu.open && stateNameField.edit)
contextMenu.dismiss()
}
onActiveFocusChanged: {
if (activeFocus)
root.currentStateInternalId = internalNodeId
}
onEditingFinished: {
if (stateNameField.oldValue === stateNameField.text)
return
stateNameField.oldValue = stateNameField.text
if (stateNameField.text !== myRoot.delegateStateName)
statesEditorModel.renameState(internalNodeId, stateNameField.text)
}
Component.onCompleted: {
text = myRoot.delegateStateName
}
}
Text {
id: stateDefaultIndicator
anchors.right: parent.right
anchors.rightMargin: myRoot.previewMargin
anchors.verticalCenter: stateNameField.verticalCenter
color: Theme.color(Theme.DStextColor)
font.italic: true
font.pixelSize: StudioTheme.Values.myFontSize
font.family: StudioTheme.Constants.font
visible: (isDefaultState || (isBaseState && !modelHasDefaultState))
text: qsTr("Default")
}
}
Image {
id: stateImage
anchors.centerIn: parent
source: delegateStateImageSource
sourceSize.width: delegateStateImageSize
sourceSize.height: delegateStateImageSize
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
}
}
}
Text {
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)
font.italic: true
font.pixelSize: Theme.smallFontPixelSize()
visible: expanded && (isDefaultState || (isBaseState && !modelHasDefaultState))
text: ("* " + qsTr("Default"))
}
BindingEditor {
id: bindingEditor
property string newWhenCondition
property Timer timer: Timer {
@@ -258,8 +306,6 @@ Rectangle {
onTriggered: statesEditorModel.setWhenCondition(internalNodeId, bindingEditor.newWhenCondition)
}
id: bindingEditor
stateModelNodeProperty: statesEditorModel.stateModelNode()
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/
**
** This file is part of Qt Creator.
@@ -33,16 +33,29 @@ import StudioTheme 1.0 as StudioTheme
FocusScope {
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 deleteState(int internalNodeId)
signal duplicateCurrentState
property int stateImageSize: 180
property int stateImageSize: 200
property int padding: 2
property int delegateWidth: root.stateImageSize + 44
property int delegateHeight: root.height - StudioTheme.Values.scrollBarThickness - root.padding * 2 + 1
property int innerSpacing: 0
property int delegateWidth: root.stateImageSize
+ 2 * (root.delegateStateMargin + root.delegatePreviewMargin)
property int delegateHeight: root.height
- StudioTheme.Values.scrollBarThickness
- 2 * (root.padding + StudioTheme.Values.border)
property int innerSpacing: 2
property int currentStateInternalId: 0
property bool expanded: true
@@ -59,7 +72,7 @@ FocusScope {
Rectangle {
id: background
anchors.fill: parent
color: Theme.qmlDesignerBackgroundColorDarkAlternate()
color: Theme.color(Theme.QmlDesigner_BackgroundColorDarkAlternate)
}
MouseArea {
@@ -95,7 +108,7 @@ FocusScope {
Item {
id: addStateItem
property int buttonLeftSpacing: 8 * (root.expanded ? 1 : 2)
property int buttonLeftSpacing: 8 * (root.expanded ? 1 : 2)
anchors.right: parent.right
width: root.delegateHeight / 2 + buttonLeftSpacing
@@ -103,37 +116,35 @@ FocusScope {
AbstractButton {
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.")
visible: canAddNewStates
anchors.right: parent.right
anchors.rightMargin: 8
anchors.verticalCenter: parent.verticalCenter
width: Math.max(parent.height / 2 - 8, 18)
height: width
height: root.expanded ? 80 : width
onClicked: {
root.closeContextMenu()
root.createNewState()
}
background: Rectangle {
property color buttonBaseColor: Qt.darker(Theme.qmlDesignerBackgroundColorDarkAlternate(), 1.1)
color: addStateButton.hovered ? Qt.lighter(buttonBaseColor, 1.2) : buttonBaseColor
border.color: Theme.qmlDesignerBorderColor()
border.width: 1
Image {
source: "image://icons/plus"
width: 16
height: 16
anchors.centerIn: parent
smooth: false
}
}
}
}
Rectangle {
color: Theme.color(Theme.DSsliderActiveTrackFocus)
x: root.padding
y: root.padding
width: Math.min((root.delegateWidth * flickable.count) + (2 * (flickable.count - 1)),
flickable.width)
height: root.delegateHeight
}
ListView {
id: flickable
@@ -155,15 +166,21 @@ FocusScope {
id: statesDelegate
width: root.delegateWidth
height: root.delegateHeight
isBaseState: 0 == internalNodeId
isCurrentState: root.currentStateInternalId == internalNodeId
baseColor: isCurrentState ? Theme.color(Theme.QmlDesigner_HighlightColor) : background.color
isBaseState: 0 === internalNodeId
isCurrentState: root.currentStateInternalId === internalNodeId
baseColor: isCurrentState ? Theme.color(Theme.DSinteraction) : background.color
delegateStateName: stateName
delegateStateImageSource: stateImageSource
delegateStateImageSize: stateImageSize
delegateHasWhenCondition: hasWhenCondition
delegateWhenConditionString: whenConditionString
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