From 4c1403c983104ece372c6a35b21051c44ea585f8 Mon Sep 17 00:00:00 2001 From: Ad5001 Date: Mon, 23 Sep 2024 20:55:48 +0200 Subject: [PATCH] Implementing modules requiring interfaces --- .../LogarithmPlotter/History/History.qml | 9 +- .../LogarithmPlotter/LogGraphCanvas.qml | 8 +- .../eu/ad5001/LogarithmPlotter/Settings.qml | 2 +- .../LogarithmPlotter/js/module/canvas.mjs | 233 ++++++++++++------ .../LogarithmPlotter/js/module/common.mjs | 40 ++- .../LogarithmPlotter/js/module/expreval.mjs | 5 +- .../LogarithmPlotter/js/module/history.mjs | 70 ++++-- .../ad5001/LogarithmPlotter/js/module/io.mjs | 66 ++++- .../LogarithmPlotter/js/module/latex.mjs | 5 +- .../js/module/preferences.mjs | 5 +- 10 files changed, 312 insertions(+), 131 deletions(-) diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml index e1e527d..85abbc7 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml @@ -212,8 +212,11 @@ Item { } Component.onCompleted: { - Modules.History.history = historyObj - Modules.History.themeTextColor = sysPalette.windowText - Modules.History.imageDepth = Screen.devicePixelRatio + Modules.History.initialize({ + historyObj, + themeTextColor: sysPalette.windowText.toString(), + imageDepth: Screen.devicePixelRatio, + fontSize: 14 + }) } } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml index 4159497..2d7eb08 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml @@ -120,12 +120,6 @@ Canvas { */ property bool showygrad: false - /*! - \qmlproperty int LogGraphCanvas::maxgradx - Max power of the logarithmic scaled on the x axis in logarithmic mode. - */ - property int maxgradx: 90 - /*! \qmlproperty var LogGraphCanvas::imageLoaders Dictionary of format {image: [callback.image data]} containing data for defered image loading. @@ -139,7 +133,7 @@ Canvas { Component.onCompleted: { imageLoaders = {} - Modules.Canvas.initialize(canvas, drawingErrorDialog) + Modules.Canvas.initialize({ canvas, drawingErrorDialog }) } Native.MessageDialog { diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Settings.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Settings.qml index c94bef1..3c6e994 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Settings.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Settings.qml @@ -128,7 +128,7 @@ ScrollView { property string saveFilename: "" Component.onCompleted: { - Modules.IO.initialize(root, settings, alert) + Modules.IO.initialize({ root, settings, alert }) } Column { diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/canvas.mjs b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/canvas.mjs index 020ff88..75efb04 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/canvas.mjs +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/canvas.mjs @@ -24,23 +24,53 @@ import Objects from "./objects.mjs" import History from "./history.mjs" +/** + * @typedef {Settings} Canvas + * @property {object} imageLoaders + * @property {function()} requestPaint + * @property {function(string)} getContext + * @property {function(rect)} markDirty + * @property {function(string)} loadImage + */ + class CanvasAPI extends Module { - constructor() { - super('Canvas', [ - Modules.Objects, - Modules.History - ]) + super("Canvas", { + canvas: { + width: "number", + height: "number", + xmin: "number", + ymax: "number", + xzoom: "number", + yzoom: "number", + xaxisstep: "number", + yaxisstep: "number", + xlabel: "string", + ylabel: "string", + linewidth: "number", + textsize: "number", + logscalex: "boolean", + showxgrad: "boolean", + showygrad: "boolean", + imageLoaders: "object", + getContext: Function, + markDirty: Function, + loadImage: Function, + requestPaint: Function, + }, + drawingErrorDialog: { + showDialog: Function, + } + }) - /** @type {HTMLCanvasElement} */ + /** @type {Canvas} */ this._canvas = null /** @type {CanvasRenderingContext2D} */ this._ctx = null /** - * @type {Object} - * @property {function(string, string, string)} showDialog + * @type {{showDialog(string, string, string)}} * @private */ this._drawingErrorDialog = null @@ -62,86 +92,132 @@ class CanvasAPI extends Module { } } - initialize(canvasObject, drawingErrorDialog) { - this._canvas = canvasObject + /** + * Initialize the module. + * @param {Canvas} canvas + * @param {{showDialog(string, string, string)}} drawingErrorDialog + */ + initialize({ canvas, drawingErrorDialog }) { + super.initialize({ canvas, drawingErrorDialog }) + this._canvas = canvas this._drawingErrorDialog = drawingErrorDialog } - get width() { return this._canvas.width } + get width() { + if(!this.initialized) throw new Error("Attempting width before initialize!") + return this._canvas.width + } - get height() { return this._canvas.height } + get height() { + if(!this.initialized) throw new Error("Attempting height before initialize!") + return this._canvas.height + } /** * Minimum x of the diagram, provided from settings. * @returns {number} */ - get xmin() { return this._canvas.xmin } + get xmin() { + if(!this.initialized) throw new Error("Attempting xmin before initialize!") + return this._canvas.xmin + } /** * Zoom on the x-axis of the diagram, provided from settings. * @returns {number} */ - get xzoom() { return this._canvas.xzoom } + get xzoom() { + if(!this.initialized) throw new Error("Attempting xzoom before initialize!") + return this._canvas.xzoom + } /** * Maximum y of the diagram, provided from settings. * @returns {number} */ - get ymax() { return this._canvas.ymax } + get ymax() { + if(!this.initialized) throw new Error("Attempting ymax before initialize!") + return this._canvas.ymax + } /** * Zoom on the y-axis of the diagram, provided from settings. * @returns {number} */ - get yzoom() { return this._canvas.yzoom } + get yzoom() { + if(!this.initialized) throw new Error("Attempting yzoom before initialize!") + return this._canvas.yzoom + } /** * Label used on the x-axis, provided from settings. * @returns {string} */ - get xlabel() { return this._canvas.xlabel } + get xlabel() { + if(!this.initialized) throw new Error("Attempting xlabel before initialize!") + return this._canvas.xlabel + } /** * Label used on the y-axis, provided from settings. * @returns {string} */ - get ylabel() { return this._canvas.ylabel } + get ylabel() { + if(!this.initialized) throw new Error("Attempting ylabel before initialize!") + return this._canvas.ylabel + } /** * Width of lines that will be drawn into the canvas, provided from settings. * @returns {number} */ - get linewidth() { return this._canvas.linewidth } + get linewidth() { + if(!this.initialized) throw new Error("Attempting linewidth before initialize!") + return this._canvas.linewidth + } /** * Font size of the text that will be drawn into the canvas, provided from settings. * @returns {number} */ - get textsize() { return this._canvas.textsize } + get textsize() { + if(!this.initialized) throw new Error("Attempting textsize before initialize!") + return this._canvas.textsize + } /** * True if the canvas should be in logarithmic mode, false otherwise. * @returns {boolean} */ - get logscalex() { return this._canvas.logscalex } + get logscalex() { + if(!this.initialized) throw new Error("Attempting logscalex before initialize!") + return this._canvas.logscalex + } /** * True if the x graduation should be shown, false otherwise. * @returns {boolean} */ - get showxgrad() { return this._canvas.showxgrad } + get showxgrad() { + if(!this.initialized) throw new Error("Attempting showxgrad before initialize!") + return this._canvas.showxgrad + } /** * True if the y graduation should be shown, false otherwise. * @returns {boolean} */ - get showygrad() { return this._canvas.showygrad } + get showygrad() { + if(!this.initialized) throw new Error("Attempting showygrad before initialize!") + return this._canvas.showygrad + } /** * Max power of the logarithmic scaled on the x axis in logarithmic mode. * @returns {number} */ get maxgradx() { + if(!this.initialized) throw new Error("Attempting maxgradx before initialize!") return Math.min( 309, // 10e309 = Infinity (beyond this land be dragons) Math.max( @@ -156,6 +232,7 @@ class CanvasAPI extends Module { // requestPaint() { + if(!this.initialized) throw new Error("Attempting requestPaint before initialize!") this._canvas.requestPaint() } @@ -163,6 +240,7 @@ class CanvasAPI extends Module { * Redraws the entire canvas */ redraw() { + if(!this.initialized) throw new Error("Attempting redraw before initialize!") this._ctx = this._canvas.getContext("2d") this._computeAxes() this._reset() @@ -171,7 +249,7 @@ class CanvasAPI extends Module { this._drawLabels() this._ctx.lineWidth = this.linewidth for(let objType in Objects.currentObjects) { - for(let obj of Objects.currentObjects[objType]){ + for(let obj of Objects.currentObjects[objType]) { this._ctx.strokeStyle = obj.color this._ctx.fillStyle = obj.color if(obj.visible) @@ -202,12 +280,12 @@ class CanvasAPI extends Module { x: { expression: exprX, value: x1, - maxDraw: Math.ceil(Math.max(Math.abs(this.xmin), Math.abs(this.px2x(this.width)))/x1) + maxDraw: Math.ceil(Math.max(Math.abs(this.xmin), Math.abs(this.px2x(this.width))) / x1) }, y: { expression: exprY, value: y1, - maxDraw: Math.ceil(Math.max(Math.abs(this.ymax), Math.abs(this.px2y(this.height)))/y1) + maxDraw: Math.ceil(Math.max(Math.abs(this.ymax), Math.abs(this.px2y(this.height))) / y1) } } } @@ -216,14 +294,14 @@ class CanvasAPI extends Module { * Resets the canvas to a blank one with default setting. * @private */ - _reset(){ + _reset() { // Reset this._ctx.fillStyle = "#FFFFFF" this._ctx.strokeStyle = "#000000" this._ctx.font = `${this.textsize}px sans-serif` - this._ctx.fillRect(0,0,this.width,this.height) + this._ctx.fillRect(0, 0, this.width, this.height) } - + /** * Draws the grid. * @private @@ -233,18 +311,18 @@ class CanvasAPI extends Module { if(this.logscalex) { for(let xpow = -this.maxgradx; xpow <= this.maxgradx; xpow++) { for(let xmulti = 1; xmulti < 10; xmulti++) { - this.drawXLine(Math.pow(10, xpow)*xmulti) + this.drawXLine(Math.pow(10, xpow) * xmulti) } } } else { - for(let x = 0; x < this.axesSteps.x.maxDraw; x+=1) { - this.drawXLine(x*this.axesSteps.x.value) - this.drawXLine(-x*this.axesSteps.x.value) + for(let x = 0; x < this.axesSteps.x.maxDraw; x += 1) { + this.drawXLine(x * this.axesSteps.x.value) + this.drawXLine(-x * this.axesSteps.x.value) } } - for(let y = 0; y < this.axesSteps.y.maxDraw; y+=1) { - this.drawYLine(y*this.axesSteps.y.value) - this.drawYLine(-y*this.axesSteps.y.value) + for(let y = 0; y < this.axesSteps.y.maxDraw; y += 1) { + this.drawYLine(y * this.axesSteps.y.value) + this.drawYLine(-y * this.axesSteps.y.value) } } @@ -260,10 +338,10 @@ class CanvasAPI extends Module { let axisypx = this.x2px(axisypos) // X coordinate of Y axis let axisxpx = this.y2px(0) // Y coordinate of X axis // Drawing arrows - this.drawLine(axisypx, 0, axisypx-10, 10) - this.drawLine(axisypx, 0, axisypx+10, 10) - this.drawLine(this.width, axisxpx, this.width-10, axisxpx-10) - this.drawLine(this.width, axisxpx, this.width-10, axisxpx+10) + this.drawLine(axisypx, 0, axisypx - 10, 10) + this.drawLine(axisypx, 0, axisypx + 10, 10) + this.drawLine(this.width, axisxpx, this.width - 10, axisxpx - 10) + this.drawLine(this.width, axisxpx, this.width - 10, axisxpx + 10) } /** @@ -276,38 +354,38 @@ class CanvasAPI extends Module { // Labels this._ctx.fillStyle = "#000000" this._ctx.font = `${this.textsize}px sans-serif` - this._ctx.fillText(this.ylabel, axisypx+10, 24) + this._ctx.fillText(this.ylabel, axisypx + 10, 24) let textWidth = this._ctx.measureText(this.xlabel).width - this._ctx.fillText(this.xlabel, this.width-14-textWidth, axisxpx-5) + this._ctx.fillText(this.xlabel, this.width - 14 - textWidth, axisxpx - 5) // Axis graduation labels - this._ctx.font = `${this.textsize-4}px sans-serif` + this._ctx.font = `${this.textsize - 4}px sans-serif` - let txtMinus = this._ctx.measureText('-').width + let txtMinus = this._ctx.measureText("-").width if(this.showxgrad) { if(this.logscalex) { - for(let xpow = -this.maxgradx; xpow <= this.maxgradx; xpow+=1) { - textWidth = this._ctx.measureText("10"+textsup(xpow)).width + for(let xpow = -this.maxgradx; xpow <= this.maxgradx; xpow += 1) { + textWidth = this._ctx.measureText("10" + textsup(xpow)).width if(xpow !== 0) - this.drawVisibleText("10"+textsup(xpow), this.x2px(Math.pow(10,xpow))-textWidth/2, axisxpx+16+(6*(xpow===1))) + this.drawVisibleText("10" + textsup(xpow), this.x2px(Math.pow(10, xpow)) - textWidth / 2, axisxpx + 16 + (6 * (xpow === 1))) } } else { for(let x = 1; x < this.axesSteps.x.maxDraw; x += 1) { - let drawX = x*this.axesSteps.x.value - let txtX = this.axesSteps.x.expression.simplify(x).toString().replace(/^\((.+)\)$/, '$1') + let drawX = x * this.axesSteps.x.value + let txtX = this.axesSteps.x.expression.simplify(x).toString().replace(/^\((.+)\)$/, "$1") let textHeight = this.measureText(txtX).height - this.drawVisibleText(txtX, this.x2px(drawX)-4, axisxpx+this.textsize/2+textHeight) - this.drawVisibleText('-'+txtX, this.x2px(-drawX)-4, axisxpx+this.textsize/2+textHeight) + this.drawVisibleText(txtX, this.x2px(drawX) - 4, axisxpx + this.textsize / 2 + textHeight) + this.drawVisibleText("-" + txtX, this.x2px(-drawX) - 4, axisxpx + this.textsize / 2 + textHeight) } } } if(this.showygrad) { for(let y = 0; y < this.axesSteps.y.maxDraw; y += 1) { - let drawY = y*this.axesSteps.y.value - let txtY = this.axesSteps.y.expression.simplify(y).toString().replace(/^\((.+)\)$/, '$1') + let drawY = y * this.axesSteps.y.value + let txtY = this.axesSteps.y.expression.simplify(y).toString().replace(/^\((.+)\)$/, "$1") textWidth = this._ctx.measureText(txtY).width - this.drawVisibleText(txtY, axisypx-6-textWidth, this.y2px(drawY)+4+(10*(y===0))) + this.drawVisibleText(txtY, axisypx - 6 - textWidth, this.y2px(drawY) + 4 + (10 * (y === 0))) if(y !== 0) - this.drawVisibleText('-'+txtY, axisypx-6-textWidth-txtMinus, this.y2px(-drawY)+4) + this.drawVisibleText("-" + txtY, axisypx - 6 - textWidth - txtMinus, this.y2px(-drawY) + 4) } } this._ctx.fillStyle = "#FFFFFF" @@ -348,7 +426,7 @@ class CanvasAPI extends Module { drawVisibleText(text, x, y) { if(x > 0 && x < this.width && y > 0 && y < this.height) { text.toString().split("\n").forEach((txt, i) => { - this._ctx.fillText(txt, x, y+(this.textsize*i)) + this._ctx.fillText(txt, x, y + (this.textsize * i)) }) } } @@ -363,7 +441,7 @@ class CanvasAPI extends Module { * @param {number} height */ drawVisibleImage(image, x, y, width, height) { - this._canvas.markDirty(Qt.rect(x, y, width, height)); + this._canvas.markDirty(Qt.rect(x, y, width, height)) this._ctx.drawImage(image, x, y, width, height) } @@ -380,7 +458,7 @@ class CanvasAPI extends Module { theight += defaultHeight if(this._ctx.measureText(txt).width > twidth) twidth = this._ctx.measureText(txt).width } - return {'width': twidth, 'height': theight} + return { "width": twidth, "height": theight } } /** @@ -392,9 +470,9 @@ class CanvasAPI extends Module { x2px(x) { if(this.logscalex) { const logxmin = Math.log(this.xmin) - return (Math.log(x)-logxmin)*this.xzoom + return (Math.log(x) - logxmin) * this.xzoom } else - return (x - this.xmin)*this.xzoom + return (x - this.xmin) * this.xzoom } /** @@ -415,9 +493,9 @@ class CanvasAPI extends Module { */ px2x(px) { if(this.logscalex) { - return Math.exp(px/this.xzoom+Math.log(this.xmin)) + return Math.exp(px / this.xzoom + Math.log(this.xmin)) } else - return (px/this.xzoom+this.xmin) + return (px / this.xzoom + this.xmin) } /** @@ -427,7 +505,7 @@ class CanvasAPI extends Module { * @returns {number} */ px2y(px) { - return -(px/this.yzoom-this.ymax) + return -(px / this.yzoom - this.ymax) } /** @@ -448,10 +526,10 @@ class CanvasAPI extends Module { * @param {number} y2 */ drawLine(x1, y1, x2, y2) { - this._ctx.beginPath(); - this._ctx.moveTo(x1, y1); - this._ctx.lineTo(x2, y2); - this._ctx.stroke(); + this._ctx.beginPath() + this._ctx.moveTo(x1, y1) + this._ctx.lineTo(x2, y2) + this._ctx.stroke() } /** @@ -463,9 +541,9 @@ class CanvasAPI extends Module { * @param {number} dashPxSize */ drawDashedLine(x1, y1, x2, y2, dashPxSize = 6) { - this._ctx.setLineDash([dashPxSize/2, dashPxSize]); + this._ctx.setLineDash([dashPxSize / 2, dashPxSize]) this.drawLine(x1, y1, x2, y2) - this._ctx.setLineDash([]); + this._ctx.setLineDash([]) } /** @@ -476,7 +554,7 @@ class CanvasAPI extends Module { */ renderLatexImage(ltxText, color, callback) { const onRendered = (imgData) => { - if(!this._canvas.isImageLoaded(imgData.source) && !this._canvas.isImageLoading(imgData.source)){ + if(!this._canvas.isImageLoaded(imgData.source) && !this._canvas.isImageLoading(imgData.source)) { // Wait until the image is loaded to callback. this._canvas.loadImage(imgData.source) this._canvas.imageLoaders[imgData.source] = [callback, imgData] @@ -496,8 +574,13 @@ class CanvasAPI extends Module { // Context methods // - get font() { return this._ctx.font } - set font(value) { return this._ctx.font = value } + get font() { + return this._ctx.font + } + + set font(value) { + return this._ctx.font = value + } /** * Draws an act on the canvas centered on a point. @@ -508,7 +591,7 @@ class CanvasAPI extends Module { * @param {number} endAngle * @param {boolean} counterclockwise */ - arc(x, y, radius, startAngle, endAngle, counterclockwise=false) { + arc(x, y, radius, startAngle, endAngle, counterclockwise = false) { this._ctx.beginPath() this._ctx.arc(x, y, radius, startAngle, endAngle, counterclockwise) this._ctx.stroke() @@ -521,9 +604,9 @@ class CanvasAPI extends Module { * @param {number} radius */ disc(x, y, radius) { - this._ctx.beginPath(); + this._ctx.beginPath() this._ctx.arc(x, y, radius, 0, 2 * Math.PI) - this._ctx.fill(); + this._ctx.fill() } /** diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/common.mjs b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/common.mjs index 1b68b89..9cd7bef 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/common.mjs +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/common.mjs @@ -24,22 +24,44 @@ export class Module { /** * * @param {string} name - Name of the API - * @param {(Module|undefined)[]} requires - List of APIs required to initialize this one. + * @param {Object.|string[]|string|object)>} initializationParameters - List of parameters for the initialize function. */ - constructor(name, requires = []) { + constructor(name, initializationParameters = {}) { console.log(`Loading module ${name}...`) - this.__check_requirements(requires, name) + this.__name = name + this.__initializationParameters = initializationParameters + this.initialized = false } /** * Checks if all requirements are defined. - * @param {(Module|undefined)[]} requires - * @param {string} name + * @param {Object.} options */ - __check_requirements(requires, name) { - for(let requirement of requires) { - if(requirement === undefined) - throw new Error(`Requirement ${requires.indexOf(requirement)} of ${name} has not been initialized.`) + initialize(options) { + if(this.initialized) + throw new Error(`Cannot reinitialize module ${this.__name}.`) + for(const [name, value] of Object.entries(this.__initializationParameters)) { + if(!options.hasOwnProperty(name)) + throw new Error(`Option '${name}' of initialize of module ${this.__name} does not exist.`) + if(typeof value === "object") { + if(value instanceof Array) + for(const k in value) + if(!options[name].hasOwnProperty(k)) + throw new Error(`Option '${name}' of initialize of module ${this.__name} does not have the property '${k}'.`) + else + for(const [k, v] in Object.entries(value)) { + if(!options[name].hasOwnProperty(k)) + throw new Error(`Option '${name} of initialize of module ${this.__name} does not have the property '${k}'.`) + else if(typeof (v) === "string" && typeof (options[name][k]) !== v) + throw new Error(`Property '${k}' of initialize option ${name} of module ${this.__name}'s type is not '${v}'.`) + else if(typeof (v) === "object" && !(options[name][k] instanceof v)) + throw new Error(`Property '${k}' of initialize option ${name} of module ${this.__name} is not a '${v}'.`) + } + + + } else if(typeof value === "string" && typeof options[name] !== value) + throw new Error(`Option '${name}' of initialize of module ${this.__name} is not a '${value}' (${typeof options[name]}).`) } + this.initialized = true } } \ No newline at end of file diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/expreval.mjs b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/expreval.mjs index 5ac849e..cc61434 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/expreval.mjs +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/expreval.mjs @@ -36,10 +36,7 @@ const evalVariables = { export class ExprParserAPI extends Module { constructor() { - super("ExprParser", [ - /** @type {ObjectsAPI} */ - Modules.Objects - ]) + super("ExprParser") this.currentVars = {} this._parser = new Parser() diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/history.mjs b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/history.mjs index 27eedcb..f773402 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/history.mjs +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/history.mjs @@ -22,25 +22,67 @@ import Latex from "./latex.mjs" class HistoryAPI extends Module { constructor() { - super('History', [ - Modules.Latex - ]) + super("History", { + historyObj: { + undo: Function, + redo: Function, + clear: Function, + addToHistory: Function, + unserialize: Function, + serialize: Function + }, + themeTextColor: "string", + imageDepth: "number", + fontSize: "number" + }) // History QML object - this.history = null; - this.themeTextColor = "#ff0000"; - this.imageDepth = 2; - this.fontSize = 14; + this.history = null + this.themeTextColor = "#FF0000" + this.imageDepth = 2 + this.fontSize = 28 } - undo() { this.history.undo() } - redo() { this.history.redo() } - clear() { this.history.clear() } - addToHistory(action) { this.history.addToHistory(action) } - unserialize(...data) { this.history.unserialize(...data) } - serialize() { return this.history.serialize() } + initialize({ historyObj, themeTextColor, imageDepth, fontSize }) { + super.initialize({ historyObj, themeTextColor, imageDepth, fontSize }) + console.log("Initializing history...") + this.history = historyObj + this.themeTextColor = themeTextColor + this.imageDepth = imageDepth + this.fontSize = fontSize + } + + undo() { + if(!this.initialized) throw new Error("Attempting undo before initialize!") + this.history.undo() + } + + redo() { + if(!this.initialized) throw new Error("Attempting redo before initialize!") + this.history.redo() + } + + clear() { + if(!this.initialized) throw new Error("Attempting clear before initialize!") + this.history.clear() + } + + addToHistory(action) { + if(!this.initialized) throw new Error("Attempting addToHistory before initialize!") + this.history.addToHistory(action) + } + + unserialize(...data) { + if(!this.initialized) throw new Error("Attempting unserialize before initialize!") + this.history.unserialize(...data) + } + + serialize() { + if(!this.initialized) throw new Error("Attempting serialize before initialize!") + return this.history.serialize() + } } /** @type {HistoryAPI} */ Modules.History = Modules.History || new HistoryAPI() -export default Modules.History \ No newline at end of file +export default Modules.History diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/io.mjs b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/io.mjs index bc9a1db..9a9d893 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/io.mjs +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/io.mjs @@ -21,13 +21,55 @@ import Objects from "./objects.mjs" import History from "./history.mjs" import Canvas from "./canvas.mjs" +/** + * @typedef Settings + * @property {number} width + * @property {number} height + * @property {number} xmin + * @property {number} ymax + * @property {number} xzoom + * @property {number} yzoom + * @property {number} xaxisstep + * @property {number} yaxisstep + * @property {string} xlabel + * @property {string} ylabel + * @property {number} linewidth + * @property {number} textsize + * @property {boolean} logscalex + * @property {boolean} showxgrad + * @property {boolean} showygrad + */ + class IOAPI extends Module { constructor() { - super("IO", [ - Modules.Objects, - Modules.History - ]) + super("IO", { + root: { + width: "number", + height: "number", + updateObjectsLists: Function, + }, + alert: { + show: Function + }, + settings: { + width: "number", + height: "number", + xmin: "number", + ymax: "number", + xzoom: "number", + yzoom: "number", + xaxisstep: "number", + yaxisstep: "number", + xlabel: "string", + ylabel: "string", + linewidth: "number", + textsize: "number", + logscalex: "boolean", + showxgrad: "boolean", + showygrad: "boolean" + } + }) /** * Path of the currently opened file. Empty if no file is opened. * @type {string} @@ -37,12 +79,13 @@ class IOAPI extends Module { /** * Initializes module with QML elements. - * @param {{width: number, height: number, updateObjectsLists: function()}} rootElement + * @param {{width: number, height: number, updateObjectsLists: function()}} root * @param {Settings} settings * @param {{show: function(string)}} alert */ - initialize(rootElement, settings, alert) { - this.rootElement = rootElement + initialize({ root, settings, alert }) { + super.initialize({ root, settings, alert }) + this.rootElement = root this.settings = settings this.alert = alert } @@ -52,6 +95,7 @@ class IOAPI extends Module { * @param {string} filename */ saveDiagram(filename) { + if(!this.initialized) throw new Error("Attempting saveDiagram before initialize!") // Add extension if necessary if(["lpf"].indexOf(filename.split(".")[filename.split(".").length - 1]) === -1) filename += ".lpf" @@ -93,11 +137,13 @@ class IOAPI extends Module { * @param {string} filename */ loadDiagram(filename) { + if(!this.initialized) throw new Error("Attempting loadDiagram before initialize!") + if(!History.initialized) throw new Error("Attempting loadDiagram before history is initialized!") let basename = filename.split("/").pop() this.alert.show(qsTranslate("io", "Loading file '%1'.").arg(basename)) let data = JSON.parse(Helper.load(filename)) let error = "" - if(Object.keys(data).includes("type") && data["type"] === "logplotv1") { + if(data.hasOwnProperty("type") && data["type"] === "logplotv1") { History.clear() // Importing settings this.settings.saveFilename = filename @@ -129,7 +175,7 @@ class IOAPI extends Module { // Another way would be to change the reference as well, but I feel like the code would be less clean. } for(let objType in data["objects"]) { - if(Object.keys(Objects.types).indexOf(objType) > -1) { + if(Object.keys(Objects.types).includes(objType)) { Objects.currentObjects[objType] = [] for(let objData of data["objects"][objType]) { /** @type {DrawableObject} */ @@ -157,7 +203,7 @@ class IOAPI extends Module { } if(error !== "") { console.log(error) - this.alert.show(qsTranslate("io", "Could not save file: ") + error) + this.alert.show(qsTranslate("io", "Could not load file: ") + error) // TODO: Error handling return } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/latex.mjs b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/latex.mjs index 32f048b..f2e9b0b 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/latex.mjs +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/latex.mjs @@ -58,10 +58,7 @@ class LatexRenderResult { class LatexAPI extends Module { constructor() { - super("Latex", [ - /** @type {ExprParserAPI} */ - Modules.ExprParser - ]) + super("Latex") /** * true if latex has been enabled by the user, false otherwise. */ diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/preferences.mjs b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/preferences.mjs index e76596e..389a5ba 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/preferences.mjs +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/preferences.mjs @@ -22,10 +22,7 @@ import DefaultGraph from "../preferences/default.mjs" class PreferencesAPI extends Module { constructor() { - super('Preferences', [ - Modules.Canvas, - Modules.Latex - ]) + super('Preferences') this.categories = { [QT_TRANSLATE_NOOP('settingCategory', 'general')]: General,