diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml index 85abbc7..e1e527d 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/History/History.qml @@ -212,11 +212,8 @@ Item { } Component.onCompleted: { - Modules.History.initialize({ - historyObj, - themeTextColor: sysPalette.windowText.toString(), - imageDepth: Screen.devicePixelRatio, - fontSize: 14 - }) + Modules.History.history = historyObj + Modules.History.themeTextColor = sysPalette.windowText + Modules.History.imageDepth = Screen.devicePixelRatio } } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml index e54781f..4159497 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/LogGraphCanvas.qml @@ -120,6 +120,12 @@ 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. @@ -133,14 +139,14 @@ Canvas { Component.onCompleted: { imageLoaders = {} - Modules.Canvas.initialize({ canvas, drawingErrorDialog }) + Modules.Canvas.initialize(canvas, drawingErrorDialog) } Native.MessageDialog { id: drawingErrorDialog title: qsTranslate("expression", "LogarithmPlotter - Drawing error") text: "" - function show(objType, objName, error) { + function showDialog(objType, objName, error) { text = qsTranslate("error", "Error while attempting to draw %1 %2:\n%3\n\nUndoing last change.").arg(objType).arg(objName).arg(error) open() } diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Settings.qml b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Settings.qml index 3c6e994..c94bef1 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 04abf68..020ff88 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/canvas.mjs +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/canvas.mjs @@ -17,28 +17,30 @@ */ import { Module } from "./common.mjs" -import { FUNCTION, Interface, CanvasInterface, DialogInterface } from "./interface.mjs" import { textsup } from "../utils.mjs" import { Expression } from "../math/index.mjs" import Latex from "./latex.mjs" import Objects from "./objects.mjs" import History from "./history.mjs" -class CanvasAPI extends Module { - constructor() { - super("Canvas", { - canvas: CanvasInterface, - drawingErrorDialog: DialogInterface - }) - /** @type {CanvasInterface} */ +class CanvasAPI extends Module { + + constructor() { + super('Canvas', [ + Modules.Objects, + Modules.History + ]) + + /** @type {HTMLCanvasElement} */ this._canvas = null /** @type {CanvasRenderingContext2D} */ this._ctx = null /** - * @type {{show(string, string, string)}} + * @type {Object} + * @property {function(string, string, string)} showDialog * @private */ this._drawingErrorDialog = null @@ -60,132 +62,86 @@ class CanvasAPI extends Module { } } - /** - * Initialize the module. - * @param {CanvasInterface} canvas - * @param {{show(string, string, string)}} drawingErrorDialog - */ - initialize({ canvas, drawingErrorDialog }) { - super.initialize({ canvas, drawingErrorDialog }) - this._canvas = canvas + initialize(canvasObject, drawingErrorDialog) { + this._canvas = canvasObject this._drawingErrorDialog = drawingErrorDialog } - get width() { - if(!this.initialized) throw new Error("Attempting width before initialize!") - return this._canvas.width - } + get width() { return this._canvas.width } - get height() { - if(!this.initialized) throw new Error("Attempting height before initialize!") - return this._canvas.height - } + get height() { return this._canvas.height } /** * Minimum x of the diagram, provided from settings. * @returns {number} */ - get xmin() { - if(!this.initialized) throw new Error("Attempting xmin before initialize!") - return this._canvas.xmin - } + get xmin() { return this._canvas.xmin } /** * Zoom on the x-axis of the diagram, provided from settings. * @returns {number} */ - get xzoom() { - if(!this.initialized) throw new Error("Attempting xzoom before initialize!") - return this._canvas.xzoom - } + get xzoom() { return this._canvas.xzoom } /** * Maximum y of the diagram, provided from settings. * @returns {number} */ - get ymax() { - if(!this.initialized) throw new Error("Attempting ymax before initialize!") - return this._canvas.ymax - } + get ymax() { return this._canvas.ymax } /** * Zoom on the y-axis of the diagram, provided from settings. * @returns {number} */ - get yzoom() { - if(!this.initialized) throw new Error("Attempting yzoom before initialize!") - return this._canvas.yzoom - } + get yzoom() { return this._canvas.yzoom } /** * Label used on the x-axis, provided from settings. * @returns {string} */ - get xlabel() { - if(!this.initialized) throw new Error("Attempting xlabel before initialize!") - return this._canvas.xlabel - } + get xlabel() { return this._canvas.xlabel } /** * Label used on the y-axis, provided from settings. * @returns {string} */ - get ylabel() { - if(!this.initialized) throw new Error("Attempting ylabel before initialize!") - return this._canvas.ylabel - } + get ylabel() { return this._canvas.ylabel } /** * Width of lines that will be drawn into the canvas, provided from settings. * @returns {number} */ - get linewidth() { - if(!this.initialized) throw new Error("Attempting linewidth before initialize!") - return this._canvas.linewidth - } + get linewidth() { return this._canvas.linewidth } /** * Font size of the text that will be drawn into the canvas, provided from settings. * @returns {number} */ - get textsize() { - if(!this.initialized) throw new Error("Attempting textsize before initialize!") - return this._canvas.textsize - } + get textsize() { return this._canvas.textsize } /** * True if the canvas should be in logarithmic mode, false otherwise. * @returns {boolean} */ - get logscalex() { - if(!this.initialized) throw new Error("Attempting logscalex before initialize!") - return this._canvas.logscalex - } + get logscalex() { return this._canvas.logscalex } /** * True if the x graduation should be shown, false otherwise. * @returns {boolean} */ - get showxgrad() { - if(!this.initialized) throw new Error("Attempting showxgrad before initialize!") - return this._canvas.showxgrad - } + get showxgrad() { return this._canvas.showxgrad } /** * True if the y graduation should be shown, false otherwise. * @returns {boolean} */ - get showygrad() { - if(!this.initialized) throw new Error("Attempting showygrad before initialize!") - return this._canvas.showygrad - } + get showygrad() { 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( @@ -200,7 +156,6 @@ class CanvasAPI extends Module { // requestPaint() { - if(!this.initialized) throw new Error("Attempting requestPaint before initialize!") this._canvas.requestPaint() } @@ -208,7 +163,6 @@ 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() @@ -217,7 +171,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) @@ -248,12 +202,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) } } } @@ -262,14 +216,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 @@ -279,18 +233,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) } } @@ -306,10 +260,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) } /** @@ -322,38 +276,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" @@ -394,7 +348,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)) }) } } @@ -409,7 +363,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) } @@ -426,7 +380,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} } /** @@ -438,9 +392,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 } /** @@ -461,9 +415,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) } /** @@ -473,7 +427,7 @@ class CanvasAPI extends Module { * @returns {number} */ px2y(px) { - return -(px / this.yzoom - this.ymax) + return -(px/this.yzoom-this.ymax) } /** @@ -494,10 +448,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(); } /** @@ -509,9 +463,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([]); } /** @@ -522,7 +476,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] @@ -542,13 +496,8 @@ 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. @@ -559,7 +508,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() @@ -572,9 +521,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 6902745..1b68b89 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/common.mjs +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/common.mjs @@ -16,8 +16,6 @@ * along with this program. If not, see . */ -import { Interface } from "./interface.mjs" - /** * Base class for global APIs in runtime. */ @@ -26,30 +24,22 @@ export class Module { /** * * @param {string} name - Name of the API - * @param {Object.} initializationParameters - List of parameters for the initialize function. + * @param {(Module|undefined)[]} requires - List of APIs required to initialize this one. */ - constructor(name, initializationParameters = {}) { + constructor(name, requires = []) { console.log(`Loading module ${name}...`) - this.__name = name - this.__initializationParameters = initializationParameters - this.initialized = false + this.__check_requirements(requires, name) } /** * Checks if all requirements are defined. - * @param {Object.} options + * @param {(Module|undefined)[]} requires + * @param {string} name */ - 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 === "function" && value.prototype instanceof Interface) - Interface.check_implementation(value, options[name]) - else if(typeof value !== typeof options[name]) - throw new Error(`Option '${name}' of initialize of module ${this.__name} is not a '${value}' (${typeof options[name]}).`) + __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.`) } - 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 cc61434..5ac849e 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/expreval.mjs +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/expreval.mjs @@ -36,7 +36,10 @@ const evalVariables = { export class ExprParserAPI extends Module { constructor() { - super("ExprParser") + super("ExprParser", [ + /** @type {ObjectsAPI} */ + Modules.Objects + ]) 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 09b45d6..27eedcb 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/history.mjs +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/history.mjs @@ -18,65 +18,29 @@ import { Module } from "./common.mjs" import Latex from "./latex.mjs" -import { HistoryInterface, NUMBER, STRING } from "./interface.mjs" class HistoryAPI extends Module { constructor() { - super("History", { - historyObj: HistoryInterface, - themeTextColor: STRING, - imageDepth: NUMBER, - fontSize: NUMBER - }) + super('History', [ + Modules.Latex + ]) // History QML object - this.history = null - this.themeTextColor = "#FF0000" - this.imageDepth = 2 - this.fontSize = 28 + this.history = null; + this.themeTextColor = "#ff0000"; + this.imageDepth = 2; + this.fontSize = 14; } - 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() - } + 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() } } /** @type {HistoryAPI} */ Modules.History = Modules.History || new HistoryAPI() -export default Modules.History +export default Modules.History \ No newline at end of file diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/interface.mjs b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/interface.mjs deleted file mode 100644 index 9da3f4d..0000000 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/interface.mjs +++ /dev/null @@ -1,130 +0,0 @@ -/** - * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions. - * Copyright (C) 2021-2024 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 . - */ - -export const NUMBER = 0 -export const STRING = "string" -export const BOOLEAN = true -export const OBJECT = {} -export const FUNCTION = () => { -} - - -export class Interface { - /** - * Checks if the class to check implements the given interface. - * Throws an error if the implementation does not conform to the interface. - * @param {typeof Interface} interface_ - * @param {object} classToCheck - * @return {boolean} - */ - static check_implementation(interface_, classToCheck) { - const properties = new interface_() - const interfaceName = interface_.name - const toCheckName = classToCheck.constructor.name - for(const [property, value] of Object.entries(properties)) - if(property !== "implement") { - console.log(classToCheck[property], value) - if(!classToCheck.hasOwnProperty(property)) - // Check if the property exist - throw new Error(`Property '${property}' (${typeof value}) is present in interface ${interfaceName}, but not in implementation ${toCheckName}.`) - else if((typeof value) !== (typeof classToCheck[property])) - // Compare the types - throw new Error(`Property '${property}' of ${interfaceName} implementation ${toCheckName} is a '${typeof classToCheck[property]}' and not a '${typeof value}'.`) - else if((typeof value) === "object") - // Test type of object. - if(value instanceof Interface) - Interface.check_implementation(value, classToCheck[property]) - else if(value.prototype && !(classToCheck[property] instanceof value)) - throw new Error(`Property '${property}' of ${interfaceName} implementation ${toCheckName} is not '${value.constructor.name}'.`) - } - } - - /** - * Decorator to automatically check if a class conforms to the current interface. - * @param {object} class_ - */ - implement(class_) { - Interface.check_implementation(this, class_) - return class_ - } -} - - -export class SettingsInterface extends Interface { - constructor() { - super() - this.width = NUMBER - this.height = NUMBER - this.xmin = NUMBER - this.ymax = NUMBER - this.xzoom = NUMBER - this.yzoom = NUMBER - this.xaxisstep = STRING - this.yaxisstep = STRING - this.xlabel = STRING - this.ylabel = STRING - this.linewidth = NUMBER - this.textsize = NUMBER - this.logscalex = BOOLEAN - this.showxgrad = BOOLEAN - this.showygrad = BOOLEAN - } -} - -export class CanvasInterface extends SettingsInterface { - constructor() { - super() - this.imageLoaders = OBJECT - /** @type {function(string): CanvasRenderingContext2D} */ - this.getContext = FUNCTION - /** @type {function(rect)} */ - this.markDirty = FUNCTION - /** @type {function(string)} */ - this.loadImage = FUNCTION - /** @type {function()} */ - this.requestPaint = FUNCTION - } -} - -export class RootInterface extends Interface { - constructor() { - super() - this.width = NUMBER - this.height = NUMBER - this.updateObjectsLists = FUNCTION - } -} - -export class DialogInterface extends Interface { - constructor() { - super() - this.show = FUNCTION - } -} - -export class HistoryInterface extends Interface { - constructor() { - super() - this.undo = FUNCTION - this.redo = FUNCTION - this.clear = FUNCTION - this.addToHistory = FUNCTION - this.unserialize = FUNCTION - this.serialize = FUNCTION - } -} \ No newline at end of file diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/io.mjs b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/io.mjs index 2a540a7..bc9a1db 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/io.mjs +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/io.mjs @@ -20,17 +20,14 @@ import { Module } from "./common.mjs" import Objects from "./objects.mjs" import History from "./history.mjs" import Canvas from "./canvas.mjs" -import { DialogInterface, FUNCTION, Interface, RootInterface, SettingsInterface } from "./interface.mjs" - class IOAPI extends Module { constructor() { - super("IO", { - alert: DialogInterface, - root: RootInterface, - settings: SettingsInterface - }) + super("IO", [ + Modules.Objects, + Modules.History + ]) /** * Path of the currently opened file. Empty if no file is opened. * @type {string} @@ -40,13 +37,12 @@ class IOAPI extends Module { /** * Initializes module with QML elements. - * @param {RootInterface} root - * @param {SettingsInterface} settings + * @param {{width: number, height: number, updateObjectsLists: function()}} rootElement + * @param {Settings} settings * @param {{show: function(string)}} alert */ - initialize({ root, settings, alert }) { - super.initialize({ root, settings, alert }) - this.rootElement = root + initialize(rootElement, settings, alert) { + this.rootElement = rootElement this.settings = settings this.alert = alert } @@ -56,7 +52,6 @@ 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" @@ -98,13 +93,11 @@ 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(data.hasOwnProperty("type") && data["type"] === "logplotv1") { + if(Object.keys(data).includes("type") && data["type"] === "logplotv1") { History.clear() // Importing settings this.settings.saveFilename = filename @@ -136,7 +129,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).includes(objType)) { + if(Object.keys(Objects.types).indexOf(objType) > -1) { Objects.currentObjects[objType] = [] for(let objData of data["objects"][objType]) { /** @type {DrawableObject} */ @@ -164,7 +157,7 @@ class IOAPI extends Module { } if(error !== "") { console.log(error) - this.alert.show(qsTranslate("io", "Could not load file: ") + error) + this.alert.show(qsTranslate("io", "Could not save 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 f2e9b0b..32f048b 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/latex.mjs +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/latex.mjs @@ -58,7 +58,10 @@ class LatexRenderResult { class LatexAPI extends Module { constructor() { - super("Latex") + super("Latex", [ + /** @type {ExprParserAPI} */ + Modules.ExprParser + ]) /** * 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 389a5ba..e76596e 100644 --- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/preferences.mjs +++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/module/preferences.mjs @@ -22,7 +22,10 @@ import DefaultGraph from "../preferences/default.mjs" class PreferencesAPI extends Module { constructor() { - super('Preferences') + super('Preferences', [ + Modules.Canvas, + Modules.Latex + ]) this.categories = { [QT_TRANSLATE_NOOP('settingCategory', 'general')]: General,