Compare commits

..

No commits in common. "507747d5bef500926a11ceca0a641a52fb7ed546" and "6a1386f15c787e4f7e0a658aa06b554efa40a68b" have entirely different histories.

5 changed files with 72 additions and 106 deletions

View File

@ -1,8 +1,7 @@
import os, sys, json import os, sys, json
#TODO: port to QT once that little mainloop issue has been resolved...
import tkinter as tk import tkinter as tk
from tkinter import ttk from tkinter import ttk
import util import gui_helper, util
class Config: class Config:
def __init__(self, file_path, default_config): def __init__(self, file_path, default_config):
@ -19,19 +18,19 @@ class Config:
util.error("An exception occurred while trying to load the configuration.", handle_gracefully=False) util.error("An exception occurred while trying to load the configuration.", handle_gracefully=False)
else: else:
# config not found # config not found
dialog_communication = util.Communication() dialog_interaction_handler = gui_helper.Window_Interaction_Handler()
dialog = tk.Tk() dialog = tk.Tk()
dialog.title("No configuration found") dialog.title("No configuration found")
ttk.Label(dialog, text="No configuration found!").pack() ttk.Label(dialog, text="No configuration found!").pack()
buttons_frame = tk.Frame(dialog) buttons_frame = tk.Frame(dialog)
buttons_frame.pack() buttons_frame.pack()
ttk.Button(buttons_frame, text="Create", command=lambda: dialog_communication.send("create", True, additional_action=dialog.destroy)).grid(column=0, row=0) ttk.Button(buttons_frame, text="Create", command=lambda: dialog_interaction_handler.interact("create", True, additional_action=dialog.destroy)).grid(column=0, row=0)
ttk.Button(buttons_frame, text="Quit", command=lambda: dialog_communication.send("create", False, additional_action=dialog.destroy)).grid(column=1, row=0) ttk.Button(buttons_frame, text="Quit", command=lambda: dialog_interaction_handler.interact("create", False, additional_action=dialog.destroy)).grid(column=1, row=0)
dialog.resizable(0,0) dialog.resizable(0,0)
dialog.mainloop() dialog.mainloop()
if dialog_communication.get("create"): if dialog_interaction_handler.get_result("create"):
self.__current_config = default_config self.__current_config = default_config
try: try:
config_file = open(self.__file_path, "w") config_file = open(self.__file_path, "w")

View File

@ -1,40 +1,13 @@
from PySide6 import QtWidgets class window:
import util def __init__(self):
pass
gui_handler_communication = util.Communication() def __del__(self):
app = QtWidgets.QApplication([])
class Window:
def __init__(self, title="Concorde", size_x=640, size_y=480):
self.window = QtWidgets.QWidget()
self.window.setWindowTitle(title)
self.window.resize(size_x, size_y)
self.window.show()
def __del__(self):
#TODO: whatever needs to be done here
pass pass
def set_title(self, title): def set_title(self, title):
self.window.setWindowTitle(title) pass
def get_geometry(self):
def get_size(self):
#TODO: implement
util.warn("Not implemented!")
return None return None
def set_geometry(self, geometry):
def set_size(self, size_x, size_y): pass
self.window.resize(size_x, size_y)
def update_menus(self, menu_dict): def update_menus(self, menu_dict):
#TODO: implement pass
util.warn("Not implemented!")
#TODO: This needs to run in a thread but Qt really doesn't want it to. There are two ways around this:
# - create the QtWidgets.QApplication inside a thread and run all QT stuff inside that thread
# - make a generic wrapper for window mainloop that will always run in the main thread while the actual main control flow of the program gets moved to another thread
# There are some issues with these workarounds though; mainly that QT isn't thread safe.
# I really want to keep QT running in its own thread because I want to retain the ability to arbitrarily spawn and manipulate windows while other windows are running.
# Another issue that is probably easily worked around / fixed is that app.exec() will return once all running windows are closed.
def fixme_window_mainloop_workaround_to_just_get_a_window_started_really_should_not_be_implemented_this_way_for_reasons_stated_in_the_comment_above_the_definition_of_this_function():
app.exec()

View File

