Compare commits

...

261 commits

Author SHA1 Message Date
ovari
a2f8a924e0
Translated using Weblate (Hungarian)
Currently translated at 100.0% (264 of 264 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/hu/
2025-03-13 15:24:08 +01:00
fbef5dc28a
Updating copyrights to 2025.
All checks were successful
continuous-integration/drone/push Build is passing
2025-02-06 19:14:00 +01:00
8245264874
Merge branch 'master' of https://git.ad5001.eu/Ad5001/LogarithmPlotter
All checks were successful
continuous-integration/drone/push Build is passing
2025-02-06 19:09:22 +01:00
310afa5672
Disabling experimental threaded rendering by default for now. 2025-02-06 19:08:39 +01:00
தமிழ்நேரம்
5fa118233c
Translated using Weblate (Tamil)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 99.6% (263 of 264 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/ta/
2025-01-14 02:00:46 +01:00
2c8011056d
Fixing not recreating canvas context if it already exists.
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-12 18:08:44 +01:00
54f82eab92
Translated using Weblate (French)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 100.0% (264 of 264 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/fr/
2025-01-12 18:08:24 +01:00
6101c0c645
Translated using Weblate (German)
Currently translated at 100.0% (264 of 264 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/de/
2025-01-12 18:08:24 +01:00
b673038b15
Translated using Weblate (English)
Currently translated at 100.0% (264 of 264 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/en/
2025-01-12 18:08:23 +01:00
3b244fad2c
Updating translations + credits for Tamil.
Some checks failed
continuous-integration/drone/push Build is failing
2025-01-12 17:42:48 +01:00
தமிழ்நேரம்
004b3f5612
Added translation using Weblate (Tamil)
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-12 17:22:40 +01:00
6025742e86
Fixing bugs.
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-06 16:23:06 +01:00
fdcc8105ba
Removing debug
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-29 02:58:32 +01:00
da8aa59b0a
Improving characters choosing popup.
All checks were successful
continuous-integration/drone/push Build is passing
+ No longer covering the input
+ No longer cut off when editing the name
+ Improved keyboard navigation.
2024-10-29 02:50:11 +01:00
f5b489ef44
Fixing macOS build script. 2024-10-29 01:37:44 +01:00
8429ff3739
Updating dependencies locK.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-28 23:05:55 +01:00
440575325e
Fixing Helper version importing. 2024-10-28 23:04:42 +01:00
45fef876ec
Fixing issue with margins being shown despite an object not being displayed.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-28 19:09:25 +01:00
43e41a5da4
Adding new test files
All checks were successful
continuous-integration/drone/push Build is passing
Including:
- magnitude.lpf & phase.lpf: regular use case magnitude and phase
- all.lpf: tests all objects
- stress.lpf: over 200 objects to be rendered
2024-10-28 18:51:13 +01:00
687b14429a
Improving reliability of threaded rendering, separating JS Utils into separate files.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-28 18:47:55 +01:00
ovari
49e94317d4
Translated using Weblate (Hungarian)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 100.0% (265 of 265 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/hu/
2024-10-28 09:17:49 +01:00
727dda2623
Adding loading screen for rendering LaTeX formula when threaded setting is enabled.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-27 02:40:42 +02:00
27c9fe0473
Fixing newly made issue with PickLocation. 2024-10-27 00:46:42 +02:00
e6de739d0c
Rewirring paths to improve import names and such. 2024-10-27 00:45:04 +02:00
f52ee65c56
Improving stability of Function drawing. 2024-10-26 23:37:20 +02:00
8da10497d2
Adding different revisions for different debian packages depending on their dependencies
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-26 22:46:41 +02:00
5d0542ffcc
Ensuring app icons are white. 2024-10-26 22:46:22 +02:00
90f4691c54
Updating icons to comply with KDE HIG. 2024-10-26 22:44:18 +02:00
c39498c60f
Finally got rid of the camelCase2Readable Utils function.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-26 05:55:34 +02:00
2594fd6844
Adding new expression tests.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-26 01:06:24 +02:00
a01b7a17ef
Merge branch 'master' of https://git.ad5001.eu/Ad5001/LogarithmPlotter
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-22 02:51:42 +02:00
67799e9908
Removing debug from python. 2024-10-22 02:50:56 +02:00
d53f50193a
Finishing latex and polyfill tests. 2024-10-22 02:50:24 +02:00
14e8cef6af
Fixing issues with LaTeX and rendering variable pi. 2024-10-22 02:50:00 +02:00
b989a685e9
Fixing issue with LaTeX sqrt. 2024-10-22 01:05:06 +02:00
e35f6cebec
Starting Latex tests. 2024-10-20 00:11:35 +02:00
6251835aa0
Translated using Weblate (German)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 100.0% (265 of 265 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/de/
2024-10-18 16:09:36 +02:00
14c092b9fa
Fixing tests
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-17 05:28:03 +02:00
811262b1fb
Changing lupdate and lrelease to use pyside6 versions, updating images so I no longer have to install node to build.
Some checks failed
continuous-integration/drone/push Build is failing
2024-10-17 05:09:33 +02:00
3c0d99d9c0
Exiting when not all tests are fulfilled.
Some checks failed
continuous-integration/drone/push Build is failing
2024-10-17 03:44:35 +02:00
2899ac6cde
Fixing unit testing importing unexpected and unused libraries.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-17 03:41:41 +02:00
a182c703f4
Finishing testing promises.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-17 03:38:36 +02:00
ef465b34e7
Finishing natural language plugin. 2024-10-17 02:08:24 +02:00
8fab9d8e52
Starting natural language plugin. 2024-10-16 22:18:53 +02:00
34caf20593
Fixing LaTeX tests, adding new sexy natural language method spy, started testing Promises. 2024-10-16 05:38:49 +02:00
a85a4721e3
Fixing double redraw when opening a file.
Some checks failed
continuous-integration/drone/push Build is failing
2024-10-15 20:39:03 +02:00
aeaaba759f
Starting latex render locking. 2024-10-15 19:21:40 +02:00
ccddb068a6
Fixing tests for Promises (new ones need to be written) 2024-10-15 18:06:24 +02:00
37ac400f23
Enabling latex async generation by default, default LaTeX setting now depends on state of installation.
Some checks failed
continuous-integration/drone/push Build is failing
2024-10-15 03:52:47 +02:00
5313428250
Improving stability of asynchronous LaTeX renderer. 2024-10-15 03:52:06 +02:00
cf73b35a9a
Adding experimental async LaTeX renderer (speeds up rendering ridiculously, but causes instability) 2024-10-15 03:01:27 +02:00
f734e40ad9
Starting PyPromise 2024-10-15 02:28:27 +02:00
b33e1329db
Removing typed config functions in Helper.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-14 23:22:57 +02:00
2995b2271a
Fixing mind-bogingingly strange issue causing Qt crash when attempting to set WeakSet during mouse move events.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-14 17:55:53 +02:00
a26dbc8a00
Getting rid of Qt5Compat, ridding dependency on PySide6-Addons
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-14 17:39:02 +02:00
89e78913de
Adding dependencies for Ubuntu 24.10.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-14 17:28:43 +02:00
c03afdf4ee
Upgrading deb packaging
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-14 17:18:58 +02:00
3a81441d0b
Finished expr-eval testing
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-13 00:33:22 +02:00
edf4518494
Starting expr-eval's tests. 2024-10-12 20:37:16 +02:00
345458f453
Adding new test for Settings Module
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-12 06:19:30 +02:00
974baa6cc2
Adding base module tests
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-12 05:31:42 +02:00
4c1b705240
Mocking interfaces (+adding new method to canvas to make it more JS-like)
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-12 04:57:07 +02:00
885d1f5dc3
Adding test for Utils
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-12 03:22:49 +02:00
0abb22130f
Disable domain tests, started base tests. 2024-10-12 00:40:46 +02:00
42d5add810
Fixing tests and LaTeX
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-11 22:33:57 +02:00
e2d259f866
Fixing French localization.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-11 22:18:35 +02:00
8a878b4cc1
Storing LaTeX renders in cache directory instead of temporary to store them for later use.
All checks were successful
continuous-integration/drone/push Build is passing
+ Makes reponening files instantaneous.
+ Improves performance of 'base state' objects (e.g. A = (1, 0) or f(x) = x).
2024-10-11 22:04:12 +02:00
07e58a3a55
Translated using Weblate (French)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 100.0% (265 of 265 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/fr/
2024-10-11 22:00:30 +02:00
c592b92212
Translated using Weblate (Spanish)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 100.0% (265 of 265 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-10-11 19:18:30 +02:00
7935d0134d
Fixing wrap on Greet Screen buttons in certain locales.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-11 19:06:33 +02:00
5745587c72
Fixing git version detection. 2024-10-11 19:06:15 +02:00
84adc787e5
Fixing typo in Spanish translation 2024-10-11 19:05:53 +02:00
f3307b47d9
Fixing bug with saving files 2024-10-11 19:05:34 +02:00
9017f84c06
Updating metadata and python package lock. 2024-10-11 18:21:03 +02:00
00ab895b21
Adding x value as argument for derivative objects.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-11 02:38:11 +02:00
82e6d2ffe3
Removing HistoryInterface (no longer needed)
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-11 02:35:13 +02:00
b91dbfb311
Finishing touches on putting History off QML.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-11 02:14:42 +02:00
448d94fee3
Fixed many issues with new History module, including saved status.
+ Fixed (old) bug that label content wasn't being saved.
2024-10-11 02:03:27 +02:00
2dc9234b22
Decoupled History from QML 2024-10-11 01:14:52 +02:00
54363b25bc
Fixing issue with Replace All when replacement string includes source string.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-10 23:56:42 +02:00
52f859349a
Converting actual settings to new Settings module. 2024-10-10 23:28:25 +02:00
d1ac70a946
Switching a lot of stuff to new Settings module
+ Fixing a bug that did not load the showygrad setting properly.
2024-10-10 19:15:46 +02:00
f4920aadb6
Merge branch 'master' of https://git.ad5001.eu/Ad5001/LogarithmPlotter
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-10 06:50:08 +02:00
af2950c3d2
Starting Settings modules + implemented basic events for ECMAScript <=> Qt compat. 2024-10-10 06:49:14 +02:00
gallegonovato
bd346240bd
Translated using Weblate (Spanish)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-10-10 03:34:21 +00:00
9663c33563
Improving MJS lupdate hacky script to take private fields into account.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-10 05:33:01 +02:00
934dd3ea1b
Adding private fields for Modules 2024-10-10 05:25:34 +02:00
b02ed87a29
Updating package-lock 2024-10-10 04:56:09 +02:00
40d86c8f82
Translated using Weblate (French)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/fr/
2024-10-09 20:22:37 +02:00
6b3cce4252
Translated using Weblate (German)
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/de/
2024-10-09 20:22:36 +02:00
8c273f4220
Translated using Weblate (English)
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/en/
2024-10-09 20:22:36 +02:00
a60ac79d83
Updating translations to new folder structure.
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-09 20:15:27 +02:00
23c3b771c2
Merge branch 'master' of https://git.ad5001.eu/Ad5001/LogarithmPlotter
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-09 20:04:07 +02:00
041d4f424e
Reorganisation du projet pour séparer le module ECMAScript du reste de l'application.
Merge branch 'rollup-js'
2024-10-09 20:02:53 +02:00
1fc19f6ba3
Adding rebuild to scripts
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2024-10-01 21:50:10 +02:00
ovari
7ef55e48e8
Translated using Weblate (Hungarian)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/hu/
2024-10-01 17:23:20 +02:00
07e556da56
Removing building when testing current build.
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-30 01:45:02 +02:00
cd6f258720
Fixing CI
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-30 01:39:59 +02:00
1c7e9d627d
Updating tests
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-30 01:35:24 +02:00
e2841c0129
Updating remaining paths in scripts 2024-09-30 01:27:30 +02:00
ca5c7492dc
Fixing deb building 2024-09-30 00:54:30 +02:00
34cb856dd4
Reorganizing paths 2024-09-30 00:23:39 +02:00
e9d204daab
Code coverage for JS
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-28 03:49:14 +02:00
a2443d7915
Adding coverage 2024-09-28 03:46:16 +02:00
56a0817960
Testing!
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-28 03:32:51 +02:00
c74c2fb747
Merge branch 'master' of https://git.ad5001.eu/Ad5001/LogarithmPlotter
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-27 22:30:36 +02:00
c2eae30bd6
Updating qmldirs 2024-09-27 22:26:15 +02:00
80cea6d280
Translated using Weblate (Hungarian)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 95.1% (256 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/hu/
2024-09-27 18:16:19 +02:00
f8ce98d4ad
Removing logplotter.svg file (duplicate) + adding PySide6-Addons as dependency 2024-09-27 04:15:34 +02:00
c806f09b10
Improving translations update script.
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-27 03:02:55 +02:00
c32d70e9ed
Reformatting JS files
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-27 02:54:20 +02:00
8cefc56ac7
Adding JS polyfills to avoid issues because core-js does not deal well with the environment it's given. 2024-09-27 02:34:42 +02:00
850d076268
Using more modern ECMAScript 2024-09-26 23:16:58 +02:00
95b47effdf
Removing unique file dependencies in QML, removing comments from JS Builds (except first one, ~-30% build size)
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-26 22:36:42 +02:00
49aa23de92
Removing the need for releasing translations after building
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-26 03:28:41 +02:00
4a1b333198
Updating APT before installing in CI
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-26 03:26:41 +02:00
b5bdbb6294
Adding building for JS
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-26 03:24:57 +02:00
309b0fafb0
Adding tests for debug
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-26 00:01:30 +02:00
fbb85083c1
Translated using Weblate (German)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/de/
2024-09-25 22:15:42 +02:00
f9af0c34dd
Source mapping and debugging 2024-09-25 19:18:04 +02:00
gallegonovato
17b6e40d60
Translated using Weblate (Spanish)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-09-24 19:15:41 +02:00
937cb07d0b
Working mjs building 2024-09-24 05:23:12 +02:00
6a1f01ba1f
Better interfaces!
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-24 00:04:11 +02:00
4c1403c983
Implementing modules requiring interfaces 2024-09-23 20:55:48 +02:00
8c8964e75e
Renaming internal ExprEval Expression class to ExprEvalExpression
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-23 18:37:57 +02:00
45dff33bb5
Moving mathlib and historylib into math/index and history/index
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-23 18:32:11 +02:00
bac802ec5b
Using translated property name in usage error messages.
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-23 18:23:45 +02:00
34a436fe49
Merge branch 'master' of https://git.ad5001.eu/Ad5001/LogarithmPlotter
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-23 18:19:09 +02:00
cb2ffcf77a
Translated using Weblate (Hungarian)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 94.7% (255 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/hu/
2024-09-23 18:19:00 +02:00
a27d3109ed
Translated using Weblate (French)
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/fr/
2024-09-23 18:19:00 +02:00
a998c52eec
Translated using Weblate (Spanish)
Currently translated at 98.8% (266 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-09-23 18:19:00 +02:00
8b8a280b37
Translated using Weblate (German)
Currently translated at 99.6% (268 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/de/
2024-09-23 18:19:00 +02:00
3befff41fa
Translated using Weblate (English)
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/en/
2024-09-23 18:18:59 +02:00
9810435456
Updating usages 2024-09-23 18:18:56 +02:00
84a65cd1fc
Testing the Helper.
All checks were successful
continuous-integration/drone/push Build is passing
We're now getting to 88% coverage on python. I don't think I can get it much higher between the statements that pytest doesn't count,
the ones which aren't easy to reproduce in test env (eg no internet connection), and the ones essential to the app's startup workflow.
2024-09-23 05:58:29 +02:00
5bdf81b2ed
Adding new python 2024-09-23 04:35:10 +02:00
c66d08b352
Moving Modules to separate directory
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-22 21:59:11 +02:00
a4e9ad7f5a
Removing usage of "Modules" to refer to modules in JavaScript (using imports instead) 2024-09-22 19:35:40 +02:00
a88be86350
Adding translations to current branch
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-22 19:18:18 +02:00
4baf4f8aa6
Updating some keys (should be the last time) 2024-09-22 19:17:24 +02:00
1f2b8e5c4b
Translated using Weblate (French)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/fr/
2024-09-22 19:13:12 +02:00
gallegonovato
8eac624bb2
Translated using Weblate (Spanish)
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-09-22 19:13:12 +02:00
976088ad03
Translated using Weblate (German)
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/de/
2024-09-22 19:13:12 +02:00
dcb63c48e9
Translated using Weblate (English)
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/en/
2024-09-22 19:13:12 +02:00
dcc47104ef
Changing all JS qsTr to qsTranslate (better compatibility moving forward) 2024-09-22 19:10:23 +02:00
a32d480b43
Renaming objects to their proper english names. 2024-09-22 18:58:19 +02:00
e0601379ba
Update README
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-22 18:44:45 +02:00
3c42cbb6d0
Updating translations for new expr-eval
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-22 18:28:36 +02:00
cc0f277da7
Nearly rewrote expr-eval to be compatible as an ECMAScript module, the last blocker for many bugs and JS tests!
All checks were successful
continuous-integration/drone/push Build is passing
commit f91538de446ef0e497ec7e87e2729f504a4172cb
Author: Ad5001 <mail@ad5001.eu>
Date:   Sun Sep 22 05:55:12 2024 +0200

    Converted expr-eval back to regular JS!

commit 23c346f6c65b5b5c4bb4ad610f0554bd1d9a3700
Author: Ad5001 <mail@ad5001.eu>
Date:   Sun Sep 22 05:06:59 2024 +0200

    Reformatting

commit 66608c980fd44f26ae8e6855ecd5fc3e7db55a7b
Author: Ad5001 <mail@ad5001.eu>
Date:   Sun Sep 22 05:04:27 2024 +0200

    Removed all 'var's

commit 545886fd38c99cf11bc576caa40bec0d7fe0ac30
Author: Ad5001 <mail@ad5001.eu>
Date:   Sun Sep 22 04:53:32 2024 +0200

    Removing function definition

commit 489602b24bb70cb6ad782871e269a22c92fcf072
Author: Ad5001 <mail@ad5001.eu>
Date:   Sun Sep 22 04:51:21 2024 +0200

    Removing semicolons

commit 3ee069edbeb8ebfb5c7d15d319014f7a085ff623
Author: Ad5001 <mail@ad5001.eu>
Date:   Sun Sep 22 04:49:32 2024 +0200

    Converting all classes to ECMAScript classes
2024-09-22 05:57:36 +02:00
1299fe469d
Updating README
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-21 03:21:49 +02:00
5d0f3eec56
Translated using Weblate (Hungarian)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 95.9% (258 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/hu/
2024-09-21 02:47:17 +02:00
gallegonovato
c8ada79776
Translated using Weblate (Spanish)
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-09-21 02:47:17 +02:00
43a0aa3529
Translated using Weblate (English)
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/en/
2024-09-21 02:47:17 +02:00
9c76d469d6
Merge branch 'master' of https://git.ad5001.eu/Ad5001/LogarithmPlotter
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-20 23:59:56 +02:00
3c57f207b6
Translated using Weblate (Hungarian)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 96.2% (259 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/hu/
2024-09-20 23:59:20 +02:00
77d03e5837
Translated using Weblate (Norwegian Bokmål)
Currently translated at 71.7% (193 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/nb_NO/
2024-09-20 23:59:20 +02:00
ed5b7e95a6
Translated using Weblate (French)
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/fr/
2024-09-20 23:59:20 +02:00
2bf7df12a8
Translated using Weblate (Spanish)
Currently translated at 98.5% (265 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-09-20 23:59:20 +02:00
0e23d9181e
Translated using Weblate (German)
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/de/
2024-09-20 23:59:20 +02:00
7e698eda32
Translated using Weblate (English)
Currently translated at 100.0% (269 of 269 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/en/
2024-09-20 23:59:20 +02:00
6e92c428f9
Removing vanished translation from Spanish file 2024-09-20 23:52:05 +02:00
b18e1ca56e
Update translation files
All checks were successful
continuous-integration/drone/push Build is passing
Updated by "Cleanup translation files" hook in Weblate.

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/
2024-09-20 23:51:37 +02:00
1ef1d27452
Translated using Weblate (Hungarian)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 96.1% (298 of 310 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/hu/
2024-09-20 23:51:00 +02:00
7c12b757ee
Translated using Weblate (Norwegian Bokmål)
Currently translated at 68.0% (211 of 310 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/nb_NO/
2024-09-20 23:51:00 +02:00
484888f80f
Translated using Weblate (French)
Currently translated at 100.0% (310 of 310 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/fr/
2024-09-20 23:51:00 +02:00
4e265b66c2
Translated using Weblate (Spanish)
Currently translated at 98.3% (305 of 310 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-09-20 23:50:59 +02:00
6d3f4ba372
Translated using Weblate (German)
Currently translated at 100.0% (310 of 310 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/de/
2024-09-20 23:50:56 +02:00
2321a1076c
Translated using Weblate (English)
Currently translated at 100.0% (310 of 310 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/en/
2024-09-20 23:50:14 +02:00
dd2ae7a2c8
Implemented workaround for QTBUG-123819 (lupdate not parsing *.mjs files)
All checks were successful
continuous-integration/drone/push Build is passing
Woohoo! No longer any duplicate and vanished translations (might cause a few that need to be checked, but translations should be properlerly reused).
2024-09-20 23:44:29 +02:00
2fc9bdee86
Fixing import of Objects
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-20 22:58:37 +02:00
67190e1b4c
Fixing rendering of LaTeX for position changing.
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-20 22:14:52 +02:00
8ab461ff72
Removing ObjectsCommon tests
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-20 19:29:02 +02:00
9b5356f8e7
Fixing another bug with X Cursor relating to rounding to a superior precision than what the number originally has.
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-20 19:28:11 +02:00
370402f303
Fixing a particularly smelly bug in regard to X Cursor targetting causing issues with certain functions. 2024-09-20 19:02:10 +02:00
7f57ed13c7
Removing ObjectsCommon API 2024-09-20 17:56:59 +02:00
325eef57e2
Fixing ES flag in Thanks 2024-09-20 17:40:42 +02:00
956de5f9e3
FIxing building location
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-19 21:57:41 +02:00
48427b7923
Fixing lrelease installation
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-19 21:33:29 +02:00
fceb5e711c
Upgrading CI images
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-19 20:21:04 +02:00
836d13386e
Adding building translations in CI.
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-19 18:19:35 +02:00
c3daa92280
Testing for modules existance in globals.
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-19 02:34:49 +02:00
d566c285fd
Adding values and types to PyJS 2024-09-19 02:20:42 +02:00
a9e47dbc17
Adding main tests (note: full main app may not be completely tested though) 2024-09-19 01:52:23 +02:00
4a5756f24d
Update translation files
All checks were successful
continuous-integration/drone/push Build is passing
Updated by "Cleanup translation files" hook in Weblate.

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/
2024-09-18 22:57:16 +00:00
a250f532d9
Adding pyside6-addons as dependency until https://bugreports.qt.io/browse/PYSIDE-2871 is resolved.
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-19 00:51:28 +02:00
e68411e93c
Fixing typos 2024-09-19 00:51:16 +02:00
b55b2a11fe
Starting main tests 2024-09-19 00:50:47 +02:00
7dd64c8e31
Fixing issue with Settings no longer being translated.
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-19 00:22:03 +02:00
8f95479689
Making pyinstaller command multiline. 2024-09-18 23:26:07 +02:00
9712ff15bb
Giving script a GUI env lest Qt dumps
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-18 23:20:00 +02:00
a3cf99f3af
Filtering report paths
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-18 23:19:00 +02:00
2ee7da7995
Fixing CI building
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-18 23:11:44 +02:00
3104dea918
Trying to fix building
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-18 23:03:44 +02:00
cb0db7fae1
Running tests from script
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-18 22:52:53 +02:00
4ac7de48b0
Latex tests 2024-09-18 22:51:23 +02:00
5211821a84
Setting up Poetry for dependency management.
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-18 18:15:30 +02:00
29e48e284c
Adding pytest to drone ci
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-18 18:01:51 +02:00
4759bdcd33
Continuing python tests
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-18 00:31:17 +02:00
9072e94d14
Starting python tests
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-18 00:30:58 +02:00
b50d56d511
Improving python coding format 2024-09-17 22:43:24 +02:00
1bf175b09c
Adding type hints 2024-09-17 22:26:17 +02:00
52fd95551c
Adding translations (again)
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-17 22:02:19 +02:00
769ad22ea6
Cleaning up and update Linux data
+ Removing (no longer working) local install for linux.

+ Moving appstream changelog generation to scripts.

+ Updating debian package information.
2024-09-17 21:58:12 +02:00
gallegonovato
8b36ad81ab
Translated using Weblate (Spanish)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 100.0% (309 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-09-17 21:38:38 +02:00
1e32faa1d1
Adding translations
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-17 20:38:01 +02:00
78d7e6f310
Bumping required Python version to v3.9 + adding new Polyfills for IDEs. 2024-09-17 20:36:46 +02:00
ab45109206
Fixing typos. 2024-09-17 19:21:29 +02:00
12b48a2e74
Translated using Weblate (French)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 100.0% (309 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/fr/
2024-09-17 02:20:41 +02:00
1bc3aaf53b
Translated using Weblate (Spanish)
Currently translated at 99.6% (308 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-09-17 02:20:40 +02:00
b52cc1de29
Translated using Weblate (German)
Currently translated at 100.0% (309 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/de/
2024-09-17 02:20:40 +02:00
214dd687b1
Translated using Weblate (Hungarian)
Currently translated at 98.0% (303 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/hu/
2024-09-17 02:19:33 +02:00
6b4da2b061
Translated using Weblate (French)
Currently translated at 100.0% (309 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/fr/
2024-09-17 02:19:33 +02:00
gallegonovato
bcf76dcd28
Translated using Weblate (Spanish)
Currently translated at 100.0% (309 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-09-17 02:19:33 +02:00
207a2254f3
Translated using Weblate (German)
Currently translated at 100.0% (309 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/de/
2024-09-17 02:19:32 +02:00
0f39930b88
Translated using Weblate (English)
Currently translated at 100.0% (309 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/en/
2024-09-17 02:19:32 +02:00
d4e97f2860
Moving last methods from LogGraphCanvas to Canvas JS module. 2024-09-17 02:14:47 +02:00
a2fa16949a
Fixing some bugs, including outzooming too much. 2024-09-17 01:58:34 +02:00
91e4220397
Upping logarithmic graduation limit to 309 (maximum before Infinity, probably some dragons to be had there) 2024-09-17 01:35:47 +02:00
d7fe760900
Slightly improving phases sum cleanness.
Didn't have quite as many bugs, but isn't quite as clean as the magnitude one as of now
2024-09-17 01:01:46 +02:00
a16f02fd5f
Refractoring the magnitude sum object cache calculation which should (hopefully) reduce bugs and improve maintainability. 2024-09-17 00:44:14 +02:00
601efc6122
Fixing issue with LocationPickOverlay snap to grid. 2024-09-16 23:52:42 +02:00
51807a80d0
Fixing position of filter item 2024-09-16 23:41:34 +02:00
ef14db8bbb
Fixing issue with object's execution category 2024-09-16 23:33:59 +02:00
7e0262e4fe
Making Objects List Latex render async 2024-09-16 23:33:08 +02:00
70f1c03cb6
Making history items being rendered with LaTeX (e.g. positions and properties) asynchronous. 2024-09-16 22:56:54 +02:00
8d6891c4f0
Starting async LaTeX rendering. 2024-09-16 22:05:17 +02:00
c9a597ea82
Translated using Weblate (Norwegian Bokmål)
Currently translated at 69.2% (214 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/nb_NO/
2024-09-16 21:17:26 +02:00
c1a468148d
Translated using Weblate (French)
Currently translated at 100.0% (309 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/fr/
2024-09-16 21:17:26 +02:00
59d4d2f728
Translated using Weblate (Spanish)
Currently translated at 80.5% (249 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-09-16 21:17:26 +02:00
gallegonovato
9ca48bbcfa
Translated using Weblate (Spanish)
Currently translated at 80.5% (249 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-09-16 21:17:25 +02:00
3994d8d49d
Translated using Weblate (German)
Currently translated at 100.0% (309 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/de/
2024-09-16 21:17:25 +02:00
53124fc8d7
Translated using Weblate (Norwegian Bokmål)
Currently translated at 69.9% (216 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/nb_NO/
2024-09-16 21:01:51 +02:00
35fef4cb1e
Translated using Weblate (French)
Currently translated at 100.0% (309 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/fr/
2024-09-16 21:01:51 +02:00
f1e2278695
Translated using Weblate (Spanish)
Currently translated at 75.7% (234 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-09-16 21:01:51 +02:00
gallegonovato
6a1f0013d6
Translated using Weblate (Spanish)
Currently translated at 75.7% (234 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-09-16 21:01:51 +02:00
6626362d23
Translated using Weblate (German)
Currently translated at 99.6% (308 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/de/
2024-09-16 21:01:51 +02:00
107cea1308
Translated using Weblate (English)
Currently translated at 100.0% (309 of 309 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/en/
2024-09-16 21:01:51 +02:00
7b0bc4469f
Improving message for missing packages in LaTeX. 2024-09-16 20:15:57 +02:00
e3eea751cb
Improving ThanksTo (to add scrolling) 2024-09-16 20:05:57 +02:00
7b76a8fe08
Improving testing of LaTeX configuration. 2024-09-16 20:01:35 +02:00
4b1cf2cd9d
Improving linux metainfo generation. 2024-09-16 20:00:56 +02:00
88797d00be
Adding new translations for v0.6.0 + adding Spanish credits 2024-09-16 19:34:35 +02:00
f98852c336
Merge branch 'master' of https://git.ad5001.eu/Ad5001/LogarithmPlotter 2024-09-15 21:34:50 +02:00
606ec428ab
Fixing issue with setting JS objects being serialized into ListViews.
+ Fixing broken links on Linux
2024-09-15 21:30:44 +02:00
ovari
136ac4c7bc
Translated using Weblate (Hungarian)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 100.0% (304 of 304 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/hu/
2024-04-21 08:07:05 +02:00
gallegonovato
87d8882db1
Translated using Weblate (Spanish)
All checks were successful
continuous-integration/drone/push Build is passing
Currently translated at 80.2% (244 of 304 strings)

Translation: LogarithmPlotter/LogarithmPlotter
Translate-URL: https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/es/
2024-04-03 23:01:47 +02:00
915c6b5246
Setting version to v0.6.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-04-03 22:05:57 +02:00
54f9802975
Adding default canvas settings
All checks were successful
continuous-integration/drone/push Build is passing
+ Getting rid of Qt5COmpat for Icon.
+ Fixing some (non production) bugs.
2024-04-03 21:39:06 +02:00
997a1645a0
Removing Settings submenu.
All checks were successful
continuous-integration/drone/push Build is passing
2024-04-02 22:50:43 +02:00
fefb0f92b0
New, rewamped Greet Screen. 2024-04-02 22:49:56 +02:00
665906ecb3
New preferences panel. 2024-04-02 22:11:54 +02:00
781a0f4aae
Enforcing type safety at export
All checks were successful
continuous-integration/drone/push Build is passing
2024-04-02 00:11:56 +02:00
5f8c756dc7
Enforcing type safety at import. 2024-04-01 23:48:57 +02:00
8e75f13e9a
Removing vanished translations.
All checks were successful
continuous-integration/drone/push Build is passing
2024-03-29 17:56:09 +01:00
82e8413e56
Creating IO JS module.
All checks were successful
continuous-integration/drone/push Build is passing
2024-03-29 17:53:10 +01:00
73cba85592
Creating Canvas JS Module.
All checks were successful
continuous-integration/drone/push Build is passing
2024-03-29 01:55:13 +01:00
861bb001c9
Changing version, making Helper objects globals, adding their polyfills.
All checks were successful
continuous-integration/drone/push Build is passing
2024-03-28 22:52:14 +01:00
08fea34366
Converting as many JS libraries to ECMAScript modules.
All checks were successful
continuous-integration/drone/push Build is passing
2024-03-28 03:09:37 +01:00
a6fcf6da19
Fixing sequence no longer working with current rendering method.
All checks were successful
continuous-integration/drone/push Build is passing
2024-03-25 18:58:07 +01:00
f730121047
Fixing the icon on wayland, building on MacOS, and date on changelog
All checks were successful
continuous-integration/drone/push Build is passing
2024-03-06 18:52:58 +01:00
80f1077b35
Updating snapcraft
All checks were successful
continuous-integration/drone/push Build is passing
2024-01-11 23:28:42 +01:00
353 changed files with 36728 additions and 20481 deletions

34
.gitignore vendored
View file

@ -1,13 +1,19 @@
# Building
build/ build/
dist/ dist/
deb_dist/ deb_dist/
linux/flatpak/AppDir assets/linux/flatpak/AppDir
linux/flatpak/repo assets/linux/flatpak/repo
linux/flatpak/build-dir assets/linux/flatpak/build-dir
linux/flatpak/.flatpak-builder assets/linux/flatpak/.flatpak-builder
*.snap *.snap
*.spec *.spec
*.zip *.zip
*.tar.gz
*.spec
*.egg-info/
# Runtime data
**/**.qmlc **/**.qmlc
**/**.jsc **/**.jsc
**/**.pyc **/**.pyc
@ -20,17 +26,21 @@ linux/flatpak/.flatpak-builder
.DS_Store .DS_Store
**/.DS_Store **/.DS_Store
**/__pycache__/ **/__pycache__/
# IDE Data
.ropeproject .ropeproject
.vscode .vscode
build *.kdev4
.kdev4
docs/html docs/html
.directory .directory
*.kdev4
*.lpf *.lpf
*.lgg *.lgg
*.spec
.kdev4 # Tests
AccountFree.pro common/coverage/
AccountFree.pro.user **/.coverage
*.egg-info/
*.tar.gz # npm
common/node_modules
runtime-pyside6/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/index.mjs*

4
.gitmodules vendored
View file

@ -1,3 +1,3 @@
[submodule "LogarithmPlotter/qml/eu/ad5001/MixedMenu"] [submodule "runtime-pyside6/LogarithmPlotter/qml/eu/ad5001/MixedMenu"]
path = LogarithmPlotter/qml/eu/ad5001/MixedMenu path = runtime-pyside6/LogarithmPlotter/qml/eu/ad5001/MixedMenu
url = https://git.ad5001.eu/Ad5001/MixedMenu url = https://git.ad5001.eu/Ad5001/MixedMenu

View file

@ -1,6 +1,6 @@
# Changelog # Changelog
## v0.5.0 (11 Jan 2023) ## v0.5.0 (11 Jan 2024)
**New** **New**

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,2 +0,0 @@
#!/bin/bash
lrelease *.ts

View file

@ -1,2 +0,0 @@
#!/bin/bash
lupdate -extensions js,qs,qml,py -recursive .. -ts lp_*.ts

View file

@ -1,155 +0,0 @@
"""
* 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/>.
"""
from time import time
from PySide6.QtWidgets import QApplication
from PySide6.QtQml import QQmlApplicationEngine
from PySide6.QtCore import Qt, QTranslator, QLocale
from PySide6.QtGui import QIcon
from tempfile import TemporaryDirectory
from os import getcwd, chdir, environ, path, remove, close
from platform import release as os_release
from sys import platform, argv, version as sys_version, exit
from sys import path as sys_path
start_time = time()
# Create the temporary directory for saving copied screenshots and latex files
tempdir = TemporaryDirectory()
tmpfile = path.join(tempdir.name, 'graph.png')
pwd = getcwd()
chdir(path.dirname(path.realpath(__file__)))
if path.realpath(path.join(getcwd(), "..")) not in sys_path:
sys_path.append(path.realpath(path.join(getcwd(), "..")))
from LogarithmPlotter import __VERSION__
from LogarithmPlotter.util import config, native
from LogarithmPlotter.util.update import check_for_updates
from LogarithmPlotter.util.helper import Helper
from LogarithmPlotter.util.latex import Latex
config.init()
def get_linux_theme():
des = {
"KDE": "Fusion",
"gnome": "Basic",
"lxqt": "Fusion",
"mate": "Fusion",
}
if "XDG_SESSION_DESKTOP" in environ:
return des[environ["XDG_SESSION_DESKTOP"]] if environ["XDG_SESSION_DESKTOP"] in des else "Fusion"
else:
# Android
return "Material"
def run():
if not 'QT_QUICK_CONTROLS_STYLE' in environ:
environ["QT_QUICK_CONTROLS_STYLE"] = {
"linux": get_linux_theme(),
"freebsd": get_linux_theme(),
"win32": "Universal" if os_release == "10" else "Fusion",
"cygwin": "Fusion",
"darwin": "macOS"
}[platform]
dep_time = time()
print("Loaded dependencies in " + str((dep_time - start_time)*1000) + "ms.")
icon_fallbacks = QIcon.fallbackSearchPaths();
base_icon_path = path.join(getcwd(), "qml", "eu", "ad5001", "LogarithmPlotter", "icons")
icon_fallbacks.append(path.realpath(path.join(base_icon_path, "common")))
icon_fallbacks.append(path.realpath(path.join(base_icon_path, "objects")))
icon_fallbacks.append(path.realpath(path.join(base_icon_path, "history")))
icon_fallbacks.append(path.realpath(path.join(base_icon_path, "settings")))
icon_fallbacks.append(path.realpath(path.join(base_icon_path, "settings", "custom")))
QIcon.setFallbackSearchPaths(icon_fallbacks);
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
app = QApplication(argv)
app.setApplicationName("LogarithmPlotter")
app.setOrganizationName("Ad5001")
app.styleHints().setShowShortcutsInContextMenus(True)
app.setWindowIcon(QIcon(path.realpath(path.join(getcwd(), "logarithmplotter.svg"))))
# Installing translators
translator = QTranslator()
# Check if lang is forced.
forcedlang = [p for p in argv if p[:7]=="--lang="]
locale = QLocale(forcedlang[0][7:]) if len(forcedlang) > 0 else QLocale()
if (translator.load(locale, "lp", "_", path.realpath(path.join(getcwd(), "i18n")))):
app.installTranslator(translator);
# Installing macOS file handler.
macOSFileOpenHandler = None
if platform == "darwin":
macOSFileOpenHandler = native.MacOSFileOpenHandler()
app.installEventFilter(macOSFileOpenHandler)
engine = QQmlApplicationEngine()
global tmpfile
helper = Helper(pwd, tmpfile)
latex = Latex(tempdir)
engine.rootContext().setContextProperty("Helper", helper)
engine.rootContext().setContextProperty("Latex", latex)
engine.rootContext().setContextProperty("TestBuild", "--test-build" in argv)
engine.rootContext().setContextProperty("StartTime", dep_time)
app.translate("About","About LogarithmPlotter") # FOR SOME REASON, if this isn't included, Qt refuses to load the QML file.
engine.addImportPath(path.realpath(path.join(getcwd(), "qml")))
engine.load(path.realpath(path.join(getcwd(), "qml", "eu", "ad5001", "LogarithmPlotter", "LogarithmPlotter.qml")))
if not engine.rootObjects():
print("No root object", path.realpath(path.join(getcwd(), "qml")))
print(path.realpath(path.join(getcwd(), "qml", "eu", "ad5001", "LogarithmPlotter", "LogarithmPlotter.qml")))
exit(-1)
# Open the current diagram
chdir(pwd)
if len(argv) > 0 and path.exists(argv[-1]) and argv[-1].split('.')[-1] in ['lpf']:
engine.rootObjects()[0].loadDiagram(argv[-1])
chdir(path.dirname(path.realpath(__file__)))
if platform == "darwin":
macOSFileOpenHandler.init_graphics(engine.rootObjects()[0])
# Check for LaTeX installation if LaTeX support is enabled
if config.getSetting("enable_latex"):
latex.check_latex_install()
# Check for updates
if config.getSetting("check_for_updates"):
check_for_updates(__VERSION__, engine.rootObjects()[0])
exit_code = app.exec()
tempdir.cleanup()
config.save()
exit(exit_code)
if __name__ == "__main__":
run()

View file

@ -1,221 +0,0 @@
/**
* 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 QtQml
import QtQuick.Window
import "../js/objects.js" as Objects
import "../js/historylib.js" as HistoryLib
import "../js/history/common.js" as HistoryCommon
/*!
\qmltype History
\inqmlmodule eu.ad5001.LogarithmPlotter.History
\brief QObject holding persistantly for undo & redo stacks.
\sa HistoryBrowser, historylib
*/
Item {
// Using a QtObject is necessary in order to have proper property propagation in QML
id: historyObj
/*!
\qmlproperty int History::undoCount
Count of undo actions.
*/
property int undoCount: 0
/*!
\qmlproperty int History::redoCount
Count of redo actions.
*/
property int redoCount: 0
/*!
\qmlproperty var History::undoStack
Stack of undo actions.
*/
property var undoStack: []
/*!
\qmlproperty var History::redoStack
Stack of redo actions.
*/
property var redoStack: []
/*!
\qmlproperty bool History::saved
true when no modification was done to the current working file, false otherwise.
*/
property bool saved: true
/*!
\qmlmethod void History::clear()
Clears both undo and redo stacks completly.
*/
function clear() {
undoCount = 0
redoCount = 0
undoStack = []
redoStack = []
}
/*!
\qmlmethod var History::serialize()
Serializes history into JSON-able content.
*/
function serialize() {
let undoSt = [], redoSt = [];
for(let i = 0; i < undoCount; i++)
undoSt.push([
undoStack[i].type(),
undoStack[i].export()
]);
for(let i = 0; i < redoCount; i++)
redoSt.push([
redoStack[i].type(),
redoStack[i].export()
]);
return [undoSt, redoSt]
}
/*!
\qmlmethod void History::unserialize(var undoSt, var redoSt)
Unserializes both \c undoSt stack and \c redoSt stack from serialized content.
*/
function unserialize(undoSt, redoSt) {
clear();
for(let i = 0; i < undoSt.length; i++)
undoStack.push(new HistoryLib.Actions[undoSt[i][0]](...undoSt[i][1]))
for(let i = 0; i < redoSt.length; i++)
redoStack.push(new HistoryLib.Actions[redoSt[i][0]](...redoSt[i][1]))
undoCount = undoSt.length;
redoCount = redoSt.length;
objectLists.update()
}
/*!
\qmlmethod void History::addToHistory(var action)
Adds an instance of historylib.Action to history.
*/
function addToHistory(action) {
if(action instanceof HistoryLib.Action) {
console.log("Added new entry to history: " + action.getReadableString())
undoStack.push(action)
undoCount++;
if(Helper.getSettingBool("reset_redo_stack")) {
redoStack = []
redoCount = 0
}
saved = false
}
}
/*!
\qmlmethod void History::undo(bool updateObjectList = true)
Undoes the historylib.Action at the top of the undo stack and pushes it to the top of the redo stack.
By default, will update the graph and the object list. This behavior can be disabled by setting the \c updateObjectList to false.
*/
function undo(updateObjectList = true) {
if(undoStack.length > 0) {
var action = undoStack.pop()
action.undo()
if(updateObjectList)
objectLists.update()
redoStack.push(action)
undoCount--;
redoCount++;
saved = false
}
}
/*!
\qmlmethod void History::redo(bool updateObjectList = true)
Redoes the historylib.Action at the top of the redo stack and pushes it to the top of the undo stack.
By default, will update the graph and the object list. This behavior can be disabled by setting the \c updateObjectList to false.
*/
function redo(updateObjectList = true) {
if(redoStack.length > 0) {
var action = redoStack.pop()
action.redo()
if(updateObjectList)
objectLists.update()
undoStack.push(action)
undoCount++;
redoCount--;
saved = false
}
}
/*!
\qmlmethod void History::undoMultipleDefered(int toUndoCount)
Undoes several historylib.Action at the top of the undo stack and pushes them to the top of the redo stack.
It undoes them deferedly to avoid overwhelming the computer while creating a cool short accelerated summary of all changes.
*/
function undoMultipleDefered(toUndoCount) {
undoTimer.toUndoCount = toUndoCount;
undoTimer.start()
if(toUndoCount > 0)
saved = false
}
/*!
\qmlmethod void History::redoMultipleDefered(int toRedoCount)
Redoes several historylib.Action at the top of the redo stack and pushes them to the top of the undo stack.
It redoes them deferedly to avoid overwhelming the computer while creating a cool short accelerated summary of all changes.
*/
function redoMultipleDefered(toRedoCount) {
redoTimer.toRedoCount = toRedoCount;
redoTimer.start()
if(toRedoCount > 0)
saved = false
}
Timer {
id: undoTimer
interval: 5; running: false; repeat: true
property int toUndoCount: 0
onTriggered: {
if(toUndoCount > 0) {
historyObj.undo(toUndoCount % 4 == 1) // Only redraw once every 4 changes.
toUndoCount--;
} else {
running = false;
}
}
}
Timer {
id: redoTimer
interval: 5; running: false; repeat: true
property int toRedoCount: 0
onTriggered: {
if(toRedoCount > 0) {
historyObj.redo(toRedoCount % 4 == 1) // Only redraw once every 4 changes.
toRedoCount--;
} else {
running = false;
}
}
}
Component.onCompleted: {
HistoryLib.history = historyObj
HistoryCommon.themeTextColor = sysPalette.windowText
HistoryCommon.imageDepth = Screen.devicePixelRatio
}
}

View file

@ -1,5 +0,0 @@
module eu.ad5001.LogarithmPlotter.History
History 1.0 History.qml
HistoryBrowser 1.0 HistoryBrowser.qml
HistoryItem 1.0 HistoryItem.qml

View file

@ -1,493 +0,0 @@
/**
* 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 Qt.labs.platform as Native
import "js/objects.js" as Objects
import "js/utils.js" as Utils
import "js/mathlib.js" as MathLib
/*!
\qmltype LogGraphCanvas
\inqmlmodule eu.ad5001.LogarithmPlotter
\brief Canvas used to display the diagram.
Provides a customized canvas with several helper methods to be used by objects.
\sa LogarithmPlotter, PickLocationOverlay
*/
Canvas {
id: canvas
anchors.top: separator.bottom
anchors.left: parent.left
height: parent.height - 90
width: parent.width
/*!
\qmlproperty double LogGraphCanvas::xmin
Minimum x of the diagram, provided from settings.
\sa Settings
*/
property double xmin: 0
/*!
\qmlproperty double LogGraphCanvas::ymax
Maximum y of the diagram, provided from settings.
\sa Settings
*/
property double ymax: 0
/*!
\qmlproperty double LogGraphCanvas::xzoom
Zoom on the x axis of the diagram, provided from settings.
\sa Settings
*/
property double xzoom: 10
/*!
\qmlproperty double LogGraphCanvas::yzoom
Zoom on the y axis of the diagram, provided from settings.
\sa Settings
*/
property double yzoom: 10
/*!
\qmlproperty string LogGraphCanvas::xaxisstep
Step of the x axis graduation, provided from settings.
\note: Only available in non-logarithmic mode.
\sa Settings
*/
property string xaxisstep: "4"
/*!
\qmlproperty string LogGraphCanvas::yaxisstep
Step of the y axis graduation, provided from settings.
\sa Settings
*/
property string yaxisstep: "4"
/*!
\qmlproperty string LogGraphCanvas::xlabel
Label used on the x axis, provided from settings.
\sa Settings
*/
property string xlabel: ""
/*!
\qmlproperty string LogGraphCanvas::ylabel
Label used on the y axis, provided from settings.
\sa Settings
*/
property string ylabel: ""
/*!
\qmlproperty double LogGraphCanvas::linewidth
Width of lines that will be drawn into the canvas, provided from settings.
\sa Settings
*/
property double linewidth: 1
/*!
\qmlproperty double LogGraphCanvas::textsize
Font size of the text that will be drawn into the canvas, provided from settings.
\sa Settings
*/
property double textsize: 14
/*!
\qmlproperty bool LogGraphCanvas::logscalex
true if the canvas should be in logarithmic mode, false otherwise.
Provided from settings.
\sa Settings
*/
property bool logscalex: false
/*!
\qmlproperty bool LogGraphCanvas::showxgrad
true if the x graduation should be shown, false otherwise.
Provided from settings.
\sa Settings
*/
property bool showxgrad: false
/*!
\qmlproperty bool LogGraphCanvas::showygrad
true if the y graduation should be shown, false otherwise.
Provided from settings.
\sa Settings
*/
property bool showygrad: false
/*!
\qmlproperty int LogGraphCanvas::maxgradx
Max power of the logarithmic scaled on the x axis in logarithmic mode.
*/
property int maxgradx: 20
/*!
\qmlproperty var LogGraphCanvas::yaxisstepExpr
Expression for the y axis step (used to create labels).
*/
property var yaxisstepExpr: (new MathLib.Expression(`x*(${yaxisstep})`))
/*!
\qmlproperty double LogGraphCanvas::yaxisstep1
Value of the for the y axis step.
*/
property double yaxisstep1: yaxisstepExpr.execute(1)
/*!
\qmlproperty int LogGraphCanvas::drawMaxY
Minimum value of y that should be drawn onto the canvas.
*/
property int drawMaxY: Math.ceil(Math.max(Math.abs(ymax), Math.abs(px2y(canvasSize.height)))/yaxisstep1)
/*!
\qmlproperty var LogGraphCanvas::xaxisstepExpr
Expression for the x axis step (used to create labels).
*/
property var xaxisstepExpr: (new MathLib.Expression(`x*(${xaxisstep})`))
/*!
\qmlproperty double LogGraphCanvas::xaxisstep1
Value of the for the x axis step.
*/
property double xaxisstep1: xaxisstepExpr.execute(1)
/*!
\qmlproperty int LogGraphCanvas::drawMaxX
Maximum value of x that should be drawn onto the canvas.
*/
property int drawMaxX: Math.ceil(Math.max(Math.abs(xmin), Math.abs(px2x(canvasSize.width)))/xaxisstep1)
/*!
\qmlproperty var LogGraphCanvas::imageLoaders
Dictionary of format {image: [callback.image data]} containing data for defered image loading.
*/
property var imageLoaders: {}
/*!
\qmlproperty var LogGraphCanvas::ctx
Cache for the 2D context so that it may be used asynchronously.
*/
property var ctx
Component.onCompleted: imageLoaders = {}
Native.MessageDialog {
id: drawingErrorDialog
title: qsTranslate("expression", "LogarithmPlotter - Drawing error")
text: ""
function showDialog(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')
if(rect.width == canvas.width) { // Redraw full canvas
ctx = getContext("2d");
reset(ctx)
drawGrille(ctx)
drawAxises(ctx)
drawLabels(ctx)
ctx.lineWidth = linewidth
for(var objType in Objects.currentObjects) {
for(var obj of Objects.currentObjects[objType]){
ctx.strokeStyle = obj.color
ctx.fillStyle = obj.color
if(obj.visible)
try {
obj.draw(canvas, ctx)
} catch(e) {
// Drawing throws an error. Generally, it's due to a new modification (or the opening of a file)
drawingErrorDialog.showDialog(objType, obj.name, e.message)
history.undo()
}
}
}
ctx.lineWidth = 1
}
}
onImageLoaded: {
Object.keys(imageLoaders).forEach((key) => {
if(isImageLoaded(key)) {
// Calling callback
imageLoaders[key][0](canvas, ctx, imageLoaders[key][1])
delete imageLoaders[key]
}
})
}
/*!
\qmlmethod void LogGraphCanvas::reset(var ctx)
Resets the canvas to a blank one with default setting using 2D \c ctx.
*/
function reset(ctx){
// Reset
ctx.fillStyle = "#FFFFFF"
ctx.strokeStyle = "#000000"
ctx.font = `${canvas.textsize}px sans-serif`
ctx.fillRect(0,0,width,height)
}
// Drawing the log based graph
/*!
\qmlmethod void LogGraphCanvas::drawGrille(var ctx)
Draws the grid using 2D \c ctx.
*/
function drawGrille(ctx) {
ctx.strokeStyle = "#C0C0C0"
if(logscalex) {
for(var xpow = -maxgradx; xpow <= maxgradx; xpow++) {
for(var xmulti = 1; xmulti < 10; xmulti++) {
drawXLine(ctx, Math.pow(10, xpow)*xmulti)
}
}
} else {
for(var x = 0; x < drawMaxX; x+=1) {
drawXLine(ctx, x*xaxisstep1)
drawXLine(ctx, -x*xaxisstep1)
}
}
for(var y = 0; y < drawMaxY; y+=1) {
drawYLine(ctx, y*yaxisstep1)
drawYLine(ctx, -y*yaxisstep1)
}
}
/*!
\qmlmethod void LogGraphCanvas::drawAxises(var ctx)
Draws the graph axises using 2D \c ctx.
*/
function drawAxises(ctx) {
ctx.strokeStyle = "#000000"
var axisypos = logscalex ? 1 : 0
drawXLine(ctx, axisypos)
drawYLine(ctx, 0)
var axisypx = x2px(axisypos) // X coordinate of Y axis
var axisxpx = y2px(0) // Y coordinate of X axis
// Drawing arrows
drawLine(ctx, axisypx, 0, axisypx-10, 10)
drawLine(ctx, axisypx, 0, axisypx+10, 10)
drawLine(ctx, canvasSize.width, axisxpx, canvasSize.width-10, axisxpx-10)
drawLine(ctx, canvasSize.width, axisxpx, canvasSize.width-10, axisxpx+10)
}
/*!
\qmlmethod void LogGraphCanvas::drawLabels(var ctx)
Draws all labels (graduation & axises labels) using 2D \c ctx.
*/
function drawLabels(ctx) {
var axisypx = x2px(logscalex ? 1 : 0) // X coordinate of Y axis
var axisxpx = y2px(0) // Y coordinate of X axis
// Labels
ctx.fillStyle = "#000000"
ctx.font = `${canvas.textsize}px sans-serif`
ctx.fillText(ylabel, axisypx+10, 24)
var textSize = ctx.measureText(xlabel).width
ctx.fillText(xlabel, canvasSize.width-14-textSize, axisxpx-5)
// Axis graduation labels
ctx.font = `${canvas.textsize-4}px sans-serif`
var txtMinus = ctx.measureText('-').width
if(showxgrad) {
if(logscalex) {
for(var xpow = -maxgradx; xpow <= maxgradx; xpow+=1) {
var textSize = ctx.measureText("10"+Utils.textsup(xpow)).width
if(xpow != 0)
drawVisibleText(ctx, "10"+Utils.textsup(xpow), x2px(Math.pow(10,xpow))-textSize/2, axisxpx+16+(6*(xpow==1)))
}
} else {
for(var x = 1; x < drawMaxX; x += 1) {
var drawX = x*xaxisstep1
var txtX = xaxisstepExpr.simplify(x).replace(/^\((.+)\)$/, '$1')
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).replace(/^\((.+)\)$/, '$1')
var textSize = ctx.measureText(txtY).width
drawVisibleText(ctx, txtY, axisypx-6-textSize, y2px(drawY)+4+(10*(y==0)))
if(y != 0)
drawVisibleText(ctx, '-'+txtY, axisypx-6-textSize-txtMinus, y2px(-drawY)+4)
}
}
ctx.fillStyle = "#FFFFFF"
}
/*!
\qmlmethod void LogGraphCanvas::drawXLine(var ctx, double x)
Draws an horizontal line at \c x plot coordinate using 2D \c ctx.
*/
function drawXLine(ctx, x) {
if(isVisible(x, ymax)) {
drawLine(ctx, x2px(x), 0, x2px(x), canvasSize.height)
}
}
/*!
\qmlmethod void LogGraphCanvas::drawXLine(var ctx, double x)
Draws an vertical line at \c y plot coordinate using 2D \c ctx.
*/
function drawYLine(ctx, y) {
if(isVisible(xmin, y)) {
drawLine(ctx, 0, y2px(y), canvasSize.width, y2px(y))
}
}
/*!
\qmlmethod void LogGraphCanvas::drawVisibleText(var ctx, string text, double x, double y)
Writes multline \c text onto the canvas using 2D \c ctx.
\note The \c x and \c y properties here are relative to the canvas, not the plot.
*/
function drawVisibleText(ctx, text, x, y) {
if(x > 0 && x < canvasSize.width && y > 0 && y < canvasSize.height) {
text.toString().split("\n").forEach(function(txt, i){
ctx.fillText(txt, x, y+(canvas.textsize*i))
})
}
}
/*!
\qmlmethod void LogGraphCanvas::drawVisibleImage(var ctx, var image, double x, double y)
Draws an \c image onto the canvas using 2D \c ctx.
\note The \c x, \c y \c width and \c height properties here are relative to the canvas, not the plot.
*/
function drawVisibleImage(ctx, image, x, y, width, height) {
//console.log("Drawing image", isImageLoaded(image), isImageError(image))
markDirty(Qt.rect(x, y, width, height));
ctx.drawImage(image, x, y, width, height)
/*if(true || (x > 0 && x < canvasSize.width && y > 0 && y < canvasSize.height)) {
}*/
}
/*!
\qmlmethod var LogGraphCanvas::measureText(var ctx, string text)
Measures the wicth and height of a multiline \c text that would be drawn onto the canvas using 2D \c ctx.
Return format: dictionary {"width": width, "height": height}
*/
function measureText(ctx, text) {
let theight = 0
let twidth = 0
let defaultHeight = ctx.measureText("M").width // Approximate but good enough!
text.split("\n").forEach(function(txt, i){
theight += defaultHeight
if(ctx.measureText(txt).width > twidth) twidth = ctx.measureText(txt).width
})
return {'width': twidth, 'height': theight}
}
/*!
\qmlmethod double LogGraphCanvas::x2px(double x)
Converts an \c x coordinate to it's relative position on the canvas.
It supports both logarithmic and non logarithmic scale depending on the currently selected mode.
*/
function x2px(x) {
if(logscalex) {
var logxmin = Math.log(xmin)
return (Math.log(x)-logxmin)*xzoom
} else return (x - xmin)*xzoom
}
/*!
\qmlmethod double LogGraphCanvas::y2px(double y)
Converts an \c y coordinate to it's relative position on the canvas.
The y axis not supporting logarithmic scale, it only support linear convertion.
*/
function y2px(y) {
return (ymax-y)*yzoom
}
/*!
\qmlmethod double LogGraphCanvas::px2x(double px)
Converts an x \c px position on the canvas to it's corresponding coordinate on the plot.
It supports both logarithmic and non logarithmic scale depending on the currently selected mode.
*/
function px2x(px) {
if(logscalex) {
return Math.exp(px/xzoom+Math.log(xmin))
} else return (px/xzoom+xmin)
}
/*!
\qmlmethod double LogGraphCanvas::px2x(double px)
Converts an x \c px position on the canvas to it's corresponding coordinate on the plot.
It supports both logarithmic and non logarithmic scale depending on the currently selected mode.
*/
function px2y(px) {
return -(px/yzoom-ymax)
}
/*!
\qmlmethod bool LogGraphCanvas::isVisible(double x, double y)
Checks whether a plot point (\c x, \c y) is visible or not on the canvas.
*/
function isVisible(x, y) {
return (x2px(x) >= 0 && x2px(x) <= canvasSize.width) && (y2px(y) >= 0 && y2px(y) <= canvasSize.height)
}
/*!
\qmlmethod bool LogGraphCanvas::drawLine(var ctx, double x1, double y1, double x2, double y2)
Draws a line from plot point (\c x1, \c y1) to plot point (\c x2, \¢ y2) using 2D \c ctx.
*/
function drawLine(ctx, x1, y1, x2, y2) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
/*!
\qmlmethod bool LogGraphCanvas::drawDashedLine2(var ctx, double x1, double y1, double x2, double y2)
Draws a dashed line from plot point (\c x1, \c y1) to plot point (\c x2, \¢ y2) using 2D \c ctx.
*/
function drawDashedLine2(ctx, x1, y1, x2, y2, dashPxSize = 5) {
ctx.setLineDash([dashPxSize, dashPxSize]);
drawLine(ctx, x1, y1, x2, y2)
ctx.setLineDash([]);
}
/*!
\qmlmethod bool LogGraphCanvas::drawDashedLine(var ctx, double x1, double y1, double x2, double y2)
Draws a dashed line from plot point (\c x1, \c y1) to plot point (\c x2, \¢ y2) using 2D \c ctx.
(Legacy slower method)
*/
function drawDashedLine(ctx, x1, y1, x2, y2, dashPxSize = 10) {
var distance = Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))
var progPerc = dashPxSize/distance
ctx.beginPath();
ctx.moveTo(x1, y1);
for(var i = 0; i < 1; i += progPerc) {
ctx.lineTo(x1-(x1-x2)*i, y1-(y1-y2)*i)
ctx.moveTo(x1-(x1-x2)*(i+progPerc/2), y1-(y1-y2)*(i+progPerc/2))
}
ctx.stroke();
}
/*!
\qmlmethod var LogGraphCanvas::renderLatexImage(string ltxText, color)
Renders latex markup \c ltxText to an image and loads it. Returns a dictionary with three values: source, width and height.
*/
function renderLatexImage(ltxText, color, callback) {
let [ltxSrc, ltxWidth, ltxHeight] = Latex.render(ltxText, textsize, color).split(",")
let imgData = {
"source": ltxSrc,
"width": parseFloat(ltxWidth),
"height": parseFloat(ltxHeight)
};
if(!isImageLoaded(ltxSrc) && !isImageLoading(ltxSrc)){
// Wait until the image is loaded to callback.
loadImage(ltxSrc)
imageLoaders[ltxSrc] = [callback, imgData]
} else {
// Callback directly
callback(canvas, ctx, imgData)
}
}
}

View file

@ -1,378 +0,0 @@
/**
* 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 QtQml
import QtQuick.Controls
import eu.ad5001.MixedMenu 1.1
import QtQuick.Layouts 1.12
import QtQuick
// Auto loading all objects.
import "js/objs/autoload.js" as ALObjects
import "js/objects.js" as Objects
import "js/math/latex.js" as LatexJS
import eu.ad5001.LogarithmPlotter.History 1.0
import eu.ad5001.LogarithmPlotter.ObjectLists 1.0
import eu.ad5001.LogarithmPlotter.Popup 1.0 as Popup
/*!
\qmltype LogarithmPlotter
\inqmlmodule eu.ad5001.LogarithmPlotter
\brief Main window of LogarithmPlotter
\sa AppMenuBar, History, GreetScreen, Changelog, Alert, ObjectLists, Settings, HistoryBrowser, LogGraphCanvas, PickLocationOverlay.
*/
ApplicationWindow {
id: root
visible: true
width: 1000
height: 500
color: sysPalette.window
title: "LogarithmPlotter " + (settings.saveFilename != "" ? " - " + settings.saveFilename.split('/').pop() : "") + (history.saved ? "" : "*")
SystemPalette {
id: sysPalette; colorGroup: SystemPalette.Active
Component.onCompleted: {
// LatexJS initialization.
LatexJS.enabled = Helper.getSettingBool("enable_latex")
LatexJS.Renderer = Latex
LatexJS.defaultColor = sysPalette.windowText
}
}
SystemPalette { id: sysPaletteIn; colorGroup: SystemPalette.Disabled }
menuBar: appMenu.trueItem
AppMenuBar {id: appMenu}
History { id: history }
Popup.GreetScreen {}
Popup.Changelog {id: changelog}
Popup.About {id: about}
Popup.ThanksTo {id: thanksTo}
Popup.Alert {
id: alert
anchors.bottom: parent.bottom
anchors.bottomMargin: 5
z: 3
}
Item {
id: sidebar
width: 300
height: parent.height
//y: root.menuBar.height
readonly property bool inPortrait: root.width < root.height
/*modal: true// inPortrait
interactive: inPortrait
position: inPortrait ? 0 : 1
*/
visible: !inPortrait
TabBar {
id: sidebarSelector
width: parent.width
anchors.top: parent.top
TabButton {
text: qsTr("Objects")
icon.name: 'polygon-add-nodes'
icon.color: sysPalette.windowText
//height: 24
}
TabButton {
text: qsTr("Settings")
icon.name: 'preferences-system-symbolic'
icon.color: sysPalette.windowText
//height: 24
}
TabButton {
text: qsTr("History")
icon.name: 'view-history'
icon.color: sysPalette.windowText
//height: 24
}
}
StackLayout {
id: sidebarContents
anchors.top: sidebarSelector.bottom
anchors.left: parent.left
anchors.topMargin: 5
anchors.leftMargin: 5
anchors.bottom: parent.bottom
//anchors.bottomMargin: sidebarSelector.height
width: parent.width - 5
currentIndex: sidebarSelector.currentIndex
z: -1
clip: true
ObjectLists {
id: objectLists
onChanged: drawCanvas.requestPaint()
}
Settings {
id: settings
canvas: drawCanvas
onChanged: drawCanvas.requestPaint()
}
HistoryBrowser {
id: historyBrowser
}
}
}
LogGraphCanvas {
id: drawCanvas
anchors.top: parent.top
anchors.left: sidebar.inPortrait ? parent.left : sidebar.right
height: parent.height
width: sidebar.inPortrait ? parent.width : parent.width - sidebar.width//*sidebar.position
x: sidebar.width//*sidebar.position
xmin: settings.xmin
ymax: settings.ymax
xzoom: settings.xzoom
yzoom: settings.yzoom
xlabel: settings.xlabel
ylabel: settings.ylabel
yaxisstep: settings.yaxisstep
xaxisstep: settings.xaxisstep
logscalex: settings.logscalex
linewidth: settings.linewidth
textsize: settings.textsize
showxgrad: settings.showxgrad
showygrad: settings.showygrad
property bool firstDrawDone: false
onPainted: if(!firstDrawDone) {
firstDrawDone = true;
console.info("First paint done in " + (new Date().getTime()-(StartTime*1000)) + "ms")
if(TestBuild == true) {
console.log("Plot drawn in canvas, terminating test of build in 100ms.")
testBuildTimer.start()
}
}
ViewPositionChangeOverlay {
id: viewPositionChanger
anchors.fill: parent
canvas: parent
settingsInstance: settings
}
PickLocationOverlay {
id: positionPicker
anchors.fill: parent
canvas: parent
}
}
/*!
\qmlmethod void LogarithmPlotter::saveDiagram(string filename)
Saves the diagram to a certain \c filename.
*/
function saveDiagram(filename) {
if(['lpf'].indexOf(filename.split('.')[filename.split('.').length-1]) == -1)
filename += '.lpf'
settings.saveFilename = filename
var objs = {}
for(var objType in Objects.currentObjects){
objs[objType] = []
for(var obj of Objects.currentObjects[objType]) {
objs[objType].push(obj.export())
}
}
Helper.write(filename, JSON.stringify({
"xzoom": settings.xzoom,
"yzoom": settings.yzoom,
"xmin": settings.xmin,
"ymax": settings.ymax,
"xaxisstep": settings.xaxisstep,
"yaxisstep": settings.yaxisstep,
"xaxislabel": settings.xlabel,
"yaxislabel": settings.ylabel,
"logscalex": settings.logscalex,
"linewidth": settings.linewidth,
"showxgrad": settings.showxgrad,
"showygrad": settings.showygrad,
"textsize": settings.textsize,
"history": history.serialize(),
"width": root.width,
"height": root.height,
"objects": objs,
"type": "logplotv1"
}))
alert.show(qsTr("Saved plot to '%1'.").arg(filename.split("/").pop()))
history.saved = true
}
/*!
\qmlmethod void LogarithmPlotter::saveDiagram(string filename)
Loads the diagram from a certain \c filename.
*/
function loadDiagram(filename) {
let basename = filename.split("/").pop()
alert.show(qsTr("Loading file '%1'.").arg(basename))
let data = JSON.parse(Helper.load(filename))
let error = "";
if(Object.keys(data).includes("type") && data["type"] == "logplotv1") {
history.clear()
// Importing settings
settings.saveFilename = filename
settings.xzoom = data["xzoom"]
settings.yzoom = data["yzoom"]
settings.xmin = data["xmin"]
settings.ymax = data["ymax"]
settings.xaxisstep = data["xaxisstep"]
settings.yaxisstep = data["yaxisstep"]
settings.xlabel = data["xaxislabel"]
settings.ylabel = data["yaxislabel"]
settings.logscalex = data["logscalex"]
if("showxgrad" in data)
settings.showxgrad = data["showxgrad"]
if("showygrad" in data)
settings.textsize = data["showygrad"]
if("linewidth" in data)
settings.linewidth = data["linewidth"]
if("textsize" in data)
settings.textsize = data["textsize"]
root.height = data["height"]
root.width = data["width"]
// Importing objects
Objects.currentObjects = {}
Object.keys(Objects.currentObjectsByName).forEach(key => {
delete Objects.currentObjectsByName[key];
// Required to keep the same reference for the copy of the object used in expression variable detection.
// Another way would be to change the reference as well, but I feel like the code would be less clean.
})
for(let objType in data['objects']) {
if(Object.keys(Objects.types).indexOf(objType) > -1) {
Objects.currentObjects[objType] = []
for(let objData of data['objects'][objType]) {
let obj = new Objects.types[objType](...objData)
Objects.currentObjects[objType].push(obj)
Objects.currentObjectsByName[obj.name] = obj
}
} else {
error += qsTr("Unknown object type: %1.").arg(objType) + "\n";
}
}
// Updating object dependencies.
for(let objName in Objects.currentObjectsByName)
Objects.currentObjectsByName[objName].update()
// Importing history
if("history" in data)
history.unserialize(...data["history"])
// Refreshing sidebar
if(sidebarSelector.currentIndex == 0) {
// For some reason, if we load a file while the tab is on object,
// we get stuck in a Qt-side loop? Qt bug or side-effect here, I don't know.
sidebarSelector.currentIndex = 1
objectLists.update()
delayRefreshTimer.start()
} else {
objectLists.update()
}
} else {
error = qsTr("Invalid file provided.")
}
if(error != "") {
console.log(error)
alert.show(qsTr("Could not save file: ") + error)
// TODO: Error handling
return
}
drawCanvas.requestPaint()
alert.show(qsTr("Loaded file '%1'.").arg(basename))
history.saved = true
}
Timer {
id: delayRefreshTimer
repeat: false
interval: 1
onTriggered: sidebarSelector.currentIndex = 0
}
Timer {
id: testBuildTimer
repeat: false
interval: 100
onTriggered: Qt.quit() // Quit after paint on test build
}
onClosing: function(close) {
if(!history.saved) {
close.accepted = false
appMenu.openSaveUnsavedChangesDialog()
}
}
/*!
\qmlmethod void LogarithmPlotter::copyDiagramToClipboard()
Copies the current diagram image to the clipboard.
*/
function copyDiagramToClipboard() {
var file = Helper.gettmpfile()
drawCanvas.save(file)
Helper.copyImageToClipboard()
alert.show(qsTr("Copied plot screenshot to clipboard!"))
}
/*!
\qmlmethod void LogarithmPlotter::showAlert(string alertText)
Shows an alert on the diagram.
*/
function showAlert(alertText) {
// This function is called from the backend and is used to show alerts from there.
alert.show(alertText)
}
Menu {
id: updateMenu
title: qsTr("&Update")
Action {
text: qsTr("&Update LogarithmPlotter")
icon.name: 'update'
onTriggered: Qt.openUrlExternally("https://dev.apps.ad5001.eu/logarithmplotter")
}
}
/*!
\qmlmethod void LogarithmPlotter::showUpdateMenu()
Shows the update menu in the AppMenuBar.
*/
function showUpdateMenu() {
appMenu.addMenu(updateMenu)
}
}

View file

@ -1,236 +0,0 @@
/**
* 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 "../js/math/latex.js" as Latex
/*!
\qmltype GreetScreen
\inqmlmodule eu.ad5001.LogarithmPlotter.Popup
\brief Overlay displayed when LogarithmPlotter is launched for the first time or when it was just updated.
It contains several settings as well as an easy access to the changelog
\sa LogarithmPlotter, Settings, AppMenuBar, Changelog
*/
Popup {
id: greetingPopup
x: (parent.width-width)/2
y: Math.max(20, (parent.height-height)/2)
width: Math.max(welcome.width+70, checkForUpdatesSetting.width, resetRedoStackSetting.width)+20
height: Math.min(parent.height-40, 700)
modal: true
focus: true
clip: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
ScrollView {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.bottomMargin: bottomButtons.height + 20
clip: true
Column {
width: greetingPopup.width - 25
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())
}
Label {
id: helpText
anchors.horizontalCenter: parent.horizontalCenter
wrapMode: Text.WordWrap
font.pixelSize: 14
width: parent.width - 50
text: qsTr("Take a few seconds to configure LogarithmPlotter.\nThese settings can be changed at any time from the \"Settings\" menu.")
}
CheckBox {
id: checkForUpdatesSetting
anchors.left: parent.left
checked: Helper.getSettingBool("check_for_updates")
text: qsTr('Check for updates on startup (requires online connectivity)')
onClicked: {
Helper.setSettingBool("check_for_updates", checked)
// Set in the menu bar
appMenu.settingsMenu.children[0].checked = checked
}
}
CheckBox {
id: resetRedoStackSetting
anchors.left: parent.left
checked: Helper.getSettingBool("reset_redo_stack")
text: qsTr('Reset redo stack when a new action is added to history')
onClicked: {
Helper.setSettingBool("reset_redo_stack", checked)
appMenu.settingsMenu.children[1].checked = checked
}
}
CheckBox {
id: enableLatexSetting
anchors.left: parent.left
checked: Helper.getSettingBool("enable_latex")
text: qsTr('Enable LaTeX rendering')
onClicked: {
Helper.setSettingBool("enable_latex", checked)
appMenu.settingsMenu.children[2].checked = checked
}
}
CheckBox {
id: autocloseFormulaSetting
anchors.left: parent.left
checked: Helper.getSettingBool("expression_editor.autoclose")
text: qsTr('Automatically close parenthesises and brackets in expressions')
onClicked: {
Helper.setSettingBool("expression_editor.autoclose", checked)
appMenu.settingsMenu.children[3].children[0].checked = checked
}
}
CheckBox {
id: colorizeFormulaSetting
anchors.left: parent.left
checked: Helper.getSettingBool("expression_editor.colorize")
text: qsTr('Enable syntax highlighting for expressions')
onClicked: {
Helper.setSettingBool("expression_editor.colorize", checked)
appMenu.settingsMenu.children[3].children[1].checked = checked
}
}
CheckBox {
id: autocompleteFormulaSetting
anchors.left: parent.left
checked: Helper.getSettingBool("autocompletion.enabled")
text: qsTr('Enable autocompletion interface in expression editor')
onClicked: {
Helper.setSettingBool("autocompletion.enabled", checked)
appMenu.settingsMenu.children[3].children[2].checked = checked
}
}
Row {
anchors.left: parent.left
anchors.leftMargin: 10
spacing: 10
Label {
id: colorSchemeLabel
anchors.verticalCenter: parent.verticalCenter
wrapMode: Text.WordWrap
text: qsTr("Color scheme:")
}
ComboBox {
model: ["Breeze Light", "Breeze Dark", "Solarized", "Github Light", "Github Dark", "Nord", "Monokai"]
currentIndex: Helper.getSettingInt("expression_editor.color_scheme")
onActivated: function(index) {
Helper.setSettingInt("expression_editor.color_scheme", index)
}
}
}
}
}
Rectangle {
id: bottomSeparator
opacity: 0.3
color: sysPalette.windowText
width: parent.width * 2 / 3
height: 1
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: bottomButtons.top
anchors.bottomMargin: 9
}
Row {
id: bottomButtons
anchors.bottom: parent.bottom
anchors.bottomMargin: 7
spacing: 10
anchors.horizontalCenter: parent.horizontalCenter
Button {
id: userManualBtn
text: qsTr("User manual")
font.pixelSize: 18
onClicked: Qt.openUrlExternally("https://git.ad5001.eu/Ad5001/LogarithmPlotter/wiki/_Sidebar")
}
Button {
id: changelogBtn
text: qsTr("Changelog")
font.pixelSize: 18
onClicked: changelog.open()
}
Button {
id: doneBtn
text: qsTr("Done")
font.pixelSize: 18
onClicked: greetingPopup.close()
}
}
Component.onCompleted: if(Helper.getSetting("last_install_greet") != Helper.getVersion()) {
greetingPopup.open()
}
onClosed: Helper.setSetting("last_install_greet", Helper.getVersion())
}

View file

@ -1,334 +0,0 @@
/**
* 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: about
title: qsTr("Thanks and Contributions - LogarithmPlotter")
width: 450
minimumHeight: 710
Column {
anchors {
top: parent.top;
left: parent.left;
bottom: parent.bottom;
right: parent.right;
topMargin: margin;
leftMargin: margin;
bottomMargin: margin;
rightMargin: 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: {
append({
tranName: '🇬🇧 ' + qsTr('English'),
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/en/',
authors: [{
authorLine: 'Ad5001',
email: 'mail@ad5001.eu',
website: 'https://ad5001.eu',
websiteName: qsTr('Website')
}]
})
append({
tranName: '🇫🇷 ' + qsTr('French'),
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/fr/',
authors: [{
authorLine: 'Ad5001',
website: 'https://ad5001.eu',
websiteName: qsTr('Website')
}]
})
append({
tranName: '🇩🇪 ' + qsTr('German'),
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/de/',
authors: [{
authorLine: 'Ad5001',
website: 'https://ad5001.eu',
websiteName: qsTr('Website')
}]
})
append({
tranName: '🇭🇺 ' + qsTr('Hungarian'),
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/hu/',
authors: [{
authorLine: 'Óvári',
website: 'https://github.com/ovari',
websiteName: qsTr('Github')
}]
})
append({
tranName: '🇳🇴 ' + qsTr('Norwegian'),
link: 'https://hosted.weblate.org/projects/logarithmplotter/logarithmplotter/no/',
authors: [{
authorLine: 'Allan Nordhøy',
website: 'https://github.com/comradekingu',
websiteName: qsTr('Github')
}]
})
}
}
header: Label {
id: translationsHeader
wrapMode: Text.WordWrap
font.pixelSize: 25
text: qsTr("Translations included")
height: implicitHeight + 10
}
delegate: Column {
id: tranClmn
width: translationsListView.width
Item {
width: parent.width
height: translationHeader.height + 10
Label {
id: translationHeader
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
wrapMode: Text.WordWrap
font.pixelSize: 18
text: tranName
}
Row {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
height: 30
spacing: 10
Button {
height: parent.height
text: qsTr('Improve')
icon.name: 'web-browser'
onClicked: Qt.openUrlExternally(link)
}
}
}
ListView {
id: tranAuthors
anchors.left: parent.left
anchors.leftMargin: 10
model: authors
width: parent.width - 10
implicitHeight: contentItem.childrenRect.height
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.right: parent.right
anchors.verticalCenter: parent.verticalCenter
height: 30
spacing: 10
Button {
text: websiteName
icon.name: 'web-browser'
height: parent.height
onClicked: Qt.openUrlExternally(website)
}
}
}
}
}
}
}
}

View file

@ -1 +0,0 @@
../../common/position.svg

View file

@ -1 +0,0 @@
../../common/position.svg

View file

@ -1 +0,0 @@
../../common/position.svg

File diff suppressed because it is too large Load diff

View file

@ -1,95 +0,0 @@
/**
* 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/>.
*/
.pragma library
.import "../objects.js" as Objects
.import "../mathlib.js" as MathLib
.import "../math/latex.js" as Latex
.import "../utils.js" as Utils
.import "../objs/common.js" as Common
.import "common.js" as C
class EditedPosition extends C.Action {
// Action used for objects that have a X and Y expression properties (points, texts...)
type(){return 'EditedPosition'}
icon(){return 'position'}
color(darkVer=false){
return darkVer ? 'seagreen' : 'lightseagreen';
}
constructor(targetName = "", targetType = "Point", previousXValue = "", newXValue = "", previousYValue = "", newYValue = "") {
super(targetName, targetType)
let imports = {
'previousXValue': previousXValue,
'previousYValue': previousYValue,
'newXValue': newXValue,
'newYValue': newYValue
}
for(let name in imports)
this[name] = (typeof imports[name]) == 'string' ? new MathLib.Expression(imports[name]) : imports[name]
this.setReadableValues()
}
undo() {
Objects.currentObjectsByName[this.targetName].x = this.previousXValue
Objects.currentObjectsByName[this.targetName].y = this.previousYValue
Objects.currentObjectsByName[this.targetName].update()
}
redo() {
Objects.currentObjectsByName[this.targetName].x = this.newXValue
Objects.currentObjectsByName[this.targetName].y = this.newYValue
Objects.currentObjectsByName[this.targetName].update()
}
setReadableValues() {
this.prevString = `(${this.previousXValue.toString()},${this.previousYValue.toString()})`
this.nextString = `(${this.newXValue.toString()},${this.newYValue.toString()})`
// Render as LaTeX
if(Latex.enabled) {
this.prevHTML = this.renderLatexAsHtml(`\\left(${this.previousXValue.latexMarkup},${this.previousYValue.latexMarkup}\\right)`)
this.nextHTML = this.renderLatexAsHtml(`\\left(${this.newXValue.latexMarkup},${this.newYValue.latexMarkup}\\right)`)
} else {
this.prevHTML = '<tt style="background: rgba(128,128,128,0.1);">&nbsp;'+Utils.escapeHTML(this.prevString)+'&nbsp;</tt>'
this.nextHTML = '<tt style="background: rgba(128,128,128,0.1);">&nbsp;'+Utils.escapeHTML(this.nextString)+'&nbsp;</tt>'
}
}
export() {
return [this.targetName, this.targetType,
this.previousXValue.toEditableString(), this.newXValue.toEditableString(),
this.previousYValue.toEditableString(), this.newYValue.toEditableString()]
}
getReadableString() {
return qsTr('Position of %1 %2 set from "%3" to "%4".')
.arg(Objects.types[this.targetType].displayType())
.arg(this.targetName).arg(this.prevString).arg(this.nextString)
}
getHTMLString() {
return qsTr('Position of %1 set from %2 to %3.')
.arg('<b style="font-size: 15px;">&nbsp;' + this.targetName + '&nbsp;</b>')
.arg(this.prevHTML)
.arg(this.nextHTML)
}
}

View file

@ -1,99 +0,0 @@
/**
* 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/>.
*/
.pragma library
.import "../expr-eval.js" as ExprEval
.import "../utils.js" as Utils
.import "latex.js" as Latex
var evalVariables = { // Variables not provided by expr-eval.js, needs to be provided manually
"pi": Math.PI,
"PI": Math.PI,
"π": Math.PI,
"inf": Infinity,
"infinity": Infinity,
"Infinity": Infinity,
"∞": Infinity,
"e": Math.E,
"E": Math.E,
"true": true,
"false": false
}
var currentVars = {}
var currentObjectsByName = {} // Mirror of currentObjectsByName in objects.js
const parser = new ExprEval.Parser()
parser.consts = Object.assign({}, parser.consts, evalVariables)
/**
* Parses arguments for a function, returns the corresponding JS function if it exists.
* Throws either usage error otherwise.
* @param {array} args - Arguments of the function, either [ ExecutableObject ] or [ string, variable ].
* @param {string} usage1 - Usage for executable object.
* @param {string} usage2 - Usage for string function.
* @return {callable} JS function to call..
*/
function parseArgumentsForFunction(args, usage1, usage2) {
let f, target, variable
if(args.length == 1) {
// Parse object
f = args[0]
if(typeof f != 'object' || !f.execute)
throw EvalError(qsTranslate('usage', 'Usage: %1').arg(usage1))
let target = f
f = (x) => target.execute(x)
} else if(args.length == 2) {
// Parse variable
[f,variable] = args
if(typeof f != 'string' || typeof variable != 'string')
throw EvalError(qsTranslate('usage', 'Usage: %1').arg(usage2))
f = parser.parse(f).toJSFunction(variable, currentVars)
} else
throw EvalError(qsTranslate('usage', 'Usage: %1 or\n%2').arg(usage1).arg(usage2))
return f
}
// Function definition
parser.functions.integral = function(a, b, ...args) {
let usage1 = qsTranslate('usage', 'integral(<from: number>, <to: number>, <f: ExecutableObject>)')
let usage2 = qsTranslate('usage', 'integral(<from: number>, <to: number>, <f: string>, <variable: string>)')
let f = parseArgumentsForFunction(args, usage1, usage2)
if(a == null || b == null)
throw EvalError(qsTranslate('usage', 'Usage: %1 or\n%2').arg(usage1).arg(usage2))
// https://en.wikipedia.org/wiki/Simpson%27s_rule
// Simpler, faster than tokenizing the expression
return (b-a)/6*(f(a)+4*f((a+b)/2)+f(b))
}
parser.functions.derivative = function(...args) {
let usage1 = qsTranslate('usage', 'derivative(<f: ExecutableObject>, <x: number>)')
let usage2 = qsTranslate('usage', 'derivative(<f: string>, <variable: string>, <x: number>)')
let x = args.pop()
let f = parseArgumentsForFunction(args, usage1, usage2)
if(x == null)
throw EvalError(qsTranslate('usage', 'Usage: %1 or\n%2').arg(usage1).arg(usage2))
let derivative_precision = x/10
return (f(x+derivative_precision/2)-f(x-derivative_precision/2))/derivative_precision
}

View file

@ -1,99 +0,0 @@
/**
* 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/>.
*/
.pragma library
.import "common.js" as C
.import "latex.js" as Latex
.import "../utils.js" as Utils
/**
* Represents any kind of x-based or non variable based expression.
*/
class Expression {
constructor(expr) {
this.expr = Utils.exponentsToExpression(expr)
this.calc = C.parser.parse(this.expr).simplify()
this.cached = this.isConstant()
this.cachedValue = this.cached && this.allRequirementsFullfilled() ? this.calc.evaluate(C.currentObjectsByName) : null
this.latexMarkup = Latex.expression(this.calc.tokens)
}
isConstant() {
let vars = this.calc.variables()
return !vars.includes("x") && !vars.includes("n")
}
requiredObjects() {
return this.calc.variables().filter(objName => objName != "x" && objName != "n")
}
allRequirementsFullfilled() {
return this.requiredObjects().every(objName => objName in C.currentObjectsByName)
}
undefinedVariables() {
return this.requiredObjects().filter(objName => !(objName in C.currentObjectsByName))
}
recache() {
if(this.cached)
this.cachedValue = this.calc.evaluate(C.currentObjectsByName)
}
execute(x = 1) {
if(this.cached) {
if(this.cachedValue == null)
this.cachedValue = this.calc.evaluate(C.currentObjectsByName)
return this.cachedValue
}
C.currentVars = Object.assign({'x': x}, C.currentObjectsByName)
return this.calc.evaluate(C.currentVars)
}
simplify(x) {
var expr = this.calc.substitute('x', x).simplify()
if(expr.evaluate() == 0) return '0'
var str = Utils.makeExpressionReadable(expr.toString());
if(str != undefined && str.match(/^\d*\.\d+$/)) {
if(str.split('.')[1].split('0').length > 7) {
// Likely rounding error
str = parseFloat(str.substring(0, str.length-1)).toString();
}
}
return str
}
duplicate() {
return new Expression(this.toEditableString())
}
toEditableString() {
return this.calc.toString()
}
toString(forceSign=false) {
let str = Utils.makeExpressionReadable(this.calc.toString())
if(str[0] != '-' && forceSign) str = '+' + str
return str
}
}
function executeExpression(expr){
return (new Expression(expr.toString())).execute()
}

View file

@ -1,282 +0,0 @@
/**
* 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/>.
*/
.pragma library
.import "../expr-eval.js" as ExprEval
/**
* true if latex has been enabled by the user, false otherwise.
*/
var enabled = false
/**
* LaTeX python backend QObject.
*/
var Renderer = null
/**
* Default window color used to render LaTeX formulas.
*/
var defaultColor = "black"
/**
* Puts element within parenthesis.
*
* @param {string} elem - element to put within parenthesis.
* @returns {string}
*/
function par(elem) {
return '(' + elem + ')'
}
/**
* Checks if the element contains at least one of the elements of
* the string array contents, but not at the first position of the string,
* and returns the parenthesis version if so.
*
* @param {string} elem - element to put within parenthesis.
* @param {Array} contents - Array of elements to put within parenthesis.
* @returns {string}
*/
function parif(elem, contents) {
elem = elem.toString()
if(elem[0] != "(" && elem[elem.length-1] != ")" && contents.some(x => elem.indexOf(x) > 0))
return par(elem)
if(elem[0] == "(" && elem[elem.length-1] == ")")
return elem.substr(1, elem.length-2)
return elem
}
/**
* Creates a latex expression for a function.
*
* @param {string} f - Function to convert
* @param {Array} args - Arguments of the function
* @returns {string}
*/
function functionToLatex(f, args) {
switch(f) {
case "derivative":
if(args.length == 3)
return '\\frac{d' + args[0].substr(1, args[0].length-2).replace(new RegExp(args[1].substr(1, args[1].length-2), 'g'), 'x') + '}{dx}';
else
return '\\frac{d' + args[0] + '}{dx}(x)';
break;
case "integral":
if(args.length == 4)
return '\\int\\limits_{' + args[0] + '}^{' + args[1] + '}' + args[2].substr(1, args[2].length-2) + ' d' + args[3].substr(1, args[3].length-2);
else
return '\\int\\limits_{' + args[0] + '}^{' + args[1] + '}' + args[2] + '(t) dt';
break;
case "sqrt":
return '\\sqrt\\left(' + args.join(', ') + '\\right)';
break;
case "abs":
return '\\left|' + args.join(', ') + '\\right|';
break;
case "floor":
return '\\left\\lfloor' + args.join(', ') + '\\right\\rfloor';
break;
case "ceil":
return '\\left\\lceil' + args.join(', ') + '\\right\\rceil';
break;
default:
return '\\mathrm{' + f + '}\\left(' + args.join(', ') + '\\right)';
break;
}
}
/**
* Creates a latex variable from a variable.
*
* @param {string} vari - variable text to convert
* @param {bool} wrapIn$ - checks whether the escaped chars should be escaped
* @returns {string}
*/
function variable(vari, wrapIn$ = false) {
let unicodechars = ["α","β","γ","δ","ε","ζ","η",
"π","θ","κ","λ","μ","ξ","ρ",
"ς","σ","τ","φ","χ","ψ","ω",
"Γ","Δ","Θ","Λ","Ξ","Π","Σ",
"Φ","Ψ","Ω","ₐ","ₑ","ₒ","ₓ",
"ₕ","ₖ","ₗ","ₘ","ₙ","ₚ","ₛ",
"ₜ","¹","²","³","⁴","⁵","⁶",
"⁷","⁸","⁹","⁰","₁","₂","₃",
"₄","₅","₆","₇","₈","₉","₀",
"pi", "∞"]
let equivalchars = ["\\alpha","\\beta","\\gamma","\\delta","\\epsilon","\\zeta","\\eta",
"\\pi","\\theta","\\kappa","\\lambda","\\mu","\\xi","\\rho",
"\\sigma","\\sigma","\\tau","\\phi","\\chi","\\psi","\\omega",
"\\Gamma","\\Delta","\\Theta","\\Lambda","\\Xi","\\Pi","\\Sigma",
"\\Phy","\\Psi","\\Omega","{}_{a}","{}_{e}","{}_{o}","{}_{x}",
"{}_{h}","{}_{k}","{}_{l}","{}_{m}","{}_{n}","{}_{p}","{}_{s}",
"{}_{t}","{}^{1}","{}^{2}","{}^{3}","{}^{4}","{}^{5}","{}^{6}",
"{}^{7}","{}^{8}","{}^{9}","{}^{0}","{}_{1}","{}_{2}","{}_{3}",
"{}_{4}","{}_{5}","{}_{6}","{}_{7}","{}_{8}","{}_{9}","{}_{0}",
"\\pi", "\\infty"]
if(wrapIn$)
for(let i = 0; i < unicodechars.length; i++) {
if(vari.includes(unicodechars[i]))
vari = vari.replace(new RegExp(unicodechars[i], 'g'), '$'+equivalchars[i]+'$')
}
else
for(let i = 0; i < unicodechars.length; i++) {
if(vari.includes(unicodechars[i]))
vari = vari.replace(new RegExp(unicodechars[i], 'g'), equivalchars[i])
}
return vari;
}
/**
* Converts expr-eval tokens to a latex string.
*
* @param {Array} tokens - expr-eval tokens list
* @returns {string}
*/
function expression(tokens) {
var nstack = [];
var n1, n2, n3;
var f, args, argCount;
for (var i = 0; i < tokens.length; i++) {
var item = tokens[i];
var type = item.type;
switch(type) {
case ExprEval.INUMBER:
if(item.value == Infinity) {
nstack.push("\\infty")
} else if(typeof item.value === 'number' && item.value < 0) {
nstack.push(par(item.value));
} else if(Array.isArray(item.value)) {
nstack.push('[' + item.value.map(ExprEval.escapeValue).join(', ') + ']');
} else {
nstack.push(ExprEval.escapeValue(item.value));
}
break;
case ExprEval.IOP2:
n2 = nstack.pop();
n1 = nstack.pop();
f = item.value;
switch(f) {
case '-':
case '+':
nstack.push(n1 + f + n2);
break;
case '||':
case 'or':
case '&&':
case 'and':
case '==':
case '!=':
nstack.push(par(n1) + f + par(n2));
break;
case '*':
if(n2 == "\\pi" || n2 == "e" || n2 == "x" || n2 == "n")
nstack.push(parif(n1,['+','-']) + n2)
else
nstack.push(parif(n1,['+','-']) + " \\times " + parif(n2,['+','-']));
break;
case '/':
nstack.push("\\frac{" + n1 + "}{" + n2 + "}");
break;
case '^':
nstack.push(parif(n1,['+','-','*','/','!']) + "^{" + n2 + "}");
break;
case '%':
nstack.push(parif(n1,['+','-','*','/','!','^']) + " \\mathrm{mod} " + parif(n2,['+','-','*','/','!','^']));
break;
case '[':
nstack.push(n1 + '[' + n2 + ']');
break;
default:
throw new EvalError("Unknown operator " + ope + ".");
}
break;
case ExprEval.IOP3: // Thirdiary operator
n3 = nstack.pop();
n2 = nstack.pop();
n1 = nstack.pop();
f = item.value;
if (f === '?') {
nstack.push('(' + n1 + ' ? ' + n2 + ' : ' + n3 + ')');
} else {
throw new EvalError('Unknown operator ' + ope + '.');
}
break;
case ExprEval.IVAR:
case ExprEval.IVARNAME:
nstack.push(variable(item.value.toString()));
break;
case ExprEval.IOP1: // Unary operator
n1 = nstack.pop();
f = item.value;
switch(f) {
case '-':
case '+':
nstack.push(par(f + n1));
break;
case '!':
nstack.push(parif(n1,['+','-','*','/','^']) + '!');
break;
default:
nstack.push(f + parif(n1,['+','-','*','/','^']));
break;
}
break;
case ExprEval.IFUNCALL:
argCount = item.value;
args = [];
while (argCount-- > 0) {
args.unshift(nstack.pop());
}
f = nstack.pop();
// Handling various functions
nstack.push(functionToLatex(f, args))
break;
case ExprEval.IFUNDEF:
nstack.push(par(n1 + '(' + args.join(', ') + ') = ' + n2));
break;
case ExprEval.IMEMBER:
n1 = nstack.pop();
nstack.push(n1 + '.' + item.value);
break;
case ExprEval.IARRAY:
argCount = item.value;
args = [];
while (argCount-- > 0) {
args.unshift(nstack.pop());
}
nstack.push('[' + args.join(', ') + ']');
break;
case ExprEval.IEXPR:
nstack.push('(' + expression(item.value) + ')');
break;
case ExprEval.IENDSTATEMENT:
break;
default:
throw new EvalError('invalid Expression');
break;
}
}
if (nstack.length > 1) {
nstack = [ nstack.join(';') ]
}
return String(nstack[0]);
}

View file

@ -1,96 +0,0 @@
/**
* 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/>.
*/
.pragma library
.import "utils.js" as Utils
.import "math/common.js" as MathCommons
.import "parameters.js" as P
var types = {}
var currentObjects = {}
var currentObjectsByName = {}
MathCommons.currentObjectsByName = currentObjectsByName // Required for using objects in variables.
function renameObject(oldName, newName) {
/**
* Renames an object from its old name to the new one.
* @param {string} oldName - Current name of the object.
* @param {string} newName - Name to rename the object to.
*/
let obj = currentObjectsByName[oldName]
delete currentObjectsByName[oldName]
currentObjectsByName[newName] = obj
obj.name = newName
}
function deleteObject(objName) {
/**
* Deletes an object by its given name.
* @param {string} objName - Current name of the object.
*/
let obj = currentObjectsByName[objName]
currentObjects[obj.type].splice(currentObjects[obj.type].indexOf(obj),1)
obj.delete()
delete currentObjectsByName[objName]
}
function getObjectsName(objType) {
/**
* Gets a list of all names of a certain object type.
* @param {string} objType - Type of the object to query. Can be ExecutableObject for all ExecutableObjects.
* @return {array} List of names of the objects.
*/
if(objType == "ExecutableObject") {
// NOTE: QMLJS does not support flatMap.
// return getExecutableTypes().flatMap(elemType => currentObjects[elemType].map(obj => obj.name))
let types = getExecutableTypes()
let elementNames = ['']
for(let elemType of types)
elementNames = elementNames.concat(currentObjects[elemType].map(obj => obj.name))
return elementNames
}
if(currentObjects[objType] == undefined) return []
return currentObjects[objType].map(obj => obj.name)
}
function getExecutableTypes() {
/**
* Returns a list of all object types which are executable objects.
* @return {array} List of all object types which are executable objects.
*/
return Object.keys(currentObjects).filter(objType => types[objType].executable())
}
function createNewRegisteredObject(objType, args=[]) {
/**
* Creates and register an object in the database.
* @param {string} objType - Type of the object to create.
* @param {string} args - List of arguments for the objects (can be empty).
* @return {[objType]} Newly created object.
*/
if(Object.keys(types).indexOf(objType) == -1) return null // Object type does not exist.
var newobj = new types[objType](...args)
if(Object.keys(currentObjects).indexOf(objType) == -1) {
currentObjects[objType] = []
}
currentObjects[objType].push(newobj)
currentObjectsByName[newobj.name] = newobj
return newobj
}

View file

@ -1,146 +0,0 @@
/**
* 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/>.
*/
.pragma library
.import "common.js" as Common
.import "function.js" as F
.import "../objects.js" as Objects
.import "../utils.js" as Utils
.import "../mathlib.js" as MathLib
.import "../historylib.js" as HistoryLib
.import "../parameters.js" as P
.import "../math/latex.js" as Latex
class GainBode extends Common.ExecutableObject {
static type(){return 'Gain Bode'}
static displayType(){return qsTr('Bode Magnitude')}
static displayTypeMultiple(){return qsTr('Bode Magnitudes')}
static properties() {return {
[QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'),
[QT_TRANSLATE_NOOP('prop','pass')]: P.Enum.BodePass,
[QT_TRANSLATE_NOOP('prop','gain')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
[QT_TRANSLATE_NOOP('prop','omGraduation')]: 'boolean'
}}
constructor(name = null, visible = true, color = null, labelContent = 'name + value',
om_0 = '', pass = 'high', gain = '20', labelPosition = 'above', labelX = 1, omGraduation = false) {
if(name == null) name = Common.getNewName('G')
if(name == 'G') name = 'G₀' // G is reserved for sum of BODE magnitudes (Somme gains Bode).
super(name, visible, color, labelContent)
if(typeof om_0 == "string") {
// Point name or create one
om_0 = Objects.currentObjectsByName[om_0]
if(om_0 == null) {
// Create new point
om_0 = Objects.createNewRegisteredObject('Point', [Common.getNewName('ω'), true, this.color, 'name'])
HistoryLib.history.addToHistory(new HistoryLib.CreateNewObject(om_0.name, 'Point', om_0.export()))
om_0.update()
labelPosition = 'below'
}
om_0.requiredBy.push(this)
}
this.om_0 = om_0
this.pass = pass
if(typeof gain == 'number' || typeof gain == 'string') gain = new MathLib.Expression(gain.toString())
this.gain = gain
this.labelPosition = labelPosition
this.labelX = labelX
this.omGraduation = omGraduation
}
getReadableString() {
let pass = this.pass == "low" ? qsTr("low-pass") : qsTr("high-pass");
return `${this.name}: ${pass}; ${this.om_0.name} = ${this.om_0.x}\n ${' '.repeat(this.name.length)}${this.gain.toString(true)} dB/dec`
}
getLatexString() {
let pass = this.pass == "low" ? qsTr("low-pass") : qsTr("high-pass");
return `\\mathrm{${Latex.variable(this.name)}:}\\begin{array}{l}
\\textsf{${pass}};${Latex.variable(this.om_0.name)} = ${this.om_0.x.latexMarkup} \\\\
${this.gain.latexMarkup}\\textsf{ dB/dec}
\\end{array}`
}
export() {
return [this.name, this.visible, this.color.toString(), this.labelContent,
this.om_0.name, this.pass.toString(), this.gain.toEditableString(), this.labelPosition, this.labelX, this.omGraduation]
}
execute(x=1) {
if(typeof x == 'string') x = MathLib.executeExpression(x)
if((this.pass == 'high' && x < this.om_0.x) || (this.pass == 'low' && x > this.om_0.x)) {
var dbfn = new MathLib.Expression(`${this.gain.execute()}*(ln(x)-ln(${this.om_0.x}))/ln(10)+${this.om_0.y}`)
return dbfn.execute(x)
} else {
return this.om_0.y.execute()
}
}
simplify(x = 1) {
var xval = x
if(typeof x == 'string') xval = MathLib.executeExpression(x)
if((this.pass == 'high' && xval < this.om_0.x) || (this.pass == 'low' && xval > this.om_0.x)) {
var dbfn = new MathLib.Expression(`${this.gain.execute()}*(ln(x)-ln(${this.om_0.x}))/ln(10)+${this.om_0.y}`)
return dbfn.simplify(x)
} else {
return this.om_0.y.toString()
}
}
canExecute(x = 1) {
return true
}
draw(canvas, ctx) {
var base = [canvas.x2px(this.om_0.x), canvas.y2px(this.om_0.y)]
var dbfn = new MathLib.Expression(`${this.gain.execute()}*(log10(x)-log10(${this.om_0.x}))+${this.om_0.y}`)
var inDrawDom = new MathLib.EmptySet()
if(this.pass == 'high') {
// High pass, linear line from begining, then constant to the end.
canvas.drawLine(ctx, base[0], base[1], canvas.canvasSize.width, base[1])
inDrawDom = MathLib.parseDomain(`]-inf;${this.om_0.x}[`)
} else {
// Low pass, constant from the beginning, linear line to the end.
canvas.drawLine(ctx, base[0], base[1], 0, base[1])
inDrawDom = MathLib.parseDomain(`]${this.om_0.x};+inf[`)
}
F.Function.drawFunction(canvas, ctx, dbfn, inDrawDom, MathLib.Domain.R)
// Dashed line representing break in function
var xpos = canvas.x2px(this.om_0.x.execute())
var dashPxSize = 10
for(var i = 0; i < canvas.canvasSize.height && this.omGraduation; i += dashPxSize*2)
canvas.drawLine(ctx, xpos, i, xpos, i+dashPxSize)
// Label
this.drawLabel(canvas, ctx, this.labelPosition, canvas.x2px(this.labelX), canvas.y2px(this.execute(this.labelX)))
}
update() {
super.update()
if(Objects.currentObjects['Somme gains Bode'] != undefined && Objects.currentObjects['Somme gains Bode'].length > 0) {
Objects.currentObjects['Somme gains Bode'][0].recalculateCache()
} else {
Objects.createNewRegisteredObject('Somme gains Bode')
}
}
}

View file

@ -1,128 +0,0 @@
/**
* 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/>.
*/
.pragma library
.import "common.js" as Common
.import "../objects.js" as Objects
.import "../mathlib.js" as MathLib
.import "../historylib.js" as HistoryLib
.import "../parameters.js" as P
.import "../math/latex.js" as Latex
class PhaseBode extends Common.ExecutableObject {
static type(){return 'Phase Bode'}
static displayType(){return qsTr('Bode Phase')}
static displayTypeMultiple(){return qsTr('Bode Phases')}
static properties() {return {
[QT_TRANSLATE_NOOP('prop','om_0')]: new P.ObjectType('Point'),
[QT_TRANSLATE_NOOP('prop','phase')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','unit')]: new P.Enum('°', 'deg', 'rad'),
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number'
}}
constructor(name = null, visible = true, color = null, labelContent = 'name + value',
om_0 = '', phase = 90, unit = '°', labelPosition = 'above', labelX = 1) {
if(name == null) name = Common.getNewName('φ')
if(name == 'φ') name = 'φ₀' // φ is reserved for sum of BODE phases (Somme phases Bode).
super(name, visible, color, labelContent)
if(typeof phase == 'number' || typeof phase == 'string') phase = new MathLib.Expression(phase.toString())
this.phase = phase
if(typeof om_0 == "string") {
// Point name or create one
om_0 = Objects.currentObjectsByName[om_0]
if(om_0 == null) {
// Create new point
om_0 = Objects.createNewRegisteredObject('Point', [Common.getNewName('ω'), this.color, 'name'])
om_0.labelPosition = this.phase.execute() >= 0 ? 'above' : 'below'
HistoryLib.history.addToHistory(new HistoryLib.CreateNewObject(om_0.name, 'Point', om_0.export()))
labelPosition = 'below'
}
om_0.requiredBy.push(this)
}
this.om_0 = om_0
this.unit = unit
this.labelPosition = labelPosition
this.labelX = labelX
}
export() {
return [this.name, this.visible, this.color.toString(), this.labelContent,
this.om_0.name, this.phase.toEditableString(), this.unit, this.labelPosition, this.labelX]
}
getReadableString() {
return `${this.name}: ${this.phase.toString(true)}${this.unit} at ${this.om_0.name} = ${this.om_0.x}`
}
getLatexString() {
return `${Latex.variable(this.name)}: ${this.phase.latexMarkup}\\textsf{${this.unit} at }${Latex.variable(this.om_0.name)} = ${this.om_0.x.latexMarkup}`
}
execute(x=1) {
if(typeof x == 'string') x = MathLib.executeExpression(x)
if(x < this.om_0.x) {
return this.om_0.y.execute()
} else {
return this.om_0.y.execute() + this.phase.execute()
}
}
simplify(x = 1) {
var xval = x
if(typeof x == 'string') xval = MathLib.executeExpression(x)
if(xval < this.om_0.x) {
return this.om_0.y.toString()
} else {
var newExp = this.om_0.y.toEditableString() + ' + ' + this.phase.toEditableString()
return (new MathLib.Expression(newExp)).toString()
}
}
canExecute(x = 1) {
return true
}
draw(canvas, ctx) {
var baseX = canvas.x2px(this.om_0.x.execute())
var omy = this.om_0.y.execute()
var augmt = this.phase.execute()
var baseY = canvas.y2px(omy)
var augmtY = canvas.y2px(omy+augmt)
// Before change line.
canvas.drawLine(ctx, 0, baseY, Math.min(baseX, canvas.canvasSize.height), baseY)
// Transition line.
canvas.drawLine(ctx, baseX, baseY, baseX, augmtY)
// After change line
canvas.drawLine(ctx, Math.max(0, baseX), augmtY, canvas.canvasSize.width, augmtY)
// Label
this.drawLabel(canvas, ctx, this.labelPosition, canvas.x2px(this.labelX), canvas.y2px(this.execute(this.labelX)))
}
update() {
if(Objects.currentObjects['Somme phases Bode'] != undefined && Objects.currentObjects['Somme phases Bode'].length > 0) {
Objects.currentObjects['Somme phases Bode'][0].recalculateCache()
} else {
Objects.createNewRegisteredObject('Somme phases Bode')
}
}
}

View file

@ -1,83 +0,0 @@
/**
* 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/>.
*/
.pragma library
.import "common.js" as Common
.import "../mathlib.js" as MathLib
.import "../parameters.js" as P
.import "../math/latex.js" as Latex
class Point extends Common.DrawableObject {
static type(){return 'Point'}
static displayType(){return qsTr('Point')}
static displayTypeMultiple(){return qsTr('Points')}
static properties() {return {
[QT_TRANSLATE_NOOP('prop','x')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','y')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','pointStyle')]: new P.Enum('●', '✕', '')
}}
constructor(name = null, visible = true, color = null, labelContent = 'name + value',
x = 1, y = 0, labelPosition = 'above', pointStyle = '●') {
if(name == null) name = Common.getNewName('ABCDEFJKLMNOPQRSTUVW')
super(name, visible, color, labelContent)
if(typeof x == 'number' || typeof x == 'string') x = new MathLib.Expression(x.toString())
this.x = x
if(typeof y == 'number' || typeof y == 'string') y = new MathLib.Expression(y.toString())
this.y = y
this.labelPosition = labelPosition
this.pointStyle = pointStyle
}
getReadableString() {
return `${this.name} = (${this.x}, ${this.y})`
}
getLatexString() {
return `${Latex.variable(this.name)} = \\left(${this.x.latexMarkup}, ${this.y.latexMarkup}\\right)`
}
export() {
return [this.name, this.visible, this.color.toString(), this.labelContent, this.x.toEditableString(), this.y.toEditableString(), this.labelPosition, this.pointStyle]
}
draw(canvas, ctx) {
var [canvasX, canvasY] = [canvas.x2px(this.x.execute()), canvas.y2px(this.y.execute())]
var pointSize = 8+(ctx.lineWidth*2)
switch(this.pointStyle) {
case '●':
ctx.beginPath();
ctx.ellipse(canvasX-pointSize/2, canvasY-pointSize/2, pointSize, pointSize)
ctx.fill();
break;
case '✕':
canvas.drawLine(ctx, canvasX-pointSize/2, canvasY-pointSize/2, canvasX+pointSize/2, canvasY+pointSize/2)
canvas.drawLine(ctx, canvasX-pointSize/2, canvasY+pointSize/2, canvasX+pointSize/2, canvasY-pointSize/2)
break;
case '':
ctx.fillRect(canvasX-pointSize/2, canvasY-1, pointSize, 2)
ctx.fillRect(canvasX-1, canvasY-pointSize/2, 2, pointSize)
break;
}
this.drawLabel(canvas, ctx, this.labelPosition, canvasX, canvasY)
}
}

View file

@ -1,153 +0,0 @@
/**
* 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/>.
*/
.pragma library
.import "common.js" as Common
.import "../parameters.js" as P
.import "../math/latex.js" as Latex
class RepartitionFunction extends Common.ExecutableObject {
static type(){return 'Repartition'}
static displayType(){return qsTr('Repartition')}
static displayTypeMultiple(){return qsTr('Repartition functions')}
static properties() {return {
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
'comment1': QT_TRANSLATE_NOOP(
'comment',
'Note: Specify the probability for each value.'
),
[QT_TRANSLATE_NOOP('prop','probabilities')]: new P.Dictionary('string', 'float', /^-?[\d.,]+$/, /^-?[\d\.,]+$/, 'P({name_} = ', ') = '),
}}
constructor(name = null, visible = true, color = null, labelContent = 'name + value',
beginIncluded = true, drawLineEnds = true, probabilities = {'0': '0'}, labelPosition = 'above', labelX = 1) {
if(name == null) name = Common.getNewName('XYZUVW', "F_")
super(name, visible, color, labelContent)
this.beginIncluded = beginIncluded
this.drawLineEnds = drawLineEnds
this.probabilities = probabilities
this.labelPosition = labelPosition
this.labelX = labelX
this.update()
}
export() {
return [this.name, this.visible, this.color.toString(), this.labelContent,
this.beginIncluded, this.drawLineEnds, this.probabilities, this.labelPosition, this.labelX]
}
getReadableString() {
let keys = Object.keys(this.probabilities).sort((a,b) => a-b);
let varname = this.name.substring(this.name.indexOf("_")+1)
return `${this.name}(x) = P(${varname} ≤ x)\n` + keys.map(idx => `P(${varname}=${idx})=${this.probabilities[idx]}`).join("; ")
}
getLatexString() {
let keys = Object.keys(this.probabilities).sort((a,b) => a-b);
let funcName = Latex.variable(this.name)
let varName = Latex.variable(this.name.substring(this.name.indexOf("_")+1))
return `\\begin{array}{l}{${funcName}}(x) = P(${varName} \\le x)\\\\` + keys.map(idx => `P(${varName}=${idx})=${this.probabilities[idx]}`).join("; ") + '\\end{array}'
}
execute(x = 1) {
var ret = 0;
Object.keys(this.probabilities).sort((a,b) => a-b).forEach(idx => {
if(x >= idx) ret += parseFloat(this.probabilities[idx].replace(/,/g, '.'))
})
return ret
}
canExecute(x = 1) {return true}
// Simplify returns the simplified string of the expression.
simplify(x = 1) {
return this.execute(x)
}
getLabel() {
switch(this.labelContent) {
case 'name':
return `${this.name}(x)`
case 'name + value':
return this.getReadableString()
case 'null':
return ''
}
}
draw(canvas, ctx) {
var currentY = 0;
var keys = Object.keys(this.probabilities).map(idx => parseInt(idx)).sort((a,b) => a-b)
if(canvas.isVisible(keys[0],this.probabilities[keys[0]].replace(/,/g, '.'))) {
canvas.drawLine(ctx,
0,
canvas.y2px(0),
canvas.x2px(keys[0]),
canvas.y2px(0)
)
if(canvas.isVisible(keys[0],0)) {
ctx.beginPath();
ctx.arc(canvas.x2px(keys[0])+4,canvas.y2px(0), 4, Math.PI / 2, 3 * Math.PI / 2);
ctx.stroke();
}
}
for(var i = 0; i < keys.length-1; i++) {
var idx = keys[i];
currentY += parseFloat(this.probabilities[idx].replace(/,/g, '.'));
if(canvas.isVisible(idx,currentY) || canvas.isVisible(keys[i+1],currentY)) {
canvas.drawLine(ctx,
Math.max(0,canvas.x2px(idx)),
canvas.y2px(currentY),
Math.min(canvas.canvasSize.width,canvas.x2px(keys[i+1])),
canvas.y2px(currentY)
)
if(canvas.isVisible(idx,currentY)) {
ctx.beginPath();
ctx.arc(canvas.x2px(idx),canvas.y2px(currentY), 4, 0, 2 * Math.PI);
ctx.fill();
}
if(canvas.isVisible(keys[i+1],currentY)) {
ctx.beginPath();
ctx.arc(canvas.x2px(keys[i+1])+4,canvas.y2px(currentY), 4, Math.PI / 2, 3 * Math.PI / 2);
ctx.stroke();
}
}
}
if(canvas.isVisible(keys[keys.length-1],currentY+parseFloat(this.probabilities[keys[keys.length-1]]))) {
canvas.drawLine(ctx,
Math.max(0,canvas.x2px(keys[keys.length-1])),
canvas.y2px(currentY+parseFloat(this.probabilities[keys[keys.length-1]].replace(/,/g, '.'))),
canvas.canvasSize.width,
canvas.y2px(currentY+parseFloat(this.probabilities[keys[keys.length-1]].replace(/,/g, '.')))
)
ctx.beginPath();
ctx.arc(
canvas.x2px(keys[keys.length-1]),
canvas.y2px(currentY+parseFloat(this.probabilities[keys[keys.length-1]].replace(/,/g, '.'))),
4, 0, 2 * Math.PI);
ctx.fill();
}
// Label
this.drawLabel(canvas, ctx, this.labelPosition, canvas.x2px(this.labelX), canvas.y2px(this.execute(this.labelX)))
}
}

View file

@ -1,131 +0,0 @@
/**
* 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/>.
*/
.pragma library
.import "common.js" as Common
.import "function.js" as F
.import "../mathlib.js" as MathLib
.import "../parameters.js" as P
.import "../math/latex.js" as Latex
class Sequence extends Common.ExecutableObject {
static type(){return 'Sequence'}
static displayType(){return qsTr('Sequence')}
static displayTypeMultiple(){return qsTr('Sequences')}
static properties() {return {
[QT_TRANSLATE_NOOP('prop','drawPoints')]: 'boolean',
[QT_TRANSLATE_NOOP('prop','drawDashedLines')]: 'boolean',
[QT_TRANSLATE_NOOP('prop','defaultExpression')]: new P.Dictionary('string', 'int', /^.+$/, /^\d+$/, '{name}[n+', '] = ', true),
'comment1': QT_TRANSLATE_NOOP(
'comment',
'Note: Use %1[n] to refer to %1ₙ, %1[n+1] for %1ₙ₊₁...'
),
[QT_TRANSLATE_NOOP('prop','baseValues')]: new P.Dictionary('string', 'int', /^.+$/, /^\d+$/, '{name}[', '] = '),
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
}}
constructor(name = null, visible = true, color = null, labelContent = 'name + value',
drawPoints = true, drawDashedLines = true, defaultExp = {1: "n"},
baseValues = {0: 0}, labelPosition = 'above', labelX = 1) {
if(name == null) name = Common.getNewName('uvwPSUVWabcde')
super(name, visible, color, labelContent)
this.drawPoints = drawPoints
this.drawDashedLines = drawDashedLines
this.defaultExpression = defaultExp
this.baseValues = baseValues
this.labelPosition = labelPosition
this.labelX = labelX
this.update()
}
export() {
return [this.name, this.visible, this.color.toString(), this.labelContent,
this.drawPoints, this.drawDashedLines, this.defaultExpression, this.baseValues, this.labelPosition, this.labelX]
}
update() {
super.update()
if(
this.sequence == null || this.baseValues != this.sequence.baseValues ||
this.sequence.name != this.name ||
this.sequence.expr != Object.values(this.defaultExpression)[0] ||
this.sequence.valuePlus != Object.keys(this.defaultExpression)[0]
)
this.sequence = new MathLib.Sequence(
this.name, this.baseValues,
Object.keys(this.defaultExpression)[0],
Object.values(this.defaultExpression)[0]
)
}
getReadableString() {
return this.sequence.toString()
}
getLatexString() {
return this.sequence.toLatexString()
}
execute(x = 1) {
if(x % 1 == 0)
return this.sequence.execute(x)
return null
}
canExecute(x = 1) {return x%1 == 0}
// Simplify returns the simplified string of the expression.
simplify(x = 1) {
if(x % 1 == 0)
return this.sequence.simplify(x)
return null
}
getLabel() {
switch(this.labelContent) {
case 'name':
return `(${this.name}ₙ)`
case 'name + value':
return this.getReadableString()
case 'null':
return ''
}
}
getLatexLabel() {
switch(this.labelContent) {
case 'name':
return `(${Latex.variable(this.name)}_n)`
case 'name + value':
return this.getLatexString()
case 'null':
return ''
}
}
draw(canvas, ctx) {
F.Function.drawFunction(canvas, ctx, this.sequence, canvas.logscalex ? MathLib.Domain.NE : MathLib.Domain.N, MathLib.Domain.R, this.drawPoints, this.drawDashedLines)
// Label
this.drawLabel(canvas, ctx, this.labelPosition, canvas.x2px(this.labelX), canvas.y2px(this.execute(this.labelX)))
}
}

View file

@ -1,145 +0,0 @@
/**
* 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/>.
*/
.pragma library
.import "common.js" as Common
.import "function.js" as F
.import "../objects.js" as Objects
.import "../mathlib.js" as MathLib
.import "../parameters.js" as P
.import "../math/latex.js" as Latex
class SommeGainsBode extends Common.ExecutableObject {
static type(){return 'Somme gains Bode'}
static displayType(){return qsTr('Bode Magnitudes Sum')}
static displayTypeMultiple(){return qsTr('Bode Magnitudes Sum')}
static createable() {return false}
static properties() {return {
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
}}
constructor(name = null, visible = true, color = null, labelContent = 'name + value',
labelPosition = 'above', labelX = 1) {
if(name == null) name = 'G'
super(name, visible, color, labelContent)
this.labelPosition = labelPosition
this.labelX = labelX
this.recalculateCache()
}
export() {
return [this.name, this.visible, this.color.toString(), this.labelContent, this.labelPosition, this.labelX]
}
getReadableString() {
return `${this.name} = ${Objects.getObjectsName('Gain Bode').join(' + ')}`
}
getLatexString() {
return `${Latex.variable(this.name)} = ${Objects.getObjectsName('Gain Bode').map(name => Latex.variable(name)).join(' + ')}`
}
execute(x = 0) {
for(var [dbfn, inDrawDom] of this.cachedParts) {
if(inDrawDom.includes(x)) {
return dbfn.execute(x)
}
}
return null
}
canExecute(x = 1) {
return true // Should always be true
}
simplify(x = 1) {
for(var [dbfn, inDrawDom] of this.cachedParts) {
if(inDrawDom.includes(x)) {
return dbfn.simplify(x)
}
}
return ''
}
recalculateCache() {
this.cachedParts = []
// Calculating this is fairly resource expansive so it's cached.
if(Objects.currentObjects['Gain Bode'] != undefined) {
console.log('Recalculating cache gain')
// Minimum to draw (can be expended if needed, just not infinite or it'll cause issues.
var drawMin = 0.001
var baseY = 0
var om0xGains = {1000000000: 0} // To draw the last part
var om0xPass = {1000000000: 'high'} // To draw the last part
Objects.currentObjects['Gain Bode'].forEach(function(gainObj) { // Sorting by their om_0 position.
var om0x = gainObj.om_0.x.execute()
if(om0xGains[om0x] == undefined) {
om0xGains[om0x] = gainObj.gain.execute()
om0xPass[om0x] = gainObj.pass == 'high'
} else {
om0xGains[om0x+0.001] = gainObj.gain.execute()
om0xPass[om0x+0.001] = gainObj.pass == 'high'
}
baseY += gainObj.execute(drawMin)
})
// Sorting the om_0x
var om0xList = Object.keys(om0xGains).map(x => parseFloat(x)) // THEY WERE CONVERTED TO STRINGS...
om0xList.sort((a,b) => a - b)
// Adding the total gains.
var gainsBeforeP = []
var gainsAfterP = []
var gainTotal = 0
for(var om0x of om0xList){
if(om0xPass[om0x]) { // High-pass
gainsBeforeP.push(om0xGains[om0x])
gainsAfterP.push(0)
gainTotal += om0xGains[om0x] // Gain at first
} else {
gainsBeforeP.push(0)
gainsAfterP.push(om0xGains[om0x])
}
}
// Calculating parts
var previousPallier = drawMin
for(var pallier = 0; pallier < om0xList.length; pallier++) {
var dbfn = new MathLib.Expression(`${gainTotal}*(ln(x)-ln(${previousPallier}))/ln(10)+${baseY}`)
var inDrawDom = MathLib.parseDomain(`]${previousPallier};${om0xList[pallier]}]`)
this.cachedParts.push([dbfn, inDrawDom])
previousPallier = om0xList[pallier]
baseY = dbfn.execute(om0xList[pallier])
gainTotal += gainsAfterP[pallier] - gainsBeforeP[pallier]
}
}
}
draw(canvas, ctx) {
if(this.cachedParts.length > 0) {
for(var [dbfn, inDrawDom] of this.cachedParts) {
F.Function.drawFunction(canvas, ctx, dbfn, inDrawDom, MathLib.Domain.R)
if(inDrawDom.includes(this.labelX)) {
// Label
this.drawLabel(canvas, ctx, this.labelPosition, canvas.x2px(this.labelX), canvas.y2px(this.execute(this.labelX)))
}
}
}
}
}

View file

@ -1,129 +0,0 @@
/**
* 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/>.
*/
.pragma library
.import "common.js" as Common
.import "../objects.js" as Objects
.import "../mathlib.js" as MathLib
.import "../parameters.js" as P
.import "../math/latex.js" as Latex
class SommePhasesBode extends Common.ExecutableObject {
static type(){return 'Somme phases Bode'}
static displayType(){return qsTr('Bode Phases Sum')}
static displayTypeMultiple(){return qsTr('Bode Phases Sum')}
static createable() {return false}
static properties() {return {
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Position,
[QT_TRANSLATE_NOOP('prop','labelX')]: 'number',
}}
constructor(name = null, visible = true, color = null, labelContent = 'name + value',
labelPosition = 'above', labelX = 1) {
if(name == null) name = 'φ'
super(name, visible, color, labelContent)
this.labelPosition = labelPosition
this.labelX = labelX
this.recalculateCache()
}
export() {
return [this.name, this.visible, this.color.toString(), this.labelContent, this.labelPosition, this.labelX]
}
getReadableString() {
return `${this.name} = ${Objects.getObjectsName('Phase Bode').join(' + ')}`
}
getLatexString() {
return `${Latex.variable(this.name)} = ${Objects.getObjectsName('Phase Bode').map(name => Latex.variable(name)).join(' + ')}`
}
execute(x=1) {
if(typeof x == 'string') x = MathLib.executeExpression(x)
for(var i = 0; i < this.om0xList.length-1; i++) {
if(x >= this.om0xList[i] && x < this.om0xList[i+1]) return this.phasesList[i]
}
}
simplify(x = 1) {
var xval = x
if(typeof x == 'string') xval = MathLib.executeExpression(x)
for(var i = 0; i < this.om0xList.length-1; i++) {
if(xval >= this.om0xList[i] && xval < this.om0xList[i+1]) {
return (new MathLib.Expression(this.phasesExprList[i])).simplify()
}
}
return '0'
}
canExecute(x = 1) {
return true
}
recalculateCache() {
// Minimum to draw (can be expended if needed, just not infinite or it'll cause issues.
var drawMin = 0.001
var drawMax = 100000
this.om0xList = [drawMin, drawMax]
this.phasesList = [0]
this.phasesExprList = ['0']
var phasesDict = {}
var phasesExprDict = {}
phasesDict[drawMax] = 0
if(Objects.currentObjects['Phase Bode'] != undefined) {
console.log('Recalculating cache phase')
for(var obj of Objects.currentObjects['Phase Bode']) {
this.om0xList.push(obj.om_0.x.execute())
if(phasesDict[obj.om_0.x.execute()] == undefined) {
phasesDict[obj.om_0.x.execute()] = obj.phase.execute()
phasesExprDict[obj.om_0.x.execute()] = obj.phase.toEditableString()
} else {
phasesDict[obj.om_0.x.execute()] += obj.phase.execute()
phasesExprDict[obj.om_0.x.execute()] += '+' + obj.phase.toEditableString()
}
this.phasesList[0] += obj.om_0.y.execute()
this.phasesExprList[0] += '+' + obj.om_0.y.toEditableString()
}
this.om0xList.sort((a,b) => a - b)
var totalAdded = this.phasesList[0]
for(var i = 1; i < this.om0xList.length; i++) {
this.phasesList[i] = this.phasesList[i-1] + phasesDict[this.om0xList[i]]
this.phasesExprList[i] = this.phasesExprList[i-1] + '+' + phasesDict[this.om0xList[i]]
}
}
}
draw(canvas, ctx) {
for(var i = 0; i < this.om0xList.length-1; i++) {
var om0xBegin = canvas.x2px(this.om0xList[i])
var om0xEnd = canvas.x2px(this.om0xList[i+1])
var baseY = canvas.y2px(this.phasesList[i])
var nextY = canvas.y2px(this.phasesList[i+1])
canvas.drawLine(ctx, om0xBegin, baseY, om0xEnd, baseY)
canvas.drawLine(ctx, om0xEnd, baseY, om0xEnd, nextY)
}
// Label
this.drawLabel(canvas, ctx, this.labelPosition, canvas.x2px(this.labelX), canvas.y2px(this.execute(this.labelX)))
}
}

View file

@ -1,100 +0,0 @@
/**
* 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/>.
*/
.pragma library
.import "common.js" as Common
.import "../mathlib.js" as MathLib
.import "../parameters.js" as P
.import "../math/latex.js" as Latex
class Text extends Common.DrawableObject {
static type(){return 'Text'}
static displayType(){return qsTr('Text')}
static displayTypeMultiple(){return qsTr('Texts')}
static properties() {return {
[QT_TRANSLATE_NOOP('prop','x')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','y')]: new P.Expression(),
[QT_TRANSLATE_NOOP('prop','labelPosition')]: P.Enum.Positioning,
[QT_TRANSLATE_NOOP('prop','text')]: 'string',
'comment1': QT_TRANSLATE_NOOP(
'comment',
'If you have latex enabled, you can use use latex markup in between $$ to create equations.'
),
[QT_TRANSLATE_NOOP('prop','disableLatex')]: 'boolean'
}}
constructor(name = null, visible = true, color = null, labelContent = 'null',
x = 1, y = 0, labelPosition = 'center', text = 'New text', disableLatex = false) {
if(name == null) name = Common.getNewName('t')
super(name, visible, color, labelContent)
if(typeof x == 'number' || typeof x == 'string') x = new MathLib.Expression(x.toString())
this.x = x
if(typeof y == 'number' || typeof y == 'string') y = new MathLib.Expression(y.toString())
this.y = y
this.labelPosition = labelPosition
this.text = text
this.disableLatex = disableLatex
}
getReadableString() {
return `${this.name} = "${this.text}"`
}
latexMarkupText() {
// Check whether the text contains latex escaped elements.
let txt = []
this.text.split('$$').forEach(function(t) { txt = txt.concat(Latex.variable(t, true).replace(/\$\$/g, '').split('$')) })
let newTxt = txt[0]
let i
// Split between normal text and latex escaped.
for(i = 0; i < txt.length-1; i++)
if(i & 0x01) // Every odd number
newTxt += '\\textsf{'+Latex.variable(txt[i+1])
else
newTxt += '}'+txt[i+1]
// Finished by a }
if(i & 0x01)
newTxt += "{"
return newTxt
}
getLatexString() {
return `${Latex.variable(this.name)} = "\\textsf{${this.latexMarkupText()}}"`
}
export() {
return [this.name, this.visible, this.color.toString(), this.labelContent, this.x.toEditableString(), this.y.toEditableString(), this.labelPosition, this.text, this.disableLatex]
}
getLabel() {
return this.text
}
getLatexLabel() {
return `\\textsf{${this.latexMarkupText()}}`
}
draw(canvas, ctx) {
let yOffset = this.disableLatex ? canvas.textsize-4 : 0
this.drawLabel(canvas, ctx, this.labelPosition, canvas.x2px(this.x.execute()), canvas.y2px(this.y.execute())+yOffset, this.disableLatex)
}
}

View file

@ -1,128 +0,0 @@
/**
* 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/>.
*/
class Expression {
constructor(...variables) {
this.type = 'Expression'
this.variables = variables
}
toString() {
return this.variables.length == 0 ? 'Number' : `Expression(${this.variables.join(', ')})`
}
}
class Enum {
constructor(...values) {
this.type = 'Enum'
this.values = values
this.translatedValues = values.map(x => qsTr(x))
}
toString() {
return this.type
}
}
class ObjectType {
constructor(objType) {
this.type = 'ObjectType'
this.objType = objType
}
toString() {
return this.objType
}
}
class List {
constructor(type, format = /^.+$/, label = '', forbidAdding = false) {
// type can be string, int and double.
this.type = 'List'
this.valueType = type
this.format = format
this.label = label
this.forbidAdding = forbidAdding
}
toString() {
return this.objType
}
}
class Dictionary {
constructor(type, keyType = 'string', format = /^.+$/, keyFormat = /^.+$/, preKeyLabel = '', postKeyLabel = ': ', forbidAdding = false) {
// type & keyType can be string, int and double.
this.type = 'Dict'
this.valueType = type
this.keyType = keyType
this.format = format
this.keyFormat = keyFormat
this.preKeyLabel = preKeyLabel
this.postKeyLabel = postKeyLabel
this.forbidAdding = forbidAdding
}
toString() {
return 'Dictionary'
}
}
// Common parameters for Enums
Enum.Position = new Enum(
QT_TR_NOOP('above'),
QT_TR_NOOP('below'),
QT_TR_NOOP('left'),
QT_TR_NOOP('right'),
QT_TR_NOOP('above-left'),
QT_TR_NOOP('above-right'),
QT_TR_NOOP('below-left'),
QT_TR_NOOP('below-right')
)
Enum.Positioning = new Enum(
QT_TR_NOOP('center'),
QT_TR_NOOP('top'),
QT_TR_NOOP('bottom'),
QT_TR_NOOP('left'),
QT_TR_NOOP('right'),
QT_TR_NOOP('top-left'),
QT_TR_NOOP('top-right'),
QT_TR_NOOP('bottom-left'),
QT_TR_NOOP('bottom-right')
)
Enum.FunctionDisplayType = new Enum(
QT_TR_NOOP('application'),
QT_TR_NOOP('function')
)
Enum.BodePass = new Enum(
QT_TR_NOOP('high'),
QT_TR_NOOP('low')
)
Enum.XCursorValuePosition = new Enum(
QT_TR_NOOP('Next to target'),
QT_TR_NOOP('With label'),
QT_TR_NOOP('Hidden')
)

View file

@ -1,136 +0,0 @@
/**
* 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/>.
*/
// Contains polyfill math functions used for reference.
.pragma library
function factorial(x) {
if (x < 0) // Integrating by less than 0
if(isFinite(n))
return Infinity
else
throw new EvalError("Cannot calculate the factorial of -∞.")
return gamma(x+1)
}
let GAMMA_G = 4.7421875
let GAMMA_P = [
0.99999999999999709182,
57.156235665862923517, -59.597960355475491248,
14.136097974741747174, -0.49191381609762019978,
0.33994649984811888699e-4,
0.46523628927048575665e-4, -0.98374475304879564677e-4,
0.15808870322491248884e-3, -0.21026444172410488319e-3,
0.21743961811521264320e-3, -0.16431810653676389022e-3,
0.84418223983852743293e-4, -0.26190838401581408670e-4,
0.36899182659531622704e-5
]
function gamma(n) {
if(n <= 0) // Integrating by less than 0
if(isFinite(n))
return Infinity
else
throw new EvalError("Cannot calculate Γ(-∞).")
if(n >= 171.35)
return Infinity // Would return more than 2^1024 - 1 (aka Number.INT_MAX)
if(n === Math.round(n) && isFinite(n)) {
// Calculating (n-1)!
let res = n - 1
for(let i = n - 2; i > 1; i++)
res *= i
if(res === 0)
res = 1 // 0! is per definition 1
return res
}
// Section below adapted function adapted from math.js
if(n < 0.5)
return Math.PI / (Math.sin(Math.PI * n) * gamma(1 - n))
if(n > 85.0) { // Extended Stirling Approx
let twoN = n * n
let threeN = twoN * n
let fourN = threeN * n
let fiveN = fourN * n
return Math.sqrt(2 * Math.PI / n) * Math.pow((n / Math.E), n) *
(1 + (1 / (12 * n)) + (1 / (288 * twoN)) - (139 / (51840 * threeN)) -
(571 / (2488320 * fourN)) + (163879 / (209018880 * fiveN)) +
(5246819 / (75246796800 * fiveN * n)))
}
--n
let x = GAMMA_P[0]
for (let i = 1; i < GAMMA_P.length; ++i) {
x += GAMMA_P[i] / (n + i)
}
let t = n + GAMMA_G + 0.5
return Math.sqrt(2 * Math.PI) * Math.pow(t, n + 0.5) * Math.exp(-t) * x
}
function arrayMap(f, arr) {
if (typeof f != 'function')
throw new EvalError(qsTranslate('error', 'First argument to map is not a function.'))
if (!Array.isArray(arr))
throw new EvalError(qsTranslate('error', 'Second argument to map is not an array.'))
return arr.map(f)
}
function arrayFold(f, init, arr) {
if (typeof f != 'function')
throw new EvalError(qsTranslate('error', 'First argument to fold is not a function.'))
if (!Array.isArray(arr))
throw new EvalError(qsTranslate('error', 'Second argument to fold is not an array.'))
return arr.reduce(f, init)
}
function arrayFilter(f, arr) {
if (typeof f != 'function')
throw new EvalError(qsTranslate('error', 'First argument to filter is not a function.'))
if (!Array.isArray(arr))
throw new EvalError(qsTranslate('error', 'Second argument to filter is not an array.'))
return arr.filter(f)
}
function arrayFilter(f, arr) {
if (typeof f != 'function')
throw new EvalError(qsTranslate('error', 'First argument to filter is not a function.'))
if (!Array.isArray(arr))
throw new EvalError(qsTranslate('error', 'Second argument to filter is not an array.'))
return arr.filter(f)
}
function arrayJoin(sep, arr) {
if (!Array.isArray(arr))
throw new Error(qsTranslate('error', 'Second argument to join is not an array.'))
return arr.join(sep)
}
function indexOf(target, s) {
if (!(Array.isArray(s) || typeof s === 'string'))
throw new Error(qsTranslate('error', 'Second argument to indexOf is not a string or array.'))
return s.indexOf(target)
}

View file

@ -1,177 +0,0 @@
/**
* 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/>.
*/
.pragma library
.import "polyfill.js" as Polyfill
const CONSTANTS = {
"π": Math.PI,
"pi": Math.PI,
"inf": Infinity,
"infinity": Infinity,
"∞": Infinity,
"e": Math.E
};
const CONSTANTS_LIST = Object.keys(CONSTANTS);
const FUNCTIONS = {
// The functions commented are the one either not implemented
// in the parser, or not to be used for autocompletion.
// Unary operators
//'+': Number,
//'-': (x) => -x,
//'!'
// Other operations
'length': (s) => Array.isArray(s) ? s.length : String(s).length,
// Boolean functions
'not': (x) => !x,
// Math functions
'abs': Math.abs,
'acos': Math.acos,
'acosh': Math.acosh,
'asin': Math.asin,
'asinh': Math.asinh,
'atan': Math.atan,
'atan2': Math.atan2,
'atanh': Math.atanh,
'cbrt': Math.cbrt,
'ceil': Math.ceil,
//'clz32': Math.clz32,
'cos': Math.cos,
'cosh': Math.cosh,
'exp': Math.exp,
'expm1': Math.expm1,
'floor': Math.floor,
//'fround': Math.fround,
'hypot': Math.hypot,
//'imul': Math.imul,
'lg': Math.log10,
'ln': Math.log,
'log': Math.log,
'log10': Math.log10,
'log1p': Math.log1p,
'log2': Math.log2,
'max': Math.max,
'min': Math.min,
'pow': Math.log2,
'random': Math.random,
'round': Math.round,
'sign': Math.sign,
'sin': Math.sin,
'sinh': Math.sinh,
'sqrt': Math.sqrt,
'tan': Math.tan,
'tanh': Math.tanh,
'trunc': Math.trunc,
// Functions in expr-eval, ported here.
'fac': Polyfill.factorial,
'gamma': Polyfill.gamma,
'Γ': Polyfill.gamma,
'roundTo': (x, exp) => Number(x).toFixed(exp),
// 'map': Polyfill.arrayMap,
// 'fold': Polyfill.arrayFold,
// 'filter': Polyfill.arrayFilter,
// 'indexOf': Polyfill.indexOf,
// 'join': Polyfill.arrayJoin,
// Integral & derivative (only here for autocomplete).
'integral': () => 0, // TODO: Implement
'derivative': () => 0,
}
const FUNCTIONS_LIST = Object.keys(FUNCTIONS);
class P {
// Parameter class.
constructor(type, name = '', optional = false, multipleAllowed = false) {
this.name = name
this.type = type
this.optional = optional
this.multipleAllowed = multipleAllowed
}
toString() {
let base_string = this.type
if(this.name != '')
base_string = `${this.name}: ${base_string}`
if(this.multipleAllowed)
base_string += '...'
if(!this.optional)
base_string = `<${base_string}>`
else
base_string = `[${base_string}]`
return base_string
}
}
let string = new P('string')
let bool = new P('bool')
let number = new P('number')
let array = new P('array')
const FUNCTIONS_USAGE = {
'length': [string],
'not': [bool],
// Math functions
'abs': [number],
'acos': [number],
'acosh': [number],
'asin': [number],
'asinh': [number],
'atan': [number],
'atan2': [number],
'atanh': [number],
'cbrt': [number],
'ceil': [number],
//'clz32': [number],
'cos': [number],
'cosh': [number],
'exp': [number],
'expm1': [number],
'floor': [number],
//'fround': [number],
'hypot': [number],
//'imul': [number],
'lg': [number],
'ln': [number],
'log': [number],
'log10': [number],
'log1p': [number],
'log2': [number],
'max': [number, number, new P('numbers', '', true, true)],
'min': [number, number, new P('numbers', '', true, true)],
'pow': [number, new P('number', 'exp')],
'random': [number, number],
'round': [number],
'sign': [number],
'sin': [number],
'sinh': [number],
'sqrt': [number],
'tan': [number],
'tanh': [number],
'trunc': [number],
// Functions in expr-eval, ported here.
'fac': [number],
'gamma': [number],
'Γ': [number],
'roundTo': [number, new P('number')],
// Function manipulation
'derivative': [new P('f'), new P('string', 'var', true), number],
'integral': [new P('from'), new P('to'), new P('f'), new P('string', 'var', true)],
}

View file

@ -1,369 +0,0 @@
/**
* 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/>.
*/
.pragma library
var powerpos = {
"-": "⁻",
"+": "⁺",
"=": "⁼",
" ": "",
"(": "⁽",
")": "⁾",
"0": "⁰",
"1": "¹",
"2": "²",
"3": "³",
"4": "⁴",
"5": "⁵",
"6": "⁶",
"7": "⁷",
"8": "⁸",
"9": "⁹",
"a": "ᵃ",
"b": "ᵇ",
"c": "ᶜ",
"d": "ᵈ",
"e": "ᵉ",
"f": "ᶠ",
"g": "ᵍ",
"h": "ʰ",
"i": "ⁱ",
"j": "ʲ",
"k": "ᵏ",
"l": "ˡ",
"m": "ᵐ",
"n": "ⁿ",
"o": "ᵒ",
"p": "ᵖ",
"r": "ʳ",
"s": "ˢ",
"t": "ᵗ",
"u": "ᵘ",
"v": "ᵛ",
"w": "ʷ",
"x": "ˣ",
"y": "ʸ",
"z": "ᶻ"
}
var exponents = [
"⁰","¹","²","³","⁴","⁵","⁶","⁷","⁸","⁹"
]
var exponentReg = new RegExp('(['+exponents.join('')+']+)', 'g')
var indicepos = {
"-": "₋",
"+": "₊",
"=": "₌",
"(": "₍",
")": "₎",
" ": "",
"0": "₀",
"1": "₁",
"2": "₂",
"3": "₃",
"4": "₄",
"5": "₅",
"6": "₆",
"7": "₇",
"8": "₈",
"9": "₉",
"a": "ₐ",
"e": "ₑ",
"h": "ₕ",
"i": "ᵢ",
"j": "ⱼ",
"k": "ₖ",
"l": "ₗ",
"m": "ₘ",
"n": "ₙ",
"o": "ₒ",
"p": "ₚ",
"r": "ᵣ",
"s": "ₛ",
"t": "ₜ",
"u": "ᵤ",
"v": "ᵥ",
"x": "ₓ",
}
// Put a text in sup position
function textsup(text) {
var ret = ""
text = text.toString()
for (var i = 0; i < text.length; i++) {
if(Object.keys(powerpos).indexOf(text[i]) >= 0) {
ret += powerpos[text[i]]
} else {
ret += text[i]
}
}
return ret
}
// Put a text in sub position
function textsub(text) {
var ret = ""
text = text.toString()
for (var i = 0; i < text.length; i++) {
if(Object.keys(indicepos).indexOf(text[i]) >= 0) {
ret += indicepos[text[i]]
} else {
ret += text[i]
}
}
return ret
}
function simplifyExpression(str) {
var replacements = [
// Operations not done by parser.
// [// Decomposition way 2
// /(^|[+-] |\()([-.\d\w]+) ([*/]) \((([-.\d\w] [*/] )?[-\d\w.]+) ([+\-]) (([-.\d\w] [*/] )?[\d\w.+]+)\)($| [+-]|\))/g,
// "$1$2 $3 $4 $6 $2 $3 $7$9"
// ],
// [ // Decomposition way 2
// /(^|[+-] |\()\((([-.\d\w] [*/] )?[-\d\w.]+) ([+\-]) (([-.\d\w] [*/] )?[\d\w.+]+)\) ([*/]) ([-.\d\w]+)($| [+-]|\))/g,
// "$1$2 $7 $8 $4 $5 $7 $8$9"
// ],
[ // Factorisation of π elements.
/(([-\d\w.]+ [*/] )*)(pi|π)(( [/*] [-\d\w.]+)*) ([+-]) (([-\d\w.]+ [*/] )*)(pi|π)(( [/*] [-\d\w.]+)*)?/g,
function(match, m1, n1, pi1, m2, ope2, n2, opeM, m3, n3, pi2, m4, ope4, n4) {
// g1, g2, g3 , g4, g5, g6, g7, g8, g9, g10, g11,g12 , g13
// We don't care about mx & pix, ope2 & ope4 are either / or * for n2 & n4.
// n1 & n3 are multiplied, opeM is the main operation (- or +).
// Putting all n in form of number
//n2 = n2 == undefined ? 1 : parseFloat(n)
n1 = m1 == undefined ? 1 : eval(m1 + '1')
n2 = m2 == undefined ? 1 : eval('1' + m2)
n3 = m3 == undefined ? 1 : eval(m3 + '1')
n4 = m4 == undefined ? 1 : eval('1' + m4)
//var [n1, n2, n3, n4] = [n1, n2, n3, n4].map(n => n == undefined ? 1 : parseFloat(n))
// Falling back to * in case it does not exist (the corresponding n would be 1)
var [ope2, ope4] = [ope2, ope4].map(ope => ope == '/' ? '/' : '*')
var coeff1 = n1*n2
var coeff2 = n3*n4
var coefficient = coeff1+coeff2-(opeM == '-' ? 2*coeff2 : 0)
return `${coefficient} * π`
}
],
[ // Removing parenthesis when content is only added from both sides.
/(^|[+-] |\()\(([^)(]+)\)($| [+-]|\))/g,
function(match, b4, middle, after) {return `${b4}${middle}${after}`}
],
[ // Removing parenthesis when content is only multiplied.
/(^|[*\/] |\()\(([^)(+-]+)\)($| [*\/+-]|\))/g,
function(match, b4, middle, after) {return `${b4}${middle}${after}`}
],
[ // Removing parenthesis when content is only multiplied.
/(^|[*\/-+] |\()\(([^)(+-]+)\)($| [*\/]|\))/g,
function(match, b4, middle, after) {return `${b4}${middle}${after}`}
],
[// Simplification additions/substractions.
/(^|[^*\/] |\()([-.\d]+) (\+|\-) (\([^)(]+\)|[^)(]+) (\+|\-) ([-.\d]+)($| [^*\/]|\))/g,
function(match, b4, n1, op1, middle, op2, n2, after) {
var total
if(op2 == '+') {
total = parseFloat(n1) + parseFloat(n2)
} else {
total = parseFloat(n1) - parseFloat(n2)
}
return `${b4}${total} ${op1} ${middle}${after}`
}
],
[// Simplification multiplications/divisions.
/([-.\d]+) (\*|\/) (\([^)(]+\)|[^)(+-]+) (\*|\/) ([-.\d]+)/g,
function(match, n1, op1, middle, op2, n2) {
if(parseInt(n1) == n1 && parseInt(n2) == n2 && op2 == '/' &&
(parseInt(n1) / parseInt(n2)) % 1 != 0) {
// Non int result for int division.
return `(${n1} / ${n2}) ${op1} ${middle}`
} else {
if(op2 == '*') {
return `${parseFloat(n1) * parseFloat(n2)} ${op1} ${middle}`
} else {
return `${parseFloat(n1) / parseFloat(n2)} ${op1} ${middle}`
}
}
}
],
[// Starting & ending parenthesis if not needed.
/^\s*\((.*)\)\s*$/g,
function(match, middle) {
var str = middle
// Replace all groups
while(/\([^)(]+\)/g.test(str))
str = str.replace(/\([^)(]+\)/g, '')
// There shouldn't be any more parenthesis
// If there is, that means the 2 parenthesis are needed.
if(!str.includes(')') && !str.includes('(')) {
return middle
} else {
return `(${middle})`
}
}
],
// Simple simplifications
// [/(\s|^|\()0(\.0+)? \* (\([^)(]+\))/g, '$10'],
// [/(\s|^|\()0(\.0+)? \* ([^)(+-]+)/g, '$10'],
// [/(\([^)(]\)) \* 0(\.0+)?(\s|$|\))/g, '0$3'],
// [/([^)(+-]) \* 0(\.0+)?(\s|$|\))/g, '0$3'],
// [/(\s|^|\()1(\.0+)? (\*|\/) /g, '$1'],
// [/(\s|^|\()0(\.0+)? (\+|\-) /g, '$1'],
// [/ (\*|\/) 1(\.0+)?(\s|$|\))/g, '$3'],
// [/ (\+|\-) 0(\.0+)?(\s|$|\))/g, '$3'],
// [/(^| |\() /g, '$1'],
// [/ ($|\))/g, '$1'],
]
// Replacements
var found
do {
found = false
for(var replacement of replacements)
while(replacement[0].test(str)) {
found = true
str = str.replace(replacement[0], replacement[1])
}
} while(found)
return str
}
function makeExpressionReadable(str) {
var replacements = [
// variables
[/pi/g, 'π'],
[/Infinity/g, '∞'],
[/inf/g, '∞'],
// Other
[/ \* /g, '×'],
[/ \^ /g, '^'],
[/\^\(([\d\w+-]+)\)/g, function(match, p1) { return textsup(p1) }],
[/\^([\d\w+-]+)/g, function(match, p1) { return textsup(p1) }],
[/_\(([\d\w+-]+)\)/g, function(match, p1) { return textsub(p1) }],
[/_([\d\w+-]+)/g, function(match, p1) { return textsub(p1) }],
[/\[([^\[\]]+)\]/g, function(match, p1) { return textsub(p1) }],
[/(\d|\))×/g, '$1'],
//[/×(\d|\()/g, '$1'],
[/([^a-z])\(([^)(+.\/-]+)\)/g, "$1×$2"],
[/integral\((.+),\s?(.+),\s?("|')(.+)("|'),\s?("|')(.+)("|')\)/g, function(match, a, b, p1, body, p2, p3, by, p4) {
if(a.length < b.length) {
return `${textsub(a)}${textsup(b)} ${body} d${by}`
} else {
return `${textsup(b)}${textsub(a)} ${body} d${by}`
}
}],
[/derivative\(?("|')(.+)("|'), ?("|')(.+)("|'), ?(.+)\)?/g, function(match, p1, body, p2, p3, by, p4, x) {
return `d(${body.replace(new RegExp(by, 'g'), 'x')})/dx`
}]
]
// str = simplifyExpression(str)
// Replacements
for(var replacement of replacements)
while(replacement[0].test(str))
str = str.replace(replacement[0], replacement[1])
return str
}
function parseName(str, removeUnallowed = true) {
var replacements = [
// Greek letters
[/([^a-z]|^)al(pha)?([^a-z]|$)/g, '$1α$3'],
[/([^a-z]|^)be(ta)?([^a-z]|$)/g, '$1β$3'],
[/([^a-z]|^)ga(mma)?([^a-z]|$)/g, '$1γ$3'],
[/([^a-z]|^)de(lta)?([^a-z]|$)/g, '$1δ$3'],
[/([^a-z]|^)ep(silon)?([^a-z]|$)/g, '$1ε$3'],
[/([^a-z]|^)ze(ta)?([^a-z]|$)/g, '$1ζ$3'],
[/([^a-z]|^)et(a)?([^a-z]|$)/g, '$1η$3'],
[/([^a-z]|^)th(eta)?([^a-z]|$)/g, '$1θ$3'],
[/([^a-z]|^)io(ta)?([^a-z]|$)/g, '$1ι$3'],
[/([^a-z]|^)ka(ppa)([^a-z]|$)?/g, '$1κ$3'],
[/([^a-z]|^)la(mbda)?([^a-z]|$)/g, '$1λ$3'],
[/([^a-z]|^)mu([^a-z]|$)/g, '$1μ$2'],
[/([^a-z]|^)nu([^a-z]|$)/g, '$1ν$2'],
[/([^a-z]|^)xi([^a-z]|$)/g, '$1ξ$2'],
[/([^a-z]|^)rh(o)?([^a-z]|$)/g, '$1ρ$3'],
[/([^a-z]|^)si(gma)?([^a-z]|$)/g, '$1σ$3'],
[/([^a-z]|^)ta(u)?([^a-z]|$)/g, '$1τ$3'],
[/([^a-z]|^)up(silon)?([^a-z]|$)/g, '$1υ$3'],
[/([^a-z]|^)ph(i)?([^a-z]|$)/g, '$1φ$3'],
[/([^a-z]|^)ch(i)?([^a-z]|$)/g, '$1χ$3'],
[/([^a-z]|^)ps(i)?([^a-z]|$)/g, '$1ψ$3'],
[/([^a-z]|^)om(ega)?([^a-z]|$)/g, '$1ω$3'],
// Capital greek letters
[/([^a-z]|^)gga(mma)?([^a-z]|$)/g, '$1Γ$3'],
[/([^a-z]|^)gde(lta)?([^a-z]|$)/g, '$1Δ$3'],
[/([^a-z]|^)gth(eta)?([^a-z]|$)/g, '$1Θ$3'],
[/([^a-z]|^)gla(mbda)?([^a-z]|$)/g, '$1Λ$3'],
[/([^a-z]|^)gxi([^a-z]|$)/g, '$1Ξ$2'],
[/([^a-z]|^)gpi([^a-z]|$)/g, '$1Π$2'],
[/([^a-z]|^)gsi(gma)([^a-z]|$)?/g, '$1Σ$3'],
[/([^a-z]|^)gph(i)?([^a-z]|$)/g, '$1Φ$3'],
[/([^a-z]|^)gps(i)?([^a-z]|$)/g, '$1Ψ$3'],
[/([^a-z]|^)gom(ega)?([^a-z]|$)/g, '$1Ω$3'],
// Underscores
// [/_\(([^_]+)\)/g, function(match, p1) { return textsub(p1) }],
// [/_([^" ]+)/g, function(match, p1) { return textsub(p1) }],
// Array elements
[/\[([^\]\[]+)\]/g, function(match, p1) { return textsub(p1) }],
// Removing
[/[xπ\\∪∩\]\[ ()^/÷*×+=\d-]/g , ''],
]
if(!removeUnallowed) replacements.pop()
// Replacements
for(var replacement of replacements)
str = str.replace(replacement[0], replacement[1])
return str
}
String.prototype.toLatinUppercase = function() {
return this.replace(/[a-z]/g, function(match){return match.toUpperCase()})
}
function camelCase2readable(label) {
var parsed = parseName(label, false)
return parsed.charAt(0).toLatinUppercase() + parsed.slice(1).replace(/([A-Z])/g," $1")
}
function getRandomColor() {
var clrs = '0123456789ABCDEF';
var color = '#';
for(var i = 0; i < 6; i++) {
color += clrs[Math.floor(Math.random() * (16-5*(i%2==0)))];
}
return color;
}
function escapeHTML(str) {
return str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;') ;
}
/**
* Parses exponents and replaces them with expression values
* @param {string} expression - The expression to replace in.
* @return {string} The parsed expression
*/
function exponentsToExpression(expression) {
return expression.replace(exponentReg, (m, exp) => '^' + exp.split('').map((x) => exponents.indexOf(x)).join(''))
}

View file

@ -1,4 +0,0 @@
module eu.ad5001.LogarithmPlotter
Settings 1.0 Settings.qml
Alert 1.0 Alert.qml

View file

@ -1,170 +0,0 @@
"""
* 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/>.
"""
from PySide6.QtWidgets import QMessageBox, QApplication
from PySide6.QtCore import QRunnable, QThreadPool, QThread, QObject, Signal, Slot, QCoreApplication
from PySide6.QtQml import QQmlApplicationEngine
from PySide6.QtGui import QImage
from PySide6 import __version__ as PySide6_version
from os import chdir, path
from json import loads
from sys import version as sys_version
from urllib.request import urlopen
from urllib.error import HTTPError, URLError
from LogarithmPlotter import __VERSION__
from LogarithmPlotter.util import config
class ChangelogFetcher(QRunnable):
def __init__(self, helper):
QRunnable.__init__(self)
self.helper = helper
def run(self):
msg_text = "Unknown changelog error."
try:
# Fetching version
r = urlopen("https://api.ad5001.eu/changelog/logarithmplotter/?version=" + __VERSION__)
lines = r.readlines()
r.close()
msg_text = "".join(map(lambda x: x.decode('utf-8'), lines)).strip()
except HTTPError as e:
msg_text = QCoreApplication.translate("changelog","Could not fetch changelog: Server error {}.").format(str(e.code))
except URLError as e:
msg_text = QCoreApplication.translate("changelog","Could not fetch update: {}.").format(str(e.reason))
self.helper.gotChangelog.emit(msg_text)
class Helper(QObject):
changelogFetched = Signal(str)
gotChangelog = Signal(str)
def __init__(self, cwd: str, tmpfile: str):
QObject.__init__(self)
self.cwd = cwd
self.tmpfile = tmpfile
self.gotChangelog.connect(self.fetched)
def fetched(self, changelog: str):
self.changelogFetched.emit(changelog)
@Slot(str, str)
def write(self, filename, filedata):
chdir(self.cwd)
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(self.cwd)
data = '{}'
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
elif data[:3] == "LPF":
# More recent version of LogarithmPlotter file, but incompatible with the current format
raise Exception(QCoreApplication.translate("This file was created by a more recent version of LogarithmPlotter and cannot be backloaded in LogarithmPlotter v{}.\nPlease update LogarithmPlotter to open this file.".format(__VERSION__)))
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
try:
chdir(path.dirname(path.realpath(__file__)))
except NotADirectoryError as e:
# Triggered on bundled versions of MacOS when it shouldn't. Prevents opening files.
# See more at https://git.ad5001.eu/Ad5001/LogarithmPlotter/issues/1
pass
return data
@Slot(result=str)
def gettmpfile(self):
return self.tmpfile
@Slot()
def copyImageToClipboard(self):
clipboard = QApplication.clipboard()
clipboard.setImage(QImage(self.tmpfile))
@Slot(result=str)
def getVersion(self):
return __VERSION__
@Slot(str, result=str)
def getSetting(self, namespace):
return config.getSetting(namespace)
@Slot(str, result=int)
def getSettingInt(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, int)
def setSettingInt(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, PySide6 & Python
"""
return QCoreApplication.translate('main',"Built with PySide6 (Qt) v{} and python v{}").format(PySide6_version, sys_version.split("\n")[0])
@Slot()
def fetchChangelog(self):
changelog_cache_path = path.join(path.dirname(path.realpath(__file__)), "CHANGELOG.md")
print(changelog_cache_path)
if path.exists(changelog_cache_path):
# We have a cached version of the changelog, for env that don't have access to the internet.
f = open(changelog_cache_path);
self.changelogFetched.emit("".join(f.readlines()).strip())
f.close()
else:
# Fetch it from the internet.
runnable = ChangelogFetcher(self)
QThreadPool.globalInstance().start(runnable)

View file

@ -1,195 +0,0 @@
"""
* 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/>.
"""
from PySide6.QtCore import QObject, Slot, Property, QCoreApplication
from PySide6.QtGui import QImage, QColor
from PySide6.QtWidgets import QApplication, QMessageBox
from os import path, remove
from string import Template
from tempfile import TemporaryDirectory
from subprocess import Popen, TimeoutExpired, PIPE
from platform import system
from shutil import which
from sys import argv
"""
Searches for a valid Latex and DVIPNG (http://savannah.nongnu.org/projects/dvipng/)
installation and collects the binary path in the DVIPNG_PATH variable.
If not found, it will send an alert to the user.
"""
LATEX_PATH = which('latex')
DVIPNG_PATH = which('dvipng')
DEFAULT_LATEX_DOC = Template(r"""
\documentclass[]{minimal}
\usepackage[utf8]{inputenc}
\usepackage{calligra}
\usepackage{amsfonts}
\title{}
\author{}
\begin{document}
$$$$ $markup $$$$
\end{document}
""")
class Latex(QObject):
"""
Base class to convert Latex equations into PNG images with custom font color and size.
It doesn't have any python dependency, but requires a working latex installation and
dvipng to be installed on the system.
"""
def __init__(self, tempdir: TemporaryDirectory):
QObject.__init__(self)
self.tempdir = tempdir
def check_latex_install(self):
"""
Checks if the current latex installation is valid.
"""
if LATEX_PATH is None:
print("No Latex installation found.")
if "--test-build" not in argv:
QMessageBox.warning(None, "LogarithmPlotter - Latex setup", QCoreApplication.translate("latex", "No Latex installation found.\nIf you already have a latex distribution installed, make sure it's installed on your path.\nOtherwise, you can download a Latex distribution like TeX Live at https://tug.org/texlive/."))
elif DVIPNG_PATH is None:
print("DVIPNG not found.")
if "--test-build" not in argv:
QMessageBox.warning(None, "LogarithmPlotter - Latex setup", QCoreApplication.translate("latex", "DVIPNG was not found. Make sure you include it from your Latex distribution."))
@Property(bool)
def latexSupported(self):
return LATEX_PATH is not None and DVIPNG_PATH is not None
@Slot(str, float, QColor, result=str)
def render(self, latex_markup: str, font_size: float, color: QColor) -> str:
"""
Prepares and renders a latex string into a png file.
"""
markup_hash = "render"+str(hash(latex_markup))
export_path = path.join(self.tempdir.name, f'{markup_hash}_{int(font_size)}_{color.rgb()}')
if self.latexSupported and not path.exists(export_path + ".png"):
print("Rendering", latex_markup, export_path)
# Generating file
try:
latex_path = path.join(self.tempdir.name, str(markup_hash))
# If the formula is just recolored or the font is just changed, no need to recreate the DVI.
if not path.exists(latex_path + ".dvi"):
self.create_latex_doc(latex_path, latex_markup)
self.convert_latex_to_dvi(latex_path)
self.cleanup(latex_path)
# Creating four pictures of different sizes to better handle dpi.
self.convert_dvi_to_png(latex_path, export_path, font_size, color)
# self.convert_dvi_to_png(latex_path, export_path+"@2", font_size*2, color)
# self.convert_dvi_to_png(latex_path, export_path+"@3", font_size*3, color)
# self.convert_dvi_to_png(latex_path, export_path+"@4", font_size*4, color)
except Exception as e: # One of the processes failed. A message will be sent every time.
raise e
img = QImage(export_path);
# Small hack, not very optimized since we load the image twice, but you can't pass a QImage to QML and expect it to be loaded
return f'{export_path}.png,{img.width()},{img.height()}'
def create_latex_doc(self, export_path: str, latex_markup: str):
"""
Creates a temporary latex document with base file_hash as file name and a given expression markup latex_markup.
"""
ltx_path = export_path + ".tex"
f = open(export_path + ".tex", 'w')
f.write(DEFAULT_LATEX_DOC.substitute(markup = latex_markup))
f.close()
def convert_latex_to_dvi(self, export_path: str):
"""
Converts a TEX file to a DVI file.
"""
self.run([
LATEX_PATH,
export_path + ".tex"
])
def convert_dvi_to_png(self, dvi_path: str, export_path: str, font_size: float, color: QColor):
"""
Converts a DVI file to a PNG file.
Documentation: https://linux.die.net/man/1/dvipng
"""
fg = color.convertTo(QColor.Rgb)
fg = f'rgb {fg.redF()} {fg.greenF()} {fg.blueF()}'
depth = int(font_size * 72.27 / 100) * 10
self.run([
DVIPNG_PATH,
'-T', 'tight', # Make sure image borders are as tight around the equation as possible to avoid blank space.
'--truecolor', # Make sure it's rendered in 24 bit colors.
'-D',f'{depth}', # Depth of the image
'-bg', 'Transparent', # Transparent background
'-fg',f'{fg}', # Foreground of the wanted color.
f'{dvi_path}.dvi', # Input file
'-o',f'{export_path}.png', # Output file
])
def run(self, process: list):
"""
Runs a subprocess and handles exceptions and messages them to the user.
"""
proc = Popen(process, stdout=PIPE, stderr=PIPE, cwd=self.tempdir.name)
try:
out, err = proc.communicate(timeout=2) # 2 seconds is already FAR too long.
if proc.returncode != 0:
# Process errored
QMessageBox.warning(None, "LogarithmPlotter - Latex",
QCoreApplication.translate("latex", "An exception occured within the creation of the latex formula.\nProcess '{}' ended with a non-zero return code {}:\n\n{}\nPlease make sure your latex installation is correct and report a bug if so.")
.format(" ".join(process), proc.returncode, str(out, 'utf8')+"\n"+str(err,'utf8')))
raise Exception(" ".join(process) + " process exited with return code " + str(proc.returncode) + ":\n" + str(out, 'utf8')+"\n"+str(err,'utf8'))
except TimeoutExpired as e:
# Process timed out
proc.kill()
out, err = proc.communicate()
QMessageBox.warning(None, "LogarithmPlotter - Latex",
QCoreApplication.translate("latex", "An exception occured within the creation of the latex formula.\nProcess '{}' took too long to finish:\n{}\nPlease make sure your latex installation is correct and report a bug if so.")
.format(" ".join(process), str(out, 'utf8')+"\n"+str(err,'utf8')))
raise Exception(" ".join(process) + " process timed out:\n" + str(out, 'utf8')+"\n"+str(err,'utf8'))
def cleanup(self, export_path):
"""
Removes auxiliary, logs and Tex temporary files.
"""
for i in [".tex", ".aux", ".log"]:
remove(export_path + i)
"""
@Slot(str, float, QColor, result=str)
def render_legacy(self, latexstring, font_size, color = True):
exprpath = path.join(self.tempdir.name, f'{hash(latexstring)}_{font_size}_{color.rgb()}.png')
print("Rendering", latexstring, exprpath)
if not path.exists(exprpath):
fg = color.convertTo(QColor.Rgb)
fg = f'rgb {fg.redF()} {fg.greenF()} {fg.blueF()}'
preview('$${' + latexstring + '}$$', viewer='file', filename=exprpath, dvioptions=[
"-T", "tight",
"-z", "0",
"--truecolor",
f"-D {int(font_size * 72.27 / 100) * 10}", # See https://linux.die.net/man/1/dvipng#-D for convertion
"-bg", "Transparent",
"-fg", fg],
euler=False)
img = QImage(exprpath);
# Small hack, not very optimized since we load the image twice, but you can't pass a QImage to QML and expect it to be loaded
return f'{exprpath},{img.width()},{img.height()}'
"""

View file

@ -1,4 +1,5 @@
# ![icon](https://git.ad5001.eu/Ad5001/LogarithmPlotter/raw/branch/master/logplotter.svg) LogarithmPlotter # ![icon](https://apps.ad5001.eu/icons/apps/svg/logarithmplotter.svg) LogarithmPlotter
[![Build Status](https://ci.ad5001.eu/api/badges/Ad5001/LogarithmPlotter/status.svg)](https://ci.ad5001.eu/Ad5001/LogarithmPlotter) [![Build Status](https://ci.ad5001.eu/api/badges/Ad5001/LogarithmPlotter/status.svg)](https://ci.ad5001.eu/Ad5001/LogarithmPlotter)
[![Translation status](https://hosted.weblate.org/widgets/logarithmplotter/-/logarithmplotter/svg-badge.svg)](https://hosted.weblate.org/engage/logarithmplotter/) [![Translation status](https://hosted.weblate.org/widgets/logarithmplotter/-/logarithmplotter/svg-badge.svg)](https://hosted.weblate.org/engage/logarithmplotter/)
[![On flathub](https://img.shields.io/flathub/v/eu.ad5001.LogarithmPlotter?label=on%20flathub&logo=Flathub&logoColor=white&color=4A86CF)](https://flathub.org/apps/details/eu.ad5001.LogarithmPlotter) [![On flathub](https://img.shields.io/flathub/v/eu.ad5001.LogarithmPlotter?label=on%20flathub&logo=Flathub&logoColor=white&color=4A86CF)](https://flathub.org/apps/details/eu.ad5001.LogarithmPlotter)
@ -7,56 +8,79 @@
2D plotter software to make Bode plots, sequences and distribution functions. 2D plotter software to make Bode plots, sequences and distribution functions.
## Screenshots ## Screenshots
![Magnitude example](https://apps.ad5001.eu/img/full/logarithmplotter.png) ![Magnitude example](https://apps.ad5001.eu/img/full/logarithmplotter.png)
![Phase example](https://apps.ad5001.eu/img/en/logarithmplotter/phase.png) ![Phase example](https://apps.ad5001.eu/img/en/logarithmplotter/phase.png)
![Object settings](https://apps.ad5001.eu/img/en/logarithmplotter/object-settings.webp) ![Object settings](https://apps.ad5001.eu/img/en/logarithmplotter/object-settings.webp)
You can find more screenshots on the [app website](https://apps.ad5001.eu/logarithmplotter/). You can find more screenshots on the [app's website](https://apps.ad5001.eu/logarithmplotter/).
## Run ## Build & Run
You can simply run LogarithmPlotter using `python3 run.py`. First, you'll need to install all the required dependencies:
In order to test translations, you can use the `--lang=<lang code>` command line option to force the detected locale of LogarithmPlotter. - [Python 3](https://python.org) with [poetry](https://python-poetry.org/), setup a virtual environment, go to the `runtime-pyside6` directory, and call
`poetry install`.
- [npm](https://npmjs.com) (or [yarn](https://yarnpkg.com/)), go to the `common` directory, and run `npm install` (or `yarn install`).
You can simply run LogarithmPlotter using `python3 run.py`. It automatically compiles the language files (requires
`pyside6-lrelease` to be installed and in path), and the JavaScript modules.
If you do not wish do recompile the files again on every run, you can use the build script (`scripts/build.sh`) and run
`python3 build/runtime-pyside6/LogarithmPlotter/logarithmplotter.py`.
In order to test translations, you can use the `--lang=<lang code>` commandline option to force the locale.
## Install ## Install
### Generate installers: ### Generate installers:
All scripts noted here can be found in the `scripts` directory. All scripts noted here can be found in the `scripts` directory.
You can generate installers from LogarithmPlotter after installing all the dependencies: You can generate installers for LogarithmPlotter after installing all the dependencies.
For all builds, you need [Python 3](https://python.org) with [PySide6](https://pypi.org/project/PySide6/) installable with `pip install PySide6`.
- Windows installer: - Windows installer (crosscompiling from Linux):
- You need `pyinstaller`. You can install it using `pip install pyinstaller`. - Run `build-wine.sh` (requires wine) to build an exe for LogarithmPlotter in build/runtime-pyside6/dist.
- Run the `build-windows.bat` script (or `build-wine.sh` if you're cross-compiling with wine on Linux) to build an exe for LogarithmPlotter. - You also need [NSIS](https://nsis.sourceforge.io/Main_Page) (the [nsis](https://pkgs.org/download/nsis) package is available on linux).
- You also need [NSIS](https://nsis.sourceforge.io/Main_Page) (Linux users can install the [nsis](https://pkgs.org/download/nsis) package). - Run the `package-wine.sh` script. You will find a logarithmplotter-setup.exe installer in the build/runtime-pyside6/dist/logarithmplotter/ folder.
- Run the `package-windows.bat` script (or `package-wine.sh`if you're cross-compiling on Linux). You will find a logarithmplotter-setup.exe installer in the dist/accountfree/ folder.
- MacOS Archive creator installer: - MacOS Archive creator installer:
- You need `pyinstaller`. You can install it using `pip install pyinstaller`. - Run the `build-macosx.sh` script to build an .app for LogarithmPlotter which can be found in the build/runtime-pyside6/dist directory.
- Run the `build-macosx.sh` script to build an .app for LogarithmPlotter which can be found in the dist directory. - Run the `package-macosx.sh` script. You will find a LogarithmPlotter-v&lt;version&gt;-setup.dmg installer in the
- Run the `package-macosx.sh` script. You will find a LogarithmPlotter-v0.1-dev-setup.dmg installer in the dist/ folder. build/runtime-pyside6/build/pysdist/ folder.
- Linux packages: - Linux packages:
- To build a DEB, you need DPKG and stdeb. You can install the later by using `pip install stdeb`. - Run `package-deb.sh`. It will create an DSC and a DEB in build/runtime-pyside6/deb_dist/
- To build and install the flatpak, you need [flatpak-builder](https://docs.flatpak.org/en/latest/flatpak-builder.html) installed. - Run `scripts/build.sh` followed by `snapcraft`. It .snap file in the root directory.
- To build the snap, you need [snapcraft](https://snapcraft.io) installed. - See [the flatpak repo](https://github.com/Ad5001/eu.ad5001.LogarithmPlotter) for instrutions on how to build the flatpak.
- Run `package-linux.sh`.
### Linux
Run `bash linux/install_local.sh`
## Contribute ## Contribute
There are several ways to contribute to LogarithmPlotter. There are several ways you can contribute to LogarithmPlotter.
- You can help to translate [the project on Hosted Weblate](https://hosted.weblate.org/engage/logarithmplotter/):
[![Translation status](https://hosted.weblate.org/widgets/logarithmplotter/-/logarithmplotter/multi-auto.svg)](https://hosted.weblate.org/engage/logarithmplotter/)
- You can help the development of LogarithmPlotter. In order to get started, take a look at the [wiki](https://git.ad5001.eu/Ad5001/LogarithmPlotter/wiki/_pages). - You can help to translate [the project on Hosted Weblate](https://hosted.weblate.org/engage/logarithmplotter/):
[![Translation status](https://hosted.weblate.org/widgets/logarithmplotter/-/logarithmplotter/multi-auto.svg)](https://hosted.weblate.org/engage/logarithmplotter/)
- You can help the development of LogarithmPlotter. In order to get started, take a look at
the [wiki](https://git.ad5001.eu/Ad5001/LogarithmPlotter/wiki/_pages).
## Tests
To run LogarithmPlotter's tests, follow these steps:
- Python
- Install python3 and [poetry](https://python-poetry.org/)
- Create and activate virtual env (recommended)
- Go into `runtime-pyside6` and run `poetry install --with test`
- ECMAScript
- Install node with npm
- Go into `common` and run `npm install -D`
Finally, to actually run the tests:
- Run `scripts/run-tests.sh`
## Legal notice ## Legal notice
LogarithmPlotter - 2D plotter software to make BODE plots, sequences and repartition functions.
Copyright (C) 2021-2024 Ad5001 <mail@ad5001.eu> LogarithmPlotter - 2D plotter software to make Bode plots, sequences and repartition functions.
Copyright (C) 2021-2025 Ad5001 <mail@ad5001.eu>
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -71,12 +95,19 @@ There are several ways to contribute to LogarithmPlotter.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
Language files translations located at LogarithmPlotter/i18n are licensed under GNU GPL3.0+ and are copyrighted by their original authors. See LICENSE.md for more details: See LICENSE.md for more details. Language files translations located at assets/i18n are licensed under GNU GPL3.0+ and
- 🇳🇴 Norwegian translation by [Allan Nordhøy](https://github.com/comradekingu) are copyrighted by their original authors:
- 🇭🇺 Hungarian translation by [Óvári](https://github.com/ovari) - 🇭🇺 Hungarian translation by [Óvári](https://github.com/ovari)
- 🇳🇴 Norwegian translation by [Allan Nordhøy](https://github.com/comradekingu)
- 🇪🇸 Spanish translation by gallegonovato and [IngrownMink4](https://github.com/IngrownMink4)
### Libraries used ### Libraries used
LogarithmPlotter includes [expr-eval](https://github.com/silentmatt/expr-eval) a port of [ndef.parser](https://web.archive.org/web/20111023001618/http://www.undefined.ch/mparser/index.html) by Raphael Graf &lt;r@undefined.ch&gt;, ported to javascript by Matthew Crumley &lt;email@matthewcrumley.com&gt; (http://silentmatt.com/), and then to QMLJS by Ad5001. LogarithmPlotter includes [expr-eval](https://github.com/silentmatt/expr-eval) a port
of [ndef.parser](https://web.archive.org/web/20111023001618/http://www.undefined.ch/mparser/index.html) by Raphael Graf
&lt;r@undefined.ch&gt;, ported to javascript by Matthew Crumley
&lt;email@matthewcrumley.com&gt; (http://silentmatt.com/), and then to QMLJS by Ad5001.
The specific file (LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/expr-eval.js) is licensed under the [MIT License](https://raw.githubusercontent.com/silentmatt/expr-eval/master/LICENSE.txt). All files in (common/src/lib/expr-eval/) except integration.mjs are licensed
under the [MIT License](https://raw.githubusercontent.com/silentmatt/expr-eval/master/LICENSE.txt).

1996
assets/i18n/lp_de.ts Normal file

File diff suppressed because it is too large Load diff

1996
assets/i18n/lp_en.ts Normal file

File diff suppressed because it is too large Load diff

1985
assets/i18n/lp_es.ts Normal file

File diff suppressed because it is too large Load diff

1999
assets/i18n/lp_fr.ts Normal file

File diff suppressed because it is too large Load diff

1996
assets/i18n/lp_hu.ts Normal file

File diff suppressed because it is too large Load diff

1836
assets/i18n/lp_nb_NO.ts Normal file

File diff suppressed because it is too large Load diff

1597
assets/i18n/lp_ta.ts Normal file

File diff suppressed because it is too large Load diff

1569
assets/i18n/lp_template.ts Normal file

File diff suppressed because it is too large Load diff

2
assets/i18n/release.sh Executable file
View file

@ -0,0 +1,2 @@
#!/bin/bash
pyside6-lrelease *.ts

65
assets/i18n/update.sh Executable file
View file

@ -0,0 +1,65 @@
#!/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"
}
rm ../qml/eu/ad5001/LogarithmPlotter/js/index.mjs # Remove index which should not be scanned
files=$(find ../../common/src -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" "^export *" "/*export *"
replace "${file%.*}.js" '.mjs"$' '.mjs"*/'
replace "${file%.*}.js" "^export default" "/*export default*/"
replace "${file%.*}.js" "^export" "/*export*/"
replace "${file%.*}.js" "async " "/*async */"
replace "${file%.*}.js" "await" "/*await */"
replace "${file%.*}.js" " #" "// #"
replace "${file%.*}.js" "this.#" "/*this.#*/"
done
echo "----------------------------"
echo "| Updating translations... |"
echo "----------------------------"
pyside6-lupdate -extensions js,qs,qml,py -recursive ../../common/src -recursive ../../runtime-pyside6/LogarithmPlotter -ts lp_*.ts
# Updating locations in files
for lp in *.ts; do
echo "Replacing locations in $lp..."
for file in $files; do
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" "/*await */" "await"
replace "$file" "/*async */" "async "
replace "$file" "^/*export*/" "export"
replace "$file" "^/*export default*/" "export default"
replace "$file" '.mjs"*/' '.mjs"'
replace "$file" "^/*import" "import"
replace "$file" "^/*export" "export"
replace "$file" "// #" " #"
replace "$file" "/*this.#*/" "this.#"
done

View file

Before

Width:  |  Height:  |  Size: 198 B

After

Width:  |  Height:  |  Size: 198 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 289 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 620 B

After

Width:  |  Height:  |  Size: 620 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 261 B

After

Width:  |  Height:  |  Size: 261 B

Before After
Before After

View file

@ -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

View file

@ -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

View file

Before

Width:  |  Height:  |  Size: 273 B

After

Width:  |  Height:  |  Size: 273 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 696 B

After

Width:  |  Height:  |  Size: 696 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 270 B

After

Width:  |  Height:  |  Size: 270 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 370 B

After

Width:  |  Height:  |  Size: 370 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Before After
Before After

View file

@ -0,0 +1 @@
../common/close.svg

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before After
Before After

View file

@ -0,0 +1 @@
../common/appearance.svg

View file

@ -0,0 +1 @@
../common/appearance.svg

View file

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Before After
Before After

View file

@ -0,0 +1 @@
../common/arrow.svg

View file

@ -0,0 +1 @@
../common/position.svg

Some files were not shown because too many files have changed in this diff Show more