Compare commits
4 commits
master
...
complete-c
Author | SHA1 | Date | |
---|---|---|---|
64d5f11ff9 | |||
80d0dad63a | |||
d7704110dd | |||
666d611e95 |
35
.gitignore
vendored
|
@ -1,19 +1,13 @@
|
||||||
# Building
|
|
||||||
build/
|
build/
|
||||||
dist/
|
dist/
|
||||||
deb_dist/
|
deb_dist/
|
||||||
assets/linux/flatpak/AppDir
|
linux/flatpak/AppDir
|
||||||
assets/linux/flatpak/repo
|
linux/flatpak/repo
|
||||||
assets/linux/flatpak/build-dir
|
linux/flatpak/build-dir
|
||||||
assets/linux/flatpak/.flatpak-builder
|
linux/flatpak/.flatpak-builder
|
||||||
*.snap
|
*.snap
|
||||||
*.spec
|
*.spec
|
||||||
*.zip
|
*.zip
|
||||||
*.tar.gz
|
|
||||||
*.spec
|
|
||||||
*.egg-info/
|
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
**/**.qmlc
|
**/**.qmlc
|
||||||
**/**.jsc
|
**/**.jsc
|
||||||
**/**.pyc
|
**/**.pyc
|
||||||
|
@ -22,25 +16,20 @@ assets/linux/flatpak/.flatpak-builder
|
||||||
*.jsc
|
*.jsc
|
||||||
*.qmlc
|
*.qmlc
|
||||||
*.log
|
*.log
|
||||||
**/*.dxvk-cache
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
**/.DS_Store
|
**/.DS_Store
|
||||||
**/__pycache__/
|
**/__pycache__/
|
||||||
|
|
||||||
# IDE Data
|
|
||||||
.ropeproject
|
.ropeproject
|
||||||
.vscode
|
.vscode
|
||||||
*.kdev4
|
build
|
||||||
.kdev4
|
|
||||||
docs/html
|
docs/html
|
||||||
.directory
|
.directory
|
||||||
|
*.kdev4
|
||||||
*.lpf
|
*.lpf
|
||||||
*.lgg
|
*.lgg
|
||||||
|
*.spec
|
||||||
# Tests
|
.kdev4
|
||||||
common/coverage/
|
AccountFree.pro
|
||||||
**/.coverage
|
AccountFree.pro.user
|
||||||
|
*.egg-info/
|
||||||
# npm
|
*.tar.gz
|
||||||
common/node_modules
|
|
||||||
runtime-pyside6/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/index.mjs*
|
|
||||||
|
|
7
.gitmodules
vendored
|
@ -1,3 +1,6 @@
|
||||||
[submodule "runtime-pyside6/LogarithmPlotter/qml/eu/ad5001/MixedMenu"]
|
[submodule "LogarithmPlotter/qml/eu/ad5001/MixedMenu"]
|
||||||
path = runtime-pyside6/LogarithmPlotter/qml/eu/ad5001/MixedMenu
|
path = LogarithmPlotter/qml/eu/ad5001/MixedMenu
|
||||||
url = https://git.ad5001.eu/Ad5001/MixedMenu
|
url = https://git.ad5001.eu/Ad5001/MixedMenu
|
||||||
|
[submodule "linux/flatpak"]
|
||||||
|
path = linux/flatpak
|
||||||
|
url = https://github.com/Ad5001/eu.ad5001.LogarithmPlotter
|
||||||
|
|
118
CHANGELOG.md
|
@ -1,123 +1,5 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## v0.5.0 (11 Jan 2024)
|
|
||||||
|
|
||||||
**New**
|
|
||||||
|
|
||||||
* New, reworked application icon.
|
|
||||||
* Graph is now mouse interactive:
|
|
||||||
* You can now drag to move and scroll to zoom!
|
|
||||||
* Builtin functions now provide usage when used in the autocomplete of the expression editor.
|
|
||||||
|
|
||||||
**Changes**
|
|
||||||
|
|
||||||
* When creating an object that can be positioned, new default behavior is to pick first instead of opening object settings.
|
|
||||||
* Icons with text now use the SVG's text element, allowing them to integrate better with the system's default font.
|
|
||||||
* Special characters popup is now context aware (e.g. no sub/supscript symbols in expressions).
|
|
||||||
* New symbols in special characters popup.
|
|
||||||
* Integrals and derivatives can now be provided with an executable object (e.g. Functions) instead of strings as function.
|
|
||||||
* New description on Linux.
|
|
||||||
|
|
||||||
**Fixed bugs**
|
|
||||||
|
|
||||||
* Fixing ∞ 'variable' in domains and expressions.
|
|
||||||
* Several other bugs related to constants in expresions were fixed as well.
|
|
||||||
* Builtin functions now send an error message when not provided with the proper arguments.
|
|
||||||
|
|
||||||
**Internal changes**
|
|
||||||
|
|
||||||
* Updated to PySide6 v6.6.1.
|
|
||||||
* Reworked continuous functions' rendering to make it faster.
|
|
||||||
* Removed old bits from an unfinished new parser that weren't used.
|
|
||||||
|
|
||||||
## v0.4.0 (27 May 2023)
|
|
||||||
|
|
||||||
**Changes**
|
|
||||||
|
|
||||||
* Fully ported to PySide6 (Qt6).
|
|
||||||
* Greet screen settings are now scrollable.
|
|
||||||
* Changelog is now freezed to current version.
|
|
||||||
|
|
||||||
**New**
|
|
||||||
|
|
||||||
* Customizable color schemes for expressions.
|
|
||||||
* New, rewamped and improved picked location overlay settings:
|
|
||||||
* It's now possible to disable picking x or y when setting a location.
|
|
||||||
* Properties which are related to positioning (X, Y, Label's X position) can now be set using the picker.
|
|
||||||
* Visual redesign that enhances readability of settings.
|
|
||||||
* There is now a button to hide picker settings.
|
|
||||||
|
|
||||||
**Fixed bugs**
|
|
||||||
|
|
||||||
* Cursors in expression are now easier to see.
|
|
||||||
* Symbols in LaTeX rendered Texts cause the LaTeX renderer to crash.
|
|
||||||
* Underscores in distribution names are automatically removed if the name is modified.
|
|
||||||
* Autocomplete categories now properly respect theme colors.
|
|
||||||
* Functions in expressions (like indexOf, map...) now properly send errors when the arguments are of the wrong type or count.
|
|
||||||
* Executable Objects called (like functions, bode magnitures, phases...) now send an error if provided with no arguments.
|
|
||||||
* Function calls with no argument no longer make LogarithmPlotter crash under certain circumstances.
|
|
||||||
* Thank you dialog's lists are no longer draggable.
|
|
||||||
|
|
||||||
**Internal changes**
|
|
||||||
|
|
||||||
* A lot of inner changes led by porting to Qt6, fixing a lot of bugs at the same time.
|
|
||||||
* Disabled auto detect of visual theme if the `QT_QUICK_CONTROLS_STYLE` environment variable is set.
|
|
||||||
* (macOS, Windows, Flatpak) Drastically reducing installer sizes (more than halved).
|
|
||||||
* (Launchpad/Ubuntu) Using custom built packages of PySide6, meaning smaller installation and distro dependency.
|
|
||||||
|
|
||||||
## v0.3.0 (28 Oct 2022)
|
|
||||||
|
|
||||||
**New**
|
|
||||||
|
|
||||||
* New completely revamped expression editor:
|
|
||||||
* Automatic closing of parentheses and brackets (can be disabled in settings).
|
|
||||||
* Syntax highlighting (can be disabled in the settings).
|
|
||||||
* Autocompletion is now available (for functions, variables and constants, object names and properties) (can be disabled in the settings).
|
|
||||||
* Object properties can now be used in expressions (e.g. if you have a point named A, you can use A.x to access its x value).
|
|
||||||
* Executable objects can be now be used in expressions (e.g. if you have a function named 'f', it's accessible using `f(<value>)`).
|
|
||||||
* LaTeX-rendered formulas are now used in the Objects and History tabs when LaTeX rendering is enabled.
|
|
||||||
* Errors in formulas are now reported in message boxes.
|
|
||||||
|
|
||||||
**Changes**
|
|
||||||
|
|
||||||
* The Object Editor dialog has been completely reworked internally, resulting in notable performance improvements.
|
|
||||||
* Vast improvements to the objects system: names can no longer be shared amongst different objects.
|
|
||||||
* Disabled access to custom variable and function definition in expressions (can cause issues and vulnerabilities)
|
|
||||||
* When using the set position cursor, the position change is now saved a single history action.
|
|
||||||
* Distribution are now prefixed with an 'F_' to prevent confusion with X Cursors.
|
|
||||||
|
|
||||||
**Added translations**
|
|
||||||
|
|
||||||
* Autocompletion categories (English, French, German, Hungarian).
|
|
||||||
* Expression editor settings (English, French, German, Hungarian).
|
|
||||||
* Expression syntax errors (English, French, German, Hungarian).
|
|
||||||
* On top of the above:
|
|
||||||
* Hungarian: v0.2.0 added text (thanks @ovari!)
|
|
||||||
* Spanish: Menu bars (thanks @Sergio Varela)
|
|
||||||
* You can contribute to translation on [Weblate](https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/#repository).
|
|
||||||
|
|
||||||
**Fixed bugs**
|
|
||||||
|
|
||||||
* Fixing Texts not being properly recognized as texts when saving.
|
|
||||||
* Text's 'Disable LaTeX' property is now properly saved.
|
|
||||||
* X Cursors LaTeX rendering made the app crash.
|
|
||||||
* Attempting to insert special character no longer automatically saves the expression you're editing.
|
|
||||||
* Proper HDPI support for icons and buttons (note: HDPI is not available for the rendered canvas yet).
|
|
||||||
* Support for non-latin characters in variables (e.g. greek letters, subtext, suptext)
|
|
||||||
* Silent error when misentering variable names in the expression editor causing internal issues.
|
|
||||||
* Fixing some utils function simplifying parentheses when they shouldn't have.
|
|
||||||
* (flatpak and KDE SDK) Fixing the sometimes invisible buttons on the objects tab on startup.
|
|
||||||
* (macos) Application string version does not match LogarithmPlotter's version.
|
|
||||||
* (debian) (Normally) Fixing deb building.
|
|
||||||
|
|
||||||
**Internal changes**
|
|
||||||
|
|
||||||
* Object dependencies are now registered on both the dependant object, and the object it's depending on.
|
|
||||||
* Objects now have a proper per-name registry.
|
|
||||||
* Object Editor Dialog has been reworked to use loaders insteads.
|
|
||||||
* Reworked the file loading system to be able to load dependencies properly.
|
|
||||||
|
|
||||||
|
|
||||||
## v0.2.0 (22 Apr 2022)
|
## v0.2.0 (22 Apr 2022)
|
||||||
|
|
||||||
**New**
|
**New**
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""
|
"""
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -17,19 +17,19 @@
|
||||||
"""
|
"""
|
||||||
from shutil import which
|
from shutil import which
|
||||||
|
|
||||||
__VERSION__ = "0.6.0"
|
__VERSION__ = "0.3.0"
|
||||||
is_release = False
|
is_release = False
|
||||||
|
|
||||||
|
|
||||||
# Check if development version, if so get the date of the latest git patch
|
# Check if development version, if so get the date of the latest git patch
|
||||||
# and append it to the version string.
|
# and append it to the version string.
|
||||||
if not is_release and which('git') is not None:
|
if not is_release and which('git') is not None:
|
||||||
from os.path import realpath, join, dirname, exists
|
from os.path import realpath, join, dirname, exists
|
||||||
from subprocess import check_output
|
from subprocess import check_output
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
# Command to check date of latest git commit
|
# Command to check date of latest git commit
|
||||||
cmd = ['git', 'log', '--format=%ci', '-n 1']
|
cmd = ['git', 'log', '--format=%ci', '-n 1']
|
||||||
cwd = realpath(join(dirname(__file__), '..', '..', '..')) # Root LogarithmPlotter directory.
|
cwd = realpath(join(dirname(__file__), '..')) # Root AccountFree directory.
|
||||||
if exists(join(cwd, '.git')):
|
if exists(join(cwd, '.git')):
|
||||||
date_str = check_output(cmd, cwd=cwd).decode('utf-8').split(' ')[0]
|
date_str = check_output(cmd, cwd=cwd).decode('utf-8').split(' ')[0]
|
||||||
try:
|
try:
|
||||||
|
@ -39,3 +39,6 @@ if not is_release and which('git') is not None:
|
||||||
# Date cannot be parsed, not git root?
|
# Date cannot be parsed, not git root?
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
from .logarithmplotter import run
|
||||||
|
run()
|
|
@ -1,6 +1,6 @@
|
||||||
"""
|
"""
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -15,6 +15,6 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
"""
|
"""
|
||||||
from LogarithmPlotter.logarithmplotter import create_qapp
|
if __name__ == "__main__":
|
||||||
|
from .logarithmplotter import run
|
||||||
app = create_qapp()
|
run()
|
1555
LogarithmPlotter/i18n/lp_de.ts
Normal file
1555
LogarithmPlotter/i18n/lp_en.ts
Normal file
1460
LogarithmPlotter/i18n/lp_es.ts
Normal file
1564
LogarithmPlotter/i18n/lp_fr.ts
Normal file
1544
LogarithmPlotter/i18n/lp_hu.ts
Normal file
1535
LogarithmPlotter/i18n/lp_nb_NO.ts
Normal file
1460
LogarithmPlotter/i18n/lp_template.ts
Normal file
2
LogarithmPlotter/i18n/release.sh
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/bash
|
||||||
|
lrelease *.ts
|
2
LogarithmPlotter/i18n/update.sh
Executable file
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/bash
|
||||||
|
lupdate -extensions js,qs,qml,py -recursive .. -ts lp_*.ts
|
154
LogarithmPlotter/logarithmplotter.py
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
"""
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
from PySide2.QtWidgets import QApplication
|
||||||
|
from PySide2.QtQml import QQmlApplicationEngine
|
||||||
|
from PySide2.QtCore import Qt, QTranslator, QLocale
|
||||||
|
from PySide2.QtGui import QIcon
|
||||||
|
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
from os import getcwd, chdir, environ, path, remove, close
|
||||||
|
from platform import release as os_release
|
||||||
|
from sys import platform, argv, version as sys_version, exit
|
||||||
|
from sys import path as sys_path
|
||||||
|
|
||||||
|
start_time = time()
|
||||||
|
|
||||||
|
# Create the temporary directory for saving copied screenshots and latex files
|
||||||
|
tempdir = TemporaryDirectory()
|
||||||
|
tmpfile = path.join(tempdir.name, 'graph.png')
|
||||||
|
pwd = getcwd()
|
||||||
|
|
||||||
|
chdir(path.dirname(path.realpath(__file__)))
|
||||||
|
|
||||||
|
if path.realpath(path.join(getcwd(), "..")) not in sys_path:
|
||||||
|
sys_path.append(path.realpath(path.join(getcwd(), "..")))
|
||||||
|
|
||||||
|
|
||||||
|
from LogarithmPlotter import __VERSION__
|
||||||
|
from LogarithmPlotter.util import config, native
|
||||||
|
from LogarithmPlotter.util.update import check_for_updates
|
||||||
|
from LogarithmPlotter.util.helper import Helper
|
||||||
|
from LogarithmPlotter.util.latex import Latex
|
||||||
|
|
||||||
|
config.init()
|
||||||
|
|
||||||
|
def get_linux_theme():
|
||||||
|
des = {
|
||||||
|
"KDE": "org.kde.desktop",
|
||||||
|
"gnome": "default",
|
||||||
|
"lxqt": "fusion",
|
||||||
|
"mate": "fusion",
|
||||||
|
}
|
||||||
|
if "XDG_SESSION_DESKTOP" in environ:
|
||||||
|
return des[environ["XDG_SESSION_DESKTOP"]] if environ["XDG_SESSION_DESKTOP"] in des else "fusion"
|
||||||
|
else:
|
||||||
|
# Android
|
||||||
|
return "Material"
|
||||||
|
|
||||||
|
def run():
|
||||||
|
|
||||||
|
environ["QT_QUICK_CONTROLS_STYLE"] = {
|
||||||
|
"linux": get_linux_theme(),
|
||||||
|
"freebsd": get_linux_theme(),
|
||||||
|
"win32": "universal" if os_release == "10" else "fusion",
|
||||||
|
"cygwin": "fusion",
|
||||||
|
"darwin": "default"
|
||||||
|
}[platform]
|
||||||
|
|
||||||
|
dep_time = time()
|
||||||
|
print("Loaded dependencies in " + str((dep_time - start_time)*1000) + "ms.")
|
||||||
|
|
||||||
|
icon_fallbacks = QIcon.fallbackSearchPaths();
|
||||||
|
base_icon_path = path.join(getcwd(), "qml", "eu", "ad5001", "LogarithmPlotter", "icons")
|
||||||
|
icon_fallbacks.append(path.realpath(path.join(base_icon_path, "common")))
|
||||||
|
icon_fallbacks.append(path.realpath(path.join(base_icon_path, "objects")))
|
||||||
|
icon_fallbacks.append(path.realpath(path.join(base_icon_path, "history")))
|
||||||
|
icon_fallbacks.append(path.realpath(path.join(base_icon_path, "settings")))
|
||||||
|
icon_fallbacks.append(path.realpath(path.join(base_icon_path, "settings", "custom")))
|
||||||
|
QIcon.setFallbackSearchPaths(icon_fallbacks);
|
||||||
|
|
||||||
|
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
|
||||||
|
app = QApplication(argv)
|
||||||
|
app.setApplicationName("LogarithmPlotter")
|
||||||
|
app.setOrganizationName("Ad5001")
|
||||||
|
app.styleHints().setShowShortcutsInContextMenus(True)
|
||||||
|
app.setWindowIcon(QIcon(path.realpath(path.join(getcwd(), "logarithmplotter.svg"))))
|
||||||
|
|
||||||
|
# Installing translators
|
||||||
|
translator = QTranslator()
|
||||||
|
# Check if lang is forced.
|
||||||
|
forcedlang = [p for p in argv if p[:7]=="--lang="]
|
||||||
|
locale = QLocale(forcedlang[0][7:]) if len(forcedlang) > 0 else QLocale()
|
||||||
|
if (translator.load(locale, "lp", "_", path.realpath(path.join(getcwd(), "i18n")))):
|
||||||
|
app.installTranslator(translator);
|
||||||
|
|
||||||
|
# Installing macOS file handler.
|
||||||
|
macOSFileOpenHandler = None
|
||||||
|
if platform == "darwin":
|
||||||
|
macOSFileOpenHandler = native.MacOSFileOpenHandler()
|
||||||
|
app.installEventFilter(macOSFileOpenHandler)
|
||||||
|
|
||||||
|
engine = QQmlApplicationEngine()
|
||||||
|
global tmpfile
|
||||||
|
helper = Helper(pwd, tmpfile)
|
||||||
|
latex = Latex(tempdir)
|
||||||
|
engine.rootContext().setContextProperty("Helper", helper)
|
||||||
|
engine.rootContext().setContextProperty("Latex", latex)
|
||||||
|
engine.rootContext().setContextProperty("TestBuild", "--test-build" in argv)
|
||||||
|
engine.rootContext().setContextProperty("StartTime", dep_time)
|
||||||
|
|
||||||
|
app.translate("About","About LogarithmPlotter") # FOR SOME REASON, if this isn't included, Qt refuses to load the QML file.
|
||||||
|
|
||||||
|
engine.addImportPath(path.realpath(path.join(getcwd(), "qml")))
|
||||||
|
engine.load(path.realpath(path.join(getcwd(), "qml", "eu", "ad5001", "LogarithmPlotter", "LogarithmPlotter.qml")))
|
||||||
|
|
||||||
|
|
||||||
|
if not engine.rootObjects():
|
||||||
|
print("No root object", path.realpath(path.join(getcwd(), "qml")))
|
||||||
|
print(path.realpath(path.join(getcwd(), "qml", "eu", "ad5001", "LogarithmPlotter", "LogarithmPlotter.qml")))
|
||||||
|
exit(-1)
|
||||||
|
|
||||||
|
# Open the current diagram
|
||||||
|
chdir(pwd)
|
||||||
|
if len(argv) > 0 and path.exists(argv[-1]) and argv[-1].split('.')[-1] in ['lpf']:
|
||||||
|
engine.rootObjects()[0].loadDiagram(argv[-1])
|
||||||
|
chdir(path.dirname(path.realpath(__file__)))
|
||||||
|
|
||||||
|
if platform == "darwin":
|
||||||
|
macOSFileOpenHandler.init_graphics(engine.rootObjects()[0])
|
||||||
|
|
||||||
|
# Check for LaTeX installation if LaTeX support is enabled
|
||||||
|
if config.getSetting("enable_latex"):
|
||||||
|
latex.check_latex_install()
|
||||||
|
|
||||||
|
# Check for updates
|
||||||
|
if config.getSetting("check_for_updates"):
|
||||||
|
check_for_updates(__VERSION__, engine.rootObjects()[0])
|
||||||
|
|
||||||
|
exit_code = app.exec_()
|
||||||
|
|
||||||
|
tempdir.cleanup()
|
||||||
|
config.save()
|
||||||
|
exit(exit_code)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
run()
|
||||||
|
|
9
LogarithmPlotter/logarithmplotter.svg
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<svg id="SVGRoot" width="48" height="48" version="1.1" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<title>LogarithmPlotter Icon v1.0</title>
|
||||||
|
<g fill-rule="evenodd" stroke-width="2">
|
||||||
|
<rect width="48" height="48" ry="6" fill="#fff"/>
|
||||||
|
<rect x="2" y="38" width="44" height="4" stroke-opacity="0"/>
|
||||||
|
<rect x="18" y="2" width="4" height="44" stroke-opacity="0"/>
|
||||||
|
</g>
|
||||||
|
<path d="M 42.05,2 A 40.05,36.05 0 0 1 2,38.05" fill="none" stroke="#f00" stroke-width="3.9012"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 488 B |
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,11 +16,13 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick 2.12
|
||||||
import Qt.labs.platform as Native
|
import QtQuick.Dialogs 1.3
|
||||||
//import QtQuick.Controls 2.15
|
//import QtQuick.Controls 2.15
|
||||||
import eu.ad5001.MixedMenu 1.1
|
import eu.ad5001.MixedMenu 1.1
|
||||||
import eu.ad5001.LogarithmPlotter.Common
|
import "js/objects.js" as Objects
|
||||||
|
import "js/historylib.js" as HistoryLib
|
||||||
|
import "js/math/latex.js" as LatexJS
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -33,6 +35,7 @@ import eu.ad5001.LogarithmPlotter.Common
|
||||||
\sa LogarithmPlotter
|
\sa LogarithmPlotter
|
||||||
*/
|
*/
|
||||||
MenuBar {
|
MenuBar {
|
||||||
|
property var settings: settingsMenu
|
||||||
|
|
||||||
Menu {
|
Menu {
|
||||||
title: qsTr("&File")
|
title: qsTr("&File")
|
||||||
|
@ -41,7 +44,6 @@ MenuBar {
|
||||||
shortcut: StandardKey.Open
|
shortcut: StandardKey.Open
|
||||||
onTriggered: settings.load()
|
onTriggered: settings.load()
|
||||||
icon.name: 'document-open'
|
icon.name: 'document-open'
|
||||||
icon.color: sysPalette.windowText
|
|
||||||
|
|
||||||
}
|
}
|
||||||
Action {
|
Action {
|
||||||
|
@ -49,14 +51,13 @@ MenuBar {
|
||||||
shortcut: StandardKey.Save
|
shortcut: StandardKey.Save
|
||||||
onTriggered: settings.save()
|
onTriggered: settings.save()
|
||||||
icon.name: 'document-save'
|
icon.name: 'document-save'
|
||||||
icon.color: sysPalette.windowText
|
|
||||||
}
|
}
|
||||||
Action {
|
Action {
|
||||||
text: qsTr("Save &As...")
|
text: qsTr("Save &As...")
|
||||||
shortcut: StandardKey.SaveAs
|
shortcut: StandardKey.SaveAs
|
||||||
onTriggered: settings.saveAs()
|
onTriggered: settings.saveAs()
|
||||||
icon.color: sysPalette.windowText
|
|
||||||
icon.name: 'document-save-as'
|
icon.name: 'document-save-as'
|
||||||
|
|
||||||
}
|
}
|
||||||
MenuSeparator { }
|
MenuSeparator { }
|
||||||
Action {
|
Action {
|
||||||
|
@ -70,7 +71,6 @@ MenuBar {
|
||||||
}
|
}
|
||||||
|
|
||||||
icon.name: 'application-exit'
|
icon.name: 'application-exit'
|
||||||
icon.color: sysPalette.windowText
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,31 +79,25 @@ MenuBar {
|
||||||
Action {
|
Action {
|
||||||
text: qsTr("&Undo")
|
text: qsTr("&Undo")
|
||||||
shortcut: StandardKey.Undo
|
shortcut: StandardKey.Undo
|
||||||
onTriggered: Modules.History.undo()
|
onTriggered: history.undo()
|
||||||
icon.name: 'edit-undo'
|
icon.name: 'edit-undo'
|
||||||
icon.color: enabled ? sysPalette.windowText : sysPaletteIn.windowText
|
icon.color: enabled ? sysPalette.windowText : sysPaletteIn.windowText
|
||||||
|
enabled: history.undoCount > 0
|
||||||
}
|
}
|
||||||
Action {
|
Action {
|
||||||
text: qsTr("&Redo")
|
text: qsTr("&Redo")
|
||||||
shortcut: StandardKey.Redo
|
shortcut: StandardKey.Redo
|
||||||
onTriggered: Modules.History.redo()
|
onTriggered: history.redo()
|
||||||
icon.name: 'edit-redo'
|
icon.name: 'edit-redo'
|
||||||
icon.color: enabled ? sysPalette.windowText : sysPaletteIn.windowText
|
icon.color: enabled ? sysPalette.windowText : sysPaletteIn.windowText
|
||||||
|
enabled: history.redoCount > 0
|
||||||
}
|
}
|
||||||
|
MenuSeparator { }
|
||||||
Action {
|
Action {
|
||||||
text: qsTr("&Copy plot")
|
text: qsTr("&Copy plot")
|
||||||
shortcut: StandardKey.Copy
|
shortcut: StandardKey.Copy
|
||||||
onTriggered: root.copyDiagramToClipboard()
|
onTriggered: root.copyDiagramToClipboard()
|
||||||
icon.name: 'edit-copy'
|
icon.name: 'edit-copy'
|
||||||
icon.color: sysPalette.windowText
|
|
||||||
}
|
|
||||||
MenuSeparator { }
|
|
||||||
Action {
|
|
||||||
text: qsTr("&Preferences")
|
|
||||||
shortcut: StandardKey.Copy
|
|
||||||
onTriggered: preferences.open()
|
|
||||||
icon.name: 'settings'
|
|
||||||
icon.color: sysPalette.windowText
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,83 +105,147 @@ MenuBar {
|
||||||
title: qsTr("&Create")
|
title: qsTr("&Create")
|
||||||
// Services repeater
|
// Services repeater
|
||||||
Repeater {
|
Repeater {
|
||||||
model: Object.keys(Modules.Objects.types)
|
model: Object.keys(Objects.types)
|
||||||
|
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: Modules.Objects.types[modelData].displayType()
|
text: Objects.types[modelData].displayType()
|
||||||
visible: Modules.Objects.types[modelData].createable()
|
visible: Objects.types[modelData].createable()
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
icon.name: modelData
|
icon.name: modelData
|
||||||
icon.source: './icons/objects/' + modelData + '.svg'
|
icon.source: './icons/objects/' + modelData + '.svg'
|
||||||
icon.color: sysPalette.buttonText
|
icon.color: sysPalette.buttonText
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
var newObj = Modules.Objects.createNewRegisteredObject(modelData)
|
var newObj = Objects.createNewRegisteredObject(modelData)
|
||||||
Modules.History.addToHistory(new JS.HistoryLib.CreateNewObject(newObj.name, modelData, newObj.export()))
|
history.addToHistory(new HistoryLib.CreateNewObject(newObj.name, modelData, newObj.export()))
|
||||||
objectLists.update()
|
objectLists.update()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
id: settingsMenu
|
||||||
|
title: qsTr("&Settings")
|
||||||
|
Action {
|
||||||
|
id: checkForUpdatesMenuSetting
|
||||||
|
text: qsTr("Check for updates on startup")
|
||||||
|
checkable: true
|
||||||
|
checked: Helper.getSettingBool("check_for_updates")
|
||||||
|
onTriggered: Helper.setSettingBool("check_for_updates", checked)
|
||||||
|
icon.name: 'update'
|
||||||
|
}
|
||||||
|
|
||||||
|
Action {
|
||||||
|
id: resetRedoStackMenuSetting
|
||||||
|
text: qsTr("Reset redo stack automaticly")
|
||||||
|
checkable: true
|
||||||
|
checked: Helper.getSettingBool("reset_redo_stack")
|
||||||
|
onTriggered: Helper.setSettingBool("reset_redo_stack", checked)
|
||||||
|
icon.name: 'timeline'
|
||||||
|
}
|
||||||
|
|
||||||
|
Action {
|
||||||
|
id: enableLatexJSSetting
|
||||||
|
text: qsTr("Enable LaTeX rendering")
|
||||||
|
checkable: true
|
||||||
|
checked: Helper.getSettingBool("enable_latex")
|
||||||
|
onTriggered: {
|
||||||
|
Helper.setSettingBool("enable_latex", checked)
|
||||||
|
LatexJS.enabled = checked
|
||||||
|
drawCanvas.requestPaint()
|
||||||
|
}
|
||||||
|
icon.name: 'Expression'
|
||||||
|
}
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
title: qsTr("Expression editor")
|
||||||
|
|
||||||
|
Action {
|
||||||
|
id: autocloseFormulaSetting
|
||||||
|
text: qsTr("Automatically close parenthesises and brackets")
|
||||||
|
checkable: true
|
||||||
|
checked: Helper.getSettingBool("expression_editor.autoclose")
|
||||||
|
onTriggered: {
|
||||||
|
Helper.setSettingBool("expression_editor.autoclose", checked)
|
||||||
|
}
|
||||||
|
icon.name: 'Text'
|
||||||
|
}
|
||||||
|
|
||||||
|
Action {
|
||||||
|
id: colorizeFormulaSetting
|
||||||
|
text: qsTr("Enable syntax highlighting")
|
||||||
|
checkable: true
|
||||||
|
checked: Helper.getSettingBool("expression_editor.colorize")
|
||||||
|
onTriggered: {
|
||||||
|
Helper.setSettingBool("expression_editor.colorize", checked)
|
||||||
|
}
|
||||||
|
icon.name: 'appearance'
|
||||||
|
}
|
||||||
|
|
||||||
|
Action {
|
||||||
|
id: autocompleteFormulaSetting
|
||||||
|
text: qsTr("Enable autocompletion")
|
||||||
|
checkable: true
|
||||||
|
checked: Helper.getSettingBool("autocompletion.enabled")
|
||||||
|
onTriggered: {
|
||||||
|
Helper.setSettingBool("autocompletion.enabled", checked)
|
||||||
|
}
|
||||||
|
icon.name: 'label'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Menu {
|
Menu {
|
||||||
title: qsTr("&Help")
|
title: qsTr("&Help")
|
||||||
Action {
|
Action {
|
||||||
text: qsTr("&Source code")
|
text: qsTr("&Source code")
|
||||||
icon.name: 'software-sources'
|
icon.name: 'software-sources'
|
||||||
icon.color: sysPalette.windowText
|
|
||||||
onTriggered: Qt.openUrlExternally("https://git.ad5001.eu/Ad5001/LogarithmPlotter")
|
onTriggered: Qt.openUrlExternally("https://git.ad5001.eu/Ad5001/LogarithmPlotter")
|
||||||
}
|
}
|
||||||
Action {
|
Action {
|
||||||
text: qsTr("&Report a bug")
|
text: qsTr("&Report a bug")
|
||||||
icon.name: 'tools-report-bug'
|
icon.name: 'tools-report-bug'
|
||||||
icon.color: sysPalette.windowText
|
|
||||||
onTriggered: Qt.openUrlExternally("https://git.ad5001.eu/Ad5001/LogarithmPlotter/issues")
|
onTriggered: Qt.openUrlExternally("https://git.ad5001.eu/Ad5001/LogarithmPlotter/issues")
|
||||||
}
|
}
|
||||||
Action {
|
Action {
|
||||||
text: qsTr("&User manual")
|
text: qsTr("&User manual")
|
||||||
icon.name: 'documentation'
|
icon.name: 'documentation'
|
||||||
icon.color: sysPalette.windowText
|
|
||||||
onTriggered: Qt.openUrlExternally("https://git.ad5001.eu/Ad5001/LogarithmPlotter/wiki/_Sidebar")
|
onTriggered: Qt.openUrlExternally("https://git.ad5001.eu/Ad5001/LogarithmPlotter/wiki/_Sidebar")
|
||||||
}
|
}
|
||||||
Action {
|
Action {
|
||||||
text: qsTr("&Changelog")
|
text: qsTr("&Changelog")
|
||||||
icon.name: 'state-information'
|
icon.name: 'state-information'
|
||||||
icon.color: sysPalette.windowText
|
|
||||||
onTriggered: changelog.open()
|
onTriggered: changelog.open()
|
||||||
}
|
}
|
||||||
Action {
|
Action {
|
||||||
text: qsTr("&Help translating!")
|
text: qsTr("&Help translating!")
|
||||||
icon.name: 'translate'
|
icon.name: 'translator'
|
||||||
icon.color: sysPalette.windowText
|
|
||||||
onTriggered: Qt.openUrlExternally("https://hosted.weblate.org/engage/logarithmplotter/")
|
onTriggered: Qt.openUrlExternally("https://hosted.weblate.org/engage/logarithmplotter/")
|
||||||
}
|
}
|
||||||
MenuSeparator { }
|
MenuSeparator { }
|
||||||
Action {
|
Action {
|
||||||
text: qsTr("&Thanks")
|
text: qsTr("&Thanks")
|
||||||
icon.name: 'help-about'
|
icon.name: 'about'
|
||||||
icon.color: sysPalette.windowText
|
|
||||||
onTriggered: thanksTo.open()
|
onTriggered: thanksTo.open()
|
||||||
}
|
}
|
||||||
Action {
|
Action {
|
||||||
text: qsTr("&About")
|
text: qsTr("&About")
|
||||||
shortcut: StandardKey.HelpContents
|
shortcut: StandardKey.HelpContents
|
||||||
icon.name: 'help-about'
|
icon.name: 'about'
|
||||||
icon.color: sysPalette.windowText
|
|
||||||
onTriggered: about.open()
|
onTriggered: about.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Native.MessageDialog {
|
MessageDialog {
|
||||||
id: saveUnsavedChangesDialog
|
id: saveUnsavedChangesDialog
|
||||||
title: qsTr("Save unsaved changes?")
|
title: qsTr("Save unsaved changes?")
|
||||||
|
icon: StandardIcon.Question
|
||||||
text: qsTr("This plot contains unsaved changes. By doing this, all unsaved data will be lost. Continue?")
|
text: qsTr("This plot contains unsaved changes. By doing this, all unsaved data will be lost. Continue?")
|
||||||
buttons: Native.MessageDialog.Save | Native.MessageDialog.Discard | Native.MessageDialog.Cancel
|
standardButtons: StandardButton.Yes | StandardButton.No
|
||||||
|
onYes: Qt.quit()
|
||||||
onSaveClicked: settings.save()
|
|
||||||
onDiscardClicked: Qt.quit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function openSaveUnsavedChangesDialog() {
|
function showSaveUnsavedChangesDialog() {
|
||||||
saveUnsavedChangesDialog.open()
|
saveUnsavedChangesDialog.visible = true
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,219 @@
|
||||||
|
/**
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
import QtQml 2.12
|
||||||
|
import "../js/objects.js" as Objects
|
||||||
|
import "../js/historylib.js" as HistoryLib
|
||||||
|
import "../js/history/common.js" as HistoryCommon
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmltype History
|
||||||
|
\inqmlmodule eu.ad5001.LogarithmPlotter.History
|
||||||
|
\brief QObject holding persistantly for undo & redo stacks.
|
||||||
|
|
||||||
|
\sa HistoryBrowser, historylib
|
||||||
|
*/
|
||||||
|
Item {
|
||||||
|
// Using a QtObject is necessary in order to have proper property propagation in QML
|
||||||
|
id: historyObj
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty int History::undoCount
|
||||||
|
Count of undo actions.
|
||||||
|
*/
|
||||||
|
property int undoCount: 0
|
||||||
|
/*!
|
||||||
|
\qmlproperty int History::redoCount
|
||||||
|
Count of redo actions.
|
||||||
|
*/
|
||||||
|
property int redoCount: 0
|
||||||
|
/*!
|
||||||
|
\qmlproperty var History::undoStack
|
||||||
|
Stack of undo actions.
|
||||||
|
*/
|
||||||
|
property var undoStack: []
|
||||||
|
/*!
|
||||||
|
\qmlproperty var History::redoStack
|
||||||
|
Stack of redo actions.
|
||||||
|
*/
|
||||||
|
property var redoStack: []
|
||||||
|
/*!
|
||||||
|
\qmlproperty bool History::saved
|
||||||
|
true when no modification was done to the current working file, false otherwise.
|
||||||
|
*/
|
||||||
|
property bool saved: true
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void History::clear()
|
||||||
|
Clears both undo and redo stacks completly.
|
||||||
|
*/
|
||||||
|
function clear() {
|
||||||
|
undoCount = 0
|
||||||
|
redoCount = 0
|
||||||
|
undoStack = []
|
||||||
|
redoStack = []
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod var History::serialize()
|
||||||
|
Serializes history into JSON-able content.
|
||||||
|
*/
|
||||||
|
function serialize() {
|
||||||
|
let undoSt = [], redoSt = [];
|
||||||
|
for(let i = 0; i < undoCount; i++)
|
||||||
|
undoSt.push([
|
||||||
|
undoStack[i].type(),
|
||||||
|
undoStack[i].export()
|
||||||
|
]);
|
||||||
|
for(let i = 0; i < redoCount; i++)
|
||||||
|
redoSt.push([
|
||||||
|
redoStack[i].type(),
|
||||||
|
redoStack[i].export()
|
||||||
|
]);
|
||||||
|
return [undoSt, redoSt]
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void History::unserialize(var undoSt, var redoSt)
|
||||||
|
Unserializes both \c undoSt stack and \c redoSt stack from serialized content.
|
||||||
|
*/
|
||||||
|
function unserialize(undoSt, redoSt) {
|
||||||
|
clear();
|
||||||
|
for(let i = 0; i < undoSt.length; i++)
|
||||||
|
undoStack.push(new HistoryLib.Actions[undoSt[i][0]](...undoSt[i][1]))
|
||||||
|
for(let i = 0; i < redoSt.length; i++)
|
||||||
|
redoStack.push(new HistoryLib.Actions[redoSt[i][0]](...redoSt[i][1]))
|
||||||
|
undoCount = undoSt.length;
|
||||||
|
redoCount = redoSt.length;
|
||||||
|
objectLists.update()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void History::addToHistory(var action)
|
||||||
|
Adds an instance of historylib.Action to history.
|
||||||
|
*/
|
||||||
|
function addToHistory(action) {
|
||||||
|
if(action instanceof HistoryLib.Action) {
|
||||||
|
console.log("Added new entry to history: " + action.getReadableString())
|
||||||
|
undoStack.push(action)
|
||||||
|
undoCount++;
|
||||||
|
if(Helper.getSettingBool("reset_redo_stack")) {
|
||||||
|
redoStack = []
|
||||||
|
redoCount = 0
|
||||||
|
}
|
||||||
|
saved = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void History::undo(bool updateObjectList = true)
|
||||||
|
Undoes the historylib.Action at the top of the undo stack and pushes it to the top of the redo stack.
|
||||||
|
By default, will update the graph and the object list. This behavior can be disabled by setting the \c updateObjectList to false.
|
||||||
|
*/
|
||||||
|
function undo(updateObjectList = true) {
|
||||||
|
if(undoStack.length > 0) {
|
||||||
|
var action = undoStack.pop()
|
||||||
|
action.undo()
|
||||||
|
if(updateObjectList)
|
||||||
|
objectLists.update()
|
||||||
|
redoStack.push(action)
|
||||||
|
undoCount--;
|
||||||
|
redoCount++;
|
||||||
|
saved = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void History::redo(bool updateObjectList = true)
|
||||||
|
Redoes the historylib.Action at the top of the redo stack and pushes it to the top of the undo stack.
|
||||||
|
By default, will update the graph and the object list. This behavior can be disabled by setting the \c updateObjectList to false.
|
||||||
|
*/
|
||||||
|
function redo(updateObjectList = true) {
|
||||||
|
if(redoStack.length > 0) {
|
||||||
|
var action = redoStack.pop()
|
||||||
|
action.redo()
|
||||||
|
if(updateObjectList)
|
||||||
|
objectLists.update()
|
||||||
|
undoStack.push(action)
|
||||||
|
undoCount++;
|
||||||
|
redoCount--;
|
||||||
|
saved = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void History::undoMultipleDefered(int toUndoCount)
|
||||||
|
Undoes several historylib.Action at the top of the undo stack and pushes them to the top of the redo stack.
|
||||||
|
It undoes them deferedly to avoid overwhelming the computer while creating a cool short accelerated summary of all changes.
|
||||||
|
*/
|
||||||
|
function undoMultipleDefered(toUndoCount) {
|
||||||
|
undoTimer.toUndoCount = toUndoCount;
|
||||||
|
undoTimer.start()
|
||||||
|
if(toUndoCount > 0)
|
||||||
|
saved = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void History::redoMultipleDefered(int toRedoCount)
|
||||||
|
Redoes several historylib.Action at the top of the redo stack and pushes them to the top of the undo stack.
|
||||||
|
It redoes them deferedly to avoid overwhelming the computer while creating a cool short accelerated summary of all changes.
|
||||||
|
*/
|
||||||
|
function redoMultipleDefered(toRedoCount) {
|
||||||
|
redoTimer.toRedoCount = toRedoCount;
|
||||||
|
redoTimer.start()
|
||||||
|
if(toRedoCount > 0)
|
||||||
|
saved = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: undoTimer
|
||||||
|
interval: 5; running: false; repeat: true
|
||||||
|
property int toUndoCount: 0
|
||||||
|
onTriggered: {
|
||||||
|
if(toUndoCount > 0) {
|
||||||
|
historyObj.undo(toUndoCount % 4 == 1) // Only redraw once every 4 changes.
|
||||||
|
toUndoCount--;
|
||||||
|
} else {
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: redoTimer
|
||||||
|
interval: 5; running: false; repeat: true
|
||||||
|
property int toRedoCount: 0
|
||||||
|
onTriggered: {
|
||||||
|
if(toRedoCount > 0) {
|
||||||
|
historyObj.redo(toRedoCount % 4 == 1) // Only redraw once every 4 changes.
|
||||||
|
toRedoCount--;
|
||||||
|
} else {
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
HistoryLib.history = historyObj
|
||||||
|
HistoryCommon.themeTextColor = sysPalette.windowText
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,15 +16,14 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pragma ComponentBehavior: Bound
|
import QtQuick.Controls 2.12
|
||||||
|
import QtQuick 2.12
|
||||||
import QtQuick.Controls
|
|
||||||
import QtQuick
|
|
||||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||||
|
import "../js/utils.js" as Utils
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmltype Browser
|
\qmltype HistoryBrowser
|
||||||
\inqmlmodule eu.ad5001.LogarithmPlotter.History
|
\inqmlmodule eu.ad5001.LogarithmPlotter.History
|
||||||
\brief Tab of the drawer that allows to navigate through the undo and redo history.
|
\brief Tab of the drawer that allows to navigate through the undo and redo history.
|
||||||
|
|
||||||
|
@ -49,26 +48,12 @@ Item {
|
||||||
*/
|
*/
|
||||||
property bool darkTheme: isDarkTheme()
|
property bool darkTheme: isDarkTheme()
|
||||||
|
|
||||||
/*!
|
|
||||||
\qmlproperty int HistoryBrowser::undoCount
|
|
||||||
Number of actions in the undo stack.
|
|
||||||
*/
|
|
||||||
property int undoCount: 0
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\qmlproperty int HistoryBrowser::redoCount
|
|
||||||
Number of actions in the redo stack.
|
|
||||||
*/
|
|
||||||
property int redoCount: 0
|
|
||||||
|
|
||||||
Setting.TextSetting {
|
Setting.TextSetting {
|
||||||
id: filterInput
|
id: filterInput
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.rightMargin: 5
|
|
||||||
placeholderText: qsTr("Filter...")
|
placeholderText: qsTr("Filter...")
|
||||||
category: "all"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollView {
|
ScrollView {
|
||||||
|
@ -90,22 +75,19 @@ Item {
|
||||||
id: redoColumn
|
id: redoColumn
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
width: historyBrowser.actionWidth
|
width: actionWidth
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: historyBrowser.redoCount
|
model: history.redoCount
|
||||||
|
|
||||||
SingleItem {
|
HistoryItem {
|
||||||
id: redoButton
|
id: redoButton
|
||||||
width: historyBrowser.actionWidth
|
width: actionWidth
|
||||||
//height: actionHeight
|
//height: actionHeight
|
||||||
isRedo: true
|
isRedo: true
|
||||||
|
idx: index
|
||||||
darkTheme: historyBrowser.darkTheme
|
darkTheme: historyBrowser.darkTheme
|
||||||
hidden: !(filterInput.value == "" || content.includes(filterInput.value))
|
hidden: !(filterInput.value == "" || content.includes(filterInput.value))
|
||||||
onClicked: {
|
|
||||||
redoTimer.toRedoCount = Modules.History.redoStack.length-index
|
|
||||||
redoTimer.start()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,14 +100,14 @@ Item {
|
||||||
transform: Rotation { origin.x: 30; origin.y: 30; angle: 270}
|
transform: Rotation { origin.x: 30; origin.y: 30; angle: 270}
|
||||||
height: 70
|
height: 70
|
||||||
width: 20
|
width: 20
|
||||||
visible: historyBrowser.redoCount > 0
|
visible: history.redoCount > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: nowRect
|
id: nowRect
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: redoColumn.bottom
|
anchors.top: redoColumn.bottom
|
||||||
width: historyBrowser.actionWidth
|
width: actionWidth
|
||||||
height: 40
|
height: 40
|
||||||
color: sysPalette.highlight
|
color: sysPalette.highlight
|
||||||
Text {
|
Text {
|
||||||
|
@ -141,24 +123,20 @@ Item {
|
||||||
id: undoColumn
|
id: undoColumn
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: nowRect.bottom
|
anchors.top: nowRect.bottom
|
||||||
width: historyBrowser.actionWidth
|
width: actionWidth
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: historyBrowser.undoCount
|
model: history.undoCount
|
||||||
|
|
||||||
|
|
||||||
SingleItem {
|
HistoryItem {
|
||||||
id: undoButton
|
id: undoButton
|
||||||
width: historyBrowser.actionWidth
|
width: actionWidth
|
||||||
//height: actionHeight
|
//height: actionHeight
|
||||||
isRedo: false
|
isRedo: false
|
||||||
|
idx: index
|
||||||
darkTheme: historyBrowser.darkTheme
|
darkTheme: historyBrowser.darkTheme
|
||||||
hidden: !(filterInput.value == "" || content.includes(filterInput.value))
|
hidden: !(filterInput.value == "" || content.includes(filterInput.value))
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
undoTimer.toUndoCount = +index+1
|
|
||||||
undoTimer.start()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,39 +149,7 @@ Item {
|
||||||
transform: Rotation { origin.x: 30; origin.y: 30; angle: 270}
|
transform: Rotation { origin.x: 30; origin.y: 30; angle: 270}
|
||||||
height: 60
|
height: 60
|
||||||
width: 20
|
width: 20
|
||||||
visible: historyBrowser.undoCount > 0
|
visible: history.undoCount > 0
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: undoTimer
|
|
||||||
interval: 5; running: false; repeat: true
|
|
||||||
property int toUndoCount: 0
|
|
||||||
onTriggered: {
|
|
||||||
if(toUndoCount > 0) {
|
|
||||||
Modules.History.undo()
|
|
||||||
if(toUndoCount % 3 === 1)
|
|
||||||
Modules.Canvas.requestPaint()
|
|
||||||
toUndoCount--;
|
|
||||||
} else {
|
|
||||||
running = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: redoTimer
|
|
||||||
interval: 5; running: false; repeat: true
|
|
||||||
property int toRedoCount: 0
|
|
||||||
onTriggered: {
|
|
||||||
if(toRedoCount > 0) {
|
|
||||||
Modules.History.redo()
|
|
||||||
if(toRedoCount % 3 === 1)
|
|
||||||
Modules.Canvas.requestPaint()
|
|
||||||
toRedoCount--;
|
|
||||||
} else {
|
|
||||||
running = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,18 +162,6 @@ Item {
|
||||||
let hex = sysPalette.windowText.toString()
|
let hex = sysPalette.windowText.toString()
|
||||||
// We only check the first parameter, as on all normal OSes, text color is grayscale.
|
// We only check the first parameter, as on all normal OSes, text color is grayscale.
|
||||||
return parseInt(hex.substr(1,2), 16) > 128
|
return parseInt(hex.substr(1,2), 16) > 128
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
Modules.History.initialize({
|
|
||||||
helper: Helper,
|
|
||||||
themeTextColor: sysPalette.windowText.toString(),
|
|
||||||
imageDepth: Screen.devicePixelRatio,
|
|
||||||
fontSize: 14
|
|
||||||
})
|
|
||||||
Modules.History.on("cleared loaded added undone redone", () => {
|
|
||||||
undoCount = Modules.History.undoStack.length
|
|
||||||
redoCount = Modules.History.redoStack.length
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,13 +16,15 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick.Controls 2.12
|
||||||
import QtQuick.Controls
|
import QtQuick 2.12
|
||||||
|
import QtGraphicalEffects 1.15
|
||||||
|
import "../js/utils.js" as Utils
|
||||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmltype SingleItem
|
\qmltype HistoryItem
|
||||||
\inqmlmodule eu.ad5001.LogarithmPlotter.History
|
\inqmlmodule eu.ad5001.LogarithmPlotter.History
|
||||||
\brief Item representing an history action.
|
\brief Item representing an history action.
|
||||||
|
|
||||||
|
@ -40,17 +42,17 @@ Button {
|
||||||
\qmlproperty bool HistoryItem::isRedo
|
\qmlproperty bool HistoryItem::isRedo
|
||||||
true if the action is in the redo stack, false othewise.
|
true if the action is in the redo stack, false othewise.
|
||||||
*/
|
*/
|
||||||
required property bool isRedo
|
property bool isRedo
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty int HistoryItem::index
|
\qmlproperty int HistoryItem::idx
|
||||||
Index of the item within the HistoryBrowser list.
|
Index of the item within the HistoryBrowser list.
|
||||||
*/
|
*/
|
||||||
required property int index
|
property int idx
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty bool HistoryItem::darkTheme
|
\qmlproperty bool HistoryItem::darkTheme
|
||||||
true when the system is running with a dark theme, false otherwise.
|
true when the system is running with a dark theme, false otherwise.
|
||||||
*/
|
*/
|
||||||
required property bool darkTheme
|
property bool darkTheme
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty bool HistoryItem::hidden
|
\qmlproperty bool HistoryItem::hidden
|
||||||
true when the item is filtered out, false otherwise.
|
true when the item is filtered out, false otherwise.
|
||||||
|
@ -60,7 +62,7 @@ Button {
|
||||||
\qmlproperty int HistoryItem::historyAction
|
\qmlproperty int HistoryItem::historyAction
|
||||||
Associated history action.
|
Associated history action.
|
||||||
*/
|
*/
|
||||||
readonly property var historyAction: isRedo ? Modules.History.redoStack.at(index) : Modules.History.undoStack.at(-index-1)
|
readonly property var historyAction: isRedo ? history.redoStack[idx] : history.undoStack[history.undoCount-idx-1]
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty int HistoryItem::actionHeight
|
\qmlproperty int HistoryItem::actionHeight
|
||||||
|
@ -81,11 +83,12 @@ Button {
|
||||||
height: hidden ? 8 : Math.max(actionHeight, label.height + 15)
|
height: hidden ? 8 : Math.max(actionHeight, label.height + 15)
|
||||||
|
|
||||||
|
|
||||||
Rectangle {
|
LinearGradient {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
//opacity: hidden ? 0.6 : 1
|
//opacity: hidden ? 0.6 : 1
|
||||||
|
start: Qt.point(0, 0)
|
||||||
|
end: Qt.point(parent.width, 0)
|
||||||
gradient: Gradient {
|
gradient: Gradient {
|
||||||
orientation: Gradient.Horizontal
|
|
||||||
GradientStop { position: 0.1; color: "transparent" }
|
GradientStop { position: 0.1; color: "transparent" }
|
||||||
GradientStop { position: 1.5; color: clr }
|
GradientStop { position: 1.5; color: clr }
|
||||||
}
|
}
|
||||||
|
@ -113,23 +116,10 @@ Button {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: !hidden
|
visible: !hidden
|
||||||
font.pixelSize: 14
|
font.pixelSize: 14
|
||||||
text: ""
|
text: historyAction.getHTMLString().replace(/\$\{tag_color\}/g, clr)
|
||||||
textFormat: Text.RichText
|
textFormat: Text.RichText
|
||||||
clip: true
|
clip: true
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
|
|
||||||
Component.onCompleted: function() {
|
|
||||||
// Render HTML, might be string, but could also be a promise
|
|
||||||
const html = historyAction.getHTMLString()
|
|
||||||
if(typeof html === "string") {
|
|
||||||
label.text = html.replace(/\$\{tag_color\}/g, clr)
|
|
||||||
} else {
|
|
||||||
// Promise! We need to way to wait for it to be completed.
|
|
||||||
html.then(rendered => {
|
|
||||||
label.text = rendered.replace(/\$\{tag_color\}/g, clr)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
@ -142,9 +132,18 @@ Button {
|
||||||
color: sysPalette.windowText
|
color: sysPalette.windowText
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//text: content
|
||||||
|
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
ToolTip.delay: 200
|
ToolTip.delay: 200
|
||||||
ToolTip.text: content
|
ToolTip.text: content
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if(isRedo)
|
||||||
|
history.redoMultipleDefered(history.redoCount-idx)
|
||||||
|
else
|
||||||
|
history.undoMultipleDefered(+idx+1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
module eu.ad5001.LogarithmPlotter.History
|
||||||
|
|
||||||
|
History 1.0 History.qml
|
||||||
|
HistoryBrowser 1.0 HistoryBrowser.qml
|
||||||
|
HistoryItem 1.0 HistoryItem.qml
|
|
@ -0,0 +1,475 @@
|
||||||
|
/**
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
import "js/objects.js" as Objects
|
||||||
|
import "js/utils.js" as Utils
|
||||||
|
import "js/mathlib.js" as MathLib
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmltype LogGraphCanvas
|
||||||
|
\inqmlmodule eu.ad5001.LogarithmPlotter
|
||||||
|
\brief Canvas used to display the diagram.
|
||||||
|
|
||||||
|
Provides a customized canvas with several helper methods to be used by objects.
|
||||||
|
|
||||||
|
\sa LogarithmPlotter, PickLocationOverlay
|
||||||
|
*/
|
||||||
|
Canvas {
|
||||||
|
id: canvas
|
||||||
|
anchors.top: separator.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
height: parent.height - 90
|
||||||
|
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 int LogGraphCanvas::maxgradx
|
||||||
|
Max power of the logarithmic scaled on the x axis in logarithmic mode.
|
||||||
|
*/
|
||||||
|
property int maxgradx: 20
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty var LogGraphCanvas::yaxisstepExpr
|
||||||
|
Expression for the y axis step (used to create labels).
|
||||||
|
*/
|
||||||
|
property var yaxisstepExpr: (new MathLib.Expression(`x*(${yaxisstep})`))
|
||||||
|
/*!
|
||||||
|
\qmlproperty double LogGraphCanvas::yaxisstep1
|
||||||
|
Value of the for the y axis step.
|
||||||
|
*/
|
||||||
|
property double yaxisstep1: yaxisstepExpr.execute(1)
|
||||||
|
/*!
|
||||||
|
\qmlproperty int LogGraphCanvas::drawMaxY
|
||||||
|
Minimum value of y that should be drawn onto the canvas.
|
||||||
|
*/
|
||||||
|
property int drawMaxY: Math.ceil(Math.max(Math.abs(ymax), Math.abs(px2y(canvasSize.height)))/yaxisstep1)
|
||||||
|
/*!
|
||||||
|
\qmlproperty var LogGraphCanvas::xaxisstepExpr
|
||||||
|
Expression for the x axis step (used to create labels).
|
||||||
|
*/
|
||||||
|
property var xaxisstepExpr: (new MathLib.Expression(`x*(${xaxisstep})`))
|
||||||
|
/*!
|
||||||
|
\qmlproperty double LogGraphCanvas::xaxisstep1
|
||||||
|
Value of the for the x axis step.
|
||||||
|
*/
|
||||||
|
property double xaxisstep1: xaxisstepExpr.execute(1)
|
||||||
|
/*!
|
||||||
|
\qmlproperty int LogGraphCanvas::drawMaxX
|
||||||
|
Maximum value of x that should be drawn onto the canvas.
|
||||||
|
*/
|
||||||
|
property int drawMaxX: Math.ceil(Math.max(Math.abs(xmin), Math.abs(px2x(canvasSize.width)))/xaxisstep1)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty var LogGraphCanvas::imageLoaders
|
||||||
|
Dictionary of format {image: [callback.image data]} containing data for defered image loading.
|
||||||
|
*/
|
||||||
|
property var imageLoaders: {}
|
||||||
|
/*!
|
||||||
|
\qmlproperty var LogGraphCanvas::ctx
|
||||||
|
Cache for the 2D context so that it may be used asynchronously.
|
||||||
|
*/
|
||||||
|
property var ctx
|
||||||
|
|
||||||
|
Component.onCompleted: imageLoaders = {}
|
||||||
|
|
||||||
|
onPaint: function(rect) {
|
||||||
|
//console.log('Redrawing')
|
||||||
|
if(rect.width == canvas.width) { // Redraw full canvas
|
||||||
|
ctx = getContext("2d");
|
||||||
|
reset(ctx)
|
||||||
|
drawGrille(ctx)
|
||||||
|
drawAxises(ctx)
|
||||||
|
drawLabels(ctx)
|
||||||
|
ctx.lineWidth = linewidth
|
||||||
|
for(var objType in Objects.currentObjects) {
|
||||||
|
for(var obj of Objects.currentObjects[objType]){
|
||||||
|
ctx.strokeStyle = obj.color
|
||||||
|
ctx.fillStyle = obj.color
|
||||||
|
if(obj.visible) obj.draw(canvas, ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.lineWidth = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onImageLoaded: {
|
||||||
|
Object.keys(imageLoaders).forEach((key) => {
|
||||||
|
if(isImageLoaded(key)) {
|
||||||
|
// Calling callback
|
||||||
|
imageLoaders[key][0](canvas, ctx, imageLoaders[key][1])
|
||||||
|
delete imageLoaders[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void LogGraphCanvas::reset(var ctx)
|
||||||
|
Resets the canvas to a blank one with default setting using 2D \c ctx.
|
||||||
|
*/
|
||||||
|
function reset(ctx){
|
||||||
|
// Reset
|
||||||
|
ctx.fillStyle = "#FFFFFF"
|
||||||
|
ctx.strokeStyle = "#000000"
|
||||||
|
ctx.font = `${canvas.textsize}px sans-serif`
|
||||||
|
ctx.fillRect(0,0,width,height)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drawing the log based graph
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void LogGraphCanvas::drawGrille(var ctx)
|
||||||
|
Draws the grid using 2D \c ctx.
|
||||||
|
*/
|
||||||
|
function drawGrille(ctx) {
|
||||||
|
ctx.strokeStyle = "#C0C0C0"
|
||||||
|
if(logscalex) {
|
||||||
|
for(var xpow = -maxgradx; xpow <= maxgradx; xpow++) {
|
||||||
|
for(var xmulti = 1; xmulti < 10; xmulti++) {
|
||||||
|
drawXLine(ctx, Math.pow(10, xpow)*xmulti)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(var x = 0; x < drawMaxX; x+=1) {
|
||||||
|
drawXLine(ctx, x*xaxisstep1)
|
||||||
|
drawXLine(ctx, -x*xaxisstep1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(var y = 0; y < drawMaxY; y+=1) {
|
||||||
|
drawYLine(ctx, y*yaxisstep1)
|
||||||
|
drawYLine(ctx, -y*yaxisstep1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void LogGraphCanvas::drawAxises(var ctx)
|
||||||
|
Draws the graph axises using 2D \c ctx.
|
||||||
|
*/
|
||||||
|
function drawAxises(ctx) {
|
||||||
|
ctx.strokeStyle = "#000000"
|
||||||
|
var axisypos = logscalex ? 1 : 0
|
||||||
|
drawXLine(ctx, axisypos)
|
||||||
|
drawYLine(ctx, 0)
|
||||||
|
var axisypx = x2px(axisypos) // X coordinate of Y axis
|
||||||
|
var axisxpx = y2px(0) // Y coordinate of X axis
|
||||||
|
// Drawing arrows
|
||||||
|
drawLine(ctx, axisypx, 0, axisypx-10, 10)
|
||||||
|
drawLine(ctx, axisypx, 0, axisypx+10, 10)
|
||||||
|
drawLine(ctx, canvasSize.width, axisxpx, canvasSize.width-10, axisxpx-10)
|
||||||
|
drawLine(ctx, canvasSize.width, axisxpx, canvasSize.width-10, axisxpx+10)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void LogGraphCanvas::drawLabels(var ctx)
|
||||||
|
Draws all labels (graduation & axises labels) using 2D \c ctx.
|
||||||
|
*/
|
||||||
|
function drawLabels(ctx) {
|
||||||
|
var axisypx = x2px(logscalex ? 1 : 0) // X coordinate of Y axis
|
||||||
|
var axisxpx = y2px(0) // Y coordinate of X axis
|
||||||
|
// Labels
|
||||||
|
ctx.fillStyle = "#000000"
|
||||||
|
ctx.font = `${canvas.textsize}px sans-serif`
|
||||||
|
ctx.fillText(ylabel, axisypx+10, 24)
|
||||||
|
var textSize = ctx.measureText(xlabel).width
|
||||||
|
ctx.fillText(xlabel, canvasSize.width-14-textSize, axisxpx-5)
|
||||||
|
// Axis graduation labels
|
||||||
|
ctx.font = `${canvas.textsize-4}px sans-serif`
|
||||||
|
|
||||||
|
var txtMinus = ctx.measureText('-').width
|
||||||
|
if(showxgrad) {
|
||||||
|
if(logscalex) {
|
||||||
|
for(var xpow = -maxgradx; xpow <= maxgradx; xpow+=1) {
|
||||||
|
var textSize = ctx.measureText("10"+Utils.textsup(xpow)).width
|
||||||
|
if(xpow != 0)
|
||||||
|
drawVisibleText(ctx, "10"+Utils.textsup(xpow), x2px(Math.pow(10,xpow))-textSize/2, axisxpx+16+(6*(y==0)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(var x = 1; x < drawMaxX; x += 1) {
|
||||||
|
var drawX = x*xaxisstep1
|
||||||
|
var txtX = xaxisstepExpr.simplify(x)
|
||||||
|
var textSize = measureText(ctx, txtX, 6).height
|
||||||
|
drawVisibleText(ctx, txtX, x2px(drawX)-4, axisxpx+textsize/2+textSize)
|
||||||
|
drawVisibleText(ctx, '-'+txtX, x2px(-drawX)-4, axisxpx+textsize/2+textSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(showygrad) {
|
||||||
|
for(var y = 0; y < drawMaxY; y += 1) {
|
||||||
|
var drawY = y*yaxisstep1
|
||||||
|
var txtY = yaxisstepExpr.simplify(y)
|
||||||
|
var textSize = ctx.measureText(txtY).width
|
||||||
|
drawVisibleText(ctx, txtY, axisypx-6-textSize, y2px(drawY)+4+(10*(y==0)))
|
||||||
|
if(y != 0)
|
||||||
|
drawVisibleText(ctx, '-'+txtY, axisypx-6-textSize-txtMinus, y2px(-drawY)+4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.fillStyle = "#FFFFFF"
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void LogGraphCanvas::drawXLine(var ctx, double x)
|
||||||
|
Draws an horizontal line at \c x plot coordinate using 2D \c ctx.
|
||||||
|
*/
|
||||||
|
function drawXLine(ctx, x) {
|
||||||
|
if(visible(x, ymax)) {
|
||||||
|
drawLine(ctx, x2px(x), 0, x2px(x), canvasSize.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void LogGraphCanvas::drawXLine(var ctx, double x)
|
||||||
|
Draws an vertical line at \c y plot coordinate using 2D \c ctx.
|
||||||
|
*/
|
||||||
|
function drawYLine(ctx, y) {
|
||||||
|
if(visible(xmin, y)) {
|
||||||
|
drawLine(ctx, 0, y2px(y), canvasSize.width, y2px(y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void LogGraphCanvas::drawVisibleText(var ctx, string text, double x, double y)
|
||||||
|
Writes multline \c text onto the canvas using 2D \c ctx.
|
||||||
|
\note The \c x and \c y properties here are relative to the canvas, not the plot.
|
||||||
|
*/
|
||||||
|
function drawVisibleText(ctx, text, x, y) {
|
||||||
|
if(x > 0 && x < canvasSize.width && y > 0 && y < canvasSize.height) {
|
||||||
|
text.toString().split("\n").forEach(function(txt, i){
|
||||||
|
ctx.fillText(txt, x, y+(canvas.textsize*i))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void LogGraphCanvas::drawVisibleImage(var ctx, var image, double x, double y)
|
||||||
|
Draws an \c image onto the canvas using 2D \c ctx.
|
||||||
|
\note The \c x, \c y \c width and \c height properties here are relative to the canvas, not the plot.
|
||||||
|
*/
|
||||||
|
function drawVisibleImage(ctx, image, x, y, width, height) {
|
||||||
|
//console.log("Drawing image", isImageLoaded(image), isImageError(image))
|
||||||
|
markDirty(Qt.rect(x, y, width, height));
|
||||||
|
ctx.drawImage(image, x, y, width, height)
|
||||||
|
/*if(true || (x > 0 && x < canvasSize.width && y > 0 && y < canvasSize.height)) {
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod var LogGraphCanvas::measureText(var ctx, string text)
|
||||||
|
Measures the wicth and height of a multiline \c text that would be drawn onto the canvas using 2D \c ctx.
|
||||||
|
Return format: dictionary {"width": width, "height": height}
|
||||||
|
*/
|
||||||
|
function measureText(ctx, text) {
|
||||||
|
let theight = 0
|
||||||
|
let twidth = 0
|
||||||
|
let defaultHeight = ctx.measureText("M").width // Approximate but good enough!
|
||||||
|
text.split("\n").forEach(function(txt, i){
|
||||||
|
theight += defaultHeight
|
||||||
|
if(ctx.measureText(txt).width > twidth) twidth = ctx.measureText(txt).width
|
||||||
|
})
|
||||||
|
return {'width': twidth, 'height': theight}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod double LogGraphCanvas::x2px(double x)
|
||||||
|
Converts an \c x coordinate to it's relative position on the canvas.
|
||||||
|
It supports both logarithmic and non logarithmic scale depending on the currently selected mode.
|
||||||
|
*/
|
||||||
|
function x2px(x) {
|
||||||
|
if(logscalex) {
|
||||||
|
var logxmin = Math.log(xmin)
|
||||||
|
return (Math.log(x)-logxmin)*xzoom
|
||||||
|
} else return (x - xmin)*xzoom
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod double LogGraphCanvas::y2px(double y)
|
||||||
|
Converts an \c y coordinate to it's relative position on the canvas.
|
||||||
|
The y axis not supporting logarithmic scale, it only support linear convertion.
|
||||||
|
*/
|
||||||
|
function y2px(y) {
|
||||||
|
return (ymax-y)*yzoom
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod double LogGraphCanvas::px2x(double px)
|
||||||
|
Converts an x \c px position on the canvas to it's corresponding coordinate on the plot.
|
||||||
|
It supports both logarithmic and non logarithmic scale depending on the currently selected mode.
|
||||||
|
*/
|
||||||
|
function px2x(px) {
|
||||||
|
if(logscalex) {
|
||||||
|
return Math.exp(px/xzoom+Math.log(xmin))
|
||||||
|
} else return (px/xzoom+xmin)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod double LogGraphCanvas::px2x(double px)
|
||||||
|
Converts an x \c px position on the canvas to it's corresponding coordinate on the plot.
|
||||||
|
It supports both logarithmic and non logarithmic scale depending on the currently selected mode.
|
||||||
|
*/
|
||||||
|
function px2y(px) {
|
||||||
|
return -(px/yzoom-ymax)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod bool LogGraphCanvas::visible(double x, double y)
|
||||||
|
Checks whether a plot point (\c x, \c y) is visible or not on the canvas.
|
||||||
|
*/
|
||||||
|
function visible(x, y) {
|
||||||
|
return (x2px(x) >= 0 && x2px(x) <= canvasSize.width) && (y2px(y) >= 0 && y2px(y) <= canvasSize.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod bool LogGraphCanvas::drawLine(var ctx, double x1, double y1, double x2, double y2)
|
||||||
|
Draws a line from plot point (\c x1, \c y1) to plot point (\c x2, \¢ y2) using 2D \c ctx.
|
||||||
|
*/
|
||||||
|
function drawLine(ctx, x1, y1, x2, y2) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x1, y1);
|
||||||
|
ctx.lineTo(x2, y2);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod bool LogGraphCanvas::drawDashedLine2(var ctx, double x1, double y1, double x2, double y2)
|
||||||
|
Draws a dashed line from plot point (\c x1, \c y1) to plot point (\c x2, \¢ y2) using 2D \c ctx.
|
||||||
|
*/
|
||||||
|
function drawDashedLine2(ctx, x1, y1, x2, y2, dashPxSize = 5) {
|
||||||
|
ctx.setLineDash([dashPxSize, dashPxSize]);
|
||||||
|
drawLine(ctx, x1, y1, x2, y2)
|
||||||
|
ctx.setLineDash([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod bool LogGraphCanvas::drawDashedLine(var ctx, double x1, double y1, double x2, double y2)
|
||||||
|
Draws a dashed line from plot point (\c x1, \c y1) to plot point (\c x2, \¢ y2) using 2D \c ctx.
|
||||||
|
(Legacy slower method)
|
||||||
|
*/
|
||||||
|
function drawDashedLine(ctx, x1, y1, x2, y2, dashPxSize = 10) {
|
||||||
|
var distance = Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))
|
||||||
|
var progPerc = dashPxSize/distance
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x1, y1);
|
||||||
|
for(var i = 0; i < 1; i += progPerc) {
|
||||||
|
ctx.lineTo(x1-(x1-x2)*i, y1-(y1-y2)*i)
|
||||||
|
ctx.moveTo(x1-(x1-x2)*(i+progPerc/2), y1-(y1-y2)*(i+progPerc/2))
|
||||||
|
}
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod var LogGraphCanvas::renderLatexImage(string ltxText, color)
|
||||||
|
Renders latex markup \c ltxText to an image and loads it. Returns a dictionary with three values: source, width and height.
|
||||||
|
*/
|
||||||
|
function renderLatexImage(ltxText, color, callback) {
|
||||||
|
let [ltxSrc, ltxWidth, ltxHeight] = Latex.render(ltxText, textsize, color).split(",")
|
||||||
|
let imgData = {
|
||||||
|
"source": ltxSrc,
|
||||||
|
"width": parseFloat(ltxWidth),
|
||||||
|
"height": parseFloat(ltxHeight)
|
||||||
|
};
|
||||||
|
if(!isImageLoaded(ltxSrc) && !isImageLoading(ltxSrc)){
|
||||||
|
// Wait until the image is loaded to callback.
|
||||||
|
loadImage(ltxSrc)
|
||||||
|
imageLoaders[ltxSrc] = [callback, imgData]
|
||||||
|
} else {
|
||||||
|
// Callback directly
|
||||||
|
callback(canvas, ctx, imgData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,371 @@
|
||||||
|
/**
|
||||||
|
* 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 <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 "js/math/latex.js" as LatexJS
|
||||||
|
import eu.ad5001.LogarithmPlotter.History 1.0
|
||||||
|
import eu.ad5001.LogarithmPlotter.ObjectLists 1.0
|
||||||
|
import eu.ad5001.LogarithmPlotter.Popup 1.0 as Popup
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmltype LogarithmPlotter
|
||||||
|
\inqmlmodule eu.ad5001.LogarithmPlotter
|
||||||
|
\brief Main window of LogarithmPlotter
|
||||||
|
|
||||||
|
\sa AppMenuBar, History, GreetScreen, Changelog, Alert, ObjectLists, Settings, HistoryBrowser, LogGraphCanvas, PickLocationOverlay.
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
// LatexJS initialization.
|
||||||
|
LatexJS.enabled = Helper.getSettingBool("enable_latex")
|
||||||
|
LatexJS.Renderer = Latex
|
||||||
|
LatexJS.defaultColor = sysPalette.windowText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SystemPalette { id: sysPaletteIn; colorGroup: SystemPalette.Disabled }
|
||||||
|
|
||||||
|
menuBar: appMenu.trueItem
|
||||||
|
|
||||||
|
AppMenuBar {id: appMenu}
|
||||||
|
|
||||||
|
History { id: history }
|
||||||
|
|
||||||
|
Popup.GreetScreen {}
|
||||||
|
|
||||||
|
Popup.Changelog {id: changelog}
|
||||||
|
|
||||||
|
Popup.About {id: about}
|
||||||
|
|
||||||
|
Popup.ThanksTo {id: thanksTo}
|
||||||
|
|
||||||
|
Popup.Alert {
|
||||||
|
id: alert
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: 5
|
||||||
|
z: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: sidebar
|
||||||
|
width: 300
|
||||||
|
height: parent.height
|
||||||
|
//y: root.menuBar.height
|
||||||
|
readonly property bool inPortrait: root.width < root.height
|
||||||
|
/*modal: true// 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.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
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void LogarithmPlotter::saveDiagram(string filename)
|
||||||
|
Saves the diagram to a certain \c filename.
|
||||||
|
*/
|
||||||
|
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.xlabel,
|
||||||
|
"yaxislabel": settings.ylabel,
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void LogarithmPlotter::saveDiagram(string filename)
|
||||||
|
Loads the diagram from a certain \c filename.
|
||||||
|
*/
|
||||||
|
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.xlabel = data["xaxislabel"]
|
||||||
|
settings.ylabel = 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 = {}
|
||||||
|
Object.keys(Objects.currentObjectsByName).forEach(key => {
|
||||||
|
delete Objects.currentObjectsByName[key];
|
||||||
|
// Required to keep the same reference for the copy of the object used in expression variable detection.
|
||||||
|
// Another way would be to change the reference as well, but I feel like the code would be less clean.
|
||||||
|
})
|
||||||
|
for(let objType in data['objects']) {
|
||||||
|
if(Object.keys(Objects.types).indexOf(objType) > -1) {
|
||||||
|
Objects.currentObjects[objType] = []
|
||||||
|
for(let objData of data['objects'][objType]) {
|
||||||
|
let obj = new Objects.types[objType](...objData)
|
||||||
|
Objects.currentObjects[objType].push(obj)
|
||||||
|
Objects.currentObjectsByName[obj.name] = obj
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error += qsTr("Unknown object type: %1.").arg(objType) + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updating object dependencies.
|
||||||
|
for(let objName in Objects.currentObjectsByName)
|
||||||
|
Objects.currentObjectsByName[objName].update()
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void LogarithmPlotter::copyDiagramToClipboard()
|
||||||
|
Copies the current diagram image to the clipboard.
|
||||||
|
*/
|
||||||
|
function copyDiagramToClipboard() {
|
||||||
|
var file = Helper.gettmpfile()
|
||||||
|
drawCanvas.save(file)
|
||||||
|
Helper.copyImageToClipboard()
|
||||||
|
alert.show(qsTr("Copied plot screenshot to clipboard!"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void LogarithmPlotter::showAlert(string alertText)
|
||||||
|
Shows an alert on the diagram.
|
||||||
|
*/
|
||||||
|
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: Qt.openUrlExternally("https://dev.apps.ad5001.eu/logarithmplotter")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void LogarithmPlotter::showUpdateMenu()
|
||||||
|
Shows the update menu in the AppMenuBar.
|
||||||
|
*/
|
||||||
|
function showUpdateMenu() {
|
||||||
|
appMenu.addMenu(updateMenu)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,11 +16,13 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick 2.12
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls 2.12
|
||||||
import Qt.labs.platform as Native
|
|
||||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||||
import eu.ad5001.LogarithmPlotter.Common
|
import "../../js/objects.js" as Objects
|
||||||
|
import "../../js/historylib.js" as HistoryLib
|
||||||
|
import "../../js/utils.js" as Utils
|
||||||
|
import "../../js/mathlib.js" as MathLib
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmltype CustomPropertyList
|
\qmltype CustomPropertyList
|
||||||
|
@ -41,13 +43,8 @@ Repeater {
|
||||||
Object whose properties to list and edit.
|
Object whose properties to list and edit.
|
||||||
*/
|
*/
|
||||||
property var obj
|
property var obj
|
||||||
/*!
|
|
||||||
\qmlproperty var CustomPropertyList::positionPicker
|
|
||||||
Reference to the global PositionPicker QML object.
|
|
||||||
*/
|
|
||||||
property var positionPicker
|
|
||||||
|
|
||||||
readonly property var textTypes: ['Domain', 'string', 'number', 'int']
|
readonly property var textTypes: ['Domain', 'string', 'number']
|
||||||
readonly property var comboBoxTypes: ['ObjectType', 'Enum']
|
readonly property var comboBoxTypes: ['ObjectType', 'Enum']
|
||||||
readonly property var listTypes: ['List', 'Dict']
|
readonly property var listTypes: ['List', 'Dict']
|
||||||
|
|
||||||
|
@ -74,13 +71,13 @@ Repeater {
|
||||||
Setting.ExpressionEditor {
|
Setting.ExpressionEditor {
|
||||||
height: 30
|
height: 30
|
||||||
label: propertyLabel
|
label: propertyLabel
|
||||||
icon: `properties/${propertyIcon}.svg`
|
icon: `settings/custom/${propertyIcon}.svg`
|
||||||
defValue: JS.Utils.simplifyExpression(obj[propertyName].toEditableString())
|
defValue: Utils.simplifyExpression(obj[propertyName].toEditableString())
|
||||||
self: obj.name
|
self: obj.name
|
||||||
variables: propertyType.variables
|
variables: propertyType.variables
|
||||||
onChanged: function(newExpr) {
|
onChanged: function(newExpr) {
|
||||||
if(obj[propertyName].toString() != newExpr.toString()) {
|
if(obj[propertyName].toString() != newExpr.toString()) {
|
||||||
Modules.History.addToHistory(new JS.HistoryLib.EditedProperty(
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
obj.name, objType, propertyName,
|
obj.name, objType, propertyName,
|
||||||
obj[propertyName], newExpr
|
obj[propertyName], newExpr
|
||||||
))
|
))
|
||||||
|
@ -99,31 +96,20 @@ Repeater {
|
||||||
Setting.TextSetting {
|
Setting.TextSetting {
|
||||||
height: 30
|
height: 30
|
||||||
label: propertyLabel
|
label: propertyLabel
|
||||||
icon: `properties/${propertyIcon}.svg`
|
icon: `settings/custom/${propertyIcon}.svg`
|
||||||
min: propertyType == "int" ? 0 : -Infinity
|
isDouble: propertyType == 'number'
|
||||||
isInt: propertyType == "int"
|
|
||||||
isDouble: propertyType == "number"
|
|
||||||
defValue: obj[propertyName] == null ? '' : obj[propertyName].toString()
|
defValue: obj[propertyName] == null ? '' : obj[propertyName].toString()
|
||||||
category: {
|
|
||||||
return {
|
|
||||||
"Domain": "domain",
|
|
||||||
"string": "all",
|
|
||||||
"number": "all",
|
|
||||||
"int": "all",
|
|
||||||
}[propertyType]
|
|
||||||
}
|
|
||||||
onChanged: function(newValue) {
|
onChanged: function(newValue) {
|
||||||
try {
|
try {
|
||||||
var newValueParsed = {
|
var newValueParsed = {
|
||||||
"Domain": () => JS.MathLib.parseDomain(newValue),
|
'Domain': () => MathLib.parseDomain(newValue),
|
||||||
"string": () => newValue,
|
'string': () => newValue,
|
||||||
"number": () => newValue,
|
'number': () => parseFloat(newValue)
|
||||||
"int": () => newValue
|
|
||||||
}[propertyType]()
|
}[propertyType]()
|
||||||
|
|
||||||
// Ensuring old and new values are different to prevent useless adding to history.
|
// Ensuring old and new values are different to prevent useless adding to history.
|
||||||
if(obj[propertyName] != newValueParsed) {
|
if(obj[propertyName] != newValueParsed) {
|
||||||
Modules.History.addToHistory(new JS.HistoryLib.EditedProperty(
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
obj.name, objType, propertyName,
|
obj.name, objType, propertyName,
|
||||||
obj[propertyName], newValueParsed
|
obj[propertyName], newValueParsed
|
||||||
))
|
))
|
||||||
|
@ -132,23 +118,20 @@ Repeater {
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
// Error in expression or domain
|
// Error in expression or domain
|
||||||
console.trace()
|
|
||||||
parsingErrorDialog.showDialog(propertyName, newValue, e.message)
|
parsingErrorDialog.showDialog(propertyName, newValue, e.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Native.MessageDialog {
|
// D.MessageDialog {
|
||||||
id: parsingErrorDialog
|
// id: parsingErrorDialog
|
||||||
title: qsTranslate("expression", "LogarithmPlotter - Parsing error")
|
// title: qsTranslate("expression", "LogarithmPlotter - Parsing error")
|
||||||
text: ""
|
// text: ""
|
||||||
function showDialog(propName, propValue, error) {
|
// function showDialog(propName, propValue, error) {
|
||||||
text = qsTranslate("error", "Error while parsing expression for property %1:\n%2\n\nEvaluated expression: %3")
|
// text = qsTranslate("error", "Error while parsing expression for property %1:\n%2\n\nEvaluated expression: %3").arg(propName).arg(error).arg(propValue)
|
||||||
.arg(qsTranslate('prop', propName))
|
// open()
|
||||||
.arg(error).arg(propValue)
|
// }
|
||||||
open()
|
// }
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +142,7 @@ Repeater {
|
||||||
CheckBox {
|
CheckBox {
|
||||||
height: 20
|
height: 20
|
||||||
text: propertyLabel
|
text: propertyLabel
|
||||||
//icon: `properties/${propertyIcon}.svg`
|
//icon: `settings/custom/${propertyIcon}.svg`
|
||||||
|
|
||||||
checked: {
|
checked: {
|
||||||
//if(obj[propertyName] == null) {
|
//if(obj[propertyName] == null) {
|
||||||
|
@ -168,7 +151,7 @@ Repeater {
|
||||||
return obj[propertyName]
|
return obj[propertyName]
|
||||||
}
|
}
|
||||||
onClicked: {
|
onClicked: {
|
||||||
Modules.History.addToHistory(new JS.HistoryLib.EditedProperty(
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
obj.name, objType, propertyName,
|
obj.name, objType, propertyName,
|
||||||
obj[propertyName], this.checked
|
obj[propertyName], this.checked
|
||||||
))
|
))
|
||||||
|
@ -185,15 +168,15 @@ Repeater {
|
||||||
Setting.ComboBoxSetting {
|
Setting.ComboBoxSetting {
|
||||||
height: 30
|
height: 30
|
||||||
label: propertyLabel
|
label: propertyLabel
|
||||||
icon: `properties/${propertyIcon}.svg`
|
icon: `settings/custom/${propertyIcon}.svg`
|
||||||
// True to select an object of type, false for enums.
|
// True to select an object of type, false for enums.
|
||||||
property bool selectObjMode: paramTypeIn(propertyType, ['ObjectType'])
|
property bool selectObjMode: paramTypeIn(propertyType, ['ObjectType'])
|
||||||
property bool isRealObject: !selectObjMode || (propertyType.objType != "ExecutableObject" && propertyType.objType != "DrawableObject")
|
property bool isRealObject: !selectObjMode || (propertyType.objType != "ExecutableObject" && propertyType.objType != "DrawableObject")
|
||||||
|
|
||||||
// Base, untranslated version of the model.
|
// Base, untranslated version of the model.
|
||||||
property var baseModel: selectObjMode ?
|
property var baseModel: selectObjMode ?
|
||||||
Modules.Objects.getObjectsName(propertyType.objType).concat(
|
Objects.getObjectsName(propertyType.objType).concat(
|
||||||
isRealObject ? [qsTr("+ Create new %1").arg(Modules.Objects.types[propertyType.objType].displayType())] : [])
|
isRealObject ? [qsTr("+ Create new %1").arg(Objects.types[propertyType.objType].displayType())] : [])
|
||||||
: propertyType.values
|
: propertyType.values
|
||||||
// Translated version of the model.
|
// Translated version of the model.
|
||||||
model: selectObjMode ? baseModel : propertyType.translatedValues
|
model: selectObjMode ? baseModel : propertyType.translatedValues
|
||||||
|
@ -203,32 +186,30 @@ Repeater {
|
||||||
if(selectObjMode) {
|
if(selectObjMode) {
|
||||||
// This is only done when what we're selecting are Objects.
|
// This is only done when what we're selecting are Objects.
|
||||||
// Setting object property.
|
// Setting object property.
|
||||||
var selectedObj = Modules.Objects.currentObjectsByName[baseModel[newIndex]]
|
var selectedObj = Objects.currentObjectsByName[baseModel[newIndex]]
|
||||||
if(newIndex != 0) {
|
if(newIndex != 0) {
|
||||||
// Make sure we don't set the object to null.
|
// Make sure we don't set the object to null.
|
||||||
if(selectedObj == null) {
|
if(selectedObj == null) {
|
||||||
// Creating new object.
|
// Creating new object.
|
||||||
selectedObj = Modules.Objects.createNewRegisteredObject(propertyType.objType)
|
selectedObj = Objects.createNewRegisteredObject(propertyType.objType)
|
||||||
Modules.History.addToHistory(
|
history.addToHistory(new HistoryLib.CreateNewObject(selectedObj.name, propertyType.objType, selectedObj.export()))
|
||||||
new JS.HistoryLib.CreateNewObject(selectedObj.name, propertyType.objType, selectedObj.export())
|
baseModel = Objects.getObjectsName(propertyType.objType).concat(
|
||||||
)
|
isRealObject ? [qsTr("+ Create new %1").arg(Objects.types[propertyType.objType].displayType())] :
|
||||||
baseModel = Modules.Objects.getObjectsName(propertyType.objType).concat(
|
|
||||||
isRealObject ? [qsTr("+ Create new %1").arg(Modules.Objects.types[propertyType.objType].displayType())] :
|
|
||||||
[])
|
[])
|
||||||
currentIndex = baseModel.indexOf(selectedObj.name)
|
currentIndex = baseModel.indexOf(selectedObj.name)
|
||||||
}
|
}
|
||||||
selectedObj.requiredBy.push(Modules.Objects.currentObjects[objType][objIndex])
|
selectedObj.requiredBy.push(Objects.currentObjects[objType][objIndex])
|
||||||
//Modules.Objects.currentObjects[objType][objIndex].requiredBy = obj[propertyName].filter((obj) => obj.name != obj.name)
|
//Objects.currentObjects[objType][objIndex].requiredBy = obj[propertyName].filter((obj) => obj.name != obj.name)
|
||||||
}
|
}
|
||||||
obj.requiredBy = obj.requiredBy.filter((obj) => obj.name != obj.name)
|
obj.requiredBy = obj.requiredBy.filter((obj) => obj.name != obj.name)
|
||||||
Modules.History.addToHistory(new JS.HistoryLib.EditedProperty(
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
obj.name, objType, propertyName,
|
obj.name, objType, propertyName,
|
||||||
obj[propertyName], selectedObj
|
obj[propertyName], selectedObj
|
||||||
))
|
))
|
||||||
obj[propertyName] = selectedObj
|
obj[propertyName] = selectedObj
|
||||||
} else if(baseModel[newIndex] != obj[propertyName]) {
|
} else if(baseModel[newIndex] != obj[propertyName]) {
|
||||||
// Ensuring new property is different to not add useless history entries.
|
// Ensuring new property is different to not add useless history entries.
|
||||||
Modules.History.addToHistory(new JS.HistoryLib.EditedProperty(
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
obj.name, objType, propertyName,
|
obj.name, objType, propertyName,
|
||||||
obj[propertyName], baseModel[newIndex]
|
obj[propertyName], baseModel[newIndex]
|
||||||
))
|
))
|
||||||
|
@ -246,7 +227,7 @@ Repeater {
|
||||||
|
|
||||||
Setting.ListSetting {
|
Setting.ListSetting {
|
||||||
label: propertyLabel
|
label: propertyLabel
|
||||||
//icon: `properties/${propertyIcon}.svg`
|
//icon: `settings/custom/${propertyIcon}.svg`
|
||||||
dictionaryMode: paramTypeIn(propertyType, ['Dict'])
|
dictionaryMode: paramTypeIn(propertyType, ['Dict'])
|
||||||
keyType: dictionaryMode ? propertyType.keyType : 'string'
|
keyType: dictionaryMode ? propertyType.keyType : 'string'
|
||||||
valueType: propertyType.valueType
|
valueType: propertyType.valueType
|
||||||
|
@ -258,10 +239,11 @@ Repeater {
|
||||||
|
|
||||||
onChanged: {
|
onChanged: {
|
||||||
var exported = exportModel()
|
var exported = exportModel()
|
||||||
Modules.History.addToHistory(new JS.HistoryLib.EditedProperty(
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
obj.name, objType, propertyName,
|
obj.name, objType, propertyName,
|
||||||
obj[propertyName], exported
|
obj[propertyName], exported
|
||||||
))
|
))
|
||||||
|
//Objects.currentObjects[objType][objIndex][propertyName] = exported
|
||||||
obj[propertyName] = exported
|
obj[propertyName] = exported
|
||||||
root.changed()
|
root.changed()
|
||||||
}
|
}
|
||||||
|
@ -273,17 +255,13 @@ Repeater {
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: Component {
|
delegate: Component {
|
||||||
Row {
|
|
||||||
width: dlgProperties.width
|
|
||||||
spacing: 5
|
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: propertyEditor
|
//height: customPropComment.height + customPropText.height + customPropCheckBox.height + customPropCombo.height + customPropListDict.height
|
||||||
width: dlgProperties.width - pointerButton.width
|
width: dlgProperties.width
|
||||||
property string propertyName: modelData[0]
|
property string propertyName: modelData[0]
|
||||||
property var propertyType: modelData[1]
|
property var propertyType: modelData[1]
|
||||||
property string propertyLabel: qsTranslate('prop',propertyName)
|
property string propertyLabel: qsTranslate('prop',propertyName)
|
||||||
property string propertyIcon: propertyName
|
property string propertyIcon: Utils.camelCase2readable(propertyName)
|
||||||
|
|
||||||
sourceComponent: {
|
sourceComponent: {
|
||||||
if(propertyName.startsWith('comment'))
|
if(propertyName.startsWith('comment'))
|
||||||
|
@ -302,40 +280,5 @@ Repeater {
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
|
||||||
id: pointerButton
|
|
||||||
height: parent.height
|
|
||||||
width: visible ? height : 0
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
property bool isXProp: ['labelX', 'x'].includes(propertyEditor.propertyName)
|
|
||||||
property bool isYProp: ['y'].includes(propertyEditor.propertyName)
|
|
||||||
visible: isXProp || isYProp
|
|
||||||
ToolTip.visible: hovered
|
|
||||||
ToolTip.text: qsTr("Pick on graph")
|
|
||||||
|
|
||||||
Setting.Icon {
|
|
||||||
id: icon
|
|
||||||
width: 18
|
|
||||||
height: 18
|
|
||||||
anchors.centerIn: parent
|
|
||||||
|
|
||||||
color: sysPalette.windowText
|
|
||||||
source: '../icons/common/position.svg'
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
positionPicker.objType = objType
|
|
||||||
positionPicker.objName = obj.name
|
|
||||||
positionPicker.pickX = isXProp
|
|
||||||
positionPicker.pickY = isYProp
|
|
||||||
positionPicker.propertyX = propertyEditor.propertyName
|
|
||||||
positionPicker.propertyY = propertyEditor.propertyName
|
|
||||||
positionPicker.visible = true
|
|
||||||
objEditor.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
/**
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Controls 2.12
|
||||||
|
import QtQuick.Dialogs 1.3 as D
|
||||||
|
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||||
|
import "../../js/objects.js" as Objects
|
||||||
|
import "../../js/objs/common.js" as ObjectsCommons
|
||||||
|
import "../../js/historylib.js" as HistoryLib
|
||||||
|
import "../../js/utils.js" as Utils
|
||||||
|
import "../../js/mathlib.js" as MathLib
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmltype Dialog
|
||||||
|
\inqmlmodule eu.ad5001.LogarithmPlotter.ObjectLists.Editor
|
||||||
|
\brief Dialog used to edit properties of objects.
|
||||||
|
|
||||||
|
This class contains the dialog that allows to edit all properties of objects.
|
||||||
|
\todo In the future, this class should be optimized so that each property doesn't instanciate one instance of each setting type.
|
||||||
|
|
||||||
|
\sa Loader, ObjectLists
|
||||||
|
*/
|
||||||
|
D.Dialog {
|
||||||
|
id: objEditor
|
||||||
|
/*!
|
||||||
|
\qmlproperty string EditorDialog::objType
|
||||||
|
Type of object being edited by the dialog.
|
||||||
|
*/
|
||||||
|
property string objType: 'Point'
|
||||||
|
/*!
|
||||||
|
\qmlproperty int EditorDialog::objIndex
|
||||||
|
Index of the objects amongst the ones of it's type.
|
||||||
|
*/
|
||||||
|
property int objIndex: 0
|
||||||
|
/*!
|
||||||
|
\qmlproperty var EditorDialog::obj
|
||||||
|
Instance of the object being edited.
|
||||||
|
*/
|
||||||
|
property var obj: Objects.currentObjects[objType][objIndex]
|
||||||
|
|
||||||
|
title: "LogarithmPlotter"
|
||||||
|
width: 350
|
||||||
|
height: 400
|
||||||
|
|
||||||
|
// Disable closing on return/enter, causing issues with autocomplete.
|
||||||
|
onActionChosen: if(action.key == Qt.Key_Enter || action.key == Qt.Key_Return) action.accepted = false
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: dlgTitle
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
text: qsTr("Edit properties of %1 %2").arg(Objects.types[objEditor.objType].displayType()).arg(objEditor.obj.name)
|
||||||
|
font.pixelSize: 20
|
||||||
|
color: sysPalette.windowText
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: dlgProperties
|
||||||
|
anchors.top: dlgTitle.bottom
|
||||||
|
width: objEditor.width - 20
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
D.MessageDialog {
|
||||||
|
id: invalidNameDialog
|
||||||
|
title: qsTr("LogarithmPlotter - Invalid object name")
|
||||||
|
text: ""
|
||||||
|
function showDialog(objectName) {
|
||||||
|
text = qsTr("An object with the name '%1' already exists.").arg(objectName)
|
||||||
|
open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Setting.TextSetting {
|
||||||
|
id: nameProperty
|
||||||
|
height: 30
|
||||||
|
label: qsTr("Name")
|
||||||
|
icon: "common/label.svg"
|
||||||
|
width: dlgProperties.width
|
||||||
|
value: objEditor.obj.name
|
||||||
|
onChanged: function(newValue) {
|
||||||
|
let newName = Utils.parseName(newValue)
|
||||||
|
if(newName != '' && objEditor.obj.name != newName) {
|
||||||
|
if(newName in Objects.currentObjectsByName) {
|
||||||
|
invalidNameDialog.showDialog(newName)
|
||||||
|
} else {
|
||||||
|
history.addToHistory(new HistoryLib.NameChanged(
|
||||||
|
objEditor.obj.name, objEditor.objType, newName
|
||||||
|
))
|
||||||
|
Objects.renameObject(obj.name, newName)
|
||||||
|
objEditor.obj = Objects.currentObjects[objEditor.objType][objEditor.objIndex]
|
||||||
|
objectListList.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Setting.ComboBoxSetting {
|
||||||
|
id: labelContentProperty
|
||||||
|
height: 30
|
||||||
|
width: dlgProperties.width
|
||||||
|
label: qsTr("Label content")
|
||||||
|
model: [qsTr("null"), qsTr("name"), qsTr("name + value")]
|
||||||
|
property var idModel: ["null", "name", "name + value"]
|
||||||
|
icon: "common/label.svg"
|
||||||
|
currentIndex: idModel.indexOf(objEditor.obj.labelContent)
|
||||||
|
onActivated: function(newIndex) {
|
||||||
|
if(idModel[newIndex] != objEditor.obj.labelContent) {
|
||||||
|
objEditor.obj.labelContent = idModel[newIndex]
|
||||||
|
objEditor.obj.update()
|
||||||
|
objectListList.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dynamic properties
|
||||||
|
CustomPropertyList {
|
||||||
|
id: dlgCustomProperties
|
||||||
|
obj: objEditor.obj
|
||||||
|
|
||||||
|
onChanged: {
|
||||||
|
obj.update()
|
||||||
|
objectListList.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void EditorDialog::show()
|
||||||
|
Shows the editor after the object to be edited is set.
|
||||||
|
*/
|
||||||
|
function show() {
|
||||||
|
dlgCustomProperties.model = [] // Reset
|
||||||
|
let objProps = Objects.types[objEditor.objType].properties()
|
||||||
|
dlgCustomProperties.model = Object.keys(objProps).map(prop => [prop, objProps[prop]]) // Converted to 2-dimentional array.
|
||||||
|
objEditor.open()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,10 +16,11 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick 2.12
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls 2.12
|
||||||
|
import "../js/objects.js" as Objects
|
||||||
|
import "../js/historylib.js" as HistoryLib
|
||||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||||
import eu.ad5001.LogarithmPlotter.Common
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -33,21 +34,6 @@ Column {
|
||||||
id: createRow
|
id: createRow
|
||||||
property var objectEditor
|
property var objectEditor
|
||||||
property var objectLists
|
property var objectLists
|
||||||
property var posPicker
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\qmlmethod int ObjectCreationGrid::openEditorDialog(var obj)
|
|
||||||
Opens the editor dialog for an object \c obj.
|
|
||||||
*/
|
|
||||||
function openEditorDialog(obj) {
|
|
||||||
// Open editor
|
|
||||||
objectEditor.obj = obj
|
|
||||||
objectEditor.objType = obj.type
|
|
||||||
objectEditor.objIndex = Modules.Objects.currentObjects[obj.type].indexOf(obj)
|
|
||||||
objectEditor.open()
|
|
||||||
// Disconnect potential link
|
|
||||||
posPicker.picked.disconnect(openEditorDialog)
|
|
||||||
}
|
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
id: createTitle
|
id: createTitle
|
||||||
|
@ -60,12 +46,12 @@ Column {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
columns: 3
|
columns: 3
|
||||||
Repeater {
|
Repeater {
|
||||||
model: Object.keys(Modules.Objects.types)
|
model: Object.keys(Objects.types)
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: createBtn
|
id: createBtn
|
||||||
width: 96
|
width: 96
|
||||||
visible: Modules.Objects.types[modelData].createable()
|
visible: Objects.types[modelData].createable()
|
||||||
height: visible ? width*0.8 : 0
|
height: visible ? width*0.8 : 0
|
||||||
// The KDE SDK is kinda buggy, so it respects neither specified color nor display propreties.
|
// The KDE SDK is kinda buggy, so it respects neither specified color nor display propreties.
|
||||||
//display: AbstractButton.TextUnderIcon
|
//display: AbstractButton.TextUnderIcon
|
||||||
|
@ -93,7 +79,7 @@ Column {
|
||||||
anchors.rightMargin: 4
|
anchors.rightMargin: 4
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
font.pixelSize: 14
|
font.pixelSize: 14
|
||||||
text: Modules.Objects.types[modelData].displayType()
|
text: Objects.types[modelData].displayType()
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
clip: true
|
clip: true
|
||||||
}
|
}
|
||||||
|
@ -103,28 +89,13 @@ Column {
|
||||||
ToolTip.text: label.text
|
ToolTip.text: label.text
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
let newObj = Modules.Objects.createNewRegisteredObject(modelData)
|
var newObj = Objects.createNewRegisteredObject(modelData)
|
||||||
Modules.History.addToHistory(new JS.HistoryLib.CreateNewObject(
|
history.addToHistory(new HistoryLib.CreateNewObject(newObj.name, modelData, newObj.export()))
|
||||||
newObj.name, modelData, newObj.export()
|
|
||||||
))
|
|
||||||
objectLists.update()
|
objectLists.update()
|
||||||
|
objectEditor.obj = Objects.currentObjects[modelData][Objects.currentObjects[modelData].length - 1]
|
||||||
let hasXProp = newObj.constructor.properties().hasOwnProperty('x')
|
objectEditor.objType = modelData
|
||||||
let hasYProp = newObj.constructor.properties().hasOwnProperty('y')
|
objectEditor.objIndex = Objects.currentObjects[modelData].length - 1
|
||||||
if(hasXProp || hasYProp) {
|
objectEditor.show()
|
||||||
// Open picker
|
|
||||||
posPicker.objType = newObj.type
|
|
||||||
posPicker.objName = newObj.name
|
|
||||||
posPicker.pickX = hasXProp
|
|
||||||
posPicker.pickY = hasYProp
|
|
||||||
posPicker.propertyX = 'x'
|
|
||||||
posPicker.propertyY = 'y'
|
|
||||||
posPicker.visible = true
|
|
||||||
posPicker.picked.connect(openEditorDialog)
|
|
||||||
} else {
|
|
||||||
// Open editor
|
|
||||||
openEditorDialog(newObj)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,11 +16,12 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick 2.12
|
||||||
// import QtQuick.Dialogs 1.3 as D
|
import QtQuick.Dialogs 1.3 as D
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls 2.12
|
||||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||||
import eu.ad5001.LogarithmPlotter.ObjectLists.Editor 1.0 as Editor
|
import eu.ad5001.LogarithmPlotter.ObjectLists.Editor 1.0 as Editor
|
||||||
|
import "../js/objects.js" as Objects
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmltype ObjectLists
|
\qmltype ObjectLists
|
||||||
|
@ -46,7 +47,7 @@ ScrollView {
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
id: objectsListView
|
id: objectsListView
|
||||||
model: Object.keys(Modules.Objects.types)
|
model: Object.keys(Objects.types)
|
||||||
//width: implicitWidth //objectListList.width - (implicitHeight > objectListList.parent.height ? 20 : 0)
|
//width: implicitWidth //objectListList.width - (implicitHeight > objectListList.parent.height ? 20 : 0)
|
||||||
implicitHeight: contentItem.childrenRect.height + footerItem.height + 10
|
implicitHeight: contentItem.childrenRect.height + footerItem.height + 10
|
||||||
|
|
||||||
|
@ -54,9 +55,9 @@ ScrollView {
|
||||||
id: objTypeList
|
id: objTypeList
|
||||||
property string objType: objectsListView.model[index]
|
property string objType: objectsListView.model[index]
|
||||||
property var editingRows: []
|
property var editingRows: []
|
||||||
model: Modules.Objects.currentObjects[objType]
|
model: Objects.currentObjects[objType]
|
||||||
width: objectsListView.width
|
width: objectsListView.width
|
||||||
height: contentItem.childrenRect.height + (visible ? 10 : 0)
|
implicitHeight: contentItem.childrenRect.height
|
||||||
visible: model != undefined && model.length > 0
|
visible: model != undefined && model.length > 0
|
||||||
interactive: false
|
interactive: false
|
||||||
|
|
||||||
|
@ -69,23 +70,21 @@ ScrollView {
|
||||||
|
|
||||||
CheckBox {
|
CheckBox {
|
||||||
id: typeVisibilityCheckBox
|
id: typeVisibilityCheckBox
|
||||||
checked: Modules.Objects.currentObjects[objType] != undefined ? Modules.Objects.currentObjects[objType].every(obj => obj.visible) : true
|
checked: Objects.currentObjects[objType] != undefined ? Objects.currentObjects[objType].every(obj => obj.visible) : true
|
||||||
onClicked: {
|
onClicked: {
|
||||||
for(const obj of Modules.Objects.currentObjects[objType]) obj.visible = this.checked
|
for(var obj of Objects.currentObjects[objType]) obj.visible = this.checked
|
||||||
for(const obj of objTypeList.editingRows) obj.objVisible = this.checked
|
for(var obj of objTypeList.editingRows) obj.objVisible = this.checked
|
||||||
objectListList.changed()
|
objectListList.changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
ToolTip.text: checked ?
|
ToolTip.text: checked ? qsTr("Hide all %1").arg(Objects.types[objType].displayTypeMultiple()) : qsTr("Show all %1").arg(Objects.types[objType].displayTypeMultiple())
|
||||||
qsTr("Hide all %1").arg(Modules.Objects.types[objType].displayTypeMultiple()) :
|
|
||||||
qsTr("Show all %1").arg(Modules.Objects.types[objType].displayTypeMultiple())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
id: typeHeaderText
|
id: typeHeaderText
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
text: qsTranslate("control", "%1: ").arg(Modules.Objects.types[objType].displayTypeMultiple())
|
text: qsTranslate("control", "%1: ").arg(Objects.types[objType].displayTypeMultiple())
|
||||||
font.pixelSize: 20
|
font.pixelSize: 20
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,11 +92,11 @@ ScrollView {
|
||||||
delegate: ObjectRow {
|
delegate: ObjectRow {
|
||||||
id: controlRow
|
id: controlRow
|
||||||
width: objTypeList.width
|
width: objTypeList.width
|
||||||
obj: Modules.Objects.currentObjects[objType][index]
|
obj: Objects.currentObjects[objType][index]
|
||||||
posPicker: positionPicker
|
posPicker: positionPicker
|
||||||
|
|
||||||
onChanged: {
|
onChanged: {
|
||||||
obj = Modules.Objects.currentObjects[objType][index]
|
obj = Objects.currentObjects[objType][index]
|
||||||
objectListList.update()
|
objectListList.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,15 +110,12 @@ ScrollView {
|
||||||
width: objectsListView.width
|
width: objectsListView.width
|
||||||
objectEditor: objEditor
|
objectEditor: objEditor
|
||||||
objectLists: objectListList
|
objectLists: objectListList
|
||||||
posPicker: positionPicker
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Object editor
|
// Object editor
|
||||||
Editor.Dialog {
|
Editor.Dialog {
|
||||||
id: objEditor
|
id: objEditor
|
||||||
|
|
||||||
posPicker: positionPicker
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -129,7 +125,7 @@ ScrollView {
|
||||||
function update() {
|
function update() {
|
||||||
objectListList.changed()
|
objectListList.changed()
|
||||||
for(var objType in objectListList.listViews) {
|
for(var objType in objectListList.listViews) {
|
||||||
objectListList.listViews[objType].model = Modules.Objects.currentObjects[objType]
|
objectListList.listViews[objType].model = Objects.currentObjects[objType]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,12 +16,13 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick 2.12
|
||||||
import QtQuick.Dialogs
|
import QtQuick.Dialogs 1.3 as D
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls 2.12
|
||||||
import QtQuick.Window
|
|
||||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||||
import eu.ad5001.LogarithmPlotter.Common
|
import "../js/objects.js" as Objects
|
||||||
|
import "../js/historylib.js" as HistoryLib
|
||||||
|
import "../js/math/latex.js" as LatexJS
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -72,7 +73,7 @@ Item {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: 5
|
anchors.leftMargin: 5
|
||||||
onClicked: {
|
onClicked: {
|
||||||
Modules.History.addToHistory(new JS.HistoryLib.EditedVisibility(
|
history.addToHistory(new HistoryLib.EditedVisibility(
|
||||||
obj.name, obj.type, this.checked
|
obj.name, obj.type, this.checked
|
||||||
))
|
))
|
||||||
obj.visible = this.checked
|
obj.visible = this.checked
|
||||||
|
@ -89,47 +90,31 @@ Item {
|
||||||
id: objDescription
|
id: objDescription
|
||||||
anchors.left: objVisibilityCheckBox.right
|
anchors.left: objVisibilityCheckBox.right
|
||||||
anchors.right: deleteButton.left
|
anchors.right: deleteButton.left
|
||||||
height: Modules.Latex.enabled ? Math.max(parent.minHeight, latexDescription.height+4) : parent.minHeight
|
height: LatexJS.enabled ? Math.max(parent.minHeight, latexDescription.height+4) : parent.minHeight
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
text: Modules.Latex.enabled ? "" : obj.getReadableString()
|
text: LatexJS.enabled ? "" : obj.getReadableString()
|
||||||
font.pixelSize: 14
|
font.pixelSize: 14
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: latexDescription
|
id: latexDescription
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
visible: Modules.Latex.enabled
|
visible: LatexJS.enabled
|
||||||
property double depth: Screen.devicePixelRatio
|
property double depth: 2
|
||||||
source: ""
|
property var ltxInfo: visible ? Latex.render(obj.getLatexString(), depth*parent.font.pixelSize+4, parent.color).split(",") : ["","0","0"]
|
||||||
width: 0/depth
|
source: visible ? ltxInfo[0] : ""
|
||||||
height: 0/depth
|
width: parseInt(ltxInfo[1])/depth
|
||||||
|
height: parseInt(ltxInfo[2])/depth
|
||||||
Component.onCompleted: function() {
|
|
||||||
if(Modules.Latex.enabled) {
|
|
||||||
const args = [obj.getLatexString(), depth*(parent.font.pixelSize+2), parent.color]
|
|
||||||
const prerendered = Modules.Latex.findPrerendered(...args)
|
|
||||||
if(prerendered !== null) {
|
|
||||||
source = prerendered.source
|
|
||||||
width = prerendered.width/depth
|
|
||||||
height = prerendered.height/depth
|
|
||||||
} else
|
|
||||||
Modules.Latex.requestAsyncRender(...args).then(info => {
|
|
||||||
source = info.source
|
|
||||||
width = info.width/depth
|
|
||||||
height = info.height/depth
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
objEditor.obj = Modules.Objects.currentObjects[obj.type][index]
|
objEditor.obj = Objects.currentObjects[obj.type][index]
|
||||||
objEditor.objType = obj.type
|
objEditor.objType = obj.type
|
||||||
objEditor.objIndex = index
|
objEditor.objIndex = index
|
||||||
//objEditor.editingRow = objectRow
|
//objEditor.editingRow = objectRow
|
||||||
objEditor.open()
|
objEditor.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,15 +192,15 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorDialog {
|
D.ColorDialog {
|
||||||
id: pickColor
|
id: pickColor
|
||||||
selectedColor: obj.color
|
color: obj.color
|
||||||
title: qsTr("Pick new color for %1 %2").arg(obj.constructor.displayType()).arg(obj.name)
|
title: qsTr("Pick new color for %1 %2").arg(obj.constructor.displayType()).arg(obj.name)
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
Modules.History.addToHistory(new JS.HistoryLib.ColorChanged(
|
history.addToHistory(new HistoryLib.ColorChanged(
|
||||||
obj.name, obj.type, obj.color, selectedColor.toString()
|
obj.name, obj.type, obj.color, color.toString()
|
||||||
))
|
))
|
||||||
obj.color = selectedColor.toString()
|
obj.color = color.toString()
|
||||||
changed()
|
changed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,14 +212,10 @@ Item {
|
||||||
function deleteRecursively(object) {
|
function deleteRecursively(object) {
|
||||||
for(let toRemove of object.requiredBy)
|
for(let toRemove of object.requiredBy)
|
||||||
deleteRecursively(toRemove)
|
deleteRecursively(toRemove)
|
||||||
if(Modules.Objects.currentObjectsByName[object.name] !== undefined) {
|
|
||||||
// Object still exists
|
|
||||||
// Temporary fix for objects require not being propertly updated.
|
|
||||||
object.requiredBy = []
|
object.requiredBy = []
|
||||||
Modules.History.addToHistory(new JS.HistoryLib.DeleteObject(
|
history.addToHistory(new HistoryLib.DeleteObject(
|
||||||
object.name, object.type, object.export()
|
object.name, object.type, object.export()
|
||||||
))
|
))
|
||||||
Modules.Objects.deleteObject(object.name)
|
Objects.deleteObject(object.name)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,222 @@
|
||||||
|
/**
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Controls 2.12
|
||||||
|
import "js/objects.js" as Objects
|
||||||
|
import "js/mathlib.js" as MathLib
|
||||||
|
import "js/historylib.js" as HistoryLib
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmltype PickLocationOverlay
|
||||||
|
\inqmlmodule eu.ad5001.LogarithmPlotter
|
||||||
|
\brief Overlay used to pick a new location for an object.
|
||||||
|
|
||||||
|
Provides an overlay over the canvas that can be shown when the user clicks the "Set position" button
|
||||||
|
on a specific object. It allows the user to pick a new location on the canvas to place the object at.
|
||||||
|
This overlay allows to set the precision of the pick as well as whether the pick should be on the plot grid.
|
||||||
|
|
||||||
|
\sa LogarithmPlotter, LogGraphCanvas
|
||||||
|
*/
|
||||||
|
Item {
|
||||||
|
id: pickerRoot
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlproperty var PickLocationOverlay::canvas
|
||||||
|
logGraphCanvas instance.
|
||||||
|
*/
|
||||||
|
property var canvas
|
||||||
|
/*!
|
||||||
|
\qmlproperty string PickLocationOverlay::objType
|
||||||
|
Type of object whose position the user is picking.
|
||||||
|
*/
|
||||||
|
property string objType: 'Point'
|
||||||
|
/*!
|
||||||
|
\qmlproperty string PickLocationOverlay::objType
|
||||||
|
Name of the object whose position the user is picking.
|
||||||
|
*/
|
||||||
|
property string objName: 'A'
|
||||||
|
/*!
|
||||||
|
\qmlproperty bool PickLocationOverlay::pickX
|
||||||
|
true if the user should be picking a position on the x axis.
|
||||||
|
*/
|
||||||
|
property bool pickX: true
|
||||||
|
/*!
|
||||||
|
\qmlproperty bool PickLocationOverlay::pickY
|
||||||
|
true if the user should be picking a position on the y axis.
|
||||||
|
*/
|
||||||
|
property bool pickY: true
|
||||||
|
/*!
|
||||||
|
\qmlproperty string PickLocationOverlay::propertyX
|
||||||
|
Name of the object's property whose x value is being changed.
|
||||||
|
*/
|
||||||
|
property string propertyX: 'x'
|
||||||
|
/*!
|
||||||
|
\qmlproperty string PickLocationOverlay::propertyY
|
||||||
|
Name of the object's property whose y value is being changed.
|
||||||
|
*/
|
||||||
|
property string propertyY: 'y'
|
||||||
|
/*!
|
||||||
|
\qmlproperty int PickLocationOverlay::precision
|
||||||
|
Precision of the picked value (post-dot precision).
|
||||||
|
*/
|
||||||
|
property alias precision: precisionSlider.value
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
color: sysPalette.window
|
||||||
|
opacity: 0.35
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: picker
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: parent.visible
|
||||||
|
cursorShape: Qt.CrossCursor
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
onClicked: {
|
||||||
|
if(mouse.button == Qt.LeftButton) { // Validate
|
||||||
|
let newValueX = !parent.pickX ? null : parseValue(picked.mouseX.toString(), objType, propertyX)
|
||||||
|
let newValueY = !parent.pickY ? null : parseValue(picked.mouseY.toString(), objType, propertyY)
|
||||||
|
let obj = Objects.currentObjectsByName[objName]
|
||||||
|
// Set values
|
||||||
|
if(parent.pickX && parent.pickY) {
|
||||||
|
history.addToHistory(new HistoryLib.EditedPosition(
|
||||||
|
objName, objType, obj[propertyX], newValueX, obj[propertyY], newValueY
|
||||||
|
))
|
||||||
|
obj[propertyX] = newValueX
|
||||||
|
obj[propertyY] = newValueY
|
||||||
|
} else if(parent.pickX) {
|
||||||
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
|
objName, objType, propertyX, obj[propertyX], newValueX
|
||||||
|
))
|
||||||
|
obj[propertyX] = newValueX
|
||||||
|
} else if(parent.pickY) {
|
||||||
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
|
objName, objType, propertyY, obj[propertyY], newValueY
|
||||||
|
))
|
||||||
|
obj[propertyY] = newValueY
|
||||||
|
}
|
||||||
|
obj.update()
|
||||||
|
objectLists.update()
|
||||||
|
}
|
||||||
|
pickerRoot.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
height: precisionSlider.height
|
||||||
|
Text {
|
||||||
|
text: " "+ qsTr("Pointer precision:") + " "
|
||||||
|
color: 'black'
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Slider {
|
||||||
|
id: precisionSlider
|
||||||
|
from: 0
|
||||||
|
value: 2
|
||||||
|
to: 10
|
||||||
|
stepSize: 1
|
||||||
|
ToolTip {
|
||||||
|
parent: precisionSlider.handle
|
||||||
|
visible: precisionSlider.pressed
|
||||||
|
text: precisionSlider.value.toFixed(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: snapToGridCheckbox
|
||||||
|
text: qsTr("Snap to grid")
|
||||||
|
checked: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: xCursor
|
||||||
|
width: 1
|
||||||
|
height: parent.height
|
||||||
|
color: 'black'
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: canvas.x2px(picked.mouseX)
|
||||||
|
visible: parent.pickX
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: yCursor
|
||||||
|
width: parent.width
|
||||||
|
height: 1
|
||||||
|
color: 'black'
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.topMargin: canvas.y2px(picked.mouseY)
|
||||||
|
visible: parent.pickY
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: picked
|
||||||
|
x: picker.mouseX - width - 5
|
||||||
|
y: picker.mouseY - height - 5
|
||||||
|
property double axisX: canvas.xaxisstep1
|
||||||
|
property double mouseX: {
|
||||||
|
let xpos = canvas.px2x(picker.mouseX)
|
||||||
|
if(snapToGridCheckbox.checked) {
|
||||||
|
if(canvas.logscalex) {
|
||||||
|
// Calculate the logged power
|
||||||
|
let pow = Math.pow(10, Math.floor(Math.log10(xpos)))
|
||||||
|
return pow*Math.round(xpos/pow)
|
||||||
|
} else {
|
||||||
|
return canvas.xaxisstep1*Math.round(xpos/canvas.xaxisstep1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return xpos.toFixed(parent.precision)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
property double mouseY: {
|
||||||
|
let ypos = canvas.px2y(picker.mouseY)
|
||||||
|
if(snapToGridCheckbox.checked) {
|
||||||
|
return canvas.yaxisstep1*Math.round(ypos/canvas.yaxisstep1)
|
||||||
|
} else {
|
||||||
|
return ypos.toFixed(parent.precision)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
color: 'black'
|
||||||
|
text: {
|
||||||
|
if(parent.pickX && parent.pickY)
|
||||||
|
return `(${mouseX}, ${mouseY})`
|
||||||
|
if(parent.pickX)
|
||||||
|
return `X = ${mouseX}`
|
||||||
|
if(parent.pickY)
|
||||||
|
return `Y = ${mouseY}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void History::parseValue(string value, string objType, string propertyName)
|
||||||
|
Parses a given \c value as an expression or a number depending on the type of \c propertyName of all \c objType.
|
||||||
|
*/
|
||||||
|
function parseValue(value, objType, propertyName) {
|
||||||
|
if(Objects.types[objType].properties()[propertyName] == 'number')
|
||||||
|
return parseFloat(value)
|
||||||
|
else
|
||||||
|
return new MathLib.Expression(value)
|
||||||
|
}
|
||||||
|
}
|
124
LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Popup/About.qml
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/**
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Dialogs 1.3 as D
|
||||||
|
import QtQuick.Controls 2.12
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmltype About
|
||||||
|
\inqmlmodule eu.ad5001.LogarithmPlotter.Popup
|
||||||
|
\brief About popup of LogarithmPlotter.
|
||||||
|
|
||||||
|
\sa LogarithmPlotter
|
||||||
|
*/
|
||||||
|
D.Dialog {
|
||||||
|
id: about
|
||||||
|
title: qsTr("About LogarithmPlotter")
|
||||||
|
width: 400
|
||||||
|
height: 600
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: logo
|
||||||
|
source: "../icons/logarithmplotter.svg"
|
||||||
|
sourceSize.width: 64
|
||||||
|
sourceSize.height: 64
|
||||||
|
width: 64
|
||||||
|
height: 64
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.rightMargin: width/2
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: 10
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: appName
|
||||||
|
anchors.top: logo.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.topMargin: 10
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
width: parent.width
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: 25
|
||||||
|
text: qsTr("LogarithmPlotter v%1").arg(Helper.getVersion())
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: description
|
||||||
|
anchors.top: appName.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.topMargin: 10
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
width: parent.width
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: 18
|
||||||
|
text: qsTr("2D plotter software to make BODE plots, sequences and repartition functions.")
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: debugInfos
|
||||||
|
anchors.top: description.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.topMargin: 10
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
width: parent.width
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: 14
|
||||||
|
text: Helper.getDebugInfos()
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: copyrightInfos
|
||||||
|
anchors.top: debugInfos.bottom
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.topMargin: 10
|
||||||
|
width: Math.min(410, parent.width)
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
textFormat: Text.RichText
|
||||||
|
font.pixelSize: 13
|
||||||
|
text: "Copyright © 2022 Ad5001 <mail@ad5001.eu><br>
|
||||||
|
<br>
|
||||||
|
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.<br>
|
||||||
|
<br>
|
||||||
|
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.<br>
|
||||||
|
<br>
|
||||||
|
You should have received a copy of the GNU General Public License along with this program. If not, see <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>."
|
||||||
|
onLinkActivated: Qt.openUrlExternally(link)
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.top: copyrightInfos.bottom
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.topMargin: 10
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: openIssueButton
|
||||||
|
text: qsTr('Report a bug')
|
||||||
|
icon.name: 'tools-report-bug'
|
||||||
|
onClicked: Qt.openUrlExternally('https://git.ad5001.eu/Ad5001/LogarithmPlotter')
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: officialWebsiteButton
|
||||||
|
text: qsTr('Official website')
|
||||||
|
icon.name: 'web-browser'
|
||||||
|
onClicked: Qt.openUrlExternally('https://apps.ad5001.eu/logarithmplotter/')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick 2.12
|
||||||
/*!
|
/*!
|
||||||
\qmltype Alert
|
\qmltype Alert
|
||||||
\inqmlmodule eu.ad5001.LogarithmPlotter.Popup
|
\inqmlmodule eu.ad5001.LogarithmPlotter.Popup
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,8 +16,8 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick 2.12
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls 2.12
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmltype Changelog
|
\qmltype Changelog
|
||||||
|
@ -32,7 +32,7 @@ Popup {
|
||||||
id: changelogPopup
|
id: changelogPopup
|
||||||
x: (parent.width-width)/2
|
x: (parent.width-width)/2
|
||||||
y: Math.max(20, (parent.height-height)/2)
|
y: Math.max(20, (parent.height-height)/2)
|
||||||
width: 800
|
width: changelog.width+40
|
||||||
height: Math.min(parent.height-40, 500)
|
height: Math.min(parent.height-40, 500)
|
||||||
modal: true
|
modal: true
|
||||||
focus: true
|
focus: true
|
||||||
|
@ -44,62 +44,42 @@ Popup {
|
||||||
*/
|
*/
|
||||||
property bool changelogNeedsFetching: true
|
property bool changelogNeedsFetching: true
|
||||||
|
|
||||||
onAboutToShow: if(changelogNeedsFetching) {
|
onAboutToShow: if(changelogNeedsFetching) Helper.fetchChangelog()
|
||||||
Helper.fetchChangelog().then((fetchedText) => {
|
|
||||||
changelogNeedsFetching = false
|
Connections {
|
||||||
changelog.text = fetchedText
|
target: Helper
|
||||||
changelogView.contentItem.implicitHeight = changelog.height
|
function onChangelogFetched(chl) {
|
||||||
}, (error) => {
|
changelogNeedsFetching = false;
|
||||||
const e = qsTranslate("changelog", "Could not fetch update: {}.").replace('{}', error)
|
changelog.text = chl
|
||||||
console.error(e)
|
}
|
||||||
changelogNeedsFetching = false
|
|
||||||
changelog.text = e
|
|
||||||
changelogView.contentItem.implicitHeight = changelog.height
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollView {
|
ScrollView {
|
||||||
id: changelogView
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 10
|
anchors.topMargin: 10
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: 10
|
anchors.leftMargin: 10
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: 10
|
|
||||||
anchors.bottom: doneBtn.top
|
anchors.bottom: doneBtn.top
|
||||||
anchors.bottomMargin: 10
|
anchors.bottomMargin: 10
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
id: changelog
|
id: changelog
|
||||||
color: sysPalette.windowText
|
color: sysPalette.windowText
|
||||||
width: 760
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
textFormat: TextEdit.MarkdownText
|
textFormat: TextEdit.MarkdownText
|
||||||
|
|
||||||
text: qsTr("Fetching changelog...")
|
text: qsTr("Fetching changelog...")
|
||||||
onLinkActivated: Qt.openUrlExternally(link)
|
onLinkActivated: Qt.openUrlExternally(link)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
}
|
||||||
id: bottomSeparator
|
|
||||||
opacity: 0.3
|
|
||||||
color: sysPalette.windowText
|
|
||||||
width: parent.width * 2 / 3
|
|
||||||
height: 1
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.bottom: doneBtn.top
|
|
||||||
anchors.bottomMargin: 7
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: doneBtn
|
id: doneBtn
|
||||||
text: qsTr("Close")
|
text: qsTr("Done")
|
||||||
font.pixelSize: 18
|
font.pixelSize: 18
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.bottomMargin: 7
|
anchors.bottomMargin: 10
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
onClicked: changelogPopup.close()
|
onClicked: changelogPopup.close()
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Qt.labs.platform
|
import QtQuick.Dialogs 1.3 as D
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmltype FileDialog
|
\qmltype FileDialog
|
||||||
|
@ -25,7 +25,7 @@ import Qt.labs.platform
|
||||||
|
|
||||||
\sa LogarithmPlotter, Settings
|
\sa LogarithmPlotter, Settings
|
||||||
*/
|
*/
|
||||||
FileDialog {
|
D.FileDialog {
|
||||||
id: fileDialog
|
id: fileDialog
|
||||||
|
|
||||||
property bool exportMode: false
|
property bool exportMode: false
|
||||||
|
@ -33,6 +33,6 @@ FileDialog {
|
||||||
title: exportMode ? qsTr("Export Logarithm Plot file") : qsTr("Import Logarithm Plot file")
|
title: exportMode ? qsTr("Export Logarithm Plot file") : qsTr("Import Logarithm Plot file")
|
||||||
nameFilters: ["Logarithm Plot File (*.lpf)", "All files (*)"]
|
nameFilters: ["Logarithm Plot File (*.lpf)", "All files (*)"]
|
||||||
|
|
||||||
defaultSuffix: 'lpf'
|
folder: shortcuts.documents
|
||||||
fileMode: exportMode ? FileDialog.SaveFile : FileDialog.OpenFile
|
selectExisting: !exportMode
|
||||||
}
|
}
|
|
@ -0,0 +1,209 @@
|
||||||
|
/**
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Controls 2.12
|
||||||
|
import "../js/math/latex.js" as Latex
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmltype GreetScreen
|
||||||
|
\inqmlmodule eu.ad5001.LogarithmPlotter.Popup
|
||||||
|
\brief Overlay displayed when LogarithmPlotter is launched for the first time or when it was just updated.
|
||||||
|
|
||||||
|
It contains several settings as well as an easy access to the changelog
|
||||||
|
|
||||||
|
\sa LogarithmPlotter, Settings, AppMenuBar, Changelog
|
||||||
|
*/
|
||||||
|
Popup {
|
||||||
|
id: greetingPopup
|
||||||
|
x: (parent.width-width)/2
|
||||||
|
y: Math.max(20, (parent.height-height)/2)
|
||||||
|
width: Math.max(welcome.width+70, checkForUpdatesSetting.width, resetRedoStackSetting.width)+20
|
||||||
|
height: Math.min(parent.height-40, 500)
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: welcome
|
||||||
|
height: logo.height
|
||||||
|
width: logo.width + 10 + welcomeText.width
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: (parent.width-width)/2
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: logo
|
||||||
|
source: "../icons/logarithmplotter.svg"
|
||||||
|
sourceSize.width: 48
|
||||||
|
sourceSize.height: 48
|
||||||
|
width: 48
|
||||||
|
height: 48
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: welcomeText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: logo.right
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
//width: parent.width
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: 32
|
||||||
|
text: qsTr("Welcome to LogarithmPlotter")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: versionText
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: welcome.bottom
|
||||||
|
anchors.topMargin: 10
|
||||||
|
//width: parent.width
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
width: implicitWidth
|
||||||
|
font.pixelSize: 18
|
||||||
|
font.italic: true
|
||||||
|
text: qsTr("Version %1").arg(Helper.getVersion())
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: helpText
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: versionText.bottom
|
||||||
|
anchors.topMargin: 40
|
||||||
|
//width: parent.width
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: 14
|
||||||
|
width: parent.width - 50
|
||||||
|
text: qsTr("Take a few seconds to configure LogarithmPlotter.\nThese settings can be changed at any time from the \"Settings\" menu.")
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: checkForUpdatesSetting
|
||||||
|
anchors.left: parent.left
|
||||||
|
//anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: helpText.bottom
|
||||||
|
anchors.topMargin: 10
|
||||||
|
checked: Helper.getSettingBool("check_for_updates")
|
||||||
|
text: qsTr('Check for updates on startup (requires online connectivity)')
|
||||||
|
onClicked: {
|
||||||
|
Helper.setSettingBool("check_for_updates", checked)
|
||||||
|
// Set in the menu bar
|
||||||
|
appMenu.settings.children[0].checked = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: resetRedoStackSetting
|
||||||
|
anchors.left: parent.left
|
||||||
|
//anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: checkForUpdatesSetting.bottom
|
||||||
|
checked: Helper.getSettingBool("reset_redo_stack")
|
||||||
|
text: qsTr('Reset redo stack when a new action is added to history')
|
||||||
|
onClicked: {
|
||||||
|
Helper.setSettingBool("reset_redo_stack", checked)
|
||||||
|
appMenu.settings.children[1].checked = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: enableLatexSetting
|
||||||
|
anchors.left: parent.left
|
||||||
|
//anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: resetRedoStackSetting.bottom
|
||||||
|
checked: Helper.getSettingBool("enable_latex")
|
||||||
|
text: qsTr('Enable LaTeX rendering')
|
||||||
|
onClicked: {
|
||||||
|
Helper.setSettingBool("enable_latex", checked)
|
||||||
|
appMenu.settings.children[2].checked = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: autocloseFormulaSetting
|
||||||
|
anchors.left: parent.left
|
||||||
|
//anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: enableLatexSetting.bottom
|
||||||
|
checked: Helper.getSettingBool("expression_editor.autoclose")
|
||||||
|
text: qsTr('Automatically close parenthesises and brackets in expressions')
|
||||||
|
onClicked: {
|
||||||
|
Helper.setSettingBool("expression_editor.autoclose", checked)
|
||||||
|
appMenu.settings.children[3].children[0].checked = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: colorizeFormulaSetting
|
||||||
|
anchors.left: parent.left
|
||||||
|
//anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: autocloseFormulaSetting.bottom
|
||||||
|
checked: Helper.getSettingBool("expression_editor.colorize")
|
||||||
|
text: qsTr('Enable syntax highlighting for expressions')
|
||||||
|
onClicked: {
|
||||||
|
Helper.setSettingBool("expression_editor.colorize", checked)
|
||||||
|
appMenu.settings.children[3].children[1].checked = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: autocompleteFormulaSetting
|
||||||
|
anchors.left: parent.left
|
||||||
|
//anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: colorizeFormulaSetting.bottom
|
||||||
|
checked: Helper.getSettingBool("autocompletion.enabled")
|
||||||
|
text: qsTr('Enable autocompletion interface in expression editor')
|
||||||
|
onClicked: {
|
||||||
|
Helper.setSettingBool("autocompletion.enabled", checked)
|
||||||
|
appMenu.settings.children[3].children[2].checked = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: 10
|
||||||
|
spacing: 10
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: userManualBtn
|
||||||
|
text: qsTr("User manual")
|
||||||
|
font.pixelSize: 18
|
||||||
|
onClicked: Qt.openUrlExternally("https://git.ad5001.eu/Ad5001/LogarithmPlotter/wiki/_Sidebar")
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: changelogBtn
|
||||||
|
text: qsTr("Changelog")
|
||||||
|
font.pixelSize: 18
|
||||||
|
onClicked: changelog.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: doneBtn
|
||||||
|
text: qsTr("Done")
|
||||||
|
font.pixelSize: 18
|
||||||
|
onClicked: greetingPopup.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: if(Helper.getSetting("last_install_greet") != Helper.getVersion()) {
|
||||||
|
greetingPopup.open()
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosed: Helper.setSetting("last_install_greet", Helper.getVersion())
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/**
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick.Controls 2.12
|
||||||
|
import QtQuick 2.12
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmltype InsertCharacter
|
||||||
|
\inqmlmodule eu.ad5001.LogarithmPlotter.Setting
|
||||||
|
\brief Popup to insert special character.
|
||||||
|
|
||||||
|
\sa TextSetting, ExpressionEditor
|
||||||
|
*/
|
||||||
|
Popup {
|
||||||
|
id: insertPopup
|
||||||
|
|
||||||
|
signal selected(string character)
|
||||||
|
|
||||||
|
width: 280
|
||||||
|
height: insertGrid.insertChars.length/insertGrid.columns*(width/insertGrid.columns)
|
||||||
|
modal: true
|
||||||
|
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
|
||||||
|
|
||||||
|
Grid {
|
||||||
|
id: insertGrid
|
||||||
|
width: parent.width
|
||||||
|
columns: 7
|
||||||
|
|
||||||
|
property var insertChars: [
|
||||||
|
"α","β","γ","δ","ε","ζ","η",
|
||||||
|
"π","θ","κ","λ","μ","ξ","ρ",
|
||||||
|
"ς","σ","τ","φ","χ","ψ","ω",
|
||||||
|
"Γ","Δ","Θ","Λ","Ξ","Π","Σ",
|
||||||
|
"Φ","Ψ","Ω","ₐ","ₑ","ₒ","ₓ",
|
||||||
|
"ₕ","ₖ","ₗ","ₘ","ₙ","ₚ","ₛ",
|
||||||
|
"ₜ","¹","²","³","⁴","⁵","⁶",
|
||||||
|
"⁷","⁸","⁹","⁰","₁","₂","₃",
|
||||||
|
"₄","₅","₆","₇","₈","₉","₀"
|
||||||
|
]
|
||||||
|
Repeater {
|
||||||
|
model: parent.insertChars.length
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: insertBtn
|
||||||
|
width: insertGrid.width/insertGrid.columns
|
||||||
|
height: width
|
||||||
|
text: insertGrid.insertChars[modelData]
|
||||||
|
flat: text == " "
|
||||||
|
font.pixelSize: 18
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
selected(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,320 @@
|
||||||
|
/**
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick 2.12
|
||||||
|
import QtQuick.Dialogs 1.3 as D
|
||||||
|
import QtQuick.Controls 2.12
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmltype ThanksTo
|
||||||
|
\inqmlmodule eu.ad5001.LogarithmPlotter.Popup
|
||||||
|
\brief Thanks to popup of LogarithmPlotter.
|
||||||
|
|
||||||
|
\sa LogarithmPlotter
|
||||||
|
*/
|
||||||
|
D.Dialog {
|
||||||
|
id: about
|
||||||
|
title: qsTr("Thanks and Contributions - LogarithmPlotter")
|
||||||
|
width: 400
|
||||||
|
height: 600
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: librariesListView
|
||||||
|
anchors.left: parent.left
|
||||||
|
width: parent.width
|
||||||
|
//height: parent.height
|
||||||
|
implicitHeight: contentItem.childrenRect.height
|
||||||
|
|
||||||
|
model: ListModel {
|
||||||
|
Component.onCompleted: {
|
||||||
|
append({
|
||||||
|
libName: 'expr-eval',
|
||||||
|
license: 'MIT',
|
||||||
|
licenseLink: 'https://raw.githubusercontent.com/silentmatt/expr-eval/master/LICENSE.txt',
|
||||||
|
linkName: qsTr('Source code'),
|
||||||
|
link: 'https://github.com/silentmatt/expr-eval',
|
||||||
|
authors: [{
|
||||||
|
authorLine: qsTr('Original library by Raphael Graf'),
|
||||||
|
email: 'r@undefined.ch',
|
||||||
|
website: 'https://web.archive.org/web/20111023001618/http://www.undefined.ch/mparser/index.html',
|
||||||
|
websiteName: qsTr('Source')
|
||||||
|
}, {
|
||||||
|
authorLine: qsTr('Ported to Javascript by Matthew Crumley'),
|
||||||
|
email: 'email@matthewcrumley.com',
|
||||||
|
website: 'https://silentmatt.com/',
|
||||||
|
websiteName: qsTr('Website')
|
||||||
|
}, {
|
||||||
|
authorLine: qsTr('Ported to QMLJS by Ad5001'),
|
||||||
|
email: 'mail@ad5001.eu',
|
||||||
|
website: 'https://ad5001.eu/',
|
||||||
|
websiteName: qsTr('Website')
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header: Label {
|
||||||
|
id: librariesUsedHeader
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: 25
|
||||||
|
text: qsTr("Libraries included")
|
||||||
|
height: implicitHeight + 10
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: Column {
|
||||||
|
id: libClmn
|
||||||
|
width: librariesListView.width
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Item {
|
||||||
|
height: libraryHeader.height
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: libraryHeader
|
||||||
|
anchors.left: parent.left
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: 18
|
||||||
|
text: libName
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: parent.height
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Button {
|
||||||
|
height: parent.height
|
||||||
|
text: license
|
||||||
|
icon.name: 'license'
|
||||||
|
onClicked: Qt.openUrlExternally(licenseLink)
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
height: parent.height
|
||||||
|
text: linkName
|
||||||
|
icon.name: 'web-browser'
|
||||||
|
onClicked: Qt.openUrlExternally(link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: libAuthors
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
model: authors
|
||||||
|
width: parent.width - 10
|
||||||
|
implicitHeight: contentItem.childrenRect.height
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
id: libAuthor
|
||||||
|
width: librariesListView.width - 10
|
||||||
|
height: 50
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: libAuthorName
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: buttons.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: 14
|
||||||
|
text: authorLine
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: buttons
|
||||||
|
anchors.right: parent.right
|
||||||
|
height: parent.height
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Button {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: websiteName
|
||||||
|
icon.name: 'web-browser'
|
||||||
|
height: parent.height - 10
|
||||||
|
onClicked: Qt.openUrlExternally(website)
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: qsTr('Email')
|
||||||
|
icon.name: 'email'
|
||||||
|
height: parent.height - 10
|
||||||
|
onClicked: Qt.openUrlExternally('mailto:' + email)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: libSeparator
|
||||||
|
opacity: 0.3
|
||||||
|
color: sysPalette.windowText
|
||||||
|
width: parent.width
|
||||||
|
height: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: translationsListView
|
||||||
|
anchors.left: parent.left
|
||||||
|
width: parent.width
|
||||||
|
implicitHeight: contentItem.childrenRect.height
|
||||||
|
spacing: 3
|
||||||
|
|
||||||
|
|
||||||
|
model: ListModel {
|
||||||
|
Component.onCompleted: {
|
||||||
|
append({
|
||||||
|
tranName: '🇬🇧 ' + qsTr('English'),
|
||||||
|
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/en/',
|
||||||
|
authors: [{
|
||||||
|
authorLine: 'Ad5001',
|
||||||
|
email: 'mail@ad5001.eu',
|
||||||
|
website: 'https://ad5001.eu',
|
||||||
|
websiteName: qsTr('Website')
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
append({
|
||||||
|
tranName: '🇫🇷 ' + qsTr('French'),
|
||||||
|
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/fr/',
|
||||||
|
authors: [{
|
||||||
|
authorLine: 'Ad5001',
|
||||||
|
website: 'https://ad5001.eu',
|
||||||
|
websiteName: qsTr('Website')
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
append({
|
||||||
|
tranName: '🇩🇪 ' + qsTr('German'),
|
||||||
|
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/de/',
|
||||||
|
authors: [{
|
||||||
|
authorLine: 'Ad5001',
|
||||||
|
website: 'https://ad5001.eu',
|
||||||
|
websiteName: qsTr('Website')
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
append({
|
||||||
|
tranName: '🇭🇺 ' + qsTr('Hungarian'),
|
||||||
|
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/hu/',
|
||||||
|
authors: [{
|
||||||
|
authorLine: 'Óvári',
|
||||||
|
website: 'https://github.com/ovari',
|
||||||
|
websiteName: qsTr('Github')
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
append({
|
||||||
|
tranName: '🇳🇴 ' + qsTr('Norwegian'),
|
||||||
|
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/no/',
|
||||||
|
authors: [{
|
||||||
|
authorLine: 'Allan Nordhøy',
|
||||||
|
website: 'https://github.com/comradekingu',
|
||||||
|
websiteName: qsTr('Github')
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header: Label {
|
||||||
|
id: translationsHeader
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: 25
|
||||||
|
text: qsTr("Translations included")
|
||||||
|
height: implicitHeight + 10
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: Column {
|
||||||
|
id: tranClmn
|
||||||
|
width: translationsListView.width
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: translationHeader.height + 10
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: translationHeader
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: 18
|
||||||
|
text: tranName
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
height: 30
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Button {
|
||||||
|
height: parent.height
|
||||||
|
text: qsTr('Improve')
|
||||||
|
icon.name: 'web-browser'
|
||||||
|
onClicked: Qt.openUrlExternally(link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: tranAuthors
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 10
|
||||||
|
model: authors
|
||||||
|
width: parent.width - 10
|
||||||
|
implicitHeight: contentItem.childrenRect.height
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
id: tranAuthor
|
||||||
|
width: tranAuthors.width
|
||||||
|
height: 40
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: tranAuthorName
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: buttons.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
font.pixelSize: 14
|
||||||
|
text: authorLine
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: buttons
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
height: 30
|
||||||
|
spacing: 10
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: websiteName
|
||||||
|
icon.name: 'web-browser'
|
||||||
|
height: parent.height
|
||||||
|
onClicked: Qt.openUrlExternally(website)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,9 @@
|
||||||
module eu.ad5001.LogarithmPlotter.Popup
|
module eu.ad5001.LogarithmPlotter.Popup
|
||||||
|
|
||||||
Alert 1.0 Alert.qml
|
|
||||||
About 1.0 About.qml
|
About 1.0 About.qml
|
||||||
BaseDialog 1.0 BaseDialog.qml
|
Alert 1.0 Alert.qml
|
||||||
Changelog 1.0 Changelog.qml
|
|
||||||
FileDialog 1.0 FileDialog.qml
|
FileDialog 1.0 FileDialog.qml
|
||||||
GreetScreen 1.0 GreetScreen.qml
|
GreetScreen 1.0 GreetScreen.qml
|
||||||
InsertCharacter 1.0 InsertCharacter.qml
|
Changelog 1.0 Changelog.qml
|
||||||
Preferences 1.0 Preferences.qml
|
|
||||||
ThanksTo 1.0 ThanksTo.qml
|
ThanksTo 1.0 ThanksTo.qml
|
||||||
|
InsertCharacter 1.0 InsertCharacter.qml
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,8 +16,8 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick 2.12
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls 2.12
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmltype AutocompletionCategory
|
\qmltype AutocompletionCategory
|
||||||
|
@ -84,12 +84,11 @@ ListView {
|
||||||
Text {
|
Text {
|
||||||
leftPadding: 5
|
leftPadding: 5
|
||||||
text: listFiltered.category
|
text: listFiltered.category
|
||||||
color: sysPalette.windowText
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
height: 1
|
height: 1
|
||||||
color: 'gray'
|
color: 'black'
|
||||||
width: parent.width
|
width: parent.width
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,11 +112,9 @@ ListView {
|
||||||
Text {
|
Text {
|
||||||
id: annotationText
|
id: annotationText
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
topPadding: 2
|
topPadding: 2
|
||||||
bottomPadding: 2
|
bottomPadding: 2
|
||||||
rightPadding: 15
|
rightPadding: 15
|
||||||
font.pixelSize: autocompleteText.font.pixelSize - 2
|
|
||||||
text: listFiltered.model[index].annotation
|
text: listFiltered.model[index].annotation
|
||||||
color: parent.selected ? sysPaletteIn.highlightedText : sysPaletteIn.windowText
|
color: parent.selected ? sysPaletteIn.highlightedText : sysPaletteIn.windowText
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,8 +16,8 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick 2.12
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls 2.12
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmltype ComboBoxSetting
|
\qmltype ComboBoxSetting
|
||||||
|
@ -114,7 +114,6 @@ Item {
|
||||||
anchors.left: iconLabel.right
|
anchors.left: iconLabel.right
|
||||||
anchors.leftMargin: icon == "" ? 0 : 5
|
anchors.leftMargin: icon == "" ? 0 : 5
|
||||||
height: 30
|
height: 30
|
||||||
width: Math.max(85, implicitWidth)
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
text: qsTranslate("control", "%1: ").arg(control.label)
|
text: qsTranslate("control", "%1: ").arg(control.label)
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,11 +16,14 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls 2.12
|
||||||
import QtQuick
|
import QtQuick 2.12
|
||||||
import Qt.labs.platform as Native
|
import QtQuick.Dialogs 1.3 as D
|
||||||
import eu.ad5001.LogarithmPlotter.Popup 1.0 as P
|
import eu.ad5001.LogarithmPlotter.Popup 1.0 as P
|
||||||
import eu.ad5001.LogarithmPlotter.Common
|
import "../js/mathlib.js" as MathLib
|
||||||
|
import "../js/utils.js" as Utils
|
||||||
|
import "../js/objects.js" as Objects
|
||||||
|
import "../js/parsing/parsing.js" as Parsing
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -78,17 +81,6 @@ Item {
|
||||||
Icon path of the editor.
|
Icon path of the editor.
|
||||||
*/
|
*/
|
||||||
property string icon: ""
|
property string icon: ""
|
||||||
/*!
|
|
||||||
\qmlproperty bool ExpressionEditor::allowGraphObjects
|
|
||||||
If true, allows graph objects to be used as part of the expression.
|
|
||||||
*/
|
|
||||||
property bool allowGraphObjects: true
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\qmlproperty var ExpressionEditor::errorDialog
|
|
||||||
Allows to summon the error dialog when using additional external parsing.
|
|
||||||
*/
|
|
||||||
readonly property alias errorDialog: parsingErrorDialog
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty string ExpressionEditor::openAndCloseMatches
|
\qmlproperty string ExpressionEditor::openAndCloseMatches
|
||||||
|
@ -103,110 +95,53 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty string ExpressionEditor::colorSchemes
|
\qmlproperty string ExpressionEditor::colorScheme
|
||||||
Color schemes of the editor.
|
Color scheme of the editor, currently based on Breeze Light.
|
||||||
|
TODO: Make it configurable.
|
||||||
*/
|
*/
|
||||||
readonly property var colorSchemes: [
|
readonly property var colorScheme: {
|
||||||
{ // Breeze Light
|
|
||||||
'NORMAL': "#1F1C1B",
|
'NORMAL': "#1F1C1B",
|
||||||
'VARIABLE': "#0057AE",
|
'VARIABLE': "#0057AE",
|
||||||
'CONSTANT': "#006E28",
|
'CONSTANT': "#5E2F00",
|
||||||
'FUNCTION': "#644A9B",
|
'FUNCTION': "#644A9B",
|
||||||
'OPERATOR': "#CA60CA",
|
|
||||||
'STRING': "#BF0303",
|
|
||||||
'NUMBER': "#B08000"
|
|
||||||
},
|
|
||||||
{ // Breeze Dark
|
|
||||||
'NORMAL': "#CFCFC2",
|
|
||||||
'VARIABLE': "#2980B9",
|
|
||||||
'CONSTANT': "#27AE60",
|
|
||||||
'FUNCTION': "#8E44AD",
|
|
||||||
'OPERATOR': "#A44EA4",
|
'OPERATOR': "#A44EA4",
|
||||||
'STRING': "#F44F4F",
|
'STRING': "#9C0E0E",
|
||||||
'NUMBER': "#F67400"
|
'NUMBER': "#805C00"
|
||||||
},
|
|
||||||
{ // Solarized
|
|
||||||
'NORMAL': "#839496",
|
|
||||||
'VARIABLE': "#B58900",
|
|
||||||
'CONSTANT': "#859900",
|
|
||||||
'FUNCTION': "#268BD2",
|
|
||||||
'OPERATOR': "#859900",
|
|
||||||
'STRING': "#2AA198",
|
|
||||||
'NUMBER': "#2AA198"
|
|
||||||
},
|
|
||||||
{ // GitHub Light
|
|
||||||
'NORMAL': "#24292E",
|
|
||||||
'VARIABLE': "#D73A49",
|
|
||||||
'CONSTANT': "#6F42C1",
|
|
||||||
'FUNCTION': "#6F42C1",
|
|
||||||
'OPERATOR': "#24292E",
|
|
||||||
'STRING': "#032F62",
|
|
||||||
'NUMBER': "#005CC5"
|
|
||||||
},
|
|
||||||
{ // GitHub Dark
|
|
||||||
'NORMAL': "#E1E4E8",
|
|
||||||
'VARIABLE': "#F97583",
|
|
||||||
'CONSTANT': "#B392f0",
|
|
||||||
'FUNCTION': "#B392f0",
|
|
||||||
'OPERATOR': "#E1E4E8",
|
|
||||||
'STRING': "#9ECBFF",
|
|
||||||
'NUMBER': "#79B8FF"
|
|
||||||
},
|
|
||||||
{ // Nord
|
|
||||||
'NORMAL': "#D8DEE9",
|
|
||||||
'VARIABLE': "#81A1C1",
|
|
||||||
'CONSTANT': "#8FBCBB",
|
|
||||||
'FUNCTION': "#88C0D0",
|
|
||||||
'OPERATOR': "#81A1C1",
|
|
||||||
'STRING': "#A3BE8C",
|
|
||||||
'NUMBER': "#B48EAD"
|
|
||||||
},
|
|
||||||
{ // Monokai
|
|
||||||
'NORMAL': "#F8F8F2",
|
|
||||||
'VARIABLE': "#66D9EF",
|
|
||||||
'CONSTANT': "#F92672",
|
|
||||||
'FUNCTION': "#A6E22E",
|
|
||||||
'OPERATOR': "#F8F8F2",
|
|
||||||
'STRING': "#E6DB74",
|
|
||||||
'NUMBER': "#AE81FF"
|
|
||||||
}
|
}
|
||||||
]
|
|
||||||
|
|
||||||
Icon {
|
Icon {
|
||||||
id: iconLabel
|
id: iconLabel
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: parent.icon == "" ? 0 : 3
|
anchors.topMargin: icon == "" ? 0 : 3
|
||||||
source: control.visible && parent.icon != "" ? "../icons/" + control.icon : ""
|
source: control.visible && icon != "" ? "../icons/" + control.icon : ""
|
||||||
width: height
|
width: height
|
||||||
height: parent.icon == "" || !visible ? 0 : 24
|
height: 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: parent.icon == "" ? 0 : 5
|
anchors.leftMargin: icon == "" ? 0 : 5
|
||||||
anchors.top: parent.top
|
|
||||||
height: parent.height
|
height: parent.height
|
||||||
width: Math.max(85, implicitWidth)
|
anchors.top: parent.top
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
//color: sysPalette.windowText
|
//color: sysPalette.windowText
|
||||||
text: visible ? qsTranslate("control", "%1: ").arg(control.label) : ""
|
text: visible ? qsTranslate("control", "%1: ").arg(control.label) : ""
|
||||||
visible: control.label != ""
|
visible: control.label != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
Native.MessageDialog {
|
D.MessageDialog {
|
||||||
id: parsingErrorDialog
|
id: parsingErrorDialog
|
||||||
title: qsTranslate("expression", "LogarithmPlotter - Parsing error")
|
title: qsTranslate("expression", "LogarithmPlotter - Parsing error")
|
||||||
text: ""
|
text: ""
|
||||||
function showDialog(propName, propValue, error) {
|
function showDialog(propName, propValue, error) {
|
||||||
text = qsTranslate("expression", "Error while parsing expression for property %1:\n%2\n\nEvaluated expression: %3")
|
text = qsTranslate("expression", "Error while parsing expression for property %1:\n%2\n\nEvaluated expression: %3").arg(propName).arg(error).arg(propValue)
|
||||||
.arg(qsTranslate('prop', propName))
|
|
||||||
.arg(error).arg(propValue)
|
|
||||||
open()
|
open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: editor
|
id: editor
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
@ -217,13 +152,13 @@ Item {
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
horizontalAlignment: control.label == "" ? TextInput.AlignLeft : TextInput.AlignHCenter
|
horizontalAlignment: control.label == "" ? TextInput.AlignLeft : TextInput.AlignHCenter
|
||||||
text: control.defValue
|
text: control.defValue
|
||||||
color: syntaxHighlightingEnabled ? sysPalette.window : sysPalette.windowText
|
color: syntaxHighlightingEnabled ? "transparent" : sysPalette.windowText
|
||||||
focus: true
|
focus: true
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
|
|
||||||
property bool autocompleteEnabled: Helper.getSetting("autocompletion.enabled")
|
property bool autocompleteEnabled: Helper.getSettingBool("autocompletion.enabled")
|
||||||
property bool syntaxHighlightingEnabled: Helper.getSetting("expression_editor.colorize")
|
property bool syntaxHighlightingEnabled: Helper.getSettingBool("expression_editor.colorize")
|
||||||
property bool autoClosing: Helper.getSetting("expression_editor.autoclose")
|
property bool autoClosing: Helper.getSettingBool("expression_editor.autoclose")
|
||||||
property var tokens: autocompleteEnabled || syntaxHighlightingEnabled ? parent.tokens(text) : []
|
property var tokens: autocompleteEnabled || syntaxHighlightingEnabled ? parent.tokens(text) : []
|
||||||
|
|
||||||
Keys.priority: Keys.BeforeItem // Required for knowing which key the user presses.
|
Keys.priority: Keys.BeforeItem // Required for knowing which key the user presses.
|
||||||
|
@ -231,8 +166,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() != parent.defValue) {
|
if(value != "" && value.toString() != defValue) {
|
||||||
let expr = parent.parse(value)
|
let expr = parse(value)
|
||||||
if(expr != null) {
|
if(expr != null) {
|
||||||
control.changed(expr)
|
control.changed(expr)
|
||||||
defValue = expr.toEditableString()
|
defValue = expr.toEditableString()
|
||||||
|
@ -240,6 +175,8 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//onTextEdited: acPopupContent.itemSelected = 0
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
onActiveFocusChanged: {
|
||||||
if(activeFocus && autocompleteEnabled)
|
if(activeFocus && autocompleteEnabled)
|
||||||
autocompletePopup.open()
|
autocompletePopup.open()
|
||||||
|
@ -247,12 +184,6 @@ Item {
|
||||||
autocompletePopup.close()
|
autocompletePopup.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
cursorDelegate: Rectangle {
|
|
||||||
visible: editor.cursorVisible
|
|
||||||
color: sysPalette.windowText
|
|
||||||
width: editor.cursorRectangle.width
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onUpPressed: function(event) {
|
Keys.onUpPressed: function(event) {
|
||||||
if(autocompleteEnabled)
|
if(autocompleteEnabled)
|
||||||
if(acPopupContent.itemSelected == 0)
|
if(acPopupContent.itemSelected == 0)
|
||||||
|
@ -273,17 +204,22 @@ Item {
|
||||||
|
|
||||||
Keys.onPressed: function(event) {
|
Keys.onPressed: function(event) {
|
||||||
// Autocomplete popup events
|
// Autocomplete popup events
|
||||||
|
//console.log(acPopupContent.currentToken.dot, acPopupContent.previousToken.dot, "@", acPopupContent.currentToken.identifier, acPopupContent.previousToken.identifier, acPopupContent.previousToken2.identifier, objectPropertiesList.objectName, JSON.stringify(objectPropertiesList.baseText), objectPropertiesList.model.length, JSON.stringify(objectPropertiesList.categoryItems))
|
||||||
|
//console.log("Pressed key:", event.key, Qt.Key_Return, Qt.Key_Enter, event.text, acPopupContent.itemCount)
|
||||||
if(autocompleteEnabled && (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) && acPopupContent.itemCount > 0) {
|
if(autocompleteEnabled && (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) && acPopupContent.itemCount > 0) {
|
||||||
acPopupContent.autocomplete()
|
acPopupContent.autocomplete()
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
} else
|
} else
|
||||||
acPopupContent.itemSelected = 0
|
acPopupContent.itemSelected = 0
|
||||||
|
/*if(event.key == Qt.Key_Left) { // TODO: Don't reset the position when the key moved is still on the same word
|
||||||
|
if(!acPopupContent.identifierTokenTypes.includes())
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
if(event.text in parent.openAndCloseMatches && autoClosing) {
|
if(event.text in openAndCloseMatches && autoClosing) {
|
||||||
let start = selectionStart
|
let start = selectionStart
|
||||||
insert(selectionStart, event.text)
|
insert(selectionStart, event.text)
|
||||||
insert(selectionEnd, parent.openAndCloseMatches[event.text])
|
insert(selectionEnd, openAndCloseMatches[event.text])
|
||||||
cursorPosition = start+1
|
cursorPosition = start+1
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
}
|
}
|
||||||
|
@ -317,9 +253,9 @@ Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
readonly property var identifierTokenTypes: [
|
readonly property var identifierTokenTypes: [
|
||||||
JS.Parsing.TokenType.VARIABLE,
|
Parsing.TokenType.VARIABLE,
|
||||||
JS.Parsing.TokenType.FUNCTION,
|
Parsing.TokenType.FUNCTION,
|
||||||
JS.Parsing.TokenType.CONSTANT
|
Parsing.TokenType.CONSTANT
|
||||||
]
|
]
|
||||||
property var currentToken: generateTokenInformation(getTokenAt(editor.tokens, editor.cursorPosition))
|
property var currentToken: generateTokenInformation(getTokenAt(editor.tokens, editor.cursorPosition))
|
||||||
property var previousToken: generateTokenInformation(getPreviousToken(currentToken.token))
|
property var previousToken: generateTokenInformation(getPreviousToken(currentToken.token))
|
||||||
|
@ -344,7 +280,7 @@ Item {
|
||||||
'value': exists ? token.value : null,
|
'value': exists ? token.value : null,
|
||||||
'type': exists ? token.type : null,
|
'type': exists ? token.type : null,
|
||||||
'startPosition': exists ? token.startPosition : 0,
|
'startPosition': exists ? token.startPosition : 0,
|
||||||
'dot': exists ? (token.type == JS.Parsing.TokenType.PUNCT && token.value == ".") : false,
|
'dot': exists ? (token.type == Parsing.TokenType.PUNCT && token.value == ".") : false,
|
||||||
'identifier': exists ? identifierTokenTypes.includes(token.type) : false
|
'identifier': exists ? identifierTokenTypes.includes(token.type) : false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -383,7 +319,7 @@ Item {
|
||||||
*/
|
*/
|
||||||
function getPreviousToken(token) {
|
function getPreviousToken(token) {
|
||||||
let newToken = getTokenAt(editor.tokens, token.startPosition)
|
let newToken = getTokenAt(editor.tokens, token.startPosition)
|
||||||
if(newToken != null && newToken.type == JS.Parsing.TokenType.WHITESPACE)
|
if(newToken != null && newToken.type == Parsing.TokenType.WHITESPACE)
|
||||||
return getPreviousToken(newToken)
|
return getPreviousToken(newToken)
|
||||||
return newToken
|
return newToken
|
||||||
}
|
}
|
||||||
|
@ -392,7 +328,7 @@ Item {
|
||||||
id: objectPropertiesList
|
id: objectPropertiesList
|
||||||
|
|
||||||
category: qsTr("Object Properties")
|
category: qsTr("Object Properties")
|
||||||
visbilityCondition: control.allowGraphObjects && doesObjectExist
|
visbilityCondition: doesObjectExist
|
||||||
itemStartIndex: 0
|
itemStartIndex: 0
|
||||||
itemSelected: parent.itemSelected
|
itemSelected: parent.itemSelected
|
||||||
property bool isEnteringProperty: (
|
property bool isEnteringProperty: (
|
||||||
|
@ -403,9 +339,9 @@ Item {
|
||||||
property string objectName: isEnteringProperty ?
|
property string objectName: isEnteringProperty ?
|
||||||
(parent.currentToken.dot ? parent.previousToken.value : parent.previousToken2.value)
|
(parent.currentToken.dot ? parent.previousToken.value : parent.previousToken2.value)
|
||||||
: ""
|
: ""
|
||||||
property bool doesObjectExist: isEnteringProperty && (objectName in Modules.Objects.currentObjectsByName)
|
property bool doesObjectExist: isEnteringProperty && objectName in Objects.currentObjectsByName
|
||||||
property var objectProperties: doesObjectExist ?
|
property var objectProperties: doesObjectExist ?
|
||||||
Modules.Objects.currentObjectsByName[objectName].constructor.properties() :
|
Objects.currentObjectsByName[objectName].constructor.properties() :
|
||||||
{}
|
{}
|
||||||
categoryItems: Object.keys(objectProperties)
|
categoryItems: Object.keys(objectProperties)
|
||||||
autocompleteGenerator: (item) => {
|
autocompleteGenerator: (item) => {
|
||||||
|
@ -442,9 +378,9 @@ Item {
|
||||||
visbilityCondition: parent.currentToken.identifier && !parent.previousToken.dot
|
visbilityCondition: parent.currentToken.identifier && !parent.previousToken.dot
|
||||||
itemStartIndex: variablesList.itemStartIndex + variablesList.model.length
|
itemStartIndex: variablesList.itemStartIndex + variablesList.model.length
|
||||||
itemSelected: parent.itemSelected
|
itemSelected: parent.itemSelected
|
||||||
categoryItems: JS.Parsing.CONSTANTS_LIST
|
categoryItems: Parsing.CONSTANTS_LIST
|
||||||
autocompleteGenerator: (item) => {return {
|
autocompleteGenerator: (item) => {return {
|
||||||
'text': item, 'annotation': JS.Parsing.CONSTANTS[item],
|
'text': item, 'annotation': '',
|
||||||
'autocomplete': item + " ", 'cursorFinalOffset': 0
|
'autocomplete': item + " ", 'cursorFinalOffset': 0
|
||||||
}}
|
}}
|
||||||
baseText: parent.visible ? parent.currentToken.value : ""
|
baseText: parent.visible ? parent.currentToken.value : ""
|
||||||
|
@ -457,9 +393,9 @@ Item {
|
||||||
visbilityCondition: parent.currentToken.identifier && !parent.previousToken.dot
|
visbilityCondition: parent.currentToken.identifier && !parent.previousToken.dot
|
||||||
itemStartIndex: constantsList.itemStartIndex + constantsList.model.length
|
itemStartIndex: constantsList.itemStartIndex + constantsList.model.length
|
||||||
itemSelected: parent.itemSelected
|
itemSelected: parent.itemSelected
|
||||||
categoryItems: JS.Parsing.FUNCTIONS_LIST
|
categoryItems: Parsing.FUNCTIONS_LIST
|
||||||
autocompleteGenerator: (item) => {return {
|
autocompleteGenerator: (item) => {return {
|
||||||
'text': item, 'annotation': JS.Parsing.FUNCTIONS_USAGE[item].join(', '),
|
'text': item, 'annotation': '',
|
||||||
'autocomplete': item+'()', 'cursorFinalOffset': -1
|
'autocomplete': item+'()', 'cursorFinalOffset': -1
|
||||||
}}
|
}}
|
||||||
baseText: parent.visible ? parent.currentToken.value : ""
|
baseText: parent.visible ? parent.currentToken.value : ""
|
||||||
|
@ -469,12 +405,12 @@ Item {
|
||||||
id: executableObjectsList
|
id: executableObjectsList
|
||||||
|
|
||||||
category: qsTr("Executable Objects")
|
category: qsTr("Executable Objects")
|
||||||
visbilityCondition: control.allowGraphObjects && parent.currentToken.identifier && !parent.previousToken.dot
|
visbilityCondition: parent.currentToken.identifier && !parent.previousToken.dot
|
||||||
itemStartIndex: functionsList.itemStartIndex + functionsList.model.length
|
itemStartIndex: functionsList.itemStartIndex + functionsList.model.length
|
||||||
itemSelected: parent.itemSelected
|
itemSelected: parent.itemSelected
|
||||||
categoryItems: Modules.Objects.getObjectsName("ExecutableObject").filter(obj => obj != self)
|
categoryItems: Objects.getObjectsName("ExecutableObject").filter(obj => obj != self)
|
||||||
autocompleteGenerator: (item) => {return {
|
autocompleteGenerator: (item) => {return {
|
||||||
'text': item, 'annotation': Modules.Objects.currentObjectsByName[item] == null ? '' : Modules.Objects.currentObjectsByName[item].constructor.displayType(),
|
'text': item, 'annotation': Objects.currentObjectsByName[item] == null ? '' : Objects.currentObjectsByName[item].constructor.displayType(),
|
||||||
'autocomplete': item+'()', 'cursorFinalOffset': -1
|
'autocomplete': item+'()', 'cursorFinalOffset': -1
|
||||||
}}
|
}}
|
||||||
baseText: parent.visible ? parent.currentToken.value : ""
|
baseText: parent.visible ? parent.currentToken.value : ""
|
||||||
|
@ -484,12 +420,12 @@ Item {
|
||||||
id: objectsList
|
id: objectsList
|
||||||
|
|
||||||
category: qsTr("Objects")
|
category: qsTr("Objects")
|
||||||
visbilityCondition: control.allowGraphObjects && parent.currentToken.identifier && !parent.previousToken.dot
|
visbilityCondition: parent.currentToken.identifier && !parent.previousToken.dot
|
||||||
itemStartIndex: executableObjectsList.itemStartIndex + executableObjectsList.model.length
|
itemStartIndex: executableObjectsList.itemStartIndex + executableObjectsList.model.length
|
||||||
itemSelected: parent.itemSelected
|
itemSelected: parent.itemSelected
|
||||||
categoryItems: Object.keys(Modules.Objects.currentObjectsByName).filter(obj => obj != self)
|
categoryItems: Object.keys(Objects.currentObjectsByName).filter(obj => obj != self)
|
||||||
autocompleteGenerator: (item) => {return {
|
autocompleteGenerator: (item) => {return {
|
||||||
'text': item, 'annotation': `${Modules.Objects.currentObjectsByName[item].constructor.displayType()}`,
|
'text': item, 'annotation': `${Objects.currentObjectsByName[item].constructor.displayType()}`,
|
||||||
'autocomplete': item+'.', 'cursorFinalOffset': 0
|
'autocomplete': item+'.', 'cursorFinalOffset': 0
|
||||||
}}
|
}}
|
||||||
baseText: parent.visible ? parent.currentToken.value : ""
|
baseText: parent.visible ? parent.currentToken.value : ""
|
||||||
|
@ -500,41 +436,27 @@ Item {
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: insertButton
|
id: insertButton
|
||||||
|
text: "α"
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 5
|
anchors.rightMargin: 5
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
width: 20
|
width: 20
|
||||||
height: width
|
height: width
|
||||||
|
|
||||||
Icon {
|
|
||||||
id: icon
|
|
||||||
width: 12
|
|
||||||
height: 12
|
|
||||||
anchors.centerIn: parent
|
|
||||||
|
|
||||||
color: sysPalette.windowText
|
|
||||||
source: '../icons/properties/expression.svg'
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
insertPopup.open()
|
insertPopup.open()
|
||||||
insertPopup.setFocus()
|
insertPopup.focus = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
P.InsertCharacter {
|
P.InsertCharacter {
|
||||||
id: insertPopup
|
id: insertPopup
|
||||||
|
|
||||||
x: parent.width - width
|
x: Math.round((parent.width - width) / 2)
|
||||||
y: parent.height
|
y: Math.round((parent.height - height) / 2)
|
||||||
|
|
||||||
category: "expression"
|
|
||||||
|
|
||||||
onSelected: function(c) {
|
onSelected: function(c) {
|
||||||
editor.insert(editor.cursorPosition, c)
|
editor.insert(editor.cursorPosition, c)
|
||||||
}
|
insertPopup.close()
|
||||||
|
|
||||||
onClosed: function() {
|
|
||||||
focus = false
|
focus = false
|
||||||
editor.focus = true
|
editor.focus = true
|
||||||
}
|
}
|
||||||
|
@ -548,9 +470,9 @@ Item {
|
||||||
function parse(newExpression) {
|
function parse(newExpression) {
|
||||||
let expr = null
|
let expr = null
|
||||||
try {
|
try {
|
||||||
expr = new JS.MathLib.Expression(value.toString())
|
expr = new MathLib.Expression(value.toString())
|
||||||
// Check if the expression is valid, throws error otherwise.
|
// Check if the expression is valid, throws error otherwise.
|
||||||
if(!expr.allRequirementsFulfilled()) {
|
if(!expr.allRequirementsFullfilled()) {
|
||||||
let undefVars = expr.undefinedVariables()
|
let undefVars = expr.undefinedVariables()
|
||||||
if(undefVars.length > 1)
|
if(undefVars.length > 1)
|
||||||
throw new Error(qsTranslate('error', 'No object found with names %1.').arg(undefVars.join(', ')))
|
throw new Error(qsTranslate('error', 'No object found with names %1.').arg(undefVars.join(', ')))
|
||||||
|
@ -561,8 +483,8 @@ Item {
|
||||||
throw new Error(qsTranslate('error', 'Object cannot be dependent on itself.'))
|
throw new Error(qsTranslate('error', 'Object cannot be dependent on itself.'))
|
||||||
// Recursive dependencies
|
// Recursive dependencies
|
||||||
let dependentOnSelfObjects = expr.requiredObjects().filter(
|
let dependentOnSelfObjects = expr.requiredObjects().filter(
|
||||||
(obj) => Modules.Objects.currentObjectsByName[obj].getDependenciesList()
|
(obj) => Objects.currentObjectsByName[obj].getDependenciesList()
|
||||||
.includes(Modules.Objects.currentObjectsByName[control.self])
|
.includes(Objects.currentObjectsByName[control.self])
|
||||||
)
|
)
|
||||||
if(dependentOnSelfObjects.length == 1)
|
if(dependentOnSelfObjects.length == 1)
|
||||||
throw new Error(qsTranslate('error', 'Circular dependency detected. Object %1 depends on %2.').arg(dependentOnSelfObjects[0].toString()).arg(control.self))
|
throw new Error(qsTranslate('error', 'Circular dependency detected. Object %1 depends on %2.').arg(dependentOnSelfObjects[0].toString()).arg(control.self))
|
||||||
|
@ -582,7 +504,7 @@ Item {
|
||||||
Generates a list of tokens from the given.
|
Generates a list of tokens from the given.
|
||||||
*/
|
*/
|
||||||
function tokens(text) {
|
function tokens(text) {
|
||||||
let tokenizer = new JS.Parsing.Tokenizer(new JS.Parsing.Input(text), true, false)
|
let tokenizer = new Parsing.Tokenizer(new Parsing.Input(text), true, true, false)
|
||||||
let tokenList = []
|
let tokenList = []
|
||||||
let token
|
let token
|
||||||
while((token = tokenizer.next()) != null)
|
while((token = tokenizer.next()) != null)
|
||||||
|
@ -612,31 +534,30 @@ Item {
|
||||||
*/
|
*/
|
||||||
function colorize(tokenList) {
|
function colorize(tokenList) {
|
||||||
let parsedText = ""
|
let parsedText = ""
|
||||||
let scheme = colorSchemes[Helper.getSetting("expression_editor.color_scheme")]
|
|
||||||
for(let token of tokenList) {
|
for(let token of tokenList) {
|
||||||
switch(token.type) {
|
switch(token.type) {
|
||||||
case JS.Parsing.TokenType.VARIABLE:
|
case Parsing.TokenType.VARIABLE:
|
||||||
parsedText += `<font color="${scheme.VARIABLE}">${token.value}</font>`
|
parsedText += `<font color="${colorScheme.VARIABLE}">${token.value}</font>`
|
||||||
break;
|
break;
|
||||||
case JS.Parsing.TokenType.CONSTANT:
|
case Parsing.TokenType.CONSTANT:
|
||||||
parsedText += `<font color="${scheme.CONSTANT}">${token.value}</font>`
|
parsedText += `<font color="${colorScheme.CONSTANT}">${token.value}</font>`
|
||||||
break;
|
break;
|
||||||
case JS.Parsing.TokenType.FUNCTION:
|
case Parsing.TokenType.FUNCTION:
|
||||||
parsedText += `<font color="${scheme.FUNCTION}">${JS.Utils.escapeHTML(token.value)}</font>`
|
parsedText += `<font color="${colorScheme.FUNCTION}">${Utils.escapeHTML(token.value)}</font>`
|
||||||
break;
|
break;
|
||||||
case JS.Parsing.TokenType.OPERATOR:
|
case Parsing.TokenType.OPERATOR:
|
||||||
parsedText += `<font color="${scheme.OPERATOR}">${JS.Utils.escapeHTML(token.value)}</font>`
|
parsedText += `<font color="${colorScheme.OPERATOR}">${Utils.escapeHTML(token.value)}</font>`
|
||||||
break;
|
break;
|
||||||
case JS.Parsing.TokenType.NUMBER:
|
case Parsing.TokenType.NUMBER:
|
||||||
parsedText += `<font color="${scheme.NUMBER}">${JS.Utils.escapeHTML(token.value)}</font>`
|
parsedText += `<font color="${colorScheme.NUMBER}">${Utils.escapeHTML(token.value)}</font>`
|
||||||
break;
|
break;
|
||||||
case JS.Parsing.TokenType.STRING:
|
case Parsing.TokenType.STRING:
|
||||||
parsedText += `<font color="${scheme.STRING}">${token.limitator}${JS.Utils.escapeHTML(token.value)}${token.limitator}</font>`
|
parsedText += `<font color="${colorScheme.STRING}">${token.limitator}${Utils.escapeHTML(token.value)}${token.limitator}</font>`
|
||||||
break;
|
break;
|
||||||
case JS.Parsing.TokenType.WHITESPACE:
|
case Parsing.TokenType.WHITESPACE:
|
||||||
case JS.Parsing.TokenType.PUNCT:
|
case Parsing.TokenType.PUNCT:
|
||||||
default:
|
default:
|
||||||
parsedText += JS.Utils.escapeHTML(token.value).replace(/ /g, ' ')
|
parsedText += Utils.escapeHTML(token.value).replace(/ /g, ' ')
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -15,9 +15,8 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import QtQuick
|
import QtQuick 2.7
|
||||||
import QtQuick.Window
|
import QtGraphicalEffects 1.0
|
||||||
import QtQuick.Controls.impl
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmltype Icon
|
\qmltype Icon
|
||||||
|
@ -41,16 +40,20 @@ Item {
|
||||||
\qmlproperty string Icon::source
|
\qmlproperty string Icon::source
|
||||||
Path of the icon image source.
|
Path of the icon image source.
|
||||||
*/
|
*/
|
||||||
property alias sourceSize: img.sourceS
|
property alias sourceSize: img.sourceSize.width
|
||||||
|
|
||||||
ColorImage {
|
Image {
|
||||||
id: img
|
id: img
|
||||||
height: parent.height
|
height: parent.height
|
||||||
width: parent.width
|
width: parent.width
|
||||||
// visible: false
|
//smooth: true
|
||||||
property int sourceS: width*Screen.devicePixelRatio
|
visible: false
|
||||||
sourceSize.width: sourceS
|
sourceSize.width: width*2
|
||||||
sourceSize.height: sourceS
|
sourceSize.height: width*2
|
||||||
|
}
|
||||||
|
ColorOverlay {
|
||||||
|
anchors.fill: img
|
||||||
|
source: img
|
||||||
color: parent.color
|
color: parent.color
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,9 +16,9 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick 2.12
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls 2.12
|
||||||
import QtQml.Models
|
import QtQml.Models 2.12
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmltype ListSetting
|
\qmltype ListSetting
|
||||||
|
@ -140,8 +140,8 @@ Column {
|
||||||
visible: control.dictionaryMode
|
visible: control.dictionaryMode
|
||||||
height: parent.height
|
height: parent.height
|
||||||
width: visible ? 50 : 0
|
width: visible ? 50 : 0
|
||||||
validator: RegularExpressionValidator {
|
validator: RegExpValidator {
|
||||||
regularExpression: control.keyRegexp
|
regExp: control.keyRegexp
|
||||||
}
|
}
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
horizontalAlignment: TextInput.AlignHCenter
|
horizontalAlignment: TextInput.AlignHCenter
|
||||||
|
@ -180,8 +180,8 @@ Column {
|
||||||
id: valueInput
|
id: valueInput
|
||||||
height: parent.height
|
height: parent.height
|
||||||
width: parent.width - x - deleteButton.width - 5
|
width: parent.width - x - deleteButton.width - 5
|
||||||
validator: RegularExpressionValidator {
|
validator: RegExpValidator {
|
||||||
regularExpression: control.valueRegexp
|
regExp: control.valueRegexp
|
||||||
}
|
}
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
horizontalAlignment: TextInput.AlignHCenter
|
horizontalAlignment: TextInput.AlignHCenter
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,8 +16,8 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls 2.12
|
||||||
import QtQuick
|
import QtQuick 2.12
|
||||||
import eu.ad5001.LogarithmPlotter.Popup 1.0 as Popup
|
import eu.ad5001.LogarithmPlotter.Popup 1.0 as Popup
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -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(var newValue)
|
signal changed(string newValue)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty bool TextSetting::isInt
|
\qmlproperty bool TextSetting::isInt
|
||||||
|
@ -49,12 +49,6 @@ Item {
|
||||||
If true, the input is being parsed an double before being emitting the \a changed signal.
|
If true, the input is being parsed an double before being emitting the \a changed signal.
|
||||||
*/
|
*/
|
||||||
property bool isDouble: false
|
property bool isDouble: false
|
||||||
/*!
|
|
||||||
\qmlproperty bool TextSetting::category
|
|
||||||
Type of special character to insert from the popup.
|
|
||||||
\sa InsertCharacter::category
|
|
||||||
*/
|
|
||||||
property alias category: insertPopup.category
|
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty double TextSetting::min
|
\qmlproperty double TextSetting::min
|
||||||
Minimum value for numbers that can be entered into the input.
|
Minimum value for numbers that can be entered into the input.
|
||||||
|
@ -100,15 +94,15 @@ Item {
|
||||||
id: labelItem
|
id: labelItem
|
||||||
anchors.left: iconLabel.right
|
anchors.left: iconLabel.right
|
||||||
anchors.leftMargin: icon == "" ? 0 : 5
|
anchors.leftMargin: icon == "" ? 0 : 5
|
||||||
anchors.top: parent.top
|
|
||||||
height: parent.height
|
height: parent.height
|
||||||
width: visible ? Math.max(85, implicitWidth) : 0
|
anchors.top: parent.top
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
//color: sysPalette.windowText
|
//color: sysPalette.windowText
|
||||||
text: visible ? qsTranslate("control", "%1: ").arg(control.label) : ""
|
text: visible ? qsTranslate("control", "%1: ").arg(control.label) : ""
|
||||||
visible: control.label != ""
|
visible: control.label != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: input
|
id: input
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
@ -119,23 +113,18 @@ Item {
|
||||||
verticalAlignment: TextInput.AlignVCenter
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
horizontalAlignment: control.label == "" ? TextInput.AlignLeft : TextInput.AlignHCenter
|
horizontalAlignment: control.label == "" ? TextInput.AlignLeft : TextInput.AlignHCenter
|
||||||
color: sysPalette.windowText
|
color: sysPalette.windowText
|
||||||
validator: RegularExpressionValidator {
|
validator: RegExpValidator {
|
||||||
regularExpression: control.isInt ? /-?[0-9]+/ : control.isDouble ? /-?[0-9]+(\.[0-9]+)?/ : /.+/
|
regExp: control.isInt ? /-?[0-9]+/ : control.isDouble ? /-?[0-9]+(\.[0-9]+)?/ : /.+/
|
||||||
}
|
}
|
||||||
focus: true
|
focus: true
|
||||||
text: control.defValue
|
text: control.defValue
|
||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
onEditingFinished: function() {
|
onEditingFinished: {
|
||||||
if(insertButton.focus || insertPopup.focus) return
|
if(insertButton.focus || insertPopup.focus) return
|
||||||
let value = text
|
var value = text
|
||||||
if(control.isInt) {
|
if(control.isInt) value = Math.max(control.min,parseInt(value).toString()=="NaN"?control.min:parseInt(value))
|
||||||
let parsed = parseInt(value)
|
if(control.isDouble) value = Math.max(control.min,parseFloat(value).toString()=="NaN"?control.min:parseFloat(value))
|
||||||
value = isNaN(parsed) ? control.min : Math.max(control.min,parsed)
|
if(value != "" && value.toString() != defValue) {
|
||||||
} else if(control.isDouble) {
|
|
||||||
let parsed = parseFloat(value)
|
|
||||||
value = isNaN(parsed) ? control.min : Math.max(control.min,parsed)
|
|
||||||
}
|
|
||||||
if(value !== "" && value.toString() != defValue) {
|
|
||||||
control.changed(value)
|
control.changed(value)
|
||||||
defValue = value.toString()
|
defValue = value.toString()
|
||||||
}
|
}
|
||||||
|
@ -144,40 +133,28 @@ Item {
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: insertButton
|
id: insertButton
|
||||||
|
text: "α"
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 5
|
anchors.rightMargin: 5
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
width: 20
|
width: 20
|
||||||
height: width
|
height: width
|
||||||
visible: !isInt && !isDouble
|
visible: !isInt && !isDouble
|
||||||
|
|
||||||
Icon {
|
|
||||||
id: icon
|
|
||||||
width: 12
|
|
||||||
height: 12
|
|
||||||
anchors.centerIn: parent
|
|
||||||
|
|
||||||
color: sysPalette.windowText
|
|
||||||
source: '../icons/properties/expression.svg'
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
insertPopup.open()
|
insertPopup.open()
|
||||||
insertPopup.setFocus()
|
insertPopup.focus = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Popup.InsertCharacter {
|
Popup.InsertCharacter {
|
||||||
id: insertPopup
|
id: insertPopup
|
||||||
|
|
||||||
x: parent.width - width
|
x: Math.round((parent.width - width) / 2)
|
||||||
y: parent.height
|
y: Math.round((parent.height - height) / 2)
|
||||||
|
|
||||||
onSelected: function(c) {
|
onSelected: function(c) {
|
||||||
input.insert(input.cursorPosition, c)
|
input.insert(input.cursorPosition, c)
|
||||||
}
|
insertPopup.close()
|
||||||
|
|
||||||
onClosed: function() {
|
|
||||||
focus = false
|
focus = false
|
||||||
input.focus = true
|
input.focus = true
|
||||||
}
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
module eu.ad5001.LogarithmPlotter.Setting
|
module eu.ad5001.LogarithmPlotter.Setting
|
||||||
|
|
||||||
AutocompletionCategory 1.0 AutocompletionCategory.qml
|
|
||||||
ComboBoxSetting 1.0 ComboBoxSetting.qml
|
ComboBoxSetting 1.0 ComboBoxSetting.qml
|
||||||
ExpressionEditor 1.0 ExpressionEditor.qml
|
|
||||||
Icon 1.0 Icon.qml
|
Icon 1.0 Icon.qml
|
||||||
ListSetting 1.0 ListSetting.qml
|
ListSetting 1.0 ListSetting.qml
|
||||||
TextSetting 1.0 TextSetting.qml
|
TextSetting 1.0 TextSetting.qml
|
||||||
|
ExpressionEditor 1.0 ExpressionEditor.qml
|
||||||
|
AutocompletionCategory 1.0 AutocompletionCategory.qml
|
|
@ -1,6 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||||
* Copyright (C) 2021-2024 Ad5001
|
* Copyright (C) 2022 Ad5001
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,11 +16,11 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick.Controls 2.12
|
||||||
import QtQuick.Controls
|
import QtQuick 2.12
|
||||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||||
import eu.ad5001.LogarithmPlotter.Popup 1.0 as Popup
|
import eu.ad5001.LogarithmPlotter.Popup 1.0 as Popup
|
||||||
import eu.ad5001.LogarithmPlotter.Common
|
import "js/utils.js" as Utils
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmltype Settings
|
\qmltype Settings
|
||||||
|
@ -44,83 +44,88 @@ ScrollView {
|
||||||
Zoom on the x axis of the diagram, provided from settings.
|
Zoom on the x axis of the diagram, provided from settings.
|
||||||
\sa Settings
|
\sa Settings
|
||||||
*/
|
*/
|
||||||
property double xzoom: Helper.getSetting('default_graph.xzoom')
|
property double xzoom: 100
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty double Settings::yzoom
|
\qmlproperty double Settings::yzoom
|
||||||
Zoom on the y axis of the diagram, provided from settings.
|
Zoom on the y axis of the diagram, provided from settings.
|
||||||
\sa Settings
|
\sa Settings
|
||||||
*/
|
*/
|
||||||
property double yzoom: Helper.getSetting('default_graph.yzoom')
|
property double yzoom: 10
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty double Settings::xmin
|
\qmlproperty double Settings::xmin
|
||||||
Minimum x of the diagram, provided from settings.
|
Minimum x of the diagram, provided from settings.
|
||||||
\sa Settings
|
\sa Settings
|
||||||
*/
|
*/
|
||||||
property double xmin: Helper.getSetting('default_graph.xmin')
|
property double xmin: 5/10
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty double Settings::ymax
|
\qmlproperty double Settings::ymax
|
||||||
Maximum y of the diagram, provided from settings.
|
Maximum y of the diagram, provided from settings.
|
||||||
\sa Settings
|
\sa Settings
|
||||||
*/
|
*/
|
||||||
property double ymax: Helper.getSetting('default_graph.ymax')
|
property double ymax: 25
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty string Settings::xaxisstep
|
\qmlproperty string Settings::xaxisstep
|
||||||
Step of the x axis graduation, provided from settings.
|
Step of the x axis graduation, provided from settings.
|
||||||
\note: Only available in non-logarithmic mode.
|
\note: Only available in non-logarithmic mode.
|
||||||
\sa Settings
|
\sa Settings
|
||||||
*/
|
*/
|
||||||
property string xaxisstep: Helper.getSetting('default_graph.xaxisstep')
|
property string xaxisstep: "4"
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty string Settings::yaxisstep
|
\qmlproperty string Settings::yaxisstep
|
||||||
Step of the y axis graduation, provided from settings.
|
Step of the y axis graduation, provided from settings.
|
||||||
\sa Settings
|
\sa Settings
|
||||||
*/
|
*/
|
||||||
property string yaxisstep: Helper.getSetting('default_graph.yaxisstep')
|
property string yaxisstep: "4"
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty string Settings::xlabel
|
\qmlproperty string Settings::xlabel
|
||||||
Label used on the x axis, provided from settings.
|
Label used on the x axis, provided from settings.
|
||||||
\sa Settings
|
\sa Settings
|
||||||
*/
|
*/
|
||||||
property string xlabel: Helper.getSetting('default_graph.xlabel')
|
property string xlabel: ""
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty string Settings::ylabel
|
\qmlproperty string Settings::ylabel
|
||||||
Label used on the y axis, provided from settings.
|
Label used on the y axis, provided from settings.
|
||||||
\sa Settings
|
\sa Settings
|
||||||
*/
|
*/
|
||||||
property string ylabel: Helper.getSetting('default_graph.ylabel')
|
property string ylabel: ""
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty double Settings::linewidth
|
\qmlproperty double Settings::linewidth
|
||||||
Width of lines that will be drawn into the canvas, provided from settings.
|
Width of lines that will be drawn into the canvas, provided from settings.
|
||||||
\sa Settings
|
\sa Settings
|
||||||
*/
|
*/
|
||||||
property double linewidth: Helper.getSetting('default_graph.linewidth')
|
property double linewidth: 1
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty double Settings::textsize
|
\qmlproperty double Settings::textsize
|
||||||
Font size of the text that will be drawn into the canvas, provided from settings.
|
Font size of the text that will be drawn into the canvas, provided from settings.
|
||||||
\sa Settings
|
\sa Settings
|
||||||
*/
|
*/
|
||||||
property double textsize: Helper.getSetting('default_graph.textsize')
|
property double textsize: 18
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty bool Settings::logscalex
|
\qmlproperty bool Settings::logscalex
|
||||||
true if the canvas should be in logarithmic mode, false otherwise.
|
true if the canvas should be in logarithmic mode, false otherwise.
|
||||||
Provided from settings.
|
Provided from settings.
|
||||||
\sa Settings
|
\sa Settings
|
||||||
*/
|
*/
|
||||||
property bool logscalex: Helper.getSetting('default_graph.logscalex')
|
property bool logscalex: true
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty bool Settings::showxgrad
|
\qmlproperty bool Settings::showxgrad
|
||||||
true if the x graduation should be shown, false otherwise.
|
true if the x graduation should be shown, false otherwise.
|
||||||
Provided from settings.
|
Provided from settings.
|
||||||
\sa Settings
|
\sa Settings
|
||||||
*/
|
*/
|
||||||
property bool showxgrad: Helper.getSetting('default_graph.showxgrad')
|
property bool showxgrad: true
|
||||||
/*!
|
/*!
|
||||||
\qmlproperty bool Settings::showygrad
|
\qmlproperty bool Settings::showygrad
|
||||||
true if the y graduation should be shown, false otherwise.
|
true if the y graduation should be shown, false otherwise.
|
||||||
Provided from settings.
|
Provided from settings.
|
||||||
\sa Settings
|
\sa Settings
|
||||||
*/
|
*/
|
||||||
property bool showygrad: Helper.getSetting('default_graph.showygrad')
|
property bool showygrad: true
|
||||||
|
/*!
|
||||||
|
\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
|
||||||
|
@ -130,19 +135,16 @@ ScrollView {
|
||||||
Popup.FileDialog {
|
Popup.FileDialog {
|
||||||
id: fdiag
|
id: fdiag
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
var filePath = fdiag.currentFile.toString().substr(7)
|
var filePath = fileUrl.toString().substr(7)
|
||||||
Modules.Settings.set("saveFilename", filePath)
|
settings.saveFilename = filePath
|
||||||
if(exportMode) {
|
if(exportMode) {
|
||||||
Modules.IO.saveDiagram(filePath)
|
root.saveDiagram(filePath)
|
||||||
} else {
|
} else {
|
||||||
Modules.IO.loadDiagram(filePath)
|
root.loadDiagram(filePath)
|
||||||
// Adding labels.
|
if(xAxisLabel.find(settings.xlabel) == -1) xAxisLabel.model.append({text: settings.xlabel})
|
||||||
if(xAxisLabel.find(Modules.Settings.xlabel) === -1)
|
xAxisLabel.editText = settings.xlabel
|
||||||
xAxisLabel.model.append({text: Modules.Settings.xlabel})
|
if(yAxisLabel.find(settings.ylabel) == -1) yAxisLabel.model.append({text: settings.ylabel})
|
||||||
xAxisLabel.editText = Modules.Settings.xlabel
|
yAxisLabel.editText = settings.ylabel
|
||||||
if(yAxisLabel.find(Modules.Settings.ylabel) === -1)
|
|
||||||
yAxisLabel.model.append({text: Modules.Settings.ylabel})
|
|
||||||
yAxisLabel.editText = Modules.Settings.ylabel
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,39 +155,28 @@ ScrollView {
|
||||||
height: 30
|
height: 30
|
||||||
isDouble: true
|
isDouble: true
|
||||||
label: qsTr("X Zoom")
|
label: qsTr("X Zoom")
|
||||||
min: 0.1
|
min: 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) {
|
||||||
Modules.Settings.set("xzoom", newValue, true)
|
settings.xzoom = newValue
|
||||||
settings.changed()
|
settings.changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
function update(newValue) {
|
|
||||||
value = Modules.Settings.xzoom.toFixed(2)
|
|
||||||
maxX.update()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Setting.TextSetting {
|
Setting.TextSetting {
|
||||||
id: zoomY
|
id: zoomY
|
||||||
height: 30
|
height: 30
|
||||||
isDouble: true
|
isDouble: true
|
||||||
min: 0.1
|
|
||||||
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) {
|
||||||
Modules.Settings.set("yzoom", newValue, true)
|
settings.yzoom = newValue
|
||||||
settings.changed()
|
settings.changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
function update(newValue) {
|
|
||||||
value = Modules.Settings.yzoom.toFixed(2)
|
|
||||||
minY.update()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Positioning the graph
|
// Positioning the graph
|
||||||
|
@ -197,18 +188,14 @@ 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) {
|
||||||
Modules.Settings.set("xmin", newValue, true)
|
if(parseFloat(maxX.value) > newValue) {
|
||||||
|
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,16 +207,11 @@ 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) {
|
||||||
Modules.Settings.set("ymax", newValue, true)
|
settings.ymax = newValue
|
||||||
settings.changed()
|
settings.changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
function update() {
|
|
||||||
value = Modules.Settings.ymax
|
|
||||||
minY.update()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Setting.TextSetting {
|
Setting.TextSetting {
|
||||||
|
@ -240,24 +222,15 @@ ScrollView {
|
||||||
label: qsTr("Max X")
|
label: qsTr("Max X")
|
||||||
icon: "settings/xmax.svg"
|
icon: "settings/xmax.svg"
|
||||||
width: settings.settingWidth
|
width: settings.settingWidth
|
||||||
|
value: canvas.px2x(canvas.canvasSize.width).toFixed(2)
|
||||||
onChanged: function(xvaluemax) {
|
onChanged: function(xvaluemax) {
|
||||||
if(xvaluemax > Modules.Settings.xmin) {
|
if(xvaluemax > settings.xmin) {
|
||||||
const newXZoom = Modules.Settings.xzoom * canvas.width/(Modules.Canvas.x2px(xvaluemax)) // Adjusting zoom to fit. = (end)/(px of current point)
|
settings.xzoom = settings.xzoom * canvas.canvasSize.width/(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 {
|
||||||
|
@ -268,56 +241,42 @@ ScrollView {
|
||||||
label: qsTr("Min Y")
|
label: qsTr("Min Y")
|
||||||
icon: "settings/ymin.svg"
|
icon: "settings/ymin.svg"
|
||||||
width: settings.settingWidth
|
width: settings.settingWidth
|
||||||
|
defValue: canvas.px2y(canvas.canvasSize.height).toFixed(2)
|
||||||
onChanged: function(yvaluemin) {
|
onChanged: function(yvaluemin) {
|
||||||
if(yvaluemin < settings.ymax) {
|
if(yvaluemin < settings.ymax) {
|
||||||
const newYZoom = Modules.Settings.yzoom * canvas.height/(Modules.Canvas.y2px(yvaluemin)) // Adjusting zoom to fit. = (end)/(px of current point)
|
settings.yzoom = settings.yzoom * canvas.canvasSize.height/(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 {
|
||||||
id: xAxisStep
|
id: xAxisStep
|
||||||
height: 30
|
height: 30
|
||||||
category: "expression"
|
|
||||||
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) {
|
||||||
Modules.Settings.set("xaxisstep", newValue, true)
|
settings.xaxisstep = newValue
|
||||||
settings.changed()
|
settings.changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
function update() {
|
|
||||||
value = Modules.Settings.xaxisstep
|
|
||||||
visible = !Modules.Settings.logscalex
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Setting.TextSetting {
|
Setting.TextSetting {
|
||||||
id: yAxisStep
|
id: yAxisStep
|
||||||
height: 30
|
height: 30
|
||||||
category: "expression"
|
|
||||||
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) {
|
||||||
Modules.Settings.set("yaxisstep", newValue, true)
|
settings.yaxisstep = newValue
|
||||||
settings.changed()
|
settings.changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
function update() { value = Modules.Settings.yaxisstep }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Setting.TextSetting {
|
Setting.TextSetting {
|
||||||
|
@ -328,13 +287,11 @@ 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) {
|
||||||
Modules.Settings.set("linewidth", newValue, true)
|
settings.linewidth = newValue
|
||||||
settings.changed()
|
settings.changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
function update() { value = Modules.Settings.linewidth }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Setting.TextSetting {
|
Setting.TextSetting {
|
||||||
|
@ -345,13 +302,11 @@ 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) {
|
||||||
Modules.Settings.set("textsize", newValue, true)
|
settings.textsize = newValue
|
||||||
settings.changed()
|
settings.changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
function update() { value = Modules.Settings.textsize }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Setting.ComboBoxSetting {
|
Setting.ComboBoxSetting {
|
||||||
|
@ -360,31 +315,24 @@ 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 = Utils.parseName(editText, false)
|
||||||
if(find(editText) === -1) model.append({text: editText})
|
if (find(editText) === -1) model.append({text: editText})
|
||||||
currentIndex = find(editText)
|
settings.xlabel = editText
|
||||||
Modules.Settings.set("xlabel", editText, true)
|
|
||||||
settings.changed()
|
settings.changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
onActivated: function(selectedId) {
|
onActivated: function(selectedId) {
|
||||||
Modules.Settings.set("xlabel", model.get(selectedId).text, true)
|
settings.xlabel = model.get(selectedId).text
|
||||||
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 {
|
||||||
|
@ -393,7 +341,6 @@ 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" }
|
||||||
|
@ -402,52 +349,39 @@ 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 = Utils.parseName(editText, false)
|
||||||
if(find(editText) === -1) model.append({text: editText})
|
if (find(editText) === -1) model.append({text: editText, yaxisstep: root.yaxisstep})
|
||||||
currentIndex = find(editText)
|
settings.ylabel = editText
|
||||||
Modules.Settings.set("ylabel", editText, true)
|
|
||||||
settings.changed()
|
settings.changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
onActivated: function(selectedId) {
|
onActivated: function(selectedId) {
|
||||||
Modules.Settings.set("ylabel", model.get(selectedId).text, true)
|
settings.ylabel = model.get(selectedId).text
|
||||||
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: {
|
||||||
Modules.Settings.set("logscalex", checked, true)
|
settings.logscalex = checked
|
||||||
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: {
|
||||||
Modules.Settings.set("showxgrad", checked, true)
|
settings.showxgrad = checked
|
||||||
settings.changed()
|
settings.changed()
|
||||||
}
|
}
|
||||||
|
|
||||||
function update() { checked = Modules.Settings.showxgrad }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckBox {
|
CheckBox {
|
||||||
|
@ -455,10 +389,9 @@ ScrollView {
|
||||||
checked: settings.showygrad
|
checked: settings.showygrad
|
||||||
text: qsTr('Show Y graduation')
|
text: qsTr('Show Y graduation')
|
||||||
onClicked: {
|
onClicked: {
|
||||||
Modules.Settings.set("showygrad", checked, true)
|
settings.showygrad = checked
|
||||||
settings.changed()
|
settings.changed()
|
||||||
}
|
}
|
||||||
function update() { checked = Modules.Settings.showygrad }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
|
@ -504,10 +437,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(Modules.Settings.saveFilename == "") {
|
if(settings.saveFilename == "") {
|
||||||
saveAs()
|
saveAs()
|
||||||
} else {
|
} else {
|
||||||
Modules.IO.saveDiagram(Modules.Settings.saveFilename)
|
root.saveDiagram(settings.saveFilename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,30 +461,4 @@ 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 })
|
|
||||||
}
|
|
||||||
}
|
}
|
Before Width: | Height: | Size: 370 B After Width: | Height: | Size: 370 B |
Before Width: | Height: | Size: 198 B After Width: | Height: | Size: 198 B |
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 289 B After Width: | Height: | Size: 289 B |
Before Width: | Height: | Size: 620 B After Width: | Height: | Size: 620 B |
Before Width: | Height: | Size: 261 B After Width: | Height: | Size: 261 B |
Before Width: | Height: | Size: 273 B After Width: | Height: | Size: 273 B |
Before Width: | Height: | Size: 270 B After Width: | Height: | Size: 270 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1,110 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24.0px"
|
||||||
|
height="24.0px"
|
||||||
|
viewBox="0 0 24.0 24.0"
|
||||||
|
version="1.1"
|
||||||
|
id="SVGRoot"
|
||||||
|
sodipodi:docname="Function.svg"
|
||||||
|
inkscape:version="1.0.1 (3bc2e813f5, 2021-09-07)">
|
||||||
|
<defs
|
||||||
|
id="defs833" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="31.678384"
|
||||||
|
inkscape:cx="15.268708"
|
||||||
|
inkscape:cy="12.238724"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid1403" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata10">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
<dc:date>2021</dc:date>
|
||||||
|
<dc:creator>
|
||||||
|
<cc:Agent>
|
||||||
|
<dc:title>Ad5001</dc:title>
|
||||||
|
</cc:Agent>
|
||||||
|
</dc:creator>
|
||||||
|
<dc:rights>
|
||||||
|
<cc:Agent>
|
||||||
|
<dc:title>(C) Ad5001 2021 - Licensed under CC4.0-BY-NC-SA</dc:title>
|
||||||
|
</cc:Agent>
|
||||||
|
</dc:rights>
|
||||||
|
<cc:license
|
||||||
|
rdf:resource="http://creativecommons.org/licenses/by-nc-nd/4.0/" />
|
||||||
|
</cc:Work>
|
||||||
|
<cc:License
|
||||||
|
rdf:about="http://creativecommons.org/licenses/by-nc-nd/4.0/">
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||||
|
<cc:permits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||||
|
<cc:requires
|
||||||
|
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||||
|
<cc:prohibits
|
||||||
|
rdf:resource="http://creativecommons.org/ns#CommercialUse" />
|
||||||
|
</cc:License>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Calque 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
id="rect1415"
|
||||||
|
style="fill:#000000;fill-rule:evenodd"
|
||||||
|
d="M 2,9 C 2,5 6,5 6,5 H 7 V 7 H 6 C 6,7 4,7 4,9 v 2 h 2 v 2 H 4 v 5 H 2 V 13 H 0 v -2 h 2 z"
|
||||||
|
sodipodi:nodetypes="ccccccccccccccccc" />
|
||||||
|
<path
|
||||||
|
id="rect839"
|
||||||
|
style="fill:#000000;fill-rule:evenodd;stroke-width:2"
|
||||||
|
d="m 12,3 v 2 c 0,0 -2,0 -2,7 0,7 2,7 2,7 v 2 C 8,21 8,12 8,12 8,12 8,3 12,3 Z"
|
||||||
|
sodipodi:nodetypes="ccccccc" />
|
||||||
|
<path
|
||||||
|
id="rect857"
|
||||||
|
style="fill:#000000;fill-rule:evenodd;stroke-width:2"
|
||||||
|
d="m 12,10 h 2 l 6,8 h -2 z"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
id="rect857-7"
|
||||||
|
style="fill:#000000;fill-rule:evenodd;stroke-width:2"
|
||||||
|
d="m 12,18 h 2 l 6,-8 h -2 z"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
id="rect839-3"
|
||||||
|
style="fill:#000000;fill-rule:evenodd;stroke-width:2"
|
||||||
|
d="m 20,3 v 2 c 0,0 2,0 2,7 0,7 -2,7 -2,7 v 2 c 4,0 4,-9 4,-9 0,0 0,-9 -4,-9 z"
|
||||||
|
sodipodi:nodetypes="ccccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.6 KiB |
|
@ -0,0 +1,92 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24.0px"
|
||||||
|
height="24.0px"
|
||||||
|
viewBox="0 0 24.0 24.0"
|
||||||
|
version="1.1"
|
||||||
|
id="SVGRoot"
|
||||||
|
sodipodi:docname="Gain Bode.svg"
|
||||||
|
inkscape:version="1.0.1 (3bc2e813f5, 2021-09-07)">
|
||||||
|
<defs
|
||||||
|
id="defs1469" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="15.839192"
|
||||||
|
inkscape:cx="15.763196"
|
||||||
|
inkscape:cy="7.8365971"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid2039" />
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid2058" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata1472">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Calque 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<rect
|
||||||
|
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:14.257;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0"
|
||||||
|
id="rect835"
|
||||||
|
width="14"
|
||||||
|
height="2"
|
||||||
|
x="0"
|
||||||
|
y="17" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:17.3333px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||||
|
x="-0.12666447"
|
||||||
|
y="12.134649"
|
||||||
|
id="text839"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan837"
|
||||||
|
x="-0.12666447"
|
||||||
|
y="12.134649"
|
||||||
|
style="font-size:17.3333px">ω</tspan></text>
|
||||||
|
<circle
|
||||||
|
style="fill:#000000;fill-rule:evenodd;stroke-width:2"
|
||||||
|
id="path837"
|
||||||
|
cx="13"
|
||||||
|
cy="18"
|
||||||
|
r="4" />
|
||||||
|
<path
|
||||||
|
id="rect837"
|
||||||
|
style="fill:#000000;fill-rule:evenodd;stroke-width:2.10035"
|
||||||
|
transform="rotate(30)"
|
||||||
|
d="m 20.686533,-6.169873 2.232051,-0.1339746 -0.06218,13.8923049 -2.23205,0.1339746 z"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
|
@ -0,0 +1,88 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24.0px"
|
||||||
|
height="24.0px"
|
||||||
|
viewBox="0 0 24.0 24.0"
|
||||||
|
version="1.1"
|
||||||
|
id="SVGRoot"
|
||||||
|
sodipodi:docname="Phase Bode.svg"
|
||||||
|
inkscape:version="1.0.1 (3bc2e813f5, 2021-09-07)">
|
||||||
|
<defs
|
||||||
|
id="defs10" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="22.4"
|
||||||
|
inkscape:cx="15.347905"
|
||||||
|
inkscape:cy="8.3727678"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid19" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata13">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Calque 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:1.1547"
|
||||||
|
id="rect26"
|
||||||
|
width="8"
|
||||||
|
height="2"
|
||||||
|
x="5"
|
||||||
|
y="18" />
|
||||||
|
<path
|
||||||
|
id="rect26-3"
|
||||||
|
style="fill:#000000;stroke-width:1.22474"
|
||||||
|
d="m 15,2 v 14 h 2 V 4 h 7 V 2 Z"
|
||||||
|
sodipodi:nodetypes="ccccccc" />
|
||||||
|
<circle
|
||||||
|
style="fill:#000000;stroke-width:2.09999"
|
||||||
|
id="path45"
|
||||||
|
cx="16"
|
||||||
|
cy="19"
|
||||||
|
r="4" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:18px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;text-anchor:middle;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none"
|
||||||
|
x="6.4359932"
|
||||||
|
y="11.702"
|
||||||
|
id="text49"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan47"
|
||||||
|
x="6.4359932"
|
||||||
|
y="11.702"
|
||||||
|
style="font-size:18px;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none">φ</tspan></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path style="opacity:1;vector-effect:none;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0" d="M9.98 18.12a3.5 3.5 0 0 1-3.064 3.855 3.5 3.5 0 0 1-3.887-3.022 3.5 3.5 0 0 1 2.982-3.919 3.5 3.5 0 0 1 3.95 2.94"/><text xml:space="preserve" style="font-style:normal;font-weight:400;font-size:17.3373px;line-height:1.25;font-family:sans-serif;letter-spacing:0;word-spacing:0;fill-opacity:1;stroke:none;stroke-width:1.00023" x="12.067" y="13.923" transform="scale(.99447 1.00556)"><tspan x="12.067" y="13.923" style="font-size:17.3373px;stroke-width:1.00023">A</tspan></text></svg>
|
After Width: | Height: | Size: 772 B |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
@ -0,0 +1,103 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24.0px"
|
||||||
|
height="24.0px"
|
||||||
|
viewBox="0 0 24.0 24.0"
|
||||||
|
version="1.1"
|
||||||
|
id="SVGRoot"
|
||||||
|
sodipodi:docname="Sequence.svg"
|
||||||
|
inkscape:version="1.0.1 (3bc2e813f5, 2021-09-07)">
|
||||||
|
<defs
|
||||||
|
id="defs10" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="22.4"
|
||||||
|
inkscape:cx="-1.4929284"
|
||||||
|
inkscape:cy="9.7261905"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
showgrid="true"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid19" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata13">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Calque 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:17.3333px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;text-anchor:middle"
|
||||||
|
x="7.483983"
|
||||||
|
y="16.134649"
|
||||||
|
id="text908"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan906"
|
||||||
|
x="7.483983"
|
||||||
|
y="16.134649"
|
||||||
|
style="font-size:17.3333px">u</tspan></text>
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:17px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;text-anchor:middle;stroke-width:1.00003"
|
||||||
|
x="16.365566"
|
||||||
|
y="18.663307"
|
||||||
|
id="text912"
|
||||||
|
transform="scale(1.0000324,0.9999676)"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan910"
|
||||||
|
x="16.365566"
|
||||||
|
y="18.663307"
|
||||||
|
style="font-size:17px;stroke-width:1.00003">n</tspan></text>
|
||||||
|
<g
|
||||||
|
aria-label="("
|
||||||
|
id="text852"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:12px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.4396;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
transform="matrix(1.0022756,0,0,1.2616817,-0.26079098,-9.0560687)">
|
||||||
|
<path
|
||||||
|
d="M 2.712,9.86 C 1.536,11.528 0.48,12.956 0.48,15.8 c 0,2.844 1.056,4.272 2.232,5.94 L 3.408,21.26 C 2.328,19.664 1.632,18.368 1.632,15.8 c 0,-2.58 0.696,-3.864 1.776,-5.46 z"
|
||||||
|
style="font-size:12px;stroke:#000000;stroke-width:0.4396;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path854" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
aria-label="("
|
||||||
|
id="text852-3"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:12px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.4396;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
transform="matrix(-1.0030304,0,0,1.2658306,24.414952,-9.1000412)">
|
||||||
|
<path
|
||||||
|
d="M 2.712,9.86 C 1.536,11.528 0.48,12.956 0.48,15.8 c 0,2.844 1.056,4.272 2.232,5.94 L 3.408,21.26 C 2.328,19.664 1.632,18.368 1.632,15.8 c 0,-2.58 0.696,-3.864 1.776,-5.46 z"
|
||||||
|
style="font-size:12px;stroke:#000000;stroke-width:0.4396;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path854-6" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.9 KiB |
|
@ -0,0 +1,96 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24.0px"
|
||||||
|
height="24.0px"
|
||||||
|
viewBox="0 0 24.0 24.0"
|
||||||
|
version="1.1"
|
||||||
|
id="SVGRoot"
|
||||||
|
sodipodi:docname="Somme gains Bode.svg"
|
||||||
|
inkscape:version="1.0.1 (3bc2e813f5, 2021-09-07)">
|
||||||
|
<defs
|
||||||
|
id="defs1469" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="63.356768"
|
||||||
|
inkscape:cx="15.947723"
|
||||||
|
inkscape:cy="5.6917309"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid2039" />
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid2058" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata1472">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Calque 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
id="rect838"
|
||||||
|
style="fill:#000000;fill-rule:evenodd;stroke-width:2"
|
||||||
|
d="M 2,2 H 8 V 3 H 4 L 7,6 4,9 h 4 v 1 H 2 V 9 L 5,6 2,3 Z"
|
||||||
|
sodipodi:nodetypes="ccccccccccccc" />
|
||||||
|
<rect
|
||||||
|
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:14.257;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0"
|
||||||
|
id="rect835"
|
||||||
|
width="14"
|
||||||
|
height="2"
|
||||||
|
x="0"
|
||||||
|
y="17" />
|
||||||
|
<circle
|
||||||
|
style="fill:#000000;fill-rule:evenodd;stroke-width:2"
|
||||||
|
id="path837"
|
||||||
|
cx="13"
|
||||||
|
cy="18"
|
||||||
|
r="4" />
|
||||||
|
<path
|
||||||
|
id="rect837"
|
||||||
|
style="fill:#000000;fill-rule:evenodd;stroke-width:2.10035"
|
||||||
|
transform="rotate(30)"
|
||||||
|
d="m 20.686533,-6.169873 2.232051,-0.1339746 -0.06218,13.8923049 -2.23205,0.1339746 z"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<g
|
||||||
|
aria-label="G"
|
||||||
|
id="text846"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:12px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none">
|
||||||
|
<path
|
||||||
|
d="m 13,2 c 0,0 -3,0 -3,3 0,3 0,5 3,5 2,0 3,0 3,-2 V 6 h -3 v 1 h 2 v 1 c 0,1 -1,1 -2,1 -1,0 -2,0 -2,-4 0,-1 1,-2 2,-2 2,0 2,1 2,1 h 1 c 0,0 0,-2 -3,-2 z"
|
||||||
|
style="font-size:12px"
|
||||||
|
id="path848"
|
||||||
|
sodipodi:nodetypes="sssccccccsssccs" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.1 KiB |
|
@ -0,0 +1,93 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24.0px"
|
||||||
|
height="24.0px"
|
||||||
|
viewBox="0 0 24.0 24.0"
|
||||||
|
version="1.1"
|
||||||
|
id="SVGRoot"
|
||||||
|
sodipodi:docname="Somme gains Bode.svg"
|
||||||
|
inkscape:version="1.0.1 (3bc2e813f5, 2021-09-07)">
|
||||||
|
<defs
|
||||||
|
id="defs1469" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="22.4"
|
||||||
|
inkscape:cx="22.985246"
|
||||||
|
inkscape:cy="9.8906279"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid2039" />
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid2058" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata1472">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Calque 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
id="path1414"
|
||||||
|
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0"
|
||||||
|
d="m 19.979376,19.120606 a 3.5,3.5 0 0 1 -3.06333,3.854578 3.5,3.5 0 0 1 -3.886652,-3.022533 3.5,3.5 0 0 1 2.9814,-3.918293 3.5,3.5 0 0 1 3.9495,2.939936" />
|
||||||
|
<rect
|
||||||
|
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:16.166;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0"
|
||||||
|
id="rect835"
|
||||||
|
width="18"
|
||||||
|
height="2"
|
||||||
|
x="0"
|
||||||
|
y="18.5" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:16px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||||
|
x="-0.5703125"
|
||||||
|
y="11.875"
|
||||||
|
id="text839"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan837"
|
||||||
|
x="-0.5703125"
|
||||||
|
y="11.875"
|
||||||
|
style="font-size:16px">ΣG</tspan></text>
|
||||||
|
<rect
|
||||||
|
style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:19.0663;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0"
|
||||||
|
id="rect835-3"
|
||||||
|
width="25.038315"
|
||||||
|
height="2"
|
||||||
|
x="-10.17229"
|
||||||
|
y="23.748709"
|
||||||
|
ry="0"
|
||||||
|
transform="rotate(-60)" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
|
@ -0,0 +1,92 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24.0px"
|
||||||
|
height="24.0px"
|
||||||
|
viewBox="0 0 24.0 24.0"
|
||||||
|
version="1.1"
|
||||||
|
id="SVGRoot"
|
||||||
|
sodipodi:docname="Somme phases Bode.svg"
|
||||||
|
inkscape:version="1.0.1 (3bc2e813f5, 2021-09-07)">
|
||||||
|
<defs
|
||||||
|
id="defs10" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="22.4"
|
||||||
|
inkscape:cx="15.347905"
|
||||||
|
inkscape:cy="8.3727678"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
showgrid="true">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid19" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata13">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Calque 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:1.41421"
|
||||||
|
id="rect26"
|
||||||
|
width="12"
|
||||||
|
height="2"
|
||||||
|
x="9"
|
||||||
|
y="18" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:0.912867"
|
||||||
|
id="rect26-3"
|
||||||
|
width="5"
|
||||||
|
height="2"
|
||||||
|
x="19"
|
||||||
|
y="2" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;stroke-width:1.5"
|
||||||
|
id="rect43"
|
||||||
|
width="2"
|
||||||
|
height="16"
|
||||||
|
x="19"
|
||||||
|
y="4" />
|
||||||
|
<circle
|
||||||
|
style="fill:#000000;stroke-width:2.09999"
|
||||||
|
id="path45"
|
||||||
|
cx="20"
|
||||||
|
cy="19"
|
||||||
|
r="3.5" />
|
||||||
|
<text
|
||||||
|
xml:space="preserve"
|
||||||
|
style="font-size:16px;line-height:1.25;font-family:sans-serif;text-align:center;letter-spacing:0px;text-anchor:middle"
|
||||||
|
x="8.7617188"
|
||||||
|
y="11.664062"
|
||||||
|
id="text49"><tspan
|
||||||
|
sodipodi:role="line"
|
||||||
|
id="tspan47"
|
||||||
|
x="8.7617188"
|
||||||
|
y="11.664062"
|
||||||
|
style="font-size:16px">Σφ</tspan></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
|
@ -0,0 +1,77 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24.0px"
|
||||||
|
height="24.0px"
|
||||||
|
viewBox="0 0 24.0 24.0"
|
||||||
|
version="1.1"
|
||||||
|
id="SVGRoot"
|
||||||
|
sodipodi:docname="Text.svg"
|
||||||
|
inkscape:version="1.0.1 (3bc2e813f5, 2021-09-07)">
|
||||||
|
<defs
|
||||||
|
id="defs1469" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="22.4"
|
||||||
|
inkscape:cx="13.763421"
|
||||||
|
inkscape:cy="16.975675"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid2039" />
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid2058" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata1472">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Calque 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<g
|
||||||
|
aria-label="X"
|
||||||
|
transform="matrix(0.99446808,0,0,1.0055627,2,0.50000001)"
|
||||||
|
id="text14"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:17.3373px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.00023" />
|
||||||
|
<path
|
||||||
|
id="rect12"
|
||||||
|
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.670999;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 4,3 h 8 V 5 H 9 v 14 h 3 v 2 H 4 V 19 H 7 V 5 H 4 Z"
|
||||||
|
sodipodi:nodetypes="ccccccccccccc" />
|
||||||
|
<path
|
||||||
|
id="rect837"
|
||||||
|
style="fill:#000000;fill-rule:evenodd;stroke-width:2"
|
||||||
|
d="m 16,5 h 2 v 3 h 2 v 2 h -2 v 5 c 0,2 2,2 2,2 v 2 c 0,0 -4,0 -4,-4 V 10 H 14 V 8 h 2 z"
|
||||||
|
sodipodi:nodetypes="ccccccccccccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
|
@ -0,0 +1,85 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24.0px"
|
||||||
|
height="24.0px"
|
||||||
|
viewBox="0 0 24.0 24.0"
|
||||||
|
version="1.1"
|
||||||
|
id="SVGRoot"
|
||||||
|
sodipodi:docname="X Cursor.svg"
|
||||||
|
inkscape:version="1.0.1 (3bc2e813f5, 2021-09-07)">
|
||||||
|
<defs
|
||||||
|
id="defs1469" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="22.4"
|
||||||
|
inkscape:cx="19.545462"
|
||||||
|
inkscape:cy="13.163586"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:window-width="1829"
|
||||||
|
inkscape:window-height="916"
|
||||||
|
inkscape:window-x="19"
|
||||||
|
inkscape:window-y="31"
|
||||||
|
inkscape:window-maximized="0">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid2039" />
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid2058" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata1472">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Calque 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<g
|
||||||
|
aria-label="X"
|
||||||
|
transform="matrix(0.99446808,0,0,1.0055627,-2.2765848e-8,0.50000001)"
|
||||||
|
id="text14"
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:17.3373px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.00023" />
|
||||||
|
<rect
|
||||||
|
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.774803;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect12"
|
||||||
|
width="2"
|
||||||
|
height="24"
|
||||||
|
x="17"
|
||||||
|
y="0"
|
||||||
|
ry="2.14841e-13" />
|
||||||
|
<path
|
||||||
|
id="rect835"
|
||||||
|
style="fill:#000000;fill-rule:evenodd;stroke-width:2"
|
||||||
|
d="m 5,2 h 2 l 8,14 h -2 z"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
<path
|
||||||
|
id="rect835-6"
|
||||||
|
style="fill:#000000;fill-rule:evenodd;stroke-width:2"
|
||||||
|
d="M 15,2 H 13 L 5,16 h 2 z"
|
||||||
|
sodipodi:nodetypes="ccccc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
@ -0,0 +1 @@
|
||||||
|
../../common/appearance.svg
|
|
@ -0,0 +1 @@
|
||||||
|
../../common/appearance.svg
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
@ -0,0 +1 @@
|
||||||
|
../../common/arrow.svg
|
|
@ -0,0 +1 @@
|
||||||
|
../../common/position.svg
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
@ -0,0 +1 @@
|
||||||
|
../../common/angle.svg
|
|
@ -0,0 +1 @@
|
||||||
|
../../common/appearance.svg
|
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 2 KiB |
|
@ -0,0 +1 @@
|
||||||
|
../../common/target.svg
|
|
@ -0,0 +1 @@
|
||||||
|
../../common/position.svg
|
|
@ -0,0 +1 @@
|
||||||
|
../../common/label.svg
|
|
@ -0,0 +1 @@
|
||||||
|
../../common/angle.svg
|
|
@ -0,0 +1 @@
|
||||||
|
../../common/position.svg
|
|
@ -0,0 +1 @@
|
||||||
|
../../common/position.svg
|
|
@ -0,0 +1 @@
|
||||||
|
../../common/angle.svg
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 675 B After Width: | Height: | Size: 675 B |
Before Width: | Height: | Size: 414 B After Width: | Height: | Size: 414 B |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |