/** * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions. * Copyright (C) 2022 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 . */ import QtQuick.Controls 2.12 import QtQuick 2.12 import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting import eu.ad5001.LogarithmPlotter.Popup 1.0 as Popup import "js/utils.js" as Utils /*! \qmltype Settings \inqmlmodule eu.ad5001.LogarithmPlotter \brief Tab of the drawer that allows the user to customize how the diagram looks. All canvas settings can found in this scrollable view, as well as buttons to copy and save the graph. \sa LogarithmPlotter, LogGraphCanvas */ ScrollView { id: settings signal changed() property int settingWidth: settings.width - ScrollBar.vertical.width property Canvas canvas /*! \qmlproperty double Settings::xzoom Zoom on the x axis of the diagram, provided from settings. \sa Settings */ property double xzoom: 100 /*! \qmlproperty double Settings::yzoom Zoom on the y axis of the diagram, provided from settings. \sa Settings */ property double yzoom: 10 /*! \qmlproperty double Settings::xmin Minimum x of the diagram, provided from settings. \sa Settings */ property double xmin: 5/10 /*! \qmlproperty double Settings::ymax Maximum y of the diagram, provided from settings. \sa Settings */ property double ymax: 25 /*! \qmlproperty string Settings::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 Settings::yaxisstep Step of the y axis graduation, provided from settings. \sa Settings */ property string yaxisstep: "4" /*! \qmlproperty string Settings::xlabel Label used on the x axis, provided from settings. \sa Settings */ property string xlabel: "" /*! \qmlproperty string Settings::ylabel Label used on the y axis, provided from settings. \sa Settings */ property string ylabel: "" /*! \qmlproperty double Settings::linewidth Width of lines that will be drawn into the canvas, provided from settings. \sa Settings */ property double linewidth: 1 /*! \qmlproperty double Settings::textsize Font size of the text that will be drawn into the canvas, provided from settings. \sa Settings */ property double textsize: 14 /*! \qmlproperty bool Settings::logscalex true if the canvas should be in logarithmic mode, false otherwise. Provided from settings. \sa Settings */ property bool logscalex: true /*! \qmlproperty bool Settings::showxgrad true if the x graduation should be shown, false otherwise. Provided from settings. \sa Settings */ property bool showxgrad: true /*! \qmlproperty bool Settings::showygrad true if the y graduation should be shown, false otherwise. Provided from settings. \sa Settings */ property bool showygrad: true /*! \qmlproperty bool Settings::saveFilename Path of the currently opened file. Empty if no file is opened. */ property string saveFilename: "" Column { spacing: 10 width: parent.width bottomPadding: 20 Popup.FileDialog { id: fdiag onAccepted: { var filePath = fileUrl.toString().substr(7) settings.saveFilename = filePath if(exportMode) { root.saveDiagram(filePath) } else { root.loadDiagram(filePath) if(xAxisLabel.find(settings.xlabel) == -1) xAxisLabel.model.append({text: settings.xlabel}) xAxisLabel.editText = settings.xlabel if(yAxisLabel.find(settings.ylabel) == -1) yAxisLabel.model.append({text: settings.ylabel}) yAxisLabel.editText = settings.ylabel } } } // Zoom Setting.TextSetting { id: zoomX height: 30 isDouble: true label: qsTr("X Zoom") min: 1 icon: "settings/xzoom.svg" width: settings.settingWidth value: settings.xzoom.toFixed(2) onChanged: function(newValue) { settings.xzoom = newValue settings.changed() } } Setting.TextSetting { id: zoomY height: 30 isDouble: true label: qsTr("Y Zoom") icon: "settings/yzoom.svg" width: settings.settingWidth value: settings.yzoom.toFixed(2) onChanged: function(newValue) { settings.yzoom = newValue settings.changed() } } // Positioning the graph Setting.TextSetting { id: minX height: 30 isDouble: true min: -Infinity label: qsTr("Min X") icon: "settings/xmin.svg" width: settings.settingWidth defValue: settings.xmin onChanged: function(newValue) { if(parseFloat(maxX.value) > newValue) { settings.xmin = newValue settings.changed() } else { alert.show("Minimum x value must be inferior to maximum.") } } } Setting.TextSetting { id: maxY height: 30 isDouble: true min: -Infinity label: qsTr("Max Y") icon: "settings/ymax.svg" width: settings.settingWidth defValue: settings.ymax onChanged: function(newValue) { settings.ymax = newValue settings.changed() } } Setting.TextSetting { id: maxX height: 30 isDouble: true min: -Infinity label: qsTr("Max X") icon: "settings/xmax.svg" width: settings.settingWidth value: canvas.px2x(canvas.canvasSize.width).toFixed(2) onChanged: function(xvaluemax) { if(xvaluemax > settings.xmin) { settings.xzoom = settings.xzoom * canvas.canvasSize.width/(canvas.x2px(xvaluemax)) // Adjusting zoom to fit. = (end)/(px of current point) settings.changed() } else { alert.show("Maximum x value must be superior to minimum.") } } } Setting.TextSetting { id: minY height: 30 isDouble: true min: -Infinity label: qsTr("Min Y") icon: "settings/ymin.svg" width: settings.settingWidth defValue: canvas.px2y(canvas.canvasSize.height).toFixed(2) onChanged: function(yvaluemin) { if(yvaluemin < settings.ymax) { settings.yzoom = settings.yzoom * canvas.canvasSize.height/(canvas.y2px(yvaluemin)) // Adjusting zoom to fit. = (end)/(px of current point) settings.changed() } else { alert.show("Minimum y value must be inferior to maximum.") } } } Setting.TextSetting { id: xAxisStep height: 30 label: qsTr("X Axis Step") icon: "settings/xaxisstep.svg" width: settings.settingWidth defValue: settings.xaxisstep visible: !settings.logscalex onChanged: function(newValue) { settings.xaxisstep = newValue settings.changed() } } Setting.TextSetting { id: yAxisStep height: 30 label: qsTr("Y Axis Step") icon: "settings/yaxisstep.svg" width: settings.settingWidth defValue: settings.yaxisstep onChanged: function(newValue) { settings.yaxisstep = newValue settings.changed() } } Setting.TextSetting { id: lineWidth height: 30 isDouble: true label: qsTr("Line width") min: 1 icon: "settings/linewidth.svg" width: settings.settingWidth defValue: settings.linewidth onChanged: function(newValue) { settings.linewidth = newValue settings.changed() } } Setting.TextSetting { id: textSize height: 30 isDouble: true label: qsTr("Text size (px)") min: 1 icon: "settings/textsize.svg" width: settings.settingWidth defValue: settings.textsize onChanged: function(newValue) { settings.textsize = newValue settings.changed() } } Setting.ComboBoxSetting { id: xAxisLabel height: 30 width: settings.settingWidth label: qsTr('X Label') icon: "settings/xlabel.svg" model: ListModel { ListElement { text: "" } ListElement { text: "x" } ListElement { text: "ω (rad/s)" } } currentIndex: find(settings.xlabel) editable: true onAccepted: function(){ editText = Utils.parseName(editText, false) if (find(editText) === -1) model.append({text: editText}) settings.xlabel = editText settings.changed() } onActivated: function(selectedId) { settings.xlabel = model.get(selectedId).text settings.changed() } Component.onCompleted: editText = settings.xlabel } Setting.ComboBoxSetting { id: yAxisLabel height: 30 width: settings.settingWidth label: qsTr('Y Label') icon: "settings/ylabel.svg" model: ListModel { ListElement { text: "" } ListElement { text: "y" } ListElement { text: "G (dB)" } ListElement { text: "φ (°)" } ListElement { text: "φ (deg)" } ListElement { text: "φ (rad)" } } currentIndex: find(settings.ylabel) editable: true onAccepted: function(){ editText = Utils.parseName(editText, false) if (find(editText) === -1) model.append({text: editText, yaxisstep: root.yaxisstep}) settings.ylabel = editText settings.changed() } onActivated: function(selectedId) { settings.ylabel = model.get(selectedId).text settings.changed() } Component.onCompleted: editText = settings.ylabel } CheckBox { id: logScaleX checked: settings.logscalex text: qsTr('X Log scale') onClicked: { settings.logscalex = checked settings.changed() } } CheckBox { id: showXGrad checked: settings.showxgrad text: qsTr('Show X graduation') onClicked: { settings.showxgrad = checked settings.changed() } } CheckBox { id: showYGrad checked: settings.showygrad text: qsTr('Show Y graduation') onClicked: { settings.showygrad = checked settings.changed() } } Button { id: copyToClipboard height: 30 width: settings.settingWidth text: qsTr("Copy to clipboard") icon.name: 'editcopy' onClicked: root.copyDiagramToClipboard() } Button { id: saveDiagram height: 30 width: settings.settingWidth text: qsTr("Save plot") icon.name: 'document-save' onClicked: save() } Button { id: saveDiagramAs height: 30 width: settings.settingWidth text: qsTr("Save plot as") icon.name: 'document-save-as' onClicked: saveAs() } Button { id: loadDiagram height: 30 width: settings.settingWidth text: qsTr("Load plot") icon.name: 'document-open' onClicked: load() } } /*! \qmlmethod void LogGraphCanvas::save() Saves the current canvas in the opened file. If no file is currently opened, prompts to pick a save location. */ function save() { if(settings.saveFilename == "") { saveAs() } else { root.saveDiagram(settings.saveFilename) } } /*! \qmlmethod void LogGraphCanvas::saveAs() Prompts the user to pick a new save location. */ function saveAs() { fdiag.exportMode = true fdiag.open() } /*! \qmlmethod void LogGraphCanvas::saveAs() Prompts the user to pick a diagram to load. */ function load() { fdiag.exportMode = false fdiag.open() } }