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.
@@ -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 = 55, width: int = None,
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
- resize=False, frame_border_color=None, text_color=None, autocomplete=False,
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.height = height
143
- self.height_new = height
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
- cols = max(1, event.width // min_btn_width)
190
-
191
- for child in self.group_frame.grid_slaves():
192
- child.grid_forget()
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
- col = idx % cols
197
- btn.grid(row=row, column=col, sticky="ew", padx=2, pady=2)
198
-
199
- for c in range(cols):
200
- self.group_frame.grid_columnconfigure(c, weight=1)
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=("Segoe UI", 12),
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.resize:
346
- displayed_items = len(self.filtered_values) if self.filtered_values is not None else len(self.values)
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
- **kwargs)
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.height = kwargs.pop("height")
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.2
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
+ [![PyPI Downloads](https://static.pepy.tech/badge/ctkscrollabledropdownpp)](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 ctkscrollabledropdownpp import CTkScrollableDropdown
44
+ from CTkScrollableDropdownPP import CTkScrollableDropdown
43
45
 
44
46
  app = ctk.CTk()
45
- btn = ctk.CTkButton(app, text='Select')
46
- btn.pack(pady=20)
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=btn,
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=[('1-50', r'^Item [1-4]'), ('Others', '__OTHERS__')]
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.2
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
+ [![PyPI Downloads](https://static.pepy.tech/badge/ctkscrollabledropdownpp)](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 ctkscrollabledropdownpp import CTkScrollableDropdown
44
+ from CTkScrollableDropdownPP import CTkScrollableDropdown
43
45
 
44
46
  app = ctk.CTk()
45
- btn = ctk.CTkButton(app, text='Select')
46
- btn.pack(pady=20)
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=btn,
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=[('1-50', r'^Item [1-4]'), ('Others', '__OTHERS__')]
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
+ [![PyPI Downloads](https://static.pepy.tech/badge/ctkscrollabledropdownpp)](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 ctkscrollabledropdownpp import CTkScrollableDropdown
27
+ from CTkScrollableDropdownPP import CTkScrollableDropdown
26
28
 
27
29
  app = ctk.CTk()
28
- btn = ctk.CTkButton(app, text='Select')
29
- btn.pack(pady=20)
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=btn,
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=[('1-50', r'^Item [1-4]'), ('Others', '__OTHERS__')]
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()
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "CTkScrollableDropdownPP"
7
- version = "2.0.2"
7
+ version = "2.0.4"
8
8
  description = "Enhanced CTkScrollableDropdown with pagination, search and groups support"
9
9
  authors = [
10
10
  {name = "PLauncher-Team"},