-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmain.py
255 lines (210 loc) · 9.85 KB
/
main.py
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
import customtkinter as ctk
import application.gui.main_menu as main_menu
import application.gui.popups as popups
import application.gui.open_project as openproj
import threading
import git
import os
import subprocess
import sys
from tkinter import PhotoImage
from application.builder_utils import *
class Application:
##############################
##### Set Up Application #####
##############################
def __init__(self, root):
# Set viewing mode
# ctk.set_appearance_mode("light") # Options are "light", "dark", or "system"
version_txt_path = get_resource_path('version.txt', os.path.abspath(__file__))
version = "Unversioned"
try:
with open(version_txt_path, 'r') as file:
version = file.readline().strip()
except Exception as e:
print(f"Couldn't find version.txt correctly: {e}")
# Window Title
window_title = "PYNQ SoC Builder "+version
# Set root and title
self.root = root
self.root.title(window_title)
self.root.geometry("1200x800")
self.root.minsize(800, 500)
# self.root.resizable(False, False) # Dont let the window be resizable
# self.root.protocol("WM_DELETE_WINDOW", self.on_close) # Set function to handle close
# Shared Variables (Shared between all pages)
# self.build_running = False # Flag - True build is running, False build not running
# self.build_force_quit_event = threading.Event() # Event to trigger Build threads to quit
self.dialog_response = None # Stores response from Dialog Pop-Up
self.top_level_message = None # Set top_level_message to be presented by dialog/alert
self.toplevel_window = None # Var for top level window objects
self.hdlgen_path = None # Current Project
self.hdlgen_prj = None # Current Project Object
self.path_to_markdown = None # Path to markdown file.
self.problem_link = None
self.page1 = main_menu.MainPage(self)
self.page2 = openproj.OpenProjectPage(self)
self.show_page(self.page2)
#####################################
##### Return Application Height #####
#####################################
def get_window_height(self):
# Wait for the window to be displayed and its size to be finalized
self.root.update_idletasks()
self.root.update()
return self.root.winfo_height()
####################################
##### Return Application Width #####
####################################
def get_window_width(self):
# Wait for the window to be displayed and its size to be finalized
self.root.update_idletasks()
self.root.update()
return self.root.winfo_width()
#####################
##### Show Page #####
#####################
def show_page(self, page):
# Hide all existing pages
self.page1.hide()
self.page2.hide()
# self.page3.hide()
page.show() # Show requested page.
# TODO: Instead of individual functions here we can have a "Open Popup(popups.Alert_Window)" API where any popup class can be passed
# Not really a priority by any means. Just a clean up task.
#############################
##### Open Alert Pop-Up #####
#############################
def open_alert(self):
if self.toplevel_window is None or not self.toplevel_window.winfo_exists():
self.toplevel_window = popups.Alert_Window(self) # Create window if None or destroyed
else:
self.toplevel_window.focus() # if window exists focus it.
###############################
##### Open Problem Pop-Up #####
###############################
def open_problem(self):
if self.toplevel_window is None or not self.toplevel_window.winfo_exists():
self.toplevel_window = popups.Problem_Window(self) # Create window if None or destroyed
else:
self.toplevel_window.focus() # if window exists focus it.
###################################
##### Open Launch FPGA Pop-Up #####
###################################
def open_fpga_popup(self):
if self.toplevel_window is None or not self.toplevel_window.winfo_exists():
self.toplevel_window = popups.FPGA_Window(self) # Create window if None or destroyed
else:
self.toplevel_window.focus() # if window exists focus it.
################################
##### Open Markdown Pop-Up #####
################################
def open_markdown(self):
if self.toplevel_window is None or not self.toplevel_window.winfo_exists():
self.toplevel_window = popups.MarkdownWindow(self) # Create window if None or destroyed
self.toplevel_window.focus() # Focus the window aswell.
else:
self.toplevel_window.focus() # if window exists focus it.
##############################
##### Open Dialog Pop-Up #####
##############################
def open_dialog(self):
if self.toplevel_window is None or not self.toplevel_window.winfo_exists():
self.toplevel_window = popups.Dialog_Window(self) # Create window if None or destroyed
else:
self.toplevel_window.focus() # if window exists focus it.
#####################################
##### Close Application Handler #####
#####################################
def close_application(self):
# Is a build currently running?
if self.hdlgen_prj.build_running:
# Prompt user if they are sure:
self.top_level_message = "A build is currently running and will force quit. Are you sure?"
self.open_dialog()
# Wait for the user to click their response
self.toplevel_window.wait_window()
# print(self.dialog_response)
response = self.dialog_response
if response == "yes":
# terminate process, by continuing past this if block
self.hdlgen_prj.build_force_quit_event.set()
pass
elif response == "no":
# leave and take no action
return
else:
print("Invalid response from Dialog, not quitting (default)")
return
# Quit behaviour:
print("Closing Application")
self.root.destroy() # kill tkinter window
exit() # quit app
#################################
##### Close Project Handler #####
#################################
def close_project(self):
restart_program()
def restart_program():
print("Restarting the application with updated code...")
new_process = subprocess.Popen([sys.executable] + sys.argv)
# Log the new process ID
print(f"Started new process with PID: {new_process.pid}")
# Exit the current process
sys.exit()
#######################################
##### Launch Application Function #####
#######################################
if __name__ == "__main__":
root = ctk.CTk()
ctk.deactivate_automatic_dpi_awareness()
app = Application(root)
if (not is_running_as_executable()):
try:
repo = git.Repo(os.getcwd())
# Get the active branch
current_branch = repo.active_branch
print(f"Current branch: {current_branch}")
if current_branch.name == "master": # Temporarily changed to auto_updater for testing purposes
# Fetch updates from the remote
# Configure remote URL with credentials (for HTTPS)
repo.remotes.origin.set_url("https://github.com/Logicademy/PYNQ-SoC-Builder.git")
origin = repo.remotes.origin
origin.fetch()
# Compare local and remote commits
local_commit = repo.head.commit # Local commit
remote_commit = repo.refs['origin/master'].commit # Remote branch's commit
print(f"Local Hash: {local_commit.hexsha}")
print(f"Local Commit: {local_commit}")
print(f"Remote Commit: {remote_commit}")
if local_commit.hexsha != remote_commit.hexsha:
print("New commits are available!")
# Launch User Prompt
app.top_level_message = "An update is available, would you like to install it?"
app.open_dialog()
app.toplevel_window.wait_window() # Wait for user's response
else:
print("Your branch is up-to-date.")
if app.dialog_response == "yes":
origin.pull()
restart_program()
else:
print("Skipping update, running application...")
except git.InvalidGitRepositoryError:
app.top_level_message = "Could not find Git repository - Cannot check for updates."
app.problem_link = "https://github.com/Logicademy/PYNQ-SoC-Builder/blob/master/docs/markdown/git_not_found.md"
app.open_problem()
app.toplevel_window.wait_window() # Wait for user's response
except Exception as e:
print(f"Could not auto-update project, please do manually or re-clone from Github.com/Logicademy/PYNQ-SoC-Builder - {e}")
try:
# current_dir = os.getcwd()
# Set the icon using the ctypes library
# icon_path = current_dir + "/docs/images/favicon.png" # Replace with the actual path
#print(icon_path)
#root.iconbitmap(icon_path)
icon_path = get_resource_path('docs/images/favicon.png', os.path.abspath(__file__))
root.iconphoto(False, PhotoImage(file=icon_path))
except Exception as e:
print(f"Could not set taskbar image: {e}")
root.mainloop()