Variables & objects (+ their type) in autocompletion.
This commit is contained in:
parent
77ae54fa18
commit
15b87fc15d
12 changed files with 102 additions and 35 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 : ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()]
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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('●', '✕', '+')
|
||||
}}
|
||||
|
|
|
@ -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')}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -16,6 +16,13 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
class Expression {
|
||||
constructor(...variables) {
|
||||
this.type = 'Expression'
|
||||
this.variables = variables
|
||||
}
|
||||
}
|
||||
|
||||
class Enum {
|
||||
constructor(...values) {
|
||||
this.type = 'Enum'
|
||||
|
|
Loading…
Reference in a new issue