diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/ObjectLists/Editor/CustomPropertyList.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/ObjectLists/Editor/CustomPropertyList.qml index 42499a9..aa26594 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/ObjectLists/Editor/CustomPropertyList.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/ObjectLists/Editor/CustomPropertyList.qml @@ -74,6 +74,7 @@ Repeater { icon: `settings/custom/${propertyIcon}.svg` defValue: Utils.simplifyExpression(obj[propertyName].toEditableString()) self: obj.name + variables: propertyType.variables onChanged: function(newExpr) { if(obj[propertyName].toString() != newExpr.toString()) { history.addToHistory(new HistoryLib.EditedProperty( @@ -267,7 +268,7 @@ Repeater { return commentComponent else if(propertyType == 'boolean') return checkboxComponent - else if(propertyType == 'Expression') + else if(paramTypeIn(propertyType, ['Expression'])) return expressionEditorComponent else if(paramTypeIn(propertyType, textTypes)) return textEditorComponent diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/AutocompletionCategory.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/AutocompletionCategory.qml index 77805fb..b0d2df9 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/AutocompletionCategory.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/AutocompletionCategory.qml @@ -33,6 +33,11 @@ ListView { Start index of the first element in this list compared to the global autocompletion index. */ property int itemStartIndex: 0 + /*! + \qmlproperty int AutocompletionCategory::itemSelected + The global autocompletion index. + */ + property int itemSelected: 0 /*! \qmlproperty string AutocompletionCategory::category @@ -49,9 +54,9 @@ ListView { /*! \qmlproperty var AutocompletionCategory::autocompleteGenerator Javascript function taking the name of the item to create an autocompletion item (dictionary with - a 'text', 'autocomplete', and 'cursorFinalOffset' keys. + a 'text', 'annotation' 'autocomplete', and 'cursorFinalOffset' keys. */ - property var autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item, 'cursorFinalOffset': 0}} + property var autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item, 'annotation': '', 'cursorFinalOffset': 0}} /*! \qmlproperty string AutocompletionCategory::baseText @@ -60,7 +65,7 @@ ListView { property string baseText: "" width: parent.width visible: model.length > 0 - implicitHeight: contentItem.childrenRect.height + headerItem.height + implicitHeight: contentItem.childrenRect.height model: parent.visible ? categoryItems.filter((item) => item.includes(baseText)).map(autocompleteGenerator) : [] header: Column { @@ -82,10 +87,10 @@ ListView { } delegate: Rectangle { - property bool selected: index + listFiltered.itemStartIndex == acPopupContent.itemSelected + property bool selected: index + listFiltered.itemStartIndex == listFiltered.itemSelected - width: autocompleteText.width - height: autocompleteText.height + width: listFiltered.width + height: Math.max(autocompleteText.height, annotationText.height) color: selected ? sysPalette.highlight : 'transparent' Text { @@ -94,8 +99,17 @@ ListView { bottomPadding: 2 leftPadding: 15 text: listFiltered.model[index].text - width: listFiltered.width color: parent.selected ? sysPalette.highlightedText : sysPalette.windowText } + + Text { + id: annotationText + anchors.right: parent.right + topPadding: 2 + bottomPadding: 2 + rightPadding: 15 + text: listFiltered.model[index].annotation + color: parent.selected ? sysPaletteIn.highlightedText : sysPaletteIn.windowText + } } } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/ExpressionEditor.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/ExpressionEditor.qml index 2450a1d..c7b86c1 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/ExpressionEditor.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Setting/ExpressionEditor.qml @@ -61,6 +61,11 @@ Item { Used to prevent circular dependency. */ property string self: "" + /*! + \qmlproperty var ExpressionEditor::variables + Accepted variables for the expression. + */ + property var variables: [] /*! \qmlproperty string ExpressionEditor::placeholderText Value of the editor. @@ -250,8 +255,8 @@ Item { visible: currentToken != null && identifierTokenTypes.includes(currentToken.type) // Focus handling. - readonly property var lists: [constantsList, functionsList, executableObjectList] - readonly property int itemCount: constantsList.model.length + functionsList.model.length + executableObjectList.model.length + readonly property var lists: [variablesList, constantsList, functionsList, executableObjectsList, objectsList] + readonly property int itemCount: variablesList.model.length, constantsList.model.length + functionsList.model.length + executableObjectsList.model.length + objectsList.model.length property int itemSelected: 0 /*! @@ -276,40 +281,79 @@ Item { function autocomplete() { let autotext = autocompleteAt(itemSelected) let startPos = currentToken.startPosition - console.log("Autocompleting",autotext.text,startPos) editor.remove(startPos, startPos+currentToken.value.length) editor.insert(startPos, autotext.autocomplete) editor.cursorPosition = startPos+autotext.autocomplete.length+autotext.cursorFinalOffset } + AutocompletionCategory { + id: variablesList + + category: qsTr("Variables") + itemStartIndex: 0 + itemSelected: parent.itemSelected + categoryItems: control.variables + autocompleteGenerator: (item) => {return { + 'text': item, 'annotation': '', + 'autocomplete': item + " ", 'cursorFinalOffset': 0 + }} + baseText: parent.visible ? parent.currentToken.value : "" + } + AutocompletionCategory { id: constantsList - itemStartIndex: 0 category: qsTr("Constants") + itemStartIndex: variablesList.model.length + itemSelected: parent.itemSelected categoryItems: Parsing.CONSTANTS_LIST - autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item + " ", 'cursorFinalOffset': 0}} - baseText: parent.currentToken.value + autocompleteGenerator: (item) => {return { + 'text': item, 'annotation': '', + 'autocomplete': item + " ", 'cursorFinalOffset': 0 + }} + baseText: parent.visible ? parent.currentToken.value : "" } AutocompletionCategory { id: functionsList - itemStartIndex: constantsList.model.length category: qsTr("Functions") + itemStartIndex: variablesList.model.length + constantsList.model.length + itemSelected: parent.itemSelected categoryItems: Parsing.FUNCTIONS_LIST - autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item+'()', 'cursorFinalOffset': -1}} - baseText: parent.currentToken.value + autocompleteGenerator: (item) => {return { + 'text': item, 'annotation': '', + 'autocomplete': item+'()', 'cursorFinalOffset': -1 + }} + baseText: parent.visible ? parent.currentToken.value : "" } AutocompletionCategory { - id: executableObjectList + id: executableObjectsList - itemStartIndex: constantsList.model.length + functionsList.model.length category: qsTr("Executable Objects") - categoryItems: Objects.getObjectsName("ExecutableObject") - autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item+'()', 'cursorFinalOffset': -1}} - baseText: parent.currentToken.value + itemStartIndex: variablesList.model.length + constantsList.model.length + functionsList.model.length + itemSelected: parent.itemSelected + categoryItems: Objects.getObjectsName("ExecutableObject").filter(obj => obj != self) + autocompleteGenerator: (item) => {return { + 'text': item, 'annotation': `${Objects.currentObjectsByName[item].constructor.displayType()}`, + 'autocomplete': item+'()', 'cursorFinalOffset': -1 + }} + baseText: parent.visible ? parent.currentToken.value : "" + } + + AutocompletionCategory { + id: objectsList + + category: qsTr("Objects") + itemStartIndex: executableObjectsList.model.length + variablesList.model.length + constantsList.model.length + functionsList.model.length + itemSelected: parent.itemSelected + categoryItems: Object.keys(Objects.currentObjectsByName).filter(obj => obj != self) + autocompleteGenerator: (item) => {return { + 'text': item, 'annotation': `${Objects.currentObjectsByName[item].constructor.displayType()}`, + 'autocomplete': item+'.', 'cursorFinalOffset': 0 + }} + baseText: parent.visible ? parent.currentToken.value : "" } } } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/history/position.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/history/position.js index d33ad71..1a2ba46 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/history/position.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/history/position.js @@ -75,7 +75,7 @@ class EditedPosition extends C.Action { } export() { - return [this.targetName, this.targetType, this.targetProperty, + return [this.targetName, this.targetType, this.previousXValue.toEditableString(), this.newXValue.toEditableString(), this.previousYValue.toEditableString(), this.newYValue.toEditableString()] } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/common.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/common.js index 6c15ce5..907bf63 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/common.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/common.js @@ -30,9 +30,10 @@ * Creates a new name for an object, based on the \c allowedLetters. * If variables with each of the allowedLetters is created, a subscript * number is added to the name. + * @param {string} prefix - Prefix to the name. * @return {string} New unused name for a new object. */ -function getNewName(allowedLetters) { +function getNewName(allowedLetters, prefix='') { // Allows to get a new name, based on the allowed letters, // as well as adding a sub number when needs be. var newid = 0 @@ -40,7 +41,7 @@ function getNewName(allowedLetters) { do { var letter = allowedLetters[newid % allowedLetters.length] var num = Math.floor((newid - (newid % allowedLetters.length)) / allowedLetters.length) - ret = letter + (num > 0 ? Utils.textsub(num-1) : '') + ret = prefix + letter + (num > 0 ? Utils.textsub(num-1) : '') newid += 1 } while(ret in Objects.currentObjectsByName) return ret @@ -80,10 +81,10 @@ class DrawableObject { * List of properties used in the Object Editor. * * Properties are set with key as property name and - * value as it's type name (e.g 'Expression', 'string'...), + * value as it's type name (e.g 'numbers', 'string'...), * an Enum for enumerations, an ObjectType for DrawableObjects * with a specific type, a List instance for lists, a - * Dictionary instance for dictionaries... + * Dictionary instance for dictionaries, an Expression for expressions... * * If the property is to be translated, the key should be passed * through the QT_TRANSLATE_NOOP macro in that form: diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/function.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/function.js index 746d880..85a798f 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/function.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/function.js @@ -30,7 +30,7 @@ class Function extends Common.ExecutableObject { static displayType(){return qsTr('Function')} static displayTypeMultiple(){return qsTr('Functions')} static properties() {return { - [QT_TRANSLATE_NOOP('prop','expression')]: 'Expression', + [QT_TRANSLATE_NOOP('prop','expression')]: new P.Expression('x'), [QT_TRANSLATE_NOOP('prop','definitionDomain')]: 'Domain', [QT_TRANSLATE_NOOP('prop','destinationDomain')]: 'Domain', 'comment1': QT_TRANSLATE_NOOP( diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/gainbode.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/gainbode.js index 72d583f..0130a9e 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/gainbode.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/gainbode.js @@ -35,7 +35,7 @@ class GainBode extends Common.ExecutableObject { static properties() {return { [QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'), [QT_TRANSLATE_NOOP('prop','pass')]: P.Enum.BodePass, - [QT_TRANSLATE_NOOP('prop','gain')]: 'Expression', + [QT_TRANSLATE_NOOP('prop','gain')]: new P.Expression(), [QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position, [QT_TRANSLATE_NOOP('prop','labelX')]: 'number', [QT_TRANSLATE_NOOP('prop','omGraduation')]: 'boolean' diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/phasebode.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/phasebode.js index f8d2aaf..528910b 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/phasebode.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/phasebode.js @@ -32,7 +32,7 @@ class PhaseBode extends Common.ExecutableObject { static displayTypeMultiple(){return qsTr('Bode Phases')} static properties() {return { [QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'), - [QT_TRANSLATE_NOOP('prop','phase')]: 'Expression', + [QT_TRANSLATE_NOOP('prop','phase')]: new P.Expression(), [QT_TRANSLATE_NOOP('prop','unit')]: new P.Enum('°', 'deg', 'rad'), [QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position, [QT_TRANSLATE_NOOP('prop','labelX')]: 'number' diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/point.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/point.js index 1f35192..760ab68 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/point.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/point.js @@ -30,8 +30,8 @@ class Point extends Common.DrawableObject { static displayTypeMultiple(){return qsTr('Points')} static properties() {return { - [QT_TRANSLATE_NOOP('prop','x')]: 'Expression', - [QT_TRANSLATE_NOOP('prop','y')]: 'Expression', + [QT_TRANSLATE_NOOP('prop','x')]: new P.Expression(), + [QT_TRANSLATE_NOOP('prop','y')]: new P.Expression(), [QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position, [QT_TRANSLATE_NOOP('prop','pointStyle')]: new P.Enum('●', '✕', '+') }} diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sommegainsbode.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sommegainsbode.js index 8f5854c..70e7440 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sommegainsbode.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/sommegainsbode.js @@ -26,7 +26,7 @@ .import "../math/latex.js" as Latex -class SommeGainsBode extends Common.DrawableObject { +class SommeGainsBode extends Common.ExecutableObject { static type(){return 'Somme gains Bode'} static displayType(){return qsTr('Bode Magnitudes Sum')} static displayTypeMultiple(){return qsTr('Bode Magnitudes Sum')} diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/text.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/text.js index 5d98e4e..99e9936 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/text.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/objs/text.js @@ -30,8 +30,8 @@ class Text extends Common.DrawableObject { static displayType(){return qsTr('Text')} static displayTypeMultiple(){return qsTr('Texts')} static properties() {return { - [QT_TRANSLATE_NOOP('prop','x')]: 'Expression', - [QT_TRANSLATE_NOOP('prop','y')]: 'Expression', + [QT_TRANSLATE_NOOP('prop','x')]: new P.Expression(), + [QT_TRANSLATE_NOOP('prop','y')]: new P.Expression(), [QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Positioning, [QT_TRANSLATE_NOOP('prop','text')]: 'string', 'comment1': QT_TRANSLATE_NOOP( diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/parameters.js b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/parameters.js index 75309a8..1733a90 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/parameters.js +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/parameters.js @@ -16,6 +16,13 @@ * along with this program. If not, see . */ +class Expression { + constructor(...variables) { + this.type = 'Expression' + this.variables = variables + } +} + class Enum { constructor(...values) { this.type = 'Enum'