diff --git a/config.py b/config.py index 4894992..8ad5b06 100644 --- a/config.py +++ b/config.py @@ -14,8 +14,8 @@ LS_COMMANDS = { "cur_split_name": "getcurrentsplitname\r\n" } -# Default Window Size -DEFAULT_WINDOW = {"WIDTH": 400, "HEIGHT": 300, "TITLE": "SplitNotes"} +# Default Window Settings +DEFAULT_WINDOW = {"TITLE": "SplitNotes"} # Default Welcome Message DEFAULT_MSG = "Right Click to Open Notes." @@ -23,11 +23,14 @@ DEFAULT_MSG = "Right Click to Open Notes." # Update time for polling livesplit and other actions (in seconds) POLLING_TIME = 0.5 -# file names and path for resources +# File names and path for resources RESOURCE_FOLDER = "resources" ICONS = {"GREEN": "green.png", "RED": "red.png", "SETTINGS": "settings_icon.png"} SETTINGS_FILE = "config.cfg" +# Default Scrollbar Width +SCROLLBAR_WIDTH = 16 + # Popup menu options MENU_OPTIONS = { "SINGLE": "Set Single Layout", @@ -49,14 +52,9 @@ MAX_FILE_SIZE = 1000000000 # 1 Giga-Byte # To be added to title to alert user that timer is running RUNNING_ALERT = "RUNNING" -# Font for notes/ -# TODO FIX THIS -FONT = {"NAME": "arial", "SMALL": 12, "BIG": 16} +# Font for gui widgets GUI_FONT = ("arial", 12) -# Color scheme -COLOR = {"TEXT": "black", "TEXT_BG": "ivory"} - # Files tht should be displayed and opened a notes TEXT_FILES = [ ("Text Files", ("*.txt", "*.log", "*.asc", "*.conf", "*.cfg")), @@ -64,7 +62,7 @@ TEXT_FILES = [ ] # Default content of config.cfg file -DEFAULT_CONFIG = "notes=\nfont_size=12\nfont=arial\ntext_color=#000000\nbackground_color=#FFFFFF\ndouble_layout=False\nserver_port=16834" +DEFAULT_CONFIG = "notes=\nfont_size=12\nfont=arial\ntext_color=#000000\nbackground_color=#FFFFFF\ndouble_layout=False\nserver_port=16834\nwidth=400\nheight=300" # Required settings REQUIRED_SETTINGS = ("notes", @@ -73,7 +71,9 @@ REQUIRED_SETTINGS = ("notes", "text_color", "background_color", "server_port", - "double_layout" + "double_layout", + "width", + "height" ) # Settings window options diff --git a/main_window.py b/main_window.py index d4c9fce..e95e5c4 100644 --- a/main_window.py +++ b/main_window.py @@ -1,8 +1,6 @@ import tkinter from tkinter import messagebox -from tkinter import font -import socket import os import sys @@ -17,7 +15,8 @@ runtime_info = { "active_split": -1, "notes": [], "server_port": 0, - "force_reset": False + "force_reset": False, + "double_layout": False } root = tkinter.Tk() @@ -41,7 +40,7 @@ def update(window, com_socket, text1, text2): Function to loop along tkinter mainloop. """ if runtime_info["force_reset"]: - #boolean flag to force a connection reset + # Boolean flag to force a connection reset com_socket = reset_connection(com_socket, window, text1, text2) runtime_info["force_reset"] = False @@ -242,6 +241,7 @@ def load_notes(window, text1, text2, com_socket): else: show_info(config.ERRORS["NOTES_EMPTY"], True) + def show_info(info, warning=False): """ Displays an info popup window. @@ -335,15 +335,22 @@ def set_title_notes(window, index, split_name=False): def menu_open_settings(root_wnd, box1, box2, text1, text2): + """ + Opens the settings menu. + """ setting_handler.edit_settings(root_wnd, (lambda settings: apply_settings(settings, root_wnd, - box1,box2, + box1, box2, text1, text2))) def apply_settings(settings, window, box1, box2, text1, text2): - #Server port change + """ + Applies the given settings to the given components. + Settings must be a correctly formatted dictionary. + """ + # Server port change if not (runtime_info["server_port"] == int(settings["server_port"])): runtime_info["server_port"] = int(settings["server_port"]) runtime_info["force_reset"] = True @@ -361,6 +368,26 @@ def apply_settings(settings, window, box1, box2, text1, text2): text2.config(fg=settings["text_color"], bg=settings["background_color"]) +def save_geometry_settings(width, height): + """ + Saves given width and height to settigns file. + """ + settings = setting_handler.load_settings() + settings["width"] = str(width) + settings["height"] = str(height) + setting_handler.save_settings(settings) + + +def do_on_close(root_wnd): + """ + Function that is called when the main tk window is closed. + Saves root_wnd's width and height to the settings file and + then closes the window. + """ + save_geometry_settings(root_wnd.winfo_width(), root_wnd.winfo_height()) + root_wnd.destroy() + + def init_UI(root): """Draws default UI and creates event bindings.""" @@ -372,15 +399,14 @@ def init_UI(root): runtime_info["server_port"] = int(settings["server_port"]) # Graphical components - root.geometry(str(config.DEFAULT_WINDOW["WIDTH"]) + "x" + str(config.DEFAULT_WINDOW["HEIGHT"])) + root.geometry(settings["width"] + "x" + settings["height"]) box1 = tkinter.Frame(root) box2 = tkinter.Frame(root) - scroll1 = tkinter.Scrollbar(box1) + scroll1 = tkinter.Scrollbar(box1, width=config.SCROLLBAR_WIDTH) + scroll2 = tkinter.Scrollbar(box2, width=config.SCROLLBAR_WIDTH) scroll1.pack(side=tkinter.RIGHT, fill=tkinter.Y) - - scroll2 = tkinter.Scrollbar(box2) scroll2.pack(side=tkinter.RIGHT, fill=tkinter.Y) text1 = tkinter.Text( @@ -393,7 +419,6 @@ def init_UI(root): text1.config(state=tkinter.DISABLED) text1.pack(fill=tkinter.BOTH, expand=True) - text2 = tkinter.Text( box2, yscrollcommand=scroll2.set, @@ -451,9 +476,13 @@ def init_UI(root): root.bind("", (lambda e: right_arrow(root, com_socket, text1, text2))) root.bind("", (lambda e: left_arrow(root, com_socket, text1, text2))) + # Window close bind + root.protocol("WM_DELETE_WINDOW", (lambda: do_on_close(root))) + # call update loop update(root, com_socket, text1, text2) + root.geometry(settings["width"] + "x" + settings["height"]) init_UI(root) diff --git a/note_reader.py b/note_reader.py index 211a263..85fea47 100644 --- a/note_reader.py +++ b/note_reader.py @@ -36,7 +36,11 @@ def get_note_lines(file_path): f_lines = [] keep_reading = True while keep_reading: - cur_line = notes_file.readline() + + try: + cur_line = notes_file.readline() + except: + return False if cur_line: f_lines.append(cur_line) @@ -123,4 +127,5 @@ def select_file(): def file_exists(file): - return path.isfile(file) \ No newline at end of file + """Checks if given path leads to an existing file.""" + return path.isfile(file) diff --git a/setting_handler.py b/setting_handler.py index 01ba985..8c4442f 100644 --- a/setting_handler.py +++ b/setting_handler.py @@ -33,7 +33,7 @@ def load_settings(): settings_content = get_file_lines(settings_file) except: # File not found - settings_content = set_default_settings(); + settings_content = set_default_settings() settings = format_settings(settings_content) @@ -121,6 +121,12 @@ def validate_settings(settings): (settings["double_layout"] == "False")): return False + if not validate_pixels(settings["width"]): + return False + + if not validate_pixels(settings["height"]): + return False + return True @@ -172,7 +178,6 @@ def edit_settings(root_wnd, apply_method): text=config.SETTINGS_OPTIONS["DEFAULT_SERVER_PORT"], font=config.GUI_FONT) - # Font Selection selected_font = tkinter.StringVar(settings_wnd) selected_font.set(settings["font"]) @@ -210,8 +215,7 @@ def edit_settings(root_wnd, apply_method): # Background color Selection bg_color = tkinter.Button(settings_wnd, width=3, - height=1, - ) + height=1) if validate_color(settings["background_color"]): bg_color.configure(background=settings["background_color"]) @@ -322,13 +326,16 @@ def validate_server_port(port): Returns Whether or not gicen port is a valid server port. """ try: - port = int(port) + int(port) return True except: return False def save_settings(settings): + """ + Saves given settings to the settings file. + """ file_content = "" for key in settings.keys(): @@ -338,10 +345,31 @@ def save_settings(settings): def decode_boolean_setting(setting): + """ + Decodes a boolean string of "True" or "False" + to the coorect boolean value. + """ return setting == "True" + def encode_boolean_setting(value): + """ + Encodes a boolean to the string "True" or "False". + """ if value: return "True" else: return "False" + + +def validate_pixels(pixels): + """ + Checks if given string can be used as a pixel value for height or width. + Height or Width ar assumed to never surpass 10000 + """ + try: + pixels = int(pixels) + except: + return False + + return 0 < pixels < 10000