MoreCustomTkinterWidgets 5.2.0__tar.gz → 5.4.0__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.
Files changed (34) hide show
  1. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/LICENSE +1 -1
  2. {morecustomtkinterwidgets-5.2.0/src/MoreCustomTkinterWidgets.egg-info → morecustomtkinterwidgets-5.4.0}/PKG-INFO +4 -5
  3. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/README.md +3 -4
  4. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/pyproject.toml +1 -1
  5. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/AnimatedImage.py +18 -12
  6. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Selector.py +44 -25
  7. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/__init__.py +2 -2
  8. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0/src/MoreCustomTkinterWidgets.egg-info}/PKG-INFO +4 -5
  9. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/setup.cfg +0 -0
  10. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/AskDialog.py +0 -0
  11. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/AskValue.py +0 -0
  12. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/BetterCTkImage.py +0 -0
  13. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/DateSelector.py +0 -0
  14. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/FileExplorer.py +0 -0
  15. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Images/back_arrow_dark.png +0 -0
  16. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Images/back_arrow_light.png +0 -0
  17. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Images/error.png +0 -0
  18. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Images/file_dark.png +0 -0
  19. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Images/file_light.png +0 -0
  20. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Images/folder_dark.png +0 -0
  21. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Images/folder_light.png +0 -0
  22. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Images/forward_arrow_dark.png +0 -0
  23. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Images/forward_arrow_light.png +0 -0
  24. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Images/info.png +0 -0
  25. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Images/new_folder_dark.png +0 -0
  26. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Images/new_folder_light.png +0 -0
  27. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Images/warning.png +0 -0
  28. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Message.py +0 -0
  29. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/Separator.py +0 -0
  30. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets/SmoothFrame.py +0 -0
  31. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets.egg-info/SOURCES.txt +0 -0
  32. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets.egg-info/dependency_links.txt +0 -0
  33. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets.egg-info/requires.txt +0 -0
  34. {morecustomtkinterwidgets-5.2.0 → morecustomtkinterwidgets-5.4.0}/src/MoreCustomTkinterWidgets.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024-2025 Fastattack
3
+ Copyright (c) 2024-2026 Fastattack
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MoreCustomTkinterWidgets
3
- Version: 5.2.0
3
+ Version: 5.4.0
4
4
  Summary: A package containing more widgets for customtkinter
5
5
  Author: Fastattack
6
6
  License: MIT License
@@ -17,14 +17,13 @@ Requires-Dist: Pillow>=9.5.0
17
17
  Dynamic: license-file
18
18
 
19
19
  # MoreCustomTkinterWidgets
20
- By Fastattack, 2024
20
+ By Fastattack, 2024-2026
21
21
 
