psiutils 0.2.19__py3-none-any.whl → 0.2.22__py3-none-any.whl

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.
psiutils/_date_picker.py CHANGED
@@ -1,8 +1,9 @@
1
+
2
+ from functools import partial
1
3
  import tkinter as tk
2
4
  from tkinter import ttk
3
5
  import tkinter.font as tkFont
4
6
  from tkcalendar import DateEntry
5
- from functools import partial
6
7
  from datetime import datetime, timedelta
7
8
  from dateutil.parser import parse
8
9
 
@@ -15,7 +16,7 @@ TIME_WIDTH = 3
15
16
  INCREMENT_BUTTON_SIZE = 2
16
17
  INCREMENT_BUTTON_FONT_SIZE = 8
17
18
  DATE_FORMAT = '%d/%m/%Y'
18
- PICKER_DATE_PATTERN = 'dd/mm/yyyy',
19
+ PICKER_DATE_PATTERN = 'dd/mm/yyyy'
19
20
  MAX_HOURS = 23
20
21
  MAX_MINS = 59
21
22
  TALL_COMBO_PADDING = 6
psiutils/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.2.19'
1
+ __version__ = '0.2.22'
psiutils/buttons.py CHANGED
@@ -257,6 +257,7 @@ icon_buttons = {
257
257
  'start': (txt.START, 'start'),
258
258
  'update': (txt.UPDATE, 'update'),
259
259
  'upgrade': (txt.UPGRADE, 'upgrade'),
260
+ 'upload': (txt.UPLOAD, 'upload'),
260
261
  'use': (txt.USE, 'done'),
261
262
  'windows': (txt.WINDOWS, 'windows'),
262
263
  }
