From 644ce9afa4b7af9151a04842076d6903fc40253f Mon Sep 17 00:00:00 2001 From: misygauziya Date: Sun, 27 Aug 2023 04:56:36 +0900 Subject: [PATCH] [Add] New GUI from Shiina --- VRCT.py | 499 -------------- ctk_scrollable_dropdown.py | 47 +- img/arrow_left_disabled.png | Bin 0 -> 974 bytes img/arrow_left_white.png | Bin 0 -> 969 bytes img/configuration_icon_disabled.png | Bin 0 -> 2069 bytes img/configuration_icon_white.png | Bin 0 -> 1688 bytes img/foreground_icon_disabled.png | Bin 0 -> 232 bytes img/foreground_icon_white.png | Bin 0 -> 227 bytes img/headphones_icon_disabled.png | Bin 0 -> 1328 bytes img/headphones_icon_white.png | Bin 0 -> 1171 bytes img/help_icon_disabled.png | Bin 0 -> 1715 bytes img/help_icon_white.png | Bin 0 -> 1595 bytes img/mic_icon_disabled.png | Bin 0 -> 1108 bytes img/mic_icon_white.png | Bin 0 -> 952 bytes img/narrow_arrow_down.png | Bin 0 -> 785 bytes img/translation_icon_disabled.png | Bin 0 -> 1440 bytes img/translation_icon_white.png | Bin 0 -> 1237 bytes img/vrct_logo_for_dark_mode.png | Bin 0 -> 7087 bytes img/vrct_logo_for_light_mode.png | Bin 0 -> 7664 bytes img/vrct_logo_mark_black.png | Bin 0 -> 1018 bytes img/vrct_logo_mark_white.png | Bin 0 -> 898 bytes main.py | 8 + utils.py | 108 +-- vrct_gui/__init__.py | 1 + vrct_gui/_changeMainWindowWidgetsStatus.py | 148 +++++ vrct_gui/_printToTextbox.py | 37 ++ vrct_gui/config_window/ConfigWindow.py | 36 + vrct_gui/config_window/__init__.py | 1 + vrct_gui/config_window/widgets/__init__.py | 4 + .../widgets/createConfigWindowTitle.py | 39 ++ .../widgets/createSettingBoxTitle.py | 20 + .../__init__.py | 1 + .../addConfigSideMenuItem.py | 109 +++ .../createSettingBoxContainer.py | 61 ++ .../createSideMenuAndSettingsBoxContainers.py | 149 +++++ .../SettingBoxGenerator.py | 494 ++++++++++++++ .../setting_box_containers/__init__.py | 1 + .../setting_box_general/__init__.py | 1 + .../createSettingBox_General.py | 225 +++++++ vrct_gui/main_window/__init__.py | 1 + .../main_window/createMainWindowWidgets.py | 93 +++ vrct_gui/main_window/widgets/__init__.py | 4 + .../widgets/create_entry_message_box.py | 21 + .../widgets/create_minimize_sidebar_button.py | 58 ++ .../main_window/widgets/create_sidebar.py | 622 ++++++++++++++++++ .../main_window/widgets/create_textbox.py | 177 +++++ vrct_gui/ui_managers/ColorThemeManager.py | 360 ++++++++++ vrct_gui/ui_managers/ImageFilenameManager.py | 54 ++ vrct_gui/ui_managers/UiScalingManager.py | 184 ++++++ vrct_gui/ui_managers/__init__.py | 3 + vrct_gui/ui_utils/__init__.py | 1 + vrct_gui/ui_utils/ui_utils.py | 150 +++++ vrct_gui/vrct_gui.py | 107 +++ window_help_and_info.py | 154 +++++ 54 files changed, 3364 insertions(+), 614 deletions(-) delete mode 100644 VRCT.py create mode 100644 img/arrow_left_disabled.png create mode 100644 img/arrow_left_white.png create mode 100644 img/configuration_icon_disabled.png create mode 100644 img/configuration_icon_white.png create mode 100644 img/foreground_icon_disabled.png create mode 100644 img/foreground_icon_white.png create mode 100644 img/headphones_icon_disabled.png create mode 100644 img/headphones_icon_white.png create mode 100644 img/help_icon_disabled.png create mode 100644 img/help_icon_white.png create mode 100644 img/mic_icon_disabled.png create mode 100644 img/mic_icon_white.png create mode 100644 img/narrow_arrow_down.png create mode 100644 img/translation_icon_disabled.png create mode 100644 img/translation_icon_white.png create mode 100644 img/vrct_logo_for_dark_mode.png create mode 100644 img/vrct_logo_for_light_mode.png create mode 100644 img/vrct_logo_mark_black.png create mode 100644 img/vrct_logo_mark_white.png create mode 100644 main.py create mode 100644 vrct_gui/__init__.py create mode 100644 vrct_gui/_changeMainWindowWidgetsStatus.py create mode 100644 vrct_gui/_printToTextbox.py create mode 100644 vrct_gui/config_window/ConfigWindow.py create mode 100644 vrct_gui/config_window/__init__.py create mode 100644 vrct_gui/config_window/widgets/__init__.py create mode 100644 vrct_gui/config_window/widgets/createConfigWindowTitle.py create mode 100644 vrct_gui/config_window/widgets/createSettingBoxTitle.py create mode 100644 vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/__init__.py create mode 100644 vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/addConfigSideMenuItem.py create mode 100644 vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/createSettingBoxContainer.py create mode 100644 vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/createSideMenuAndSettingsBoxContainers.py create mode 100644 vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/SettingBoxGenerator.py create mode 100644 vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/__init__.py create mode 100644 vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_general/__init__.py create mode 100644 vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_general/createSettingBox_General.py create mode 100644 vrct_gui/main_window/__init__.py create mode 100644 vrct_gui/main_window/createMainWindowWidgets.py create mode 100644 vrct_gui/main_window/widgets/__init__.py create mode 100644 vrct_gui/main_window/widgets/create_entry_message_box.py create mode 100644 vrct_gui/main_window/widgets/create_minimize_sidebar_button.py create mode 100644 vrct_gui/main_window/widgets/create_sidebar.py create mode 100644 vrct_gui/main_window/widgets/create_textbox.py create mode 100644 vrct_gui/ui_managers/ColorThemeManager.py create mode 100644 vrct_gui/ui_managers/ImageFilenameManager.py create mode 100644 vrct_gui/ui_managers/UiScalingManager.py create mode 100644 vrct_gui/ui_managers/__init__.py create mode 100644 vrct_gui/ui_utils/__init__.py create mode 100644 vrct_gui/ui_utils/ui_utils.py create mode 100644 vrct_gui/vrct_gui.py create mode 100644 window_help_and_info.py diff --git a/VRCT.py b/VRCT.py deleted file mode 100644 index ff7e41c8..00000000 --- a/VRCT.py +++ /dev/null @@ -1,499 +0,0 @@ -from time import sleep -from os import path as os_path - -import customtkinter -from customtkinter import CTk, CTkFrame, CTkCheckBox, CTkFont, CTkButton, CTkImage, CTkTabview, CTkTextbox, CTkEntry -from PIL.Image import open as Image_open - -from threading import Thread -from utils import print_textbox, get_localized_text, widget_main_window_label_setter -from window_config import ToplevelWindowConfig -from window_information import ToplevelWindowInformation -from config import config -from model import model - -class App(CTk): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - ## set UI theme - customtkinter.set_appearance_mode(config.APPEARANCE_THEME) - customtkinter.set_default_color_theme("blue") - - # init main window - self.iconbitmap(os_path.join(os_path.dirname(__file__), "img", "app.ico")) - self.title("VRCT") - self.geometry(f"{400}x{175}") - self.minsize(400, 175) - self.grid_columnconfigure(1, weight=1) - self.grid_rowconfigure(0, weight=1) - self.wm_attributes("-alpha", config.TRANSPARENCY/100) - customtkinter.set_widget_scaling(int(config.UI_SCALING.replace("%", "")) / 100) - self.protocol("WM_DELETE_WINDOW", self.delete_window) - - # add sidebar - self.add_sidebar() - - # add entry message box - self.entry_message_box = CTkEntry( - self, - placeholder_text="message", - font=CTkFont(family=config.FONT_FAMILY), - ) - self.entry_message_box.grid(row=1, column=1, columnspan=2, padx=5, pady=(5, 10), sticky="nsew") - self.entry_message_box.bind("", self.entry_message_box_press_key_enter) - self.entry_message_box.bind("", self.entry_message_box_press_key_any) - self.entry_message_box.bind("", self.entry_message_box_leave) - - # add tabview textbox - self.add_tabview_logs(get_localized_text(f"{config.UI_LANGUAGE}")) - - self.config_window = ToplevelWindowConfig(self) - self.information_window = ToplevelWindowInformation(self) - self.init_process() - - def init_process(self): - # set translator - if model.authenticationTranslator() is False: - # error update Auth key - self.printLogAuthenticationError() - - # set word filter - model.addKeywords() - - # check OSC started - model.checkOSCStarted() - - # check Software Updated - model.checkSoftwareUpdated() - - def button_config_callback(self): - self.foreground_stop() - self.transcription_stop() - self.checkbox_translation.configure(state="disabled") - self.checkbox_transcription_send.configure(state="disabled") - self.checkbox_transcription_receive.configure(state="disabled") - self.checkbox_foreground.configure(state="disabled") - self.tabview_logs.configure(state="disabled") - self.textbox_message_log.configure(state="disabled") - self.textbox_message_send_log.configure(state="disabled") - self.textbox_message_receive_log.configure(state="disabled") - self.textbox_message_system_log.configure(state="disabled") - self.entry_message_box.configure(state="disabled") - self.button_config.configure(state="disabled", fg_color=["gray92", "gray14"]) - self.button_information.configure(state="disabled", fg_color=["gray92", "gray14"]) - self.config_window.deiconify() - self.config_window.focus_set() - self.config_window.focus() - self.config_window.grab_set() - - def button_information_callback(self): - self.information_window.deiconify() - self.information_window.focus_set() - self.information_window.focus() - - def checkbox_translation_callback(self): - config.ENABLE_TRANSLATION = self.checkbox_translation.get() - if config.ENABLE_TRANSLATION is True: - self.printLogStartTranslation() - else: - self.printLogStopTranslation() - - def transcription_send_start(self): - model.startMicTranscript(self.sendMicMessage) - self.printLogStartVoice2chatbox() - self.checkbox_transcription_send.configure(state="normal") - self.checkbox_transcription_receive.configure(state="normal") - self.button_config.configure(state="normal", fg_color=["#3B8ED0", "#1F6AA5"]) - - def transcription_send_stop(self): - model.stopMicTranscript() - self.printLogStopVoice2chatbox() - self.checkbox_transcription_send.configure(state="normal") - self.checkbox_transcription_receive.configure(state="normal") - self.button_config.configure(state="normal", fg_color=["#3B8ED0", "#1F6AA5"]) - - def transcription_send_stop_for_config(self): - model.stopMicTranscript() - self.printLogStopVoice2chatbox() - - def checkbox_transcription_send_callback(self): - config.ENABLE_TRANSCRIPTION_SEND = self.checkbox_transcription_send.get() - self.checkbox_transcription_send.configure(state="disabled") - self.checkbox_transcription_receive.configure(state="disabled") - self.button_config.configure(state="disabled", fg_color=["gray92", "gray14"]) - if config.ENABLE_TRANSCRIPTION_SEND is True: - th_transcription_send_start = Thread(target=self.transcription_send_start) - th_transcription_send_start.daemon = True - th_transcription_send_start.start() - else: - th_transcription_send_stop = Thread(target=self.transcription_send_stop) - th_transcription_send_stop.daemon = True - th_transcription_send_stop.start() - - def transcription_receive_start(self): - model.startSpeakerTranscript(self.receiveSpeakerMessage) - self.printLogStartSpeaker2log() - self.checkbox_transcription_send.configure(state="normal") - self.checkbox_transcription_receive.configure(state="normal") - self.button_config.configure(state="normal", fg_color=["#3B8ED0", "#1F6AA5"]) - - def transcription_receive_stop(self): - model.stopSpeakerTranscript() - self.printLogStopSpeaker2log() - self.checkbox_transcription_send.configure(state="normal") - self.checkbox_transcription_receive.configure(state="normal") - self.button_config.configure(state="normal", fg_color=["#3B8ED0", "#1F6AA5"]) - - def transcription_receive_stop_for_config(self): - model.stopSpeakerTranscript() - self.printLogStopSpeaker2log() - - def checkbox_transcription_receive_callback(self): - config.ENABLE_TRANSCRIPTION_RECEIVE = self.checkbox_transcription_receive.get() - self.checkbox_transcription_send.configure(state="disabled") - self.checkbox_transcription_receive.configure(state="disabled") - self.button_config.configure(state="disabled", fg_color=["gray92", "gray14"]) - if config.ENABLE_TRANSCRIPTION_RECEIVE is True: - th_transcription_receive_start = Thread(target=self.transcription_receive_start) - th_transcription_receive_start.daemon = True - th_transcription_receive_start.start() - else: - th_transcription_receive_stop = Thread(target=self.transcription_receive_stop) - th_transcription_receive_stop.daemon = True - th_transcription_receive_stop.start() - - def transcription_start(self): - if config.ENABLE_TRANSCRIPTION_SEND is True: - th_transcription_send_start = Thread(target=self.transcription_send_start) - th_transcription_send_start.daemon = True - th_transcription_send_start.start() - sleep(2) - if config.ENABLE_TRANSCRIPTION_RECEIVE is True: - th_transcription_receive_start = Thread(target=self.transcription_receive_start) - th_transcription_receive_start.daemon = True - th_transcription_receive_start.start() - - def transcription_stop(self): - if config.ENABLE_TRANSCRIPTION_SEND is True: - th_transcription_send_stop = Thread(target=self.transcription_send_stop_for_config) - th_transcription_send_stop.daemon = True - th_transcription_send_stop.start() - if config.ENABLE_TRANSCRIPTION_RECEIVE is True: - th_transcription_receive_stop = Thread(target=self.transcription_receive_stop_for_config) - th_transcription_receive_stop.daemon = True - th_transcription_receive_stop.start() - - def checkbox_foreground_callback(self): - config.ENABLE_FOREGROUND = self.checkbox_foreground.get() - if config.ENABLE_FOREGROUND: - self.attributes("-topmost", True) - self.printLogStartForeground() - else: - self.attributes("-topmost", False) - self.printLogStopForeground() - - def foreground_start(self): - if config.ENABLE_FOREGROUND: - self.attributes("-topmost", True) - self.printLogStartForeground() - - def foreground_stop(self): - if config.ENABLE_FOREGROUND: - self.attributes("-topmost", False) - self.printLogStopForeground() - - def entry_message_box_press_key_enter(self, event): - # osc stop send typing - model.oscStopSendTyping() - - if config.ENABLE_FOREGROUND: - self.attributes("-topmost", True) - - message = self.entry_message_box.get() - self.sendChatMessage(message) - - def entry_message_box_press_key_any(self, event): - # osc start send typing - model.oscStartSendTyping() - if config.ENABLE_FOREGROUND: - self.attributes("-topmost", False) - - if event.keysym != "??": - if len(event.char) != 0 and event.keysym in config.BREAK_KEYSYM_LIST: - self.entry_message_box.insert("end", event.char) - return "break" - - def entry_message_box_leave(self, event): - # osc stop send typing - model.oscStopSendTyping() - if config.ENABLE_FOREGROUND: - self.attributes("-topmost", True) - - def delete_window(self): - self.quit() - self.destroy() - - def add_sidebar(self): - init_lang_text = "Loading..." - self.sidebar_frame = CTkFrame(master=self, corner_radius=0) - - # add checkbox translation - self.checkbox_translation = CTkCheckBox( - self.sidebar_frame, - text=init_lang_text, - onvalue=True, - offvalue=False, - command=self.checkbox_translation_callback, - font=CTkFont(family=config.FONT_FAMILY) - ) - - # add checkbox transcription send - self.checkbox_transcription_send = CTkCheckBox( - self.sidebar_frame, - text=init_lang_text, - onvalue=True, - offvalue=False, - command=self.checkbox_transcription_send_callback, - font=CTkFont(family=config.FONT_FAMILY) - ) - - # add checkbox transcription receive - self.checkbox_transcription_receive = CTkCheckBox( - self.sidebar_frame, - text=init_lang_text, - onvalue=True, - offvalue=False, - command=self.checkbox_transcription_receive_callback, - font=CTkFont(family=config.FONT_FAMILY) - ) - - # add checkbox foreground - self.checkbox_foreground = CTkCheckBox( - self.sidebar_frame, - text=init_lang_text, - onvalue=True, - offvalue=False, - command=self.checkbox_foreground_callback, - font=CTkFont(family=config.FONT_FAMILY) - ) - - # add button information - self.button_information = CTkButton( - self.sidebar_frame, - text=None, - width=36, - command=self.button_information_callback, - image=CTkImage(Image_open(os_path.join(os_path.dirname(__file__), "img", "info-icon-white.png"))) - ) - - # add button config - self.button_config = CTkButton( - self.sidebar_frame, - text=None, - width=36, - command=self.button_config_callback, - image=CTkImage(Image_open(os_path.join(os_path.dirname(__file__), "img", "config-icon-white.png"))) - ) - - self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsw") - self.sidebar_frame.grid_rowconfigure(5, weight=1) - self.checkbox_translation.grid(row=0, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we") - self.checkbox_transcription_send.grid(row=1, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we") - self.checkbox_transcription_receive.grid(row=2, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we") - self.checkbox_foreground.grid(row=3, column=0, columnspan=2, padx=10, pady=(5, 5), sticky="we") - self.button_information.grid(row=5, column=0, padx=(10, 5), pady=(5, 5), sticky="wse") - self.button_config.grid(row=5, column=1, padx=(5, 10), pady=(5, 5), sticky="wse") - - def delete_tabview_logs(self, pre_language_yaml_data): - self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_log"]) - self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_send"]) - self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_receive"]) - self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_system"]) - - def add_tabview_logs(self, language_yaml_data): - main_tab_title_log = language_yaml_data["main_tab_title_log"] - main_tab_title_send = language_yaml_data["main_tab_title_send"] - main_tab_title_receive = language_yaml_data["main_tab_title_receive"] - main_tab_title_system = language_yaml_data["main_tab_title_system"] - - # add tabview textbox - self.tabview_logs = CTkTabview(master=self) - self.tabview_logs.add(main_tab_title_log) - self.tabview_logs.add(main_tab_title_send) - self.tabview_logs.add(main_tab_title_receive) - self.tabview_logs.add(main_tab_title_system) - self.tabview_logs.grid(row=0, column=1, padx=0, pady=0, sticky="nsew") - self.tabview_logs._segmented_button.configure(font=CTkFont(family=config.FONT_FAMILY)) - self.tabview_logs._segmented_button.grid(sticky="W") - self.tabview_logs.tab(main_tab_title_log).grid_rowconfigure(0, weight=1) - self.tabview_logs.tab(main_tab_title_log).grid_columnconfigure(0, weight=1) - self.tabview_logs.tab(main_tab_title_send).grid_rowconfigure(0, weight=1) - self.tabview_logs.tab(main_tab_title_send).grid_columnconfigure(0, weight=1) - self.tabview_logs.tab(main_tab_title_receive).grid_rowconfigure(0, weight=1) - self.tabview_logs.tab(main_tab_title_receive).grid_columnconfigure(0, weight=1) - self.tabview_logs.tab(main_tab_title_system).grid_rowconfigure(0, weight=1) - self.tabview_logs.tab(main_tab_title_system).grid_columnconfigure(0, weight=1) - self.tabview_logs.configure(fg_color="transparent") - - # add textbox message log - self.textbox_message_log = CTkTextbox( - self.tabview_logs.tab(main_tab_title_log), - font=CTkFont(family=config.FONT_FAMILY) - ) - - # add textbox message send log - self.textbox_message_send_log = CTkTextbox( - self.tabview_logs.tab(main_tab_title_send), - font=CTkFont(family=config.FONT_FAMILY) - ) - - # add textbox message receive log - self.textbox_message_receive_log = CTkTextbox( - self.tabview_logs.tab(main_tab_title_receive), - font=CTkFont(family=config.FONT_FAMILY) - ) - - # add textbox message system log - self.textbox_message_system_log = CTkTextbox( - self.tabview_logs.tab(main_tab_title_system), - font=CTkFont(family=config.FONT_FAMILY) - ) - - self.textbox_message_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew") - self.textbox_message_send_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew") - self.textbox_message_receive_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew") - self.textbox_message_system_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew") - self.textbox_message_log.configure(state='disabled') - self.textbox_message_send_log.configure(state='disabled') - self.textbox_message_receive_log.configure(state='disabled') - self.textbox_message_system_log.configure(state='disabled') - - widget_main_window_label_setter(self, language_yaml_data) - - def printLogAuthenticationError(self): - print_textbox(self.textbox_message_log, "Auth Key or language setting is incorrect", "ERROR") - print_textbox(self.textbox_message_system_log, "Auth Key or language setting is incorrect", "ERROR") - - def printLogStartTranslation(self): - print_textbox(self.textbox_message_log, "Start translation", "INFO") - print_textbox(self.textbox_message_system_log, "Start translation", "INFO") - - def printLogStopTranslation(self): - print_textbox(self.textbox_message_log, "Stop translation", "INFO") - print_textbox(self.textbox_message_system_log, "Stop translation", "INFO") - - def printLogStartVoice2chatbox(self): - print_textbox(self.textbox_message_log, "Start voice2chatbox", "INFO") - print_textbox(self.textbox_message_system_log, "Start voice2chatbox", "INFO") - - def printLogStopVoice2chatbox(self): - print_textbox(self.textbox_message_log, "Stop voice2chatbox", "INFO") - print_textbox(self.textbox_message_system_log, "Stop voice2chatbox", "INFO") - - def printLogStartSpeaker2log(self): - print_textbox(self.textbox_message_log, "Start speaker2log", "INFO") - print_textbox(self.textbox_message_system_log, "Start speaker2log", "INFO") - - def printLogStopSpeaker2log(self): - print_textbox(self.textbox_message_log, "Stop speaker2log", "INFO") - print_textbox(self.textbox_message_system_log, "Stop speaker2log", "INFO") - - def printLogStartForeground(self): - print_textbox(self.textbox_message_log, "Start foreground", "INFO") - print_textbox(self.textbox_message_system_log, "Start foreground", "INFO") - - def printLogStopForeground(self): - print_textbox(self.textbox_message_log, "Stop foreground", "INFO") - print_textbox(self.textbox_message_system_log, "Stop foreground", "INFO") - - def printLogDetectWordFilter(self, message): - print_textbox(self.textbox_message_log, f"Detect WordFilter :{message}", "INFO") - print_textbox(self.textbox_message_system_log, f"Detect WordFilter :{message}", "INFO") - - def printLogOSCError(self): - print_textbox(self.textbox_message_log, "OSC is not enabled, please enable OSC and rejoin.", "ERROR") - print_textbox(self.textbox_message_system_log, "OSC is not enabled, please enable OSC and rejoin.", "ERROR") - - def printLogSendMessage(self, message): - print_textbox(self.textbox_message_log, f"{message}", "SEND") - print_textbox(self.textbox_message_send_log, f"{message}", "SEND") - - def printLogReceiveMessage(self, message): - print_textbox(self.textbox_message_log, f"{message}", "RECEIVE") - print_textbox(self.textbox_message_receive_log, f"{message}", "RECEIVE") - - def sendChatMessage(self, message): - if len(message) > 0: - # translate - if config.ENABLE_TRANSLATION is False: - chat_message = f"{message}" - elif model.getTranslatorStatus() is False: - self.printLogAuthenticationError() - chat_message = f"{message}" - else: - chat_message = model.getInputTranslate(message) - - # send OSC message - if config.ENABLE_OSC is True: - model.oscSendMessage(chat_message) - else: - self.printLogOSCError() - - # update textbox message log - self.printLogSendMessage(chat_message) - - # delete message in entry message box - if config.ENABLE_AUTO_CLEAR_CHATBOX is True: - self.entry_message_box.delete(0, customtkinter.END) - - def sendMicMessage(self, message): - if len(message) > 0: - # word filter - if model.checkKeywords(message): - self.printLogDetectWordFilter(message) - return - - # translate - if config.ENABLE_TRANSLATION is False: - voice_message = f"{message}" - elif model.getTranslatorStatus() is False: - self.printLogAuthenticationError() - voice_message = f"{message}" - else: - voice_message = model.getInputTranslate(message) - - if config.ENABLE_TRANSCRIPTION_SEND is True: - if config.ENABLE_OSC is True: - # osc send message - model.oscSendMessage(voice_message) - else: - self.printLogOSCError() - # update textbox message log - self.printLogSendMessage(voice_message) - - def receiveSpeakerMessage(self, message): - if len(message) > 0: - # translate - if config.ENABLE_TRANSLATION is False: - voice_message = f"{message}" - elif model.getTranslatorStatus() is False: - self.printLogAuthenticationError() - voice_message = f"{message}" - else: - voice_message = model.getOutputTranslate(message) - - if config.ENABLE_TRANSCRIPTION_RECEIVE is True: - # update textbox message receive log - self.printLogReceiveMessage(voice_message) - if config.ENABLE_NOTICE_XSOVERLAY is True: - model.notificationXsoverlay(voice_message) - -if __name__ == "__main__": - try: - app = App() - app.mainloop() - except Exception as e: - import traceback - with open('error.log', 'a') as f: - traceback.print_exc(file=f) \ No newline at end of file diff --git a/ctk_scrollable_dropdown.py b/ctk_scrollable_dropdown.py index 81b98205..f0f48c3e 100644 --- a/ctk_scrollable_dropdown.py +++ b/ctk_scrollable_dropdown.py @@ -15,19 +15,25 @@ import time class CTkScrollableDropdown(customtkinter.CTkToplevel): def __init__(self, attach, x=None, y=None, button_color=None, height: int = 200, width: int = None, - fg_color=None, button_height: int = 20, justify="center", scrollbar_button_color=None, + fg_color=None, max_button_height: int = 20, justify="center", scrollbar_button_color=None, scrollbar=True, scrollbar_button_hover_color=None, frame_border_width=2, values=[], - command=None, image_values=[], alpha: float = 0.97, frame_corner_radius=20, double_click=False, - resize=True, frame_border_color=None, text_color=None, autocomplete=False, **button_kwargs): + command=None, image_values=[], alpha: float = 0.97, double_click=False, + resize=True, frame_border_color=None, text_color=None, autocomplete=False, + max_height: int = None, button_pady: int = 0, min_show_button_num: int = 1, + button_corner_radius: int = None, frame_corner_radius=0, + **button_kwargs): super().__init__(takefocus=1) self.transient(self.master) self.alpha = alpha self.attach = attach self.corner = frame_corner_radius + # とりあえずframe_corner_radiusはframe_corner_radiusの名前のまま使いたい + self.frame_corner_radius = frame_corner_radius self.padding = 0 self.focus_something = False self.disable = True + self.font_size = 12 if button_kwargs.get("font", None) is None else button_kwargs["font"]._size if sys.platform.startswith("win"): self.after(100, lambda: self.overrideredirect(True)) @@ -48,7 +54,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): self.hide = True self.attach.bind('', lambda e: self._withdraw() if not self.disable else None, add="+") self.attach.winfo_toplevel().bind('', lambda e: self._withdraw() if not self.disable else None, add="+") - self.attach.winfo_toplevel().bind("", lambda e: self._withdraw() if not self.disable else None, add="+") + self.attach.winfo_toplevel().bind("", lambda e: self._withdraw() if not self.disable else None, add="+") self.attach.winfo_toplevel().bind("", lambda e: self._withdraw() if not self.disable else None, add="+") self.attach.winfo_toplevel().bind("", lambda e: self._withdraw() if not self.disable else None, add="+") @@ -84,6 +90,10 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): self.autocomplete = autocomplete self.var_update = customtkinter.StringVar() self.appear = False + self.max_height = max_height + self.button_pady = button_pady + self.min_show_button_num = min_show_button_num + self.button_corner_radius = button_corner_radius if justify.lower()=="left": self.justify = "w" @@ -92,7 +102,7 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): else: self.justify = "c" - self.button_height = button_height + self.button_height = max_button_height + self.font_size self.values = values self.button_num = len(self.values) self.image_values = None if len(image_values)!=len(self.values) else image_values @@ -179,8 +189,10 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): text_color=self.text_color, image=self.image_values[i] if self.image_values is not None else None, anchor=self.justify, + corner_radius= self.button_corner_radius, command=lambda k=row: self._attach_key_press(k), **button_kwargs) - self.widgets[self.i].pack(fill="x", pady=2, padx=(self.padding, 0)) + pady = 0 if self.button_num-1 == self.i else self.button_pady + self.widgets[self.i].pack(fill="x", pady=(0, pady), padx=(self.padding, 0)) self.i+=1 self.hide = False @@ -195,12 +207,25 @@ class CTkScrollableDropdown(customtkinter.CTkToplevel): self.width_new = self.attach.winfo_width() if self.width is None else self.width if self.resize: - if self.button_num==1: - self.height_new = self.button_height * self.button_num + 45 + button_height_include_pady = self.button_height + self.button_pady + + if self.min_show_button_num < self.button_num: + min_buttons_height = button_height_include_pady * self.min_show_button_num else: - self.height_new = self.button_height * self.button_num + 35 - if self.height_new>self.height: - self.height_new = self.height + min_buttons_height = button_height_include_pady * self.button_num + # delete last one's pady px + min_buttons_height -= self.button_pady + + # minor adjustment + 5px + min_buttons_height += 5 + # adjust by frame_corner_radius + min_buttons_height += (self.frame_corner_radius * 2) + + if self.max_height: + if min_buttons_height>self.max_height: + min_buttons_height = self.max_height + + self.height_new = min_buttons_height self.geometry('{}x{}+{}+{}'.format(self.width_new, self.height_new, self.x_pos, self.y_pos)) diff --git a/img/arrow_left_disabled.png b/img/arrow_left_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..5b5f3afaf5b9d90597727eb57423f6781b1c51ab GIT binary patch literal 974 zcmV;<12O!GP)4h=_=2Qa4ik(TjgT>7f)UrHDw8QbdXe5yABv51R!M(UK_;@MhZX0x;{G+uP}MW}miaw*NN*+SuJc ze&8h$Z6hLb&h5w}F%SW5>>dEmd+@!|lV}G>^j$z3yBEL=5pDg`@6Nd$-vdUXuL9cG zeSd@hRie}B=%EtO#_k93jEJ@fs()sVE)I==HufNZwh(@Und@1a%t_jg`T#!xKoiks zLG@3}TyJH`g0%fgM?f3f41oX0%(W1Bq6$Yq8=C=mL`1Qm`nrGeZ$kU2L_iyR7{CK5 zyiz=xrO9%hzDl1$+Snrj@M}t`k-YGw3ut4H2Eea&;TtPO`YcUA8+#1EePNsLl~SWw z+IU;E-%V=|K#75(RX11ZR| zMzXZ=p)B}90@~Oq05^s3OUyiyrH!>R;d2XU(>?>>hNNy3MQ@mSG)o)nWy9wZ(8itv z+;t)RqEcMT(#FRs;E4iPVr|;z0e4jhzo3+=r_G5^RlySljKCA!z7POEAIEX6YIw1L zHujQp?urn8E{@}Rb8>v6YIv~#5p4=+v*VmYKj4W1-T`gwB>EP|UR~OLAu> zh9R-F=2MEfazj<777qb~P!I5YxYA_4GNC=r}quUx=O z90V{el-N*;$Fek;9~uEKvENIGj+nf}KTm1;c1G69k{8T8NkrcS)wct(xTCM9l&vgz z#mwVG^!0D`d|cgDBi>)yxgA!*X2X__=m(&Rys-1GIaNeOG;d(OT0Jg>X= z_jC6?XRo!so2kc-&E0ZD_eu_$nth!!fs zKQeP8OXD%^_>}?}>$U*6qZI#vnH%*ic@;88We1tDZYzMBL^PlXpJV1`Jxkt%&Ql41 zv2G`T>jC0N>RIx(ow-WiLdLpX0pe$wdAMEiL?y3)v2HhjYsx=nMnoD}8o%pg&eB%E zShpuY{IrOSbSj>xq!lpM?E`R0DSj%7WF)P{GiA)(@d_C0_6LZ6CnCdTiSHP|Sa%S> zMddh?A~Kw%@%ysGcLZRpI|Sf@a*PRP9?sHuwoLJD0~qTL130e?f8)RNb7hNf3&2=+ z6u>!U_-mgYe5gV^QQ%j|Sa%G-8D;n@5pHH_^06xML;)*ctUDecek_WlQMGtAfU)i* zfYZt`^MQe=nbzX@s>Q1Th-g8;nBM^^x*?t@;2rR*a7r1TM^QAI)`o%`Rh0pFh~oiU zX>1^hMr*a9O1DyQE)@DDilV5Q)`lv3ncGU{jCDrbM>-)*T2)>L!J`k!49~8EIJs&HjM2ddeqvrPKta z)x^fSy#OvNA*MaVbl(7Yh&=$VC?RG%#8lq^c!=Equ9B{;^4_Q0lYIl=Awn8kvmT5&|E~eX~yiyRReEy|IKay{I>f8FK>br__#X5g<;00000NkvXXu0mjfo0rBR literal 0 HcmV?d00001 diff --git a/img/configuration_icon_disabled.png b/img/configuration_icon_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..03a4a217a2db292605f54b8257aa9460865e5720 GIT binary patch literal 2069 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 VV!l88avA7K22WQ%mvv4FO#m;{S=s;q literal 0 HcmV?d00001 diff --git a/img/foreground_icon_white.png b/img/foreground_icon_white.png new file mode 100644 index 0000000000000000000000000000000000000000..50370ad1d3cddf36bb00cf03b86e3ae8d82418a2 GIT binary patch literal 227 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC&H|6fVg?4jBOuH;Rhv&5C^*&A z#W5t~-rF0FTn!2WZV!2`-}^r&Zo#&|7GAgYjo;rg>DHxP*z)Dx_NR^4qAczDpSd2t ze^xqDx%vMIhAlk7RA}Dqm|JKRR~X0t-#N1v;)NhZBn2rg1d-HgwN><`2=P+0 zm&|NzErQnewWT*GQhX3v`p{AfrEg*j)mqHVW_FX1+JHzkRw`PdA`;pnZ3!YJ1TSHC zXV3Zikd5rU*=&-r;O}iNXU^|GXJ*d%26%+O&|F+(XlPj6pS-_WYu*arIRNbd+5lc$ z=;j`PF#w|gE(xMDEsGXicyVW^_BDW$Os`N%y#erkX0$cbF<}g#ucee3)WOCjE*pB5;jX2LNWYE3HR*ZTIDQ3D9f1`?c050fcAThKMpmlxe^xthGMTYrC({ zxQ`jiN43@t0HcoVbpUB18WBQVU$SKJ-`hI3<^bS_;WNRzcki`ntvi@`3xF`GR4Mgtt#(yMz)cN?v)Sxl03IvaJ#HBCY0Hd_&9!_nPBOJ3pI5(@^*s>^ z1|N^dyDDbtsw3ceUcBrA5JDWBZ+QT)%-Ag<#KE%NtzJHFRy)6H0A_xvc$Ch%-hO#ABl9${c~T7NY@Tcz>%^5TT|)5iiKlEfNVCq z38gE{oM9N>EtLE;a;neb?|(R#^EUry0A_x^c$qR?+EfHlm#KbOl*oa*g65(or7Ee}%i8MU3%YR~g7GxK3T zg)z{~x%XoBSp{oH-{Uip1=(YfG&2Nn+xF!G$`)$z# z!$L}V9Hqtc|Am~C^0=_f=ok?l_1mUVi0G(gM#lsI7*c)!;HKYF4REvIJhhlJ&FF-b zA_8E+f1k{PaVbT_G@}y_0suh5ieHmbZXu!@ejC<;h;B$JwvM3%5(Hv)mc zy2AgMhiNp%iRe%u5LlP6VkI}Yq9*Q+cVz&4=(+=+dHH-7Gw(!EQ9s|NM5HlQ)ZYYf mm57D{hA|MYQPe-eZ~g@fapSuE2LH|g0000P)dpGb0!@#-socsIEIrpCP9k@%r$aFMv?beZ_~^XAQ4EF#NAWCO4nSl*(oXlBnk=MHxrKnP)}h@1gRO>X(h%sz0={oFxM6GB)c zB5woR$esz;&1|i6?!p}hP_0&rg+k#cU`@v5Av1f~Id`%X@r*#$i^wNrzgOqdG+o=* z*Eia%e#>`2RbOi&e>ldtx?6bw=iKQS<7yylx~x>y*IU(ZIs!?OlvVXNz&Bj_JjS@w zdq3W-d_9#)MT^DaXTXaMmqucY4|?za&Z^gR1XT5n4Ef_}n!YsM@&M&>Ii_j46FA;* zsidlJHmjF80@Z4@w@@hj2@KSCl9@g1oEx5Q`FcVKi$vs?hG!>fn%>*j*LTZGojC%k z`bkB=XiY557#G(Eu0ool_*_O=43 zR4P5d6ZK_gwy(dxf7<7LGs@+1G_!pT#T%>D>Ma|`TLLH)3hS7QmIs!NuiOEkrWsK z{s7LJ+4nKVBU!6(W&pK>{VgDCFGQ(SnwF!O76DjBaRTg%F@D&X_)n1uAv{#eyp}b4 zKu!TnFj&jfCX<}Wbs&VWLPSoqlAi-C6Oj`kgcVZ)NRq^h$Wfr2w_zKUMdWCbBz`gg zRec{=lDAn0EU7soNs=s9)r&w+J2i8D2kIF$v-?$5ceE=%$LJA}9SUs9+oTINDXkBf z<~qw2SeUm(7cA`PaCa`Ez?Hluy5Nce=kvDcg7XR-%iE$0j%keXAXAg){|lpLc2K?d z!@&N$ZSH{m&beU)h%vqkT*}+111{B^Z*Jzi_lcQp0cQR9{Q!T~fbUM4l#}r2Z0c l&dk1zF@Do5slQ9!{0kL7ntSQ+x{m+=002ovPDHLkV1hchB;^1A literal 0 HcmV?d00001 diff --git a/img/help_icon_disabled.png b/img/help_icon_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..03e1c086e9c7d467dc98d0a09e2f10550370da4f GIT binary patch literal 1715 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 P00000NkvXXu0mjfrNnKG literal 0 HcmV?d00001 diff --git a/img/translation_icon_disabled.png b/img/translation_icon_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..533feb8182515f6cbc346d21ef231fc044abfafc GIT binary patch literal 1440 zcmV;R1z-A!P)M)Q6>%LVf7Ng0)b! z+iW)3-K5a!LJ?dn6&0;k3l?8mv{exLU=hR*R&8dINxHFXwTj|PQL2KtNcEuvseLHY zhq{|)X72GJH|sRrq-ism-2;K#GiT16-#vG3?m2{@#V(X$j^peG@C1N$-VY(A+z@mo zgyT4Sx*a?KFmu1-ID3NjYXI2kR}j$&Ddj{e8Nb+xW4lmVYRH!<@{ zrPLPvzHB$G!klx^Kl}|0@%Lf0f=Y{z&U1)16WN& z-vT&CL_aQO@IdV)zM*8&skbxf)C3WgHPAbmbZP>?Y}T}Mrd7x+7C>7W001jjT<3XS z9{?z&%&ch(rIZUG3g8le>|y}4m4U2jzu|e_&j41}!I@d;;K9sKWlj6T6H_PKo{-Q0 zOv`?bnP1Yj6#x)IOb8(kYLkBexXe6Wsa$PqdkqzU8PC^(rWc6lv{v7vl-jLfUKT>^ zs@d|hr@s8Ut*nLy0KII4h?D@70YE9W4?r&w{Sb@we6V80^3SyG?Q?ULm0<$3vu4i# z7;s(pJ0fy@;AJ61dMLitHLb#+)?bm*xa7ZCO1Y-Dclm|Q4?k306aXTcVCGW*?q+5H zP(+lEL?Zi{d3n~f_bH|JYuop?4L<7n?;lAGo$p5Ab-CdZN{=OHdU|^97eZ_iLTr;# z-jzwG(yr?s@I3EVWZ>s<}?bi_z09*#}6A^tJi^V<~ zia(~7B)~$FNvC$Ux*k@I-IXoR$`$)`nfewpuMgrF&CF5l>#*ZEXRTbZ4*-NF^UvI> zP99_zO0jM>2sBK;Qfk^Rlwtz4w9Jd+ILA7H2)o8M089c{@4JwwR;!8Q*?e1$q%_uy zq!QbbeOM_Sp0x`gufiItAy);kywLOc!Nx`Q4wKf}zMeZVK1`3x1n zb-f+X?MNb;NslGpUC7R~3c?4F$lFtQjHHGxEo2+^67v7TPBt^r+v?@|&~@D%&1^#h zuyVx*eJ`krL?WLwvmH(hR*1-7Q8hhUv^=Zdieydus=tVjMx%EIQP2Rjs;pYA{yiT& zQMDTx2(-rb2k$t}vBqb0BLgoo^WiQ`%ymLUdjrovr#1FX1V1CCJQ_GaDjBZ`A+~lC uqWw-)!H)@JEiYw6!zf5K8T=T zl=M&vQ9=YQNl{Uj^icE?R1gF`Bti6ttt=BNv6qT^lOpw{CCmp|!~~a}`}^&>Y_mJR z)5H8muj8!FI(P2Q_w5|cJ#)VIoZq>>a~L5YNs>VkIUpiW0Goj#-Ju3dsOq??eqfB5 z@6ume2!OSAy@>o60`CPTRCRZ$RGQ43K$0YbQ55~z!{D!y@ZN9DIuntIJex!C0Gq>a zWeRc5od)hr>AtVm>tp3|`BFEItJUhdLZNUN*ppJ9iR1XbtO@)_>cD#MhmA2^1>ZvA z-;}Br$MLEx2}HDXo0|o1t=;CF`^#GUS|`riWU<@Mb^``FF|yWf7m>BVP8zkm&pCGv zn2h82WY$4tP5^iV*q)NN07rnYfqi{XKtz53&H@htBfzh~SrPeTC4+~?8Mr0lIDRjV z<1t_oKvmz5<9N(_Kj)nL)>^xFr3iFdLRf3J0P6un~Ry%$nxe>6|z5u)uZ07+~bxc*?3MSJuGO@oAl-1k_5XweXj}s2Dh#Ue8@O!;p|D;x{eHCmg z#bR-7zY#bI5Jk~%T)Wpqz@(}^TB%ePi^bxupr2h>SeQyb?7iPOJ3G57j$?`ASaK(z zs$;+fU>$HL;DMvw`<+1SoI4~UM}qmsLqkK0>F13x=SN0HYFP)~ggECkt!Vd_s@3XX z6h)&zQB_YFV=h^1$3^6^l-V!d`-hA%bG-_-9Xe`z<#KtRYX>-u1URLtpV#a4&nlIQ z&og-FFax)Pyk_j45Xf`J&U~QBd&Z7{iL^F~qQli{b=~cH&3nccYwgP-^6u?=@!oGV z#++};dC%BguT`#Gxw2|_c=&3c&wIx1da>1d=$G3RoO5piuLp54Wc0#K?63150hCIm zN$>quRXqrtq0zE>j;X1s2-u%e4Mb72e>pxfznd&41J>FdBJy*K`dl2xcX#SP*Q;+U zMC7TI*v$G}*4oideXJOPBuNbLa1iHI^_?Y%^(O%l*$dne#N)t6G;X>8k0eR5y59*j zr#Mvg%dmQHF3DC0g8fOrTDuw87R1DRe=*myvaVxB3oPYxjuAcOAOBxUjIWVa=K~ zi%a>>Jp-NAcEHHMz`(AX8RWW2OOj+Q@IX^m)n`=ohKpVlMb7~{QiMxXx>yO zN~O|=?d+_zk%;UF;+`Z)hKw;&?QC-`p_VV~_)>PEttLS%wroFEhJdy9e&C*KG5Rl- zvJG31V@nXf{-tCcXx;-&FEWtnjNKCa;nv^EJOka%*vo;c9?YD;N~~2fg)wGcRd>@; zN?8Z5s=JLb^F8T8J({s=z!_CN=)K?C{O8O6`FJp9C=!h@00000NkvXXu0mjf*7a0H literal 0 HcmV?d00001 diff --git a/img/vrct_logo_for_dark_mode.png b/img/vrct_logo_for_dark_mode.png new file mode 100644 index 0000000000000000000000000000000000000000..7eeaabc26f728a7991160400ead86a6a2139948b GIT binary patch literal 7087 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 F{{b%nsA&KI literal 0 HcmV?d00001 diff --git a/img/vrct_logo_for_light_mode.png b/img/vrct_logo_for_light_mode.png new file mode 100644 index 0000000000000000000000000000000000000000..75b1afd911aec2a3d791198c1fb9c6b071529e0c GIT binary patch literal 7664 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 literal 0 HcmV?d00001 diff --git a/img/vrct_logo_mark_white.png b/img/vrct_logo_mark_white.png new file mode 100644 index 0000000000000000000000000000000000000000..0a6f1968fa8e156c214edec51b9c1d9f928cc6a7 GIT binary patch literal 898 zcmeAS@N?(olHy`uVBq!ia0vp^9zg8K!3HFY9zE&@Qk(@Ik;M!Q+`=Ht$S`Y;1W=H% zILO_JVcj{Imp~3nx}&cn1H;CC?mvmF3=B+vJzX3_Dj46+>CS!RAkfDCdBTJZjeI-! zCUL#H#JEyn3DXWP1yKifcg~$$9_$abI@UAI6B6RsQ9og#kaik}PQ}~V{+srEbndoa zdwuuj-6sWZSk})TX;+Hse+b=11skW1x8Vo1x+kPDHDFy+>2R%eeH_ReUEK+ulqe& z=lo;aV=N2r2Hejvvo+bEwBC_#h*!4wiv2$Bwk2o+49Hv`iDvvmftCba)~{yF{`h>lGvT! zeRPpnDX%}9!fBvYCK=~v{A(3y$T!}jhE^T? zF9PfBKiS#OKW|@aT5$CAx(n}LT{>Pjy|>_d`{Lkz!pmUv+?#~}&dJHMU8nxD`9kP~Gy+kg21r;i)*Z^Z2vn)X07e9xCIp(CE90<&8a z<8s1IrfrV(GE@)0q{CVCZsHpDuU=Y~ueHOprnar{e`i@H%(6G=_|5s1*GuC!RJSbY z^WB&dERo4xIq!P=0`)1&^cFSnPf_Y&J!A2qRp?0I0Xdbw53j$Ud|GJxn>!iavs4$V z{B2v}c;v%}|GFKGOW4Ysd6@Y4dKapkn z-Gn1&E4&26U!Qf~y6xjq>A zL9{8sVAd>&u`8WOD#92wV!D45B<;{an^LB{Ts5jlY0+ literal 0 HcmV?d00001 diff --git a/main.py b/main.py new file mode 100644 index 00000000..ac80e5f5 --- /dev/null +++ b/main.py @@ -0,0 +1,8 @@ +from vrct_gui import vrct_gui + +class VRCT(): + def __init__(self): + pass +if __name__ == "__main__": + # vrct_gui = VRCT_GUI() + vrct_gui.start() \ No newline at end of file diff --git a/utils.py b/utils.py index 2bee5814..3033cb13 100644 --- a/utils.py +++ b/utils.py @@ -1,106 +1,6 @@ from os import path as os_path -import yaml -from datetime import datetime +from PIL.Image import open as Image_open -def print_textbox(textbox, message, tags=None): - now = datetime.now() - now = now.strftime('%H:%M:%S') - - textbox.tag_config("ERROR", foreground="#FF0000") - textbox.tag_config("INFO", foreground="#1BFF00") - textbox.tag_config("SEND", foreground="#0378e2") - textbox.tag_config("RECEIVE", foreground="#ffa500") - - textbox.configure(state='normal') - textbox.insert("end", f"[{now}][") - textbox.insert("end", f"{tags}", tags) - textbox.insert("end", f"]{message}\n") - textbox.configure(state='disabled') - textbox.see("end") - -def get_localized_text(language): - file_path = os_path.join(os_path.dirname(__file__), "locales.yml") - - with open(file_path, encoding="utf-8") as file: - languages_yaml_data = yaml.safe_load(file) - default_language = "en" - if language in languages_yaml_data: - localized_text = languages_yaml_data[language] - if default_language in languages_yaml_data: - default_text = languages_yaml_data[default_language] - merged_text = {**default_text, **localized_text} - return merged_text - else: - return localized_text - else: - return None - -def get_key_by_value(dictionary, value): - for key, val in dictionary.items(): - if val == value: - return key - return None - -def widget_config_window_label_setter(self, language_yaml_data): - widget_names = [ - # tab UI - "label_transparency", - "label_appearance_theme", - "label_ui_scaling", - "label_font_family", - "label_ui_language", - - # tab Translation - "label_translation_translator", - "label_translation_input_language", - "label_translation_output_language", - - # tab Transcription - "label_input_mic_host", - "label_input_mic_device", - "label_input_mic_voice_language", - "label_input_mic_energy_threshold", - "checkbox_input_mic_threshold_check", - "label_input_mic_dynamic_energy_threshold", - "label_input_mic_record_timeout", - "label_input_mic_phrase_timeout", - "label_input_mic_max_phrases", - "label_input_mic_word_filter", - - "label_input_speaker_device", - "label_input_speaker_voice_language", - "label_input_speaker_energy_threshold", - "checkbox_input_speaker_threshold_check", - "label_input_speaker_dynamic_energy_threshold", - "label_input_speaker_record_timeout", - "label_input_speaker_phrase_timeout", - "label_input_speaker_max_phrases", - - # tab Parameter - "label_ip_address", - "label_port", - "label_authkey", - "label_message_format", - - # tab Others - "label_checkbox_auto_clear_chatbox", - "label_checkbox_notice_xsoverlay", - ] - for name in widget_names: - widget = getattr(self, name) - text_value = language_yaml_data.get(name) - if widget is not None and text_value is not None: - widget.configure(text=text_value + ":") - -def widget_main_window_label_setter(self, language_yaml_data): - widget_names = [ - "checkbox_translation", - "checkbox_transcription_send", - "checkbox_transcription_receive", - "checkbox_foreground", - ] - for name in widget_names: - widget = getattr(self, name) - text_value = language_yaml_data.get(name) - if widget is not None and text_value is not None: - widget.configure(text=text_value) \ No newline at end of file +def getImageFile(file_name): + img = Image_open(os_path.join(os_path.dirname(__file__), "img", file_name)) + return img \ No newline at end of file diff --git a/vrct_gui/__init__.py b/vrct_gui/__init__.py new file mode 100644 index 00000000..5c2e8cca --- /dev/null +++ b/vrct_gui/__init__.py @@ -0,0 +1 @@ +from .vrct_gui import vrct_gui \ No newline at end of file diff --git a/vrct_gui/_changeMainWindowWidgetsStatus.py b/vrct_gui/_changeMainWindowWidgetsStatus.py new file mode 100644 index 00000000..602555c2 --- /dev/null +++ b/vrct_gui/_changeMainWindowWidgetsStatus.py @@ -0,0 +1,148 @@ +from customtkinter import CTkImage + +from .ui_utils import getImageFileFromUiUtils + + +def _changeMainWindowWidgetsStatus(vrct_gui, settings, status, target_names): + COMPACT_MODE_ICON_SIZE_TUPLES = (settings.COMPACT_MODE_ICON_SIZE, settings.COMPACT_MODE_ICON_SIZE) + + if target_names == "All": + target_names = ["translation_switch", "transcription_send_switch", "transcription_receive_switch", "foreground_switch", "quick_language_settings", "config_button", "minimize_sidebar_button", "entry_message_box"] + + + + + def update_switch_status(widget_frame, widget_label, widget_switch_box, widget_selected_mark, widget_compact_mode_icon, icon_name, disabled_icon_name): + if status == "disabled": + widget_frame.configure(cursor="") + widget_label.configure(text_color=settings.ctm.SF__TEXT_DISABLED_COLOR) + widget_switch_box.configure(state="disabled", progress_color=settings.ctm.SF__SWITCH_BOX_DISABLE_BG_COLOR) + widget_selected_mark.configure(fg_color=settings.ctm.SF__SELECTED_MARK_DISABLE_BG_COLOR) + icon_filename = disabled_icon_name + elif status == "normal": + widget_frame.configure(cursor="hand2") + widget_label.configure(text_color=settings.ctm.LABELS_TEXT_COLOR) + widget_switch_box.configure(state="normal", progress_color=settings.ctm.SF__SWITCH_BOX_ACTIVE_BG_COLOR) + widget_selected_mark.configure(fg_color=settings.ctm.SF__SELECTED_MARK_ACTIVE_BG_COLOR) + icon_filename = icon_name + + image = CTkImage(getImageFileFromUiUtils(icon_filename), size=COMPACT_MODE_ICON_SIZE_TUPLES) + widget_compact_mode_icon.configure(image=image) + + + + + for target_name in target_names: + match target_name: + case "translation_switch": + update_switch_status( + widget_frame=vrct_gui.translation_frame, + widget_label=vrct_gui.label_translation, + widget_switch_box=vrct_gui.translation_switch_box, + widget_selected_mark=vrct_gui.translation_selected_mark, + widget_compact_mode_icon=vrct_gui.translation_compact_mode_icon, + icon_name=settings.image_filename.TRANSLATION_ICON, + disabled_icon_name=settings.image_filename.TRANSLATION_ICON_DISABLED + ) + case "transcription_send_switch": + update_switch_status( + widget_frame=vrct_gui.transcription_send_frame, + widget_label=vrct_gui.label_transcription_send, + widget_switch_box=vrct_gui.transcription_send_switch_box, + widget_selected_mark=vrct_gui.transcription_send_selected_mark, + widget_compact_mode_icon=vrct_gui.transcription_send_compact_mode_icon, + icon_name=settings.image_filename.MIC_ICON, + disabled_icon_name=settings.image_filename.MIC_ICON_DISABLED + ) + case "transcription_receive_switch": + update_switch_status( + widget_frame=vrct_gui.transcription_receive_frame, + widget_label=vrct_gui.label_transcription_receive, + widget_switch_box=vrct_gui.transcription_receive_switch_box, + widget_selected_mark=vrct_gui.transcription_receive_selected_mark, + widget_compact_mode_icon=vrct_gui.transcription_receive_compact_mode_icon, + icon_name=settings.image_filename.HEADPHONES_ICON, + disabled_icon_name=settings.image_filename.HEADPHONES_ICON_DISABLED + ) + case "foreground_switch": + update_switch_status( + widget_frame=vrct_gui.foreground_frame, + widget_label=vrct_gui.label_foreground, + widget_switch_box=vrct_gui.foreground_switch_box, + widget_selected_mark=vrct_gui.foreground_selected_mark, + widget_compact_mode_icon=vrct_gui.foreground_compact_mode_icon, + icon_name=settings.image_filename.FOREGROUND_ICON, + disabled_icon_name=settings.image_filename.FOREGROUND_ICON_DISABLED + ) + + + + + + + case "quick_language_settings": + if status == "disabled": + vrct_gui.sqls__container_title.configure(text_color=settings.ctm.SF__TEXT_DISABLED_COLOR) + vrct_gui.sqls__title_text_your_language.configure(text_color=settings.ctm.SF__TEXT_DISABLED_COLOR) + vrct_gui.sqls__title_text_target_language.configure(text_color=settings.ctm.SF__TEXT_DISABLED_COLOR) + vrct_gui.current_active_preset_tab.children["!ctklabel"].configure(text_color=settings.ctm.SQLS__PRESETS_TAB_ACTIVE_TEXT_COLOR_PASSIVE) + vrct_gui.sqls__optionmenu_your_language.configure(state="disabled") + vrct_gui.sqls__optionmenu_target_language.configure(state="disabled") + + elif status == "normal": + vrct_gui.sqls__container_title.configure(text_color=settings.ctm.LABELS_TEXT_COLOR) + vrct_gui.sqls__title_text_your_language.configure(text_color=settings.ctm.LABELS_TEXT_COLOR) + vrct_gui.sqls__title_text_target_language.configure(text_color=settings.ctm.LABELS_TEXT_COLOR) + vrct_gui.current_active_preset_tab.children["!ctklabel"].configure(text_color=settings.ctm.SQLS__PRESETS_TAB_ACTIVE_TEXT_COLOR) + vrct_gui.current_active_preset_tab.children["!ctklabel"].configure(text_color=settings.ctm.SQLS__PRESETS_TAB_ACTIVE_TEXT_COLOR) + vrct_gui.sqls__optionmenu_your_language.configure(state="normal") + vrct_gui.sqls__optionmenu_target_language.configure(state="normal") + + + case "config_button": + if status == "disabled": + vrct_gui.sidebar_config_button_wrapper.configure(cursor="") + vrct_gui.sidebar_config_button.configure( + image=CTkImage(getImageFileFromUiUtils(settings.image_filename.CONFIGURATION_ICON_DISABLED)), + ) + elif status == "normal": + vrct_gui.sidebar_config_button_wrapper.configure(cursor="hand2") + vrct_gui.sidebar_config_button.configure( + image=CTkImage(getImageFileFromUiUtils(settings.image_filename.CONFIGURATION_ICON)), + ) + + + case "minimize_sidebar_button": + LOGO_SIZE = vrct_gui.minimize_sidebar_button.cget("image").cget("size") + if status == "disabled": + vrct_gui.minimize_sidebar_button_container.configure(cursor="") + + + if settings.IS_SIDEBAR_COMPACT_MODE is True: + image_file = CTkImage(getImageFileFromUiUtils(settings.image_filename.ARROW_LEFT_DISABLED).rotate(180), size=LOGO_SIZE) + else: + image_file = CTkImage(getImageFileFromUiUtils(settings.image_filename.ARROW_LEFT_DISABLED), size=LOGO_SIZE) + vrct_gui.minimize_sidebar_button.configure(image=image_file) + + elif status == "normal": + vrct_gui.minimize_sidebar_button_container.configure(cursor="hand2") + if settings.IS_SIDEBAR_COMPACT_MODE is True: + image_file = CTkImage(getImageFileFromUiUtils(settings.image_filename.ARROW_LEFT).rotate(180), size=LOGO_SIZE) + else: + image_file = CTkImage(getImageFileFromUiUtils(settings.image_filename.ARROW_LEFT), size=LOGO_SIZE) + vrct_gui.minimize_sidebar_button.configure(image=image_file) + + + case "entry_message_box": + if status == "disabled": + vrct_gui.entry_message_box.configure(state="disabled", placeholder_text_color=settings.ctm.TEXTBOX_ENTRY_PLACEHOLDER_DISABLED_COLOR, text_color=settings.ctm.TEXTBOX_ENTRY_TEXT_DISABLED_COLOR) + elif status == "normal": + vrct_gui.entry_message_box.configure(state="normal", placeholder_text_color=settings.ctm.TEXTBOX_ENTRY_PLACEHOLDER_COLOR, text_color=settings.ctm.TEXTBOX_ENTRY_TEXT_COLOR) + + + case _: + raise ValueError(f"No matching case for target_name: {target_name}") + + + + vrct_gui.update() \ No newline at end of file diff --git a/vrct_gui/_printToTextbox.py b/vrct_gui/_printToTextbox.py new file mode 100644 index 00000000..c0a696c7 --- /dev/null +++ b/vrct_gui/_printToTextbox.py @@ -0,0 +1,37 @@ +from datetime import datetime +from customtkinter import CTkFont +from config import config + + +def _printToTextbox(settings, target_textbox, original_message, translated_message, tags=None): + now_raw_data = datetime.now() + now = now_raw_data.strftime('%H:%M:%S') + now_hm = now_raw_data.strftime('%H:%M') + + target_textbox.tag_config("NORMAL_TEXT", foreground=settings.ctm.TEXTBOX_TEXT_COLOR) + + target_textbox.tag_config("ERROR", foreground="#FF0000") + + target_textbox.tag_config("INFO", justify="center") + target_textbox.tag_config("INFO_COLOR", foreground="#1BFF00") + + target_textbox.tag_config("SEND", justify="left") + target_textbox.tag_config("SEND_COLOR", foreground="#0378e2") + + target_textbox.tag_config("RECEIVE", justify="left") + target_textbox.tag_config("RECEIVE_COLOR", foreground="#ffa500") + + target_textbox._textbox.tag_configure("START", spacing1=10) + + target_textbox._textbox.tag_configure("LABEL", font=CTkFont(family=config.FONT_FAMILY, size=12, weight="normal")) + target_textbox._textbox.tag_configure("TIMESTAMP", font=CTkFont(family=config.FONT_FAMILY, size=12, weight="normal")) + target_textbox._textbox.tag_configure("ORIGINAL_MESSAGE", font=CTkFont(family=config.FONT_FAMILY, size=12, weight="normal")) + target_textbox._textbox.tag_configure("TRANSLATED_MESSAGE", font=CTkFont(family=config.FONT_FAMILY, size=16, weight="normal")) + + target_textbox.configure(state='normal') + target_textbox.insert("end", f"[{tags}] ", ("START", "LABEL", tags, f"{tags}_COLOR")) + target_textbox.insert("end", f"{now_hm} ", ("TIMESTAMP", tags)) + target_textbox.insert("end", f"{original_message}\n", ("ORIGINAL_MESSAGE", "NORMAL_TEXT", tags)) + target_textbox.insert("end", f"{translated_message}\n", ("TRANSLATED_MESSAGE", "NORMAL_TEXT", tags)) + target_textbox.configure(state='disabled') + target_textbox.see("end") \ No newline at end of file diff --git a/vrct_gui/config_window/ConfigWindow.py b/vrct_gui/config_window/ConfigWindow.py new file mode 100644 index 00000000..bcee1594 --- /dev/null +++ b/vrct_gui/config_window/ConfigWindow.py @@ -0,0 +1,36 @@ +from .widgets import createConfigWindowTitle, createSettingBoxTitle, createSideMenuAndSettingsBoxContainers + +from customtkinter import CTkToplevel + +from ..ui_utils import setDefaultActiveTab + +from config import config + +class ConfigWindow(CTkToplevel): + def __init__(self, vrct_gui, settings): + super().__init__() + + self.INPUT_MIC_RECORD_TIMEOUT = 3 + self.INPUT_SOURCE_LANG = "aaaaaaaaa" + self.INPUT_SPEAKER_ENERGY_THRESHOLD = 300 + self.MAX_SPEAKER_ENERGY_THRESHOLD = 4000 + self.INPUT_MIC_PHRASE_TIMEOUT = 3 + + + # configure window + self.title("test config_window.py") + self.geometry(f"{1080}x{680}") + + + self.configure(fg_color="#ff7f50") + self.protocol("WM_DELETE_WINDOW", vrct_gui.closeConfigWindow) + + + + + createConfigWindowTitle(config_window=self, settings=settings) + + createSettingBoxTitle(config_window=self, settings=settings) + + + createSideMenuAndSettingsBoxContainers(config_window=self, settings=settings) diff --git a/vrct_gui/config_window/__init__.py b/vrct_gui/config_window/__init__.py new file mode 100644 index 00000000..c6dbe941 --- /dev/null +++ b/vrct_gui/config_window/__init__.py @@ -0,0 +1 @@ +from .ConfigWindow import ConfigWindow \ No newline at end of file diff --git a/vrct_gui/config_window/widgets/__init__.py b/vrct_gui/config_window/widgets/__init__.py new file mode 100644 index 00000000..08f2304b --- /dev/null +++ b/vrct_gui/config_window/widgets/__init__.py @@ -0,0 +1,4 @@ +from .createConfigWindowTitle import createConfigWindowTitle +from .createSettingBoxTitle import createSettingBoxTitle + +from .createSideMenuAndSettingsBoxContainers import createSideMenuAndSettingsBoxContainers \ No newline at end of file diff --git a/vrct_gui/config_window/widgets/createConfigWindowTitle.py b/vrct_gui/config_window/widgets/createConfigWindowTitle.py new file mode 100644 index 00000000..bbbd9606 --- /dev/null +++ b/vrct_gui/config_window/widgets/createConfigWindowTitle.py @@ -0,0 +1,39 @@ +from customtkinter import CTkFont, CTkFrame, CTkLabel, CTkImage + +from ...ui_utils import getImageFileFromUiUtils + + +def createConfigWindowTitle(config_window, settings): + + config_window.grid_columnconfigure(0, weight=0, minsize=settings.uism.TOP_BAR_SIDE__WIDTH) + config_window.grid_rowconfigure(0, weight=0, minsize=settings.uism.TOP_BAR__HEIGHT) + config_window.side_menu_config_window_title_logo_frame = CTkFrame(config_window, corner_radius=0, fg_color=settings.ctm.TOP_BAR_BG_COLOR, width=0, height=0) + config_window.side_menu_config_window_title_logo_frame.grid(row=0, column=0, sticky="nsew") + + config_window.side_menu_config_window_title_logo_frame.grid_rowconfigure(0,weight=1) + config_window.side_menu_config_window_title_logo_frame.grid_columnconfigure(0,weight=1) + config_window.side_menu_config_window_title_logo_wrapper = CTkFrame(config_window.side_menu_config_window_title_logo_frame, corner_radius=0, fg_color=settings.ctm.TOP_BAR_BG_COLOR, width=0, height=0) + config_window.side_menu_config_window_title_logo_wrapper.grid(row=0, column=0, padx=settings.uism.TOP_BAR_SIDE__TITLE_PADX, pady=settings.uism.TOP_BAR__IPADY, sticky="nsew") + + + + + config_window.side_menu_config_window_title_logo_wrapper.grid_rowconfigure(0,weight=1) + config_window.side_menu_config_window_title = CTkLabel( + config_window.side_menu_config_window_title_logo_frame, + text="Settings", + height=0, + anchor="w", + font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.TOP_BAR_SIDE__CONFIG_TITLE_FONT_SIZE, weight="bold"), + text_color=settings.ctm.LABELS_TEXT_COLOR, + ) + config_window.side_menu_config_window_title.place(relx=0.275, rely=0.5, anchor="w") + + config_window.side_menu_config_window_title_logo = CTkLabel( + config_window.side_menu_config_window_title_logo_frame, + text=None, + height=0, + anchor="w", + image=CTkImage(getImageFileFromUiUtils(settings.image_filename.VRCT_LOGO_MARK),size=settings.uism.TOP_BAR_SIDE__CONFIG_LOGO_MARK_SIZE), + ) + config_window.side_menu_config_window_title_logo.place(relx=0.08, rely=0.59, anchor="w") diff --git a/vrct_gui/config_window/widgets/createSettingBoxTitle.py b/vrct_gui/config_window/widgets/createSettingBoxTitle.py new file mode 100644 index 00000000..57f5c573 --- /dev/null +++ b/vrct_gui/config_window/widgets/createSettingBoxTitle.py @@ -0,0 +1,20 @@ +from customtkinter import CTkFont, CTkFrame, CTkLabel + +def createSettingBoxTitle(config_window, settings): + + config_window.grid_columnconfigure(1, weight=1) + config_window.main_current_active_config_title_container = CTkFrame(config_window, corner_radius=0, fg_color=settings.ctm.TOP_BAR_BG_COLOR, width=0, height=0) + config_window.main_current_active_config_title_container.grid(row=0, column=1, sticky="nsew") + + + config_window.main_current_active_config_title_container.grid_rowconfigure(0, weight=1) + config_window.main_current_active_config_title = CTkLabel( + config_window.main_current_active_config_title_container, + height=0, + text=None, + anchor="w", + font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.TOP_BAR_MAIN__TITLE_FONT_SIZE, weight="bold"), + text_color=settings.ctm.LABELS_TEXT_COLOR + ) + config_window.main_current_active_config_title.grid(row=0, column=0, padx=0, pady=settings.uism.TOP_BAR__IPADY) + diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/__init__.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/__init__.py new file mode 100644 index 00000000..245472c9 --- /dev/null +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/__init__.py @@ -0,0 +1 @@ +from .createSideMenuAndSettingsBoxContainers import createSideMenuAndSettingsBoxContainers \ No newline at end of file diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/addConfigSideMenuItem.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/addConfigSideMenuItem.py new file mode 100644 index 00000000..1f518a07 --- /dev/null +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/addConfigSideMenuItem.py @@ -0,0 +1,109 @@ +from customtkinter import CTkFont, CTkFrame, CTkLabel + +from ....ui_utils import bindEnterAndLeaveColor, bindButtonPressColor, bindButtonReleaseFunction, switchActiveTabAndPassiveTab, switchTabsColor + + + +def addConfigSideMenuItem(config_window, settings, side_menu_settings, side_menu_row, all_side_menu_tab_attr_name): + + + def switchActiveAndPassiveSettingBoxContainerTabsColor(target_active_widget): + + setting_box_container_tabs = [] + for tab_attr_name in all_side_menu_tab_attr_name: + tab_attr = getattr(config_window, tab_attr_name) + setting_box_container_tabs.append(tab_attr) + + switchTabsColor( + target_widget=target_active_widget, + tab_buttons=setting_box_container_tabs, + active_bg_color=settings.ctm.SIDE_MENU_LABELS_BG_COLOR, + active_text_color=settings.ctm.SIDE_MENU_LABELS_SELECTED_TEXT_COLOR, + passive_bg_color=settings.ctm.SIDE_MENU_LABELS_BG_COLOR, + passive_text_color=settings.ctm.LABELS_TEXT_COLOR + ) + + for setting_box_container_tab in setting_box_container_tabs: + setting_box_container_tab.children["!ctkframe"].place(relx=-1) + + target_active_widget.children["!ctkframe"].place(relx=0) + + + + + def switchSettingBoxContainerTabFunction(target_active_widget): + switchActiveAndPassiveSettingBoxContainerTabsColor(target_active_widget) + switchActiveTabAndPassiveTab(target_active_widget, config_window.current_active_side_menu_tab, config_window.current_active_side_menu_tab.passive_function, settings.ctm.SIDE_MENU_LABELS_HOVERED_BG_COLOR, settings.ctm.SIDE_MENU_LABELS_CLICKED_BG_COLOR, settings.ctm.SIDE_MENU_LABELS_BG_COLOR) + config_window.current_active_side_menu_tab = target_active_widget + + + + + + + def switchSettingBoxContainer(target_setting_box_container_attr_name): + config_window.current_active_setting_box_container.grid_remove() + config_window.current_active_setting_box_container = getattr(config_window, target_setting_box_container_attr_name) + config_window.current_active_setting_box_container.grid() + + # Move to the top position when the setting box is switched. + config_window.main_setting_box_scrollable_container._parent_canvas.yview_moveto("0") + + + def switchToTargetSettingBoxContainer(e, text, target_active_tab_widget_attr_name, target_setting_box_container_attr_name): + print("switchToTargetSettingBoxContainer", target_setting_box_container_attr_name) + config_window.main_current_active_config_title.configure(text=text) + target_active_tab_widget = getattr(config_window, target_active_tab_widget_attr_name) + switchSettingBoxContainerTabFunction(target_active_tab_widget) + switchSettingBoxContainer(target_setting_box_container_attr_name) + + + + + side_menu_tab_attr_name = side_menu_settings["side_menu_tab_attr_name"] + label_attr_name = side_menu_settings["label_attr_name"] + selected_mark_attr_name = side_menu_settings["selected_mark_attr_name"] + text = side_menu_settings["text"] + setting_box_container_attr_name = side_menu_settings["setting_box_container_settings"]["setting_box_container_attr_name"] + command = lambda e: switchToTargetSettingBoxContainer( + e=e, + text=text, + target_active_tab_widget_attr_name=side_menu_tab_attr_name, + target_setting_box_container_attr_name=setting_box_container_attr_name, + ) + + + # Side menu + frame_widget = CTkFrame(config_window.side_menu_container, corner_radius=0, fg_color=settings.ctm.SIDE_MENU_LABELS_BG_COLOR, cursor="hand2", width=0, height=0) + setattr(config_window, side_menu_tab_attr_name, frame_widget) + + frame_widget.grid(row=side_menu_row, column=0, pady=(0,1), sticky="ew") + frame_widget.grid_columnconfigure(0, weight=1) + + label_widget = CTkLabel( + frame_widget, + text=text, + height=0, + corner_radius=0, + font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.SIDE_MENU_LABELS_FONT_SIZE, weight="normal"), + anchor="w", + text_color=settings.ctm.LABELS_TEXT_COLOR, + ) + setattr(config_window, label_attr_name, label_widget) + + selected_mark_widget = CTkFrame(frame_widget, corner_radius=0, fg_color=settings.ctm.SIDE_MENU_SELECTED_MARK_ACTIVE_BG_COLOR, width=3, height=0) + setattr(config_window, selected_mark_attr_name, selected_mark_widget) + + + + + + # Arrange + selected_mark_widget.place(relx=-1, rely=0.5, relheight=1, anchor="w") + label_widget.grid(row=0, column=0, padx=settings.uism.SIDE_MENU_LABELS_IPADX, pady=settings.uism.SIDE_MENU_LABELS_IPADY, sticky="ew") + + bindEnterAndLeaveColor([frame_widget, label_widget], settings.ctm.SIDE_MENU_LABELS_HOVERED_BG_COLOR, settings.ctm.SIDE_MENU_LABELS_BG_COLOR) + bindButtonPressColor([frame_widget, label_widget], settings.ctm.SIDE_MENU_LABELS_CLICKED_BG_COLOR, settings.ctm.SIDE_MENU_LABELS_BG_COLOR) + + frame_widget.passive_function = command + bindButtonReleaseFunction([frame_widget, label_widget], command) diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/createSettingBoxContainer.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/createSettingBoxContainer.py new file mode 100644 index 00000000..7935e7d6 --- /dev/null +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/createSettingBoxContainer.py @@ -0,0 +1,61 @@ +from customtkinter import CTkFont, CTkFrame, CTkLabel + + +def createSettingBoxContainer(config_window, settings, setting_box_container_settings): + + + def createSectionTitle(container_widget, section_title): + setting_box_wrapper_section_title_frame = CTkFrame(container_widget, corner_radius=0, fg_color=settings.ctm.MAIN_BG_COLOR, width=0, height=0) + + setting_box_wrapper_section_title = CTkLabel( + setting_box_wrapper_section_title_frame, + text=section_title, + anchor="w", + height=0, + font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.SB__SECTION_TITLE_FONT_SIZE, weight="normal"), + text_color=settings.ctm.LABELS_TEXT_COLOR + ) + setting_box_wrapper_section_title.grid(row=0, column=0, padx=0, pady=settings.uism.SB__SECTION_TITLE_BOTTOM_PADY) + + return setting_box_wrapper_section_title_frame + + # Common setting + + # Setting box container + setting_box_container_widget = CTkFrame(config_window.main_setting_box_bg_wrapper, corner_radius=0, fg_color=settings.ctm.MAIN_BG_COLOR, width=0, height=0) + setattr(config_window, setting_box_container_settings["setting_box_container_attr_name"], setting_box_container_widget) + + + + + setting_boxes_length = len(setting_box_container_settings["setting_boxes"]) + setting_box_row = 0 + for i, setting_box_setting in enumerate(setting_box_container_settings["setting_boxes"]): + SB__TOP_PADY = 0 + SB__BOTTOM_PADY = settings.uism.SB__BOTTOM_PADY + + setting_box_and_section_title_wrapper = CTkFrame(setting_box_container_widget, fg_color=settings.ctm.SB__WRAPPER_BG_COLOR, corner_radius=0, width=0, height=0) + + if setting_box_setting["section_title"] is not None: + setting_box_wrapper_section_title_frame= createSectionTitle( + container_widget=setting_box_and_section_title_wrapper, + section_title=setting_box_setting["section_title"], + ) + setting_box_wrapper_section_title_frame.grid(row=0, column=0, sticky="ew", padx=0, pady=0) + if i == 0: SB__TOP_PADY = settings.uism.SB__TOP_PADY_IF_WITH_SECTION_TITLE + + # if the first one of setting boxes, adjust top pady + if i == 0: SB__TOP_PADY = settings.uism.SB__TOP_PADY_IF_WITHOUT_SECTION_TITLE + + # if the last one of setting boxes, remove bottom pady + if i+1 == setting_boxes_length: SB__BOTTOM_PADY = 0 + + setting_box_wrapper = CTkFrame(setting_box_and_section_title_wrapper, fg_color=settings.ctm.SB__WRAPPER_BG_COLOR, corner_radius=0, width=0, height=0) + setting_box_wrapper.grid(row=1, column=0) + setting_box_row+=1 + + setting_box_and_section_title_wrapper.grid(row=setting_box_row, column=0, sticky="ew", padx=0, pady=(SB__TOP_PADY, SB__BOTTOM_PADY)) + + if setting_box_setting["setting_box"] is not None: + setting_box_setting["setting_box"](setting_box_wrapper=setting_box_wrapper, config_window=config_window, settings=settings) + diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/createSideMenuAndSettingsBoxContainers.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/createSideMenuAndSettingsBoxContainers.py new file mode 100644 index 00000000..161d5e96 --- /dev/null +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/createSideMenuAndSettingsBoxContainers.py @@ -0,0 +1,149 @@ +from customtkinter import CTkFrame, CTkScrollableFrame + +from ....ui_utils import setDefaultActiveTab + +from .addConfigSideMenuItem import addConfigSideMenuItem +from .createSettingBoxContainer import createSettingBoxContainer + + +from .setting_box_containers import createSettingBox_General + + +def createSideMenuAndSettingsBoxContainers(config_window, settings): + + # Main container + config_window.main_bg_container = CTkFrame(config_window, corner_radius=0, fg_color=settings.ctm.MAIN_BG_COLOR, width=0, height=0) + config_window.main_bg_container.grid(row=1, column=1, sticky="nsew") + + config_window.main_bg_container.grid_columnconfigure(0, weight=1) + config_window.main_bg_container.grid_rowconfigure(0, weight=0) + + + + + # Side menu Base + config_window.grid_rowconfigure(1, weight=1) + config_window.side_menu_bg_container = CTkFrame(config_window, corner_radius=0, fg_color=settings.ctm.SIDE_MENU_BG_COLOR, width=0, height=0) + config_window.side_menu_bg_container.grid(row=1, column=0, sticky="nsew") + + + config_window.side_menu_container = CTkFrame(config_window.side_menu_bg_container, corner_radius=0, fg_color=settings.ctm.SIDE_MENU_LABELS_BG_FOR_FAKE_BORDER_COLOR, width=0, height=0) + config_window.side_menu_container.grid(row=0, column=0, padx=settings.uism.TOP_BAR_SIDE__TITLE_PADX, pady=(settings.uism.SIDE_MENU_TOP_PADY, 0)) + + + + # Setting box container + config_window.main_bg_container.grid_rowconfigure(1, weight=1) + config_window.main_setting_box_scrollable_container = CTkScrollableFrame(config_window.main_bg_container, corner_radius=0, fg_color=settings.ctm.MAIN_BG_COLOR) + config_window.main_setting_box_scrollable_container.grid(row=1, column=0, sticky="nsew") + + + config_window.main_setting_box_bg_wrapper = CTkFrame(config_window.main_setting_box_scrollable_container, corner_radius=0, width=0, height=0, fg_color=settings.ctm.MAIN_BG_COLOR) + config_window.main_setting_box_bg_wrapper.grid(row=0, column=0, pady=settings.uism.SB__BOTTOM_MARGIN, sticky="n") + + + + side_menu_and_setting_box_containers_settings = [ + { + "side_menu_tab_attr_name": "side_menu_tab_general", + "label_attr_name": "label_general", + "selected_mark_attr_name": "translation_selected_mark", + "text": "General", + "setting_box_container_settings": { + "setting_box_container_attr_name": "setting_box_container_general", + "setting_boxes": [ + { "section_title": None, "setting_box": createSettingBox_General }, + # { "section_title": "General Section Title", "setting_box": createSettingBox_General }, + # { "section_title": None, "setting_box": createSettingBox_General }, + ] + }, + "activate_by_default": True, + }, + { + "side_menu_tab_attr_name": "side_menu_tab_translation", + "label_attr_name": "label_translation", + "selected_mark_attr_name": "transcription_send_selected_mark", + "text": "Translation", + "setting_box_container_settings": { + "setting_box_container_attr_name": "setting_box_container_translation", + "setting_boxes": [ + { "section_title": None, "setting_box": None }, + ] + }, + }, + { + "side_menu_tab_attr_name": "side_menu_tab_transcription", + "label_attr_name": "label_transcription", + "selected_mark_attr_name": "transcription_receive_selected_mark", + "text": "Transcription", + "setting_box_container_settings": { + "setting_box_container_attr_name": "setting_box_container_transcription", + "setting_boxes": [ + { "section_title": None, "setting_box": None }, + ] + }, + }, + { + "side_menu_tab_attr_name": "side_menu_tab_parameters", + "label_attr_name": "label_parameters", + "selected_mark_attr_name": "foreground_selected_mark", + "text": "Parameters", + "setting_box_container_settings": { + "setting_box_container_attr_name": "setting_box_container_parameters", + "setting_boxes": [ + { "section_title": None, "setting_box": None }, + ] + }, + }, + { + "side_menu_tab_attr_name": "side_menu_tab_others", + "label_attr_name": "label_others", + "selected_mark_attr_name": "foreground_selected_mark", + "text": "Others", + "setting_box_container_settings": { + "setting_box_container_attr_name": "setting_box_container_others", + "setting_boxes": [ + { "section_title": None, "setting_box": None }, + ] + }, + }, + ] + + all_side_menu_tab_attr_name = [item["side_menu_tab_attr_name"] for item in side_menu_and_setting_box_containers_settings] + + side_menu_row=0 + for sm_and_sbc_setting in side_menu_and_setting_box_containers_settings: + addConfigSideMenuItem( + config_window=config_window, + settings=settings, + side_menu_settings=sm_and_sbc_setting, + side_menu_row=side_menu_row, + all_side_menu_tab_attr_name=all_side_menu_tab_attr_name, + ) + side_menu_row+=1 + + + createSettingBoxContainer( + config_window=config_window, + settings=settings, + setting_box_container_settings=sm_and_sbc_setting["setting_box_container_settings"], + + ) + + + if sm_and_sbc_setting.get("activate_by_default", None) is not None: + # Set default active side menu tab + config_window.main_current_active_config_title.configure(text=sm_and_sbc_setting["text"]) + config_window.current_active_side_menu_tab = getattr(config_window, sm_and_sbc_setting["side_menu_tab_attr_name"]) + setDefaultActiveTab( + active_tab_widget=config_window.current_active_side_menu_tab, + active_bg_color=settings.ctm.SIDE_MENU_LABELS_BG_COLOR, + active_text_color=settings.ctm.SIDE_MENU_LABELS_SELECTED_TEXT_COLOR + ) + config_window.current_active_side_menu_tab.children["!ctkframe"].place(relx=0) + + # Set default active setting box container + config_window.current_active_setting_box_container = getattr(config_window, sm_and_sbc_setting["setting_box_container_settings"]["setting_box_container_attr_name"]) + config_window.current_active_setting_box_container.grid() + + diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/SettingBoxGenerator.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/SettingBoxGenerator.py new file mode 100644 index 00000000..5e0a530d --- /dev/null +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/SettingBoxGenerator.py @@ -0,0 +1,494 @@ +from customtkinter import CTkOptionMenu, CTkFont, CTkFrame, CTkLabel, CTkRadioButton, CTkEntry, CTkSlider, CTkSwitch, CTkCheckBox, CTkProgressBar, END as CTK_END +from ctk_scrollable_dropdown import CTkScrollableDropdown + +from vrct_gui.ui_utils import createButtonWithImage + + + +class SettingBoxGenerator(): + def __init__(self, config_window, settings): + + self.IS_CONFIG_WINDOW_COMPACT_MODE = settings.IS_CONFIG_WINDOW_COMPACT_MODE + self.ctm = settings.ctm + self.uism = settings.uism + self.FONT_FAMILY = settings.FONT_FAMILY + self.config_window = config_window + + + + def _createSettingBoxFrameWrapper(self, setting_box_frame): + setting_box_frame_wrapper = CTkFrame(setting_box_frame, corner_radius=0, fg_color=self.ctm.SB__BG_COLOR, width=self.uism.SB__MAIN_WIDTH, height=0) + setting_box_frame_wrapper.grid(row=0, column=0, padx=self.uism.SB__IPADX, pady=self.uism.SB__IPADY, sticky="ew") + setting_box_frame_wrapper.grid_columnconfigure((0,1), weight=1, minsize=int(self.uism.SB__MAIN_WIDTH / 2)) + return setting_box_frame_wrapper + + def _createSettingBoxFrame(self, parent_widget, label_text, desc_text): + setting_box_frame = CTkFrame(parent_widget, corner_radius=0, fg_color=self.ctm.SB__BG_COLOR, width=0, height=0) + setting_box_frame_wrapper = self._createSettingBoxFrameWrapper(setting_box_frame) + self._setSettingBoxLabels(setting_box_frame_wrapper, label_text, desc_text) + + # "pady=(0,1)" is for bottom padding. It can be removed(override) when you do like "self.attr_name.grid(row=row, pady=0)" + setting_box_frame.grid(column=0, padx=0, pady=(0,1), sticky="ew") + return (setting_box_frame, setting_box_frame_wrapper) + + def _setSettingBoxLabels(self, setting_box_frame, label_text, desc_text=False): + + setting_box_labels_frame = CTkFrame(setting_box_frame, corner_radius=0, fg_color=self.ctm.SB__BG_COLOR, width=0, height=0) + + setting_box_label = CTkLabel( + setting_box_labels_frame, + text=label_text, + anchor="w", + # height=0, + font=CTkFont(family=self.FONT_FAMILY, size=self.uism.SB__LABEL_FONT_SIZE, weight="normal"), + text_color=self.ctm.LABELS_TEXT_COLOR + ) + setting_box_label.grid(row=0, column=0, padx=0, pady=0, sticky="ew") + + if desc_text == False or self.IS_CONFIG_WINDOW_COMPACT_MODE is True: + pass + else: + self.setting_box_desc = CTkLabel( + setting_box_labels_frame, + text=desc_text, + anchor="w", + justify="left", + # height=0, + wraplength=int(self.uism.SB__MAIN_WIDTH / 2), + font=CTkFont(family=self.FONT_FAMILY, size=self.uism.SB__DESC_FONT_SIZE, weight="normal"), + text_color=self.ctm.LABELS_DESC_TEXT_COLOR + ) + self.setting_box_desc.grid(row=1, column=0, padx=0, pady=(self.uism.SB__DESC_TOP_PADY,0), sticky="ew") + + setting_box_labels_frame.grid(row=0, column=0, padx=0, pady=0, sticky="w") + + + + def createSettingBoxDropdownMenu(self, parent_widget, label_text, desc_text, optionmenu_attr_name, dropdown_menu_attr_name, dropdown_menu_values, command, variable): + (setting_box_frame, setting_box_frame_wrapper) = self._createSettingBoxFrame(parent_widget, label_text, desc_text) + + setting_box_dropdown_menu_frame = CTkFrame(setting_box_frame_wrapper, corner_radius=0, width=0, height=0, fg_color=self.ctm.SB__BG_COLOR) + setting_box_dropdown_menu_frame.grid(row=0, column=1, padx=0, sticky="e") + + self.createOption_DropdownMenu( + setting_box_dropdown_menu_frame=setting_box_dropdown_menu_frame, + optionmenu_attr_name=optionmenu_attr_name, + dropdown_menu_attr_name=dropdown_menu_attr_name, + dropdown_menu_values=dropdown_menu_values, + command=command, + variable=variable, + ) + + return setting_box_frame + + + + + def createSettingBoxSwitch(self, parent_widget, label_text, desc_text, switch_attr_name, is_checked, command): + (setting_box_frame, setting_box_frame_wrapper) = self._createSettingBoxFrame(parent_widget, label_text, desc_text) + + setting_box_switch_frame = CTkFrame(setting_box_frame_wrapper, corner_radius=0, width=0, height=0, fg_color=self.ctm.SB__BG_COLOR) + setting_box_switch_frame.grid(row=0, column=1, padx=0, sticky="e") + + switch_widget = CTkSwitch( + setting_box_switch_frame, + text=None, + height=0, + width=0, + corner_radius=int(self.uism.SB__SWITCH_BOX_HEIGHT/2), + border_width=0, + switch_height=self.uism.SB__SWITCH_BOX_HEIGHT, + switch_width=self.uism.SB__SWITCH_BOX_WIDTH, + onvalue=True, + offvalue=False, + command=command, + fg_color=self.ctm.SB__SWITCH_BOX_BG_COLOR, + # bg_color="red", + progress_color=self.ctm.SB__SWITCH_BOX_ACTIVE_BG_COLOR, + ) + setattr(self.config_window, switch_attr_name, switch_widget) + + switch_widget.select() if is_checked else switch_widget.deselect() + + switch_widget.grid(row=0, column=0) + + return setting_box_frame + + + + def createSettingBoxCheckbox(self, parent_widget, label_text, desc_text, checkbox_attr_name, is_checked, command): + (setting_box_frame, setting_box_frame_wrapper) = self._createSettingBoxFrame(parent_widget, label_text, desc_text) + + setting_box_checkbox_frame = CTkFrame(setting_box_frame_wrapper, corner_radius=0, width=0, height=0, fg_color=self.ctm.SB__BG_COLOR) + setting_box_checkbox_frame.grid(row=0, column=1, padx=0, sticky="e") + + checkbox_widget = CTkCheckBox( + setting_box_checkbox_frame, + text=None, + width=0, + checkbox_width=self.uism.SB__CHECKBOX_SIZE, + checkbox_height=self.uism.SB__CHECKBOX_SIZE, + onvalue=True, + offvalue=False, + command=command, + corner_radius=self.uism.SB__CHECKBOX_CORNER_RADIUS, + border_width=self.uism.SB__CHECKBOX_BORDER_WIDTH, + border_color=self.ctm.SB__CHECKBOX_BORDER_COLOR, + hover_color=self.ctm.SB__CHECKBOX_HOVER_COLOR, + checkmark_color=self.ctm.SB__CHECKBOX_CHECKMARK_COLOR, + fg_color=self.ctm.SB__CHECKBOX_CHECKED_COLOR, + # fg_color=self.ctm.SB__SWITCH_BOX_BG_COLOR, + # bg_color="red", + # progress_color=self.ctm.SB__SWITCH_BOX_ACTIVE_BG_COLOR, + ) + setattr(self.config_window, checkbox_attr_name, checkbox_widget) + + checkbox_widget.select() if is_checked else checkbox_widget.deselect() + + checkbox_widget.grid(row=0, column=0) + + return setting_box_frame + + + + + + + def createSettingBoxSlider(self, parent_widget, label_text, desc_text, slider_attr_name, slider_range, slider_number_of_steps, command, variable): + (setting_box_frame, setting_box_frame_wrapper) = self._createSettingBoxFrame(parent_widget, label_text, desc_text) + + setting_box_slider_frame = CTkFrame(setting_box_frame_wrapper, corner_radius=0, width=0, height=0, fg_color=self.ctm.SB__BG_COLOR) + setting_box_slider_frame.grid(row=0, column=1, padx=0, sticky="e") + + slider_widget = CTkSlider( + setting_box_slider_frame, + from_=slider_range[0], + to=slider_range[1], + number_of_steps=slider_number_of_steps, + button_color=self.ctm.SB__SLIDER_BUTTON_COLOR, + button_hover_color=self.ctm.SB__SLIDER_BUTTON_HOVERED_COLOR, + command=command, + variable=variable, + ) + setattr(self.config_window, slider_attr_name, slider_widget) + + slider_widget.grid(row=0, column=0) + + return setting_box_frame + + + + + def createSettingBoxProgressbarXSlider(self, + parent_widget, label_text, desc_text, command, + entry_attr_name, + slider_attr_name, slider_range, slider_number_of_steps, + progressbar_attr_name, + passive_button_attr_name, passive_button_command, + active_button_attr_name, active_button_command, + button_image_filename, + variable, + ): + + + (setting_box_frame, setting_box_frame_wrapper) = self._createSettingBoxFrame(parent_widget, label_text, desc_text) + + setting_box_progressbar_x_slider_frame = CTkFrame(setting_box_frame_wrapper, corner_radius=0, width=0, height=0, fg_color=self.ctm.SB__BG_COLOR) + setting_box_progressbar_x_slider_frame.grid(row=0, column=1, padx=0, sticky="e") + + + ENTRY_WIDTH = self.uism.SB__PROGRESSBAR_X_SLIDER__ENTRY_WIDTH + BAR_WIDTH = self.uism.SB__PROGRESSBAR_X_SLIDER__BAR_WIDTH + + BAR_PADDING = int(ENTRY_WIDTH + self.uism.SB__PROGRESSBAR_X_SLIDER__BAR_RIGHT_PADX) + BUTTON_PADDING = int(BAR_WIDTH + BAR_PADDING + self.uism.SB__PROGRESSBAR_X_SLIDER__BUTTON_RIGHT_PADX) + + def adjusted_command__for_entry_bind__Any_KeyRelease(e): + # try: + # int(e.widget.get()) + # except: + # e.widget.delete(0, CTK_END) + # return + # print(int(e.widget.get())) + + + i = int(e.widget.get()) + if i < 0 or i > slider_range[1]: + e.widget.delete(0, CTK_END) + i = max(0, min(int(e.widget.get()), slider_range[1])) + # e.widget.insert(0, i) + command(i) + def adjusted_command__for_slider(value): + command(int(value)) + + entry_widget = CTkEntry( + setting_box_progressbar_x_slider_frame, + width=ENTRY_WIDTH, + height=self.uism.SB__PROGRESSBAR_X_SLIDER__ENTRY_HEIGHT, + textvariable=variable, + font=CTkFont(family=self.FONT_FAMILY, size=self.uism.SB__ENTRY_FONT_SIZE, weight="normal"), + ) + + entry_widget.bind("", adjusted_command__for_entry_bind__Any_KeyRelease) + entry_widget.grid(row=0, column=0, padx=0, pady=0, sticky="e") + setattr(self.config_window, entry_attr_name, entry_widget) + + + # at least 2px is needed otherwise the slider button is gonna broken. + SLIDER_BORDER_WIDTH = max(2,self.uism.SB__PROGRESSBAR_X_SLIDER__SLIDER_BUTTON_LENGTH) + SLIDER_BUTTON_LENGTH = int(SLIDER_BORDER_WIDTH/2) + slider_widget = CTkSlider( + setting_box_progressbar_x_slider_frame, + from_=slider_range[0], + to=slider_range[1], + number_of_steps=slider_number_of_steps, + command=adjusted_command__for_slider, + variable=variable, + height=self.uism.SB__PROGRESSBAR_X_SLIDER__SLIDER_HEIGHT, + width=BAR_WIDTH, + border_width=0, + button_length=SLIDER_BORDER_WIDTH, + button_corner_radius=SLIDER_BUTTON_LENGTH, + corner_radius=0, + button_color=self.ctm.SB__PROGRESSBAR_X_SLIDER__SLIDER_BUTTON_COLOR, + button_hover_color=self.ctm.SB__PROGRESSBAR_X_SLIDER__SLIDER_BUTTON_HOVERED_COLOR, + fg_color=self.ctm.SB__BG_COLOR, + progress_color=self.ctm.SB__BG_COLOR, + border_color=self.ctm.SB__BG_COLOR, + ) + slider_widget.grid(row=0, column=0, padx=(0, BAR_PADDING), sticky="e") + setattr(self.config_window, slider_attr_name, slider_widget) + + + + + progressbar_widget = CTkProgressBar( + setting_box_progressbar_x_slider_frame, + width=BAR_WIDTH, + height=self.uism.SB__PROGRESSBAR_X_SLIDER__PROGRESSBAR_HEIGHT, + corner_radius=0, + ) + setattr(self.config_window, progressbar_attr_name, progressbar_widget) + progressbar_widget.grid(row=0, column=0, padx=(0, BAR_PADDING), sticky="e") + progressbar_widget.set(0) + + + + + passive_button_wrapper = self._createPassiveButtonForProgressbarXSlider(setting_box_progressbar_x_slider_frame, BUTTON_PADDING, passive_button_command, button_image_filename) + setattr(self.config_window, passive_button_attr_name, passive_button_wrapper) + + active_button_wrapper = self._createActiveButtonForProgressbarXSlider(setting_box_progressbar_x_slider_frame, BUTTON_PADDING, active_button_command, button_image_filename) + setattr(self.config_window, active_button_attr_name, active_button_wrapper) + + passive_button_wrapper.grid() + return setting_box_frame + + + + + def createSettingBoxEntry(self, parent_widget, label_text, desc_text, entry_attr_name, entry_width, entry_bind__Any_KeyRelease, entry_textvariable): + (setting_box_frame, setting_box_frame_wrapper) = self._createSettingBoxFrame(parent_widget, label_text, desc_text) + + setting_box_entry_frame = CTkFrame(setting_box_frame_wrapper, corner_radius=0, width=0, height=0, fg_color=self.ctm.SB__BG_COLOR) + setting_box_entry_frame.grid(row=0, column=1, padx=0, sticky="e") + + entry_widget = CTkEntry( + setting_box_entry_frame, + width=entry_width, + height=self.uism.SB__PROGRESSBAR_X_SLIDER__ENTRY_HEIGHT, + textvariable=entry_textvariable, + font=CTkFont(family=self.FONT_FAMILY, size=self.uism.SB__ENTRY_FONT_SIZE, weight="normal"), + ) + entry_widget.bind("", entry_bind__Any_KeyRelease) + setattr(self.config_window, entry_attr_name, entry_widget) + + + entry_widget.grid(row=0, column=0) + + return setting_box_frame + + + + # if setting_box_type == "dropdown_menu_x_dropdown_menu": + # self.setting_box_dropdown_menu_x_dropdown_menu = CTkFrame(self.setting_box, corner_radius=0, fg_color=self.ctm.SB__BG_COLOR, width=0, height=0) + # self.setting_box_dropdown_menu_x_dropdown_menu.grid(row=0, column=1, padx=(0, self.uism.SB__RIGHT_PADX), rowspan=2, sticky="e") + + + + # # Labels + # self.optionmenu_label_left = CTkLabel( + # self.setting_box_dropdown_menu_x_dropdown_menu, + # text=kwargs["left_dropdown_menu_label"], + # font=CTkFont(family=self.FONT_FAMILY, size=self.uism.SB__OPTION_MENU_FONT_SIZE, weight="normal"), + # ) + # self.optionmenu_label_left.grid(row=0, column=0) + + # self.the_space_between_optionmenu = CTkLabel( + # self.setting_box_dropdown_menu_x_dropdown_menu, + # text=None, + # ) + # self.the_space_between_optionmenu.grid(row=0, column=1) + + + # self.optionmenu_label_right = CTkLabel( + # self.setting_box_dropdown_menu_x_dropdown_menu, + # text=kwargs["right_dropdown_menu_label"], + # font=CTkFont(family=self.FONT_FAMILY, size=self.uism.SB__OPTION_MENU_FONT_SIZE, weight="normal"), + # ) + # self.optionmenu_label_right.grid(row=0, column=2) + + + + # # Option menus + # self.createOption_DropdownMenu( + # setattr_obj, + # self.setting_box_dropdown_menu_x_dropdown_menu, + # kwargs["left_optionmenu_attr_name"], + # kwargs["left_dropdown_menu_attr_name"], + # dropdown_menu_values=kwargs["left_dropdown_menu_values"], + # width=150, + # command=kwargs["left_dropdown_menu_command"], + # variable=kwargs["left_dropdown_menu_variable"], + # ) + # getattr(setattr_obj, kwargs["left_optionmenu_attr_name"]).grid(row=1, column=0) + + + + # self.the_label_between_optionmenu = CTkLabel( + # self.setting_box_dropdown_menu_x_dropdown_menu, + # text="-->", + # # anchor="w", + # font=CTkFont(family=self.FONT_FAMILY, size=self.uism.SB__OPTION_MENU_FONT_SIZE, weight="normal"), + # text_color=self.ctm.LABELS_TEXT_COLOR + # ) + # self.the_label_between_optionmenu.grid(row=1, column=1, padx=self.uism.SB__RIGHT_PADX/2) + + + # self.createOption_DropdownMenu( + # setattr_obj, + # self.setting_box_dropdown_menu_x_dropdown_menu, + # kwargs["right_optionmenu_attr_name"], + # kwargs["right_dropdown_menu_attr_name"], + # dropdown_menu_values=kwargs["right_dropdown_menu_values"], + # width=150, + # command=kwargs["right_dropdown_menu_command"], + # variable=kwargs["right_dropdown_menu_variable"], + # ) + # getattr(setattr_obj, kwargs["right_optionmenu_attr_name"]).grid(row=1, column=2) + + + + + # if setting_box_type == "radio_buttons": + # self.setting_box_radio_buttons_frame = CTkFrame(self.setting_box, corner_radius=0, width=0, height=0) + # self.setting_box_radio_buttons_frame.grid(row=0, column=1, padx=(0, self.uism.SB__RIGHT_PADX), rowspan=2, sticky="e") + + # RADIO_BUTTON_RIGHT_PAD = 14 + # self.setting_box_radio_button_1 = CTkRadioButton( + # self.setting_box_radio_buttons_frame, + # text="lorem ipsum", + # font=CTkFont(family=self.FONT_FAMILY, size=self.uism.SB__RADIO_BUTTON_FONT_SIZE, weight="normal") + # ) + # self.setting_box_radio_button_1.grid(row=0, column=0, padx=(0,RADIO_BUTTON_RIGHT_PAD), sticky="e") + + # self.setting_box_radio_button_2 = CTkRadioButton( + # self.setting_box_radio_buttons_frame, + # text="lorem ipsum", + # font=CTkFont(family=self.FONT_FAMILY, size=self.uism.SB__RADIO_BUTTON_FONT_SIZE, weight="normal") + # ) + # self.setting_box_radio_button_2.grid(row=0, column=1, padx=(0,RADIO_BUTTON_RIGHT_PAD), sticky="e") + + # self.setting_box_radio_button_3 = CTkRadioButton( + # self.setting_box_radio_buttons_frame, + # text="lorem ipsum", + # font=CTkFont(family=self.FONT_FAMILY, size=self.uism.SB__RADIO_BUTTON_FONT_SIZE, weight="normal") + # ) + # self.setting_box_radio_button_3.grid(row=0, column=2, padx=(0,RADIO_BUTTON_RIGHT_PAD), sticky="e") + + + + + + def createOption_DropdownMenu(self, setting_box_dropdown_menu_frame, optionmenu_attr_name, dropdown_menu_attr_name, dropdown_menu_values, command, variable): + option_menu_widget = CTkOptionMenu( + setting_box_dropdown_menu_frame, + height=self.uism.SB__OPTIONMENU_HEIGHT, + width=self.uism.SB__OPTIONMENU_WIDTH, + button_color=self.ctm.SB__OPTIONMENU_BG_COLOR, + button_hover_color=self.ctm.SB__OPTIONMENU_HOVERED_BG_COLOR, + fg_color=self.ctm.SB__OPTIONMENU_BG_COLOR, + font=CTkFont(family=self.FONT_FAMILY, size=self.uism.SB__OPTION_MENU_FONT_SIZE, weight="normal"), + variable=variable, + anchor="w", + ) + option_menu_widget.grid(row=0, column=0, sticky="e") + setattr(self.config_window, optionmenu_attr_name, option_menu_widget) + + # set the value to the option menu's variable automatically + def adjustedCommand(selected_value): + option_menu_widget.set(selected_value) + command(selected_value) + + dropdown_menu_widget = CTkScrollableDropdown( + option_menu_widget, + values=dropdown_menu_values, + justify="left", + width=self.uism.SB__DROPDOWN_MENU_WIDTH, + min_show_button_num=6, + button_pady=0, + frame_corner_radius=self.uism.SB__DROPDOWN_MENU_FRAME_CORNER_RADIUS, + max_button_height=self.uism.SB__DROPDOWN_MENU_MAX_BUTTON_HEIGHT, + max_height=self.uism.SB__DROPDOWN_MENU_FRAME_MAX_HEIGHT, + font=CTkFont(family=self.FONT_FAMILY, size=self.uism.SB__OPTION_MENU_FONT_SIZE, weight="normal"), + command=adjustedCommand, + ) + + # dropdown_menu_widget.bind( + # "", + # lambda e: dropdown_menu_widget._withdraw() if not str(e.widget).startswith(str(dropdown_menu_widget.frame._parent_frame)) else None, + # ) + dropdown_menu_widget.bind( + "", + lambda e: print(e), + ) + + setattr(self.config_window, dropdown_menu_attr_name, dropdown_menu_widget) + return option_menu_widget + + + + + def _createPassiveButtonForProgressbarXSlider(self, setting_box_progressbar_x_slider_frame, BUTTON_PADDING, button_command, button_image_filename): + button_wrapper = createButtonWithImage( + parent_widget=setting_box_progressbar_x_slider_frame, + button_fg_color=self.ctm.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_COLOR, + button_enter_color=self.ctm.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_HOVERED_COLOR, + button_clicked_color=self.ctm.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_CLICKED_COLOR, + button_image_filename=button_image_filename, + button_image_size=self.uism.SB__PROGRESSBAR_X_SLIDER__BUTTON_ICON_SIZE, + button_ipadxy=self.uism.SB__PROGRESSBAR_X_SLIDER__BUTTON_IPADXY, + button_command=button_command, + shape="circle", + ) + button_wrapper.grid(row=0, column=0, padx=(0,BUTTON_PADDING), sticky="e") + button_wrapper.grid_remove() + return button_wrapper + + + + def _createActiveButtonForProgressbarXSlider(self, setting_box_progressbar_x_slider_frame, BUTTON_PADDING, button_command, button_image_filename): + button_wrapper = createButtonWithImage( + parent_widget=setting_box_progressbar_x_slider_frame, + button_fg_color=self.ctm.SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_COLOR, + button_enter_color=self.ctm.SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_HOVERED_COLOR, + button_clicked_color=self.ctm.SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_CLICKED_COLOR, + button_image_filename=button_image_filename, + button_image_size=self.uism.SB__PROGRESSBAR_X_SLIDER__BUTTON_ICON_SIZE, + button_ipadxy=self.uism.SB__PROGRESSBAR_X_SLIDER__BUTTON_IPADXY, + button_command=button_command, + shape="circle", + ) + button_wrapper.grid(row=0, column=0, padx=(0,BUTTON_PADDING), sticky="e") + button_wrapper.grid_remove() + return button_wrapper \ No newline at end of file diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/__init__.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/__init__.py new file mode 100644 index 00000000..f992f8c0 --- /dev/null +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/__init__.py @@ -0,0 +1 @@ +from .setting_box_general import createSettingBox_General \ No newline at end of file diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_general/__init__.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_general/__init__.py new file mode 100644 index 00000000..c0c243b9 --- /dev/null +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_general/__init__.py @@ -0,0 +1 @@ +from .createSettingBox_General import createSettingBox_General \ No newline at end of file diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_general/createSettingBox_General.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_general/createSettingBox_General.py new file mode 100644 index 00000000..70fd7bd3 --- /dev/null +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_general/createSettingBox_General.py @@ -0,0 +1,225 @@ +from time import sleep + +from customtkinter import StringVar, IntVar + + +from ..SettingBoxGenerator import SettingBoxGenerator + +from config import config + +def createSettingBox_General(setting_box_wrapper, config_window, settings): + + + sbg = SettingBoxGenerator(config_window, settings) + + createSettingBoxDropdownMenu = sbg.createSettingBoxDropdownMenu + createSettingBoxSwitch = sbg.createSettingBoxSwitch + createSettingBoxCheckbox = sbg.createSettingBoxCheckbox + createSettingBoxSlider = sbg.createSettingBoxSlider + createSettingBoxProgressbarXSlider = sbg.createSettingBoxProgressbarXSlider + createSettingBoxEntry = sbg.createSettingBoxEntry + + + + def checkbox_input_speaker_threshold_check_callback(e, passive_button_wrapper_widget, active_button_wrapper_widget, is_turned_on): + print("is_turned_on", is_turned_on) + + if is_turned_on is True: + passive_button_widget = passive_button_wrapper_widget.children["!ctklabel"] + passive_button_wrapper_widget.configure(fg_color=settings.ctm.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_DISABLED_COLOR) + passive_button_widget.configure(fg_color=settings.ctm.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_DISABLED_COLOR) + passive_button_wrapper_widget.update_idletasks() + sleep(1) + + passive_button_wrapper_widget.grid_remove() + active_button_wrapper_widget.grid() + + elif is_turned_on is False: + # active_button_widget = active_button_wrapper_widget.children["!ctklabel"] + # active_button_wrapper_widget.configure(fg_color=settings.ctm.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_DISABLED_COLOR) + # active_button_widget.configure(fg_color=settings.ctm.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_DISABLED_COLOR) + # active_button_wrapper_widget.update_idletasks() + # sleep(3) + + active_button_wrapper_widget.grid_remove() + passive_button_wrapper_widget.grid() + + # def slider_input_speaker_energy_threshold_callback(self, value): + # config_window.INPUT_SPEAKER_ENERGY_THRESHOLD = int(value) + + def set_input_threshold(value): + print(value) + config.INPUT_SPEAKER_ENERGY_THRESHOLD = value + print(config.INPUT_SPEAKER_ENERGY_THRESHOLD) + + + + + + + + + + def dropdownMenuFun(selected_value, optionmenu_widget, dropdown_menu_widget): + print(selected_value) + config.INPUT_SOURCE_LANG = selected_value + + def switchFun(_, switch_box_widget): + print(switch_box_widget.get()) + + def checkboxFun(_, checkbox_box_widget): + print(checkbox_box_widget.get()) + + def sliderFun(_, value, slider_widget): + print(value) + + def entryFun(e, entry_widget): + print(e.widget.get()) + config_window.INPUT_MIC_PHRASE_TIMEOUT = int(e.widget.get()) + print(config_window.INPUT_MIC_PHRASE_TIMEOUT) + + + + row=0 + config_window.sb__dropdown_menu_1 = createSettingBoxDropdownMenu( + parent_widget=setting_box_wrapper, + label_text="Option Menu", + desc_text="Select your preferences from the options menu.\nYou can choose your preferred language.", + optionmenu_attr_name="optionmenu_attr_name_1", + dropdown_menu_attr_name="dropdown_menu_attr_name_1", + dropdown_menu_values=["tt", "Japanese", "English"], + command=lambda value: dropdownMenuFun(value, config_window.optionmenu_attr_name_1, config_window.dropdown_menu_attr_name_1), + variable=StringVar(value=config.INPUT_SOURCE_LANG) + ) + config_window.sb__dropdown_menu_1.grid(row=row) + row+=1 + + + config_window.sb__dropdown_menu_2 = createSettingBoxDropdownMenu( + parent_widget=setting_box_wrapper, + label_text="Option Menu", + desc_text="Select your preferences from the options menu.\nYou can choose your preferred language.", + optionmenu_attr_name="optionmenu_attr_name_2", + dropdown_menu_attr_name="dropdown_menu_attr_name_1", + dropdown_menu_values=["tt", "Japanese", "English"], + command=lambda value: dropdownMenuFun(value, config_window.optionmenu_attr_name_2, config_window.dropdown_menu_attr_name_1), + variable=StringVar(value=config.INPUT_SOURCE_LANG) + ) + config_window.sb__dropdown_menu_2.grid(row=row) + row+=1 + + config_window.sb__switch_1 = createSettingBoxSwitch( + parent_widget=setting_box_wrapper, + label_text="Switch", + desc_text="Turning this switch on will bring happiness.\nAs for turning it off... I leave that to your imagination", + switch_attr_name="switch_attr_name_1", + command=lambda: switchFun(config_window.switch_attr_name_1), + is_checked=True, + ) + config_window.sb__switch_1.grid(row=row) + row+=1 + + config_window.sb__checkbox_1 = createSettingBoxCheckbox( + parent_widget=setting_box_wrapper, + label_text="Checkbox", + desc_text="Checkbox ticked, a checkmark.", + checkbox_attr_name="checkbox_attr_name_1", + command=lambda: checkboxFun(config_window.checkbox_attr_name_1), + is_checked=False, + ) + config_window.sb__checkbox_1.grid(row=row) + row+=1 + + config_window.sb__slider_1 = createSettingBoxSlider( + parent_widget=setting_box_wrapper, + label_text="Slider", + desc_text="Adjust using the slider; the balance is up to you.", + slider_attr_name="slider_attr_name_1", + slider_range=(0, config_window.MAX_SPEAKER_ENERGY_THRESHOLD), + slider_number_of_steps=config_window.MAX_SPEAKER_ENERGY_THRESHOLD, + command=lambda value: sliderFun(value, config_window.slider_attr_name_1), + variable=IntVar(value=config_window.INPUT_SPEAKER_ENERGY_THRESHOLD), + ) + config_window.sb__slider_1.grid(row=row) + row+=1 + + + config_window.sb__progressbar_x_slider_1 = createSettingBoxProgressbarXSlider( + parent_widget=setting_box_wrapper, + label_text="Progressbar and Slider for check the threshold", + desc_text="just the slider to modify the threshold for activating voice input.\nPress the microphone button to start input, and you can adjust it while monitoring the actual volume.", + command=set_input_threshold, # ? + variable=IntVar(value=config.INPUT_MIC_ENERGY_THRESHOLD), + entry_attr_name="progressbar_x_slider__entry_attr_name_1", + + + slider_attr_name="progressbar_x_slider__slider_attr_name_1", + slider_range=(0, config_window.MAX_SPEAKER_ENERGY_THRESHOLD), + slider_number_of_steps=config_window.MAX_SPEAKER_ENERGY_THRESHOLD, + + progressbar_attr_name="progressbar_x_slider__progressbar_attr_name_1", + + passive_button_attr_name="progressbar_x_slider__passive_button_attr_name_1", + passive_button_command=lambda e: checkbox_input_speaker_threshold_check_callback( + e, + config_window.progressbar_x_slider__passive_button_attr_name_1, + config_window.progressbar_x_slider__active_button_attr_name_1, + is_turned_on=True, + ), + active_button_attr_name="progressbar_x_slider__active_button_attr_name_1", + active_button_command=lambda e: checkbox_input_speaker_threshold_check_callback( + e, + config_window.progressbar_x_slider__passive_button_attr_name_1, + config_window.progressbar_x_slider__active_button_attr_name_1, + is_turned_on=False, + ), + button_image_filename="mic_icon_white.png" + ) + config_window.sb__progressbar_x_slider_1.grid(row=row) + row+=1 + + config_window.sb__progressbar_x_slider_2 = createSettingBoxProgressbarXSlider( + parent_widget=setting_box_wrapper, + label_text="Progressbar and Slider for check the threshold2", + desc_text="just the slider to modify the threshold for activating voice input.\nPress the microphone button to start input, and you can adjust it while monitoring the actual volume.", + command=set_input_threshold, # ? + variable=IntVar(value=config.INPUT_SPEAKER_ENERGY_THRESHOLD), + + entry_attr_name="progressbar_x_slider__entry_attr_name_2", + + + slider_attr_name="progressbar_x_slider__slider_attr_name_2", + slider_range=(0, config_window.MAX_SPEAKER_ENERGY_THRESHOLD), + slider_number_of_steps=config_window.MAX_SPEAKER_ENERGY_THRESHOLD, + progressbar_attr_name="progressbar_x_slider__progressbar_attr_name_2", + + passive_button_attr_name="progressbar_x_slider__passive_button_attr_name_2", + passive_button_command=lambda e: checkbox_input_speaker_threshold_check_callback( + e, + config_window.progressbar_x_slider__passive_button_attr_name_2, + config_window.progressbar_x_slider__active_button_attr_name_2, + is_turned_on=True, + ), + active_button_attr_name="progressbar_x_slider__active_button_attr_name_2", + active_button_command=lambda e: checkbox_input_speaker_threshold_check_callback( + e, + config_window.progressbar_x_slider__passive_button_attr_name_2, + config_window.progressbar_x_slider__active_button_attr_name_2, + is_turned_on=False, + ), + button_image_filename="headphones_icon_white.png" + ) + config_window.sb__progressbar_x_slider_2.grid(row=row) + row+=1 + + config_window.sb__entry_1 = createSettingBoxEntry( + parent_widget=setting_box_wrapper, + label_text="Entry", + desc_text="Please input a numerical value.", + entry_attr_name="entry_attr_name_1", + entry_width=settings.uism.SB__ENTRY_WIDTH_100, + entry_bind__Any_KeyRelease=lambda value: entryFun(value, config_window.entry_attr_name_1), + entry_textvariable=IntVar(value=config_window.INPUT_MIC_PHRASE_TIMEOUT), + ) + config_window.sb__entry_1.grid(row=row, pady=0) + row+=1 \ No newline at end of file diff --git a/vrct_gui/main_window/__init__.py b/vrct_gui/main_window/__init__.py new file mode 100644 index 00000000..a34b6566 --- /dev/null +++ b/vrct_gui/main_window/__init__.py @@ -0,0 +1 @@ +from .createMainWindowWidgets import createMainWindowWidgets \ No newline at end of file diff --git a/vrct_gui/main_window/createMainWindowWidgets.py b/vrct_gui/main_window/createMainWindowWidgets.py new file mode 100644 index 00000000..980a15be --- /dev/null +++ b/vrct_gui/main_window/createMainWindowWidgets.py @@ -0,0 +1,93 @@ +from .widgets import createSidebar, createMinimizeSidebarButton, createTextbox, createEntryMessageBox + +from customtkinter import CTkFrame + +from ..ui_utils import createButtonWithImage, getImagePath + + +def createMainWindowWidgets(vrct_gui, settings): + vrct_gui.protocol("WM_DELETE_WINDOW", vrct_gui.quitVRCT) + + # self.IS_DEVELOPER_MODE = False + # self.IS_DEVELOPER_MODE = True + + + + + # self.YOUR_LANGUAGE = "Japanese\n(Japan)" + # self.TARGET_LANGUAGE = "English\n(United States)" + + vrct_gui.iconbitmap(getImagePath("app.ico")) + vrct_gui.title("VRCT") + vrct_gui.geometry(f"{880}x{640}") + vrct_gui.minsize(400, 175) + + + # Main Container + vrct_gui.grid_columnconfigure(1, weight=1) + + vrct_gui.configure(fg_color="#ff7f50") + # return + + + # Main Container + vrct_gui.main_bg_container = CTkFrame(vrct_gui, corner_radius=0, fg_color=settings.ctm.MAIN_BG_COLOR, width=0, height=0) + vrct_gui.main_bg_container.grid(row=0, column=1, sticky="nsew") + + + # top bar + vrct_gui.main_bg_container.grid_columnconfigure(0, weight=1) + vrct_gui.main_topbar_container = CTkFrame(vrct_gui.main_bg_container, corner_radius=0, fg_color=settings.ctm.MAIN_BG_COLOR, width=0, height=0) + vrct_gui.main_topbar_container.grid(row=0, column=0, sticky="ew") + + + + + + vrct_gui.main_topbar_container.columnconfigure(1,weight=1) + vrct_gui.main_topbar_center_container = CTkFrame(vrct_gui.main_topbar_container, corner_radius=0, fg_color=settings.ctm.MAIN_BG_COLOR, width=0, height=0) + vrct_gui.main_topbar_center_container.grid(row=0, column=1, sticky="nsew") + + + + + # Help and Info button + vrct_gui.help_and_info_button_container = createButtonWithImage( + parent_widget=vrct_gui.main_topbar_container, + button_fg_color=settings.ctm.HELP_AND_INFO_BUTTON_BG_COLOR, + button_enter_color=settings.ctm.HELP_AND_INFO_BUTTON_HOVERED_BG_COLOR, + button_clicked_color=settings.ctm.HELP_AND_INFO_BUTTON_CLICKED_BG_COLOR, + button_image_filename=settings.image_filename.HELP_ICON, + button_image_size=settings.uism.HELP_AND_INFO_BUTTON_SIZE, + button_ipadxy=settings.uism.HELP_AND_INFO_BUTTON_IPADXY, + button_command=vrct_gui.openHelpAndInfoWindow, + corner_radius=settings.uism.HELP_AND_INFO_BUTTON_CORNER_RADIUS, + ) + vrct_gui.help_and_info_button_container.grid(row=0, column=3, padx=settings.uism.HELP_AND_INFO_BUTTON_PADX, pady=settings.uism.HELP_AND_INFO_BUTTON_PADY, sticky="e") + + createSidebar(settings, vrct_gui) + + createMinimizeSidebarButton(settings, vrct_gui) + + createTextbox(settings, vrct_gui) + + createEntryMessageBox(settings, vrct_gui) + + + + + + # def delete_window(self): + # self.vrct_gui.quit() + # self.vrct_gui.destroy() + + # def openConfigWindow(self, e): + # self.config_window.deiconify() + # self.config_window.focus_set() + # self.config_window.focus() + # self.config_window.grab_set() + + # def openHelpAndInfoWindow(self, e): + # self.information_window.deiconify() + # self.information_window.focus_set() + # self.information_window.focus() \ No newline at end of file diff --git a/vrct_gui/main_window/widgets/__init__.py b/vrct_gui/main_window/widgets/__init__.py new file mode 100644 index 00000000..ac037cb8 --- /dev/null +++ b/vrct_gui/main_window/widgets/__init__.py @@ -0,0 +1,4 @@ +from .create_sidebar import createSidebar +from .create_minimize_sidebar_button import createMinimizeSidebarButton +from .create_textbox import createTextbox +from .create_entry_message_box import createEntryMessageBox diff --git a/vrct_gui/main_window/widgets/create_entry_message_box.py b/vrct_gui/main_window/widgets/create_entry_message_box.py new file mode 100644 index 00000000..61dfe593 --- /dev/null +++ b/vrct_gui/main_window/widgets/create_entry_message_box.py @@ -0,0 +1,21 @@ + +from customtkinter import CTkFont, CTkFrame, CTkEntry + +def createEntryMessageBox(settings, main_window): + main_window.main_entry_message_container = CTkFrame(main_window.main_bg_container, corner_radius=0, fg_color=settings.ctm.MAIN_BG_COLOR, width=0, height=0) + main_window.main_entry_message_container.grid(row=2, column=0, sticky="ew") + + + main_window.main_entry_message_container.columnconfigure(0, weight=1) + main_window.entry_message_box = CTkEntry( + main_window.main_entry_message_container, + border_color=settings.ctm.TEXTBOX_ENTRY_BORDER_COLOR, + fg_color=settings.ctm.TEXTBOX_ENTRY_BG_COLOR, + text_color=settings.ctm.TEXTBOX_ENTRY_TEXT_COLOR, + placeholder_text="Enter your message...", + placeholder_text_color=settings.ctm.TEXTBOX_ENTRY_PLACEHOLDER_COLOR, + height=settings.uism.TEXTBOX_ENTRY_HEIGHT, + font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.TEXTBOX_ENTRY_FONT_SIZE, weight="normal"), + ) + main_window.entry_message_box.grid(row=0, column=0, padx=settings.uism.TEXTBOX_ENTRY_PADX, pady=settings.uism.TEXTBOX_ENTRY_PADY, sticky="nsew") + main_window.entry_message_box._entry.grid(padx=settings.uism.TEXTBOX_ENTRY_IPADX, pady=settings.uism.TEXTBOX_ENTRY_IPADY) diff --git a/vrct_gui/main_window/widgets/create_minimize_sidebar_button.py b/vrct_gui/main_window/widgets/create_minimize_sidebar_button.py new file mode 100644 index 00000000..97414c70 --- /dev/null +++ b/vrct_gui/main_window/widgets/create_minimize_sidebar_button.py @@ -0,0 +1,58 @@ + +from customtkinter import CTkFrame, CTkLabel, CTkImage + +from ...ui_utils import getImageFileFromUiUtils, bindEnterAndLeaveColor, bindButtonPressColor, bindButtonReleaseFunction + +from .create_sidebar import createSidebar + + +def createMinimizeSidebarButton(settings, main_window): + + def enableCompactMode(e): + settings.IS_SIDEBAR_COMPACT_MODE = True + main_window.minimize_sidebar_button_container.destroy() + createMinimizeSidebarButton(settings, main_window) + main_window.sidebar_bg_container.destroy() + createSidebar(settings, main_window) + + def disableCompactMode(e): + settings.IS_SIDEBAR_COMPACT_MODE = False + main_window.minimize_sidebar_button_container.destroy() + createMinimizeSidebarButton(settings, main_window) + main_window.sidebar_bg_container.destroy() + createSidebar(settings, main_window) + + + main_window.minimize_sidebar_button_container = CTkFrame(main_window.main_topbar_container, corner_radius=0, fg_color=settings.ctm.MINIMIZE_SIDEBAR_BUTTON_BG_COLOR, cursor="hand2", width=0, height=0) + + + + main_window.minimize_sidebar_button = CTkLabel( + main_window.minimize_sidebar_button_container, + text=None, + corner_radius=0, + height=0, + image=CTkImage(getImageFileFromUiUtils(settings.image_filename.ARROW_LEFT),size=(settings.uism.MINIMIZE_SIDEBAR_BUTTON_ICON_SIZE_X,settings.uism.MINIMIZE_SIDEBAR_BUTTON_ICON_SIZE_Y)) + ) + + + if settings.IS_SIDEBAR_COMPACT_MODE is True: + image_file = CTkImage(getImageFileFromUiUtils(settings.image_filename.ARROW_LEFT).rotate(180),size=(settings.uism.MINIMIZE_SIDEBAR_BUTTON_ICON_SIZE_X,settings.uism.MINIMIZE_SIDEBAR_BUTTON_ICON_SIZE_Y)) + bindButtonReleaseFunction([main_window.minimize_sidebar_button_container, main_window.minimize_sidebar_button], disableCompactMode) + + else: + image_file = CTkImage(getImageFileFromUiUtils(settings.image_filename.ARROW_LEFT),size=(settings.uism.MINIMIZE_SIDEBAR_BUTTON_ICON_SIZE_X,settings.uism.MINIMIZE_SIDEBAR_BUTTON_ICON_SIZE_Y)) + bindButtonReleaseFunction([main_window.minimize_sidebar_button_container, main_window.minimize_sidebar_button], enableCompactMode) + + main_window.minimize_sidebar_button_container.grid_rowconfigure((0,2), weight=1) + main_window.minimize_sidebar_button.configure(image=image_file) + main_window.minimize_sidebar_button_container.grid(row=0, column=0, sticky="nsw") + main_window.minimize_sidebar_button.grid(row=1, column=0, padx=0, pady=0) + + + bindEnterAndLeaveColor([main_window.minimize_sidebar_button, main_window.minimize_sidebar_button_container], settings.ctm.MINIMIZE_SIDEBAR_BUTTON_HOVERED_BG_COLOR, settings.ctm.MINIMIZE_SIDEBAR_BUTTON_BG_COLOR) + bindButtonPressColor([main_window.minimize_sidebar_button, main_window.minimize_sidebar_button_container], settings.ctm.MINIMIZE_SIDEBAR_BUTTON_CLICKED_BG_COLOR, settings.ctm.MINIMIZE_SIDEBAR_BUTTON_BG_COLOR) + + + + diff --git a/vrct_gui/main_window/widgets/create_sidebar.py b/vrct_gui/main_window/widgets/create_sidebar.py new file mode 100644 index 00000000..1b290954 --- /dev/null +++ b/vrct_gui/main_window/widgets/create_sidebar.py @@ -0,0 +1,622 @@ +from customtkinter import CTkOptionMenu, CTkFont, CTkFrame, CTkLabel, CTkSwitch, CTkImage, StringVar + +from ...ui_utils import getImageFileFromUiUtils, openImageKeepAspectRatio, retag, getLatestHeight, bindEnterAndLeaveColor, bindButtonPressColor, bindEnterAndLeaveFunction, bindButtonReleaseFunction, bindButtonPressAndReleaseFunction, setDefaultActiveTab, bindButtonFunctionAndColor, switchActiveTabAndPassiveTab, switchTabsColor + +from time import sleep + + +def createSidebar(settings, main_window): + from vrct_gui import vrct_gui + changeMainWindowWidgetsStatus = vrct_gui.changeMainWindowWidgetsStatus + + + + + + def toggleSidebarFeatureSelectedMarkIfTurnedOn(is_turned_on, mark): + mark.place(relx=0.85) if is_turned_on else mark.place(relx=-1) + + + def toggleTranslationFeature(): + is_turned_on = getattr(main_window, "translation_switch_box").get() + print(is_turned_on) + toggleSidebarFeatureSelectedMarkIfTurnedOn(is_turned_on, main_window.translation_selected_mark) + toggleTranslationFeatures = [toggleTranslationFeature] + + def toggleTranscriptionSendFeature(): + is_turned_on = getattr(main_window, "transcription_send_switch_box").get() + print(is_turned_on) + toggleSidebarFeatureSelectedMarkIfTurnedOn(is_turned_on, main_window.transcription_send_selected_mark) + if is_turned_on is True: + changeMainWindowWidgetsStatus("disabled", "All") + sleep(1.5) + changeMainWindowWidgetsStatus("normal", "All") + + def toggleTranscriptionReceiveFeature(): + is_turned_on = getattr(main_window, "transcription_receive_switch_box").get() + print(is_turned_on) + toggleSidebarFeatureSelectedMarkIfTurnedOn(is_turned_on, main_window.transcription_receive_selected_mark) + if is_turned_on is True: + changeMainWindowWidgetsStatus("disabled", "All") + sleep(1.5) + changeMainWindowWidgetsStatus("normal", "All") + + + def toggleForegroundFeature(): + is_turned_on = getattr(main_window, "foreground_switch_box").get() + print(is_turned_on) + toggleSidebarFeatureSelectedMarkIfTurnedOn(is_turned_on, main_window.foreground_selected_mark) + + + + + def toggleTranslationSwitchBox(e): + main_window.translation_switch_box.toggle() + + def toggleTranscriptionSendSwitchBox(e): + main_window.transcription_send_switch_box.toggle() + + def toggleTranscriptionReceiveSwitchBox(e): + main_window.transcription_receive_switch_box.toggle() + + def toggleForegroundSwitchBox(e): + main_window.foreground_switch_box.toggle() + + + def changeSidebarFeaturesColorByEvents(ww, event_name): + target_frame_widget = getattr(main_window, ww) + if event_name == "enter": + target_frame_widget.configure(fg_color=settings.ctm.SF__HOVERED_BG_COLOR) + target_frame_widget.children["!ctkswitch"].configure(fg_color=settings.ctm.SF__SWITCH_BOX_HOVERED_BG_COLOR, progress_color=settings.ctm.SF__SWITCH_BOX_ACTIVE_HOVERED_BG_COLOR) + target_frame_widget.children["!ctkframe"].configure(fg_color=settings.ctm.SF__SELECTED_MARK_ACTIVE_HOVERED_BG_COLOR) + + elif event_name == "leave": + target_frame_widget.configure(fg_color=settings.ctm.SF__BG_COLOR) + target_frame_widget.children["!ctkswitch"].configure(fg_color=settings.ctm.SF__SWITCH_BOX_BG_COLOR, progress_color=settings.ctm.SF__SWITCH_BOX_ACTIVE_BG_COLOR) + target_frame_widget.children["!ctkframe"].configure(fg_color=settings.ctm.SF__SELECTED_MARK_ACTIVE_BG_COLOR) + + elif event_name == "button_press": + target_frame_widget.configure(fg_color=settings.ctm.SF__CLICKED_BG_COLOR) + target_frame_widget.children["!ctkswitch"].configure(fg_color=settings.ctm.SF__SWITCH_BOX_CLICKED_BG_COLOR, progress_color=settings.ctm.SF__SWITCH_BOX_ACTIVE_CLICKED_BG_COLOR) + target_frame_widget.children["!ctkframe"].configure(fg_color=settings.ctm.SF__SELECTED_MARK_ACTIVE_CLICKED_BG_COLOR) + + elif event_name == "button_release": + target_frame_widget.configure(fg_color=settings.ctm.SF__BG_COLOR) + target_frame_widget.children["!ctkswitch"].configure(fg_color=settings.ctm.SF__SWITCH_BOX_BG_COLOR, progress_color=settings.ctm.SF__SWITCH_BOX_ACTIVE_BG_COLOR) + target_frame_widget.children["!ctkframe"].configure(fg_color=settings.ctm.SF__SELECTED_MARK_ACTIVE_BG_COLOR) + + + + + + def switchActiveAndPassivePresetsTabsColor(target_active_widget): + quick_setting_tabs = [ + getattr(main_window, "sqls__presets_button_1"), + getattr(main_window, "sqls__presets_button_2"), + getattr(main_window, "sqls__presets_button_3") + ] + + switchTabsColor( + target_widget=target_active_widget, + tab_buttons=quick_setting_tabs, + active_bg_color=settings.ctm.SQLS__PRESETS_TAB_BG_ACTIVE_COLOR, + active_text_color=settings.ctm.SQLS__PRESETS_TAB_ACTIVE_TEXT_COLOR, + passive_bg_color=settings.ctm.SIDEBAR_BG_COLOR, + passive_text_color=settings.ctm.SQLS__PRESETS_TAB_ACTIVE_TEXT_COLOR_PASSIVE + ) + + def switchPresetTabFunction(target_active_widget): + switchActiveAndPassivePresetsTabsColor(target_active_widget) + switchActiveTabAndPassiveTab(target_active_widget, main_window.current_active_preset_tab, main_window.current_active_preset_tab.passive_function, settings.ctm.SQLS__PRESETS_TAB_BG_HOVERED_COLOR, settings.ctm.SQLS__PRESETS_TAB_BG_CLICKED_COLOR, settings.ctm.SQLS__PRESETS_TAB_BG_PASSIVE_COLOR) + + main_window.sqls__optionmenu_your_language.configure(variable=StringVar(value=main_window.YOUR_LANGUAGE)) + main_window.sqls__optionmenu_target_language.configure(variable=StringVar(value=main_window.TARGET_LANGUAGE)) + main_window.current_active_preset_tab = target_active_widget + + + + + + + + def switchToPreset1(e): + print("1") + main_window.YOUR_LANGUAGE = "Japanese\n(Japan)" + main_window.TARGET_LANGUAGE = "English\n(United States)" + target_active_widget = getattr(main_window, "sqls__presets_button_1") + switchPresetTabFunction(target_active_widget) + + def switchToPreset2(e): + print("2") + main_window.YOUR_LANGUAGE = "English\n(United States)" + main_window.TARGET_LANGUAGE = "Japanese\n(Japan)" + target_active_widget = getattr(main_window, "sqls__presets_button_2") + switchPresetTabFunction(target_active_widget) + + def switchToPreset3(e): + print("3") + main_window.YOUR_LANGUAGE = "Japanese\n(Japan)" + main_window.TARGET_LANGUAGE = "Chinese, Cantonese\n(Traditional Hong Kong)" + target_active_widget = getattr(main_window, "sqls__presets_button_3") + switchPresetTabFunction(target_active_widget) + + + + + + def createOption_DropdownMenu_for_quickSettings(setattr_obj, parent_widget, optionmenu_attr_name, dropdown_menu_attr_name, dropdown_menu_values=None, width:int = 200, font_size:int = 10, text_color="white", command=None, variable=""): + setattr(setattr_obj, optionmenu_attr_name, CTkOptionMenu( + parent_widget, + height=30, + width=width, + values=dropdown_menu_values, + button_color=settings.ctm.SQLS__DROPDOWN_MENU_BG_COLOR, + fg_color=settings.ctm.SQLS__DROPDOWN_MENU_BG_COLOR, + text_color=text_color, + font=CTkFont(family=settings.FONT_FAMILY, size=font_size, weight="normal"), + variable=variable, + anchor="center", + )) + target_optionmenu_attr = getattr(setattr_obj, optionmenu_attr_name) + target_optionmenu_attr.grid(row=0, column=0, sticky="e") + + + + + def createQuickLanguageSettingBox(parent_widget, title_text, title_text_attr_name, optionmenu_attr_name, dropdown_menu_attr_name, dropdown_menu_values, variable): + sqls__box = CTkFrame(parent_widget, corner_radius=0, fg_color=settings.ctm.SQLS__BOX_BG_COLOR, width=0, height=0) + + sqls__box.columnconfigure((0,2), weight=1) + + sqls__box_wrapper = CTkFrame(sqls__box, corner_radius=0, fg_color=settings.ctm.SQLS__BOX_BG_COLOR, width=0, height=0) + sqls__box_wrapper.grid(row=2, column=1, padx=0, pady=settings.uism.SQLS__BOX_IPADY) + + sqls__label = CTkLabel( + sqls__box_wrapper, + text=title_text, + height=0, + font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.SQLS__BOX_SECTION_TITLE_FONT_SIZE, weight="normal"), + text_color=settings.ctm.SQLS__BOX_SECTION_TITLE_TEXT_COLOR + ) + sqls__label.grid(row=0, column=0, pady=(0,settings.uism.SQLS__BOX_SECTION_TITLE_BOTTOM_PADY)) + setattr(main_window, title_text_attr_name, sqls__label) + + + + + createOption_DropdownMenu_for_quickSettings( + main_window, + sqls__box_wrapper, + optionmenu_attr_name, + dropdown_menu_attr_name, + dropdown_menu_values=dropdown_menu_values, + # command=self.fakeCommand, + width=settings.uism.SQLS__BOX_DROPDOWN_MENU_WIDTH, + font_size=settings.uism.SQLS__BOX_DROPDOWN_MENU_FONT_SIZE, + text_color=settings.ctm.LABELS_TEXT_COLOR, + variable=variable, + # variable=StringVar(value="Chinese, Cantonese\n(Traditional Hong Kong)"), + ) + getattr(main_window, optionmenu_attr_name).grid(row=1, column=0, padx=0, pady=0) + + return sqls__box + + + + + + + # Side Bar Container + main_window.sidebar_bg_container = CTkFrame(main_window, corner_radius=0, fg_color=settings.ctm.SIDEBAR_BG_COLOR, width=0, height=0) + main_window.sidebar_bg_container.grid(row=0, column=0, sticky="nsew") + + + MIN_SIDEBAR_WIDTH = settings.uism.COMPACT_MODE_SIDEBAR_WIDTH if settings.IS_SIDEBAR_COMPACT_MODE is True else settings.uism.SIDEBAR_WIDTH + main_window.sidebar_bg_container.grid_columnconfigure(0, weight=0, minsize=MIN_SIDEBAR_WIDTH) + main_window.grid_rowconfigure(0, weight=1) + + + (img, width, height) = openImageKeepAspectRatio(settings.image_filename.VRCT_LOGO, settings.uism.SF__LOGO_MAX_SIZE) + main_window.sidebar_logo = CTkLabel( + main_window.sidebar_bg_container, + fg_color=settings.ctm.SIDEBAR_BG_COLOR, + text=None, + height=0, + image=CTkImage(img, size=(width,height)) + ) + + # "height-a_s" represents the adjustment in size, and the "pady+a_s/2" indicates a padding increase of 4 pixels to compensate for the reduction. + a_s = settings.uism.SF__LOGO_HEIGHT_FOR_ADJUSTMENT + (img, width, height) = openImageKeepAspectRatio(settings.image_filename.VRCT_LOGO_MARK, height-a_s) + main_window.sidebar_compact_mode_logo = CTkLabel( + main_window.sidebar_bg_container, + fg_color=settings.ctm.SIDEBAR_BG_COLOR, + text=None, + height=0, + image=CTkImage(img, size=(width,height)) + ) + + if settings.IS_SIDEBAR_COMPACT_MODE is True: + main_window.sidebar_compact_mode_logo.grid(row=0, column=0, pady=( + int(settings.uism.SF__LOGO_PADY[0]+a_s/2), + int(settings.uism.SF__LOGO_PADY[1]+a_s/2) + )) + else: + main_window.sidebar_logo.grid(row=0, column=0, pady=settings.uism.SF__LOGO_PADY) + + # Sidebar Features + main_window.sidebar_features_container = CTkFrame(main_window.sidebar_bg_container, corner_radius=0, fg_color="transparent", width=0, height=0) + main_window.sidebar_features_container.grid(row=1, column=0, pady=0, sticky="ew") + main_window.sidebar_features_container.grid_columnconfigure(0, weight=1) + + + + sidebar_features_settings = [ + { + "frame_attr_name": "translation_frame", + "command": lambda:[func() for func in toggleTranslationFeatures], + "switch_box_attr_name": "translation_switch_box", + "toggle_switch_box_command": toggleTranslationSwitchBox, + "label_attr_name": "label_translation", + "compact_mode_icon_attr_name": "translation_compact_mode_icon", + "selected_mark_attr_name": "translation_selected_mark", + "text": "Translation", + "icon_file_name": settings.image_filename.TRANSLATION_ICON, + }, + { + "frame_attr_name": "transcription_send_frame", + "command": toggleTranscriptionSendFeature, + "switch_box_attr_name": "transcription_send_switch_box", + "toggle_switch_box_command": toggleTranscriptionSendSwitchBox, + "label_attr_name": "label_transcription_send", + "compact_mode_icon_attr_name": "transcription_send_compact_mode_icon", + "selected_mark_attr_name": "transcription_send_selected_mark", + "text": "Voice2chatbox", + "icon_file_name": settings.image_filename.MIC_ICON, + }, + { + "frame_attr_name": "transcription_receive_frame", + "command": toggleTranscriptionReceiveFeature, + "switch_box_attr_name": "transcription_receive_switch_box", + "toggle_switch_box_command": toggleTranscriptionReceiveSwitchBox, + "label_attr_name": "label_transcription_receive", + "compact_mode_icon_attr_name": "transcription_receive_compact_mode_icon", + "selected_mark_attr_name": "transcription_receive_selected_mark", + "text": "Speaker2chatbox", + "icon_file_name": settings.image_filename.HEADPHONES_ICON, + }, + { + "frame_attr_name": "foreground_frame", + "command": toggleForegroundFeature, + "switch_box_attr_name": "foreground_switch_box", + "toggle_switch_box_command": toggleForegroundSwitchBox, + "label_attr_name": "label_foreground", + "compact_mode_icon_attr_name": "foreground_compact_mode_icon", + "selected_mark_attr_name": "foreground_selected_mark", + "text": "Foreground", + "icon_file_name": settings.image_filename.FOREGROUND_ICON, + }, + ] + + + + row=0 + for sfs in sidebar_features_settings: + frame_attr_name = sfs["frame_attr_name"] + command = sfs["command"] + switch_box_attr_name = sfs["switch_box_attr_name"] + toggle_switch_box_command = sfs["toggle_switch_box_command"] + label_attr_name = sfs["label_attr_name"] + compact_mode_icon_attr_name = sfs["compact_mode_icon_attr_name"] + selected_mark_attr_name = sfs["selected_mark_attr_name"] + text = sfs["text"] + icon_file_name = sfs["icon_file_name"] + + frame_widget = CTkFrame(main_window.sidebar_features_container, corner_radius=0, fg_color=settings.ctm.SF__BG_COLOR, cursor="hand2", width=0, height=0) + setattr(main_window, frame_attr_name, frame_widget) + + frame_widget.grid(row=row, column=0, pady=(0,1), sticky="ew") + frame_widget.grid_columnconfigure(0, weight=1) + + label_widget = CTkLabel( + frame_widget, + text=text, + height=0, + corner_radius=0, + font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.SF__LABEL_FONT_SIZE, weight="normal"), + anchor="w", + text_color=settings.ctm.LABELS_TEXT_COLOR, + ) + setattr(main_window, label_attr_name, label_widget) + + + switch_box_widget = CTkSwitch( + frame_widget, + text=None, + height=0, + width=0, + corner_radius=int(settings.uism.SF__SWITCH_BOX_HEIGHT/2), + border_width=0, + switch_height=settings.uism.SF__SWITCH_BOX_HEIGHT, + switch_width=settings.uism.SF__SWITCH_BOX_WIDTH, + onvalue=True, + offvalue=False, + command=command, + fg_color=settings.ctm.SF__SWITCH_BOX_BG_COLOR, + bg_color=settings.ctm.SF__BG_COLOR, + progress_color=settings.ctm.SF__SWITCH_BOX_ACTIVE_BG_COLOR, + ) + # # if sfs["is_checked"] is True: + # # target_attr.select() + # # else: + # # target_attr.deselect() + setattr(main_window, switch_box_attr_name, switch_box_widget) + + + if settings.COMPACT_MODE_ICON_SIZE == 0: + label_widget.grid(row=row, column=0, pady=settings.uism.SF__LABELS_IPADY, padx=(settings.uism.SF__LABEL_LEFT_PAD,0), sticky="ew") + settings.COMPACT_MODE_ICON_SIZE = int(getLatestHeight(frame_widget) - settings.uism.SF__COMPACT_MODE_ICON_PADY*2) + label_widget.grid_remove() + + + # for compact mode + compact_mode_icon_widget = CTkLabel( + frame_widget, + text=None, + height=0, + corner_radius=0, + image=CTkImage(getImageFileFromUiUtils(icon_file_name),size=(settings.COMPACT_MODE_ICON_SIZE,settings.COMPACT_MODE_ICON_SIZE)), + ) + setattr(main_window, compact_mode_icon_attr_name, compact_mode_icon_widget) + + selected_mark_widget = CTkFrame(frame_widget, corner_radius=0, fg_color=settings.ctm.SF__SELECTED_MARK_ACTIVE_BG_COLOR, width=settings.uism.SF__SELECTED_MARK_WIDTH, height=0) + setattr(main_window, selected_mark_attr_name, selected_mark_widget) + + + # Arrange + if settings.IS_SIDEBAR_COMPACT_MODE is True: + compact_mode_icon_widget.grid(row=row, column=0, pady=settings.uism.SF__COMPACT_MODE_ICON_PADY) + selected_mark_widget.place(relx=-1, rely=0.5, relheight=0.75, anchor="center") + else: + label_widget.grid(row=row, column=0, pady=settings.uism.SF__LABELS_IPADY, padx=(settings.uism.SF__LABEL_LEFT_PAD,0), sticky="ew") + switch_box_widget.grid(row=row, column=0, padx=(0,settings.uism.SF__SWITCH_BOX_RIGHT_PAD), sticky="e") + + + # Unbind the event "" originally set up by the widget to manually control it. + switch_box_widget._canvas.unbind("") + switch_box_widget._text_label.unbind("") + + bindButtonReleaseFunction([compact_mode_icon_widget, frame_widget, label_widget, selected_mark_widget, switch_box_widget._canvas, switch_box_widget._bg_canvas], toggle_switch_box_command) + + retag("vrct_"+frame_attr_name, compact_mode_icon_widget, frame_widget, label_widget, selected_mark_widget, switch_box_widget) + + def commonEventFunction(e, event_type): + for ww in e.widget.master.bindtags(): + if ww.startswith("vrct_"): + ww = ww.replace("vrct_", "") + changeSidebarFeaturesColorByEvents(ww, event_type) + break + + def enterFunction(e): + commonEventFunction(e, "enter") + + def leaveFunction(e): + commonEventFunction(e, "leave") + + def buttonPressFunction(e): + commonEventFunction(e, "button_press") + + def buttonReleasedFunction(e): + commonEventFunction(e, "button_release") + + bindEnterAndLeaveFunction([compact_mode_icon_widget, frame_widget, label_widget, selected_mark_widget, switch_box_widget._canvas, switch_box_widget._bg_canvas], enterFunction, leaveFunction) + + bindButtonPressAndReleaseFunction([compact_mode_icon_widget, frame_widget, label_widget, selected_mark_widget, switch_box_widget._canvas, switch_box_widget._bg_canvas], buttonPressFunction, buttonReleasedFunction) + + row+=1 + + + + + + # Sidebar Quick Language Settings, SQLS + main_window.sqls__container = CTkFrame(main_window.sidebar_bg_container, corner_radius=0, fg_color=settings.ctm.SIDEBAR_BG_COLOR, width=0, height=0) + + if settings.IS_SIDEBAR_COMPACT_MODE is False: + main_window.sqls__container.grid(row=2, column=0, sticky="new") + + main_window.sqls__container.grid_columnconfigure(0, weight=1) + + + main_window.sqls__container_title = CTkLabel(main_window.sqls__container, + # text="言語設定", + text="Language Settings", + height=0, + font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.SQLS__TITLE_FONT_SIZE, weight="normal"), + text_color=settings.ctm.SQLS__TITLE_TEXT_COLOR + ) + main_window.sqls__container_title.grid(row=0, column=0, pady=settings.uism.SQLS__TITLE_PADY, sticky="nsew") + + + + # Presets buttons + main_window.sidebar_bg_container.grid_rowconfigure(2, weight=1) + main_window.sqls__presets_buttons_box = CTkFrame(main_window.sqls__container, corner_radius=0, fg_color=settings.ctm.SIDEBAR_BG_COLOR, width=0, height=0) + main_window.sqls__presets_buttons_box.grid(row=1, column=0, sticky="ew") + + main_window.sqls__presets_buttons_box.grid_columnconfigure((0,1,2), weight=1) + + + preset_tabs_settings = [ + { + "preset_tab_attr_name": "sqls__presets_button_1", + "command": switchToPreset1, + "text": "1", + }, + { + "preset_tab_attr_name": "sqls__presets_button_2", + "command": switchToPreset2, + "text": "2", + }, + { + "preset_tab_attr_name": "sqls__presets_button_3", + "command": switchToPreset3, + "text": "3", + }, + ] + + column=0 + for preset_tab_settings in preset_tabs_settings: + preset_tab_attr_name = preset_tab_settings["preset_tab_attr_name"] + command = preset_tab_settings["command"] + text = preset_tab_settings["text"] + + setattr( + main_window, + preset_tab_attr_name, + CTkFrame( + main_window.sqls__presets_buttons_box, + corner_radius=0, + fg_color=settings.ctm.SQLS__PRESETS_TAB_BG_PASSIVE_COLOR, + width=0, + height=30, + cursor="hand2", + ) + ) + parent_widget = getattr(main_window, preset_tab_attr_name) + parent_widget.grid(row=0, column=column, sticky="ew") + + label_widget = CTkLabel( + parent_widget, + text=text, + height=0, + fg_color=settings.ctm.SQLS__PRESETS_TAB_BG_PASSIVE_COLOR, + font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.SQLS__PRESET_TAB_NUMBER_FONT_SIZE, weight="bold"), + anchor="center", + text_color=settings.ctm.SQLS__PRESETS_TAB_ACTIVE_TEXT_COLOR_PASSIVE + ) + label_widget.place(relx=0.5, rely=0.5, anchor="center") + + + + bindEnterAndLeaveColor([parent_widget, label_widget], settings.ctm.SQLS__PRESETS_TAB_BG_HOVERED_COLOR, settings.ctm.SQLS__PRESETS_TAB_BG_PASSIVE_COLOR) + bindButtonPressColor([parent_widget, label_widget], settings.ctm.SQLS__PRESETS_TAB_BG_CLICKED_COLOR, settings.ctm.SQLS__PRESETS_TAB_BG_PASSIVE_COLOR) + + parent_widget.passive_function = command + bindButtonReleaseFunction([parent_widget, label_widget], command) + + column+=1 + + # Set default active preset tab + main_window.current_active_preset_tab = getattr(main_window, "sqls__presets_button_1") + setDefaultActiveTab( + active_tab_widget=main_window.current_active_preset_tab, + active_bg_color=settings.ctm.SQLS__PRESETS_TAB_BG_ACTIVE_COLOR, + active_text_color=settings.ctm.SQLS__PRESETS_TAB_ACTIVE_TEXT_COLOR + ) + + + # Quick Language settings BOX + main_window.sqls__box_frame = CTkFrame(main_window.sqls__container, corner_radius=0, fg_color=settings.ctm.SQLS__BG_COLOR, width=0, height=0) + main_window.sqls__box_frame.grid(row=2, column=0, sticky="ew") + main_window.sqls__box_frame.grid_columnconfigure(0, weight=1) + + # Your language + main_window.sqls__box_your_language = createQuickLanguageSettingBox( + parent_widget=main_window.sqls__box_frame, + # title_text="あなたの言語", + title_text="Your Language", + title_text_attr_name="sqls__title_text_your_language", + optionmenu_attr_name="sqls__optionmenu_your_language", + dropdown_menu_attr_name="sqls__dropdown_menu_your_language", + dropdown_menu_values=["1""2","pppp\npppp"], + variable=StringVar(value=main_window.YOUR_LANGUAGE) + ) + main_window.sqls__box_your_language.grid(row=2, column=0, padx=0, pady=(settings.uism.SQLS__BOX_TOP_PADY,0),sticky="ew") + + + # Both direction arrow icon + main_window.sqls__arrow_direction_box = CTkFrame(main_window.sqls__box_frame, corner_radius=0, fg_color=settings.ctm.SQLS__BG_COLOR, width=0, height=0) + main_window.sqls__arrow_direction_box.grid(row=3, column=0, padx=0, pady=settings.uism.SQLS__BOX_ARROWS_PADY,sticky="ew") + + main_window.sqls__arrow_direction_box.grid_columnconfigure((0,4), weight=1) + + main_window.sqls__both_direction_up = CTkLabel( + main_window.sqls__arrow_direction_box, + text=None, + height=0, + image=CTkImage(getImageFileFromUiUtils(settings.image_filename.NARROW_ARROW_DOWN).rotate(180),size=settings.uism.SQLS__BOX_ARROWS_IMAGE_SIZE) + + ) + main_window.sqls__both_direction_up.grid(row=0, column=1, pady=0) + + main_window.sqls__both_direction_desc = CTkLabel( + main_window.sqls__arrow_direction_box, + # text="双方向に翻訳", + text="Translate Each Other", + height=0, + font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.SQLS__BOX_ARROWS_DESC_FONT_SIZE, weight="normal"), + text_color=settings.ctm.SQLS__BOX_ARROWS_TEXT_COLOR, + ) + main_window.sqls__both_direction_desc.grid(row=0, column=2, padx=settings.uism.SQLS__BOX_ARROWS_DESC_PADX, pady=0) + + main_window.sqls__both_direction_label_down = CTkLabel( + main_window.sqls__arrow_direction_box, + text=None, + height=0, + image=CTkImage(getImageFileFromUiUtils(settings.image_filename.NARROW_ARROW_DOWN).rotate(0),size=settings.uism.SQLS__BOX_ARROWS_IMAGE_SIZE) + + ) + main_window.sqls__both_direction_label_down.grid(row=0, column=3, pady=0) + + + + # Target language + main_window.sqls__box_target_language = createQuickLanguageSettingBox( + parent_widget=main_window.sqls__box_frame, + # title_text="相手の言語", + title_text="Target Language", + title_text_attr_name="sqls__title_text_target_language", + optionmenu_attr_name="sqls__optionmenu_target_language", + dropdown_menu_attr_name="sqls__dropdown_menu_target_language", + dropdown_menu_values=["1""2","pppp\npppp2"], + variable=StringVar(value=main_window.TARGET_LANGUAGE) + ) + main_window.sqls__box_target_language.grid(row=4, column=0, padx=0, pady=(0,0),sticky="ew") + + + + + + # Config Button + main_window.sidebar_config_button_container = CTkFrame(main_window.sidebar_bg_container, corner_radius=0, fg_color=settings.ctm.CONFIG_BUTTON_BG_COLOR, width=0, height=0) + main_window.sidebar_config_button_container.grid(row=3, column=0, sticky="ew") + + + main_window.sidebar_config_button_container.grid_columnconfigure(0, weight=1) + main_window.sidebar_config_button_wrapper = CTkFrame(main_window.sidebar_config_button_container, corner_radius=settings.uism.SIDEBAR_CONFIG_BUTTON_CORNER_RADIUS, fg_color=settings.ctm.CONFIG_BUTTON_BG_COLOR, height=0, width=0, cursor="hand2") + main_window.sidebar_config_button_wrapper.grid(row=0, column=0, padx=settings.uism.SIDEBAR_CONFIG_BUTTON_PADX, pady=settings.uism.SIDEBAR_CONFIG_BUTTON_PADY, sticky="ew") + + + + + main_window.sidebar_config_button_wrapper.grid_columnconfigure(0, weight=1) + + settings.uism.CONFIG_BUTTON_PADX= 0 + main_window.sidebar_config_button = CTkLabel( + main_window.sidebar_config_button_wrapper, + text=None, + height=0, + image=CTkImage(getImageFileFromUiUtils(settings.image_filename.CONFIGURATION_ICON),size=(settings.COMPACT_MODE_ICON_SIZE,settings.COMPACT_MODE_ICON_SIZE)) + ) + main_window.sidebar_config_button.grid(row=0, column=0, padx=0, pady=settings.uism.SIDEBAR_CONFIG_BUTTON_IPADY) + + + bindButtonFunctionAndColor( + target_widgets=[main_window.sidebar_config_button_wrapper, main_window.sidebar_config_button], + enter_color=settings.ctm.CONFIG_BUTTON_HOVERED_BG_COLOR, + leave_color=settings.ctm.CONFIG_BUTTON_BG_COLOR, + clicked_color=settings.ctm.CONFIG_BUTTON_CLICKED_BG_COLOR, + buttonReleasedFunction=main_window.openConfigWindow, + ) + diff --git a/vrct_gui/main_window/widgets/create_textbox.py b/vrct_gui/main_window/widgets/create_textbox.py new file mode 100644 index 00000000..1bc4a05b --- /dev/null +++ b/vrct_gui/main_window/widgets/create_textbox.py @@ -0,0 +1,177 @@ +from customtkinter import CTkFont, CTkFrame, CTkLabel, CTkTextbox + +from ...ui_utils import getLatestWidth, getLongestText, bindEnterAndLeaveColor, bindButtonPressColor, bindButtonReleaseFunction, setDefaultActiveTab, switchActiveTabAndPassiveTab, switchTabsColor + + +def createTextbox(settings, main_window): + + def switchTextbox(target_textbox_attr_name): + main_window.current_active_textbox.grid_remove() + main_window.current_active_textbox = getattr(main_window, target_textbox_attr_name) + main_window.current_active_textbox.grid() + + def switchToTextboxAll(e): + print("switchToTextboxAll") + target_active_widget = getattr(main_window, "textbox_tab_all") + switchTextboxTabFunction(target_active_widget) + switchTextbox("textbox_all") + + def switchToTextboxSent(e): + print("switchToTextboxSent") + target_active_widget = getattr(main_window, "textbox_tab_sent") + switchTextboxTabFunction(target_active_widget) + switchTextbox("textbox_sent") + + def switchToTextboxReceived(e): + print("switchToTextboxReceived") + target_active_widget = getattr(main_window, "textbox_tab_received") + switchTextboxTabFunction(target_active_widget) + switchTextbox("textbox_received") + + def switchToTextboxSystem(e): + print("switchToTextboxSystem") + target_active_widget = getattr(main_window, "textbox_tab_system") + switchTextboxTabFunction(target_active_widget) + switchTextbox("textbox_system") + + + def switchTextboxTabFunction(target_active_widget): + switchActiveAndPassiveTextboxTabsColor(target_active_widget) + switchActiveTabAndPassiveTab(target_active_widget, main_window.current_active_textbox_tab, main_window.current_active_textbox_tab.passive_function, settings.ctm.TEXTBOX_TAB_BG_HOVERED_COLOR, settings.ctm.TEXTBOX_TAB_BG_CLICKED_COLOR, settings.ctm.TEXTBOX_TAB_BG_PASSIVE_COLOR) + main_window.current_active_textbox_tab = target_active_widget + + def switchActiveAndPassiveTextboxTabsColor(target_active_widget): + textbox_tabs = [ + getattr(main_window, "textbox_tab_all"), + getattr(main_window, "textbox_tab_sent"), + getattr(main_window, "textbox_tab_received"), + getattr(main_window, "textbox_tab_system") + ] + + switchTabsColor( + target_widget=target_active_widget, + tab_buttons=textbox_tabs, + active_bg_color=settings.ctm.TEXTBOX_BG_COLOR, + active_text_color=settings.ctm.SQLS__PRESETS_TAB_ACTIVE_TEXT_COLOR, + passive_bg_color=settings.ctm.TEXTBOX_TAB_BG_PASSIVE_COLOR, + passive_text_color=settings.ctm.TEXTBOX_TAB_TEXT_PASSIVE_COLOR + ) + + + + + # Text box + main_window.main_bg_container.grid_rowconfigure(1, weight=1) + main_window.main_textbox_container = CTkFrame(main_window.main_bg_container, corner_radius=0, fg_color=settings.ctm.MAIN_BG_COLOR, width=0, height=0) + main_window.main_textbox_container.grid(row=1, column=0, sticky="nsew") + + main_window.main_textbox_container.columnconfigure(0,weight=1) + main_window.main_textbox_container.rowconfigure(0,weight=1) + + main_window.textbox_switch_tabs_container = CTkFrame(main_window.main_topbar_center_container, corner_radius=0, fg_color=settings.ctm.MAIN_BG_COLOR, width=0, height=0) + main_window.textbox_switch_tabs_container.place(relx=0.07, rely=1.15, anchor="sw") + + main_window.textbox_switch_tabs_container.grid_columnconfigure((0,1,2,3), weight=1, uniform="textbox_tabs") + + textbox_settings = [ + { + "textbox_tab_attr_name": "textbox_tab_all", + "command": switchToTextboxAll, + "textbox_attr_name": "textbox_all", + "text": "All", + }, + { + "textbox_tab_attr_name": "textbox_tab_sent", + "command": switchToTextboxSent, + "textbox_attr_name": "textbox_sent", + "text": "Sent", + }, + + { + "textbox_tab_attr_name": "textbox_tab_received", + "command": switchToTextboxReceived, + "textbox_attr_name": "textbox_received", + "text": "Received", + }, + + { + "textbox_tab_attr_name": "textbox_tab_system", + "command": switchToTextboxSystem, + "textbox_attr_name": "textbox_system", + "text": "System", + }, + ] + + + longest_text = getLongestText(textbox_settings) + + setattr(main_window, "_mlw", CTkLabel( + main_window, + text=longest_text, + corner_radius=0, + font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.TEXTBOX_TAB_FONT_SIZE, weight="normal"), + height=0, + anchor="center", + )) + label_widget = getattr(main_window, "_mlw") + label_widget.grid() + MAX_LABEL_WIDTH = getLatestWidth(label_widget) + label_widget.grid_remove() + + + column=0 + for textbox_setting in textbox_settings: + setattr(main_window, textbox_setting["textbox_tab_attr_name"], CTkFrame(main_window.textbox_switch_tabs_container, corner_radius=settings.uism.TEXTBOX_TAB_CORNER_RADIUS, fg_color=settings.ctm.TEXTBOX_TAB_BG_PASSIVE_COLOR, cursor="hand2", width=0, height=0) + ) + target_widget = getattr(main_window, textbox_setting["textbox_tab_attr_name"]) + target_widget.grid(row=0, column=column, pady=0, padx=(0,2), sticky="ew") + + + + setattr(main_window, "label_widget", CTkLabel( + target_widget, + text=textbox_setting["text"], + corner_radius=0, + font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.TEXTBOX_TAB_FONT_SIZE, weight="normal"), + height=0, + width=MAX_LABEL_WIDTH, + anchor="center", + text_color=settings.ctm.TEXTBOX_TAB_TEXT_PASSIVE_COLOR, + )) + label_widget = getattr(main_window, "label_widget") + label_widget.grid(row=0, column=column) + + label_widget.grid(row=0, column=column, pady=settings.uism.TEXTBOX_TAB_PADY, padx=settings.uism.TEXTBOX_TAB_PADX) + + bindEnterAndLeaveColor([target_widget, label_widget], settings.ctm.TEXTBOX_TAB_BG_HOVERED_COLOR, settings.ctm.TEXTBOX_TAB_BG_PASSIVE_COLOR) + bindButtonPressColor([target_widget, label_widget], settings.ctm.TEXTBOX_TAB_BG_CLICKED_COLOR, settings.ctm.TEXTBOX_TAB_BG_PASSIVE_COLOR) + + target_widget.passive_function = textbox_setting["command"] + bindButtonReleaseFunction([target_widget, label_widget], textbox_setting["command"]) + + + + setattr(main_window, textbox_setting["textbox_attr_name"], CTkTextbox( + main_window.main_textbox_container, + corner_radius=settings.uism.TEXTBOX_CORNER_RADIUS, + fg_color=settings.ctm.TEXTBOX_BG_COLOR, + text_color="lime", # Textbox's text_color is set when printing. so this is for prevent from non-setting text_color like the gloves used in food factories are blue. + )) + textbox_widget = getattr(main_window, textbox_setting["textbox_attr_name"]) + textbox_widget.grid(row=0, column=0, padx=settings.uism.TEXTBOX_PADX, pady=0, sticky="nsew") + textbox_widget.grid_remove() + textbox_widget.configure(state="disabled") + # print_textbox(main_window, textbox_widget, "send", textbox_setting["textbox_attr_name"], "SEND") + + column+=1 + + # Set default active textbox tab + main_window.current_active_textbox_tab = getattr(main_window, "textbox_tab_all") + setDefaultActiveTab( + active_tab_widget=main_window.current_active_textbox_tab, + active_bg_color=settings.ctm.TEXTBOX_TAB_BG_ACTIVE_COLOR, + active_text_color=settings.ctm.TEXTBOX_TAB_TEXT_ACTIVE_COLOR + ) + + main_window.current_active_textbox = getattr(main_window, "textbox_all") + main_window.current_active_textbox.grid() diff --git a/vrct_gui/ui_managers/ColorThemeManager.py b/vrct_gui/ui_managers/ColorThemeManager.py new file mode 100644 index 00000000..df0fbe50 --- /dev/null +++ b/vrct_gui/ui_managers/ColorThemeManager.py @@ -0,0 +1,360 @@ +from types import SimpleNamespace + +class ColorThemeManager(): + def __init__(self, theme): + print(theme) + self.main = SimpleNamespace() + self.config_window = SimpleNamespace() + + self.PRIMARY_100_COLOR = "#c4eac1" + self.PRIMARY_200_COLOR = "#9cdd98" + self.PRIMARY_300_COLOR = "#70d16c" + self.PRIMARY_400_COLOR = "#49c649" + self.PRIMARY_500_COLOR = "#0abb1d" + self.PRIMARY_600_COLOR = "#00ac11" + self.PRIMARY_650_COLOR = "#00A309" + self.PRIMARY_700_COLOR = "#009900" + self.PRIMARY_800_COLOR = "#008800" + self.PRIMARY_900_COLOR = "#006900" + + + self.DARK_100_COLOR = "#f5f7fb" + self.DARK_200_COLOR = "#f1f2f6" + self.DARK_300_COLOR = "#e9eaee" + self.DARK_400_COLOR = "#c7c8cc" + self.DARK_500_COLOR = "#a9aaae" + self.DARK_600_COLOR = "#7f8084" + self.DARK_700_COLOR = "#6a6c6f" + self.DARK_750_COLOR = "#5b5c5f" + self.DARK_800_COLOR = "#4b4c4f" + self.DARK_825_COLOR = "#434447" + self.DARK_850_COLOR = "#3a3b3e" + self.DARK_875_COLOR = "#323336" + self.DARK_888_COLOR = "#2e2f32" + self.DARK_900_COLOR = "#292a2d" + self.DARK_925_COLOR = "#242528" + self.DARK_950_COLOR = "#1f2022" + self.DARK_975_COLOR = "#1a1b1d" + self.DARK_1000_COLOR = "#151517" # THE DARKEST COLOR + + + self.LIGHT_100_COLOR = "#f2f2f2" # THE LIGHTEST COLOR + self.LIGHT_200_COLOR = "#e9e9e9" + self.LIGHT_250_COLOR = "#e1e1e1" + self.LIGHT_300_COLOR = "#d9d9d9" + self.LIGHT_325_COLOR = "#d0d0d0" + self.LIGHT_350_COLOR = "#c7c7c7" + self.LIGHT_375_COLOR = "#bebebe" + self.LIGHT_400_COLOR = "#b5b5b5" + self.LIGHT_450_COLOR = "#a5a5a5" + self.LIGHT_500_COLOR = "#959595" + self.LIGHT_600_COLOR = "#6d6d6d" + self.LIGHT_700_COLOR = "#5a5a5a" + self.LIGHT_750_COLOR = "#515151" + self.LIGHT_800_COLOR = "#3b3b3b" + self.LIGHT_850_COLOR = "#323232" + self.LIGHT_875_COLOR = "#2b2b2b" + self.LIGHT_900_COLOR = "#1b1b1b" + # self.LIGHT_925_COLOR = "#121212" + # self.LIGHT_950_COLOR = "#0c0c0c" + # self.LIGHT_975_COLOR = "#070707" + self.LIGHT_1000_COLOR = "#010101" + + + if theme == "Dark": + self._createDarkModeColor() + elif theme == "Light": + self._createLightModeColor() + + + def _createDarkModeColor(self): + # Common + self.main.BASIC_TEXT_COLOR = self.LIGHT_100_COLOR + self.main.LABELS_TEXT_COLOR = self.main.BASIC_TEXT_COLOR + + # Main + self.main.MAIN_BG_COLOR = self.DARK_900_COLOR + + self.main.TEXTBOX_BG_COLOR = self.DARK_950_COLOR + self.main.TEXTBOX_TEXT_COLOR = self.main.BASIC_TEXT_COLOR + self.main.TEXTBOX_TAB_BG_PASSIVE_COLOR = self.DARK_850_COLOR + self.main.TEXTBOX_TAB_BG_ACTIVE_COLOR = self.main.TEXTBOX_BG_COLOR + self.main.TEXTBOX_TAB_BG_HOVERED_COLOR = self.DARK_800_COLOR + self.main.TEXTBOX_TAB_BG_CLICKED_COLOR = self.DARK_850_COLOR + self.main.TEXTBOX_TAB_TEXT_ACTIVE_COLOR = self.main.BASIC_TEXT_COLOR + self.main.TEXTBOX_TAB_TEXT_PASSIVE_COLOR = self.DARK_500_COLOR + + self.main.TEXTBOX_ENTRY_TEXT_COLOR = self.DARK_300_COLOR + self.main.TEXTBOX_ENTRY_TEXT_DISABLED_COLOR = self.DARK_500_COLOR + self.main.TEXTBOX_ENTRY_BG_COLOR = self.DARK_875_COLOR + self.main.TEXTBOX_ENTRY_BORDER_COLOR = self.DARK_750_COLOR + self.main.TEXTBOX_ENTRY_PLACEHOLDER_COLOR = self.DARK_500_COLOR + self.main.TEXTBOX_ENTRY_PLACEHOLDER_DISABLED_COLOR = self.DARK_700_COLOR + + + + # Sidebar + self.main.SIDEBAR_BG_COLOR = self.DARK_875_COLOR + + # Sidebar Features + self.main.SF__BG_COLOR = self.DARK_850_COLOR + self.main.SF__HOVERED_BG_COLOR = self.DARK_800_COLOR + self.main.SF__CLICKED_BG_COLOR = self.DARK_900_COLOR + self.main.SF__TEXT_DISABLED_COLOR = self.DARK_500_COLOR + + self.main.SF__SWITCH_BOX_BG_COLOR = self.DARK_800_COLOR + self.main.SF__SWITCH_BOX_HOVERED_BG_COLOR = self.DARK_750_COLOR + self.main.SF__SWITCH_BOX_CLICKED_BG_COLOR = self.DARK_850_COLOR + self.main.SF__SWITCH_BOX_ACTIVE_BG_COLOR = self.PRIMARY_650_COLOR + self.main.SF__SWITCH_BOX_ACTIVE_HOVERED_BG_COLOR = self.PRIMARY_500_COLOR + self.main.SF__SWITCH_BOX_ACTIVE_CLICKED_BG_COLOR = self.PRIMARY_700_COLOR + self.main.SF__SWITCH_BOX_DISABLE_BG_COLOR = self.PRIMARY_900_COLOR + + self.main.SF__SELECTED_MARK_ACTIVE_BG_COLOR = self.main.SF__SWITCH_BOX_ACTIVE_BG_COLOR + self.main.SF__SELECTED_MARK_ACTIVE_HOVERED_BG_COLOR = self.main.SF__SWITCH_BOX_ACTIVE_HOVERED_BG_COLOR + self.main.SF__SELECTED_MARK_ACTIVE_CLICKED_BG_COLOR = self.main.SF__SWITCH_BOX_ACTIVE_CLICKED_BG_COLOR + self.main.SF__SELECTED_MARK_DISABLE_BG_COLOR = self.main.SF__SWITCH_BOX_DISABLE_BG_COLOR + + + # Sidebar quick settings + self.main.SQLS__TITLE_TEXT_COLOR = self.DARK_400_COLOR + + self.main.SQLS__BG_COLOR = self.DARK_825_COLOR + + self.main.SQLS__PRESETS_TAB_BG_HOVERED_COLOR = self.DARK_850_COLOR + self.main.SQLS__PRESETS_TAB_BG_CLICKED_COLOR = self.DARK_888_COLOR + self.main.SQLS__PRESETS_TAB_BG_PASSIVE_COLOR = self.main.SIDEBAR_BG_COLOR + self.main.SQLS__PRESETS_TAB_BG_ACTIVE_COLOR = self.main.SQLS__BG_COLOR + self.main.SQLS__PRESETS_TAB_ACTIVE_TEXT_COLOR_PASSIVE = self.DARK_600_COLOR + self.main.SQLS__PRESETS_TAB_ACTIVE_TEXT_COLOR = self.main.BASIC_TEXT_COLOR + + self.main.SQLS__BOX_BG_COLOR = self.DARK_850_COLOR + self.main.SQLS__BOX_SECTION_TITLE_TEXT_COLOR = self.DARK_400_COLOR + self.main.SQLS__BOX_ARROWS_TEXT_COLOR = self.DARK_500_COLOR + + self.main.SQLS__DROPDOWN_MENU_BG_COLOR = self.DARK_900_COLOR + + + self.main.CONFIG_BUTTON_BG_COLOR = self.main.SIDEBAR_BG_COLOR + self.main.CONFIG_BUTTON_HOVERED_BG_COLOR = self.DARK_800_COLOR + self.main.CONFIG_BUTTON_CLICKED_BG_COLOR = self.DARK_900_COLOR + # self.main.CONFIG_BUTTON_DISABLE_COLOR = self.DARK_900_COLOR + + self.main.MINIMIZE_SIDEBAR_BUTTON_BG_COLOR = self.main.SIDEBAR_BG_COLOR + self.main.MINIMIZE_SIDEBAR_BUTTON_HOVERED_BG_COLOR = self.DARK_800_COLOR + self.main.MINIMIZE_SIDEBAR_BUTTON_CLICKED_BG_COLOR = self.DARK_900_COLOR + # self.main.MINIMIZE_SIDEBAR_BUTTON_DISABLE_COLOR = self.DARK_900_COLOR + + self.main.HELP_AND_INFO_BUTTON_BG_COLOR = self.main.MAIN_BG_COLOR + self.main.HELP_AND_INFO_BUTTON_HOVERED_BG_COLOR = self.DARK_850_COLOR + self.main.HELP_AND_INFO_BUTTON_CLICKED_BG_COLOR = self.DARK_950_COLOR + # self.main.HELP_AND_INFO_BUTTON_DISABLE_COLOR = self.DARK_900_COLOR + + + # Common + self.config_window.BASIC_TEXT_COLOR = self.main.BASIC_TEXT_COLOR + self.config_window.LABELS_TEXT_COLOR = self.config_window.BASIC_TEXT_COLOR + self.config_window.LABELS_DESC_TEXT_COLOR = self.DARK_500_COLOR + + + # Top bar + self.config_window.TOP_BAR_BG_COLOR = self.DARK_850_COLOR + + + # Main + self.config_window.MAIN_BG_COLOR = self.DARK_950_COLOR + + # This is for fake border color + self.config_window.SB__WRAPPER_BG_COLOR = self.DARK_750_COLOR + + self.config_window.SB__BG_COLOR = self.DARK_888_COLOR + + self.config_window.SB__OPTIONMENU_BG_COLOR = self.DARK_925_COLOR + self.config_window.SB__OPTIONMENU_HOVERED_BG_COLOR = self.DARK_850_COLOR + + self.config_window.SB__SLIDER_BUTTON_COLOR = self.DARK_700_COLOR + self.config_window.SB__SLIDER_BUTTON_HOVERED_COLOR = self.DARK_600_COLOR + + self.config_window.SB__SWITCH_BOX_BG_COLOR = self.main.SF__SWITCH_BOX_BG_COLOR + self.config_window.SB__SWITCH_BOX_ACTIVE_BG_COLOR = self.main.SF__SWITCH_BOX_ACTIVE_BG_COLOR + + self.config_window.SB__CHECKBOX_BORDER_COLOR = self.DARK_500_COLOR + self.config_window.SB__CHECKBOX_HOVER_COLOR = self.DARK_800_COLOR + self.config_window.SB__CHECKBOX_CHECKED_COLOR = self.PRIMARY_700_COLOR + self.config_window.SB__CHECKBOX_CHECKMARK_COLOR = self.config_window.BASIC_TEXT_COLOR + + self.config_window.SB__PROGRESSBAR_X_SLIDER__SLIDER_BUTTON_COLOR = self.PRIMARY_700_COLOR + self.config_window.SB__PROGRESSBAR_X_SLIDER__SLIDER_BUTTON_HOVERED_COLOR = self.PRIMARY_500_COLOR + self.config_window.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_COLOR = self.DARK_800_COLOR + + self.config_window.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_COLOR = self.DARK_800_COLOR + self.config_window.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_HOVERED_COLOR = self.DARK_700_COLOR + self.config_window.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_CLICKED_COLOR = self.DARK_900_COLOR + self.config_window.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_DISABLED_COLOR = self.DARK_850_COLOR + + self.config_window.SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_COLOR = self.PRIMARY_700_COLOR + self.config_window.SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_HOVERED_COLOR = self.PRIMARY_600_COLOR + self.config_window.SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_CLICKED_COLOR = self.PRIMARY_900_COLOR + # self.config_window.SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_DISABLED_COLOR = self.PRIMARY_900_COLOR + + + # Side menu + self.config_window.SIDE_MENU_BG_COLOR = self.config_window.MAIN_BG_COLOR + + self.config_window.SIDE_MENU_LABELS_BG_COLOR = self.config_window.SIDE_MENU_BG_COLOR + self.config_window.SIDE_MENU_LABELS_BG_FOR_FAKE_BORDER_COLOR = self.config_window.SIDE_MENU_BG_COLOR + self.config_window.SIDE_MENU_LABELS_HOVERED_BG_COLOR = self.DARK_850_COLOR + self.config_window.SIDE_MENU_LABELS_CLICKED_BG_COLOR = self.PRIMARY_900_COLOR + self.config_window.SIDE_MENU_LABELS_SELECTED_TEXT_COLOR = self.PRIMARY_300_COLOR + + self.config_window.SIDE_MENU_SELECTED_MARK_ACTIVE_BG_COLOR = self.main.SF__SWITCH_BOX_ACTIVE_BG_COLOR + + + + + + + + + + def _createLightModeColor(self): + # Common + self.main.BASIC_TEXT_COLOR = self.DARK_1000_COLOR + self.main.LABELS_TEXT_COLOR = self.main.BASIC_TEXT_COLOR + + # Main + self.main.MAIN_BG_COLOR = self.LIGHT_300_COLOR + + self.main.TEXTBOX_BG_COLOR = self.LIGHT_200_COLOR + self.main.TEXTBOX_TEXT_COLOR = self.main.BASIC_TEXT_COLOR + self.main.TEXTBOX_TAB_BG_PASSIVE_COLOR = self.LIGHT_350_COLOR + self.main.TEXTBOX_TAB_BG_ACTIVE_COLOR = self.main.TEXTBOX_BG_COLOR + self.main.TEXTBOX_TAB_BG_HOVERED_COLOR = self.LIGHT_300_COLOR + self.main.TEXTBOX_TAB_BG_CLICKED_COLOR = self.LIGHT_350_COLOR + self.main.TEXTBOX_TAB_TEXT_ACTIVE_COLOR = self.main.BASIC_TEXT_COLOR + self.main.TEXTBOX_TAB_TEXT_PASSIVE_COLOR = self.LIGHT_500_COLOR + + self.main.TEXTBOX_ENTRY_TEXT_COLOR = self.LIGHT_800_COLOR + self.main.TEXTBOX_ENTRY_TEXT_DISABLED_COLOR = self.LIGHT_500_COLOR + self.main.TEXTBOX_ENTRY_BG_COLOR = self.LIGHT_325_COLOR + self.main.TEXTBOX_ENTRY_BORDER_COLOR = self.LIGHT_450_COLOR + self.main.TEXTBOX_ENTRY_PLACEHOLDER_COLOR = self.LIGHT_600_COLOR + self.main.TEXTBOX_ENTRY_PLACEHOLDER_DISABLED_COLOR = self.LIGHT_700_COLOR + + + + # Sidebar + self.main.SIDEBAR_BG_COLOR = self.LIGHT_375_COLOR + + # Sidebar Features + self.main.SF__BG_COLOR = self.LIGHT_350_COLOR + self.main.SF__HOVERED_BG_COLOR = self.LIGHT_300_COLOR + self.main.SF__CLICKED_BG_COLOR = self.LIGHT_200_COLOR + self.main.SF__TEXT_DISABLED_COLOR = self.LIGHT_500_COLOR + + self.main.SF__SWITCH_BOX_BG_COLOR = self.LIGHT_300_COLOR + self.main.SF__SWITCH_BOX_HOVERED_BG_COLOR = self.LIGHT_450_COLOR + self.main.SF__SWITCH_BOX_CLICKED_BG_COLOR = self.LIGHT_350_COLOR + self.main.SF__SWITCH_BOX_ACTIVE_BG_COLOR = self.PRIMARY_650_COLOR + self.main.SF__SWITCH_BOX_ACTIVE_HOVERED_BG_COLOR = self.PRIMARY_500_COLOR + self.main.SF__SWITCH_BOX_ACTIVE_CLICKED_BG_COLOR = self.PRIMARY_700_COLOR + self.main.SF__SWITCH_BOX_DISABLE_BG_COLOR = self.PRIMARY_900_COLOR + + self.main.SF__SELECTED_MARK_ACTIVE_BG_COLOR = self.main.SF__SWITCH_BOX_ACTIVE_BG_COLOR + self.main.SF__SELECTED_MARK_ACTIVE_HOVERED_BG_COLOR = self.main.SF__SWITCH_BOX_ACTIVE_HOVERED_BG_COLOR + self.main.SF__SELECTED_MARK_ACTIVE_CLICKED_BG_COLOR = self.main.SF__SWITCH_BOX_ACTIVE_CLICKED_BG_COLOR + self.main.SF__SELECTED_MARK_DISABLE_BG_COLOR = self.main.SF__SWITCH_BOX_DISABLE_BG_COLOR + + + # Sidebar quick settings + self.main.SQLS__TITLE_TEXT_COLOR = self.LIGHT_800_COLOR + + self.main.SQLS__BG_COLOR = self.LIGHT_300_COLOR + + self.main.SQLS__PRESETS_TAB_BG_HOVERED_COLOR = self.LIGHT_350_COLOR + self.main.SQLS__PRESETS_TAB_BG_CLICKED_COLOR = self.LIGHT_800_COLOR + self.main.SQLS__PRESETS_TAB_BG_PASSIVE_COLOR = self.main.SIDEBAR_BG_COLOR + self.main.SQLS__PRESETS_TAB_BG_ACTIVE_COLOR = self.main.SQLS__BG_COLOR + self.main.SQLS__PRESETS_TAB_ACTIVE_TEXT_COLOR_PASSIVE = self.LIGHT_600_COLOR + self.main.SQLS__PRESETS_TAB_ACTIVE_TEXT_COLOR = self.main.BASIC_TEXT_COLOR + + self.main.SQLS__BOX_BG_COLOR = self.LIGHT_350_COLOR + self.main.SQLS__BOX_SECTION_TITLE_TEXT_COLOR = self.LIGHT_800_COLOR + self.main.SQLS__BOX_ARROWS_TEXT_COLOR = self.LIGHT_700_COLOR + + self.main.SQLS__DROPDOWN_MENU_BG_COLOR = self.LIGHT_500_COLOR + + + self.main.CONFIG_BUTTON_BG_COLOR = self.main.SIDEBAR_BG_COLOR + self.main.CONFIG_BUTTON_HOVERED_BG_COLOR = self.LIGHT_800_COLOR + self.main.CONFIG_BUTTON_CLICKED_BG_COLOR = self.LIGHT_900_COLOR + # self.main.CONFIG_BUTTON_DISABLE_COLOR = self.LIGHT_900_COLOR + + self.main.MINIMIZE_SIDEBAR_BUTTON_BG_COLOR = self.main.SIDEBAR_BG_COLOR + self.main.MINIMIZE_SIDEBAR_BUTTON_HOVERED_BG_COLOR = self.LIGHT_800_COLOR + self.main.MINIMIZE_SIDEBAR_BUTTON_CLICKED_BG_COLOR = self.LIGHT_900_COLOR + # self.main.MINIMIZE_SIDEBAR_BUTTON_DISABLE_COLOR = self.LIGHT_900_COLOR + + self.main.HELP_AND_INFO_BUTTON_BG_COLOR = self.main.MAIN_BG_COLOR + self.main.HELP_AND_INFO_BUTTON_HOVERED_BG_COLOR = self.LIGHT_350_COLOR + self.main.HELP_AND_INFO_BUTTON_CLICKED_BG_COLOR = self.LIGHT_450_COLOR + # self.main.HELP_AND_INFO_BUTTON_DISABLE_COLOR = self.LIGHT_900_COLOR + + + # Common + self.config_window.BASIC_TEXT_COLOR = self.main.BASIC_TEXT_COLOR + self.config_window.LABELS_TEXT_COLOR = self.config_window.BASIC_TEXT_COLOR + self.config_window.LABELS_DESC_TEXT_COLOR = self.DARK_500_COLOR + + + # Top bar + self.config_window.TOP_BAR_BG_COLOR = self.DARK_850_COLOR + + + # Main + self.config_window.MAIN_BG_COLOR = self.DARK_950_COLOR + + # This is for fake border color + self.config_window.SB__WRAPPER_BG_COLOR = self.DARK_750_COLOR + + self.config_window.SB__BG_COLOR = self.DARK_888_COLOR + + self.config_window.SB__OPTIONMENU_BG_COLOR = self.DARK_925_COLOR + self.config_window.SB__OPTIONMENU_HOVERED_BG_COLOR = self.DARK_850_COLOR + + self.config_window.SB__SLIDER_BUTTON_COLOR = self.DARK_700_COLOR + self.config_window.SB__SLIDER_BUTTON_HOVERED_COLOR = self.DARK_600_COLOR + + self.config_window.SB__SWITCH_BOX_BG_COLOR = self.main.SF__SWITCH_BOX_BG_COLOR + self.config_window.SB__SWITCH_BOX_ACTIVE_BG_COLOR = self.main.SF__SWITCH_BOX_ACTIVE_BG_COLOR + + self.config_window.SB__CHECKBOX_BORDER_COLOR = self.DARK_500_COLOR + self.config_window.SB__CHECKBOX_HOVER_COLOR = self.DARK_800_COLOR + self.config_window.SB__CHECKBOX_CHECKED_COLOR = self.PRIMARY_700_COLOR + self.config_window.SB__CHECKBOX_CHECKMARK_COLOR = self.config_window.BASIC_TEXT_COLOR + + self.config_window.SB__PROGRESSBAR_X_SLIDER__SLIDER_BUTTON_COLOR = self.PRIMARY_700_COLOR + self.config_window.SB__PROGRESSBAR_X_SLIDER__SLIDER_BUTTON_HOVERED_COLOR = self.PRIMARY_500_COLOR + self.config_window.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_COLOR = self.DARK_800_COLOR + + self.config_window.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_COLOR = self.DARK_800_COLOR + self.config_window.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_HOVERED_COLOR = self.DARK_700_COLOR + self.config_window.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_CLICKED_COLOR = self.DARK_900_COLOR + self.config_window.SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_DISABLED_COLOR = self.DARK_850_COLOR + + self.config_window.SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_COLOR = self.PRIMARY_700_COLOR + self.config_window.SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_HOVERED_COLOR = self.PRIMARY_600_COLOR + self.config_window.SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_CLICKED_COLOR = self.PRIMARY_900_COLOR + # self.config_window.SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_DISABLED_COLOR = self.PRIMARY_900_COLOR + + + # Side menu + self.config_window.SIDE_MENU_BG_COLOR = self.config_window.MAIN_BG_COLOR + + self.config_window.SIDE_MENU_LABELS_BG_COLOR = self.config_window.SIDE_MENU_BG_COLOR + self.config_window.SIDE_MENU_LABELS_BG_FOR_FAKE_BORDER_COLOR = self.config_window.SIDE_MENU_BG_COLOR + self.config_window.SIDE_MENU_LABELS_HOVERED_BG_COLOR = self.DARK_850_COLOR + self.config_window.SIDE_MENU_LABELS_CLICKED_BG_COLOR = self.PRIMARY_900_COLOR + self.config_window.SIDE_MENU_LABELS_SELECTED_TEXT_COLOR = self.PRIMARY_300_COLOR + + self.config_window.SIDE_MENU_SELECTED_MARK_ACTIVE_BG_COLOR = self.main.SF__SWITCH_BOX_ACTIVE_BG_COLOR diff --git a/vrct_gui/ui_managers/ImageFilenameManager.py b/vrct_gui/ui_managers/ImageFilenameManager.py new file mode 100644 index 00000000..82573f37 --- /dev/null +++ b/vrct_gui/ui_managers/ImageFilenameManager.py @@ -0,0 +1,54 @@ +class ImageFilenameManager(): + def __init__(self, theme:str ="Dark"): + if theme == "Dark": + return self._createDarkModeImages() + elif theme == "Light": + return self._createLightModeImages() + + + def _createDarkModeImages(self): + self.VRCT_LOGO = "vrct_logo_for_dark_mode.png" + self.VRCT_LOGO_MARK = "vrct_logo_mark_white.png" + + self.TRANSLATION_ICON = "translation_icon_white.png" + self.TRANSLATION_ICON_DISABLED = "translation_icon_disabled.png" + self.MIC_ICON = "mic_icon_white.png" + self.MIC_ICON_DISABLED = "mic_icon_disabled.png" + self.HEADPHONES_ICON = "headphones_icon_white.png" + self.HEADPHONES_ICON_DISABLED = "headphones_icon_disabled.png" + self.FOREGROUND_ICON = "foreground_icon_white.png" + self.FOREGROUND_ICON_DISABLED = "foreground_icon_disabled.png" + + self.NARROW_ARROW_DOWN = "narrow_arrow_down.png" + + self.CONFIGURATION_ICON = "configuration_icon_white.png" + self.CONFIGURATION_ICON_DISABLED = "configuration_icon_disabled.png" + + self.ARROW_LEFT = "arrow_left_white.png" + self.ARROW_LEFT_DISABLED = "arrow_left_disabled.png" + + self.HELP_ICON = "help_icon_white.png" + + def _createLightModeImages(self): + self.VRCT_LOGO = "vrct_logo_for_light_mode.png" + self.VRCT_LOGO_MARK = "vrct_logo_mark_black.png" + + + self.TRANSLATION_ICON = "translation_icon_white.png" + self.TRANSLATION_ICON_DISABLED = "translation_icon_disabled.png" + self.MIC_ICON = "mic_icon_white.png" + self.MIC_ICON_DISABLED = "mic_icon_disabled.png" + self.HEADPHONES_ICON = "headphones_icon_white.png" + self.HEADPHONES_ICON_DISABLED = "headphones_icon_disabled.png" + self.FOREGROUND_ICON = "foreground_icon_white.png" + self.FOREGROUND_ICON_DISABLED = "foreground_icon_disabled.png" + + self.NARROW_ARROW_DOWN = "narrow_arrow_down.png" + + self.CONFIGURATION_ICON = "configuration_icon_white.png" + self.CONFIGURATION_ICON_DISABLED = "configuration_icon_disabled.png" + + self.ARROW_LEFT = "arrow_left_white.png" + self.ARROW_LEFT_DISABLED = "arrow_left_disabled.png" + + self.HELP_ICON = "help_icon_white.png" \ No newline at end of file diff --git a/vrct_gui/ui_managers/UiScalingManager.py b/vrct_gui/ui_managers/UiScalingManager.py new file mode 100644 index 00000000..8d013108 --- /dev/null +++ b/vrct_gui/ui_managers/UiScalingManager.py @@ -0,0 +1,184 @@ +from types import SimpleNamespace + +class UiScalingManager(): + def __init__(self, scaling_percentage): + scaling_float = int(scaling_percentage.replace("%", "")) / 100 + print(scaling_float) + self.SCALING_FLOAT = max(scaling_float, 0.4) + self.main = SimpleNamespace() + self.config_window = SimpleNamespace() + + return self._calculatedUiSizes() + + + + + def _calculatedUiSizes(self): + # Common + + # Main + self.main.TEXTBOX_PADX = self._calculateUiSize(16) + self.main.TEXTBOX_CORNER_RADIUS = self._calculateUiSize(6) + + self.main.TEXTBOX_TAB_CORNER_RADIUS = self._calculateUiSize(8) + self.main.TEXTBOX_TAB_FONT_SIZE = self._calculateUiSize(12) + self.main.TEXTBOX_TAB_PADX = self._calculateUiSize(10) + self.main.TEXTBOX_TAB_PADY = (self._calculateUiSize(4), self._calculateUiSize(10)) + + self.main.TEXTBOX_ENTRY_FONT_SIZE = self._calculateUiSize(16) + self.main.TEXTBOX_ENTRY_HEIGHT = self._calculateUiSize(40) + self.main.TEXTBOX_ENTRY_PADX = self.main.TEXTBOX_PADX + self.main.TEXTBOX_ENTRY_PADY = self._calculateUiSize(10) + self.main.TEXTBOX_ENTRY_IPADX = self._calculateUiSize(14) + self.main.TEXTBOX_ENTRY_IPADY = (self._calculateUiSize(2, True), self._calculateUiSize(3, True)) + + + # Sidebar + self.main.SIDEBAR_WIDTH = self._calculateUiSize(230) + self.main.COMPACT_MODE_SIDEBAR_WIDTH = self._calculateUiSize(60) + + # Sidebar Features + self.main.SF__LOGO_MAX_SIZE = self._calculateUiSize(120) + self.main.SF__LOGO_PADY = (self._calculateUiSize(12),self._calculateUiSize(8)) + self.main.SF__LOGO_HEIGHT_FOR_ADJUSTMENT = (self._calculateUiSize(8)) + + self.main.SF__LABELS_IPADY = self._calculateUiSize(16) + self.main.SF__COMPACT_MODE_ICON_PADY = self.main.SF__LABELS_IPADY + self.main.SF__LABEL_LEFT_PAD = self._calculateUiSize(20) + self.main.SF__LABEL_FONT_SIZE = self._calculateUiSize(16) + + self.main.SF__SWITCH_BOX_RIGHT_PAD = self._calculateUiSize(10) + self.main.SF__SWITCH_BOX_WIDTH = self._calculateUiSize(40) + self.main.SF__SWITCH_BOX_HEIGHT = self._calculateUiSize(16) + + self.main.SF__SELECTED_MARK_WIDTH = self._calculateUiSize(3, True) + + + # Sidebar Quick Language Settings, SQLS + self.main.SQLS__TITLE_FONT_SIZE = self._calculateUiSize(16) + self.main.SQLS__TITLE_PADY = (self._calculateUiSize(12), self._calculateUiSize(6)) + + self.main.SQLS__PRESET_TAB_NUMBER_FONT_SIZE = self._calculateUiSize(16) + + self.main.SQLS__BOX_SECTION_TITLE_FONT_SIZE = self._calculateUiSize(16) + self.main.SQLS__BOX_SECTION_TITLE_BOTTOM_PADY = self._calculateUiSize(10) + self.main.SQLS__BOX_IPADY = (self._calculateUiSize(8),self._calculateUiSize(18)) + self.main.SQLS__BOX_DROPDOWN_MENU_FONT_SIZE = self._calculateUiSize(14) + self.main.SQLS__BOX_DROPDOWN_MENU_WIDTH = self._calculateUiSize(200) + self.main.SQLS__BOX_ARROWS_PADY = self._calculateUiSize(10) + self.main.SQLS__BOX_ARROWS_IMAGE_SIZE = self.dupTuple(self._calculateUiSize(16)) + self.main.SQLS__BOX_ARROWS_DESC_FONT_SIZE = self._calculateUiSize(12) + self.main.SQLS__BOX_ARROWS_DESC_PADX = self._calculateUiSize(6) + self.main.SQLS__BOX_TOP_PADY = self._calculateUiSize(16) + + self.main.SIDEBAR_CONFIG_BUTTON_CORNER_RADIUS = self._calculateUiSize(6) + self.main.SIDEBAR_CONFIG_BUTTON_PADX = self._calculateUiSize(10) + self.main.SIDEBAR_CONFIG_BUTTON_PADY = self._calculateUiSize(10) + self.main.SIDEBAR_CONFIG_BUTTON_IPADY = self._calculateUiSize(8) + + + self.main.HELP_AND_INFO_BUTTON_CORNER_RADIUS = self._calculateUiSize(6) + self.main.HELP_AND_INFO_BUTTON_SIZE = self._calculateUiSize(24) + self.main.HELP_AND_INFO_BUTTON_PADX = (0, self._calculateUiSize(6)) + self.main.HELP_AND_INFO_BUTTON_PADY = (self._calculateUiSize(6),0) + self.main.HELP_AND_INFO_BUTTON_IPADXY = self._calculateUiSize(6) + + self.main.MINIMIZE_SIDEBAR_BUTTON_ICON_SIZE_X = int(self.main.TEXTBOX_PADX/2+self.main.TEXTBOX_CORNER_RADIUS*2) + self.main.MINIMIZE_SIDEBAR_BUTTON_ICON_SIZE_Y = self._calculateUiSize(26) + + + + + # Top bar common + self.config_window.TOP_BAR__HEIGHT = self._calculateUiSize(40) + self.config_window.TOP_BAR__IPADY = self._calculateUiSize(12) + + # Top bar Side + self.config_window.TOP_BAR_SIDE__WIDTH = self._calculateUiSize(220) + self.config_window.TOP_BAR_SIDE__CONFIG_LOGO_MARK_SIZE = self.dupTuple(self._calculateUiSize(30)) + self.config_window.TOP_BAR_SIDE__CONFIG_TITLE_FONT_SIZE = self._calculateUiSize(22) + self.config_window.TOP_BAR_SIDE__CONFIG_TITLE_LEFT_PADX = int(self.config_window.TOP_BAR_SIDE__CONFIG_TITLE_FONT_SIZE + self._calculateUiSize(16)) + self.config_window.TOP_BAR_SIDE__TITLE_PADX= self._calculateUiSize(30) + + # Side menu + self.config_window.SIDE_MENU_TOP_PADY= self._calculateUiSize(54) + self.config_window.SIDE_MENU_LABELS_IPADX = self._calculateUiSize(20) + self.config_window.SIDE_MENU_LABELS_IPADY= self._calculateUiSize(8) + self.config_window.SIDE_MENU_LABELS_FONT_SIZE= self._calculateUiSize(18) + + + # Top bar Main + self.config_window.TOP_BAR_MAIN__TITLE_FONT_SIZE = self._calculateUiSize(22) + + + # Setting Box + self.config_window.SB__MAIN_WIDTH = self._calculateUiSize(720) + self.config_window.SB__TOP_PADY_IF_WITH_SECTION_TITLE = (self._calculateUiSize(24)) + self.config_window.SB__TOP_PADY_IF_WITHOUT_SECTION_TITLE = (self._calculateUiSize(64)) + self.config_window.SB__BOTTOM_PADY = (self._calculateUiSize(40)) + self.config_window.SB__IPADX = self._calculateUiSize(20) + self.config_window.SB__IPADY = self._calculateUiSize(12) + self.config_window.SB__BOTTOM_MARGIN = (0, self._calculateUiSize(60)) + + self.config_window.SB__SECTION_TITLE_FONT_SIZE = self._calculateUiSize(20) + self.config_window.SB__SECTION_TITLE_BOTTOM_PADY = (0, self._calculateUiSize(10)) + + self.config_window.SB__LABEL_FONT_SIZE = self._calculateUiSize(16) + self.config_window.SB__DESC_FONT_SIZE = self._calculateUiSize(14) + self.config_window.SB__DESC_TOP_PADY = self._calculateUiSize(2) + + + + self.config_window.SB__SELECTOR_FONT_SIZE = self._calculateUiSize(14) + self.config_window.SB__RADIO_BUTTON_FONT_SIZE = self.config_window.SB__SELECTOR_FONT_SIZE + self.config_window.SB__BUTTON_FONT_SIZE = self.config_window.SB__SELECTOR_FONT_SIZE + + + + self.config_window.SB__OPTION_MENU_FONT_SIZE = self.config_window.SB__SELECTOR_FONT_SIZE + self.config_window.SB__OPTIONMENU_HEIGHT = self._calculateUiSize(30) + self.config_window.SB__OPTIONMENU_WIDTH = self._calculateUiSize(200) + self.config_window.SB__DROPDOWN_MENU_WIDTH = self.config_window.SB__OPTIONMENU_WIDTH + self.config_window.SB__DROPDOWN_MENU_MAX_BUTTON_HEIGHT = int(self.config_window.SB__OPTION_MENU_FONT_SIZE + self._calculateUiSize(6)) + self.config_window.SB__DROPDOWN_MENU_FRAME_CORNER_RADIUS = self._calculateUiSize(10) + self.config_window.SB__DROPDOWN_MENU_FRAME_MAX_HEIGHT = self._calculateUiSize(200) + + + self.config_window.SB__SWITCH_WIDTH = self._calculateUiSize(50) + + self.config_window.SB__SWITCH_BOX_WIDTH = self._calculateUiSize(40) + self.config_window.SB__SWITCH_BOX_HEIGHT = self._calculateUiSize(16) + + self.config_window.SB__CHECKBOX_SIZE = self._calculateUiSize(24) + self.config_window.SB__CHECKBOX_BORDER_WIDTH = self._calculateUiSize(2) + self.config_window.SB__CHECKBOX_CORNER_RADIUS = self._calculateUiSize(4) + + self.config_window.SB__ENTRY_FONT_SIZE = self.config_window.SB__SELECTOR_FONT_SIZE + self.config_window.SB__ENTRY_HEIGHT = self._calculateUiSize(30) + + # SB__ENTRY_WIDTH_10 ... SB__ENTRY_WIDTH_200 + for i in range(10, 201, 10): + setattr(self.config_window, f'SB__ENTRY_WIDTH_{i}', self._calculateUiSize(i)) + + + self.config_window.SB__PROGRESSBAR_X_SLIDER__ENTRY_WIDTH = self.config_window.SB__ENTRY_WIDTH_50 + self.config_window.SB__PROGRESSBAR_X_SLIDER__ENTRY_HEIGHT = self.config_window.SB__ENTRY_HEIGHT + self.config_window.SB__PROGRESSBAR_X_SLIDER__SLIDER_HEIGHT = self._calculateUiSize(40) + self.config_window.SB__PROGRESSBAR_X_SLIDER__SLIDER_BUTTON_LENGTH = self._calculateUiSize(2) + self.config_window.SB__PROGRESSBAR_X_SLIDER__BAR_WIDTH = self._calculateUiSize(200) + self.config_window.SB__PROGRESSBAR_X_SLIDER__PROGRESSBAR_HEIGHT = self._calculateUiSize(8) + self.config_window.SB__PROGRESSBAR_X_SLIDER__BAR_RIGHT_PADX = self._calculateUiSize(20) + + self.config_window.SB__PROGRESSBAR_X_SLIDER__BUTTON_RIGHT_PADX = self._calculateUiSize(20) + self.config_window.SB__PROGRESSBAR_X_SLIDER__BUTTON_IPADXY = self._calculateUiSize(10) + self.config_window.SB__PROGRESSBAR_X_SLIDER__BUTTON_ICON_SIZE = self._calculateUiSize(20) + + + + def _calculateUiSize(self, default_size, is_allowed_odd: bool = False): + size = int(default_size * self.SCALING_FLOAT) + size += 1 if not is_allowed_odd and size % 2 != 0 else 0 + return size + + def dupTuple(self, value): + return (value, value) \ No newline at end of file diff --git a/vrct_gui/ui_managers/__init__.py b/vrct_gui/ui_managers/__init__.py new file mode 100644 index 00000000..f6a5abc0 --- /dev/null +++ b/vrct_gui/ui_managers/__init__.py @@ -0,0 +1,3 @@ +from .ColorThemeManager import ColorThemeManager +from .ImageFilenameManager import ImageFilenameManager +from .UiScalingManager import UiScalingManager \ No newline at end of file diff --git a/vrct_gui/ui_utils/__init__.py b/vrct_gui/ui_utils/__init__.py new file mode 100644 index 00000000..bc2a1337 --- /dev/null +++ b/vrct_gui/ui_utils/__init__.py @@ -0,0 +1 @@ +from .ui_utils import * \ No newline at end of file diff --git a/vrct_gui/ui_utils/ui_utils.py b/vrct_gui/ui_utils/ui_utils.py new file mode 100644 index 00000000..eb45ea3d --- /dev/null +++ b/vrct_gui/ui_utils/ui_utils.py @@ -0,0 +1,150 @@ +from os import path as os_path +from PIL.Image import open as Image_open, LANCZOS + +from customtkinter import CTkFrame, CTkLabel, CTkImage + +def getImagePath(file_name): + # root\img\file_name + return os_path.join(os_path.dirname(os_path.dirname(os_path.dirname(__file__))), "img", file_name) + +def getImageFileFromUiUtils(file_name): + # root\img\file_name + img = Image_open(os_path.join(os_path.dirname(os_path.dirname(os_path.dirname(__file__))), "img", file_name)) + return img + +def openImageKeepAspectRatio(file_name, desired_width): + img = getImageFileFromUiUtils(file_name) + wpercent = (desired_width/float(img.size[0])) + hsize = int((float(img.size[1])*float(wpercent))) + img = img.resize((desired_width,hsize), LANCZOS) + return (img, desired_width, hsize) + +def retag(tag, *args): + for widget in args: + widget.bindtags((tag,) + widget.bindtags()) + + +def getLatestWidth(target_widget): + target_widget.update_idletasks() + return target_widget.winfo_width() + +def getLatestHeight(target_widget): + target_widget.update_idletasks() + return target_widget.winfo_height() + +def getLongestText(settings): + max_length = max(len(item["text"]) for item in settings) + max_length = 0 + longest_text = "" + + for item in settings: + if len(item["text"]) > max_length: + max_length = len(item["text"]) + longest_text = item["text"] + return longest_text + +def bindEnterAndLeaveColor(target_widgets, enter_color, leave_color): + for target_widget in target_widgets: + target_widget.bind("", lambda e, widgets=target_widgets: [w.configure(fg_color=enter_color) for w in widgets], "+") + target_widget.bind("", lambda e, widgets=target_widgets: [w.configure(fg_color=leave_color) for w in widgets], "+") + + +def bindButtonPressColor(target_widgets, clicked_color, released_color): + for target_widget in target_widgets: + target_widget.bind("", lambda e, widgets=target_widgets: [w.configure(fg_color=clicked_color) for w in widgets], "+") + target_widget.bind("", lambda e, widgets=target_widgets: [w.configure(fg_color=released_color) for w in widgets], "+") + +def bindEnterAndLeaveFunction(target_widgets, enterFunction, leaveFunction): + for target_widget in target_widgets: + target_widget.bind("", enterFunction, "+") + target_widget.bind("", leaveFunction, "+") + +def bindButtonPressFunction(target_widgets, buttonPressedFunction): + for target_widget in target_widgets: + target_widget.bind("", buttonPressedFunction, "+") + +def bindButtonReleaseFunction(target_widgets, buttonReleasedFunction): + for target_widget in target_widgets: + target_widget.bind("", buttonReleasedFunction, "+") + +def bindButtonPressAndReleaseFunction(target_widgets, buttonPressedFunction, buttonReleasedFunction): + for target_widget in target_widgets: + target_widget.bind("", buttonPressedFunction, "+") + target_widget.bind("", buttonReleasedFunction, "+") + + +def bindButtonFunctionAndColor(target_widgets, enter_color, leave_color, clicked_color, buttonReleasedFunction): + bindEnterAndLeaveColor(target_widgets, enter_color, leave_color) + bindButtonPressColor(target_widgets, clicked_color, enter_color) + bindButtonReleaseFunction(target_widgets, buttonReleasedFunction) + +def unbindEventFromActiveTabWidget(active_tab_widget): + for event_name in ["", "", "", ""]: + active_tab_widget.unbind(event_name) + active_tab_widget.children["!ctklabel"].unbind(event_name) + +def setDefaultActiveTab(active_tab_widget, active_bg_color, active_text_color): + active_tab_widget.configure(fg_color=active_bg_color, cursor="") + active_tab_widget.children["!ctklabel"].configure(fg_color=active_bg_color, text_color=active_text_color) + unbindEventFromActiveTabWidget(active_tab_widget) + + +def switchActiveTabAndPassiveTab(active_tab_widget, current_active_tab_widget, current_active_tab_passive_function, hovered_color, clicked_color, passive_color): + + + active_tab_widget.configure(cursor="") + unbindEventFromActiveTabWidget(active_tab_widget) + + + rebindFunctionToTab(current_active_tab_widget, current_active_tab_passive_function, hovered_color, clicked_color, passive_color) + +def rebindFunctionToTab(passive_tab_widget, passive_tab_function, hovered_color, clicked_color, passive_color): + + passive_tab_widget.configure(cursor="hand2") + bindEnterAndLeaveColor([passive_tab_widget, passive_tab_widget.children["!ctklabel"]], hovered_color, passive_color) + bindButtonPressColor([passive_tab_widget, passive_tab_widget.children["!ctklabel"]], clicked_color, passive_color) + + bindButtonReleaseFunction([passive_tab_widget, passive_tab_widget.children["!ctklabel"]], passive_tab_function) + +def switchTabsColor(target_widget, tab_buttons, active_bg_color, active_text_color, passive_bg_color, passive_text_color): + # Change all tabs' color to passive color at first + for tab_button in tab_buttons: + tab_button.configure(fg_color=passive_bg_color) + tab_button.children["!ctklabel"].configure(fg_color=passive_bg_color, text_color=passive_text_color) + + # Then, set active color to the active tab + target_widget.configure(fg_color=active_bg_color) + target_widget.children["!ctklabel"].configure(fg_color=active_bg_color, text_color=active_text_color) + + + + + + +def createButtonWithImage(parent_widget, button_fg_color, button_enter_color, button_clicked_color, button_image_filename, button_image_size, button_ipadxy, button_command, corner_radius: int = 0 ,shape: str = "normal"): + button_wrapper = CTkFrame(parent_widget, corner_radius=corner_radius, fg_color=button_fg_color, height=0, width=0, cursor="hand2") + + button_widget = CTkLabel( + button_wrapper, + text=None, + height=0, + image=CTkImage(getImageFileFromUiUtils(button_image_filename),size=(button_image_size,button_image_size)), + ) + button_widget.grid(row=0, column=0, padx=button_ipadxy, pady=button_ipadxy) + + bindButtonFunctionAndColor( + target_widgets=[button_wrapper, button_widget], + enter_color=button_enter_color, + leave_color=button_fg_color, + clicked_color=button_clicked_color, + buttonReleasedFunction=button_command, + ) + + if shape == "circle": + # To round the corners of the button into a circle + button_wrapper.grid() + button_wrapper.configure(corner_radius=int(getLatestWidth(button_wrapper)/2)) + button_wrapper.grid_remove() + + + return button_wrapper diff --git a/vrct_gui/vrct_gui.py b/vrct_gui/vrct_gui.py new file mode 100644 index 00000000..795f1b94 --- /dev/null +++ b/vrct_gui/vrct_gui.py @@ -0,0 +1,107 @@ +from types import SimpleNamespace + +from customtkinter import CTk, get_appearance_mode + +# from window_help_and_info import ToplevelWindowInformation + +from .ui_managers import ColorThemeManager, ImageFilenameManager, UiScalingManager +from ._changeMainWindowWidgetsStatus import _changeMainWindowWidgetsStatus +from ._printToTextbox import _printToTextbox + +from .main_window import createMainWindowWidgets +from .config_window import ConfigWindow + +from config import config + + +class VRCT_GUI(CTk): + def __init__(self): + super().__init__() + self.settings = SimpleNamespace() + theme = get_appearance_mode() if config.APPEARANCE_THEME == "System" else config.APPEARANCE_THEME + all_ctm = ColorThemeManager(theme) + all_uism = UiScalingManager(config.UI_SCALING) + image_filename = ImageFilenameManager(theme) + + common_args = { + "image_filename": image_filename, + "FONT_FAMILY": config.FONT_FAMILY, + } + + self.settings.main = SimpleNamespace( + ctm=all_ctm.main, + uism=all_uism.main, + IS_SIDEBAR_COMPACT_MODE=False, + COMPACT_MODE_ICON_SIZE=0, + **common_args + ) + + self.settings.config_window = SimpleNamespace( + ctm=all_ctm.config_window, + uism=all_uism.config_window, + IS_CONFIG_WINDOW_COMPACT_MODE=False, + **common_args + ) + + + self.YOUR_LANGUAGE = "Japanese\n(Japan)" + self.TARGET_LANGUAGE = "English\n(United States)" + + + self.config_window = ConfigWindow(vrct_gui=self, settings=self.settings.config_window) + self.config_window.withdraw() + + # self.information_window = ToplevelWindowInformation(self) + + + + def start(self): + createMainWindowWidgets(vrct_gui=self, settings=self.settings.main) + # self.printToTextbox(self.textbox_all, "Translation started. You: Japanese (japan). Target: English (American english)", "", "INFO") + # self.printToTextbox(self.textbox_all, "テキスト送信テスト", "Test send text", "SEND") + # self.printToTextbox(self.textbox_all, "こんにちは、こんにちは。", "Hi hi hello.", "SEND") + # self.printToTextbox(self.textbox_all, "Hi~ how are you doing.", "やあ~、元気かい?", "RECEIVE") + self.mainloop() + + + def quitVRCT(self): + self.quit() + self.destroy() + + + def openConfigWindow(self, e): + self.config_window.deiconify() + self.config_window.focus_set() + self.config_window.focus() + self.config_window.grab_set() + + def closeConfigWindow(self): + self.config_window.withdraw() + self.config_window.grab_release() + + + + def openHelpAndInfoWindow(self, e): + self.information_window.deiconify() + self.information_window.focus_set() + self.information_window.focus() + + def changeMainWindowWidgetsStatus(self, status, target_names): + _changeMainWindowWidgetsStatus( + vrct_gui=self, + settings=self.settings.main, + status=status, + target_names=target_names, + ) + + def printToTextbox(self, target_textbox, original_message, translated_message, tags=None): + _printToTextbox( + settings=self.settings.main, + target_textbox=target_textbox, + original_message=original_message, + translated_message=translated_message, + tags=tags, + ) + + +vrct_gui = VRCT_GUI() \ No newline at end of file diff --git a/window_help_and_info.py b/window_help_and_info.py new file mode 100644 index 00000000..cc0d3b7f --- /dev/null +++ b/window_help_and_info.py @@ -0,0 +1,154 @@ +import os +from customtkinter import CTkToplevel, CTkTextbox, CTkFont + +class ToplevelWindowInformation(CTkToplevel): + def __init__(self, parent, *args, **kwargs): + super().__init__(parent, *args, **kwargs) + self.withdraw() + self.parent = parent + self.grid_columnconfigure(0, weight=1) + self.grid_rowconfigure(0, weight=1) + # self.geometry(f"{500}x{300}") + self.minsize(500, 300) + + self.after(200, lambda: self.iconbitmap(os.path.join(os.path.dirname(__file__), "img", "app.ico"))) + self.title("Information") + # create textbox information + self.textbox_information = CTkTextbox( + self, + font=CTkFont(family=self.parent.FONT_FAMILY) + ) + self.textbox_information.grid(row=0, column=0, padx=(10, 10), pady=(10, 10), sticky="nsew") + textbox_information_message = """VRCT(v1.3.1) + +# 概要 +VRChatで使用されるChatBoxをOSC経由でメッセージを送信するツールになります。 +翻訳エンジンを使用してメッセージとその翻訳部分を同時に送信することができます。 +(翻訳エンジンはDeepL,Google,Bingに対応) + +# 使用方法 + 初期設定時 + 0. VRChatのOSCを有効にする(重要) + + (任意) + 1. DeepLのAPIを使用するためにアカウント登録し、認証キーを取得する + 2. ギアアイコンのボタンでconfigウィンドウを開く + 3. ParameterタブのDeepL Auth Keyに認証キーを記載 + 4. configウィンドウを閉じる + + 通常使用時 + 1. メッセージボックスにメッセージを記入 + 2. Enterキーを押し、メッセージを送信する + +# その他の設定 + translation チェックボックス: 翻訳の有効無効 + voice2chatbox チェックボックス : マイクの音声を文字起こししてチャットボックスに送信する + speaker2log チェックボックス : スピーカーの音声から文字起こししてログに表示する + foreground チェックボックス: 最前面表示の有効無効 + + テキストボックス + logタブ + すべてのログを表示 + sendタブ + 送信したメッセージを表示 + receiveタブ + 受信したメッセージを表示 + systemタブ + 機能についてのメッセージを表示 + + configウィンドウ + UIタブ + Transparency: ウィンドウの透過度の調整 + Appearance Theme: ウィンドウテーマを選択 + UI Scaling: UIサイズを調整 + Font Family: 表示フォントを選択 + (New!) UI Language: UIの表示言語を選択 + Translationタブ + Select Translator: 翻訳エンジンの変更 + Send Language: 送信するメッセージに対して翻訳する言語[source, target]を選択 + Receive Language: 受信したメッセージに対して翻訳する言語[source, target]を選択 + Transcriptionタブ + (New!) Input Mic Host: マイクのホストAPIを選択 + Input Mic Device: マイクを選択 + Input Mic Voice Language: 入力する音声の言語 + Input Mic Energy Threshold: 音声取得のしきい値 + (New!) Check threshold point: Input Mic Energy Thresholdのしきい値を視覚化 + Input Mic Dynamic Energy Threshold: 音声取得のしきい値の自動調整 + Input Mic Record Timeout: 音声の区切りの無音時間 + Input Mic Phase Timeout: 文字起こしする音声時間の上限 + Input Mic Max Phrases: 保留する単語の上限 + (New!) Input Mic Word Filter: MICの文字起こし時にWord Filterで設定した文字が入っていた場合にChatboxに表示しない (ex AAA,BBB,CCC) + Input Speaker Device: スピーカーを選択 + Input Speaker Voice Language: 受信する音声の言語 + Input Speaker Energy Threshold: 音声取得のしきい値 + (New!) Check threshold point: (New!)Input Speaker Energy Thresholdのしきい値を視覚化 + Input Speaker Dynamic Energy Threshold: 音声取得のしきい値の自動調整 + Input Speaker Record Timeout: 音声の区切りの無音時間 + Input Speaker Phase Timeout: 文字起こしする音声時間の上限 + Input Speaker Max Phrases: 保留する単語の上限 + Parameterタブ + OSC IP address: 変更不要 + OSC port: 変更不要 + DeepL Auth key: DeepLの認証キーの設定 + Message Format: 送信するメッセージのデコレーションの設定 + [message]がメッセージボックスに記入したメッセージに置換される + [translation]が翻訳されたメッセージに置換される + 初期フォーマット:"[message]([translation])" + Othersタブ + (New!) Auto clear chat box: メッセージ送信後に書き込んだメッセージを空にする + + 設定の初期化 + config.jsonを削除 + +# お問い合わせ +要望などはTwitterまで +https://twitter.com/misya_ai + +# アップデート履歴 +[2023-05-29: v0.1b] v0.1b リリース +[2023-05-30: v0.2b] +- configボタンをギアアイコンに変更 +- 詳細情報のボタンを追加 +- 翻訳機能有効無効のチェックボックスを追加 +- 最前面表示の有効無効のチェックボックスを追加 +- いくつかのバグを修正 +[2023-06-03: v0.3b] +- 全体的にUIを刷新 +- 透過機能を追加 +- テーマのLight/Dark/Systemのモードの変更機能を追加 +- UIのスケール変更機能を追加 +- フォントの変更機能を追加 +[2023-06-06: v0.4b] +- 翻訳エンジンを追加 +- 入力と出力の翻訳言語を選択できるように変更 +[2023-06-20: v1.0] +- マイクからの音声の文字起こし機能を追加 +- スピーカーからの音声の文字起こし機能を追加 +[2023-06-28: v1.1] +- いくつかのバクを修正 +- 翻訳/文字起こし言語の表記を略称からわかりやすい文字に変更 +- 文字起こしの処理の軽量化 +[2023-07-05: v1.2] +- 文字起こし精度の向上 +[2023-07-21: v1.3] +- UIの表示言語を日本語/英語を選択できる機能を追加 +- Energy Thresholdの視覚化機能を追加 +- 文字起こしの誤認識対策のため、Word Filterを追加 +- WASAPI以外のHostAPIでもマイクとして使用できるようにHostAPIを選択できる機能を追加 +- メッセージ送信後に書き込んだメッセージを空にするか選択できる機能を追加 +- バグ対策のため、translation/voice2chatbox/speaker2log/foregroundは起動時はOFFになるように変更 +- バグ対策のため、スピーカーについて既定デバイス以外を選択した時にERRORが出るように変更 +- 半角入力時に一部の文字が書き込めないバグを修正 +[2023-07-22: v1.3.1] +- UIの表示言語選択に韓国語を追加 + +# 注意事項 +再配布とかはやめてね +""" + + self.textbox_information.insert("end", textbox_information_message) + self.textbox_information.configure(state='disabled') + self.protocol("WM_DELETE_WINDOW", self.delete_window) + + def delete_window(self): + self.withdraw() \ No newline at end of file