diff --git a/README.md b/README.md index 2f518a2..8f5ead1 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ - [Introduction](#introduction) - [Requirements](#requirements) - [:computer: System](#computer-system) + - [Linux](#linux) + - [Windows](#windows) + - [MacOs](#macos) - [:snake: Python](#snake-python) - [:floppy\_disk: Bootloader \& Firmware](#floppy_disk-bootloader--firmware) - [Usage](#usage) @@ -34,26 +37,26 @@ With OpenOCD, the program steps are : ## Requirements ### :computer: System +#### Linux + - [OpenOCD](https://openocd.org/): `sudo apt install openocd` + - Python 3.x: `sudo apt install python3` + - Python3 pip: `sudo apt install python3-pip` + +:bulb: All in one: `sudo apt install openocd python3 python3-pip` + +#### Windows - [OpenOCD](https://openocd.org/): - - Linux: `sudo apt install openocd` - - Windows: - - [https://github.com/openocd-org/openocd/releases/latest](https://github.com/openocd-org/openocd/releases/latest) + - Download lastest release form [https://github.com/openocd-org/openocd/releases/latest](https://github.com/openocd-org/openocd/releases/latest) - add the `bin` folder to your [path](https://www.architectryan.com/2018/03/17/add-to-the-path-on-windows-10/) (e.g `C:/openOCD/bin`). - - Python 3.x: - - Linux: `sudo apt install python3` - - Windows: [https://www.python.org/downloads/windows/](https://www.python.org/downloads/windows/) - - Python3 pip: - - Linux: `sudo apt install python3-pip` - - Windows (If not installed with Python): [https://packaging.python.org/en/latest/tutorials/installing-packages/#requirements-for-installing-packages](https://packaging.python.org/en/latest/tutorials/installing-packages/#requirements-for-installing-packages) - - python3 tk: - - Linux: `sudo apt install python3-tk` - - Windows: [https://www.geeksforgeeks.org/how-to-install-tkinter-in-windows/](https://www.geeksforgeeks.org/how-to-install-tkinter-in-windows/) - -:bulb: All in one (Linux only): `sudo apt install openocd python3 python3-pip python3-tk` + - Python 3.x: Download it from [https://www.python.org/downloads/windows/](https://www.python.org/downloads/windows/) + - Python3 pip: If not installed with Python, here are the instructions: [https://packaging.python.org/en/latest/tutorials/installing-packages/#requirements-for-installing-packages](https://packaging.python.org/en/latest/tutorials/installing-packages/#requirements-for-installing-packages) +#### MacOs + Untested, but certainly identical to Linux. + ### :snake: Python - [virtual-env](https://docs.python-guide.org/dev/virtualenvs/#lower-level-virtualenv): `pip install virtualenv` _(optionnal)_ - - [PySimpleGUI](https://pysimplegui.readthedocs.io/en/latest/): `pip install pysimplegui` + - [Tkinter](https://docs.python.org/fr/3/library/tkinter.html): `pip install tkinter` - [psutil](https://psutil.readthedocs.io/en/latest/): `pip install psutil` :bulb: You can install everything (virtual env include), with the `install.sh` script (Linux only). diff --git a/azure.tcl b/azure.tcl new file mode 100644 index 0000000..3e75502 --- /dev/null +++ b/azure.tcl @@ -0,0 +1,87 @@ +# Copyright © 2021 rdbende + +source [file join [file dirname [info script]] theme light.tcl] +source [file join [file dirname [info script]] theme dark.tcl] + +option add *tearOff 0 + +proc set_theme {mode} { + if {$mode == "dark"} { + ttk::style theme use "azure-dark" + + array set colors { + -fg "#ffffff" + -bg "#333333" + -disabledfg "#ffffff" + -disabledbg "#737373" + -selectfg "#ffffff" + -selectbg "#007fff" + } + + ttk::style configure . \ + -background $colors(-bg) \ + -foreground $colors(-fg) \ + -troughcolor $colors(-bg) \ + -focuscolor $colors(-selectbg) \ + -selectbackground $colors(-selectbg) \ + -selectforeground $colors(-selectfg) \ + -insertcolor $colors(-fg) \ + -insertwidth 1 \ + -fieldbackground $colors(-selectbg) \ + -font {"Segoe Ui" 10} \ + -borderwidth 1 \ + -relief flat + + tk_setPalette background [ttk::style lookup . -background] \ + foreground [ttk::style lookup . -foreground] \ + highlightColor [ttk::style lookup . -focuscolor] \ + selectBackground [ttk::style lookup . -selectbackground] \ + selectForeground [ttk::style lookup . -selectforeground] \ + activeBackground [ttk::style lookup . -selectbackground] \ + activeForeground [ttk::style lookup . -selectforeground] + + ttk::style map . -foreground [list disabled $colors(-disabledfg)] + + option add *font [ttk::style lookup . -font] + option add *Menu.selectcolor $colors(-fg) + + } elseif {$mode == "light"} { + ttk::style theme use "azure-light" + + array set colors { + -fg "#000000" + -bg "#ffffff" + -disabledfg "#737373" + -disabledbg "#ffffff" + -selectfg "#ffffff" + -selectbg "#007fff" + } + + ttk::style configure . \ + -background $colors(-bg) \ + -foreground $colors(-fg) \ + -troughcolor $colors(-bg) \ + -focuscolor $colors(-selectbg) \ + -selectbackground $colors(-selectbg) \ + -selectforeground $colors(-selectfg) \ + -insertcolor $colors(-fg) \ + -insertwidth 1 \ + -fieldbackground $colors(-selectbg) \ + -font {"Segoe Ui" 10} \ + -borderwidth 1 \ + -relief flat + + tk_setPalette background [ttk::style lookup . -background] \ + foreground [ttk::style lookup . -foreground] \ + highlightColor [ttk::style lookup . -focuscolor] \ + selectBackground [ttk::style lookup . -selectbackground] \ + selectForeground [ttk::style lookup . -selectforeground] \ + activeBackground [ttk::style lookup . -selectbackground] \ + activeForeground [ttk::style lookup . -selectforeground] + + ttk::style map . -foreground [list disabled $colors(-disabledfg)] + + option add *font [ttk::style lookup . -font] + option add *Menu.selectcolor $colors(-fg) + } +} diff --git a/doc/screenshot.png b/doc/screenshot.png index 59d8ac5..b0edb78 100644 Binary files a/doc/screenshot.png and b/doc/screenshot.png differ diff --git a/easy_daplink.py b/easy_daplink.py index 2b5db74..5a1b183 100644 --- a/easy_daplink.py +++ b/easy_daplink.py @@ -1,181 +1,178 @@ -from datetime import datetime -from sys import stderr import time import os +import sys import threading import subprocess import shutil import psutil import re -import PySimpleGUI as sg +import tkinter as tk +import tkinter.filedialog as tkFileDialog +import tkinter.messagebox as tkMessageBox +from tkinter import ttk from settings import Settings +from logtext import LogText SCRIPT_FOLDER = "-SCRIPT_FOLDER-" BOOTLOADER = "-BOOTLOADER-" FIRMWARE = "-FIRMWARE-" PROGRAM = "-TEST_PROGRAM-" -START_BUTTON = "-START-" TIMEOUT_MOUNT = "-TIMEOUT_MOUNT_POINT-" MAINTENACE_MOUNT_NAME = "-MAINTENANCE_MOUNT_POINT-" -PROGRAM_MOUNT_NAME = "-PROGRAMMING_MOUNT_POINT-" +TARGET_MOUNT_NAME = "-PROGRAMMING_MOUNT_POINT-" + + +def ask_open_file(title_dialog, stringvar: tk.StringVar, setting_key: str | None): + file_path = tkFileDialog.askopenfilename(filetypes=[("BIN files", "*.bin"), ("HEX files", "*.hex"), ("All Files", "*.* *")], title=title_dialog, initialdir=os.path.dirname(stringvar.get())) + + if file_path != () and file_path != "": + stringvar.set(file_path) + + if setting_key != None: + settings.set_value(setting_key, file_path) + +def ask_open_folder(title_dialog, stringvar: tk.StringVar, setting_key: str | None): + directory_path = tkFileDialog.askdirectory(mustexist=True, title=title_dialog, initialdir=stringvar.get()) + + if directory_path != () and directory_path != "": + stringvar.set(directory_path) + + if setting_key != None: + settings.set_value(setting_key, directory_path) + +GRID_PADS = {'padx': '4px', 'pady': '2px'} +MAIN_PADS = {'padx': '4px', 'pady': '2px'} settings = Settings("settings.dat") -sg.theme("BlueMono") - -layout = [ - [ - sg.Text("OpenOCD 'scripts' folder:"), - sg.Input(enable_events=True, key=SCRIPT_FOLDER, default_text=settings.get_value_or_default(SCRIPT_FOLDER, "/usr/share/openocd/scripts/") ), - sg.FolderBrowse(initial_folder=settings.get_value(SCRIPT_FOLDER)) - ], - [ - sg.Text("Select the BOOTLOADER file:"), - sg.Input(enable_events=True, key=BOOTLOADER, default_text=settings.get_value(BOOTLOADER)), - sg.FileBrowse(file_types=(("Compatible files", "*.bin *.hex"), ("BIN files", "*.bin"), ("HEX files", "*.hex"), ("All Files", "*.* *"),), initial_folder=os.path.dirname(settings.get_value_or_default(BOOTLOADER, ""))) - ], - [ - sg.Text("Select the FIRMWARE file:"), - sg.Input(enable_events=True, key=FIRMWARE, default_text=settings.get_value(FIRMWARE)), - sg.FileBrowse(file_types=(("Compatible files", "*.bin *.hex"), ("BIN files", "*.bin"), ("HEX files", "*.hex"), ("All Files", "*.* *"),), initial_folder=os.path.dirname(settings.get_value_or_default(FIRMWARE, ""))) - ], - [ - sg.Text("Select the TEST PROGRAM file (skip if empty):"), - sg.Input(enable_events=True, key=PROGRAM, default_text=settings.get_value(PROGRAM)), - sg.FileBrowse(file_types=(("Compatible files", "*.bin *.hex"), ("BIN files", "*.bin"), ("HEX files", "*.hex"), ("All Files", "*.* *"),), initial_folder=os.path.dirname(settings.get_value_or_default(PROGRAM, ""))) - ], - [ - sg.Text("\"MAINTENANCE\" mount point name: "), - sg.Input(enable_events=True, key=MAINTENACE_MOUNT_NAME, default_text=settings.get_value_or_default(MAINTENACE_MOUNT_NAME, "MAINTENANCE") ) - ], - [ - sg.Text("\"DAPLINK\" programming mount point name: "), - sg.Input(enable_events=True, key=PROGRAM_MOUNT_NAME, default_text=settings.get_value_or_default(PROGRAM_MOUNT_NAME, "DIS_L4IOT" ) ) - ], - [ - sg.Text("Timeout (in milliseconds) for mount points: "), - sg.Input(enable_events=True, key=TIMEOUT_MOUNT, default_text=settings.get_value_or_default(TIMEOUT_MOUNT, "10000" ) ) - ], - [ - sg.Button(button_text="Start !", enable_events=True, key=START_BUTTON, expand_x=True, disabled=True) - ], - [ - sg.Multiline(disabled=True, expand_x=True, autoscroll=True, size=(None, 30), key="-LOG-", font="monospace 8") - ] -] - -window = sg.Window(title="Simple DapLink board", layout=layout, margins=(32, 32)) +window = tk.Tk() +window.title("Easy Flash DapLink") -def main(): - default_bg_input = sg.theme_input_background_color() - running_thread = None - while True: - event, values = window.read(100) +window.tk.call("source", "azure.tcl") +# window.tk.call("set_theme", "dark") +# ttk.Style().theme_use('azure-dark') +window.tk.call("set_theme", "light") +ttk.Style().theme_use('azure-light') - if event == sg.WIN_CLOSED or event == "Quit": - break +string_script_folder = tk.StringVar(value=settings.get_value_or_default(SCRIPT_FOLDER, "/usr/share/openocd/scripts/")) +string_file_bootloader = tk.StringVar(value=settings.get_value_or_default(BOOTLOADER, "")) +string_file_firmware = tk.StringVar(value=settings.get_value_or_default(FIRMWARE, "")) +string_file_test = tk.StringVar(value=settings.get_value_or_default(PROGRAM, "")) - elif event == SCRIPT_FOLDER : - if is_valid_dir(values[SCRIPT_FOLDER]): - window[SCRIPT_FOLDER].update(background_color=default_bg_input) - settings.set_value(SCRIPT_FOLDER, values[SCRIPT_FOLDER]) - else: - window[SCRIPT_FOLDER].update(background_color="#DD5555") - - elif event == BOOTLOADER : - if is_valid_file(values[BOOTLOADER]): - window[BOOTLOADER].update(background_color=default_bg_input) - settings.set_value(BOOTLOADER, values[BOOTLOADER]) - else: - window[BOOTLOADER].update(background_color="#DD5555") - - elif event == FIRMWARE : - if is_valid_file(values[FIRMWARE]): - window[FIRMWARE].update(background_color=default_bg_input) - settings.set_value(FIRMWARE, values[FIRMWARE]) - else: - window[FIRMWARE].update(background_color="#DD5555") - - elif event == PROGRAM : - if is_valid_file(values[PROGRAM]) or len(values[PROGRAM]) == 0: - window[PROGRAM].update(background_color=default_bg_input) - settings.set_value(PROGRAM, values[PROGRAM]) - else: - window[PROGRAM].update(background_color="#DD5555") - - elif event == TIMEOUT_MOUNT : - if is_valid_number(values[TIMEOUT_MOUNT]): - window[TIMEOUT_MOUNT].update(background_color=default_bg_input) - settings.set_value(TIMEOUT_MOUNT, values[TIMEOUT_MOUNT]) - else: - window[TIMEOUT_MOUNT].update(background_color="#DD5555") - - elif event == MAINTENACE_MOUNT_NAME : - if len(values[MAINTENACE_MOUNT_NAME]) > 0: - window[MAINTENACE_MOUNT_NAME].update(background_color=default_bg_input) - settings.set_value(MAINTENACE_MOUNT_NAME, values[MAINTENACE_MOUNT_NAME]) - else: - window[MAINTENACE_MOUNT_NAME].update(background_color="#DD5555") - - elif event == PROGRAM_MOUNT_NAME : - settings.set_value(PROGRAM_MOUNT_NAME, values[PROGRAM_MOUNT_NAME]) - - elif event == START_BUTTON: - running_thread = threading.Thread(target=openocd_procedure, args=(values,)) - running_thread.start() - - # elif event != None : - # print(event) - - update_start_button_state(values, running_thread != None) +string_maintenant_mount = tk.StringVar(value=settings.get_value_or_default(MAINTENACE_MOUNT_NAME, "MAINTENANCE")) +string_target_mount = tk.StringVar(value=settings.get_value_or_default(TARGET_MOUNT_NAME, "DIS_L4IOT" )) +string_timeout = tk.StringVar(value=settings.get_value_or_default(TIMEOUT_MOUNT, "10000" )) - if running_thread != None and not running_thread.is_alive(): - running_thread = None +log_text: LogText +running_thread: threading.Thread = None - window.close() +def validate_number(num): + return num.isdigit() +def main(): + global running_thread + global log_text + str_validate_number = (window.register(validate_number), '%P') -################################################################### -#### LOG FUNCTIONS ############################################# -############################################################# + ### + # Panel files & folder + ### + layout_files = ttk.Frame(master=window) + layout_files.grid_columnconfigure(1, weight=1) + + ttk.Label(master=layout_files, text="OpenOCD 'scripts' folder").grid(column=0, row=0, sticky='NE', **GRID_PADS) + ttk.Entry(master=layout_files, textvariable=string_script_folder, state=tk.NORMAL).grid(column=1, row=0, sticky='EW', **GRID_PADS) + ttk.Button(master=layout_files, text="Browse...", command=lambda: ask_open_folder("Select the script directory", string_script_folder, SCRIPT_FOLDER)).grid(column=2, row=0, sticky='E', **GRID_PADS) + + ttk.Label(master=layout_files, text="Bootloader file").grid(column=0, row=1, sticky='E', **GRID_PADS) + ttk.Entry(master=layout_files, textvariable=string_file_bootloader, state=tk.NORMAL).grid(column=1, row=1, sticky='EW', **GRID_PADS) + ttk.Button(master=layout_files, text="Browse...", command=lambda: ask_open_file("Select the Bootloader file", string_file_bootloader, BOOTLOADER)).grid(column=2, row=1, sticky='E', **GRID_PADS) + + ttk.Label(master=layout_files, text="Firmware file").grid(column=0, row=2, sticky='E', **GRID_PADS) + ttk.Entry(master=layout_files, textvariable=string_file_firmware, state=tk.NORMAL).grid(column=1, row=2, sticky='EW', **GRID_PADS) + ttk.Button(master=layout_files, text="Browse...", command=lambda: ask_open_file("Select the firmware file", string_file_firmware, FIRMWARE)).grid(column=2, row=2, sticky='E', **GRID_PADS) + + ttk.Label(master=layout_files, text="Test file (skip if empty)").grid(column=0, row=3, sticky='E', **GRID_PADS) + ttk.Entry(master=layout_files, textvariable=string_file_test, state=tk.NORMAL).grid(column=1, row=3, sticky='EW', **GRID_PADS) + ttk.Button(master=layout_files, text="Browse...", command=lambda: ask_open_file("Select the test file", string_file_test, PROGRAM)).grid(column=2, row=3, sticky='E', **GRID_PADS) + + ### + # Panel Mount points & timeout + ### + layout_params = ttk.Frame(master=window) + layout_params.grid_columnconfigure(1, weight=1) + + ttk.Label(master=layout_params, text="'MAINTENANCE' mount point name").grid(column=0, row=0, sticky='E', **GRID_PADS) + ttk.Entry(master=layout_params, textvariable=string_maintenant_mount).grid(column=1, row=0, sticky='EW', **GRID_PADS) -def log(msg, level, no_time=False): - log = window["-LOG-"] + ttk.Label(master=layout_params, text="Target mount point name").grid(column=0, row=1, sticky='E', **GRID_PADS) + ttk.Entry(master=layout_params, textvariable=string_target_mount).grid(column=1, row=1, sticky='EW', **GRID_PADS) - if no_time: - final_msg = msg - else: - final_msg = "[{}] {}".format(datetime.now().strftime("%H:%M:%S.%f"), msg) + ttk.Label(master=layout_params, text="Timeout (in ms) for mount points").grid(column=0, row=2, sticky='E', **GRID_PADS) + ttk.Entry(master=layout_params, textvariable=string_timeout, validate='all', validatecommand=str_validate_number).grid(column=1, row=2, sticky='EW', **GRID_PADS) + + ### + # Panel Log + ### + layout_log = ttk.Frame(master=window) - if level == "error": - log.print(final_msg, text_color="red") - elif level == "warning": - log.print(final_msg, text_color="orange") - elif level == "info": - log.print(final_msg) + text_scroll_v = ttk.Scrollbar(master=layout_log, orient='vertical') + text_scroll_v.pack(side=tk.RIGHT, fill=tk.Y) + log_text = LogText(master=layout_log, yscrollcommand=text_scroll_v.set) -def log_error(msg, no_time=False): - log(msg, "error", no_time) + text_scroll_v.config(command=log_text.yview) + log_text.pack(fill=tk.BOTH) + ### + # Pack the layout + ### + layout_files.pack(fill=tk.X, **MAIN_PADS) + layout_params.pack(fill=tk.X, **MAIN_PADS) + ttk.Button(master=window, style='Accent.TButton', text="Flash DAPLink", command=run_flash).pack(fill=tk.X, **MAIN_PADS) + layout_log.pack(fill=tk.BOTH, **MAIN_PADS) -def log_warning(msg, no_time=False): - log(msg, "warning", no_time) + sys.stdout.write = redirector_stdout + sys.stderr.write = redirector_stderr + window.mainloop() + + settings.set_value(MAINTENACE_MOUNT_NAME, string_maintenant_mount.get()) + settings.set_value(TARGET_MOUNT_NAME, string_target_mount.get()) + settings.set_value(TIMEOUT_MOUNT, string_timeout.get()) -def log_info(msg, no_time=False): - log(msg, "info", no_time) +def run_flash(): + global running_thread + (check_ok, msg) = check_entries() + if running_thread != None and running_thread.is_alive() == False: + running_thread = None + + if running_thread != None: + tkMessageBox.showwarning(title="Already running", message="Flash process is already running...", icon=tkMessageBox.WARNING) + return + elif not check_ok: + tkMessageBox.showerror(title="Invalid entry", message=msg, icon=tkMessageBox.ERROR ) + return + else: + running_thread = threading.Thread(target=openocd_procedure, args=(string_script_folder.get(), string_file_bootloader.get(), string_file_firmware.get(), string_file_test.get(), string_maintenant_mount.get(), string_target_mount.get(), string_timeout.get())) + running_thread.start() ################################################################### #### UTILS FUNCTIONS ########################################### ############################################################# +def redirector_stdout(input_str): + log_text.log_info(input_str, False, False) + +def redirector_stderr(input_str): + log_text.log_error(input_str, False, False) + def is_valid_file(filepath): if len(filepath) == 0: return False @@ -188,87 +185,91 @@ def is_valid_dir(dirpath): return os.path.isdir(dirpath) +def check_entries() -> tuple[bool, str]: + if not is_valid_dir(string_script_folder.get()): + return (False, "Invalid path to OpenOCD script folder") + + if not is_valid_file(string_file_bootloader.get()): + return (False, "Invalid path to bootloader file") + + if not is_valid_file(string_file_firmware.get()): + return (False, "Invalid path to firmware file") + + if len( string_file_test.get() ) > 0 and len( string_target_mount.get() ) > 0 and not is_valid_file(string_file_test.get()): + return (False, "Invalid path to test file") + + if len( string_maintenant_mount.get() ) == 0: + return (False, "Maintenace mount name can't be empty") + + if len( string_target_mount.get() ) == 0: + return (False, "Target mount name can't be empty") -def is_valid_number(num): - return num.isdigit() - - -def update_start_button_state(values, is_thread_running): - if is_valid_dir(values[SCRIPT_FOLDER]) and \ - is_valid_file(values[BOOTLOADER]) and \ - is_valid_file(values[FIRMWARE]) and \ - is_valid_number(values[TIMEOUT_MOUNT]) and \ - len(values[MAINTENACE_MOUNT_NAME]) > 0 and \ - len(values[PROGRAM_MOUNT_NAME]) > 0 and \ - not is_thread_running: - window[START_BUTTON].update(disabled=False) - else: - window[START_BUTTON].update(disabled=True) - - + return (True, "") ################################################################### #### OPENOCD FUNCTIONS ######################################### ############################################################# -def openocd_procedure(values): - log_info("------------------ START ------------------", True) +def openocd_procedure(path_script: str, path_bootloader: str, path_firmware: str, path_program: str, mount_maintenance: str, mount_program: str, timeout: str): + global running_thread + + log_text.log_info("------------------ START ------------------", True) start = time.time() is_ok = True - steps(values) + steps(path_script, path_bootloader, path_firmware, path_program, mount_maintenance, mount_program, timeout) duration = int((time.time() - start) * 1000) - log_info("------------------ FINISH ------------------", True) - log_info("Duration: {} s".format(duration / 1000.0), True) - log_info("--------------------------------------------\n\n", True) - + log_text.log_info("------------------ FINISH ------------------", True) + log_text.log_info("Duration: {} s".format(duration / 1000.0), True) + log_text.log_info("--------------------------------------------\n\n", True) + running_thread = None -def steps(values): +def steps(path_script: str, path_bootloader: str, path_firmware: str, path_program: str, mount_maintenance: str, mount_program: str, timeout: str): - log_info("Unlocking the target (RDP)") - if not openocd_unlock(values[SCRIPT_FOLDER]) : - log_error("Failed to unlock the target... Abort") + log_text.log_info("Unlocking the target (RDP)") + if not openocd_unlock(path_script) : + log_text.log_error("Failed to unlock the target... Abort") return - log_info("Mass erase the target") - if not openocd_mass_erase(values[SCRIPT_FOLDER]) : - log_error("Failed to erase the target... Abort") + log_text.log_info("Mass erase the target") + if not openocd_mass_erase(path_script) : + log_text.log_error("Failed to erase the target... Abort") return - log_info("Flash the target") - if not openocd_flash(values[BOOTLOADER], values[SCRIPT_FOLDER]) : - log_error("Failed to flash the target... Abort") + log_text.log_info("Flash the target") + if not openocd_flash(path_bootloader, path_script) : + log_text.log_error("Failed to flash the target... Abort") return - log_info("Wait for device '{}' mount point".format(values[MAINTENACE_MOUNT_NAME])) - if not openocd_wait_mountpoint(int(values[TIMEOUT_MOUNT]), values[MAINTENACE_MOUNT_NAME]) : - log_error("Failed to open the target... Abort") + log_text.log_info("Wait for device '{}' mount point".format(mount_maintenance)) + if not openocd_wait_mountpoint(int(timeout), mount_maintenance) : + log_text.log_error("Failed to open the target... Abort") return - log_info("Search for 'Git SHA' from DETAILS.TXT in '{}' mount point: ".format(values[MAINTENACE_MOUNT_NAME])) - openocd_read_SHA(values[MAINTENACE_MOUNT_NAME]) + log_text.log_info("Search for 'Git SHA' from DETAILS.TXT in '{}' mount point: ".format(mount_maintenance)) + openocd_read_SHA(mount_maintenance) - log_info("Send firmware to device") - if not openocd_copy_firmware(values[FIRMWARE], values[MAINTENACE_MOUNT_NAME]) : - log_error("Failed to copy the firmware to the target... Abort") + log_text.log_info("Send firmware to device") + if not openocd_copy_firmware(path_firmware, mount_maintenance) : + log_text.log_error("Failed to copy the firmware to the target... Abort") return - log_info("Wait for device {} mount point".format(values[PROGRAM_MOUNT_NAME])) - if not openocd_wait_mountpoint(int(values[TIMEOUT_MOUNT]), values[PROGRAM_MOUNT_NAME]) : - log_error("Failed to open the target... Abort") + log_text.log_info("Wait for device {} mount point".format(mount_program)) + if not openocd_wait_mountpoint(int(timeout), mount_program) : + log_text.log_error("Failed to open the target... Abort") return else: - log_info("Search for 'Git SHA' from DETAILS.TXT of '{}' mount point: ".format(values[PROGRAM_MOUNT_NAME])) - openocd_read_SHA(values[PROGRAM_MOUNT_NAME]) + log_text.log_info("Search for 'Git SHA' from DETAILS.TXT of '{}' mount point: ".format(mount_program)) + openocd_read_SHA(mount_program) - if len(values[PROGRAM]) == 0: - log_warning("Skipping programming steps") + if len(path_program) == 0: + log_text.log_warning("Skipping programming steps") return else: - log_info("Send program to device") - if not openocd_copy_firmware(values[PROGRAM], values[PROGRAM_MOUNT_NAME]) : - log_error("Failed to copy the program to the target... Abort") + log_text.log_info("Send program to device") + if not openocd_copy_firmware(path_program, mount_program) : + log_text.log_error("Failed to copy the program to the target... Abort") return @@ -278,8 +279,8 @@ def openocd_unlock(script_folder): if proc.returncode == 0: return True - log_info(proc.stdout, True) - log_error(proc.stderr, True) + log_text.log_info(proc.stdout, False) + log_text.log_error(proc.stderr, False) return False @@ -289,8 +290,8 @@ def openocd_mass_erase(script_folder): if proc.returncode == 0: return True - log_info(proc.stdout, True) - log_error(proc.stderr, True) + log_text.log_info(proc.stdout, False) + log_text.log_error(proc.stderr, False) return False @@ -301,8 +302,8 @@ def openocd_flash(bootloader, script_folder): if proc.returncode == 0: return True - log_info(proc.stdout, True) - log_error(proc.stderr, True) + log_text.log_info(proc.stdout, False) + log_text.log_error(proc.stderr, False) return False @@ -319,7 +320,7 @@ def openocd_wait_mountpoint(timeout, mount_point): return True if (time.time() - tmp) * 1000 > 1000: - log_info("Waiting...") + log_text.log_info("Waiting...") tmp = time.time() if (time.time() - start) * 1000 >= timeout: @@ -339,7 +340,11 @@ def openocd_copy_firmware(file, mount_point): if target == None: return False - shutil.copy(file, target, follow_symlinks=True) + try: + shutil.copy(file, target, follow_symlinks=True) + except Exception as e: + log_text.log_error("Failed to copy firmware file.\nError: {}".format(e)) + return False return True @@ -354,20 +359,21 @@ def openocd_read_SHA(mount_point): break if path == None : - log_error("Failed to find the '{}' mountpoint".format(path)) + log_text.log_error("Failed to find the '{}' mountpoint".format(path)) + return + + try: + with open("{}/DETAILS.TXT".format(path), "r") as f: + content = f.read() + except Exception as e: + log_text.log_error("Unable to open read the Git SHA.\nError: {}".format(e)) return - with open("{}/DETAILS.TXT".format(path), "r") as f: - content = f.read() - res = re.search(r'Git SHA: ([a-zA-Z0-9]*)$', content, re.MULTILINE) if res != None: - log_info(res.group(0)) + log_text.log_info(res.group(0)) else: - log_warning("No SHA found in file...") + log_text.log_warning("No SHA found in file...") - -window["-LOG-"].reroute_stdout_to_here() -window["-LOG-"].reroute_stderr_to_here() main() diff --git a/install.sh b/install.sh index 101a042..9a0d752 100755 --- a/install.sh +++ b/install.sh @@ -5,27 +5,25 @@ NC='\033[0m' # No Color echo -e "${GREEN}=> Installing system dependency${NC}" -sudo apt install openocd python3 python3-pip python3-tk +sudo apt install openocd python3 python3-pip python3-venv -echo -e "\n\n\n${GREEN}=> Virtual env.${NC}" -echo -e "\n\n ${ORANGE}Installing virtualenv (pip)${NC}" -pip install virtualenv | sed 's/^/ /' +echo -e "\n${GREEN}=> Virtual env.${NC}" -echo -e "\n\n ${ORANGE}Create virtual env${NC}" -virtualenv venv | sed 's/^/ /' +echo -e "\n ${ORANGE}Create virtual env${NC}" +python3 -m venv venv | sed 's/^/ /' -echo -e "\n\n\n${GREEN}=> Enter in venv${NC}" +echo -e "\n${GREEN}=> Enter in venv${NC}" source ./venv/bin/activate -echo -e "\n\n\n${GREEN}=> Python depencies${NC}" -pip install pysimplegui psutil +echo -e "\n${GREEN}=> Python depencies${NC}" +pip install tk psutil -echo -e "\n\n ${ORANGE}pip freeze${NC}" +echo -e "\n ${ORANGE}pip freeze${NC}" pip freeze | sed 's/^/ /' -echo -e "\n\n\n${GREEN}=> Exit venv${NC}" +echo -e "\n${GREEN}=> Exit venv${NC}" deactivate -echo -e "\n\n\n${GREEN}========= Done ! =========${NC}" +echo -e "\n${GREEN}========= Done ! =========${NC}" read -s -p "Press any key to close ..." echo -e "\n\n" \ No newline at end of file diff --git a/logtext.py b/logtext.py new file mode 100644 index 0000000..bd10fbd --- /dev/null +++ b/logtext.py @@ -0,0 +1,50 @@ +from enum import Enum +from datetime import datetime + +import tkinter as tk +from tkinter import ttk + +class LogType(Enum): + INFO = "INFO", + WARNING = "WARNING", + ERROR = "ERROR" + + +class LogText(tk.Text): + def __init__(self, **kw): + super().__init__(**kw) + self.tag_configure(LogType.INFO, foreground="#000000") + self.tag_configure(LogType.WARNING, foreground="#FFB54C") + self.tag_configure(LogType.ERROR, foreground="#FF6961") + + def log(self, type: LogType, text: str, print_time: bool = True): + final_msg = "" + + self.configure(state=tk.NORMAL) + + if print_time: + final_msg = "[{}] {}".format(datetime.now().strftime("%H:%M:%S.%f"), text) + else: + final_msg = text + + super().insert(tk.END, final_msg, type) + super().see(tk.END) + self.configure(state=tk.DISABLED) + + def log_error(self, text: str, print_time: bool = True, add_newline: bool = True): + if add_newline : + text += "\n" + + self.log(LogType.ERROR, text, print_time) + + def log_warning(self, text: str, print_time: bool = True, add_newline: bool = True): + if add_newline : + text += "\n" + + self.log(LogType.WARNING, text, print_time) + + def log_info(self, text: str, print_time: bool = True, add_newline: bool = True): + if add_newline : + text += "\n" + + self.log(LogType.INFO, text, print_time) \ No newline at end of file diff --git a/theme/dark.tcl b/theme/dark.tcl new file mode 100644 index 0000000..333e53d --- /dev/null +++ b/theme/dark.tcl @@ -0,0 +1,539 @@ +# Copyright (c) 2021 rdbende + +# The Azure theme is a beautiful modern ttk theme inspired by Microsoft's fluent design. + +package require Tk 8.6 + +namespace eval ttk::theme::azure-dark { + variable version 2.0 + package provide ttk::theme::azure-dark $version + + ttk::style theme create azure-dark -parent clam -settings { + proc load_images {imgdir} { + variable I + foreach file [glob -directory $imgdir *.png] { + set img [file tail [file rootname $file]] + set I($img) [image create photo -file $file -format png] + } + } + + load_images [file join [file dirname [info script]] dark] + + array set colors { + -fg "#ffffff" + -bg "#333333" + -disabledfg "#aaaaaa" + -disabledbg "#737373" + -selectfg "#ffffff" + -selectbg "#007fff" + } + + ttk::style layout TButton { + Button.button -children { + Button.padding -children { + Button.label -side left -expand true + } + } + } + + ttk::style layout Toolbutton { + Toolbutton.button -children { + Toolbutton.padding -children { + Toolbutton.label -side left -expand true + } + } + } + + ttk::style layout TMenubutton { + Menubutton.button -children { + Menubutton.padding -children { + Menubutton.indicator -side right + Menubutton.label -side right -expand true + } + } + } + + ttk::style layout TOptionMenu { + OptionMenu.button -children { + OptionMenu.padding -children { + OptionMenu.indicator -side right + OptionMenu.label -side right -expand true + } + } + } + + ttk::style layout Accent.TButton { + AccentButton.button -children { + AccentButton.padding -children { + AccentButton.label -side left -expand true + } + } + } + + ttk::style layout TCheckbutton { + Checkbutton.button -children { + Checkbutton.padding -children { + Checkbutton.indicator -side left + Checkbutton.label -side right -expand true + } + } + } + + ttk::style layout Switch.TCheckbutton { + Switch.button -children { + Switch.padding -children { + Switch.indicator -side left + Switch.label -side right -expand true + } + } + } + + ttk::style layout Toggle.TButton { + ToggleButton.button -children { + ToggleButton.padding -children { + ToggleButton.label -side left -expand true + } + } + } + + ttk::style layout TRadiobutton { + Radiobutton.button -children { + Radiobutton.padding -children { + Radiobutton.indicator -side left + Radiobutton.label -side right -expand true + } + } + } + + ttk::style layout Vertical.TScrollbar { + Vertical.Scrollbar.trough -sticky ns -children { + Vertical.Scrollbar.thumb -expand true + } + } + + ttk::style layout Horizontal.TScrollbar { + Horizontal.Scrollbar.trough -sticky ew -children { + Horizontal.Scrollbar.thumb -expand true + } + } + + ttk::style layout TCombobox { + Combobox.field -sticky nswe -children { + Combobox.padding -expand true -sticky nswe -children { + Combobox.textarea -sticky nswe + } + } + Combobox.button -side right -sticky ns -children { + Combobox.arrow -sticky nsew + } + } + + ttk::style layout TSpinbox { + Spinbox.field -sticky nsew -children { + Spinbox.padding -expand true -sticky nswe -children { + Spinbox.textarea -sticky nswe + } + + } + Spinbox.button -side right -sticky ns -children { + null -side right -children { + Spinbox.uparrow -side top + Spinbox.downarrow -side bottom + } + } + } + + ttk::style layout Horizontal.TSeparator { + Horizontal.separator -sticky nswe + } + + ttk::style layout Vertical.TSeparator { + Vertical.separator -sticky nswe + } + + ttk::style layout Horizontal.Tick.TScale { + Horizontal.TickScale.trough -sticky ew -children { + Horizontal.TickScale.slider -sticky w + } + } + + ttk::style layout Vertical.Tick.TScale { + Vertical.TickScale.trough -sticky ns -children { + Vertical.TickScale.slider -sticky n + } + } + + ttk::style layout Card.TFrame { + Card.field { + Card.padding -expand 1 + } + } + + ttk::style layout TLabelframe { + Labelframe.border { + Labelframe.padding -expand 1 -children { + Labelframe.label -side right + } + } + } + + ttk::style layout TNotebook.Tab { + Notebook.tab -children { + Notebook.padding -side top -children { + Notebook.label -side top -sticky {} + } + } + } + + ttk::style layout Treeview.Item { + Treeitem.padding -sticky nswe -children { + Treeitem.indicator -side left -sticky {} + Treeitem.image -side left -sticky {} + Treeitem.text -side left -sticky {} + } + } + + + # Elements + + # Button + ttk::style configure TButton -padding {8 4 8 4} -width -10 -anchor center + + ttk::style element create Button.button image \ + [list $I(rect-basic) \ + {selected disabled} $I(rect-basic) \ + disabled $I(rect-basic) \ + pressed $I(rect-basic) \ + selected $I(rect-basic) \ + active $I(button-hover) \ + focus $I(button-hover) \ + ] -border 4 -sticky ewns + + # Toolbutton + ttk::style configure Toolbutton -padding {8 4 8 4} -width -10 -anchor center + + ttk::style element create Toolbutton.button image \ + [list $I(empty) \ + {selected disabled} $I(empty) \ + disabled $I(empty) \ + pressed $I(rect-basic) \ + selected $I(rect-basic) \ + active $I(rect-basic) \ + ] -border 4 -sticky ewns + + # Menubutton + ttk::style configure TMenubutton -padding {8 4 4 4} + + ttk::style element create Menubutton.button \ + image [list $I(rect-basic) \ + disabled $I(rect-basic) \ + pressed $I(rect-basic) \ + active $I(button-hover) \ + ] -border 4 -sticky ewns + + ttk::style element create Menubutton.indicator \ + image [list $I(down) \ + active $I(down) \ + pressed $I(down) \ + disabled $I(down) \ + ] -width 15 -sticky e + + # OptionMenu + ttk::style configure TOptionMenu -padding {8 4 4 4} + + ttk::style element create OptionMenu.button \ + image [list $I(rect-basic) \ + disabled $I(rect-basic) \ + pressed $I(rect-basic) \ + active $I(button-hover) \ + ] -border 4 -sticky ewns + + ttk::style element create OptionMenu.indicator \ + image [list $I(down) \ + active $I(down) \ + pressed $I(down) \ + disabled $I(down) \ + ] -width 15 -sticky e + + # AccentButton + ttk::style configure Accent.TButton -padding {8 4 8 4} -width -10 -anchor center + + ttk::style element create AccentButton.button image \ + [list $I(rect-accent) \ + {selected disabled} $I(rect-accent-hover) \ + disabled $I(rect-accent-hover) \ + pressed $I(rect-accent) \ + selected $I(rect-accent) \ + active $I(rect-accent-hover) \ + focus $I(rect-accent-hover) \ + ] -border 4 -sticky ewns + + # Checkbutton + ttk::style configure TCheckbutton -padding 4 + + ttk::style element create Checkbutton.indicator image \ + [list $I(box-basic) \ + {alternate disabled} $I(check-tri-basic) \ + {selected disabled} $I(check-basic) \ + disabled $I(box-basic) \ + {pressed alternate} $I(check-tri-hover) \ + {active alternate} $I(check-tri-hover) \ + alternate $I(check-tri-accent) \ + {pressed selected} $I(check-hover) \ + {active selected} $I(check-hover) \ + selected $I(check-accent) \ + {pressed !selected} $I(rect-hover) \ + active $I(box-hover) \ + ] -width 26 -sticky w + + # Switch + ttk::style element create Switch.indicator image \ + [list $I(off-basic) \ + {selected disabled} $I(on-basic) \ + disabled $I(off-basic) \ + {pressed selected} $I(on-accent) \ + {active selected} $I(on-accent) \ + selected $I(on-accent) \ + {pressed !selected} $I(off-basic) \ + active $I(off-basic) \ + ] -width 46 -sticky w + + # ToggleButton + ttk::style configure Toggle.TButton -padding {8 4 8 4} -width -10 -anchor center + + ttk::style element create ToggleButton.button image \ + [list $I(rect-basic) \ + {selected disabled} $I(rect-accent-hover) \ + disabled $I(rect-basic) \ + {pressed selected} $I(rect-basic) \ + {active selected} $I(rect-accent) \ + selected $I(rect-accent) \ + {pressed !selected} $I(rect-accent) \ + active $I(rect-basic) \ + ] -border 4 -sticky ewns + + # Radiobutton + ttk::style configure TRadiobutton -padding 4 + + ttk::style element create Radiobutton.indicator image \ + [list $I(outline-basic) \ + {alternate disabled} $I(radio-tri-basic) \ + {selected disabled} $I(radio-basic) \ + disabled $I(outline-basic) \ + {pressed alternate} $I(radio-tri-hover) \ + {active alternate} $I(radio-tri-hover) \ + alternate $I(radio-tri-accent) \ + {pressed selected} $I(radio-hover) \ + {active selected} $I(radio-hover) \ + selected $I(radio-accent) \ + {pressed !selected} $I(circle-hover) \ + active $I(outline-hover) \ + ] -width 26 -sticky w + + # Scrollbar + ttk::style element create Horizontal.Scrollbar.trough image $I(hor-basic) \ + -sticky ew + + ttk::style element create Horizontal.Scrollbar.thumb \ + image [list $I(hor-accent) \ + disabled $I(hor-basic) \ + pressed $I(hor-hover) \ + active $I(hor-hover) \ + ] -sticky ew + + ttk::style element create Vertical.Scrollbar.trough image $I(vert-basic) \ + -sticky ns + + ttk::style element create Vertical.Scrollbar.thumb \ + image [list $I(vert-accent) \ + disabled $I(vert-basic) \ + pressed $I(vert-hover) \ + active $I(vert-hover) \ + ] -sticky ns + + # Scale + ttk::style element create Horizontal.Scale.trough image $I(scale-hor) \ + -border 5 -padding 0 + + ttk::style element create Horizontal.Scale.slider \ + image [list $I(circle-accent) \ + disabled $I(circle-basic) \ + pressed $I(circle-hover) \ + active $I(circle-hover) \ + ] -sticky {} + + ttk::style element create Vertical.Scale.trough image $I(scale-vert) \ + -border 5 -padding 0 + + ttk::style element create Vertical.Scale.slider \ + image [list $I(circle-accent) \ + disabled $I(circle-basic) \ + pressed $I(circle-hover) \ + active $I(circle-hover) \ + ] -sticky {} + + # Tickscale + ttk::style element create Horizontal.TickScale.trough image $I(scale-hor) \ + -border 5 -padding 0 + + ttk::style element create Horizontal.TickScale.slider \ + image [list $I(tick-hor-accent) \ + disabled $I(tick-hor-basic) \ + pressed $I(tick-hor-hover) \ + active $I(tick-hor-hover) \ + ] -sticky {} + + ttk::style element create Vertical.TickScale.trough image $I(scale-vert) \ + -border 5 -padding 0 + + ttk::style element create Vertical.TickScale.slider \ + image [list $I(tick-vert-accent) \ + disabled $I(tick-vert-basic) \ + pressed $I(tick-vert-hover) \ + active $I(tick-vert-hover) \ + ] -sticky {} + + # Progressbar + ttk::style element create Horizontal.Progressbar.trough image $I(hor-basic) \ + -sticky ew + + ttk::style element create Horizontal.Progressbar.pbar image $I(hor-accent) \ + -sticky ew + + ttk::style element create Vertical.Progressbar.trough image $I(vert-basic) \ + -sticky ns + + ttk::style element create Vertical.Progressbar.pbar image $I(vert-accent) \ + -sticky ns + + # Entry + ttk::style element create Entry.field \ + image [list $I(box-basic) \ + {focus hover} $I(box-accent) \ + invalid $I(box-invalid) \ + disabled $I(box-basic) \ + focus $I(box-accent) \ + hover $I(box-hover) \ + ] -border 5 -padding {8} -sticky news + + # Combobox + ttk::style map TCombobox -selectbackground [list \ + {!focus} $colors(-selectbg) \ + {readonly hover} $colors(-selectbg) \ + {readonly focus} $colors(-selectbg) \ + ] + + ttk::style map TCombobox -selectforeground [list \ + {!focus} $colors(-selectfg) \ + {readonly hover} $colors(-selectfg) \ + {readonly focus} $colors(-selectfg) \ + ] + + ttk::style element create Combobox.field \ + image [list $I(box-basic) \ + {readonly disabled} $I(rect-basic) \ + {readonly pressed} $I(rect-basic) \ + {readonly focus hover} $I(button-hover) \ + {readonly focus} $I(button-hover) \ + {readonly hover} $I(button-hover) \ + {focus hover} $I(box-accent) \ + readonly $I(rect-basic) \ + invalid $I(box-invalid) \ + disabled $I(box-basic) \ + focus $I(box-accent) \ + hover $I(box-hover) \ + ] -border 5 -padding {8} + + ttk::style element create Combobox.button \ + image [list $I(combo-button-basic) \ + {!readonly focus} $I(combo-button-focus) \ + {readonly focus} $I(combo-button-hover) \ + {readonly hover} $I(combo-button-hover) + ] -border 5 -padding {2 6 6 6} + + ttk::style element create Combobox.arrow image $I(down) \ + -width 15 -sticky e + + # Spinbox + ttk::style element create Spinbox.field \ + image [list $I(box-basic) \ + invalid $I(box-invalid) \ + disabled $I(box-basic) \ + focus $I(box-accent) \ + hover $I(box-hover) \ + ] -border 5 -padding {8} -sticky news + + ttk::style element create Spinbox.uparrow \ + image [list $I(up) \ + disabled $I(up) \ + pressed $I(up-accent) \ + active $I(up-accent) \ + ] -border 4 -width 15 -sticky e + + ttk::style element create Spinbox.downarrow \ + image [list $I(down) \ + disabled $I(down) \ + pressed $I(down-accent) \ + active $I(down-accent) \ + ] -border 4 -width 15 -sticky e + + ttk::style element create Spinbox.button \ + image [list $I(combo-button-basic) \ + {!readonly focus} $I(combo-button-focus) \ + {readonly focus} $I(combo-button-hover) \ + {readonly hover} $I(combo-button-hover) + ] -border 5 -padding {2 6 6 6} + + # Sizegrip + ttk::style element create Sizegrip.sizegrip image $I(size) \ + -sticky ewns + + # Separator + ttk::style element create Horizontal.separator image $I(separator) + + ttk::style element create Vertical.separator image $I(separator) + + # Card + ttk::style element create Card.field image $I(card) \ + -border 10 -padding 4 -sticky news + + # Labelframe + ttk::style element create Labelframe.border image $I(card) \ + -border 5 -padding 4 -sticky news + + # Notebook + ttk::style element create Notebook.client \ + image $I(notebook) -border 5 + + ttk::style element create Notebook.tab \ + image [list $I(tab-disabled) \ + selected $I(tab-basic) \ + active $I(tab-hover) \ + ] -border 5 -padding {14 4} + + # Treeview + ttk::style element create Treeview.field image $I(card) \ + -border 5 + + ttk::style element create Treeheading.cell \ + image [list $I(tree-basic) \ + pressed $I(tree-pressed) + ] -border 5 -padding 4 -sticky ewns + + ttk::style element create Treeitem.indicator \ + image [list $I(right) \ + user2 $I(empty) \ + user1 $I(down) \ + ] -width 26 -sticky {} + + ttk::style configure Treeview -background $colors(-bg) + ttk::style configure Treeview.Item -padding {2 0 0 0} + ttk::style map Treeview \ + -background [list selected $colors(-selectbg)] \ + -foreground [list selected $colors(-selectfg)] + + # Panedwindow + # Insane hack to remove clam's ugly sash + ttk::style configure Sash -gripcount 0 + } +} diff --git a/theme/dark/box-accent.png b/theme/dark/box-accent.png new file mode 100644 index 0000000..d0e186b Binary files /dev/null and b/theme/dark/box-accent.png differ diff --git a/theme/dark/box-basic.png b/theme/dark/box-basic.png new file mode 100644 index 0000000..0b28fed Binary files /dev/null and b/theme/dark/box-basic.png differ diff --git a/theme/dark/box-hover.png b/theme/dark/box-hover.png new file mode 100644 index 0000000..3ca7c19 Binary files /dev/null and b/theme/dark/box-hover.png differ diff --git a/theme/dark/box-invalid.png b/theme/dark/box-invalid.png new file mode 100644 index 0000000..f180e94 Binary files /dev/null and b/theme/dark/box-invalid.png differ diff --git a/theme/dark/button-hover.png b/theme/dark/button-hover.png new file mode 100644 index 0000000..300eb09 Binary files /dev/null and b/theme/dark/button-hover.png differ diff --git a/theme/dark/card.png b/theme/dark/card.png new file mode 100644 index 0000000..3978e9f Binary files /dev/null and b/theme/dark/card.png differ diff --git a/theme/dark/check-accent.png b/theme/dark/check-accent.png new file mode 100644 index 0000000..9854ec3 Binary files /dev/null and b/theme/dark/check-accent.png differ diff --git a/theme/dark/check-basic.png b/theme/dark/check-basic.png new file mode 100644 index 0000000..529718e Binary files /dev/null and b/theme/dark/check-basic.png differ diff --git a/theme/dark/check-hover.png b/theme/dark/check-hover.png new file mode 100644 index 0000000..c96c80c Binary files /dev/null and b/theme/dark/check-hover.png differ diff --git a/theme/dark/check-tri-accent.png b/theme/dark/check-tri-accent.png new file mode 100644 index 0000000..c0539f9 Binary files /dev/null and b/theme/dark/check-tri-accent.png differ diff --git a/theme/dark/check-tri-basic.png b/theme/dark/check-tri-basic.png new file mode 100644 index 0000000..d0188f5 Binary files /dev/null and b/theme/dark/check-tri-basic.png differ diff --git a/theme/dark/check-tri-hover.png b/theme/dark/check-tri-hover.png new file mode 100644 index 0000000..ae3e19f Binary files /dev/null and b/theme/dark/check-tri-hover.png differ diff --git a/theme/dark/circle-accent.png b/theme/dark/circle-accent.png new file mode 100644 index 0000000..e9a5ee5 Binary files /dev/null and b/theme/dark/circle-accent.png differ diff --git a/theme/dark/circle-basic.png b/theme/dark/circle-basic.png new file mode 100644 index 0000000..85f2bac Binary files /dev/null and b/theme/dark/circle-basic.png differ diff --git a/theme/dark/circle-hover.png b/theme/dark/circle-hover.png new file mode 100644 index 0000000..b439cd6 Binary files /dev/null and b/theme/dark/circle-hover.png differ diff --git a/theme/dark/combo-button-basic.png b/theme/dark/combo-button-basic.png new file mode 100644 index 0000000..4aef1b2 Binary files /dev/null and b/theme/dark/combo-button-basic.png differ diff --git a/theme/dark/combo-button-focus.png b/theme/dark/combo-button-focus.png new file mode 100644 index 0000000..5b1e0ff Binary files /dev/null and b/theme/dark/combo-button-focus.png differ diff --git a/theme/dark/combo-button-hover.png b/theme/dark/combo-button-hover.png new file mode 100644 index 0000000..493cf52 Binary files /dev/null and b/theme/dark/combo-button-hover.png differ diff --git a/theme/dark/down-accent.png b/theme/dark/down-accent.png new file mode 100644 index 0000000..5bb987d Binary files /dev/null and b/theme/dark/down-accent.png differ diff --git a/theme/dark/down.png b/theme/dark/down.png new file mode 100644 index 0000000..d83f92d Binary files /dev/null and b/theme/dark/down.png differ diff --git a/theme/dark/empty.png b/theme/dark/empty.png new file mode 100644 index 0000000..202e3de Binary files /dev/null and b/theme/dark/empty.png differ diff --git a/theme/dark/hor-accent.png b/theme/dark/hor-accent.png new file mode 100644 index 0000000..e59a1c6 Binary files /dev/null and b/theme/dark/hor-accent.png differ diff --git a/theme/dark/hor-basic.png b/theme/dark/hor-basic.png new file mode 100644 index 0000000..bbc2e50 Binary files /dev/null and b/theme/dark/hor-basic.png differ diff --git a/theme/dark/hor-hover.png b/theme/dark/hor-hover.png new file mode 100644 index 0000000..56216f4 Binary files /dev/null and b/theme/dark/hor-hover.png differ diff --git a/theme/dark/notebook.png b/theme/dark/notebook.png new file mode 100644 index 0000000..5b937c1 Binary files /dev/null and b/theme/dark/notebook.png differ diff --git a/theme/dark/off-basic.png b/theme/dark/off-basic.png new file mode 100644 index 0000000..2ca539a Binary files /dev/null and b/theme/dark/off-basic.png differ diff --git a/theme/dark/on-accent.png b/theme/dark/on-accent.png new file mode 100644 index 0000000..4a33465 Binary files /dev/null and b/theme/dark/on-accent.png differ diff --git a/theme/dark/on-basic.png b/theme/dark/on-basic.png new file mode 100644 index 0000000..9dce6a5 Binary files /dev/null and b/theme/dark/on-basic.png differ diff --git a/theme/dark/outline-basic.png b/theme/dark/outline-basic.png new file mode 100644 index 0000000..2f76a1b Binary files /dev/null and b/theme/dark/outline-basic.png differ diff --git a/theme/dark/outline-hover.png b/theme/dark/outline-hover.png new file mode 100644 index 0000000..7ce5290 Binary files /dev/null and b/theme/dark/outline-hover.png differ diff --git a/theme/dark/radio-accent.png b/theme/dark/radio-accent.png new file mode 100644 index 0000000..c34e4a8 Binary files /dev/null and b/theme/dark/radio-accent.png differ diff --git a/theme/dark/radio-basic.png b/theme/dark/radio-basic.png new file mode 100644 index 0000000..f9b55a6 Binary files /dev/null and b/theme/dark/radio-basic.png differ diff --git a/theme/dark/radio-hover.png b/theme/dark/radio-hover.png new file mode 100644 index 0000000..4f3eab8 Binary files /dev/null and b/theme/dark/radio-hover.png differ diff --git a/theme/dark/radio-tri-accent.png b/theme/dark/radio-tri-accent.png new file mode 100644 index 0000000..8084141 Binary files /dev/null and b/theme/dark/radio-tri-accent.png differ diff --git a/theme/dark/radio-tri-basic.png b/theme/dark/radio-tri-basic.png new file mode 100644 index 0000000..def9e27 Binary files /dev/null and b/theme/dark/radio-tri-basic.png differ diff --git a/theme/dark/radio-tri-hover.png b/theme/dark/radio-tri-hover.png new file mode 100644 index 0000000..86f1b59 Binary files /dev/null and b/theme/dark/radio-tri-hover.png differ diff --git a/theme/dark/rect-accent-hover.png b/theme/dark/rect-accent-hover.png new file mode 100644 index 0000000..bb49129 Binary files /dev/null and b/theme/dark/rect-accent-hover.png differ diff --git a/theme/dark/rect-accent.png b/theme/dark/rect-accent.png new file mode 100644 index 0000000..5e7c72c Binary files /dev/null and b/theme/dark/rect-accent.png differ diff --git a/theme/dark/rect-basic.png b/theme/dark/rect-basic.png new file mode 100644 index 0000000..8ab4d10 Binary files /dev/null and b/theme/dark/rect-basic.png differ diff --git a/theme/dark/rect-hover.png b/theme/dark/rect-hover.png new file mode 100644 index 0000000..b9e4c35 Binary files /dev/null and b/theme/dark/rect-hover.png differ diff --git a/theme/dark/right.png b/theme/dark/right.png new file mode 100644 index 0000000..bc840c2 Binary files /dev/null and b/theme/dark/right.png differ diff --git a/theme/dark/scale-hor.png b/theme/dark/scale-hor.png new file mode 100644 index 0000000..570530e Binary files /dev/null and b/theme/dark/scale-hor.png differ diff --git a/theme/dark/scale-vert.png b/theme/dark/scale-vert.png new file mode 100644 index 0000000..c6fcf6f Binary files /dev/null and b/theme/dark/scale-vert.png differ diff --git a/theme/dark/separator.png b/theme/dark/separator.png new file mode 100644 index 0000000..411c970 Binary files /dev/null and b/theme/dark/separator.png differ diff --git a/theme/dark/size.png b/theme/dark/size.png new file mode 100644 index 0000000..51c682e Binary files /dev/null and b/theme/dark/size.png differ diff --git a/theme/dark/tab-basic.png b/theme/dark/tab-basic.png new file mode 100644 index 0000000..6db676b Binary files /dev/null and b/theme/dark/tab-basic.png differ diff --git a/theme/dark/tab-disabled.png b/theme/dark/tab-disabled.png new file mode 100644 index 0000000..736c438 Binary files /dev/null and b/theme/dark/tab-disabled.png differ diff --git a/theme/dark/tab-hover.png b/theme/dark/tab-hover.png new file mode 100644 index 0000000..213e82b Binary files /dev/null and b/theme/dark/tab-hover.png differ diff --git a/theme/dark/tick-hor-accent.png b/theme/dark/tick-hor-accent.png new file mode 100644 index 0000000..b7c28dd Binary files /dev/null and b/theme/dark/tick-hor-accent.png differ diff --git a/theme/dark/tick-hor-basic.png b/theme/dark/tick-hor-basic.png new file mode 100644 index 0000000..ee4b441 Binary files /dev/null and b/theme/dark/tick-hor-basic.png differ diff --git a/theme/dark/tick-hor-hover.png b/theme/dark/tick-hor-hover.png new file mode 100644 index 0000000..bc859f4 Binary files /dev/null and b/theme/dark/tick-hor-hover.png differ diff --git a/theme/dark/tick-vert-accent.png b/theme/dark/tick-vert-accent.png new file mode 100644 index 0000000..da4f481 Binary files /dev/null and b/theme/dark/tick-vert-accent.png differ diff --git a/theme/dark/tick-vert-basic.png b/theme/dark/tick-vert-basic.png new file mode 100644 index 0000000..9e0a5ee Binary files /dev/null and b/theme/dark/tick-vert-basic.png differ diff --git a/theme/dark/tick-vert-hover.png b/theme/dark/tick-vert-hover.png new file mode 100644 index 0000000..e9ff3a3 Binary files /dev/null and b/theme/dark/tick-vert-hover.png differ diff --git a/theme/dark/tree-basic.png b/theme/dark/tree-basic.png new file mode 100644 index 0000000..c71808d Binary files /dev/null and b/theme/dark/tree-basic.png differ diff --git a/theme/dark/tree-pressed.png b/theme/dark/tree-pressed.png new file mode 100644 index 0000000..96d3a53 Binary files /dev/null and b/theme/dark/tree-pressed.png differ diff --git a/theme/dark/up-accent.png b/theme/dark/up-accent.png new file mode 100644 index 0000000..54a20f8 Binary files /dev/null and b/theme/dark/up-accent.png differ diff --git a/theme/dark/up.png b/theme/dark/up.png new file mode 100644 index 0000000..069d440 Binary files /dev/null and b/theme/dark/up.png differ diff --git a/theme/dark/vert-accent.png b/theme/dark/vert-accent.png new file mode 100644 index 0000000..1c228fd Binary files /dev/null and b/theme/dark/vert-accent.png differ diff --git a/theme/dark/vert-basic.png b/theme/dark/vert-basic.png new file mode 100644 index 0000000..4f6c46e Binary files /dev/null and b/theme/dark/vert-basic.png differ diff --git a/theme/dark/vert-hover.png b/theme/dark/vert-hover.png new file mode 100644 index 0000000..142ccce Binary files /dev/null and b/theme/dark/vert-hover.png differ diff --git a/theme/light.tcl b/theme/light.tcl new file mode 100644 index 0000000..29bdb03 --- /dev/null +++ b/theme/light.tcl @@ -0,0 +1,539 @@ +# Copyright (c) 2021 rdbende + +# The Azure theme is a beautiful modern ttk theme inspired by Microsoft's fluent design. + +package require Tk 8.6 + +namespace eval ttk::theme::azure-light { + variable version 2.0 + package provide ttk::theme::azure-light $version + + ttk::style theme create azure-light -parent clam -settings { + proc load_images {imgdir} { + variable I + foreach file [glob -directory $imgdir *.png] { + set img [file tail [file rootname $file]] + set I($img) [image create photo -file $file -format png] + } + } + + load_images [file join [file dirname [info script]] light] + + array set colors { + -fg "#000000" + -bg "#ffffff" + -disabledfg "#737373" + -disabledbg "#ffffff" + -selectfg "#ffffff" + -selectbg "#007fff" + } + + ttk::style layout TButton { + Button.button -children { + Button.padding -children { + Button.label -side left -expand true + } + } + } + + ttk::style layout Toolbutton { + Toolbutton.button -children { + Toolbutton.padding -children { + Toolbutton.label -side left -expand true + } + } + } + + ttk::style layout TMenubutton { + Menubutton.button -children { + Menubutton.padding -children { + Menubutton.indicator -side right + Menubutton.label -side right -expand true + } + } + } + + ttk::style layout TOptionMenu { + OptionMenu.button -children { + OptionMenu.padding -children { + OptionMenu.indicator -side right + OptionMenu.label -side right -expand true + } + } + } + + ttk::style layout Accent.TButton { + AccentButton.button -children { + AccentButton.padding -children { + AccentButton.label -side left -expand true + } + } + } + + ttk::style layout TCheckbutton { + Checkbutton.button -children { + Checkbutton.padding -children { + Checkbutton.indicator -side left + Checkbutton.label -side right -expand true + } + } + } + + ttk::style layout Switch.TCheckbutton { + Switch.button -children { + Switch.padding -children { + Switch.indicator -side left + Switch.label -side right -expand true + } + } + } + + ttk::style layout Toggle.TButton { + ToggleButton.button -children { + ToggleButton.padding -children { + ToggleButton.label -side left -expand true + } + } + } + + ttk::style layout TRadiobutton { + Radiobutton.button -children { + Radiobutton.padding -children { + Radiobutton.indicator -side left + Radiobutton.label -side right -expand true + } + } + } + + ttk::style layout Vertical.TScrollbar { + Vertical.Scrollbar.trough -sticky ns -children { + Vertical.Scrollbar.thumb -expand true + } + } + + ttk::style layout Horizontal.TScrollbar { + Horizontal.Scrollbar.trough -sticky ew -children { + Horizontal.Scrollbar.thumb -expand true + } + } + + ttk::style layout TCombobox { + Combobox.field -sticky nswe -children { + Combobox.padding -expand true -sticky nswe -children { + Combobox.textarea -sticky nswe + } + } + Combobox.button -side right -sticky ns -children { + Combobox.arrow -sticky nsew + } + } + + ttk::style layout TSpinbox { + Spinbox.field -sticky nsew -children { + Spinbox.padding -expand true -sticky nswe -children { + Spinbox.textarea -sticky nswe + } + + } + Spinbox.button -side right -sticky ns -children { + null -side right -children { + Spinbox.uparrow -side top + Spinbox.downarrow -side bottom + } + } + } + + ttk::style layout Horizontal.TSeparator { + Horizontal.separator -sticky nswe + } + + ttk::style layout Vertical.TSeparator { + Vertical.separator -sticky nswe + } + + ttk::style layout Horizontal.Tick.TScale { + Horizontal.TickScale.trough -sticky ew -children { + Horizontal.TickScale.slider -sticky w + } + } + + ttk::style layout Vertical.Tick.TScale { + Vertical.TickScale.trough -sticky ns -children { + Vertical.TickScale.slider -sticky n + } + } + + ttk::style layout Card.TFrame { + Card.field { + Card.padding -expand 1 + } + } + + ttk::style layout TLabelframe { + Labelframe.border { + Labelframe.padding -expand 1 -children { + Labelframe.label -side right + } + } + } + + ttk::style layout TNotebook.Tab { + Notebook.tab -children { + Notebook.padding -side top -children { + Notebook.label -side top -sticky {} + } + } + } + + ttk::style layout Treeview.Item { + Treeitem.padding -sticky nswe -children { + Treeitem.indicator -side left -sticky {} + Treeitem.image -side left -sticky {} + Treeitem.text -side left -sticky {} + } + } + + + # Elements + + # Button + ttk::style configure TButton -padding {8 4 8 4} -width -10 -anchor center + + ttk::style element create Button.button image \ + [list $I(rect-basic) \ + {selected disabled} $I(rect-basic) \ + disabled $I(rect-basic) \ + selected $I(rect-basic) \ + pressed $I(rect-basic) \ + active $I(button-hover) \ + focus $I(button-hover) \ + ] -border 4 -sticky ewns + + # Toolbutton + ttk::style configure Toolbutton -padding {8 4 8 4} -width -10 -anchor center + + ttk::style element create Toolbutton.button image \ + [list $I(empty) \ + {selected disabled} $I(empty) \ + disabled $I(empty) \ + selected $I(rect-basic) \ + pressed $I(rect-basic) \ + active $I(rect-basic) \ + ] -border 4 -sticky ewns + + # Menubutton + ttk::style configure TMenubutton -padding {8 4 4 4} + + ttk::style element create Menubutton.button \ + image [list $I(rect-basic) \ + disabled $I(rect-basic) \ + pressed $I(rect-basic) \ + active $I(button-hover) \ + ] -border 4 -sticky ewns + + ttk::style element create Menubutton.indicator \ + image [list $I(down) \ + active $I(down) \ + pressed $I(down) \ + disabled $I(down) \ + ] -width 15 -sticky e + + # OptionMenu + ttk::style configure TOptionMenu -padding {8 4 4 4} + + ttk::style element create OptionMenu.button \ + image [list $I(rect-basic) \ + disabled $I(rect-basic) \ + pressed $I(rect-basic) \ + active $I(button-hover) \ + ] -border 4 -sticky ewns + + ttk::style element create OptionMenu.indicator \ + image [list $I(down) \ + active $I(down) \ + pressed $I(down) \ + disabled $I(down) \ + ] -width 15 -sticky e + + # AccentButton + ttk::style configure Accent.TButton -padding {8 4 8 4} -width -10 -anchor center + + ttk::style element create AccentButton.button image \ + [list $I(rect-accent) \ + {selected disabled} $I(rect-accent-hover) \ + disabled $I(rect-accent-hover) \ + selected $I(rect-accent) \ + pressed $I(rect-accent) \ + active $I(rect-accent-hover) \ + focus $I(rect-accent-hover) \ + ] -border 4 -sticky ewns + + # Checkbutton + ttk::style configure TCheckbutton -padding 4 + + ttk::style element create Checkbutton.indicator image \ + [list $I(box-basic) \ + {alternate disabled} $I(check-tri-basic) \ + {selected disabled} $I(check-basic) \ + disabled $I(box-basic) \ + {pressed alternate} $I(check-tri-hover) \ + {active alternate} $I(check-tri-hover) \ + alternate $I(check-tri-accent) \ + {pressed selected} $I(check-hover) \ + {active selected} $I(check-hover) \ + selected $I(check-accent) \ + {pressed !selected} $I(rect-hover) \ + active $I(box-hover) \ + ] -width 26 -sticky w + + # Switch + ttk::style element create Switch.indicator image \ + [list $I(off-basic) \ + {selected disabled} $I(on-basic) \ + disabled $I(off-basic) \ + {pressed selected} $I(on-hover) \ + {active selected} $I(on-hover) \ + selected $I(on-accent) \ + {pressed !selected} $I(off-hover) \ + active $I(off-hover) \ + ] -width 46 -sticky w + + # ToggleButton + ttk::style configure Toggle.TButton -padding {8 4 8 4} -width -10 -anchor center + + ttk::style element create ToggleButton.button image \ + [list $I(rect-basic) \ + {selected disabled} $I(rect-accent-hover) \ + disabled $I(rect-basic) \ + {pressed selected} $I(rect-basic) \ + {active selected} $I(rect-accent) \ + selected $I(rect-accent) \ + {pressed !selected} $I(rect-accent) \ + active $I(rect-basic) \ + ] -border 4 -sticky ewns + + # Radiobutton + ttk::style configure TRadiobutton -padding 4 + + ttk::style element create Radiobutton.indicator image \ + [list $I(outline-basic) \ + {alternate disabled} $I(radio-tri-basic) \ + {selected disabled} $I(radio-basic) \ + disabled $I(outline-basic) \ + {pressed alternate} $I(radio-tri-hover) \ + {active alternate} $I(radio-tri-hover) \ + alternate $I(radio-tri-accent) \ + {pressed selected} $I(radio-hover) \ + {active selected} $I(radio-hover) \ + selected $I(radio-accent) \ + {pressed !selected} $I(circle-hover) \ + active $I(outline-hover) \ + ] -width 26 -sticky w + + # Scrollbar + ttk::style element create Horizontal.Scrollbar.trough image $I(hor-basic) \ + -sticky ew + + ttk::style element create Horizontal.Scrollbar.thumb \ + image [list $I(hor-accent) \ + disabled $I(hor-basic) \ + pressed $I(hor-hover) \ + active $I(hor-hover) \ + ] -sticky ew + + ttk::style element create Vertical.Scrollbar.trough image $I(vert-basic) \ + -sticky ns + + ttk::style element create Vertical.Scrollbar.thumb \ + image [list $I(vert-accent) \ + disabled $I(vert-basic) \ + pressed $I(vert-hover) \ + active $I(vert-hover) \ + ] -sticky ns + + # Scale + ttk::style element create Horizontal.Scale.trough image $I(scale-hor) \ + -border 5 -padding 0 + + ttk::style element create Horizontal.Scale.slider \ + image [list $I(circle-accent) \ + disabled $I(circle-basic) \ + pressed $I(circle-hover) \ + active $I(circle-hover) \ + ] -sticky {} + + ttk::style element create Vertical.Scale.trough image $I(scale-vert) \ + -border 5 -padding 0 + + ttk::style element create Vertical.Scale.slider \ + image [list $I(circle-accent) \ + disabled $I(circle-basic) \ + pressed $I(circle-hover) \ + active $I(circle-hover) \ + ] -sticky {} + + # Tickscale + ttk::style element create Horizontal.TickScale.trough image $I(scale-hor) \ + -border 5 -padding 0 + + ttk::style element create Horizontal.TickScale.slider \ + image [list $I(tick-hor-accent) \ + disabled $I(tick-hor-basic) \ + pressed $I(tick-hor-hover) \ + active $I(tick-hor-hover) \ + ] -sticky {} + + ttk::style element create Vertical.TickScale.trough image $I(scale-vert) \ + -border 5 -padding 0 + + ttk::style element create Vertical.TickScale.slider \ + image [list $I(tick-vert-accent) \ + disabled $I(tick-vert-basic) \ + pressed $I(tick-vert-hover) \ + active $I(tick-vert-hover) \ + ] -sticky {} + + # Progressbar + ttk::style element create Horizontal.Progressbar.trough image $I(hor-basic) \ + -sticky ew + + ttk::style element create Horizontal.Progressbar.pbar image $I(hor-accent) \ + -sticky ew + + ttk::style element create Vertical.Progressbar.trough image $I(vert-basic) \ + -sticky ns + + ttk::style element create Vertical.Progressbar.pbar image $I(vert-accent) \ + -sticky ns + + # Entry + ttk::style element create Entry.field \ + image [list $I(box-basic) \ + {focus hover} $I(box-accent) \ + invalid $I(box-invalid) \ + disabled $I(box-basic) \ + focus $I(box-accent) \ + hover $I(box-hover) \ + ] -border 5 -padding {8} -sticky news + + # Combobox + ttk::style map TCombobox -selectbackground [list \ + {!focus} $colors(-selectbg) \ + {readonly hover} $colors(-selectbg) \ + {readonly focus} $colors(-selectbg) \ + ] + + ttk::style map TCombobox -selectforeground [list \ + {!focus} $colors(-selectfg) \ + {readonly hover} $colors(-selectfg) \ + {readonly focus} $colors(-selectfg) \ + ] + + ttk::style element create Combobox.field \ + image [list $I(box-basic) \ + {readonly disabled} $I(rect-basic) \ + {readonly pressed} $I(rect-basic) \ + {readonly focus hover} $I(button-hover) \ + {readonly focus} $I(button-hover) \ + {readonly hover} $I(button-hover) \ + {focus hover} $I(box-accent) \ + readonly $I(rect-basic) \ + invalid $I(box-invalid) \ + disabled $I(box-basic) \ + focus $I(box-accent) \ + hover $I(box-hover) \ + ] -border 5 -padding {8} + + ttk::style element create Combobox.button \ + image [list $I(combo-button-basic) \ + {!readonly focus} $I(combo-button-focus) \ + {readonly focus} $I(combo-button-hover) \ + {readonly hover} $I(combo-button-hover) + ] -border 5 -padding {2 6 6 6} + + ttk::style element create Combobox.arrow image $I(down) \ + -width 15 -sticky e + + # Spinbox + ttk::style element create Spinbox.field \ + image [list $I(box-basic) \ + invalid $I(box-invalid) \ + disabled $I(box-basic) \ + focus $I(box-accent) \ + hover $I(box-hover) \ + ] -border 5 -padding {8} -sticky news + + ttk::style element create Spinbox.uparrow \ + image [list $I(up) \ + disabled $I(up) \ + pressed $I(up-accent) \ + active $I(up-accent) \ + ] -border 4 -width 15 -sticky e + + ttk::style element create Spinbox.downarrow \ + image [list $I(down) \ + disabled $I(down) \ + pressed $I(down-accent) \ + active $I(down-accent) \ + ] -border 4 -width 15 -sticky e + + ttk::style element create Spinbox.button \ + image [list $I(combo-button-basic) \ + {!readonly focus} $I(combo-button-focus) \ + {readonly focus} $I(combo-button-hover) \ + {readonly hover} $I(combo-button-hover) + ] -border 5 -padding {2 6 6 6} + + # Sizegrip + ttk::style element create Sizegrip.sizegrip image $I(size) \ + -sticky ewns + + # Separator + ttk::style element create Horizontal.separator image $I(separator) + + ttk::style element create Vertical.separator image $I(separator) + + # Card + ttk::style element create Card.field image $I(card) \ + -border 10 -padding 4 -sticky news + + # Labelframe + ttk::style element create Labelframe.border image $I(card) \ + -border 5 -padding 4 -sticky news + + # Notebook + ttk::style element create Notebook.client \ + image $I(notebook) -border 5 + + ttk::style element create Notebook.tab \ + image [list $I(tab-disabled) \ + selected $I(tab-basic) \ + active $I(tab-hover) \ + ] -border 5 -padding {14 4} + + # Treeview + ttk::style element create Treeview.field image $I(card) \ + -border 5 + + ttk::style element create Treeheading.cell \ + image [list $I(tree-basic) \ + pressed $I(tree-pressed) + ] -border 5 -padding 4 -sticky ewns + + ttk::style element create Treeitem.indicator \ + image [list $I(right) \ + user2 $I(empty) \ + user1 $I(down) \ + ] -width 26 -sticky {} + + ttk::style configure Treeview -background $colors(-bg) + ttk::style configure Treeview.Item -padding {2 0 0 0} + ttk::style map Treeview \ + -background [list selected #ccc] \ + -foreground [list selected $colors(-fg)] + + # Panedwindow + # Insane hack to remove clam's ugly sash + ttk::style configure Sash -gripcount 0 + } +} diff --git a/theme/light/box-accent.png b/theme/light/box-accent.png new file mode 100644 index 0000000..89f1faf Binary files /dev/null and b/theme/light/box-accent.png differ diff --git a/theme/light/box-basic.png b/theme/light/box-basic.png new file mode 100644 index 0000000..090a00b Binary files /dev/null and b/theme/light/box-basic.png differ diff --git a/theme/light/box-hover.png b/theme/light/box-hover.png new file mode 100644 index 0000000..e691da4 Binary files /dev/null and b/theme/light/box-hover.png differ diff --git a/theme/light/box-invalid.png b/theme/light/box-invalid.png new file mode 100644 index 0000000..1f16f5c Binary files /dev/null and b/theme/light/box-invalid.png differ diff --git a/theme/light/button-hover.png b/theme/light/button-hover.png new file mode 100644 index 0000000..13366eb Binary files /dev/null and b/theme/light/button-hover.png differ diff --git a/theme/light/card.png b/theme/light/card.png new file mode 100644 index 0000000..09152f5 Binary files /dev/null and b/theme/light/card.png differ diff --git a/theme/light/check-accent.png b/theme/light/check-accent.png new file mode 100644 index 0000000..4aea79b Binary files /dev/null and b/theme/light/check-accent.png differ diff --git a/theme/light/check-basic.png b/theme/light/check-basic.png new file mode 100644 index 0000000..0c00612 Binary files /dev/null and b/theme/light/check-basic.png differ diff --git a/theme/light/check-hover.png b/theme/light/check-hover.png new file mode 100644 index 0000000..3811696 Binary files /dev/null and b/theme/light/check-hover.png differ diff --git a/theme/light/check-tri-accent.png b/theme/light/check-tri-accent.png new file mode 100644 index 0000000..d6baad5 Binary files /dev/null and b/theme/light/check-tri-accent.png differ diff --git a/theme/light/check-tri-basic.png b/theme/light/check-tri-basic.png new file mode 100644 index 0000000..e92bea5 Binary files /dev/null and b/theme/light/check-tri-basic.png differ diff --git a/theme/light/check-tri-hover.png b/theme/light/check-tri-hover.png new file mode 100644 index 0000000..d611d76 Binary files /dev/null and b/theme/light/check-tri-hover.png differ diff --git a/theme/light/circle-accent.png b/theme/light/circle-accent.png new file mode 100644 index 0000000..ea76e7a Binary files /dev/null and b/theme/light/circle-accent.png differ diff --git a/theme/light/circle-basic.png b/theme/light/circle-basic.png new file mode 100644 index 0000000..b16202e Binary files /dev/null and b/theme/light/circle-basic.png differ diff --git a/theme/light/circle-hover.png b/theme/light/circle-hover.png new file mode 100644 index 0000000..6ea1803 Binary files /dev/null and b/theme/light/circle-hover.png differ diff --git a/theme/light/combo-button-basic.png b/theme/light/combo-button-basic.png new file mode 100644 index 0000000..b7daa04 Binary files /dev/null and b/theme/light/combo-button-basic.png differ diff --git a/theme/light/combo-button-focus.png b/theme/light/combo-button-focus.png new file mode 100644 index 0000000..59c7db4 Binary files /dev/null and b/theme/light/combo-button-focus.png differ diff --git a/theme/light/combo-button-hover.png b/theme/light/combo-button-hover.png new file mode 100644 index 0000000..1d06c57 Binary files /dev/null and b/theme/light/combo-button-hover.png differ diff --git a/theme/light/down-accent.png b/theme/light/down-accent.png new file mode 100644 index 0000000..5bb987d Binary files /dev/null and b/theme/light/down-accent.png differ diff --git a/theme/light/down.png b/theme/light/down.png new file mode 100644 index 0000000..1fd7e4f Binary files /dev/null and b/theme/light/down.png differ diff --git a/theme/light/empty.png b/theme/light/empty.png new file mode 100644 index 0000000..202e3de Binary files /dev/null and b/theme/light/empty.png differ diff --git a/theme/light/hor-accent.png b/theme/light/hor-accent.png new file mode 100644 index 0000000..145b10e Binary files /dev/null and b/theme/light/hor-accent.png differ diff --git a/theme/light/hor-basic.png b/theme/light/hor-basic.png new file mode 100644 index 0000000..eb18d1e Binary files /dev/null and b/theme/light/hor-basic.png differ diff --git a/theme/light/hor-hover.png b/theme/light/hor-hover.png new file mode 100644 index 0000000..4d6c0f1 Binary files /dev/null and b/theme/light/hor-hover.png differ diff --git a/theme/light/notebook.png b/theme/light/notebook.png new file mode 100644 index 0000000..430d9f2 Binary files /dev/null and b/theme/light/notebook.png differ diff --git a/theme/light/off-basic.png b/theme/light/off-basic.png new file mode 100644 index 0000000..cf383f0 Binary files /dev/null and b/theme/light/off-basic.png differ diff --git a/theme/light/off-hover.png b/theme/light/off-hover.png new file mode 100644 index 0000000..893b39c Binary files /dev/null and b/theme/light/off-hover.png differ diff --git a/theme/light/on-accent.png b/theme/light/on-accent.png new file mode 100644 index 0000000..f5a86c9 Binary files /dev/null and b/theme/light/on-accent.png differ diff --git a/theme/light/on-basic.png b/theme/light/on-basic.png new file mode 100644 index 0000000..23ec72f Binary files /dev/null and b/theme/light/on-basic.png differ diff --git a/theme/light/on-hover.png b/theme/light/on-hover.png new file mode 100644 index 0000000..d55f7ae Binary files /dev/null and b/theme/light/on-hover.png differ diff --git a/theme/light/outline-basic.png b/theme/light/outline-basic.png new file mode 100644 index 0000000..2e79874 Binary files /dev/null and b/theme/light/outline-basic.png differ diff --git a/theme/light/outline-hover.png b/theme/light/outline-hover.png new file mode 100644 index 0000000..502915d Binary files /dev/null and b/theme/light/outline-hover.png differ diff --git a/theme/light/radio-accent.png b/theme/light/radio-accent.png new file mode 100644 index 0000000..1f7329d Binary files /dev/null and b/theme/light/radio-accent.png differ diff --git a/theme/light/radio-basic.png b/theme/light/radio-basic.png new file mode 100644 index 0000000..793531e Binary files /dev/null and b/theme/light/radio-basic.png differ diff --git a/theme/light/radio-hover.png b/theme/light/radio-hover.png new file mode 100644 index 0000000..d6faa74 Binary files /dev/null and b/theme/light/radio-hover.png differ diff --git a/theme/light/radio-tri-accent.png b/theme/light/radio-tri-accent.png new file mode 100644 index 0000000..86dd4cb Binary files /dev/null and b/theme/light/radio-tri-accent.png differ diff --git a/theme/light/radio-tri-basic.png b/theme/light/radio-tri-basic.png new file mode 100644 index 0000000..da85d03 Binary files /dev/null and b/theme/light/radio-tri-basic.png differ diff --git a/theme/light/radio-tri-hover.png b/theme/light/radio-tri-hover.png new file mode 100644 index 0000000..ded14a6 Binary files /dev/null and b/theme/light/radio-tri-hover.png differ diff --git a/theme/light/rect-accent-hover.png b/theme/light/rect-accent-hover.png new file mode 100644 index 0000000..5daa96a Binary files /dev/null and b/theme/light/rect-accent-hover.png differ diff --git a/theme/light/rect-accent.png b/theme/light/rect-accent.png new file mode 100644 index 0000000..2d08674 Binary files /dev/null and b/theme/light/rect-accent.png differ diff --git a/theme/light/rect-basic.png b/theme/light/rect-basic.png new file mode 100644 index 0000000..239ca31 Binary files /dev/null and b/theme/light/rect-basic.png differ diff --git a/theme/light/rect-hover.png b/theme/light/rect-hover.png new file mode 100644 index 0000000..9252c4f Binary files /dev/null and b/theme/light/rect-hover.png differ diff --git a/theme/light/right.png b/theme/light/right.png new file mode 100644 index 0000000..8122cc9 Binary files /dev/null and b/theme/light/right.png differ diff --git a/theme/light/scale-hor.png b/theme/light/scale-hor.png new file mode 100644 index 0000000..d11f508 Binary files /dev/null and b/theme/light/scale-hor.png differ diff --git a/theme/light/scale-vert.png b/theme/light/scale-vert.png new file mode 100644 index 0000000..f78595d Binary files /dev/null and b/theme/light/scale-vert.png differ diff --git a/theme/light/separator.png b/theme/light/separator.png new file mode 100644 index 0000000..7bffc9a Binary files /dev/null and b/theme/light/separator.png differ diff --git a/theme/light/size.png b/theme/light/size.png new file mode 100644 index 0000000..bde3ade Binary files /dev/null and b/theme/light/size.png differ diff --git a/theme/light/tab-basic.png b/theme/light/tab-basic.png new file mode 100644 index 0000000..365fdff Binary files /dev/null and b/theme/light/tab-basic.png differ diff --git a/theme/light/tab-disabled.png b/theme/light/tab-disabled.png new file mode 100644 index 0000000..eeee518 Binary files /dev/null and b/theme/light/tab-disabled.png differ diff --git a/theme/light/tab-hover.png b/theme/light/tab-hover.png new file mode 100644 index 0000000..5003806 Binary files /dev/null and b/theme/light/tab-hover.png differ diff --git a/theme/light/tick-hor-accent.png b/theme/light/tick-hor-accent.png new file mode 100644 index 0000000..6940b1c Binary files /dev/null and b/theme/light/tick-hor-accent.png differ diff --git a/theme/light/tick-hor-basic.png b/theme/light/tick-hor-basic.png new file mode 100644 index 0000000..ba727d7 Binary files /dev/null and b/theme/light/tick-hor-basic.png differ diff --git a/theme/light/tick-hor-hover.png b/theme/light/tick-hor-hover.png new file mode 100644 index 0000000..cb66b59 Binary files /dev/null and b/theme/light/tick-hor-hover.png differ diff --git a/theme/light/tick-vert-accent.png b/theme/light/tick-vert-accent.png new file mode 100644 index 0000000..dfdb89c Binary files /dev/null and b/theme/light/tick-vert-accent.png differ diff --git a/theme/light/tick-vert-basic.png b/theme/light/tick-vert-basic.png new file mode 100644 index 0000000..a58440d Binary files /dev/null and b/theme/light/tick-vert-basic.png differ diff --git a/theme/light/tick-vert-hover.png b/theme/light/tick-vert-hover.png new file mode 100644 index 0000000..18cbec5 Binary files /dev/null and b/theme/light/tick-vert-hover.png differ diff --git a/theme/light/tree-basic.png b/theme/light/tree-basic.png new file mode 100644 index 0000000..755062b Binary files /dev/null and b/theme/light/tree-basic.png differ diff --git a/theme/light/tree-pressed.png b/theme/light/tree-pressed.png new file mode 100644 index 0000000..ee28416 Binary files /dev/null and b/theme/light/tree-pressed.png differ diff --git a/theme/light/up-accent.png b/theme/light/up-accent.png new file mode 100644 index 0000000..54a20f8 Binary files /dev/null and b/theme/light/up-accent.png differ diff --git a/theme/light/up.png b/theme/light/up.png new file mode 100644 index 0000000..16568f2 Binary files /dev/null and b/theme/light/up.png differ diff --git a/theme/light/vert-accent.png b/theme/light/vert-accent.png new file mode 100644 index 0000000..7f87bdc Binary files /dev/null and b/theme/light/vert-accent.png differ diff --git a/theme/light/vert-basic.png b/theme/light/vert-basic.png new file mode 100644 index 0000000..d5f61ec Binary files /dev/null and b/theme/light/vert-basic.png differ diff --git a/theme/light/vert-hover.png b/theme/light/vert-hover.png new file mode 100644 index 0000000..bfdc9d0 Binary files /dev/null and b/theme/light/vert-hover.png differ