Binary file
Binary file
Binary file
psiutils/text.py CHANGED
@@ -54,6 +54,7 @@ psi_strings = {
54
54
  'START': 'Start',
55
55
  'UPDATE': 'Update',
56
56
  'UPGRADE': 'Upgrade',
57
+ 'UPLOAD': 'Upload',
57
58
  'USE': 'Use',
58
59
  'WINDOWS': 'Windows',
59
60
  'YES': 'Yes',
psiutils/treeview.py CHANGED
@@ -1,10 +1,12 @@
1
1
 
2
+ from pathlib import Path
3
+ import tkinter as tk
2
4
  from tkinter import ttk
3
5
  import dateutil # type: ignore
4
6
  from dateutil.parser import parse # type: ignore
7
+ from PIL import Image, ImageTk
5
8
 
6
- UNCHECKED = '\u2610'
7
- CHECKED = '\u2612'
9
+ CHECK_BOX_SIZE = (20, 20)
8
10
 
9
11
 
10
12
  def sort_treeview(tree: ttk.Treeview, col: int, reverse: bool) -> None:
@@ -39,47 +41,109 @@ def sort_treeview(tree: ttk.Treeview, col: int, reverse: bool) -> None:
39
41
 
40
42
 
41
43
  class CheckTreeView(ttk.Treeview):
42
- def __init__(self, master=None, width=200, clicked=None,
43
- unchecked=UNCHECKED, checked=CHECKED, **kwargs):
44
+ def __init__(
45
+ self,
46
+ master,
47
+ column_defs,
48
+ **kwargs):
44
49
  """
45
- :param width: the width of the check list
46
- :param clicked: the optional function if a checkbox is clicked. Takes a
47
- `iid` parameter.
48
- :param unchecked: the character for an unchecked box (default is
49
- "\u2610")
50
- :param unchecked: the character for a checked box (default is "\u2612")
51
50
 
51
+ :param column_defs: a tuple defining column (key, text, width)
52
52
  Other parameters are passed to the `TreeView`.
53
53
  """
54
+ super().__init__(master, **kwargs)
55
+ self.column_defs = column_defs
56
+ self["show"] = "tree headings"
57
+ self._configure_columns()
58
+
59
+ (
60
+ self.unchecked_image,
61
+ self.checked_image
62
+ ) = self._get_checkbox_images()
63
+
54
64
  if "selectmode" not in kwargs:
55
65
  kwargs["selectmode"] = "none"
56
66
  if "show" not in kwargs:
57
67
  kwargs["show"] = "tree"
58
- ttk.Treeview.__init__(self, master, **kwargs)
59
- self.number_selected = 0
60
68
 
61
- def item_click(self, pos_x: int, pos_y: int) -> int:
62
- element = self.identify("element", pos_x, pos_y)
63
- if element == "text":
64
- iid = self.identify_row(pos_y)
65
- self._toggle(iid)
66
- return self.number_selected
69
+ def _get_checkbox_images(
70
+ self) -> tuple[ImageTk.PhotoImage, ImageTk.PhotoImage]:
71
+
72
+ icon_path = f'{Path(__file__).parent}/icons/'
73
+ unchecked_img = Image.open(f"{icon_path}checkbox_unchecked.png")
74
+ unchecked_img = unchecked_img.resize(CHECK_BOX_SIZE, Image.LANCZOS)
75
+ unchecked = ImageTk.PhotoImage(unchecked_img)
76
+
77
+ checked_img = tk.PhotoImage(file=f"{icon_path}checkbox_checked.png")
78
+ checked_img = Image.open(f"{icon_path}checkbox_checked.png")
79
+ checked_img = checked_img.resize(CHECK_BOX_SIZE, Image.LANCZOS)
80
+ checked = ImageTk.PhotoImage(checked_img)
81
+ return (unchecked, checked)
82
+
83
+ def _configure_columns(self) -> None:
84
+ column_ids = [col[0] for col in self.column_defs]
85
+ self["columns"] = column_ids[1:]
86
+
87
+ # Configure each column
88
+ for index, (col_id, heading, width) in enumerate(self.column_defs):
89
+ if index == 0:
90
+ self.column(
91
+ "#0",
92
+ width=width,
93
+ minwidth=width,
94
+ stretch=False,
95
+ anchor="center")
96
+ self.heading("#0", text=heading)
97
+ else:
98
+ self.column(col_id, width=width, anchor="w", stretch=True)
99
+ self.heading(col_id, text=heading)
100
+
101
+ def populate(self, items: list[tuple], checked: bool = False) -> None:
102
+ self.delete(*self.get_children())
103
+ item_checked = (self.checked_image
104
+ if checked else self.unchecked_image)
105
+ for item in items:
106
+ iid = self.insert(
107
+ parent='',
108
+ index='end',
109
+ image=item_checked,
110
+ values=item
111
+ )
112
+ if checked:
113
+ self.item(iid, tags=("checked",))
114
+ else:
115
+ self.item(iid, tags=("unchecked"))
67
116
 
68
- def _toggle(self, iid):
117
+ def item_click(self, event) -> int:
118
+ iid = self.identify_row(event.y)
119
+ if not iid:
120
+ return
121
+
122
+ current_img = self.item(iid, "image")[0]
123
+ if current_img == str(self.unchecked_image):
124
+ self.item(iid, image=self.checked_image, tags=("checked",))
125
+ else:
126
+ self.item(iid, image=self.unchecked_image, tags=("unchecked"))
127
+
128
+ return "break"
129
+
130
+ def checked_items(self) -> list[tuple]:
69
131
  """
70
- Toggle the checkbox `iid`
132
+ Returns a list of the values (text columns) for all currently
133
+ checked rows.
134
+
135
+ Each returned tuple contains the values from the data columns only
136
+ (excludes the checkbox image in the tree column).
137
+
138
+ Example return value:
139
+ [("docs", "report.pdf", "Read this file"),
140
+ ("code", "main.py", "Fix bug")]
71
141
  """
72
- values = list(self.item(iid).values())[2]
73
- new_value = UNCHECKED
74
- number = -1
75
- if values[0] == UNCHECKED:
76
- new_value = CHECKED
77
- number = 1
78
- values = [new_value] + list(values[1:])
79
- self.item(iid, values=values)
80
- self.number_selected = self.number_selected + number
81
-
82
- def populate(self, items: list[tuple]) -> None:
83
- for item in items:
84
- values = [UNCHECKED] + list(item)
85
- self.insert('', 'end', values=values)
142
+ checked_items = []
143
+
144
+ for iid in self.get_children(''):
145
+ tags = self.item(iid, "tags")
146
+ if "checked" in tags:
147
+ values = self.item(iid, "values")
148
+ checked_items.append(values)
149
+ return checked_items
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: psiutils
3
- Version: 0.2.19
3
+ Version: 0.2.22
4
4
  Summary: Various TKinter utilities.
5
5
  Author: Jeff
6
6
  Author-email: Jeff <<jeffwatkins2000@gmail.com>>
@@ -1,10 +1,10 @@
1
1
  psiutils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  psiutils/_about_frame.py,sha256=Ei9RMja36x2Xc9SecCXnqXd9EzDe1LIHq4ZDDbKtc_I,7656
3
- psiutils/_date_picker.py,sha256=Db6r-NCbNHQCXiXlu4RFB-C4T_1Cn597FQvKWHjGFjU,6228
3
+ psiutils/_date_picker.py,sha256=7frDxqBu0_JAiieCgISh5e0htQQwA9wdraOH3WwkqWo,6228
4
4
  psiutils/_logger.py,sha256=9nXxKWUyu4xqIILjTSUKRAMOG4cFy_EGJTTo0FtUAGU,2859
5
5
  psiutils/_notify.py,sha256=rQfYxPxsSwAEJBNXaAZSNlRmZLWB1sah1E1Oja9y-mw,437
6
- psiutils/_version.py,sha256=03OfPLthYtC55XCorTutkAl4vnGLWEzy16PIUJHl7C8,22
7
- psiutils/buttons.py,sha256=KOHBSH5_PgArG5T0hMU8weM30C97Hp3Wqco7emiBn0Y,8851
6
+ psiutils/_version.py,sha256=De4-ZBTkg15yQWcmhABmI639YXbl5ed1kdRnlGDHXuc,22
7
+ psiutils/buttons.py,sha256=OMUy7gCrT_bWl_UbPuW28PhAm9Akh5_aQqsNk2kshkU,8889
8
8
  psiutils/constants.py,sha256=AJOw73GL9Rx9BEmfduTy32S3dM3Rp6iIOYALY0J7JSw,1541
9
9
  psiutils/drag_manager.py,sha256=L04GzKIinWXzGCawvTnn18F1AEt8PUPS1U-HqCVrh48,3470
10
10
  psiutils/errors.py,sha256=tAypFkpzpbeOppO9zKQimlnRVyr3sMPoiwh0yK3Yc88,562
@@ -13,6 +13,8 @@ psiutils/icons/backup.png,sha256=kKL5xewG83RQMTr4piNf8SEPNlhHUUtqqcizBuwWU2U,717
13
13
  psiutils/icons/build.png,sha256=MgQS4yPxfa5EBXCF5gXu2S6vqjUsRBhR4S6vCzOtrzQ,1169
14
14
  psiutils/icons/cancel.png,sha256=O2YSv7wxSV5rhT1WiZ9McqO3pilCKNfZdJNwQceH87E,2168
15
15
  psiutils/icons/check.png,sha256=8KqO0lWJvhcbSx1KI8QKfCkwLsszzotL9iBrXfwyf1Q,748
16
+ psiutils/icons/checkbox_checked.png,sha256=TOcYTFLrXEerPSeMA0aCUulvHIVuqfe_uQra7AWEN5o,525
17
+ psiutils/icons/checkbox_unchecked.png,sha256=vmaVN0ir9vWVxLQ4nuqIqqvn3zNIch4Gk7NnNcWYrvI,317
16
18
  psiutils/icons/clear.png,sha256=UwO_Sf8ZCJro1ymtVA4T3XwWIbkQd-hr_dv0J8EaBxA,859
17
19
  psiutils/icons/code.png,sha256=en7AOAITRFfsULX6WVU-nxY9LDEORVGsFVqXDXRqIG0,953
18
20
  psiutils/icons/compare.png,sha256=7wEoI2Os7gGU8t1mwlJ5lKDZXkgkLyJRcs0dMyHyo1Q,565
@@ -47,6 +49,7 @@ psiutils/icons/send.png,sha256=4PSUVt8NAKLIxYEYpdMQHNigmfjyUSL8VAsMBmBxxmM,968
47
49
  psiutils/icons/start.png,sha256=lzi6occJJXKXlRoFjx76h1YhQy2lLk9IqCf-xDKadDc,1936
48
50
  psiutils/icons/update.png,sha256=buOCd1Mq5M8Jbcd2HX6eZjLAQPxM5psFTGNqkkI7c7c,2212
49
51
  psiutils/icons/upgrade.png,sha256=kvoT7pwvQGoQIL0AjvbTIx6TTfvw2JjdHv23QxY1I1Y,1201
52
+ psiutils/icons/upload.png,sha256=Vd5Wvk4anJsbPdnkVKgmbWB5FT-xpARsD5zAZtj15S8,587
50
53
  psiutils/icons/windows.png,sha256=orrq_I9aYHMcUJHdtfLWbAEJZwzPjja9VMwZPm9jsjg,2264
51
54
  psiutils/images/icon-error.png,sha256=Fk1IMjyqXACUbfcCGTHM-Q1Gb_53hzzyRGO1JbxgNB8,5957
52
55
  psiutils/images/icon-info.png,sha256=JFCbGkYfO1BD7VRYQXmTMjOePPRrwjkl-KSFHtKIBE4,5979
@@ -54,10 +57,10 @@ psiutils/images/icon-query.png,sha256=e18hqkew4eOxABvECKn7BGO2VTHTE-XLMWPSQfSW9d
54
57
  psiutils/known_paths.py,sha256=Ydhk-Ie_q827ti35Hru8YwUx5awdO2FEG845k1N0hPo,9543
55
58
  psiutils/menus.py,sha256=4pUHb3fEYzLnsftxdKB_NjlPryj_pu7WN5Iy5Quy9-M,1746
56
59
  psiutils/messagebox.py,sha256=ODFodaDahAm31A8M4MVp9FXdhI0zhW8PZdUbBqbVQEY,4973
57
- psiutils/text.py,sha256=zp46Pfyhyqwwo8MeZMMBeLGCT3meRjmdcbTZqF0IxqE,3206
58
- psiutils/treeview.py,sha256=jtSzLWrnFIBDWV5YhWNRoZwgW-Kj8_7XVqZyusr-riQ,2826
60
+ psiutils/text.py,sha256=wo8iZLd979SQHy3wq5jjIt0URel5G1ze53HQ5XLfuBE,3230
61
+ psiutils/treeview.py,sha256=zQfSvjQaBhNnyAoNIivAteYFVs8NPgU-i9PN4SvwvQo,4899
59
62
  psiutils/utilities.py,sha256=hBntrigp7WiuzRoGGhS96QVE-7pF2OdYT882jwMTrlQ,3355
60
63
  psiutils/widgets.py,sha256=haHVcsm4Y9gYQinr0VlrfHg2H83Pnlj_jxjb4aXd37A,11420
61
- psiutils-0.2.19.dist-info/WHEEL,sha256=e_m4S054HL0hyR3CpOk-b7Q7fDX6BuFkgL5OjAExXas,80
62
- psiutils-0.2.19.dist-info/METADATA,sha256=YRPX8Vcs3MqE2STtI_q3ARFuFcgraRMzvN1PwdGLDm4,2109
63
- psiutils-0.2.19.dist-info/RECORD,,
64
+ psiutils-0.2.22.dist-info/WHEEL,sha256=fAguSjoiATBe7TNBkJwOjyL1Tt4wwiaQGtNtjRPNMQA,80
65
+ psiutils-0.2.22.dist-info/METADATA,sha256=ZbIuXlnyzTifyPV3tijJRnfIdEdW2jbdfeZbO1shPSI,2109
66
+ psiutils-0.2.22.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.9.27
2
+ Generator: uv 0.9.28
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any