SwiftGUI 0.11.19__tar.gz → 0.12.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. {swiftgui-0.11.19 → swiftgui-0.12.0}/PKG-INFO +35 -34
  2. swiftgui-0.12.0/README.md +100 -0
  3. {swiftgui-0.11.19 → swiftgui-0.12.0}/pyproject.toml +1 -1
  4. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Base.py +71 -3
  5. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Text.py +1 -1
  6. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Combined_Elements/BaseCombinedElement.py +6 -0
  7. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Combined_Elements/Form.py +104 -43
  8. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Examples/AllElements.py +9 -6
  9. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/Table.py +3 -1
  10. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/GlobalOptions.py +14 -3
  11. swiftgui-0.12.0/src/SwiftGUI/Popups/TooltipPopup.py +41 -0
  12. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Popups/__init__.py +1 -0
  13. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Themes/FourColors.py +3 -0
  14. swiftgui-0.12.0/src/SwiftGUI/Tooltips.py +112 -0
  15. swiftgui-0.12.0/src/SwiftGUI/Validate/Base.py +119 -0
  16. swiftgui-0.12.0/src/SwiftGUI/Validate/Common.py +82 -0
  17. swiftgui-0.12.0/src/SwiftGUI/Validate/Regex.py +20 -0
  18. swiftgui-0.12.0/src/SwiftGUI/Validate/__init__.py +4 -0
  19. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Button.py +1 -1
  20. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Checkbox.py +1 -1
  21. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Combobox.py +8 -4
  22. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Frame.py +3 -0
  23. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Input.py +3 -3
  24. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Listbox.py +1 -1
  25. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Radiobutton.py +1 -1
  26. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Scale.py +1 -1
  27. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Spinbox.py +21 -16
  28. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Text.py +1 -1
  29. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/TextField.py +1 -1
  30. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Treeview.py +1 -1
  31. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Windows.py +34 -2
  32. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/__init__.py +3 -0
  33. swiftgui-0.11.19/README.md +0 -99
  34. {swiftgui-0.11.19 → swiftgui-0.12.0}/LICENSE +0 -0
  35. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/BasePopup.py +0 -0
  36. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Arc.py +0 -0
  37. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Bitmap.py +0 -0
  38. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Element.py +0 -0
  39. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Image.py +0 -0
  40. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Line.py +0 -0
  41. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Oval.py +0 -0
  42. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Polygon.py +0 -0
  43. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/Rectangle.py +0 -0
  44. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/_Base.py +0 -0
  45. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Canvas_Elements/__init__.py +0 -0
  46. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Colors.py +0 -0
  47. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Combined_Elements/Calendar.py +0 -0
  48. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Combined_Elements/Console.py +0 -0
  49. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Combined_Elements/MultistateButton.py +0 -0
  50. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Compat.py +0 -0
  51. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Debug.py +0 -0
  52. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/DecoratorKeys.py +0 -0
  53. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/ElementFlags.py +0 -0
  54. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Events.py +0 -0
  55. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Examples/AllThemes.py +0 -0
  56. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Examples/GlobalOptionBrowser.py +0 -0
  57. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Examples/Previews.py +0 -0
  58. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Examples/__init__.py +0 -0
  59. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Exceptions.py +0 -0
  60. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/ColorChooserButton.py +0 -0
  61. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/ComboboxMapping.py +0 -0
  62. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/FileBrowseButton.py +0 -0
  63. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/Image.py +0 -0
  64. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/ImageButton.py +0 -0
  65. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/PythonConsole.py +0 -0
  66. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/Separator.py +0 -0
  67. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/Spacer.py +0 -0
  68. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Extended_Elements/TabFrame.py +0 -0
  69. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Extras/SwiftGUI.py +0 -0
  70. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Extras/__init__.py +0 -0
  71. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Files/ConfigFile.py +0 -0
  72. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Files/ConfigurationEditor.py +0 -0
  73. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Files/DictFile.py +0 -0
  74. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Files/ProgramDirectory.py +0 -0
  75. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Files/__init__.py +0 -0
  76. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Fonts.py +0 -0
  77. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/KeyFunctions.py +0 -0
  78. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Literals.py +0 -0
  79. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Popups/ElementPopup.py +0 -0
  80. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Popups/ListPicker.py +0 -0
  81. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Popups/SmallPopups.py +0 -0
  82. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Popups/VirtualKeyboard.py +0 -0
  83. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Themes/Thematic.py +0 -0
  84. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Themes/_BaseTheme.py +0 -0
  85. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Themes/__init__.py +0 -0
  86. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Tools.py +0 -0
  87. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Utilities/Images.py +0 -0
  88. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Utilities/Threads.py +0 -0
  89. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Canvas.py +0 -0
  90. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/GridFrame.py +0 -0
  91. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/LabelFrame.py +0 -0
  92. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Notebook.py +0 -0
  93. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Progressbar.py +0 -0
  94. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/Scrollbar.py +0 -0
  95. {swiftgui-0.11.19 → swiftgui-0.12.0}/src/SwiftGUI/Widget_Elements/TKContainer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: SwiftGUI
