easykinter 0.0.1__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.
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.4
2
+ Name: easykinter
3
+ Version: 0.0.1
4
+ Summary: A wrapper to make Tkinter 90% less boring.
5
+ Author-email: Starly <starly.alt.acc1@gmail.com>
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Operating System :: Microsoft :: Windows
9
+ Requires-Python: >=3.12
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: pillow>=10.0.0
File without changes
@@ -0,0 +1,22 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "easykinter"
7
+ version = "0.0.1"
8
+ authors = [
9
+ { name="Starly", email="starly.alt.acc1@gmail.com" },
10
+ ]
11
+ description = "A wrapper to make Tkinter 90% less boring."
12
+ readme = "README.md"
13
+ requires-python = ">=3.12"
14
+ dependencies = ["pillow>=10.0.0"]
15
+ license = { text = "MIT" }
16
+ classifiers = [
17
+ "Programming Language :: Python :: 3",
18
+ "Operating System :: Microsoft :: Windows",
19
+ ]
20
+
21
+ [tool.setuptools.packages.find]
22
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,932 @@
1
+ import tkinter as tk
2
+ import warnings as warn
3
+ from PIL import Image as img, ImageTk as imgtk
4
+ import atexit as _atexit
5
+
6
+ #region all the nice and dandy EasyKinter functions
7
+
8
+ #region Code that Automatically Runs mainloop() DO NOT TOUCH
9
+ #verifying if mainloop was called
10
+ _MainloopCalled = False
11
+ _OriginalMainloop = tk.Tk.mainloop
12
+
13
+ def _newmainloop(self, n=0):
14
+ global _MainloopCalled
15
+ _MainloopCalled = True
16
+ return _OriginalMainloop(self, n)
17
+
18
+ tk.Tk.mainloop = _newmainloop
19
+
20
+ #now call the function if mainloop wasn't written, and we're good to go.
21
+ def _auto_run():
22
+ global _MainloopCalled
23
+ if not _MainloopCalled and hasattr(tk, "_default_root") and tk._default_root:
24
+ try:
25
+ tk._default_root.mainloop()
26
+ except Exception:
27
+ pass
28
+ _atexit.register(_auto_run)
29
+ #hell yeah.
30
+ #endregion
31
+
32
+ #region Create Root Window Function
33
+ def CreateRoot(Title="Root Tkinter Window", SizeX=250, SizeY=250, PosX=None, PosY = None, HideWindow=False):
34
+ """
35
+ # This function creates a new Root window and returns the value of the fully created window when done.
36
+
37
+ **Title** = What the Tk window's name will be upon creation.
38
+
39
+ **Geometry Configs**:
40
+ SizeX = Dictates the width of your window.
41
+ SizeY = Dictates the height of your window.
42
+
43
+ PosX = Position in your screen where the window is created, cannot be higher than the size of your monitor. (Width)
44
+ PosY = Position in your screen where the window is created, cannot be higher than the size of your monitor. (Height)
45
+
46
+ **Extra**:
47
+ HideWindow = Tells the program if your window will be hidden upon creation.
48
+ """
49
+
50
+ if tk._default_root is not None:
51
+ raise RuntimeError(f"Root window could not be created as a root instance already exists.")
52
+
53
+ else:
54
+ newRoot = tk.Tk()
55
+ newRoot.title(Title)
56
+ newRoot.geometry(f"{SizeX}x{SizeY}{f'+{PosX}' if PosX is not None else ''}{f'+{PosY}' if PosY is not None else ''}")
57
+
58
+ if HideWindow:
59
+ newRoot.withdraw()
60
+ newRoot.update_idletasks()
61
+
62
+ return newRoot
63
+ # endregion
64
+
65
+ #region Create Toplevel Window Function
66
+ def CreateToplevel(Title="Toplevel Tkinter Window", Parent=None, Child=None, SizeX=250, SizeY=250, PosX=None, PosY=None):
67
+ """
68
+ # This function creates a new Toplevel window and returns the value of the fully created window when done.
69
+
70
+ **Title** = What the TopLevel window's name will be upon creation.
71
+
72
+ **Geometry Configs**:
73
+ SizeX = Dictates the width of your window.
74
+ SizeY = Dictates the height of your window.
75
+
76
+ PosX = Position in your screen where the window is created, cannot be higher than the size of your monitor. (Width)
77
+ PosY = Position in your screen where the window is created, cannot be higher than the size of your monitor. (Height)
78
+
79
+ **Extra**:
80
+ Parent = Tells the program what parent this toplevel window will have. This can greatly affect the window's behavior.
81
+ """
82
+
83
+ WindowName = tk.Toplevel(Parent)
84
+ WindowName.title(Title)
85
+ WindowName.geometry(f"{SizeX}x{SizeY}{f'+{PosX}' if PosX is not None else ''}{f'+{PosY}' if PosY is not None else ''}")
86
+
87
+ if Child is not None:
88
+ if not isinstance(Child (tk.Toplevel, tk.Tk)):
89
+ raise ValueError(f"Could not link {WindowName} with {Child} as {Child} is not a Toplevel or Tk window. Did you try checking the 'Child=' value?")
90
+
91
+ else:
92
+ Child.transient(WindowName)
93
+ WindowName.update_idletasks()
94
+
95
+ return WindowName
96
+ #endregion
97
+
98
+ #region W.I.P Customization Function
99
+ def ExtraCustomize(TargetWindow, background="#f0f0f0", hideTitleBar=False, ResizableWidth=None, ResizableHeight=None):
100
+ """
101
+ # (W.I.P) This function allows you to fully customize and color any window you want.
102
+
103
+ **TargetWindow** = The name of the window or widget that will be targetted.
104
+
105
+ **Coloring Configs:**
106
+ background = What the color of the widget's background will be set to.
107
+
108
+ **Extra:**
109
+ hideTitleBar = Will apply overridedirect(True) to window if value is set to true.
110
+ ResizableWidth = Dictates wether your window can be resized horizontally.
111
+ ResizableHeight = Dictates if your window can be resized vertically.
112
+ """
113
+
114
+ if TargetWindow is None:
115
+ raise ValueError(f"Expected a Tkinter window/frame, but got None instead.")
116
+
117
+ elif not isinstance(TargetWindow, (tk.Tk, tk.Toplevel)):
118
+ raise TypeError(f"Expected a Tkinter window, but got {type(TargetWindow).__name__} instead.")
119
+
120
+ else:
121
+ TargetWindow.configure(bg=background)
122
+
123
+ if hideTitleBar:
124
+ TargetWindow.overrideredirect(True)
125
+
126
+ if ResizableHeight is not None or ResizableWidth is not None:
127
+ if isinstance(TargetWindow, (tk.Tk, tk.Toplevel)):
128
+ TargetWindow.resizable(ResizableWidth, ResizableHeight)
129
+
130
+ else:
131
+ warn.warn(f"Resize attributes were skipped as the target was a '{type(TargetWindow).__name__}' and it cannot have a Resizeable attrbute. Have you tried using tk.Toplevel or tk.Tk?", category=RuntimeWarning)
132
+ #endregion
133
+
134
+ #region Creating Customizeable Labels and Auto-Pack Function
135
+ def CreateLabel(ForWindow, Text="New Label", font="Arial", FontSize=12, LabelImage=None, ImageCompound="Center", optionalCustomization = "", BgColor="#f0f0f0", FgColor="#000000", PackType=None, Anchor="center", PadX=0, PadY=0, Side=tk.TOP, Row=0, Column=0, Sticky=None, X=None, Y=None, RelX=None, RelY=None):
136
+ """
137
+ # This function creates and returns a custom label that can be also packed within the same function.
138
+
139
+ **ForWindow** = This dictates that target where the label will be created for.
140
+
141
+ **Formatting:**
142
+ text = What text the label will contain.
143
+ font = What custom font the label will use.
144
+ FontSize = The size of the font used.
145
+ OptionalCustomization = Dictates special font formatting such as bold, italic, or underline.
146
+ (Options: 'bold', 'italic', 'underline', 'overstrike')
147
+ LabelImage = What custom image the label will have. (Must be a tk.PhotoImage object.)
148
+ ImageCompound = What direction the image will be placed on top of the text.
149
+ (Options: 'top', 'left', 'center', 'right', 'bottom', 'none')
150
+
151
+ **Extra Customization:**
152
+ BgColor = What the background of the label will be colored as.
153
+ FgColor = The color of the text within the label.
154
+ Anchor = Where the text will be anchored, affects where it will be packed.
155
+
156
+ # Packing Types and their parameters:
157
+
158
+ **Pack (The default type, packs label and contains borders.):**
159
+ PadX = Width for the padding of the label.
160
+ PadY = Height for the padding of the label.
161
+ Side = Side where the label will go to in the widget, is relative.
162
+ Sticky = Position where the label will stick to in the widget, is not relative.
163
+
164
+ **Grid (for mounting grids and organized sheets):**
165
+ Row = The row where your element will be placed. (Horizontal)
166
+ Column = the column where your element will be placed. (Vertical)
167
+ PadX = the padding width your element will have, affects elements in and outside of the grid.
168
+ PadY = the padding height your element will have, affects elements in and outside of the grid.
169
+
170
+ **Place (for accurately placing elements in absolute or relative positions):**
171
+ X = The absolute position of the element in your window, cannot be moved. (Width)
172
+ Y = The absolute position of the element in your window, cannot be moved. (Height)
173
+ RelX = The relative position of the element in your window, can be moved. (Width)
174
+ RelY = The relative position of the element in your window, can be moved. (Height)
175
+ """
176
+
177
+ if not isinstance(ForWindow, (tk.Tk, tk.Frame, tk.Toplevel)):
178
+ raise TypeError(f"Expected a Tkinter window/frame, but got {type(ForWindow).__name__} instead.")
179
+
180
+ if ImageCompound is not None:
181
+ ImageCompound = ImageCompound.lower()
182
+
183
+ if ImageCompound == "top":
184
+ ImageCompound = tk.TOP
185
+
186
+ elif ImageCompound == "left":
187
+ ImageCompound = tk.LEFT
188
+
189
+ elif ImageCompound == "center":
190
+ ImageCompound = tk.CENTER
191
+
192
+ elif ImageCompound == "right":
193
+ ImageCompound = tk.RIGHT
194
+
195
+ elif ImageCompound == "bottom":
196
+ ImageCompound = tk.BOTTOM
197
+
198
+ newLabel = tk.Label(ForWindow, image=LabelImage, compound=ImageCompound, text=Text, font=(font, FontSize, optionalCustomization), bg=BgColor, fg=FgColor)
199
+
200
+ if PackType is not None:
201
+ PackType = PackType.lower()
202
+
203
+ if PackType is not None and PackType not in ["place", "grid", "pack"]:
204
+ raise ValueError(f"Expected a proper packing style, but got {PackType} instead. Current packing types are 'Pack', 'Grid', or 'Place'")
205
+
206
+ elif PackType == "pack":
207
+ newLabel.pack(anchor=Anchor, padx=PadX, pady=PadY, side=Side, sticky=Sticky)
208
+
209
+ elif PackType == "place":
210
+ newLabel.place(x=X, y=Y, relx=RelX, rely=RelY, anchor=Anchor)
211
+
212
+ elif PackType == "grid":
213
+ newLabel.grid(row=Row, column=Column, padx=PadX, pady=PadY)
214
+
215
+ return newLabel
216
+ #endregion
217
+
218
+ #region Creating Text Entry Widget and Custom Keybinding Function
219
+ def CreateEntry(ForWindow, CustomFunc=None, CustomFuncKeybind=None, PlaceHolderEnabled=True, PlaceHolderText="Insert text here...", PlaceHolderTextColor="Gray", Width=None, Font="Arial", FontSize=12, FontProperties=None, borderwidth=None, bg=None, fg="#000000", PackType=None, Anchor="center", PadX=0, PadY=0, Side=tk.TOP, Row=0, Column=0, Sticky=None, X=None, Y=None, RelX=None, RelY=None):
220
+ """
221
+ # This function automatically creates and customizes an Entry widget in tkinter. Can also additionally trigger a funtion or be automatically packed.
222
+
223
+ **Logic parameters:**
224
+ ForWindow = Defines the target window where the entry will be created.
225
+ CustomFunc = Sets a function to automatically trigger when the set keybind is activated. Must be added alongside **CustomFuncKeybind.**
226
+ CustomFuncKeybind = Sets a keybind for a function to trigger when entering said keybind in the entry widget. Must be added alongside **CustomFunc.**
227
+ PlaceHolderEnabled = Dictates wether the Entry widget will have a pre-built placeholder.
228
+
229
+ **UX and Customization:**
230
+ PlaceHolderText = Defines what text will appear in the placeholder UI.
231
+ PlaceHolderTextColor = Defines what color of the placeholder text will be.
232
+ Width = Defines the width of the input box.
233
+ Font = Defines the custom font the text will have in the input.
234
+ FontSize: = Defines the size of the text in the Entry box. Also affects Entry box height.
235
+ FontPorperties = Wether a custom font property will be applied.
236
+ (Current properties availiable = 'Bold', 'Italic', 'Underline', 'Overstrike')
237
+ bg = What the background of the label will be colored as.
238
+ fg = The color of the text within the label.
239
+
240
+ # Packing Types and their parameters:
241
+
242
+ **Pack (The default type, packs label and contains borders.):**
243
+ PadX = Width for the padding of the label.
244
+ PadY = Height for the padding of the label.
245
+ Side = Side where the label will go to in the widget, is relative.
246
+ Sticky = Position where the label will stick to in the widget, is not relative.
247
+
248
+ **Grid (for mounting grids and organized sheets):**
249
+ Row = The row where your element will be placed. (Horizontal)
250
+ Column = the column where your element will be placed. (Vertical)
251
+ PadX = the padding width your element will have, affects elements in and outside of the grid.
252
+ PadY = the padding height your element will have, affects elements in and outside of the grid.
253
+
254
+ **Place (for accurately placing elements in absolute or relative positions):**
255
+ X = The absolute position of the element in your window, cannot be moved. (Width)
256
+ Y = The absolute position of the element in your window, cannot be moved. (Height)
257
+ RelX = The relative position of the element in your window, can be moved. (Width)
258
+ RelY = The relative position of the element in your window, can be moved. (Height)
259
+ """
260
+
261
+ def on_entry_click(event=None):
262
+ if NewEntry.get() == PlaceHolderText:
263
+ NewEntry.delete(0, tk.END)
264
+ NewEntry.config(fg=fg.lower())
265
+
266
+ def on_focus_out(event=None):
267
+ if not NewEntry.get():
268
+ NewEntry.insert(0, PlaceHolderText)
269
+ NewEntry.config(fg=PlaceHolderTextColor.lower())
270
+
271
+
272
+ NewEntry = tk.Entry(ForWindow, width=Width if Width is not None else 20, font=(Font.capitalize(), FontSize, FontProperties.lower() if FontProperties else "normal"), bg=bg, fg=fg, borderwidth=borderwidth if borderwidth is not None else 1)
273
+
274
+ if CustomFuncKeybind is not None and CustomFunc is not None:
275
+ def eventNeedlessFunction(event):
276
+ CustomFunc()
277
+
278
+ NewEntry.bind(CustomFuncKeybind, eventNeedlessFunction)
279
+
280
+ elif CustomFuncKeybind is not None or CustomFunc is not None:
281
+ raise ValueError("The function could not be called as the Function Keybind values have not been filled properly. Did you try checking both 'CustomFunc__' values?")
282
+
283
+ if PlaceHolderEnabled:
284
+ NewEntry.bind("<FocusIn>", on_entry_click)
285
+ NewEntry.bind("<FocusOut>", on_focus_out)
286
+ on_focus_out()
287
+
288
+
289
+ if PackType is not None:
290
+ PackType = PackType.lower()
291
+
292
+ if PackType is not None and PackType not in ["place", "grid", "pack"]:
293
+ raise ValueError(f"Expected a proper packing style, but got {PackType} instead. Current packing types are 'Pack', 'Grid', or 'Place'")
294
+
295
+ elif PackType == "pack":
296
+ NewEntry.pack(anchor=Anchor, padx=PadX, pady=PadY, side=Side, sticky=Sticky)
297
+
298
+ elif PackType == "place":
299
+ NewEntry.place(x=X, y=Y, relx=RelX, rely=RelY, anchor=Anchor)
300
+
301
+ elif PackType == "grid":
302
+ NewEntry.grid(row=Row if Row is not None else 0, column=Column if Column is not None else 0, padx=PadX, pady=PadY)
303
+
304
+ return NewEntry
305
+ #endregion
306
+
307
+ #region Creating Button Widget and Custom Keybinding Function
308
+ def CreateButton(ForWindow, Text="New Button", Image=None, Compound="center", font="Arial", FontSize=12, optionalCustomization = "", CommandFunc=None, ButtonWidth=100, ButtonHeight=30, BgColor="#f0f0f0", FgColor="#000000", PackType=None, Anchor="center", PadX=0, PadY=0, Side=tk.TOP, Row=0, Column=0, Sticky=None, X=None, Y=None, RelX=None, RelY=None):
309
+ """
310
+ # This function creates and returns a custom button that can be also packed within the same function.
311
+
312
+ **ForWindow** = This dictates that target where the button will be created for.
313
+
314
+ **Button Contents:**
315
+ Text = What custom text will the button have.
316
+ Image = What custom image the button will have.
317
+
318
+ **Formatting:**
319
+ Compound = What direction the image will be placed on top of the text.
320
+ (Options: 'top', 'left', 'center', 'right', 'bottom', 'none')
321
+ font = What custom font the button will use.
322
+ FontSize = The size of the font used.
323
+ OptionalCustomization = Dictates special font formatting such as bold, italic, or underline.
324
+ (Options: 'bold', 'italic', 'underline', 'overstrike')
325
+
326
+ **Extra Customization:**
327
+ BgColor = What the background of the button will be colored as.
328
+ FgColor = The color of the text within the button.
329
+ Anchor = Where the text will be anchored, affects where it will be packed.
330
+
331
+ # Packing Types and their parameters:
332
+
333
+ **Pack (The default type, packs label and contains borders.):**
334
+ PadX = Width for the padding of the label.
335
+ PadY = Height for the padding of the label.
336
+ Side = Side where the label will go to in the widget, is relative.
337
+ Sticky = Position where the label will stick to in the widget, is not relative.
338
+
339
+ **Grid (for mounting grids and organized sheets):**
340
+ Row = The row where your element will be placed. (Horizontal)
341
+ Column = the column where your element will be placed. (Vertical)
342
+ PadX = the padding width your element will have, affects elements in and outside of the grid.
343
+ PadY = the padding height your element will have, affects elements in and outside of the grid.
344
+
345
+ **Place (for accurately placing elements in absolute or relative positions):**
346
+ X = The absolute position of the element in your window, cannot be moved. (Width)
347
+ Y = The absolute position of the element in your window, cannot be moved. (Height)
348
+ RelX = The relative position of the element in your window, can be moved. (Width)
349
+ RelY = The relative position of the element in your window, can be moved. (Height)
350
+ """
351
+
352
+ if not isinstance(ForWindow, (tk.Tk, tk.Frame, tk.Toplevel)):
353
+ raise TypeError(f"Expected a Tkinter window/frame, but got {type(ForWindow).__name__} instead.")
354
+
355
+ TransparentPixel = "R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
356
+ TrasnparentImage = tk.PhotoImage(data=TransparentPixel)
357
+
358
+ Compound = Compound.lower()
359
+
360
+ if Image is None:
361
+ newButton = tk.Button(ForWindow, command=CommandFunc, image=TrasnparentImage, text=Text, compound=Compound, font=(font, FontSize, optionalCustomization), width=ButtonWidth, height=ButtonHeight, bg=BgColor, fg=FgColor)
362
+ newButton.image = TrasnparentImage
363
+
364
+ else:
365
+ newButton = tk.Button(ForWindow, command=CommandFunc, image=Image, text=Text, compound=Compound, font=(font, FontSize, optionalCustomization), width=ButtonWidth, height=ButtonHeight, bg=BgColor, fg=FgColor)
366
+ newButton.image = Image
367
+
368
+ if PackType is not None:
369
+ PackType = PackType.lower()
370
+
371
+ if PackType is not None and PackType not in ["place", "grid", "pack"]:
372
+ raise ValueError(f"Expected a proper packing style, but got {PackType} instead. Current packing types are 'Pack', 'Grid', or 'Place'")
373
+
374
+ elif PackType == "pack":
375
+ newButton.pack(anchor=Anchor, padx=PadX, pady=PadY, side=Side, sticky=Sticky)
376
+
377
+ elif PackType == "place":
378
+ newButton.place(x=X, y=Y, relx=RelX, rely=RelY, anchor=Anchor)
379
+
380
+ elif PackType == "grid":
381
+ newButton.grid(row=Row, column=Column, padx=PadX, pady=PadY)
382
+
383
+ return newButton
384
+ #endregion
385
+
386
+ #region Creating AplhaNumerical Input Widgets and Miscellaneous
387
+ def CreateMiscInputs(ForWindow, InputType, Border=2, CustomFont="Arial", CustomFontSize=12, CustomFontExtra="", BgColor="#f0f0f0", FgColor="#000000", CommandKeybind=None, CommandFunction=None, SpinboxFrom=-100, SpinboxTo=100, ScaleLength=100, ScaleRepeatDelay=1, ScaleResolution=1, PackType=None, PadX=None, PadY=None, Anchor="center", Side=tk.TOP, Row=0, Column=0, Sticky=None, X=None, Y=None, RelX=None, RelY=None):
388
+ """
389
+ # This function can create, pack, and set a command for other, miscellaneous Aplhanumerical input widgets and returns the widget.
390
+
391
+ **Essential Parameters:**
392
+ ForWindow = This parameter dictates what window the custom widget will be created for.
393
+ InputType = This parameter dictates what custom widget will be created.
394
+ (Options: Text, Spinbox, Scale)
395
+
396
+ **Customization Parameters:**
397
+ Border = This parameter defines the border of the created widget.
398
+ CustomFont = This parameter defines the Font that will be used in the created widget.
399
+ CustomFontSize = This parameter defines the custom Font Size that the widget will have.
400
+ CustomFontExtra = This parameter defines any extra properties the font can have, such as Bold.
401
+ (Options: 'Bold', 'Italic', 'Underline', 'Overstrike'.)
402
+ BgColor = Defines the background color of the widget.
403
+ FgColor = Defines the foreground color of the widget.
404
+
405
+ **Custom Keybind Parameters:**
406
+ CommandKeybind = What the custom keybind of said widget will be. Must have CommandFunction to work.
407
+ CommandFunction = The command that will be executed when pressing the respective keybind. Must have CommandKeybind to work.
408
+
409
+ **SpinBox Specific Parameters:**
410
+ SpinboxFrom = The minimum value that the SpinBox can have.
411
+ SpinboxTo = The maximum value that the spinbox can have.
412
+
413
+ **Scale Specific Parameters:**
414
+ ScaleLength = The length of the scale in pixels. (Width, X value.)
415
+ ScaleRepeatDelay = The frequency that the scale will show numbers based on their position.
416
+ (For example, a ScaleRepeatDelay of 0.5 would show numbers every 0.5.)
417
+ ScaleResolution = The rounding that the scale will have upon selecting a value, where it snaps your cursor to said value.
418
+ (For example, setting to 1 snaps your selector to every integer, skipping decimals. Setting to -1 disables rounding.)
419
+
420
+ # Packing Types and their parameters:
421
+
422
+ **Pack (The default type, packs label and contains borders.):**
423
+ PadX = Width for the padding of the label.
424
+ PadY = Height for the padding of the label.
425
+ Side = Side where the label will go to in the widget, is relative.
426
+ Sticky = Position where the label will stick to in the widget, is not relative.
427
+
428
+ **Grid (for mounting grids and organized sheets):**
429
+ Row = The row where your element will be placed. (Horizontal)
430
+ Column = the column where your element will be placed. (Vertical)
431
+ PadX = the padding width your element will have, affects elements in and outside of the grid.
432
+ PadY = the padding height your element will have, affects elements in and outside of the grid.
433
+
434
+ **Place (for accurately placing elements in absolute or relative positions):**
435
+ X = The absolute position of the element in your window, cannot be moved. (Width)
436
+ Y = The absolute position of the element in your window, cannot be moved. (Height)
437
+ RelX = The relative position of the element in your window, can be moved. (Width)
438
+ RelY = The relative position of the element in your window, can be moved. (Height)
439
+ """
440
+
441
+ if not ForWindow or not InputType:
442
+ raise ValueError("Could not create miscellaneous input types as one of the necessary values wew not given. Did you try filling the primary essential values?")
443
+
444
+ else:
445
+ InputType = InputType.lower()
446
+
447
+ if InputType == "text":
448
+ NewInput = tk.Text(ForWindow, bg=BgColor, fg=FgColor, bd=Border, font=(CustomFont.capitalize(), CustomFontSize, CustomFontExtra.capitalize()))
449
+
450
+ elif InputType == "spinbox":
451
+ NewInput = tk.Spinbox(ForWindow, bg=BgColor, fg=FgColor, bd=Border, font=(CustomFont.capitalize(), CustomFontSize, CustomFontExtra.capitalize()), from_=SpinboxFrom, to=SpinboxTo)
452
+
453
+ elif InputType == "scale":
454
+ NewInput = NewInput = tk.Scale(ForWindow, bg=BgColor, fg=FgColor, bd=Border, font=(CustomFont.capitalize(), CustomFontSize, CustomFontExtra.capitalize()), repeatdelay=ScaleRepeatDelay, resolution=ScaleResolution, length=ScaleLength)
455
+
456
+ if CommandKeybind is not None and CommandFunction is not None:
457
+ def eventNeedlessFunction(event):
458
+ CommandFunction()
459
+
460
+ NewInput.bind(CommandKeybind, eventNeedlessFunction)
461
+
462
+ elif CommandKeybind is not None or CommandFunction is not None:
463
+ raise ValueError("Could not bind a command to this widget as one of the proper 'Command__' were not filled. Did you try checking both the 'Command__' parameters?")
464
+
465
+ if PackType is not None:
466
+ PackType = PackType.lower()
467
+
468
+ if PackType is not None and PackType not in ["place", "grid", "pack"]:
469
+ raise ValueError(f"Expected a proper packing style, but got {PackType} instead. Current packing types are 'Pack', 'Grid', or 'Place'")
470
+
471
+ elif PackType == "pack":
472
+ NewInput.pack(anchor=Anchor, padx=PadX, pady=PadY, side=Side, sticky=Sticky)
473
+
474
+ elif PackType == "place":
475
+ NewInput.place(x=X, y=Y, relx=RelX, rely=RelY, anchor=Anchor)
476
+
477
+ elif PackType == "grid":
478
+ NewInput.grid(row=Row if Row is not None else 0, column=Column if Column is not None else 0, padx=PadX, pady=PadY)
479
+
480
+ return NewInput
481
+ #endregion
482
+
483
+ #region Creating Boolean Input Widgets and Miscellaneous
484
+ def CreateBoolInputs(ForWindow, WidgetType, Border=2, CustomText="", CustomFont="Arial", CustomFontSize=12, CustomFontExtra="", BgColor="#f0f0f0", FgColor="#000000", CommandKeybind=None, CommandFunction=None, CheckBoxState="NORMAL", CheckBoxOnValue=1, CheckBoxOffValue=0,PackType=None, PadX=None, PadY=None, Anchor="center", Side=tk.TOP, Row=0, Column=0, Sticky=None, X=None, Y=None, RelX=None, RelY=None):
485
+ """
486
+ # Creates a miscellaneous input from the Bool type.
487
+
488
+ **Essential Parameters:**
489
+ ForWindow = This parameter dictates what window the custom widget will be created for.
490
+ WidgetType = This parameter dictates what custom widget will be created.
491
+ (Options: Text, Spinbox, Scale)
492
+
493
+ **Customization Parameters:**
494
+ Border = This parameter defines the border of the created widget.
495
+ CustomFont = This parameter defines the Font that will be used in the created widget.
496
+ CustomFontSize = This parameter defines the custom Font Size that the widget will have.
497
+ CustomFontExtra = This parameter defines any extra properties the font can have, such as Bold.
498
+ (Options: 'Bold', 'Italic', 'Underline', 'Overstrike'.)
499
+ BgColor = Defines the background color of the widget.
500
+ FgColor = Defines the foreground color of the widget.
501
+
502
+ **Custom Keybind Parameters:**
503
+ CommandKeybind = What the custom keybind of said widget will be. Must have CommandFunction to work.
504
+ CommandFunction = The command that will be executed when pressing the respective keybind. Must have CommandKeybind to work.
505
+
506
+ **CheckBox Specific Parameters:**
507
+ CheckBoxState = 'NORMAL' for the checkbox to function normally. 'DISABLED' for the checkbox to not work.
508
+ CheckBoxOnValue = The value that the checkbox will return when on.
509
+ CheckBoxOffValue = The value that the checkbox will return when off.
510
+
511
+ # Packing Types and their parameters:
512
+
513
+ **Pack (The default type, packs label and contains borders.):**
514
+ PadX = Width for the padding of the label.
515
+ PadY = Height for the padding of the label.
516
+ Side = Side where the label will go to in the widget, is relative.
517
+ Sticky = Position where the label will stick to in the widget, is not relative.
518
+
519
+ **Grid (for mounting grids and organized sheets):**
520
+ Row = The row where your element will be placed. (Horizontal)
521
+ Column = the column where your element will be placed. (Vertical)
522
+ PadX = the padding width your element will have, affects elements in and outside of the grid.
523
+ PadY = the padding height your element will have, affects elements in and outside of the grid.
524
+
525
+ **Place (for accurately placing elements in absolute or relative positions):**
526
+ X = The absolute position of the element in your window, cannot be moved. (Width)
527
+ Y = The absolute position of the element in your window, cannot be moved. (Height)
528
+ RelX = The relative position of the element in your window, can be moved. (Width)
529
+ RelY = The relative position of the element in your window, can be moved. (Height)
530
+ """
531
+
532
+ if not ForWindow or not WidgetType:
533
+ raise ValueError("Could not create a bool input widget as the essential parameters were not filled. Did you try checking 'ForWindow' and 'WidgetType'?")
534
+
535
+ else:
536
+ WidgetType = WidgetType.lower()
537
+
538
+ if WidgetType == "checkbutton":
539
+ NewBool = tk.Checkbutton(ForWindow, bd=Border, text=CustomText, anchor=Anchor, font=(CustomFont.capitalize(), CustomFontSize, CustomFontExtra.capitalize()), bg=BgColor, fg=FgColor, state=CheckBoxState, onvalue=CheckBoxOnValue, offvalue=CheckBoxOffValue)
540
+
541
+ elif WidgetType == "radiobutton":
542
+ NewBool = tk.Radiobutton(ForWindow, bd=Border, anchor=Anchor, text=CustomText, font=(CustomFont.capitalize(), CustomFontSize, CustomFontExtra.capitalize()), bg=BgColor, fg=FgColor)
543
+
544
+ elif WidgetType == "listbox":
545
+ NewBool = tk.Listbox(ForWindow, bd=Border, text=CustomText, font=(CustomFont.capitalize(), CustomFontSize, CustomFontExtra.capitalize()), bg=BgColor, fg=FgColor)
546
+
547
+ if CommandKeybind is not None and CommandFunction is not None:
548
+ def eventNeedlessFunction(event):
549
+ CommandFunction()
550
+
551
+ NewBool.bind(CommandKeybind, eventNeedlessFunction)
552
+
553
+ elif CommandKeybind is not None or CommandFunction is not None:
554
+ raise ValueError("Could not bind a command to this widget as one of the proper 'Command__' were not filled. Did you try checking both the 'Command__' parameters?")
555
+
556
+ if PackType is not None:
557
+ PackType = PackType.lower()
558
+
559
+ if PackType is not None and PackType not in ["place", "grid", "pack"]:
560
+ raise ValueError(f"Expected a proper packing style, but got {PackType} instead. Current packing types are 'Pack', 'Grid', or 'Place'")
561
+
562
+ elif PackType == "pack":
563
+ NewBool.pack(anchor=Anchor, padx=PadX, pady=PadY, side=Side, sticky=Sticky)
564
+
565
+ elif PackType == "place":
566
+ NewBool.place(x=X, y=Y, relx=RelX, rely=RelY, anchor=Anchor)
567
+
568
+ elif PackType == "grid":
569
+ NewBool.grid(row=Row if Row is not None else 0, column=Column if Column is not None else 0, padx=PadX, pady=PadY)
570
+
571
+ return NewBool
572
+ #endregion
573
+
574
+ #region Better Bind With Additional Improved Features
575
+ def BetterBind(TargetWindow, KeyToBind, FunctionToBind, After=1, RepeatTimes=0, RepeatDelay=1):
576
+ """
577
+ # A function that improves Tkinter's .bind() feature, improving it with a new nit-picked quality of life add-ons.
578
+
579
+ **Necessary parameters:**
580
+ TargetWindow = The Tkinter element you want to bind your function and keybind to.
581
+ FunctionToBind = The function you wish to bind to a key, that runs within the element.
582
+ KeyToBind = The Keybind you want to set to your element to run your script.
583
+ (Luckily, here's a couple references!)
584
+ https://web.archive.org/web/20190512164300id_/http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/event-types.html
585
+ https://web.archive.org/web/20190515021108id_/http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/key-names.html
586
+ https://www.tcl-lang.org/man/tcl8.4/TkCmd/keysyms.htm
587
+
588
+ **Additional parameters:**
589
+ After = Dictates the time in **milliseconds** the function will take to run.
590
+ RepeatTimes = The amount of times the function will repeat after running once.
591
+ (Note: You can repeat infinitely by typing 'inf' or -1.)
592
+ RepeatDelay = The delay in **milliseconds** that a function will take to repeat.
593
+ """
594
+
595
+ if TargetWindow and KeyToBind and FunctionToBind:
596
+ #this is for a single key
597
+ if len(KeyToBind) == 1:
598
+ FinalKey = KeyToBind
599
+
600
+ #this is for the war veterans whose died plenty for not using <>
601
+ elif KeyToBind.startswith("<") and KeyToBind.endswith(">"):
602
+ KeyToBind = KeyToBind.title()
603
+
604
+ FinalKey = f"{KeyToBind}"
605
+
606
+ #and for the people with dementia
607
+ else:
608
+ KeyToBind = KeyToBind.title()
609
+
610
+ FinalKey = f"<{KeyToBind}>"
611
+
612
+ def EventlessBind(event):
613
+ def StartFunctions():
614
+ FunctionRunCount = 0
615
+
616
+ def repeatingFunction():
617
+ nonlocal FunctionRunCount, RepeatTimes
618
+ FunctionToBind()
619
+
620
+ if isinstance(RepeatTimes, str) and RepeatTimes.lower() == "inf":
621
+ RepeatTimes = -1
622
+
623
+ elif isinstance(RepeatTimes, str) and RepeatTimes != "inf":
624
+ raise TypeError("The function oculd not be repeated as the value typed for RepeatTimes is invalid. Did you try checking the RepeatTimes value type?")
625
+
626
+ FunctionRunCount += 1
627
+
628
+ if FunctionRunCount <= RepeatTimes or RepeatTimes == -1:
629
+ TargetWindow.after(RepeatDelay, repeatingFunction)
630
+
631
+ repeatingFunction()
632
+
633
+ TargetWindow.after(After, StartFunctions)
634
+
635
+ TargetWindow.bind(FinalKey, EventlessBind)
636
+
637
+ else:
638
+ raise ValueError("Could not bind function to an element as one of the necessary parameters were not filled. Have you tried filling all '__ToBind' parameters?")
639
+ #endregion
640
+
641
+ #region Moving Windows and Changing Their Geometry Smoothly Function
642
+ def BetterGeometry(TargetWindow, SizeX=0, SizeY=0, PosX=None, PosY=None, SizeSmooth=0, PosSmooth=0, Delay=1):
643
+ """
644
+ # This function is a better way to set a window's geometry, both in size and position on screen, smoothing included.
645
+
646
+ **TargetWindow** = The window in which position or size will be altered.
647
+
648
+ **Geometry Positions:**
649
+ SizeX = The final width that the window will have.
650
+ SizeY = The final height that the window will have.
651
+ PosX = The final width position that the window will have.
652
+ PosY = The final height position that the window will have.
653
+
654
+ **Additional Parameters:**
655
+ SizeSmooth = How much the change from the current size to the final size will be smoothed. **The lesser the number, the smoother.**
656
+ PosSmooth = How much the movement from the current position to the final position will be smoothed. **The lesser the number, the smoother.**
657
+ Delay = The delay in time that will take for the window to go to it's next position. **The lesser the number, the smoother.**
658
+ """
659
+
660
+ TargetWindowX = TargetWindow.winfo_width()
661
+ TargetWindowY = TargetWindow.winfo_height()
662
+
663
+ if SizeSmooth == 0 and PosSmooth == 0:
664
+ TargetWindow.geometry(f"{SizeX if SizeX != 0 else TargetWindowX}x{SizeY if SizeY != 0 else TargetWindowY}{f'+{PosX}' if PosX is not None else ''}{f'+{PosY}' if PosY is not None else ''}")
665
+
666
+ else:
667
+ s_smooth = max(1, int(SizeSmooth)) if SizeSmooth and SizeSmooth > 0 else 0
668
+ p_smooth = max(1, int(PosSmooth)) if PosSmooth and PosSmooth > 0 else 0
669
+
670
+ curX, curY = TargetWindow.winfo_x(), TargetWindow.winfo_y()
671
+ curW, curH = TargetWindow.winfo_width(), TargetWindow.winfo_height()
672
+
673
+ tX = int(PosX) if PosX is not None else curX
674
+ tY = int(PosY) if PosY is not None else curY
675
+ tW = int(SizeX) if (SizeX is not None and SizeX != 0) else curW
676
+ tH = int(SizeY) if (SizeY is not None and SizeY != 0) else curH
677
+
678
+ def TheTrueSmooth():
679
+ nonlocal curX, curY, curW, curH
680
+
681
+ if p_smooth > 0:
682
+ if curX != tX:
683
+ diffX = tX - curX
684
+ if abs(diffX) <= p_smooth: curX = tX
685
+ else: curX += p_smooth if diffX > 0 else -p_smooth
686
+ if curY != tY:
687
+ diffY = tY - curY
688
+ if abs(diffY) <= p_smooth: curY = tY
689
+ else: curY += p_smooth if diffY > 0 else -p_smooth
690
+
691
+ if s_smooth > 0:
692
+ if curW != tW:
693
+ diffW = tW - curW
694
+ if abs(diffW) <= s_smooth: curW = tW
695
+ else: curW += s_smooth if diffW > 0 else -s_smooth
696
+ if curH != tH:
697
+ diffH = tH - curH
698
+ if abs(diffH) <= s_smooth: curH = tH
699
+ else: curH += s_smooth if diffH > 0 else -s_smooth
700
+
701
+ TargetWindow.geometry(f"{curW}x{curH}+{curX}+{curY}")
702
+
703
+ if curX != tX or curY != tY or curW != tW or curH != tH:
704
+ TargetWindow.after(Delay, TheTrueSmooth)
705
+
706
+ TheTrueSmooth()
707
+ #endregion
708
+
709
+ #endregion
710
+
711
+ ############################################
712
+ # time to move on to tk.Canvas, my nightmare
713
+ ############################################
714
+
715
+ #region ahhh... tk.Canvas, where hell sets loose
716
+
717
+ #region Function that Automatically Creates and Packs Canvas
718
+ def CreateCanvas(TargetWindow, SizeX=250, SizeY=250, BgColor="#f0f0f0", PackType=None, Anchor="center", PadX=0, PadY=0, Side=tk.TOP, Row=0, Column=0, Sticky=None, X=None, Y=None, RelX=None, RelY=None):
719
+ """
720
+ # Creates a tk.Canvas element and automatically packs it.
721
+
722
+ **Necessary parameters:**
723
+ TargetWindow = The window that will be receiving the Canvas.
724
+
725
+ **Geometry Parameters:**
726
+ SizeX = The width in pixels of the Canvas Widget.
727
+ SizeY = The height in pixels of the Canvas Widget.
728
+
729
+ **Extra Customization:**
730
+ BgColor = What the background of the label will be colored as.
731
+
732
+ # Packing Types and their parameters:
733
+
734
+ **Pack (The default type, packs label and contains borders.):**
735
+ PadX = Width for the padding of the label.
736
+ PadY = Height for the padding of the label.
737
+ Side = Side where the label will go to in the widget, is relative.
738
+ Sticky = Position where the label will stick to in the widget, is not relative.
739
+
740
+ **Grid (for mounting grids and organized sheets):**
741
+ Row = The row where your element will be placed. (Horizontal)
742
+ Column = the column where your element will be placed. (Vertical)
743
+ PadX = the padding width your element will have, affects elements in and outside of the grid.
744
+ PadY = the padding height your element will have, affects elements in and outside of the grid.
745
+
746
+ **Place (for accurately placing elements in absolute or relative positions):**
747
+ X = The absolute position of the element in your window, cannot be moved. (Width)
748
+ Y = The absolute position of the element in your window, cannot be moved. (Height)
749
+ RelX = The relative position of the element in your window, can be moved. (Width)
750
+ RelY = The relative position of the element in your window, can be moved. (Height)
751
+ """
752
+
753
+ if not isinstance(TargetWindow, (tk.Tk, tk.Toplevel)):
754
+ raise TypeError(f"Expected a Tkinter window, but got {type(TargetWindow).__name__} instead.")
755
+
756
+ NewCanvas = tk.Canvas(TargetWindow, width=SizeX, height=SizeY, bg=BgColor)
757
+
758
+ if PackType is not None:
759
+ PackType = PackType.lower()
760
+
761
+ if PackType is not None and PackType not in ["place", "grid", "pack"]:
762
+ raise ValueError(f"Expected a proper packing style, but got {PackType} instead. Current packing types are 'Pack', 'Grid', or 'Place'")
763
+
764
+ elif PackType == "pack":
765
+ NewCanvas.pack(anchor=Anchor, padx=PadX, pady=PadY, side=Side, sticky=Sticky)
766
+
767
+ elif PackType == "place":
768
+ NewCanvas.place(x=X, y=Y, relx=RelX, rely=RelY, anchor=Anchor)
769
+
770
+ elif PackType == "grid":
771
+ NewCanvas.grid(row=Row, column=Column, padx=PadX, pady=PadY)
772
+
773
+ return NewCanvas
774
+ #endregion
775
+
776
+ #region Creating Various Shapes in Canvas
777
+ def CreateCanvasShapes(ForCanvas, Shape, PosX, PosY, SquareSize=25, RectangleX=20, RectangleY=40, CircleSize=25, OvalX=20, OvalY=40, color="blue", OutlineColor="black", ActiveColor=None):
778
+ """
779
+ # Creates a custom shape for a tk.Canvas and automatically centers it in the give ncoordinates and size.
780
+
781
+ **Necessary parameters:**
782
+ ForCanvas = Dictates the used tk.Canvas that the shape will be placed in.
783
+ Shape = What shape will be placed in the tk.Canvas.
784
+ (Options: Square, Rectangle, Circle, Oval)
785
+
786
+ **Geometry parameters:**
787
+ PosX = The horizontal position in pixels where the shape will be placed.
788
+ PosY = The vertical position in pixels where the shape will be placed.
789
+
790
+ **Customization parameters:**
791
+ Color = The color that the shape will be filled with.
792
+ OutlineColor = The color of the shape's border.
793
+ ActiveColor = The color that the shappe will have when it's hovered on, changes back to normal when hovering off.
794
+
795
+ # Shape specific parameters
796
+
797
+ **Square parameters:**
798
+ SquareSize = The size in pixels that the square will have.
799
+
800
+ **Circle parameters:**
801
+ CircleSize = The size in pixels that the circle will have.
802
+
803
+ **Rectangle parameters:**
804
+ RectangleX = The width of the rectangle in pixels.
805
+ RectangleY = The height of the rectangle in pixels.
806
+
807
+ **Oval parameters:**
808
+ OvalX = The width of the oval in pixels.
809
+ OvalY = The height of the oval in pixels.
810
+ """
811
+
812
+ if not isinstance(ForCanvas, tk.Canvas):
813
+ raise ValueError(f"Could not create custom canvas shape as {ForCanvas} is not a valid canvas. Did you try checking the tk.Canvas given?")
814
+
815
+ Shape = Shape.lower()
816
+ color = color.lower()
817
+ OutlineColor = OutlineColor.lower()
818
+ ActiveColor = color if ActiveColor is None else ActiveColor.lower()
819
+
820
+ if Shape == "square":
821
+ offset = SquareSize // 2
822
+ NewShape = ForCanvas.create_rectangle(PosX - offset, PosY - offset, PosX + offset, PosY + offset, fill=color, outline=OutlineColor, activefill=ActiveColor)
823
+
824
+ elif Shape == "rectangle":
825
+ Xoffset = RectangleX // 2
826
+ Yoffset = RectangleY // 2
827
+
828
+ x1 = PosX - Yoffset
829
+ y1 = PosY - Xoffset
830
+ x2 = PosX + Yoffset
831
+ y2 = PosY + Xoffset
832
+
833
+ NewShape = ForCanvas.create_rectangle(x1, y1, x2, y2, fill=color, outline=OutlineColor, activefill=ActiveColor)
834
+
835
+ elif Shape == "circle":
836
+ offset = CircleSize // 2
837
+ NewShape = ForCanvas.create_oval(PosX - offset, PosY - offset, PosX + offset, PosY + offset, fill=color, outline=OutlineColor, activefill=ActiveColor)
838
+
839
+ elif Shape == "oval":
840
+ Xoffset = OvalX // 2
841
+ Yoffset = OvalY // 2
842
+
843
+ x1 = PosX - Xoffset
844
+ y1 = PosY - Yoffset
845
+ x2 = PosX + Yoffset
846
+ y2 = PosY + Xoffset
847
+
848
+ NewShape = ForCanvas.create_oval(x1, y1, x2, y2, fill=color, outline=OutlineColor, activefill=ActiveColor)
849
+
850
+ else:
851
+ raise ValueError(f"Could not create custom canvas shape as {Shape} is not a valid option. Did you try checking the allowed shapes in the doctype?")
852
+
853
+ return NewShape
854
+ #endregion
855
+
856
+ #endregion
857
+
858
+ #############################################
859
+ # time to do some extra stuff that's cool too
860
+ #############################################
861
+
862
+ #region Messing with Pillow and Image Rendering
863
+ def BetterPhotoImage(Image, RotateDegrees=None, RotateChangeSize=False, ResizeImageX=None, ResizeImageY=None, MirrorImage=None):
864
+ """
865
+ # Renders and modifies a custom image using PIL and returns the modified Tkinter ready image.
866
+
867
+ **Required parameters:**
868
+ Image = The file name of the image being used.
869
+
870
+ **Image customization parameters:**
871
+ RotateDegrees = The angle, in degrees, where the image will be rotated. **Must be an integer.**
872
+ RotateChangeSize = Wether when rotating an image, the size will maintain for be affected. **Does not work without RotateDegrees.**
873
+ MirrorImage = If the image will be mirrored vertically or horizontally.
874
+ (Options: 'None', 'Vertical', 'Horizontal')
875
+
876
+ **Resizing parameters:**
877
+ ResizeImageX = Value, in pixels, what the window's width will be resized to.
878
+ ResizeImageY = Valye, in pixels, what the window's height will be resized to.
879
+ """
880
+ #function to tell wether the image is actually valid
881
+ def is_valid_image_pillow(imgg):
882
+ try:
883
+ with img.open(imgg) as immg:
884
+ immg.verify()
885
+ return True
886
+ except (IOError, SyntaxError):
887
+ return False
888
+ #liar liar pants on fire i guess
889
+
890
+ #back to the actual code
891
+ if is_valid_image_pillow(Image):
892
+ NewImage = img.open(Image)
893
+
894
+ if NewImage.mode != 'RGBA':
895
+ NewImage = NewImage.convert('RGBA')
896
+
897
+ IMGwidth, IMGheight = NewImage.size
898
+
899
+ if RotateDegrees is not None:
900
+ if not isinstance(RotateDegrees, bool):
901
+ warn.warn(f"'RotateChangeSize' value was {RotateChangeSize} and as it is not True or False, was defaulted to false.")
902
+ RotateChangeSize = False
903
+
904
+ if not isinstance(RotateDegrees, int):
905
+ raise TypeError("Could not properly rotate image as the value given was not a proper integer. Did you try ")
906
+
907
+ NewImage = NewImage.rotate(RotateDegrees, expand=RotateChangeSize, fillcolor=(0, 0, 0, 0))
908
+ IMGwidth, IMGheight = NewImage.size
909
+
910
+ if ResizeImageX is not None or ResizeImageY is not None:
911
+ NewImage = NewImage.resize((ResizeImageX if ResizeImageX is not None else IMGwidth, ResizeImageY if ResizeImageY is not None else IMGheight))
912
+
913
+ if MirrorImage is not None:
914
+ MirrorImage = MirrorImage.lower()
915
+
916
+ if MirrorImage == "vertical":
917
+ NewImage = NewImage.transpose(Image.FLIP_TOP_BOTTOM)
918
+
919
+ elif MirrorImage == "horizontal":
920
+ NewImage = NewImage.transpose(Image.FLIP_TOP_BOTTOM)
921
+
922
+ else:
923
+ raise ValueError("Could not flip image as the given value was not 'vertical' or 'horizontal'. Did you try checking the 'MirrorImage' value?")
924
+
925
+ NewImage = imgtk.PhotoImage(NewImage)
926
+
927
+ return NewImage
928
+
929
+ else:
930
+ raise ValueError("Could not create a ImageTk image as the file given was not a proper image file/format. Did you try checking the 'Image' parameter given?")
931
+
932
+ #endregion
@@ -0,0 +1,8 @@
1
+ from .EasyKinter import *
2
+
3
+ import tkinter
4
+ tk = tkinter
5
+
6
+ from PIL import Image, ImageTk
7
+ PILimg = Image
8
+ PILimgtk = ImageTk
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.4
2
+ Name: easykinter
3
+ Version: 0.0.1
4
+ Summary: A wrapper to make Tkinter 90% less boring.
5
+ Author-email: Starly <starly.alt.acc1@gmail.com>
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Operating System :: Microsoft :: Windows
9
+ Requires-Python: >=3.12
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: pillow>=10.0.0
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/easykinter/EasyKinter.py
4
+ src/easykinter/__init__.py
5
+ src/easykinter.egg-info/PKG-INFO
6
+ src/easykinter.egg-info/SOURCES.txt
7
+ src/easykinter.egg-info/dependency_links.txt
8
+ src/easykinter.egg-info/requires.txt
9
+ src/easykinter.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ pillow>=10.0.0
@@ -0,0 +1 @@
1
+ easykinter