mirror of
https://github.com/ApfelTeeSaft/SplitNotes.git
synced 2026-08-27 11:53:28 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91d71308df | ||
|
|
6e30be4b4a | ||
|
|
a49e0934af | ||
|
|
fe83570cec |
@@ -3,7 +3,7 @@ Software for syncing notes with LiveSplit using the LiveSplit server component.
|
||||
|
||||
Splitnotes automatically shows notes for the split you are currently on.
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
## Install
|
||||
@@ -45,12 +45,18 @@ Example:
|
||||
2. Choose your text file.
|
||||
3. Make sure that notes for the right amount of splits have been loaded.
|
||||
|
||||
**Change Settings**
|
||||
1. Right-Click in SplitNotes and select "Settings"
|
||||
2. The settings menu will show up. Here you can set things like font, font size, text and background color and the server port.
|
||||
|
||||
## Features
|
||||
|
||||
* Automatically displayed notes based on the active split in LiveSplit.
|
||||
* Ability to preview notes in the software when no run is going on by using the right and left arrow keys.
|
||||
* Two different font sizes to make sure that notes are easy to read.
|
||||
* Double layout to preview notes for both current and next split.
|
||||
* Multiple settings to change the look of the text.
|
||||
* Ability to set a custom port for interaction with the LiveSplit Server.
|
||||
|
||||
#### Development
|
||||
Written in mainly procedural Python using tkinter GUI library.
|
||||
|
||||
Binary file not shown.
@@ -44,7 +44,8 @@ MENU_OPTIONS = {
|
||||
# Error messages
|
||||
ERRORS = {"NOTES_EMPTY": ("Error!", "Notes empty or can't be loaded!"),
|
||||
"FONT_SIZE": ("Error!", "Invalid Font Size!"),
|
||||
"SERVER_PORT": ("Error!", "Invalid server port!")}
|
||||
"SERVER_PORT": ("Error!", "Invalid server port!"),
|
||||
"SEPARATOR": ("Error!", "Invalid split separator!")}
|
||||
|
||||
# Max file size for notes
|
||||
MAX_FILE_SIZE = 1000000000 # 1 Giga-Byte
|
||||
@@ -62,7 +63,9 @@ 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\nwidth=400\nheight=300"
|
||||
DEFAULT_CONFIG = "notes=\nfont_size=12\nfont=arial\ntext_color=#000000\nbackground_color=#FFFFFF\ndouble_layout=False\nserver_port=16834\nwidth=400\nheight=300\nseparator=new_line"
|
||||
|
||||
NEWLINE_CONSTANT = "new_line"
|
||||
|
||||
# Required settings
|
||||
REQUIRED_SETTINGS = ("notes",
|
||||
@@ -73,13 +76,14 @@ REQUIRED_SETTINGS = ("notes",
|
||||
"server_port",
|
||||
"double_layout",
|
||||
"width",
|
||||
"height"
|
||||
"height",
|
||||
"separator"
|
||||
)
|
||||
|
||||
# Settings window options
|
||||
SETTINGS_WINDOW = {"TITLE": "Settings",
|
||||
"WIDTH": 360,
|
||||
"HEIGHT": 330,
|
||||
"HEIGHT": 410,
|
||||
"CANCEL": "Cancel",
|
||||
"SAVE": "Save"}
|
||||
|
||||
@@ -90,7 +94,9 @@ SETTINGS_OPTIONS = {"FONT": "Font",
|
||||
"BG_COLOR": "Background Color",
|
||||
"SERVER_PORT": "LiveSplit Server port",
|
||||
"DEFAULT_SERVER_PORT": "(Default is 16834)",
|
||||
"DOUBLE_LAYOUT": "Use double layout"}
|
||||
"DOUBLE_LAYOUT": "Use double layout",
|
||||
"NEW_LINE_SEPARATOR": "Newline as split separator",
|
||||
"CUSTOM_SEPARATOR": "Custom split separator"}
|
||||
|
||||
# Fonts that can be selected
|
||||
AVAILABLE_FONTS = ("arial",
|
||||
@@ -100,4 +106,4 @@ AVAILABLE_FONTS = ("arial",
|
||||
"ms serif",
|
||||
"system",
|
||||
"times new roman",
|
||||
"verdana")
|
||||
"verdana")
|
||||
+33
-7
@@ -16,7 +16,8 @@ runtime_info = {
|
||||
"notes": [],
|
||||
"server_port": 0,
|
||||
"force_reset": False,
|
||||
"double_layout": False
|
||||
"double_layout": False,
|
||||
"settings": {}
|
||||
}
|
||||
|
||||
root = tkinter.Tk()
|
||||
@@ -219,7 +220,7 @@ def load_notes(window, text1, text2, com_socket):
|
||||
file = noter.select_file()
|
||||
|
||||
if file:
|
||||
notes = noter.get_notes(file)
|
||||
notes = noter.get_notes(file, runtime_info["settings"]["separator"])
|
||||
if notes:
|
||||
# Notes loaded correctly
|
||||
runtime_info["notes"] = notes
|
||||
@@ -334,7 +335,7 @@ def set_title_notes(window, index, split_name=False):
|
||||
update_title(title, window)
|
||||
|
||||
|
||||
def menu_open_settings(root_wnd, box1, box2, text1, text2):
|
||||
def menu_open_settings(root_wnd, box1, box2, text1, text2, com_socket):
|
||||
"""
|
||||
Opens the settings menu.
|
||||
"""
|
||||
@@ -342,14 +343,16 @@ def menu_open_settings(root_wnd, box1, box2, text1, text2):
|
||||
(lambda settings: apply_settings(settings,
|
||||
root_wnd,
|
||||
box1, box2,
|
||||
text1, text2)))
|
||||
text1, text2, com_socket)))
|
||||
|
||||
|
||||
def apply_settings(settings, window, box1, box2, text1, text2):
|
||||
def apply_settings(settings, window, box1, box2, text1, text2, com_socket):
|
||||
"""
|
||||
Applies the given settings to the given components.
|
||||
Settings must be a correctly formatted dictionary.
|
||||
"""
|
||||
runtime_info["settings"] = settings
|
||||
|
||||
# Server port change
|
||||
if not (runtime_info["server_port"] == int(settings["server_port"])):
|
||||
runtime_info["server_port"] = int(settings["server_port"])
|
||||
@@ -367,6 +370,28 @@ def apply_settings(settings, window, box1, box2, text1, text2):
|
||||
text1.config(fg=settings["text_color"], bg=settings["background_color"])
|
||||
text2.config(fg=settings["text_color"], bg=settings["background_color"])
|
||||
|
||||
old_note_length = len(runtime_info["notes"])
|
||||
|
||||
if settings["notes"] and noter.file_exists(settings["notes"]):
|
||||
new_notes = noter.get_notes(settings["notes"], settings["separator"])
|
||||
|
||||
if new_notes:
|
||||
# Notes loaded correctly
|
||||
runtime_info["notes"] = new_notes
|
||||
|
||||
new_note_length = len(new_notes)
|
||||
|
||||
if not (new_note_length == old_note_length):
|
||||
show_info(("Notes Loaded",
|
||||
("Loaded notes with " + str(new_note_length) + " splits.")))
|
||||
|
||||
if not runtime_info["timer_running"]:
|
||||
runtime_info["active_split"] = -1
|
||||
|
||||
update_GUI(window, com_socket, text1, text2)
|
||||
else:
|
||||
show_info(config.ERRORS["NOTES_EMPTY"], True)
|
||||
|
||||
|
||||
def save_geometry_settings(width, height):
|
||||
"""
|
||||
@@ -397,6 +422,7 @@ def init_UI(root):
|
||||
# Load Settings
|
||||
settings = setting_handler.load_settings()
|
||||
runtime_info["server_port"] = int(settings["server_port"])
|
||||
runtime_info["settings"] = settings
|
||||
|
||||
# Graphical components
|
||||
root.geometry(settings["width"] + "x" + settings["height"])
|
||||
@@ -453,7 +479,7 @@ def init_UI(root):
|
||||
)
|
||||
popup.add_command(
|
||||
label=config.MENU_OPTIONS["SETTINGS"],
|
||||
command=(lambda: menu_open_settings(root, box1, box2, text1, text2))
|
||||
command=(lambda: menu_open_settings(root, box1, box2, text1, text2, com_socket))
|
||||
)
|
||||
|
||||
# Set default window icon and title
|
||||
@@ -464,7 +490,7 @@ def init_UI(root):
|
||||
settings = setting_handler.load_settings()
|
||||
|
||||
if settings["notes"] and noter.file_exists(settings["notes"]):
|
||||
notes = noter.get_notes(settings["notes"])
|
||||
notes = noter.get_notes(settings["notes"], settings["separator"])
|
||||
|
||||
if notes:
|
||||
runtime_info["notes"] = notes
|
||||
|
||||
+17
-10
@@ -5,9 +5,10 @@ import config
|
||||
|
||||
"""
|
||||
NOTE STANDARD FORMATTING
|
||||
|
||||
empty newlines separate notes for different splits
|
||||
|
||||
It is also possible to set your own split separator in the settings menu
|
||||
|
||||
lines that start and end with [ ] are ignored for notes.
|
||||
these can be used for titles.
|
||||
(ex. [Split1] is not included in notes)
|
||||
@@ -50,21 +51,29 @@ def get_note_lines(file_path):
|
||||
return f_lines
|
||||
|
||||
|
||||
def encode_notes(note_lines):
|
||||
def decode_notes(note_lines, separator):
|
||||
"""
|
||||
Takes a list containing strings.
|
||||
Encodes given strings according to the note formatting.
|
||||
Returns the list containing the notes for every split.
|
||||
"""
|
||||
|
||||
#Check if newline is being used as separator
|
||||
|
||||
if separator == config.NEWLINE_CONSTANT:
|
||||
separator = "" # left after stripping newline
|
||||
|
||||
def is_title(line):
|
||||
if not line:
|
||||
return False
|
||||
|
||||
return (line[0] == "[") and (line[-1] == "]")
|
||||
|
||||
def is_newline(line):
|
||||
return (line == "\n") or (line == "\r")
|
||||
def is_separator(line):
|
||||
return (line == separator)
|
||||
|
||||
def is_newline(s):
|
||||
return (s == "\n")
|
||||
|
||||
def remove_new_line(line):
|
||||
if (len(line) >= 1) and (is_newline(line[-1])):
|
||||
@@ -76,15 +85,13 @@ def encode_notes(note_lines):
|
||||
cur_notes = ""
|
||||
|
||||
for line in note_lines:
|
||||
# remove whitespace at beginning and end
|
||||
line = line.strip(" ")
|
||||
line = remove_new_line(line)
|
||||
|
||||
if is_newline(line):
|
||||
if is_separator(line):
|
||||
if cur_notes:
|
||||
note_list.append(cur_notes)
|
||||
cur_notes = ""
|
||||
else:
|
||||
line = remove_new_line(line)
|
||||
if not is_title(line):
|
||||
cur_notes += line + "\n" # newline
|
||||
|
||||
@@ -94,7 +101,7 @@ def encode_notes(note_lines):
|
||||
return note_list
|
||||
|
||||
|
||||
def get_notes(file_path):
|
||||
def get_notes(file_path, separator):
|
||||
"""
|
||||
Takes a path to a file and returns a list with the notes
|
||||
in the file encoded according to the note fromatting.
|
||||
@@ -106,7 +113,7 @@ def get_notes(file_path):
|
||||
if not note_lines:
|
||||
return False
|
||||
|
||||
note_list = encode_notes(note_lines)
|
||||
note_list = decode_notes(note_lines, separator)
|
||||
|
||||
return note_list
|
||||
|
||||
|
||||
+61
-11
@@ -127,6 +127,9 @@ def validate_settings(settings):
|
||||
if not validate_pixels(settings["height"]):
|
||||
return False
|
||||
|
||||
if not validate_separator(settings["separator"]):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@@ -171,6 +174,12 @@ def edit_settings(root_wnd, apply_method):
|
||||
layout_label = tkinter.Label(settings_wnd,
|
||||
text=config.SETTINGS_OPTIONS["DOUBLE_LAYOUT"],
|
||||
font=config.GUI_FONT)
|
||||
newline_label = tkinter.Label(settings_wnd,
|
||||
text=config.SETTINGS_OPTIONS["NEW_LINE_SEPARATOR"],
|
||||
font=config.GUI_FONT)
|
||||
separator_label = tkinter.Label(settings_wnd,
|
||||
text=config.SETTINGS_OPTIONS["CUSTOM_SEPARATOR"],
|
||||
font=config.GUI_FONT)
|
||||
port_label = tkinter.Label(settings_wnd,
|
||||
text=config.SETTINGS_OPTIONS["SERVER_PORT"],
|
||||
font=config.GUI_FONT)
|
||||
@@ -243,6 +252,28 @@ def edit_settings(root_wnd, apply_method):
|
||||
if decode_boolean_setting(settings["double_layout"]):
|
||||
double_layout_btn.select()
|
||||
|
||||
# Separator selection
|
||||
separator_entry = tkinter.Entry(settings_wnd, width=14, font=config.GUI_FONT)
|
||||
|
||||
def set_separator_active(active):
|
||||
if active:
|
||||
separator_entry.configure(state="normal")
|
||||
else:
|
||||
separator_entry.configure(state="disabled")
|
||||
|
||||
use_newline = tkinter.BooleanVar()
|
||||
newline_btn = tkinter.Checkbutton(settings_wnd,
|
||||
variable=use_newline,
|
||||
command=
|
||||
(lambda: set_separator_active(not use_newline.get()))
|
||||
)
|
||||
|
||||
if settings["separator"] == config.NEWLINE_CONSTANT:
|
||||
newline_btn.select()
|
||||
set_separator_active(False);
|
||||
else:
|
||||
separator_entry.insert(0, settings["separator"])
|
||||
|
||||
# Save and cancel buttons
|
||||
def control_and_save():
|
||||
errors_found = False
|
||||
@@ -252,6 +283,11 @@ def edit_settings(root_wnd, apply_method):
|
||||
chosen_font_size = font_size_entry.get()
|
||||
chosen_port = port_entry.get()
|
||||
|
||||
if use_newline.get():
|
||||
chosen_separator = config.NEWLINE_CONSTANT
|
||||
else:
|
||||
chosen_separator = separator_entry.get()
|
||||
|
||||
settings["double_layout"] = encode_boolean_setting(double_layout.get())
|
||||
|
||||
if not validate_font_size(chosen_font_size):
|
||||
@@ -266,6 +302,12 @@ def edit_settings(root_wnd, apply_method):
|
||||
else:
|
||||
settings["server_port"] = chosen_port
|
||||
|
||||
if not validate_separator(chosen_separator):
|
||||
msgbox.showerror(config.ERRORS["SEPARATOR"][0], config.ERRORS["SEPARATOR"][1])
|
||||
errors_found = True
|
||||
else:
|
||||
settings["separator"] = chosen_separator
|
||||
|
||||
if not errors_found:
|
||||
save_settings(settings)
|
||||
apply_method(settings)
|
||||
@@ -288,18 +330,22 @@ def edit_settings(root_wnd, apply_method):
|
||||
text_color_label.place(x=15, y=95)
|
||||
bg_color_label.place(x=15, y=135)
|
||||
layout_label.place(x=15, y=175)
|
||||
port_label.place(x=15, y=215)
|
||||
default_port_label.place(x=15, y=240)
|
||||
newline_label.place(x=15, y=215)
|
||||
separator_label.place(x=15, y=240)
|
||||
port_label.place(x=15, y=280)
|
||||
default_port_label.place(x=15, y=305)
|
||||
|
||||
font_dropdown.place(x=178, y=15)
|
||||
font_size_entry.place(x=180, y=55)
|
||||
text_color.place(x=180, y=95)
|
||||
bg_color.place(x=180, y=135)
|
||||
double_layout_btn.place(x=180, y=175)
|
||||
port_entry.place(x=180, y=215)
|
||||
font_dropdown.place(x=208, y=15)
|
||||
font_size_entry.place(x=210, y=55)
|
||||
text_color.place(x=210, y=95)
|
||||
bg_color.place(x=210, y=135)
|
||||
double_layout_btn.place(x=210, y=175)
|
||||
newline_btn.place(x=210, y=215)
|
||||
separator_entry.place(x=210, y=240)
|
||||
port_entry.place(x=210, y=280)
|
||||
|
||||
save_btn.place(x=110, y=280)
|
||||
cancel_btn.place(x=190, y=280)
|
||||
save_btn.place(x=110, y=350)
|
||||
cancel_btn.place(x=190, y=350)
|
||||
|
||||
|
||||
def validate_color(color):
|
||||
@@ -365,7 +411,7 @@ def encode_boolean_setting(value):
|
||||
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
|
||||
Height or Width or assumed to never surpass 10000
|
||||
"""
|
||||
try:
|
||||
pixels = int(pixels)
|
||||
@@ -373,3 +419,7 @@ def validate_pixels(pixels):
|
||||
return False
|
||||
|
||||
return 0 < pixels < 10000
|
||||
|
||||
|
||||
def validate_separator(separator):
|
||||
return separator.strip()
|
||||
|
||||
Reference in New Issue
Block a user