Paramerters and enums as class, now simpler implementation with more abstractions for parameters.

Also fixing a lot of bugs along the way.
This commit is contained in:
Ad5001 2020-12-26 14:49:48 +01:00
parent 5af98c67b0
commit 7e47b3cdf9
5 changed files with 125 additions and 87 deletions

View file

@ -97,7 +97,7 @@ Column {
verticalAlignment: TextInput.AlignVCenter
horizontalAlignment: TextInput.AlignHCenter
color: sysPalette.windowText
text: visible ? control.model.get(index).key : false
text: visible ? control.model.get(index).val : false
selectByMouse: true
onEditingFinished: {
var value = text
@ -112,7 +112,7 @@ Column {
value = ""
}
if(value != "" && keyInput.acceptableInput) {
control.model.setProperty(index, 'value', value)
control.model.setProperty(index, 'val', value)
control.changed()
}
}
@ -128,8 +128,8 @@ Column {
onClicked: {
control.model.append({
key: "",
value: ""
key: control.keyType == 'string' ? '' : model.count,
val: control.valueType == 'string' ? '' : 0
})
}
}
@ -138,8 +138,8 @@ Column {
model.clear()
for(var key in importer)
model.append({
key: key,
value: importer[key]
key: control.keyType == 'string' ? key.toString() : parseFloat(key),
val: control.valueType == 'string' ? importer[key].toString() : parseFloat(importer[key])
})
}
@ -147,12 +147,12 @@ Column {
if(dictionaryMode) {
var ret = {}
for(var i = 0; i < model.count; i++)
ret[model.get(i).key] = model.get(i).value
ret[model.get(i).key] = model.get(i).val
return ret
} else {
var ret = []
for(var i = 0; i < model.count; i++)
ret.push(model.get(i).value)
ret.push(model.get(i).val)
}
}
}

View file

