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`
|
icon: `settings/custom/${propertyIcon}.svg`
|
||||||
defValue: Utils.simplifyExpression(obj[propertyName].toEditableString())
|
defValue: Utils.simplifyExpression(obj[propertyName].toEditableString())
|
||||||
self: obj.name
|
self: obj.name
|
||||||
|
variables: propertyType.variables
|
||||||
onChanged: function(newExpr) {
|
onChanged: function(newExpr) {
|
||||||
if(obj[propertyName].toString() != newExpr.toString()) {
|
if(obj[propertyName].toString() != newExpr.toString()) {
|
||||||
history.addToHistory(new HistoryLib.EditedProperty(
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
|
@ -267,7 +268,7 @@ Repeater {
|
||||||
return commentComponent
|
return commentComponent
|
||||||
else if(propertyType == 'boolean')
|
else if(propertyType == 'boolean')
|
||||||
return checkboxComponent
|
return checkboxComponent
|
||||||
else if(propertyType == 'Expression')
|
else if(paramTypeIn(propertyType, ['Expression']))
|
||||||
return expressionEditorComponent
|
return expressionEditorComponent
|
||||||
else if(paramTypeIn(propertyType, textTypes))
|
else if(paramTypeIn(propertyType, textTypes))
|
||||||
return textEditorComponent
|
return textEditorComponent
|
||||||
|
|
|
@ -33,6 +33,11 @@ ListView {
|
||||||
Start index of the first element in this list compared to the global autocompletion index.
|
Start index of the first element in this list compared to the global autocompletion index.
|
||||||
*/
|
*/
|
||||||
property int itemStartIndex: 0
|
property int itemStartIndex: 0
|
||||||
|
/*!
|
||||||
|
\qmlproperty int AutocompletionCategory::itemSelected
|
||||||
|
The global autocompletion index.
|
||||||
|
*/
|
||||||
|
property int itemSelected: 0
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty string AutocompletionCategory::category
|
\qmlproperty string AutocompletionCategory::category
|
||||||
|
@ -49,9 +54,9 @@ ListView {
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty var AutocompletionCategory::autocompleteGenerator
|
\qmlproperty var AutocompletionCategory::autocompleteGenerator
|
||||||
Javascript function taking the name of the item to create an autocompletion item (dictionary with
|
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
|
\qmlproperty string AutocompletionCategory::baseText
|
||||||
|
@ -60,7 +65,7 @@ ListView {
|
||||||
property string baseText: ""
|
property string baseText: ""
|
||||||
width: parent.width
|
width: parent.width
|
||||||
visible: model.length > 0
|
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) : []
|
model: parent.visible ? categoryItems.filter((item) => item.includes(baseText)).map(autocompleteGenerator) : []
|
||||||
|
|
||||||
header: Column {
|
header: Column {
|
||||||
|
@ -82,10 +87,10 @@ ListView {
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
property bool selected: index + listFiltered.itemStartIndex == acPopupContent.itemSelected
|
property bool selected: index + listFiltered.itemStartIndex == listFiltered.itemSelected
|
||||||
|
|
||||||
width: autocompleteText.width
|
width: listFiltered.width
|
||||||
height: autocompleteText.height
|
height: Math.max(autocompleteText.height, annotationText.height)
|
||||||
color: selected ? sysPalette.highlight : 'transparent'
|
color: selected ? sysPalette.highlight : 'transparent'
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
@ -94,8 +99,17 @@ ListView {
|
||||||
bottomPadding: 2
|
bottomPadding: 2
|
||||||
leftPadding: 15
|
leftPadding: 15
|
||||||
text: listFiltered.model[index].text
|
text: listFiltered.model[index].text
|
||||||
width: listFiltered.width
|
|
||||||
color: parent.selected ? sysPalette.highlightedText : sysPalette.windowText
|
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.
|
Used to prevent circular dependency.
|
||||||
*/
|
*/
|
||||||
property string self: ""
|
property string self: ""
|
||||||
|
/*!
|
||||||
|
\qmlproperty var ExpressionEditor::variables
|
||||||
|
Accepted variables for the expression.
|
||||||
|
*/
|
||||||
|
property var variables: []
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty string ExpressionEditor::placeholderText
|
\qmlproperty string ExpressionEditor::placeholderText
|
||||||
Value of the editor.
|
Value of the editor.
|
||||||
|
@ -250,8 +255,8 @@ Item {
|
||||||
visible: currentToken != null && identifierTokenTypes.includes(currentToken.type)
|
visible: currentToken != null && identifierTokenTypes.includes(currentToken.type)
|
||||||
|
|
||||||
// Focus handling.
|
// Focus handling.
|
||||||
readonly property var lists: [constantsList, functionsList, executableObjectList]
|
readonly property var lists: [variablesList, constantsList, functionsList, executableObjectsList, objectsList]
|
||||||
readonly property int itemCount: constantsList.model.length + functionsList.model.length + executableObjectList.model.length
|
readonly property int itemCount: variablesList.model.length, constantsList.model.length + functionsList.model.length + executableObjectsList.model.length + objectsList.model.length
|
||||||
property int itemSelected: 0
|
property int itemSelected: 0
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -276,40 +281,79 @@ Item {
|
||||||
function autocomplete() {
|
function autocomplete() {
|
||||||
let autotext = autocompleteAt(itemSelected)
|
let autotext = autocompleteAt(itemSelected)
|
||||||
let startPos = currentToken.startPosition
|
let startPos = currentToken.startPosition
|
||||||
console.log("Autocompleting",autotext.text,startPos)
|
|
||||||
editor.remove(startPos, startPos+currentToken.value.length)
|
editor.remove(startPos, startPos+currentToken.value.length)
|
||||||
editor.insert(startPos, autotext.autocomplete)
|
editor.insert(startPos, autotext.autocomplete)
|
||||||
editor.cursorPosition = startPos+autotext.autocomplete.length+autotext.cursorFinalOffset
|
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 {
|
AutocompletionCategory {
|
||||||
id: constantsList
|
id: constantsList
|
||||||
|
|
||||||
itemStartIndex: 0
|
|
||||||
category: qsTr("Constants")
|
category: qsTr("Constants")
|
||||||
|
itemStartIndex: variablesList.model.length
|
||||||
|
itemSelected: parent.itemSelected
|
||||||
categoryItems: Parsing.CONSTANTS_LIST
|
categoryItems: Parsing.CONSTANTS_LIST
|
||||||
autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item + " ", 'cursorFinalOffset': 0}}
|
autocompleteGenerator: (item) => {return {
|
||||||
baseText: parent.currentToken.value
|
'text': item, 'annotation': '',
|
||||||
|
'autocomplete': item + " ", 'cursorFinalOffset': 0
|
||||||
|
}}
|
||||||
|
baseText: parent.visible ? parent.currentToken.value : ""
|
||||||
}
|
}
|
||||||
|
|
||||||
AutocompletionCategory {
|
AutocompletionCategory {
|
||||||
id: functionsList
|
id: functionsList
|
||||||
|
|
||||||
itemStartIndex: constantsList.model.length
|
|
||||||
category: qsTr("Functions")
|
category: qsTr("Functions")
|
||||||
|
itemStartIndex: variablesList.model.length + constantsList.model.length
|
||||||
|
itemSelected: parent.itemSelected
|
||||||
categoryItems: Parsing.FUNCTIONS_LIST
|
categoryItems: Parsing.FUNCTIONS_LIST
|
||||||
autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item+'()', 'cursorFinalOffset': -1}}
|
autocompleteGenerator: (item) => {return {
|
||||||
baseText: parent.currentToken.value
|
'text': item, 'annotation': '',
|
||||||
|
'autocomplete': item+'()', 'cursorFinalOffset': -1
|
||||||
|
}}
|
||||||
|
baseText: parent.visible ? parent.currentToken.value : ""
|
||||||
}
|
}
|
||||||
|
|
||||||
AutocompletionCategory {
|
AutocompletionCategory {
|
||||||
id: executableObjectList
|
id: executableObjectsList
|
||||||
|
|
||||||
itemStartIndex: constantsList.model.length + functionsList.model.length
|
|
||||||
category: qsTr("Executable Objects")
|
category: qsTr("Executable Objects")
|
||||||
categoryItems: Objects.getObjectsName("ExecutableObject")
|
itemStartIndex: variablesList.model.length + constantsList.model.length + functionsList.model.length
|
||||||
autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item+'()', 'cursorFinalOffset': -1}}
|
itemSelected: parent.itemSelected
|
||||||
baseText: parent.currentToken.value
|
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() {
|
export() {
|
||||||
return [this.targetName, this.targetType, this.targetProperty,
|
return [this.targetName, this.targetType,
|
||||||
this.previousXValue.toEditableString(), this.newXValue.toEditableString(),
|
this.previousXValue.toEditableString(), this.newXValue.toEditableString(),
|
||||||
this.previousYValue.toEditableString(), this.newYValue.toEditableString()]
|
this.previousYValue.toEditableString(), this.newYValue.toEditableString()]
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,10 @@
|
||||||
* Creates a new name for an object, based on the \c allowedLetters.
|
* Creates a new name for an object, based on the \c allowedLetters.
|
||||||
* If variables with each of the allowedLetters is created, a subscript
|
* If variables with each of the allowedLetters is created, a subscript
|
||||||
* number is added to the name.
|
* number is added to the name.
|
||||||
|
* @param {string} prefix - Prefix to the name.
|
||||||
* @return {string} New unused name for a new object.
|
* @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,
|
// Allows to get a new name, based on the allowed letters,
|
||||||
// as well as adding a sub number when needs be.
|
// as well as adding a sub number when needs be.
|
||||||
var newid = 0
|
var newid = 0
|
||||||
|
@ -40,7 +41,7 @@ function getNewName(allowedLetters) {
|
||||||
do {
|
do {
|
||||||
var letter = allowedLetters[newid % allowedLetters.length]
|
var letter = allowedLetters[newid % allowedLetters.length]
|
||||||
var num = Math.floor((newid - (newid % allowedLetters.length)) / 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
|
newid += 1
|
||||||
} while(ret in Objects.currentObjectsByName)
|
} while(ret in Objects.currentObjectsByName)
|
||||||
return ret
|
return ret
|
||||||
|
@ -80,10 +81,10 @@ class DrawableObject {
|
||||||
* List of properties used in the Object Editor.
|
* List of properties used in the Object Editor.
|
||||||
*
|
*
|
||||||
* Properties are set with key as property name and
|
* 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
|
* an Enum for enumerations, an ObjectType for DrawableObjects
|
||||||
* with a specific type, a List instance for lists, a
|
* 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
|
* If the property is to be translated, the key should be passed
|
||||||
* through the QT_TRANSLATE_NOOP macro in that form:
|
* through the QT_TRANSLATE_NOOP macro in that form:
|
||||||
|
|
|
@ -30,7 +30,7 @@ class Function extends Common.ExecutableObject {
|
||||||
static displayType(){return qsTr('Function')}
|
static displayType(){return qsTr('Function')}
|
||||||
static displayTypeMultiple(){return qsTr('Functions')}
|
static displayTypeMultiple(){return qsTr('Functions')}
|
||||||
static properties() {return {
|
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','definitionDomain')]: 'Domain',
|
||||||
[QT_TRANSLATE_NOOP('prop','destinationDomain')]: 'Domain',
|
[QT_TRANSLATE_NOOP('prop','destinationDomain')]: 'Domain',
|
||||||
'comment1': QT_TRANSLATE_NOOP(
|
'comment1': QT_TRANSLATE_NOOP(
|
||||||
|
|
|
@ -35,7 +35,7 @@ class GainBode extends Common.ExecutableObject {
|
||||||
static properties() {return {
|
static properties() {return {
|
||||||
[QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'),
|
[QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'),
|
||||||
[QT_TRANSLATE_NOOP('prop','pass')]: P.Enum.BodePass,
|
[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','labelPosition')]: P.Enum.Position,
|
||||||
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
|
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
|
||||||
[QT_TRANSLATE_NOOP('prop','omGraduation')]: 'boolean'
|
[QT_TRANSLATE_NOOP('prop','omGraduation')]: 'boolean'
|
||||||
|
|
|
@ -32,7 +32,7 @@ class PhaseBode extends Common.ExecutableObject {
|
||||||
static displayTypeMultiple(){return qsTr('Bode Phases')}
|
static displayTypeMultiple(){return qsTr('Bode Phases')}
|
||||||
static properties() {return {
|
static properties() {return {
|
||||||
[QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'),
|
[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','unit')]: new P.Enum('°', 'deg', 'rad'),
|
||||||
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
|
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
|
||||||
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number'
|
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number'
|
||||||
|
|
|
@ -30,8 +30,8 @@ class Point extends Common.DrawableObject {
|
||||||
static displayTypeMultiple(){return qsTr('Points')}
|
static displayTypeMultiple(){return qsTr('Points')}
|
||||||
|
|
||||||
static properties() {return {
|
static properties() {return {
|
||||||
[QT_TRANSLATE_NOOP('prop','x')]: 'Expression',
|
[QT_TRANSLATE_NOOP('prop','x')]: new P.Expression(),
|
||||||
[QT_TRANSLATE_NOOP('prop','y')]: 'Expression',
|
[QT_TRANSLATE_NOOP('prop','y')]: new P.Expression(),
|
||||||
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
|
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
|
||||||
[QT_TRANSLATE_NOOP('prop','pointStyle')]: new P.Enum('●', '✕', '+')
|
[QT_TRANSLATE_NOOP('prop','pointStyle')]: new P.Enum('●', '✕', '+')
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
.import "../math/latex.js" as Latex
|
.import "../math/latex.js" as Latex
|
||||||
|
|
||||||
|
|
||||||
class SommeGainsBode extends Common.DrawableObject {
|
class SommeGainsBode extends Common.ExecutableObject {
|
||||||
static type(){return 'Somme gains Bode'}
|
static type(){return 'Somme gains Bode'}
|
||||||
static displayType(){return qsTr('Bode Magnitudes Sum')}
|
static displayType(){return qsTr('Bode Magnitudes Sum')}
|
||||||
static displayTypeMultiple(){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 displayType(){return qsTr('Text')}
|
||||||
static displayTypeMultiple(){return qsTr('Texts')}
|
static displayTypeMultiple(){return qsTr('Texts')}
|
||||||
static properties() {return {
|
static properties() {return {
|
||||||
[QT_TRANSLATE_NOOP('prop','x')]: 'Expression',
|
[QT_TRANSLATE_NOOP('prop','x')]: new P.Expression(),
|
||||||
[QT_TRANSLATE_NOOP('prop','y')]: 'Expression',
|
[QT_TRANSLATE_NOOP('prop','y')]: new P.Expression(),
|
||||||
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Positioning,
|
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Positioning,
|
||||||
[QT_TRANSLATE_NOOP('prop','text')]: 'string',
|
[QT_TRANSLATE_NOOP('prop','text')]: 'string',
|
||||||
'comment1': QT_TRANSLATE_NOOP(
|
'comment1': QT_TRANSLATE_NOOP(
|
||||||
|
|
|
@ -16,6 +16,13 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
class Expression {
|
||||||
|
constructor(...variables) {
|
||||||
|
this.type = 'Expression'
|
||||||
|
this.variables = variables
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Enum {
|
class Enum {
|
||||||
constructor(...values) {
|
constructor(...values) {
|
||||||
this.type = 'Enum'
|
this.type = 'Enum'
|
||||||
|
|
Loading…
Reference in a new issue