22
22
  [![Pypi](https://img.shields.io/pypi/v/MoreCustomTkinterWidgets?label=Pypi)](https://pypi.org/project/MoreCustomTkinterWidgets)
23
23
  [![GitHub - Total commits](https://img.shields.io/github/commit-activity/t/fastattackv/MoreCustomTkinterWidgets?label=Total%20GitHub%20commits&color=darkblue)](https://github.com/fastattackv/MoreCustomTkinterWidgets)
24
24
  [![GitHub - Last commit](https://img.shields.io/github/last-commit/fastattackv/MoreCustomTkinterWidgets?label=Last%20GitHub%20commit&color=darkblue)](https://github.com/fastattackv/MoreCustomTkinterWidgets)
25
25
  [![Pypi - Monthly downloads](https://img.shields.io/pypi/dm/MoreCustomTkinterWidgets)](https://pypi.org/project/MoreCustomTkinterWidgets)
26
26
  [![Pypi - Total downloads](https://static.pepy.tech/personalized-badge/MoreCustomTkinterWidgets?period=total&units=international_system&left_color=grey&right_color=green&left_text=Total%20Downloads)](https://pypi.org/project/MoreCustomTkinterWidgets)
27
- [![Lines number](https://tokei.rs/b1/github/fastattackv/MoreCustomTkinterWidgets?category=lines)](https://github.com/fastattackv/MoreCustomTkinterWidgets/tree/main/Source%20Code)
28
27
 
29
28
  > [!NOTE]
30
29
  > The package is cross-platform, but the Message class will only be able to create sounds if the winsound module is installed (only available on windows)
@@ -39,8 +38,8 @@ To install the package, you should use pip. Install the package with the followi
39
38
 
40
39
  ## Widgets
41
40
 
42
- [![Examples](https://img.shields.io/badge/Examples_for_all_widgets-red)](Examples.md)
43
- [![Patch Notes](https://img.shields.io/badge/Patch_Notes-yellow)](Patch%20notes.md)
41
+ [Examples](Examples.md)
42
+ [Patch Notes](Patch%20notes.md)
44
43
 
45
44
  ### SmoothFrame
46
45
  This widget is a normal frame but with one upgrade: animations !
@@ -1,12 +1,11 @@
1
1
  # MoreCustomTkinterWidgets
2
- By Fastattack, 2024
2
+ By Fastattack, 2024-2026
3
3
 
4
4
  [![Pypi](https://img.shields.io/pypi/v/MoreCustomTkinterWidgets?label=Pypi)](https://pypi.org/project/MoreCustomTkinterWidgets)
5
5
  [![GitHub - Total commits](https://img.shields.io/github/commit-activity/t/fastattackv/MoreCustomTkinterWidgets?label=Total%20GitHub%20commits&color=darkblue)](https://github.com/fastattackv/MoreCustomTkinterWidgets)
6
6
  [![GitHub - Last commit](https://img.shields.io/github/last-commit/fastattackv/MoreCustomTkinterWidgets?label=Last%20GitHub%20commit&color=darkblue)](https://github.com/fastattackv/MoreCustomTkinterWidgets)
7
7
  [![Pypi - Monthly downloads](https://img.shields.io/pypi/dm/MoreCustomTkinterWidgets)](https://pypi.org/project/MoreCustomTkinterWidgets)
8
8
  [![Pypi - Total downloads](https://static.pepy.tech/personalized-badge/MoreCustomTkinterWidgets?period=total&units=international_system&left_color=grey&right_color=green&left_text=Total%20Downloads)](https://pypi.org/project/MoreCustomTkinterWidgets)
9
- [![Lines number](https://tokei.rs/b1/github/fastattackv/MoreCustomTkinterWidgets?category=lines)](https://github.com/fastattackv/MoreCustomTkinterWidgets/tree/main/Source%20Code)
10
9
 
11
10
  > [!NOTE]
12
11
  > The package is cross-platform, but the Message class will only be able to create sounds if the winsound module is installed (only available on windows)
@@ -21,8 +20,8 @@ To install the package, you should use pip. Install the package with the followi
21
20
 
22
21
  ## Widgets
23
22
 
24
- [![Examples](https://img.shields.io/badge/Examples_for_all_widgets-red)](Examples.md)
25
- [![Patch Notes](https://img.shields.io/badge/Patch_Notes-yellow)](Patch%20notes.md)
23
+ [Examples](Examples.md)
24
+ [Patch Notes](Patch%20notes.md)
26
25
 
27
26
  ### SmoothFrame
28
27
  This widget is a normal frame but with one upgrade: animations !
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "MoreCustomTkinterWidgets"
7
- version = "5.2.0"
7
+ version = "5.4.0"
8
8
  dependencies = [
9
9
  "customtkinter>=5.2.1",
10
10
  "Pillow>=9.5.0",
@@ -95,11 +95,14 @@ class AnimatedImage(ctk.CTkImage):
95
95
  return self._currently_animating
96
96
 
97
97
  def start_animation(self):
98
- """ Starts the animation loop """
99
- self._currently_animating = True
100
- time_between_2_frames = self._light_image.info["duration"] if self._light_image is not None else self._dark_image.info["duration"]
101
- self._time_between_frames = int(time_between_2_frames * self._speed_multiplier)
102
- self._next_frame()
98
+ """ Starts the animation loop. HAS TO BE CALLED AFTER THE IMAGE IS USED """
99
+ if self._configure_callback_list:
100
+ self._currently_animating = True
101
+ time_between_2_frames = self._light_image.info["duration"] if self._light_image is not None else self._dark_image.info["duration"]
102
+ self._time_between_frames = int(time_between_2_frames * self._speed_multiplier)
103
+ self._next_frame()
104
+ else:
105
+ raise RuntimeError("Tried to start the animation before using the image in a widget")
103
106
 
104
107
  def stop_animation(self):
105
108
  """ Stops the animation loop """
@@ -112,18 +115,21 @@ class AnimatedImage(ctk.CTkImage):
112
115
  raise RuntimeError("Tried to stop the animation but it was not already running")
113
116
 
114
117
  def start_animation_for(self, ms: int, reset_after_complete=False):
115
- """Starts the animation and stops automatically after the given time
118
+ """Starts the animation and stops automatically after the given time. HAS TO BE CALLED AFTER THE IMAGE IS USED
116
119
 
117
120
  :param ms: time to run the animation for (in ms)
118
121
  :param reset_after_complete: if set to True: resets to the first frame of the animation when the animation stops
119
122
  """
120
- try:
121
- self._configure_callback_list[0].__self__.after(ms, self.stop_animation)
122
- except AttributeError:
123
- pass
123
+ if self._configure_callback_list:
124
+ try:
125
+ self._configure_callback_list[0].__self__.after(ms, self.stop_animation)
126
+ except AttributeError:
127
+ pass
128
+ else:
129
+ self.start_animation()
130
+ self.reset_after_complete = reset_after_complete
124
131
  else:
125
- self.start_animation()
126
- self.reset_after_complete = reset_after_complete
132
+ raise RuntimeError("Tried to start the animation before using the image in a widget")
127
133
 
128
134
  def set_to_frame(self, frame_index: int):
129
135
  """Sets the animation to the given frame
@@ -1,36 +1,52 @@
1
1
  import customtkinter as ctk
2
+ from customtkinter import ThemeManager
2
3
 
3
4
 
4
5
  class Selector(ctk.CTkFrame):
5
- def __init__(self, master, items: list[str], multiple_choices=True, *args, **kwargs):
6
+ def __init__(self, master, names_list: list[str], multiple_choices=True, search_mode: str="fuzzy", *args, **kwargs):
6
7
  """Selector widgets to select options in a list of options. Includes a search bar to find different elements faster.
7
8
 
8
9
  :param master: master window for the widget
9
- :param items: list of the possible options, they should all be different
10
+ :param names_list: list of the possible options, they should all be different
10
11
  :param multiple_choices: Optional: if set to False, the user will be allowed to select only one item (default=True)
12
+ :param search_mode: Optional: if set to "exact": the search will only show the items that start with exactly the given string, if set to "fuzzy": the search will show items that contain the search as a substring (default="fuzzy")
11
13
  :param args: args for the CTkFrame widget
12
14
  :param kwargs: kwargs for the CTkFrame widget
13
15
  """
14
16
  super().__init__(master, *args, **kwargs)
15
17
 
18
+ self.grid_rowconfigure(0, weight=0)
19
+ self.grid_rowconfigure(1, weight=1)
20
+ self.grid_columnconfigure(0, weight=1)
21
+ self.grid_columnconfigure(1, weight=0)
22
+
16
23
  self.search_var = ctk.StringVar(self)
17
24
  self.search_var.trace_add("write", self._search_modified)
18
25
  self.search_bar = ctk.CTkEntry(self, textvariable=self.search_var)
26
+ self.empty_search_button = ctk.CTkButton(self, width=10, height=10, fg_color="transparent", border_color=ThemeManager.theme["CTkEntry"]["border_color"], border_width=2, text="X", command=self._empty_search)
19
27
  color = kwargs.pop("fg_color") if "fg_color" in kwargs else "transparent"
20
28
  self.checkboxes_frame = ctk.CTkScrollableFrame(self, fg_color=color, *args, **kwargs)
21
- self.search_bar.pack(anchor="n", fill="x")
22
- self.checkboxes_frame.pack(expand=True, fill="both", side="bottom")
29
+ self.search_bar.grid(row=0, column=0, padx=3, pady=3, sticky="nsew")
30
+ self.empty_search_button.grid(row=0, column=1, padx=3, pady=3, sticky="nsew")
31
+ self.checkboxes_frame.grid(row=1, column=0, columnspan=2, padx=3, pady=3, sticky="nsew")
23
32
 
24
33
  self.checkboxes = []
25
34
  self.selected_indexes = []
26
35
  self.multiple_choices = multiple_choices
27
36
 
28
- if len(set(items)) == len(items): # not 2 times the same item
29
- for index in range(len(items)):
30
- self.checkboxes.append(ctk.CTkCheckBox(self.checkboxes_frame, text=items[index], command=lambda a=index: self._selection(a)))
37
+ if search_mode == "exact":
38
+ self.exact_search = True
39
+ elif search_mode == "fuzzy":
40
+ self.exact_search = False
41
+ else:
42
+ raise ValueError(f"The given search_mode is incorrect: {search_mode}")
43
+
44
+ if len(set(names_list)) == len(names_list): # not 2 times the same item
45
+ for index in range(len(names_list)):
46
+ self.checkboxes.append(ctk.CTkCheckBox(self.checkboxes_frame, text=names_list[index], command=lambda a=index: self._selection(a)))
31
47
  self._search_modified()
32
48
  else:
33
- raise ValueError("There is two times or more the same item in the given items list")
49
+ raise ValueError("There is two times or more the same item in the given names_list")
34
50
 
35
51
  def _selection(self, index: int):
36
52
  """ Internal method: selects / unselects the given index """
@@ -56,42 +72,45 @@ class Selector(ctk.CTkFrame):
56
72
  """ Internal method: modifies the search """
57
73
  value = self.search_var.get()
58
74
  row = 0
59
- for x in range(len(self.checkboxes)):
60
- if self.checkboxes[x].cget("text").startswith(value):
61
- self.checkboxes[x].grid(row=row, column=0, padx=3, pady=3)
75
+ for i in range(len(self.checkboxes)):
76
+ text = self.checkboxes[i].cget("text")
77
+ if (self.exact_search and text.startswith(value)) or (not self.exact_search and value in text.lower()):
78
+ self.checkboxes[i].grid(row=row, column=0, pady=3, sticky="w")
62
79
  row += 1
63
80
  else:
64
- self.checkboxes[x].grid_forget()
81
+ self.checkboxes[i].grid_forget()
65
82
  self._reset_scroll()
66
83
 
84
+ def _empty_search(self):
85
+ """ Internal method: empties the search bar """
86
+ self.search_var.set("")
87
+
67
88
  def get_all_items(self) -> list:
68
89
  """ Returns all the items in the selector """
69
90
  return [checkbox.cget("text") for checkbox in self.checkboxes]
70
91
 
71
- def configure_selector(self, items: list = None, multiple_choices: bool = None):
72
- """Changes the given arguments
73
-
74
- :param items: new items to show, if [] is given: deletes all old items
75
- :param multiple_choices: if set to False, the user will be allowed to select only one item
76
- """
77
- if items is not None:
78
- if len(set(items)) == len(items): # not 2 times the same item
92
+ def configure(self, require_redraw=False, **kwargs):
93
+ if "names_list" in kwargs:
94
+ names_list = kwargs.pop("names_list")
95
+ if len(set(names_list)) == len(names_list): # not 2 times the same item
79
96
  # destroy old widgets
80
97
  for checkbox in self.checkboxes:
81
98
  checkbox.destroy()
82
99
  self.checkboxes.clear()
83
100
  self.selected_indexes.clear()
84
-
85
101
  # create new ones
86
- for index in range(len(items)):
87
- self.checkboxes.append(ctk.CTkCheckBox(self.checkboxes_frame, text=items[index], command=lambda a=index: self._selection(a)))
102
+ for index in range(len(names_list)):
103
+ self.checkboxes.append(ctk.CTkCheckBox(self.checkboxes_frame, text=names_list[index], command=lambda a=index: self._selection(a)))
88
104
  self._search_modified()
89
105
  else:
90
- raise ValueError("There is two times or more the same item in the given items list")
106
+ raise ValueError("There is two times or more the same item in the given names_list")
91
107
 
92
- if multiple_choices is not None:
108
+ if "multiple_choices" in kwargs:
109
+ multiple_choices = kwargs.pop("multiple_choices")
93
110
  self.multiple_choices = multiple_choices
94
111
 
112
+ super().configure(require_redraw=require_redraw, **kwargs)
113
+
95
114
  def clear_selections(self):
96
115
  """ Clears the selections """
97
116
  for index in self.selected_indexes:
@@ -10,5 +10,5 @@ from .Separator import Separator
10
10
  from .DateSelector import Date, DateSelector, DateSelectorButton
11
11
 
12
12
 
13
- _version = "5.2.0"
14
- __version__ = "5.2.0"
13
+ _version = "5.4.0"
14
+ __version__ = "5.4.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MoreCustomTkinterWidgets
3
- Version: 5.2.0
3
+ Version: 5.4.0
4
4
  Summary: A package containing more widgets for customtkinter
5
5
  Author: Fastattack
6
6
  License: MIT License
@@ -17,14 +17,13 @@ Requires-Dist: Pillow>=9.5.0
17
17
  Dynamic: license-file
18
18
 
19
19
  # MoreCustomTkinterWidgets
20
- By Fastattack, 2024
20
+ By Fastattack, 2024-2026
21
21
 
22
22
  [![Pypi](https://img.shields.io/pypi/v/MoreCustomTkinterWidgets?label=Pypi)](https://pypi.org/project/MoreCustomTkinterWidgets)
23
23
  [![GitHub - Total commits](https://img.shields.io/github/commit-activity/t/fastattackv/MoreCustomTkinterWidgets?label=Total%20GitHub%20commits&color=darkblue)](https://github.com/fastattackv/MoreCustomTkinterWidgets)
24
24
  [![GitHub - Last commit](https://img.shields.io/github/last-commit/fastattackv/MoreCustomTkinterWidgets?label=Last%20GitHub%20commit&color=darkblue)](https://github.com/fastattackv/MoreCustomTkinterWidgets)
25
25
  [![Pypi - Monthly downloads](https://img.shields.io/pypi/dm/MoreCustomTkinterWidgets)](https://pypi.org/project/MoreCustomTkinterWidgets)
26
26
  [![Pypi - Total downloads](https://static.pepy.tech/personalized-badge/MoreCustomTkinterWidgets?period=total&units=international_system&left_color=grey&right_color=green&left_text=Total%20Downloads)](https://pypi.org/project/MoreCustomTkinterWidgets)
27
- [![Lines number](https://tokei.rs/b1/github/fastattackv/MoreCustomTkinterWidgets?category=lines)](https://github.com/fastattackv/MoreCustomTkinterWidgets/tree/main/Source%20Code)
28
27
 
29
28
  > [!NOTE]
30
29
  > The package is cross-platform, but the Message class will only be able to create sounds if the winsound module is installed (only available on windows)
@@ -39,8 +38,8 @@ To install the package, you should use pip. Install the package with the followi
39
38
 
40
39
  ## Widgets
41
40
 
42
- [![Examples](https://img.shields.io/badge/Examples_for_all_widgets-red)](Examples.md)
43
- [![Patch Notes](https://img.shields.io/badge/Patch_Notes-yellow)](Patch%20notes.md)
41
+ [Examples](Examples.md)
42
+ [Patch Notes](Patch%20notes.md)
44
43
 
45
44
  ### SmoothFrame
46
45
  This widget is a normal frame but with one upgrade: animations !