@ -246,8 +246,8 @@ ListView {
currentIndex: model.indexOf(objEditor.obj.labelContent)
onActivated: function(newIndex) {
Objects.currentObjects[objEditor.objType][objEditor.objIndex].labelContent = model[newIndex]
objEditor.obj = Objects.currentObjects[objEditor.objType][objEditor.objIndex]
objEditor.editingRow.obj = Objects.currentObjects[objEditor.objType][objEditor.objIndex]
//objEditor.obj = Objects.currentObjects[objEditor.objType][objEditor.objIndex]
//objEditor.editingRow.obj = objEditor.obj
objectListList.update()
}
}
@ -266,7 +266,7 @@ ListView {
height: 30
width: parent.width
visible: modelData[0].startsWith('comment')
text: visible ? modelData[1].replace('{name}', objEditor.obj.name) : ''
text: visible ? modelData[1].replace(/\{name\}/g, objEditor.obj.name) : ''
color: sysPalette.windowText
}
@ -276,7 +276,7 @@ ListView {
width: parent.width
label: parent.label
isDouble: modelData[1] == 'number'
visible: ['Expression', 'Domain', 'string', 'number'].includes(modelData[1])
visible: paramTypeIn(modelData[1], ['Expression', 'Domain', 'string', 'number'])
defValue: visible ? {
'Expression': () => Utils.simplifyExpression(objEditor.obj[modelData[0]].toEditableString()),
'Domain': () => objEditor.obj[modelData[0]].toString(),
@ -314,20 +314,20 @@ ListView {
width: dlgProperties.width
label: parent.label
// True to select an object of type, false for enums.
property bool selectObjMode: (typeof modelData[1] == "string" && Object.keys(Objects.types).includes(modelData[1]))
property bool selectObjMode: paramTypeIn(modelData[1], ['ObjectType'])
model: visible ?
(selectObjMode ? Objects.getObjectsName(modelData[1]).concat(['+ Create new ' + modelData[1]]) : modelData[1])
(selectObjMode ? Objects.getObjectsName(modelData[1].objType).concat(['+ Create new ' + modelData[1].objType]) : modelData[1].values)
: []
visible: Array.isArray(modelData[1]) || selectObjMode
visible: paramTypeIn(modelData[1], ['ObjectType', 'Enum'])
currentIndex: model.indexOf(selectObjMode ? objEditor.obj[modelData[0]].name : objEditor.obj[modelData[0]])
onActivated: function(newIndex) {
// Setting object property.
if(selectObjMode) {
var selectedObj = Objects.getObjectByName(model[newIndex], modelData[1])
var selectedObj = Objects.getObjectByName(model[newIndex], modelData[1].objType)
if(selectedObj == null) {
selectedObj = Objects.createNewRegisteredObject(modelData[1])
model = Objects.getObjectsName(modelData[1]).concat(['+ Create new ' + modelData[1]])
selectedObj = Objects.createNewRegisteredObject(modelData[1].objType)
model = Objects.getObjectsName(modelData[1].objType).concat(['+ Create new ' + modelData[1].objType])
currentIndex = model.indexOf(selectedObj.name)
}
Objects.currentObjects[objEditor.objType][objEditor.objIndex][modelData[0]].requiredBy = objEditor.obj[modelData[0]].filter((obj) => objEditor.obj.name != obj.name)
@ -346,24 +346,23 @@ ListView {
id: customPropListDict
width: parent.width
visible: typeof modelData[1] == 'object' && 'type' in modelData[1] && (modelData[1].type == 'List' || modelData[1].type == 'Dict')
visible: paramTypeIn(modelData[1], ['List', 'Dict'])
label: parent.label
dictionaryMode: visible ? modelData[1].type == 'Dict' : false
dictionaryMode: paramTypeIn(modelData[1], ['Dict'])
keyType: dictionaryMode ? modelData[1].keyType : 'string'
valueType: visible ? modelData[1].type : 'string'
preKeyLabel: (dictionaryMode ? modelData[1].preKeyLabel : modelData[1].label).replace('{name}', objEditor.obj.name)
postKeyLabel: (dictionaryMode ? modelData[1].postKeyLabel : '').replace('{name}', objEditor.obj.name)
valueType: visible ? modelData[1].valueType : 'string'
preKeyLabel: visible ? (dictionaryMode ? modelData[1].preKeyLabel : modelData[1].label).replace(/\{name\}/g, objEditor.obj.name) : ''
postKeyLabel: visible ? (dictionaryMode ? modelData[1].postKeyLabel : '').replace(/\{name\}/g, objEditor.obj.name) : ''
keyRegexp: dictionaryMode ? modelData[1].keyFormat : /^.+$/
valueRegexp: visible ? modelData[1].format : /^.+$/
forbidAdding: visible ? modelData[1].forbidAdding : false
onChanged: {
Objects.currentObjects[objEditor.objType][objEditor.objIndex][modelData[0]] = exportModel()
objectListList.update()
}
Component.onCompleted: {
console.log('Visible', visible, modelData[0], modelData[1])
console.log('Type', ('type' in modelData[1]), modelData[1].type)
if(visible) importModel(objEditor.obj[modelData[0]])
}
}
@ -372,6 +371,7 @@ ListView {
}
function show() {
dlgCustomProperties.model = [] // Reset
var objProps = Objects.types[objEditor.objType].properties()
dlgCustomProperties.model = Object.keys(objProps).map(prop => [prop, objProps[prop]]) // Converted to 2-dimentional array.
objEditor.open()
@ -415,4 +415,11 @@ ListView {
objectListList.listViews[objType].model = Objects.currentObjects[objType]
}
}
function paramTypeIn(parameter, types = []) {
if(types.includes(parameter.toString())) return true
if(typeof parameter == 'object' && 'type' in parameter)
return types.includes(parameter.type)
return false
}
}

View file

@ -223,7 +223,7 @@ class EmptySet extends Domain {
static import(frm) { return new EmptySet() }
}
class Interval extends Domain {
class Range extends Domain {
constructor(begin, end, openBegin, openEnd) {
super()
if(typeof begin == 'number' || typeof begin == 'string') begin = new Expression(begin.toString())
@ -251,7 +251,7 @@ class Interval extends Domain {
if(domain instanceof UnionDomain) return domain.union(this)
if(domain instanceof IntersectionDomain) return new UnionDomain(this, domain)
if(domain instanceof MinusDomain) return new UnionDomain(this, domain)
if(domain instanceof Interval) return new UnionDomain(this, domain)
if(domain instanceof Range) return new UnionDomain(this, domain)
}
intersection(domain) {
@ -260,14 +260,14 @@ class Interval extends Domain {
if(domain instanceof UnionDomain) return new IntersectionDomain(this, domain)
if(domain instanceof IntersectionDomain) return domain.intersection(this)
if(domain instanceof MinusDomain) return new IntersectionDomain(this, domain)
if(domain instanceof Interval) return new IntersectionDomain(this, domain)
if(domain instanceof Range) return new IntersectionDomain(this, domain)
}
static import(frm) {
var openBegin = frm.trim().charAt(0) == "]"
var openEnd = frm.trim().charAt(frm.length -1) == "["
var [begin, end] = frm.substr(1, frm.length-2).split(";")
return new Interval(begin.trim(), end.trim(), openBegin, openEnd)
return new Range(begin.trim(), end.trim(), openBegin, openEnd)
}
}
@ -312,7 +312,7 @@ class SpecialDomain extends Domain {
if(domain instanceof UnionDomain) return new UnionDomain(this, domain)
if(domain instanceof IntersectionDomain) return new UnionDomain(this, domain)
if(domain instanceof MinusDomain) return new UnionDomain(this, domain)
if(domain instanceof Interval) return new UnionDomain(this, domain)
if(domain instanceof Range) return new UnionDomain(this, domain)
}
intersection(domain) {
@ -321,7 +321,7 @@ class SpecialDomain extends Domain {
if(domain instanceof UnionDomain) return new IntersectionDomain(this, domain)
if(domain instanceof IntersectionDomain) return new IntersectionDomain(this, domain)
if(domain instanceof MinusDomain) return new IntersectionDomain(this, domain)
if(domain instanceof Interval) return new IntersectionDomain(this, domain)
if(domain instanceof Range) return new IntersectionDomain(this, domain)
}
}
@ -389,7 +389,7 @@ class DomainSet extends SpecialDomain {
var notIncludedValues = []
for(var value in this.values) {
var value = this.executedValues[i]
if(domain instanceof Interval) {
if(domain instanceof Range) {
if(domain.begin.execute() == value && domain.openBegin) {
domain.openBegin = false
}
@ -416,7 +416,7 @@ class DomainSet extends SpecialDomain {
var includedValues = []
for(var i in this.values) {
var value = this.executedValues[i]
if(domain instanceof Interval) {
if(domain instanceof Range) {
if(domain.begin.execute() == value && !domain.openBegin) {
domain.openBegin = false
}
@ -455,7 +455,7 @@ class UnionDomain extends Domain {
union(domain) {
if(domain instanceof EmptySet) return this
if(domain instanceof DomainSet) return domain.union(this)
if(domain instanceof Interval) return domain.union(this)
if(domain instanceof Range) return domain.union(this)
if(domain instanceof UnionDomain) return new UnionDomain(this, domain)
if(domain instanceof IntersectionDomain) return new UnionDomain(this, domain)
if(domain instanceof MinusDomain) return new MinusDomain(this, domain)
@ -496,7 +496,7 @@ class IntersectionDomain extends Domain {
union(domain) {
if(domain instanceof EmptySet) return this
if(domain instanceof DomainSet) return domain.union(this)
if(domain instanceof Interval) return domain.union(this)
if(domain instanceof Range) return domain.union(this)
if(domain instanceof UnionDomain) return this.dom1.union(domain.dom1).union(this.dom2).union(domain.dom2)
if(domain instanceof IntersectionDomain) return new UnionDomain(this, domain)
if(domain instanceof MinusDomain) return new MinusDomain(this, domain)
@ -545,15 +545,15 @@ class MinusDomain extends Domain {
Domain.RE = new MinusDomain("R", "{0}")
Domain.RE.displayName = "*"
Domain.R = new Interval(-Infinity,Infinity,true,true)
Domain.R = new Range(-Infinity,Infinity,true,true)
Domain.R.displayName = ""
Domain.RP = new Interval(0,Infinity,true,false)
Domain.RP = new Range(0,Infinity,true,false)
Domain.RP.displayName = "ℝ⁺"
Domain.RM = new Interval(-Infinity,0,true,false)
Domain.RM = new Range(-Infinity,0,true,false)
Domain.RM.displayName = "ℝ⁻"
Domain.RPE = new Interval(0,Infinity,true,true)
Domain.RPE = new Range(0,Infinity,true,true)
Domain.RPE.displayName = "ℝ⁺*"
Domain.RME = new Interval(-Infinity,0,true,true)
Domain.RME = new Range(-Infinity,0,true,true)
Domain.RME.displayName = "ℝ⁻*"
Domain.N = new SpecialDomain('', x => x%1==0 && x >= 0,
x => Math.max(Math.floor(x)+1, 0),
@ -601,7 +601,7 @@ function parseDomainSimple(domain) {
if(domain.includes("∩")) return IntersectionDomain.import(domain)
if(domain.includes("") || domain.includes("\\")) return MinusDomain.import(domain)
if(domain.charAt(0) == "{" && domain.charAt(domain.length -1) == "}") return DomainSet.import(domain)
if(domain.includes("]") || domain.includes("[")) return Interval.import(domain)
if(domain.includes("]") || domain.includes("[")) return Range.import(domain)
if(["R", "", "N", "", "Z", ""].some(str => domain.toUpperCase().includes(str)))
return Domain.import(domain)
if(domain[0] == 'D') return refedDomains[parseInt(domain.substr(1))]

View file

@ -20,7 +20,7 @@
.import "utils.js" as Utils
.import "mathlib.js" as MathLib
.import "parameters.js" as P
function getNewName(allowedLetters) {
@ -35,31 +35,6 @@ function getNewName(allowedLetters) {
return ret
}
class List {
constructor(type, format = /^.+$/, label = '', forbidAdding = false) {
// type can be string, int and double.
this.type = 'List'
this.valueType = type
this.format = format
this.label = label
this.forbidAdding = forbidAdding
}
}
class Dictionary {
constructor(type, keyType = 'string', format = /^.+$/, keyFormat = /^.+$/, preKeyLabel = '', postKeyLabel = ': ', forbidAdding = false) {
// type & keyType can be string, int and double.
this.type = 'Dict'
this.valueType = type
this.keyType = keyType
this.format = format
this.keyFormat = keyFormat
this.preKeyLabel = preKeyLabel
this.postKeyLabel = postKeyLabel
this.forbidAdding = forbidAdding
}
}
class DrawableObject {
// Class to extend for every type of object that
// can be drawn on the canvas.
@ -144,8 +119,8 @@ class Point extends DrawableObject {
static properties() {return {
'x': 'Expression',
'y': 'Expression',
'labelPosition': ['top', 'bottom', 'left', 'right', 'top-left', 'top-right', 'bottom-left', 'bottom-right'],
'pointStyle': ['●', '✕', ''],
'labelPosition': new P.Enum('top', 'bottom', 'left', 'right', 'top-left', 'top-right', 'bottom-left', 'bottom-right'),
'pointStyle': new P.Enum('●', '✕', ''),
}}
constructor(name = null, visible = true, color = null, labelContent = 'name + value',
@ -229,8 +204,8 @@ class Function extends ExecutableObject {
'inDomain': 'Domain',
'outDomain': 'Domain',
'comment1': 'Ex: R+* (ℝ⁺*), N* (*), Z-* (ℤ⁻*), ]0;1[, {3;4;5}',
'labelPosition': ['above', 'below'],
'displayMode': ['application', 'function'],
'labelPosition': new P.Enum('above', 'below'),
'displayMode': new P.Enum('application', 'function'),
'labelX': 'number'
}}
@ -348,10 +323,10 @@ class GainBode extends ExecutableObject {
static type(){return 'Gain Bode'}
static typeMultiple(){return 'Gains Bode'}
static properties() {return {
'om_0': 'Point',
'pass': ['high', 'low'],
'om_0': new P.ObjectType('Point'),
'pass': new P.Enum('high', 'low'),
'gain': 'Expression',
'labelPosition': ['above', 'below'],
'labelPosition': new P.Enum('above', 'below'),
'labelX': 'number'
}}
@ -463,7 +438,7 @@ class SommeGainsBode extends DrawableObject {
static typeMultiple(){return 'Somme gains Bode'}
static createable() {return false}
static properties() {return {
'labelPosition': ['above', 'below'],
'labelPosition': new P.Enum('above', 'below'),
'labelX': 'number'
}}
@ -588,10 +563,10 @@ class PhaseBode extends ExecutableObject {
static type(){return 'Phase Bode'}
static typeMultiple(){return 'Phases Bode'}
static properties() {return {
'om_0': 'Point',
'om_0': new P.ObjectType('Point'),
'phase': 'Expression',
'unit': ['°', 'deg', 'rad'],
'labelPosition': ['above', 'below'],
'unit': new P.Enum('°', 'deg', 'rad'),
'labelPosition': new P.Enum('above', 'below'),
'labelX': 'number'
}}
@ -700,7 +675,7 @@ class SommePhasesBode extends ExecutableObject {
static typeMultiple(){return 'Somme phases Bode'}
static createable() {return false}
static properties() {return {
'labelPosition': ['above', 'below'],
'labelPosition': new P.Enum('above', 'below'),
'labelX': 'number'
}}
@ -816,16 +791,16 @@ class CursorX extends DrawableObject {
})
return {
'x': 'Expression',
'targetElement': elementNames,
'labelPosition': ['left', 'right'],
'targetElement': new P.Enum(...elementNames),
'labelPosition': new P.Enum('left', 'right'),
'approximate': 'Boolean',
'rounding': 'number',
'displayStyle': [
'displayStyle': new P.Enum(
'— — — — — — —',
'⸺⸺⸺⸺⸺⸺',
'• • • • • • • • • •'
],
'targetValuePosition' : ['Next to target', 'With label', 'Hidden']
),
'targetValuePosition' : new P.Enum('Next to target', 'With label', 'Hidden')
}
}
@ -947,9 +922,9 @@ class Sequence extends ExecutableObject {
static type(){return 'Sequence'}
static typeMultiple(){return 'Sequences'}
static properties() {return {
'defaultExpression': new Dictionary('string', 'int', /^.+$/, /^(\d+)$/, '{name}[n+', '] = ', true),
'comment1': 'NOTE: Use {name}[n] to refer to uₙ, u[n+1] for uₙ₊₁...',
'markedValues': new Dictionary('string', 'int', /^.+$/, /^(\d+)$/, '{name}[', '] = '),
'defaultExpression': new P.Dictionary('string', 'int', /^.+$/, /^(\d+)$/, '{name}[n+', '] = ', true),
'comment1': 'Note: Use {name}[n] to refer to {name}ₙ, {name}[n+1] for {name}ₙ₊₁...',
'markedValues': new P.Dictionary('string', 'int', /^.+$/, /^(\d+)$/, '{name}[', '] = '),
}}
constructor(name = null, visible = true, color = null, labelContent = 'name + value',

56
qml/js/parameters.js Normal file
View file

@ -0,0 +1,56 @@
/**
* Logarithm Graph Creator - Create graphs with logarithm scales.
* Copyright (C) 2020 Ad5001
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
class Enum {
constructor(...values) {
this.type = 'Enum'
this.values = values
}
}
class ObjectType {
constructor(objType) {
this.type = 'ObjectType'
this.objType = objType
}
}
class List {
constructor(type, format = /^.+$/, label = '', forbidAdding = false) {
// type can be string, int and double.
this.type = 'List'
this.valueType = type
this.format = format
this.label = label
this.forbidAdding = forbidAdding
}
}
class Dictionary {
constructor(type, keyType = 'string', format = /^.+$/, keyFormat = /^.+$/, preKeyLabel = '', postKeyLabel = ': ', forbidAdding = false) {
// type & keyType can be string, int and double.
this.type = 'Dict'
this.valueType = type
this.keyType = keyType
this.format = format
this.keyFormat = keyFormat
this.preKeyLabel = preKeyLabel
this.postKeyLabel = postKeyLabel
this.forbidAdding = forbidAdding
}
}