QmlDesigner: Fix ExpressionTextField popup

Fix the ListView/Popup which is shown on the ExpressionTextField when
requesting auto completion.

* Fix key behavior of the auto completion list
* Adapt to the look and feel of the property editor
* Fix size and position of the TextField and the overlayed Label

Task-number: QDS-2561
Change-Id: Ie8df6a2960b1c273600543532f0a136eb0c542b5
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Henning Gruendl
2020-07-16 13:01:41 +02:00
committed by Henning Gründl
parent d1aabbe262
commit 9f2bb4abaf
3 changed files with 197 additions and 83 deletions

View File

@@ -66,15 +66,12 @@ Rectangle {
RoundedPanel {
Layout.fillWidth: true
height: 24
height: StudioTheme.Values.height
Label {
x: 6
anchors.fill: parent
anchors.leftMargin: 16
anchors.leftMargin: StudioTheme.Values.inputHorizontalPadding
text: backendValues.className.value
verticalAlignment: Text.AlignVCenter
}
ToolTipArea {
anchors.fill: parent
@@ -88,10 +85,10 @@ Rectangle {
}
ExpressionTextField {
z: 2
id: typeLineEdit
z: 2
completeOnlyTypes: true
replaceCurrentTextByCompletion: true
anchors.fill: parent
visible: false
@@ -107,11 +104,18 @@ Rectangle {
typeLineEdit.blockEditingFinished = true
if (visible)
if (typeLineEdit.visible)
changeTypeName(typeLineEdit.text.trim())
visible = false
typeLineEdit.visible = false
typeLineEdit.blockEditingFinished = false
typeLineEdit.completionList.model = null
}
onRejected: {
typeLineEdit.visible = false
typeLineEdit.completionList.model = null
}
}

View File

@@ -63,15 +63,12 @@ Rectangle {
RoundedPanel {
Layout.fillWidth: true
height: 24
height: StudioTheme.Values.height
Label {
x: 6
anchors.fill: parent
anchors.leftMargin: 16
anchors.leftMargin: StudioTheme.Values.inputHorizontalPadding
text: backendValues.className.value
verticalAlignment: Text.AlignVCenter
}
ToolTipArea {
anchors.fill: parent
@@ -88,7 +85,7 @@ Rectangle {
z: 2
id: typeLineEdit
completeOnlyTypes: true
replaceCurrentTextByCompletion: true
anchors.fill: parent
visible: false
@@ -96,10 +93,26 @@ Rectangle {
showButtons: false
fixedSize: true
property bool blockEditingFinished: false
onEditingFinished: {
if (visible)
if (typeLineEdit.blockEditingFinished)
return
typeLineEdit.blockEditingFinished = true
if (typeLineEdit.visible)
changeTypeName(typeLineEdit.text.trim())
visible = false
typeLineEdit.visible = false
typeLineEdit.blockEditingFinished = false
typeLineEdit.completionList.model = null
}
onRejected: {
typeLineEdit.visible = false
typeLineEdit.completionList.model = null
}
}

View File

@@ -23,13 +23,14 @@
**
****************************************************************************/
import QtQuick 2.1
import "Constants.js" as Constants
import StudioControls 1.0 as StudioControls
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuickDesignerTheme 1.0
import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
StudioControls.TextField {
id: textField
signal rejected
@@ -38,103 +39,199 @@ StudioControls.TextField {
actionIndicator.visible: false
property bool completeOnlyTypes: false
property bool completionActive: listView.count > 0
property bool completionActive: listView.model !== null
property bool dotCompletion: false
property int dotCursorPos: 0
property string prefix
property alias showButtons: buttonrow.visible
property bool fixedSize: false
property bool replaceCurrentTextByCompletion: false
property alias completionList: listView
function commitCompletion() {
if (replaceCurrentTextByCompletion) {
textField.text = listView.currentItem.text
} else {
var cursorPos = textField.cursorPosition
var string = textField.text
var before = string.slice(0, cursorPos - textField.prefix.length)
var after = string.slice(cursorPos)
textField.text = before + listView.currentItem.text + after
textField.cursorPosition = cursorPos + listView.currentItem.text.length - prefix.length
}
listView.model = null
}
ListView {
id: listView
Popup {
id: textFieldPopup
x: textField.x
y: textField.height - StudioTheme.Values.border
width: textField.width
// TODO Setting the height on the popup solved the problem with the popup of height 0,
// but it has the problem that it sometimes extend over the border of the actual window
// and is then cut off.
height: Math.min(contentItem.implicitHeight + textFieldPopup.topPadding + textFieldPopup.bottomPadding,
textField.Window.height - topMargin - bottomMargin,
StudioTheme.Values.maxComboBoxPopupHeight)
padding: StudioTheme.Values.border
margins: 0 // If not defined margin will be -1
closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnPressOutsideParent
| Popup.CloseOnEscape | Popup.CloseOnReleaseOutside
| Popup.CloseOnReleaseOutsideParent
clip: true
cacheBuffer: 0
snapMode: ListView.SnapToItem
boundsBehavior: Flickable.StopAtBounds
visible: textField.completionActive
delegate: Text {
onClosed: listView.model = null
contentItem: ListView {
id: listView
clip: true
implicitHeight: contentHeight
boundsBehavior: Flickable.StopAtBounds
ScrollBar.vertical: StudioControls.ScrollBar {
id: popupScrollBar
}
model: null
delegate: ItemDelegate {
id: myItemDelegate
width: textFieldPopup.width - textFieldPopup.leftPadding - textFieldPopup.rightPadding
- (popupScrollBar.visible ? popupScrollBar.contentItem.implicitWidth
+ 2 : 0) // TODO Magic number
height: StudioTheme.Values.height - 2 * StudioTheme.Values.border
padding: 0
text: itemDelegateText.text
contentItem: Text {
id: itemDelegateText
leftPadding: 8
text: modelData
color: Theme.color(Theme.PanelTextColorLight)
Rectangle {
visible: index === listView.currentIndex
z: -1
anchors.fill: parent
color: Theme.qmlDesignerBackgroundColorDarkAlternate()
color: StudioTheme.Values.themeTextColor
font: textField.font
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
background: Rectangle {
color: "transparent"
}
hoverEnabled: true
onHoveredChanged: {
if (hovered)
listView.currentIndex = index
}
onClicked: {
listView.currentIndex = index
if (textField.completionActive)
textField.commitCompletion()
}
}
anchors.top: parent.top
anchors.topMargin: 26
anchors.bottomMargin: textField.fixedSize ? -180 : 12
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 200
spacing: 2
children: [
Rectangle {
visible: textField.fixedSize
anchors.fill: parent
color: Theme.qmlDesignerBackgroundColorDarker()
border.color: Theme.qmlDesignerBorderColor()
anchors.rightMargin: 12
z: -1
highlight: Rectangle {
id: listViewHighlight
width: textFieldPopup.width - textFieldPopup.leftPadding - textFieldPopup.rightPadding
- (popupScrollBar.visible ? popupScrollBar.contentItem.implicitWidth
+ 2 : 0)
height: StudioTheme.Values.height - 2 * StudioTheme.Values.border
color: StudioTheme.Values.themeInteraction
y: listView.currentItem.y
}
highlightFollowsCurrentItem: false
}
]
background: Rectangle {
color: StudioTheme.Values.themeControlBackground
border.color: StudioTheme.Values.themeInteraction
border.width: StudioTheme.Values.border
}
enter: Transition {
}
exit: Transition {
}
}
verticalAlignment: Text.AlignTop
onPressed: listView.model = null
Keys.priority: Keys.BeforeItem
Keys.onPressed: {
var text = textField.text
var pos = textField.cursorPosition
var explicitComplete = true
if (event.key === Qt.Key_Period) {
switch (event.key) {
case Qt.Key_Period:
textField.dotCursorPos = textField.cursorPosition + 1
var list = autoComplete(textField.text+".", textField.dotCursorPos, false, textField.completeOnlyTypes)
textField.prefix = list.pop()
listView.model = list;
text = textField.text + "."
pos = textField.dotCursorPos
explicitComplete = false
textField.dotCompletion = true
} else {
if (textField.completionActive) {
var list2 = autoComplete(textField.text + event.text,
textField.cursorPosition + event.text.length,
true, textField.completeOnlyTypes)
textField.prefix = list2.pop()
listView.model = list2;
}
break
case Qt.Key_Right:
if (!textField.completionActive)
return
pos = Math.min(textField.cursorPosition + 1, textField.text.length)
break
case Qt.Key_Left:
if (!textField.completionActive)
return
pos = Math.max(0, textField.cursorPosition - 1)
break
case Qt.Key_Backspace:
if (!textField.completionActive)
return
pos = textField.cursorPosition - 1
if (pos < 0)
return
text = textField.text.substring(0, pos) + textField.text.substring(textField.cursorPosition)
break
case Qt.Key_Delete:
return
default:
if (!textField.completionActive)
return
var tmp = textField.text
text = tmp.substring(0, textField.cursorPosition) + event.text + tmp.substring(textField.cursorPosition)
pos = textField.cursorPosition + event.text.length
}
var list = autoComplete(text.trim(), pos, explicitComplete, textField.completeOnlyTypes)
textField.prefix = text.substring(0, pos)
if (list.length && list[list.length - 1] === textField.prefix)
list.pop()
listView.model = list
}
Keys.onSpacePressed: {
if (event.modifiers & Qt.ControlModifier) {
var list = autoComplete(textField.text, textField.cursorPosition, true, textField.completeOnlyTypes)
textField.prefix = list.pop()
listView.model = list;
textField.prefix = textField.text.substring(0, textField.cursorPosition)
if (list.length && list[list.length - 1] === textField.prefix)
list.pop()
listView.model = list
textField.dotCompletion = false
event.accepted = true;
if (list.length === 1)
textField.commitCompletion()
} else {
event.accepted = false
}