Compare commits
486 commits
Author | SHA1 | Date | |
---|---|---|---|
c74c2fb747 | |||
c2eae30bd6 | |||
80cea6d280 | |||
f8ce98d4ad | |||
fbb85083c1 | |||
|
17b6e40d60 | ||
6a1f01ba1f | |||
4c1403c983 | |||
8c8964e75e | |||
45dff33bb5 | |||
bac802ec5b | |||
34a436fe49 | |||
cb2ffcf77a | |||
a27d3109ed | |||
a998c52eec | |||
8b8a280b37 | |||
3befff41fa | |||
9810435456 | |||
84a65cd1fc | |||
5bdf81b2ed | |||
c66d08b352 | |||
a4e9ad7f5a | |||
a88be86350 | |||
4baf4f8aa6 | |||
1f2b8e5c4b | |||
|
8eac624bb2 | ||
976088ad03 | |||
dcb63c48e9 | |||
dcc47104ef | |||
a32d480b43 | |||
e0601379ba | |||
3c42cbb6d0 | |||
cc0f277da7 | |||
1299fe469d | |||
5d0f3eec56 | |||
|
c8ada79776 | ||
43a0aa3529 | |||
9c76d469d6 | |||
3c57f207b6 | |||
77d03e5837 | |||
ed5b7e95a6 | |||
2bf7df12a8 | |||
0e23d9181e | |||
7e698eda32 | |||
6e92c428f9 | |||
b18e1ca56e | |||
1ef1d27452 | |||
7c12b757ee | |||
484888f80f | |||
4e265b66c2 | |||
6d3f4ba372 | |||
2321a1076c | |||
dd2ae7a2c8 | |||
2fc9bdee86 | |||
67190e1b4c | |||
8ab461ff72 | |||
9b5356f8e7 | |||
370402f303 | |||
7f57ed13c7 | |||
325eef57e2 | |||
956de5f9e3 | |||
48427b7923 | |||
fceb5e711c | |||
836d13386e | |||
c3daa92280 | |||
d566c285fd | |||
a9e47dbc17 | |||
4a5756f24d | |||
a250f532d9 | |||
e68411e93c | |||
b55b2a11fe | |||
7dd64c8e31 | |||
8f95479689 | |||
9712ff15bb | |||
a3cf99f3af | |||
2ee7da7995 | |||
3104dea918 | |||
cb0db7fae1 | |||
4ac7de48b0 | |||
5211821a84 | |||
29e48e284c | |||
4759bdcd33 | |||
9072e94d14 | |||
b50d56d511 | |||
1bf175b09c | |||
52fd95551c | |||
769ad22ea6 | |||
|
8b36ad81ab | ||
1e32faa1d1 | |||
78d7e6f310 | |||
ab45109206 | |||
12b48a2e74 | |||
1bc3aaf53b | |||
b52cc1de29 | |||
214dd687b1 | |||
6b4da2b061 | |||
|
bcf76dcd28 | ||
207a2254f3 | |||
0f39930b88 | |||
d4e97f2860 | |||
a2fa16949a | |||
91e4220397 | |||
d7fe760900 | |||
a16f02fd5f | |||
601efc6122 | |||
51807a80d0 | |||
ef14db8bbb | |||
7e0262e4fe | |||
70f1c03cb6 | |||
8d6891c4f0 | |||
c9a597ea82 | |||
c1a468148d | |||
59d4d2f728 | |||
|
9ca48bbcfa | ||
3994d8d49d | |||
53124fc8d7 | |||
35fef4cb1e | |||
f1e2278695 | |||
|
6a1f0013d6 | ||
6626362d23 | |||
107cea1308 | |||
7b0bc4469f | |||
e3eea751cb | |||
7b76a8fe08 | |||
4b1cf2cd9d | |||
88797d00be | |||
f98852c336 | |||
606ec428ab | |||
|
136ac4c7bc | ||
|
87d8882db1 | ||
915c6b5246 | |||
54f9802975 | |||
997a1645a0 | |||
fefb0f92b0 | |||
665906ecb3 | |||
781a0f4aae | |||
5f8c756dc7 | |||
8e75f13e9a | |||
82e8413e56 | |||
73cba85592 | |||
861bb001c9 | |||
08fea34366 | |||
a6fcf6da19 | |||
f730121047 | |||
80f1077b35 | |||
33c790b113 | |||
f9b0bb99ce | |||
557592708f | |||
1f72c76fb4 | |||
66b4c8df90 | |||
70b1ac09f7 | |||
2d6389bfd5 | |||
d0851b819f | |||
cff994d9d7 | |||
fde2526c54 | |||
e5fe8afd06 | |||
f9a7443631 | |||
874046960f | |||
d53573d468 | |||
1da1221c51 | |||
|
8bb147cbee | ||
bd2e692285 | |||
298acaace2 | |||
5284c71ee7 | |||
b8d679e118 | |||
22106f97b5 | |||
bf211df67d | |||
803416d08d | |||
d991deee7b | |||
ed4d30573c | |||
3f1d089a78 | |||
4b692894f2 | |||
062fde6b16 | |||
2b5d442d3a | |||
038dd9f4a8 | |||
cf754a7a34 | |||
bc35b18da0 | |||
7542d63121 | |||
4fe1086d68 | |||
a66ccd1319 | |||
9879e7fbc9 | |||
999999832a | |||
7408520819 | |||
9f2b08b938 | |||
3039aade29 | |||
d6a83b0f4b | |||
0b5aa36c23 | |||
25347a8eff | |||
|
d6d7f3a511 | ||
e67619771b | |||
df3e7d4796 | |||
19e403ce98 | |||
273d5539ec | |||
5e7dbb8fa6 | |||
1e30bee220 | |||
ebf07dccfa | |||
95546bd14e | |||
59145905ea | |||
66da751b36 | |||
deb4355756 | |||
8358cc142c | |||
62e70885e0 | |||
6fa0aea0e5 | |||
08edd7be14 | |||
16effe064c | |||
98f01845e1 | |||
87b4787a2b | |||
a610d0949e | |||
803670635b | |||
09c1a44150 | |||
40743e54c3 | |||
9239eac78a | |||
35ce1c4824 | |||
75e70903f1 | |||
016a21ecb4 | |||
f7dd40d2f5 | |||
d1843b455a | |||
6abbbe5e61 | |||
5cef8e23fa | |||
d6dee6a2be | |||
3da51430f1 | |||
ae930be621 | |||
abae3ef94b | |||
82d53748b3 | |||
fce2a5ba0d | |||
3904dc0217 | |||
7a80455e25 | |||
20c1ed005e | |||
d8534d1e0d | |||
4be92a07e3 | |||
b143f7e10d | |||
0ac690d0c1 | |||
37150b5823 | |||
0539f988e2 | |||
bf067b7e7c | |||
9f20a80228 | |||
5ef8cac1c0 | |||
7ec80e6682 | |||
43d78e17e5 | |||
93308f2bfa | |||
508f316bc5 | |||
424eef6e17 | |||
f40c242877 | |||
aecc02c606 | |||
78ffc8c645 | |||
98f26d4919 | |||
65c42abd26 | |||
ba98fc3611 | |||
839f8e9f36 | |||
fe13351e99 | |||
225ae67834 | |||
6307855b87 | |||
3a36e41738 | |||
ee26bc04c5 | |||
|
02c7cb8afc | ||
0a064694f5 | |||
b0b77834a8 | |||
fb1c4c0de7 | |||
d969661b33 | |||
86656fe46c | |||
4b6d333cee | |||
9ca8903a3e | |||
a3faeeb7d0 | |||
244935d7e2 | |||
677d13278d | |||
7241add9e5 | |||
356169c749 | |||
7e427e5bb9 | |||
3cd4ad6a20 | |||
0e41c12e03 | |||
fc68d3da6a | |||
0561782293 | |||
47a9f63d66 | |||
7f548796f2 | |||
15b87fc15d | |||
77ae54fa18 | |||
5da8dcefe5 | |||
16efe31b5f | |||
6e21f2eea1 | |||
c85dba737d | |||
218c55b491 | |||
e98be96b0d | |||
c5851e6d95 | |||
de1be925b0 | |||
ddb5156396 | |||
7686204786 | |||
acadad2bd1 | |||
1ceccc15cf | |||
97338506a4 | |||
e7ba1d9ff5 | |||
b519e34016 | |||
dc532fcd19 | |||
971a9d10d2 | |||
4564d5446f | |||
32db56304b | |||
64d1419452 | |||
fcf5ef9539 | |||
6116ffe4e7 | |||
2a8cab9398 | |||
29e62fee6e | |||
d65f343b60 | |||
f76b601139 | |||
9facc2389c | |||
15fd660e0c | |||
dfdd576296 | |||
b8d312bb23 | |||
8c6784663e | |||
1a433eba27 | |||
1ba594c4f7 | |||
6b535dd8a2 | |||
fad5325501 | |||
3dc69cc9ba | |||
2d46de35d2 | |||
|
ef04b2aa58 | ||
|
876ea1eaa8 | ||
20f8d68f13 | |||
a5ce17e7f3 | |||
cf3e775834 | |||
cb733a556c | |||
22c9151e0c | |||
871630ef0b | |||
6b2afd3a1b | |||
b496807576 | |||
b45e105202 | |||
6129bcf928 | |||
b69aaa2d7a | |||
1b91176f2d | |||
3a2fcb1be1 | |||
836e6d8922 | |||
eef42655e5 | |||
1f581c46ec | |||
f77b1ce331 | |||
86f3399a53 | |||
3e7b36a420 | |||
27759362cb | |||
7120e3a781 | |||
166d1a2485 | |||
2691ba687f | |||
4c9c9668bb | |||
b72bbeab4f | |||
7723107ff6 | |||
6539ca8caa | |||
12ecf3b19b | |||
07ae71de36 | |||
06bb00cc17 | |||
ec90779912 | |||
2ce66df4dd | |||
8251504fbe | |||
650e43894c | |||
de0220fecf | |||
c4ffcdaa35 | |||
0975189615 | |||
ccf3de5783 | |||
b5600046e9 | |||
1142ca1c00 | |||
23cd86a2e3 | |||
1c0850a200 | |||
8b01a8f0e8 | |||
8f1bc652b4 | |||
44e39e5265 | |||
20c910f884 | |||
86eb454e39 | |||
90abfe63f6 | |||
d34701b980 | |||
c535d48039 | |||
5b0add3876 | |||
fcd6b71cb6 | |||
df6e3234ea | |||
71ff9aa33b | |||
080c6cea54 | |||
d7a3fe0f6d | |||
867b9fed68 | |||
87104a3d71 | |||
a4d8dd92c2 | |||
ae62d3d26a | |||
0c05a62982 | |||
6cce189f0a | |||
9c26195f66 | |||
f229dc014c | |||
ca51f979b8 | |||
f4c6e82c6d | |||
dd7e078525 | |||
033f065f92 | |||
f4dfca4171 | |||
c4893c675c | |||
599f144c1c | |||
546317388e | |||
fea238c706 | |||
fec6a6b00a | |||
499feace1c | |||
727231c954 | |||
f11792c03a | |||
09a7a9b704 | |||
b080c3d683 | |||
460e0ab178 | |||
7b24a54ca2 | |||
1b5d0725c8 | |||
3f107f1ba4 | |||
600027a707 | |||
e23a8755e9 | |||
32c6b3e342 | |||
b51fe6ae84 | |||
719d56127d | |||
2d12291075 | |||
3119c3f9dc | |||
73877a0dd4 | |||
82d2ee84b7 | |||
78343cf153 | |||
2f8df68453 | |||
a13784569a | |||
714129d86e | |||
7030af60f1 | |||
77688fa715 | |||
2d7c038b46 | |||
9873263308 | |||
95f7e683c7 | |||
402061a4b1 | |||
12fb88cab9 | |||
7a8b35c83b | |||
b852eed489 | |||
22328c6227 | |||
b84f236277 | |||
fe6c805bc7 | |||
64e5770ceb | |||
77374cf5f4 | |||
3c0ba835c4 | |||
0b9c5d2b46 | |||
0e3f6f48fd | |||
d8541bab92 | |||
|
7d1f63909a | ||
47b15814db | |||
e384ec7929 | |||
d0fb6e9a3a | |||
0e2c1bdae4 | |||
7a25ba2f7a | |||
542d34ea6b | |||
73e429f59a | |||
4a6777f637 | |||
b03ae3b784 | |||
83cdff4ea8 | |||
6f249aa072 | |||
f0e0c4c088 | |||
bf738e390f | |||
10aa536021 | |||
422c3ea532 | |||
fa4eab1389 | |||
cdac8d3dc2 | |||
75db744caa | |||
8f8cfbd358 | |||
d2a9d13ef3 | |||
7f9714c3f8 | |||
edba293b76 | |||
9b1c43beb7 | |||
c86eed95ca | |||
3afa9d0c8e | |||
a7a430c723 | |||
36e3c3cba2 | |||
|
c68cbb9eda | ||
08d4c9f23b | |||
359d5d32d1 | |||
3f131f9906 | |||
424393bc05 | |||
8754519dbc | |||
5cab1b99c6 | |||
75389e15d8 | |||
5cf773256e | |||
d19008355c | |||
3d0cda87c9 | |||
faae76fbbd | |||
5bad125c44 | |||
0075c03c9d | |||
92594f5af3 | |||
efecad40ae | |||
4ad4b53de4 | |||
f58b972359 | |||
4dfba09d02 | |||
eb3b103c3e | |||
2acb5d5c77 | |||
|
0438a25298 | ||
bf11edbc9a | |||
1e2e257dcb | |||
886ea498f1 | |||
352739293c | |||
173a80f5d2 | |||
7c96255dfb | |||
6c49f9e935 |
10
.gitignore
vendored
|
@ -12,22 +12,24 @@ linux/flatpak/.flatpak-builder
|
|||
**/**.jsc
|
||||
**/**.pyc
|
||||
**/**.qm
|
||||
**/**.log
|
||||
*.jsc
|
||||
*.qmlc
|
||||
*.log
|
||||
**/*.dxvk-cache
|
||||
.DS_Store
|
||||
**/.DS_Store
|
||||
**/__pycache__/
|
||||
.ropeproject
|
||||
.vscode
|
||||
*.kdev4
|
||||
.kdev4
|
||||
.coverage
|
||||
build
|
||||
docs/html
|
||||
.directory
|
||||
*.kdev4
|
||||
*.lpf
|
||||
*.lgg
|
||||
*.spec
|
||||
.kdev4
|
||||
AccountFree.pro
|
||||
AccountFree.pro.user
|
||||
*.egg-info/
|
||||
*.tar.gz
|
||||
|
|
3
.gitmodules
vendored
|
@ -1,6 +1,3 @@
|
|||
[submodule "LogarithmPlotter/qml/eu/ad5001/MixedMenu"]
|
||||
path = LogarithmPlotter/qml/eu/ad5001/MixedMenu
|
||||
url = https://git.ad5001.eu/Ad5001/MixedMenu
|
||||
[submodule "linux/flatpak"]
|
||||
path = linux/flatpak
|
||||
url = https://github.com/Ad5001/eu.ad5001.LogarithmPlotter
|
||||
|
|
311
CHANGELOG.md
|
@ -1,46 +1,313 @@
|
|||
# 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)
|
||||
|
||||
**New**
|
||||
|
||||
* There is now a [user manual](https://git.ad5001.eu/Ad5001/LogarithmPlotter/wiki/_Sidebar) for LogarithmPlotter! Contributions apprecriated.
|
||||
|
||||
**Changes**
|
||||
|
||||
* A link to [LogarithmPlotter's official website](https://apps.ad5001.eu/logarithmplotter/) has been added in the about dialog.
|
||||
* A link to the [user manual](https://git.ad5001.eu/Ad5001/LogarithmPlotter/wiki/_Sidebar) has been added both on the greeting screen and the `Help` menu.
|
||||
|
||||
**Added translations**
|
||||
|
||||
* User manual.
|
||||
* Official website.
|
||||
|
||||
**Fixed bugs**
|
||||
|
||||
* The label position of X Cursors now display the label even when unexpected values are entered.
|
||||
* X Cursors target object in history are now properly rendered when no object were selected
|
||||
* Fixed slight clipping at the bottom of the border.
|
||||
* TextInput no longer allow to input forbidden characters for numbers.
|
||||
* ALT+ shortcuts on the menu bar now work. NOTE: May break some mobile configuration. [Qt bug report](https://bugreports.qt.io/browse/QTBUG-100539)
|
||||
* (flatpak) Buttons on side menu to create object now have proper width on startup.
|
||||
|
||||
**Internal changes**
|
||||
|
||||
* There is now a script to generate offline versions of the manual based on their online version.
|
||||
* Sidebar button width is now fixed.
|
||||
* Artifacts have been added to appstream metadata.
|
||||
|
||||
## v0.1.7 (03 Feb 2022)
|
||||
|
||||
**New**
|
||||
|
||||
* The history browser has been completly redesigned, improving UX.
|
||||
* The history browser now features a filter bar.
|
||||
* All side panel tabs now have a visually identifiable scrollbar.
|
||||
|
||||
**Changes**
|
||||
|
||||
* Shorter rich text representations of history entries to improve readability.
|
||||
* Usage of gradiants and icons to better identify history entries at a glance.
|
||||
* History entries are now showing the whole label on several lines, instead of cutting it at the end.
|
||||
* New history action for renaming.
|
||||
* New history action for coloring. Note: color changing history entries created in previous versions of LogarithmPlotter will not be updated.
|
||||
* Tooltips for object creation buttons have been added.
|
||||
* Tooltips have been set to have a delay of 200ms to match most software's handling of them.
|
||||
* Object creation buttons now have a unified style accross all platforms.
|
||||
|
||||
**Added translations**
|
||||
|
||||
* History action of renaming objects.
|
||||
* History action of changing the color of objects.
|
||||
* Filtering for history browser.
|
||||
|
||||
**Fixed bugs**
|
||||
|
||||
* Visibility history actions (shown and hidden) are now properly savedmaking loading them not automaticly changed to "Show".
|
||||
* Name changes history actions are now properly saved.
|
||||
* Non translated object type on the "+ Create new object" item selection combobox for Bode Magnitude and Phase.
|
||||
* Proper handling for future LogarithmPlotter files.
|
||||
* Shortcuts not being displayed in the menu bar are now properly shown.
|
||||
* (flatpak) Black versions of the icons when using a black theme with the KDE SDK.
|
||||
* (debian) Fixed launchpad building properly.
|
||||
|
||||
**Internal changes**
|
||||
|
||||
* Better organisation on icons.
|
||||
* Historylib has been separated in several files.
|
||||
* Trying to switch metainfo once more to try and fix another bug.
|
||||
* Keywords added to metainfo.
|
||||
|
||||
## v0.1.6 (29 Jan 2022)
|
||||
|
||||
**New**
|
||||
|
||||
* A new changelog popup is available at startup and in the help menu.
|
||||
|
||||
**Added translations**
|
||||
|
||||
* Object properties names.
|
||||
* Object properties enum values.
|
||||
* Object comments.
|
||||
* Most elements using a ":".
|
||||
|
||||
**Fixed bugs**
|
||||
|
||||
* X Cursor's targets can now be set to null.
|
||||
* History now imports domains and objects properly.
|
||||
* Proper handling for future LogarithmPlotter files.
|
||||
* (debian) Fixing bug that created a /build directory and didn't put the icons in the right directories.
|
||||
|
||||
**Other**
|
||||
|
||||
* Other: Refractoring done on helper.
|
||||
* Other: All QML elements are now properly commented.
|
||||
* Other: Scripts have been moved to it's own directory.
|
||||
* Other: Added changelog to metainfo for flathub.
|
||||
|
||||
## v0.1.5 (26 Jan 2022)
|
||||
|
||||
**New**
|
||||
|
||||
* LogarithmPlotter has now better handling of very high values in logarithmic scale.
|
||||
|
||||
**Added translations**
|
||||
|
||||
* Flatpak metadata, including translated image.
|
||||
|
||||
**Fixed bugs**
|
||||
|
||||
* (!) File saving dialog was not working.
|
||||
* (!) Debian packages does include any language file.
|
||||
* X Cursor pointing does not detect any object.
|
||||
|
||||
## v0.1.4 (24 Jan 2022)
|
||||
|
||||
* New feature: LogarithmPlotter detects unsaved changes.
|
||||
* New feature: LogarithmPlotter is now translated! See https://hosted.weblate.org/engage/logarithmplotter/ to help.
|
||||
**New**
|
||||
|
||||
* LogarithmPlotter detects unsaved changes.
|
||||
* LogarithmPlotter is now translated!
|
||||
* New translation: English by Ad5001: 100%
|
||||
* New translation: French by Ad5001: 100%
|
||||
* New translation: German by Ad5001: 100%
|
||||
* New translation: Hungarian by Óvári (@ovari on github): 100%
|
||||
* New translation: Norvegian by Allan Nordhøy (@comradekingu on github): 80%
|
||||
|
||||
**Fixed bugs**
|
||||
|
||||
* Fixed bug: No notification when closing LogarithmPlotter with unsaved changes.
|
||||
* Fixed bug: π unavailable in symbols.
|
||||
|
||||
-- Ad5001 <mail@ad5001.eu> Wed, 24 Jan 2022 20:00:00 +0100
|
||||
|
||||
## v0.1.3 (18 Jan 2022)
|
||||
|
||||
* Fixed bug: Confined packages (snapcraft & flatpak) won't show error messages related to update checks.
|
||||
* FIxed bug: Equations of the form (x + y) / z were not being simplified properly.
|
||||
**Fixed bugs**
|
||||
|
||||
-- Ad5001 <mail@ad5001.eu> Wed, 18 Jan 2022 20:00:00 +0100
|
||||
|
||||
## v0.1.3 (18 Jan 2022)
|
||||
|
||||
* Fixed bug: Confined packages (snapcraft & flatpak) won't show error messages related to update checks.
|
||||
* FIxed bug: Equations of the form (x + y) / z were not being simplified properly.
|
||||
|
||||
-- Ad5001 <mail@ad5001.eu> Wed, 19 Jan 2022 20:00:00 +0100
|
||||
* Sandboxed packages (snapcraft and flatpak) won't show error messages related to update checks.
|
||||
* Equations of the form (x + y) / z were not being simplified properly.
|
||||
|
||||
## v0.1.2 (30 Sep 2021)
|
||||
|
||||
* Fixed bug: Unable to move Bode diagrams elements when having deleted the sum element.
|
||||
* Fixed bug: Names were not not being changed from previous object when editing a new one.
|
||||
* Fixed bug: Bode Magnitude was not drawn far enough
|
||||
* Fixed bug: Bode Magnitude had undefined ending.
|
||||
* Fixed other bugs from v0.1.1.
|
||||
**Fixed bugs**
|
||||
|
||||
-- Ad5001 <mail@ad5001.eu> Mon, 30 Sep 2021 20:00:00 +0100
|
||||
* Unable to move Bode diagrams elements when having deleted the sum element.
|
||||
* Names were not not being changed from previous object when editing a new one.
|
||||
* Bode Magnitude was not drawn far enough.
|
||||
* Bode Magnitude had undefined ending.
|
||||
* Other bugs patched in v0.1.1.
|
||||
|
||||
## v0.1 (26 Aug 2021)
|
||||
|
||||
* Initial release.
|
||||
|
||||
-- Ad5001 <mail@ad5001.eu> Mon, 06 Jun 2021 08:48:28 +0100
|
||||
|
||||
|
|
|
@ -630,8 +630,8 @@ attach them to the start of each source file to most effectively state
|
|||
the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
LogarithmPlotter - Create graphs with logarithm scales.
|
||||
Copyright (C) 2021 Ad5001
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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
|
||||
|
@ -652,7 +652,7 @@ mail.
|
|||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
LogarithmPlotter Copyright (C) 2021 Ad5001
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
@ -673,4 +673,3 @@ library, you may consider it more useful to permit linking proprietary
|
|||
applications with the library. If this is what you want to do, use the
|
||||
GNU Lesser General Public License instead of this License. But first,
|
||||
please read <https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
|
@ -17,9 +17,8 @@
|
|||
"""
|
||||
from shutil import which
|
||||
|
||||
__VERSION__ = "0.1.4"
|
||||
is_release = True
|
||||
|
||||
__VERSION__ = "0.6.0"
|
||||
is_release = False
|
||||
|
||||
# Check if development version, if so get the date of the latest git patch
|
||||
# and append it to the version string.
|
||||
|
@ -27,6 +26,7 @@ if not is_release and which('git') is not None:
|
|||
from os.path import realpath, join, dirname, exists
|
||||
from subprocess import check_output
|
||||
from datetime import datetime
|
||||
|
||||
# Command to check date of latest git commit
|
||||
cmd = ['git', 'log', '--format=%ci', '-n 1']
|
||||
cwd = realpath(join(dirname(__file__), '..')) # Root AccountFree directory.
|
||||
|
@ -39,6 +39,3 @@ if not is_release and which('git') is not None:
|
|||
# Date cannot be parsed, not git root?
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
from .logarithmplotter import run
|
||||
run()
|
||||
|
|
|
@ -1,2 +1,54 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# This file automatically renames .mjs files to js, and (tries) to fix most common ECMAScript
|
||||
# specificities so that lupdate doesn't cry out in pain.
|
||||
# See also: https://bugreports.qt.io/browse/QTBUG-123819
|
||||
#
|
||||
|
||||
escape() {
|
||||
str="$1"
|
||||
str="${str//\//\\/}" # Escape slashes
|
||||
str="${str//\*/\\*}" # Escape asterixes
|
||||
echo "$str"
|
||||
}
|
||||
|
||||
replace() {
|
||||
file="$1"
|
||||
from="$(escape "$2")"
|
||||
to="$(escape "$3")"
|
||||
sed -i "s/${from}/${to}/g" "$file"
|
||||
}
|
||||
|
||||
files=$(find .. -name *.mjs)
|
||||
for file in $files; do
|
||||
echo "Moving '$file' to '${file%.*}.js'..."
|
||||
mv "$file" "${file%.*}.js"
|
||||
# Replacements to make it valid js
|
||||
replace "${file%.*}.js" "^import" "/*import"
|
||||
replace "${file%.*}.js" '.mjs"$' '.mjs"*/'
|
||||
replace "${file%.*}.js" "^export default" "/*export default*/"
|
||||
replace "${file%.*}.js" "^export" "/*export*/"
|
||||
done
|
||||
|
||||
echo "----------------------------"
|
||||
echo "| Updating translations... |"
|
||||
echo "----------------------------"
|
||||
lupdate -extensions js,qs,qml,py -recursive .. -ts lp_*.ts
|
||||
# Updating locations in files
|
||||
for lp in *.ts; do
|
||||
echo "Replacing locations in $lp..."
|
||||
for file in $files; do
|
||||
echo " > Replacing for file $file..."
|
||||
replace "$lp" "${file%.*}.js" "$file"
|
||||
done
|
||||
done
|
||||
|
||||
for file in $files; do
|
||||
echo "Moving '${file%.*}.js' to '$file'..."
|
||||
mv "${file%.*}.js" "$file"
|
||||
# Resetting changes
|
||||
replace "$file" "^/*import" "import"
|
||||
replace "$file" '.mjs"*/$' '.mjs"'
|
||||
replace "$file" "^/*export default*/" "export default"
|
||||
replace "$file" "^/*export*/" "export"
|
||||
done
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
|
@ -16,214 +16,183 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
from os import getcwd, chdir, environ, path
|
||||
from platform import release as os_release
|
||||
from sys import path as sys_path
|
||||
from sys import platform, argv, exit
|
||||
from tempfile import TemporaryDirectory
|
||||
from time import time
|
||||
|
||||
from PySide6.QtCore import QTranslator, QLocale
|
||||
from PySide6.QtGui import QIcon
|
||||
from PySide6.QtQml import QQmlApplicationEngine
|
||||
from PySide6.QtQuickControls2 import QQuickStyle
|
||||
from PySide6.QtWidgets import QApplication
|
||||
|
||||
start_time = time()
|
||||
|
||||
from PySide2.QtWidgets import QApplication, QFileDialog
|
||||
from PySide2.QtQml import QQmlApplicationEngine, qmlRegisterType
|
||||
from PySide2.QtCore import Qt, QObject, Signal, Slot, Property, QTranslator, QLocale, QCoreApplication
|
||||
from PySide2.QtGui import QIcon, QImage, QKeySequence
|
||||
from PySide2 import __version__ as PySide2_version
|
||||
|
||||
from tempfile import mkstemp
|
||||
from os import getcwd, chdir, environ, path, remove, close
|
||||
from platform import release as os_release
|
||||
from json import dumps, loads
|
||||
from sys import platform, argv, version as sys_version, exit
|
||||
from webbrowser import open as openWeb
|
||||
|
||||
# Create the temporary file for saving copied screenshots
|
||||
fd, tmpfile = mkstemp(suffix='.png')
|
||||
# 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__)))
|
||||
logarithmplotter_path = path.dirname(path.realpath(__file__))
|
||||
chdir(logarithmplotter_path)
|
||||
|
||||
from sys import path as sys_path
|
||||
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
|
||||
from LogarithmPlotter.util.js import PyJSValue
|
||||
|
||||
from LogarithmPlotter import config, native, __VERSION__
|
||||
from LogarithmPlotter.update import check_for_updates
|
||||
LINUX_THEMES = { # See https://specifications.freedesktop.org/menu-spec/latest/onlyshowin-registry.html
|
||||
"COSMIC": "Basic",
|
||||
"GNOME": "Basic",
|
||||
"GNOME-Classic": "Basic",
|
||||
"GNOME-Flashback": "Basic",
|
||||
"KDE": "Fusion",
|
||||
"LXDE": "Basic",
|
||||
"LXQt": "Fusion",
|
||||
"MATE": "Fusion",
|
||||
"TDE": "Fusion",
|
||||
"Unity": "Basic",
|
||||
"XFCE": "Basic",
|
||||
"Cinnamon": "Fusion",
|
||||
"Pantheon": "Basic",
|
||||
"DDE": "Basic",
|
||||
"EDE": "Fusion",
|
||||
"Endless": "Basic",
|
||||
"Old": "Fusion",
|
||||
}
|
||||
|
||||
config.init()
|
||||
|
||||
def get_linux_theme():
|
||||
des = {
|
||||
"KDE": "org.kde.desktop",
|
||||
"gnome": "default",
|
||||
"lxqt": "fusion",
|
||||
"mate": "fusion",
|
||||
}
|
||||
def get_linux_theme() -> str:
|
||||
if "XDG_SESSION_DESKTOP" in environ:
|
||||
return des[environ["XDG_SESSION_DESKTOP"]] if environ["XDG_SESSION_DESKTOP"] in des else "fusion"
|
||||
if environ["XDG_SESSION_DESKTOP"] in LINUX_THEMES:
|
||||
return LINUX_THEMES[environ["XDG_SESSION_DESKTOP"]]
|
||||
return "Fusion"
|
||||
else:
|
||||
# Android
|
||||
return "Material"
|
||||
|
||||
class Helper(QObject):
|
||||
|
||||
def __init__(self, engine: QQmlApplicationEngine):
|
||||
QObject.__init__(self)
|
||||
self.engine = engine;
|
||||
|
||||
@Slot(str, str)
|
||||
def write(self, filename, filedata):
|
||||
chdir(pwd)
|
||||
if path.exists(path.dirname(path.realpath(filename))):
|
||||
if filename.split(".")[-1] == "lpf":
|
||||
# Add header to file
|
||||
filedata = "LPFv1" + filedata
|
||||
f = open(path.realpath(filename), 'w', -1, 'utf8')
|
||||
f.write(filedata)
|
||||
f.close()
|
||||
chdir(path.dirname(path.realpath(__file__)))
|
||||
|
||||
@Slot(str, result=str)
|
||||
def load(self, filename):
|
||||
chdir(pwd)
|
||||
data = '{}'
|
||||
from PySide2.QtWidgets import QMessageBox
|
||||
if path.exists(path.realpath(filename)):
|
||||
f = open(path.realpath(filename), 'r', -1, 'utf8')
|
||||
data = f.read()
|
||||
f.close()
|
||||
try:
|
||||
if data[:5] == "LPFv1":
|
||||
# V1 version of the file
|
||||
data = data[5:]
|
||||
elif data[0] == "{" and "type" in loads(data) and loads(data)["type"] == "logplotv1":
|
||||
pass
|
||||
else:
|
||||
raise Exception("Invalid LogarithmPlotter file.")
|
||||
except Exception as e: # If file can't be loaded
|
||||
QMessageBox.warning(None, 'LogarithmPlotter', QCoreApplication.translate('main','Could not open file "{}":\n{}').format(filename, e), QMessageBox.Ok) # Cannot parse file
|
||||
else:
|
||||
QMessageBox.warning(None, 'LogarithmPlotter', QCoreApplication.translate('main','Could not open file: "{}"\nFile does not exist.').format(filename), QMessageBox.Ok) # Cannot parse file
|
||||
chdir(path.dirname(path.realpath(__file__)))
|
||||
return data
|
||||
|
||||
@Slot(result=str)
|
||||
def gettmpfile(self):
|
||||
global tmpfile
|
||||
return tmpfile
|
||||
|
||||
@Slot()
|
||||
def copyImageToClipboard(self):
|
||||
global tmpfile
|
||||
clipboard = QApplication.clipboard()
|
||||
clipboard.setImage(QImage(tmpfile))
|
||||
|
||||
@Slot(result=str)
|
||||
def getVersion(self):
|
||||
return __VERSION__
|
||||
|
||||
@Slot(str, result=str)
|
||||
def getSetting(self, namespace):
|
||||
return config.getSetting(namespace)
|
||||
|
||||
@Slot(str, result=bool)
|
||||
def getSettingBool(self, namespace):
|
||||
return config.getSetting(namespace)
|
||||
|
||||
@Slot(str, str)
|
||||
def setSetting(self, namespace, value):
|
||||
return config.setSetting(namespace, value)
|
||||
|
||||
@Slot(str, bool)
|
||||
def setSettingBool(self, namespace, value):
|
||||
return config.setSetting(namespace, value)
|
||||
|
||||
@Slot(str)
|
||||
def setLanguage(self, new_lang):
|
||||
config.setSetting("language", new_lang)
|
||||
|
||||
@Slot(result=str)
|
||||
def getDebugInfos(self):
|
||||
"""
|
||||
Returns the version info about Qt, PySide2 & Python
|
||||
"""
|
||||
return QCoreApplication.translate('main',"Built with PySide2 (Qt) v{} and python v{}").format(PySide2_version, sys_version.split("\n")[0])
|
||||
|
||||
@Slot(str)
|
||||
def openUrl(self, url):
|
||||
openWeb(url)
|
||||
|
||||
def run():
|
||||
|
||||
environ["QT_QUICK_CONTROLS_STYLE"] = {
|
||||
def get_platform_qt_style(os) -> str:
|
||||
return {
|
||||
"linux": get_linux_theme(),
|
||||
"freebsd": get_linux_theme(),
|
||||
"win32": "universal" if os_release == "10" else "fusion",
|
||||
"cygwin": "fusion",
|
||||
"darwin": "default"
|
||||
}[platform]
|
||||
"win32": "Universal" if os_release() in ["10", "11", "12", "13", "14"] else "Windows",
|
||||
"cygwin": "Fusion",
|
||||
"darwin": "macOS"
|
||||
}[os]
|
||||
|
||||
dep_time = time()
|
||||
print("Loaded dependencies in " + str((dep_time - start_time)*1000) + "ms.")
|
||||
|
||||
icon_fallbacks = QIcon.fallbackSearchPaths();
|
||||
icon_fallbacks.append(path.realpath(path.join(getcwd(), "qml", "eu", "ad5001", "LogarithmPlotter", "icons")))
|
||||
icon_fallbacks.append(path.realpath(path.join(getcwd(), "qml", "eu", "ad5001", "LogarithmPlotter", "icons", "settings")))
|
||||
icon_fallbacks.append(path.realpath(path.join(getcwd(), "qml", "eu", "ad5001", "LogarithmPlotter", "icons", "settings", "custom")))
|
||||
QIcon.setFallbackSearchPaths(icon_fallbacks);
|
||||
def register_icon_directories() -> None:
|
||||
icon_fallbacks = QIcon.fallbackSearchPaths()
|
||||
base_icon_path = path.join(logarithmplotter_path, "qml", "eu", "ad5001", "LogarithmPlotter", "icons")
|
||||
paths = [["common"], ["objects"], ["history"], ["settings"], ["settings", "custom"]]
|
||||
for p in paths:
|
||||
icon_fallbacks.append(path.realpath(path.join(base_icon_path, *p)))
|
||||
QIcon.setFallbackSearchPaths(icon_fallbacks)
|
||||
|
||||
|
||||
def create_qapp() -> QApplication:
|
||||
app = QApplication(argv)
|
||||
app.setApplicationName("LogarithmPlotter")
|
||||
app.setApplicationDisplayName("LogarithmPlotter")
|
||||
app.setApplicationVersion(f"v{__VERSION__}")
|
||||
app.setDesktopFileName("eu.ad5001.LogarithmPlotter")
|
||||
app.setOrganizationName("Ad5001")
|
||||
app.setWindowIcon(QIcon(path.realpath(path.join(getcwd(), "logarithmplotter.svg"))))
|
||||
app.styleHints().setShowShortcutsInContextMenus(True)
|
||||
app.setWindowIcon(QIcon(path.realpath(path.join(logarithmplotter_path, "logarithmplotter.svg"))))
|
||||
return app
|
||||
|
||||
|
||||
def install_translation(app: QApplication) -> QTranslator:
|
||||
# Installing translators
|
||||
translator = QTranslator()
|
||||
# Check if lang is forced.
|
||||
forcedlang = [p for p in argv if p[:7]=="--lang="]
|
||||
forcedlang = [p for p in argv if p[:7] == "--lang="]
|
||||
i18n_path = path.realpath(path.join(logarithmplotter_path, "i18n"))
|
||||
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);
|
||||
if not translator.load(locale, "lp", "_", i18n_path):
|
||||
# Load default translation
|
||||
print("Loading default language en...")
|
||||
translator.load(QLocale("en"), "lp", "_", i18n_path)
|
||||
app.installTranslator(translator)
|
||||
return translator
|
||||
|
||||
# Installing macOS file handler.
|
||||
macOSFileOpenHandler = None
|
||||
if platform == "darwin":
|
||||
macOSFileOpenHandler = native.MacOSFileOpenHandler()
|
||||
app.installEventFilter(macOSFileOpenHandler)
|
||||
|
||||
def create_engine(helper: Helper, latex: Latex, dep_time: float) -> tuple[QQmlApplicationEngine, PyJSValue]:
|
||||
global tmpfile
|
||||
engine = QQmlApplicationEngine()
|
||||
helper = Helper(engine)
|
||||
engine.rootContext().setContextProperty("Helper", helper)
|
||||
js_globals = PyJSValue(engine.globalObject())
|
||||
js_globals.Modules = engine.newObject()
|
||||
js_globals.Helper = engine.newQObject(helper)
|
||||
js_globals.Latex = engine.newQObject(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.
|
||||
qml_path = path.realpath(path.join(logarithmplotter_path, "qml"))
|
||||
engine.addImportPath(qml_path)
|
||||
engine.load(path.join(qml_path, "eu", "ad5001", "LogarithmPlotter", "LogarithmPlotter.qml"))
|
||||
|
||||
engine.addImportPath(path.realpath(path.join(getcwd(), "qml")))
|
||||
engine.load(path.realpath(path.join(getcwd(), "qml", "eu", "ad5001", "LogarithmPlotter", "LogarithmPlotter.qml")))
|
||||
return engine, js_globals
|
||||
|
||||
|
||||
if not engine.rootObjects():
|
||||
def run():
|
||||
config.init()
|
||||
|
||||
if not 'QT_QUICK_CONTROLS_STYLE' in environ:
|
||||
QQuickStyle.setStyle(get_platform_qt_style(platform))
|
||||
|
||||
dep_time = time()
|
||||
print("Loaded dependencies in " + str((dep_time - start_time) * 1000) + "ms.")
|
||||
|
||||
register_icon_directories()
|
||||
app = create_qapp()
|
||||
translator = install_translation(app)
|
||||
|
||||
# Installing macOS file handler.
|
||||
macos_file_open_handler = None
|
||||
if platform == "darwin":
|
||||
macos_file_open_handler = native.MacOSFileOpenHandler()
|
||||
app.installEventFilter(macos_file_open_handler)
|
||||
|
||||
helper = Helper(pwd, tmpfile)
|
||||
latex = Latex(tempdir)
|
||||
engine, js_globals = create_engine(helper, latex, dep_time)
|
||||
|
||||
if len(engine.rootObjects()) == 0: # No root objects loaded
|
||||
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])
|
||||
js_globals.Modules.IO.loadDiagram(argv[-1])
|
||||
chdir(path.dirname(path.realpath(__file__)))
|
||||
|
||||
if platform == "darwin":
|
||||
macOSFileOpenHandler.init_graphics(engine.rootObjects()[0])
|
||||
macos_file_open_handler.init_io(js_globals.Modules.IO)
|
||||
|
||||
# Check for LaTeX installation if LaTeX support is enabled
|
||||
if config.getSetting("enable_latex"):
|
||||
latex.checkLatexInstallation()
|
||||
|
||||
# Check for updates
|
||||
if config.getSetting("check_for_updates"):
|
||||
check_for_updates(__VERSION__, engine.rootObjects()[0])
|
||||
|
||||
exit_code = app.exec_()
|
||||
exit_code = app.exec()
|
||||
|
||||
close(fd)
|
||||
remove(tmpfile)
|
||||
tempdir.cleanup()
|
||||
config.save()
|
||||
exit(exit_code)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
|
||||
|
|
|
@ -1,9 +1,64 @@
|
|||
<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>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="24.0px"
|
||||
height="24.0px"
|
||||
viewBox="0 0 24.0 24.0"
|
||||
version="1.1"
|
||||
id="SVGRoot"
|
||||
xml:space="preserve"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"><title
|
||||
id="title836">LogarithmPlotter Icon v1.0</title><defs
|
||||
id="defs833" /><metadata
|
||||
id="metadata836"><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>LogarithmPlotter Icon v1.0</dc:title><cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-nc-sa/4.0/" /><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 - All rights reserved</dc:title></cc:Agent></dc:rights></cc:Work><cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-nc-sa/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:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /><cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" /></cc:License></rdf:RDF></metadata><g
|
||||
id="layer2"
|
||||
transform="matrix(1,0,0,0.94444444,0,1.1666667)"
|
||||
style="fill:#666666"><rect
|
||||
style="fill:#666666;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect1546"
|
||||
width="18"
|
||||
height="18"
|
||||
x="3"
|
||||
y="3"
|
||||
ry="2.25" /></g><g
|
||||
id="layer2-6"
|
||||
transform="matrix(1,0,0,0.94444444,0,0.16666668)"
|
||||
style="fill:#f9f9f9"><rect
|
||||
style="fill:#f9f9f9;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect1546-7"
|
||||
width="18"
|
||||
height="18"
|
||||
x="3"
|
||||
y="3"
|
||||
ry="2.25" /></g><g
|
||||
id="layer1"
|
||||
style="stroke-width:2;stroke-dasharray:none"><rect
|
||||
style="fill:#000000;fill-rule:evenodd;stroke-width:1.86898;stroke-dasharray:none;stroke-opacity:0"
|
||||
id="rect1410"
|
||||
width="14"
|
||||
height="2"
|
||||
x="5"
|
||||
y="15.5" /><rect
|
||||
style="fill:#000000;fill-rule:evenodd;stroke-width:2;stroke-dasharray:none;stroke-opacity:0"
|
||||
id="rect1412"
|
||||
width="2"
|
||||
height="15"
|
||||
x="9"
|
||||
y="3.9768662" /><path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path1529"
|
||||
d="M 18,4 C 18,10.017307 13.40948,15.5 5,15.5" /></g></svg>
|
||||
|
|
Before Width: | Height: | Size: 488 B After Width: | Height: | Size: 3.1 KiB |
|
@ -1,107 +0,0 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Dialogs 1.3 as D
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
|
||||
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: Helper.openUrl(link)
|
||||
}
|
||||
|
||||
Button {
|
||||
id: openIssueButton
|
||||
anchors.top: copyrightInfos.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.topMargin: 10
|
||||
text: qsTr('Report a bug')
|
||||
icon.name: 'bug'
|
||||
onClicked: Helper.openUrl('https://git.ad5001.eu/Ad5001/LogarithmPlotter')
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
|
@ -16,12 +16,22 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Dialogs 1.3
|
||||
import QtQuick
|
||||
import Qt.labs.platform as Native
|
||||
//import QtQuick.Controls 2.15
|
||||
import eu.ad5001.MixedMenu 1.1
|
||||
import "js/objects.js" as Objects
|
||||
import "js/historylib.js" as HistoryLib
|
||||
import "js/history/index.mjs" as HistoryLib
|
||||
|
||||
|
||||
/*!
|
||||
\qmltype AppMenuBar
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter
|
||||
\brief MenuBar for LogarithmPlotter.
|
||||
|
||||
Makes use of eu.ad5001.LogarithmPlotter.
|
||||
|
||||
\sa LogarithmPlotter
|
||||
*/
|
||||
MenuBar {
|
||||
|
||||
Menu {
|
||||
|
@ -79,30 +89,36 @@ MenuBar {
|
|||
icon.color: enabled ? sysPalette.windowText : sysPaletteIn.windowText
|
||||
enabled: history.redoCount > 0
|
||||
}
|
||||
MenuSeparator { }
|
||||
Action {
|
||||
text: qsTr("&Copy plot")
|
||||
shortcut: StandardKey.Copy
|
||||
onTriggered: root.copyDiagramToClipboard()
|
||||
icon.name: 'edit-copy'
|
||||
}
|
||||
MenuSeparator { }
|
||||
Action {
|
||||
text: qsTr("&Preferences")
|
||||
shortcut: StandardKey.Copy
|
||||
onTriggered: preferences.open()
|
||||
icon.name: 'settings'
|
||||
}
|
||||
}
|
||||
|
||||
Menu {
|
||||
title: qsTr("&Create")
|
||||
// Services repeater
|
||||
Repeater {
|
||||
model: Object.keys(Objects.types)
|
||||
model: Object.keys(Modules.Objects.types)
|
||||
|
||||
MenuItem {
|
||||
text: Objects.types[modelData].displayType()
|
||||
visible: Objects.types[modelData].createable()
|
||||
text: Modules.Objects.types[modelData].displayType()
|
||||
visible: Modules.Objects.types[modelData].createable()
|
||||
height: visible ? implicitHeight : 0
|
||||
icon.name: modelData
|
||||
icon.source: './icons/' + modelData + '.svg'
|
||||
icon.source: './icons/objects/' + modelData + '.svg'
|
||||
icon.color: sysPalette.buttonText
|
||||
onTriggered: {
|
||||
var newObj = Objects.createNewRegisteredObject(modelData)
|
||||
var newObj = Modules.Objects.createNewRegisteredObject(modelData)
|
||||
history.addToHistory(new HistoryLib.CreateNewObject(newObj.name, modelData, newObj.export()))
|
||||
objectLists.update()
|
||||
}
|
||||
|
@ -110,45 +126,39 @@ MenuBar {
|
|||
}
|
||||
}
|
||||
|
||||
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'
|
||||
}
|
||||
}
|
||||
|
||||
Menu {
|
||||
title: qsTr("&Help")
|
||||
Action {
|
||||
text: qsTr("&Source code")
|
||||
icon.name: 'code'
|
||||
onTriggered: Helper.openUrl("https://git.ad5001.eu/Ad5001/LogarithmPlotter/issues")
|
||||
icon.name: 'software-sources'
|
||||
onTriggered: Qt.openUrlExternally("https://git.ad5001.eu/Ad5001/LogarithmPlotter")
|
||||
}
|
||||
Action {
|
||||
text: qsTr("&Report a bug")
|
||||
icon.name: 'bug'
|
||||
onTriggered: Helper.openUrl("https://git.ad5001.eu/Ad5001/LogarithmPlotter/issues")
|
||||
icon.name: 'tools-report-bug'
|
||||
onTriggered: Qt.openUrlExternally("https://git.ad5001.eu/Ad5001/LogarithmPlotter/issues")
|
||||
}
|
||||
Action {
|
||||
text: qsTr("&User manual")
|
||||
icon.name: 'documentation'
|
||||
onTriggered: Qt.openUrlExternally("https://git.ad5001.eu/Ad5001/LogarithmPlotter/wiki/_Sidebar")
|
||||
}
|
||||
Action {
|
||||
text: qsTr("&Changelog")
|
||||
icon.name: 'state-information'
|
||||
onTriggered: changelog.open()
|
||||
}
|
||||
Action {
|
||||
text: qsTr("&Help translating!")
|
||||
icon.name: 'translator'
|
||||
onTriggered: Helper.openUrl("https://hosted.weblate.org/engage/logarithmplotter/")
|
||||
onTriggered: Qt.openUrlExternally("https://hosted.weblate.org/engage/logarithmplotter/")
|
||||
}
|
||||
MenuSeparator { }
|
||||
Action {
|
||||
text: qsTr("&Thanks")
|
||||
icon.name: 'about'
|
||||
onTriggered: thanksTo.open()
|
||||
}
|
||||
Action {
|
||||
text: qsTr("&About")
|
||||
shortcut: StandardKey.HelpContents
|
||||
|
@ -157,16 +167,17 @@ MenuBar {
|
|||
}
|
||||
}
|
||||
|
||||
MessageDialog {
|
||||
Native.MessageDialog {
|
||||
id: saveUnsavedChangesDialog
|
||||
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?")
|
||||
standardButtons: StandardButton.Yes | StandardButton.No
|
||||
onYes: Qt.quit()
|
||||
buttons: Native.MessageDialog.Save | Native.MessageDialog.Discard | Native.MessageDialog.Cancel
|
||||
|
||||
onSaveClicked: settings.save()
|
||||
onDiscardClicked: Qt.quit()
|
||||
}
|
||||
|
||||
function showSaveUnsavedChangesDialog() {
|
||||
saveUnsavedChangesDialog.visible = true
|
||||
function openSaveUnsavedChangesDialog() {
|
||||
saveUnsavedChangesDialog.open()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
Item {
|
||||
id: control
|
||||
height: 30
|
||||
|
||||
signal activated(int newIndex)
|
||||
signal accepted()
|
||||
|
||||
property string label: ''
|
||||
property alias model: combox.model
|
||||
property alias editable: combox.editable
|
||||
property alias editText: combox.editText
|
||||
property alias currentIndex: combox.currentIndex
|
||||
property string icon: ""
|
||||
|
||||
function find(elementName) {
|
||||
return combox.find(elementName)
|
||||
}
|
||||
|
||||
Icon {
|
||||
id: iconLabel
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: icon == "" ? 0 : 3
|
||||
source: control.visible ? control.icon : ""
|
||||
width: height
|
||||
height: icon == "" && visible ? 0 : 24
|
||||
color: sysPalette.windowText
|
||||
}
|
||||
|
||||
Label {
|
||||
id: labelItem
|
||||
anchors.left: iconLabel.right
|
||||
anchors.leftMargin: icon == "" ? 0 : 5
|
||||
height: 30
|
||||
anchors.top: parent.top
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
text: control.label +": "
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: combox
|
||||
height: 30
|
||||
anchors.left: labelItem.right
|
||||
anchors.leftMargin: 5
|
||||
width: control.width - labelItem.width - iconLabel.width - 10
|
||||
onActivated: function(newIndex) {
|
||||
control.activated(newIndex)
|
||||
}
|
||||
onAccepted: control.accepted()
|
||||
}
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
|
||||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
Popup {
|
||||
id: greetingPopup
|
||||
x: (parent.width-width)/2
|
||||
y: Math.max(20, (parent.height-height)/2)
|
||||
width: Math.max(welcome.width, 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
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: qsTr("Done")
|
||||
font.pixelSize: 20
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 10
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
onClicked: greetingPopup.close()
|
||||
}
|
||||
|
||||
Timer {
|
||||
running: Helper.getSetting("last_install_greet") != Helper.getVersion()
|
||||
repeat: false
|
||||
interval: 50
|
||||
onTriggered: greetingPopup.open()
|
||||
}
|
||||
|
||||
onClosed: Helper.setSetting("last_install_greet", Helper.getVersion())
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
|
@ -16,27 +16,65 @@
|
|||
* 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 QtQuick
|
||||
import QtQml
|
||||
import QtQuick.Window
|
||||
import "../js/history/index.mjs" as HistoryLib
|
||||
|
||||
/*!
|
||||
\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: []
|
||||
// Only true when no modification was done to the current working file.
|
||||
/*!
|
||||
\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++)
|
||||
|
@ -52,6 +90,10 @@ Item {
|
|||
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++)
|
||||
|
@ -63,7 +105,10 @@ Item {
|
|||
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())
|
||||
|
@ -77,11 +122,17 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
function undo() {
|
||||
/*!
|
||||
\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()
|
||||
objectLists.update()
|
||||
if(updateObjectList)
|
||||
objectLists.update()
|
||||
redoStack.push(action)
|
||||
undoCount--;
|
||||
redoCount++;
|
||||
|
@ -89,11 +140,17 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
function redo() {
|
||||
/*!
|
||||
\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()
|
||||
objectLists.update()
|
||||
if(updateObjectList)
|
||||
objectLists.update()
|
||||
undoStack.push(action)
|
||||
undoCount++;
|
||||
redoCount--;
|
||||
|
@ -101,6 +158,11 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\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()
|
||||
|
@ -108,6 +170,12 @@ Item {
|
|||
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()
|
||||
|
@ -121,7 +189,7 @@ Item {
|
|||
property int toUndoCount: 0
|
||||
onTriggered: {
|
||||
if(toUndoCount > 0) {
|
||||
historyObj.undo()
|
||||
historyObj.undo(toUndoCount % 4 == 1) // Only redraw once every 4 changes.
|
||||
toUndoCount--;
|
||||
} else {
|
||||
running = false;
|
||||
|
@ -135,7 +203,7 @@ Item {
|
|||
property int toRedoCount: 0
|
||||
onTriggered: {
|
||||
if(toRedoCount > 0) {
|
||||
historyObj.redo()
|
||||
historyObj.redo(toRedoCount % 4 == 1) // Only redraw once every 4 changes.
|
||||
toRedoCount--;
|
||||
} else {
|
||||
running = false;
|
||||
|
@ -144,6 +212,11 @@ Item {
|
|||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
HistoryLib.history = historyObj
|
||||
Modules.History.initialize({
|
||||
historyObj,
|
||||
themeTextColor: sysPalette.windowText.toString(),
|
||||
imageDepth: Screen.devicePixelRatio,
|
||||
fontSize: 14
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 Ad5001
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick.Controls
|
||||
import QtQuick
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
import "../js/utils.mjs" as Utils
|
||||
|
||||
|
||||
/*!
|
||||
\qmltype HistoryBrowser
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.History
|
||||
\brief Tab of the drawer that allows to navigate through the undo and redo history.
|
||||
|
||||
Creates a scrollable view containing a list of history actions based on the redo stack, then a "Now" indicator
|
||||
followed by the entirety of the saved undo stack. Each action can be click to restore a state of the graph at
|
||||
some point of the history.
|
||||
|
||||
\sa LogarithmPlotter, Settings, ObjectLists
|
||||
*/
|
||||
Item {
|
||||
id: historyBrowser
|
||||
|
||||
/*!
|
||||
\qmlproperty int HistoryBrowser::actionWidth
|
||||
Width of the actions.
|
||||
*/
|
||||
property int actionWidth: width-20
|
||||
|
||||
/*!
|
||||
\qmlproperty int HistoryBrowser::darkTheme
|
||||
true when the system is running with a dark theme, false otherwise.
|
||||
*/
|
||||
property bool darkTheme: isDarkTheme()
|
||||
|
||||
Setting.TextSetting {
|
||||
id: filterInput
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: 5
|
||||
placeholderText: qsTr("Filter...")
|
||||
category: "all"
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.top: filterInput.bottom
|
||||
|
||||
ScrollBar.horizontal.visible: false
|
||||
clip: true
|
||||
|
||||
Flickable {
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
contentHeight: redoColumn.height + nowRect.height + undoColumn.height
|
||||
contentWidth: parent.width
|
||||
|
||||
Column {
|
||||
id: redoColumn
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
width: actionWidth
|
||||
|
||||
Repeater {
|
||||
model: history.redoCount
|
||||
|
||||
HistoryItem {
|
||||
id: redoButton
|
||||
width: actionWidth
|
||||
//height: actionHeight
|
||||
isRedo: true
|
||||
idx: index
|
||||
darkTheme: historyBrowser.darkTheme
|
||||
hidden: !(filterInput.value == "" || content.includes(filterInput.value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: nowRect.top
|
||||
text: qsTr("Redo >")
|
||||
color: sysPaletteIn.windowText
|
||||
transform: Rotation { origin.x: 30; origin.y: 30; angle: 270}
|
||||
height: 70
|
||||
width: 20
|
||||
visible: history.redoCount > 0
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: nowRect
|
||||
anchors.right: parent.right
|
||||
anchors.top: redoColumn.bottom
|
||||
width: actionWidth
|
||||
height: 40
|
||||
color: sysPalette.highlight
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 5
|
||||
text: qsTr("> Now")
|
||||
color: sysPalette.windowText
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: undoColumn
|
||||
anchors.right: parent.right
|
||||
anchors.top: nowRect.bottom
|
||||
width: actionWidth
|
||||
|
||||
Repeater {
|
||||
model: history.undoCount
|
||||
|
||||
|
||||
HistoryItem {
|
||||
id: undoButton
|
||||
width: actionWidth
|
||||
//height: actionHeight
|
||||
isRedo: false
|
||||
idx: index
|
||||
darkTheme: historyBrowser.darkTheme
|
||||
hidden: !(filterInput.value == "" || content.includes(filterInput.value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.top: undoColumn.top
|
||||
text: qsTr("< Undo")
|
||||
color: sysPaletteIn.windowText
|
||||
transform: Rotation { origin.x: 30; origin.y: 30; angle: 270}
|
||||
height: 60
|
||||
width: 20
|
||||
visible: history.undoCount > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod bool HistoryBrowser::isDarkTheme()
|
||||
Checks whether the system is running with a light or dark theme.
|
||||
*/
|
||||
function isDarkTheme() {
|
||||
let hex = sysPalette.windowText.toString()
|
||||
// We only check the first parameter, as on all normal OSes, text color is grayscale.
|
||||
return parseInt(hex.substr(1,2), 16) > 128
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 Ad5001
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick.Controls
|
||||
import QtQuick
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import "../js/utils.mjs" as Utils
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
|
||||
|
||||
/*!
|
||||
\qmltype HistoryItem
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.History
|
||||
\brief Item representing an history action.
|
||||
|
||||
Creates a scrollable view containing a list of history actions based on the redo stack, then a "Now" indicator
|
||||
followed by the entirety of the saved undo stack. Each action can be click to restore a state of the graph at
|
||||
some point of the history.
|
||||
|
||||
\sa HistoryBrowser
|
||||
*/
|
||||
Button {
|
||||
id: redoButton
|
||||
flat: true
|
||||
|
||||
/*!
|
||||
\qmlproperty bool HistoryItem::isRedo
|
||||
true if the action is in the redo stack, false othewise.
|
||||
*/
|
||||
property bool isRedo
|
||||
/*!
|
||||
\qmlproperty int HistoryItem::idx
|
||||
Index of the item within the HistoryBrowser list.
|
||||
*/
|
||||
property int idx
|
||||
/*!
|
||||
\qmlproperty bool HistoryItem::darkTheme
|
||||
true when the system is running with a dark theme, false otherwise.
|
||||
*/
|
||||
property bool darkTheme
|
||||
/*!
|
||||
\qmlproperty bool HistoryItem::hidden
|
||||
true when the item is filtered out, false otherwise.
|
||||
*/
|
||||
property bool hidden: false
|
||||
/*!
|
||||
\qmlproperty int HistoryItem::historyAction
|
||||
Associated history action.
|
||||
*/
|
||||
readonly property var historyAction: isRedo ? history.redoStack[idx] : history.undoStack[history.undoCount-idx-1]
|
||||
|
||||
/*!
|
||||
\qmlproperty int HistoryItem::actionHeight
|
||||
Base height of the action.
|
||||
*/
|
||||
readonly property int actionHeight: 40
|
||||
/*!
|
||||
\qmlproperty color HistoryItem::clr
|
||||
Color of the history action.
|
||||
*/
|
||||
readonly property color clr: historyAction.color(darkTheme)
|
||||
/*!
|
||||
\qmlproperty string HistoryItem::clr
|
||||
Label description of the history item.
|
||||
*/
|
||||
readonly property string content: historyAction.getReadableString()
|
||||
|
||||
height: hidden ? 8 : Math.max(actionHeight, label.height + 15)
|
||||
|
||||
|
||||
LinearGradient {
|
||||
anchors.fill: parent
|
||||
//opacity: hidden ? 0.6 : 1
|
||||
start: Qt.point(0, 0)
|
||||
end: Qt.point(parent.width, 0)
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0.1; color: "transparent" }
|
||||
GradientStop { position: 1.5; color: clr }
|
||||
}
|
||||
}
|
||||
|
||||
Setting.Icon {
|
||||
id: icon
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 6
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: !hidden
|
||||
width: 18
|
||||
height: 18
|
||||
|
||||
color: sysPalette.windowText
|
||||
source: `../icons/history/${historyAction.icon()}.svg`
|
||||
}
|
||||
|
||||
Label {
|
||||
id: label
|
||||
anchors.left: icon.right
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 6
|
||||
anchors.rightMargin: 20
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: !hidden
|
||||
font.pixelSize: 14
|
||||
text: ""
|
||||
textFormat: Text.RichText
|
||||
clip: true
|
||||
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 {
|
||||
id: hiddenDot
|
||||
anchors.centerIn: parent
|
||||
visible: hidden
|
||||
width: 5
|
||||
height: 5
|
||||
radius: 5
|
||||
color: sysPalette.windowText
|
||||
}
|
||||
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.delay: 200
|
||||
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
|
|
@ -1,124 +0,0 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick 2.12
|
||||
import "js/utils.js" as Utils
|
||||
|
||||
ScrollView {
|
||||
id: historyBrowser
|
||||
|
||||
property int actionWidth: width-20
|
||||
|
||||
Flickable {
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
contentHeight: redoColumn.height + nowRect.height + undoColumn.height
|
||||
contentWidth: parent.width
|
||||
|
||||
Column {
|
||||
id: redoColumn
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
width: historyBrowser.actionWidth
|
||||
|
||||
Repeater {
|
||||
model: history.redoCount
|
||||
|
||||
Button {
|
||||
id: redoButton
|
||||
width: historyBrowser.actionWidth
|
||||
height: 30
|
||||
flat: true
|
||||
text: history.redoStack[index].getReadableString()
|
||||
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: text
|
||||
|
||||
onClicked: {
|
||||
history.redoMultipleDefered(history.redoCount-index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: nowRect.top
|
||||
text: qsTr("Redo >")
|
||||
color: sysPaletteIn.windowText
|
||||
transform: Rotation { origin.x: 30; origin.y: 30; angle: 270}
|
||||
height: 70
|
||||
width: 20
|
||||
visible: history.redoCount > 0
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: nowRect
|
||||
anchors.right: parent.right
|
||||
anchors.top: redoColumn.bottom
|
||||
width: historyBrowser.actionWidth
|
||||
height: 30
|
||||
color: sysPalette.highlight
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 5
|
||||
text: qsTr("> Now")
|
||||
color: sysPalette.windowText
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: undoColumn
|
||||
anchors.right: parent.right
|
||||
anchors.top: nowRect.bottom
|
||||
width: historyBrowser.actionWidth
|
||||
|
||||
Repeater {
|
||||
model: history.undoCount
|
||||
|
||||
Button {
|
||||
id: undoButton
|
||||
width: historyBrowser.actionWidth
|
||||
height: 30
|
||||
flat: true
|
||||
text: history.undoStack[history.undoCount-index-1].getReadableString()
|
||||
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: text
|
||||
|
||||
onClicked: {
|
||||
history.undoMultipleDefered(index+1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.top: undoColumn.top
|
||||
text: qsTr("< Undo")
|
||||
color: sysPaletteIn.windowText
|
||||
transform: Rotation { origin.x: 30; origin.y: 30; angle: 270}
|
||||
height: 60
|
||||
width: 20
|
||||
visible: history.undoCount > 0
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
|
@ -16,12 +16,20 @@
|
|||
* 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
|
||||
import QtQuick
|
||||
import Qt.labs.platform as Native
|
||||
import "js/utils.mjs" as Utils
|
||||
import "js/math/index.mjs" 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
|
||||
|
@ -29,213 +37,129 @@ Canvas {
|
|||
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: ""
|
||||
property int maxgradx: 10
|
||||
/*!
|
||||
\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
|
||||
|
||||
property var yaxisstepExpr: (new MathLib.Expression(`x*(${yaxisstep})`))
|
||||
property double yaxisstep1: yaxisstepExpr.execute(1)
|
||||
property int drawMaxY: Math.ceil(Math.max(Math.abs(ymax), Math.abs(px2y(canvasSize.height)))/yaxisstep1)
|
||||
property var xaxisstepExpr: (new MathLib.Expression(`x*(${xaxisstep})`))
|
||||
property double xaxisstep1: xaxisstepExpr.execute(1)
|
||||
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 = {}
|
||||
Modules.Canvas.initialize({ canvas, drawingErrorDialog })
|
||||
}
|
||||
|
||||
onPaint: {
|
||||
Native.MessageDialog {
|
||||
id: drawingErrorDialog
|
||||
title: qsTranslate("expression", "LogarithmPlotter - Drawing error")
|
||||
text: ""
|
||||
function show(objType, objName, error) {
|
||||
text = qsTranslate("error", "Error while attempting to draw %1 %2:\n%3\n\nUndoing last change.").arg(objType).arg(objName).arg(error)
|
||||
open()
|
||||
}
|
||||
}
|
||||
|
||||
onPaint: function(rect) {
|
||||
//console.log('Redrawing')
|
||||
var ctx = getContext("2d");
|
||||
reset(ctx)
|
||||
drawGrille(ctx)
|
||||
drawAxises(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)
|
||||
if(rect.width == canvas.width) { // Redraw full canvas
|
||||
Modules.Canvas.redraw()
|
||||
}
|
||||
}
|
||||
|
||||
onImageLoaded: {
|
||||
Object.keys(imageLoaders).forEach((key) => {
|
||||
if(isImageLoaded(key)) {
|
||||
// Calling callback
|
||||
imageLoaders[key][0](canvas, ctx, imageLoaders[key][1])
|
||||
delete imageLoaders[key]
|
||||
}
|
||||
}
|
||||
ctx.lineWidth = 1
|
||||
drawLabels(ctx)
|
||||
|
||||
}
|
||||
|
||||
function reset(ctx){
|
||||
// Reset
|
||||
ctx.fillStyle = "#FFFFFF"
|
||||
ctx.strokeStyle = "#000000"
|
||||
ctx.font = `${canvas.textsize-2}px sans-serif`
|
||||
ctx.fillRect(0,0,width,height)
|
||||
}
|
||||
|
||||
// Drawing the log based graph
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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+2}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-2}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"
|
||||
}
|
||||
|
||||
function drawXLine(ctx, x) {
|
||||
if(visible(x, ymax)) {
|
||||
drawLine(ctx, x2px(x), 0, x2px(x), canvasSize.height)
|
||||
}
|
||||
}
|
||||
|
||||
function drawYLine(ctx, y) {
|
||||
if(visible(xmin, y)) {
|
||||
drawLine(ctx, 0, y2px(y), canvasSize.width, y2px(y))
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Method to calculate multi-line string dimensions
|
||||
function measureText(ctx, text) {
|
||||
var theight = 0
|
||||
var twidth = 0
|
||||
text.split("\n").forEach(function(txt, i){
|
||||
theight += canvas.textsize
|
||||
if(ctx.measureText(txt).width > twidth) twidth = ctx.measureText(txt).width
|
||||
})
|
||||
return {'width': twidth, 'height': theight}
|
||||
}
|
||||
|
||||
// Converts x coordinate to it's relative position on the canvas
|
||||
function x2px(x) {
|
||||
if(logscalex) {
|
||||
var logxmin = Math.log(xmin)
|
||||
return (Math.log(x)-logxmin)*xzoom
|
||||
} else return (x - xmin)*xzoom
|
||||
}
|
||||
// Converts y coordinate to it's relative position on the canvas
|
||||
// Y is NOT ln based.
|
||||
function y2px(y) {
|
||||
return (ymax-y)*yzoom
|
||||
}
|
||||
// Reverse functions
|
||||
function px2x(px) {
|
||||
if(logscalex) {
|
||||
return Math.exp(px/xzoom+Math.log(xmin))
|
||||
} else return (px/xzoom+xmin)
|
||||
}
|
||||
function px2y(px) {
|
||||
return -(px/yzoom-ymax)
|
||||
}
|
||||
// Checks whether a point is visible or not.
|
||||
function visible(x, y) {
|
||||
return (x2px(x) >= 0 && x2px(x) <= canvasSize.width) && (y2px(y) >= 0 && y2px(y) <= canvasSize.height)
|
||||
}
|
||||
// Draws a line from a (x1, y1) to (x2, y2)
|
||||
function drawLine(ctx, x1, y1, x2, y2) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x1, y1);
|
||||
ctx.lineTo(x2, y2);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
function drawDashedLine2(ctx, x1, y1, x2, y2, dashPxSize = 5) {
|
||||
ctx.setLineDash([dashPxSize, dashPxSize]);
|
||||
drawLine(ctx, x1, y1, x2, y2)
|
||||
ctx.setLineDash([]);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
|
@ -16,18 +16,26 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQml 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQml
|
||||
import QtQuick.Controls
|
||||
import eu.ad5001.MixedMenu 1.1
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick 2.12
|
||||
// Auto loading all objects.
|
||||
import "js/objs/autoload.js" as ALObjects
|
||||
import QtQuick
|
||||
|
||||
import "js/objects.js" as Objects
|
||||
// Auto loading all modules.
|
||||
import "js/autoload.mjs" as ModulesAutoload
|
||||
|
||||
import eu.ad5001.LogarithmPlotter.History 1.0
|
||||
import eu.ad5001.LogarithmPlotter.ObjectLists 1.0
|
||||
import eu.ad5001.LogarithmPlotter.Popup 1.0 as Popup
|
||||
|
||||
/*!
|
||||
\qmltype LogarithmPlotter
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter
|
||||
\brief Main window of LogarithmPlotter
|
||||
|
||||
\sa AppMenuBar, History, GreetScreen, Changelog, Alert, ObjectLists, Settings, HistoryBrowser, LogGraphCanvas, PickLocationOverlay.
|
||||
*/
|
||||
ApplicationWindow {
|
||||
id: root
|
||||
visible: true
|
||||
|
@ -39,33 +47,39 @@ ApplicationWindow {
|
|||
SystemPalette { id: sysPalette; colorGroup: SystemPalette.Active }
|
||||
SystemPalette { id: sysPaletteIn; colorGroup: SystemPalette.Disabled }
|
||||
|
||||
|
||||
menuBar: appMenu.trueItem
|
||||
|
||||
GreetScreen {}
|
||||
|
||||
AppMenuBar {id: appMenu}
|
||||
|
||||
History { id: history }
|
||||
|
||||
About {id: about}
|
||||
Popup.GreetScreen {}
|
||||
|
||||
Alert {
|
||||
Popup.Preferences {id: preferences}
|
||||
|
||||
Popup.Changelog {id: changelog}
|
||||
|
||||
Popup.About {id: about}
|
||||
|
||||
Popup.ThanksTo {id: thanksTo}
|
||||
|
||||
Popup.Alert {
|
||||
id: alert
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 5
|
||||
z: 3
|
||||
}
|
||||
|
||||
Drawer {
|
||||
Item {
|
||||
id: sidebar
|
||||
width: 300
|
||||
height: parent.height
|
||||
y: root.menuBar.height
|
||||
//y: root.menuBar.height
|
||||
readonly property bool inPortrait: root.width < root.height
|
||||
modal: inPortrait
|
||||
/*modal: true// inPortrait
|
||||
interactive: inPortrait
|
||||
position: inPortrait ? 0 : 1
|
||||
*/
|
||||
visible: !inPortrait
|
||||
|
||||
|
||||
|
@ -100,7 +114,7 @@ ApplicationWindow {
|
|||
anchors.topMargin: 5
|
||||
anchors.leftMargin: 5
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: sidebarSelector.height
|
||||
//anchors.bottomMargin: sidebarSelector.height
|
||||
width: parent.width - 5
|
||||
currentIndex: sidebarSelector.currentIndex
|
||||
z: -1
|
||||
|
@ -128,15 +142,15 @@ ApplicationWindow {
|
|||
anchors.top: parent.top
|
||||
anchors.left: sidebar.inPortrait ? parent.left : sidebar.right
|
||||
height: parent.height
|
||||
width: sidebar.inPortrait ? parent.width : parent.width - sidebar.position*sidebar.width
|
||||
x: sidebar.position*sidebar.width
|
||||
width: sidebar.inPortrait ? parent.width : parent.width - sidebar.width//*sidebar.position
|
||||
x: sidebar.width//*sidebar.position
|
||||
|
||||
xmin: settings.xmin
|
||||
ymax: settings.ymax
|
||||
xzoom: settings.xzoom
|
||||
yzoom: settings.yzoom
|
||||
xlabel: settings.xaxislabel
|
||||
ylabel: settings.yaxislabel
|
||||
xlabel: settings.xlabel
|
||||
ylabel: settings.ylabel
|
||||
yaxisstep: settings.yaxisstep
|
||||
xaxisstep: settings.xaxisstep
|
||||
logscalex: settings.logscalex
|
||||
|
@ -147,7 +161,7 @@ ApplicationWindow {
|
|||
|
||||
property bool firstDrawDone: false
|
||||
|
||||
onPainted: if(!firstDrawDone) {
|
||||
onPainted: if(!firstDrawDone) {
|
||||
firstDrawDone = true;
|
||||
console.info("First paint done in " + (new Date().getTime()-(StartTime*1000)) + "ms")
|
||||
if(TestBuild == true) {
|
||||
|
@ -156,6 +170,13 @@ ApplicationWindow {
|
|||
}
|
||||
}
|
||||
|
||||
ViewPositionChangeOverlay {
|
||||
id: viewPositionChanger
|
||||
anchors.fill: parent
|
||||
canvas: parent
|
||||
settingsInstance: settings
|
||||
}
|
||||
|
||||
PickLocationOverlay {
|
||||
id: positionPicker
|
||||
anchors.fill: parent
|
||||
|
@ -163,109 +184,6 @@ ApplicationWindow {
|
|||
}
|
||||
}
|
||||
|
||||
function saveDiagram(filename) {
|
||||
if(['lpf'].indexOf(filename.split('.')[filename.split('.').length-1]) == -1)
|
||||
filename += '.lpf'
|
||||
settings.saveFilename = filename
|
||||
var objs = {}
|
||||
for(var objType in Objects.currentObjects){
|
||||
objs[objType] = []
|
||||
for(var obj of Objects.currentObjects[objType]) {
|
||||
objs[objType].push(obj.export())
|
||||
}
|
||||
}
|
||||
Helper.write(filename, JSON.stringify({
|
||||
"xzoom": settings.xzoom,
|
||||
"yzoom": settings.yzoom,
|
||||
"xmin": settings.xmin,
|
||||
"ymax": settings.ymax,
|
||||
"xaxisstep": settings.xaxisstep,
|
||||
"yaxisstep": settings.yaxisstep,
|
||||
"xaxislabel": settings.xaxislabel,
|
||||
"yaxislabel": settings.yaxislabel,
|
||||
"logscalex": settings.logscalex,
|
||||
"linewidth": settings.linewidth,
|
||||
"showxgrad": settings.showxgrad,
|
||||
"showygrad": settings.showygrad,
|
||||
"textsize": settings.textsize,
|
||||
"history": history.serialize(),
|
||||
"width": root.width,
|
||||
"height": root.height,
|
||||
"objects": objs,
|
||||
"type": "logplotv1"
|
||||
}))
|
||||
alert.show(qsTr("Saved plot to '%1'.").arg(filename.split("/").pop()))
|
||||
history.saved = true
|
||||
}
|
||||
|
||||
function loadDiagram(filename) {
|
||||
let basename = filename.split("/").pop()
|
||||
alert.show(qsTr("Loading file '%1'.").arg(basename))
|
||||
let data = JSON.parse(Helper.load(filename))
|
||||
let error = "";
|
||||
if(Object.keys(data).includes("type") && data["type"] == "logplotv1") {
|
||||
history.clear()
|
||||
// Importing settings
|
||||
settings.saveFilename = filename
|
||||
settings.xzoom = data["xzoom"]
|
||||
settings.yzoom = data["yzoom"]
|
||||
settings.xmin = data["xmin"]
|
||||
settings.ymax = data["ymax"]
|
||||
settings.xaxisstep = data["xaxisstep"]
|
||||
settings.yaxisstep = data["yaxisstep"]
|
||||
settings.xaxislabel = data["xaxislabel"]
|
||||
settings.yaxislabel = data["yaxislabel"]
|
||||
settings.logscalex = data["logscalex"]
|
||||
if("showxgrad" in data)
|
||||
settings.showxgrad = data["showxgrad"]
|
||||
if("showygrad" in data)
|
||||
settings.textsize = data["showygrad"]
|
||||
if("linewidth" in data)
|
||||
settings.linewidth = data["linewidth"]
|
||||
if("textsize" in data)
|
||||
settings.textsize = data["textsize"]
|
||||
if("history" in data)
|
||||
history.unserialize(...data["history"])
|
||||
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";
|
||||
}
|
||||
}
|
||||
// Refreshing sidebar
|
||||
if(sidebarSelector.currentIndex == 0) {
|
||||
// For some reason, if we load a file while the tab is on object,
|
||||
// we get stuck in a Qt-side loop? Qt bug or side-effect here, I don't know.
|
||||
sidebarSelector.currentIndex = 1
|
||||
objectLists.update()
|
||||
delayRefreshTimer.start()
|
||||
} else {
|
||||
objectLists.update()
|
||||
}
|
||||
} else {
|
||||
error = qsTr("Invalid file provided.")
|
||||
}
|
||||
if(error != "") {
|
||||
console.log(error)
|
||||
alert.show(qsTr("Could not save file: ") + error)
|
||||
// TODO: Error handling
|
||||
return
|
||||
}
|
||||
drawCanvas.requestPaint()
|
||||
alert.show(qsTr("Loaded file '%1'.").arg(basename))
|
||||
history.saved = true
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: delayRefreshTimer
|
||||
repeat: false
|
||||
|
@ -280,13 +198,33 @@ ApplicationWindow {
|
|||
onTriggered: Qt.quit() // Quit after paint on test build
|
||||
}
|
||||
|
||||
onClosing: {
|
||||
onClosing: function(close) {
|
||||
if(!history.saved) {
|
||||
close.accepted = false
|
||||
appMenu.showSaveUnsavedChangesDialog()
|
||||
appMenu.openSaveUnsavedChangesDialog()
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\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()
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod void LogarithmPlotter::copyDiagramToClipboard()
|
||||
Copies the current diagram image to the clipboard.
|
||||
*/
|
||||
function copyDiagramToClipboard() {
|
||||
var file = Helper.gettmpfile()
|
||||
drawCanvas.save(file)
|
||||
|
@ -294,6 +232,10 @@ ApplicationWindow {
|
|||
alert.show(qsTr("Copied plot screenshot to clipboard!"))
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod void LogarithmPlotter::showAlert(string alertText)
|
||||
Shows an alert on the diagram.
|
||||
*/
|
||||
function showAlert(alertText) {
|
||||
// This function is called from the backend and is used to show alerts from there.
|
||||
alert.show(alertText)
|
||||
|
@ -306,10 +248,14 @@ ApplicationWindow {
|
|||
Action {
|
||||
text: qsTr("&Update LogarithmPlotter")
|
||||
icon.name: 'update'
|
||||
onTriggered: Helper.openUrl("https://dev.apps.ad5001.eu/logarithmplotter")
|
||||
onTriggered: Qt.openUrlExternally("https://apps.ad5001.eu/logarithmplotter/")
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod void LogarithmPlotter::showUpdateMenu()
|
||||
Shows the update menu in the AppMenuBar.
|
||||
*/
|
||||
function showUpdateMenu() {
|
||||
appMenu.addMenu(updateMenu)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,342 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
import QtQuick.Controls
|
||||
import Qt.labs.platform as Native
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
import "../../js/history/index.mjs" as HistoryLib
|
||||
import "../../js/utils.mjs" as Utils
|
||||
import "../../js/math/index.mjs" as MathLib
|
||||
|
||||
/*!
|
||||
\qmltype CustomPropertyList
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.ObjectLists.Editor
|
||||
\brief Lists all custom properties editors inside a repeater and allow for edition.
|
||||
|
||||
This class repeats all of the custom properties and loads the appropriate editor for each kind of property.
|
||||
|
||||
\sa Dialog
|
||||
*/
|
||||
Repeater {
|
||||
id: root
|
||||
|
||||
signal changed()
|
||||
|
||||
/*!
|
||||
\qmlproperty var CustomPropertyList::obj
|
||||
Object whose properties to list and edit.
|
||||
*/
|
||||
property var obj
|
||||
/*!
|
||||
\qmlproperty var CustomPropertyList::positionPicker
|
||||
Reference to the global PositionPicker QML object.
|
||||
*/
|
||||
property var positionPicker
|
||||
|
||||
readonly property var textTypes: ['Domain', 'string', 'number', 'int']
|
||||
readonly property var comboBoxTypes: ['ObjectType', 'Enum']
|
||||
readonly property var listTypes: ['List', 'Dict']
|
||||
|
||||
|
||||
// NOTE: All components have the declared properties 'propertyLabel', 'propertyIcon', propertyName' and 'propertyType' to access the object in question.
|
||||
Component {
|
||||
id: commentComponent
|
||||
|
||||
// Item for comments.
|
||||
// NOTE: propertyType here is the content of the comment (yes, it's a bit backwards, but it's more clear on the properties side).
|
||||
Label {
|
||||
// Translated text with object name.
|
||||
property string trText: qsTranslate('comment', propertyType).toString()
|
||||
text: (trText.includes("%1") ? trText.arg(obj.name) : trText).toString()
|
||||
//color: sysPalette.windowText
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: expressionEditorComponent
|
||||
|
||||
// Setting for expressions
|
||||
Setting.ExpressionEditor {
|
||||
height: 30
|
||||
label: propertyLabel
|
||||
icon: `settings/custom/${propertyIcon}.svg`
|
||||
defValue: Utils.simplifyExpression(obj[propertyName].toEditableString())
|
||||
self: obj.name
|
||||
variables: propertyType.variables
|
||||
onChanged: function(newExpr) {
|
||||
if(obj[propertyName].toString() != newExpr.toString()) {
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
obj.name, objType, propertyName,
|
||||
obj[propertyName], newExpr
|
||||
))
|
||||
obj[propertyName] = newExpr
|
||||
root.changed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Component {
|
||||
id: textEditorComponent
|
||||
|
||||
// Setting for text & number settings as well as domains
|
||||
Setting.TextSetting {
|
||||
height: 30
|
||||
label: propertyLabel
|
||||
icon: `settings/custom/${propertyIcon}.svg`
|
||||
min: propertyType == "int" ? 0 : -Infinity
|
||||
isInt: propertyType == "int"
|
||||
isDouble: propertyType == "number"
|
||||
defValue: obj[propertyName] == null ? '' : obj[propertyName].toString()
|
||||
category: {
|
||||
return {
|
||||
"Domain": "domain",
|
||||
"string": "all",
|
||||
"number": "all",
|
||||
"int": "all",
|
||||
}[propertyType]
|
||||
}
|
||||
onChanged: function(newValue) {
|
||||
try {
|
||||
var newValueParsed = {
|
||||
"Domain": () => MathLib.parseDomain(newValue),
|
||||
"string": () => newValue,
|
||||
"number": () => newValue,
|
||||
"int": () => newValue
|
||||
}[propertyType]()
|
||||
|
||||
// Ensuring old and new values are different to prevent useless adding to history.
|
||||
if(obj[propertyName] != newValueParsed) {
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
obj.name, objType, propertyName,
|
||||
obj[propertyName], newValueParsed
|
||||
))
|
||||
obj[propertyName] = newValueParsed
|
||||
root.changed()
|
||||
}
|
||||
} catch(e) {
|
||||
// Error in expression or domain
|
||||
console.trace()
|
||||
parsingErrorDialog.showDialog(propertyName, newValue, e.message)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Native.MessageDialog {
|
||||
id: parsingErrorDialog
|
||||
title: qsTranslate("expression", "LogarithmPlotter - Parsing error")
|
||||
text: ""
|
||||
function showDialog(propName, propValue, error) {
|
||||
text = qsTranslate("error", "Error while parsing expression for property %1:\n%2\n\nEvaluated expression: %3")
|
||||
.arg(qsTranslate('prop', propName))
|
||||
.arg(error).arg(propValue)
|
||||
open()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: checkboxComponent
|
||||
|
||||
// Setting for boolean
|
||||
CheckBox {
|
||||
height: 20
|
||||
text: propertyLabel
|
||||
//icon: `settings/custom/${propertyIcon}.svg`
|
||||
|
||||
checked: {
|
||||
//if(obj[propertyName] == null) {
|
||||
// return false
|
||||
//}
|
||||
return obj[propertyName]
|
||||
}
|
||||
onClicked: {
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
obj.name, objType, propertyName,
|
||||
obj[propertyName], this.checked
|
||||
))
|
||||
obj[propertyName] = this.checked
|
||||
root.changed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: comboBoxComponent
|
||||
|
||||
// Setting when selecting data from an enum, or an object of a certain type.
|
||||
Setting.ComboBoxSetting {
|
||||
height: 30
|
||||
label: propertyLabel
|
||||
icon: `settings/custom/${propertyIcon}.svg`
|
||||
// True to select an object of type, false for enums.
|
||||
property bool selectObjMode: paramTypeIn(propertyType, ['ObjectType'])
|
||||
property bool isRealObject: !selectObjMode || (propertyType.objType != "ExecutableObject" && propertyType.objType != "DrawableObject")
|
||||
|
||||
// Base, untranslated version of the model.
|
||||
property var baseModel: selectObjMode ?
|
||||
Modules.Objects.getObjectsName(propertyType.objType).concat(
|
||||
isRealObject ? [qsTr("+ Create new %1").arg(Modules.Objects.types[propertyType.objType].displayType())] : [])
|
||||
: propertyType.values
|
||||
// Translated version of the model.
|
||||
model: selectObjMode ? baseModel : propertyType.translatedValues
|
||||
currentIndex: baseModel.indexOf(selectObjMode ? obj[propertyName].name : obj[propertyName])
|
||||
|
||||
onActivated: function(newIndex) {
|
||||
if(selectObjMode) {
|
||||
// This is only done when what we're selecting are Objects.
|
||||
// Setting object property.
|
||||
var selectedObj = Modules.Objects.currentObjectsByName[baseModel[newIndex]]
|
||||
if(newIndex != 0) {
|
||||
// Make sure we don't set the object to null.
|
||||
if(selectedObj == null) {
|
||||
// Creating new object.
|
||||
selectedObj = Modules.Objects.createNewRegisteredObject(propertyType.objType)
|
||||
history.addToHistory(new HistoryLib.CreateNewObject(selectedObj.name, propertyType.objType, selectedObj.export()))
|
||||
baseModel = Modules.Objects.getObjectsName(propertyType.objType).concat(
|
||||
isRealObject ? [qsTr("+ Create new %1").arg(Modules.Objects.types[propertyType.objType].displayType())] :
|
||||
[])
|
||||
currentIndex = baseModel.indexOf(selectedObj.name)
|
||||
}
|
||||
selectedObj.requiredBy.push(Modules.Objects.currentObjects[objType][objIndex])
|
||||
//Modules.Objects.currentObjects[objType][objIndex].requiredBy = obj[propertyName].filter((obj) => obj.name != obj.name)
|
||||
}
|
||||
obj.requiredBy = obj.requiredBy.filter((obj) => obj.name != obj.name)
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
obj.name, objType, propertyName,
|
||||
obj[propertyName], selectedObj
|
||||
))
|
||||
obj[propertyName] = selectedObj
|
||||
} else if(baseModel[newIndex] != obj[propertyName]) {
|
||||
// Ensuring new property is different to not add useless history entries.
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
obj.name, objType, propertyName,
|
||||
obj[propertyName], baseModel[newIndex]
|
||||
))
|
||||
obj[propertyName] = baseModel[newIndex]
|
||||
}
|
||||
// Refreshing
|
||||
root.changed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
// Setting to edit lists or dictionaries (e.g sequences & repartition function values)
|
||||
id: listDictEditorComponent
|
||||
|
||||
Setting.ListSetting {
|
||||
label: propertyLabel
|
||||
//icon: `settings/custom/${propertyIcon}.svg`
|
||||
dictionaryMode: paramTypeIn(propertyType, ['Dict'])
|
||||
keyType: dictionaryMode ? propertyType.keyType : 'string'
|
||||
valueType: propertyType.valueType
|
||||
preKeyLabel: (dictionaryMode ? propertyType.preKeyLabel : propertyType.label).replace(/\{name\}/g, obj.name).replace(/\{name_\}/g, obj.name.substring(obj.name.indexOf("_")+1))
|
||||
postKeyLabel: (dictionaryMode ? propertyType.postKeyLabel : '').replace(/\{name\}/g, obj.name).replace(/\{name_\}/g, obj.name.substring(obj.name.indexOf("_")+1))
|
||||
keyRegexp: dictionaryMode ? propertyType.keyFormat : /^.+$/
|
||||
valueRegexp: propertyType.format
|
||||
forbidAdding: propertyType.forbidAdding
|
||||
|
||||
onChanged: {
|
||||
var exported = exportModel()
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
obj.name, objType, propertyName,
|
||||
obj[propertyName], exported
|
||||
))
|
||||
//Modules.Objects.currentObjects[objType][objIndex][propertyName] = exported
|
||||
obj[propertyName] = exported
|
||||
root.changed()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
importModel(obj[propertyName])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Component {
|
||||
Row {
|
||||
width: dlgProperties.width
|
||||
spacing: 5
|
||||
|
||||
Loader {
|
||||
id: propertyEditor
|
||||
width: dlgProperties.width - pointerButton.width
|
||||
property string propertyName: modelData[0]
|
||||
property var propertyType: modelData[1]
|
||||
property string propertyLabel: qsTranslate('prop',propertyName)
|
||||
property string propertyIcon: Utils.camelCase2readable(propertyName)
|
||||
|
||||
sourceComponent: {
|
||||
if(propertyName.startsWith('comment'))
|
||||
return commentComponent
|
||||
else if(propertyType == 'boolean')
|
||||
return checkboxComponent
|
||||
else if(paramTypeIn(propertyType, ['Expression']))
|
||||
return expressionEditorComponent
|
||||
else if(paramTypeIn(propertyType, textTypes))
|
||||
return textEditorComponent
|
||||
else if(paramTypeIn(propertyType, comboBoxTypes))
|
||||
return comboBoxComponent
|
||||
else if(paramTypeIn(propertyType, listTypes))
|
||||
return listDictEditorComponent
|
||||
else
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: pointerButton
|
||||
height: parent.height
|
||||
width: visible ? height : 0
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
property bool isXProp: ['labelX', 'x'].includes(propertyEditor.propertyName)
|
||||
property bool isYProp: ['y'].includes(propertyEditor.propertyName)
|
||||
visible: isXProp || isYProp
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: qsTr("Pick on graph")
|
||||
|
||||
Setting.Icon {
|
||||
id: icon
|
||||
width: 18
|
||||
height: 18
|
||||
anchors.centerIn: parent
|
||||
|
||||
color: sysPalette.windowText
|
||||
source: '../icons/common/position.svg'
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
positionPicker.objType = objType
|
||||
positionPicker.objName = obj.name
|
||||
positionPicker.pickX = isXProp
|
||||
positionPicker.pickY = isYProp
|
||||
positionPicker.propertyX = propertyEditor.propertyName
|
||||
positionPicker.propertyY = propertyEditor.propertyName
|
||||
positionPicker.visible = true
|
||||
objEditor.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Dialogs as D
|
||||
import Qt.labs.platform as Native
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
import eu.ad5001.LogarithmPlotter.Popup 1.0 as Popup
|
||||
import "../../js/history/index.mjs" as HistoryLib
|
||||
import "../../js/utils.mjs" as Utils
|
||||
import "../../js/math/index.mjs" as MathLib
|
||||
|
||||
/*!
|
||||
\qmltype Dialog
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.ObjectLists.Editor
|
||||
\brief Dialog used to edit properties of objects.
|
||||
|
||||
This class contains the dialog that allows to edit all properties of objects.
|
||||
\todo In the future, this class should be optimized so that each property doesn't instanciate one instance of each setting type.
|
||||
|
||||
\sa Loader, ObjectLists
|
||||
*/
|
||||
Popup.BaseDialog {
|
||||
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: Modules.Objects.currentObjects[objType][objIndex]
|
||||
/*!
|
||||
\qmlproperty var EditorDialog::posPicker
|
||||
Reference to the global PositionPicker QML object.
|
||||
*/
|
||||
property var posPicker
|
||||
|
||||
title: "LogarithmPlotter"
|
||||
width: 350
|
||||
minimumHeight: Math.max(450,dlgProperties.height + margin*4 + 30)
|
||||
maximumHeight: minimumHeight
|
||||
|
||||
Item {
|
||||
anchors {
|
||||
top: parent.top;
|
||||
left: parent.left;
|
||||
bottom: parent.bottom;
|
||||
right: parent.right;
|
||||
topMargin: margin;
|
||||
leftMargin: margin;
|
||||
bottomMargin: margin + 30;
|
||||
rightMargin: margin;
|
||||
}
|
||||
|
||||
Column {
|
||||
id: dlgProperties
|
||||
anchors.top: parent.top
|
||||
width: objEditor.width - 20
|
||||
spacing: 10
|
||||
|
||||
Label {
|
||||
id: dlgTitle
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
text: qsTr("Edit properties of %1 %2").arg(Modules.Objects.types[objEditor.objType].displayType()).arg(objEditor.obj.name)
|
||||
font.pixelSize: 20
|
||||
color: sysPalette.windowText
|
||||
}
|
||||
|
||||
Native.MessageDialog {
|
||||
id: invalidNameDialog
|
||||
title: qsTr("LogarithmPlotter - Invalid object name")
|
||||
text: ""
|
||||
function showDialog(objectName) {
|
||||
text = qsTr("An object with the name '%1' already exists.").arg(objectName)
|
||||
open()
|
||||
}
|
||||
}
|
||||
|
||||
Setting.TextSetting {
|
||||
id: nameProperty
|
||||
height: 30
|
||||
label: qsTr("Name")
|
||||
icon: "common/label.svg"
|
||||
category: "name"
|
||||
width: dlgProperties.width
|
||||
value: objEditor.obj.name
|
||||
onChanged: function(newValue) {
|
||||
let newName = Utils.parseName(newValue)
|
||||
if(newName != '' && objEditor.obj.name != newName) {
|
||||
if(newName in Modules.Objects.currentObjectsByName) {
|
||||
invalidNameDialog.showDialog(newName)
|
||||
} else {
|
||||
history.addToHistory(new HistoryLib.NameChanged(
|
||||
objEditor.obj.name, objEditor.objType, newName
|
||||
))
|
||||
Modules.Objects.renameObject(obj.name, newName)
|
||||
objEditor.obj = Modules.Objects.currentObjects[objEditor.objType][objEditor.objIndex]
|
||||
objectListList.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Setting.ComboBoxSetting {
|
||||
id: labelContentProperty
|
||||
height: 30
|
||||
width: dlgProperties.width
|
||||
label: qsTr("Label content")
|
||||
model: [qsTr("null"), qsTr("name"), qsTr("name + value")]
|
||||
property var idModel: ["null", "name", "name + value"]
|
||||
icon: "common/label.svg"
|
||||
currentIndex: idModel.indexOf(objEditor.obj.labelContent)
|
||||
onActivated: function(newIndex) {
|
||||
if(idModel[newIndex] != objEditor.obj.labelContent) {
|
||||
objEditor.obj.labelContent = idModel[newIndex]
|
||||
objEditor.obj.update()
|
||||
objectListList.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic properties
|
||||
CustomPropertyList {
|
||||
id: dlgCustomProperties
|
||||
obj: objEditor.obj
|
||||
positionPicker: posPicker
|
||||
|
||||
onChanged: {
|
||||
obj.update()
|
||||
objectListList.update()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod void EditorDialog::open()
|
||||
Shows the editor after the object to be edited is set.
|
||||
*/
|
||||
function open() {
|
||||
dlgCustomProperties.model = [] // Reset
|
||||
let objProps = Modules.Objects.types[objEditor.objType].properties()
|
||||
dlgCustomProperties.model = Object.keys(objProps).map(prop => [prop, objProps[prop]]) // Converted to 2-dimentional array.
|
||||
objEditor.show()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
module eu.ad5001.LogarithmPlotter.ObjectLists.Editor
|
||||
|
||||
Dialog 1.0 Dialog.qml
|
||||
CustomPropertyList 1.0 CustomPropertyList.qml
|
||||
|
|
@ -1,270 +0,0 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Dialogs 1.3 as D
|
||||
import eu.ad5001.LogarithmPlotter 1.0
|
||||
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
|
||||
|
||||
D.Dialog {
|
||||
id: objEditor
|
||||
property string objType: 'Point'
|
||||
property int objIndex: 0
|
||||
property var obj: Objects.currentObjects[objType][objIndex]
|
||||
property QtObject editingRow: QtObject{}
|
||||
property var objectLists
|
||||
title: `LogarithmPlotter`
|
||||
width: 300
|
||||
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
|
||||
|
||||
TextSetting {
|
||||
id: nameProperty
|
||||
height: 30
|
||||
label: qsTr("Name")
|
||||
icon: "icons/settings/custom/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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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: "icons/settings/custom/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: Utils.camelCase2readable(modelData[0])
|
||||
|
||||
// Item for comments
|
||||
Label {
|
||||
id: customPropComment
|
||||
width: parent.width
|
||||
height: visible ? implicitHeight : 0
|
||||
visible: modelData[0].startsWith('comment')
|
||||
text: visible ? (modelData[1].replace(/\{name\}/g, objEditor.obj.name)) : ''
|
||||
//color: sysPalette.windowText
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
// Setting for text & number settings as well as domains & expressions
|
||||
TextSetting {
|
||||
id: customPropText
|
||||
height: visible ? 30 : 0
|
||||
width: parent.width
|
||||
label: parent.label
|
||||
icon: `icons/settings/custom/${parent.label}.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 ? `icons/settings/custom/${parent.label}.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.
|
||||
ComboBoxSetting {
|
||||
id: customPropCombo
|
||||
width: dlgProperties.width
|
||||
height: visible ? 30 : 0
|
||||
label: parent.label
|
||||
icon: visible ? `icons/settings/custom/${parent.label}.svg` : ''
|
||||
// True to select an object of type, false for enums.
|
||||
property bool selectObjMode: paramTypeIn(modelData[1], ['ObjectType'])
|
||||
|
||||
property var baseModel: visible ?
|
||||
(selectObjMode ? Objects.getObjectsName(modelData[1].objType).concat([qsTr("+ Create new %1").arg(Objects.types[modelData[1].objType].displayType())]) : modelData[1].values)
|
||||
: []
|
||||
// Translate the model if necessary.
|
||||
model: selectObjMode ? baseModel : baseModel.map(x => qsTr(x))
|
||||
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(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([qsTr("+ Create new %1").arg(Objects.types[modelData[1].objType].displayType())])
|
||||
currentIndex = baseModel.indexOf(selectedObj.name)
|
||||
}
|
||||
//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)
|
||||
selectedObj.requiredBy.push(Objects.currentObjects[objEditor.objType][objEditor.objIndex])
|
||||
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)
|
||||
ListSetting {
|
||||
id: customPropListDict
|
||||
width: parent.width
|
||||
height: visible ? implicitHeight : 0
|
||||
|
||||
visible: paramTypeIn(modelData[1], ['List', 'Dict'])
|
||||
label: parent.label
|
||||
//icon: `icons/settings/custom/${parent.label}.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]])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function show() {
|
||||
dlgCustomProperties.model = [] // Reset
|
||||
var 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 repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
|
@ -16,15 +16,38 @@
|
|||
* 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/historylib.js" as HistoryLib
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import "../js/history/index.mjs" as HistoryLib
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
|
||||
|
||||
/*!
|
||||
\qmltype ObjectCreationGrid
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.ObjectLists
|
||||
\brief Grid with buttons to create objects.
|
||||
|
||||
\sa LogarithmPlotter, ObjectLists
|
||||
*/
|
||||
Column {
|
||||
id: createRow
|
||||
property var objectEditor
|
||||
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 {
|
||||
id: createTitle
|
||||
|
@ -37,30 +60,69 @@ Column {
|
|||
width: parent.width
|
||||
columns: 3
|
||||
Repeater {
|
||||
model: Object.keys(Objects.types)
|
||||
model: Object.keys(Modules.Objects.types)
|
||||
|
||||
Button {
|
||||
id: createBtn
|
||||
text: Objects.types[modelData].displayType()
|
||||
width: parent.width/3
|
||||
visible: Objects.types[modelData].createable()
|
||||
height: visible ? implicitHeight : 0
|
||||
display: AbstractButton.TextUnderIcon
|
||||
icon.name: modelData
|
||||
icon.source: '../icons/' + modelData + '.svg'
|
||||
icon.width: 24
|
||||
icon.height: 24
|
||||
icon.color: sysPalette.buttonText
|
||||
width: 96
|
||||
visible: Modules.Objects.types[modelData].createable()
|
||||
height: visible ? width*0.8 : 0
|
||||
// The KDE SDK is kinda buggy, so it respects neither specified color nor display propreties.
|
||||
//display: AbstractButton.TextUnderIcon
|
||||
|
||||
Setting.Icon {
|
||||
id: icon
|
||||
width: 24
|
||||
height: 24
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: (parent.width-width)/2
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: (label.y-height)/2
|
||||
|
||||
color: sysPalette.windowText
|
||||
source: '../icons/objects/'+modelData+'.svg'
|
||||
}
|
||||
|
||||
Label {
|
||||
id: label
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 5
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 4
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 4
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pixelSize: 14
|
||||
text: Modules.Objects.types[modelData].displayType()
|
||||
wrapMode: Text.WordWrap
|
||||
clip: true
|
||||
}
|
||||
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.delay: 200
|
||||
ToolTip.text: label.text
|
||||
|
||||
onClicked: {
|
||||
var newObj = Objects.createNewRegisteredObject(modelData)
|
||||
let newObj = Modules.Objects.createNewRegisteredObject(modelData)
|
||||
history.addToHistory(new HistoryLib.CreateNewObject(newObj.name, modelData, newObj.export()))
|
||||
objectLists.update()
|
||||
objectEditor.obj = Objects.currentObjects[modelData][Objects.currentObjects[modelData].length - 1]
|
||||
objectEditor.objType = modelData
|
||||
objectEditor.objIndex = Objects.currentObjects[modelData].length - 1
|
||||
objectEditor.editingRow = objectLists.listViews[modelData].editingRows[objectEditor.objIndex]
|
||||
objectEditor.show()
|
||||
|
||||
let hasXProp = newObj.constructor.properties().hasOwnProperty('x')
|
||||
let hasYProp = newObj.constructor.properties().hasOwnProperty('y')
|
||||
if(hasXProp || hasYProp) {
|
||||
// Open picker
|
||||
posPicker.objType = newObj.type
|
||||
posPicker.objName = newObj.name
|
||||
posPicker.pickX = hasXProp
|
||||
posPicker.pickY = hasYProp
|
||||
posPicker.propertyX = 'x'
|
||||
posPicker.propertyY = 'y'
|
||||
posPicker.visible = true
|
||||
posPicker.picked.connect(openEditorDialog)
|
||||
} else {
|
||||
// Open editor
|
||||
openEditorDialog(newObj)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
|
@ -16,219 +16,128 @@
|
|||
* 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 "../js/objects.js" as Objects
|
||||
import "../js/historylib.js" as HistoryLib
|
||||
import QtQuick
|
||||
// import QtQuick.Dialogs 1.3 as D
|
||||
import QtQuick.Controls
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
import eu.ad5001.LogarithmPlotter.ObjectLists.Editor 1.0 as Editor
|
||||
|
||||
/*!
|
||||
\qmltype ObjectLists
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.ObjectLists
|
||||
\brief Tab of the drawer that allows the user to manage the objects.
|
||||
|
||||
ListView {
|
||||
This item allows the user to synthetically 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 -_-
|
||||
|
||||
model: Object.keys(Objects.types)
|
||||
implicitHeight: contentItem.childrenRect.height + footer.height + 10
|
||||
|
||||
delegate: ListView {
|
||||
id: objTypeList
|
||||
property string objType: objectListList.model[index]
|
||||
property var editingRows: []
|
||||
model: Objects.currentObjects[objType]
|
||||
width: objectListList.width
|
||||
implicitHeight: contentItem.childrenRect.height
|
||||
visible: model != undefined && model.length > 0
|
||||
interactive: false
|
||||
ScrollBar.horizontal.visible: false
|
||||
ScrollBar.vertical.visible: true
|
||||
|
||||
Component.onCompleted: objectListList.listViews[objType] = objTypeList // Listing in order to be refreshed
|
||||
ListView {
|
||||
id: objectsListView
|
||||
model: Object.keys(Modules.Objects.types)
|
||||
//width: implicitWidth //objectListList.width - (implicitHeight > objectListList.parent.height ? 20 : 0)
|
||||
implicitHeight: contentItem.childrenRect.height + footerItem.height + 10
|
||||
|
||||
header: Row {
|
||||
width: typeHeaderText.width + typeVisibilityCheckBox.visible
|
||||
height: visible ? 20 : 0
|
||||
visible: objTypeList.visible
|
||||
delegate: ListView {
|
||||
id: objTypeList
|
||||
property string objType: objectsListView.model[index]
|
||||
property var editingRows: []
|
||||
model: Modules.Objects.currentObjects[objType]
|
||||
width: objectsListView.width
|
||||
implicitHeight: contentItem.childrenRect.height
|
||||
visible: model != undefined && model.length > 0
|
||||
interactive: false
|
||||
|
||||
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()
|
||||
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: Modules.Objects.currentObjects[objType] != undefined ? Modules.Objects.currentObjects[objType].every(obj => obj.visible) : true
|
||||
onClicked: {
|
||||
for(const obj of Modules.Objects.currentObjects[objType]) obj.visible = this.checked
|
||||
for(const obj of objTypeList.editingRows) obj.objVisible = this.checked
|
||||
objectListList.changed()
|
||||
}
|
||||
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: checked ?
|
||||
qsTr("Hide all %1").arg(Modules.Objects.types[objType].displayTypeMultiple()) :
|
||||
qsTr("Show all %1").arg(Modules.Objects.types[objType].displayTypeMultiple())
|
||||
}
|
||||
|
||||
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(Modules.Objects.types[objType].displayTypeMultiple())
|
||||
font.pixelSize: 20
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
id: typeHeaderText
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
text: Objects.types[objType].displayTypeMultiple() + ":"
|
||||
font.pixelSize: 20
|
||||
delegate: ObjectRow {
|
||||
id: controlRow
|
||||
width: objTypeList.width
|
||||
obj: Modules.Objects.currentObjects[objType][index]
|
||||
posPicker: positionPicker
|
||||
|
||||
onChanged: {
|
||||
obj = Modules.Objects.currentObjects[objType][index]
|
||||
objectListList.update()
|
||||
}
|
||||
|
||||
Component.onCompleted: objTypeList.editingRows.push(controlRow)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
icon.name: 'position'
|
||||
icon.source: '../icons/position.svg'
|
||||
icon.color: sysPalette.buttonText
|
||||
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/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.arg(obj.name)
|
||||
title: qsTr("Pick new color for %1 %2").arg(Objects.types[objType].displayType())
|
||||
onAccepted: {
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
obj.name, objType, "color",
|
||||
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
|
||||
posPicker: positionPicker
|
||||
}
|
||||
}
|
||||
|
||||
// Object editor
|
||||
EditorDialog {
|
||||
Editor.Dialog {
|
||||
id: objEditor
|
||||
objectLists: objectListList
|
||||
}
|
||||
|
||||
// Create items
|
||||
footer: ObjectCreationGrid {
|
||||
id: createRow
|
||||
width: parent.width
|
||||
objectEditor: objEditor
|
||||
objectLists: objectListList
|
||||
|
||||
posPicker: positionPicker
|
||||
}
|
||||
|
||||
/*!
|
||||
\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]
|
||||
objectListList.listViews[objType].model = Modules.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)
|
||||
|
|
|
@ -0,0 +1,240 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
import QtQuick.Dialogs
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Window
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
import "../js/history/index.mjs" as HistoryLib
|
||||
|
||||
|
||||
/*!
|
||||
\qmltype ObjectRow
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.ObjectLists
|
||||
\brief Row describing an object.
|
||||
|
||||
This item allows the user to see, control, and modify a graph object.
|
||||
It includes the visibility checkbox, the description label (optionally latex if enabled),
|
||||
the reposition and delete buttons, and the color picker.
|
||||
|
||||
\sa LogarithmPlotter, ObjectCreationGrid, ObjectLists
|
||||
*/
|
||||
Item {
|
||||
id: objectRow
|
||||
|
||||
signal changed()
|
||||
|
||||
/*!
|
||||
\qmlproperty var ObjectRow::obj
|
||||
Object to show.
|
||||
*/
|
||||
property var obj
|
||||
/*!
|
||||
\qmlproperty var ObjectRow::posPicker
|
||||
Reference to the global PositionPicker QML object.
|
||||
*/
|
||||
property var posPicker
|
||||
|
||||
/*!
|
||||
\qmlproperty bool ObjectRow::objVisible
|
||||
True if the object should be visible, false otherwise.
|
||||
*/
|
||||
property alias objVisible: objVisibilityCheckBox.checked
|
||||
/*!
|
||||
\qmlproperty bool ObjectRow::minHeight
|
||||
Minimum height of the row.
|
||||
*/
|
||||
readonly property int minHeight: 40
|
||||
|
||||
height: objDescription.height
|
||||
width: obj.typeList.width
|
||||
|
||||
CheckBox {
|
||||
id: objVisibilityCheckBox
|
||||
checked: obj.visible
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 5
|
||||
onClicked: {
|
||||
history.addToHistory(new HistoryLib.EditedVisibility(
|
||||
obj.name, obj.type, this.checked
|
||||
))
|
||||
obj.visible = this.checked
|
||||
changed()
|
||||
}
|
||||
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: checked ?
|
||||
qsTr("Hide %1 %2").arg(obj.constructor.displayType()).arg(obj.name) :
|
||||
qsTr("Show %1 %2").arg(obj.constructor.displayType()).arg(obj.name)
|
||||
}
|
||||
|
||||
Label {
|
||||
id: objDescription
|
||||
anchors.left: objVisibilityCheckBox.right
|
||||
anchors.right: deleteButton.left
|
||||
height: Modules.Latex.enabled ? Math.max(parent.minHeight, latexDescription.height+4) : parent.minHeight
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
text: Modules.Latex.enabled ? "" : obj.getReadableString()
|
||||
font.pixelSize: 14
|
||||
|
||||
Image {
|
||||
id: latexDescription
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
visible: Modules.Latex.enabled
|
||||
property double depth: Screen.devicePixelRatio
|
||||
source: ""
|
||||
width: 0/depth
|
||||
height: 0/depth
|
||||
|
||||
Component.onCompleted: function() {
|
||||
if(Modules.Latex.enabled) {
|
||||
const args = [obj.getLatexString(), depth*(parent.font.pixelSize+2), parent.color]
|
||||
const prerendered = Modules.Latex.findPrerendered(...args)
|
||||
if(prerendered !== null) {
|
||||
source = prerendered.source
|
||||
width = prerendered.width/depth
|
||||
height = prerendered.height/depth
|
||||
} else
|
||||
Modules.Latex.requestAsyncRender(...args).then(info => {
|
||||
source = info.source
|
||||
width = info.width/depth
|
||||
height = info.height/depth
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
objEditor.obj = Modules.Objects.currentObjects[obj.type][index]
|
||||
objEditor.objType = obj.type
|
||||
objEditor.objIndex = index
|
||||
//objEditor.editingRow = objectRow
|
||||
objEditor.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: pointerButton
|
||||
width: parent.height - 10
|
||||
height: width
|
||||
anchors.right: deleteButton.left
|
||||
anchors.rightMargin: 5
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
Setting.Icon {
|
||||
id: icon
|
||||
width: 18
|
||||
height: 18
|
||||
anchors.centerIn: parent
|
||||
|
||||
color: sysPalette.windowText
|
||||
source: '../icons/common/position.svg'
|
||||
}
|
||||
|
||||
property bool hasXProp: obj.constructor.properties().hasOwnProperty('x')
|
||||
property bool hasYProp: obj.constructor.properties().hasOwnProperty('y')
|
||||
visible: hasXProp || hasYProp
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: qsTr("Set %1 %2 position").arg(obj.constructor.displayType()).arg(obj.name)
|
||||
|
||||
onClicked: {
|
||||
posPicker.objType = obj.type
|
||||
posPicker.objName = obj.name
|
||||
posPicker.pickX = hasXProp
|
||||
posPicker.pickY = hasYProp
|
||||
posPicker.propertyX = 'x'
|
||||
posPicker.propertyY = 'y'
|
||||
posPicker.visible = true
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: deleteButton
|
||||
width: parent.minHeight - 10
|
||||
height: width
|
||||
anchors.right: colorPickRect.left
|
||||
anchors.rightMargin: 5
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
icon.name: 'delete'
|
||||
icon.source: '../icons/common/delete.svg'
|
||||
icon.color: sysPalette.buttonText
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: qsTr("Delete %1 %2").arg(obj.constructor.displayType()).arg(obj.name)
|
||||
|
||||
onClicked: {
|
||||
deleteRecursively(obj)
|
||||
changed()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: colorPickRect
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 5
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
color: obj.color
|
||||
width: parent.minHeight - 10
|
||||
height: width
|
||||
radius: Math.min(width, height)
|
||||
border.width: 2
|
||||
border.color: sysPalette.windowText
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: pickColor.open()
|
||||
}
|
||||
}
|
||||
|
||||
ColorDialog {
|
||||
id: pickColor
|
||||
selectedColor: obj.color
|
||||
title: qsTr("Pick new color for %1 %2").arg(obj.constructor.displayType()).arg(obj.name)
|
||||
onAccepted: {
|
||||
history.addToHistory(new HistoryLib.ColorChanged(
|
||||
obj.name, obj.type, obj.color, selectedColor.toString()
|
||||
))
|
||||
obj.color = selectedColor.toString()
|
||||
changed()
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod void ObjectRow::deleteRecursively(var object)
|
||||
Deletes an object and it's dependencies recursively.
|
||||
*/
|
||||
function deleteRecursively(object) {
|
||||
for(let toRemove of object.requiredBy)
|
||||
deleteRecursively(toRemove)
|
||||
if(Modules.Objects.currentObjectsByName[object.name] !== undefined) {
|
||||
// Object still exists
|
||||
// Temporary fix for objects require not being propertly updated.
|
||||
object.requiredBy = []
|
||||
history.addToHistory(new HistoryLib.DeleteObject(
|
||||
object.name, object.type, object.export()
|
||||
))
|
||||
Modules.Objects.deleteObject(object.name)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,5 +2,4 @@ module eu.ad5001.LogarithmPlotter.ObjectLists
|
|||
|
||||
ObjectLists 1.0 ObjectLists.qml
|
||||
ObjectCreationGrid 1.0 ObjectCreationGrid.qml
|
||||
EditorDialog 1.0 EditorDialog.qml
|
||||
|
||||
ObjectRow 1.0 ObjectRow.qml
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
|
@ -16,24 +16,86 @@
|
|||
* 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
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
import "js/math/index.mjs" as MathLib
|
||||
import "js/history/index.mjs" 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
|
||||
clip: true
|
||||
|
||||
/*!
|
||||
\qmlsignal PickLocationOverlay::picked(var obj)
|
||||
|
||||
Emitted when a location has been picked
|
||||
The corresponding handler is \c onPicked.
|
||||
*/
|
||||
signal picked(var obj)
|
||||
|
||||
/*!
|
||||
\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'
|
||||
property bool pickY: true
|
||||
/*!
|
||||
\qmlproperty bool PickLocationOverlay::pickX
|
||||
true if the property in propertyX is pickable.
|
||||
*/
|
||||
property bool pickX: true
|
||||
/*!
|
||||
\qmlproperty bool PickLocationOverlay::pickY
|
||||
true if the property in propertyY is pickable.
|
||||
*/
|
||||
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
|
||||
/*!
|
||||
\qmlproperty bool PickLocationOverlay::userPickX
|
||||
true if the user can and wants to be picking a position on the x axis.
|
||||
*/
|
||||
readonly property bool userPickX: pickX && pickXCheckbox.checked
|
||||
/*!
|
||||
\qmlproperty bool PickLocationOverlay::userPickY
|
||||
true if the user can and wants to be picking a position on the y axis.
|
||||
*/
|
||||
readonly property bool userPickY: pickY && pickYCheckbox.checked
|
||||
|
||||
Rectangle {
|
||||
color: sysPalette.window
|
||||
|
@ -47,66 +109,149 @@ Item {
|
|||
hoverEnabled: parent.visible
|
||||
cursorShape: Qt.CrossCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onClicked: {
|
||||
onClicked: function(mouse) {
|
||||
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
|
||||
let newValueX = !parent.userPickX ? null : parseValue(picked.mouseX.toString(), objType, propertyX)
|
||||
let newValueY = !parent.userPickY ? null : parseValue(picked.mouseY.toString(), objType, propertyY)
|
||||
let obj = Modules.Objects.currentObjectsByName[objName]
|
||||
// Set values
|
||||
if(parent.userPickX && parent.userPickY) {
|
||||
history.addToHistory(new HistoryLib.EditedPosition(
|
||||
objName, objType, obj[propertyX], newValueX, obj[propertyY], newValueY
|
||||
))
|
||||
obj[propertyX] = newValue
|
||||
obj[propertyX] = newValueX
|
||||
obj[propertyY] = newValueY
|
||||
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)
|
||||
pickerRoot.picked(obj)
|
||||
} else if(parent.userPickX) {
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
objName, objType, propertyY, obj[propertyY], newValue
|
||||
objName, objType, propertyX, obj[propertyX], newValueX
|
||||
))
|
||||
obj[propertyY] = newValue
|
||||
obj[propertyX] = newValueX
|
||||
obj.update()
|
||||
objectLists.update()
|
||||
pickerRoot.picked(obj)
|
||||
} else if(parent.userPickY) {
|
||||
history.addToHistory(new HistoryLib.EditedProperty(
|
||||
objName, objType, propertyY, obj[propertyY], newValueY
|
||||
))
|
||||
obj[propertyY] = newValueY
|
||||
obj.update()
|
||||
objectLists.update()
|
||||
pickerRoot.picked(obj)
|
||||
}
|
||||
}
|
||||
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)
|
||||
|
||||
Rectangle {
|
||||
id: pickerSettings
|
||||
radius: 15
|
||||
color: sysPalette.window
|
||||
width: pickerSettingsColumn.width + 30;
|
||||
height: pickerSettingsColumn.height + 20
|
||||
property bool folded: false;
|
||||
x: -15 - ((width-55) * folded);
|
||||
y: 10
|
||||
z: 2
|
||||
|
||||
Row {
|
||||
id: pickerSettingsColumn
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: parent.top
|
||||
leftMargin: 20
|
||||
topMargin: 10
|
||||
}
|
||||
}
|
||||
spacing: 15
|
||||
property int cellHeight: 15
|
||||
|
||||
CheckBox {
|
||||
id: snapToGridCheckbox
|
||||
text: qsTr("Snap to grid")
|
||||
checked: false
|
||||
Column {
|
||||
spacing: 5
|
||||
// width: 100
|
||||
|
||||
Text {
|
||||
text: qsTr("Pointer precision:")
|
||||
color: sysPalette.windowText
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
height: pickerSettingsColumn.cellHeight
|
||||
}
|
||||
|
||||
Text {
|
||||
text: qsTr("Snap to grid:")
|
||||
color: sysPalette.windowText
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
height: pickerSettingsColumn.cellHeight
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: pickXCheckbox
|
||||
height: pickerSettingsColumn.cellHeight
|
||||
text: qsTr("Pick X")
|
||||
checked: pickX
|
||||
visible: pickX
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: 5
|
||||
|
||||
Slider {
|
||||
id: precisionSlider
|
||||
from: 0
|
||||
value: 2
|
||||
to: 10
|
||||
stepSize: 1
|
||||
height: pickerSettingsColumn.cellHeight
|
||||
|
||||
ToolTip {
|
||||
parent: precisionSlider.handle
|
||||
visible: precisionSlider.pressed
|
||||
text: precisionSlider.value.toFixed(0)
|
||||
}
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: snapToGridCheckbox
|
||||
height: pickerSettingsColumn.cellHeight
|
||||
// text: qsTr("Snap to grid")
|
||||
checked: false
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: pickYCheckbox
|
||||
height: pickerSettingsColumn.cellHeight
|
||||
text: qsTr("Pick Y")
|
||||
checked: pickY
|
||||
visible: pickY
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
width: 24
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
flat: true
|
||||
|
||||
onClicked: pickerSettings.folded = !pickerSettings.folded
|
||||
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.delay: 200
|
||||
ToolTip.text: pickerSettings.folded ? qsTr("Open picker settings") : qsTr("Hide picker settings")
|
||||
|
||||
Setting.Icon {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 18
|
||||
height: 18
|
||||
color: sysPalette.windowText
|
||||
source: `../icons/common/settings.svg`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,8 +262,8 @@ Item {
|
|||
color: 'black'
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: canvas.x2px(picked.mouseX)
|
||||
visible: parent.pickX
|
||||
anchors.leftMargin: Modules.Canvas.x2px(picked.mouseX)
|
||||
visible: parent.userPickX
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
@ -128,47 +273,60 @@ Item {
|
|||
color: 'black'
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.topMargin: canvas.y2px(picked.mouseY)
|
||||
visible: parent.pickY
|
||||
anchors.topMargin: Modules.Canvas.y2px(picked.mouseY)
|
||||
visible: parent.userPickY
|
||||
}
|
||||
|
||||
Text {
|
||||
id: picked
|
||||
x: picker.mouseX - width - 5
|
||||
y: picker.mouseY - height - 5
|
||||
property double axisX: canvas.xaxisstep1
|
||||
color: 'black'
|
||||
property double mouseX: {
|
||||
let xpos = canvas.px2x(picker.mouseX)
|
||||
const axisX = Modules.Canvas.axesSteps.x.value
|
||||
const xpos = Modules.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)
|
||||
return axisX*Math.round(xpos/axisX)
|
||||
}
|
||||
} else {
|
||||
return xpos.toFixed(parent.precision)
|
||||
}
|
||||
}
|
||||
property double mouseY: {
|
||||
let ypos = canvas.px2y(picker.mouseY)
|
||||
const axisY = Modules.Canvas.axesSteps.y.value
|
||||
const ypos = Modules.Canvas.px2y(picker.mouseY)
|
||||
if(snapToGridCheckbox.checked) {
|
||||
return canvas.yaxisstep1*Math.round(ypos/canvas.yaxisstep1)
|
||||
return axisY*Math.round(ypos/axisY)
|
||||
} else {
|
||||
return ypos.toFixed(parent.precision)
|
||||
}
|
||||
}
|
||||
color: 'black'
|
||||
text: {
|
||||
if(parent.pickX && parent.pickY)
|
||||
if(parent.userPickX && parent.userPickY)
|
||||
return `(${mouseX}, ${mouseY})`
|
||||
if(parent.pickX)
|
||||
else if(parent.userPickX)
|
||||
return `X = ${mouseX}`
|
||||
if(parent.pickY)
|
||||
else if(parent.userPickY)
|
||||
return `Y = ${mouseY}`
|
||||
else
|
||||
return qsTr('(no pick selected)')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\qmlmethod void History::parseValue(string value, string objType, string propertyName)
|
||||
Parses a given \c value as an expression or a number depending on the type of \c propertyName of all \c objType.
|
||||
*/
|
||||
function parseValue(value, objType, propertyName) {
|
||||
if(Modules.Objects.types[objType].properties()[propertyName] == 'number')
|
||||
return parseFloat(value)
|
||||
else
|
||||
return new MathLib.Expression(value)
|
||||
}
|
||||
}
|
||||
|
|
137
LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Popup/About.qml
Normal file
|
@ -0,0 +1,137 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
import QtQuick.Controls
|
||||
|
||||
/*!
|
||||
\qmltype About
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.Popup
|
||||
\brief About popup of LogarithmPlotter.
|
||||
|
||||
\sa LogarithmPlotter
|
||||
*/
|
||||
BaseDialog {
|
||||
id: about
|
||||
title: qsTr("About LogarithmPlotter")
|
||||
width: 400
|
||||
minimumHeight: 600
|
||||
|
||||
Item {
|
||||
anchors {
|
||||
top: parent.top;
|
||||
left: parent.left;
|
||||
bottom: parent.bottom;
|
||||
right: parent.right;
|
||||
topMargin: margin;
|
||||
leftMargin: margin;
|
||||
bottomMargin: margin;
|
||||
rightMargin: margin;
|
||||
}
|
||||
|
||||
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 © 2021-2024 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 {
|
||||
id: buttonsRow
|
||||
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 repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
|
@ -16,8 +16,16 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick
|
||||
/*!
|
||||
\qmltype Alert
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.Popup
|
||||
\brief Alert used to show status messages to the user.
|
||||
|
||||
This class (only one instance) allows messages to be displayed to the user that will fade in time.
|
||||
|
||||
\sa LogarithmPlotter
|
||||
*/
|
||||
Rectangle {
|
||||
id: alert
|
||||
color: "black"
|
||||
|
@ -27,8 +35,20 @@ Rectangle {
|
|||
width: textItem.width + 10
|
||||
height: textItem.height + 10
|
||||
|
||||
/*!
|
||||
\qmlproperty int Alert::fadingX
|
||||
X of the object that is being animated.
|
||||
*/
|
||||
property int fadingX: parent.width - width - 10
|
||||
/*!
|
||||
\qmlproperty int Alert::fadeTime
|
||||
Length in millisecond of the animation.
|
||||
*/
|
||||
property int fadeTime: 200
|
||||
/*!
|
||||
\qmlproperty string Alert::text
|
||||
Text of the alert.
|
||||
*/
|
||||
property alias text: textItem.text
|
||||
|
||||
Text {
|
||||
|
@ -64,6 +84,10 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod void Alert::show(string alertText)
|
||||
Show an alert with a certain \c alertText.
|
||||
*/
|
||||
function show(alertText) {
|
||||
visible = true
|
||||
fadeTimer.restart()
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
import QtQuick.Controls
|
||||
|
||||
/*!
|
||||
\qmltype BaseDialog
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.Popup
|
||||
\brief Base dialog window in replacement of Dialog Popup from Qt 5.
|
||||
|
||||
\sa LogarithmPlotter
|
||||
*/
|
||||
|
||||
Window {
|
||||
id: base
|
||||
color: sysPalette.window
|
||||
visible: false;
|
||||
flags: Qt.Dialog | Qt.Popup | Qt.MSWindowsFixedSizeDialogHint
|
||||
modality: Qt.WindowModal
|
||||
minimumWidth: width
|
||||
maximumWidth: width
|
||||
height: minimumHeight
|
||||
property int margin: 10
|
||||
|
||||
Button {
|
||||
id: closeButton
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.bottomMargin: margin
|
||||
anchors.rightMargin: margin
|
||||
text: qsTr('Close')
|
||||
onClicked: close()
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
sequence: "Esc"
|
||||
onActivated: base.close()
|
||||
}
|
||||
|
||||
function open() {
|
||||
show()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
import QtQuick.Controls
|
||||
|
||||
/*!
|
||||
\qmltype Changelog
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.Popup
|
||||
\brief Overlay used to display the current changelog to the user.
|
||||
|
||||
\note The changelog is either fetched from https://api.ad5001.eu/changelog/logarithmplotter/ or taken locally when a file named CHANGELOG.md exists within the main source code.
|
||||
|
||||
\sa LogarithmPlotter, GreetScreen
|
||||
*/
|
||||
Popup {
|
||||
id: changelogPopup
|
||||
x: (parent.width-width)/2
|
||||
y: Math.max(20, (parent.height-height)/2)
|
||||
width: 800
|
||||
height: Math.min(parent.height-40, 500)
|
||||
modal: true
|
||||
focus: true
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||
|
||||
/*!
|
||||
\qmlproperty string Changelog::changelogNeedsFetching
|
||||
true when the changelog has yet to be loaded, set to false the moment it's loaded.
|
||||
*/
|
||||
property bool changelogNeedsFetching: true
|
||||
|
||||
onAboutToShow: if(changelogNeedsFetching) {
|
||||
Helper.fetchChangelog()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Helper
|
||||
function onChangelogFetched(chl) {
|
||||
changelogNeedsFetching = false;
|
||||
changelog.text = chl
|
||||
changelogView.contentItem.implicitHeight = changelog.height
|
||||
// console.log(changelog.height, changelogView.contentItem.implicitHeight)
|
||||
}
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
id: changelogView
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 10
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 10
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 10
|
||||
anchors.bottom: doneBtn.top
|
||||
anchors.bottomMargin: 10
|
||||
clip: true
|
||||
|
||||
|
||||
Label {
|
||||
id: changelog
|
||||
color: sysPalette.windowText
|
||||
width: 760
|
||||
wrapMode: Text.WordWrap
|
||||
textFormat: TextEdit.MarkdownText
|
||||
|
||||
text: qsTr("Fetching changelog...")
|
||||
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 {
|
||||
id: doneBtn
|
||||
text: qsTr("Close")
|
||||
font.pixelSize: 18
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 7
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
onClicked: changelogPopup.close()
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
|
@ -16,9 +16,16 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick.Dialogs 1.3 as D
|
||||
import Qt.labs.platform
|
||||
|
||||
D.FileDialog {
|
||||
/*!
|
||||
\qmltype FileDialog
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.Popup
|
||||
\brief Dialog used to prompt the user to save or load Logarithm Plot Files.
|
||||
|
||||
\sa LogarithmPlotter, Settings
|
||||
*/
|
||||
FileDialog {
|
||||
id: fileDialog
|
||||
|
||||
property bool exportMode: false
|
||||
|
@ -26,6 +33,6 @@ D.FileDialog {
|
|||
title: exportMode ? qsTr("Export Logarithm Plot file") : qsTr("Import Logarithm Plot file")
|
||||
nameFilters: ["Logarithm Plot File (*.lpf)", "All files (*)"]
|
||||
|
||||
folder: shortcuts.documents
|
||||
selectExisting: !exportMode
|
||||
defaultSuffix: 'lpf'
|
||||
fileMode: exportMode ? FileDialog.SaveFile : FileDialog.OpenFile
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
import QtQuick.Controls
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
|
||||
/*!
|
||||
\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: greetingLayout.width+20
|
||||
height: Math.min(parent.height-40, 700)
|
||||
modal: true
|
||||
focus: true
|
||||
clip: true
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||
|
||||
Column {
|
||||
id: greetingLayout
|
||||
width: 600
|
||||
spacing: 10
|
||||
clip: true
|
||||
topPadding: 35
|
||||
|
||||
Row {
|
||||
id: welcome
|
||||
height: logo.height
|
||||
spacing: 10
|
||||
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
|
||||
wrapMode: Text.WordWrap
|
||||
font.pixelSize: 32
|
||||
text: qsTr("Welcome to LogarithmPlotter")
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
id: versionText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
wrapMode: Text.WordWrap
|
||||
width: implicitWidth
|
||||
font.pixelSize: 18
|
||||
font.italic: true
|
||||
text: qsTr("Version %1").arg(Helper.getVersion())
|
||||
}
|
||||
}
|
||||
|
||||
Grid {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: greetingLayout.bottom
|
||||
anchors.topMargin: 50
|
||||
columns: 2
|
||||
spacing: 10
|
||||
|
||||
Repeater {
|
||||
model: [{
|
||||
name: qsTr("Changelog"),
|
||||
icon: 'common/new.svg',
|
||||
onClicked: () => changelog.open()
|
||||
},{
|
||||
name: qsTr("Preferences"),
|
||||
icon: 'common/settings.svg',
|
||||
onClicked: () => preferences.open()
|
||||
},{
|
||||
name: qsTr("User manual"),
|
||||
icon: 'common/manual.svg',
|
||||
onClicked: () => Qt.openUrlExternally("https://git.ad5001.eu/Ad5001/LogarithmPlotter/wiki/_Sidebar")
|
||||
},{
|
||||
name: qsTr("Close"),
|
||||
icon: 'common/close.svg',
|
||||
onClicked: () => greetingPopup.close()
|
||||
}]
|
||||
|
||||
Button {
|
||||
id: createBtn
|
||||
width: 96
|
||||
height: 96
|
||||
onClicked: modelData.onClicked()
|
||||
|
||||
Setting.Icon {
|
||||
id: icon
|
||||
width: 24
|
||||
height: 24
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: (parent.width-width)/2
|
||||
top: parent.top
|
||||
topMargin: (label.y-height)/2
|
||||
}
|
||||
color: sysPalette.windowText
|
||||
source: '../icons/' + modelData.icon
|
||||
}
|
||||
|
||||
Label {
|
||||
id: label
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
bottomMargin: 5
|
||||
left: parent.left
|
||||
leftMargin: 4
|
||||
right: parent.right
|
||||
rightMargin: 4
|
||||
}
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pixelSize: 14
|
||||
text: modelData.name
|
||||
wrapMode: Text.WordWrap
|
||||
clip: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: if(Helper.getSetting("last_install_greet") != Helper.getVersion()+1) {
|
||||
greetingPopup.open()
|
||||
}
|
||||
|
||||
onClosed: Helper.setSetting("last_install_greet", Helper.getVersion())
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 Ad5001
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick.Controls
|
||||
import QtQuick
|
||||
|
||||
/*!
|
||||
\qmltype InsertCharacter
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.Setting
|
||||
\brief Popup to insert special character.
|
||||
|
||||
\sa TextSetting, ExpressionEditor
|
||||
*/
|
||||
Popup {
|
||||
id: insertPopup
|
||||
|
||||
signal selected(string character)
|
||||
|
||||
/*!
|
||||
\qmlproperty string InsertCharacter::category
|
||||
Type of special character to insert.
|
||||
Possible values:
|
||||
- expression
|
||||
- domain
|
||||
- name
|
||||
- all
|
||||
*/
|
||||
property string category: 'all'
|
||||
|
||||
width: 280
|
||||
height: Math.ceil(insertGrid.insertChars.length/insertGrid.columns)*(width/insertGrid.columns)+5
|
||||
modal: true
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
|
||||
|
||||
Grid {
|
||||
id: insertGrid
|
||||
width: parent.width
|
||||
columns: 7
|
||||
|
||||
property var insertCharsExpression: [
|
||||
"∞","π","¹","²","³","⁴","⁵",
|
||||
"⁶","⁷","⁸","⁹","⁰"
|
||||
]
|
||||
|
||||
property var insertCharsDomain: [
|
||||
"∅","∪","∩","∖","ℝ","ℕ","ℤ",
|
||||
"⁺","⁻",...insertCharsExpression
|
||||
]
|
||||
|
||||
property var insertCharsName: [
|
||||
"α","β","γ","δ","ε","ζ","η",
|
||||
"π","θ","κ","λ","μ","ξ","ρ",
|
||||
"ς","σ","τ","φ","χ","ψ","ω",
|
||||
"Γ","Δ","Θ","Λ","Ξ","Π","Σ",
|
||||
"Φ","Ψ","Ω","ₐ","ₑ","ₒ","ₓ",
|
||||
"ₕ","ₖ","ₗ","ₘ","ₙ","ₚ","ₛ",
|
||||
"ₜ","₁","₂","₃","₄","₅","₆",
|
||||
"₇","₈","₉","₀"
|
||||
]
|
||||
|
||||
property var insertCharsAll: [
|
||||
...insertCharsName, ...insertCharsDomain
|
||||
]
|
||||
|
||||
property var insertChars: {
|
||||
return {
|
||||
"expression": insertCharsExpression,
|
||||
"domain": insertCharsDomain,
|
||||
"name": insertCharsName,
|
||||
"all": insertCharsAll
|
||||
}[insertPopup.category]
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: parent.insertChars.length
|
||||
|
||||
Button {
|
||||
id: insertBtn
|
||||
width: insertGrid.width/insertGrid.columns
|
||||
height: width
|
||||
text: insertGrid.insertChars[modelData]
|
||||
flat: text == " "
|
||||
font.pixelSize: 18
|
||||
|
||||
onClicked: {
|
||||
selected(text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,256 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
import "../js/preferences/common.mjs" as S
|
||||
import "../js/utils.mjs" as Utils
|
||||
|
||||
/*!
|
||||
\qmltype Preferences
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.Popup
|
||||
\brief Popup to change global application preferences.
|
||||
|
||||
\sa LogarithmPlotter, GreetScreen
|
||||
*/
|
||||
Popup {
|
||||
id: preferencesPopup
|
||||
x: (parent.width-width)/2
|
||||
y: Math.max(20, (parent.height-height)/2)
|
||||
width: settingPopupRow.width + 30
|
||||
height: settingPopupRow.height + 20
|
||||
modal: true
|
||||
focus: true
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||
|
||||
// Components for the preferences
|
||||
Component {
|
||||
id: boolSettingComponent
|
||||
|
||||
CheckBox {
|
||||
height: 20
|
||||
text: setting.name
|
||||
checked: setting.value()
|
||||
onClicked: setting.set(this.checked)
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: enumIntSettingComponent
|
||||
|
||||
// Setting when selecting data from an enum, or an object of a certain type.
|
||||
Setting.ComboBoxSetting {
|
||||
height: 30
|
||||
label: setting.name
|
||||
icon: `settings/${setting.icon}.svg`
|
||||
currentIndex: setting.value()
|
||||
model: setting.values
|
||||
onActivated: function(newIndex) { setting.set(newIndex) }
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: stringSettingComponent
|
||||
|
||||
Setting.ComboBoxSetting {
|
||||
height: 30
|
||||
label: setting.name
|
||||
icon: `settings/${setting.icon}.svg`
|
||||
editable: true
|
||||
currentIndex: find(setting.value())
|
||||
model: setting.defaultValues
|
||||
onAccepted: function() {
|
||||
editText = Utils.parseName(editText, false)
|
||||
if(find(editText) === -1) model.append(editText)
|
||||
setting.set(editText)
|
||||
}
|
||||
onActivated: function(selectedId) {
|
||||
setting.set(model[selectedId])
|
||||
}
|
||||
Component.onCompleted: editText = setting.value()
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: numberSettingComponent
|
||||
|
||||
Setting.TextSetting {
|
||||
height: 30
|
||||
isDouble: true
|
||||
label: setting.name
|
||||
min: setting.min()
|
||||
icon: `settings/${setting.icon}.svg`
|
||||
value: setting.value()
|
||||
onChanged: function(newValue) {
|
||||
if(newValue < setting.max())
|
||||
setting.set(newValue)
|
||||
else {
|
||||
value = setting.max()
|
||||
setting.set(setting.max())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: expressionSettingComponent
|
||||
|
||||
Setting.ExpressionEditor {
|
||||
height: 30
|
||||
label: setting.name
|
||||
icon: `settings/${setting.icon}.svg`
|
||||
defValue: Utils.simplifyExpression(setting.value())
|
||||
variables: setting.variables
|
||||
allowGraphObjects: false
|
||||
property string propertyName: setting.name
|
||||
onChanged: function(newExpr) {
|
||||
try {
|
||||
setting.set(newExpr)
|
||||
} catch(e) {
|
||||
errorDialog.showDialog(propertyName, newExpr, e.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: settingPopupRow
|
||||
height: 300
|
||||
width: categories.width + categorySeparator.width + settingView.width + 70
|
||||
spacing: 15
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
topMargin: 10
|
||||
bottomMargin: 10
|
||||
rightMargin: 15
|
||||
leftMargin: 15
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: categories
|
||||
width: 150
|
||||
height: parent.height
|
||||
spacing: 0
|
||||
clip: true
|
||||
|
||||
Repeater {
|
||||
model: Object.keys(Modules.Preferences.categories)
|
||||
|
||||
Button {
|
||||
// width: 150
|
||||
Layout.fillWidth: true
|
||||
text: qsTranslate('settingCategory', modelData)
|
||||
|
||||
onClicked: {
|
||||
settingView.modelName = modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
|
||||
Button {
|
||||
id: closeButton
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
text: qsTr('Close')
|
||||
onClicked: preferencesPopup.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: categorySeparator
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: 5
|
||||
}
|
||||
opacity: 0.3
|
||||
color: sysPalette.windowText
|
||||
height: parent.height - 10
|
||||
width: 1
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: settingView
|
||||
clip: true
|
||||
width: 500
|
||||
spacing: 10
|
||||
model: Modules.Preferences.categories[modelName]
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
}
|
||||
ScrollBar.vertical: ScrollBar { }
|
||||
property string modelName: 'general'
|
||||
|
||||
|
||||
header: Text {
|
||||
id: settingCategoryName
|
||||
font.pixelSize: 32
|
||||
height: 48
|
||||
color: sysPalette.windowText
|
||||
text: qsTranslate('settingCategory', settingView.modelName)
|
||||
|
||||
Rectangle {
|
||||
id: bottomSeparator
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 8
|
||||
opacity: 0.3
|
||||
color: sysPalette.windowText
|
||||
width: settingView.width
|
||||
height: 1
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Component {
|
||||
Loader {
|
||||
width: settingView.width - 20
|
||||
property var setting: Modules.Preferences.categories[settingView.modelName][index]
|
||||
sourceComponent: {
|
||||
if(setting.type === "bool")
|
||||
return boolSettingComponent
|
||||
else if(setting.type === "enum")
|
||||
return enumIntSettingComponent
|
||||
else if(setting.type === "number")
|
||||
return numberSettingComponent
|
||||
else if(setting.type === "expression")
|
||||
return expressionSettingComponent
|
||||
else if(setting.type === "string")
|
||||
return stringSettingComponent
|
||||
else
|
||||
console.log('Unknown setting type!', setting.constructor.nameInConfig, setting.constructor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Component.onCompleted: open()
|
||||
}
|
|
@ -0,0 +1,357 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
import QtQuick.Dialogs
|
||||
import QtQuick.Controls
|
||||
|
||||
/*!
|
||||
\qmltype ThanksTo
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.Popup
|
||||
\brief Thanks to popup of LogarithmPlotter.
|
||||
|
||||
\sa LogarithmPlotter
|
||||
*/
|
||||
BaseDialog {
|
||||
id: thanks
|
||||
title: qsTr("Thanks and Contributions - LogarithmPlotter")
|
||||
width: 450
|
||||
minimumHeight: 600
|
||||
|
||||
ScrollView {
|
||||
|
||||
anchors {
|
||||
top: parent.top;
|
||||
left: parent.left;
|
||||
bottom: parent.bottom;
|
||||
right: parent.right;
|
||||
topMargin: margin;
|
||||
leftMargin: margin;
|
||||
bottomMargin: margin+30;
|
||||
}
|
||||
|
||||
Column {
|
||||
|
||||
anchors {
|
||||
left: parent.left;
|
||||
}
|
||||
|
||||
width: thanks.width - 2*margin
|
||||
spacing: 10
|
||||
|
||||
ListView {
|
||||
id: librariesListView
|
||||
anchors.left: parent.left
|
||||
width: parent.width
|
||||
//height: parent.height
|
||||
implicitHeight: contentItem.childrenRect.height
|
||||
interactive: false
|
||||
|
||||
model: ListModel {
|
||||
Component.onCompleted: {
|
||||
append({
|
||||
libName: 'expr-eval',
|
||||
license: 'MIT',
|
||||
licenseLink: 'https://raw.githubusercontent.com/silentmatt/expr-eval/master/LICENSE.txt',
|
||||
linkName: qsTr('Source code'),
|
||||
link: 'https://github.com/silentmatt/expr-eval',
|
||||
authors: [{
|
||||
authorLine: qsTr('Original library by Raphael Graf'),
|
||||
email: 'r@undefined.ch',
|
||||
website: 'https://web.archive.org/web/20111023001618/http://www.undefined.ch/mparser/index.html',
|
||||
websiteName: qsTr('Source')
|
||||
}, {
|
||||
authorLine: qsTr('Ported to Javascript by Matthew Crumley'),
|
||||
email: 'email@matthewcrumley.com',
|
||||
website: 'https://silentmatt.com/',
|
||||
websiteName: qsTr('Website')
|
||||
}, {
|
||||
authorLine: qsTr('Ported to QMLJS by Ad5001'),
|
||||
email: 'mail@ad5001.eu',
|
||||
website: 'https://ad5001.eu/',
|
||||
websiteName: qsTr('Website')
|
||||
}]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
header: Label {
|
||||
id: librariesUsedHeader
|
||||
wrapMode: Text.WordWrap
|
||||
font.pixelSize: 25
|
||||
text: qsTr("Libraries included")
|
||||
height: implicitHeight + 10
|
||||
}
|
||||
|
||||
delegate: Column {
|
||||
id: libClmn
|
||||
width: librariesListView.width
|
||||
spacing: 10
|
||||
|
||||
Item {
|
||||
height: libraryHeader.height
|
||||
width: parent.width
|
||||
|
||||
Label {
|
||||
id: libraryHeader
|
||||
anchors.left: parent.left
|
||||
wrapMode: Text.WordWrap
|
||||
font.pixelSize: 18
|
||||
text: libName
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
height: parent.height
|
||||
spacing: 10
|
||||
|
||||
Button {
|
||||
height: parent.height
|
||||
text: license
|
||||
icon.name: 'license'
|
||||
onClicked: Qt.openUrlExternally(licenseLink)
|
||||
}
|
||||
|
||||
Button {
|
||||
height: parent.height
|
||||
text: linkName
|
||||
icon.name: 'web-browser'
|
||||
onClicked: Qt.openUrlExternally(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: libAuthors
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 10
|
||||
model: authors
|
||||
width: parent.width - 10
|
||||
implicitHeight: contentItem.childrenRect.height
|
||||
interactive: false
|
||||
|
||||
delegate: Item {
|
||||
id: libAuthor
|
||||
width: librariesListView.width - 10
|
||||
height: 50
|
||||
|
||||
Label {
|
||||
id: libAuthorName
|
||||
anchors.left: parent.left
|
||||
anchors.right: buttons.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
wrapMode: Text.WordWrap
|
||||
font.pixelSize: 14
|
||||
text: authorLine
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons
|
||||
anchors.right: parent.right
|
||||
height: parent.height
|
||||
spacing: 10
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: websiteName
|
||||
icon.name: 'web-browser'
|
||||
height: parent.height - 10
|
||||
onClicked: Qt.openUrlExternally(website)
|
||||
}
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr('Email')
|
||||
icon.name: 'email'
|
||||
height: parent.height - 10
|
||||
onClicked: Qt.openUrlExternally('mailto:' + email)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: libSeparator
|
||||
opacity: 0.3
|
||||
color: sysPalette.windowText
|
||||
width: parent.width
|
||||
height: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: translationsListView
|
||||
anchors.left: parent.left
|
||||
width: parent.width
|
||||
implicitHeight: contentItem.childrenRect.height
|
||||
interactive: false
|
||||
spacing: 3
|
||||
|
||||
|
||||
model: ListModel {
|
||||
Component.onCompleted: {
|
||||
const authors = {
|
||||
Ad5001: {
|
||||
authorLine: 'Ad5001',
|
||||
email: 'mail@ad5001.eu',
|
||||
website: 'https://ad5001.eu',
|
||||
websiteName: qsTr('Website')
|
||||
},
|
||||
Ovari: {
|
||||
authorLine: 'Óvári',
|
||||
website: 'https://github.com/ovari',
|
||||
websiteName: qsTr('Github')
|
||||
},
|
||||
comradekingu: {
|
||||
authorLine: 'Allan Nordhøy',
|
||||
website: 'https://github.com/comradekingu',
|
||||
websiteName: qsTr('Github')
|
||||
},
|
||||
IngrownMink4: {
|
||||
authorLine: 'IngrownMink4',
|
||||
website: 'https://github.com/IngrownMink4',
|
||||
websiteName: qsTr('Github')
|
||||
},
|
||||
gallegonovato: {
|
||||
authorLine: 'gallegonovato',
|
||||
website: '',
|
||||
websiteName: ''
|
||||
}
|
||||
}
|
||||
|
||||
append({
|
||||
tranName: '🇬🇧 ' + qsTr('English'),
|
||||
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/en/',
|
||||
authors: [authors.Ad5001]
|
||||
})
|
||||
append({
|
||||
tranName: '🇫🇷 ' + qsTr('French'),
|
||||
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/fr/',
|
||||
authors: [authors.Ad5001]
|
||||
})
|
||||
append({
|
||||
tranName: '🇩🇪 ' + qsTr('German'),
|
||||
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/de/',
|
||||
authors: [authors.Ad5001]
|
||||
})
|
||||
append({
|
||||
tranName: '🇭🇺 ' + qsTr('Hungarian'),
|
||||
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/hu/',
|
||||
authors: [authors.Ovari]
|
||||
})
|
||||
append({
|
||||
tranName: '🇳🇴 ' + qsTr('Norwegian'),
|
||||
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/no/',
|
||||
authors: [authors.comradekingu, authors.Ad5001]
|
||||
})
|
||||
append({
|
||||
tranName: '🇪🇸 ' + qsTr('Spanish'),
|
||||
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/',
|
||||
authors: [authors.IngrownMink4, authors.gallegonovato]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
header: Label {
|
||||
id: translationsHeader
|
||||
wrapMode: Text.WordWrap
|
||||
font.pixelSize: 25
|
||||
text: qsTr("Translations included")
|
||||
height: implicitHeight + 10
|
||||
}
|
||||
|
||||
delegate: Column {
|
||||
id: tranClmn
|
||||
width: translationsListView.width
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: translationHeader.height + 10
|
||||
|
||||
Label {
|
||||
id: translationHeader
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
wrapMode: Text.WordWrap
|
||||
font.pixelSize: 18
|
||||
text: tranName
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
height: 30
|
||||
spacing: 10
|
||||
|
||||
Button {
|
||||
height: parent.height
|
||||
text: qsTr('Improve')
|
||||
icon.name: 'web-browser'
|
||||
onClicked: Qt.openUrlExternally(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: tranAuthors
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 10
|
||||
model: authors
|
||||
width: parent.width - 10
|
||||
implicitHeight: contentItem.childrenRect.height
|
||||
interactive: false
|
||||
|
||||
delegate: Item {
|
||||
id: tranAuthor
|
||||
width: tranAuthors.width
|
||||
height: 40
|
||||
|
||||
Label {
|
||||
id: tranAuthorName
|
||||
anchors.left: parent.left
|
||||
//anchors.right: buttons.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
wrapMode: Text.WordWrap
|
||||
font.pixelSize: 14
|
||||
text: authorLine
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons
|
||||
anchors.left: tranAuthorName.right
|
||||
anchors.leftMargin: 10
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
height: 30
|
||||
spacing: 10
|
||||
|
||||
Button {
|
||||
text: websiteName
|
||||
visible: websiteName !== ""
|
||||
icon.name: 'web-browser'
|
||||
height: parent.height
|
||||
onClicked: Qt.openUrlExternally(website)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/Popup/qmldir
Normal file
|
@ -0,0 +1,11 @@
|
|||
module eu.ad5001.LogarithmPlotter.Popup
|
||||
|
||||
Alert 1.0 Alert.qml
|
||||
About 1.0 About.qml
|
||||
BaseDialog 1.0 BaseDialog.qml
|
||||
Changelog 1.0 Changelog.qml
|
||||
FileDialog 1.0 FileDialog.qml
|
||||
GreetScreen 1.0 GreetScreen.qml
|
||||
InsertCharacter 1.0 InsertCharacter.qml
|
||||
Preferences 1.0 Preferences.qml
|
||||
ThanksTo 1.0 ThanksTo.qml
|
|
@ -0,0 +1,125 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
import QtQuick.Controls
|
||||
|
||||
/*!
|
||||
\qmltype AutocompletionCategory
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.Setting
|
||||
\brief ListView representing a category of autocompletion.
|
||||
|
||||
\sa ExpressionEditor
|
||||
*/
|
||||
ListView {
|
||||
id: listFiltered
|
||||
/*!
|
||||
\qmlproperty int AutocompletionCategory::itemStartIndex
|
||||
Start index of the first element in this list compared to the global autocompletion index.
|
||||
*/
|
||||
property int itemStartIndex: 0
|
||||
/*!
|
||||
\qmlproperty int AutocompletionCategory::itemSelected
|
||||
The global autocompletion index.
|
||||
*/
|
||||
property int itemSelected: 0
|
||||
|
||||
/*!
|
||||
\qmlproperty string AutocompletionCategory::category
|
||||
Name of the category.
|
||||
*/
|
||||
property string category: ""
|
||||
|
||||
/*!
|
||||
\qmlproperty var AutocompletionCategory::categoryItems
|
||||
List of items in this category. To be filtered by the autocomplete to filters.
|
||||
*/
|
||||
property var categoryItems: []
|
||||
|
||||
/*!
|
||||
\qmlproperty var AutocompletionCategory::autocompleteGenerator
|
||||
Javascript function taking the name of the item to create an autocompletion item (dictionary with
|
||||
a 'text', 'annotation' 'autocomplete', and 'cursorFinalOffset' keys.
|
||||
*/
|
||||
property var autocompleteGenerator: (item) => {return {'text': item, 'autocomplete': item, 'annotation': '', 'cursorFinalOffset': 0}}
|
||||
|
||||
/*!
|
||||
\qmlproperty string AutocompletionCategory::baseText
|
||||
Text to autocomplete.
|
||||
*/
|
||||
property string baseText: ""
|
||||
|
||||
/*!
|
||||
\qmlproperty bool AutocompletionCategory::visbilityCondition
|
||||
Condition to be met for the category to be visible.
|
||||
*/
|
||||
property bool visbilityCondition: true
|
||||
|
||||
width: parent.width
|
||||
visible: model.length > 0
|
||||
implicitHeight: contentItem.childrenRect.height
|
||||
model: visbilityCondition ? categoryItems.filter((item) => item.includes(baseText)).map(autocompleteGenerator) : []
|
||||
|
||||
header: Column {
|
||||
width: listFiltered.width
|
||||
spacing: 2
|
||||
topPadding: 5
|
||||
bottomPadding: 5
|
||||
|
||||
Text {
|
||||
leftPadding: 5
|
||||
text: listFiltered.category
|
||||
color: sysPalette.windowText
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
height: 1
|
||||
color: 'gray'
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Rectangle {
|
||||
property bool selected: index + listFiltered.itemStartIndex == listFiltered.itemSelected
|
||||
|
||||
width: listFiltered.width
|
||||
height: Math.max(autocompleteText.height, annotationText.height)
|
||||
color: selected ? sysPalette.highlight : 'transparent'
|
||||
|
||||
Text {
|
||||
id: autocompleteText
|
||||
topPadding: 2
|
||||
bottomPadding: 2
|
||||
leftPadding: 15
|
||||
text: listFiltered.model[index].text
|
||||
color: parent.selected ? sysPalette.highlightedText : sysPalette.windowText
|
||||
}
|
||||
|
||||
Text {
|
||||
id: annotationText
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
topPadding: 2
|
||||
bottomPadding: 2
|
||||
rightPadding: 15
|
||||
font.pixelSize: autocompleteText.font.pixelSize - 2
|
||||
text: listFiltered.model[index].annotation
|
||||
color: parent.selected ? sysPaletteIn.highlightedText : sysPaletteIn.windowText
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
import QtQuick.Controls
|
||||
|
||||
/*!
|
||||
\qmltype ComboBoxSetting
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.Setting
|
||||
\brief Combo box with an icon and label to make a proper setting.
|
||||
|
||||
\sa EditorDialog, Settings, Icon
|
||||
*/
|
||||
Item {
|
||||
id: control
|
||||
height: 30
|
||||
|
||||
/*!
|
||||
\qmlsignal ComboBoxSetting::activated(int newIndex)
|
||||
|
||||
Alias of ComboBox.activated.
|
||||
The corresponding handler is \c onActivated.
|
||||
\sa https://doc.qt.io/qt-5/qml-qtquick-controls2-combobox.html#activated-signal
|
||||
*/
|
||||
signal activated(int newIndex)
|
||||
/*!
|
||||
\qmlsignal ComboBoxSetting::accepted()
|
||||
|
||||
Alias of ComboBox.accepted.
|
||||
The corresponding handler is \c onAccepted.
|
||||
\sa https://doc.qt.io/qt-5/qml-qtquick-controls2-combobox.html#accepted-signal
|
||||
*/
|
||||
signal accepted()
|
||||
|
||||
/*!
|
||||
\qmlproperty string ComboBoxSetting::label
|
||||
Label of the setting.
|
||||
*/
|
||||
property string label: ''
|
||||
/*!
|
||||
\qmlproperty string ComboBoxSetting::icon
|
||||
Icon path of the setting.
|
||||
*/
|
||||
property string icon: ""
|
||||
|
||||
/*!
|
||||
\qmlproperty var ComboBoxSetting::model
|
||||
Model of the combo box.
|
||||
\sa https://doc.qt.io/qt-5/qml-qtquick-controls2-combobox.html#model-prop
|
||||
*/
|
||||
property alias model: combox.model
|
||||
/*!
|
||||
\qmlproperty bool ComboBoxSetting::editable
|
||||
Whether the combo box accepts user-inputed values.
|
||||
\sa https://doc.qt.io/qt-5/qml-qtquick-controls2-combobox.html#editable-prop
|
||||
*/
|
||||
property alias editable: combox.editable
|
||||
/*!
|
||||
\qmlproperty string ComboBoxSetting::editText
|
||||
Text in the text field of an editable combo box.
|
||||
\sa https://doc.qt.io/qt-5/qml-qtquick-controls2-combobox.html#editText-prop
|
||||
*/
|
||||
property alias editText: combox.editText
|
||||
/*!
|
||||
\qmlproperty string ComboBoxSetting::currentIndex
|
||||
Index of the current item in the combo box.
|
||||
The default value is -1 when count is 0, and 0 otherwise
|
||||
\sa https://doc.qt.io/qt-5/qml-qtquick-controls2-combobox.html#currentIndex-prop
|
||||
*/
|
||||
property alias currentIndex: combox.currentIndex
|
||||
/*!
|
||||
\qmlproperty string ComboBoxSetting::currentIndex
|
||||
Input text validator for an editable combo box
|
||||
\sa https://doc.qt.io/qt-5/qml-qtquick-controls2-combobox.html#validator-prop
|
||||
*/
|
||||
property alias validator: combox.validator
|
||||
|
||||
/*!
|
||||
\qmlmethod int ComboBoxSetting::find(string elementName)
|
||||
Returns the index of the specified \a elementName, or -1 if no match is found.
|
||||
\sa https://doc.qt.io/qt-5/qml-qtquick-controls2-combobox.html#find-method
|
||||
*/
|
||||
function find(elementName) {
|
||||
return combox.find(elementName)
|
||||
}
|
||||
|
||||
Icon {
|
||||
id: iconLabel
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: icon == "" ? 0 : 3
|
||||
source: control.visible ? "../icons/" + control.icon : ""
|
||||
width: height
|
||||
height: icon == "" && visible ? 0 : 24
|
||||
color: sysPalette.windowText
|
||||
}
|
||||
|
||||
Label {
|
||||
id: labelItem
|
||||
anchors.left: iconLabel.right
|
||||
anchors.leftMargin: icon == "" ? 0 : 5
|
||||
height: 30
|
||||
width: Math.max(85, implicitWidth)
|
||||
anchors.top: parent.top
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
text: qsTranslate("control", "%1: ").arg(control.label)
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: combox
|
||||
height: 30
|
||||
anchors.left: labelItem.right
|
||||
anchors.leftMargin: 5
|
||||
width: control.width - labelItem.width - iconLabel.width - 10
|
||||
onActivated: function(newIndex) {
|
||||
control.activated(newIndex)
|
||||
}
|
||||
onAccepted: control.accepted()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,636 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 Ad5001
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick.Controls
|
||||
import QtQuick
|
||||
import Qt.labs.platform as Native
|
||||
import eu.ad5001.LogarithmPlotter.Popup 1.0 as P
|
||||
import "../js/math/index.mjs" as MathLib
|
||||
import "../js/utils.mjs" as Utils
|
||||
import "../js/parsing/parsing.mjs" as Parsing
|
||||
|
||||
|
||||
/*!
|
||||
\qmltype ExpressionEditor
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.Setting
|
||||
\brief Setting to edit strings and numbers.
|
||||
|
||||
\sa EditorDialog, AutocompletionCategory
|
||||
*/
|
||||
Item {
|
||||
id: control
|
||||
height: 30
|
||||
|
||||
/*!
|
||||
\qmlsignal ExpressionEditor::changed(var newValue)
|
||||
|
||||
Emitted when the value of the expression has been changed.
|
||||
The corresponding handler is \c onChanged.
|
||||
*/
|
||||
signal changed(var newValue)
|
||||
|
||||
/*!
|
||||
\qmlproperty string ExpressionEditor::defValue
|
||||
Default editable expression value of the editor.
|
||||
*/
|
||||
property string defValue
|
||||
/*!
|
||||
\qmlproperty string ExpressionEditor::value
|
||||
Value of the editor.
|
||||
*/
|
||||
property alias value: editor.text
|
||||
/*!
|
||||
\qmlproperty string ExpressionEditor::self
|
||||
Object or context of the expression to be edited.
|
||||
Used to prevent circular dependency.
|
||||
*/
|
||||
property string self: ""
|
||||
/*!
|
||||
\qmlproperty var ExpressionEditor::variables
|
||||
Accepted variables for the expression.
|
||||
*/
|
||||
property var variables: []
|
||||
/*!
|
||||
\qmlproperty string ExpressionEditor::placeholderText
|
||||
Value of the editor.
|
||||
*/
|
||||
property alias placeholderText: editor.placeholderText
|
||||
/*!
|
||||
\qmlproperty string ExpressionEditor::label
|
||||
Label of the editor.
|
||||
*/
|
||||
property string label
|
||||
/*!
|
||||
\qmlproperty string ExpressionEditor::icon
|
||||
Icon path of the editor.
|
||||
*/
|
||||
property string icon: ""
|
||||
/*!
|
||||
\qmlproperty bool ExpressionEditor::allowGraphObjects
|
||||
If true, allows graph objects to be used as part of the expression.
|
||||
*/
|
||||
property bool allowGraphObjects: true
|
||||
|
||||
/*!
|
||||
\qmlproperty var ExpressionEditor::errorDialog
|
||||
Allows to summon the error dialog when using additional external parsing.
|
||||
*/
|
||||
readonly property alias errorDialog: parsingErrorDialog
|
||||
|
||||
/*!
|
||||
\qmlproperty string ExpressionEditor::openAndCloseMatches
|
||||
Characters that when pressed, should be immediately followed up by their closing character.
|
||||
TODO: Make it configurable.
|
||||
*/
|
||||
readonly property var openAndCloseMatches: {
|
||||
"(": ")",
|
||||
"[": "]",
|
||||
"'": "'",
|
||||
'"': '"'
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlproperty string ExpressionEditor::colorSchemes
|
||||
Color schemes of the editor.
|
||||
*/
|
||||
readonly property var colorSchemes: [
|
||||
{ // Breeze Light
|
||||
'NORMAL': "#1F1C1B",
|
||||
'VARIABLE': "#0057AE",
|
||||
'CONSTANT': "#006E28",
|
||||
'FUNCTION': "#644A9B",
|
||||
'OPERATOR': "#CA60CA",
|
||||
'STRING': "#BF0303",
|
||||
'NUMBER': "#B08000"
|
||||
},
|
||||
{ // Breeze Dark
|
||||
'NORMAL': "#CFCFC2",
|
||||
'VARIABLE': "#2980B9",
|
||||
'CONSTANT': "#27AE60",
|
||||
'FUNCTION': "#8E44AD",
|
||||
'OPERATOR': "#A44EA4",
|
||||
'STRING': "#F44F4F",
|
||||
'NUMBER': "#F67400"
|
||||
},
|
||||
{ // Solarized
|
||||
'NORMAL': "#839496",
|
||||
'VARIABLE': "#B58900",
|
||||
'CONSTANT': "#859900",
|
||||
'FUNCTION': "#268BD2",
|
||||
'OPERATOR': "#859900",
|
||||
'STRING': "#2AA198",
|
||||
'NUMBER': "#2AA198"
|
||||
},
|
||||
{ // GitHub Light
|
||||
'NORMAL': "#24292E",
|
||||
'VARIABLE': "#D73A49",
|
||||
'CONSTANT': "#6F42C1",
|
||||
'FUNCTION': "#6F42C1",
|
||||
'OPERATOR': "#24292E",
|
||||
'STRING': "#032F62",
|
||||
'NUMBER': "#005CC5"
|
||||
},
|
||||
{ // GitHub Dark
|
||||
'NORMAL': "#E1E4E8",
|
||||
'VARIABLE': "#F97583",
|
||||
'CONSTANT': "#B392f0",
|
||||
'FUNCTION': "#B392f0",
|
||||
'OPERATOR': "#E1E4E8",
|
||||
'STRING': "#9ECBFF",
|
||||
'NUMBER': "#79B8FF"
|
||||
},
|
||||
{ // Nord
|
||||
'NORMAL': "#D8DEE9",
|
||||
'VARIABLE': "#81A1C1",
|
||||
'CONSTANT': "#8FBCBB",
|
||||
'FUNCTION': "#88C0D0",
|
||||
'OPERATOR': "#81A1C1",
|
||||
'STRING': "#A3BE8C",
|
||||
'NUMBER': "#B48EAD"
|
||||
},
|
||||
{ // Monokai
|
||||
'NORMAL': "#F8F8F2",
|
||||
'VARIABLE': "#66D9EF",
|
||||
'CONSTANT': "#F92672",
|
||||
'FUNCTION': "#A6E22E",
|
||||
'OPERATOR': "#F8F8F2",
|
||||
'STRING': "#E6DB74",
|
||||
'NUMBER': "#AE81FF"
|
||||
}
|
||||
]
|
||||
|
||||
Icon {
|
||||
id: iconLabel
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: icon == "" ? 0 : 3
|
||||
source: control.visible && icon != "" ? "../icons/" + control.icon : ""
|
||||
width: height
|
||||
height: icon == "" || !visible ? 0 : 24
|
||||
color: sysPalette.windowText
|
||||
}
|
||||
|
||||
Label {
|
||||
id: labelItem
|
||||
anchors.left: iconLabel.right
|
||||
anchors.leftMargin: icon == "" ? 0 : 5
|
||||
anchors.top: parent.top
|
||||
height: parent.height
|
||||
width: Math.max(85, implicitWidth)
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
//color: sysPalette.windowText
|
||||
text: visible ? qsTranslate("control", "%1: ").arg(control.label) : ""
|
||||
visible: control.label != ""
|
||||
}
|
||||
|
||||
Native.MessageDialog {
|
||||
id: parsingErrorDialog
|
||||
title: qsTranslate("expression", "LogarithmPlotter - Parsing error")
|
||||
text: ""
|
||||
function showDialog(propName, propValue, error) {
|
||||
text = qsTranslate("expression", "Error while parsing expression for property %1:\n%2\n\nEvaluated expression: %3")
|
||||
.arg(qsTranslate('prop', propName))
|
||||
.arg(error).arg(propValue)
|
||||
open()
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: editor
|
||||
anchors.top: parent.top
|
||||
anchors.left: labelItem.right
|
||||
anchors.leftMargin: 5
|
||||
width: control.width - (labelItem.visible ? labelItem.width + 5 : 0) - iconLabel.width - 5
|
||||
height: parent.height
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
horizontalAlignment: control.label == "" ? TextInput.AlignLeft : TextInput.AlignHCenter
|
||||
text: control.defValue
|
||||
color: syntaxHighlightingEnabled ? sysPalette.window : sysPalette.windowText
|
||||
focus: true
|
||||
selectByMouse: true
|
||||
|
||||
property bool autocompleteEnabled: Helper.getSettingBool("autocompletion.enabled")
|
||||
property bool syntaxHighlightingEnabled: Helper.getSettingBool("expression_editor.colorize")
|
||||
property bool autoClosing: Helper.getSettingBool("expression_editor.autoclose")
|
||||
property var tokens: autocompleteEnabled || syntaxHighlightingEnabled ? parent.tokens(text) : []
|
||||
|
||||
Keys.priority: Keys.BeforeItem // Required for knowing which key the user presses.
|
||||
|
||||
onEditingFinished: {
|
||||
if(insertButton.focus || insertPopup.focus) return
|
||||
let value = text
|
||||
if(value != "" && value.toString() != defValue) {
|
||||
let expr = parse(value)
|
||||
if(expr != null) {
|
||||
control.changed(expr)
|
||||
defValue = expr.toEditableString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if(activeFocus && autocompleteEnabled)
|
||||
autocompletePopup.open()
|
||||
else
|
||||
autocompletePopup.close()
|
||||
}
|
||||
|
||||
cursorDelegate: Rectangle {
|
||||
visible: editor.cursorVisible
|
||||
color: sysPalette.windowText
|
||||
width: editor.cursorRectangle.width
|
||||
}
|
||||
|
||||
Keys.onUpPressed: function(event) {
|
||||
if(autocompleteEnabled)
|
||||
if(acPopupContent.itemSelected == 0)
|
||||
acPopupContent.itemSelected = acPopupContent.itemCount-1
|
||||
else
|
||||
acPopupContent.itemSelected = acPopupContent.itemSelected-1
|
||||
event.accepted = true
|
||||
}
|
||||
|
||||
Keys.onDownPressed: function(event) {
|
||||
if(autocompleteEnabled)
|
||||
if(acPopupContent.itemSelected == Math.min(acPopupContent.itemCount-1))
|
||||
acPopupContent.itemSelected = 0
|
||||
else
|
||||
acPopupContent.itemSelected = acPopupContent.itemSelected+1
|
||||
event.accepted = true
|
||||
}
|
||||
|
||||
Keys.onPressed: function(event) {
|
||||
// Autocomplete popup events
|
||||
if(autocompleteEnabled && (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) && acPopupContent.itemCount > 0) {
|
||||
acPopupContent.autocomplete()
|
||||
event.accepted = true
|
||||
} else
|
||||
acPopupContent.itemSelected = 0
|
||||
|
||||
|
||||
if(event.text in openAndCloseMatches && autoClosing) {
|
||||
let start = selectionStart
|
||||
insert(selectionStart, event.text)
|
||||
insert(selectionEnd, openAndCloseMatches[event.text])
|
||||
cursorPosition = start+1
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: colorizedEditor
|
||||
anchors.fill: editor
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
horizontalAlignment: control.label == "" ? TextInput.AlignLeft : TextInput.AlignHCenter
|
||||
textFormat: Text.StyledText
|
||||
text: parent.syntaxHighlightingEnabled ? colorize(parent.tokens) : ""
|
||||
color: sysPalette.windowText
|
||||
visible: parent.syntaxHighlightingEnabled
|
||||
//font.pixelSize: parent.font.pixelSize
|
||||
//opacity: editor.activeFocus ? 0 : 1
|
||||
}
|
||||
|
||||
Popup {
|
||||
id: autocompletePopup
|
||||
x: 0
|
||||
y: parent.height
|
||||
closePolicy: Popup.NoAutoClose
|
||||
|
||||
width: editor.width
|
||||
height: acPopupContent.height
|
||||
padding: 0
|
||||
|
||||
Column {
|
||||
id: acPopupContent
|
||||
width: parent.width
|
||||
|
||||
readonly property var identifierTokenTypes: [
|
||||
Parsing.TokenType.VARIABLE,
|
||||
Parsing.TokenType.FUNCTION,
|
||||
Parsing.TokenType.CONSTANT
|
||||
]
|
||||
property var currentToken: generateTokenInformation(getTokenAt(editor.tokens, editor.cursorPosition))
|
||||
property var previousToken: generateTokenInformation(getPreviousToken(currentToken.token))
|
||||
property var previousToken2: generateTokenInformation(getPreviousToken(previousToken.token))
|
||||
property var previousToken3: generateTokenInformation(getPreviousToken(previousToken2.token))
|
||||
visible: currentToken.exists
|
||||
|
||||
// Focus handling.
|
||||
readonly property var lists: [objectPropertiesList, variablesList, constantsList, functionsList, executableObjectsList, objectsList]
|
||||
readonly property int itemCount: objectPropertiesList.model.length + variablesList.model.length + constantsList.model.length + functionsList.model.length + executableObjectsList.model.length + objectsList.model.length
|
||||
property int itemSelected: 0
|
||||
|
||||
/*!
|
||||
\qmlmethod var ExpressionEditor::generateTokenInformation(var token)
|
||||
Generates basic information about the given token (existence and type) used in autocompletion).
|
||||
*/
|
||||
function generateTokenInformation(token) {
|
||||
let exists = token != null
|
||||
return {
|
||||
'token': token,
|
||||
'exists': exists,
|
||||
'value': exists ? token.value : null,
|
||||
'type': exists ? token.type : null,
|
||||
'startPosition': exists ? token.startPosition : 0,
|
||||
'dot': exists ? (token.type == Parsing.TokenType.PUNCT && token.value == ".") : false,
|
||||
'identifier': exists ? identifierTokenTypes.includes(token.type) : false
|
||||
}
|
||||
}
|
||||
/*!
|
||||
\qmlmethod void ExpressionEditor::autocompleteInfoAt(int idx)
|
||||
Returns the autocompletion text information at a given position.
|
||||
The information contains key 'text' (description text), 'autocomplete' (text to insert)
|
||||
and 'cursorFinalOffset' (amount to add to the cursor's position after the end of the autocomplete)
|
||||
*/
|
||||
function autocompleteInfoAt(idx) {
|
||||
if(idx >= itemCount) return ""
|
||||
let startIndex = 0
|
||||
for(let list of lists) {
|
||||
if(idx < startIndex + list.model.length)
|
||||
return list.model[idx-startIndex]
|
||||
startIndex += list.model.length
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod void ExpressionEditor::autocomplete()
|
||||
Autocompletes with the current selected word.
|
||||
*/
|
||||
function autocomplete() {
|
||||
let autotext = autocompleteInfoAt(itemSelected)
|
||||
let startPos = currentToken.startPosition
|
||||
console.log("Replacing", currentToken.value, "at", startPos, "with", autotext.autocomplete)
|
||||
editor.remove(startPos, startPos+currentToken.value.length)
|
||||
editor.insert(startPos, autotext.autocomplete)
|
||||
editor.cursorPosition = startPos+autotext.autocomplete.length+autotext.cursorFinalOffset
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod var ExpressionEditor::getPreviousToken(var token)
|
||||
Returns the token before this one.
|
||||
*/
|
||||
function getPreviousToken(token) {
|
||||
let newToken = getTokenAt(editor.tokens, token.startPosition)
|
||||
if(newToken != null && newToken.type == Parsing.TokenType.WHITESPACE)
|
||||
return getPreviousToken(newToken)
|
||||
return newToken
|
||||
}
|
||||
|
||||
AutocompletionCategory {
|
||||
id: objectPropertiesList
|
||||
|
||||
category: qsTr("Object Properties")
|
||||
visbilityCondition: control.allowGraphObjects && doesObjectExist
|
||||
itemStartIndex: 0
|
||||
itemSelected: parent.itemSelected
|
||||
property bool isEnteringProperty: (
|
||||
// Current token is dot.
|
||||
(parent.currentToken.dot && parent.previousToken.identifier && !parent.previousToken2.dot) ||
|
||||
// Current token is property identifier
|
||||
(parent.currentToken.identifier && parent.previousToken.dot && parent.previousToken2.identifier && !parent.previousToken3.dot))
|
||||
property string objectName: isEnteringProperty ?
|
||||
(parent.currentToken.dot ? parent.previousToken.value : parent.previousToken2.value)
|
||||
: ""
|
||||
property bool doesObjectExist: isEnteringProperty && (objectName in Modules.Objects.currentObjectsByName)
|
||||
property var objectProperties: doesObjectExist ?
|
||||
Modules.Objects.currentObjectsByName[objectName].constructor.properties() :
|
||||
{}
|
||||
categoryItems: Object.keys(objectProperties)
|
||||
autocompleteGenerator: (item) => {
|
||||
let propType = objectProperties[item]
|
||||
return {
|
||||
'text': item, 'annotation': propType == null ? '' : propType.toString(),
|
||||
'autocomplete': parent.currentToken.dot ? `.${item} ` : `${item} `,
|
||||
'cursorFinalOffset': 0
|
||||
}
|
||||
|
||||
}
|
||||
baseText: parent.visible && !parent.currentToken.dot ? parent.currentToken.value : ""
|
||||
}
|
||||
|
||||
AutocompletionCategory {
|
||||
id: variablesList
|
||||
|
||||
category: qsTr("Variables")
|
||||
visbilityCondition: parent.currentToken.identifier && !parent.previousToken.dot
|
||||
itemStartIndex: objectPropertiesList.model.length
|
||||
itemSelected: parent.itemSelected
|
||||
categoryItems: control.variables
|
||||
autocompleteGenerator: (item) => {return {
|
||||
'text': item, 'annotation': '',
|
||||
'autocomplete': item + " ", 'cursorFinalOffset': 0
|
||||
}}
|
||||
baseText: parent.visible ? parent.currentToken.value : ""
|
||||
}
|
||||
|
||||
AutocompletionCategory {
|
||||
id: constantsList
|
||||
|
||||
category: qsTr("Constants")
|
||||
visbilityCondition: parent.currentToken.identifier && !parent.previousToken.dot
|
||||
itemStartIndex: variablesList.itemStartIndex + variablesList.model.length
|
||||
itemSelected: parent.itemSelected
|
||||
categoryItems: Parsing.CONSTANTS_LIST
|
||||
autocompleteGenerator: (item) => {return {
|
||||
'text': item, 'annotation': Parsing.CONSTANTS[item],
|
||||
'autocomplete': item + " ", 'cursorFinalOffset': 0
|
||||
}}
|
||||
baseText: parent.visible ? parent.currentToken.value : ""
|
||||
}
|
||||
|
||||
AutocompletionCategory {
|
||||
id: functionsList
|
||||
|
||||
category: qsTr("Functions")
|
||||
visbilityCondition: parent.currentToken.identifier && !parent.previousToken.dot
|
||||
itemStartIndex: constantsList.itemStartIndex + constantsList.model.length
|
||||
itemSelected: parent.itemSelected
|
||||
categoryItems: Parsing.FUNCTIONS_LIST
|
||||
autocompleteGenerator: (item) => {return {
|
||||
'text': item, 'annotation': Parsing.FUNCTIONS_USAGE[item].join(', '),
|
||||
'autocomplete': item+'()', 'cursorFinalOffset': -1
|
||||
}}
|
||||
baseText: parent.visible ? parent.currentToken.value : ""
|
||||
}
|
||||
|
||||
AutocompletionCategory {
|
||||
id: executableObjectsList
|
||||
|
||||
category: qsTr("Executable Objects")
|
||||
visbilityCondition: control.allowGraphObjects && parent.currentToken.identifier && !parent.previousToken.dot
|
||||
itemStartIndex: functionsList.itemStartIndex + functionsList.model.length
|
||||
itemSelected: parent.itemSelected
|
||||
categoryItems: Modules.Objects.getObjectsName("ExecutableObject").filter(obj => obj != self)
|
||||
autocompleteGenerator: (item) => {return {
|
||||
'text': item, 'annotation': Modules.Objects.currentObjectsByName[item] == null ? '' : Modules.Objects.currentObjectsByName[item].constructor.displayType(),
|
||||
'autocomplete': item+'()', 'cursorFinalOffset': -1
|
||||
}}
|
||||
baseText: parent.visible ? parent.currentToken.value : ""
|
||||
}
|
||||
|
||||
AutocompletionCategory {
|
||||
id: objectsList
|
||||
|
||||
category: qsTr("Objects")
|
||||
visbilityCondition: control.allowGraphObjects && parent.currentToken.identifier && !parent.previousToken.dot
|
||||
itemStartIndex: executableObjectsList.itemStartIndex + executableObjectsList.model.length
|
||||
itemSelected: parent.itemSelected
|
||||
categoryItems: Object.keys(Modules.Objects.currentObjectsByName).filter(obj => obj != self)
|
||||
autocompleteGenerator: (item) => {return {
|
||||
'text': item, 'annotation': `${Modules.Objects.currentObjectsByName[item].constructor.displayType()}`,
|
||||
'autocomplete': item+'.', 'cursorFinalOffset': 0
|
||||
}}
|
||||
baseText: parent.visible ? parent.currentToken.value : ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: insertButton
|
||||
text: "α"
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 5
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 20
|
||||
height: width
|
||||
onClicked: {
|
||||
insertPopup.open()
|
||||
insertPopup.focus = true
|
||||
}
|
||||
}
|
||||
|
||||
P.InsertCharacter {
|
||||
id: insertPopup
|
||||
|
||||
x: Math.round((parent.width - width) / 2)
|
||||
y: Math.round((parent.height - height) / 2)
|
||||
|
||||
category: "expression"
|
||||
|
||||
onSelected: function(c) {
|
||||
editor.insert(editor.cursorPosition, c)
|
||||
insertPopup.close()
|
||||
focus = false
|
||||
editor.focus = true
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod var ExpressionEditor::parse(string newExpression)
|
||||
Parses the \c newExpression as an expression, checks for errors, shows them if any.
|
||||
Returns the parsed expression if possible, null otherwise..
|
||||
*/
|
||||
function parse(newExpression) {
|
||||
let expr = null
|
||||
try {
|
||||
expr = new MathLib.Expression(value.toString())
|
||||
// Check if the expression is valid, throws error otherwise.
|
||||
if(!expr.allRequirementsFullfilled()) {
|
||||
let undefVars = expr.undefinedVariables()
|
||||
if(undefVars.length > 1)
|
||||
throw new Error(qsTranslate('error', 'No object found with names %1.').arg(undefVars.join(', ')))
|
||||
else
|
||||
throw new Error(qsTranslate('error', 'No object found with name %1.').arg(undefVars.join(', ')))
|
||||
}
|
||||
if(expr.requiredObjects().includes(control.self))
|
||||
throw new Error(qsTranslate('error', 'Object cannot be dependent on itself.'))
|
||||
// Recursive dependencies
|
||||
let dependentOnSelfObjects = expr.requiredObjects().filter(
|
||||
(obj) => Modules.Objects.currentObjectsByName[obj].getDependenciesList()
|
||||
.includes(Modules.Objects.currentObjectsByName[control.self])
|
||||
)
|
||||
if(dependentOnSelfObjects.length == 1)
|
||||
throw new Error(qsTranslate('error', 'Circular dependency detected. Object %1 depends on %2.').arg(dependentOnSelfObjects[0].toString()).arg(control.self))
|
||||
else if(dependentOnSelfObjects.length > 1)
|
||||
throw new Error(qsTranslate('error', 'Circular dependency detected. Objects %1 depend on %2.').arg(dependentOnSelfObjects.map(obj => obj.toString()).join(', ')).arg(control.self))
|
||||
//console.log(control.self, propertyName, expr.execute())
|
||||
return expr
|
||||
} catch(e) {
|
||||
// Error in expression
|
||||
parsingErrorDialog.showDialog(propertyName, newExpression, e.message)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod var ExpressionEditor::tokens(string expressionText)
|
||||
Generates a list of tokens from the given.
|
||||
*/
|
||||
function tokens(text) {
|
||||
let tokenizer = new Parsing.Tokenizer(new Parsing.Input(text), true, false)
|
||||
let tokenList = []
|
||||
let token
|
||||
while((token = tokenizer.next()) != null)
|
||||
tokenList.push(token)
|
||||
return tokenList
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod var ExpressionEditor::getTokenAt(var tokens, int position)
|
||||
Gets the token at the given position within the text.
|
||||
Returns null if out of bounds.
|
||||
*/
|
||||
function getTokenAt(tokenList, position) {
|
||||
let currentPosition = 0
|
||||
for(let token of tokenList)
|
||||
if(position <= (currentPosition + token.value.length))
|
||||
return token
|
||||
else
|
||||
currentPosition += token.value.length
|
||||
return null
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod var ExpressionEditor::colorize(var tokenList)
|
||||
Creates an HTML colorized string of the given tokens.
|
||||
Returns the colorized and escaped expression if possible, null otherwise..
|
||||
*/
|
||||
function colorize(tokenList) {
|
||||
let parsedText = ""
|
||||
let scheme = colorSchemes[Helper.getSettingInt("expression_editor.color_scheme")]
|
||||
for(let token of tokenList) {
|
||||
switch(token.type) {
|
||||
case Parsing.TokenType.VARIABLE:
|
||||
parsedText += `<font color="${scheme.VARIABLE}">${token.value}</font>`
|
||||
break;
|
||||
case Parsing.TokenType.CONSTANT:
|
||||
parsedText += `<font color="${scheme.CONSTANT}">${token.value}</font>`
|
||||
break;
|
||||
case Parsing.TokenType.FUNCTION:
|
||||
parsedText += `<font color="${scheme.FUNCTION}">${Utils.escapeHTML(token.value)}</font>`
|
||||
break;
|
||||
case Parsing.TokenType.OPERATOR:
|
||||
parsedText += `<font color="${scheme.OPERATOR}">${Utils.escapeHTML(token.value)}</font>`
|
||||
break;
|
||||
case Parsing.TokenType.NUMBER:
|
||||
parsedText += `<font color="${scheme.NUMBER}">${Utils.escapeHTML(token.value)}</font>`
|
||||
break;
|
||||
case Parsing.TokenType.STRING:
|
||||
parsedText += `<font color="${scheme.STRING}">${token.limitator}${Utils.escapeHTML(token.value)}${token.limitator}</font>`
|
||||
break;
|
||||
case Parsing.TokenType.WHITESPACE:
|
||||
case Parsing.TokenType.PUNCT:
|
||||
default:
|
||||
parsedText += Utils.escapeHTML(token.value).replace(/ /g, ' ')
|
||||
break;
|
||||
}
|
||||
}
|
||||
return parsedText
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
import QtQuick.Window
|
||||
import QtQuick.Controls.impl
|
||||
|
||||
/*!
|
||||
\qmltype Icon
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.Setting
|
||||
\brief Colorable image.
|
||||
|
||||
\sa ComboBoxSetting, ListSetting, TextSetting
|
||||
*/
|
||||
Item {
|
||||
/*!
|
||||
\qmlproperty string Icon::color
|
||||
Overlay color of the icon.
|
||||
*/
|
||||
property color color: "#000000"
|
||||
/*!
|
||||
\qmlproperty string Icon::source
|
||||
Path of the icon image source.
|
||||
*/
|
||||
property alias source: img.source
|
||||
/*!
|
||||
\qmlproperty string Icon::source
|
||||
Path of the icon image source.
|
||||
*/
|
||||
property alias sourceSize: img.sourceS
|
||||
|
||||
ColorImage {
|
||||
id: img
|
||||
height: parent.height
|
||||
width: parent.width
|
||||
// visible: false
|
||||
property int sourceS: width*Screen.devicePixelRatio
|
||||
sourceSize.width: sourceS
|
||||
sourceSize.height: sourceS
|
||||
color: parent.color
|
||||
}
|
||||
}
|
|
@ -1,24 +1,100 @@
|
|||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQml.Models 2.12
|
||||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
import QtQuick.Controls
|
||||
import QtQml.Models
|
||||
|
||||
/*!
|
||||
\qmltype ListSetting
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.Setting
|
||||
\brief Setting to create and edit lists and dictionaries.
|
||||
|
||||
\sa EditorDialog, Settings, Icon
|
||||
*/
|
||||
Column {
|
||||
id: control
|
||||
|
||||
/*!
|
||||
\qmlsignal ListSetting::changed()
|
||||
|
||||
Emitted when an entry of the setting has been changed.
|
||||
The corresponding handler is \c onChanged.
|
||||
*/
|
||||
signal changed()
|
||||
|
||||
/*!
|
||||
\qmlproperty string ListSetting::label
|
||||
Label of the setting.
|
||||
*/
|
||||
property string label: ''
|
||||
/*!
|
||||
\qmlproperty string ListSetting::icon
|
||||
Icon path of the setting.
|
||||
*/
|
||||
property string icon: ''
|
||||
/*!
|
||||
\qmlproperty bool ListSetting::dictionaryMode
|
||||
true to set the export mode to dictionary, false for list.
|
||||
*/
|
||||
property bool dictionaryMode: false
|
||||
/*!
|
||||
\qmlproperty string ListSetting::keyType
|
||||
Type for keys for dictionary, can be either "string" or "number".
|
||||
*/
|
||||
property string keyType: "string"
|
||||
/*!
|
||||
\qmlproperty string ListSetting::keyType
|
||||
Type for values of the dictionary or list, can be either "string" or "number".
|
||||
*/
|
||||
property string valueType: "string"
|
||||
/*!
|
||||
\qmlproperty string ListSetting::preKeyLabel
|
||||
Text to be put before the key for each entry.
|
||||
*/
|
||||
property string preKeyLabel: ""
|
||||
/*!
|
||||
\qmlproperty string ListSetting::postKeyLabel
|
||||
Text to be put after the key for each entry. Only for dictionaries.
|
||||
*/
|
||||
property string postKeyLabel: ": "
|
||||
/*!
|
||||
\qmlproperty var ListSetting::keyRegexp
|
||||
Regular expression used in the validator for keys. Only for dictionaries.
|
||||
*/
|
||||
property var keyRegexp: /^.+$/
|
||||
/*!
|
||||
\qmlproperty var ListSetting::valueRegexp
|
||||
Regular expression used in the validator for values.
|
||||
*/
|
||||
property var valueRegexp: /^.+$/
|
||||
/*!
|
||||
\qmlproperty bool ListSetting::forbidAdding
|
||||
If true, prevents the user from adding or removing new entries.
|
||||
*/
|
||||
property bool forbidAdding: false
|
||||
|
||||
/*!
|
||||
\qmlproperty bool ListSetting::model
|
||||
Model of the list/dictionnary, in the form of [{key: < key >, val: < value > }].
|
||||
|
||||
Use the \a importModel method to set the model.
|
||||
*/
|
||||
property alias model: repeater.model
|
||||
|
||||
Row {
|
||||
|
@ -28,7 +104,7 @@ Column {
|
|||
id: iconLabel
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: icon == "" ? 0 : 3
|
||||
source: control.visible ? control.icon : ""
|
||||
source: control.visible ? "../icons/" + control.icon : ""
|
||||
width: height
|
||||
height: icon == "" || !visible ? 0 : 24
|
||||
color: sysPalette.windowText
|
||||
|
@ -37,7 +113,7 @@ Column {
|
|||
id: labelItem
|
||||
height: 30
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
text: control.label +": "
|
||||
text: qsTranslate("control", "%1: ").arg(control.label)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,8 +140,8 @@ Column {
|
|||
visible: control.dictionaryMode
|
||||
height: parent.height
|
||||
width: visible ? 50 : 0
|
||||
validator: RegExpValidator {
|
||||
regExp: control.keyRegexp
|
||||
validator: RegularExpressionValidator {
|
||||
regularExpression: control.keyRegexp
|
||||
}
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
horizontalAlignment: TextInput.AlignHCenter
|
||||
|
@ -104,8 +180,8 @@ Column {
|
|||
id: valueInput
|
||||
height: parent.height
|
||||
width: parent.width - x - deleteButton.width - 5
|
||||
validator: RegExpValidator {
|
||||
regExp: control.valueRegexp
|
||||
validator: RegularExpressionValidator {
|
||||
regularExpression: control.valueRegexp
|
||||
}
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
horizontalAlignment: TextInput.AlignHCenter
|
||||
|
@ -140,7 +216,7 @@ Column {
|
|||
id: deleteButton
|
||||
width: visible ? parent.height : 0
|
||||
height: width
|
||||
icon.source: './icons/delete.svg'
|
||||
icon.source: './icons/common/delete.svg'
|
||||
icon.name: 'delete'
|
||||
visible: !control.forbidAdding
|
||||
|
||||
|
@ -154,7 +230,7 @@ Column {
|
|||
Button {
|
||||
id: addEntryBtn
|
||||
visible: !control.forbidAdding
|
||||
text: '+ Add Entry'
|
||||
text: qsTr('+ Add Entry')
|
||||
width: control.width
|
||||
|
||||
onClicked: {
|
||||
|
@ -165,6 +241,10 @@ Column {
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod void ListSetting::importModel(var importer)
|
||||
Imports either a list or a dictionnary in the model.
|
||||
*/
|
||||
function importModel(importer) {
|
||||
model.clear()
|
||||
for(var key in importer)
|
||||
|
@ -174,6 +254,11 @@ Column {
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\qmlmethod void ListSetting::exportModel()
|
||||
Exports the model either a list or a dictionnary in the model depending on \a dictionaryMode.
|
||||
*/
|
||||
function exportModel() {
|
||||
if(dictionaryMode) {
|
||||
var ret = {}
|
|
@ -0,0 +1,173 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 Ad5001
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick.Controls
|
||||
import QtQuick
|
||||
import eu.ad5001.LogarithmPlotter.Popup 1.0 as Popup
|
||||
|
||||
/*!
|
||||
\qmltype TextSetting
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter.Setting
|
||||
\brief Setting to edit strings and numbers.
|
||||
|
||||
\sa EditorDialog, Settings, Icon
|
||||
*/
|
||||
Item {
|
||||
id: control
|
||||
height: 30
|
||||
|
||||
/*!
|
||||
\qmlsignal TextSetting::changed(string newValue)
|
||||
|
||||
Emitted when the value of the text has been changed.
|
||||
The corresponding handler is \c onChanged.
|
||||
*/
|
||||
signal changed(string newValue)
|
||||
|
||||
/*!
|
||||
\qmlproperty bool TextSetting::isInt
|
||||
If true, the input is being parsed an int before being emitting the \a changed signal.
|
||||
*/
|
||||
property bool isInt: false
|
||||
/*!
|
||||
\qmlproperty bool TextSetting::isDouble
|
||||
If true, the input is being parsed an double before being emitting the \a changed signal.
|
||||
*/
|
||||
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
|
||||
Minimum value for numbers that can be entered into the input.
|
||||
*/
|
||||
property double min: -1
|
||||
/*!
|
||||
\qmlproperty string TextSetting::defValue
|
||||
Default value of the input.
|
||||
*/
|
||||
property string defValue
|
||||
/*!
|
||||
\qmlproperty string TextSetting::value
|
||||
Value of the input.
|
||||
*/
|
||||
property alias value: input.text
|
||||
/*!
|
||||
\qmlproperty string TextSetting::placeholderText
|
||||
Value of the input.
|
||||
*/
|
||||
property alias placeholderText: input.placeholderText
|
||||
/*!
|
||||
\qmlproperty string TextSetting::label
|
||||
Label of the setting.
|
||||
*/
|
||||
property string label
|
||||
/*!
|
||||
\qmlproperty string TextSetting::icon
|
||||
Icon path of the setting.
|
||||
*/
|
||||
property string icon: ""
|
||||
|
||||
Icon {
|
||||
id: iconLabel
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: icon == "" ? 0 : 3
|
||||
source: control.visible && icon != "" ? "../icons/" + control.icon : ""
|
||||
width: height
|
||||
height: icon == "" || !visible ? 0 : 24
|
||||
color: sysPalette.windowText
|
||||
}
|
||||
|
||||
Label {
|
||||
id: labelItem
|
||||
anchors.left: iconLabel.right
|
||||
anchors.leftMargin: icon == "" ? 0 : 5
|
||||
anchors.top: parent.top
|
||||
height: parent.height
|
||||
width: visible ? Math.max(85, implicitWidth) : 0
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
//color: sysPalette.windowText
|
||||
text: visible ? qsTranslate("control", "%1: ").arg(control.label) : ""
|
||||
visible: control.label != ""
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: input
|
||||
anchors.top: parent.top
|
||||
anchors.left: labelItem.right
|
||||
anchors.leftMargin: 5
|
||||
width: control.width - (labelItem.visible ? labelItem.width + 5 : 0) - iconLabel.width - 5
|
||||
height: parent.height
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
horizontalAlignment: control.label == "" ? TextInput.AlignLeft : TextInput.AlignHCenter
|
||||
color: sysPalette.windowText
|
||||
validator: RegularExpressionValidator {
|
||||
regularExpression: control.isInt ? /-?[0-9]+/ : control.isDouble ? /-?[0-9]+(\.[0-9]+)?/ : /.+/
|
||||
}
|
||||
focus: true
|
||||
text: control.defValue
|
||||
selectByMouse: true
|
||||
onEditingFinished: function() {
|
||||
if(insertButton.focus || insertPopup.focus) return
|
||||
let value = text
|
||||
if(control.isInt) {
|
||||
let parsed = parseInt(value)
|
||||
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)
|
||||
defValue = value.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: insertButton
|
||||
text: "α"
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 5
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 20
|
||||
height: width
|
||||
visible: !isInt && !isDouble
|
||||
onClicked: {
|
||||
insertPopup.open()
|
||||
insertPopup.focus = true
|
||||
}
|
||||
}
|
||||
|
||||
Popup.InsertCharacter {
|
||||
id: insertPopup
|
||||
|
||||
x: Math.round((parent.width - width) / 2)
|
||||
y: Math.round((parent.height - height) / 2)
|
||||
|
||||
onSelected: function(c) {
|
||||
input.insert(input.cursorPosition, c)
|
||||
insertPopup.close()
|
||||
focus = false
|
||||
input.focus = true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
module eu.ad5001.LogarithmPlotter.Setting
|
||||
|
||||
AutocompletionCategory 1.0 AutocompletionCategory.qml
|
||||
ComboBoxSetting 1.0 ComboBoxSetting.qml
|
||||
ExpressionEditor 1.0 ExpressionEditor.qml
|
||||
Icon 1.0 Icon.qml
|
||||
ListSetting 1.0 ListSetting.qml
|
||||
TextSetting 1.0 TextSetting.qml
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
|
@ -16,11 +16,21 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Dialogs 1.1
|
||||
import "js/utils.js" as Utils
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
import eu.ad5001.LogarithmPlotter.Popup 1.0 as Popup
|
||||
import "js/utils.mjs" as Utils
|
||||
|
||||
/*!
|
||||
\qmltype Settings
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter
|
||||
\brief Tab of the drawer that allows the user to customize how the diagram looks.
|
||||
|
||||
All canvas settings can found in this scrollable view, as well as buttons to copy and save the graph.
|
||||
|
||||
\sa LogarithmPlotter, LogGraphCanvas
|
||||
*/
|
||||
ScrollView {
|
||||
id: settings
|
||||
|
||||
|
@ -29,51 +39,128 @@ ScrollView {
|
|||
property int settingWidth: settings.width - ScrollBar.vertical.width
|
||||
property Canvas canvas
|
||||
|
||||
property double xzoom: 100
|
||||
property double yzoom: 10
|
||||
property double xmin: 5/10
|
||||
property double ymax: 25
|
||||
property string xaxisstep: "4"
|
||||
property string yaxisstep: "4"
|
||||
property string xaxislabel: ""
|
||||
property string yaxislabel: ""
|
||||
property double linewidth: 1
|
||||
property double textsize: 14
|
||||
property bool logscalex: true
|
||||
/*!
|
||||
\qmlproperty double Settings::xzoom
|
||||
Zoom on the x axis of the diagram, provided from settings.
|
||||
\sa Settings
|
||||
*/
|
||||
property double xzoom: Helper.getSettingInt('default_graph.xzoom')
|
||||
/*!
|
||||
\qmlproperty double Settings::yzoom
|
||||
Zoom on the y axis of the diagram, provided from settings.
|
||||
\sa Settings
|
||||
*/
|
||||
property double yzoom: Helper.getSettingInt('default_graph.yzoom')
|
||||
/*!
|
||||
\qmlproperty double Settings::xmin
|
||||
Minimum x of the diagram, provided from settings.
|
||||
\sa Settings
|
||||
*/
|
||||
property double xmin: Helper.getSettingInt('default_graph.xmin')
|
||||
/*!
|
||||
\qmlproperty double Settings::ymax
|
||||
Maximum y of the diagram, provided from settings.
|
||||
\sa Settings
|
||||
*/
|
||||
property double ymax: Helper.getSettingInt('default_graph.ymax')
|
||||
/*!
|
||||
\qmlproperty string Settings::xaxisstep
|
||||
Step of the x axis graduation, provided from settings.
|
||||
\note: Only available in non-logarithmic mode.
|
||||
\sa Settings
|
||||
*/
|
||||
property string xaxisstep: Helper.getSetting('default_graph.xaxisstep')
|
||||
/*!
|
||||
\qmlproperty string Settings::yaxisstep
|
||||
Step of the y axis graduation, provided from settings.
|
||||
\sa Settings
|
||||
*/
|
||||
property string yaxisstep: Helper.getSetting('default_graph.yaxisstep')
|
||||
/*!
|
||||
\qmlproperty string Settings::xlabel
|
||||
Label used on the x axis, provided from settings.
|
||||
\sa Settings
|
||||
*/
|
||||
property string xlabel: Helper.getSetting('default_graph.xlabel')
|
||||
/*!
|
||||
\qmlproperty string Settings::ylabel
|
||||
Label used on the y axis, provided from settings.
|
||||
\sa Settings
|
||||
*/
|
||||
property string ylabel: Helper.getSetting('default_graph.ylabel')
|
||||
/*!
|
||||
\qmlproperty double Settings::linewidth
|
||||
Width of lines that will be drawn into the canvas, provided from settings.
|
||||
\sa Settings
|
||||
*/
|
||||
property double linewidth: Helper.getSettingInt('default_graph.linewidth')
|
||||
/*!
|
||||
\qmlproperty double Settings::textsize
|
||||
Font size of the text that will be drawn into the canvas, provided from settings.
|
||||
\sa Settings
|
||||
*/
|
||||
property double textsize: Helper.getSettingInt('default_graph.textsize')
|
||||
/*!
|
||||
\qmlproperty bool Settings::logscalex
|
||||
true if the canvas should be in logarithmic mode, false otherwise.
|
||||
Provided from settings.
|
||||
\sa Settings
|
||||
*/
|
||||
property bool logscalex: Helper.getSettingBool('default_graph.logscalex')
|
||||
/*!
|
||||
\qmlproperty bool Settings::showxgrad
|
||||
true if the x graduation should be shown, false otherwise.
|
||||
Provided from settings.
|
||||
\sa Settings
|
||||
*/
|
||||
property bool showxgrad: Helper.getSettingBool('default_graph.showxgrad')
|
||||
/*!
|
||||
\qmlproperty bool Settings::showygrad
|
||||
true if the y graduation should be shown, false otherwise.
|
||||
Provided from settings.
|
||||
\sa Settings
|
||||
*/
|
||||
property bool showygrad: Helper.getSettingBool('default_graph.showygrad')
|
||||
/*!
|
||||
\qmlproperty bool Settings::saveFilename
|
||||
Path of the currently opened file. Empty if no file is opened.
|
||||
*/
|
||||
property string saveFilename: ""
|
||||
property bool showxgrad: true
|
||||
property bool showygrad: true
|
||||
|
||||
Component.onCompleted: {
|
||||
Modules.IO.initialize({ root, settings, alert })
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: 10
|
||||
width: parent.width
|
||||
bottomPadding: 20
|
||||
|
||||
FileDialog {
|
||||
Popup.FileDialog {
|
||||
id: fdiag
|
||||
onAccepted: {
|
||||
var filePath = fileUrl.toString().substr(7)
|
||||
var filePath = fdiag.currentFile.toString().substr(7)
|
||||
settings.saveFilename = filePath
|
||||
if(exportMode) {
|
||||
root.saveDiagram(filePath)
|
||||
Modules.IO.saveDiagram(filePath)
|
||||
} else {
|
||||
root.loadDiagram(filePath)
|
||||
if(xAxisLabel.find(settings.xaxislabel) == -1) xAxisLabel.model.append({text: settings.xaxislabel})
|
||||
xAxisLabel.editText = settings.xaxislabel
|
||||
if(yAxisLabel.find(settings.yaxislabel) == -1) yAxisLabel.model.append({text: settings.yaxislabel})
|
||||
yAxisLabel.editText = settings.yaxislabel
|
||||
Modules.IO.loadDiagram(filePath)
|
||||
if(xAxisLabel.find(settings.xlabel) == -1) xAxisLabel.model.append({text: settings.xlabel})
|
||||
xAxisLabel.editText = settings.xlabel
|
||||
if(yAxisLabel.find(settings.ylabel) == -1) yAxisLabel.model.append({text: settings.ylabel})
|
||||
yAxisLabel.editText = settings.ylabel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Zoom
|
||||
TextSetting {
|
||||
Setting.TextSetting {
|
||||
id: zoomX
|
||||
height: 30
|
||||
isDouble: true
|
||||
label: qsTr("X Zoom")
|
||||
min: 1
|
||||
icon: "icons/settings/xzoom.svg"
|
||||
min: 0.1
|
||||
icon: "settings/xzoom.svg"
|
||||
width: settings.settingWidth
|
||||
value: settings.xzoom.toFixed(2)
|
||||
onChanged: function(newValue) {
|
||||
|
@ -82,12 +169,13 @@ ScrollView {
|
|||
}
|
||||
}
|
||||
|
||||
TextSetting {
|
||||
Setting.TextSetting {
|
||||
id: zoomY
|
||||
height: 30
|
||||
isDouble: true
|
||||
min: 0.1
|
||||
label: qsTr("Y Zoom")
|
||||
icon: "icons/settings/yzoom.svg"
|
||||
icon: "settings/yzoom.svg"
|
||||
width: settings.settingWidth
|
||||
value: settings.yzoom.toFixed(2)
|
||||
onChanged: function(newValue) {
|
||||
|
@ -97,13 +185,13 @@ ScrollView {
|
|||
}
|
||||
|
||||
// Positioning the graph
|
||||
TextSetting {
|
||||
Setting.TextSetting {
|
||||
id: minX
|
||||
height: 30
|
||||
isDouble: true
|
||||
min: -Infinity
|
||||
label: qsTr("Min X")
|
||||
icon: "icons/settings/xmin.svg"
|
||||
icon: "settings/xmin.svg"
|
||||
width: settings.settingWidth
|
||||
defValue: settings.xmin
|
||||
onChanged: function(newValue) {
|
||||
|
@ -116,13 +204,13 @@ ScrollView {
|
|||
}
|
||||
}
|
||||
|
||||
TextSetting {
|
||||
Setting.TextSetting {
|
||||
id: maxY
|
||||
height: 30
|
||||
isDouble: true
|
||||
min: -Infinity
|
||||
label: qsTr("Max Y")
|
||||
icon: "icons/settings/ymax.svg"
|
||||
icon: "settings/ymax.svg"
|
||||
width: settings.settingWidth
|
||||
defValue: settings.ymax
|
||||
onChanged: function(newValue) {
|
||||
|
@ -131,18 +219,18 @@ ScrollView {
|
|||
}
|
||||
}
|
||||
|
||||
TextSetting {
|
||||
Setting.TextSetting {
|
||||
id: maxX
|
||||
height: 30
|
||||
isDouble: true
|
||||
min: -Infinity
|
||||
label: qsTr("Max X")
|
||||
icon: "icons/settings/xmax.svg"
|
||||
icon: "settings/xmax.svg"
|
||||
width: settings.settingWidth
|
||||
value: canvas.px2x(canvas.canvasSize.width).toFixed(2)
|
||||
defValue: Modules.Canvas.px2x(canvas.width).toFixed(2)
|
||||
onChanged: function(xvaluemax) {
|
||||
if(xvaluemax > settings.xmin) {
|
||||
settings.xzoom = settings.xzoom * canvas.canvasSize.width/(canvas.x2px(xvaluemax)) // Adjusting zoom to fit. = (end)/(px of current point)
|
||||
settings.xzoom = settings.xzoom * canvas.width/(Modules.Canvas.x2px(xvaluemax)) // Adjusting zoom to fit. = (end)/(px of current point)
|
||||
settings.changed()
|
||||
} else {
|
||||
alert.show("Maximum x value must be superior to minimum.")
|
||||
|
@ -150,18 +238,18 @@ ScrollView {
|
|||
}
|
||||
}
|
||||
|
||||
TextSetting {
|
||||
Setting.TextSetting {
|
||||
id: minY
|
||||
height: 30
|
||||
isDouble: true
|
||||
min: -Infinity
|
||||
label: qsTr("Min Y")
|
||||
icon: "icons/settings/ymin.svg"
|
||||
icon: "settings/ymin.svg"
|
||||
width: settings.settingWidth
|
||||
defValue: canvas.px2y(canvas.canvasSize.height).toFixed(2)
|
||||
defValue: Modules.Canvas.px2y(canvas.height).toFixed(2)
|
||||
onChanged: function(yvaluemin) {
|
||||
if(yvaluemin < settings.ymax) {
|
||||
settings.yzoom = settings.yzoom * canvas.canvasSize.height/(canvas.y2px(yvaluemin)) // Adjusting zoom to fit. = (end)/(px of current point)
|
||||
settings.yzoom = settings.yzoom * canvas.height/(Modules.Canvas.y2px(yvaluemin)) // Adjusting zoom to fit. = (end)/(px of current point)
|
||||
settings.changed()
|
||||
} else {
|
||||
alert.show("Minimum y value must be inferior to maximum.")
|
||||
|
@ -169,11 +257,12 @@ ScrollView {
|
|||
}
|
||||
}
|
||||
|
||||
TextSetting {
|
||||
Setting.TextSetting {
|
||||
id: xAxisStep
|
||||
height: 30
|
||||
category: "expression"
|
||||
label: qsTr("X Axis Step")
|
||||
icon: "icons/settings/xaxisstep.svg"
|
||||
icon: "settings/xaxisstep.svg"
|
||||
width: settings.settingWidth
|
||||
defValue: settings.xaxisstep
|
||||
visible: !settings.logscalex
|
||||
|
@ -183,11 +272,12 @@ ScrollView {
|
|||
}
|
||||
}
|
||||
|
||||
TextSetting {
|
||||
Setting.TextSetting {
|
||||
id: yAxisStep
|
||||
height: 30
|
||||
category: "expression"
|
||||
label: qsTr("Y Axis Step")
|
||||
icon: "icons/settings/yaxisstep.svg"
|
||||
icon: "settings/yaxisstep.svg"
|
||||
width: settings.settingWidth
|
||||
defValue: settings.yaxisstep
|
||||
onChanged: function(newValue) {
|
||||
|
@ -196,13 +286,13 @@ ScrollView {
|
|||
}
|
||||
}
|
||||
|
||||
TextSetting {
|
||||
Setting.TextSetting {
|
||||
id: lineWidth
|
||||
height: 30
|
||||
isDouble: true
|
||||
label: qsTr("Line width")
|
||||
min: 1
|
||||
icon: "icons/settings/linewidth.svg"
|
||||
icon: "settings/linewidth.svg"
|
||||
width: settings.settingWidth
|
||||
defValue: settings.linewidth
|
||||
onChanged: function(newValue) {
|
||||
|
@ -211,13 +301,13 @@ ScrollView {
|
|||
}
|
||||
}
|
||||
|
||||
TextSetting {
|
||||
Setting.TextSetting {
|
||||
id: textSize
|
||||
height: 30
|
||||
isDouble: true
|
||||
label: qsTr("Text size (px)")
|
||||
min: 1
|
||||
icon: "icons/settings/textsize.svg"
|
||||
icon: "settings/textsize.svg"
|
||||
width: settings.settingWidth
|
||||
defValue: settings.textsize
|
||||
onChanged: function(newValue) {
|
||||
|
@ -226,38 +316,38 @@ ScrollView {
|
|||
}
|
||||
}
|
||||
|
||||
ComboBoxSetting {
|
||||
Setting.ComboBoxSetting {
|
||||
id: xAxisLabel
|
||||
height: 30
|
||||
width: settings.settingWidth
|
||||
label: qsTr('X Label')
|
||||
icon: "icons/settings/xlabel.svg"
|
||||
icon: "settings/xlabel.svg"
|
||||
model: ListModel {
|
||||
ListElement { text: "" }
|
||||
ListElement { text: "x" }
|
||||
ListElement { text: "ω (rad/s)" }
|
||||
}
|
||||
currentIndex: find(settings.xaxislabel)
|
||||
currentIndex: find(settings.xlabel)
|
||||
editable: true
|
||||
onAccepted: function(){
|
||||
editText = Utils.parseName(editText, false)
|
||||
if (find(editText) === -1) model.append({text: editText})
|
||||
settings.xaxislabel = editText
|
||||
settings.xlabel = editText
|
||||
settings.changed()
|
||||
}
|
||||
onActivated: function(selectedId) {
|
||||
settings.xaxislabel = model.get(selectedId).text
|
||||
settings.xlabel = model.get(selectedId).text
|
||||
settings.changed()
|
||||
}
|
||||
Component.onCompleted: editText = settings.xaxislabel
|
||||
Component.onCompleted: editText = settings.xlabel
|
||||
}
|
||||
|
||||
ComboBoxSetting {
|
||||
Setting.ComboBoxSetting {
|
||||
id: yAxisLabel
|
||||
height: 30
|
||||
width: settings.settingWidth
|
||||
label: qsTr('Y Label')
|
||||
icon: "icons/settings/ylabel.svg"
|
||||
icon: "settings/ylabel.svg"
|
||||
model: ListModel {
|
||||
ListElement { text: "" }
|
||||
ListElement { text: "y" }
|
||||
|
@ -266,19 +356,19 @@ ScrollView {
|
|||
ListElement { text: "φ (deg)" }
|
||||
ListElement { text: "φ (rad)" }
|
||||
}
|
||||
currentIndex: find(settings.yaxislabel)
|
||||
currentIndex: find(settings.ylabel)
|
||||
editable: true
|
||||
onAccepted: function(){
|
||||
editText = Utils.parseName(editText, false)
|
||||
if (find(editText) === -1) model.append({text: editText, yaxisstep: root.yaxisstep})
|
||||
settings.yaxislabel = editText
|
||||
settings.ylabel = editText
|
||||
settings.changed()
|
||||
}
|
||||
onActivated: function(selectedId) {
|
||||
settings.yaxislabel = model.get(selectedId).text
|
||||
settings.ylabel = model.get(selectedId).text
|
||||
settings.changed()
|
||||
}
|
||||
Component.onCompleted: editText = settings.yaxislabel
|
||||
Component.onCompleted: editText = settings.ylabel
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
|
@ -348,20 +438,32 @@ ScrollView {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\qmlmethod void LogGraphCanvas::save()
|
||||
Saves the current canvas in the opened file. If no file is currently opened, prompts to pick a save location.
|
||||
*/
|
||||
function save() {
|
||||
if(settings.saveFilename == "") {
|
||||
fdiag.exportMode = true
|
||||
fdiag.open()
|
||||
saveAs()
|
||||
} else {
|
||||
root.saveDiagram(settings.saveFilename)
|
||||
Modules.IO.saveDiagram(settings.saveFilename)
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod void LogGraphCanvas::saveAs()
|
||||
Prompts the user to pick a new save location.
|
||||
*/
|
||||
function saveAs() {
|
||||
fdiag.exportMode = true
|
||||
fdiag.open()
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod void LogGraphCanvas::saveAs()
|
||||
Prompts the user to pick a diagram to load.
|
||||
*/
|
||||
function load() {
|
||||
fdiag.exportMode = false
|
||||
fdiag.open()
|
||||
|
|
|
@ -1,140 +0,0 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
|
||||
* Copyright (C) 2022 Ad5001
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick 2.12
|
||||
|
||||
Item {
|
||||
id: control
|
||||
height: 30
|
||||
|
||||
signal changed(string newValue)
|
||||
|
||||
property bool isInt: false
|
||||
property bool isDouble: false
|
||||
property double min: -1
|
||||
property string label
|
||||
property string defValue
|
||||
property alias value: input.text
|
||||
property string icon: ""
|
||||
|
||||
Icon {
|
||||
id: iconLabel
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: icon == "" ? 0 : 3
|
||||
source: control.visible ? control.icon : ""
|
||||
width: height
|
||||
height: icon == "" || !visible ? 0 : 24
|
||||
color: sysPalette.windowText
|
||||
}
|
||||
|
||||
Label {
|
||||
id: labelItem
|
||||
anchors.left: iconLabel.right
|
||||
anchors.leftMargin: icon == "" ? 0 : 5
|
||||
height: parent.height
|
||||
anchors.top: parent.top
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
//color: sysPalette.windowText
|
||||
text: control.label +": "
|
||||
}
|
||||
|
||||
|
||||
TextField {
|
||||
id: input
|
||||
anchors.top: parent.top
|
||||
anchors.left: labelItem.right
|
||||
anchors.leftMargin: 5
|
||||
width: control.width - labelItem.width - iconLabel.width - 10
|
||||
height: parent.height
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
horizontalAlignment: TextInput.AlignHCenter
|
||||
color: sysPalette.windowText
|
||||
focus: true
|
||||
text: control.defValue
|
||||
selectByMouse: true
|
||||
onEditingFinished: {
|
||||
var value = text
|
||||
if(control.isInt) value = Math.max(control.min,parseInt(value).toString()=="NaN"?control.min:parseInt(value))
|
||||
if(control.isDouble) value = Math.max(control.min,parseFloat(value).toString()=="NaN"?control.min:parseFloat(value))
|
||||
if(value != "" && value.toString() != defValue) {
|
||||
control.changed(value)
|
||||
defValue = value.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "α"
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 5
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 20
|
||||
height: width
|
||||
visible: !isInt && !isDouble
|
||||
onClicked: insertPopup.open()
|
||||
}
|
||||
|
||||
Popup {
|
||||
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
|
||||
|
||||
Grid {
|
||||
id: insertGrid
|
||||
width: parent.width
|
||||
columns: 7
|
||||
|
||||
property var insertChars: [
|
||||
"α","β","γ","δ","ε","ζ","η",
|
||||
"π","θ","κ","λ","μ","ξ","ρ",
|
||||
"ς","σ","τ","φ","χ","ψ","ω",
|
||||
"Γ","Δ","Θ","Λ","Ξ","Π","Σ",
|
||||
"Φ","Ψ","Ω","ₐ","ₑ","ₒ","ₓ",
|
||||
"ₕ","ₖ","ₗ","ₘ","ₙ","ₚ","ₛ",
|
||||
"ₜ","¹","²","³","⁴","⁵","⁶",
|
||||
"⁷","⁸","⁹","⁰","₁","₂","₃",
|
||||
"₄","₅","₆","₇","₈","₉","₀"
|
||||
|
||||
]
|
||||
Repeater {
|
||||
model: parent.insertChars.length
|
||||
|
||||
Button {
|
||||
id: insertBtn
|
||||
width: insertGrid.width/insertGrid.columns
|
||||
height: width
|
||||
text: insertGrid.insertChars[modelData]
|
||||
flat: text == " "
|
||||
font.pixelSize: 18
|
||||
|
||||
onClicked: {
|
||||
input.insert(input.cursorPosition, insertGrid.insertChars[modelData])
|
||||
insertPopup.close()
|
||||
input.focus = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/**
|
||||
* LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
|
||||
* Copyright (C) 2021-2024 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
|
||||
import QtQuick.Controls
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
import "js/math/index.mjs" as MathLib
|
||||
import "js/history/index.mjs" as HistoryLib
|
||||
|
||||
/*!
|
||||
\qmltype ViewPositionChangeOverlay
|
||||
\inqmlmodule eu.ad5001.LogarithmPlotter
|
||||
\brief Overlay used allow the user to drag the canvas' position and change the zoom level.
|
||||
|
||||
Provides an overlay over the canvas that detects mouse movements and changes the canvas view position
|
||||
accordingly by providing new signals.
|
||||
|
||||
\sa LogarithmPlotter, LogGraphCanvas, Settings
|
||||
*/
|
||||
Item {
|
||||
id: viewChangeRoot
|
||||
visible: true
|
||||
clip: true
|
||||
|
||||
/*!
|
||||
\qmlsignal ViewPositionChangeOverlay::positionChanged(int deltaX, int deltaY)
|
||||
|
||||
Emmited when the user dragged the canvas and the view should be refreshed.
|
||||
The corresponding handler is \c onPositionChanged.
|
||||
*/
|
||||
signal positionChanged(int deltaX, int deltaY)
|
||||
|
||||
/*!
|
||||
\qmlsignal ViewPositionChangeOverlay::beginPositionChange()
|
||||
|
||||
Emmited when the user starts dragging the canvas.
|
||||
The corresponding handler is \c onBeginPositionChange.
|
||||
*/
|
||||
signal beginPositionChange()
|
||||
|
||||
/*!
|
||||
\qmlsignal ViewPositionChangeOverlay::endPositionChange(int deltaX, int deltaY)
|
||||
|
||||
Emmited when the user stops dragging the canvas.
|
||||
The corresponding handler is \c onEndPositionChange.
|
||||
*/
|
||||
signal endPositionChange(int deltaX, int deltaY)
|
||||
|
||||
/*!
|
||||
\qmlproperty var ViewPositionChangeOverlay::canvas
|
||||
LogGraphCanvas instance.
|
||||
*/
|
||||
property var canvas
|
||||
/*!
|
||||
\qmlproperty var ViewPositionChangeOverlay::settingsInstance
|
||||
Settings instance.
|
||||
*/
|
||||
property var settingsInstance
|
||||
/*!
|
||||
\qmlproperty int ViewPositionChangeOverlay::prevX
|
||||
The x coordinate (on the mousearea) at the last change of the canvas position.
|
||||
*/
|
||||
property int prevX
|
||||
/*!
|
||||
\qmlproperty int ViewPositionChangeOverlay::prevY
|
||||
The y coordinate (on the mousearea) at the last change of the canvas position.
|
||||
*/
|
||||
property int prevY
|
||||
/*!
|
||||
\qmlproperty double ViewPositionChangeOverlay::baseZoomMultiplier
|
||||
How much should the zoom be mutliplied/scrolled by for one scroll step (120° on the mouse wheel).
|
||||
*/
|
||||
property double baseZoomMultiplier: 0.1
|
||||
|
||||
MouseArea {
|
||||
id: dragArea
|
||||
anchors.fill: parent
|
||||
cursorShape: pressed ? Qt.ClosedHandCursor : Qt.OpenHandCursor
|
||||
property int positionChangeTimer: 0
|
||||
|
||||
function updatePosition(deltaX, deltaY) {
|
||||
const unauthorized = [NaN, Infinity, -Infinity]
|
||||
const xmin = (Modules.Canvas.px2x(Modules.Canvas.x2px(settingsInstance.xmin)-deltaX))
|
||||
const ymax = settingsInstance.ymax + deltaY/canvas.yzoom
|
||||
if(!unauthorized.includes(xmin))
|
||||
settingsInstance.xmin = xmin
|
||||
if(!unauthorized.includes(ymax))
|
||||
settingsInstance.ymax = ymax.toFixed(4)
|
||||
settingsInstance.changed()
|
||||
parent.positionChanged(deltaX, deltaY)
|
||||
|
||||
}
|
||||
|
||||
onPressed: function(mouse) {
|
||||
prevX = mouse.x
|
||||
prevY = mouse.y
|
||||
parent.beginPositionChange()
|
||||
}
|
||||
|
||||
onPositionChanged: function(mouse) {
|
||||
positionChangeTimer++
|
||||
if(positionChangeTimer == 3) {
|
||||
let deltaX = mouse.x - prevX
|
||||
let deltaY = mouse.y - prevY
|
||||
updatePosition(deltaX, deltaY)
|
||||
prevX = mouse.x
|
||||
prevY = mouse.y
|
||||
positionChangeTimer = 0
|
||||
}
|
||||
}
|
||||
|
||||
onReleased: function(mouse) {
|
||||
let deltaX = mouse.x - prevX
|
||||
let deltaY = mouse.y - prevY
|
||||
updatePosition(deltaX, deltaY)
|
||||
parent.endPositionChange(deltaX, deltaY)
|
||||
}
|
||||
|
||||
onWheel: function(wheel) {
|
||||
// Scrolling
|
||||
let scrollSteps = Math.round(wheel.angleDelta.y / 120)
|
||||
let zoomMultiplier = Math.pow(1+baseZoomMultiplier, Math.abs(scrollSteps))
|
||||
// Avoid floating-point rounding errors by removing the zoom *after*
|
||||
let xZoomDelta = (settingsInstance.xzoom*zoomMultiplier - settingsInstance.xzoom)
|
||||
let yZoomDelta = (settingsInstance.yzoom*zoomMultiplier - settingsInstance.yzoom)
|
||||
if(scrollSteps < 0) { // Negative scroll
|
||||
xZoomDelta *= -1
|
||||
yZoomDelta *= -1
|
||||
}
|
||||
let newXZoom = (settingsInstance.xzoom+xZoomDelta).toFixed(0)
|
||||
let newYZoom = (settingsInstance.yzoom+yZoomDelta).toFixed(0)
|
||||
// Check if we need to have more precision
|
||||
if(newXZoom < 10)
|
||||
newXZoom = (settingsInstance.xzoom+xZoomDelta).toFixed(4)
|
||||
if(newYZoom < 10)
|
||||
newYZoom = (settingsInstance.yzoom+yZoomDelta).toFixed(4)
|
||||
if(newXZoom > 0.5)
|
||||
settingsInstance.xzoom = newXZoom
|
||||
if(newYZoom > 0.5)
|
||||
settingsInstance.yzoom = newYZoom
|
||||
settingsInstance.changed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
<?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>
|
Before Width: | Height: | Size: 3.6 KiB |
|
@ -1,92 +0,0 @@
|
|||
<?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>
|
Before Width: | Height: | Size: 2.9 KiB |
|
@ -1,88 +0,0 @@
|
|||
<?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>
|
Before Width: | Height: | Size: 2.5 KiB |
|
@ -1,78 +0,0 @@
|
|||
<?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="Point.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="23.448337"
|
||||
inkscape:cy="9.9487426"
|
||||
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="48"
|
||||
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">
|
||||
<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 9.979376,18.120606 a 3.5,3.5 0 0 1 -3.06333,3.854578 3.5,3.5 0 0 1 -3.8866522,-3.022533 3.5,3.5 0 0 1 2.9814002,-3.918293 3.5,3.5 0 0 1 3.9495,2.939936" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
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"
|
||||
x="12.066752"
|
||||
y="13.922545"
|
||||
id="text14"
|
||||
transform="scale(0.99446808,1.0055627)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan12"
|
||||
x="12.066752"
|
||||
y="13.922545"
|
||||
style="font-size:17.3373px;stroke-width:1.00023">A</tspan></text>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.6 KiB |
|
@ -1,103 +0,0 @@
|
|||
<?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>
|
Before Width: | Height: | Size: 3.9 KiB |
|
@ -1,96 +0,0 @@
|
|||
<?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>
|
Before Width: | Height: | Size: 3.1 KiB |
|
@ -1,93 +0,0 @@
|
|||
<?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>
|
Before Width: | Height: | Size: 3.3 KiB |
|
@ -1,92 +0,0 @@
|
|||
<?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>
|
Before Width: | Height: | Size: 2.4 KiB |
|
@ -1,77 +0,0 @@
|
|||
<?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>
|
Before Width: | Height: | Size: 2.5 KiB |
|
@ -1,85 +0,0 @@
|
|||
<?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>
|
Before Width: | Height: | Size: 2.6 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path style="fill:#000;fill-rule:evenodd;stroke-width:2.26779" d="M4 16 17 3l1 2-2 2c4 3 4 7 4 8v1h-1c0-1 0-5-4-8l-8 8h15v2H2Z"/></svg>
|
After Width: | Height: | Size: 198 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M4 21.832c4.587.38 2.944-4.493 7.188-4.538l1.838 1.534c.458 5.538-6.315 6.773-9.026 3.004zm14.065-7.115c1.427-2.239 5.847-9.749 5.847-9.749.352-.623-.43-1.273-.976-.813 0 0-6.572 5.714-8.511 7.525-1.532 1.432-1.539 2.086-2.035 4.447l1.68 1.4c2.227-.915 2.868-1.039 3.995-2.81zM6.066 18.593c.666-1.134 1.748-2.977 4.447-3.262.434-2.087.607-3.3 2.547-5.112 1.373-1.282 4.938-4.409 7.021-6.229-1-2.208-4.141-4.023-8.178-3.99C5.279.055-.053 5.465 0 12.092a11.956 11.956 0 0 0 2.82 7.635c1.618.429 2.376.348 3.246-1.134zm6.952-15.835a2.006 2.006 0 0 1 2.016 1.983 2.005 2.005 0 0 1-1.986 2.016 1.997 1.997 0 0 1-2.014-1.984 1.994 1.994 0 0 1 1.984-2.015zM7.021 4.759a1.993 1.993 0 0 1 2.012 1.983 1.998 1.998 0 1 1-3.996.028 1.994 1.994 0 0 1 1.984-2.011zm-2.003 5.998a2 2 0 1 1 .03 4 1.995 1.995 0 0 1-2.011-1.985 1.998 1.998 0 0 1 1.981-2.015zm10.031 8.532c.021 2.239-.882 3.718-1.682 4.587l-.046.044c5.255-.591 9.062-4.304 6.266-7.889-1.373 2.047-2.534 2.442-4.538 3.258z" style="fill:#000"/></svg>
|
After Width: | Height: | Size: 1 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path style="fill:#000;fill-rule:evenodd;stroke-width:2" d="m9 3 3-3 3 3h-2v6l5-5-1-1h4v4l-1-1-5 5h6V9l3 3-3 3v-2h-6l5 5 1-1v4h-4l1-1-5-5v6h2l-3 3-3-3h2v-6l-5 5 1 1H3v-4l1 1 5-5H3v2l-3-3 3-3v2h6L4 6 3 7V3h4L6 4l5 5V3Z"/></svg>
|
After Width: | Height: | Size: 289 B |
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
version="1.1"
|
||||
id="svg6"
|
||||
sodipodi:docname="remove.svg"
|
||||
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
id="namedview8"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="true"
|
||||
inkscape:zoom="34.458333"
|
||||
inkscape:cx="12"
|
||||
inkscape:cy="10.505441"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1007"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg6">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid822" />
|
||||
</sodipodi:namedview>
|
||||
<path
|
||||
id="rect2"
|
||||
style="fill-rule:evenodd;stroke-width:3.16228"
|
||||
transform="rotate(135)"
|
||||
d="M -1.4142136,-26.870058 H 1.4142136 V -7.0710678 H -1.4142136 Z"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:#000000;fill-rule:evenodd;stroke-width:3.16228"
|
||||
d="M 20,6 6,20 4,18 18,4 Z"
|
||||
id="path4"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path style="fill:#000;stroke:none;stroke-width:1.55662" d="M5 8h1v14H5z"/><path style="fill:#000;stroke:none;stroke-width:2.73862" transform="scale(1 -1)" d="M2-7h20v1H2z"/><path style="fill:#000;stroke:none;stroke-width:.474342" d="M8 3h1v2H8z"/><path style="fill:#000;stroke:none;stroke-width:1.34164" d="M8 2h8v1H8z"/><path style="fill:#000;stroke:none;stroke-width:.500005" d="M15 3h1v2h-1z"/><path style="fill:#000;stroke:none;stroke-width:1.55662" d="M18 8h1v14h-1z"/><path style="fill:#000;stroke:none;stroke-width:.981983" d="M6 21h12v1H6z"/></svg>
|
After Width: | Height: | Size: 620 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path style="fill:#000;fill-rule:evenodd;stroke-width:3.05505" d="M7 5h16v2H9l-5 5 5 5h12V7h2v12H7l-6-6v-2z"/><circle style="fill:#000;fill-rule:evenodd;stroke-width:2" cx="16" cy="12" r="3"/></svg>
|
After Width: | Height: | Size: 261 B |
|
@ -0,0 +1 @@
|
|||
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd"><path d="M14 0v10l2-1.518 2 1.518v-10h4v24h-17c-1.657 0-3-1.343-3-3v-18c0-1.657 1.343-3 3-3h9zm6 20h-14.505c-1.375 0-1.375 2 0 2h14.505v-2z"/></svg>
|
After Width: | Height: | Size: 251 B |
|
@ -0,0 +1 @@
|
|||
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd"><path d="M12 0l-2.138 2.63-3.068-1.441-.787 3.297-3.389.032.722 3.312-3.039 1.5 2.088 2.671-2.088 2.67 3.039 1.499-.722 3.312 3.389.033.787 3.296 3.068-1.441 2.138 2.63 2.139-2.63 3.068 1.441.786-3.296 3.39-.033-.722-3.312 3.038-1.499-2.087-2.67 2.087-2.671-3.038-1.5.722-3.312-3.39-.032-.786-3.297-3.068 1.441-2.139-2.63zm0 15.5c.69 0 1.25.56 1.25 1.25s-.56 1.25-1.25 1.25-1.25-.56-1.25-1.25.56-1.25 1.25-1.25zm1-1.038v-7.462h-2v7.462h2z"/></svg>
|
After Width: | Height: | Size: 550 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path style="fill:#000;fill-rule:evenodd;stroke-width:2" d="M12 2S6 2 6 8c0 4 6 13.936 6 13.936S18 12 18 8c0-6-6-6-6-6zm-.05 3A3 3 0 0 1 12 5a3 3 0 0 1 3 3 3 3 0 0 1-3 3 3 3 0 0 1-3-3 3 3 0 0 1 2.95-3z"/></svg>
|
After Width: | Height: | Size: 273 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M24 13.616v-3.232l-2.869-1.02c-.198-.687-.472-1.342-.811-1.955l1.308-2.751-2.285-2.285-2.751 1.307c-.613-.339-1.269-.613-1.955-.811l-1.021-2.869h-3.232l-1.021 2.869c-.686.198-1.342.471-1.955.811l-2.751-1.308-2.285 2.285 1.308 2.752c-.339.613-.614 1.268-.811 1.955l-2.869 1.02v3.232l2.869 1.02c.197.687.472 1.342.811 1.955l-1.308 2.751 2.285 2.286 2.751-1.308c.613.339 1.269.613 1.955.811l1.021 2.869h3.232l1.021-2.869c.687-.198 1.342-.472 1.955-.811l2.751 1.308 2.285-2.286-1.308-2.751c.339-.613.613-1.268.811-1.955l2.869-1.02zm-12 2.384c-2.209 0-4-1.791-4-4s1.791-4 4-4 4 1.791 4 4-1.791 4-4 4z"/></svg>
|
After Width: | Height: | Size: 696 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path style="fill:#000;fill-rule:evenodd;stroke-width:2.05798" d="M11 3h2v8h3c0-3-3-3-3-3V6s5 0 5 5h3v2h-3c0 5-5 5-5 5v-2s3 0 3-3h-3v8h-2v-8H8c0 3 3 3 3 3v2s-5 0-5-5H3v-2h3c0-5 5-5 5-5v2s-3 0-3 3h3z"/></svg>
|
After Width: | Height: | Size: 270 B |
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path style="fill:#000;fill-opacity:1;stroke:none;stroke-width:.670999;stroke-linecap:butt;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" d="M4 3h8v2H9v14h3v2H4v-2h3V5H4Z"/><path style="fill:#000;fill-rule:evenodd;stroke-width:2" d="M16 5h2v3h2v2h-2v5c0 2 2 2 2 2v2s-4 0-4-4v-5h-2V8h2z"/></svg>
|
After Width: | Height: | Size: 370 B |
|
@ -1,104 +0,0 @@
|
|||
<?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="delete.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="34.185532"
|
||||
inkscape:cy="11.508793"
|
||||
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:none;stroke-width:1.55662"
|
||||
id="rect26"
|
||||
width="1"
|
||||
height="14"
|
||||
x="5"
|
||||
y="8" />
|
||||
<rect
|
||||
style="fill:#000000;stroke:none;stroke-width:2.73862"
|
||||
id="rect869"
|
||||
width="20"
|
||||
height="1"
|
||||
x="2"
|
||||
y="-7"
|
||||
transform="scale(1,-1)" />
|
||||
<rect
|
||||
style="fill:#000000;stroke:none;stroke-width:0.474342"
|
||||
id="rect871"
|
||||
width="1"
|
||||
height="2"
|
||||
x="8"
|
||||
y="3" />
|
||||
<rect
|
||||
style="fill:#000000;stroke:none;stroke-width:1.34164"
|
||||
id="rect873"
|
||||
width="8"
|
||||
height="1"
|
||||
x="8"
|
||||
y="2" />
|
||||
<rect
|
||||
style="fill:#000000;stroke:none;stroke-width:0.500005"
|
||||
id="rect875"
|
||||
width="1"
|
||||
height="2"
|
||||
x="15"
|
||||
y="3" />
|
||||
<rect
|
||||
style="fill:#000000;stroke:none;stroke-width:1.55662"
|
||||
id="rect26-3"
|
||||
width="1"
|
||||
height="14"
|
||||
x="18"
|
||||
y="8" />
|
||||
<rect
|
||||
style="fill:#000000;stroke:none;stroke-width:0.981983"
|
||||
id="rect894"
|
||||
width="12"
|
||||
height="1"
|
||||
x="6"
|
||||
y="21" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.6 KiB |
|
@ -0,0 +1 @@
|
|||
../common/appearance.svg
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
version="1.1"
|
||||
id="svg6"
|
||||
sodipodi:docname="add.svg"
|
||||
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
id="namedview8"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="34.458333"
|
||||
inkscape:cx="12"
|
||||
inkscape:cy="12.01451"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1007"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg6" />
|
||||
<rect
|
||||
style="fill:#000000;fill-rule:evenodd;stroke-width:3.67423"
|
||||
width="3"
|
||||
height="18"
|
||||
x="10.5"
|
||||
y="3"
|
||||
ry="0"
|
||||
id="rect2" />
|
||||
<path
|
||||
style="fill:#000000;fill-rule:evenodd;stroke-width:3.67423"
|
||||
d="m 3,10.5 h 18 v 3 H 3 Z"
|
||||
id="path4" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -0,0 +1 @@
|
|||
../common/close.svg
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
version="1.1"
|
||||
id="svg6"
|
||||
sodipodi:docname="modify.svg"
|
||||
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs10" />
|
||||
<sodipodi:namedview
|
||||
id="namedview8"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="true"
|
||||
inkscape:zoom="34.458333"
|
||||
inkscape:cx="11.767836"
|
||||
inkscape:cy="11.085853"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1007"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg6">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid827" />
|
||||
</sodipodi:namedview>
|
||||
<path
|
||||
id="rect2"
|
||||
style="fill-rule:evenodd;stroke-width:3.16228"
|
||||
d="m 8,1 h 8 V 9 L 13,6 3,16 1,14 11,4 Z"
|
||||
sodipodi:nodetypes="cccccccc" />
|
||||
<path
|
||||
id="rect2-3"
|
||||
style="fill-rule:evenodd;stroke-width:3.16228"
|
||||
d="M 16,23 H 8 v -8 l 3,3 10,-10 2,2 -10,10 z"
|
||||
sodipodi:nodetypes="cccccccc" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1 @@
|
|||
../common/label.svg
|
|
@ -0,0 +1 @@
|
|||
../common/position.svg
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
version="1.1"
|
||||
id="svg4"
|
||||
sodipodi:docname="visibility.svg"
|
||||
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs8" />
|
||||
<sodipodi:namedview
|
||||
id="namedview6"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="true"
|
||||
inkscape:zoom="34.458333"
|
||||
inkscape:cx="12"
|
||||
inkscape:cy="12.01451"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1007"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg4">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid896" />
|
||||
</sodipodi:namedview>
|
||||
<path
|
||||
d="m 12.015,7 c 4.751,0 8.063,3.012 9.504,4.636 C 20.118,13.473 16.806,17 12.015,17 7.595,17 4.085,13.464 2.537,11.593 4.03,9.946 7.354,7 12.015,7 Z m 0,-2 C 4.446,5 0,11.551 0,11.551 0,11.551 4.835,19 12.015,19 19.748,19 24,11.551 24,11.551 24,11.551 19.709,5 12.015,5 Z"
|
||||
fill="#000000"
|
||||
id="path2"
|
||||
sodipodi:nodetypes="scscsscscs" />
|
||||
<path
|
||||
id="path894"
|
||||
style="fill:#000000;fill-rule:evenodd;stroke-width:3"
|
||||
d="M 12 8.5 A 3.5 3.5 0 0 0 8.5 12 A 3.5 3.5 0 0 0 12 15.5 A 3.5 3.5 0 0 0 15.5 12 A 3.5 3.5 0 0 0 12 8.5 z M 11 9.5 A 1.5 1.5 0 0 1 12.5 11 A 1.5 1.5 0 0 1 11 12.5 A 1.5 1.5 0 0 1 9.5 11 A 1.5 1.5 0 0 1 11 9.5 z " />
|
||||
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="24.0px"
|
||||
height="24.0px"
|
||||
viewBox="0 0 24.0 24.0"
|
||||
version="1.1"
|
||||
id="SVGRoot"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs833" />
|
||||
<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:date>2021-2023</dc:date>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Ad5001</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>(C) Ad5001 2021-2023 - 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
|
||||
id="layer1">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:17.3333px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="0.012050295"
|
||||
y="17.985596"
|
||||
id="text1"><tspan
|
||||
id="tspan1"
|
||||
x="0.012050295"
|
||||
y="17.985596"
|
||||
style="font-size:17.3333px">f</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:17.3333px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="10.913334"
|
||||
y="18.134649"
|
||||
id="text1-3"><tspan
|
||||
id="tspan1-6"
|
||||
x="10.913334"
|
||||
y="18.134649"
|
||||
style="font-size:17.3333px">x</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:17.3333px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="6.3066678"
|
||||
y="17.646639"
|
||||
id="text2"><tspan
|
||||
id="tspan2"
|
||||
x="6.3066678"
|
||||
y="17.646639"
|
||||
style="font-size:17.3333px">(</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:17.3333px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="18.306667"
|
||||
y="17.646639"
|
||||
id="text2-7"><tspan
|
||||
id="tspan2-5"
|
||||
x="18.306667"
|
||||
y="17.646639"
|
||||
style="font-size:17.3333px">)</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.2 KiB |
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="24.0px"
|
||||
height="24.0px"
|
||||
viewBox="0 0 24.0 24.0"
|
||||
version="1.1"
|
||||
id="SVGRoot"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs1469" />
|
||||
<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:date>2021-2023</dc:date>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Ad5001</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>(C) Ad5001 2021-2023 - Licensed under CC4.0-BY-NC-SA</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-nc-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-nc-sa/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:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
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:17px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="-0.105"
|
||||
y="11.959"
|
||||
id="text839"><tspan
|
||||
id="tspan837"
|
||||
x="-0.105"
|
||||
y="11.959"
|
||||
style="font-size:17px">ω</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" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
|
@ -0,0 +1,86 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="24.0px"
|
||||
height="24.0px"
|
||||
viewBox="0 0 24.0 24.0"
|
||||
version="1.1"
|
||||
id="SVGRoot"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs10" />
|
||||
<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:date>2021-2023</dc:date>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Ad5001</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>(C) Ad5001 2021-2023 - Licensed under CC4.0-BY-NC-SA</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-nc-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-nc-sa/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:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
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" />
|
||||
<circle
|
||||
style="fill:#000000;stroke-width:2.09999"
|
||||
id="path45"
|
||||
cx="16"
|
||||
cy="19"
|
||||
r="4" />
|
||||
<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:0;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
x="6.1339936"
|
||||
y="11.163"
|
||||
id="text49"><tspan
|
||||
id="tspan47"
|
||||
x="6.1339936"
|
||||
y="11.163"
|
||||
style="font-size:17px;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none">φ</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
|
@ -0,0 +1,67 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<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"
|
||||
id="path1" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:400;font-size:17px;line-height:1.25;font-family:sans-serif;letter-spacing:0;word-spacing:0;fill-opacity:1;stroke:none;stroke-width:1.00023"
|
||||
x="11.964725"
|
||||
y="13.701941"
|
||||
transform="scale(0.99447036,1.0055604)"
|
||||
id="text1"><tspan
|
||||
x="11.964725"
|
||||
y="13.701941"
|
||||
style="font-size:17px;stroke-width:1.00023"
|
||||
id="tspan1">A</tspan></text>
|
||||
<metadata
|
||||
id="metadata1">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:date>2021-2023</dc:date>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Ad5001</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>(C) Ad5001 2021-2023 - Licensed under CC4.0-BY-NC-SA</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-nc-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-nc-sa/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:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
@ -0,0 +1,81 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="24.0px"
|
||||
height="24.0px"
|
||||
viewBox="0 0 24.0 24.0"
|
||||
version="1.1"
|
||||
id="SVGRoot"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs10" />
|
||||
<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:date>2021-2023</dc:date>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Ad5001</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>(C) Ad5001 2021-2023 - Licensed under CC4.0-BY-NC-SA</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
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;-inkscape-font-specification:sans-serif;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal"
|
||||
x="7.483983"
|
||||
y="16.134649"
|
||||
id="text908"><tspan
|
||||
id="tspan906"
|
||||
x="7.483983"
|
||||
y="16.134649"
|
||||
style="font-size:17.3333px;-inkscape-font-specification:sans-serif;font-family:sans-serif;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal">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;-inkscape-font-specification:sans-serif;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal"
|
||||
x="16.365566"
|
||||
y="18.663307"
|
||||
id="text912"
|
||||
transform="scale(1.0000324,0.9999676)"><tspan
|
||||
id="tspan910"
|
||||
x="16.365566"
|
||||
y="18.663307"
|
||||
style="font-size:17px;stroke-width:1.00003;-inkscape-font-specification:sans-serif;font-family:sans-serif;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal">n</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:17.3333px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;-inkscape-font-specification:sans-serif;font-stretch:normal;font-variant:normal"
|
||||
x="-0.69333196"
|
||||
y="17.646639"
|
||||
id="text2"><tspan
|
||||
id="tspan2"
|
||||
x="-0.69333196"
|
||||
y="17.646639"
|
||||
style="font-size:17.3333px;-inkscape-font-specification:sans-serif;font-family:sans-serif;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal">(</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:17.3333px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;-inkscape-font-specification:sans-serif;font-stretch:normal;font-variant:normal"
|
||||
x="18.806667"
|
||||
y="17.646639"
|
||||
id="text2-7"><tspan
|
||||
id="tspan2-5"
|
||||
x="18.806667"
|
||||
y="17.646639"
|
||||
style="font-size:17.3333px;-inkscape-font-specification:sans-serif;font-family:sans-serif;font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal">)</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.5 KiB |
|
@ -1,23 +1,21 @@
|
|||
<?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="logplotter.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2021-09-07)">
|
||||
<title
|
||||
id="title836">LogarithmPlotter Icon v1.0</title>
|
||||
sodipodi:docname="Text.svg"
|
||||
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs833" />
|
||||
id="defs1469" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
|
@ -25,34 +23,49 @@
|
|||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="22.627417"
|
||||
inkscape:cx="23.950814"
|
||||
inkscape:cy="5.6122612"
|
||||
inkscape:zoom="22.4"
|
||||
inkscape:cx="13.772321"
|
||||
inkscape:cy="8.4598214"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="true"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1011"
|
||||
inkscape:window-height="1010"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1">
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid1403" />
|
||||
id="grid2039"
|
||||
originx="0"
|
||||
originy="0"
|
||||
spacingy="1"
|
||||
spacingx="1"
|
||||
units="px"
|
||||
visible="true" />
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2058"
|
||||
originx="0"
|
||||
originy="0"
|
||||
spacingy="1"
|
||||
spacingx="1"
|
||||
units="px"
|
||||
visible="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata836">
|
||||
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>LogarithmPlotter Icon v1.0</dc:title>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-nc-sa/4.0/" />
|
||||
<dc:date>2021</dc:date>
|
||||
<dc:date>2021-2023</dc:date>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Ad5001</dc:title>
|
||||
|
@ -60,9 +73,11 @@
|
|||
</dc:creator>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>(c) Ad5001 2021 - All rights reserved</dc:title>
|
||||
<dc:title>(C) Ad5001 2021-2023 - Licensed under CC4.0-BY-NC-SA</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-nc-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-nc-sa/4.0/">
|
||||
|
@ -83,49 +98,30 @@
|
|||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Bg">
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect1546"
|
||||
width="24"
|
||||
height="24"
|
||||
x="0"
|
||||
y="0"
|
||||
ry="3" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:label="Calque 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="fill:#000000;fill-rule:evenodd;stroke-width:19.304;stroke-opacity:0"
|
||||
id="rect1410"
|
||||
width="22"
|
||||
height="2"
|
||||
x="1"
|
||||
y="19" />
|
||||
<rect
|
||||
style="fill:#000000;fill-rule:evenodd;stroke-width:19.3041;stroke-opacity:0"
|
||||
id="rect1412"
|
||||
width="2"
|
||||
height="22"
|
||||
x="9"
|
||||
y="1" />
|
||||
<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
|
||||
style="fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:1.95063;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path1529"
|
||||
sodipodi:type="arc"
|
||||
sodipodi:cx="1"
|
||||
sodipodi:cy="1"
|
||||
sodipodi:rx="20.024685"
|
||||
sodipodi:ry="18.024683"
|
||||
sodipodi:start="0"
|
||||
sodipodi:end="1.5707963"
|
||||
sodipodi:arc-type="arc"
|
||||
d="M 21.024685,1 A 20.024685,18.024683 0 0 1 1,19.024683"
|
||||
sodipodi:open="true" />
|
||||
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" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:17px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="13.844"
|
||||
y="17.387978"
|
||||
id="text1"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1"
|
||||
x="13.844"
|
||||
y="17.387978"
|
||||
style="font-size:17px">t</tspan></text>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 4 KiB After Width: | Height: | Size: 4.1 KiB |
|
@ -0,0 +1,82 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="24.0px"
|
||||
height="24.0px"
|
||||
viewBox="0 0 24.0 24.0"
|
||||
version="1.1"
|
||||
id="SVGRoot"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs1469" />
|
||||
<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:date>2021-2023</dc:date>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Ad5001</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>(C) Ad5001 2021-2023 - Licensed under CC4.0-BY-NC-SA</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-nc-sa/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-nc-sa/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:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
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="5"
|
||||
y="0"
|
||||
ry="2.14841e-13" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:17px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none"
|
||||
x="10.915"
|
||||
y="13.713"
|
||||
id="text1"><tspan
|
||||
id="tspan1"
|
||||
x="10.915"
|
||||
y="13.713"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17px;font-family:sans-serif;-inkscape-font-specification:sans-serif">X</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
|
@ -1 +0,0 @@
|
|||
./settings/custom/position.svg
|
|
@ -0,0 +1 @@
|
|||
../common/appearance.svg
|
|
@ -1 +1 @@
|
|||
appearance.svg
|
||||
../../common/appearance.svg
|
|
@ -1 +1 @@
|
|||
appearance.svg
|
||||
../../common/appearance.svg
|
|
@ -1 +1 @@
|
|||
arrow.svg
|
||||
../../common/arrow.svg
|
|
@ -1 +1 @@
|
|||
position.svg
|
||||
../../common/position.svg
|
|
@ -1 +1 @@
|
|||
angle.svg
|
||||
../../common/angle.svg
|