[ui] AttributeEditor: Generic TextField param editor improvements

* Use disabled text color when attribute is readonly.
* Improved UX: text cursor on mouse hovering.
* Simplify context menu handling.
This commit is contained in:
Yann Lanthony 2025-02-26 15:24:21 +01:00
parent f901f814f7
commit 634197583c

View file

@ -266,10 +266,28 @@ RowLayout {
id: textField id: textField
readOnly: !root.editable readOnly: !root.editable
text: attribute.value text: attribute.value
// Don't disable the component to keep interactive features (text selection, context menu...).
// Only override the look by using the Disabled palette.
SystemPalette {
id: disabledPalette
colorGroup: SystemPalette.Disabled
}
states: [
State {
when: readOnly
PropertyChanges {
target: textField
color: disabledPalette.text
}
}
]
selectByMouse: true selectByMouse: true
onEditingFinished: setTextFieldAttribute(text) onEditingFinished: setTextFieldAttribute(text)
persistentSelection: false persistentSelection: false
property bool memoryActiveFocus: false
onAccepted: { onAccepted: {
setTextFieldAttribute(text) setTextFieldAttribute(text)
parameterLabel.forceActiveFocus() parameterLabel.forceActiveFocus()
@ -294,56 +312,62 @@ RowLayout {
setTextFieldAttribute(drop.text) setTextFieldAttribute(drop.text)
} }
} }
MouseArea { onPressed: (event) => {
anchors.fill: parent if(event.button == Qt.RightButton) {
acceptedButtons: Qt.RightButton // Keep selection persistent while context menu is open to
onClicked: function(mouse) { // visualize what is being copied or what will be replaced on paste.
// Do not lose the selection during the right click persistentSelection = true;
textField.persistentSelection = true const menu = textFieldMenuComponent.createObject(textField);
// We store the status of the activeFocus before opening the popup menu.popup();
textField.memoryActiveFocus = textField.activeFocus
var menu = menuCopy.createObject(textField) if(selectedText === "") {
menu.parent = textField cursorPosition = positionAt(event.x, event.y);
menu.popup() }
if(textField.memoryActiveFocus) {
// If the focus was active, we continue to display the cursor
// to explain that we will insert the new text in this position (in case of "Paste" action)
textField.cursorVisible = true
} }
// We do not want the selection to be globally persistent
textField.persistentSelection = false
} }
property Component menuCopy : Menu { Component {
id: textFieldMenuComponent
Menu {
onOpened: {
// Keep cursor visible to see where pasting would happen.
textField.cursorVisible = true;
}
onClosed: {
// Disable selection persistency behavior once menu is closed and
// give focus back to the parent TextField.
textField.persistentSelection = false;
textField.forceActiveFocus();
destroy();
}
MenuItem { MenuItem {
text: "Copy" text: "Copy"
enabled: attribute.value != "" enabled: attribute.value != ""
onTriggered: { onTriggered: {
if (textField.selectionStart === textField.selectionEnd) { const hasSelection = textField.selectionStart !== textField.selectionEnd;
// If no selection if(hasSelection) {
Clipboard.clear() // Use `TextField.copy` to copy only the current selection.
Clipboard.setText(attribute.value) textField.copy();
} else { }
// Copy selection only else {
textField.copy() Clipboard.setText(attribute.value);
} }
} }
} }
MenuItem { MenuItem {
text: "Paste" text: "Paste"
enabled: Clipboard.getText() != "" && !readOnly enabled: !readOnly
onTriggered: { onTriggered: {
if (textField.memoryActiveFocus) { const clipboardText = Clipboard.getText();
// Replace the selected text with the clipboard if (clipboardText.length === 0) {
// or if there is no selection insert at the cursor position return;
var before = textField.text.substr(0, textField.selectionStart)
var after = textField.text.substr(textField.selectionEnd, textField.text.length)
setTextFieldAttribute(before + Clipboard.getText() + after)
// Set the cursor at the end of the added text
textField.cursorPosition = before.length + Clipboard.getText().length
} else {
setTextFieldAttribute(Clipboard.getText())
} }
const before = textField.text.substr(0, textField.selectionStart);
const after = textField.text.substr(textField.selectionEnd, textField.text.length);
const updatedValue = before + clipboardText + after;
setTextFieldAttribute(updatedValue);
// Set the cursor at the end of the added text
textField.cursorPosition = before.length + clipboardText.length;
} }
} }
} }