@ -1,6 +1,56 @@
import tkinter as tk import tkinter as tk
import util import util
# easy way to get data out of window events
class Window_Interaction_Handler:
# constructor
def __init__(self):
self.__window_interactions = {}
# add a result for an interaction event, saves results in reverse order by default, can optionally call another function
def interact(self, name, result, reverse_order=True, additional_action=None, additional_action_parameters=()):
if name in self.__window_interactions:
if reverse_order:
self.__window_interactions[name] = [result] + self.__window_interactions[name]
else:
self.__window_interactions[name] = self.__window_interactions[name] + [result]
else:
self.__window_interactions[name] = [result]
if not additional_action==None:
additional_action(*additional_action_parameters)
# get first result for a given event from the list of results (newest (default) or oldest), removes the returned result from the list by default
def get_result(self, name, remove=True):
if name in self.__window_interactions and len(self.__window_interactions[name])>0:
if remove:
result = self.__window_interactions[name].pop(0)
if len(self.__window_interactions[name])==0:
del self.__window_interactions[name]
return result
else:
return self.__window_interactions[name][0]
else:
return None
# get all results for a given event
def get_results(self, name, clear=False):
if name in self.__window_interactions and len(self.__window_interactions[name])>0:
results = self.__window_interactions[name]
if clear:
del self.__window_interactions[name]
return results
# clear results for a given event
def clear(self, name):
if name in self.__window_interactions:
del self.__window_interactions[name]
# destructor
def __del__(self):
if len(self.__window_interactions)>0:
util.warn("__window_interactions not empty upon destruction of Window_Interaction_Handler:\n"+str(self.__window_interactions))
def not_implemented(): def not_implemented():
util.warn("Not implemented!") util.warn("Not implemented!")

22
main.py
View File

@ -1,6 +1,9 @@
#!/usr/bin/python3 #!/usr/bin/python3
import os import os
import gui_helper, gui_handler import tkinter as tk
from tkinter import ttk
import gui_helper
import gui_handler
from config import Config from config import Config
################################################################################ ################################################################################
@ -8,13 +11,9 @@ from config import Config
################################################################################ ################################################################################
default_configuration = { default_configuration = {
"window size": { "window geometry": "640x480"
"x": 800,
"y": 600
}
} }
#TODO: make this a hidden file once development is far enough along that it doesnt need to be recreated constantly configuration_file_path = os.path.join(os.path.expanduser("~"), "some_ide_config.json")
configuration_file_path = os.path.join(os.path.expanduser("~"), "concorde.json")
################################################################################ ################################################################################
# PROGRAM STARTUP # PROGRAM STARTUP
@ -26,13 +25,8 @@ configuration = Config(configuration_file_path, default_configuration)
# PROGRAM MAIN WINDOW # PROGRAM MAIN WINDOW
################################################################################ ################################################################################
main_window = gui_handler.Window() main_window = gui_handler.window()
main_window.set_title("Concorde IDE") main_window.set_title("Concorde IDE")
main_window.set_size(configuration.get_configuration_value("window size")["x"], configuration.get_configuration_value("window size")["y"]) main_window.set_geometry(configuration.get_configuration_value("window geometry"))
main_window.update_menus(gui_helper.menu_structure) main_window.update_menus(gui_helper.menu_structure)
#TODO: get resolution of main window on exit and save it back to the configuration
#TODO: check if the GUI encountered an error in a toolkit agnostic way
gui_handler.fixme_window_mainloop_workaround_to_just_get_a_window_started_really_should_not_be_implemented_this_way_for_reasons_stated_in_the_comment_above_the_definition_of_this_function()

50
util.py
View File

@ -25,53 +25,3 @@ def error(message, is_exception=True, handle_gracefully=True):
pass pass
else: else:
sys.exit(EXIT_ERROR) sys.exit(EXIT_ERROR)
# easy way to communicate across events
#TODO: make thread safe
class Communication:
def __init__(self):
self.__messages = {}
# send a message tagged with name and containing content, adds to the beginning of the list of messages with the same tag by default, a function to run as an additional action can be provided
def send(self, name, content, reverse_order=True, additional_action=None):
if name in self.__messages:
if reverse_order:
self.__messages[name] = [content] + self.__messages[name]
else:
self.__messages[name] = self.__messages[name] + [content]
else:
self.__messages[name] = [content]
if additional_action == None:
pass
else:
additional_action()
# get the content of the first message tagged with name, removes the returned message by default
def get(self, name, remove=True):
if name in self.__messages and len(self.__messages[name])>0:
if remove:
content = self.__messages[name].pop(0)
if len(self.__messages[name])==0:
del self.__messages[name]
return content
else:
return self.__messages[name][0]
else:
return None
# get the contents for all messages tagged with name
def get_all(self, name, clear=False):
if name in self.__messages and len(self.__messages[name])>0:
contents = self.__messages[name]
if clear:
del self.__messages[name]
return contents
# deletes all messages tagged with name
def clear(self, name):
if name in self.__messages:
del self.__messages[name]
def __del__(self):
if len(self.__messages)>0:
warn("__messages not empty upon destruction of Communication object:\n"+str(self.__messages))