CTkScrollableDropdownPP 2.1.2__tar.gz → 2.2__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.1.2 → ctkscrollabledropdownpp-2.2}/CTkScrollableDropdownPP/ctk_scrollable_dropdown.py +127 -11
- {ctkscrollabledropdownpp-2.1.2 → ctkscrollabledropdownpp-2.2}/CTkScrollableDropdownPP.egg-info/PKG-INFO +4 -3
- {ctkscrollabledropdownpp-2.1.2 → ctkscrollabledropdownpp-2.2}/PKG-INFO +4 -3
- {ctkscrollabledropdownpp-2.1.2 → ctkscrollabledropdownpp-2.2}/README.md +3 -2
- {ctkscrollabledropdownpp-2.1.2 → ctkscrollabledropdownpp-2.2}/pyproject.toml +1 -1
- {ctkscrollabledropdownpp-2.1.2 → ctkscrollabledropdownpp-2.2}/CTkScrollableDropdownPP/__init__.py +0 -0
- {ctkscrollabledropdownpp-2.1.2 → ctkscrollabledropdownpp-2.2}/CTkScrollableDropdownPP.egg-info/SOURCES.txt +0 -0
- {ctkscrollabledropdownpp-2.1.2 → ctkscrollabledropdownpp-2.2}/CTkScrollableDropdownPP.egg-info/dependency_links.txt +0 -0
- {ctkscrollabledropdownpp-2.1.2 → ctkscrollabledropdownpp-2.2}/CTkScrollableDropdownPP.egg-info/requires.txt +0 -0
- {ctkscrollabledropdownpp-2.1.2 → ctkscrollabledropdownpp-2.2}/CTkScrollableDropdownPP.egg-info/top_level.txt +0 -0
- {ctkscrollabledropdownpp-2.1.2 → ctkscrollabledropdownpp-2.2}/LICENSE +0 -0
- {ctkscrollabledropdownpp-2.1.2 → ctkscrollabledropdownpp-2.2}/setup.cfg +0 -0
|
@@ -10,7 +10,8 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
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, font=("Segoe UI", 12),
|
|
13
|
+
groups=None, font=("Segoe UI", 12), fade_in_duration: bool = True, fps: int = 60,
|
|
14
|
+
multiple: bool = False, **button_kwargs):
|
|
14
15
|
super().__init__(master=attach.winfo_toplevel(), takefocus=1)
|
|
15
16
|
|
|
16
17
|
self.group_patterns = None
|
|
@@ -39,6 +40,12 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
39
40
|
self.current_group = 0
|
|
40
41
|
self.font = font
|
|
41
42
|
self.groups = []
|
|
43
|
+
self.fade_enabled = fade_in_duration
|
|
44
|
+
self.fps = max(1, int(fps))
|
|
45
|
+
self.fade_animation_duration = 0.25
|
|
46
|
+
self.animating = False
|
|
47
|
+
self.multiple = multiple
|
|
48
|
+
self.selected_values = []
|
|
42
49
|
|
|
43
50
|
if groups is not None:
|
|
44
51
|
for g in groups:
|
|
@@ -188,7 +195,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
188
195
|
if self.autocomplete:
|
|
189
196
|
self.bind_autocomplete()
|
|
190
197
|
self.withdraw()
|
|
191
|
-
self.attributes("-alpha",
|
|
198
|
+
self.attributes("-alpha", 0)
|
|
192
199
|
if self.groups:
|
|
193
200
|
self.switch_group(0)
|
|
194
201
|
self._init_buttons()
|
|
@@ -241,11 +248,18 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
241
248
|
self.current_page = 0
|
|
242
249
|
self._init_buttons()
|
|
243
250
|
|
|
251
|
+
def _update_button_appearance(self, btn, value):
|
|
252
|
+
if self.multiple and value in self.selected_values:
|
|
253
|
+
btn.configure(fg_color=self.hover_color)
|
|
254
|
+
else:
|
|
255
|
+
btn.configure(fg_color=self.button_color)
|
|
256
|
+
|
|
244
257
|
def update_buttons(self, values_list):
|
|
245
258
|
for i, value in enumerate(values_list):
|
|
246
259
|
if i in self.widgets:
|
|
247
260
|
btn, _ = self.widgets[i]
|
|
248
261
|
btn.configure(text=value, command=lambda v=value: self._attach_key_press(v), image=self.value_to_image.get(value))
|
|
262
|
+
self._update_button_appearance(btn, value)
|
|
249
263
|
btn.pack(fill="x", pady=2, padx=(self.padding, 0))
|
|
250
264
|
self.widgets[i][1] = True
|
|
251
265
|
else:
|
|
@@ -261,6 +275,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
261
275
|
hover_color=self.hover_color,
|
|
262
276
|
image=self.value_to_image.get(value)
|
|
263
277
|
)
|
|
278
|
+
self._update_button_appearance(btn, value)
|
|
264
279
|
btn.pack(fill="x", pady=2, padx=(self.padding, 0))
|
|
265
280
|
self.widgets[i] = [btn, True]
|
|
266
281
|
i = len(values_list)
|
|
@@ -275,10 +290,13 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
275
290
|
self.after(500, self.destroy_popup)
|
|
276
291
|
|
|
277
292
|
def _withdraw(self):
|
|
293
|
+
if self.animating:
|
|
294
|
+
return
|
|
278
295
|
if not self.winfo_exists():
|
|
279
296
|
return
|
|
280
297
|
if self.winfo_viewable() and self.hide_flag:
|
|
281
|
-
self.
|
|
298
|
+
self._animated_withdraw()
|
|
299
|
+
return
|
|
282
300
|
self.event_generate("<<Closed>>")
|
|
283
301
|
self.hide_flag = True
|
|
284
302
|
|
|
@@ -382,12 +400,17 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
382
400
|
or current_x_pos != self.x_pos
|
|
383
401
|
or current_y_pos != self.y_pos):
|
|
384
402
|
self.geometry(f"{self.width_new}x{self.height_new}+{self.x_pos}+{self.y_pos}")
|
|
385
|
-
|
|
403
|
+
if self.fade_enabled:
|
|
404
|
+
self.attributes('-alpha', 0)
|
|
405
|
+
else:
|
|
406
|
+
self.attributes('-alpha', self.alpha)
|
|
386
407
|
self.update_idletasks()
|
|
387
408
|
if self.pagination:
|
|
388
409
|
self._update_pagination_buttons(filtered=bool(self.filtered_values))
|
|
389
410
|
|
|
390
411
|
def _iconify(self):
|
|
412
|
+
if self.animating:
|
|
413
|
+
return
|
|
391
414
|
if self.attach.cget("state") == "disabled":
|
|
392
415
|
return
|
|
393
416
|
if self.disable:
|
|
@@ -401,16 +424,30 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
401
424
|
self.place_dropdown()
|
|
402
425
|
self._deiconify()
|
|
403
426
|
else:
|
|
404
|
-
self.
|
|
427
|
+
self._animated_withdraw()
|
|
405
428
|
self.hide_flag = True
|
|
406
429
|
|
|
407
430
|
def _attach_key_press(self, k):
|
|
431
|
+
if self.animating:
|
|
432
|
+
return
|
|
408
433
|
if hasattr(self, "search_var"):
|
|
409
434
|
self.search_var.set("")
|
|
410
435
|
self.event_generate("<<Selected>>")
|
|
411
436
|
self.fade = True
|
|
412
|
-
if self.
|
|
413
|
-
self.
|
|
437
|
+
if self.multiple:
|
|
438
|
+
if k in self.selected_values:
|
|
439
|
+
self.selected_values.remove(k)
|
|
440
|
+
else:
|
|
441
|
+
self.selected_values.append(k)
|
|
442
|
+
for i, (btn, visible) in self.widgets.items():
|
|
443
|
+
if visible:
|
|
444
|
+
value = btn.cget("text")
|
|
445
|
+
self._update_button_appearance(btn, value)
|
|
446
|
+
if self.command:
|
|
447
|
+
self.command(self.selected_values)
|
|
448
|
+
else:
|
|
449
|
+
if self.command:
|
|
450
|
+
self.command(k)
|
|
414
451
|
if hasattr(self, "search_var") and self.search_var.get().strip() != "":
|
|
415
452
|
self.filtered_values = None
|
|
416
453
|
self.current_page = 0
|
|
@@ -418,11 +455,12 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
418
455
|
if self.pagination:
|
|
419
456
|
self.pagination_frame.pack(fill="x", side="bottom")
|
|
420
457
|
self.fade = False
|
|
421
|
-
self.
|
|
422
|
-
|
|
458
|
+
if not self.multiple:
|
|
459
|
+
self._animated_withdraw()
|
|
460
|
+
self.hide_flag = True
|
|
423
461
|
|
|
424
462
|
def live_update(self, string=None):
|
|
425
|
-
if self.disable or self.fade:
|
|
463
|
+
if self.disable or self.fade or self.animating:
|
|
426
464
|
return
|
|
427
465
|
self.frame._parent_canvas.yview_moveto(0)
|
|
428
466
|
if string and string.strip() != "":
|
|
@@ -480,7 +518,14 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
480
518
|
|
|
481
519
|
def _deiconify(self):
|
|
482
520
|
if self.all_values:
|
|
483
|
-
self.
|
|
521
|
+
if self.fade_enabled:
|
|
522
|
+
if self.animating:
|
|
523
|
+
return
|
|
524
|
+
self.deiconify()
|
|
525
|
+
self._animate_fade_in()
|
|
526
|
+
else:
|
|
527
|
+
self.deiconify()
|
|
528
|
+
self.attributes('-alpha', self.alpha)
|
|
484
529
|
|
|
485
530
|
def popup(self, x=None, y=None):
|
|
486
531
|
self.x = x
|
|
@@ -582,3 +627,74 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel):
|
|
|
582
627
|
self.widgets[key][0].configure(**kwargs)
|
|
583
628
|
self.old_kwargs = kwargs
|
|
584
629
|
self.master.update()
|
|
630
|
+
|
|
631
|
+
def _animate_fade_in(self):
|
|
632
|
+
if not self.fade_enabled:
|
|
633
|
+
self.attributes('-alpha', self.alpha)
|
|
634
|
+
return
|
|
635
|
+
if self.animating:
|
|
636
|
+
return
|
|
637
|
+
self.animating = True
|
|
638
|
+
total_frames = max(1, int(self.fps * self.fade_animation_duration))
|
|
639
|
+
step = float(self.alpha) / total_frames
|
|
640
|
+
current = 0.0
|
|
641
|
+
interval = max(1, int(1000 / self.fps))
|
|
642
|
+
def step_fn(frame, value):
|
|
643
|
+
new_value = value + step
|
|
644
|
+
if new_value >= self.alpha or frame >= total_frames - 1:
|
|
645
|
+
try:
|
|
646
|
+
self.attributes('-alpha', self.alpha)
|
|
647
|
+
finally:
|
|
648
|
+
self.animating = False
|
|
649
|
+
return
|
|
650
|
+
try:
|
|
651
|
+
self.attributes('-alpha', new_value)
|
|
652
|
+
except Exception:
|
|
653
|
+
pass
|
|
654
|
+
self.after(interval, lambda: step_fn(frame + 1, new_value))
|
|
655
|
+
try:
|
|
656
|
+
self.attributes('-alpha', 0.0)
|
|
657
|
+
except Exception:
|
|
658
|
+
pass
|
|
659
|
+
step_fn(0, current)
|
|
660
|
+
|
|
661
|
+
def _animated_withdraw(self):
|
|
662
|
+
if not self.winfo_exists():
|
|
663
|
+
return
|
|
664
|
+
if not self.fade_enabled:
|
|
665
|
+
if self.winfo_viewable():
|
|
666
|
+
self.withdraw()
|
|
667
|
+
self.event_generate("<<Closed>>")
|
|
668
|
+
self.hide_flag = True
|
|
669
|
+
return
|
|
670
|
+
if self.animating:
|
|
671
|
+
return
|
|
672
|
+
self.animating = True
|
|
673
|
+
total_frames = max(1, int(self.fps * self.fade_animation_duration))
|
|
674
|
+
step = float(self.alpha) / total_frames
|
|
675
|
+
interval = max(1, int(1000 / self.fps))
|
|
676
|
+
current_alpha = None
|
|
677
|
+
try:
|
|
678
|
+
current_alpha = float(self.attributes('-alpha'))
|
|
679
|
+
except Exception:
|
|
680
|
+
current_alpha = self.alpha
|
|
681
|
+
def step_fn(frame, value):
|
|
682
|
+
new_value = value - step
|
|
683
|
+
if new_value <= 0 or frame >= total_frames - 1:
|
|
684
|
+
try:
|
|
685
|
+
self.attributes('-alpha', 0.0)
|
|
686
|
+
finally:
|
|
687
|
+
try:
|
|
688
|
+
if self.winfo_viewable():
|
|
689
|
+
self.withdraw()
|
|
690
|
+
finally:
|
|
691
|
+
self.event_generate("<<Closed>>")
|
|
692
|
+
self.hide_flag = True
|
|
693
|
+
self.animating = False
|
|
694
|
+
return
|
|
695
|
+
try:
|
|
696
|
+
self.attributes('-alpha', new_value)
|
|
697
|
+
except Exception:
|
|
698
|
+
pass
|
|
699
|
+
self.after(interval, lambda: step_fn(frame + 1, new_value))
|
|
700
|
+
step_fn(0, current_alpha)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: CTkScrollableDropdownPP
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2
|
|
4
4
|
Summary: Enhanced CTkScrollableDropdown with pagination, search and groups support
|
|
5
5
|
Author: PLauncher-Team, Akash Bora
|
|
6
6
|
License: MIT
|
|
@@ -20,7 +20,7 @@ Dynamic: license-file
|
|
|
20
20
|
|
|
21
21
|
[](https://pepy.tech/projects/ctkscrollabledropdownpp)
|
|
22
22
|
|
|
23
|
-
**CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, and
|
|
23
|
+
**CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, grouping support, and multiple selection.
|
|
24
24
|
|
|
25
25
|
> Based on the original [CTkScrollableDropdown](https://github.com/Akascape/CTkScrollableDropdown) project.
|
|
26
26
|
|
|
@@ -30,6 +30,7 @@ Dynamic: license-file
|
|
|
30
30
|
* Real-time filtering
|
|
31
31
|
* Grouped items (using regex or labels)
|
|
32
32
|
* Autocomplete on typing
|
|
33
|
+
* Multiple selection support
|
|
33
34
|
* Fully customizable appearance
|
|
34
35
|
|
|
35
36
|
## Installation
|
|
@@ -115,7 +116,7 @@ groups = [
|
|
|
115
116
|
dropdown = CTkScrollableDropdown(attach=combobox, button_color="#2b2b2b", height=200, width=300, fg_color="#333333",
|
|
116
117
|
values=all_values, command=lambda value: print(f"Selected: {value}"),
|
|
117
118
|
image_values=all_images, text_color="#ffffff", hover_color="#3a3a3a",
|
|
118
|
-
font=("Arial", 12), groups=groups, items_per_page=10)
|
|
119
|
+
font=("Arial", 12), groups=groups, items_per_page=10, multiple=True)
|
|
119
120
|
|
|
120
121
|
root.mainloop()
|
|
121
122
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: CTkScrollableDropdownPP
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2
|
|
4
4
|
Summary: Enhanced CTkScrollableDropdown with pagination, search and groups support
|
|
5
5
|
Author: PLauncher-Team, Akash Bora
|
|
6
6
|
License: MIT
|
|
@@ -20,7 +20,7 @@ Dynamic: license-file
|
|
|
20
20
|
|
|
21
21
|
[](https://pepy.tech/projects/ctkscrollabledropdownpp)
|
|
22
22
|
|
|
23
|
-
**CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, and
|
|
23
|
+
**CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, grouping support, and multiple selection.
|
|
24
24
|
|
|
25
25
|
> Based on the original [CTkScrollableDropdown](https://github.com/Akascape/CTkScrollableDropdown) project.
|
|
26
26
|
|
|
@@ -30,6 +30,7 @@ Dynamic: license-file
|
|
|
30
30
|
* Real-time filtering
|
|
31
31
|
* Grouped items (using regex or labels)
|
|
32
32
|
* Autocomplete on typing
|
|
33
|
+
* Multiple selection support
|
|
33
34
|
* Fully customizable appearance
|
|
34
35
|
|
|
35
36
|
## Installation
|
|
@@ -115,7 +116,7 @@ groups = [
|
|
|
115
116
|
dropdown = CTkScrollableDropdown(attach=combobox, button_color="#2b2b2b", height=200, width=300, fg_color="#333333",
|
|
116
117
|
values=all_values, command=lambda value: print(f"Selected: {value}"),
|
|
117
118
|
image_values=all_images, text_color="#ffffff", hover_color="#3a3a3a",
|
|
118
|
-
font=("Arial", 12), groups=groups, items_per_page=10)
|
|
119
|
+
font=("Arial", 12), groups=groups, items_per_page=10, multiple=True)
|
|
119
120
|
|
|
120
121
|
root.mainloop()
|
|
121
122
|
```
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://pepy.tech/projects/ctkscrollabledropdownpp)
|
|
4
4
|
|
|
5
|
-
**CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, and
|
|
5
|
+
**CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, grouping support, and multiple selection.
|
|
6
6
|
|
|
7
7
|
> Based on the original [CTkScrollableDropdown](https://github.com/Akascape/CTkScrollableDropdown) project.
|
|
8
8
|
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* Real-time filtering
|
|
13
13
|
* Grouped items (using regex or labels)
|
|
14
14
|
* Autocomplete on typing
|
|
15
|
+
* Multiple selection support
|
|
15
16
|
* Fully customizable appearance
|
|
16
17
|
|
|
17
18
|
## Installation
|
|
@@ -97,7 +98,7 @@ groups = [
|
|
|
97
98
|
dropdown = CTkScrollableDropdown(attach=combobox, button_color="#2b2b2b", height=200, width=300, fg_color="#333333",
|
|
98
99
|
values=all_values, command=lambda value: print(f"Selected: {value}"),
|
|
99
100
|
image_values=all_images, text_color="#ffffff", hover_color="#3a3a3a",
|
|
100
|
-
font=("Arial", 12), groups=groups, items_per_page=10)
|
|
101
|
+
font=("Arial", 12), groups=groups, items_per_page=10, multiple=True)
|
|
101
102
|
|
|
102
103
|
root.mainloop()
|
|
103
104
|
```
|
{ctkscrollabledropdownpp-2.1.2 → ctkscrollabledropdownpp-2.2}/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
|