Compare commits

...

3 commits

Author SHA1 Message Date
54363b25bc
Fixing issue with Replace All when replacement string includes source string.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-10 23:56:42 +02:00
52f859349a
Converting actual settings to new Settings module. 2024-10-10 23:28:25 +02:00
d1ac70a946
Switching a lot of stuff to new Settings module
+ Fixing a bug that did not load the showygrad setting properly.
2024-10-10 19:15:46 +02:00
17 changed files with 319 additions and 302 deletions

View file

@ -38,7 +38,7 @@ export class BaseEvent {
export class BaseEventEmitter { export class BaseEventEmitter {
static emits = [] static emits = []
/** @type {Record<string, function[]>} */ /** @type {Record<string, Set<function>>} */
#listeners = {} #listeners = {}
constructor() { constructor() {
@ -53,8 +53,8 @@ export class BaseEventEmitter {
* @param {string} eventType - Name of the event to listen to. Throws an error if this object does not emit this kind of event. * @param {string} eventType - Name of the event to listen to. Throws an error if this object does not emit this kind of event.
* @param {function(BaseEvent)} eventListener - The function to be called back when the event is emitted. * @param {function(BaseEvent)} eventListener - The function to be called back when the event is emitted.
*/ */
addEventListener(eventType, eventListener) { on(eventType, eventListener) {
if(!this.emits.includes(eventType)) { if(!this.constructor.emits.includes(eventType)) {
const className = this.constructor.name const className = this.constructor.name
const eventTypes = this.constructor.emits.join(", ") const eventTypes = this.constructor.emits.join(", ")
throw new Error(`Cannot listen to unknown event ${eventType} in class ${className}. ${className} only emits: ${eventTypes}`) throw new Error(`Cannot listen to unknown event ${eventType} in class ${className}. ${className} only emits: ${eventTypes}`)
@ -70,14 +70,13 @@ export class BaseEventEmitter {
* @param {function(BaseEvent)} eventListener - The function previously registered as a listener. * @param {function(BaseEvent)} eventListener - The function previously registered as a listener.
* @returns {boolean} True if the listener was removed, false if it was not found. * @returns {boolean} True if the listener was removed, false if it was not found.
*/ */
removeEventListener(eventType, eventListener) { off(eventType, eventListener) {
if(!this.emits.includes(eventType)) { if(!this.constructor.emits.includes(eventType)) {
const className = this.constructor.name const className = this.constructor.name
const eventTypes = this.constructor.emits.join(", ") const eventTypes = this.constructor.emits.join(", ")
throw new Error(`Cannot listen to unknown event ${eventType} in class ${className}. ${className} only emits: ${eventTypes}`) throw new Error(`Cannot listen to unknown event ${eventType} in class ${className}. ${className} only emits: ${eventTypes}`)
} }
return this.#listeners[eventType].delete(eventListener) return this.#listeners[eventType].delete(eventListener)
} }
/** /**
@ -88,8 +87,11 @@ export class BaseEventEmitter {
emit(e) { emit(e) {
if(!(e instanceof BaseEvent)) if(!(e instanceof BaseEvent))
throw new Error("Cannot emit non event object.") throw new Error("Cannot emit non event object.")
if(!this.emits.includes(e.name)) if(!this.constructor.emits.includes(e.name)) {
throw new Error(`Cannot emit event '${e.name}' from class ${this.constructor.name}. ${this.constructor.name} can only emits: ${this.constructor.emits.join(", ")}.`) const className = this.constructor.name
const eventTypes = this.constructor.emits.join(", ")
throw new Error(`Cannot emit event '${e.name}' from class ${className}. ${className} can only emit: ${eventTypes}`)
}
for(const listener of this.#listeners[e.name]) for(const listener of this.#listeners[e.name])
listener(e) listener(e)
} }

View file

@ -64,10 +64,7 @@ function arrayFlatMap(callbackFn, thisArg) {
* @return {String} * @return {String}
*/ */
function stringReplaceAll(from, to) { function stringReplaceAll(from, to) {
let str = this return this.split(from).join(to)
while(str.includes(from))
str = str.replace(from, to)
return str
} }

View file

@ -23,6 +23,7 @@ import { Expression } from "../math/index.mjs"
import Latex from "./latex.mjs" import Latex from "./latex.mjs"
import Objects from "./objects.mjs" import Objects from "./objects.mjs"
import History from "./history.mjs" import History from "./history.mjs"
import Settings from "./settings.mjs"
class CanvasAPI extends Module { class CanvasAPI extends Module {
/** @type {CanvasInterface} */ /** @type {CanvasInterface} */
@ -84,7 +85,7 @@ class CanvasAPI extends Module {
*/ */
get xmin() { get xmin() {
if(!this.initialized) throw new Error("Attempting xmin before initialize!") if(!this.initialized) throw new Error("Attempting xmin before initialize!")
return this.#canvas.xmin return Settings.xmin
} }
/** /**
@ -93,7 +94,7 @@ class CanvasAPI extends Module {
*/ */
get xzoom() { get xzoom() {
if(!this.initialized) throw new Error("Attempting xzoom before initialize!") if(!this.initialized) throw new Error("Attempting xzoom before initialize!")
return this.#canvas.xzoom return Settings.xzoom
} }
/** /**
@ -102,7 +103,7 @@ class CanvasAPI extends Module {
*/ */
get ymax() { get ymax() {
if(!this.initialized) throw new Error("Attempting ymax before initialize!") if(!this.initialized) throw new Error("Attempting ymax before initialize!")
return this.#canvas.ymax return Settings.ymax
} }
/** /**
@ -111,7 +112,7 @@ class CanvasAPI extends Module {
*/ */
get yzoom() { get yzoom() {
if(!this.initialized) throw new Error("Attempting yzoom before initialize!") if(!this.initialized) throw new Error("Attempting yzoom before initialize!")
return this.#canvas.yzoom return Settings.yzoom
} }
/** /**
@ -120,7 +121,7 @@ class CanvasAPI extends Module {
*/ */
get xlabel() { get xlabel() {
if(!this.initialized) throw new Error("Attempting xlabel before initialize!") if(!this.initialized) throw new Error("Attempting xlabel before initialize!")
return this.#canvas.xlabel return Settings.xlabel
} }
/** /**
@ -129,7 +130,7 @@ class CanvasAPI extends Module {
*/ */
get ylabel() { get ylabel() {
if(!this.initialized) throw new Error("Attempting ylabel before initialize!") if(!this.initialized) throw new Error("Attempting ylabel before initialize!")
return this.#canvas.ylabel return Settings.ylabel
} }
/** /**
@ -138,7 +139,7 @@ class CanvasAPI extends Module {
*/ */
get linewidth() { get linewidth() {
if(!this.initialized) throw new Error("Attempting linewidth before initialize!") if(!this.initialized) throw new Error("Attempting linewidth before initialize!")
return this.#canvas.linewidth return Settings.linewidth
} }
/** /**
@ -147,7 +148,7 @@ class CanvasAPI extends Module {
*/ */
get textsize() { get textsize() {
if(!this.initialized) throw new Error("Attempting textsize before initialize!") if(!this.initialized) throw new Error("Attempting textsize before initialize!")
return this.#canvas.textsize return Settings.textsize
} }
/** /**
@ -156,7 +157,7 @@ class CanvasAPI extends Module {
*/ */
get logscalex() { get logscalex() {
if(!this.initialized) throw new Error("Attempting logscalex before initialize!") if(!this.initialized) throw new Error("Attempting logscalex before initialize!")
return this.#canvas.logscalex return Settings.logscalex
} }
/** /**
@ -165,7 +166,7 @@ class CanvasAPI extends Module {
*/ */
get showxgrad() { get showxgrad() {
if(!this.initialized) throw new Error("Attempting showxgrad before initialize!") if(!this.initialized) throw new Error("Attempting showxgrad before initialize!")
return this.#canvas.showxgrad return Settings.showxgrad
} }
/** /**
@ -174,7 +175,7 @@ class CanvasAPI extends Module {
*/ */
get showygrad() { get showygrad() {
if(!this.initialized) throw new Error("Attempting showygrad before initialize!") if(!this.initialized) throw new Error("Attempting showygrad before initialize!")
return this.#canvas.showygrad return Settings.showygrad
} }
/** /**
@ -237,9 +238,9 @@ class CanvasAPI extends Module {
* @private * @private
*/ */
_computeAxes() { _computeAxes() {
let exprY = new Expression(`x*(${this.#canvas.yaxisstep})`) let exprY = new Expression(`x*(${Settings.yaxisstep})`)
let y1 = exprY.execute(1) let y1 = exprY.execute(1)
let exprX = new Expression(`x*(${this.#canvas.xaxisstep})`) let exprX = new Expression(`x*(${Settings.xaxisstep})`)
let x1 = exprX.execute(1) let x1 = exprX.execute(1)
this.axesSteps = { this.axesSteps = {
x: { x: {

View file

@ -17,6 +17,7 @@
*/ */
import Objects from "./objects.mjs" import Objects from "./objects.mjs"
import Settings from "./settings.mjs"
import ExprParser from "./expreval.mjs" import ExprParser from "./expreval.mjs"
import Latex from "./latex.mjs" import Latex from "./latex.mjs"
import History from "./history.mjs" import History from "./history.mjs"
@ -26,6 +27,7 @@ import Preferences from "./preferences.mjs"
export default { export default {
Objects, Objects,
Settings,
ExprParser, ExprParser,
Latex, Latex,
History, History,

View file

@ -78,7 +78,7 @@ export class SettingsInterface extends Interface {
showygrad = BOOLEAN showygrad = BOOLEAN
} }
export class CanvasInterface extends SettingsInterface { export class CanvasInterface extends Interface {
imageLoaders = OBJECT imageLoaders = OBJECT
/** @type {function(string): CanvasRenderingContext2D} */ /** @type {function(string): CanvasRenderingContext2D} */
getContext = FUNCTION getContext = FUNCTION

View file

@ -20,22 +20,20 @@ import { Module } from "./common.mjs"
import Objects from "./objects.mjs" import Objects from "./objects.mjs"
import History from "./history.mjs" import History from "./history.mjs"
import Canvas from "./canvas.mjs" import Canvas from "./canvas.mjs"
import Settings from "./settings.mjs"
import { DialogInterface, RootInterface, SettingsInterface } from "./interface.mjs" import { DialogInterface, RootInterface, SettingsInterface } from "./interface.mjs"
class IOAPI extends Module { class IOAPI extends Module {
/** @type {RootInterface} */ /** @type {RootInterface} */
#rootElement #rootElement
/** @type {SettingsInterface} */
#settings
/** @type {{show: function(string)}} */ /** @type {{show: function(string)}} */
#alert #alert
constructor() { constructor() {
super("IO", { super("IO", {
alert: DialogInterface, alert: DialogInterface,
root: RootInterface, root: RootInterface
settings: SettingsInterface
}) })
/** /**
* Path of the currently opened file. Empty if no file is opened. * Path of the currently opened file. Empty if no file is opened.
@ -47,13 +45,11 @@ class IOAPI extends Module {
/** /**
* Initializes module with QML elements. * Initializes module with QML elements.
* @param {RootInterface} root * @param {RootInterface} root
* @param {SettingsInterface} settings
* @param {{show: function(string)}} alert * @param {{show: function(string)}} alert
*/ */
initialize({ root, settings, alert }) { initialize({ root, alert }) {
super.initialize({ root, settings, alert }) super.initialize({ root, alert })
this.#rootElement = root this.#rootElement = root
this.#settings = settings
this.#alert = alert this.#alert = alert
} }
@ -66,7 +62,7 @@ class IOAPI extends Module {
// Add extension if necessary // Add extension if necessary
if(["lpf"].indexOf(filename.split(".")[filename.split(".").length - 1]) === -1) if(["lpf"].indexOf(filename.split(".")[filename.split(".").length - 1]) === -1)
filename += ".lpf" filename += ".lpf"
this.saveFilename = filename Settings.set("saveFilename", filename, false)
let objs = {} let objs = {}
for(let objType in Objects.currentObjects) { for(let objType in Objects.currentObjects) {
objs[objType] = [] objs[objType] = []
@ -75,19 +71,19 @@ class IOAPI extends Module {
} }
} }
let settings = { let settings = {
"xzoom": this.#settings.xzoom, "xzoom": Settings.xzoom,
"yzoom": this.#settings.yzoom, "yzoom": Settings.yzoom,
"xmin": this.#settings.xmin, "xmin": Settings.xmin,
"ymax": this.#settings.ymax, "ymax": Settings.ymax,
"xaxisstep": this.#settings.xaxisstep, "xaxisstep": Settings.xaxisstep,
"yaxisstep": this.#settings.yaxisstep, "yaxisstep": Settings.yaxisstep,
"xaxislabel": this.#settings.xlabel, "xaxislabel": Settings.xlabel,
"yaxislabel": this.#settings.ylabel, "yaxislabel": Settings.ylabel,
"logscalex": this.#settings.logscalex, "logscalex": Settings.logscalex,
"linewidth": this.#settings.linewidth, "linewidth": Settings.linewidth,
"showxgrad": this.#settings.showxgrad, "showxgrad": Settings.showxgrad,
"showygrad": this.#settings.showygrad, "showygrad": Settings.showygrad,
"textsize": this.#settings.textsize, "textsize": Settings.textsize,
"history": History.serialize(), "history": History.serialize(),
"width": this.#rootElement.width, "width": this.#rootElement.width,
"height": this.#rootElement.height, "height": this.#rootElement.height,
@ -113,24 +109,24 @@ class IOAPI extends Module {
if(data.hasOwnProperty("type") && data["type"] === "logplotv1") { if(data.hasOwnProperty("type") && data["type"] === "logplotv1") {
History.clear() History.clear()
// Importing settings // Importing settings
this.#settings.saveFilename = filename Settings.set("saveFilename", filename, false)
this.#settings.xzoom = parseFloat(data["xzoom"]) || 100 Settings.set("xzoom", parseFloat(data["xzoom"]) || 100, false)
this.#settings.yzoom = parseFloat(data["yzoom"]) || 10 Settings.set("yzoom", parseFloat(data["yzoom"]) || 10, false)
this.#settings.xmin = parseFloat(data["xmin"]) || 5 / 10 Settings.set("xmin", parseFloat(data["xmin"]) || 5 / 10, false)
this.#settings.ymax = parseFloat(data["ymax"]) || 24 Settings.set("ymax", parseFloat(data["ymax"]) || 24, false)
this.#settings.xaxisstep = data["xaxisstep"] || "4" Settings.set("xaxisstep", data["xaxisstep"] || "4", false)
this.#settings.yaxisstep = data["yaxisstep"] || "4" Settings.set("yaxisstep", data["yaxisstep"] || "4", false)
this.#settings.xlabel = data["xaxislabel"] || "" Settings.set("xlabel", data["xaxislabel"] || "", false)
this.#settings.ylabel = data["yaxislabel"] || "" Settings.set("ylabel", data["yaxislabel"] || "", false)
this.#settings.logscalex = data["logscalex"] === true Settings.set("logscalex", data["logscalex"] === true, false)
if("showxgrad" in data) if("showxgrad" in data)
this.#settings.showxgrad = data["showxgrad"] Settings.set("showxgrad", data["showxgrad"], false)
if("showygrad" in data) if("showygrad" in data)
this.#settings.textsize = data["showygrad"] Settings.set("showygrad", data["showygrad"], false)
if("linewidth" in data) if("linewidth" in data)
this.#settings.linewidth = data["linewidth"] Settings.set("linewidth", data["linewidth"], false)
if("textsize" in data) if("textsize" in data)
this.#settings.textsize = data["textsize"] Settings.set("textsize", data["textsize"], false)
this.#rootElement.height = parseFloat(data["height"]) || 500 this.#rootElement.height = parseFloat(data["height"]) || 500
this.#rootElement.width = parseFloat(data["width"]) || 1000 this.#rootElement.width = parseFloat(data["width"]) || 1000

View file

@ -261,7 +261,7 @@ class LatexAPI extends Module {
throw new EvalError("Unknown operator " + item.value + ".") throw new EvalError("Unknown operator " + item.value + ".")
} }
break break
case Instruction.IOP3: // Thirdiary operator case Instruction.IOP3: // Ternary operator
n3 = nstack.pop() n3 = nstack.pop()
n2 = nstack.pop() n2 = nstack.pop()
n1 = nstack.pop() n1 = nstack.pop()

View file

@ -18,6 +18,7 @@
import { Module } from "./common.mjs" import { Module } from "./common.mjs"
import { BaseEvent } from "../events.mjs" import { BaseEvent } from "../events.mjs"
import { HelperInterface } from "./interface.mjs"
/** /**
@ -47,20 +48,23 @@ class ChangedEvent extends BaseEvent {
class SettingsAPI extends Module { class SettingsAPI extends Module {
static emits = ["changed"] static emits = ["changed"]
#nonConfigurable = ["saveFilename"]
#properties = new Map([ #properties = new Map([
['xzoom', 100], ["saveFilename", ""],
['yzoom', 10], ["xzoom", 100],
['xmin', .5], ["yzoom", 10],
['ymax', 25], ["xmin", .5],
['xaxisstep', "4"], ["ymax", 25],
['yaxisstep', "4"], ["xaxisstep", "4"],
['xlabel', ""], ["yaxisstep", "4"],
['ylabel', ""], ["xlabel", ""],
['linewidth', 1], ["ylabel", ""],
['textsize', 18], ["linewidth", 1],
['logscalex', true], ["textsize", 18],
['showxgrad', true], ["logscalex", true],
['showygrad', true], ["showxgrad", true],
["showygrad", true]
]) ])
constructor() { constructor() {
@ -73,32 +77,39 @@ class SettingsAPI extends Module {
super.initialize({ helper }) super.initialize({ helper })
// Initialize default values. // Initialize default values.
for(const key of this.#properties.keys()) { for(const key of this.#properties.keys()) {
switch(typeof this.#properties.get(key)) { if(!this.#nonConfigurable.includes(key)) {
case 'boolean': switch(typeof this.#properties.get(key)) {
this.set(key, helper.getSettingBool(key), false) case "boolean":
break this.set(key, helper.getSettingBool("default_graph."+key), false)
case 'number': break
this.set(key, helper.getSettingInt(key), false) case "number":
break this.set(key, helper.getSettingInt("default_graph."+key), false)
case 'string': break
this.set(key, helper.getSetting(key), false) case "string":
break this.set(key, helper.getSetting("default_graph."+key), false)
break
}
} }
} }
} }
/** /**
* Sets a setting to a given value * Sets a setting to a given value
* *
* @param {boolean} byUser - Set to true if the user is at the origin of this change. * @param {string} property
* @param {string|number|boolean} value
* @param {boolean} byUser - Set to true if the user is at the origin of this change.
*/ */
set(property, value, byUser) { set(property, value, byUser) {
if(!this.#properties.has(property)) if(!this.#properties.has(property)) {
throw new Error(`Property ${property} is not a setting.`) throw new Error(`Property ${property} is not a setting.`)
}
const oldValue = this.#properties.get(property) const oldValue = this.#properties.get(property)
const propType = typeof oldValue const propType = typeof oldValue
if(byUser)
console.debug("Setting", property, "from", oldValue, "to", value, `(${typeof value}, ${byUser})`)
if(propType !== typeof value) if(propType !== typeof value)
throw new Error(`Value of ${property} must be a ${propType}.`) throw new Error(`Value of ${property} must be a ${propType} (${typeof value} provided).`)
this.#properties.set(property, value) this.#properties.set(property, value)
this.emit(new ChangedEvent(property, oldValue, value, byUser === true)) this.emit(new ChangedEvent(property, oldValue, value, byUser === true))
} }
@ -107,67 +118,70 @@ class SettingsAPI extends Module {
* Zoom on the x axis of the diagram. * Zoom on the x axis of the diagram.
* @returns {number} * @returns {number}
*/ */
get xzoom() { return this.#properties.get("xzoom"); } get xzoom() { return this.#properties.get("xzoom") }
/** /**
* Zoom on the y axis of the diagram. * Zoom on the y axis of the diagram.
* @returns {number} * @returns {number}
*/ */
get yzoom() { return this.#properties.get("yzoom"); } get yzoom() { return this.#properties.get("yzoom") }
/** /**
* Minimum x of the diagram. * Minimum x of the diagram.
* @returns {number} * @returns {number}
*/ */
get xmin() { return this.#properties.get("xmin"); } get xmin() { return this.#properties.get("xmin") }
/** /**
* Maximum y of the diagram. * Maximum y of the diagram.
* @returns {number} * @returns {number}
*/ */
get ymax() { return this.#properties.get("ymax"); } get ymax() { return this.#properties.get("ymax") }
/** /**
* Step of the x axis graduation (expression). * Step of the x axis graduation (expression).
* @note Only available in non-logarithmic mode. * @note Only available in non-logarithmic mode.
* @returns {string} * @returns {string}
*/ */
get xaxisstep() { return this.#properties.get("xaxisstep"); } get xaxisstep() { return this.#properties.get("xaxisstep") }
/** /**
* Step of the y axis graduation (expression). * Step of the y axis graduation (expression).
* @returns {string} * @returns {string}
*/ */
get yaxisstep() { return this.#properties.get("yaxisstep"); } get yaxisstep() { return this.#properties.get("yaxisstep") }
/** /**
* Label used on the x axis. * Label used on the x axis.
* @returns {string} * @returns {string}
*/ */
get xlabel() { return this.#properties.get("xlabel"); } get xlabel() { return this.#properties.get("xlabel") }
/** /**
* Label used on the y axis. * Label used on the y axis.
* @returns {string} * @returns {string}
*/ */
get ylabel() { return this.#properties.get("ylabel"); } get ylabel() { return this.#properties.get("ylabel") }
/** /**
* Width of lines that will be drawn into the canvas. * Width of lines that will be drawn into the canvas.
* @returns {number} * @returns {number}
*/ */
get linewidth() { return this.#properties.get("linewidth"); } get linewidth() { return this.#properties.get("linewidth") }
/** /**
* Font size of the text that will be drawn into the canvas. * Font size of the text that will be drawn into the canvas.
* @returns {number} * @returns {number}
*/ */
get textsize() { return this.#properties.get("textsize"); } get textsize() { return this.#properties.get("textsize") }
/** /**
* true if the canvas should be in logarithmic mode, false otherwise. * true if the canvas should be in logarithmic mode, false otherwise.
* @returns {boolean} * @returns {boolean}
*/ */
get logscalex() { return this.#properties.get("logscalex"); } get logscalex() { return this.#properties.get("logscalex") }
/** /**
* true if the x graduation should be shown, false otherwise. * true if the x graduation should be shown, false otherwise.
* @returns {boolean} * @returns {boolean}
*/ */
get showxgrad() { return this.#properties.get("showxgrad"); } get showxgrad() { return this.#properties.get("showxgrad") }
/** /**
* true if the y graduation should be shown, false otherwise. * true if the y graduation should be shown, false otherwise.
* @returns {boolean} * @returns {boolean}
*/ */
get showygrad() { return this.#properties.get("showygrad"); } get showygrad() { return this.#properties.get("showygrad") }
} }
Modules.Settings = Modules.Settings || new SettingsAPI()
export default Modules.Settings

View file

@ -28,7 +28,7 @@ const XZOOM = new NumberSetting(
const YZOOM = new NumberSetting( const YZOOM = new NumberSetting(
qsTranslate("Settings", "Y Zoom"), qsTranslate("Settings", "Y Zoom"),
"default_graph.xzoom", "default_graph.yzoom",
"yzoom", "yzoom",
0.1 0.1
) )

View file

@ -35,6 +35,19 @@ String.prototype.removeEnclosure = function() {
return this.substring(1, this.length - 1) return this.substring(1, this.length - 1)
} }
/**
* Rounds to a certain number of decimal places.
* From https://stackoverflow.com/a/48764436
*
* @param {number} decimalPlaces
* @return {number}
*/
Number.prototype.toDecimalPrecision = function(decimalPlaces = 0) {
const p = Math.pow(10, decimalPlaces);
const n = (this * p) * (1 + Number.EPSILON);
return Math.round(n) / p;
}
const powerpos = { const powerpos = {
"-": "⁻", "-": "⁻",
"+": "⁺", "+": "⁺",

View file

@ -30,104 +30,15 @@ import Qt.labs.platform as Native
*/ */
Canvas { Canvas {
id: canvas id: canvas
anchors.top: separator.bottom anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
height: parent.height - 90 height: parent.height - 90
width: parent.width width: parent.width
/*!
\qmlproperty double LogGraphCanvas::xmin
Minimum x of the diagram, provided from settings.
\sa Settings
*/
property double xmin: 0
/*!
\qmlproperty double LogGraphCanvas::ymax
Maximum y of the diagram, provided from settings.
\sa Settings
*/
property double ymax: 0
/*!
\qmlproperty double LogGraphCanvas::xzoom
Zoom on the x axis of the diagram, provided from settings.
\sa Settings
*/
property double xzoom: 10
/*!
\qmlproperty double LogGraphCanvas::yzoom
Zoom on the y axis of the diagram, provided from settings.
\sa Settings
*/
property double yzoom: 10
/*!
\qmlproperty string LogGraphCanvas::xaxisstep
Step of the x axis graduation, provided from settings.
\note: Only available in non-logarithmic mode.
\sa Settings
*/
property string xaxisstep: "4"
/*!
\qmlproperty string LogGraphCanvas::yaxisstep
Step of the y axis graduation, provided from settings.
\sa Settings
*/
property string yaxisstep: "4"
/*!
\qmlproperty string LogGraphCanvas::xlabel
Label used on the x axis, provided from settings.
\sa Settings
*/
property string xlabel: ""
/*!
\qmlproperty string LogGraphCanvas::ylabel
Label used on the y axis, provided from settings.
\sa Settings
*/
property string ylabel: ""
/*!
\qmlproperty double LogGraphCanvas::linewidth
Width of lines that will be drawn into the canvas, provided from settings.
\sa Settings
*/
property double linewidth: 1
/*!
\qmlproperty double LogGraphCanvas::textsize
Font size of the text that will be drawn into the canvas, provided from settings.
\sa Settings
*/
property double textsize: 14
/*!
\qmlproperty bool LogGraphCanvas::logscalex
true if the canvas should be in logarithmic mode, false otherwise.
Provided from settings.
\sa Settings
*/
property bool logscalex: false
/*!
\qmlproperty bool LogGraphCanvas::showxgrad
true if the x graduation should be shown, false otherwise.
Provided from settings.
\sa Settings
*/
property bool showxgrad: false
/*!
\qmlproperty bool LogGraphCanvas::showygrad
true if the y graduation should be shown, false otherwise.
Provided from settings.
\sa Settings
*/
property bool showygrad: false
/*! /*!
\qmlproperty var LogGraphCanvas::imageLoaders \qmlproperty var LogGraphCanvas::imageLoaders
Dictionary of format {image: [callback.image data]} containing data for defered image loading. Dictionary of format {image: [callback.image data]} containing data for defered image loading.
*/ */
property var imageLoaders: {} property var imageLoaders: {}
/*!
\qmlproperty var LogGraphCanvas::ctx
Cache for the 2D context so that it may be used asynchronously.
*/
property var ctx
Component.onCompleted: { Component.onCompleted: {
imageLoaders = {} imageLoaders = {}
@ -155,7 +66,7 @@ Canvas {
Object.keys(imageLoaders).forEach((key) => { Object.keys(imageLoaders).forEach((key) => {
if(isImageLoaded(key)) { if(isImageLoaded(key)) {
// Calling callback // Calling callback
imageLoaders[key][0](canvas, ctx, imageLoaders[key][1]) imageLoaders[key][0](imageLoaders[key][1])
delete imageLoaders[key] delete imageLoaders[key]
} }
}) })

View file

@ -42,7 +42,7 @@ ApplicationWindow {
width: 1000 width: 1000
height: 500 height: 500
color: sysPalette.window color: sysPalette.window
title: "LogarithmPlotter " + (settings.saveFilename != "" ? " - " + settings.saveFilename.split('/').pop() : "") + (history.saved ? "" : "*") title: "LogarithmPlotter"
SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active } SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active }
SystemPalette { id: sysPaletteIn; colorGroup: SystemPalette.Disabled } SystemPalette { id: sysPaletteIn; colorGroup: SystemPalette.Disabled }
@ -145,20 +145,6 @@ ApplicationWindow {
width: sidebar.inPortrait ? parent.width : parent.width - sidebar.width//*sidebar.position width: sidebar.inPortrait ? parent.width : parent.width - sidebar.width//*sidebar.position
x: sidebar.width//*sidebar.position x: sidebar.width//*sidebar.position
xmin: settings.xmin
ymax: settings.ymax
xzoom: settings.xzoom
yzoom: settings.yzoom
xlabel: settings.xlabel
ylabel: settings.ylabel
yaxisstep: settings.yaxisstep
xaxisstep: settings.xaxisstep
logscalex: settings.logscalex
linewidth: settings.linewidth
textsize: settings.textsize
showxgrad: settings.showxgrad
showygrad: settings.showygrad
property bool firstDrawDone: false property bool firstDrawDone: false
onPainted: if(!firstDrawDone) { onPainted: if(!firstDrawDone) {
@ -264,5 +250,12 @@ ApplicationWindow {
Component.onCompleted: { Component.onCompleted: {
Modules.IO.initialize({ root, settings, alert }) Modules.IO.initialize({ root, settings, alert })
Modules.Latex.initialize({ latex: Latex, helper: Helper }) Modules.Latex.initialize({ latex: Latex, helper: Helper })
Modules.Settings.on("changed", (evt) => {
if(evt.property === "saveFilename") {
const fileName = evt.newValue.split('/').pop().split('\\').pop()
if(fileName !== "")
title = `${fileName}`
}
})
} }
} }

View file

@ -285,7 +285,7 @@ Item {
const axisX = Modules.Canvas.axesSteps.x.value const axisX = Modules.Canvas.axesSteps.x.value
const xpos = Modules.Canvas.px2x(picker.mouseX) const xpos = Modules.Canvas.px2x(picker.mouseX)
if(snapToGridCheckbox.checked) { if(snapToGridCheckbox.checked) {
if(canvas.logscalex) { if(Modules.Settings.logscalex) {
// Calculate the logged power // Calculate the logged power
let pow = Math.pow(10, Math.floor(Math.log10(xpos))) let pow = Math.pow(10, Math.floor(Math.log10(xpos)))
return pow*Math.round(xpos/pow) return pow*Math.round(xpos/pow)

View file

@ -175,17 +175,17 @@ Item {
Icon { Icon {
id: iconLabel id: iconLabel
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: icon == "" ? 0 : 3 anchors.topMargin: parent.icon == "" ? 0 : 3
source: control.visible && icon != "" ? "../icons/" + control.icon : "" source: control.visible && parent.icon != "" ? "../icons/" + control.icon : ""
width: height width: height
height: icon == "" || !visible ? 0 : 24 height: parent.icon == "" || !visible ? 0 : 24
color: sysPalette.windowText color: sysPalette.windowText
} }
Label { Label {
id: labelItem id: labelItem
anchors.left: iconLabel.right anchors.left: iconLabel.right
anchors.leftMargin: icon == "" ? 0 : 5 anchors.leftMargin: parent.icon == "" ? 0 : 5
anchors.top: parent.top anchors.top: parent.top
height: parent.height height: parent.height
width: Math.max(85, implicitWidth) width: Math.max(85, implicitWidth)
@ -231,8 +231,8 @@ Item {
onEditingFinished: { onEditingFinished: {
if(insertButton.focus || insertPopup.focus) return if(insertButton.focus || insertPopup.focus) return
let value = text let value = text
if(value != "" && value.toString() != defValue) { if(value != "" && value.toString() != parent.defValue) {
let expr = parse(value) let expr = parent.parse(value)
if(expr != null) { if(expr != null) {
control.changed(expr) control.changed(expr)
defValue = expr.toEditableString() defValue = expr.toEditableString()
@ -280,10 +280,10 @@ Item {
acPopupContent.itemSelected = 0 acPopupContent.itemSelected = 0
if(event.text in openAndCloseMatches && autoClosing) { if(event.text in parent.openAndCloseMatches && autoClosing) {
let start = selectionStart let start = selectionStart
insert(selectionStart, event.text) insert(selectionStart, event.text)
insert(selectionEnd, openAndCloseMatches[event.text]) insert(selectionEnd, parent.openAndCloseMatches[event.text])
cursorPosition = start+1 cursorPosition = start+1
event.accepted = true event.accepted = true
} }

View file

@ -37,7 +37,7 @@ Item {
Emitted when the value of the text has been changed. Emitted when the value of the text has been changed.
The corresponding handler is \c onChanged. The corresponding handler is \c onChanged.
*/ */
signal changed(string newValue) signal changed(var newValue)
/*! /*!
\qmlproperty bool TextSetting::isInt \qmlproperty bool TextSetting::isInt

View file

@ -121,11 +121,6 @@ ScrollView {
\sa Settings \sa Settings
*/ */
property bool showygrad: Helper.getSettingBool('default_graph.showygrad') property bool showygrad: Helper.getSettingBool('default_graph.showygrad')
/*!
\qmlproperty bool Settings::saveFilename
Path of the currently opened file. Empty if no file is opened.
*/
property string saveFilename: ""
Column { Column {
spacing: 10 spacing: 10
@ -136,15 +131,18 @@ ScrollView {
id: fdiag id: fdiag
onAccepted: { onAccepted: {
var filePath = fdiag.currentFile.toString().substr(7) var filePath = fdiag.currentFile.toString().substr(7)
settings.saveFilename = filePath Modules.Settings.set("saveFilename", filePath)
if(exportMode) { if(exportMode) {
Modules.IO.saveDiagram(filePath) Modules.IO.saveDiagram(filePath)
} else { } else {
Modules.IO.loadDiagram(filePath) Modules.IO.loadDiagram(filePath)
if(xAxisLabel.find(settings.xlabel) == -1) xAxisLabel.model.append({text: settings.xlabel}) // Adding labels.
xAxisLabel.editText = settings.xlabel if(xAxisLabel.find(Modules.Settings.xlabel) === -1)
if(yAxisLabel.find(settings.ylabel) == -1) yAxisLabel.model.append({text: settings.ylabel}) xAxisLabel.model.append({text: Modules.Settings.xlabel})
yAxisLabel.editText = settings.ylabel xAxisLabel.editText = Modules.Settings.xlabel
if(yAxisLabel.find(Modules.Settings.ylabel) === -1)
yAxisLabel.model.append({text: Modules.Settings.ylabel})
yAxisLabel.editText = Modules.Settings.ylabel
} }
} }
} }
@ -158,11 +156,16 @@ ScrollView {
min: 0.1 min: 0.1
icon: "settings/xzoom.svg" icon: "settings/xzoom.svg"
width: settings.settingWidth width: settings.settingWidth
value: settings.xzoom.toFixed(2)
onChanged: function(newValue) { onChanged: function(newValue) {
settings.xzoom = newValue Modules.Settings.set("xzoom", newValue, true)
settings.changed() settings.changed()
} }
function update(newValue) {
value = Modules.Settings.xzoom.toFixed(2)
maxX.update()
}
} }
Setting.TextSetting { Setting.TextSetting {
@ -173,11 +176,16 @@ ScrollView {
label: qsTr("Y Zoom") label: qsTr("Y Zoom")
icon: "settings/yzoom.svg" icon: "settings/yzoom.svg"
width: settings.settingWidth width: settings.settingWidth
value: settings.yzoom.toFixed(2)
onChanged: function(newValue) { onChanged: function(newValue) {
settings.yzoom = newValue Modules.Settings.set("yzoom", newValue, true)
settings.changed() settings.changed()
} }
function update(newValue) {
value = Modules.Settings.yzoom.toFixed(2)
minY.update()
}
} }
// Positioning the graph // Positioning the graph
@ -189,14 +197,18 @@ ScrollView {
label: qsTr("Min X") label: qsTr("Min X")
icon: "settings/xmin.svg" icon: "settings/xmin.svg"
width: settings.settingWidth width: settings.settingWidth
defValue: settings.xmin
onChanged: function(newValue) { onChanged: function(newValue) {
if(parseFloat(maxX.value) > newValue) { Modules.Settings.set("xmin", newValue, true)
settings.xmin = newValue settings.changed()
settings.changed() }
} else {
alert.show("Minimum x value must be inferior to maximum.") function update(newValue) {
} let newVal = Modules.Settings.xmin
if(newVal > 1e-5)
newVal = newVal.toDecimalPrecision(8)
value = newVal
maxX.update()
} }
} }
@ -208,11 +220,16 @@ ScrollView {
label: qsTr("Max Y") label: qsTr("Max Y")
icon: "settings/ymax.svg" icon: "settings/ymax.svg"
width: settings.settingWidth width: settings.settingWidth
defValue: settings.ymax
onChanged: function(newValue) { onChanged: function(newValue) {
settings.ymax = newValue Modules.Settings.set("ymax", newValue, true)
settings.changed() settings.changed()
} }
function update() {
value = Modules.Settings.ymax
minY.update()
}
} }
Setting.TextSetting { Setting.TextSetting {
@ -223,15 +240,24 @@ ScrollView {
label: qsTr("Max X") label: qsTr("Max X")
icon: "settings/xmax.svg" icon: "settings/xmax.svg"
width: settings.settingWidth width: settings.settingWidth
defValue: Modules.Canvas.px2x(canvas.width).toFixed(2)
onChanged: function(xvaluemax) { onChanged: function(xvaluemax) {
if(xvaluemax > settings.xmin) { if(xvaluemax > Modules.Settings.xmin) {
settings.xzoom = settings.xzoom * canvas.width/(Modules.Canvas.x2px(xvaluemax)) // Adjusting zoom to fit. = (end)/(px of current point) const newXZoom = Modules.Settings.xzoom * canvas.width/(Modules.Canvas.x2px(xvaluemax)) // Adjusting zoom to fit. = (end)/(px of current point)
Modules.Settings.set("xzoom", newXZoom, true)
zoomX.update()
settings.changed() settings.changed()
} else { } else {
alert.show("Maximum x value must be superior to minimum.") alert.show("Maximum x value must be superior to minimum.")
} }
} }
function update() {
let newVal = Modules.Canvas.px2x(canvas.width)
if(newVal > 1e-5)
newVal = newVal.toDecimalPrecision(8)
value = newVal
}
} }
Setting.TextSetting { Setting.TextSetting {
@ -242,15 +268,21 @@ ScrollView {
label: qsTr("Min Y") label: qsTr("Min Y")
icon: "settings/ymin.svg" icon: "settings/ymin.svg"
width: settings.settingWidth width: settings.settingWidth
defValue: Modules.Canvas.px2y(canvas.height).toFixed(2)
onChanged: function(yvaluemin) { onChanged: function(yvaluemin) {
if(yvaluemin < settings.ymax) { if(yvaluemin < settings.ymax) {
settings.yzoom = settings.yzoom * canvas.height/(Modules.Canvas.y2px(yvaluemin)) // Adjusting zoom to fit. = (end)/(px of current point) const newYZoom = Modules.Settings.yzoom * canvas.height/(Modules.Canvas.y2px(yvaluemin)) // Adjusting zoom to fit. = (end)/(px of current point)
Modules.Settings.set("yzoom", newYZoom, true)
zoomY.update()
settings.changed() settings.changed()
} else { } else {
alert.show("Minimum y value must be inferior to maximum.") alert.show("Minimum y value must be inferior to maximum.")
} }
} }
function update() {
value = Modules.Canvas.px2y(canvas.height).toDecimalPrecision(8)
}
} }
Setting.TextSetting { Setting.TextSetting {
@ -260,12 +292,16 @@ ScrollView {
label: qsTr("X Axis Step") label: qsTr("X Axis Step")
icon: "settings/xaxisstep.svg" icon: "settings/xaxisstep.svg"
width: settings.settingWidth width: settings.settingWidth
defValue: settings.xaxisstep
visible: !settings.logscalex
onChanged: function(newValue) { onChanged: function(newValue) {
settings.xaxisstep = newValue Modules.Settings.set("xaxisstep", newValue, true)
settings.changed() settings.changed()
} }
function update() {
value = Modules.Settings.xaxisstep
visible = !Modules.Settings.logscalex
}
} }
Setting.TextSetting { Setting.TextSetting {
@ -275,11 +311,13 @@ ScrollView {
label: qsTr("Y Axis Step") label: qsTr("Y Axis Step")
icon: "settings/yaxisstep.svg" icon: "settings/yaxisstep.svg"
width: settings.settingWidth width: settings.settingWidth
defValue: settings.yaxisstep
onChanged: function(newValue) { onChanged: function(newValue) {
settings.yaxisstep = newValue Modules.Settings.set("yaxisstep", newValue, true)
settings.changed() settings.changed()
} }
function update() { value = Modules.Settings.yaxisstep }
} }
Setting.TextSetting { Setting.TextSetting {
@ -290,11 +328,13 @@ ScrollView {
min: 1 min: 1
icon: "settings/linewidth.svg" icon: "settings/linewidth.svg"
width: settings.settingWidth width: settings.settingWidth
defValue: settings.linewidth
onChanged: function(newValue) { onChanged: function(newValue) {
settings.linewidth = newValue Modules.Settings.set("linewidth", newValue, true)
settings.changed() settings.changed()
} }
function update() { value = Modules.Settings.linewidth }
} }
Setting.TextSetting { Setting.TextSetting {
@ -305,11 +345,13 @@ ScrollView {
min: 1 min: 1
icon: "settings/textsize.svg" icon: "settings/textsize.svg"
width: settings.settingWidth width: settings.settingWidth
defValue: settings.textsize
onChanged: function(newValue) { onChanged: function(newValue) {
settings.textsize = newValue Modules.Settings.set("textsize", newValue, true)
settings.changed() settings.changed()
} }
function update() { value = Modules.Settings.textsize }
} }
Setting.ComboBoxSetting { Setting.ComboBoxSetting {
@ -318,24 +360,31 @@ ScrollView {
width: settings.settingWidth width: settings.settingWidth
label: qsTr('X Label') label: qsTr('X Label')
icon: "settings/xlabel.svg" icon: "settings/xlabel.svg"
editable: true
model: ListModel { model: ListModel {
ListElement { text: "" } ListElement { text: "" }
ListElement { text: "x" } ListElement { text: "x" }
ListElement { text: "ω (rad/s)" } ListElement { text: "ω (rad/s)" }
} }
currentIndex: find(settings.xlabel)
editable: true
onAccepted: function(){ onAccepted: function(){
editText = JS.Utils.parseName(editText, false) editText = JS.Utils.parseName(editText, false)
if (find(editText) === -1) model.append({text: editText}) if(find(editText) === -1) model.append({text: editText})
settings.xlabel = editText currentIndex = find(editText)
Modules.Settings.set("xlabel", editText, true)
settings.changed() settings.changed()
} }
onActivated: function(selectedId) { onActivated: function(selectedId) {
settings.xlabel = model.get(selectedId).text Modules.Settings.set("xlabel", model.get(selectedId).text, true)
settings.changed() settings.changed()
} }
Component.onCompleted: editText = settings.xlabel
function update() {
editText = Modules.Settings.xlabel
if(find(editText) === -1) model.append({text: editText})
currentIndex = find(editText)
}
} }
Setting.ComboBoxSetting { Setting.ComboBoxSetting {
@ -344,6 +393,7 @@ ScrollView {
width: settings.settingWidth width: settings.settingWidth
label: qsTr('Y Label') label: qsTr('Y Label')
icon: "settings/ylabel.svg" icon: "settings/ylabel.svg"
editable: true
model: ListModel { model: ListModel {
ListElement { text: "" } ListElement { text: "" }
ListElement { text: "y" } ListElement { text: "y" }
@ -352,39 +402,52 @@ ScrollView {
ListElement { text: "φ (deg)" } ListElement { text: "φ (deg)" }
ListElement { text: "φ (rad)" } ListElement { text: "φ (rad)" }
} }
currentIndex: find(settings.ylabel)
editable: true
onAccepted: function(){ onAccepted: function(){
editText = JS.Utils.parseName(editText, false) editText = JS.Utils.parseName(editText, false)
if (find(editText) === -1) model.append({text: editText, yaxisstep: root.yaxisstep}) if(find(editText) === -1) model.append({text: editText})
settings.ylabel = editText currentIndex = find(editText)
Modules.Settings.set("ylabel", editText, true)
settings.changed() settings.changed()
} }
onActivated: function(selectedId) { onActivated: function(selectedId) {
settings.ylabel = model.get(selectedId).text Modules.Settings.set("ylabel", model.get(selectedId).text, true)
settings.changed() settings.changed()
} }
Component.onCompleted: editText = settings.ylabel
function update() {
editText = Modules.Settings.ylabel
if(find(editText) === -1) model.append({text: editText})
currentIndex = find(editText)
}
} }
CheckBox { CheckBox {
id: logScaleX id: logScaleX
checked: settings.logscalex
text: qsTr('X Log scale') text: qsTr('X Log scale')
onClicked: { onClicked: {
settings.logscalex = checked Modules.Settings.set("logscalex", checked, true)
if(Modules.Settings.xmin <= 0) // Reset xmin to prevent crash.
Modules.Settings.set("xmin", .5)
settings.changed() settings.changed()
} }
function update() {
checked = Modules.Settings.logscalex
xAxisStep.update()
}
} }
CheckBox { CheckBox {
id: showXGrad id: showXGrad
checked: settings.showxgrad
text: qsTr('Show X graduation') text: qsTr('Show X graduation')
onClicked: { onClicked: {
settings.showxgrad = checked Modules.Settings.set("showxgrad", checked, true)
settings.changed() settings.changed()
} }
function update() { checked = Modules.Settings.showxgrad }
} }
CheckBox { CheckBox {
@ -392,9 +455,10 @@ ScrollView {
checked: settings.showygrad checked: settings.showygrad
text: qsTr('Show Y graduation') text: qsTr('Show Y graduation')
onClicked: { onClicked: {
settings.showygrad = checked Modules.Settings.set("showygrad", checked, true)
settings.changed() settings.changed()
} }
function update() { checked = Modules.Settings.showygrad }
} }
Button { Button {
@ -440,10 +504,10 @@ ScrollView {
Saves the current canvas in the opened file. If no file is currently opened, prompts to pick a save location. Saves the current canvas in the opened file. If no file is currently opened, prompts to pick a save location.
*/ */
function save() { function save() {
if(settings.saveFilename == "") { if(Modules.Settings.saveFilename == "") {
saveAs() saveAs()
} else { } else {
Modules.IO.saveDiagram(settings.saveFilename) Modules.IO.saveDiagram(Modules.Settings.saveFilename)
} }
} }
@ -464,4 +528,30 @@ ScrollView {
fdiag.exportMode = false fdiag.exportMode = false
fdiag.open() fdiag.open()
} }
/**
* Initializing the settings
*/
Component.onCompleted: function() {
const matchedElements = new Map([
["xzoom", zoomX],
["yzoom", zoomY],
["xmin", minX],
["ymax", maxY],
["xaxisstep", xAxisStep],
["yaxisstep", yAxisStep],
["xlabel", xAxisLabel],
["ylabel", yAxisLabel],
["linewidth", lineWidth],
["textsize", textSize],
["logscalex", logScaleX],
["showxgrad", showXGrad],
["showygrad", showYGrad]
])
Modules.Settings.on("changed", (evt) => {
if(matchedElements.has(evt.property))
matchedElements.get(evt.property).update()
})
Modules.Settings.initialize({ helper: Helper })
}
} }

View file

@ -17,8 +17,6 @@
*/ */
import QtQuick import QtQuick
import QtQuick.Controls
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
/*! /*!
\qmltype ViewPositionChangeOverlay \qmltype ViewPositionChangeOverlay
@ -81,7 +79,7 @@ Item {
property int prevY property int prevY
/*! /*!
\qmlproperty double ViewPositionChangeOverlay::baseZoomMultiplier \qmlproperty double ViewPositionChangeOverlay::baseZoomMultiplier
How much should the zoom be mutliplied/scrolled by for one scroll step (120° on the mouse wheel). How much should the zoom be multiplied/scrolled by for one scroll step (120° on the mouse wheel).
*/ */
property double baseZoomMultiplier: 0.1 property double baseZoomMultiplier: 0.1
@ -91,15 +89,15 @@ Item {
cursorShape: pressed ? Qt.ClosedHandCursor : Qt.OpenHandCursor cursorShape: pressed ? Qt.ClosedHandCursor : Qt.OpenHandCursor
property int positionChangeTimer: 0 property int positionChangeTimer: 0
function updatePosition(deltaX, deltaY) { function updatePosition(deltaX, deltaY, isEnd) {
const unauthorized = [NaN, Infinity, -Infinity] const unauthorized = [NaN, Infinity, -Infinity]
const xmin = (Modules.Canvas.px2x(Modules.Canvas.x2px(settingsInstance.xmin)-deltaX)) const xmin = (Modules.Canvas.px2x(Modules.Canvas.x2px(Modules.Settings.xmin)-deltaX))
const ymax = settingsInstance.ymax + deltaY/canvas.yzoom const ymax = Modules.Settings.ymax + deltaY/Modules.Settings.yzoom
if(!unauthorized.includes(xmin)) if(!unauthorized.includes(xmin))
settingsInstance.xmin = xmin Modules.Settings.set("xmin", xmin, isEnd)
if(!unauthorized.includes(ymax)) if(!unauthorized.includes(ymax))
settingsInstance.ymax = ymax.toFixed(4) Modules.Settings.set("ymax", ymax.toDecimalPrecision(6), isEnd)
settingsInstance.changed() Modules.Canvas.requestPaint()
parent.positionChanged(deltaX, deltaY) parent.positionChanged(deltaX, deltaY)
} }
@ -113,9 +111,9 @@ Item {
onPositionChanged: function(mouse) { onPositionChanged: function(mouse) {
positionChangeTimer++ positionChangeTimer++
if(positionChangeTimer == 3) { if(positionChangeTimer == 3) {
let deltaX = mouse.x - prevX let deltaX = mouse.x - parent.prevX
let deltaY = mouse.y - prevY let deltaY = mouse.y - parent.prevY
updatePosition(deltaX, deltaY) updatePosition(deltaX, deltaY, false)
prevX = mouse.x prevX = mouse.x
prevY = mouse.y prevY = mouse.y
positionChangeTimer = 0 positionChangeTimer = 0
@ -123,35 +121,35 @@ Item {
} }
onReleased: function(mouse) { onReleased: function(mouse) {
let deltaX = mouse.x - prevX let deltaX = mouse.x - parent.prevX
let deltaY = mouse.y - prevY let deltaY = mouse.y - parent.prevY
updatePosition(deltaX, deltaY) updatePosition(deltaX, deltaY, true)
parent.endPositionChange(deltaX, deltaY) parent.endPositionChange(deltaX, deltaY)
} }
onWheel: function(wheel) { onWheel: function(wheel) {
// Scrolling // Scrolling
let scrollSteps = Math.round(wheel.angleDelta.y / 120) let scrollSteps = Math.round(wheel.angleDelta.y / 120)
let zoomMultiplier = Math.pow(1+baseZoomMultiplier, Math.abs(scrollSteps)) let zoomMultiplier = Math.pow(1+parent.baseZoomMultiplier, Math.abs(scrollSteps))
// Avoid floating-point rounding errors by removing the zoom *after* // Avoid floating-point rounding errors by removing the zoom *after*
let xZoomDelta = (settingsInstance.xzoom*zoomMultiplier - settingsInstance.xzoom) let xZoomDelta = (Modules.Settings.xzoom*zoomMultiplier - Modules.Settings.xzoom)
let yZoomDelta = (settingsInstance.yzoom*zoomMultiplier - settingsInstance.yzoom) let yZoomDelta = (Modules.Settings.yzoom*zoomMultiplier - Modules.Settings.yzoom)
if(scrollSteps < 0) { // Negative scroll if(scrollSteps < 0) { // Negative scroll
xZoomDelta *= -1 xZoomDelta *= -1
yZoomDelta *= -1 yZoomDelta *= -1
} }
let newXZoom = (settingsInstance.xzoom+xZoomDelta).toFixed(0) let newXZoom = (Modules.Settings.xzoom+xZoomDelta).toDecimalPrecision(0)
let newYZoom = (settingsInstance.yzoom+yZoomDelta).toFixed(0) let newYZoom = (Modules.Settings.yzoom+yZoomDelta).toDecimalPrecision(0)
// Check if we need to have more precision // Check if we need to have more precision
if(newXZoom < 10) if(newXZoom < 10)
newXZoom = (settingsInstance.xzoom+xZoomDelta).toFixed(4) newXZoom = (Modules.Settings.xzoom+xZoomDelta).toDecimalPrecision(4)
if(newYZoom < 10) if(newYZoom < 10)
newYZoom = (settingsInstance.yzoom+yZoomDelta).toFixed(4) newYZoom = (Modules.Settings.yzoom+yZoomDelta).toDecimalPrecision(4)
if(newXZoom > 0.5) if(newXZoom > 0.5)
settingsInstance.xzoom = newXZoom Modules.Settings.set("xzoom", newXZoom)
if(newYZoom > 0.5) if(newYZoom > 0.5)
settingsInstance.yzoom = newYZoom Modules.Settings.set("yzoom", newYZoom)
settingsInstance.changed() Modules.Canvas.requestPaint()
} }
} }
} }