VIStk 0.3.12.14__py3-none-any.whl

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,153 @@
1
+ import os
2
+ import json
3
+ import shutil
4
+ import re
5
+ import glob
6
+ from VIStk.Structures.VINFO import *
7
+ import tkinter as TK
8
+
9
+ class Screen(VINFO):
10
+ """A VIS screen object
11
+ """
12
+ def __init__(self,name:str,script:str,release:bool=False,icon:str=None,exists:bool=True,desc:str=None):
13
+ super().__init__()
14
+ self.name=name
15
+ self.script=script
16
+ self.release=release
17
+ self.icon=icon
18
+ self.path = self.p_screens+"/"+self.name
19
+ self.m_path = self.p_modules+"/"+self.name
20
+
21
+ if not exists:
22
+ with open(self.p_sinfo,"r") as f:
23
+ info = json.load(f)
24
+
25
+ info[self.title]["Screens"][self.name] = {"script":script,"release":release}
26
+ if not icon == None:
27
+ info[self.title]["Screens"][self.name]["icon"] = icon
28
+
29
+ if not desc == None:
30
+ info[self.title]["Screens"][self.name]["desc"] = desc
31
+ else:
32
+ info[self.title]["Screens"][self.name]["desc"] = "A VIS Created Executable"
33
+
34
+ info[self.title]["Screens"][self.name]["version"] = "1.0.0"#always making first major version of screen
35
+
36
+ info[self.title]["Screens"][self.name]["current"] = None#always making first major version of screen
37
+
38
+ with open(self.p_sinfo,"w") as f:
39
+ json.dump(info,f,indent=4)
40
+
41
+ shutil.copyfile(self.p_templates+"/screen.txt",self.p_project+"/"+script)
42
+ os.mkdir(self.p_screens+"/"+self.name)
43
+ os.mkdir(self.p_modules+"/"+self.name)
44
+
45
+ with open(self.p_sinfo,"r") as f:
46
+ info = json.load(f)
47
+ self.desc = info[self.title]["Screens"][self.name]["desc"]
48
+ self.s_version = info[self.title]["Screens"][self.name]["version"]
49
+ self.current = info[self.title]["Screens"][self.name]["current"]
50
+
51
+ def addElement(self,element:str) -> int:
52
+ if validName(element):
53
+ if not os.path.exists(self.path+"/f_"+element+".py"):
54
+ shutil.copyfile(self.p_templates+"/f_element.txt",self.path+"/f_"+element+".py")
55
+ print(f"Created element f_{element}.py in {self.path}")
56
+ self.patch(element)
57
+ if not os.path.exists(self.m_path+"/m_"+element+".py"):
58
+ with open(self.m_path+"/m_"+element+".py", "w"): pass
59
+ print(f"Created module m_{element}.py in {self.m_path}")
60
+ return 1
61
+ else:
62
+ return 0
63
+
64
+ def addMenu(self,menu:str) -> int:
65
+ pass #will be command line menu creation tool
66
+
67
+ def patch(self,element:str) -> int:
68
+ """Patches up the template after its copied
69
+ """
70
+ if os.path.exists(self.path+"/f_"+element+".py"):
71
+ with open(self.path+"/f_"+element+".py","r") as f:
72
+ text = f.read()
73
+ text = text.replace("<frame>","f_"+element)
74
+ with open(self.path+"/f_"+element+".py","w") as f:
75
+ f.write(text)
76
+ print(f"patched f_{element}.py")
77
+ return 1
78
+ else:
79
+ print(f"Could not patch, element does not exist.")
80
+ return 0
81
+
82
+ def stitch(self) -> int:
83
+ """Connects screen elements to a screen
84
+ """
85
+ with open(self.p_project+"/"+self.script,"r") as f: text = f.read()
86
+ stitched = []
87
+ #Elements
88
+ pattern = r"#Screen Elements.*#Screen Grid"
89
+
90
+ elements = glob.glob(self.path+'/f_*')#get all elements
91
+ for i in range(0,len(elements),1):#iterate into module format
92
+ elements[i] = elements[i].replace("\\","/")
93
+ elements[i] = elements[i].replace(self.path+"/","Screens."+self.name+".")[:-3]
94
+ stitched.append(elements[i])
95
+ #combine and change text
96
+ elements = "from " + " import *\nfrom ".join(elements) + " import *\n"
97
+ text = re.sub(pattern, "#Screen Elements\n" + elements + "\n#Screen Grid", text, flags=re.DOTALL)
98
+
99
+ #Modules
100
+ pattern = r"#Screen Modules.*#Handle Arguments"
101
+
102
+ modules = glob.glob(self.m_path+'/m_*')#get all modules
103
+ for i in range(0,len(modules),1):#iterate into module format
104
+ modules[i] = modules[i].replace("\\","/")
105
+ modules[i] = modules[i].replace(self.m_path+"/","modules."+self.name+".")[:-3]
106
+ stitched.append(modules[i])
107
+ #combine and change text
108
+ modules = "from " + " import *\nfrom ".join(modules) + " import *\n"
109
+ text = re.sub(pattern, "#Screen Modules\n" + modules + "\n#Handle Arguments", text, flags=re.DOTALL)
110
+
111
+ #write out
112
+ with open(self.p_project+"/"+self.script,"w") as f:
113
+ f.write(text)
114
+ print("Stitched: ")
115
+ for i in stitched:
116
+ print(f"\t{i} to {self.name}")
117
+
118
+ def syncVersion(self) -> int:
119
+ """Syncs the version stored in sinfo with the version in memory
120
+ """
121
+ with open(self.p_sinfo,"r") as f:
122
+ info = json.load(f)
123
+ info[self.title]["Screens"][self.name]["current"] = self.current
124
+ with open(self.p_sinfo,"w") as f:
125
+ json.dump(info,f)
126
+ return 1
127
+
128
+ def crntVersion(self) -> int:
129
+ """Checks if the version needs to be synced and returns 1 if its synced
130
+ """
131
+ if not self.s_version == self.current:
132
+ self.current = self.version
133
+ self.syncVersion()
134
+ return 1
135
+ else:
136
+ return 0
137
+
138
+ def unLoad(self,root:TK.Tk) -> int:
139
+ """Unloads all elements on the screen"""
140
+ for element in root.winfo_children():
141
+ try:
142
+ element.destroy()
143
+ except: pass
144
+ #might fail to delete widgets that get deleted by earlier deletions
145
+
146
+ def load(self) -> int:
147
+ """Loads a new screen onto the root"""
148
+ #should just need to run the python file now
149
+ #cant do that through subprocess.call when compiling
150
+ #can make python dlls? something like this for each screen
151
+ #then itll be easy to load/unload elements
152
+ #can even have these dlls take a parameter for the root
153
+ #then we can do splitscreen and windowed things if we want
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,5 @@
1
+ coll = COLLECT($insert$
2
+ strip=False,
3
+ upx=True,
4
+ upx_exclude=[],
5
+ name='$version$')
@@ -0,0 +1,25 @@
1
+ #Default Imports
2
+ from tkinter import *
3
+ from tkinter import ttk
4
+ from Screens.root import *
5
+ #File Specific Imports
6
+
7
+ #Create Frame
8
+ <frame> = ttk.Frame(root)
9
+ <frame>.grid(column=0,row=0,columnspan=1,rowspan=1,sticky=(N, S, E, W))
10
+
11
+ #Configure Frame Grid
12
+ <frame>.columnconfigure(1,weight=1)
13
+ <frame>.rowconfigure(1,weight=1)
14
+
15
+ #Declare Stringvars
16
+
17
+ #Button Commands and Functions
18
+
19
+ #Navigation
20
+
21
+ #########################
22
+ #####Visual Elements#####
23
+ #########################
24
+
25
+ #Element Descriptions
@@ -0,0 +1,43 @@
1
+ #Default Imports
2
+ from tkinter import *
3
+ from tkinter import ttk
4
+ from Screens.root import *
5
+ import sys
6
+ #File Specific Imports
7
+
8
+ #Configure Screen
9
+ w = 1080
10
+ h = 720
11
+ ws = root.winfo_screenwidth()
12
+ hs = root.winfo_screenheight()
13
+ x = (ws/2) - (w/2)
14
+ y = (hs/2) - (h/2)
15
+ root.geometry('%dx%d+%d+%d' % (w, h, x, y))
16
+ root.title("Placeholder Title")
17
+ root.minsize(1080,720)
18
+ #root.iconbitmap("<project>/Images/Icons/<some_icon>")
19
+
20
+ #Screen Elements
21
+
22
+ #Screen Grid
23
+ root.grid_columnconfigure(0,weight=1)
24
+ root.grid_rowconfigure(0,weight=1)
25
+
26
+ #Screen Modules
27
+
28
+ #Handle Arguments
29
+
30
+ #Define Loop Modules
31
+ def loop():
32
+ #screen modules run here
33
+ 1+1
34
+
35
+ #Update Loop
36
+ while True:
37
+ try:
38
+ if root.winfo_exists():
39
+ try:loop()
40
+ except:pass
41
+ root.update()
42
+ except:
43
+ break
@@ -0,0 +1,33 @@
1
+ $name$_a = Analysis(
2
+ ['../$file$'],
3
+ pathex=[],
4
+ binaries=[],
5
+ datas=[],
6
+ hiddenimports=[],
7
+ hookspath=[],
8
+ hooksconfig={},
9
+ runtime_hooks=[],
10
+ excludes=[],
11
+ noarchive=False,
12
+ optimize=0,)
13
+ $name$_pyz = PYZ($name$_a.pure)
14
+ $name$_exe = EXE(
15
+ $name$_pyz,
16
+ $name$_a.scripts,
17
+ $name$_a.binaries,
18
+ $name$_a.datas,
19
+ [],
20
+ exclude_binaries=True,
21
+ name='$name$',
22
+ debug=False,
23
+ bootloader_ignore_signals=False,
24
+ strip=False,
25
+ upx=True,
26
+ console=False,
27
+ disable_windowed_traceback=False,
28
+ argv_emulation=False,
29
+ target_arch=None,
30
+ codesign_identity=None,
31
+ entitlements_file=None,
32
+ icon=['../Icons/$icon$.ico'],
33
+ version='$meta$')
@@ -0,0 +1,30 @@
1
+ # UTF-8
2
+
3
+ VSVersionInfo(
4
+ ffi=FixedFileInfo(
5
+ filevers=($sM$,$sm$,$sp$,0),
6
+ prodvers=($M$,$m$,$p$,0),
7
+ mask=0x3f,
8
+ flags=0x0,
9
+ OS=0x40004,
10
+ fileType=0x1,
11
+ subtype=0x0,
12
+ date=(0, 0)
13
+ ),
14
+ kids=[
15
+ StringFileInfo(
16
+ [
17
+ StringTable(
18
+ u'040904B0',
19
+ [StringStruct(u'CompanyName', u'$company$'),
20
+ StringStruct(u'FileDescription', u'$desc$'),
21
+ StringStruct(u'FileVersion', u'$sM$.$sm$.$sp$'),
22
+ StringStruct(u'InternalName', u'$title$-$name$'),
23
+ StringStruct(u'LegalCopyright', u'Copyright © $year$ $company$'),
24
+ StringStruct(u'OriginalFilename', u'$name$.exe'),
25
+ StringStruct(u'ProductName', u'$name$'),
26
+ StringStruct(u'ProductVersion', u'$M$.$m$.$p$')])
27
+ ]),
28
+ VarFileInfo([VarStruct(u'Translation', [1033, 1200])])
29
+ ]
30
+ )
VIStk/VIS.py ADDED
@@ -0,0 +1,54 @@
1
+ import sys
2
+ import os
3
+ import zipfile
4
+ from importlib import metadata
5
+ from VIStk.Structures import *
6
+
7
+ inp = sys.argv
8
+ print(f"VIS Version {metadata.version("VIStk")}")
9
+
10
+
11
+ #Copied from source https://stackoverflow.com/a/75246706
12
+ def unzip_without_overwrite(src_path, dst_dir):
13
+ with zipfile.ZipFile(src_path, "r") as zf:
14
+ for member in zf.infolist():
15
+ file_path = os.path.join(dst_dir, member.filename)
16
+ if not os.path.exists(file_path):
17
+ zf.extract(member, dst_dir)
18
+ def __main__():
19
+ match inp[1]:
20
+ case "new"|"New"|"N"|"n":#Create a new VIS project
21
+ project = VINFO()
22
+
23
+ case "add" | "Add" | "a" | "A":
24
+ project = Project()
25
+ match inp[2]:
26
+ case "screen" | "Screen" | "s" | "S":
27
+ if not inp[3] == None:
28
+ screen = project.verScreen(inp[3])
29
+ if len(inp) >= 5:
30
+ match inp[4]:
31
+ case "menu" | "Menu" | "m" | "M":
32
+ screen.addMenu(inp[5])
33
+ case "elements" | "Elements" | "e" | "E":
34
+ for i in inp[5].split("-"):
35
+ screen.addElement(i)
36
+ screen.stitch()
37
+ else:
38
+ project.newScreen(inp[3])
39
+
40
+ case "stitch" | "Stitch" | "s" | "S":
41
+ project = Project()
42
+ screen = project.getScreen(inp[2])
43
+ if not screen == None:
44
+ screen.stitch()
45
+ else:
46
+ print("Screen does not exist")
47
+
48
+ case "release" | "Release" | "r" | "R":
49
+ if len(inp) == 4:
50
+ #newRelease(inp[2],inp[3])
51
+ pass
52
+ else:
53
+ #newRelease(inp[2])
54
+ pass
@@ -0,0 +1,36 @@
1
+ from tkinter import *
2
+ from tkinter import ttk
3
+ import subprocess
4
+ import os
5
+
6
+ class MenuItem():
7
+ """Each item in the menu is created from the corresponding .json file. Each path should be given relative to xyz/WOM/
8
+ """
9
+ def __init__(self,parent:Frame|Toplevel|LabelFrame|Tk,path,nav,*args,**kwargs):
10
+ """Create an item in a row on the menu
11
+ Args:
12
+ root (Tk): Master root for destruction on redirect
13
+ _root (Toplevel): Toplevel object to create menu items in
14
+ path (str): Name of .exe or absolute path to python script
15
+ nav (str): Navigation character to click button
16
+ """
17
+ self.button = Button(master=parent, *args, **kwargs)
18
+ self.parent = parent
19
+ self.root = parent.winfo_toplevel()
20
+ self.path = path
21
+ self.nav = nav
22
+ self.button.config(command = self.itemPath)
23
+ enter = lambda event: event.widget.configure(background="dodger blue")
24
+ leave = lambda event: event.widget.configure(background="gray94")
25
+ self.button.bind("<Enter>", enter)
26
+ self.button.bind("<Leave>", leave)
27
+ #self.button.pack()
28
+
29
+ def itemPath(self):
30
+ """Opens the given path or exe for the button
31
+ """
32
+ if ".exe" in self.path:
33
+ os.startfile(self.path)
34
+ else:
35
+ subprocess.call("pythonw.exe "+self.path)
36
+ self.root.destroy()
@@ -0,0 +1,22 @@
1
+ from VIStk.Objects import *
2
+ from VIStk.Widgets._VISMenu import VISMenu
3
+ from tkinter import *
4
+
5
+ class MenuWindow(SubRoot):
6
+ def __init__(self,parent:Tk|Toplevel,path:str,*args,**kwargs):
7
+ super().__init__(*args,**kwargs)
8
+
9
+ #Ensure visibility
10
+ self.focus_force()
11
+
12
+ #Load Menu
13
+ self.menu = VISMenu(self, path)
14
+
15
+ #SubWindow Geometry
16
+ self.update()
17
+ self.WindowGeometry.getGeometry(True)
18
+ self.WindowGeometry.setGeometry(width=self.winfo_width(),
19
+ height=self.winfo_height(),
20
+ align="center",
21
+ size_style="window_relative",
22
+ window_ref=parent)
@@ -0,0 +1,89 @@
1
+ from typing import Literal
2
+ from tkinter import *
3
+ from tkinter import ttk
4
+ from VIStk.Objects import SubRoot
5
+
6
+ class QuestionWindow(SubRoot):
7
+ """An empty popout window"""
8
+ def __init__(self, question:str|list[str], answer:str, parent:Toplevel|Tk, ycommand=None, droplist:list=None, *args,**kwargs):
9
+ """Will create a question window
10
+ y = yes
11
+ n = no
12
+ r = return
13
+ u = continue
14
+ b = back
15
+ x = close
16
+ c = confirm
17
+ d = dropdown
18
+ """
19
+ super().__init__(*args,**kwargs)
20
+ cs = len(list(answer))
21
+
22
+ for i in range(0,cs,1):
23
+ self.columnconfigure(i,weight=1)
24
+
25
+ #Resolve Question
26
+ if isinstance(question, str):
27
+ self.rowconfigure(0, weight=1)
28
+ rs = 1
29
+ Label(self, text=question, anchor="w").grid(row=0,column=0,columnspan=cs,sticky=(N,S,E,W))
30
+ else:
31
+ rs = len(question)
32
+ for i in range(0,rs,1):
33
+ self.rowconfigure(i, weight=1)
34
+ Label(self, text=question[i], anchor="w").grid(row=i,column=0,columnspan=cs,sticky=(N,S,E,W))
35
+ self.rowconfigure(rs, weight=1)
36
+
37
+ #Resolve Answer
38
+ self.elements = list(answer)
39
+
40
+ self.screen_elements = []
41
+ for i in range(0,len(self.elements),1):
42
+ match self.elements[i]:
43
+ case "y":
44
+ self.screen_elements.append(Button(self, text="Yes", command = lambda: self.ycom(ycommand)))
45
+ self.screen_elements[i].grid(row=rs,column=i,sticky=(N,S,E,W))
46
+ case "n":
47
+ self.screen_elements.append(Button(self, text="No", command = self.xcom))
48
+ self.screen_elements[i].grid(row=rs,column=i,sticky=(N,S,E,W))
49
+ case "r":
50
+ self.screen_elements.append(Button(self, text="Return", command = self.xcom))
51
+ self.screen_elements[i].grid(row=rs,column=i,sticky=(N,S,E,W))
52
+ case "u":
53
+ self.screen_elements.append(Button(self, text="Continue", command = lambda: self.ycom(ycommand)))
54
+ self.screen_elements[i].grid(row=rs,column=i,sticky=(N,S,E,W))
55
+ case "b":
56
+ self.screen_elements.append(Button(self, text="Back", command = self.xcom))
57
+ self.screen_elements[i].grid(row=rs,column=i,sticky=(N,S,E,W))
58
+ case "x":
59
+ self.screen_elements.append(Button(self, text="Close", command = self.xcom))
60
+ self.screen_elements[i].grid(row=rs,column=i,sticky=(N,S,E,W))
61
+ case "c":
62
+ self.screen_elements.append(Button(self, text="Confirm", command = lambda: self.ycom(ycommand)))
63
+ self.screen_elements[i].grid(row=rs,column=i,sticky=(N,S,E,W))
64
+ case "d":
65
+ self.screen_elements.append(ttk.Combobox(self, values=droplist))
66
+ self.screen_elements[i].grid(row=rs,column=i,sticky=(N,S,E,W))
67
+ case _:
68
+ pass
69
+
70
+
71
+ #Ensure visibility
72
+ self.focus_force()
73
+
74
+ #SubWindow Geometry
75
+ self.update()
76
+ self.WindowGeometry.getGeometry(True)
77
+ self.WindowGeometry.setGeometry(width=self.winfo_width(),
78
+ height=self.winfo_height(),
79
+ align="center",
80
+ size_style="window_relative",
81
+ window_ref=parent)
82
+
83
+ def ycom(self,command):
84
+ self.destroy()
85
+ if not command is None:
86
+ command()
87
+
88
+ def xcom(self):
89
+ self.destroy()
@@ -0,0 +1,51 @@
1
+ import json
2
+ from tkinter import *
3
+ from tkinter import ttk
4
+ from VIStk.Widgets import MenuItem
5
+
6
+ class VISMenu():
7
+ """The menu class drawings a column of buttons with subprocess calls to paths defined in a corresponding .json file.
8
+
9
+ Has two roots because can destory both main window and subwindow on redirect.
10
+ """
11
+ def __init__(self, parent:Frame|LabelFrame|Toplevel|Tk, path:str):
12
+ """
13
+ Args:
14
+ root (Tk): Master root for destruction on redirect
15
+ _root (Toplevel): Toplevel object to create menu on
16
+ path (str): Path to .json file describing menu
17
+ destroyOnRedirect (bool): If True the root window will be destroyed on redicet
18
+ """
19
+
20
+ self.parent = parent
21
+ self.root = self.parent.winfo_toplevel()
22
+ self.path = path
23
+ self.ob_dict = []
24
+ self.n_dict = {}
25
+
26
+ #Open json file for menu structure
27
+ with open(path) as file:
28
+ self.dict:dict = json.load(file)
29
+ self.parent.grid_columnconfigure(0,weight=1)
30
+ for i in range(0, len(self.dict.keys()), 1):
31
+ self.parent.grid_rowconfigure(i,weight=1)
32
+
33
+ x = 0
34
+ for item in self.dict:
35
+ ob = MenuItem(self.parent,
36
+ path= self.dict[item]["path"],
37
+ nav = self.dict[item]["nav"],
38
+ text = self.dict[item]["text"],
39
+ relief="flat"
40
+ )
41
+ ob.button.grid(row=x, column=0, sticky=(N,S,E,W))
42
+ self.ob_dict.append(ob)
43
+ self.n_dict[ob.nav]=ob
44
+ x += 1
45
+
46
+ self.root.bind("<KeyPress>",self.menuNav)
47
+
48
+ def menuNav(self,happ:Event):
49
+ k=happ.char
50
+ if self.n_dict.get(k) != None:
51
+ self.n_dict[k].itemPath()
@@ -0,0 +1,8 @@
1
+ from VIStk.Widgets._QuestionWindow import QuestionWindow
2
+ from tkinter import *
3
+
4
+ class WarningWindow(QuestionWindow):
5
+ def __init__(self, warning:str|list[str], parent:Toplevel|Tk, *args, **kwargs):
6
+ super().__init__(question=warning, parent=parent, answer="u", ycommand=None, *args, **kwargs)
7
+ self.screen_elements[0]["anchor"] = "center"
8
+ self.modalize()
@@ -0,0 +1,7 @@
1
+ from VIStk.Widgets._MenuItem import MenuItem
2
+ from VIStk.Widgets._VISMenu import Menu
3
+ from VIStk.Widgets._QuestionWindow import QuestionWindow
4
+ from VIStk.Widgets._MenuWindow import MenuWindow
5
+ from VIStk.Widgets._WarningWindow import WarningWindow
6
+
7
+ __all__ = ["Menu","MenuItem","MenuWindow","QuestionWindow","WarningWindow"]
VIStk/__init__.py ADDED
File without changes
VIStk/fUtil.py ADDED
@@ -0,0 +1,90 @@
1
+ from tkinter import *
2
+ from tkinter.font import Font as tkfont
3
+ import sys
4
+
5
+ global cfp
6
+ if str.upper(sys.platform)=="WIN32":
7
+ cfp = 'win'
8
+ else:
9
+ cfp = 'rasp'
10
+
11
+ class fUtil():
12
+ def __init__(self):
13
+ if cfp == 'win':
14
+ self.defont = "Arial"
15
+ else: #Liberation Sans is the Linux Available version of Arial
16
+ self.defont = "LiberationSans"
17
+
18
+ def mkfont(size:int,bold:bool=False,font:str="default"):
19
+ """Creates a font string with wom fonts"""
20
+
21
+ if font == "default":
22
+ return f"{fUtil().defont} {size}{' bold' if bold is True else ''}"
23
+
24
+ def autosize(e:Event=None, relations:list[Widget]=None, offset:int=None,shrink:int=0):
25
+ """Automatically sizes text given a widget with text."""
26
+ if not e is None: #Always need an event
27
+ #Get info from widget
28
+ widget:Widget = e.widget
29
+ w = widget.winfo_width() - 1 - shrink
30
+ h = widget.winfo_height() - 1
31
+ if w < 1 or h < 1:
32
+ return None
33
+ _root=widget.winfo_toplevel()
34
+ ffont = tkfont(_root, widget["font"])
35
+ fw = ffont.measure(widget["text"])
36
+ fh = ffont.metrics('linespace')
37
+
38
+ #Check widget with tightest relation
39
+ if not relations is None:
40
+ tempwi = widget
41
+ for wi in relations:
42
+ if isinstance(wi["text"],str):
43
+ if wi.winfo_width() > 1:
44
+ test = (wi.winfo_width() - 1 - ffont.measure(wi["text"]) < w-fw)
45
+ else:
46
+ test = False
47
+ else: test = False
48
+ if test:
49
+ widget = wi
50
+ else:
51
+ if wi.winfo_height() - 1 < h:#text has same height so only widget height must be smaller
52
+ if wi.winfo_height() > 1:
53
+ widget = wi
54
+ w = widget.winfo_width() - 1 - shrink
55
+ h = widget.winfo_height() - 1
56
+ fw = ffont.measure(widget["text"])
57
+ relations.append(tempwi)
58
+
59
+ #Final Control Sizes
60
+ _family = ffont.actual(option="family").replace(" ", "")
61
+ _size = ffont.actual(option="size")
62
+ _weight = ffont.actual(option="weight")
63
+
64
+ while True: #Make text larger than frame
65
+ if fw < w and fh < h:
66
+ _size = _size + 1
67
+ else:
68
+ break
69
+ ffont = tkfont(widget.winfo_toplevel(), f"{_family} {_size} {_weight}")
70
+ fh = ffont.metrics('linespace')
71
+ fw = ffont.measure(widget["text"])
72
+
73
+ while True: #Make text fit in frame
74
+ if fw <= w and fh <= h:
75
+ break
76
+ else:
77
+ if _size == 0:break
78
+ _size = _size - 1
79
+ ffont = tkfont(_root, f"{_family} {_size} {_weight}")
80
+ fh = ffont.metrics('linespace')
81
+ fw = ffont.measure(widget["text"])
82
+
83
+ if not offset is None: #Apply offset
84
+ _size = _size - offset
85
+
86
+ if not relations is None: #Correct relations
87
+ for wi in relations:
88
+ wi.configure(font = f"{_family} {_size} {_weight}")
89
+ else:
90
+ widget.configure(font = f"{_family} {_size} {_weight}")