From 7e47b3cdf9416bbe6887e93235dd95567f4ab1d2 Mon Sep 17 00:00:00 2001 From: Ad5001 Date: Sat, 26 Dec 2020 14:49:48 +0100 Subject: [PATCH] Paramerters and enums as class, now simpler implementation with more abstractions for parameters. Also fixing a lot of bugs along the way. --- qml/ListSetting.qml | 16 +++++------ qml/ObjectLists.qml | 41 ++++++++++++++++----------- qml/js/mathlib.js | 32 ++++++++++----------- qml/js/objects.js | 67 ++++++++++++++------------------------------ qml/js/parameters.js | 56 ++++++++++++++++++++++++++++++++++++ 5 files changed, 125 insertions(+), 87 deletions(-) create mode 100644 qml/js/parameters.js diff --git a/qml/ListSetting.qml b/qml/ListSetting.qml index 9d478af..dcfa92e 100644 --- a/qml/ListSetting.qml +++ b/qml/ListSetting.qml @@ -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) } } } diff --git a/qml/ObjectLists.qml b/qml/ObjectLists.qml index 54e6a01..d792136 100644 --- a/qml/ObjectLists.qml +++ b/qml/ObjectLists.qml @@ -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 + } } diff --git a/qml/js/mathlib.js b/qml/js/mathlib.js index a8af665..7d8d72d 100644 --- a/qml/js/mathlib.js +++ b/qml/js/mathlib.js @@ -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))] diff --git a/qml/js/objects.js b/qml/js/objects.js index 23680ba..242f7b7 100644 --- a/qml/js/objects.js +++ b/qml/js/objects.js @@ -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', diff --git a/qml/js/parameters.js b/qml/js/parameters.js new file mode 100644 index 0000000..f7bf27a --- /dev/null +++ b/qml/js/parameters.js @@ -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 . + */ + +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 + } +}