From acbdb8d4f244e469882fcd269ed463b9af4eb696 Mon Sep 17 00:00:00 2001 From: deajan Date: Tue, 21 Oct 2025 11:29:06 +0200 Subject: [PATCH] GUI: WIP wizard --- npbackup/gui/__main__.py | 4 +- npbackup/gui/buttons.py | 95 +++++++ npbackup/gui/config.py | 27 +- npbackup/gui/constants.py | 47 ++++ npbackup/gui/helpers.py | 7 +- npbackup/gui/wizard.py | 359 ++++++++++++++++++++++++ npbackup/translations/config_gui.en.yml | 1 + npbackup/translations/config_gui.fr.yml | 1 + npbackup/translations/generic.en.yml | 4 + npbackup/translations/generic.fr.yml | 4 + npbackup/translations/wizard_gui.en.yml | 11 + npbackup/translations/wizard_gui.fr.yml | 11 + resources/customization.py | 19 +- resources/update_custom_resources.py | 1 + 14 files changed, 554 insertions(+), 37 deletions(-) create mode 100644 npbackup/gui/buttons.py create mode 100644 npbackup/gui/constants.py create mode 100644 npbackup/gui/wizard.py create mode 100644 npbackup/translations/wizard_gui.en.yml create mode 100644 npbackup/translations/wizard_gui.fr.yml diff --git a/npbackup/gui/__main__.py b/npbackup/gui/__main__.py index 5c4961a..5d1e0e6 100644 --- a/npbackup/gui/__main__.py +++ b/npbackup/gui/__main__.py @@ -31,6 +31,7 @@ import _tkinter import npbackup.configuration import npbackup.common from resources.customization import ( + LOOK_AND_FEEL_TABLE, OEM_STRING, OEM_LOGO, BG_COLOR_LDR, @@ -71,7 +72,8 @@ __repo_aware_concurrency = False # Also prevents showing errors when config was just changed GUI_STATUS_IGNORE_ERRORS = True - +sg.LOOK_AND_FEEL_TABLE["CLEAR"] = LOOK_AND_FEEL_TABLE["CLEAR"] +sg.LOOK_AND_FEEL_TABLE["DARK"] = LOOK_AND_FEEL_TABLE["DARK"] sg.theme(SIMPLEGUI_THEME) sg.SetOptions(icon=OEM_ICON) diff --git a/npbackup/gui/buttons.py b/npbackup/gui/buttons.py new file mode 100644 index 0000000..551cb4f --- /dev/null +++ b/npbackup/gui/buttons.py @@ -0,0 +1,95 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# +# This file is part of npbackup + +__intname__ = "npbackup.gui.buttons" +__author__ = "Orsiris de Jong" +__copyright__ = "Copyright (C) 2023-2025 NetInvent" +__license__ = "GPL-3.0-only" +__build__ = "2025102101" + + +from PIL import Image, ImageDraw +import FreeSimpleGUI as sg + + +def backgroundPNG(MAX_W, MAX_H, backgroundColor=None): + background = Image.new("RGBA", (MAX_W, MAX_H), color=backgroundColor) + draw = ImageDraw.Draw(background) + + return [background, draw] + +def roundCorners(im, rad): + """ + Rounds the corners of an image to given radius + """ + mask = Image.new("L", im.size) + if rad > min(*im.size) // 2: + rad = min(*im.size) // 2 + draw = ImageDraw.Draw(mask) + + draw.ellipse((0, 0, rad * 2, rad * 2), fill=255) + draw.ellipse((0, im.height - rad * 2 -2, rad * 2, im.height-1) , fill=255) + draw.ellipse((im.width - rad * 2, 1, im.width, rad * 2), fill=255) + draw.ellipse( + (im.width - rad * 2, im.height - rad * 2, im.width-1, im.height-1), fill=255 + ) + draw.rectangle([rad, 0, im.width - rad, im.height], fill=255) + draw.rectangle([0, rad, im.width, im.height - rad], fill=255) + + mask = superSample(mask, 8) + im.putalpha(mask) + + return im + +def superSample(image, sample): + """ + Supersample an image for better edges + image: image object + sample: sampling multiplicator int(suggested: 2, 4, 8) + """ + w, h = image.size + + image = image.resize((int(w * sample), int(h * sample)), resample=Image.LANCZOS) + image = image.resize((image.width // sample, image.height // sample), resample=Image.LANCZOS) + + return image + +def image_to_data(im): + """ + This is for Pysimplegui library + Converts image into data to be used inside GUIs + """ + from io import BytesIO + + with BytesIO() as output: + im.save(output, format="PNG") + data = output.getvalue() + return data + +def RoundedButton(button_text=' ', corner_radius=0, button_type=sg.BUTTON_TYPE_READ_FORM, target=(None, None), + tooltip=None, file_types=sg.FILE_TYPES_ALL_FILES, initial_folder=None, default_extension='', + disabled=False, change_submits=False, enable_events=False, + image_size=(None, None), image_subsample=None, border_width=None, size=(None, None), + auto_size_button=None, button_color=None, disabled_button_color=None, highlight_colors=None, + mouseover_colors=(None, None), use_ttk_buttons=None, font=None, bind_return_key=False, focus=False, + pad=None, key=None, right_click_menu=None, expand_x=False, expand_y=False, visible=True, + metadata=None): + + button_img = backgroundPNG(50*5, 50*5, button_color[1]) + button_img[0] = roundCorners(button_img[0], 30*5) + button_img[0] = button_img[0].resize((50, 50), resample=Image.LANCZOS) + btn_img = image_to_data(button_img[0]) + if button_color is None: + button_color = sg.theme_button_color() + return sg.Button(button_text=button_text, button_type=button_type, target=target, tooltip=tooltip, + file_types=file_types, initial_folder=initial_folder, default_extension=default_extension, + disabled=disabled, change_submits=change_submits, enable_events=enable_events, + image_data=btn_img, image_size=image_size, + image_subsample=image_subsample, border_width=border_width, size=size, + auto_size_button=auto_size_button, button_color=(button_color[0], sg.theme_background_color()), + disabled_button_color=disabled_button_color, highlight_colors=highlight_colors, + mouseover_colors=mouseover_colors, use_ttk_buttons=use_ttk_buttons, font=font, + bind_return_key=bind_return_key, focus=focus, pad=pad, key=key, right_click_menu=right_click_menu, + expand_x=expand_x, expand_y=expand_y, visible=visible, metadata=metadata) \ No newline at end of file diff --git a/npbackup/gui/config.py b/npbackup/gui/config.py index ae0236b..4fc0b57 100644 --- a/npbackup/gui/config.py +++ b/npbackup/gui/config.py @@ -40,6 +40,7 @@ from resources.customization import ( ) from npbackup.task import create_scheduled_task from npbackup.gui.helpers import quick_close_simplegui_window +from npbackup.gui.constants import combo_boxes, byte_units logger = getLogger() @@ -94,33 +95,7 @@ def config_gui(full_config: dict, config_file: str): suppress_key_guessing=True, ) - combo_boxes = { - "repo_opts.compression": { - "auto": _t("config_gui.auto"), - "max": _t("config_gui.max"), - "off": _t("config_gui.off"), - }, - "backup_opts.source_type": { - "folder_list": _t("config_gui.folder_list"), - "files_from": _t("config_gui.files_from"), - "files_from_verbatim": _t("config_gui.files_from_verbatim"), - "files_from_raw": _t("config_gui.files_from_raw"), - "stdin_from_command": _t("config_gui.stdin_from_command"), - }, - "backup_opts.priority": { - "low": _t("config_gui.low"), - "normal": _t("config_gui.normal"), - "high": _t("config_gui.high"), - }, - "permissions": { - "backup": _t("config_gui.backup_perms"), - "restore": _t("config_gui.restore_perms"), - "restore_only": _t("config_gui.restore_only_perms"), - "full": _t("config_gui.full_perms"), - }, - } - byte_units = ["B", "KB", "KiB", "MB", "MiB", "GB", "GiB", "TB", "TiB", "PB", "PiB"] def get_objects() -> List[str]: """ diff --git a/npbackup/gui/constants.py b/npbackup/gui/constants.py new file mode 100644 index 0000000..3af399a --- /dev/null +++ b/npbackup/gui/constants.py @@ -0,0 +1,47 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# +# This file is part of npbackup + +__intname__ = "npbackup.gui.constants" +__author__ = "Orsiris de Jong" +__copyright__ = "Copyright (C) 2023-2025 NetInvent" +__license__ = "GPL-3.0-only" +__build__ = "2025102101" + + +from npbackup.core.i18n_helper import _t + + +combo_boxes = { + "repo_opts.compression": { + "auto": _t("config_gui.auto"), + "max": _t("config_gui.max"), + "off": _t("config_gui.off"), + }, + "backup_opts.source_type": { + "folder_list": _t("config_gui.folder_list"), + "files_from": _t("config_gui.files_from"), + "files_from_verbatim": _t("config_gui.files_from_verbatim"), + "files_from_raw": _t("config_gui.files_from_raw"), + "stdin_from_command": _t("config_gui.stdin_from_command"), + }, + "backup_opts.priority": { + "low": _t("config_gui.low"), + "normal": _t("config_gui.normal"), + "high": _t("config_gui.high"), + }, + "permissions": { + "backup": _t("config_gui.backup_perms"), + "restore": _t("config_gui.restore_perms"), + "restore_only": _t("config_gui.restore_only_perms"), + "full": _t("config_gui.full_perms"), + }, + "retention_options": { + "GFS": _t("wizard_gui.retention_gfs"), + "30days": _t("wizard_gui.retention_30days"), + "keep_all": _t("wizard_gui.retention_keep_all"), + }, +} + +byte_units = ["B", "KB", "KiB", "MB", "MiB", "GB", "GiB", "TB", "TiB", "PB", "PiB"] diff --git a/npbackup/gui/helpers.py b/npbackup/gui/helpers.py index 5d7e78c..56b49d1 100644 --- a/npbackup/gui/helpers.py +++ b/npbackup/gui/helpers.py @@ -7,7 +7,7 @@ __intname__ = "npbackup.gui.helpers" __author__ = "Orsiris de Jong" __copyright__ = "Copyright (C) 2023-2025 NetInvent" __license__ = "GPL-3.0-only" -__build__ = "2025070302" +__build__ = "2025102101" from typing import Tuple, Union @@ -29,11 +29,12 @@ from resources.customization import ( from npbackup.core.runner import NPBackupRunner from npbackup.__debug__ import _DEBUG from npbackup.__env__ import GUI_CHECK_INTERVAL -from resources.customization import SIMPLEGUI_THEME, OEM_ICON +from resources.customization import SIMPLEGUI_THEME, OEM_ICON, LOOK_AND_FEEL_TABLE logger = getLogger() - +sg.LOOK_AND_FEEL_TABLE["CLEAR"] = LOOK_AND_FEEL_TABLE["CLEAR"] +sg.LOOK_AND_FEEL_TABLE["DARK"] = LOOK_AND_FEEL_TABLE["DARK"] sg.theme(SIMPLEGUI_THEME) sg.SetOptions(icon=OEM_ICON) diff --git a/npbackup/gui/wizard.py b/npbackup/gui/wizard.py new file mode 100644 index 0000000..c68ca5d --- /dev/null +++ b/npbackup/gui/wizard.py @@ -0,0 +1,359 @@ +#! /usr/bin/env python +# -*- coding: utf-8 -*- +# +# This file is part of npbackup + +__intname__ = "npbackup.gui.wizard" +__author__ = "Orsiris de Jong" +__copyright__ = "Copyright (C) 2022-2025 NetInvent" +__license__ = "GPL-3.0-only" + + +from typing import List, Optional, Tuple +import sys +import os +import re +import gc +import textwrap +from argparse import ArgumentParser +from pathlib import Path +from logging import getLogger +import ofunctions.logger_utils +from datetime import datetime, timezone +import dateutil +from time import sleep +from ruamel.yaml.comments import CommentedMap +import atexit +from ofunctions.process import kill_childs +from ofunctions.threading import threaded +from ofunctions.misc import BytesConverter +import FreeSimpleGUI as sg +from psg_reskinner import animated_reskin, reskin +import _tkinter +import npbackup.configuration +import npbackup.common +from resources.customization import ( + LOOK_AND_FEEL_TABLE, + OEM_STRING, + OEM_LOGO, + BG_COLOR_LDR, + TXT_COLOR_LDR, + GUI_STATE_OK_BUTTON, + GUI_STATE_OLD_BUTTON, + GUI_STATE_UNKNOWN_BUTTON, + LOADER_ANIMATION, + FOLDER_ICON, + FILE_ICON, + SYMLINK_ICON, + IRREGULAR_FILE_ICON, + LICENSE_TEXT, + SIMPLEGUI_THEME, + SIMPLEGUI_DARK_THEME, + OEM_ICON, + SHORT_PRODUCT_NAME, + THEME_CHOOSER_ICON, + # WIZARD + ADD_FOLDER, + ADD_FILE, + ADD_PROPERTY, + REMOVE_PROPERTY, + HYPERV, + KVM, + WINDOWS_SYSTEM, + BACKEND_LOCAL, + BACKEND_SFTP, + BACKEND_B2, + BACKEND_S3, + BACKEND_REST, + BACKEND_WASABI, + BACKEND_GOOGLE, + BACKEND_AZURE +) +from npbackup.gui.config import config_gui, ask_manager_password +from npbackup.gui.operations import operations_gui +from npbackup.gui.helpers import get_anon_repo_uri, gui_thread_runner, HideWindow +from npbackup.gui.handle_window import handle_current_window +from npbackup.gui.constants import combo_boxes, byte_units +from npbackup.core.i18n_helper import _t +from npbackup.core import upgrade_runner +from npbackup.path_helper import CURRENT_DIR +from npbackup.__version__ import version_dict, version_string +from npbackup.__debug__ import _DEBUG, _NPBACKUP_ALLOW_AUTOUPGRADE_DEBUG +from npbackup.restic_wrapper import ResticRunner +from npbackup.restic_wrapper import schema +from npbackup.gui.buttons import RoundedButton + +sg.LOOK_AND_FEEL_TABLE["CLEAR"] = LOOK_AND_FEEL_TABLE["CLEAR"] +sg.LOOK_AND_FEEL_TABLE["DARK"] = LOOK_AND_FEEL_TABLE["DARK"] +sg.theme(SIMPLEGUI_THEME) +logger = getLogger() + + +wizard_layout_1 = [ + [sg.Text(_t("wizard_gui.welcome", font=("Helvetica", 16)))], + [sg.Push()], + [sg.Text(_t("wizard_gui.welcome_description"))], + ] + +wizard_layout_2 = [ + [ + sg.Text( + textwrap.fill(f"{_t('wizard_gui.select_backup_sources')}", 70), + size=(None, None), + expand_x=True, + justification='c', + ), + ], + [ + sg.Input(visible=False, key="--ADD-PATHS-FILE--", enable_events=True), + sg.FilesBrowse( + "", # _t("generic.add_files" + target="--ADD-PATHS-FILE--", + key="--ADD-PATHS-FILE-BUTTON--", + image_data=ADD_FILE, + border_width=0, + #button_color=(None, sg.LOOK_AND_FEEL_TABLE[SIMPLEGUI_THEME]["BACKGROUND"]) + ), + sg.Input(visible=False, key="--ADD-PATHS-FOLDER--", enable_events=True), + sg.FolderBrowse( + "", # _t("generic.add_folder"), + target="--ADD-PATHS-FOLDER--", + key="--ADD-PATHS-FOLDER-BUTTON--", + image_data=ADD_FOLDER, + border_width=0, + #button_color=(None, sg.LOOK_AND_FEEL_TABLE[SIMPLEGUI_THEME]["BACKGROUND"]) + ), + sg.Button( + "", # _t("generic.add_manually"), + key="--ADD-PATHS-MANUALLY--", + image_source=ADD_PROPERTY, + border_width=0, + #button_color=(None, sg.LOOK_AND_FEEL_TABLE[SIMPLEGUI_THEME]["BACKGROUND"]) + ), + sg.Button( + "", # _t("generic.remove_selected"), + key="--REMOVE-PATHS--", + image_data=REMOVE_PROPERTY, + border_width=0, + #button_color=(None, sg.LOOK_AND_FEEL_TABLE[SIMPLEGUI_THEME]["BACKGROUND"]) + ), + sg.Button( + "", + image_data=WINDOWS_SYSTEM, + key="-ADD-WINDOWS-SYSTEM-", + border_width=0, + ), + sg.Button( + "", + image_data=HYPERV, + key="-ADD-HYPERV-", + border_width=0, + ), + sg.Button( + "", + image_data=KVM, + key="-ADD-KVM-", + border_width=0, + ), + ], + [ + sg.Tree( + sg.TreeData(), + key="backup_opts.paths", + headings=[], + col0_heading=_t("config_gui.backup_sources"), + expand_x=True, + expand_y=True, + header_text_color=TXT_COLOR_LDR, + header_background_color=BG_COLOR_LDR, + ) + ], + ] + +wizard_layout_3 = [ + [ + sg.Text(_t("wizard_gui.backup_location", font=("Helvetica", 16))) + ], + [ + sg.Input(visible=False, key="--ADD-DESTINATION-FOLDER--", enable_events=True), + sg.FolderBrowse("", image_data=BACKEND_LOCAL, key="-BACKEND-LOCAL", border_width=0, target="--ADD-DESTINATION-FOLDER--"), + sg.Button(image_data=BACKEND_SFTP, key="-BACKEND-SFTP", border_width=0), + sg.Button(image_data=BACKEND_B2, key="-BACKEND-B2", border_width=0), + sg.Button(image_data=BACKEND_S3, key="-BACKEND-S3", border_width=0), + ], + [ + sg.Text(" HDD "), + sg.Text(" SFTP "), + sg.Text(" B2 "), + sg.Text(" S3 "), + ], + [ + sg.Button(image_data=BACKEND_REST, key="-BACKEND-REST", border_width=0), + sg.Button(image_data=BACKEND_GOOGLE, key="-BACKEND-GOOGLE", border_width=0), + sg.Button(image_data=BACKEND_AZURE, key="-BACKEND-AZURE", border_width=0), + sg.Button(image_data=BACKEND_WASABI, key="-BACKEND-WASABI", border_width=0), + ], + [ + sg.Text(" REST "), + sg.Text(" Google "), + sg.Text(" Azure "), + sg.Text(" Wasabi ") + ] +] +wizard_layout_4 = [ + [ + sg.Column( + [ + [ + sg.Column( + [ + [ + sg.Button( + "+", key="--ADD-BACKUP-TAG--", size=(3, 1) + ) + ], + [ + sg.Button( + "-", + key="--REMOVE-BACKUP-TAG--", + size=(3, 1), + ) + ], + ], + pad=0, + size=(40, 80), + ), + sg.Column( + [ + [ + sg.Tree( + sg.TreeData(), + key="backup_opts.tags", + headings=[], + col0_heading="Tags", + col0_width=30, + num_rows=3, + expand_x=True, + expand_y=True, + ) + ] + ], + pad=0, + size=(300, 80), + ), + ], + ], + pad=0, + ), + ], + +] +wizard_layout_5 = [ + [ + sg.T(_t("wizard_gui.retention_settings"), font=("Helvetica", 16)) + ], + [sg.Combo(values=list(combo_boxes["retention_options"].values()), default_value=next(iter(combo_boxes["retention_options"])), key="-RETENTION-TYPE-", enable_events=True)], +] + +wizard_layout_6 = [ + [ + sg.Text(_t("wizard_gui.end_user_experience", font=("Helvetica", 16))) + ], + [ + sg.Checkbox(_t("wizard_gui.disable_config_button"), key="-DISABLE-CONFIG-BUTTON-", default=True) + ] +] + +wizard_layout_7 = [ + [sg.Text(_t("wizard_gui.end_user_experience", font=("Helvetica", 16)))], +] + + +wizard_breadcrumbs = [ + [RoundedButton('1', button_color=("#FAFAFA", "#ADADAD"), border_width=0, key='-BREADCRUMB-1-')], + [RoundedButton('2', button_color=("#FAFAFA", "#ADADAD"), border_width=0, key='-BREADCRUMB-2-')], + [RoundedButton('3', button_color=("#FAFAFA", "#ADADAD"), border_width=0, key='-BREADCRUMB-3-')], + [RoundedButton('4', button_color=("#FAFAFA", "#ADADAD"), border_width=0, key='-BREADCRUMB-4-')], + [RoundedButton('5', button_color=("#FAFAFA", "#ADADAD"), border_width=0, key='-BREADCRUMB-5-')], + [RoundedButton('6', button_color=("#FAFAFA", "#ADADAD"), border_width=0, key='-BREADCRUMB-6-')], + [RoundedButton('7', button_color=("#FAFAFA", "#ADADAD"), border_width=0, key='-BREADCRUMB-7-')], + +] + +wizard_tabs = [ + sg.Column(wizard_layout_1, element_justification='c', key='-TAB1-'), + sg.Column(wizard_layout_2, element_justification='c', key='-TAB2-'), + sg.Column(wizard_layout_3, element_justification='c', key='-TAB3-'), + sg.Column(wizard_layout_4, element_justification='c', key='-TAB4-'), + sg.Column(wizard_layout_5, element_justification='c', key='-TAB5-'), + sg.Column(wizard_layout_6, element_justification='c', key='-TAB6-'), + sg.Column(wizard_layout_7, element_justification='c', key='-TAB7-'), +] + +wizard_layout = [ + [sg.Push(), sg.Image(source=THEME_CHOOSER_ICON, key="-THEME-",enable_events=True)], + [sg.Column(wizard_breadcrumbs, element_justification="L"), sg.Column([wizard_tabs], expand_x=True, expand_y=True)], + [sg.Button(_t("generic.cancel"), key="-PREVIOUS-"), sg.Button(_t("generic.start"), key="-NEXT-")] +] + +def start_wizard(): + CURRENT_THEME = SIMPLEGUI_THEME + NUMBER_OF_TABS = len(wizard_tabs) + current_tab = 1 + wizard = sg.Window("NPBackup Wizard", + layout=wizard_layout, + size=(800, 500), + element_justification='c',) + + def _reskin_job(): + nonlocal CURRENT_THEME + animated_reskin( + window=wizard, + new_theme=CURRENT_THEME, + theme_function=sg.theme, + lf_table=LOOK_AND_FEEL_TABLE, + ) + wizard.TKroot.after(60000, _reskin_job) + while True: + event, values = wizard.read() + if event == sg.WIN_CLOSED or event == _t("generic.cancel"): + break + if event == "-THEME-": + if CURRENT_THEME != "DARK": + CURRENT_THEME = "DARK" + else: + CURRENT_THEME = "CLEAR" + _reskin_job() + continue + if event == "-NEXT-": + if current_tab < NUMBER_OF_TABS: + current_tab += 1 + wizard["-NEXT-"].update(_t("generic.finish") if current_tab == NUMBER_OF_TABS else _t("generic.next")) + wizard["-PREVIOUS-"].update(_t("generic.cancel") if current_tab == 1 else _t("generic.previous")) + for tab_index in range(1, NUMBER_OF_TABS + 1): + if tab_index != current_tab: + wizard[f"-TAB{tab_index}-"].Update(visible=False) + wizard[f"-BREADCRUMB-{tab_index}-"].Update(button_color=("#FAFAFA", None)) + wizard[f"-TAB{current_tab}-"].Update(visible=True) + wizard[f"-BREADCRUMB-{current_tab}-"].Update(button_color=("#3F2DCB", None)) + elif current_tab == NUMBER_OF_TABS: + sg.popup(_t("wizard_gui.thank_you"), keep_on_top=True) + break + if event == "-PREVIOUS-": + if current_tab > 1: + current_tab -= 1 + wizard["-NEXT-"].update(_t("generic.finish") if current_tab == NUMBER_OF_TABS else _t("generic.next")) + wizard["-PREVIOUS-"].update(_t("generic.cancel") if current_tab == 1 else _t("generic.previous")) + for tab_index in range(1, NUMBER_OF_TABS + 1): + if tab_index != current_tab: + wizard[f"-TAB{tab_index}-"].Update(visible=False) + wizard[f"-BREADCRUMB-{tab_index}-"].Update(button_color=("#FAFAFA", None)) + wizard[f"-TAB{current_tab}-"].Update(visible=True) + wizard[f"-BREADCRUMB-{current_tab}-"].Update(button_color=("#3F2DCB", None)) + elif current_tab == 1: + break + wizard.close() + + + +start_wizard() \ No newline at end of file diff --git a/npbackup/translations/config_gui.en.yml b/npbackup/translations/config_gui.en.yml index e7a3b2e..6f15543 100644 --- a/npbackup/translations/config_gui.en.yml +++ b/npbackup/translations/config_gui.en.yml @@ -8,6 +8,7 @@ en: encrypted_data: Encrypted_Data compression: Compression backup_paths: Backup paths + backup_sources: Backup sources use_fs_snapshot: Use VSS snapshots ignore_cloud_files: Ignore in-cloud files windows_only: Windows only diff --git a/npbackup/translations/config_gui.fr.yml b/npbackup/translations/config_gui.fr.yml index e1ab7c4..080b430 100644 --- a/npbackup/translations/config_gui.fr.yml +++ b/npbackup/translations/config_gui.fr.yml @@ -9,6 +9,7 @@ fr: encrypted_data: Donnée_Chiffrée compression: Compression backup_paths: Chemins à sauvegarder + backup_sources: Éléments à sauvegarder use_fs_snapshot: Utiliser les instantanés VSS ignore_cloud_files: Exclure le fichiers dans le cloud windows_only: Windows seulement diff --git a/npbackup/translations/generic.en.yml b/npbackup/translations/generic.en.yml index 216b8de..60aa6f6 100644 --- a/npbackup/translations/generic.en.yml +++ b/npbackup/translations/generic.en.yml @@ -10,6 +10,10 @@ en: change: Change close: Close finished: Finished + next: next + previous: previous + start: Start + finish: Finish yes: Yes no: No diff --git a/npbackup/translations/generic.fr.yml b/npbackup/translations/generic.fr.yml index af59950..b1bb8e4 100644 --- a/npbackup/translations/generic.fr.yml +++ b/npbackup/translations/generic.fr.yml @@ -10,6 +10,10 @@ fr: change: Changer close: Fermer finished: Terminé + next: suivant + previous: Précédent + start: Démarrer + finish: Terminer yes: Oui no: Non diff --git a/npbackup/translations/wizard_gui.en.yml b/npbackup/translations/wizard_gui.en.yml new file mode 100644 index 0000000..a9884f3 --- /dev/null +++ b/npbackup/translations/wizard_gui.en.yml @@ -0,0 +1,11 @@ +en: + wizard_start: Start + select_backup_sources: Select backup sources + backup_source: Files & folders + backup_location: Backup location + backup_options: Backup options + summary: Summary + welcome: Welcome to the NPBackup wizard + welcome_description: This wizard will guide you through the initial configuration of NPBackup. + + thank_you: Thank you for using NPBackup! \ No newline at end of file diff --git a/npbackup/translations/wizard_gui.fr.yml b/npbackup/translations/wizard_gui.fr.yml new file mode 100644 index 0000000..d5bc046 --- /dev/null +++ b/npbackup/translations/wizard_gui.fr.yml @@ -0,0 +1,11 @@ +fr: + wizard_start: Début + select_backup_sources: Sélectionner les éléments à sauvegarder + backup_source: Fichiers & dossiers + backup_location: Emplacement de la sauvegarde + backup_options: Options de sauvegarde + summary: Résumé + welcome: Bienvenue dans l'assistant NPBackup + welcome_description: Cet assistant vous guidera à travers la configuration initiale de NPBackup. + + thank_you: Merci d'utiliser NPBackup! \ No newline at end of file diff --git a/resources/customization.py b/resources/customization.py index 3a37c18..c42b7ad 100644 --- a/resources/customization.py +++ b/resources/customization.py @@ -7,11 +7,8 @@ __intname__ = "npbackup.customization" __author__ = "Orsiris de Jong" __copyright__ = "Copyright (C) 2022-2025 NetInvent" __license__ = "GPL-3.0-only" -__build__ = "2025022601" -__version__ = "1.3.1" - - -import os +__build__ = "2025100601" +__version__ = "1.4.0" # Windows Program name for scheduled task @@ -35,9 +32,16 @@ PRODUCT_NAME = "NPBackup Network Backup Client" SHORT_PRODUCT_NAME = "NPBackup" -# SimpleGUI theme +# SimpleGUI theme see with print(sg.theme_list()) # Valid list: ['Black', 'BlueMono', 'BluePurple', 'BrightColors', 'BrownBlue', 'Dark', 'Dark2', 'DarkAmber', 'DarkBlack', 'DarkBlack1', 'DarkBlue', 'DarkBlue1', 'DarkBlue10', 'DarkBlue11', 'DarkBlue12', 'DarkBlue13', 'DarkBlue14', 'DarkBlue15', 'DarkBlue16', 'DarkBlue17', 'DarkBlue2', 'DarkBlue3', 'DarkBlue4', 'DarkBlue5', 'DarkBlue6', 'DarkBlue7', 'DarkBlue8', 'DarkBlue9', 'DarkBrown', 'DarkBrown1', 'DarkBrown2', 'DarkBrown3', 'DarkBrown4', 'DarkBrown5', 'DarkBrown6', 'DarkBrown7', 'DarkGreen', 'DarkGreen1', 'DarkGreen2', 'DarkGreen3', 'DarkGreen4', 'DarkGreen5', 'DarkGreen6', 'DarkGreen7', 'DarkGrey', 'DarkGrey1', 'DarkGrey10', 'DarkGrey11', 'DarkGrey12', 'DarkGrey13', 'DarkGrey14', 'DarkGrey15', 'DarkGrey2', 'DarkGrey3', 'DarkGrey4', 'DarkGrey5', 'DarkGrey6', 'DarkGrey7', 'DarkGrey8', 'DarkGrey9', 'DarkPurple', 'DarkPurple1', 'DarkPurple2', 'DarkPurple3', 'DarkPurple4', 'DarkPurple5', 'DarkPurple6', 'DarkPurple7', 'DarkRed', 'DarkRed1', 'DarkRed2', 'DarkTanBlue', 'DarkTeal', 'DarkTeal1', 'DarkTeal10', 'DarkTeal11', 'DarkTeal12', 'DarkTeal2', 'DarkTeal3', 'DarkTeal4', 'DarkTeal5', 'DarkTeal6', 'DarkTeal7', 'DarkTeal8', 'DarkTeal9', 'Default', 'Default1', 'DefaultNoMoreNagging', 'GrayGrayGray', 'Green', 'GreenMono', 'GreenTan', 'HotDogStand', 'Kayak', 'LightBlue', 'LightBlue1', 'LightBlue2', 'LightBlue3', 'LightBlue4', 'LightBlue5', 'LightBlue6', 'LightBlue7', 'LightBrown', 'LightBrown1', 'LightBrown10', 'LightBrown11', 'LightBrown12', 'LightBrown13', 'LightBrown2', 'LightBrown3', 'LightBrown4', 'LightBrown5', 'LightBrown6', 'LightBrown7', 'LightBrown8', 'LightBrown9', 'LightGray1', 'LightGreen', 'LightGreen1', 'LightGreen10', 'LightGreen2', 'LightGreen3', 'LightGreen4', 'LightGreen5', 'LightGreen6', 'LightGreen7', 'LightGreen8', 'LightGreen9', 'LightGrey', 'LightGrey1', 'LightGrey2', 'LightGrey3', 'LightGrey4', 'LightGrey5', 'LightGrey6', 'LightPurple', 'LightTeal', 'LightYellow', 'Material1', 'Material2', 'NeutralBlue', 'Purple', 'Python', 'PythonPlus', 'Reddit', 'Reds', 'SandyBeach', 'SystemDefault', 'SystemDefault1', 'SystemDefaultForReal', 'Tan', 'TanBlue', 'TealMono', 'Topanga'] -SIMPLEGUI_THEME = "Reddit" +LOOK_AND_FEEL_TABLE = { + 'CLEAR': {'BACKGROUND': '#ffffff','TEXT': '#1a1a1b','INPUT': '#dae0e6','TEXT_INPUT': '#222222','SCROLL': '#a5a4a4','BUTTON': ('#333333', '#ffffff'),'PROGRESS': ('#015bbb', '#fed500'),'BORDER': 1,'SLIDER_DEPTH': 0,'PROGRESS_DEPTH': 0,'ACCENT1': '#ff5414','ACCENT2': '#33a8ff','ACCENT3': '#dbf0ff',}, + 'CLEAR2' : {'BACKGROUND': '#ffffff','TEXT': '#1a1a1b','INPUT': '#dae0e6','TEXT_INPUT': '#222222','SCROLL': '#a5a4a4','BUTTON': ('#333333', "#097ad1"),'PROGRESS': ('#015bbb', '#fed500'),'BORDER': 1,'SLIDER_DEPTH': 0,'PROGRESS_DEPTH': 0,'ACCENT1': '#ff5414','ACCENT2': '#33a8ff','ACCENT3': '#dbf0ff',}, + 'DARK': {'BACKGROUND': '#001d3c','TEXT': '#ffffff','INPUT': '#015bbb','TEXT_INPUT': '#fed500','SCROLL': '#015bbb','BUTTON': ('#fed500', '#001d3c'),'PROGRESS': ('#015bbb', '#fed500'),'BORDER': 1,'SLIDER_DEPTH': 1,'PROGRESS_DEPTH': 0,}, + } + +SIMPLEGUI_THEME = "CLEAR" +SIMPLEGUI_DARK_THEME = "DARK" BG_COLOR_LDR = "#0079d3" TXT_COLOR_LDR = "#FFFFFF" GUI_STATE_OK_BUTTON = ("#FFFFFF", "#0079d3") @@ -67,6 +71,7 @@ INHERITED_SYMLINK_ICON = b"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAAXNSR SYMLINK_ICON = b"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAwUExURf///0lJSSgoKNDQ0AAAAMfHxxoaGsTExNfX1/b29hcXFy8vL+zs7MHBwSsrK+jo6JAyYacAAAAJcEhZcwAACxEAAAsRAX9kX5EAAABXSURBVBjTY8AChJSUlAxADBUXF5cAMMOtomMCmLFkDwNnMIhxz/sAhxOI0f9kD4TR8M/7BITB/2Q7iGE6geGfG4jBwNnRuwTMYAWaCGYwA+1QxLCZgQEAN90WKol5c8kAAAAASUVORK5CYII=" TREE_ICON = b"iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAACxEAAAsRAX9kX5EAAAEtSURBVDhPjZNdTsJAFIUPbalQUSEQNMQ16AJcga++uBJe9AE2wE5civvwzUDQhIClnjMz5Wc6gd7km85M7px7ettpgPH4Ukxfp5ig0MoLZZT7JtvG20PDrCINxRboD4HNGvj9AZaLA+bA/Hs/L2HsBbaskCTA5TXQG1Ds9phuHxjeAVddi4t7DUYAdCBDURwmJgtWzTKLiycN1oEEOAsdFs3Uutv8AasV0GrrFFoadgIRZwmTQ6QXQJuVRdZhfq5TNqwANyQQsw/nkBs1vQwjoI2IPTAVmeQ78KkKOAdJk0hAzxPk/ivkronqdh3CryAHql6DahOdQOgThgj2QD9SyG4IFSxj5+DUn+hTdVDwMlBAInU4FOCSF2T0/twZTcac3hDeyfPx9ZnOAHz8A2r8W8iBwGS0AAAAAElFTkSuQmCC" LOADER_ANIMATION = b"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" +THEME_CHOOSER_ICON = b"iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAMAAAAM7l6QAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAGAUExURaenp4qKinx8fHNzc3JycoyMjKurq7S0tHh4eISEhKWlpcHBwdPT09zc3N3d3b+/v6CgoH5+fnt7e7u7u3V1dZGRkc7OzvX19f////n5+cnJyYmJiXp6eqmpqXl5ecXFxf39/f7+/vz8/LOzszU1NYKCgq+vr+Tk5Ly8vJycnIaGhubm5gAAAODg4N/f36ampoeHh/Dw8KysrC0tLSMjIxoaGuvr6+jo6CIiIh0dHR4eHpOTk+Hh4XZ2dsvLywUFBSsrK6SkpJiYmAMDAyQkJNXV1bm5udfX1xgYGFlZWfr6+tHR0YCAgJubm7GxsYuLi6ioqIGBgQ0NDUBAQMbGxnR0dAQEBAsLC+7u7nd3d+fn5wICAuPj43BwcAEBAeLi4hMTE+rq6gkJCR8fH8jIyCUlJb29vfj4+CoqKrW1tSgoKGpqasLCwj8/P+Xl5RQUFAwMDGJiYq2trSAgIKOjoxEREWVlZfPz88DAwPv7+8/Pz9ra2n19fbq6unFxcQAAAJUdoOcAAACAdFJOU/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8AOAVLZwAAAAlwSFlzAAAWJAAAFiQBmxXGFAAAABh0RVh0U29mdHdhcmUAUGFpbnQuTkVUIDUuMS45bG7aPgAAALZlWElmSUkqAAgAAAAFABoBBQABAAAASgAAABsBBQABAAAAUgAAACgBAwABAAAAAwAAADEBAgAQAAAAWgAAAGmHBAABAAAAagAAAAAAAABx3QAA6AMAAHHdAADoAwAAUGFpbnQuTkVUIDUuMS45AAMAAJAHAAQAAAAwMjMwAaADAAEAAAABAAAABaAEAAEAAACUAAAAAAAAAAIAAQACAAQAAABSOTgAAgAHAAQAAAAwMTAwAAAAAP2IRfsKb4nlAAABmElEQVQ4T3XTB1PCMBgG4AqiqKCiiB+iBcTt60DFvUVFceDeuPfe2/51k5pSvGvfu/aueS5pxhdJ0SNlWKyZFluW+ORJcbY9JzfP4cx3FBS6iopFY4rdJZ5SEvGW+cpF8x9XyP4AUTBYSaGq6ppaojp3tgoq1zc0EgWC7KEKsNibqNmlCn+1tIYZ8ASoDe0dEaCNOl0hwUVdQlXuBnp60Uf9A3+cOaipxhgaxggVyJyzRoWxaIyxKMbJNsHYPZnqrDNimCKPzNg2LYxFZ0QRD8wo0uwcsRWJpHEP5ik3IS14jHkRS8Fln7TSbMyra1h3lksbm8a8FcF2444pJyPYZWw2+Nge9tngZlM7wKH3yGe6sBhWSEqYbssxTvi2GG9q8gBbp3G+qUZHksQZzmmeH4nBgSZxgUu6spuUw9AZrr03VlEt/4spehu9w/1p2KIVU3opPuCR/fuBbiyqqC8lIS+z7ryQn/D8EnqlN2taIbNo1yC8W0rvHz42KzUaKyF7TsuVw9n06R/5kr9Fo84s/Ar+yBn6FVSUXyv6yhQiB79WAAAAAElFTkSuQmCC" # Please don't change the license text which is a legal requirement. LICENSE_TEXT = """ diff --git a/resources/update_custom_resources.py b/resources/update_custom_resources.py index 83960b8..edc66d2 100644 --- a/resources/update_custom_resources.py +++ b/resources/update_custom_resources.py @@ -55,6 +55,7 @@ def update_custom_icons(): "LOADING_ANIMATION": "loading.gif", "OEM_LOGO": "oem_logo.png", "OEM_ICON": "oem_icon.png", + "THEME_CHOOSER_ICON": "theme_chooser_icon.png", } resources_dir = os.path.join(BASEDIR, os.path.pardir, "resources")