3
- Version: 0.11.19
3
+ Version: 0.12.0
4
4
  Summary: An easy-to-use package for quickly creating smaller and bigger GUIs
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -21,7 +21,6 @@ Description-Content-Type: text/markdown
21
21
 
22
22
 
23
23
  # SwiftGUI
24
-
25
24
  A python-package to easily create user-interfaces (GUIs).
26
25
 
27
26
  While most packages focus either on small, or big applications, SwiftGUI does both.
@@ -32,20 +31,20 @@ Has some minor optimizations when running in Python 3.12+.
32
31
  # Getting started / documentation
33
32
  [Start your journey here](https://github.com/CheesecakeTV/SwiftGUI-Docs/blob/main/01%20Basic%20tutorials/01%20Getting-started.md)
34
33
 
35
- The documentation now has [its own repository](https://github.com/CheesecakeTV/SwiftGUI-Docs).
34
+ [Documentation](https://github.com/CheesecakeTV/SwiftGUI-Docs).
36
35
 
37
- # Completely vibe-coding free
36
+ # Vibe-coding free
38
37
  No AI was used in writing this code.
39
38
 
40
39
  The only way I used it was to research really specific topics with tkinter.
41
40
 
42
- I did not use AI to write, check, correct, or refractor code.
43
-
44
41
  Even the documentation was written completely AI-free.
45
42
  Takes me around 2 hours per document, but that's a good price for keeping everything slop-free.
46
43
 
47
- # 35 different elements, 9 different canvas-elements
48
- (Version 0.11.0)
44
+ Yes, this does slow down development quite a bit, but I trust myself to be more reliable than an AI agent.
45
+
46
+ # 38 different elements, 9 different canvas-elements
47
+ (Version 0.12.0)
49
48
 
50
49
  `import SwiftGUI as sg`
51
50
 
@@ -60,18 +59,14 @@ This applies the `Emerald`-theme, my personal favorite.
60
59
 
61
60
  See which themes are available by calling `sg.Examples.preview_all_themes()`.
62
61
 
63
- # Alpha-phase!
64
- I am already using SwiftGUI for smaller projects and personally, like it a lot so far.
62
+ # Final minor version before Beta starts!
63
+ You might have noticed that updates for SwiftGUI are rarer than they used to be.
64
+ That's actually a good sign, it means I find less things to add/correct.
65
65
 
66
- However, until version 1.0.0, downward-compatability is not a priority.
67
- Names and functions/methods might change, which could potentially mess up your code.
66
+ There will not be version 0.13.0, but 1.0.0 instead.
68
67
 
69
- For version 1.0.0, I'll sort and standardize names, so they are easier to remember.
70
- After version 1.0.0, there will be little to no changes that might break existing code.
71
- If changes can't be avoided, there will be a separate changelog which shows everything you need to
72
- adjust so you may update without issues.
73
-
74
- Don't worry too much though, the package is pretty much ready for beta-phase.
68
+ I do have a couple of major tasks on my list before rolling out 1.0 though.
69
+ Fixing the treeview for example.
75
70
 
76
71
  # Installation
77
72
  Install using pip:
@@ -79,27 +74,28 @@ Install using pip:
79
74
  pip install SwiftGUI
80
75
  ```
81
76
 
82
- Update SwiftGUI for the newest features and elements:
77
+ Regularely update SwiftGUI for the newest features and bugfixes:
83
78
  ```bash
84
79
  pip install SwiftGUI -U
85
80
  ```
86
81
 
87
82
  # NOT a clone of PySimpleGUI
88
- SwiftGUI is it's own package with its own functionality.
83
+ SwiftGUI is it's own package, with its own functionality.
89
84
 
90
85
  I really liked PySimpleGUI (until they went "premium"),
91
- but once you work a lot with it, you'll notice the downsides of it more and more.
86
+ but once you work a lot with it, you'll notice its downsides more and more.
92
87
 
93
- **SwiftGUI can be used very simmilar to PySimpleGUI**, but has a lot of additional features.\
94
- So if you know PySimpleGUI, you won't need to start from scratch.
88
+ The basics of SwiftGUI are almost the same as PySimpleGUI.
89
+ So if you know PySimpleGUI, you already know many concepts of SwiftGUI.
95
90
 
96
- Also, there will be a lot of learning-material, including
97
- - Written tutorials (see "getting started" below)
98
- - Video tutorials (Planned for version 1.0.0)
99
- - Application notes, which are short descriptions of actual applications
91
+ There is already a collection of helpful learning material, including:
92
+ - Written tutorials (see "getting started" above)
93
+ - Application notes, which summarize different tutorials regarding specific applications
100
94
  - Examples, which show an actual application of SwiftGUI
101
95
  - The GitHub forum ([discussions](https://github.com/CheesecakeTV/SwiftGUI/discussions)) for questions
102
96
 
97
+ Video tutorials are planned for version 1.0.0.
98
+
103
99
  ## Why SwiftGUI instead of PySimpleGUI?
104
100
  I have a lot of experience with `PySimpleGUI`, used it for years.\
105
101
  It is very useful for smaller applications.
@@ -107,15 +103,20 @@ It is very useful for smaller applications.
107
103
  Unfortunately, at a certain level of complexity, you'll hit a wall.\
108
104
  All those simple features that make PySimpleGUI great, are suddenly very annoying.
109
105
 
110
- What annoys me the most is that PySimpleGUI forces you to use only the event-loop for functionality.
111
- That means, every tiny tiniest functionality needs a key and code in the event-loop.
106
+ In the earlier versions of SwiftGUI, it was ment to "fix" annoying things in PySimpleGUI.
107
+ For example:
108
+ - You are forced to use the event-loop for every tiny functionality
109
+ - You can pretty much forget about editing elements, since they are implemented so convoluded
110
+ - Some elements throw events wrong, including sg.Table and sg.Input
112
111
 
113
- SwiftGUI on the other hand offers many different ways to connect layout with functionality.
114
- That makes it easy to "copy and paste" parts of the layout.
112
+ Nowadays, SwiftGUI's functionality goes far beyond what PySimpleGUI has to offer.
115
113
 
116
- SwiftGUI also supports multiple windows much better, with every window having its own event-loop.
114
+ The reason is simple:
115
+ SwiftGUI is built for modularity and expandability.
116
+ You can easily create templates, themes, custom popups, modify elements, etc.
117
117
 
118
- On top of that, SwiftGUI enables expandability everywhere.
119
- You can easily create your own elements, themes, popups and templates.
118
+ Also, SwiftGUI works a lot better with multiple windows.
119
+ Creating a second window is almost as simple as creating a single one.
120
120
 
121
+ A lot more features are described/mentioned in the documentation.
121
122
 
@@ -0,0 +1,100 @@
1
+
2
+ # SwiftGUI
3
+ A python-package to easily create user-interfaces (GUIs).
4
+
5
+ While most packages focus either on small, or big applications, SwiftGUI does both.
6
+
7
+ ## Compatible with Python 3.10 and above
8
+ Has some minor optimizations when running in Python 3.12+.
9
+
10
+ # Getting started / documentation
11
+ [Start your journey here](https://github.com/CheesecakeTV/SwiftGUI-Docs/blob/main/01%20Basic%20tutorials/01%20Getting-started.md)
12
+
13
+ [Documentation](https://github.com/CheesecakeTV/SwiftGUI-Docs).
14
+
15
+ # Vibe-coding free
16
+ No AI was used in writing this code.
17
+
18
+ The only way I used it was to research really specific topics with tkinter.
19
+
20
+ Even the documentation was written completely AI-free.
21
+ Takes me around 2 hours per document, but that's a good price for keeping everything slop-free.
22
+
23
+ Yes, this does slow down development quite a bit, but I trust myself to be more reliable than an AI agent.
24
+
25
+ # 38 different elements, 9 different canvas-elements
26
+ (Version 0.12.0)
27
+
28
+ `import SwiftGUI as sg`
29
+
30
+ Call `sg.Examples.preview_all_elements()` for an overview of all currently available elements.
31
+
32
+ # Does your GUI look bad?
33
+ `import SwiftGUI as sg`
34
+
35
+ Just call `sg.Themes.FourColors.Emerald()` before creating the layout.
36
+
37
+ This applies the `Emerald`-theme, my personal favorite.
38
+
39
+ See which themes are available by calling `sg.Examples.preview_all_themes()`.
40
+
41
+ # Final minor version before Beta starts!
42
+ You might have noticed that updates for SwiftGUI are rarer than they used to be.
43
+ That's actually a good sign, it means I find less things to add/correct.
44
+
45
+ There will not be version 0.13.0, but 1.0.0 instead.
46
+
47
+ I do have a couple of major tasks on my list before rolling out 1.0 though.
48
+ Fixing the treeview for example.
49
+
50
+ # Installation
51
+ Install using pip:
52
+ ```bash
53
+ pip install SwiftGUI
54
+ ```
55
+
56
+ Regularely update SwiftGUI for the newest features and bugfixes:
57
+ ```bash
58
+ pip install SwiftGUI -U
59
+ ```
60
+
61
+ # NOT a clone of PySimpleGUI
62
+ SwiftGUI is it's own package, with its own functionality.
63
+
64
+ I really liked PySimpleGUI (until they went "premium"),
65
+ but once you work a lot with it, you'll notice its downsides more and more.
66
+
67
+ The basics of SwiftGUI are almost the same as PySimpleGUI.
68
+ So if you know PySimpleGUI, you already know many concepts of SwiftGUI.
69
+
70
+ There is already a collection of helpful learning material, including:
71
+ - Written tutorials (see "getting started" above)
72
+ - Application notes, which summarize different tutorials regarding specific applications
73
+ - Examples, which show an actual application of SwiftGUI
74
+ - The GitHub forum ([discussions](https://github.com/CheesecakeTV/SwiftGUI/discussions)) for questions
75
+
76
+ Video tutorials are planned for version 1.0.0.
77
+
78
+ ## Why SwiftGUI instead of PySimpleGUI?
79
+ I have a lot of experience with `PySimpleGUI`, used it for years.\
80
+ It is very useful for smaller applications.
81
+
82
+ Unfortunately, at a certain level of complexity, you'll hit a wall.\
83
+ All those simple features that make PySimpleGUI great, are suddenly very annoying.
84
+
85
+ In the earlier versions of SwiftGUI, it was ment to "fix" annoying things in PySimpleGUI.
86
+ For example:
87
+ - You are forced to use the event-loop for every tiny functionality
88
+ - You can pretty much forget about editing elements, since they are implemented so convoluded
89
+ - Some elements throw events wrong, including sg.Table and sg.Input
90
+
91
+ Nowadays, SwiftGUI's functionality goes far beyond what PySimpleGUI has to offer.
92
+
93
+ The reason is simple:
94
+ SwiftGUI is built for modularity and expandability.
95
+ You can easily create templates, themes, custom popups, modify elements, etc.
96
+
97
+ Also, SwiftGUI works a lot better with multiple windows.
98
+ Creating a second window is almost as simple as creating a single one.
99
+
100
+ A lot more features are described/mentioned in the documentation.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "SwiftGUI"
3
- version = "0.11.19"
3
+ version = "0.12.0"
4
4
  packages = [
5
5
  { include = "SwiftGUI", from = "src" }
6
6
  ]
@@ -1,10 +1,9 @@
1
- from collections.abc import Iterable, Callable
2
1
  from functools import wraps
3
- from typing import Literal, Union, Any, Hashable, Protocol
2
+ from typing import Literal, Union, Any, Hashable, Protocol, Iterable, Callable, TypeVar
4
3
  from SwiftGUI.Compat import Self
5
4
  import tkinter as tk
6
5
 
7
- from SwiftGUI import Event, GlobalOptions, Color, remove_None_vals, Literals, ReuseError, RowTypeError
6
+ from SwiftGUI import Event, GlobalOptions, Color, remove_None_vals, Literals, ReuseError, RowTypeError, Tooltips
8
7
  from SwiftGUI.ElementFlags import ElementFlag
9
8
  #from SwiftGUI.Widget_Elements.Frame import Frame
10
9
 
@@ -52,6 +51,7 @@ class _BaseSharedAttributes:
52
51
  key: Hashable = None # If given, this will be written to the event-value. Elements without a key can not throw key-events
53
52
  _key_function: Callable | Iterable[Callable] = None # Saves the key-function(s), if given
54
53
 
54
+ same_class = TypeVar("same_class")
55
55
  class BaseElement(_BaseSharedAttributes):
56
56
  """
57
57
  Base for every element and widget.
@@ -383,6 +383,52 @@ class BaseElement(_BaseSharedAttributes):
383
383
 
384
384
  return self
385
385
 
386
+ _tooltip_text: str | None = None
387
+ _bound_tooltip_functions: bool = False # True, if the events for tooltips are already bound
388
+ @run_after_window_creation
389
+ def set_tooltip(self, text: str | None = None) -> Self:
390
+ """
391
+ Add/Change/Remove a tooltip from this element.
392
+
393
+ Set it to None to deactivate tooltips for this element
394
+
395
+ :param text: Text for the tooltip to show
396
+ :return:
397
+ """
398
+ self._tooltip_text = text
399
+
400
+ if not self._bound_tooltip_functions:
401
+ self._bound_tooltip_functions = True
402
+ aw = self.window.actual_window
403
+ aw.activate_tooltips()
404
+ self.bind_event(
405
+ "Enter",
406
+ key_function=Tooltips.mouse_entered_elem_callback,
407
+ ).bind_event(
408
+ "Leave",
409
+ key_function=Tooltips.mouse_exited_elem_callback,
410
+ )
411
+
412
+ @property
413
+ def tooltip_text(self) -> str | None:
414
+ return self._tooltip_text
415
+
416
+ @tooltip_text.setter
417
+ def tooltip_text(self, text: str | None):
418
+ self.set_tooltip(text)
419
+
420
+ @classmethod
421
+ def with_go(cls: type[same_class], go_class: type[GlobalOptions.DEFAULT_OPTIONS_CLASS]) -> type[same_class]:
422
+ """
423
+ Create this element with a different global-option-class
424
+ :param go_class: The global-option-class this object should apply
425
+ :return:
426
+ """
427
+ class Modified(cls):
428
+ defaults = go_class
429
+
430
+ return Modified
431
+
386
432
  class BaseWidget(BaseElement):
387
433
  """
388
434
  Base for every Widget
@@ -720,6 +766,28 @@ class BaseWidget(BaseElement):
720
766
  def __repr__(self) -> str:
721
767
  return f"<sg.{self.__class__.__name__} element with key={self.key} at {id(self)}>"
722
768
 
769
+ def _update_special_key(self,key:str,new_val:Any) -> bool|None:
770
+
771
+ match key:
772
+ case "validatecommand":
773
+ if new_val is None:
774
+ return True
775
+
776
+ if not self.has_flag(ElementFlag.IS_CREATED):
777
+ self.update_after_window_creation(validatecommand=new_val)
778
+ return True
779
+
780
+ as_tuple = tuple(new_val)
781
+ self._tk_kwargs["validatecommand"] = (
782
+ self.tk_widget.register(as_tuple[0]),
783
+ *as_tuple[1:],
784
+ )
785
+
786
+ case _:
787
+ return super()._update_special_key(key, new_val)
788
+
789
+ return True
790
+
723
791
  class MixinScrollbar:
724
792
  """
725
793
  Base for every widget that has a scrollbar.
@@ -89,7 +89,7 @@ class Text(Canvas_Elements.BaseCanvasElement):
89
89
  new_font = font.Font(
90
90
  self.canvas.tk_widget,
91
91
  family=self._fonttype,
92
- size=self._fontsize,
92
+ size=self._fontsize if self._fontsize else 8,
93
93
  weight="bold" if self._bold else "normal",
94
94
  slant="italic" if self._italic else "roman",
95
95
  underline=bool(self._underline),
@@ -43,6 +43,7 @@ class BaseCombinedElement(MixinElementWithDefaultEvent, BaseElement):
43
43
  frame = layout
44
44
  else:
45
45
  frame = Frame(layout)
46
+ self.frame = frame
46
47
 
47
48
  if internal_key_system:
48
49
  self._has_sublayout = True
@@ -233,3 +234,8 @@ class BaseCombinedElement(MixinElementWithDefaultEvent, BaseElement):
233
234
  self.set_value(val)
234
235
 
235
236
  return self
237
+
238
+ def _bind_event_to_widget(self, tk_event: str, event_function: Callable) -> Self:
239
+ self.frame.tk_widget.bind(tk_event, event_function)
240
+
241
+
@@ -1,13 +1,7 @@
1
-
2
- from collections.abc import Iterable, Callable
3
- from functools import partial
4
- from typing import Any, Hashable, Mapping
1
+ from typing import Any, Hashable, Mapping, Iterable, Callable
5
2
  from SwiftGUI.Compat import Self
6
- import json
7
3
 
8
- from SwiftGUI import BaseElement, Frame, Text, Input, BaseCombinedElement, Button, Event
9
- #from SwiftGUI.Widget_Elements.Separator import HorizontalSeparator
10
- from SwiftGUI.Extended_Elements.Spacer import Spacer
4
+ from SwiftGUI import BaseElement, Text, Input, BaseCombinedElement, Button, Event, GlobalOptions, ValueDict, Spacer
11
5
 
12
6
 
13
7
  # Advanced / Combined elements
@@ -18,6 +12,8 @@ class Form(BaseCombinedElement):
18
12
  It is WIP, but I'm adding more functionality regularely
19
13
  I'll probably throw this whole class out of the window and redo it, since it is so unfathomly bad atm.
20
14
  """
15
+ defaults = GlobalOptions.Form
16
+ value: ValueDict | tuple
21
17
 
22
18
  def __init__(
23
19
  self,
@@ -27,11 +23,15 @@ class Form(BaseCombinedElement):
27
23
  key: Hashable = None,
28
24
  key_function: Callable | Iterable[Callable] = None,
29
25
  default_event: bool = None,
26
+ return_submits: bool = None,
30
27
  small_clear_buttons: bool = None,
31
28
  big_clear_button: bool = None,
29
+ clear_button_text: str = None,
32
30
  submit_button: bool = None,
31
+ submit_button_text: str = None,
32
+ space_over_buttons: int = None,
33
+ space_between_rows: int = None,
33
34
  #submit_key: Any = None,
34
- return_submits: bool = None,
35
35
  ):
36
36
  """
37
37
 
@@ -44,10 +44,17 @@ class Form(BaseCombinedElement):
44
44
  :param big_clear_button: One big clear-button under the inputs to clear all inputs at once
45
45
  :param submit_button: True, if there should be a submit-button that throws an event when clicked. Ignores the default event
46
46
  :param return_submits: True, if pressing enter should be equal to pressing submit. Ignores the default event
47
+ :param clear_button_text: Text on the clear-button
48
+ :param submit_button_text: Text on the submit-button
49
+ :param space_over_buttons: Height of the separator in the row before the buttons
50
+ :param space_between_rows: Height of the separators between the rows
47
51
  """
48
- self._has_key_mapping = isinstance(texts, Mapping)
52
+ space_between_rows = self.defaults.single("space_between_rows", space_between_rows)
53
+ space_over_buttons = self.defaults.single("space_over_buttons", space_over_buttons)
49
54
 
50
- if self._has_key_mapping:
55
+ self._mapping_mode = isinstance(texts, Mapping)
56
+
57
+ if self._mapping_mode:
51
58
  values = list(texts.values())
52
59
  else:
53
60
  values = list(texts)
@@ -56,41 +63,51 @@ class Form(BaseCombinedElement):
56
63
 
57
64
  self._input_elements: list[Input] = list()
58
65
  self._text_elements: list[Text] = list()
66
+ self._small_clear_button_elements: list[Button] = list()
59
67
 
60
68
  self._small_clear_buttons = small_clear_buttons
61
69
  self._return_submits = return_submits
62
70
 
63
- if self._has_key_mapping:
64
- layout = [
65
- *[
66
- self._make_row(k,t, text_len=_max_len) for t,k in texts.items()
67
- ]
71
+ if self._mapping_mode:
72
+ rows = [
73
+ self._make_row(k,t, text_len=_max_len) for t,k in texts.items()
68
74
  ]
69
75
  else:
70
- layout = [
71
- *[
72
- self._make_row(t, text_len=_max_len) for t in values
73
- ]
76
+ rows = [
77
+ self._make_row(t, text_len=_max_len) for t in values
74
78
  ]
75
79
 
80
+ layout = []
81
+ if space_between_rows:
82
+ for row in rows[:-1]:
83
+ layout.append(row)
84
+ layout.append([Spacer(height=space_between_rows)])
85
+
86
+ if len(rows):
87
+ layout.append(rows[-1])
88
+ else:
89
+ layout = rows
90
+
76
91
  button_row: list[BaseElement] = list()
77
92
 
78
- if big_clear_button:
79
- self.clear_button = Button(
80
- "Clear",
81
- key_function= lambda: self.clear_all_values(throw_default_event=True),
82
- )
83
- button_row.append(self.clear_button)
93
+ self.clear_button = Button(
94
+ self.defaults.single("clear_button_text", clear_button_text),
95
+ key_function= lambda: self.clear_all_values(throw_default_event=True),
96
+ ).set_visible(big_clear_button)
97
+ button_row.append(self.clear_button)
84
98
 
85
- if submit_button:
86
- self.submit_button = Button(
87
- "Submit",
88
- key_function=self.throw_event,
89
- )
90
- button_row.append(self.submit_button)
99
+ self.submit_button = Button(
100
+ self.defaults.single("submit_button_text", submit_button_text),
101
+ key_function=self.throw_event,
102
+ ).set_visible(submit_button)
103
+ button_row.append(self.submit_button)
91
104
 
92
- if button_row:
93
- layout.append(button_row)
105
+ if space_over_buttons:
106
+ layout.append([Spacer(height=space_over_buttons)])
107
+ elif space_between_rows:
108
+ layout.append([Spacer(height=space_between_rows)])
109
+
110
+ layout.append(button_row)
94
111
 
95
112
  super().__init__(
96
113
  layout,
@@ -102,6 +119,18 @@ class Form(BaseCombinedElement):
102
119
  if default_values is not None:
103
120
  self.set_value(default_values)
104
121
 
122
+ def _update_special_key(self,key:str,new_val:Any) -> bool|None:
123
+ match key:
124
+ case "clear_button_text":
125
+ self.clear_button.set_value(new_val)
126
+ case "submit_button_text":
127
+ self.submit_button.set_value(new_val)
128
+
129
+ case _:
130
+ return super()._update_special_key(key, new_val)
131
+
132
+ return True
133
+
105
134
  def _make_row(self, text: str, key: Hashable = None, text_len: int = 20) -> list[BaseElement]:
106
135
  """
107
136
  Create a single row of elements
@@ -128,15 +157,32 @@ class Form(BaseCombinedElement):
128
157
  ]
129
158
 
130
159
  if self._small_clear_buttons:
131
- row.append(Button(
160
+ button = Button(
132
161
  text= "x",
133
162
  width=2,
134
163
  key_function= lambda: input_elem.set_value("", throw_event=True),
135
164
  takefocus= False,
136
- ))
165
+ )
166
+ row.append(button)
167
+ self._small_clear_button_elements.append(button)
137
168
 
138
169
  return row
139
170
 
171
+ def __getitem__(self, item: Hashable | int) -> str:
172
+ assert self._mapping_mode or isinstance(item, int), f"{repr(self)} is created in list-mode, so only integer indexes can be used as key!"
173
+
174
+ return self.value[item]
175
+
176
+ def __setitem__(self, key: Hashable | int, value):
177
+ assert self._mapping_mode or isinstance(key, int), f"{repr(self)} is created in list-mode, so only integer indexes can be used as key!"
178
+
179
+ if self._mapping_mode:
180
+ if not key in self.v:
181
+ raise KeyError(f"{repr(self)} was given a key that it doesn't contain")
182
+ self.v[key] = value
183
+ else:
184
+ self._input_elements[key].value = value
185
+
140
186
  @BaseCombinedElement._run_after_window_creation
141
187
  def set_value(self, val: Iterable | Mapping) -> Self:
142
188
  """
@@ -150,7 +196,9 @@ class Form(BaseCombinedElement):
150
196
  for value, elem in zip(val, self._input_elements):
151
197
  elem.value = value
152
198
 
153
- def values(self) -> tuple:
199
+ return self
200
+
201
+ def as_tuple(self) -> tuple:
154
202
  """
155
203
  Return a tuple with all form-values one after the other
156
204
  :return:
@@ -158,10 +206,10 @@ class Form(BaseCombinedElement):
158
206
  return tuple(map(lambda a:a.value, self._input_elements))
159
207
 
160
208
  def _get_value(self):
161
- if self._has_key_mapping:
209
+ if self._mapping_mode:
162
210
  return super()._get_value()
163
211
 
164
- return self.values()
212
+ return self.as_tuple()
165
213
 
166
214
  @BaseElement._run_after_window_creation
167
215
  def update_texts(self,**kwargs) -> Self:
@@ -177,7 +225,7 @@ class Form(BaseCombinedElement):
177
225
  @BaseElement._run_after_window_creation
178
226
  def update_inputs(self,**kwargs) -> Self:
179
227
  """
180
- Evoke .update on every text-element
228
+ Evoke .update on every input-element
181
229
  :param kwargs:
182
230
  :return:
183
231
  """
@@ -185,7 +233,18 @@ class Form(BaseCombinedElement):
185
233
  elem._update_initial(**kwargs)
186
234
  return self
187
235
 
188
- def clear_all_values(self, throw_default_event: bool = False):
236
+ @BaseElement._run_after_window_creation
237
+ def update_small_clear_buttons(self,**kwargs) -> Self:
238
+ """
239
+ Evoke .update on every input-element
240
+ :param kwargs:
241
+ :return:
242
+ """
243
+ for elem in self._small_clear_button_elements:
244
+ elem._update_initial(**kwargs)
245
+ return self
246
+
247
+ def clear_all_values(self, throw_default_event: bool = False) -> Self:
189
248
  """
190
249
  Does what it says
191
250
  :return:
@@ -196,13 +255,15 @@ class Form(BaseCombinedElement):
196
255
  if throw_default_event:
197
256
  self.throw_default_event()
198
257
 
199
- def set_focus(self):
258
+ return self
259
+
260
+ def set_focus(self) -> Self:
200
261
  """
201
262
  Focus the first row of this element
202
263
  :return:
203
264
  """
204
265
  self._input_elements[0].set_focus()
205
-
266
+ return self
206
267
 
207
268
 
208
269