-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathControl.py
More file actions
304 lines (241 loc) · 13.1 KB
/
Control.py
File metadata and controls
304 lines (241 loc) · 13.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
# © 2025 B.A.D. Black Apex Development LLC
# All rights reserved.
# This software and its associated name, logo, and branding are the intellectual property of
# B.A.D. Black Apex Development LLC — registered in the State of Ohio (Entity #5448030).
# Unauthorized use, reproduction, or distribution is prohibited and may violate
# copyright, trademark, and unfair competition laws.
#Description: Responsible for controlling the flow of the program.
# -----------------------------------------------------------------------------------------
import View_HomeUI
import View_GearUI_TrainingOptions
import Model
import View_GearUI_TrainingOptions_Train
import dearpygui.dearpygui as dpg
import pygame
import os
# -----------------------------------------------------------------------------------------
pygame.mixer.init()
# -----------------------------------------------------------------------------------------
gears = dict()
is_user_logged_in = False
username_of_user_logged_in = ""
#-----------------------------------------------------------------------------------------
def main():
Model._initiate_log_file() #So log file is created overwritten anew, to prevent bloating
View_HomeUI._run_home_ui()
View_HomeUI._create_homeUI()
# -----------------------------------------------------------------------------------------
if __name__ == "__main__":
main()
# -----------------------------------------------------------------------------------------
def play_sound(filename, wait=True):
path = os.path.abspath(filename)
if not os.path.isfile(path) or os.path.getsize(path) == 0:
print(f"[Sound Error] File missing or empty: {path}")
return
try:
pygame.mixer.music.load(path)
pygame.mixer.music.play()
if wait:
while pygame.mixer.music.get_busy():
pygame.time.Clock().tick(30)
except Exception as e:
print("Audio playback failed:", e)
# -----------------------------------------------------------------------------------------
def _show_window(previous_window_tag):
dpg.show_item(previous_window_tag)
# -----------------------------------------------------------------------------------------
def _hide_window(previous_window_tag):
dpg.hide_item(previous_window_tag)
# -----------------------------------------------------------------------------------------
def _delete_window(window_tag):
dpg.delete_item(window_tag)
# -----------------------------------------------------------------------------------------
def _check_window_exists(window_tag):
if dpg.does_item_exist(window_tag):
dpg.delete_item(window_tag)
# -----------------------------------------------------------------------------------------
def _start_training_options_window(sender, appdata, user_data):
View_GearUI_TrainingOptions.start(sender, appdata, user_data)
# -----------------------------------------------------------------------------------------
def _show_training_options_train_window(sender, appdata, user_data):
global is_user_logged_in, username_of_user_logged_in
if is_user_logged_in is True and username_of_user_logged_in != "":
View_GearUI_TrainingOptions_Train.show_timer(sender, appdata, user_data)
else:
View_GearUI_TrainingOptions._popup_generic_message("User must be logged in to train \ndeployment speed.")
# -----------------------------------------------------------------------------------------
def _add_gear(gear_name: str, input_tag: str):
global is_user_logged_in, username_of_user_logged_in
View_HomeUI.inputInProgress = False
if not gear_name:
View_HomeUI._popup_add_gear_failed(isInputEmpty=True)
dpg.set_value(input_tag, "")
return
button_width = 200
child_width = 380
padding = (child_width - button_width) // 2
# theme
with dpg.theme() as red_button_theme:
with dpg.theme_component(dpg.mvButton):
dpg.add_theme_color(dpg.mvThemeCol_ButtonHovered, (150, 0, 0, 255))
dpg.add_theme_color(dpg.mvThemeCol_ButtonActive, (200, 0, 0, 255))
if gears.get(gear_name, "doesNotExist") == "doesNotExist":
gears[gear_name] = {"gear_button_tag": gear_name}
with dpg.group(horizontal=True, parent="button_container_home_ui"):
dpg.add_spacer(width=padding)
dpg.add_button(
label=gear_name,
width=button_width,
height=100,
tag=gear_name,
callback=View_GearUI_TrainingOptions.start,
user_data=[gear_name, "home_ui_parent_window"]
)
dpg.bind_item_theme(gear_name, red_button_theme)
if is_user_logged_in and username_of_user_logged_in:
Model.save_deployment_gear(gear_name=gear_name, username=username_of_user_logged_in)
dpg.hide_item(input_tag)
dpg.set_value(input_tag, "")
else:
View_HomeUI._popup_add_gear_failed(isInputEmpty=False)
dpg.set_value(input_tag, "")
# -----------------------------------------------------------------------------------------
def _remove_gear(sender, app_data, user_data):
global is_user_logged_in, username_of_user_logged_in
View_HomeUI.inputInProgress = False
input_tag = user_data[1]
if dpg.is_item_shown(input_tag):
gear_name = dpg.get_value(input_tag)
if gear_name and gears.get(str(gear_name), "doesNotExist") != "doesNotExist":
gearButtonToRemove = gears.pop(str(gear_name))
dpg.delete_item(gearButtonToRemove["gear_button_tag"])
# If a user is logged in, gear data can be deleted from their corresponding file
if is_user_logged_in == True and username_of_user_logged_in != "":
Model.delete_deployment_gear_scores(gear_name = gearButtonToRemove["gear_button_tag"], username = username_of_user_logged_in)
Model.delete_deployment_gear(gear_name = gearButtonToRemove["gear_button_tag"], username = username_of_user_logged_in)
dpg.hide_item(input_tag)
dpg.set_value(input_tag, "")
else:
View_HomeUI._popup_remove_gear_failed(isInputEmpty=(gear_name == ""))
dpg.set_value(input_tag, "")
else:
dpg.show_item(input_tag)
# -----------------------------------------------------------------------------------------
def _nuke_gear():
global is_user_logged_in, username_of_user_logged_in
if dpg.does_item_exist("nuke_confirm_window"):
dpg.delete_item("nuke_confirm_window")
play_sound("assets/audio/ui_sound_03.wav", wait=False)
def _confirm():
dpg.delete_item("nuke_confirm_window")
for gear in list(gears):
gearButtonToRemove = gears.pop(str(gear))
dpg.delete_item(gearButtonToRemove["gear_button_tag"])
# If a user is logged in, gear data can be deleted from their corresponding file
if is_user_logged_in == True and username_of_user_logged_in != "":
Model.delete_deployment_gear(gear_name = gearButtonToRemove["gear_button_tag"], username = username_of_user_logged_in)
Model.delete_deployment_gear_scores(gear_name = gearButtonToRemove["gear_button_tag"], username = username_of_user_logged_in)
def _cancel():
dpg.delete_item("nuke_confirm_window")
with dpg.window(label="Confirm Nuke", modal=True, tag="nuke_confirm_window", no_title_bar=True, width=360, height=150, pos=(300, 300)):
dpg.add_text("Are you sure you want to nuke all gear?\nThis action cannot be undone.", wrap=330)
dpg.add_spacer(height=20)
with dpg.group(horizontal=True):
dpg.add_button(label="Yes", width=75, callback=_confirm)
dpg.add_button(label="No", width=75, callback=_cancel)
# -----------------------------------------------------------------------------------------
def _save_deployment_gear_score(score: int, gear_name: str):
Model.save_deployment_gear_score(score = score, gear_name = gear_name, username = username_of_user_logged_in)
# -----------------------------------------------------------------------------------------
def get_sorted_deployment_scores(key_name: str) -> list:
global is_user_logged_in, username_of_user_logged_in
if is_user_logged_in == False and username_of_user_logged_in == "":
View_GearUI_TrainingOptions._popup_generic_message("User must be logged in to get deployment \nscores.")
return []
if len(Model._get_sorted_deployment_scores(key_name, username_of_user_logged_in)) == 0:
View_GearUI_TrainingOptions._popup_generic_message("No scores available.")
return Model._get_sorted_deployment_scores(key_name, username_of_user_logged_in)
# -----------------------------------------------------------------------------------------
def _logout_user():
global is_user_logged_in, username_of_user_logged_in
if is_user_logged_in == True and username_of_user_logged_in != "":
#reset global trackers
is_user_logged_in = False
username_of_user_logged_in = ""
#Remove gear buttons from home UI
View_HomeUI._clear_gear_buttons()
# delete corresponding dpg items in memory, this is safe because user is logging out and won't care if their gear UI is removed.
for gear in list(gears):
gearButtonToRemove = gears.pop(str(gear))
dpg.delete_item(gearButtonToRemove["gear_button_tag"])
#Change header text of HomeUI
dpg.set_value("homescreen_header_text", "Gear")
else:
return
# -----------------------------------------------------------------------------------------
def _create_user_data(sender, app_data, user_data):
global is_user_logged_in, username_of_user_logged_in
if is_user_logged_in == True and username_of_user_logged_in != "":
View_HomeUI._popup_generic_message("You must be logged out to create \nan account")
return
#So user cannot create a username or password with an empty string
if dpg.get_value(user_data[1]) == "":
View_HomeUI._popup_generic_message("You cannot create an empty username")
return
if (dpg.get_value(user_data[2]) == "") or (" " in dpg.get_value(user_data[2])):
View_HomeUI._popup_generic_message("Spaces in the password are prohibited")
return
#So user knows program is busy
View_HomeUI._popup_busy_creating_user(sender, app_data, user_data)
result = Model.create_user_data_files(sender, app_data, user_data)
#So busy popup goes away
_check_window_exists(View_HomeUI.BUSY_CREATING_USER_WINDOW_TAG)
# Yield one frame so DPG clears the modal stack, or next popup in this function bugs out and doesn't show
dpg.split_frame()
# Show popup if the username already exists
if result == "Already exists":
View_HomeUI._popup_create_user_failed(sender, app_data, user_data)
elif result == "Creation Successful":
View_HomeUI._popup_user_creation_result(dpg.get_value(user_data[1]))
# -----------------------------------------------------------------------------------------
def _delete_user_data(sender, app_data, user_data):
global is_user_logged_in, username_of_user_logged_in
if is_user_logged_in == True and username_of_user_logged_in != "":
View_HomeUI._popup_generic_message("You must be logged out to delete \nan account")
return
#So user knows program is busy
View_HomeUI._popup_busy_deleting_user(sender, app_data, user_data)
result = Model._delete_user_data_files(sender, app_data, user_data)
View_HomeUI._popup_delete_user_result(dpg.get_value(user_data[1]), result)
#delete corresponding dpg items in memory
for gear in list(gears):
gearButtonToRemove = gears.pop(str(gear))
dpg.delete_item(gearButtonToRemove["gear_button_tag"])
# So busy popup goes away
_check_window_exists(View_HomeUI.BUSY_DELETING_USER_WINDOW_TAG)
#So homescreen header text changes back to default
dpg.set_value("homescreen_header_text", View_HomeUI.homescreen_header_default_text)
# -----------------------------------------------------------------------------------------
def _load_user_data(sender, app_data, user_data):
global is_user_logged_in, username_of_user_logged_in
if is_user_logged_in == True and username_of_user_logged_in != "":
View_HomeUI._popup_generic_message("You must be logged out to login to \nan account")
return
result = Model._verify_user_password(sender, app_data, user_data)
username = result[0]
login_result = result[1]
if result == "User not in database":
View_HomeUI._popup_generic_message(f"User not in database")
return
elif login_result == False:
View_HomeUI._popup_generic_message(f'Password for User: "{username}" is invalid.')
elif login_result == True:
View_HomeUI._clear_gear_buttons()
is_user_logged_in = True
username_of_user_logged_in = username
dpg.set_value("homescreen_header_text", f"Gear for {username}")
list_of_gears = Model.load_deployment_gear(username)
if list_of_gears is not None:
View_HomeUI._load_gear_buttons(username, list_of_gears)
View_HomeUI._popup_generic_message(f'Successfully logged in as User: "{username}"')