psiutils 0.2.34__tar.gz → 0.2.35__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 (72) hide show
  1. {psiutils-0.2.34 → psiutils-0.2.35}/PKG-INFO +2 -1
  2. {psiutils-0.2.34 → psiutils-0.2.35}/pyproject.toml +15 -1
  3. psiutils-0.2.35/src/psiutils/_version.py +1 -0
  4. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/buttons.py +121 -59
  5. psiutils-0.2.35/src/psiutils/icons/paste.png +0 -0
  6. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/text.py +1 -0
  7. psiutils-0.2.34/src/psiutils/_version.py +0 -1
  8. {psiutils-0.2.34 → psiutils-0.2.35}/README.md +0 -0
  9. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/__init__.py +0 -0
  10. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/_about_frame.py +0 -0
  11. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/_logger.py +0 -0
  12. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/_notify.py +0 -0
  13. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/_scrolling_canvas.py +0 -0
  14. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/constants.py +0 -0
  15. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/date_picker.py +0 -0
  16. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/drag_manager.py +0 -0
  17. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/errors.py +0 -0
  18. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icecream_init.py +0 -0
  19. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/backup.png +0 -0
  20. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/build.png +0 -0
  21. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/cancel.png +0 -0
  22. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/check.png +0 -0
  23. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/checkbox_checked.png +0 -0
  24. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/checkbox_unchecked.png +0 -0
  25. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/clear.png +0 -0
  26. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/code.png +0 -0
  27. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/compare.png +0 -0
  28. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/convert.png +0 -0
  29. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/copy_clipboard.png +0 -0
  30. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/copy_docs.png +0 -0
  31. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/delete.png +0 -0
  32. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/diff.png +0 -0
  33. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/done.png +0 -0
  34. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/download.png +0 -0
  35. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/edit.png +0 -0
  36. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/gear.png +0 -0
  37. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/help.png +0 -0
  38. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/new.png +0 -0
  39. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/next.png +0 -0
  40. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/open.png +0 -0
  41. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/pause.png +0 -0
  42. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/preferences.png +0 -0
  43. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/previous.png +0 -0
  44. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/process.png +0 -0
  45. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/redo.png +0 -0
  46. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/refresh.png +0 -0
  47. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/rename.png +0 -0
  48. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/report.png +0 -0
  49. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/reset.png +0 -0
  50. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/restore.png +0 -0
  51. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/restore_database.png +0 -0
  52. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/restore_page.png +0 -0
  53. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/revert.png +0 -0
  54. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/run.png +0 -0
  55. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/save.png +0 -0
  56. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/script.png +0 -0
  57. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/search.png +0 -0
  58. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/send.png +0 -0
  59. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/start.png +0 -0
  60. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/update.png +0 -0
  61. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/upgrade.png +0 -0
  62. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/upload.png +0 -0
  63. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/icons/windows.png +0 -0
  64. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/images/icon-error.png +0 -0
  65. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/images/icon-info.png +0 -0
  66. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/images/icon-query.png +0 -0
  67. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/known_paths.py +0 -0
  68. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/menus.py +0 -0
  69. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/messagebox.py +0 -0
  70. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/treeview.py +0 -0
  71. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/utilities.py +0 -0
  72. {psiutils-0.2.34 → psiutils-0.2.35}/src/psiutils/widgets.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: psiutils
3
- Version: 0.2.34
3
+ Version: 0.2.35
4
4
  Summary: Various TKinter utilities.
5
5
  Author: Jeff
6
6
  Author-email: Jeff <<jeffwatkins2000@gmail.com>>
@@ -15,6 +15,7 @@ Requires-Dist: psiconfig>=0.0.14
15
15
  Requires-Dist: pycairo>=1.28.0
16
16
  Requires-Dist: pygments>=2.19.2
17
17
  Requires-Dist: pytest>=9.0.2
18
+ Requires-Dist: ruff>=0.15.15
18
19
  Requires-Dist: structlog>=25.4.0
19
20
  Requires-Dist: tkcalendar>=1.6.1
20
21
  Requires-Dist: tkinterweb>=4.4.4
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "psiutils"
3
- version = "0.2.34"
3
+ version = "0.2.35"
4
4
  description = "Various TKinter utilities."
5
5
  authors = [{name = "Jeff", "email" = "<jeffwatkins2000@gmail.com>"}]
6
6
  requires-python = '>= 3.10, < 3.13'
