mg-pso-gui 0.0.1__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Robert Cordingly
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.1
2
+ Name: mg-pso-gui
3
+ Version: 0.0.1
4
+ Summary: GUI for MG-PSO
5
+ Author: Robert Cordingly
6
+ Author-email: <rcording@uw.ed>
7
+ Keywords: python,muti-group,pso,particle,swarm,optimization,gui
8
+ Classifier: Development Status :: 1 - Planning
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Classifier: Operating System :: Unix
12
+ Classifier: Operating System :: MacOS :: MacOS X
13
+ Classifier: Operating System :: Microsoft :: Windows
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+
17
+ GUI for MG-PSO
@@ -0,0 +1,2 @@
1
+ # mg-pso-gui
2
+
@@ -0,0 +1,74 @@
1
+ from typing import Union, Tuple, Optional
2
+
3
+ from customtkinter import CTkLabel
4
+ from customtkinter import CTkButton
5
+ from customtkinter import CTkEntry
6
+ from customtkinter import CTkInputDialog
7
+ from ListParametersView import ListParametersView
8
+
9
+ class BoundsEditorWindow(CTkInputDialog):
10
+ """
11
+ Dialog with extra window, message, entry widget, cancel and ok button.
12
+ For detailed information check out the documentation.
13
+ """
14
+
15
+ def __init__(self, *args,
16
+ step_index: 0,
17
+ bound_index: 0,
18
+ option_manager: None,
19
+ **kwargs):
20
+ super().__init__(*args, **kwargs)
21
+
22
+ self.geometry("400x800")
23
+
24
+ self.step_index = step_index
25
+ self.bound_index = bound_index
26
+ self.option_manager = option_manager
27
+ self.bounds = None
28
+
29
+ def _create_widgets(self):
30
+
31
+ self.grid_columnconfigure((0, 1), weight=1)
32
+ self.rowconfigure(0, weight=1)
33
+
34
+ self.bounds = ListParametersView(
35
+ self, step_index=self.step_index, bound_index=self.bound_index, option_manager=self.option_manager)
36
+ self.bounds.grid(row=0, column=0, columnspan=2, padx=(10, 10),
37
+ pady=(10, 10), sticky="nsew")
38
+ self.bounds.grid_columnconfigure(0, weight=1)
39
+
40
+ self._ok_button = CTkButton(master=self,
41
+ width=100,
42
+ border_width=0,
43
+ fg_color=self._button_fg_color,
44
+ hover_color=self._button_hover_color,
45
+ text_color=self._button_text_color,
46
+ text='Save',
47
+ command=self._ok_event)
48
+ self._ok_button.grid(row=2, column=0, columnspan=1, padx=(20, 10), pady=(0, 20), sticky="ew")
49
+
50
+ self._cancel_button = CTkButton(master=self,
51
+ width=100,
52
+ border_width=0,
53
+ fg_color=self._button_fg_color,
54
+ hover_color=self._button_hover_color,
55
+ text_color=self._button_text_color,
56
+ text='Cancel',
57
+ command=self._ok_event)
58
+ self._cancel_button.grid(row=2, column=1, columnspan=1, padx=(10, 20), pady=(0, 20), sticky="ew")
59
+
60
+ def _ok_event(self, event=None):
61
+ # Save values in bounds editor...
62
+
63
+ self.bounds.push_to_option_manager()
64
+
65
+ self.grab_release()
66
+ self.destroy()
67
+
68
+ def _on_closing(self):
69
+ self.grab_release()
70
+ self.destroy()
71
+
72
+ def _cancel_event(self):
73
+ self.grab_release()
74
+ self.destroy()
@@ -0,0 +1,263 @@
1
+ from customtkinter import CTkScrollableFrame
2
+ from customtkinter import CTkFrame
3
+ from customtkinter import CTkLabel
4
+ from customtkinter import CTkButton
5
+ from customtkinter import CTkEntry
6
+ from customtkinter import CTkOptionMenu
7
+ from customtkinter import CTkTextbox
8
+ from customtkinter import CTkImage
9
+ from BoundsEditorWindow import BoundsEditorWindow
10
+ from CTkToolTip import *
11
+ import tkinter as tk
12
+ import json
13
+ import PIL
14
+ from PIL import Image
15
+ import os
16
+
17
+
18
+ optParams = []
19
+
20
+ details = json.load(open("bounds.json", "r"))
21
+ paramMap = {}
22
+ for param in details["parameter"]:
23
+ paramMap[param["name"]] = param
24
+ if "min" in param:
25
+ optParams.append(param["name"])
26
+
27
+ optParams.sort()
28
+
29
+ class BoundsList(CTkFrame):
30
+ def __init__(self, *args,
31
+ option_manager: None,
32
+ step_index: 0,
33
+ **kwargs):
34
+ super().__init__(*args, **kwargs)
35
+
36
+ self.edit_mode = False
37
+ self.tooltip_list = []
38
+
39
+ self.option_manager = option_manager
40
+ self.step_index = step_index
41
+ self.render()
42
+
43
+ def clear(self):
44
+ for list in self.tooltip_list:
45
+ for tooltip in list:
46
+ tooltip.destroy()
47
+ self.containerFrame.destroy()
48
+ self.tooltip_list = []
49
+
50
+ def toggle_edit_mode(self):
51
+ self.clear()
52
+ self.edit_mode = not self.edit_mode
53
+ self.render()
54
+
55
+ def refresh(self, *args):
56
+ self.clear()
57
+ self.render()
58
+
59
+ def render(self):
60
+ row = 0
61
+ index = 0
62
+
63
+ self.tooltip_list = []
64
+
65
+ self.containerFrame = CTkFrame(self)
66
+ self.containerFrame.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew")
67
+ self.containerFrame.grid_columnconfigure(0, weight=1, minsize=20)
68
+ self.containerFrame.grid_columnconfigure(5, weight=1, minsize=20)
69
+ self.containerFrame.grid_columnconfigure((1, 2, 3, 4), weight=5)
70
+
71
+ CTkLabel(self.containerFrame, text="Type:").grid(row=row, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew")
72
+ CTkLabel(self.containerFrame, text="Name:").grid(row=row, column=1, padx=(5, 5), pady=(5, 5), sticky="nsew")
73
+ CTkLabel(self.containerFrame, text="Bounds:").grid(row=row, column=2, columnspan=2, padx=(5, 5), pady=(5, 5), sticky="nsew")
74
+ CTkLabel(self.containerFrame, text="Default:").grid(row=row, column=4, padx=(5, 5), pady=(5, 5), sticky="nsew")
75
+ CTkLabel(self.containerFrame, text="Strategy:").grid(row=row, column=5, padx=(5, 5), pady=(5, 5), sticky="nsew")
76
+ row += 1
77
+
78
+ bounds = self.option_manager.get_steps()[self.step_index]["param"]
79
+
80
+ for bound in bounds:
81
+ tt1 = None
82
+ tt2 = None
83
+ tt3 = None
84
+
85
+ tt = CTkOptionMenu(self.containerFrame, dynamic_resizing=False, values=['float', 'int', 'list', 'string', 'custom'], variable=bound["type"], command=self.refresh)
86
+ #command = lambda _, index=index, option=tt: (self.update_type(index, option))
87
+ #tt.configure(command=command)
88
+ #tt.set(bound["type"].get())
89
+ tt.grid(row=row, column=0, padx=(5, 5), pady=(5, 5), sticky="new")
90
+
91
+ cc = None
92
+
93
+ bound_type = bound["type"].get()
94
+
95
+ if bound_type == "float":
96
+ cc = CTkOptionMenu(self.containerFrame, dynamic_resizing=False, values=optParams, variable=bound["name"])
97
+ cc.grid(row=row, column=1, padx=(5, 5), pady=(5, 5), sticky="new")
98
+
99
+ command = lambda _, index=index: (self.update_values(index), self.update_tooltips(index))
100
+ cc.configure(command=command)
101
+ else:
102
+
103
+ cc = CTkEntry(self.containerFrame)
104
+ cc.configure(textvariable=bound["name"])
105
+ cc.grid(row=row, column=1, padx=(5, 5), pady=(5, 5), sticky="new")
106
+
107
+
108
+ if self.edit_mode:
109
+ remove_func = lambda index=index: (self.clear(), self.option_manager.remove_bound(self.step_index, index), self.render())
110
+ bb = CTkButton(self.containerFrame, text="Remove", command=remove_func)
111
+ bb.grid(row=row, column=2, padx=(5, 5), pady=(5, 5), sticky="new")
112
+ CTkToolTip(bb, delay=0.1, alpha=0.95, message="Delete this bound...")
113
+ else:
114
+ bounds_min = CTkEntry(self.containerFrame)
115
+ vcmd = (self.register(self.validate_number), '%P', cc, bounds_min)
116
+ bounds_min.grid(row=row, column=2, padx=(5, 5), pady=(5, 5), sticky="new")
117
+ bounds_min.configure(textvariable=bound["bounds"][0], validate='all', validatecommand=vcmd)
118
+ self.validate_number(bounds_min.get(), cc, bounds_min)
119
+
120
+ bounds_max = CTkEntry(self.containerFrame)
121
+ vcmd = (self.register(self.validate_number), '%P', cc, bounds_max)
122
+ bounds_max.grid(row=row, column=3, padx=(5, 5), pady=(5, 5), sticky="new")
123
+ bounds_max.configure(textvariable=bound["bounds"][1], validate='all', validatecommand=vcmd)
124
+ self.validate_number(bounds_max.get(), cc, bounds_max)
125
+ tt2 = CTkToolTip(bounds_max, delay=0.1, alpha=0.95, message="...")
126
+
127
+ default_value = CTkEntry(self.containerFrame)
128
+ default_value.grid(row=row, column=4, padx=(5, 5), pady=(5, 5), sticky="new")
129
+ default_value.configure(textvariable=bound["default_value"])
130
+
131
+
132
+ if (bound_type == "list"):
133
+ def button_click_event(bound_index):
134
+ dialog = BoundsEditorWindow(title="Edit List Bound", step_index=self.step_index, bound_index=bound_index, option_manager=self.option_manager)
135
+ print("Number:", dialog.get_input())
136
+
137
+ open_window = lambda event=None, bound_index=index: (button_click_event(bound_index))
138
+ expand_image = CTkImage(Image.open(os.path.join("./images", "expand.png")), size=(20, 20))
139
+ button = CTkButton(self.containerFrame, width=30, text=None, image=expand_image, command=open_window)
140
+ button.grid(row=row, column=6, padx=(5, 5), pady=(5, 5), sticky="new")
141
+
142
+ calibration_strat = CTkOptionMenu(self.containerFrame, dynamic_resizing=False, values=['none', 'mean', 'single'], variable=bound["calibration_strategy"])
143
+ calibration_strat.grid(row=row, column=5, padx=(5, 5), pady=(5, 5), sticky="new")
144
+
145
+ tt1 = CTkToolTip(bounds_min, delay=0.1, alpha=0.95, message="...")
146
+ tt2 = CTkToolTip(bounds_max, delay=0.1, alpha=0.95, message="...")
147
+ if cc is not None:
148
+ tt3 = CTkToolTip(cc, delay=0.1, alpha=0.95, message="...")
149
+
150
+ self.tooltip_list.append([tt3, tt1, tt2])
151
+
152
+ self.update_tooltips(index)
153
+
154
+ row += 1
155
+ index += 1
156
+
157
+ add_func = lambda: (self.clear(), self.option_manager.add_bound(self.step_index), self.render())
158
+ if len(bounds) > 0:
159
+ if self.edit_mode:
160
+ CTkButton(self.containerFrame, text="Exit", command=self.toggle_edit_mode).grid(row=row, column=0, padx=(5, 5), pady=(5, 5), sticky="new")
161
+ else:
162
+ CTkButton(self.containerFrame, text="Edit", command=self.toggle_edit_mode).grid(row=row, column=0, padx=(5, 5), pady=(5, 5), sticky="new")
163
+ CTkButton(self.containerFrame, text="Add Parameter", command=add_func).grid(row=row, column=1, padx=(5, 5), pady=(5, 5), sticky="new")
164
+ else:
165
+ CTkButton(self.containerFrame, text="Add Parameter", command=add_func).grid(row=row, column=0, columnspan=2, padx=(5, 5), pady=(5, 5), sticky="new")
166
+
167
+ def update_type(self, index, option):
168
+ value = option.get()
169
+ self.option_manager.get_steps()[self.step_index]["param"][index]["type"].set(value)
170
+ self.refresh()
171
+
172
+ def update_values(self, index):
173
+ name = self.option_manager.get_steps()[self.step_index]["param"][index]["name"].get()
174
+ if name in paramMap:
175
+ obj = paramMap[name]
176
+ self.option_manager.get_steps()[self.step_index]["param"][index]["bounds"][0].set(obj["softmin"])
177
+ self.option_manager.get_steps()[self.step_index]["param"][index]["bounds"][1].set(obj["softmax"])
178
+
179
+ def update_tooltips(self, index):
180
+ try:
181
+ name = self.option_manager.get_steps()[self.step_index]["param"][index]["name"].get()
182
+ bound_type = self.option_manager.get_steps()[self.step_index]["param"][index]["type"].get()
183
+
184
+ tooltips = self.tooltip_list[index]
185
+ t3 = tooltips[0]
186
+ t1 = tooltips[1]
187
+ t2 = tooltips[2]
188
+
189
+ if (t1 == None or t2 == None or t3 == None):
190
+ if (t1 is not None):
191
+ t1.configure(message="")
192
+ if (t2 is not None):
193
+ t2.configure(message="")
194
+ if (t3 is not None):
195
+ t3.configure(message="")
196
+ print("update skipped")
197
+ return
198
+
199
+ if bound_type == "list":
200
+ t1.configure(message="")
201
+ t2.configure(message="")
202
+ t3.configure(message="")
203
+
204
+ if name in paramMap:
205
+ obj = paramMap[name]
206
+ description = obj["description"]
207
+ default = str(obj["value"])
208
+ min = str(obj["min"])
209
+ max = str(obj["max"])
210
+ softmin = str(obj["softmin"])
211
+ softmax = str(obj["softmax"])
212
+ unit = str(obj["unit"])
213
+ t1.configure(message=description + "\nMin: " + min + "\nSoft Min: " + softmin + "\nUnit: " + unit)
214
+ t2.configure(message=description + "\nMax: " + max + "\nSoft Max: " + softmax + "\nUnit: " + unit)
215
+ t3.configure(message=description + "\nDefault: " + default + "\nUnit: " + unit)
216
+ except:
217
+ pass
218
+
219
+ def validate_number(self, P, name, entry):
220
+
221
+ # Get the root window
222
+ root = self.winfo_toplevel()
223
+
224
+ # Get the entry widget using its internal Tkinter name
225
+ entry_widget = root.nametowidget(entry)
226
+ name_widget = root.nametowidget(name)
227
+
228
+ if isinstance(name_widget, CTkTextbox):
229
+ return True
230
+
231
+ # Call the get method on the entry widget
232
+ bound_name = name_widget.get()
233
+ value = entry_widget.get()
234
+
235
+ # Print the value of the entry widget
236
+ #print(bound_name)
237
+
238
+ if P == "" or P == "." or P == "-":
239
+ entry_widget.configure(border_color="red")
240
+ return True
241
+
242
+ try:
243
+ float(P)
244
+ entry_widget.configure(border_color=["#979DA2", "#565B5E"])
245
+
246
+ if bound_name in paramMap:
247
+ obj = paramMap[bound_name]
248
+ if "min" in obj and float(P) < float(obj["min"]):
249
+ entry_widget.configure(border_color="red")
250
+ elif "max" in obj and float(P) > float(obj["max"]):
251
+ entry_widget.configure(border_color="red")
252
+ elif "softmin" in obj and float(P) < float(obj["softmin"]):
253
+ entry_widget.configure(border_color="yellow")
254
+ elif "softmax" in obj and float(P) > float(obj["softmax"]):
255
+ entry_widget.configure(border_color="yellow")
256
+
257
+ return True
258
+ except ValueError as e:
259
+ print(e)
260
+ return False
261
+ except Exception as e:
262
+ print(e)
263
+ return False
@@ -0,0 +1,11 @@
1
+ """
2
+ CustomTkinter ToolTip
3
+ Author: Akash Bora
4
+ This is a tooltip/pop-up widget made with customtkinter.
5
+ Homepage: https://github.com/Akascape/CTkToolTip
6
+ """
7
+
8
+ __version__ = '0.4'
9
+
10
+ from .ctk_tooltip import CTkToolTip
11
+
@@ -0,0 +1,187 @@
1
+ """
2
+ CTkToolTip Widget
3
+ version: 0.4
4
+ """
5
+
6
+ import time
7
+ import sys
8
+ import customtkinter
9
+ from tkinter import Toplevel, Frame
10
+
11
+ class CTkToolTip(Toplevel):
12
+ """
13
+ Creates a ToolTip (pop-up) widget for customtkinter.
14
+ """
15
+
16
+ def __init__(
17
+ self,
18
+ widget: any = None,
19
+ message: str = None,
20
+ delay: float = 0.2,
21
+ follow: bool = True,
22
+ x_offset: int = +20,
23
+ y_offset: int = +10,
24
+ bg_color: str = None,
25
+ corner_radius: int = 10,
26
+ border_width: int = 0,
27
+ border_color: str = None,
28
+ alpha: float = 0.8,
29
+ padding: tuple = (10,2),
30
+ **message_kwargs):
31
+
32
+ super().__init__()
33
+
34
+ self.widget = widget
35
+
36
+ self.withdraw()
37
+ # Disable ToolTip's title bar
38
+ self.overrideredirect(True)
39
+
40
+ if sys.platform.startswith("win"):
41
+ self.transparent_color = self.widget._apply_appearance_mode(customtkinter.ThemeManager.theme["CTkToplevel"]["fg_color"])
42
+ self.attributes("-transparentcolor", self.transparent_color)
43
+ self.transient()
44
+ elif sys.platform.startswith("darwin"):
45
+ self.transparent_color = 'systemTransparent'
46
+ self.attributes("-transparent", True)
47
+ self.transient(self.master)
48
+ else:
49
+ self.transparent_color = '#000001'
50
+ corner_radius = 0
51
+ self.transient()
52
+
53
+ self.resizable(width=True, height=True)
54
+ self.transient()
55
+
56
+ # Make the background transparent
57
+ self.config(background=self.transparent_color)
58
+
59
+ # StringVar instance for msg string
60
+ self.messageVar = customtkinter.StringVar()
61
+ self.message = message
62
+ self.messageVar.set(self.message)
63
+
64
+ self.delay = delay
65
+ self.follow = follow
66
+ self.x_offset = x_offset
67
+ self.y_offset = y_offset
68
+ self.corner_radius = corner_radius
69
+ self.alpha = alpha
70
+ self.border_width = border_width
71
+ self.padding = padding
72
+ self.bg_color = bg_color
73
+ self.border_color = border_color
74
+ self.disable = False
75
+
76
+ # visibility status of the ToolTip inside|outside|visible
77
+ self.status = "outside"
78
+ self.last_moved = 0
79
+ self.attributes('-alpha', self.alpha)
80
+
81
+ # Add the message widget inside the tooltip
82
+ self.transparent_frame = Frame(self, bg=self.transparent_color)
83
+ self.transparent_frame.pack(padx=0, pady=0, fill="both", expand=True)
84
+
85
+ self.frame = customtkinter.CTkFrame(self.transparent_frame, bg_color=self.transparent_color, corner_radius=self.corner_radius,
86
+ border_width=self.border_width, fg_color=self.bg_color, border_color=self.border_color)
87
+ self.frame.pack(padx=0, pady=0, fill="both", expand=True)
88
+
89
+ self.message_label = customtkinter.CTkLabel(self.frame, textvariable=self.messageVar, **message_kwargs)
90
+ self.message_label.pack(fill="both", padx=self.padding[0]+self.border_width,
91
+ pady=self.padding[1]+self.border_width, expand=True)
92
+
93
+ if self.widget != None:
94
+ if self.widget.winfo_name()!="tk":
95
+ if self.frame.cget("fg_color")==self.widget.cget("bg_color"):
96
+ if not bg_color:
97
+ self._top_fg_color = self.frame._apply_appearance_mode(customtkinter.ThemeManager.theme["CTkFrame"]["top_fg_color"])
98
+ self.frame.configure(fg_color=self._top_fg_color)
99
+
100
+ # Add bindings to the widget without overriding the existing ones
101
+ self.widget.bind("<Enter>", self.on_enter, add="+")
102
+ self.widget.bind("<Leave>", self.on_leave, add="+")
103
+ self.widget.bind("<Motion>", self.on_enter, add="+")
104
+ self.widget.bind("<B1-Motion>", self.on_enter, add="+")
105
+ self.widget.bind("<Destroy>", lambda _: self.hide(), add="+")
106
+
107
+ def show(self) -> None:
108
+ """
109
+ Enable the widget.
110
+ """
111
+ self.disable = False
112
+
113
+ def on_enter(self, event) -> None:
114
+ """
115
+ Processes motion within the widget including entering and moving.
116
+ """
117
+
118
+ if self.disable: return
119
+ self.last_moved = time.time()
120
+
121
+ # Set the status as inside for the very first time
122
+ if self.status == "outside":
123
+ self.status = "inside"
124
+
125
+ # If the follow flag is not set, motion within the widget will make the ToolTip dissapear
126
+ if not self.follow:
127
+ self.status = "inside"
128
+ self.withdraw()
129
+
130
+ # Offsets the ToolTip using the coordinates od an event as an origin
131
+ self.geometry(f"+{event.x_root + self.x_offset}+{event.y_root + self.y_offset}")
132
+
133
+ # Time is in integer: milliseconds
134
+ self.after(int(self.delay * 1000), self._show)
135
+
136
+ def on_leave(self, event=None) -> None:
137
+ """
138
+ Hides the ToolTip temporarily.
139
+ """
140
+
141
+ if self.disable: return
142
+ self.status = "outside"
143
+ self.withdraw()
144
+
145
+ def _show(self) -> None:
146
+ """
147
+ Displays the ToolTip.
148
+ """
149
+
150
+ if not self.widget.winfo_exists():
151
+ self.hide()
152
+ self.destroy()
153
+
154
+ if self.status == "inside" and time.time() - self.last_moved >= self.delay:
155
+ self.status = "visible"
156
+ self.deiconify()
157
+
158
+ def hide(self) -> None:
159
+ """
160
+ Disable the widget from appearing.
161
+ """
162
+ if not self.winfo_exists():
163
+ return
164
+ self.withdraw()
165
+ self.disable = True
166
+
167
+ def is_disabled(self) -> None:
168
+ """
169
+ Return the window state
170
+ """
171
+ return self.disable
172
+
173
+ def get(self) -> None:
174
+ """
175
+ Returns the text on the tooltip.
176
+ """
177
+ return self.messageVar.get()
178
+
179
+ def configure(self, message: str = None, delay: float = None, bg_color: str = None, **kwargs):
180
+ """
181
+ Set new message or configure the label parameters.
182
+ """
183
+ if delay: self.delay = delay
184
+ if bg_color: self.frame.configure(fg_color=bg_color)
185
+
186
+ self.messageVar.set(message)
187
+ self.message_label.configure(**kwargs)
@@ -0,0 +1,61 @@
1
+ from customtkinter import CTkScrollableFrame
2
+ from customtkinter import CTkFrame
3
+ from customtkinter import CTkLabel
4
+ from customtkinter import CTkButton
5
+ from customtkinter import CTkEntry
6
+ import tkinter as tk
7
+
8
+ global option_manager
9
+
10
+ class CalibrationParametersView(CTkScrollableFrame):
11
+ def __init__(self, *args,
12
+ option_manager: None,
13
+ **kwargs):
14
+ super().__init__(*args, **kwargs)
15
+
16
+ self.option_manager = option_manager
17
+ self.key_values = option_manager.get_arguments()['calibration_parameters']
18
+ self.edit_mode = False
19
+
20
+ self.render()
21
+
22
+ def clear(self):
23
+ self.containerFrame.destroy()
24
+
25
+ def toggle_edit_mode(self):
26
+ self.clear()
27
+ self.edit_mode = not self.edit_mode
28
+ self.render()
29
+
30
+ def render(self):
31
+ row = 0
32
+ index = 0
33
+
34
+ self.containerFrame = CTkFrame(self)
35
+ self.containerFrame.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew")
36
+ self.containerFrame.grid_columnconfigure((0, 1), weight=1)
37
+
38
+ CTkLabel(self.containerFrame, text="Name:").grid(row=row, column=0, columnspan=1, padx=5, pady=5, sticky="")
39
+ CTkLabel(self.containerFrame, text="Value:").grid(row=row, column=1, columnspan=1, padx=5, pady=5, sticky="")
40
+ row += 1
41
+
42
+ for key_value_pair in self.key_values:
43
+ CTkEntry(self.containerFrame, textvariable=self.key_values[index]["name"]).grid(row=row, column=0, padx=(5, 5), pady=(5, 5), sticky="ew")
44
+
45
+ if self.edit_mode:
46
+ return_func = lambda index=index: (self.clear(), self.option_manager.remove_calibration_parameter(index), self.render())
47
+ CTkButton(self.containerFrame, text="Remove", command=return_func).grid(row=row, column=1, padx=(5, 5), pady=(5, 5), sticky="ew")
48
+ else:
49
+ bb = CTkEntry(self.containerFrame)
50
+ bb.grid(row=row, column=1, padx=(5, 5), pady=(5, 5), sticky="ew")
51
+ bb.configure(textvariable=self.key_values[index]["value"])
52
+ row += 1
53
+ index += 1
54
+
55
+ if self.edit_mode:
56
+ CTkButton(self.containerFrame, text="Exit", command=self.toggle_edit_mode).grid(row=row, column=0, padx=(5, 5), pady=(5, 5), sticky="ew")
57
+ else:
58
+ CTkButton(self.containerFrame, text="Edit", command=self.toggle_edit_mode).grid(row=row, column=0, padx=(5, 5), pady=(5, 5), sticky="ew")
59
+
60
+ add_key_func = lambda: (self.clear(), self.option_manager.add_calibration_param("name", "value"), self.render())
61
+ CTkButton(self.containerFrame, text="Add Parameter", command=add_key_func).grid(row=row, column=1, padx=(5, 5), pady=(5, 5), sticky="ew")