QmlDesigner: Add operators to expression builder

* Show operator fills when cursor is placed at position where operator
  is required
* Convert operators from real syntax to text version

Task-number: QDS-10630
Task-number: QDS-10638
Change-Id: Iffceb24024b7cde9a93c2acd0033fedd54e2ee32
Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Henning Gruendl
2023-09-12 11:14:58 +02:00
committed by Henning Gründl
parent c5d5a564c8
commit ed6f870a81
7 changed files with 108 additions and 16 deletions

View File

@@ -181,10 +181,12 @@ Column {
color: StudioTheme.Values.themeToolbarBackground color: StudioTheme.Values.themeToolbarBackground
Text { Text {
width: parent.width - 8 // twice the editor button margins
anchors.centerIn: parent anchors.centerIn: parent
text: backend.source text: backend.source
color: StudioTheme.Values.themeTextColor color: StudioTheme.Values.themeTextColor
font.pixelSize: StudioTheme.Values.myFontSize font.pixelSize: StudioTheme.Values.myFontSize
wrapMode: Text.WordWrap
} }
HelperWidgets.AbstractButton { HelperWidgets.AbstractButton {

View File

@@ -87,10 +87,68 @@ Rectangle {
newTextInput.index = index newTextInput.index = index
newTextInput.visible = true newTextInput.visible = true
newTextInput.forceActiveFocus() newTextInput.forceActiveFocus()
if (!root.shadowPillVisible)
popup.showOperators = root.conditionListModel.operatorAllowed(index)
// Open suggestion popup // Open suggestion popup
popup.open() popup.open()
} }
ListModel {
id: __operatorModel
function convertValueToName(value) {
for (var i = 0; i < __operatorModel.count; ++i) {
let element = __operatorModel.get(i)
if (element.value === value )
return element.name
}
return value
}
ListElement {
name: "AND"
value: "&&"
tooltip: QT_TR_NOOP("This is AND (&&)")
}
ListElement {
name: "OR"
value: "||"
tooltip: QT_TR_NOOP("This is OR (||)")
}
ListElement {
name: "EQUAL"
value: "==="
tooltip: QT_TR_NOOP("This is EQUAL (===)")
}
ListElement {
name: "NOT EQUAL"
value: "!=="
tooltip: QT_TR_NOOP("This is NOT EQUAL (!==)")
}
ListElement {
name: "GREATER"
value: ">"
tooltip: QT_TR_NOOP("This is GREATER (>)")
}
ListElement {
name: "LESS"
value: "<"
tooltip: QT_TR_NOOP("This is LESS (<)")
}
ListElement {
name: "GREATER OR EQUAL"
value: ">="
tooltip: QT_TR_NOOP("This is GREATER OR EQUAL (>=)")
}
ListElement {
name: "LESS OR EQUAL"
value: "<="
tooltip: QT_TR_NOOP("This is LESS OR EQUAL (<=)")
}
}
StudioControls.ToolTip { StudioControls.ToolTip {
id: toolTip id: toolTip
visible: mouseArea.containsMouse && toolTip.text !== "" visible: mouseArea.containsMouse && toolTip.text !== ""
@@ -197,6 +255,8 @@ Rectangle {
Pill { Pill {
id: pill id: pill
operatorModel: __operatorModel
onRemove: function() { onRemove: function() {
// If pill has focus due to selection or keyboard navigation // If pill has focus due to selection or keyboard navigation
if (pill.focus) if (pill.focus)
@@ -289,6 +349,8 @@ Rectangle {
y: root.height y: root.height
width: root.width width: root.width
operatorModel: __operatorModel
//onOpened: console.log("POPUP opened") //onOpened: console.log("POPUP opened")
//onClosed: console.log("POPUP closed") //onClosed: console.log("POPUP closed")

View File

@@ -31,6 +31,7 @@ FocusScope {
signal submit(int cursorPosition) signal submit(int cursorPosition)
readonly property int margin: StudioTheme.Values.flowPillMargin readonly property int margin: StudioTheme.Values.flowPillMargin
property var operatorModel
width: { width: {
if (root.isEditable()) { if (root.isEditable()) {
@@ -88,7 +89,7 @@ FocusScope {
return 0 return 0
} }
radius: 4 radius: StudioTheme.Values.flowPillRadius
Row { Row {
id: row id: row
@@ -102,7 +103,8 @@ FocusScope {
font.pixelSize: StudioTheme.Values.baseFontSize font.pixelSize: StudioTheme.Values.baseFontSize
color: root.isShadow() ? StudioTheme.Values.themeTextSelectedTextColor color: root.isShadow() ? StudioTheme.Values.themeTextSelectedTextColor
: StudioTheme.Values.themeTextColor : StudioTheme.Values.themeTextColor
text: root.value text: root.isOperator() ? root.operatorModel.convertValueToName(root.value)
: root.value
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }

View File

@@ -3,6 +3,7 @@
import QtQuick import QtQuick
import QtQuick.Controls as Controls import QtQuick.Controls as Controls
import HelperWidgets as HelperWidgets
import StudioTheme as StudioTheme import StudioTheme as StudioTheme
import StudioControls as StudioControls import StudioControls as StudioControls
import ConnectionsEditorEditorBackend import ConnectionsEditorEditorBackend
@@ -20,6 +21,8 @@ Controls.Popup {
signal exited(var value) signal exited(var value)
property alias searchActive: search.activeFocus property alias searchActive: search.activeFocus
property bool showOperators: false
property alias operatorModel: repeater.model
function reset() { function reset() {
search.clear() search.clear()
@@ -43,6 +46,7 @@ Controls.Popup {
StudioControls.SearchBox { StudioControls.SearchBox {
id: search id: search
width: parent.width width: parent.width
visible: !root.showOperators
onSearchChanged: function(value) { onSearchChanged: function(value) {
root.treeModel.setFilter(value) root.treeModel.setFilter(value)
@@ -51,12 +55,10 @@ Controls.Popup {
Controls.StackView { Controls.StackView {
id: stack id: stack
visible: !root.showOperators
width: parent.width width: parent.width
height: currentItem?.implicitHeight height: currentItem?.implicitHeight
clip: true clip: true
initialItem: mainView initialItem: mainView
} }
@@ -210,7 +212,7 @@ Controls.Popup {
} }
Item { Item {
visible: false visible: root.showOperators
width: stack.width width: stack.width
height: flow.childrenRect.height + 2 * StudioTheme.Values.flowMargin height: flow.childrenRect.height + 2 * StudioTheme.Values.flowMargin
@@ -224,30 +226,38 @@ Controls.Popup {
Repeater { Repeater {
id: repeater id: repeater
// TODO actual value + tooltip
model: ["AND", "OR", "equal", "not equal", "greater", "less", "greater then", "less then"]
Rectangle { Rectangle {
width: textItem.contentWidth + 14 id: delegate
height: 26
required property int index
required property string name
required property string value
required property string tooltip
width: textItem.contentWidth + 2 * StudioTheme.Values.flowPillMargin
height: StudioTheme.Values.flowPillHeight
color: "#161616" color: "#161616"
radius: 4 radius: StudioTheme.Values.flowPillRadius
border { border {
color: "white" color: "white"
width: mouseArea.containsMouse ? 1 : 0 width: mouseArea.containsMouse ? 1 : 0
} }
MouseArea { HelperWidgets.ToolTipArea {
id: mouseArea id: mouseArea
hoverEnabled: true hoverEnabled: true
anchors.fill: parent anchors.fill: parent
tooltip: delegate.tooltip
onClicked: root.select(delegate.value)
} }
Text { Text {
id: textItem id: textItem
font.pixelSize: 12 font.pixelSize: StudioTheme.Values.baseFontSize
color: "white" color: StudioTheme.Values.themeTextColor
text: modelData text: delegate.name
anchors.centerIn: parent anchors.centerIn: parent
} }
} }

View File

@@ -243,6 +243,7 @@ QtObject {
readonly property int flowSpacing: 7 // Odd so cursor has a center location readonly property int flowSpacing: 7 // Odd so cursor has a center location
readonly property int flowPillMargin: 4 readonly property int flowPillMargin: 4
readonly property int flowPillHeight: 20 readonly property int flowPillHeight: 20
readonly property int flowPillRadius: 4
// Theme Colors // Theme Colors

View File

@@ -1774,6 +1774,19 @@ int ConditionListModel::errorIndex() const
return m_errorIndex; return m_errorIndex;
} }
bool ConditionListModel::operatorAllowed(int cursorPosition)
{
if (m_tokens.empty())
return false;
int tokenIdx = cursorPosition - 1;
if (tokenIdx >= 0 && m_tokens[tokenIdx].type != Operator)
return true;
return false;
}
void ConditionListModel::internalSetup() void ConditionListModel::internalSetup()
{ {
setInvalid(tr("No Valid Condition")); setInvalid(tr("No Valid Condition"));

View File

@@ -146,6 +146,8 @@ public:
QString error() const; QString error() const;
int errorIndex() const; int errorIndex() const;
Q_INVOKABLE bool operatorAllowed(int cursorPosition);
signals: signals:
void validChanged(); void validChanged();
void emptyChanged(); void emptyChanged();