@@ -20,6 +20,7 @@ dependencies = [
20
20
  "pycairo>=1.28.0",
21
21
  "pygments>=2.19.2",
22
22
  "pytest>=9.0.2",
23
+ "ruff>=0.15.15",
23
24
  "structlog>=25.4.0",
24
25
  "tkcalendar>=1.6.1",
25
26
  "tkinterweb>=4.4.4",
@@ -40,3 +41,16 @@ dev = ['pytest']
40
41
  [build-system]
41
42
  requires = ['uv-build']
42
43
  build-backend = 'uv_build'
44
+
45
+ # pyproject.toml
46
+ [tool.ruff]
47
+ line-length = 79
48
+ target-version = "py311"
49
+
50
+ [tool.ruff.lint]
51
+ select = ["E", "F", "I", "N", "W", "B", "UP"]
52
+
53
+ [tool.mypy]
54
+ python_version = "3.11"
55
+ warn_return_any = true
56
+ disallow_untyped_defs = true
@@ -0,0 +1 @@
1
+ __version__ = '0.2.35'
@@ -1,44 +1,60 @@
1
1
  """Button class for Tkinter applications."""
2
2
 
3
3
  import tkinter as tk
4
- from tkinter import ttk
4
+ from dataclasses import dataclass
5
5
  from pathlib import Path
6
- from PIL import Image, ImageTk
6
+ from tkinter import ttk
7
7
 
8
- from psiutils.text import Text
8
+ from PIL import Image, ImageTk
9
9
 
10
10
  from psiutils.constants import PAD, Pad
11
- from psiutils.widgets import enter_widget, clickable_widget, HAND
11
+ from psiutils.text import Text
12
+ from psiutils.widgets import HAND, clickable_widget, enter_widget
12
13
 
13
14
  txt = Text()
14
15
 
16
+ COLOURS = {
17
+ "red": (255, 0, 0),
18
+ "blue": (0, 0, 255),
19
+ "green": (0, 160, 20),
20
+ "orange": (212, 100, 50),
21
+ }
22
+
23
+
24
+ @dataclass(slots=True)
25
+ class IconButtonConfig:
26
+ text: str
27
+ icon: str
28
+ colour: str | None = None
29
+
15
30
 
16
31
  class IconButton(ttk.Frame):
17
32
  def __init__(
18
33
  self,
19
34
  master,
20
- button_text,
35
+ text,
21
36
  icon,
22
37
  command=None,
23
38
  dimmable: bool = False,
24
39
  sticky: str = "",
25
40
  icon_path: str = "",
41
+ colour: str | tuple(int) = "",
26
42
  **kwargs,
27
43
  ):
28
44
  super().__init__(master, borderwidth=1, relief="raised", **kwargs)
29
45
  self.command = command
30
46
  self._state = tk.NORMAL
31
- self.text = button_text
47
+ self.text = text
32
48
  self.icon = icon
49
+ self.colour = colour
33
50
 
34
51
  # Icon and text
35
52
  if not icon_path:
36
53
  icon_path = f"{Path(__file__).parent}/icons/"
37
- image = Image.open(f"{icon_path}{icon}.png").resize((16, 16))
38
- photo_image = ImageTk.PhotoImage(image)
54
+ photo_image = self._get_photo_image(icon_path, icon)
39
55
 
40
56
  self.button_label = ttk.Label(
41
- self, text=button_text, image=photo_image, compound=tk.LEFT
57
+ self, text=text, image=photo_image, compound=tk.LEFT
42
58
  )
43
59
  self.button_label.image = photo_image # Prevent garbage collection
44
60
  self.button_label.pack(padx=(3, 5), pady=5)
@@ -50,6 +66,38 @@ class IconButton(ttk.Frame):
50
66
  self.sticky = sticky
51
67
  self.dimmable = dimmable
52
68
 
69
+ def _get_photo_image(
70
+ self,
71
+ path: Path,
72
+ icon: str,
73
+ ) -> ImageTk.PhotoImage:
74
+ image = (
75
+ Image.open(f"{path}{icon}.png").resize((16, 16)).convert("RGBA")
76
+ )
77
+
78
+ image = self._colour_image(image)
79
+
80
+ photo_image = ImageTk.PhotoImage(image)
81
+ return photo_image
82
+
83
+ def _colour_image(self, image: Image) -> Image:
84
+ if not self.colour:
85
+ return image
86
+
87
+ if isinstance(self.colour, str):
88
+ r, g, b = COLOURS[self.colour]
89
+
90
+ if isinstance(self.colour, tuple):
91
+ r, g, b = self.colour
92
+
93
+ pixels = image.load()
94
+
95
+ for y in range(image.size[1]):
96
+ for x in range(image.size[0]):
97
+ _, _, _, a = pixels[x, y]
98
+ pixels[x, y] = (r, g, b, a)
99
+ return image
100
+
53
101
  def __repr__(self) -> str:
54
102
  return f"IconButton: {self.text} {self.icon}"
55
103
 
@@ -109,7 +157,10 @@ class Button(ttk.Button):
109
157
 
110
158
  class ButtonFrame(ttk.Frame):
111
159
  def __init__(
112
- self, master: tk.Frame, orientation: str = tk.HORIZONTAL, **kwargs: dict
160
+ self,
161
+ master: tk.Frame,
162
+ orientation: str = tk.HORIZONTAL,
163
+ **kwargs: dict,
113
164
  ) -> None:
114
165
  super().__init__(master, **kwargs)
115
166
  self._buttons = []
@@ -120,8 +171,10 @@ class ButtonFrame(ttk.Frame):
120
171
  self._enabled = kwargs["enabled"]
121
172
 
122
173
  self.icon_buttons = {
123
- name: IconButton(self, button[0], button[1])
124
- for name, button in icon_buttons.items()
174
+ name: IconButton(
175
+ self, config.text, config.icon, colour=config.colour
176
+ )
177
+ for name, config in icon_buttons.items()
125
178
  }
126
179
 
127
180
  def icon_button(
@@ -129,10 +182,13 @@ class ButtonFrame(ttk.Frame):
129
182
  id_: str,
130
183
  command: object = None,
131
184
  dimmable: bool = False,
185
+ text: str = "",
132
186
  ) -> IconButton:
133
187
  button = self.icon_buttons[id_]
134
188
  button.dimmable = dimmable
135
189
  button.command = command
190
+ if text:
191
+ button.text = text
136
192
  return button
137
193
 
138
194
  @property
@@ -219,52 +275,56 @@ def enable_buttons(buttons: list[Button], enable: bool = True):
219
275
 
220
276
 
221
277
  icon_buttons = {
222
- "backup": (txt.BACKUP, "backup"),
223
- "build": (txt.BUILD, "build"),
224
- "check": (txt.CHECK, "check"),
225
- "clear": (txt.CLEAR, "clear"),
226
- "close": (txt.CLOSE, "cancel"),
227
- "code": (txt.CODE, "code"),
228
- "compare": (txt.COMPARE, "compare"),
229
- "config": (txt.CONFIG, "gear"),
230
- "convert": (txt.CONVERT, "convert"),
231
- "copy_docs": (txt.COPY, "copy_docs"),
232
- "copy_clipboard": (txt.COPY, "copy_clipboard"),
233
- "delete": (txt.DELETE, "delete"),
234
- "download": (txt.DOWNLOAD, "download"),
235
- "diff": (txt.DIFF, "diff"),
236
- "done": (txt.DONE, "done"),
237
- "edit": (txt.EDIT, "edit"),
238
- "exit": (txt.EXIT, "cancel"),
239
- "help": (txt.HELP, "help"),
240
- "new": (txt.NEW, "new"),
241
- "next": (txt.NEXT, "next"),
242
- "open": (txt.OPEN, "open"),
243
- "pause": (txt.PAUSE, "pause"),
244
- "preferences": (txt.PREFERENCES, "preferences"),
245
- "previous": (txt.PREVIOUS, "previous"),
246
- "process": (txt.PROCESS, "process"),
247
- "redo": (txt.REDO, "redo"),
248
- "refresh": (txt.REFRESH, "refresh"),
249
- "rename": (txt.RENAME, "rename"),
250
- "report": (txt.REPORT, "report"),
251
- "reset": (txt.RESET, "reset"),
252
- "restore": (txt.RESTORE, "restore"),
253
- "restore_database": (txt.RESTORE, "restore_database"),
254
- "restore_page": (txt.RESTORE, "restore_page"),
255
- "revert": (txt.REVERT, "revert"),
256
- "run": (txt.RUN, "start"),
257
- "save": (txt.SAVE, "save"),
258
- "script": (txt.SCRIPT, "script"),
259
- "search": (txt.SEARCH, "search"),
260
- "send": (txt.SEND, "send"),
261
- "start": (txt.START, "start"),
262
- "undo": (txt.UNDO, "revert"),
263
- "update": (txt.UPDATE, "update"),
264
- "upgrade": (txt.UPGRADE, "upgrade"),
265
- "upload": (txt.UPLOAD, "upload"),
266
- "use": (txt.USE, "done"),
267
- "windows": (txt.WINDOWS, "windows"),
278
+ "backup": IconButtonConfig(txt.BACKUP, "backup"),
279
+ "build": IconButtonConfig(txt.BUILD, "build"),
280
+ "check": IconButtonConfig(txt.CHECK, "check"),
281
+ "clear": IconButtonConfig(txt.CLEAR, "clear"),
282
+ "close": IconButtonConfig(txt.CLOSE, "cancel"),
283
+ "close-red": IconButtonConfig(txt.CLOSE, "cancel", "red"),
284
+ "code": IconButtonConfig(txt.CODE, "code"),
285
+ "code-blue": IconButtonConfig(txt.CODE, "code", "blue"),
286
+ "compare": IconButtonConfig(txt.COMPARE, "compare"),
287
+ "compare-orange": IconButtonConfig(txt.COMPARE, "compare", "orange"),
288
+ "config": IconButtonConfig(txt.CONFIG, "gear"),
289
+ "convert": IconButtonConfig(txt.CONVERT, "convert"),
290
+ "copy_docs": IconButtonConfig(txt.COPY, "copy_docs"),
291
+ "copy_clipboard": IconButtonConfig(txt.COPY, "copy_clipboard"),
292
+ "delete": IconButtonConfig(txt.DELETE, "delete"),
293
+ "download": IconButtonConfig(txt.DOWNLOAD, "download"),
294
+ "diff": IconButtonConfig(txt.DIFF, "diff"),
295
+ "done": IconButtonConfig(txt.DONE, "done"),
296
+ "edit": IconButtonConfig(txt.EDIT, "edit"),
297
+ "exit": IconButtonConfig(txt.EXIT, "cancel"),
298
+ "exit-red": IconButtonConfig(txt.EXIT, "cancel", "red"),
299
+ "exit-orange": IconButtonConfig(txt.EXIT, "cancel", "orange"),
300
+ "new": IconButtonConfig(txt.NEW, "new"),
301
+ "next": IconButtonConfig(txt.NEXT, "next"),
302
+ "open": IconButtonConfig(txt.OPEN, "open"),
303
+ "paste": IconButtonConfig(txt.PASTE, "paste"),
304
+ "pause": IconButtonConfig(txt.PAUSE, "pause"),
305
+ "preferences": IconButtonConfig(txt.PREFERENCES, "preferences"),
306
+ "previous": IconButtonConfig(txt.PREVIOUS, "previous"),
307
+ "process": IconButtonConfig(txt.PROCESS, "process"),
308
+ "redo": IconButtonConfig(txt.REDO, "redo"),
309
+ "refresh": IconButtonConfig(txt.REFRESH, "refresh"),
310
+ "rename": IconButtonConfig(txt.RENAME, "rename"),
311
+ "report": IconButtonConfig(txt.REPORT, "report"),
312
+ "reset": IconButtonConfig(txt.RESET, "reset"),
313
+ "restore": IconButtonConfig(txt.RESTORE, "restore"),
314
+ "restore_database": IconButtonConfig(txt.RESTORE, "restore_database"),
315
+ "restore_page": IconButtonConfig(txt.RESTORE, "restore_page"),
316
+ "revert": IconButtonConfig(txt.REVERT, "revert"),
317
+ "run": IconButtonConfig(txt.RUN, "start"),
318
+ "save": IconButtonConfig(txt.SAVE, "save"),
319
+ "script": IconButtonConfig(txt.SCRIPT, "script"),
320
+ "search": IconButtonConfig(txt.SEARCH, "search"),
321
+ "send": IconButtonConfig(txt.SEND, "send"),
322
+ "start": IconButtonConfig(txt.START, "start"),
323
+ "update": IconButtonConfig(txt.UPDATE, "update"),
324
+ "upgrade": IconButtonConfig(txt.UPGRADE, "upgrade"),
325
+ "upload": IconButtonConfig(txt.UPLOAD, "upload"),
326
+ "use": IconButtonConfig(txt.USE, "done"),
327
+ "windows": IconButtonConfig(txt.WINDOWS, "windows"),
268
328
  }
269
329
 
270
330
 
@@ -272,7 +332,9 @@ def list_icon_buttons() -> None:
272
332
  """List of icon_button."""
273
333
  name_length, text_length, icon_length = 15, 10, 15
274
334
 
275
- print((f"{'name':<{name_length}} {'text':<{text_length}} {'icon':<{icon_length}}"))
335
+ print(
336
+ f"{'name':<{name_length}} {'text':<{text_length}} {'icon':<{icon_length}}"
337
+ )
276
338
 
277
339
  print(
278
340
  f"{'-' * name_length:<{name_length}} "
@@ -34,6 +34,7 @@ psi_strings = {
34
34
  "NO_SUCH_FILE": "no such file or directory",
35
35
  "OK": "OK",
36
36
  "OPEN": "Open",
37
+ "PASTE": "Paste",
37
38
  "PAUSE": "Pause",
38
39
  "PREFERENCES": "Preferences",
39
40
  "PREVIOUS": "Prev",
@@ -1 +0,0 @@
1
- __version__ = '0.2.34'
File without changes