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.
@@ -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), **button_kwargs):
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", self.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.withdraw()
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
- self.attributes('-alpha', self.alpha)
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.withdraw()
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.command:
413
- self.command(k)
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.withdraw()
422
- self.hide_flag = True
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.deiconify()
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.1.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
  [![PyPI Downloads](https://static.pepy.tech/badge/ctkscrollabledropdownpp)](https://pepy.tech/projects/ctkscrollabledropdownpp)
22
22
 
23
- **CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, and grouping support.
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.1.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
  [![PyPI Downloads](https://static.pepy.tech/badge/ctkscrollabledropdownpp)](https://pepy.tech/projects/ctkscrollabledropdownpp)
22
22
 
23
- **CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, and grouping support.
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
  [![PyPI Downloads](https://static.pepy.tech/badge/ctkscrollabledropdownpp)](https://pepy.tech/projects/ctkscrollabledropdownpp)
4
4
 
5
- **CTkScrollableDropdownPP** is an enhanced dropdown widget for CustomTkinter featuring pagination, live search, and grouping support.
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
  ```
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "CTkScrollableDropdownPP"
7
- version = "2.1.2"
7
+ version = "2.2"
8
8
  description = "Enhanced CTkScrollableDropdown with pagination, search and groups support"
9
9
  authors = [
10
10
  {name = "PLauncher-Team"},