CTkScrollableDropdownPP 2.0.2__tar.gz → 2.0.4__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.
- {ctkscrollabledropdownpp-2.0.2 → ctkscrollabledropdownpp-2.0.4}/CTkScrollableDropdownPP/ctk_scrollable_dropdown.py +57 -41
- {ctkscrollabledropdownpp-2.0.2 → ctkscrollabledropdownpp-2.0.4}/CTkScrollableDropdownPP.egg-info/PKG-INFO +18 -8
- {ctkscrollabledropdownpp-2.0.2 → ctkscrollabledropdownpp-2.0.4}/PKG-INFO +18 -8
- {ctkscrollabledropdownpp-2.0.2 → ctkscrollabledropdownpp-2.0.4}/README.md +17 -7
- {ctkscrollabledropdownpp-2.0.2 → ctkscrollabledropdownpp-2.0.4}/pyproject.toml +1 -1
- {ctkscrollabledropdownpp-2.0.2 → ctkscrollabledropdownpp-2.0.4}/CTkScrollableDropdownPP/__init__.py +0 -0
- {ctkscrollabledropdownpp-2.0.2 → ctkscrollabledropdownpp-2.0.4}/CTkScrollableDropdownPP.egg-info/SOURCES.txt +0 -0
- {ctkscrollabledropdownpp-2.0.2 → ctkscrollabledropdownpp-2.0.4}/CTkScrollableDropdownPP.egg-info/dependency_links.txt +0 -0
- {ctkscrollabledropdownpp-2.0.2 → ctkscrollabledropdownpp-2.0.4}/CTkScrollableDropdownPP.egg-info/requires.txt +0 -0
- {ctkscrollabledropdownpp-2.0.2 → ctkscrollabledropdownpp-2.0.4}/CTkScrollableDropdownPP.egg-info/top_level.txt +0 -0
- {ctkscrollabledropdownpp-2.0.2 → ctkscrollabledropdownpp-2.0.4}/LICENSE +0 -0
- {ctkscrollabledropdownpp-2.0.2 → ctkscrollabledropdownpp-2.0.4}/setup.cfg +0 -0
|
@@ -4,13 +4,13 @@ import re
|
|
|
4
4
|
|
|
5
5
|
class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
6
6
|
|
|
7
|
-
def __init__(self, attach, x=None, y=None, button_color=None, height: int =
|
|
7
|
+
def __init__(self, attach, x=None, y=None, button_color=None, height: int = None, width: int = None,
|
|
8
8
|
fg_color=None, button_height: int = 20, justify="center", scrollbar_button_color=None,
|
|
9
9
|
scrollbar=True, scrollbar_button_hover_color=None, frame_border_width=0, values=[],
|
|
10
10
|
command=None, image_values=[], alpha: float = 0.95, frame_corner_radius=20, double_click=False,
|
|
11
|
-
|
|
11
|
+
frame_border_color=None, text_color=None, autocomplete=False,
|
|
12
12
|
hover_color=None, pagination: bool = True, items_per_page: int = 50,
|
|
13
|
-
groups=None, **button_kwargs):
|
|
13
|
+
groups=None, font=("Segoe UI", 12), **button_kwargs):
|
|
14
14
|
super().__init__(master=attach.winfo_toplevel(), takefocus=1)
|
|
15
15
|
|
|
16
16
|
self.group_patterns = None
|
|
@@ -37,18 +37,20 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
37
37
|
self.current_page = 0
|
|
38
38
|
self.filtered_values = None
|
|
39
39
|
self.current_group = 0
|
|
40
|
+
self.font = font
|
|
40
41
|
self.groups = []
|
|
42
|
+
|
|
41
43
|
if groups is not None:
|
|
42
44
|
for g in groups:
|
|
43
45
|
if isinstance(g, (list, tuple)) and len(g) >= 2:
|
|
44
46
|
self.groups.append({"name": g[0], "pattern": g[1]})
|
|
45
47
|
else:
|
|
46
48
|
raise ValueError(f"groups must be a list of [name, pattern], got {g!r}")
|
|
47
|
-
|
|
49
|
+
|
|
48
50
|
self.group_names = [g["name"] for g in self.groups]
|
|
49
51
|
self.group_patterns = []
|
|
50
52
|
included_values = set()
|
|
51
|
-
|
|
53
|
+
|
|
52
54
|
for g in self.groups:
|
|
53
55
|
pattern = g["pattern"]
|
|
54
56
|
if pattern == "__OTHERS__":
|
|
@@ -58,14 +60,14 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
58
60
|
self.group_patterns.append(compiled)
|
|
59
61
|
matched = [v for v in self.all_values if compiled.search(v)]
|
|
60
62
|
included_values.update(matched)
|
|
61
|
-
|
|
63
|
+
|
|
62
64
|
self.grouped_values = {}
|
|
63
65
|
for i, pat in enumerate(self.group_patterns):
|
|
64
66
|
if pat == "__OTHERS__":
|
|
65
67
|
self.grouped_values[i] = [v for v in self.all_values if v not in included_values]
|
|
66
68
|
else:
|
|
67
69
|
self.grouped_values[i] = [v for v in self.all_values if pat.search(v)]
|
|
68
|
-
|
|
70
|
+
|
|
69
71
|
if sys.platform.startswith("win"):
|
|
70
72
|
self.after(100, lambda: self.overrideredirect(True))
|
|
71
73
|
self.transparent_color = self._apply_appearance_mode(self._fg_color) if hasattr(self, '_fg_color') else "#FFFFFF"
|
|
@@ -101,15 +103,16 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
101
103
|
self.search_var = customtkinter.StringVar()
|
|
102
104
|
self.search_var.trace_add('write', lambda *args: self.live_update(self.search_var.get()))
|
|
103
105
|
self.search_entry = customtkinter.CTkEntry(self, textvariable=self.search_var)
|
|
104
|
-
self.search_entry.pack(fill="x")
|
|
106
|
+
self.search_entry.pack(fill="x", pady=(0, 5))
|
|
105
107
|
if self.groups:
|
|
106
|
-
self.group_frame = customtkinter.CTkFrame(self, fg_color=self.fg_color)
|
|
107
|
-
self.group_frame.pack(fill="x", padx=5)
|
|
108
|
+
self.group_frame = customtkinter.CTkFrame(self, fg_color=self.fg_color, bg_color=self.transparent_color)
|
|
109
|
+
self.group_frame.pack(fill="x", padx=5, pady=(0, 5))
|
|
108
110
|
self.group_buttons = []
|
|
109
111
|
for idx, name in enumerate(self.group_names):
|
|
110
112
|
btn = customtkinter.CTkButton(
|
|
111
113
|
self.group_frame,
|
|
112
114
|
text=name,
|
|
115
|
+
font=self.font,
|
|
113
116
|
height=button_height,
|
|
114
117
|
fg_color=self.button_color,
|
|
115
118
|
text_color=self.text_color,
|
|
@@ -130,7 +133,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
130
133
|
border_color=self.frame_border_color
|
|
131
134
|
)
|
|
132
135
|
self.frame._scrollbar.grid_configure(padx=3)
|
|
133
|
-
self.frame.pack(expand=True, fill="both")
|
|
136
|
+
self.frame.pack(expand=True, fill="both", pady=(3, 0))
|
|
134
137
|
if self.pagination:
|
|
135
138
|
self.button_container = customtkinter.CTkFrame(self.frame, fg_color=self.fg_color)
|
|
136
139
|
self.button_container.pack(expand=True, fill="both")
|
|
@@ -139,12 +142,14 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
139
142
|
else:
|
|
140
143
|
self.button_container = self.frame
|
|
141
144
|
self.dummy_entry = customtkinter.CTkEntry(self.frame, fg_color="transparent", border_width=0, height=1, width=1)
|
|
142
|
-
self.
|
|
143
|
-
|
|
145
|
+
self.is_height = bool(height)
|
|
146
|
+
if height is None:
|
|
147
|
+
self.height_new = attach.winfo_toplevel().winfo_height()
|
|
148
|
+
else:
|
|
149
|
+
self.height_new = height
|
|
144
150
|
self.width = width
|
|
145
151
|
self.command = command
|
|
146
152
|
self.fade = False
|
|
147
|
-
self.resize = resize
|
|
148
153
|
self.autocomplete = autocomplete
|
|
149
154
|
self.var_update = customtkinter.StringVar()
|
|
150
155
|
self.appear = True
|
|
@@ -185,19 +190,36 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
185
190
|
self._init_buttons()
|
|
186
191
|
|
|
187
192
|
def _on_group_frame_configure(self, event):
|
|
193
|
+
if not self.group_buttons:
|
|
194
|
+
return
|
|
195
|
+
|
|
188
196
|
min_btn_width = 100
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
197
|
+
n = len(self.group_buttons)
|
|
198
|
+
cols = max(1, min(n, event.width // min_btn_width))
|
|
199
|
+
rows = (n + cols - 1) // cols
|
|
200
|
+
|
|
201
|
+
frame_height = rows * self.button_height
|
|
202
|
+
if self.group_frame.winfo_height() != frame_height:
|
|
203
|
+
self.group_frame.configure(height=frame_height)
|
|
204
|
+
|
|
194
205
|
for idx, btn in enumerate(self.group_buttons):
|
|
195
206
|
row = idx // cols
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
207
|
+
col_in_row = idx % cols
|
|
208
|
+
row_start = row * cols
|
|
209
|
+
num_in_row = min(cols, n - row_start)
|
|
210
|
+
|
|
211
|
+
rel_width = 1.0 / num_in_row
|
|
212
|
+
rel_x = col_in_row * rel_width
|
|
213
|
+
rel_y = row / rows
|
|
214
|
+
rel_height = 1.0 / rows
|
|
215
|
+
|
|
216
|
+
btn.place(
|
|
217
|
+
in_=self.group_frame,
|
|
218
|
+
relx=rel_x,
|
|
219
|
+
rely=rel_y,
|
|
220
|
+
relwidth=rel_width,
|
|
221
|
+
relheight=rel_height
|
|
222
|
+
)
|
|
201
223
|
|
|
202
224
|
def switch_group(self, idx):
|
|
203
225
|
if idx == self.current_group:
|
|
@@ -214,7 +236,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
214
236
|
self.filtered_values = None
|
|
215
237
|
self.current_page = 0
|
|
216
238
|
self._init_buttons()
|
|
217
|
-
|
|
239
|
+
|
|
218
240
|
def update_buttons(self, values_list):
|
|
219
241
|
for i, value in enumerate(values_list):
|
|
220
242
|
if i in self.widgets:
|
|
@@ -226,7 +248,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
226
248
|
btn = customtkinter.CTkButton(
|
|
227
249
|
self.button_container,
|
|
228
250
|
text=value,
|
|
229
|
-
font=
|
|
251
|
+
font=self.font,
|
|
230
252
|
command=lambda v=value: self._attach_key_press(v),
|
|
231
253
|
height=self.button_height,
|
|
232
254
|
fg_color=self.button_color,
|
|
@@ -328,7 +350,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
328
350
|
self._update_pagination_buttons(filtered=bool(self.filtered_values))
|
|
329
351
|
self.frame.update_idletasks()
|
|
330
352
|
self.frame._parent_canvas.yview_moveto(len(values_to_show) / self.items_per_page)
|
|
331
|
-
|
|
353
|
+
|
|
332
354
|
def destroy_popup(self):
|
|
333
355
|
self.destroy()
|
|
334
356
|
self.disable = True
|
|
@@ -342,13 +364,8 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
342
364
|
current_y_pos = self.winfo_y()
|
|
343
365
|
self.x_pos = self.attach.winfo_rootx() if self.x is None else self.x + self.attach.winfo_rootx()
|
|
344
366
|
self.width_new = self.attach.winfo_width() if self.width is None else self.width
|
|
345
|
-
if self.
|
|
346
|
-
|
|
347
|
-
if self.pagination:
|
|
348
|
-
displayed_items = min(displayed_items, self.items_per_page)
|
|
349
|
-
base_height = 50 if self.pagination else 35
|
|
350
|
-
items_height = displayed_items * self.button_height
|
|
351
|
-
self.height_new = items_height + base_height
|
|
367
|
+
if not self.is_height:
|
|
368
|
+
self.height_new = self.attach.winfo_toplevel().winfo_height()
|
|
352
369
|
screen_height = self.winfo_screenheight()
|
|
353
370
|
dropdown_bottom = self.attach.winfo_rooty() + self.height_new
|
|
354
371
|
if dropdown_bottom > screen_height:
|
|
@@ -445,7 +462,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
445
462
|
anchor=self.justify,
|
|
446
463
|
command=lambda v=value: self._attach_key_press(v),
|
|
447
464
|
width=0
|
|
448
|
-
|
|
465
|
+
**kwargs)
|
|
449
466
|
btn.pack(fill="x", pady=2, padx=(self.padding, 0))
|
|
450
467
|
self.widgets[index] = [btn, True]
|
|
451
468
|
self.values.append(value)
|
|
@@ -472,8 +489,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
472
489
|
if self.old_kwargs == kwargs:
|
|
473
490
|
return
|
|
474
491
|
if "height" in kwargs:
|
|
475
|
-
self.
|
|
476
|
-
self.height_new = self.height
|
|
492
|
+
self.height_new = kwargs.pop("height")
|
|
477
493
|
if "alpha" in kwargs:
|
|
478
494
|
self.alpha = kwargs.pop("alpha")
|
|
479
495
|
if "width" in kwargs:
|
|
@@ -515,11 +531,11 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
515
531
|
self.groups.append({"name": g[0], "pattern": g[1]})
|
|
516
532
|
else:
|
|
517
533
|
raise ValueError(f"groups must be list of [name, pattern], got {g!r}")
|
|
518
|
-
|
|
534
|
+
|
|
519
535
|
self.group_names = [g["name"] for g in self.groups]
|
|
520
536
|
self.group_patterns = []
|
|
521
537
|
included_values = set()
|
|
522
|
-
|
|
538
|
+
|
|
523
539
|
for g in self.groups:
|
|
524
540
|
pattern = g["pattern"]
|
|
525
541
|
if pattern == "__OTHERS__":
|
|
@@ -529,14 +545,14 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
529
545
|
self.group_patterns.append(compiled)
|
|
530
546
|
matched = [v for v in self.all_values if compiled.search(v)]
|
|
531
547
|
included_values.update(matched)
|
|
532
|
-
|
|
548
|
+
|
|
533
549
|
self.grouped_values = {}
|
|
534
550
|
for i, pat in enumerate(self.group_patterns):
|
|
535
551
|
if pat == "__OTHERS__":
|
|
536
552
|
self.grouped_values[i] = [v for v in self.all_values if v not in included_values]
|
|
537
553
|
else:
|
|
538
554
|
self.grouped_values[i] = [v for v in self.all_values if pat.search(v)]
|
|
539
|
-
|
|
555
|
+
|
|
540
556
|
self.current_group = 0
|
|
541
557
|
self.switch_group(self.current_group)
|
|
542
558
|
if "image_values" in kwargs:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: CTkScrollableDropdownPP
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.4
|
|
4
4
|
Summary: Enhanced CTkScrollableDropdown with pagination, search and groups support
|
|
5
5
|
Author: PLauncher-Team, Akash Bora
|
|
6
6
|
License: MIT
|
|
@@ -17,6 +17,8 @@ Dynamic: license-file
|
|
|
17
17
|
|
|
18
18
|
# CTkScrollableDropdownPP
|
|
19
19
|
|
|
20
|
+
[](https://pepy.tech/projects/ctkscrollabledropdownpp)
|
|
21
|
+
|
|
20
22
|
**CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, and grouping support.
|
|
21
23
|
|
|
22
24
|
> Based on the original [CTkScrollableDropdown](https://github.com/Akascape/CTkScrollableDropdown) project.
|
|
@@ -39,22 +41,30 @@ pip install ctkscrollabledropdownpp
|
|
|
39
41
|
|
|
40
42
|
```python
|
|
41
43
|
import customtkinter as ctk
|
|
42
|
-
from
|
|
44
|
+
from CTkScrollableDropdownPP import CTkScrollableDropdown
|
|
43
45
|
|
|
44
46
|
app = ctk.CTk()
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
app.geometry("400x300")
|
|
48
|
+
|
|
49
|
+
combobox = ctk.CTkComboBox(
|
|
50
|
+
master=app,
|
|
51
|
+
values=[],
|
|
52
|
+
width=200,
|
|
53
|
+
height=30
|
|
54
|
+
)
|
|
55
|
+
combobox.pack(pady=50)
|
|
47
56
|
|
|
48
57
|
values = [f"Item {i}" for i in range(1, 101)]
|
|
49
58
|
|
|
50
59
|
dropdown = CTkScrollableDropdown(
|
|
51
|
-
attach=
|
|
60
|
+
attach=combobox,
|
|
52
61
|
values=values,
|
|
53
62
|
command=lambda v: print("Selected:", v),
|
|
54
|
-
items_per_page=20,
|
|
55
|
-
pagination=True,
|
|
56
63
|
autocomplete=True,
|
|
57
|
-
groups=[
|
|
64
|
+
groups=[
|
|
65
|
+
('1-50', r'^Item ([1-9]|[1-4][0-9]|50)$'),
|
|
66
|
+
('Others', '__OTHERS__')
|
|
67
|
+
],
|
|
58
68
|
)
|
|
59
69
|
|
|
60
70
|
app.mainloop()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: CTkScrollableDropdownPP
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.4
|
|
4
4
|
Summary: Enhanced CTkScrollableDropdown with pagination, search and groups support
|
|
5
5
|
Author: PLauncher-Team, Akash Bora
|
|
6
6
|
License: MIT
|
|
@@ -17,6 +17,8 @@ Dynamic: license-file
|
|
|
17
17
|
|
|
18
18
|
# CTkScrollableDropdownPP
|
|
19
19
|
|
|
20
|
+
[](https://pepy.tech/projects/ctkscrollabledropdownpp)
|
|
21
|
+
|
|
20
22
|
**CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, and grouping support.
|
|
21
23
|
|
|
22
24
|
> Based on the original [CTkScrollableDropdown](https://github.com/Akascape/CTkScrollableDropdown) project.
|
|
@@ -39,22 +41,30 @@ pip install ctkscrollabledropdownpp
|
|
|
39
41
|
|
|
40
42
|
```python
|
|
41
43
|
import customtkinter as ctk
|
|
42
|
-
from
|
|
44
|
+
from CTkScrollableDropdownPP import CTkScrollableDropdown
|
|
43
45
|
|
|
44
46
|
app = ctk.CTk()
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
app.geometry("400x300")
|
|
48
|
+
|
|
49
|
+
combobox = ctk.CTkComboBox(
|
|
50
|
+
master=app,
|
|
51
|
+
values=[],
|
|
52
|
+
width=200,
|
|
53
|
+
height=30
|
|
54
|
+
)
|
|
55
|
+
combobox.pack(pady=50)
|
|
47
56
|
|
|
48
57
|
values = [f"Item {i}" for i in range(1, 101)]
|
|
49
58
|
|
|
50
59
|
dropdown = CTkScrollableDropdown(
|
|
51
|
-
attach=
|
|
60
|
+
attach=combobox,
|
|
52
61
|
values=values,
|
|
53
62
|
command=lambda v: print("Selected:", v),
|
|
54
|
-
items_per_page=20,
|
|
55
|
-
pagination=True,
|
|
56
63
|
autocomplete=True,
|
|
57
|
-
groups=[
|
|
64
|
+
groups=[
|
|
65
|
+
('1-50', r'^Item ([1-9]|[1-4][0-9]|50)$'),
|
|
66
|
+
('Others', '__OTHERS__')
|
|
67
|
+
],
|
|
58
68
|
)
|
|
59
69
|
|
|
60
70
|
app.mainloop()
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# CTkScrollableDropdownPP
|
|
2
2
|
|
|
3
|
+
[](https://pepy.tech/projects/ctkscrollabledropdownpp)
|
|
4
|
+
|
|
3
5
|
**CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, and grouping support.
|
|
4
6
|
|
|
5
7
|
> Based on the original [CTkScrollableDropdown](https://github.com/Akascape/CTkScrollableDropdown) project.
|
|
@@ -22,22 +24,30 @@ pip install ctkscrollabledropdownpp
|
|
|
22
24
|
|
|
23
25
|
```python
|
|
24
26
|
import customtkinter as ctk
|
|
25
|
-
from
|
|
27
|
+
from CTkScrollableDropdownPP import CTkScrollableDropdown
|
|
26
28
|
|
|
27
29
|
app = ctk.CTk()
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
app.geometry("400x300")
|
|
31
|
+
|
|
32
|
+
combobox = ctk.CTkComboBox(
|
|
33
|
+
master=app,
|
|
34
|
+
values=[],
|
|
35
|
+
width=200,
|
|
36
|
+
height=30
|
|
37
|
+
)
|
|
38
|
+
combobox.pack(pady=50)
|
|
30
39
|
|
|
31
40
|
values = [f"Item {i}" for i in range(1, 101)]
|
|
32
41
|
|
|
33
42
|
dropdown = CTkScrollableDropdown(
|
|
34
|
-
attach=
|
|
43
|
+
attach=combobox,
|
|
35
44
|
values=values,
|
|
36
45
|
command=lambda v: print("Selected:", v),
|
|
37
|
-
items_per_page=20,
|
|
38
|
-
pagination=True,
|
|
39
46
|
autocomplete=True,
|
|
40
|
-
groups=[
|
|
47
|
+
groups=[
|
|
48
|
+
('1-50', r'^Item ([1-9]|[1-4][0-9]|50)$'),
|
|
49
|
+
('Others', '__OTHERS__')
|
|
50
|
+
],
|
|
41
51
|
)
|
|
42
52
|
|
|
43
53
|
app.mainloop()
|
{ctkscrollabledropdownpp-2.0.2 → ctkscrollabledropdownpp-2.0.4}/CTkScrollableDropdownPP/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|