320 lines
10 KiB
QML
320 lines
10 KiB
QML
/**
|
||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition 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 <https://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
import QtQml 2.12
|
||
import QtQuick.Controls 2.12
|
||
import eu.ad5001.MixedMenu 1.1
|
||
import QtQuick.Layouts 1.12
|
||
import QtQuick 2.12
|
||
// Auto loading all objects.
|
||
import "js/objs/autoload.js" as ALObjects
|
||
|
||
import "js/objects.js" as Objects
|
||
import eu.ad5001.LogarithmPlotter.ObjectLists 1.0
|
||
|
||
|
||
ApplicationWindow {
|
||
id: root
|
||
visible: true
|
||
width: 1000
|
||
height: 500
|
||
color: sysPalette.window
|
||
title: "LogarithmPlotter " + (settings.saveFilename != "" ? " - " + settings.saveFilename.split('/').pop() : "") + (history.saved ? "" : "*")
|
||
|
||
SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active }
|
||
SystemPalette { id: sysPaletteIn; colorGroup: SystemPalette.Disabled }
|
||
|
||
|
||
menuBar: appMenu.trueItem
|
||
|
||
GreetScreen {}
|
||
|
||
AppMenuBar {id: appMenu}
|
||
|
||
History { id: history }
|
||
|
||
About {id: about}
|
||
|
||
Alert {
|
||
id: alert
|
||
anchors.bottom: parent.bottom
|
||
anchors.bottomMargin: 5
|
||
z: 3
|
||
}
|
||
|
||
Drawer {
|
||
id: sidebar
|
||
width: 300
|
||
height: parent.height
|
||
y: root.menuBar.height
|
||
readonly property bool inPortrait: root.width < root.height
|
||
modal: inPortrait
|
||
interactive: inPortrait
|
||
position: inPortrait ? 0 : 1
|
||
visible: !inPortrait
|
||
|
||
|
||
TabBar {
|
||
id: sidebarSelector
|
||
width: parent.width
|
||
anchors.top: parent.top
|
||
TabButton {
|
||
text: qsTr("Objects")
|
||
icon.name: 'polygon-add-nodes'
|
||
icon.color: sysPalette.windowText
|
||
//height: 24
|
||
}
|
||
TabButton {
|
||
text: qsTr("Settings")
|
||
icon.name: 'preferences-system-symbolic'
|
||
icon.color: sysPalette.windowText
|
||
//height: 24
|
||
}
|
||
TabButton {
|
||
text: qsTr("History")
|
||
icon.name: 'view-history'
|
||
icon.color: sysPalette.windowText
|
||
//height: 24
|
||
}
|
||
}
|
||
|
||
StackLayout {
|
||
id: sidebarContents
|
||
anchors.top: sidebarSelector.bottom
|
||
anchors.left: parent.left
|
||
anchors.topMargin: 5
|
||
anchors.leftMargin: 5
|
||
anchors.bottom: parent.bottom
|
||
anchors.bottomMargin: sidebarSelector.height
|
||
width: parent.width - 5
|
||
currentIndex: sidebarSelector.currentIndex
|
||
z: -1
|
||
clip: true
|
||
|
||
ObjectLists {
|
||
id: objectLists
|
||
onChanged: drawCanvas.requestPaint()
|
||
}
|
||
|
||
Settings {
|
||
id: settings
|
||
canvas: drawCanvas
|
||
onChanged: drawCanvas.requestPaint()
|
||
}
|
||
|
||
HistoryBrowser {
|
||
id: historyBrowser
|
||
}
|
||
}
|
||
}
|
||
|
||
LogGraphCanvas {
|
||
id: drawCanvas
|
||
anchors.top: parent.top
|
||
anchors.left: sidebar.inPortrait ? parent.left : sidebar.right
|
||
height: parent.height
|
||
width: sidebar.inPortrait ? parent.width : parent.width - sidebar.position*sidebar.width
|
||
x: sidebar.position*sidebar.width
|
||
|
||
xmin: settings.xmin
|
||
ymax: settings.ymax
|
||
xzoom: settings.xzoom
|
||
yzoom: settings.yzoom
|
||
xlabel: settings.xaxislabel
|
||
ylabel: settings.yaxislabel
|
||
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
|
||
|
||
onPainted: if(!firstDrawDone) {
|
||
firstDrawDone = true;
|
||
console.info("First paint done in " + (new Date().getTime()-(StartTime*1000)) + "ms")
|
||
if(TestBuild == true) {
|
||
console.log("Plot drawn in canvas, terminating test of build in 100ms.")
|
||
testBuildTimer.start()
|
||
}
|
||
}
|
||
|
||
PickLocationOverlay {
|
||
id: positionPicker
|
||
anchors.fill: parent
|
||
canvas: parent
|
||
}
|
||
}
|
||
|
||
function saveDiagram(filename) {
|
||
if(['lpf'].indexOf(filename.split('.')[filename.split('.').length-1]) == -1)
|
||
filename += '.lpf'
|
||
settings.saveFilename = filename
|
||
var objs = {}
|
||
for(var objType in Objects.currentObjects){
|
||
objs[objType] = []
|
||
for(var obj of Objects.currentObjects[objType]) {
|
||
objs[objType].push(obj.export())
|
||
}
|
||
}
|
||
Helper.write(filename, JSON.stringify({
|
||
"xzoom": settings.xzoom,
|
||
"yzoom": settings.yzoom,
|
||
"xmin": settings.xmin,
|
||
"ymax": settings.ymax,
|
||
"xaxisstep": settings.xaxisstep,
|
||
"yaxisstep": settings.yaxisstep,
|
||
"xaxislabel": settings.xaxislabel,
|
||
"yaxislabel": settings.yaxislabel,
|
||
"logscalex": settings.logscalex,
|
||
"linewidth": settings.linewidth,
|
||
"showxgrad": settings.showxgrad,
|
||
"showygrad": settings.showygrad,
|
||
"textsize": settings.textsize,
|
||
"history": history.serialize(),
|
||
"width": root.width,
|
||
"height": root.height,
|
||
"objects": objs,
|
||
"type": "logplotv1"
|
||
}))
|
||
alert.show(qsTr("Saved plot to '%1'.").arg(filename.split("/").pop()))
|
||
history.saved = true
|
||
}
|
||
|
||
function loadDiagram(filename) {
|
||
let basename = filename.split("/").pop()
|
||
alert.show(qsTr("Loading file '%1'.").arg(basename))
|
||
let data = JSON.parse(Helper.load(filename))
|
||
let error = "";
|
||
if(Object.keys(data).includes("type") && data["type"] == "logplotv1") {
|
||
history.clear()
|
||
// Importing settings
|
||
settings.saveFilename = filename
|
||
settings.xzoom = data["xzoom"]
|
||
settings.yzoom = data["yzoom"]
|
||
settings.xmin = data["xmin"]
|
||
settings.ymax = data["ymax"]
|
||
settings.xaxisstep = data["xaxisstep"]
|
||
settings.yaxisstep = data["yaxisstep"]
|
||
settings.xaxislabel = data["xaxislabel"]
|
||
settings.yaxislabel = data["yaxislabel"]
|
||
settings.logscalex = data["logscalex"]
|
||
if("showxgrad" in data)
|
||
settings.showxgrad = data["showxgrad"]
|
||
if("showygrad" in data)
|
||
settings.textsize = data["showygrad"]
|
||
if("linewidth" in data)
|
||
settings.linewidth = data["linewidth"]
|
||
if("textsize" in data)
|
||
settings.textsize = data["textsize"]
|
||
root.height = data["height"]
|
||
root.width = data["width"]
|
||
|
||
// Importing objects
|
||
Objects.currentObjects = {}
|
||
for(var objType in data['objects']) {
|
||
if(Object.keys(Objects.types).indexOf(objType) > -1) {
|
||
Objects.currentObjects[objType] = []
|
||
for(var objData of data['objects'][objType]) {
|
||
var obj = new Objects.types[objType](...objData)
|
||
Objects.currentObjects[objType].push(obj)
|
||
}
|
||
} else {
|
||
error += qsTr("Unknown object type: %1.").arg(objType) + "\n";
|
||
}
|
||
}
|
||
|
||
// Importing history
|
||
if("history" in data)
|
||
history.unserialize(...data["history"])
|
||
|
||
// Refreshing sidebar
|
||
if(sidebarSelector.currentIndex == 0) {
|
||
// For some reason, if we load a file while the tab is on object,
|
||
// we get stuck in a Qt-side loop? Qt bug or side-effect here, I don't know.
|
||
sidebarSelector.currentIndex = 1
|
||
objectLists.update()
|
||
delayRefreshTimer.start()
|
||
} else {
|
||
objectLists.update()
|
||
}
|
||
} else {
|
||
error = qsTr("Invalid file provided.")
|
||
}
|
||
if(error != "") {
|
||
console.log(error)
|
||
alert.show(qsTr("Could not save file: ") + error)
|
||
// TODO: Error handling
|
||
return
|
||
}
|
||
drawCanvas.requestPaint()
|
||
alert.show(qsTr("Loaded file '%1'.").arg(basename))
|
||
history.saved = true
|
||
}
|
||
|
||
Timer {
|
||
id: delayRefreshTimer
|
||
repeat: false
|
||
interval: 1
|
||
onTriggered: sidebarSelector.currentIndex = 0
|
||
}
|
||
|
||
Timer {
|
||
id: testBuildTimer
|
||
repeat: false
|
||
interval: 100
|
||
onTriggered: Qt.quit() // Quit after paint on test build
|
||
}
|
||
|
||
onClosing: {
|
||
if(!history.saved) {
|
||
close.accepted = false
|
||
appMenu.showSaveUnsavedChangesDialog()
|
||
}
|
||
}
|
||
|
||
function copyDiagramToClipboard() {
|
||
var file = Helper.gettmpfile()
|
||
drawCanvas.save(file)
|
||
Helper.copyImageToClipboard()
|
||
alert.show(qsTr("Copied plot screenshot to clipboard!"))
|
||
}
|
||
|
||
function showAlert(alertText) {
|
||
// This function is called from the backend and is used to show alerts from there.
|
||
alert.show(alertText)
|
||
}
|
||
|
||
|
||
Menu {
|
||
id: updateMenu
|
||
title: qsTr("&Update")
|
||
Action {
|
||
text: qsTr("&Update LogarithmPlotter")
|
||
icon.name: 'update'
|
||
onTriggered: Helper.openUrl("https://dev.apps.ad5001.eu/logarithmplotter")
|
||
}
|
||
}
|
||
|
||
function showUpdateMenu() {
|
||
appMenu.addMenu(updateMenu)
|
||
}
|
||
}
|