4 Commits
Author SHA1 Message Date
Joelnir 91d71308df Added formatting options
Added the option to use another split separator than newline. Also
removed stripping of spaces at the beginning and end of lines of notes.
2016-04-15 21:16:34 +02:00
Joelnir 6e30be4b4a Merge branch 'master' of https://github.com/joelnir/SplitNotes 2016-04-15 16:18:59 +02:00
Joel a49e0934af Updated readme to reflect version 1.1
Changed a screenshot to show customization options and added text to "How to use" and "Features" about the changes in 1.1.
2016-02-20 10:43:58 +01:00
Joelnir fe83570cec Fixed Folder Name in Release 1.1
Fixed the folder name int eh compressed 1.1 folder to SplitNotes.
2016-02-20 00:59:58 +01:00
6 changed files with 130 additions and 35 deletions
+7 -1
View File
@@ -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. Splitnotes automatically shows notes for the split you are currently on.
![Screenshot 1](http://i.imgur.com/tYlSZMM.png) ![Screenshot 1](http://i.imgur.com/CMlF2pj.png)
![Screenshot 2](http://i.imgur.com/4Ei2IiJ.png) ![Screenshot 2](http://i.imgur.com/4Ei2IiJ.png)
## Install ## Install
@@ -45,12 +45,18 @@ Example:
2. Choose your text file. 2. Choose your text file.
3. Make sure that notes for the right amount of splits have been loaded. 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 ## Features
* Automatically displayed notes based on the active split in LiveSplit. * 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. * 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. * Two different font sizes to make sure that notes are easy to read.
* Double layout to preview notes for both current and next split. * 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 #### Development
Written in mainly procedural Python using tkinter GUI library. Written in mainly procedural Python using tkinter GUI library.
Binary file not shown.
+12 -6
View File
@@ -44,7 +44,8 @@ MENU_OPTIONS = {
# Error messages # Error messages
ERRORS = {"NOTES_EMPTY": ("Error!", "Notes empty or can't be loaded!"), ERRORS = {"NOTES_EMPTY": ("Error!", "Notes empty or can't be loaded!"),
"FONT_SIZE": ("Error!", "Invalid Font Size!"), "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 for notes
MAX_FILE_SIZE = 1000000000 # 1 Giga-Byte MAX_FILE_SIZE = 1000000000 # 1 Giga-Byte
@@ -62,7 +63,9 @@ TEXT_FILES = [
] ]
# Default content of config.cfg file # 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
REQUIRED_SETTINGS = ("notes", REQUIRED_SETTINGS = ("notes",
@@ -73,13 +76,14 @@ REQUIRED_SETTINGS = ("notes",
"server_port", "server_port",
"double_layout", "double_layout",
"width", "width",
"height" "height",
"separator"
) )
# Settings window options # Settings window options
SETTINGS_WINDOW = {"TITLE": "Settings", SETTINGS_WINDOW = {"TITLE": "Settings",
"WIDTH": 360, "WIDTH": 360,
"HEIGHT": 330, "HEIGHT": 410,
"CANCEL": "Cancel", "CANCEL": "Cancel",
"SAVE": "Save"} "SAVE": "Save"}
@@ -90,7 +94,9 @@ SETTINGS_OPTIONS = {"FONT": "Font",
"BG_COLOR": "Background Color", "BG_COLOR": "Background Color",
"SERVER_PORT": "LiveSplit Server port", "SERVER_PORT": "LiveSplit Server port",
"DEFAULT_SERVER_PORT": "(Default is 16834)", "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 # Fonts that can be selected
AVAILABLE_FONTS = ("arial", AVAILABLE_FONTS = ("arial",
@@ -100,4 +106,4 @@ AVAILABLE_FONTS = ("arial",
"ms serif", "ms serif",
"system", "system",
"times new roman", "times new roman",
"verdana") "verdana")
+33 -7
View File
@@ -16,7 +16,8 @@ runtime_info = {
"notes": [], "notes": [],
"server_port": 0, "server_port": 0,
"force_reset": False, "force_reset": False,
"double_layout": False "double_layout": False,
"settings": {}
} }
root = tkinter.Tk() root = tkinter.Tk()
@@ -219,7 +220,7 @@ def load_notes(window, text1, text2, com_socket):
file = noter.select_file() file = noter.select_file()
if file: if file:
notes = noter.get_notes(file) notes = noter.get_notes(file, runtime_info["settings"]["separator"])
if notes: if notes:
# Notes loaded correctly # Notes loaded correctly
runtime_info["notes"] = notes runtime_info["notes"] = notes
@@ -334,7 +335,7 @@ def set_title_notes(window, index, split_name=False):
update_title(title, window) 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. Opens the settings menu.
""" """
@@ -342,14 +343,16 @@ def menu_open_settings(root_wnd, box1, box2, text1, text2):
(lambda settings: apply_settings(settings, (lambda settings: apply_settings(settings,
root_wnd, root_wnd,
box1, box2, 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. Applies the given settings to the given components.
Settings must be a correctly formatted dictionary. Settings must be a correctly formatted dictionary.
""" """
runtime_info["settings"] = settings
# Server port change # Server port change
if not (runtime_info["server_port"] == int(settings["server_port"])): if not (runtime_info["server_port"] == int(settings["server_port"])):
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"]) text1.config(fg=settings["text_color"], bg=settings["background_color"])
text2.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): def save_geometry_settings(width, height):
""" """
@@ -397,6 +422,7 @@ def init_UI(root):
# Load Settings # Load Settings
settings = setting_handler.load_settings() settings = setting_handler.load_settings()
runtime_info["server_port"] = int(settings["server_port"]) runtime_info["server_port"] = int(settings["server_port"])
runtime_info["settings"] = settings
# Graphical components # Graphical components
root.geometry(settings["width"] + "x" + settings["height"]) root.geometry(settings["width"] + "x" + settings["height"])
@@ -453,7 +479,7 @@ def init_UI(root):
) )
popup.add_command( popup.add_command(
label=config.MENU_OPTIONS["SETTINGS"], 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 # Set default window icon and title
@@ -464,7 +490,7 @@ def init_UI(root):
settings = setting_handler.load_settings() settings = setting_handler.load_settings()
if settings["notes"] and noter.file_exists(settings["notes"]): 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: if notes:
runtime_info["notes"] = notes runtime_info["notes"] = notes
+17 -10
View File
@@ -5,9 +5,10 @@ import config
""" """
NOTE STANDARD FORMATTING NOTE STANDARD FORMATTING
empty newlines separate notes for different splits 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. lines that start and end with [ ] are ignored for notes.
these can be used for titles. these can be used for titles.
(ex. [Split1] is not included in notes) (ex. [Split1] is not included in notes)
@@ -50,21 +51,29 @@ def get_note_lines(file_path):
return f_lines return f_lines
def encode_notes(note_lines): def decode_notes(note_lines, separator):
""" """
Takes a list containing strings. Takes a list containing strings.
Encodes given strings according to the note formatting. Encodes given strings according to the note formatting.
Returns the list containing the notes for every split. 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): def is_title(line):
if not line: if not line:
return False return False
return (line[0] == "[") and (line[-1] == "]") return (line[0] == "[") and (line[-1] == "]")
def is_newline(line): def is_separator(line):
return (line == "\n") or (line == "\r") return (line == separator)
def is_newline(s):
return (s == "\n")
def remove_new_line(line): def remove_new_line(line):
if (len(line) >= 1) and (is_newline(line[-1])): if (len(line) >= 1) and (is_newline(line[-1])):
@@ -76,15 +85,13 @@ def encode_notes(note_lines):
cur_notes = "" cur_notes = ""
for line in note_lines: for line in note_lines:
# remove whitespace at beginning and end line = remove_new_line(line)
line = line.strip(" ")
if is_newline(line): if is_separator(line):
if cur_notes: if cur_notes:
note_list.append(cur_notes) note_list.append(cur_notes)
cur_notes = "" cur_notes = ""
else: else:
line = remove_new_line(line)
if not is_title(line): if not is_title(line):
cur_notes += line + "\n" # newline cur_notes += line + "\n" # newline
@@ -94,7 +101,7 @@ def encode_notes(note_lines):
return note_list 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 Takes a path to a file and returns a list with the notes
in the file encoded according to the note fromatting. in the file encoded according to the note fromatting.
@@ -106,7 +113,7 @@ def get_notes(file_path):
if not note_lines: if not note_lines:
return False return False
note_list = encode_notes(note_lines) note_list = decode_notes(note_lines, separator)
return note_list return note_list
+61 -11
View File
@@ -127,6 +127,9 @@ def validate_settings(settings):
if not validate_pixels(settings["height"]): if not validate_pixels(settings["height"]):
return False return False
if not validate_separator(settings["separator"]):
return False
return True return True
@@ -171,6 +174,12 @@ def edit_settings(root_wnd, apply_method):
layout_label = tkinter.Label(settings_wnd, layout_label = tkinter.Label(settings_wnd,
text=config.SETTINGS_OPTIONS["DOUBLE_LAYOUT"], text=config.SETTINGS_OPTIONS["DOUBLE_LAYOUT"],
font=config.GUI_FONT) 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, port_label = tkinter.Label(settings_wnd,
text=config.SETTINGS_OPTIONS["SERVER_PORT"], text=config.SETTINGS_OPTIONS["SERVER_PORT"],
font=config.GUI_FONT) font=config.GUI_FONT)
@@ -243,6 +252,28 @@ def edit_settings(root_wnd, apply_method):
if decode_boolean_setting(settings["double_layout"]): if decode_boolean_setting(settings["double_layout"]):
double_layout_btn.select() 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 # Save and cancel buttons
def control_and_save(): def control_and_save():
errors_found = False errors_found = False
@@ -252,6 +283,11 @@ def edit_settings(root_wnd, apply_method):
chosen_font_size = font_size_entry.get() chosen_font_size = font_size_entry.get()
chosen_port = port_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()) settings["double_layout"] = encode_boolean_setting(double_layout.get())
if not validate_font_size(chosen_font_size): if not validate_font_size(chosen_font_size):
@@ -266,6 +302,12 @@ def edit_settings(root_wnd, apply_method):
else: else:
settings["server_port"] = chosen_port 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: if not errors_found:
save_settings(settings) save_settings(settings)
apply_method(settings) apply_method(settings)
@@ -288,18 +330,22 @@ def edit_settings(root_wnd, apply_method):
text_color_label.place(x=15, y=95) text_color_label.place(x=15, y=95)
bg_color_label.place(x=15, y=135) bg_color_label.place(x=15, y=135)
layout_label.place(x=15, y=175) layout_label.place(x=15, y=175)
port_label.place(x=15, y=215) newline_label.place(x=15, y=215)
default_port_label.place(x=15, y=240) 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_dropdown.place(x=208, y=15)
font_size_entry.place(x=180, y=55) font_size_entry.place(x=210, y=55)
text_color.place(x=180, y=95) text_color.place(x=210, y=95)
bg_color.place(x=180, y=135) bg_color.place(x=210, y=135)
double_layout_btn.place(x=180, y=175) double_layout_btn.place(x=210, y=175)
port_entry.place(x=180, y=215) 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) save_btn.place(x=110, y=350)
cancel_btn.place(x=190, y=280) cancel_btn.place(x=190, y=350)
def validate_color(color): def validate_color(color):
@@ -365,7 +411,7 @@ def encode_boolean_setting(value):
def validate_pixels(pixels): def validate_pixels(pixels):
""" """
Checks if given string can be used as a pixel value for height or width. 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: try:
pixels = int(pixels) pixels = int(pixels)
@@ -373,3 +419,7 @@ def validate_pixels(pixels):
return False return False
return 0 < pixels < 10000 return 0 < pixels < 10000
def validate_separator(separator):
return separator.strip()