diff --git a/qml/ListSetting.qml b/qml/ListSetting.qml new file mode 100644 index 0000000..d6beb0c --- /dev/null +++ b/qml/ListSetting.qml @@ -0,0 +1,136 @@ +import QtQuick 2.12 + +ListView { + id: control + + signal changed() + + property bool dictionaryMode: false + property bool keyType: "string" + property bool valueType: "string" + property string preKeyLabel: "" + property string postKeyLabel: ": " + property var keyRegexp: /^.+$/ + property var valueRegexp: /^.+$/ + + + model: ListModel {} + + delegate: Row { + height: 30 + width: control.width + + Text { + id: preKeyText + height: parent.height + verticalAlignment: TextInput.AlignVCenter + color: sysPalette.windowText + text: control.preKeyLabel + } + + TextField { + id: keyInput + visible: control.dictionaryMode + height: parent.height + width: visible ? 50 : 0 + validator: RegularExpressionValidator { + regularExpression: control.keyRegexp + } + verticalAlignment: TextInput.AlignVCenter + horizontalAlignment: TextInput.AlignHCenter + color: sysPalette.windowText + text: visible ? model.get(index).key : false + selectByMouse: true + onEditingFinished: { + var value = text + if(control.keyType == 'int') { + value = parseFloat(value) + if(value.toString()=="NaN") + value = "" + } + if(control.keyType == 'double') { + value = parseFloat(value) + if(value.toString()=="NaN") + value = "" + } + if(value != "") { + model.setProperty(index, 'key', value) + control.changed() + } + } + } + + Text { + id: postKeyText + visible: control.dictionaryMode + height: parent.height + verticalAlignment: TextInput.AlignVCenter + color: sysPalette.windowText + text: control.postKeyLabel + } + + TextField { + id: valueInput + height: parent.height + width: parent.width - preKeyText.width - keyInput.width - postKeyText.width + validator: RegularExpressionValidator { + regularExpression: control.valueRegexp + } + verticalAlignment: TextInput.AlignVCenter + horizontalAlignment: TextInput.AlignHCenter + color: sysPalette.windowText + text: visible ? model.get(index).key : false + selectByMouse: true + onEditingFinished: { + var value = text + if(control.valueType == 'int') { + value = parseFloat(value) + if(value.toString()=="NaN") + value = "" + } + if(control.valueType == 'double') { + value = parseFloat(value) + if(value.toString()=="NaN") + value = "" + } + if(value != "") { + model.setProperty(index, 'value', value) + control.changed() + } + } + } + } + + footer: Button { + id: addEntryBtn + text: '+ Add Entry' + width: control.width + height: visible ? implicitHeight : 0 + + onClicked: { + control.model.append({ + key: "", + value: "" + }) + } + } + + function import(importer) { + model.clear() + if(dictionaryMode) { + for(var key in importer) model.append({ + key: key, + value: importer[value] + }) + } else { + for(var key in importer) model.append({ + key: key, + value: importer[value] + }) + } + } + + function export() { + if(d + } +} diff --git a/qml/LogGraph.qml b/qml/LogGraph.qml index 818982d..1eadd03 100644 --- a/qml/LogGraph.qml +++ b/qml/LogGraph.qml @@ -115,12 +115,12 @@ ApplicationWindow { function saveDiagram(filename) { var objs = {} - Object.keys(Objects.currentObjects).forEach(function(objType){ + for(var objType in Objects.currentObjects){ objs[objType] = [] - Objects.currentObjects[objType].forEach(function(obj){ + for(var obj of Objects.currentObjects[objType]) { objs[objType].push(obj.export()) - }) - }) + } + } Helper.write(filename, JSON.stringify({ "xzoom": settings.xzoom, "yzoom": settings.yzoom, @@ -140,7 +140,7 @@ ApplicationWindow { function loadDiagram(filename) { var data = JSON.parse(Helper.load(filename)) - if("type" in Object.keys(data) && data["type"] == "logplotv1") { + if(Object.keys(data).includes("type") && data["type"] == "logplotv1") { settings.xzoom = data["xzoom"] settings.yzoom = data["yzoom"] settings.xmin = data["xmin"] @@ -154,13 +154,13 @@ ApplicationWindow { root.width = data["width"] Objects.currentObjects = {} - Object.keys(data['objects']).forEach(function(objType){ + for(var objType in data['objects']) { Objects.currentObjects[objType] = [] - data['objects'][objType].forEach(function(objData){ + for(var objData of data['objects'][objType]) { var obj = new Objects.types[objType](...objData) Objects.currentObjects[objType].push(obj) - }) - }) + } + } // Refreshing sidebar if(sidebarSelector.currentIndex == 0) { // For some reason, if we load a file while the tab is on object, diff --git a/qml/LogGraphCanvas.qml b/qml/LogGraphCanvas.qml index d50837c..1045544 100644 --- a/qml/LogGraphCanvas.qml +++ b/qml/LogGraphCanvas.qml @@ -54,13 +54,13 @@ Canvas { reset(ctx) drawGrille(ctx) drawAxises(ctx) - Object.keys(Objects.currentObjects).forEach(function(objType){ - Objects.currentObjects[objType].forEach(function(obj){ + for(var objType in Objects.currentObjects) { + for(var obj of Objects.currentObjects[objType]){ ctx.strokeStyle = obj.color ctx.fillStyle = obj.color if(obj.visible) obj.draw(canvas, ctx) - }) - }) + } + } drawLabels(ctx) } diff --git a/qml/ObjectLists.qml b/qml/ObjectLists.qml index 2ab1047..dd89e4a 100644 --- a/qml/ObjectLists.qml +++ b/qml/ObjectLists.qml @@ -55,8 +55,8 @@ ListView { id: typeVisibilityCheckBox checked: Objects.currentObjects[objType] != undefined ? Objects.currentObjects[objType].every(obj => obj.visible) : true onClicked: { - Objects.currentObjects[objType].forEach(obj => obj.visible = this.checked) - objTypeList.editingRows.forEach(obj => obj.objVisible = this.checked) + for(var obj of Objects.currentObjects[objType]) obj.visible = this.checked + for(var obj of objTypeList.editingRows) obj.objVisible = this.checked objectListList.changed() } @@ -115,7 +115,7 @@ ListView { objEditor.objType = objType objEditor.objIndex = index objEditor.editingRow = controlRow - objEditor.open() + objEditor.show() } } } @@ -135,7 +135,7 @@ ListView { objEditor.objType = objType objEditor.objIndex = index objEditor.editingRow = controlRow - objEditor.open() + objEditor.show() } } @@ -192,7 +192,7 @@ ListView { id: objEditor property string objType: 'Point' property int objIndex: 0 - property var editingRow: QtObject{} + property QtObject editingRow: QtObject{} property var obj: Objects.currentObjects[objType][objIndex] title: `Logarithmic Plotter` width: 300 @@ -224,7 +224,6 @@ ListView { onChanged: function(newValue) { var newName = Utils.parseName(newValue) if(newName != '' && objEditor.obj.name != newName) { - console.log('Renaming to', newName) if(Objects.getObjectByName(newName) != null) { console.log(Objects.getObjectByName(newName).name, newName) newName = Objects.getNewName(newName) @@ -255,8 +254,7 @@ ListView { // Dynamic properties Repeater { - property var objProps: Objects.types[objEditor.objType].properties() - model: Array.from(Object.keys(objProps), prop => [prop, objProps[prop]]) // Converted to 2-dimentional array. + id: dlgCustomProperties Item { height: 30 @@ -268,17 +266,17 @@ ListView { height: 30 width: parent.width visible: modelData[0].startsWith('comment') - text: modelData[1] + text: visible ? modelData[1] : '' color: sysPalette.windowText } TextSetting { id: customPropText - height: 30 + height: visible ? 30 : 0 width: parent.width label: parent.label isDouble: modelData[1] == 'number' - visible: modelData[1] in ['Expression', 'Domain', 'string', 'number'] + visible: ['Expression', 'Domain', 'string', 'number'].includes(modelData[1]) defValue: visible ? { 'Expression': () => Utils.simplifyExpression(objEditor.obj[modelData[0]].toEditableString()), 'Domain': () => objEditor.obj[modelData[0]].toString(), @@ -316,7 +314,7 @@ ListView { width: dlgProperties.width label: parent.label // True to select an object of type, false for enums. - property bool selectObjMode: (typeof modelData[1] == "string" && modelData[1] in Object.keys(Objects.types)) + property bool selectObjMode: (typeof modelData[1] == "string" && Object.keys(Objects.types).includes(modelData[1])) model: visible ? (selectObjMode ? Objects.getObjectsName(modelData[1]).concat(['+ Create new ' + modelData[1]]) : modelData[1]) : [] @@ -346,6 +344,12 @@ ListView { } } } + + function show() { + var objProps = Objects.types[objEditor.objType].properties() + dlgCustomProperties.model = Object.keys(objProps).map(prop => [prop, objProps[prop]]) // Converted to 2-dimentional array. + objEditor.open() + } } footer: Column { @@ -371,8 +375,6 @@ ListView { height: visible ? implicitHeight : 0 icon.source: './icons/'+modelData+'.svg' // Default to dark version - - onClicked: { Objects.createNewRegisteredObject(modelData) objectListList.update() @@ -383,8 +385,8 @@ ListView { function update() { objectListList.changed() - objectListList.model.forEach(function(objType){ + for(var objType in objectListList.model) { objectListList.listViews[objType].model = Objects.currentObjects[objType] - }) + } } } diff --git a/qml/js/mathlib.js b/qml/js/mathlib.js index e9e02e6..a8af665 100644 --- a/qml/js/mathlib.js +++ b/qml/js/mathlib.js @@ -79,11 +79,13 @@ function executeExpression(expr){ } class Sequence extends Expression { - constructor(name, baseValues = {}, expr) { + constructor(name, baseValues = {}, valuePlus = 1, expr = "") { + // u[n+valuePlus] = expr console.log('Expression', expr) super(expr) this.name = name this.baseValues = baseValues + this.valuePlus = valuePlus } isConstant() { @@ -93,7 +95,7 @@ class Sequence extends Expression { execute(n = 0) { if(this.cached) return this.cachedValue if(n in this.baseValues) return this.baseValues[n] - var vars = Object.assign({'n': n-1}, evalVariables) + var vars = Object.assign({'n': n-this.valuePlus}, evalVariables) vars[this.name] = this.baseValues var un = this.calc.evaluate(vars) this.baseValues[n] = un @@ -101,7 +103,7 @@ class Sequence extends Expression { } } -var test = new Sequence('u', {0: 0}, '3*u[n]+3') +var test = new Sequence('u', {0: 0, 1: 1}, 2, '3*u[n]+3') console.log(test) for(var i=0; i<20; i++) console.log('u' + Utils.textsub(i) + ' = ' + test.execute(i)) @@ -330,8 +332,8 @@ class DomainSet extends SpecialDomain { console.log(values) var newVals = {} this.executedValues = [] - for(var i = 0; i < values.length; i++) { - var expr = new Expression(values[i].toString()) + for(var value of values) { + var expr = new Expression(value.toString()) var ex = expr.execute() newVals[ex] = expr this.executedValues.push(ex) @@ -342,8 +344,8 @@ class DomainSet extends SpecialDomain { includes(x) { if(typeof x == 'string') x = executeExpression(x) - for(var i = 0; i < this.values.length; i++) - if(x == this.values[i].execute()) return true + for(var value of this.values) + if(x == value.execute()) return true return false } @@ -385,7 +387,7 @@ class DomainSet extends SpecialDomain { return new DomainSet(values) } var notIncludedValues = [] - for(var i = 0; i < this.values.length; i++) { + for(var value in this.values) { var value = this.executedValues[i] if(domain instanceof Interval) { if(domain.begin.execute() == value && domain.openBegin) { @@ -412,7 +414,7 @@ class DomainSet extends SpecialDomain { return this } var includedValues = [] - for(var i = 0; i < this.values.length; i++) { + for(var i in this.values) { var value = this.executedValues[i] if(domain instanceof Interval) { if(domain.begin.execute() == value && !domain.openBegin) { diff --git a/qml/js/objects.js b/qml/js/objects.js index 4665631..34ee9ae 100644 --- a/qml/js/objects.js +++ b/qml/js/objects.js @@ -35,6 +35,25 @@ function getNewName(allowedLetters) { return ret } +class List { + constructor(type, format=/^.+$/, label = '') { + // type can be string, int and double. + this.type = type + this.format = format + this.label = label + } +} + +class Dictionary { + constructor(type, keyType = 'string', format = /^.+$/, keyFormat = /^.+$/, preKeyLabel = '', postKeyLabel = ': ') { + // type & keyType can be string, int and double. + this.type = type + this.keyType = keyType + this.format = format + this.preKeyLabel = preKeyLabel + this.postKeyLabel = postKeyLabel + } +} class DrawableObject { // Class to extend for every type of object that @@ -47,7 +66,9 @@ class DrawableObject { static createable() {return true} // Properties are set with key as property name and // value as it's type name (e.g 'Expression', 'string', - // 'Point'...) or an array with possibilities for enums. + // 'Point'...), an Array for enumerations, + // a List instance for lists, a Dictionary instance for + // dictionary // Used for property modifier in the sidebar. static properties() {return {}} @@ -83,14 +104,13 @@ class DrawableObject { } update() { - for(var i = 0; i < this.requiredBy.length; i++) { - this.requiredBy[i].update() + for(var req of this.requiredBy) { + req.update() } } delete() { - for(var i = 0; i < this.requiredBy.length; i++) { - var toRemove = this.requiredBy[i] + for(var toRemove of this.requiredBy) { toRemove.delete() currentObjects[toRemove.type] = currentObjects[toRemove.type].filter(obj => obj.name != toRemove.name) } @@ -460,8 +480,7 @@ class SommeGainsBode extends DrawableObject { } execute(x = 0) { - for(var i=0; i 0) { - for(var i=0; i obj.name) } -function createNewRegisteredObject(objType) { +function createNewRegisteredObject(objType, args=[]) { if(Object.keys(types).indexOf(objType) == -1) return null // Object type does not exist. - var newobj = new types[objType]() + var newobj = new types[objType](...args) if(Object.keys(currentObjects).indexOf(objType) == -1) { currentObjects[objType] = [] } diff --git a/qml/js/utils.js b/qml/js/utils.js index 0851c63..7dba4e2 100644 --- a/qml/js/utils.js +++ b/qml/js/utils.js @@ -287,7 +287,7 @@ function camelCase2readable(label) { function getRandomColor() { var clrs = '0123456789ABCDEF'; var color = '#'; - for (var i = 0; i < 6; i++) { + for(var i = 0; i < 6; i++) { color += clrs[Math.floor(Math.random() * (16-5*(i%2==0)))]; } return color;