forked from qt-creator/qt-creator
QmlDesigner: Close the color editor popup before adding
Fixes: QDS-12498 Change-Id: Id3c565ffb9fca7f186ebeb0cf8051194c7944d4d Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io> Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
This commit is contained in:
@@ -90,7 +90,7 @@ Rectangle {
|
|||||||
property int order: Qt.AscendingOrder
|
property int order: Qt.AscendingOrder
|
||||||
onClicked: {
|
onClicked: {
|
||||||
order = (order == Qt.AscendingOrder) ? Qt.DescendingOrder : Qt.AscendingOrder;
|
order = (order == Qt.AscendingOrder) ? Qt.DescendingOrder : Qt.AscendingOrder;
|
||||||
tableView.closeEditor()
|
tableView.closeEditors()
|
||||||
tableView.model.sort(-1, order)
|
tableView.model.sort(-1, order)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +173,7 @@ Rectangle {
|
|||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Sort Ascending")
|
text: qsTr("Sort Ascending")
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
tableView.closeEditor()
|
tableView.closeEditors()
|
||||||
tableView.model.sort(headerMenu.clickedHeaderIndex, Qt.AscendingOrder)
|
tableView.model.sort(headerMenu.clickedHeaderIndex, Qt.AscendingOrder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,7 +181,7 @@ Rectangle {
|
|||||||
StudioControls.MenuItem {
|
StudioControls.MenuItem {
|
||||||
text: qsTr("Sort Descending")
|
text: qsTr("Sort Descending")
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
tableView.closeEditor()
|
tableView.closeEditors()
|
||||||
tableView.model.sort(headerMenu.clickedHeaderIndex, Qt.DescendingOrder)
|
tableView.model.sort(headerMenu.clickedHeaderIndex, Qt.DescendingOrder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,6 +235,8 @@ Rectangle {
|
|||||||
property int targetRow
|
property int targetRow
|
||||||
property int targetColumn
|
property int targetColumn
|
||||||
|
|
||||||
|
property Item popupEditingItem
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignTop + Qt.AlignLeft
|
Layout.alignment: Qt.AlignTop + Qt.AlignLeft
|
||||||
Layout.preferredWidth: tableView.contentWidth
|
Layout.preferredWidth: tableView.contentWidth
|
||||||
Layout.preferredHeight: tableView.contentHeight
|
Layout.preferredHeight: tableView.contentHeight
|
||||||
@@ -261,6 +263,24 @@ Rectangle {
|
|||||||
return Math.max(h, StudioTheme.Values.collectionCellMinimumHeight)
|
return Math.max(h, StudioTheme.Values.collectionCellMinimumHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function closePopupEditor() {
|
||||||
|
if (tableView.popupEditingItem)
|
||||||
|
tableView.popupEditingItem.closeEditor()
|
||||||
|
tableView.popupEditingItem = null
|
||||||
|
}
|
||||||
|
|
||||||
|
function openNewPopupEditor(item, editor) {
|
||||||
|
if (tableView.popupEditingItem !== item) {
|
||||||
|
closePopupEditor()
|
||||||
|
tableView.popupEditingItem = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeEditors() {
|
||||||
|
closeEditor()
|
||||||
|
closePopupEditor()
|
||||||
|
}
|
||||||
|
|
||||||
function ensureRowIsVisible(row) {
|
function ensureRowIsVisible(row) {
|
||||||
let rows = tableView.model.rowCount()
|
let rows = tableView.model.rowCount()
|
||||||
let rowIsLoaded = tableView.isRowLoaded(row)
|
let rowIsLoaded = tableView.isRowLoaded(row)
|
||||||
@@ -381,7 +401,36 @@ Rectangle {
|
|||||||
Component {
|
Component {
|
||||||
id: colorEditorComponent
|
id: colorEditorComponent
|
||||||
|
|
||||||
ColorViewDelegate {}
|
ColorViewDelegate {
|
||||||
|
id: colorEditorItem
|
||||||
|
|
||||||
|
readonly property color editValue: edit
|
||||||
|
readonly property color displayValue: display
|
||||||
|
property string _frontColorStr
|
||||||
|
property string _backendColorStr
|
||||||
|
|
||||||
|
actionIndicatorVisible: false
|
||||||
|
|
||||||
|
onColorChanged: {
|
||||||
|
_frontColorStr = colorEditorItem.color.toString()
|
||||||
|
if (_frontColorStr != _backendColorStr)
|
||||||
|
edit = colorEditorItem.color
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
colorEditorItem.color = display
|
||||||
|
}
|
||||||
|
|
||||||
|
onDisplayValueChanged: {
|
||||||
|
_backendColorStr = colorEditorItem.displayValue.toString()
|
||||||
|
if (_frontColorStr != _backendColorStr)
|
||||||
|
colorEditorItem.color = colorEditorItem.displayValue
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditorOpened: (item, editor) => {
|
||||||
|
tableView.openNewPopupEditor(item, editor)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetSource() {
|
function resetSource() {
|
||||||
@@ -441,13 +490,13 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onRowsInserted(parent, first, last) {
|
function onRowsInserted(parent, first, last) {
|
||||||
tableView.closeEditor()
|
tableView.closeEditors()
|
||||||
tableView.model.selectRow(first)
|
tableView.model.selectRow(first)
|
||||||
tableView.ensureRowIsVisible(first)
|
tableView.ensureRowIsVisible(first)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onColumnsInserted(parent, first, last) {
|
function onColumnsInserted(parent, first, last) {
|
||||||
tableView.closeEditor()
|
tableView.closeEditors()
|
||||||
tableView.model.selectColumn(first)
|
tableView.model.selectColumn(first)
|
||||||
tableView.ensureColumnIsVisible(first)
|
tableView.ensureColumnIsVisible(first)
|
||||||
}
|
}
|
||||||
@@ -503,7 +552,7 @@ Rectangle {
|
|||||||
tooltip: "Add Column"
|
tooltip: "Add Column"
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tableView.closeEditor()
|
tableView.closeEditors()
|
||||||
toolbar.addNewColumn()
|
toolbar.addNewColumn()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -521,7 +570,7 @@ Rectangle {
|
|||||||
tooltip: "Add Row"
|
tooltip: "Add Row"
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tableView.closeEditor()
|
tableView.closeEditors()
|
||||||
toolbar.addNewRow()
|
toolbar.addNewRow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,170 +10,59 @@ import StudioTheme as StudioTheme
|
|||||||
import StudioControls as StudioControls
|
import StudioControls as StudioControls
|
||||||
import QtQuickDesignerTheme
|
import QtQuickDesignerTheme
|
||||||
import QtQuickDesignerColorPalette
|
import QtQuickDesignerColorPalette
|
||||||
|
import StudioHelpers
|
||||||
|
|
||||||
Row {
|
Item {
|
||||||
id: colorEditor
|
id: root
|
||||||
|
|
||||||
property color color
|
property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle
|
||||||
property bool supportGradient: false
|
|
||||||
|
|
||||||
property QtObject backendValue: QtObject {
|
property alias color: colorBackend.color
|
||||||
property color value: edit
|
|
||||||
readonly property color editColor: edit
|
|
||||||
|
|
||||||
function resetValue() {
|
property alias actionIndicatorVisible: actionIndicator.visible
|
||||||
if (value)
|
property real __actionIndicatorWidth: root.style.actionIndicatorSize.width
|
||||||
value = ""
|
property real __actionIndicatorHeight: root.style.actionIndicatorSize.height
|
||||||
|
|
||||||
|
property alias showHexTextField: hexTextField.visible
|
||||||
|
|
||||||
|
readonly property real padding: 2
|
||||||
|
readonly property real innerItemsHeight: root.height - 2 * root.padding
|
||||||
|
|
||||||
|
width: root.style.controlSize.width
|
||||||
|
height: root.style.controlSize.height
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
signal editorOpened(var item, var editorPopup)
|
||||||
|
|
||||||
|
function closeEditor() {
|
||||||
|
loader.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
onValueChanged: {
|
ColorBackend {
|
||||||
if (editColor !== value)
|
id: colorBackend
|
||||||
edit = value
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
property variant value: {
|
StudioControls.ActionIndicator {
|
||||||
if (!colorEditor.backendValue || !colorEditor.backendValue.value)
|
id: actionIndicator
|
||||||
return "white" // default color for Rectangle
|
style: root.style
|
||||||
|
__parentControl: root
|
||||||
if (colorEditor.isVector3D) {
|
x: root.padding
|
||||||
return Qt.rgba(colorEditor.backendValue.value.x,
|
y: root.padding
|
||||||
colorEditor.backendValue.value.y,
|
width: actionIndicator.visible ? root.__actionIndicatorWidth : 0
|
||||||
colorEditor.backendValue.value.z, 1)
|
height: actionIndicator.visible ? root.__actionIndicatorHeight : 0
|
||||||
}
|
|
||||||
|
|
||||||
return colorEditor.backendValue.value
|
|
||||||
}
|
|
||||||
|
|
||||||
property alias gradientPropertyName: popupDialog.gradientPropertyName
|
|
||||||
|
|
||||||
property alias gradientThumbnail: gradientThumbnail
|
|
||||||
property alias shapeGradientThumbnail: shapeGradientThumbnail
|
|
||||||
|
|
||||||
property bool shapeGradients: false
|
|
||||||
property bool isVector3D: false
|
|
||||||
property color originalColor
|
|
||||||
|
|
||||||
property bool __block: false
|
|
||||||
|
|
||||||
function resetShapeColor() {
|
|
||||||
colorEditor.backendValue.resetValue()
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeColor() {
|
|
||||||
if (colorEditor.isVector3D) {
|
|
||||||
colorEditor.backendValue.value = Qt.vector3d(colorEditor.color.r,
|
|
||||||
colorEditor.color.g,
|
|
||||||
colorEditor.color.b)
|
|
||||||
} else {
|
|
||||||
colorEditor.backendValue.value = colorEditor.color
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function initEditor() {
|
|
||||||
colorEditor.syncColor()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Syncing color from backend to frontend and block reflection
|
|
||||||
function syncColor() {
|
|
||||||
colorEditor.__block = true
|
|
||||||
colorEditor.color = colorEditor.value
|
|
||||||
hexTextField.syncColor()
|
|
||||||
colorEditor.__block = false
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
id: backendConnection
|
|
||||||
|
|
||||||
target: colorEditor
|
|
||||||
|
|
||||||
function onValueChanged() {
|
|
||||||
if (popupDialog.isSolid())
|
|
||||||
colorEditor.syncColor()
|
|
||||||
}
|
|
||||||
|
|
||||||
function onBackendValueChanged() {
|
|
||||||
if (popupDialog.isSolid())
|
|
||||||
colorEditor.syncColor()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: colorEditorTimer
|
|
||||||
|
|
||||||
repeat: false
|
|
||||||
interval: 100
|
|
||||||
running: false
|
|
||||||
onTriggered: {
|
|
||||||
backendConnection.enabled = false
|
|
||||||
colorEditor.writeColor()
|
|
||||||
hexTextField.syncColor()
|
|
||||||
backendConnection.enabled = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onColorChanged: {
|
|
||||||
if (colorEditor.__block)
|
|
||||||
return
|
|
||||||
|
|
||||||
if (!popupDialog.isInValidState)
|
|
||||||
return
|
|
||||||
|
|
||||||
popupDialog.commitToGradient()
|
|
||||||
|
|
||||||
// Delay setting the color to keep ui responsive
|
|
||||||
if (popupDialog.isSolid())
|
|
||||||
colorEditorTimer.restart()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: preview
|
id: preview
|
||||||
|
x: root.padding + actionIndicator.width
|
||||||
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
y: root.padding
|
||||||
implicitHeight: StudioTheme.Values.height
|
z: previewMouseArea.containsMouse ? 10 : 0
|
||||||
color: colorEditor.color
|
implicitWidth: root.innerItemsHeight
|
||||||
border.color: StudioTheme.Values.themeControlOutline
|
implicitHeight: root.innerItemsHeight
|
||||||
border.width: StudioTheme.Values.border
|
color: root.color
|
||||||
|
border.color: previewMouseArea.containsMouse ? root.style.border.hover : root.style.border.idle
|
||||||
Rectangle {
|
border.width: root.style.borderWidth
|
||||||
id: gradientThumbnail
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: StudioTheme.Values.border
|
|
||||||
visible: !popupDialog.isSolid()
|
|
||||||
&& !colorEditor.shapeGradients
|
|
||||||
&& popupDialog.isLinearGradient()
|
|
||||||
}
|
|
||||||
|
|
||||||
Shape {
|
|
||||||
id: shape
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: StudioTheme.Values.border
|
|
||||||
visible: !popupDialog.isSolid() && colorEditor.shapeGradients
|
|
||||||
|
|
||||||
ShapePath {
|
|
||||||
id: shapeGradientThumbnail
|
|
||||||
|
|
||||||
startX: shape.x - 1
|
|
||||||
startY: shape.y - 1
|
|
||||||
strokeWidth: -1
|
|
||||||
strokeColor: "green"
|
|
||||||
|
|
||||||
PathLine {
|
|
||||||
x: shape.x - 1
|
|
||||||
y: shape.height
|
|
||||||
}
|
|
||||||
PathLine {
|
|
||||||
x: shape.width
|
|
||||||
y: shape.height
|
|
||||||
}
|
|
||||||
PathLine {
|
|
||||||
x: shape.width
|
|
||||||
y: shape.y - 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -183,114 +72,111 @@ Row {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
id: previewMouseArea
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
onClicked: {
|
onClicked: {
|
||||||
popupDialog.visibility ? popupDialog.close() : popupDialog.open()
|
loader.toggle()
|
||||||
forceActiveFocus()
|
previewMouseArea.forceActiveFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StudioControls.PopupDialog {
|
|
||||||
id: popupDialog
|
|
||||||
|
|
||||||
property bool isInValidState: loader.active ? popupDialog.loaderItem.isInValidState : true
|
|
||||||
property QtObject loaderItem: loader.item
|
|
||||||
property string gradientPropertyName
|
|
||||||
|
|
||||||
keepOpen: loader.item?.eyeDropperActive ?? false
|
|
||||||
|
|
||||||
width: 260
|
|
||||||
|
|
||||||
function commitToGradient() {
|
|
||||||
if (!loader.active)
|
|
||||||
return
|
|
||||||
|
|
||||||
if (colorEditor.supportGradient && popupDialog.loaderItem.gradientModel.hasGradient) {
|
|
||||||
var hexColor = convertColorToString(colorEditor.color)
|
|
||||||
hexTextField.text = hexColor
|
|
||||||
colorEditor.backendValue.value = hexColor
|
|
||||||
popupDialog.loaderItem.commitGradientColor()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isSolid() {
|
|
||||||
if (!loader.active)
|
|
||||||
return true
|
|
||||||
|
|
||||||
return popupDialog.loaderItem.isSolid()
|
|
||||||
}
|
|
||||||
|
|
||||||
function isLinearGradient(){
|
|
||||||
if (!loader.active)
|
|
||||||
return false
|
|
||||||
|
|
||||||
return popupDialog.loaderItem.isLinearGradient()
|
|
||||||
}
|
|
||||||
|
|
||||||
function ensureLoader() {
|
|
||||||
if (!loader.active)
|
|
||||||
loader.active = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function open() {
|
|
||||||
popupDialog.ensureLoader()
|
|
||||||
popupDialog.loaderItem.initEditor()
|
|
||||||
popupDialog.show(preview)
|
|
||||||
}
|
|
||||||
|
|
||||||
function determineActiveColorMode() {
|
|
||||||
if (loader.active && popupDialog.loaderItem)
|
|
||||||
popupDialog.loaderItem.determineActiveColorMode()
|
|
||||||
else
|
|
||||||
colorEditor.syncColor()
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: loader
|
id: loader
|
||||||
|
|
||||||
active: colorEditor.supportGradient
|
function ensureLoader() {
|
||||||
|
if (!loader.active)
|
||||||
|
loader.active = true
|
||||||
|
if (loader.sourceComponent === null)
|
||||||
|
loader.sourceComponent = popupDialogComponent
|
||||||
|
}
|
||||||
|
|
||||||
sourceComponent: HelperWidgets.ColorEditorPopup {
|
function open() {
|
||||||
shapeGradients: colorEditor.shapeGradients
|
loader.ensureLoader()
|
||||||
supportGradient: colorEditor.supportGradient
|
loader.item.show(preview)
|
||||||
|
|
||||||
|
if (loader.status === Loader.Ready)
|
||||||
|
loader.item.originalColor = root.color
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
if (loader.item)
|
||||||
|
loader.item.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
if (loader.item)
|
||||||
|
loader.close()
|
||||||
|
else
|
||||||
|
loader.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: popupDialogComponent
|
||||||
|
|
||||||
|
|
||||||
|
StudioControls.PopupDialog {
|
||||||
|
id: popupDialog
|
||||||
|
|
||||||
|
property alias color: popup.color
|
||||||
|
property alias originalColor: popup.originalColor
|
||||||
|
titleBar: popup.titleBarContent
|
||||||
|
|
||||||
|
width: 260
|
||||||
|
|
||||||
|
StudioControls.ColorEditorPopup {
|
||||||
|
id: popup
|
||||||
width: popupDialog.contentWidth
|
width: popupDialog.contentWidth
|
||||||
|
|
||||||
|
onActivateColor: function(color) {
|
||||||
|
colorBackend.activateColor(color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosing: {
|
||||||
|
loader.sourceComponent = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceComponent: null
|
||||||
|
|
||||||
|
Binding {
|
||||||
|
target: loader.item
|
||||||
|
property: "color"
|
||||||
|
value: root.color
|
||||||
|
when: loader.status === Loader.Ready
|
||||||
}
|
}
|
||||||
|
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
popupDialog.loaderItem.initEditor()
|
loader.item.originalColor = root.color
|
||||||
popupDialog.titleBar = loader.item.titleBarContent
|
root.editorOpened(root, loader.item)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HelperWidgets.LineEdit {
|
StudioControls.TextField {
|
||||||
id: hexTextField
|
id: hexTextField
|
||||||
implicitWidth: StudioTheme.Values.twoControlColumnWidth
|
style: root.style
|
||||||
+ StudioTheme.Values.actionIndicatorWidth
|
x: root.padding + actionIndicator.width + preview.width - preview.border.width
|
||||||
width: hexTextField.implicitWidth
|
y: root.padding
|
||||||
enabled: popupDialog.isSolid()
|
width: root.width - hexTextField.x - 2 * root.padding
|
||||||
writeValueManually: true
|
height: root.innerItemsHeight
|
||||||
|
text: root.color
|
||||||
|
actionIndicatorVisible: false
|
||||||
|
translationIndicatorVisible: false
|
||||||
|
indicatorVisible: true
|
||||||
|
indicator.icon.text: StudioTheme.Constants.copy_small
|
||||||
|
indicator.onClicked: {
|
||||||
|
hexTextField.selectAll()
|
||||||
|
hexTextField.copy()
|
||||||
|
hexTextField.deselect()
|
||||||
|
}
|
||||||
|
|
||||||
validator: RegularExpressionValidator {
|
validator: RegularExpressionValidator {
|
||||||
regularExpression: /#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?/g
|
regularExpression: /#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?/g
|
||||||
}
|
}
|
||||||
showTranslateCheckBox: false
|
|
||||||
showExtendedFunctionButton: false
|
|
||||||
indicatorVisible: false
|
|
||||||
|
|
||||||
onAccepted: colorEditor.color = hexTextField.text
|
onAccepted: colorBackend.activateColor(colorFromString(hexTextField.text))
|
||||||
onCommitData: {
|
|
||||||
colorEditor.color = hexTextField.text
|
|
||||||
if (popupDialog.isSolid())
|
|
||||||
colorEditor.writeColor()
|
|
||||||
}
|
|
||||||
|
|
||||||
function syncColor() {
|
|
||||||
hexTextField.text = colorEditor.color
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: popupDialog.determineActiveColorMode()
|
|
||||||
|
|
||||||
onBackendValueChanged: popupDialog.determineActiveColorMode()
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user