diff --git a/.github/workflows/themes-screenshot-on-pr.yml b/.github/workflows/themes-screenshot-on-pr.yml index 76401c27..80e9f0ca 100644 --- a/.github/workflows/themes-screenshot-on-pr.yml +++ b/.github/workflows/themes-screenshot-on-pr.yml @@ -31,15 +31,15 @@ jobs: do if test -f "$dir/theme.yaml"; then # Keep only folder name - theme=`basename ${dir%*/}` + theme=`basename "${dir%*/}"` # Setup selected theme in config.yaml echo "Using theme $theme" - sed -i "/THEME:/c\ THEME: $theme" config.yaml + sed -i '/THEME:/c\ THEME: "'"$theme"'"' config.yaml # For tests there is no real HW: use simulated LCD mode # Check if theme is for 5" - orientation=$(grep 'DISPLAY_SIZE' $dir/theme.yaml | sed 's/ //g') + orientation=$(grep 'DISPLAY_SIZE' "$dir/theme.yaml" | sed 's/ //g') if [ "$orientation" == "DISPLAY_SIZE:5\"" ]; then sed -i "/REVISION:/c\ REVISION: SIMU5" config.yaml else diff --git a/.github/workflows/themes-screenshot-on-push.yml b/.github/workflows/themes-screenshot-on-push.yml index 1c023337..60e8bc3d 100644 --- a/.github/workflows/themes-screenshot-on-push.yml +++ b/.github/workflows/themes-screenshot-on-push.yml @@ -42,15 +42,15 @@ jobs: do if test -f "$dir/theme.yaml"; then # Keep only folder name - theme=`basename ${dir%*/}` + theme=`basename "${dir%*/}"` # Setup selected theme in config.yaml echo "Using theme $theme" - sed -i "/THEME:/c\ THEME: $theme" config.yaml - + sed -i '/THEME:/c\ THEME: "'"$theme"'"' config.yaml + # For tests there is no real HW: use simulated LCD mode # Check if theme is for 5" - orientation=$(grep 'DISPLAY_SIZE' $dir/theme.yaml | sed 's/ //g') + orientation=$(grep 'DISPLAY_SIZE' "$dir/theme.yaml" | sed 's/ //g') if [ "$orientation" == "DISPLAY_SIZE:5\"" ]; then sed -i "/REVISION:/c\ REVISION: SIMU5" config.yaml else diff --git a/configure.py b/configure.py index e435842c..d56ffcb5 100755 --- a/configure.py +++ b/configure.py @@ -40,6 +40,7 @@ import psutil import ruamel.yaml import sv_ttk + from pathlib import Path from PIL import Image from serial.tools.list_ports import comports from tktooltip import ToolTip @@ -92,11 +93,12 @@ "STUB": "Fake random data", "STATIC": "Fake static data"} reverse_map = {False: "classic", True: "reverse"} -themes_dir = 'res/themes' +MAIN_DIRECTORY = str(Path(__file__).parent.resolve()) + "/" +THEMES_DIR = MAIN_DIRECTORY + 'res/themes' def get_theme_data(name: str): - dir = os.path.join(themes_dir, name) + dir = os.path.join(THEMES_DIR, name) # checking if it is a directory if os.path.isdir(dir): # Check if a theme.yaml file exists @@ -111,7 +113,7 @@ def get_theme_data(name: str): def get_themes(size: str): themes = [] - for filename in os.listdir(themes_dir): + for filename in os.listdir(THEMES_DIR): theme_data = get_theme_data(filename) if theme_data and theme_data['display'].get("DISPLAY_SIZE", '3.5"') == size: themes.append(filename) @@ -155,7 +157,7 @@ def __init__(self): self.window = Tk() self.window.title('Turing System Monitor configuration') self.window.geometry("770x570") - self.window.iconphoto(True, PhotoImage(file="res/icons/monitor-icon-17865/64.png")) + self.window.iconphoto(True, PhotoImage(file=MAIN_DIRECTORY + "res/icons/monitor-icon-17865/64.png")) # When window gets focus again, reload theme preview in case it has been updated by theme editor self.window.bind("", self.on_theme_change) self.window.after(0, self.on_fan_speed_update) @@ -266,9 +268,9 @@ def run(self): def load_theme_preview(self): try: - theme_preview = Image.open("res/themes/" + self.theme_cb.get() + "/preview.png") + theme_preview = Image.open(MAIN_DIRECTORY + "res/themes/" + self.theme_cb.get() + "/preview.png") except: - theme_preview = Image.open("res/docs/no-preview.png") + theme_preview = Image.open(MAIN_DIRECTORY + "res/docs/no-preview.png") finally: if theme_preview.width > theme_preview.height: theme_preview = theme_preview.resize((300, 200), Image.Resampling.LANCZOS) @@ -290,7 +292,7 @@ def load_theme_preview(self): self.theme_author.place(x=10, y=self.theme_preview_img.height() + 15) def load_config_values(self): - with open("config.yaml", "rt", encoding='utf8') as stream: + with open(MAIN_DIRECTORY + "config.yaml", "rt", encoding='utf8') as stream: self.config, ind, bsi = ruamel.yaml.util.load_yaml_guess_indent(stream) # Check if theme is valid @@ -403,14 +405,14 @@ def on_theme_change(self, e=None): self.load_theme_preview() def on_theme_editor_click(self): - subprocess.Popen(os.path.join(os.getcwd(), "theme-editor.py") + " \"" + self.theme_cb.get() + "\"", shell=True) + subprocess.Popen(MAIN_DIRECTORY + "theme-editor.py" + " \"" + self.theme_cb.get() + "\"", shell=True) def on_save_click(self): self.save_config_values() def on_saverun_click(self): self.save_config_values() - subprocess.Popen(os.path.join(os.getcwd(), "main.py"), shell=True) + subprocess.Popen(MAIN_DIRECTORY + "main.py", shell=True) self.window.destroy() def on_brightness_change(self, e=None): diff --git a/library/config.py b/library/config.py index 00969ca0..32e47459 100644 --- a/library/config.py +++ b/library/config.py @@ -21,7 +21,7 @@ import os import queue import sys - +from pathlib import Path import yaml from library.log import logger @@ -34,8 +34,10 @@ def load_yaml(configfile): PATH = sys.path[0] -CONFIG_DATA = load_yaml("config.yaml") -THEME_DEFAULT = load_yaml("res/themes/default.yaml") +MAIN_DIRECTORY = Path(__file__).parent.parent.resolve() +FONTS_DIR = str(MAIN_DIRECTORY / "res" / "fonts") + "/" +CONFIG_DATA = load_yaml(MAIN_DIRECTORY / "config.yaml") +THEME_DEFAULT = load_yaml(MAIN_DIRECTORY / "res/themes/default.yaml") THEME_DATA = None @@ -51,10 +53,10 @@ def copy_default(default, theme): def load_theme(): global THEME_DATA try: - theme_path = "res/themes/" + CONFIG_DATA['config']['THEME'] + "/" - logger.info("Loading theme %s from %s" % (CONFIG_DATA['config']['THEME'], theme_path + "theme.yaml")) - THEME_DATA = load_yaml(theme_path + "theme.yaml") - THEME_DATA['PATH'] = theme_path + theme_path = Path("res/themes/" + CONFIG_DATA['config']['THEME']) + logger.info("Loading theme %s from %s" % (CONFIG_DATA['config']['THEME'], theme_path / "theme.yaml")) + THEME_DATA = load_yaml(MAIN_DIRECTORY / theme_path / "theme.yaml") + THEME_DATA['PATH'] = str(MAIN_DIRECTORY / theme_path) + "/" except: logger.error("Theme not found or contains errors!") try: diff --git a/library/display.py b/library/display.py index 4a5f8e7a..6aaacfff 100644 --- a/library/display.py +++ b/library/display.py @@ -128,7 +128,7 @@ def display_static_text(self): y=config.THEME_DATA['static_text'][text].get("Y", 0), width=config.THEME_DATA['static_text'][text].get("WIDTH", 0), height=config.THEME_DATA['static_text'][text].get("HEIGHT", 0), - font=config.THEME_DATA['static_text'][text].get("FONT", "roboto-mono/RobotoMono-Regular.ttf"), + font=config.FONTS_DIR + config.THEME_DATA['static_text'][text].get("FONT", "roboto-mono/RobotoMono-Regular.ttf"), font_size=config.THEME_DATA['static_text'][text].get("FONT_SIZE", 10), font_color=config.THEME_DATA['static_text'][text].get("FONT_COLOR", (0, 0, 0)), background_color=config.THEME_DATA['static_text'][text].get("BACKGROUND_COLOR", (255, 255, 255)), diff --git a/library/lcd/lcd_comm.py b/library/lcd/lcd_comm.py index 6f83a9a6..25cd4030 100644 --- a/library/lcd/lcd_comm.py +++ b/library/lcd/lcd_comm.py @@ -211,7 +211,7 @@ def DisplayText( y: int = 0, width: int = 0, height: int = 0, - font: str = "roboto-mono/RobotoMono-Regular.ttf", + font: str = "./res/fonts/roboto-mono/RobotoMono-Regular.ttf", font_size: int = 20, font_color: Tuple[int, int, int] = (0, 0, 0), background_color: Tuple[int, int, int] = (255, 255, 255), @@ -252,7 +252,7 @@ def DisplayText( # Get text bounding box if (font, font_size) not in self.font_cache: - self.font_cache[(font, font_size)] = ImageFont.truetype("./res/fonts/" + font, font_size) + self.font_cache[(font, font_size)] = ImageFont.truetype(font, font_size) font = self.font_cache[(font, font_size)] d = ImageDraw.Draw(text_image) @@ -354,6 +354,8 @@ def DisplayLineGraph(self, x: int, y: int, width: int, height: int, line_width: int = 2, graph_axis: bool = True, axis_color: Tuple[int, int, int] = (0, 0, 0), + font: str = "./res/fonts/roboto/Roboto-Black.ttf", + font_size: int = 10, background_color: Tuple[int, int, int] = (255, 255, 255), background_image: str = None): # Generate a plot graph and display it @@ -432,16 +434,16 @@ def DisplayLineGraph(self, x: int, y: int, width: int, height: int, # Draw Legend draw.line([0, 0, 1, 0], fill=axis_color) text = f"{int(max_value)}" - font = ImageFont.truetype("./res/fonts/" + "roboto/Roboto-Black.ttf", 10) - left, top, right, bottom = font.getbbox(text) + ttfont = ImageFont.truetype(font, font_size) + left, top, right, bottom = ttfont.getbbox(text) draw.text((2, 0 - top), text, - font=font, fill=axis_color) + font=ttfont, fill=axis_color) text = f"{int(min_value)}" - font = ImageFont.truetype("./res/fonts/" + "roboto/Roboto-Black.ttf", 10) - left, top, right, bottom = font.getbbox(text) + ttfont = ImageFont.truetype(font, font_size) + left, top, right, bottom = ttfont.getbbox(text) draw.text((width - 1 - right, height - 2 - bottom), text, - font=font, fill=axis_color) + font=ttfont, fill=axis_color) self.DisplayPILImage(graph_image, x, y) @@ -479,7 +481,7 @@ def DisplayRadialProgressBar(self, xc: int, yc: int, radius: int, bar_width: int value: int = 50, text: str = None, with_text: bool = True, - font: str = "roboto/Roboto-Black.ttf", + font: str = "./res/fonts/roboto/Roboto-Black.ttf", font_size: int = 20, font_color: Tuple[int, int, int] = (0, 0, 0), bar_color: Tuple[int, int, int] = (0, 0, 0), @@ -657,7 +659,7 @@ def DisplayRadialProgressBar(self, xc: int, yc: int, radius: int, bar_width: int if with_text: if text is None: text = f"{int(pct * 100 + .5)}%" - font = ImageFont.truetype("./res/fonts/" + font, font_size) + font = ImageFont.truetype(font, font_size) left, top, right, bottom = font.getbbox(text) w, h = right - left, bottom - top draw.text((radius - w / 2 + text_offset[0], radius - top - h / 2 + text_offset[1]), text, diff --git a/library/stats.py b/library/stats.py index 36188c30..63cbe394 100644 --- a/library/stats.py +++ b/library/stats.py @@ -108,7 +108,7 @@ def display_themed_value(theme_data, value, min_size=0, unit=''): y=theme_data.get("Y", 0), width=theme_data.get("WIDTH", 0), height=theme_data.get("HEIGHT", 0), - font=theme_data.get("FONT", "roboto-mono/RobotoMono-Regular.ttf"), + font=config.FONTS_DIR + theme_data.get("FONT", "roboto-mono/RobotoMono-Regular.ttf"), font_size=theme_data.get("FONT_SIZE", 10), font_color=theme_data.get("FONT_COLOR", (0, 0, 0)), background_color=theme_data.get("BACKGROUND_COLOR", (255, 255, 255)), @@ -184,7 +184,7 @@ def display_themed_radial_bar(theme_data, value, min_size=0, unit='', custom_tex value=value, bar_color=theme_data.get("BAR_COLOR", (0, 0, 0)), text=text, - font=theme_data.get("FONT", "roboto-mono/RobotoMono-Regular.ttf"), + font=config.FONTS_DIR + theme_data.get("FONT", "roboto-mono/RobotoMono-Regular.ttf"), font_size=theme_data.get("FONT_SIZE", 10), font_color=theme_data.get("FONT_COLOR", (0, 0, 0)), background_color=theme_data.get("BACKGROUND_COLOR", (0, 0, 0)), diff --git a/main.py b/main.py index fbe0cf0f..c27f1acd 100755 --- a/main.py +++ b/main.py @@ -41,6 +41,7 @@ import signal import subprocess import time + from pathlib import Path from PIL import Image if platform.system() == 'Windows': @@ -68,6 +69,8 @@ # If pystray cannot be loaded do not stop the program, just ignore it. The tray icon will not be displayed. pass +MAIN_DIRECTORY = str(Path(__file__).parent.resolve()) + "/" + if __name__ == "__main__": # Apply system locale to this program @@ -112,7 +115,7 @@ def on_signal_caught(signum, frame=None): def on_configure_tray(tray_icon, item): logger.info("Configure from tray icon") - subprocess.Popen(os.path.join(os.getcwd(), "configure.py"), shell=True) + subprocess.Popen(MAIN_DIRECTORY + "configure.py", shell=True) clean_stop(tray_icon) @@ -159,7 +162,7 @@ def on_win32_wm_event(hWnd, msg, wParam, lParam): tray_icon = pystray.Icon( name='Turing System Monitor', title='Turing System Monitor', - icon=Image.open("res/icons/monitor-icon-17865/64.png"), + icon=Image.open(MAIN_DIRECTORY + "res/icons/monitor-icon-17865/64.png"), menu=pystray.Menu( pystray.MenuItem( text='Configure', diff --git a/res/themes/3.5inchTheme2/preview.png b/res/themes/3.5inchTheme2/preview.png index 24418cc8..31cb7127 100644 Binary files a/res/themes/3.5inchTheme2/preview.png and b/res/themes/3.5inchTheme2/preview.png differ diff --git a/simple-program.py b/simple-program.py index ce5d0618..e1708fcd 100755 --- a/simple-program.py +++ b/simple-program.py @@ -122,7 +122,7 @@ def sighandler(signum, frame): # Display custom text with solid background lcd_comm.DisplayText("Custom italic multiline text\nright-aligned", 5, 120, - font="roboto/Roboto-Italic.ttf", + font="res/fonts/roboto/Roboto-Italic.ttf", font_size=20, font_color=(0, 0, 255), background_color=(255, 255, 0), @@ -130,7 +130,7 @@ def sighandler(signum, frame): # Display custom text with transparent background lcd_comm.DisplayText("Transparent bold text", 5, 180, - font="geforce/GeForce-Bold.ttf", + font="res/fonts/geforce/GeForce-Bold.ttf", font_size=30, font_color=(255, 255, 255), background_image=background) @@ -140,7 +140,7 @@ def sighandler(signum, frame): while not stop: start = time.perf_counter() lcd_comm.DisplayText(str(datetime.now().time()), 160, 2, - font="roboto/Roboto-Bold.ttf", + font="res/fonts/roboto/Roboto-Bold.ttf", font_size=20, font_color=(255, 0, 0), background_image=background) @@ -177,7 +177,7 @@ def sighandler(signum, frame): value=bar_value, bar_color=(255, 255, 0), text=f"{10 * int(bar_value / 10)}°C", - font="geforce/GeForce-Bold.ttf", + font="res/fonts/geforce/GeForce-Bold.ttf", font_size=20, font_color=(255, 255, 0), background_image=background) diff --git a/theme-editor.py b/theme-editor.py index 5ca59443..ba4548a0 100755 --- a/theme-editor.py +++ b/theme-editor.py @@ -225,11 +225,11 @@ def on_zone_click(event): logger.debug("Opening theme file in your default editor. If it does not work, open it manually in the " "editor of your choice") if platform.system() == 'Darwin': # macOS - subprocess.call(('open', "./" + theme_file)) + subprocess.call(('open', config.MAIN_DIRECTORY / theme_file)) elif platform.system() == 'Windows': # Windows - os.startfile(".\\" + theme_file) + os.startfile( config.MAIN_DIRECTORY / theme_file) else: # linux variants - subprocess.call(('xdg-open', "./" + theme_file)) + subprocess.call(('xdg-open', config.MAIN_DIRECTORY / theme_file)) # Load theme file and generate first preview refresh_theme() @@ -238,7 +238,7 @@ def on_zone_click(event): logger.debug("Opening theme preview window with static data") viewer = tkinter.Tk() viewer.title("Turing SysMon Theme Editor") - viewer.iconphoto(True, tkinter.PhotoImage(file="res/icons/monitor-icon-17865/64.png")) + viewer.iconphoto(True, tkinter.PhotoImage(file=config.MAIN_DIRECTORY / "res/icons/monitor-icon-17865/64.png")) viewer.geometry(str(display.lcd.get_width() + 2 * RGB_LED_MARGIN) + "x" + str( display.lcd.get_height() + 2 * RGB_LED_MARGIN + 40)) viewer.protocol("WM_DELETE_WINDOW", on_closing)