Compare commits
1 commit
master
...
latex-rend
Author | SHA1 | Date | |
---|---|---|---|
ff10b87b8b |
37
.gitignore
vendored
|
@ -1,46 +1,33 @@
|
||||||
# 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
|
||||||
**/**.qm
|
**/**.qm
|
||||||
**/**.log
|
|
||||||
*.jsc
|
*.jsc
|
||||||
*.qmlc
|
*.qmlc
|
||||||
*.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
|
||||||
|
|
157
CHANGELOG.md
|
@ -1,162 +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)
|
|
||||||
|
|
||||||
**New**
|
|
||||||
|
|
||||||
* (EXPERIMENTAL) LogarithmPlotter now has an optional LaTeX integration.
|
|
||||||
* It requires a LaTeX installation, including `latexmk` and `dvipng` available in the PATH.
|
|
||||||
* NOTE: LaTeX support is disabled by default and is only for working for the rendering on the graph.
|
|
||||||
* NOTE: The objects and history tab still use the legacy text based expression rendering.
|
|
||||||
* Thanks and contributions dialog, showing included libraries and translations, their license and author(s).
|
|
||||||
* LaTeX rendering can be disabled for texts, even if LaTeX is enabled.
|
|
||||||
|
|
||||||
**Changes**
|
|
||||||
|
|
||||||
* History re/undos only redraw the graph every 4 change at most in order to speed up the process when re/undoing a lot of changes.
|
|
||||||
* Gradients are no longer hidden when filtered out in the history tab.
|
|
||||||
|
|
||||||
**Added translations**
|
|
||||||
|
|
||||||
* LaTeX options and error messages
|
|
||||||
* Thanks and contribution dialog
|
|
||||||
* New option for text.
|
|
||||||
* Fixed translation of "repartition" which should be "distribution" in certain remaining strings.
|
|
||||||
|
|
||||||
**Fixed bugs**
|
|
||||||
|
|
||||||
* (macos) #1 - Opening files don't work on compiled versions of LogarithmPlotter on MacOS
|
|
||||||
* (snapcraft) Fixed bug preventing from launching LogarithmPlotter. This fix has been backported to v0.1.8.
|
|
||||||
* (snapcraft) Files are now properly opened.
|
|
||||||
* (snapcraft) Added changelog support.
|
|
||||||
|
|
||||||
**Internal changes**
|
|
||||||
|
|
||||||
* Moved python modules to "util" directory for more clarity.
|
|
||||||
* Moved flatpak metainfo to eu.ad5001.LogarithmPlotter repository.
|
|
||||||
* Componented the Mathlib library in order to have a more readable source.
|
|
||||||
* Added documentation for most internal JavaScript modules.
|
|
||||||
* Merge label drawing methods due to it's complexity.
|
|
||||||
* (flatpak) Updated SDK version to v5.15-21.08.
|
|
||||||
|
|
||||||
## v0.1.8 (19 Feb 2022)
|
## v0.1.8 (19 Feb 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.2.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,20 +1,20 @@
|
||||||
"""
|
"""
|
||||||
* 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
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* 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()
|
1127
LogarithmPlotter/i18n/lp_de.ts
Normal file
1136
LogarithmPlotter/i18n/lp_en.ts
Normal file
1095
LogarithmPlotter/i18n/lp_es.ts
Normal file
1145
LogarithmPlotter/i18n/lp_fr.ts
Normal file
1119
LogarithmPlotter/i18n/lp_hu.ts
Normal file
1119
LogarithmPlotter/i18n/lp_nb_NO.ts
Normal file
1095
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
|
152
LogarithmPlotter/logarithmplotter.py
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
"""
|
||||||
|
* 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])
|
||||||
|
|
||||||
|
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 Latex
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -41,7 +43,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 +50,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 +70,6 @@ MenuBar {
|
||||||
}
|
}
|
||||||
|
|
||||||
icon.name: 'application-exit'
|
icon.name: 'application-exit'
|
||||||
icon.color: sysPalette.windowText
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,31 +78,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 +104,106 @@ 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 {
|
||||||
|
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: enableLatexSetting
|
||||||
|
text: qsTr("Enable LaTeX rendering")
|
||||||
|
checkable: true
|
||||||
|
checked: Helper.getSettingBool("enable_latex")
|
||||||
|
onTriggered: {
|
||||||
|
Helper.setSettingBool("enable_latex", checked)
|
||||||
|
Latex.enabled = checked
|
||||||
|
drawCanvas.requestPaint()
|
||||||
|
}
|
||||||
|
icon.name: 'Expression'
|
||||||
|
|
||||||
|
Component.onCompleted: Latex.enabled = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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 {
|
|
||||||
text: qsTr("&Thanks")
|
|
||||||
icon.name: 'help-about'
|
|
||||||
icon.color: sysPalette.windowText
|
|
||||||
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.
|
||||||
|
|
||||||
|
@ -48,27 +47,13 @@ Item {
|
||||||
true when the system is running with a dark theme, false otherwise.
|
true when the system is running with a dark theme, false otherwise.
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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,18 +16,17 @@
|
||||||
* 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 QtQml
|
import QtQml 2.12
|
||||||
import QtQuick
|
import QtQuick.Controls 2.12
|
||||||
import QtQuick.Controls
|
|
||||||
import QtQuick.Layouts 1.12
|
|
||||||
import eu.ad5001.MixedMenu 1.1
|
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
|
||||||
|
|
||||||
// Auto loading all modules.
|
import "js/objects.js" as Objects
|
||||||
import eu.ad5001.LogarithmPlotter.Common
|
import eu.ad5001.LogarithmPlotter.History 1.0
|
||||||
|
|
||||||
import eu.ad5001.LogarithmPlotter.History 1.0 as History
|
|
||||||
import eu.ad5001.LogarithmPlotter.ObjectLists 1.0
|
import eu.ad5001.LogarithmPlotter.ObjectLists 1.0
|
||||||
import eu.ad5001.LogarithmPlotter.Overlay 1.0 as Overlay
|
|
||||||
import eu.ad5001.LogarithmPlotter.Popup 1.0 as Popup
|
import eu.ad5001.LogarithmPlotter.Popup 1.0 as Popup
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -43,7 +42,7 @@ ApplicationWindow {
|
||||||
width: 1000
|
width: 1000
|
||||||
height: 500
|
height: 500
|
||||||
color: sysPalette.window
|
color: sysPalette.window
|
||||||
title: qsTr("untitled")
|
title: "LogarithmPlotter " + (settings.saveFilename != "" ? " - " + settings.saveFilename.split('/').pop() : "") + (history.saved ? "" : "*")
|
||||||
|
|
||||||
SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active }
|
SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active }
|
||||||
SystemPalette { id: sysPaletteIn; colorGroup: SystemPalette.Disabled }
|
SystemPalette { id: sysPaletteIn; colorGroup: SystemPalette.Disabled }
|
||||||
|
@ -51,17 +50,15 @@ ApplicationWindow {
|
||||||
menuBar: appMenu.trueItem
|
menuBar: appMenu.trueItem
|
||||||
|
|
||||||
AppMenuBar {id: appMenu}
|
AppMenuBar {id: appMenu}
|
||||||
|
|
||||||
Popup.GreetScreen {}
|
|
||||||
|
|
||||||
Popup.Preferences {id: preferences}
|
History { id: history }
|
||||||
|
|
||||||
|
Popup.GreetScreen {}
|
||||||
|
|
||||||
Popup.Changelog {id: changelog}
|
Popup.Changelog {id: changelog}
|
||||||
|
|
||||||
Popup.About {id: about}
|
Popup.About {id: about}
|
||||||
|
|
||||||
Popup.ThanksTo {id: thanksTo}
|
|
||||||
|
|
||||||
Popup.Alert {
|
Popup.Alert {
|
||||||
id: alert
|
id: alert
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
@ -121,16 +118,16 @@ ApplicationWindow {
|
||||||
|
|
||||||
ObjectLists {
|
ObjectLists {
|
||||||
id: objectLists
|
id: objectLists
|
||||||
onChanged: Modules.Canvas.requestPaint()
|
onChanged: drawCanvas.requestPaint()
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings {
|
Settings {
|
||||||
id: settings
|
id: settings
|
||||||
canvas: drawCanvas
|
canvas: drawCanvas
|
||||||
onChanged: Modules.Canvas.requestPaint()
|
onChanged: drawCanvas.requestPaint()
|
||||||
}
|
}
|
||||||
|
|
||||||
History.Browser {
|
HistoryBrowser {
|
||||||
id: historyBrowser
|
id: historyBrowser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,9 +141,23 @@ ApplicationWindow {
|
||||||
width: sidebar.inPortrait ? parent.width : parent.width - sidebar.width//*sidebar.position
|
width: sidebar.inPortrait ? parent.width : parent.width - sidebar.width//*sidebar.position
|
||||||
x: sidebar.width//*sidebar.position
|
x: sidebar.width//*sidebar.position
|
||||||
|
|
||||||
|
xmin: settings.xmin
|
||||||
|
ymax: settings.ymax
|
||||||
|
xzoom: settings.xzoom
|
||||||
|
yzoom: settings.yzoom
|
||||||
|
xlabel: settings.xlabel
|
||||||
|
ylabel: settings.ylabel
|
||||||
|
yaxisstep: settings.yaxisstep
|
||||||
|
xaxisstep: settings.xaxisstep
|
||||||
|
logscalex: settings.logscalex
|
||||||
|
linewidth: settings.linewidth
|
||||||
|
textsize: settings.textsize
|
||||||
|
showxgrad: settings.showxgrad
|
||||||
|
showygrad: settings.showygrad
|
||||||
|
|
||||||
property bool firstDrawDone: false
|
property bool firstDrawDone: false
|
||||||
|
|
||||||
onPainted: if(!firstDrawDone) {
|
onPainted: if(!firstDrawDone) {
|
||||||
firstDrawDone = true;
|
firstDrawDone = true;
|
||||||
console.info("First paint done in " + (new Date().getTime()-(StartTime*1000)) + "ms")
|
console.info("First paint done in " + (new Date().getTime()-(StartTime*1000)) + "ms")
|
||||||
if(TestBuild == true) {
|
if(TestBuild == true) {
|
||||||
|
@ -155,20 +166,125 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Overlay.ViewPositionChange {
|
PickLocationOverlay {
|
||||||
id: viewPositionChanger
|
|
||||||
anchors.fill: parent
|
|
||||||
}
|
|
||||||
|
|
||||||
Overlay.PickLocation {
|
|
||||||
id: positionPicker
|
id: positionPicker
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
canvas: parent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Overlay.Loading {
|
/*!
|
||||||
id: loadingOverlay
|
\qmlmethod void LogarithmPlotter::saveDiagram(string filename)
|
||||||
anchors.fill: parent
|
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 = {}
|
||||||
|
for(var objType in data['objects']) {
|
||||||
|
if(Object.keys(Objects.types).indexOf(objType) > -1) {
|
||||||
|
Objects.currentObjects[objType] = []
|
||||||
|
for(var objData of data['objects'][objType]) {
|
||||||
|
var obj = new Objects.types[objType](...objData)
|
||||||
|
Objects.currentObjects[objType].push(obj)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error += qsTr("Unknown object type: %1.").arg(objType) + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Importing history
|
||||||
|
if("history" in data)
|
||||||
|
history.unserialize(...data["history"])
|
||||||
|
|
||||||
|
// Refreshing sidebar
|
||||||
|
if(sidebarSelector.currentIndex == 0) {
|
||||||
|
// For some reason, if we load a file while the tab is on object,
|
||||||
|
// we get stuck in a Qt-side loop? Qt bug or side-effect here, I don't know.
|
||||||
|
sidebarSelector.currentIndex = 1
|
||||||
|
objectLists.update()
|
||||||
|
delayRefreshTimer.start()
|
||||||
|
} else {
|
||||||
|
objectLists.update()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error = qsTr("Invalid file provided.")
|
||||||
|
}
|
||||||
|
if(error != "") {
|
||||||
|
console.log(error)
|
||||||
|
alert.show(qsTr("Could not save file: ") + error)
|
||||||
|
// TODO: Error handling
|
||||||
|
return
|
||||||
|
}
|
||||||
|
drawCanvas.requestPaint()
|
||||||
|
alert.show(qsTr("Loaded file '%1'.").arg(basename))
|
||||||
|
history.saved = true
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
|
@ -185,26 +301,10 @@ ApplicationWindow {
|
||||||
onTriggered: Qt.quit() // Quit after paint on test build
|
onTriggered: Qt.quit() // Quit after paint on test build
|
||||||
}
|
}
|
||||||
|
|
||||||
onClosing: function(close) {
|
onClosing: {
|
||||||
if(!Modules.IO.saved) {
|
if(!history.saved) {
|
||||||
close.accepted = false
|
close.accepted = false
|
||||||
appMenu.openSaveUnsavedChangesDialog()
|
appMenu.showSaveUnsavedChangesDialog()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\qmlmethod void LogarithmPlotter::updateObjectsLists()
|
|
||||||
Updates the objects lists when loading a file.
|
|
||||||
*/
|
|
||||||
function updateObjectsLists() {
|
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +335,7 @@ ApplicationWindow {
|
||||||
Action {
|
Action {
|
||||||
text: qsTr("&Update LogarithmPlotter")
|
text: qsTr("&Update LogarithmPlotter")
|
||||||
icon.name: 'update'
|
icon.name: 'update'
|
||||||
onTriggered: Qt.openUrlExternally("https://apps.ad5001.eu/logarithmplotter/")
|
onTriggered: Qt.openUrlExternally("https://dev.apps.ad5001.eu/logarithmplotter")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,27 +346,4 @@ ApplicationWindow {
|
||||||
function showUpdateMenu() {
|
function showUpdateMenu() {
|
||||||
appMenu.addMenu(updateMenu)
|
appMenu.addMenu(updateMenu)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializing modules
|
|
||||||
Component.onCompleted: {
|
|
||||||
Modules.IO.initialize({ root, settings, alert })
|
|
||||||
Modules.Latex.initialize({ latex: Latex, helper: Helper })
|
|
||||||
Modules.Settings.on("changed", (evt) => {
|
|
||||||
if(evt.property === "saveFilename") {
|
|
||||||
const fileName = evt.newValue.split('/').pop().split('\\').pop()
|
|
||||||
if(fileName !== "")
|
|
||||||
title = fileName
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Modules.IO.on("saved loaded", (evt) => {
|
|
||||||
// Refreshing sidebar
|
|
||||||
updateObjectsLists()
|
|
||||||
if(title.endsWith("*"))
|
|
||||||
title = title.substring(0, title.length-1)
|
|
||||||
})
|
|
||||||
Modules.IO.on("modified", () => {
|
|
||||||
if(!title.endsWith("*"))
|
|
||||||
title = title+"*"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -0,0 +1,309 @@
|
||||||
|
/**
|
||||||
|
* 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 EditorDialog
|
||||||
|
\inqmlmodule eu.ad5001.LogarithmPlotter.ObjectLists
|
||||||
|
\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 LogarithmPlotter, 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
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Setting.TextSetting {
|
||||||
|
id: nameProperty
|
||||||
|
height: 30
|
||||||
|
label: qsTr("Name")
|
||||||
|
icon: "common/label.svg"
|
||||||
|
min: 1
|
||||||
|
width: dlgProperties.width
|
||||||
|
value: objEditor.obj.name
|
||||||
|
onChanged: function(newValue) {
|
||||||
|
var newName = Utils.parseName(newValue)
|
||||||
|
if(newName != '' && objEditor.obj.name != newName) {
|
||||||
|
if(Objects.getObjectByName(newName) != null) {
|
||||||
|
newName = ObjectsCommons.getNewName(newName)
|
||||||
|
}
|
||||||
|
history.addToHistory(new HistoryLib.NameChanged(
|
||||||
|
objEditor.obj.name, objEditor.objType, newName
|
||||||
|
))
|
||||||
|
Objects.currentObjects[objEditor.objType][objEditor.objIndex].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]
|
||||||
|
objectListList.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dynamic properties
|
||||||
|
Repeater {
|
||||||
|
id: dlgCustomProperties
|
||||||
|
|
||||||
|
Item {
|
||||||
|
height: customPropComment.height + customPropText.height + customPropCheckBox.height + customPropCombo.height + customPropListDict.height
|
||||||
|
width: dlgProperties.width
|
||||||
|
property string label: qsTranslate('prop',modelData[0])
|
||||||
|
property string icon: Utils.camelCase2readable(modelData[0])
|
||||||
|
|
||||||
|
// Item for comments
|
||||||
|
Label {
|
||||||
|
id: customPropComment
|
||||||
|
width: parent.width
|
||||||
|
height: visible ? implicitHeight : 0
|
||||||
|
visible: modelData[0].startsWith('comment')
|
||||||
|
// Translated text with object name.
|
||||||
|
property string trText: visible ? qsTranslate('comment', modelData[1]).toString() : ''
|
||||||
|
text: (visible && trText.includes("%1") ? trText.arg(objEditor.obj.name) : trText).toString()
|
||||||
|
//color: sysPalette.windowText
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setting for text & number settings as well as domains & expressions
|
||||||
|
Setting.TextSetting {
|
||||||
|
id: customPropText
|
||||||
|
height: visible ? 30 : 0
|
||||||
|
width: parent.width
|
||||||
|
label: parent.label
|
||||||
|
icon: `settings/custom/${parent.icon}.svg`
|
||||||
|
isDouble: modelData[1] == 'number'
|
||||||
|
visible: paramTypeIn(modelData[1], ['Expression', 'Domain', 'string', 'number'])
|
||||||
|
defValue: visible ? {
|
||||||
|
'Expression': () => Utils.simplifyExpression(objEditor.obj[modelData[0]].toEditableString()),
|
||||||
|
'Domain': () => objEditor.obj[modelData[0]].toString(),
|
||||||
|
'string': () => objEditor.obj[modelData[0]],
|
||||||
|
'number': () => objEditor.obj[modelData[0]]
|
||||||
|
}[modelData[1]]() : ""
|
||||||
|
onChanged: function(newValue) {
|
||||||
|
var newValue = {
|
||||||
|
'Expression': () => new MathLib.Expression(newValue),
|
||||||
|
'Domain': () => MathLib.parseDomain(newValue),
|
||||||
|
'string': () => newValue,
|
||||||
|
'number': () => parseFloat(newValue)
|
||||||
|
}[modelData[1]]()
|
||||||
|
// Ensuring old and new values are different to prevent useless adding to history.
|
||||||
|
if(objEditor.obj[modelData[0]] != newValue) {
|
||||||
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
|
objEditor.obj.name, objEditor.objType, modelData[0],
|
||||||
|
objEditor.obj[modelData[0]], newValue
|
||||||
|
))
|
||||||
|
objEditor.obj[modelData[0]] = newValue
|
||||||
|
Objects.currentObjects[objEditor.objType][objEditor.objIndex].update()
|
||||||
|
objectListList.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setting for boolean
|
||||||
|
CheckBox {
|
||||||
|
id: customPropCheckBox
|
||||||
|
visible: modelData[1] == 'boolean'
|
||||||
|
height: visible ? 20 : 0
|
||||||
|
width: parent.width
|
||||||
|
text: parent.label
|
||||||
|
//icon: visible ? `settings/custom/${parent.icon}.svg` : ''
|
||||||
|
|
||||||
|
checked: visible ? objEditor.obj[modelData[0]] : false
|
||||||
|
onClicked: {
|
||||||
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
|
objEditor.obj.name, objEditor.objType, modelData[0],
|
||||||
|
objEditor.obj[modelData[0]], this.checked
|
||||||
|
))
|
||||||
|
objEditor.obj[modelData[0]] = this.checked
|
||||||
|
Objects.currentObjects[objEditor.objType][objEditor.objIndex].update()
|
||||||
|
objectListList.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setting when selecting data from an enum, or an object of a certain type.
|
||||||
|
Setting.ComboBoxSetting {
|
||||||
|
id: customPropCombo
|
||||||
|
width: dlgProperties.width
|
||||||
|
height: visible ? 30 : 0
|
||||||
|
label: parent.label
|
||||||
|
icon: visible ? `settings/custom/${parent.icon}.svg` : ''
|
||||||
|
// True to select an object of type, false for enums.
|
||||||
|
property bool selectObjMode: paramTypeIn(modelData[1], ['ObjectType'])
|
||||||
|
property bool isRealObject: !selectObjMode || (modelData[1].objType != "ExecutableObject" && modelData[1].objType != "DrawableObject")
|
||||||
|
|
||||||
|
// Base, untranslated version of the model.
|
||||||
|
property var baseModel: visible ?
|
||||||
|
(selectObjMode ?
|
||||||
|
Objects.getObjectsName(modelData[1].objType).concat(
|
||||||
|
isRealObject ? [qsTr("+ Create new %1").arg(Objects.types[modelData[1].objType].displayType())] :
|
||||||
|
[]) :
|
||||||
|
modelData[1].values)
|
||||||
|
: []
|
||||||
|
// Translated verison of the model.
|
||||||
|
model: selectObjMode ? baseModel : modelData[1].translatedValues
|
||||||
|
visible: paramTypeIn(modelData[1], ['ObjectType', 'Enum'])
|
||||||
|
currentIndex: baseModel.indexOf(selectObjMode ? objEditor.obj[modelData[0]].name : objEditor.obj[modelData[0]])
|
||||||
|
|
||||||
|
onActivated: function(newIndex) {
|
||||||
|
if(selectObjMode) {
|
||||||
|
// This is only done when what we're selecting are Objects.
|
||||||
|
// Setting object property.
|
||||||
|
var selectedObj = Objects.getObjectByName(baseModel[newIndex], modelData[1].objType)
|
||||||
|
if(newIndex != 0) {
|
||||||
|
// Make sure we don't set the object to null.
|
||||||
|
if(selectedObj == null) {
|
||||||
|
// Creating new object.
|
||||||
|
selectedObj = Objects.createNewRegisteredObject(modelData[1].objType)
|
||||||
|
history.addToHistory(new HistoryLib.CreateNewObject(selectedObj.name, modelData[1].objType, selectedObj.export()))
|
||||||
|
baseModel = Objects.getObjectsName(modelData[1].objType).concat(
|
||||||
|
isRealObject ? [qsTr("+ Create new %1").arg(Objects.types[modelData[1].objType].displayType())] :
|
||||||
|
[])
|
||||||
|
currentIndex = baseModel.indexOf(selectedObj.name)
|
||||||
|
}
|
||||||
|
selectedObj.requiredBy.push(Objects.currentObjects[objEditor.objType][objEditor.objIndex])
|
||||||
|
//Objects.currentObjects[objEditor.objType][objEditor.objIndex].requiredBy = objEditor.obj[modelData[0]].filter((obj) => objEditor.obj.name != obj.name)
|
||||||
|
}
|
||||||
|
objEditor.obj.requiredBy = objEditor.obj.requiredBy.filter((obj) => objEditor.obj.name != obj.name)
|
||||||
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
|
objEditor.obj.name, objEditor.objType, modelData[0],
|
||||||
|
objEditor.obj[modelData[0]], selectedObj
|
||||||
|
))
|
||||||
|
objEditor.obj[modelData[0]] = selectedObj
|
||||||
|
} else if(baseModel[newIndex] != objEditor.obj[modelData[0]]) {
|
||||||
|
// Ensuring new property is different to not add useless history entries.
|
||||||
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
|
objEditor.obj.name, objEditor.objType, modelData[0],
|
||||||
|
objEditor.obj[modelData[0]], baseModel[newIndex]
|
||||||
|
))
|
||||||
|
objEditor.obj[modelData[0]] = baseModel[newIndex]
|
||||||
|
}
|
||||||
|
// Refreshing
|
||||||
|
Objects.currentObjects[objEditor.objType][objEditor.objIndex].update()
|
||||||
|
objectListList.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setting to edit lists or dictionaries (e.g sequences & repartition function values)
|
||||||
|
Setting.ListSetting {
|
||||||
|
id: customPropListDict
|
||||||
|
width: parent.width
|
||||||
|
height: visible ? implicitHeight : 0
|
||||||
|
|
||||||
|
visible: paramTypeIn(modelData[1], ['List', 'Dict'])
|
||||||
|
label: parent.label
|
||||||
|
//icon: `settings/custom/${parent.icon}.svg`
|
||||||
|
dictionaryMode: paramTypeIn(modelData[1], ['Dict'])
|
||||||
|
keyType: dictionaryMode ? modelData[1].keyType : 'string'
|
||||||
|
valueType: visible ? modelData[1].valueType : 'string'
|
||||||
|
preKeyLabel: visible ? (dictionaryMode ? modelData[1].preKeyLabel : modelData[1].label).replace(/\{name\}/g, objEditor.obj.name) : ''
|
||||||
|
postKeyLabel: visible ? (dictionaryMode ? modelData[1].postKeyLabel : '').replace(/\{name\}/g, objEditor.obj.name) : ''
|
||||||
|
keyRegexp: dictionaryMode ? modelData[1].keyFormat : /^.+$/
|
||||||
|
valueRegexp: visible ? modelData[1].format : /^.+$/
|
||||||
|
forbidAdding: visible ? modelData[1].forbidAdding : false
|
||||||
|
|
||||||
|
onChanged: {
|
||||||
|
var exported = exportModel()
|
||||||
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
|
objEditor.obj.name, objEditor.objType, modelData[0],
|
||||||
|
objEditor.obj[modelData[0]], exported
|
||||||
|
))
|
||||||
|
//Objects.currentObjects[objEditor.objType][objEditor.objIndex][modelData[0]] = exported
|
||||||
|
objEditor.obj[modelData[0]] = exported
|
||||||
|
//Objects.currentObjects[objEditor.objType][objEditor.objIndex].update()
|
||||||
|
objEditor.obj.update()
|
||||||
|
objectListList.update()
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if(visible) importModel(objEditor.obj[modelData[0]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,272 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||||
|
import "../js/objects.js" as Objects
|
||||||
|
import "../js/historylib.js" as HistoryLib
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmltype ObjectLists
|
||||||
|
\inqmlmodule eu.ad5001.LogarithmPlotter
|
||||||
|
\brief Tab of the drawer that allows the user to manage the objects.
|
||||||
|
|
||||||
|
This item allows the user to syntheticly see all objects, while giving the user the ability
|
||||||
|
to show, hide, delete, change the location and color, as well as opening the editor dialog
|
||||||
|
for each object.
|
||||||
|
|
||||||
|
\sa LogarithmPlotter, ObjectCreationGrid, ObjectLists
|
||||||
|
*/
|
||||||
|
ScrollView {
|
||||||
|
id: objectListList
|
||||||
|
|
||||||
|
signal changed()
|
||||||
|
|
||||||
|
property var listViews: {'':''} // Needs to be initialized or will be undefined -_-
|
||||||
|
|
||||||
|
|
||||||
|
ScrollBar.horizontal.visible: false
|
||||||
|
ScrollBar.vertical.visible: true
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: objectsListView
|
||||||
|
model: Object.keys(Objects.types)
|
||||||
|
width: implicitWidth //objectListList.width - (implicitHeight > objectListList.parent.height ? 20 : 0)
|
||||||
|
implicitHeight: contentItem.childrenRect.height + footer.height + 10
|
||||||
|
|
||||||
|
delegate: ListView {
|
||||||
|
id: objTypeList
|
||||||
|
property string objType: objectsListView.model[index]
|
||||||
|
property var editingRows: []
|
||||||
|
model: Objects.currentObjects[objType]
|
||||||
|
width: objectsListView.width
|
||||||
|
implicitHeight: contentItem.childrenRect.height
|
||||||
|
visible: model != undefined && model.length > 0
|
||||||
|
interactive: false
|
||||||
|
|
||||||
|
Component.onCompleted: objectListList.listViews[objType] = objTypeList // Listing in order to be refreshed
|
||||||
|
|
||||||
|
header: Row {
|
||||||
|
width: typeHeaderText.width + typeVisibilityCheckBox.visible
|
||||||
|
height: visible ? 20 : 0
|
||||||
|
visible: objTypeList.visible
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: typeVisibilityCheckBox
|
||||||
|
checked: Objects.currentObjects[objType] != undefined ? Objects.currentObjects[objType].every(obj => obj.visible) : true
|
||||||
|
onClicked: {
|
||||||
|
for(var obj of Objects.currentObjects[objType]) obj.visible = this.checked
|
||||||
|
for(var obj of objTypeList.editingRows) obj.objVisible = this.checked
|
||||||
|
objectListList.changed()
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
ToolTip.text: checked ? qsTr("Hide all %1").arg(Objects.types[objType].displayTypeMultiple()) : qsTr("Show all %1").arg(Objects.types[objType].displayTypeMultiple())
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: typeHeaderText
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
text: qsTranslate("control", "%1: ").arg(Objects.types[objType].displayTypeMultiple())
|
||||||
|
font.pixelSize: 20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: Item {
|
||||||
|
id: controlRow
|
||||||
|
property var obj: Objects.currentObjects[objType][index]
|
||||||
|
property alias objVisible: objVisibilityCheckBox.checked
|
||||||
|
height: 40
|
||||||
|
width: objTypeList.width
|
||||||
|
|
||||||
|
Component.onCompleted: objTypeList.editingRows.push(controlRow)
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: objVisibilityCheckBox
|
||||||
|
checked: Objects.currentObjects[objType][index].visible
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: 5
|
||||||
|
onClicked: {
|
||||||
|
history.addToHistory(new HistoryLib.EditedVisibility(
|
||||||
|
Objects.currentObjects[objType][index].name, objType, this.checked
|
||||||
|
))
|
||||||
|
Objects.currentObjects[objType][index].visible = this.checked
|
||||||
|
objectListList.changed()
|
||||||
|
controlRow.obj = Objects.currentObjects[objType][index]
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
ToolTip.text: checked ?
|
||||||
|
qsTr("Hide %1 %2").arg(Objects.types[objType].displayType()).arg(obj.name) :
|
||||||
|
qsTr("Show %1 %2").arg(Objects.types[objType].displayType()).arg(obj.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: objDescription
|
||||||
|
anchors.left: objVisibilityCheckBox.right
|
||||||
|
anchors.right: deleteButton.left
|
||||||
|
height: parent.height
|
||||||
|
verticalAlignment: TextInput.AlignVCenter
|
||||||
|
text: obj.getReadableString()
|
||||||
|
font.pixelSize: 14
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
objEditor.obj = Objects.currentObjects[objType][index]
|
||||||
|
objEditor.objType = objType
|
||||||
|
objEditor.objIndex = index
|
||||||
|
//objEditor.editingRow = controlRow
|
||||||
|
objEditor.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: pointerButton
|
||||||
|
width: parent.height - 10
|
||||||
|
height: width
|
||||||
|
anchors.right: deleteButton.left
|
||||||
|
anchors.rightMargin: 5
|
||||||
|
anchors.topMargin: 5
|
||||||
|
|
||||||
|
Setting.Icon {
|
||||||
|
id: icon
|
||||||
|
width: 18
|
||||||
|
height: 18
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
color: sysPalette.windowText
|
||||||
|
source: '../icons/common/position.svg'
|
||||||
|
}
|
||||||
|
|
||||||
|
property bool hasXProp: Objects.types[objType].properties().hasOwnProperty('x')
|
||||||
|
property bool hasYProp: Objects.types[objType].properties().hasOwnProperty('y')
|
||||||
|
visible: hasXProp || hasYProp
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
ToolTip.text: qsTr("Set %1 %2 position").arg(Objects.types[objType].displayType()).arg(obj.name)
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
positionPicker.objType = objType
|
||||||
|
positionPicker.objName = obj.name
|
||||||
|
positionPicker.pickX = hasXProp
|
||||||
|
positionPicker.pickY = hasYProp
|
||||||
|
positionPicker.propertyX = 'x'
|
||||||
|
positionPicker.propertyY = 'y'
|
||||||
|
positionPicker.visible = true
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: deleteButton
|
||||||
|
width: parent.height - 10
|
||||||
|
height: width
|
||||||
|
anchors.right: colorPickRect.left
|
||||||
|
anchors.rightMargin: 5
|
||||||
|
anchors.topMargin: 5
|
||||||
|
icon.name: 'delete'
|
||||||
|
icon.source: '../icons/common/delete.svg'
|
||||||
|
icon.color: sysPalette.buttonText
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
ToolTip.text: qsTr("Delete %1 %2").arg(Objects.types[objType].displayType()).arg(obj.name)
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
history.addToHistory(new HistoryLib.DeleteObject(
|
||||||
|
obj.name, objType, obj.export()
|
||||||
|
))
|
||||||
|
Objects.currentObjects[objType][index].delete()
|
||||||
|
Objects.currentObjects[objType].splice(index, 1)
|
||||||
|
objectListList.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: colorPickRect
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: 5
|
||||||
|
anchors.topMargin: 5
|
||||||
|
color: obj.color
|
||||||
|
width: parent.height - 10
|
||||||
|
height: width
|
||||||
|
radius: Math.min(width, height)
|
||||||
|
border.width: 2
|
||||||
|
border.color: sysPalette.windowText
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: pickColor.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
D.ColorDialog {
|
||||||
|
id: pickColor
|
||||||
|
color: obj.color
|
||||||
|
title: qsTr("Pick new color for %1 %2").arg(Objects.types[objType].displayType()).arg(obj.name)
|
||||||
|
onAccepted: {
|
||||||
|
history.addToHistory(new HistoryLib.ColorChanged(
|
||||||
|
obj.name, objType, obj.color, color.toString()
|
||||||
|
))
|
||||||
|
obj.color = color.toString()
|
||||||
|
controlRow.obj = Objects.currentObjects[objType][index]
|
||||||
|
objectListList.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create items
|
||||||
|
footer: ObjectCreationGrid {
|
||||||
|
id: createRow
|
||||||
|
width: objectsListView.width
|
||||||
|
objectEditor: objEditor
|
||||||
|
objectLists: objectListList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object editor
|
||||||
|
EditorDialog {
|
||||||
|
id: objEditor
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void ObjectLists::update()
|
||||||
|
Updates the view of the ObjectLists.
|
||||||
|
*/
|
||||||
|
function update() {
|
||||||
|
objectListList.changed()
|
||||||
|
for(var objType in objectListList.listViews) {
|
||||||
|
objectListList.listViews[objType].model = Objects.currentObjects[objType]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmlmethod void ObjectLists::paramTypeIn(var parameter, var types)
|
||||||
|
Checks if the type of the provided \c parameter is in \c types.
|
||||||
|
\note The type can be normal string types ('boolean', 'string', 'number'...) or object types (Enum, Dictionay, Object types...). If the latter, only the type of object type should be provided in \c types. E.g: if you want to check if the parameter is an enum, add "Enum" to types.
|
||||||
|
*/
|
||||||
|
function paramTypeIn(parameter, types = []) {
|
||||||
|
if(types.includes(parameter.toString())) return true
|
||||||
|
if(typeof parameter == 'object' && 'type' in parameter)
|
||||||
|
return types.includes(parameter.type)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,4 +2,5 @@ module eu.ad5001.LogarithmPlotter.ObjectLists
|
||||||
|
|
||||||
ObjectLists 1.0 ObjectLists.qml
|
ObjectLists 1.0 ObjectLists.qml
|
||||||
ObjectCreationGrid 1.0 ObjectCreationGrid.qml
|
ObjectCreationGrid 1.0 ObjectCreationGrid.qml
|
||||||
ObjectRow 1.0 ObjectRow.qml
|
EditorDialog 1.0 EditorDialog.qml
|
||||||
|
|
|
@ -0,0 +1,217 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
if(parent.pickX) {
|
||||||
|
let newValue = picked.mouseX.toString()
|
||||||
|
newValue = {
|
||||||
|
'Expression': () => new MathLib.Expression(newValue),
|
||||||
|
'number': () => parseFloat(newValue)
|
||||||
|
}[Objects.types[objType].properties()[propertyX]]()
|
||||||
|
let obj = Objects.getObjectByName(objName, objType)
|
||||||
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
|
objName, objType, propertyX, obj[propertyX], newValue
|
||||||
|
))
|
||||||
|
obj[propertyX] = newValue
|
||||||
|
obj.update()
|
||||||
|
objectLists.update()
|
||||||
|
}
|
||||||
|
if(parent.pickY) {
|
||||||
|
let newValue = picked.mouseY.toString()
|
||||||
|
newValue = {
|
||||||
|
'Expression': () => new MathLib.Expression(newValue),
|
||||||
|
'number': () => parseFloat(newValue)
|
||||||
|
}[Objects.types[objType].properties()[propertyY]]()
|
||||||
|
let obj = Objects.getObjectByName(objName, objType)
|
||||||
|
history.addToHistory(new HistoryLib.EditedProperty(
|
||||||
|
objName, objType, propertyY, obj[propertyY], newValue
|
||||||
|
))
|
||||||
|
obj[propertyY] = newValue
|
||||||
|
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}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
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,167 @@
|
||||||
|
/**
|
||||||
|
* 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.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)
|
||||||
|
//checkForUpdatesMenuSetting.checked = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: resetRedoStackSetting
|
||||||
|
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)
|
||||||
|
//resetRedoStackMenuSetting.checked = checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
id: enableLatexSetting
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: resetRedoStackSetting.bottom
|
||||||
|
checked: Helper.getSettingBool("enable_latex")
|
||||||
|
text: qsTr('Enable LaTeX rendering')
|
||||||
|
onClicked: {
|
||||||
|
Helper.setSettingBool("enable_latex", checked)
|
||||||
|
Latex.enabled = checked
|
||||||
|
drawCanvas.requestPaint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
|
@ -1,11 +1,8 @@
|
||||||
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
|
|
|
@ -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
|
||||||
|
@ -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,19 @@ 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.height: sourceSize.width
|
||||||
sourceSize.height: sourceS
|
}
|
||||||
|
ColorOverlay {
|
||||||
|
anchors.fill: img
|
||||||
|
source: img
|
||||||
color: parent.color
|
color: parent.color
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,25 +1,28 @@
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* 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/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
{
|
|
||||||
"recursive": true,
|
import QtQuick 2.12
|
||||||
"require": [
|
import QtQuick.Controls 2.12
|
||||||
"esm",
|
|
||||||
"./test/hooks.mjs"
|
Image {
|
||||||
]
|
id: expr
|
||||||
|
property string expression
|
||||||
|
|
||||||
|
src: Latex.render(expression).split(',')[0]
|
||||||
}
|
}
|
|
@ -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,9 +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
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\qmltype TextSetting
|
\qmltype TextSetting
|
||||||
|
@ -37,7 +36,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 +48,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,14 +93,14 @@ 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
|
||||||
|
@ -119,23 +112,17 @@ 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
|
var value = text
|
||||||
let value = text
|
if(control.isInt) value = Math.max(control.min,parseInt(value).toString()=="NaN"?control.min:parseInt(value))
|
||||||
if(control.isInt) {
|
if(control.isDouble) value = Math.max(control.min,parseFloat(value).toString()=="NaN"?control.min:parseFloat(value))
|
||||||
let parsed = parseInt(value)
|
if(value != "" && value.toString() != defValue) {
|
||||||
value = isNaN(parsed) ? control.min : Math.max(control.min,parsed)
|
|
||||||
} 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()
|
||||||
}
|
}
|
||||||
|
@ -143,43 +130,61 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
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
|
||||||
|
onClicked: insertPopup.open()
|
||||||
Icon {
|
|
||||||
id: icon
|
|
||||||
width: 12
|
|
||||||
height: 12
|
|
||||||
anchors.centerIn: parent
|
|
||||||
|
|
||||||
color: sysPalette.windowText
|
|
||||||
source: '../icons/properties/expression.svg'
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
insertPopup.open()
|
|
||||||
insertPopup.setFocus()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Popup.InsertCharacter {
|
Popup {
|
||||||
id: insertPopup
|
id: insertPopup
|
||||||
|
x: Math.round((parent.width - width) / 2)
|
||||||
|
y: Math.round((parent.height - height) / 2)
|
||||||
|
width: 280
|
||||||
|
height: insertGrid.insertChars.length/insertGrid.columns*(width/insertGrid.columns)
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
|
||||||
|
|
||||||
x: parent.width - width
|
Grid {
|
||||||
y: parent.height
|
id: insertGrid
|
||||||
|
width: parent.width
|
||||||
onSelected: function(c) {
|
columns: 7
|
||||||
input.insert(input.cursorPosition, c)
|
|
||||||
}
|
property var insertChars: [
|
||||||
|
"α","β","γ","δ","ε","ζ","η",
|
||||||
onClosed: function() {
|
"π","θ","κ","λ","μ","ξ","ρ",
|
||||||
focus = false
|
"ς","σ","τ","φ","χ","ψ","ω",
|
||||||
input.focus = true
|
"Γ","Δ","Θ","Λ","Ξ","Π","Σ",
|
||||||
|
"Φ","Ψ","Ω","ₐ","ₑ","ₒ","ₓ",
|
||||||
|
"ₕ","ₖ","ₗ","ₘ","ₙ","ₚ","ₛ",
|
||||||
|
"ₜ","¹","²","³","⁴","⁵","⁶",
|
||||||
|
"⁷","⁸","⁹","⁰","₁","₂","₃",
|
||||||
|
"₄","₅","₆","₇","₈","₉","₀"
|
||||||
|
|
||||||
|
]
|
||||||
|
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: {
|
||||||
|
input.insert(input.cursorPosition, insertGrid.insertChars[modelData])
|
||||||
|
insertPopup.close()
|
||||||
|
input.focus = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,7 @@
|
||||||
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
|
||||||
|
|
|
@ -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.changed()
|
settings.xmin = newValue
|
||||||
}
|
settings.changed()
|
||||||
|
} else {
|
||||||
function update(newValue) {
|
alert.show("Minimum x value must be inferior to maximum.")
|
||||||
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 |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
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 |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |