diff --git a/batch/restart.bat b/batch/restart.bat index b86be544..b6e9b03b 100644 --- a/batch/restart.bat +++ b/batch/restart.bat @@ -1,4 +1,9 @@ @if not "%~0"=="%~dp0.\%~nx0" start /min cmd /c,"%~dp0.\%~nx0" %* & goto :eof -taskkill /im %1 /F -START "" %1 \ No newline at end of file +set name=%1 +set local_path=%~dp0 + +taskkill /im %name% /F +ping -n 2 127.0.0.1 > nul +START "" %local_path%%name% +del /f "%~dp0%~nx0" \ No newline at end of file diff --git a/batch/update.bat b/batch/update.bat index 2a7fc7b2..e0e83855 100644 --- a/batch/update.bat +++ b/batch/update.bat @@ -1,11 +1,20 @@ @if not "%~0"=="%~dp0.\%~nx0" start /min cmd /c,"%~dp0.\%~nx0" %* & goto :eof -taskkill /im %1 /F +set exe_name=%1 +set folder_name=%2 +set folder_tmp=%3 +set restart=%4 +set local_path=%~dp0 + +taskkill /im %exe_name% /F ping -n 2 127.0.0.1 > nul -del /f %1 -ping -n 2 127.0.0.1 > nul -rename %2 %1 -ping -n 2 127.0.0.1 > nul -if %3 == True ( - START "" %1 -) \ No newline at end of file +del /f %local_path%%exe_name% +rmdir /s /q %local_path%%folder_name% +xcopy %local_path%%folder_tmp% %local_path% /E /I +rmdir /s /q %local_path%%folder_tmp% + +if %restart% == True ( + START "" %local_path%%exe_name% +) +pause +del /f "%~dp0%~nx0" \ No newline at end of file diff --git a/build.bat b/build.bat index 6dcbbf71..5ad8f73a 100644 --- a/build.bat +++ b/build.bat @@ -1 +1,2 @@ -pyinstaller --onedir --onefile --windowed --clean --icon="./img/vrct_logo_mark_black.ico" --add-data "./img;img/" --add-data "./locales;locales/" --add-data "./batch;batch/" --name VRCT --exclude-module numpy --exclude-module pandas --exclude-module matplotlib --exclude-module PyQt5 main.py \ No newline at end of file +pyinstaller --windowed --clean --noconfirm --icon="./img/vrct_logo_mark_black.ico" --add-data "./img;img/" --add-data "./locales;locales/" --add-data "./batch;batch/" --name VRCT --exclude-module numpy --exclude-module pandas --exclude-module matplotlib --exclude-module PyQt5 main.py +"C:\Program Files (x86)\NSIS\makensis.exe" installer/installer.nsi \ No newline at end of file diff --git a/config.py b/config.py index 65f8fa15..b594a1b0 100644 --- a/config.py +++ b/config.py @@ -1,6 +1,6 @@ import sys import inspect -from os import path as os_path +from os import path as os_path, makedirs as os_makedirs from json import load as json_load from json import dump as json_dump import tkinter as tk @@ -8,7 +8,7 @@ from tkinter import font from languages import selectable_languages from models.translation.translation_languages import translatorEngine from models.transcription.transcription_utils import getInputDevices, getDefaultInputDevice -from utils import generatePercentageStringsList +from utils import generatePercentageStringsList, isUniqueStrings json_serializable_vars = {} def json_serializable(var_name): @@ -39,10 +39,18 @@ class Config: def VERSION(self): return self._VERSION + @property + def LOCAL_PATH(self): + return self._LOCAL_PATH + @property def PATH_CONFIG(self): return self._PATH_CONFIG + @property + def PATH_LOGS(self): + return self._PATH_LOGS + @property def GITHUB_URL(self): return self._GITHUB_URL @@ -70,7 +78,7 @@ class Config: @ENABLE_TRANSLATION.setter def ENABLE_TRANSLATION(self, value): - if type(value) is bool: + if isinstance(value, bool): self._ENABLE_TRANSLATION = value @property @@ -79,7 +87,7 @@ class Config: @ENABLE_TRANSCRIPTION_SEND.setter def ENABLE_TRANSCRIPTION_SEND(self, value): - if type(value) is bool: + if isinstance(value, bool): self._ENABLE_TRANSCRIPTION_SEND = value @property @@ -88,7 +96,7 @@ class Config: @ENABLE_TRANSCRIPTION_RECEIVE.setter def ENABLE_TRANSCRIPTION_RECEIVE(self, value): - if type(value) is bool: + if isinstance(value, bool): self._ENABLE_TRANSCRIPTION_RECEIVE = value @property @@ -97,7 +105,7 @@ class Config: @ENABLE_FOREGROUND.setter def ENABLE_FOREGROUND(self, value): - if type(value) is bool: + if isinstance(value, bool): self._ENABLE_FOREGROUND = value @property @@ -106,7 +114,7 @@ class Config: @SOURCE_COUNTRY.setter def SOURCE_COUNTRY(self, value): - if type(value) is str: + if isinstance(value, str): self._SOURCE_COUNTRY = value @property @@ -115,7 +123,7 @@ class Config: @SOURCE_LANGUAGE.setter def SOURCE_LANGUAGE(self, value): - if type(value) is str: + if isinstance(value, str): self._SOURCE_LANGUAGE = value @property @@ -124,7 +132,7 @@ class Config: @TARGET_COUNTRY.setter def TARGET_COUNTRY(self, value): - if type(value) is str: + if isinstance(value, str): self._TARGET_COUNTRY = value @property @@ -133,7 +141,7 @@ class Config: @TARGET_LANGUAGE.setter def TARGET_LANGUAGE(self, value): - if type(value) is str: + if isinstance(value, str): self._TARGET_LANGUAGE = value @property @@ -154,7 +162,7 @@ class Config: @SELECTED_TAB_NO.setter def SELECTED_TAB_NO(self, value): - if type(value) is str: + if isinstance(value, str): self._SELECTED_TAB_NO = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -165,7 +173,7 @@ class Config: @SELECTED_TAB_YOUR_LANGUAGES.setter def SELECTED_TAB_YOUR_LANGUAGES(self, value): - if type(value) is dict: + if isinstance(value, dict): self._SELECTED_TAB_YOUR_LANGUAGES = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -176,7 +184,7 @@ class Config: @SELECTED_TAB_TARGET_LANGUAGES.setter def SELECTED_TAB_TARGET_LANGUAGES(self, value): - if type(value) is dict: + if isinstance(value, dict): self._SELECTED_TAB_TARGET_LANGUAGES = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -187,7 +195,7 @@ class Config: @IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE.setter def IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE(self, value): - if type(value) is bool: + if isinstance(value, bool): self._IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -199,7 +207,7 @@ class Config: @TRANSPARENCY.setter def TRANSPARENCY(self, value): - if type(value) is int and 0 <= value <= 100: + if isinstance(value, int) and 0 <= value <= 100: self._TRANSPARENCY = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -225,6 +233,17 @@ class Config: self._UI_SCALING = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + @property + @json_serializable('TEXTBOX_UI_SCALING') + def TEXTBOX_UI_SCALING(self): + return self._TEXTBOX_UI_SCALING + + @TEXTBOX_UI_SCALING.setter + def TEXTBOX_UI_SCALING(self, value): + if isinstance(value, int) and 50 <= value <= 200: + self._TEXTBOX_UI_SCALING = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + @property @json_serializable('FONT_FAMILY') def FONT_FAMILY(self): @@ -279,7 +298,7 @@ class Config: @INPUT_MIC_ENERGY_THRESHOLD.setter def INPUT_MIC_ENERGY_THRESHOLD(self, value): - if type(value) is int: + if isinstance(value, int): self._INPUT_MIC_ENERGY_THRESHOLD = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -290,7 +309,7 @@ class Config: @INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD.setter def INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD(self, value): - if type(value) is bool: + if isinstance(value, bool): self._INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -301,7 +320,7 @@ class Config: @INPUT_MIC_RECORD_TIMEOUT.setter def INPUT_MIC_RECORD_TIMEOUT(self, value): - if type(value) is int: + if isinstance(value, int): self._INPUT_MIC_RECORD_TIMEOUT = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -312,7 +331,7 @@ class Config: @INPUT_MIC_PHRASE_TIMEOUT.setter def INPUT_MIC_PHRASE_TIMEOUT(self, value): - if type(value) is int: + if isinstance(value, int): self._INPUT_MIC_PHRASE_TIMEOUT = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -323,7 +342,7 @@ class Config: @INPUT_MIC_MAX_PHRASES.setter def INPUT_MIC_MAX_PHRASES(self, value): - if type(value) is int: + if isinstance(value, int): self._INPUT_MIC_MAX_PHRASES = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -334,8 +353,8 @@ class Config: @INPUT_MIC_WORD_FILTER.setter def INPUT_MIC_WORD_FILTER(self, value): - if type(value) is list: - self._INPUT_MIC_WORD_FILTER = value + if isinstance(value, list): + self._INPUT_MIC_WORD_FILTER = sorted(set(value), key=value.index) saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @@ -345,7 +364,7 @@ class Config: @INPUT_SPEAKER_ENERGY_THRESHOLD.setter def INPUT_SPEAKER_ENERGY_THRESHOLD(self, value): - if type(value) is int: + if isinstance(value, int): self._INPUT_SPEAKER_ENERGY_THRESHOLD = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -356,7 +375,7 @@ class Config: @INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD.setter def INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD(self, value): - if type(value) is bool: + if isinstance(value, bool): self._INPUT_SPEAKER_DYNAMIC_ENERGY_THRESHOLD = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -367,7 +386,7 @@ class Config: @INPUT_SPEAKER_RECORD_TIMEOUT.setter def INPUT_SPEAKER_RECORD_TIMEOUT(self, value): - if type(value) is int: + if isinstance(value, int): self._INPUT_SPEAKER_RECORD_TIMEOUT = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -378,7 +397,7 @@ class Config: @INPUT_SPEAKER_PHRASE_TIMEOUT.setter def INPUT_SPEAKER_PHRASE_TIMEOUT(self, value): - if type(value) is int: + if isinstance(value, int): self._INPUT_SPEAKER_PHRASE_TIMEOUT = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -389,7 +408,7 @@ class Config: @INPUT_SPEAKER_MAX_PHRASES.setter def INPUT_SPEAKER_MAX_PHRASES(self, value): - if type(value) is int: + if isinstance(value, int): self._INPUT_SPEAKER_MAX_PHRASES = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -400,7 +419,7 @@ class Config: @OSC_IP_ADDRESS.setter def OSC_IP_ADDRESS(self, value): - if type(value) is str: + if isinstance(value, str): self._OSC_IP_ADDRESS = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -411,7 +430,7 @@ class Config: @OSC_PORT.setter def OSC_PORT(self, value): - if type(value) is int: + if isinstance(value, int): self._OSC_PORT = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -422,9 +441,9 @@ class Config: @AUTH_KEYS.setter def AUTH_KEYS(self, value): - if type(value) is dict and set(value.keys()) == set(self.AUTH_KEYS.keys()): + if isinstance(value, dict) and set(value.keys()) == set(self.AUTH_KEYS.keys()): for key, value in value.items(): - if type(value) is str: + if isinstance(value, str): self._AUTH_KEYS[key] = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, self.AUTH_KEYS) @@ -435,7 +454,9 @@ class Config: @MESSAGE_FORMAT.setter def MESSAGE_FORMAT(self, value): - if type(value) is str: + if isinstance(value, str): + if isUniqueStrings(["[message]", "[translation]"], value) is False: + value = "[message]([translation])" self._MESSAGE_FORMAT = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -446,7 +467,7 @@ class Config: @ENABLE_AUTO_CLEAR_MESSAGE_BOX.setter def ENABLE_AUTO_CLEAR_MESSAGE_BOX(self, value): - if type(value) is bool: + if isinstance(value, bool): self._ENABLE_AUTO_CLEAR_MESSAGE_BOX = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -457,7 +478,7 @@ class Config: @ENABLE_NOTICE_XSOVERLAY.setter def ENABLE_NOTICE_XSOVERLAY(self, value): - if type(value) is bool: + if isinstance(value, bool): self._ENABLE_NOTICE_XSOVERLAY = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -468,7 +489,7 @@ class Config: @ENABLE_SEND_MESSAGE_TO_VRC.setter def ENABLE_SEND_MESSAGE_TO_VRC(self, value): - if type(value) is bool: + if isinstance(value, bool): self._ENABLE_SEND_MESSAGE_TO_VRC = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -480,7 +501,7 @@ class Config: # @STARTUP_OSC_ENABLED_CHECK.setter # def STARTUP_OSC_ENABLED_CHECK(self, value): - # if type(value) is bool: + # if isinstance(value, bool): # self._STARTUP_OSC_ENABLED_CHECK = value # saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -491,7 +512,7 @@ class Config: @ENABLE_LOGGER.setter def ENABLE_LOGGER(self, value): - if type(value) is bool: + if isinstance(value, bool): self._ENABLE_LOGGER = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -502,14 +523,17 @@ class Config: @IS_CONFIG_WINDOW_COMPACT_MODE.setter def IS_CONFIG_WINDOW_COMPACT_MODE(self, value): - if type(value) is bool: + if isinstance(value, bool): self._IS_CONFIG_WINDOW_COMPACT_MODE = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) def init_config(self): # Read Only - self._VERSION = "2.0.0" - self._PATH_CONFIG = os_path.join(os_path.dirname(sys.argv[0]), "config.json") + self._VERSION = "2.0.1" + self._LOCAL_PATH = os_path.dirname(sys.argv[0]) + self._PATH_CONFIG = os_path.join(self._LOCAL_PATH, "config.json") + self._PATH_LOGS = os_path.join(self._LOCAL_PATH, "logs") + os_makedirs(self._PATH_LOGS, exist_ok=True) self._GITHUB_URL = "https://api.github.com/repos/misyaguziya/VRCT/releases/latest" self._BOOTH_URL = "https://misyaguziya.booth.pm/" self._DOCUMENTS_URL = "https://mzsoftware.notion.site/VRCT-Documents-be79b7a165f64442ad8f326d86c22246" @@ -546,6 +570,7 @@ class Config: self._TRANSPARENCY = 100 self._APPEARANCE_THEME = "System" self._UI_SCALING = "100%" + self._TEXTBOX_UI_SCALING = 100 self._FONT_FAMILY = "Yu Gothic UI" self._UI_LANGUAGE = "en" self._CHOICE_MIC_HOST = getDefaultInputDevice()["host"]["name"] diff --git a/controller.py b/controller.py index d8dfc1fb..d7bdc414 100644 --- a/controller.py +++ b/controller.py @@ -1,9 +1,10 @@ from time import sleep +from subprocess import Popen from threading import Thread from config import config from model import model from view import view -from utils import get_key_by_value +from utils import get_key_by_value, isUniqueStrings from languages import selectable_languages # Common @@ -13,6 +14,14 @@ def callbackUpdateSoftware(): def callbackRestartSoftware(): model.reStartSoftware() +def callbackFilepathLogs(): + print("callbackFilepathLogs", config.PATH_LOGS.replace('/', '\\')) + Popen(['explorer', config.PATH_LOGS.replace('/', '\\')], shell=True) + +def callbackFilepathConfigFile(): + print("callbackFilepathConfigFile", config.LOCAL_PATH.replace('/', '\\')) + Popen(['explorer', config.LOCAL_PATH.replace('/', '\\')], shell=True) + # func transcription send message def sendMicMessage(message): if len(message) > 0: @@ -24,7 +33,7 @@ def sendMicMessage(message): pass else: translation = model.getInputTranslate(message) - if translation == False: + if translation is False: config.ENABLE_TRANSLATION = False translation = "" view.translationEngineLimitErrorProcess() @@ -88,7 +97,7 @@ def receiveSpeakerMessage(message): pass else: translation = model.getOutputTranslate(message) - if translation == False: + if translation is False: config.ENABLE_TRANSLATION = False translation = "" view.translationEngineLimitErrorProcess() @@ -154,7 +163,7 @@ def sendChatMessage(message): pass else: translation = model.getInputTranslate(message) - if translation == False: + if translation is False: config.ENABLE_TRANSLATION = False translation = "" view.translationEngineLimitErrorProcess() @@ -230,6 +239,15 @@ def setTargetLanguageAndCountry(select): config.CHOICE_TRANSLATOR = model.findTranslationEngine(config.SOURCE_LANGUAGE, config.TARGET_LANGUAGE) view.printToTextbox_selectedTargetLanguages(select) +def swapYourLanguageAndTargetLanguage(): + your_language = config.SELECTED_TAB_YOUR_LANGUAGES[config.SELECTED_TAB_NO] + target_language = config.SELECTED_TAB_TARGET_LANGUAGES[config.SELECTED_TAB_NO] + setYourLanguageAndCountry(target_language) + setTargetLanguageAndCountry(your_language) + # Update Selected Languages for UI + view.updateGuiVariableByPresetTabNo(config.SELECTED_TAB_NO) + + def callbackSelectedLanguagePresetTab(selected_tab_no): config.SELECTED_TAB_NO = selected_tab_no view.updateGuiVariableByPresetTabNo(config.SELECTED_TAB_NO) @@ -352,6 +370,11 @@ def callbackSetUiScaling(value): print("callbackSetUiScaling_new_scaling_float", new_scaling_float) view.showRestartButtonIfRequired() +def callbackSetTextboxUiScaling(value): + print("callbackSetTextboxUiScaling", int(value)) + config.TEXTBOX_UI_SCALING = int(value) + view.setMainWindowTextboxUiSize(config.TEXTBOX_UI_SCALING/100) + def callbackSetFontFamily(value): print("callbackSetFontFamily", value) config.FONT_FAMILY = value @@ -406,7 +429,8 @@ def callbackSetMicDevice(value): def callbackSetMicEnergyThreshold(value): print("callbackSetMicEnergyThreshold", value) - if value == "": return + if value == "": + return try: value = int(value) if 0 <= value and value <= config.MAX_MIC_ENERGY_THRESHOLD: @@ -415,7 +439,7 @@ def callbackSetMicEnergyThreshold(value): view.setGuiVariable_MicEnergyThreshold(config.INPUT_MIC_ENERGY_THRESHOLD) else: raise ValueError() - except: + except Exception: view.showErrorMessage_MicEnergyThreshold() def callbackSetMicDynamicEnergyThreshold(value): @@ -442,7 +466,8 @@ def callbackCheckMicThreshold(is_turned_on): def callbackSetMicRecordTimeout(value): print("callbackSetMicRecordTimeout", value) - if value == "": return + if value == "": + return try: value = int(value) if 0 <= value and value <= config.INPUT_MIC_PHRASE_TIMEOUT: @@ -451,12 +476,13 @@ def callbackSetMicRecordTimeout(value): view.setGuiVariable_MicRecordTimeout(config.INPUT_MIC_RECORD_TIMEOUT) else: raise ValueError() - except: + except Exception: view.showErrorMessage_MicRecordTimeout() def callbackSetMicPhraseTimeout(value): print("callbackSetMicPhraseTimeout", value) - if value == "": return + if value == "": + return try: value = int(value) if 0 <= value and value >= config.INPUT_MIC_RECORD_TIMEOUT: @@ -465,12 +491,13 @@ def callbackSetMicPhraseTimeout(value): view.setGuiVariable_MicPhraseTimeout(config.INPUT_MIC_PHRASE_TIMEOUT) else: raise ValueError() - except: + except Exception: view.showErrorMessage_MicPhraseTimeout() def callbackSetMicMaxPhrases(value): print("callbackSetMicMaxPhrases", value) - if value == "": return + if value == "": + return try: value = int(value) if 0 <= value: @@ -479,25 +506,47 @@ def callbackSetMicMaxPhrases(value): view.setGuiVariable_MicMaxPhrases(config.INPUT_MIC_MAX_PHRASES) else: raise ValueError() - except: + except Exception: view.showErrorMessage_MicMaxPhrases() -def callbackSetMicWordFilter(value): - print("callbackSetMicWordFilter", value) - word_filter = str(value) - word_filter = [w.strip() for w in word_filter.split(",") if len(w.strip()) > 0] - word_filter = ",".join(word_filter) - print("callbackSetMicWordFilter_afterSplitting", word_filter) - if len(word_filter) > 0: - config.INPUT_MIC_WORD_FILTER = word_filter.split(",") - else: - config.INPUT_MIC_WORD_FILTER = [] +def callbackSetMicWordFilter(values): + print("callbackSetMicWordFilter", values) + values = str(values) + values = [w.strip() for w in values.split(",") if len(w.strip()) > 0] + # Copy the list + new_input_mic_word_filter_list = config.INPUT_MIC_WORD_FILTER + new_added_value = [] + for value in values: + if value in new_input_mic_word_filter_list: + # If the value is already in the list, do nothing. + pass + else: + new_input_mic_word_filter_list.append(value) + new_added_value.append(value) + config.INPUT_MIC_WORD_FILTER = new_input_mic_word_filter_list + + view.addValueToList_WordFilter(new_added_value) + view.clearEntryBox_WordFilter() + view.setLatestConfigVariable("MicMicWordFilter") + model.resetKeywordProcessor() model.addKeywords() +def callbackDeleteMicWordFilter(value): + print("callbackDeleteMicWordFilter", value) + try: + new_input_mic_word_filter_list = config.INPUT_MIC_WORD_FILTER + new_input_mic_word_filter_list.remove(str(value)) + config.INPUT_MIC_WORD_FILTER = new_input_mic_word_filter_list + view.setLatestConfigVariable("MicMicWordFilter") + except Exception: + print("There was no the target word in config.INPUT_MIC_WORD_FILTER") + + def callbackSetSpeakerEnergyThreshold(value): print("callbackSetSpeakerEnergyThreshold", value) - if value == "": return + if value == "": + return try: value = int(value) if 0 <= value and value <= config.MAX_SPEAKER_ENERGY_THRESHOLD: @@ -506,7 +555,7 @@ def callbackSetSpeakerEnergyThreshold(value): view.setGuiVariable_SpeakerEnergyThreshold(config.INPUT_SPEAKER_ENERGY_THRESHOLD) else: raise ValueError() - except: + except Exception: view.showErrorMessage_SpeakerEnergyThreshold() def callbackSetSpeakerDynamicEnergyThreshold(value): @@ -539,7 +588,8 @@ def callbackCheckSpeakerThreshold(is_turned_on): def callbackSetSpeakerRecordTimeout(value): print("callbackSetSpeakerRecordTimeout", value) - if value == "": return + if value == "": + return try: value = int(value) if 0 <= value and value <= config.INPUT_SPEAKER_PHRASE_TIMEOUT: @@ -548,12 +598,13 @@ def callbackSetSpeakerRecordTimeout(value): view.setGuiVariable_SpeakerRecordTimeout(config.INPUT_SPEAKER_RECORD_TIMEOUT) else: raise ValueError() - except: + except Exception: view.showErrorMessage_SpeakerRecordTimeout() def callbackSetSpeakerPhraseTimeout(value): print("callbackSetSpeakerPhraseTimeout", value) - if value == "": return + if value == "": + return try: value = int(value) if 0 <= value and value >= config.INPUT_SPEAKER_RECORD_TIMEOUT: @@ -562,12 +613,13 @@ def callbackSetSpeakerPhraseTimeout(value): view.setGuiVariable_SpeakerPhraseTimeout(config.INPUT_SPEAKER_PHRASE_TIMEOUT) else: raise ValueError() - except: + except Exception: view.showErrorMessage_SpeakerPhraseTimeout() def callbackSetSpeakerMaxPhrases(value): print("callbackSetSpeakerMaxPhrases", value) - if value == "": return + if value == "": + return try: value = int(value) if 0 <= value: @@ -576,7 +628,7 @@ def callbackSetSpeakerMaxPhrases(value): view.setGuiVariable_SpeakerMaxPhrases(config.INPUT_SPEAKER_MAX_PHRASES) else: raise ValueError() - except: + except Exception: view.showErrorMessage_SpeakerMaxPhrases() @@ -601,7 +653,14 @@ def callbackSetEnableAutoExportMessageLogs(value): def callbackSetMessageFormat(value): print("callbackSetMessageFormat", value) if len(value) > 0: - config.MESSAGE_FORMAT = value + if isUniqueStrings(["[message]", "[translation]"], value) is True: + config.MESSAGE_FORMAT = value + view.clearErrorMessage() + view.setMessageFormatEntryWidgets(config.MESSAGE_FORMAT) + else: + view.showErrorMessage_MessageFormat() + view.setMessageFormatEntryWidgets(config.MESSAGE_FORMAT) + def callbackSetEnableSendMessageToVrc(value): print("callbackSetEnableSendMessageToVrc", value) @@ -614,12 +673,14 @@ def callbackSetEnableSendMessageToVrc(value): # Advanced Settings Tab def callbackSetOscIpAddress(value): - if value == "": return + if value == "": + return print("callbackSetOscIpAddress", str(value)) config.OSC_IP_ADDRESS = str(value) def callbackSetOscPort(value): - if value == "": return + if value == "": + return print("callbackSetOscPort", int(value)) config.OSC_PORT = int(value) @@ -658,6 +719,8 @@ def createMainWindow(): common_registers={ "callback_update_software": callbackUpdateSoftware, "callback_restart_software": callbackRestartSoftware, + "callback_filepath_logs": callbackFilepathLogs, + "callback_filepath_config_file": callbackFilepathConfigFile, }, window_action_registers={ @@ -677,6 +740,7 @@ def createMainWindow(): "callback_your_language": setYourLanguageAndCountry, "callback_target_language": setTargetLanguageAndCountry, "values": model.getListLanguageAndCountry(), + "callback_swap_languages": swapYourLanguageAndTargetLanguage, "callback_selected_language_preset_tab": callbackSelectedLanguagePresetTab, "message_box_bind_Return": messageBoxPressKeyEnter, @@ -694,6 +758,7 @@ def createMainWindow(): "callback_set_transparency": callbackSetTransparency, "callback_set_appearance": callbackSetAppearance, "callback_set_ui_scaling": callbackSetUiScaling, + "callback_set_textbox_ui_scaling": callbackSetTextboxUiScaling, "callback_set_font_family": callbackSetFontFamily, "callback_set_ui_language": callbackSetUiLanguage, @@ -712,6 +777,7 @@ def createMainWindow(): "callback_set_mic_phrase_timeout": callbackSetMicPhraseTimeout, "callback_set_mic_max_phrases": callbackSetMicMaxPhrases, "callback_set_mic_word_filter": callbackSetMicWordFilter, + "callback_delete_mic_word_filter": callbackDeleteMicWordFilter, # Transcription Tab (Speaker) "callback_set_speaker_energy_threshold": callbackSetSpeakerEnergyThreshold, diff --git a/img/app.ico b/img/app.ico deleted file mode 100644 index eca32ce7..00000000 Binary files a/img/app.ico and /dev/null differ diff --git a/img/arrow_left_black.png b/img/arrow_left_black.png new file mode 100644 index 00000000..5e3f8dfb Binary files /dev/null and b/img/arrow_left_black.png differ diff --git a/img/cancel_icon.png b/img/cancel_icon.png new file mode 100644 index 00000000..aa6c386e Binary files /dev/null and b/img/cancel_icon.png differ diff --git a/img/config-icon-white.png b/img/config-icon-white.png deleted file mode 100644 index 1222f167..00000000 Binary files a/img/config-icon-white.png and /dev/null differ diff --git a/img/configuration_icon_black.png b/img/configuration_icon_black.png new file mode 100644 index 00000000..c97dfefe Binary files /dev/null and b/img/configuration_icon_black.png differ diff --git a/img/folder_open_icon_black.png b/img/folder_open_icon_black.png new file mode 100644 index 00000000..988184b3 Binary files /dev/null and b/img/folder_open_icon_black.png differ diff --git a/img/folder_open_icon_white.png b/img/folder_open_icon_white.png new file mode 100644 index 00000000..3de75dfe Binary files /dev/null and b/img/folder_open_icon_white.png differ diff --git a/img/foreground_icon_black.png b/img/foreground_icon_black.png new file mode 100644 index 00000000..ff3594c2 Binary files /dev/null and b/img/foreground_icon_black.png differ diff --git a/img/headphones_icon_black.png b/img/headphones_icon_black.png new file mode 100644 index 00000000..2cb97ec2 Binary files /dev/null and b/img/headphones_icon_black.png differ diff --git a/img/help_icon_black.png b/img/help_icon_black.png new file mode 100644 index 00000000..156ca026 Binary files /dev/null and b/img/help_icon_black.png differ diff --git a/img/help_icon_disabled.png b/img/help_icon_disabled.png deleted file mode 100644 index 03e1c086..00000000 Binary files a/img/help_icon_disabled.png and /dev/null differ diff --git a/img/info-icon-white.png b/img/info-icon-white.png deleted file mode 100644 index 210613e0..00000000 Binary files a/img/info-icon-white.png and /dev/null differ diff --git a/img/mic_icon_black.png b/img/mic_icon_black.png new file mode 100644 index 00000000..1210b069 Binary files /dev/null and b/img/mic_icon_black.png differ diff --git a/img/narrow_arrow_down_black.png b/img/narrow_arrow_down_black.png new file mode 100644 index 00000000..21e2ea0b Binary files /dev/null and b/img/narrow_arrow_down_black.png differ diff --git a/img/narrow_arrow_down.png b/img/narrow_arrow_down_white.png similarity index 100% rename from img/narrow_arrow_down.png rename to img/narrow_arrow_down_white.png diff --git a/img/redo_icon_black.png b/img/redo_icon_black.png new file mode 100644 index 00000000..989581a3 Binary files /dev/null and b/img/redo_icon_black.png differ diff --git a/img/redo_icon_white.png b/img/redo_icon_white.png new file mode 100644 index 00000000..2a27e302 Binary files /dev/null and b/img/redo_icon_white.png differ diff --git a/img/refresh_icon.png b/img/refresh_icon.png index c5acad15..408bc2a6 100644 Binary files a/img/refresh_icon.png and b/img/refresh_icon.png differ diff --git a/img/refresh_update_icon.png b/img/refresh_update_icon.png new file mode 100644 index 00000000..c5acad15 Binary files /dev/null and b/img/refresh_update_icon.png differ diff --git a/img/save-icon.png b/img/save-icon.png deleted file mode 100644 index b74423f8..00000000 Binary files a/img/save-icon.png and /dev/null differ diff --git a/img/swap_icon_black.png b/img/swap_icon_black.png new file mode 100644 index 00000000..eec6f830 Binary files /dev/null and b/img/swap_icon_black.png differ diff --git a/img/swap_icon_white.png b/img/swap_icon_white.png new file mode 100644 index 00000000..8fa1cf53 Binary files /dev/null and b/img/swap_icon_white.png differ diff --git a/img/translation_icon_black.png b/img/translation_icon_black.png new file mode 100644 index 00000000..3e184a72 Binary files /dev/null and b/img/translation_icon_black.png differ diff --git a/img/xsoverlay.png b/img/xsoverlay.png deleted file mode 100644 index 35c793ea..00000000 Binary files a/img/xsoverlay.png and /dev/null differ diff --git a/installer/installer.nsi b/installer/installer.nsi new file mode 100644 index 00000000..f02335ee --- /dev/null +++ b/installer/installer.nsi @@ -0,0 +1,183 @@ +!define PRODUCT_VERSION "1.0.0.0" +!define VERSION "1.0.0.0" +VIProductVersion "${PRODUCT_VERSION}" +VIFileVersion "${VERSION}" +VIAddVersionKey "FileVersion" "${VERSION}" +VIAddVersionKey "ProductName" "VRCT" +VIAddVersionKey "ProductVersion" "${PRODUCT_VERSION}" +VIAddVersionKey "LegalCopyright" "Copyright m's software" +VIAddVersionKey "FileDescription" "Communication tool with translation & transcription for VRChat" + +; Modern UI +!include MUI2.nsh +; nsDialogs +!include nsDialogs.nsh +; LogicLib +!include LogicLib.nsh +; FileFunc +!include FileFunc.nsh + +!define MUI_ICON "..\img\vrct_logo_mark_black.ico" +!define MUI_UNICON "..\img\vrct_logo_mark_black.ico" + +Unicode true +; アプリケーション名 +Name "VRCT Setup" +; 作成されるインストーラ +OutFile "VRCT_Setup.exe" + +RequestExecutionLevel admin +ShowInstDetails show + +; 圧縮メソッド +SetCompressor lzma +; インストールされるディレクトリ +InstallDir "$LOCALAPPDATA\VRCT" +; XPマニフェスト +XPStyle on +; ページ +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_LICENSE "..\LICENSE" +;!insertmacro MUI_PAGE_DIRECTORY +Page custom OptionPage OptionPageLeave +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_PAGE_FINISH +; アンインストーラ ページ +!insertmacro MUI_UNPAGE_WELCOME +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_UNPAGE_FINISH +; 日本語UI +!insertmacro MUI_LANGUAGE "Japanese" +; 引数取得マクロ +!insertmacro GetParameters +!insertmacro GetOptions +; インターフェース 設定 +!define MUI_ABORTWARNING +; 変数 +Var Checkbox_InstallDocs +Var Checkbox_InstallShortcut +Var Dialog_Options +Var InstallDocs +Var InstallShortcut +Var Label_DescriptionOptions + +; 初期化時コールバック +Function .onInit + ; オプション値を初期化します。 + StrCpy $InstallDocs ${BST_CHECKED} + StrCpy $InstallShortcut ${BST_CHECKED} +FunctionEnd + +; オプション ページ +Function OptionPage + ; nsDialogsを作成します。 + nsDialogs::Create 1018 + ; 作成されたnsDialogsを変数に代入します。 + Pop $Dialog_Options + + ${If} $Dialog_Options == error + ; ダイアログの作成に失敗した場合には終了します。 + Abort + ${EndIf} + + ; ラベルを作成します。 + ${NSD_CreateLabel} 0 0 100% 12u "オプションを選択してください。" + ; ラベルを変数に代入します。 + Pop $Label_DescriptionOptions + + ${NSD_CreateCheckbox} 0 13u 100% 12u "ドキュメントをインストールする(&D)" + Pop $Checkbox_InstallDocs + + ${NSD_CreateCheckbox} 0 26u 100% 12u "デスクトップにショートカットを作成(&D)" + Pop $Checkbox_InstallShortcut + + ${If} $InstallDocs == ${BST_CHECKED} + ; チェックが入力済の場合、チェックボックスにチェックを入れます。 + ${NSD_Check} $Checkbox_InstallDocs + ${EndIf} + ${If} $InstallShortcut == ${BST_CHECKED} + ; チェックが入力済の場合、チェックボックスにチェックを入れます。 + ${NSD_Check} $Checkbox_InstallShortcut + ${EndIf} + nsDialogs::Show +FunctionEnd + +; オプション ページ退出コールバック +Function OptionPageLeave + ${NSD_GetState} $Checkbox_InstallDocs $InstallDocs + ${NSD_GetState} $Checkbox_InstallShortcut $InstallShortcut +FunctionEnd + +; デフォルト セクション +Section + ; If VRCT is already running, display a warning message and exit + StrCpy $1 "VRCT.exe" + nsProcess::_FindProcess "$1" + Pop $R1 + ${If} $R1 = 0 + nsExec::ExecToStack "taskkill /IM VRCT.exe" + ${EndIf} + + ; ディレクトリを削除 + RMDir /r "$INSTDIR" + ; スタート メニューから削除 + Delete "$SMPROGRAMS\VRCT\VRCT.lnk" + RMDir "$SMPROGRAMS\VRCT" + ; デスクトップ ショートカットを削除 + Delete "$DESKTOP\VRCT.lnk" + ; レジストリ キーを削除 + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VRCT" + + ; 出力先を指定します。 + SetOutPath "$INSTDIR" + ; インストールされるファイル + File /r "..\dist\VRCT\" + + ${If} $InstallDocs == ${BST_CHECKED} + ; ドキュメントをインストールする場合 + ; 出力先を指定します。 + SetOutPath "$INSTDIR\docs" + ; インストールされるファイル + File "..\README.txt" + ${EndIf} + + ; アンインストーラを出力 + WriteUninstaller "$INSTDIR\Uninstall.exe" + + ${If} $InstallDocs == ${BST_CHECKED} + ; デスクトップにショートカットを作成 + CreateShortCut "$DESKTOP\VRCT.lnk" "$INSTDIR\VRCT.exe" + ${EndIf} + + ; スタート メニューにショートカットを登録 + CreateDirectory "$SMPROGRAMS\VRCT" + SetOutPath "$INSTDIR" + CreateShortcut "$SMPROGRAMS\VRCT\VRCT.lnk" "$INSTDIR\VRCT.exe" "" + ; レジストリに登録 + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VRCT" "DisplayName" "VRCT" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VRCT" "UninstallString" '"$INSTDIR\Uninstall.exe"' + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VRCT" "DisplayIcon" '"$INSTDIR\_internal\img\vrct_logo_mark_black.ico"' +SectionEnd + +; アンインストーラ +Section Uninstall + ; If VRCT is already running, display a warning message and exit + StrCpy $1 "VRCT.exe" + nsProcess::_FindProcess "$1" + Pop $R1 + ${If} $R1 = 0 + MessageBox MB_OK|MB_ICONEXCLAMATION "VRCT is still running. Cannot uninstall this software.$\nPlease close VRCT and try again." /SD IDOK + Abort + ${EndIf} + ; ディレクトリを削除 + RMDir /r "$INSTDIR" + RMDir /r "$LOCALAPPDATA\VRCT" + ; スタート メニューから削除 + Delete "$SMPROGRAMS\VRCT\VRCT.lnk" + RMDir "$SMPROGRAMS\VRCT" + ; デスクトップ ショートカットを削除 + Delete "$DESKTOP\VRCT.lnk" + ; レジストリ キーを削除 + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\VRCT" +SectionEnd \ No newline at end of file diff --git a/locales/en.yml b/locales/en.yml index 3e5c4aff..887d3a92 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -7,6 +7,7 @@ main_window: language_settings: Language Settings your_language: Your Language both_direction_desc: Translate Each Other + swap_button_label: Swap Languages target_language: Target Language textbox_tab_all: All @@ -95,6 +96,10 @@ config_window: ui_size: label: UI Size + textbox_ui_size: + label: Text Box Font Size + desc: You can adjust the font size used in the logs relative to the UI size. + font_family: label: Font Family @@ -134,7 +139,9 @@ config_window: mic_word_filter: label: Mic Word Filter - desc: "It will not send the sentence if the word(s) included in the set list of words.\nHow to set: e.g. AAA,BBB,CCC" + desc: "If a registered word is detected, the text will not be sent. To add multiple words at once, separate them with a \",\" (comma). \n*Duplicate words will not be registered." + add_button_label: Add + count_desc: "Current registered word count: %{count}" speaker_dynamic_energy_threshold: @@ -175,6 +182,8 @@ config_window: message_format: label: Message Format desc: "You can change the decoration of the message you want to send.\n[message] will be replaced with the message, and [translation] will be replaced with the translated message.\nIt will be used in Notification XSOverlay too." + example_text: This is an example sentence. Fonts, line breaks, etc. may differ from the actual display. + error_message: "The characters '[message]' and '[translation]' cannot be used." send_message_to_vrc: label: Send Message To VRChat @@ -184,4 +193,7 @@ config_window: label: OSC IP Address osc_port: - label: OSC Port \ No newline at end of file + label: OSC Port + + open_config_filepath: + label: Open Config File \ No newline at end of file diff --git a/locales/ja.yml b/locales/ja.yml index 952dbfc3..313c991f 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -7,6 +7,7 @@ main_window: language_settings: 言語設定 your_language: あなたの言語 both_direction_desc: 双方向に翻訳 + swap_button_label: 言語を入れ替え target_language: 相手の言語 textbox_tab_all: 全て @@ -95,6 +96,10 @@ config_window: ui_size: label: UIサイズ + textbox_ui_size: + label: テキストボックス フォントサイズ + desc: ログに表示されるフォントのサイズを、UIサイズを基準にして倍率を変えられます。 + font_family: label: 使用フォント @@ -134,7 +139,9 @@ config_window: mic_word_filter: label: ワードフィルター - desc: "設定された単語を検出すると、その文章は送信されません。\n設定の例: AAA,BBB,CCC" + desc: "登録された単語を検出すると、その文章は送信されません。\n「,」カンマで区切ると、まとめて複数の単語を追加できます。\n※重複した単語は登録されません。" + add_button_label: 追加 + count_desc: "現在登録されている単語数: %{count}" speaker_dynamic_energy_threshold: @@ -173,7 +180,9 @@ config_window: message_format: label: 送信するメッセージのフォーマット - desc: "VRChatで相手に実際に見えるフォーマットを変更できます。\n[message]がメッセージに置換され、\n[translation]が翻訳されたメッセージに置換されます。\n※XSOverlayでの通知受け取り機能でも使われます。" + desc: "VRChatで相手に実際に見えるフォーマットを変更できます。\n[message]がメッセージに置換され、[translation]が翻訳されたメッセージに置換されます。\n※XSOverlayでの通知受け取り機能でも使われます。" + example_text: これは例文です。フォントや改行箇所など、実際の表示とは異なる場合があります。 + error_message: "[message]と[translation]という文字は使えません。" send_message_to_vrc: label: VRChatにメッセージを送信する @@ -183,4 +192,7 @@ config_window: label: OSC IP Address osc_port: - label: OSC Port \ No newline at end of file + label: OSC Port + + open_config_filepath: + label: 設定ファイルを開く \ No newline at end of file diff --git a/locales/ko.yml b/locales/ko.yml index ad08942f..fa8cc2b2 100644 --- a/locales/ko.yml +++ b/locales/ko.yml @@ -175,6 +175,7 @@ config_window: message_format: label: 전송 형식 # desc: "You can change the decoration of the message you want to send.\n[message] will be replaced with the message, and [translation] will be replaced with the translated message.\nIt will be used in Notification XSOverlay too." + example_text: 예문입니다. 글꼴, 줄 바꿈 등이 실제 표시와 다를 수 있습니다. # send_message_to_vrc: # label: Send Message To VRChat diff --git a/main.py b/main.py index 5db42c69..def1cb0b 100644 --- a/main.py +++ b/main.py @@ -12,7 +12,7 @@ if __name__ == "__main__": splash.destroySplash() controller.showMainWindow() - except Exception as e: + except Exception: import traceback with open('error.log', 'a') as f: traceback.print_exc(file=f) \ No newline at end of file diff --git a/model.py b/model.py index 51a881dd..25a7951f 100644 --- a/model.py +++ b/model.py @@ -1,9 +1,9 @@ -import sys from zipfile import ZipFile from subprocess import Popen from os import makedirs as os_makedirs -from os import path as os_path, rename as os_rename -from shutil import rmtree +from os import path as os_path +from os import remove as os_remove +from shutil import move from datetime import datetime from logging import getLogger, FileHandler, Formatter, INFO from time import sleep @@ -82,19 +82,19 @@ class Model: self.keyword_processor = KeywordProcessor() def authenticationTranslator(self, choice_translator=None, auth_key=None): - if choice_translator == None: + if choice_translator is None: choice_translator = config.CHOICE_TRANSLATOR - if auth_key == None: + if auth_key is None: auth_key = config.AUTH_KEYS[choice_translator] result = self.translator.authentication(choice_translator, auth_key) return result def startLogger(self): - os_makedirs(os_path.join(os_path.dirname(sys.argv[0]), "logs"), exist_ok=True) + os_makedirs(config.PATH_LOGS, exist_ok=True) logger = getLogger() logger.setLevel(INFO) - file_name = os_path.join(os_path.dirname(sys.argv[0]), "logs", f"{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.log") + file_name = os_path.join(config.PATH_LOGS, f"{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.log") file_handler = FileHandler(file_name, encoding="utf-8", delay=True) formatter = Formatter("[%(asctime)s] %(message)s") file_handler.setFormatter(formatter) @@ -130,10 +130,10 @@ class Model: compatible_engines.append(engine) engine_name = compatible_engines[0] - if engine_name == "DeepL" and config.AUTH_KEYS["DeepL_API"] != None: + if engine_name == "DeepL" and config.AUTH_KEYS["DeepL_API"] is not None: if self.authenticationTranslator(engine_name, config.AUTH_KEYS["DeepL_API"]) is True: engine_name = "DeepL_API" - elif engine_name == "DeepL_API" and config.AUTH_KEYS["DeepL_API"] == None: + elif engine_name == "DeepL_API" and config.AUTH_KEYS["DeepL_API"] is None: engine_name = "DeepL" return engine_name @@ -266,38 +266,40 @@ class Model: @staticmethod def updateSoftware(restart:bool=True): - filename = 'download.zip' + filename = 'VRCT.zip' program_name = 'VRCT.exe' - temporary_name = '_VRCT.exe' + folder_name = '_internal' tmp_directory_name = 'tmp' batch_name = 'update.bat' - current_directory = os_path.dirname(sys.argv[0]) - program_directory = os_path.dirname(__file__) + current_directory = config.LOCAL_PATH try: res = requests_get(config.GITHUB_URL) - url = res.json()['assets'][0]['browser_download_url'] + assets = res.json()['assets'] + url = [i["browser_download_url"] for i in assets if i["name"] == filename][0] res = requests_get(url, stream=True) os_makedirs(os_path.join(current_directory, tmp_directory_name), exist_ok=True) with open(os_path.join(current_directory, tmp_directory_name, filename), 'wb') as file: for chunk in res.iter_content(chunk_size=1024): file.write(chunk) with ZipFile(os_path.join(current_directory, tmp_directory_name, filename)) as zf: - zf.extract(program_name, os_path.join(current_directory, tmp_directory_name)) - os_rename(os_path.join(current_directory, tmp_directory_name, program_name), os_path.join(current_directory, temporary_name)) - rmtree(os_path.join(current_directory, tmp_directory_name)) - command = [os_path.join(program_directory, "batch", batch_name), program_name, temporary_name, str(restart)] - Popen(command) - except: + zf.extractall(os_path.join(current_directory, tmp_directory_name)) + os_remove(os_path.join(current_directory, tmp_directory_name, filename)) + move(os_path.join(current_directory, folder_name, "batch", batch_name), os_path.join(current_directory, batch_name)) + command = [os_path.join(current_directory, batch_name), program_name, folder_name, tmp_directory_name, str(restart)] + Popen(command, cwd=current_directory) + except Exception: webbrowser.open(config.BOOTH_URL, new=2, autoraise=True) @staticmethod def reStartSoftware(): program_name = 'VRCT.exe' + folder_name = '_internal' batch_name = 'restart.bat' - program_directory = os_path.dirname(__file__) - command = [os_path.join(program_directory, "batch", batch_name), program_name] - Popen(command) + current_directory = config.LOCAL_PATH + move(os_path.join(current_directory, folder_name, "batch", batch_name), os_path.join(current_directory, batch_name)) + command = [os_path.join(current_directory, batch_name), program_name] + Popen(command, cwd=current_directory) @staticmethod def getListInputHost(): @@ -319,7 +321,7 @@ class Model: if config.CHOICE_MIC_HOST == "NoHost" or config.CHOICE_MIC_DEVICE == "NoDevice": try: error_fnc() - except: + except Exception: pass return @@ -348,7 +350,7 @@ class Model: message = mic_transcriber.getTranscript() try: fnc(message) - except: + except Exception: pass self.mic_print_transcript = threadFnc(sendMicTranscript) @@ -367,7 +369,7 @@ class Model: if config.CHOICE_MIC_HOST == "NoHost" or config.CHOICE_MIC_DEVICE == "NoDevice": try: error_fnc() - except: + except Exception: pass return @@ -376,7 +378,7 @@ class Model: energy = mic_energy_queue.get() try: fnc(energy) - except: + except Exception: pass sleep(0.01) @@ -401,7 +403,7 @@ class Model: if speaker_device["name"] == "NoDevice": try: error_fnc() - except: + except Exception: pass return @@ -429,7 +431,7 @@ class Model: message = speaker_transcriber.getTranscript() try: fnc(message) - except: + except Exception: pass self.speaker_print_transcript = threadFnc(sendSpeakerTranscript) @@ -449,7 +451,7 @@ class Model: if speaker_device["name"] == "NoDevice": try: error_fnc() - except: + except Exception: pass return @@ -458,7 +460,7 @@ class Model: energy = speaker_energy_queue.get() try: fnc(energy) - except: + except Exception: pass sleep(0.01) diff --git a/models/osc/osc_tools.py b/models/osc/osc_tools.py index 7cb926c2..80f2b785 100644 --- a/models/osc/osc_tools.py +++ b/models/osc/osc_tools.py @@ -1,5 +1,4 @@ from time import sleep -from typing import List from pythonosc import osc_message_builder from pythonosc import udp_client from pythonosc import dispatcher @@ -15,7 +14,7 @@ def sendTyping(flag=False, ip_address="127.0.0.1", port=9000): # send OSC message def sendMessage(message=None, ip_address="127.0.0.1", port=9000): - if message != None: + if message is not None: msg = osc_message_builder.OscMessageBuilder(address="/chatbox/input") msg.add_arg(f"{message}") msg.add_arg(True) diff --git a/models/transcription/transcription_transcriber.py b/models/transcription/transcription_transcriber.py index b058f4ec..bf78566e 100644 --- a/models/transcription/transcription_transcriber.py +++ b/models/transcription/transcription_transcriber.py @@ -38,7 +38,7 @@ class AudioTranscriber: # os.close(fd) audio_data = self.audio_sources["process_data_func"]() text = self.audio_recognizer.recognize_google(audio_data, language=transcription_lang[language][country]) - except Exception as e: + except Exception: pass finally: pass diff --git a/models/translation/translation_translator.py b/models/translation/translation_translator.py index 18d2c394..c3a5682b 100644 --- a/models/translation/translation_translator.py +++ b/models/translation/translation_translator.py @@ -1,7 +1,7 @@ from deepl import Translator as deepl_Translator from deepl_translate import translate as deepl_web_Translator from translators import translate_text as other_web_Translator -from .translation_languages import translatorEngine, translation_lang +from .translation_languages import translation_lang # Translator class Translator(): @@ -16,7 +16,7 @@ class Translator(): try: self.deepl_client = deepl_Translator(authkey) self.deepl_client.translate_text(" ", target_lang="EN-US") - except: + except Exception: result = False return result @@ -52,7 +52,7 @@ class Translator(): from_language=source_language, to_language=target_language, ) - except Exception as e: + except Exception: import traceback with open('error.log', 'a') as f: traceback.print_exc(file=f) diff --git a/models/xsoverlay/notification.py b/models/xsoverlay/notification.py index 7c179f5a..cb2c03b5 100644 --- a/models/xsoverlay/notification.py +++ b/models/xsoverlay/notification.py @@ -33,7 +33,7 @@ def XSOverlay( with open(icon, "rb") as f: icon_data_bytes = f.read() icon_data = base64.b64encode(icon_data_bytes).decode("utf-8") - except: + except Exception: icon_data = "default" else: icon_data = icon diff --git a/requirements.txt b/requirements.txt index a399733d..42f4be2c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,4 +5,5 @@ customtkinter == 5.2.0 deepl == 1.15.0 flashtext == 2.7 pyyaml == 6.0.1 -python-i18n == 0.3.9 \ No newline at end of file +python-i18n == 0.3.9 +CTkToolTip == 0.8 \ No newline at end of file diff --git a/utils.py b/utils.py index 6efe6d0a..a5e38fda 100644 --- a/utils.py +++ b/utils.py @@ -1,3 +1,4 @@ +from typing import Union from os import path as os_path from PIL.Image import open as Image_open @@ -12,7 +13,8 @@ def get_key_by_value(dictionary, value): return None def callFunctionIfCallable(function, *args): - if callable(function) is True: function(*args) + if callable(function) is True: + function(*args) def isEven(number): return number % 2 == 0 @@ -26,4 +28,22 @@ def generatePercentageStringsList(start=40, end=200, step=10): strings = [] for percent in range(start, end + 1, step): strings.append(f"{percent}%") - return strings \ No newline at end of file + return strings + +def intToPercentageStringsFormatter(value:int): + return f"{value}%" + +def isUniqueStrings(unique_strings:Union[str, list], input_string:str, require=False): + import re + if isinstance(unique_strings, str): + unique_strings = [unique_strings] + patterns = [re.escape(s) for s in unique_strings] + + counts = [len(re.findall(pattern, input_string)) for pattern in patterns] + + if require is True: + # If require is True, unique_strings must appear once + return all(count == 1 for count in counts) and counts.count(1) == 2 + else: + # If require is False, check if unique strings are used exactly once + return all(count == 1 for count in counts) \ No newline at end of file diff --git a/view.py b/view.py index 3e348a96..de8b66f1 100644 --- a/view.py +++ b/view.py @@ -8,29 +8,23 @@ import i18n from languages import selectable_languages from customtkinter import StringVar, IntVar, BooleanVar, END as CTK_END, get_appearance_mode -from vrct_gui.ui_managers import ColorThemeManager, ImageFileManager, UiScalingManager +from vrct_gui.ui_managers import ColorThemeManager, UiScalingManager from vrct_gui import vrct_gui -from utils import callFunctionIfCallable, generatePercentageStringsList +from utils import callFunctionIfCallable, generatePercentageStringsList, intToPercentageStringsFormatter from config import config class View(): def __init__(self): - self.settings = SimpleNamespace() - # theme = get_appearance_mode() if config.APPEARANCE_THEME == "System" else config.APPEARANCE_THEME - theme = "Dark" - all_ctm = ColorThemeManager(theme) - all_uism = UiScalingManager(config.UI_SCALING) - image_file = ImageFileManager(theme) - + # Localization i18n.load_path.append(os_path.join(os_path.dirname(__file__), "locales")) i18n.set("fallback", "en") # The fallback language is English. i18n.set("skip_locale_root_data", True) i18n.set("filename_format", "{locale}.{format}") i18n.set("enable_memoization", True) - i18n.set("locale", config.UI_LANGUAGE) + # Save settings at startup for items that require a restart VRCT for the changes to apply self.restart_required_configs_pre_data = SimpleNamespace( appearance_theme=config.APPEARANCE_THEME, ui_scaling=config.UI_SCALING, @@ -38,9 +32,13 @@ class View(): ui_language=config.UI_LANGUAGE, ) + 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) common_args = { - "image_file": image_file, + "image_file": all_ctm.image_file, "FONT_FAMILY": config.FONT_FAMILY, } @@ -69,7 +67,6 @@ class View(): ) self.settings.error_message_window = SimpleNamespace( - ctm=all_ctm.error_message_window, uism=all_uism.error_message_window, **common_args ) @@ -84,6 +81,10 @@ class View(): # Common CALLBACK_RESTART_SOFTWARE=None, CALLBACK_UPDATE_SOFTWARE=None, + CALLBACK_OPEN_FILEPATH_LOGS=None, + CALLBACK_OPEN_FILEPATH_CONFIG_FILE=None, + + CALLBACK_QUIT_VRCT=vrct_gui._quitVRCT, CALLBACK_WHEN_DETECT_WINDOW_OVERED_SIZE=self._showDisplayOverUiSizeConfirmationModal, @@ -95,7 +96,7 @@ class View(): VAR_LABEL_CONFIRMATION_MODAL_DENY_BUTTON=StringVar(value=""), VAR_LABEL_CONFIRMATION_MODAL_ACCEPT_BUTTON=StringVar(value=""), - # Open Config Window + # Window Control (Config Window) CALLBACK_CLICKED_OPEN_CONFIG_WINDOW_BUTTON=self._openConfigWindow, CALLBACK_CLICKED_CLOSE_CONFIG_WINDOW_BUTTON=self._closeConfigWindow, CALLBACK_OPEN_CONFIG_WINDOW=None, @@ -140,6 +141,8 @@ class View(): CALLBACK_SELECTED_YOUR_LANGUAGE=None, VAR_LABEL_BOTH_DIRECTION_DESC=StringVar(value=i18n.t("main_window.both_direction_desc")), + VAR_LABEL_BOTH_DIRECTION_SWAP_BUTTON=StringVar(value=i18n.t("main_window.swap_button_label")), + CALLBACK_SWAP_LANGUAGES=None, VAR_LABEL_TARGET_LANGUAGE=StringVar(value=i18n.t("main_window.target_language")), VAR_TARGET_LANGUAGE = StringVar(value="English\n(United States)"), @@ -174,6 +177,8 @@ class View(): VAR_CONFIG_WINDOW_COMPACT_MODE_LABEL=StringVar(value=i18n.t("config_window.compact_mode")), VAR_CONFIG_WINDOW_RESTART_BUTTON_LABEL=StringVar(value=i18n.t("config_window.restart_message")), + CALLBACK_SLIDER_TOOLTIP_PERCENTAGE_FORMATTER=intToPercentageStringsFormatter, + # Side Menu Labels VAR_SIDE_MENU_LABEL_APPEARANCE=StringVar(value=i18n.t("config_window.side_menu_labels.appearance")), @@ -197,11 +202,9 @@ class View(): VAR_LABEL_APPEARANCE_THEME=StringVar(value=i18n.t("config_window.appearance_theme.label")), VAR_DESC_APPEARANCE_THEME=StringVar(value=i18n.t("config_window.appearance_theme.desc")), - LIST_APPEARANCE_THEME=["Dark"], - # LIST_APPEARANCE_THEME=["Light", "Dark", "System"], + LIST_APPEARANCE_THEME=["Light", "Dark", "System"], CALLBACK_SET_APPEARANCE_THEME=None, - VAR_APPEARANCE_THEME=StringVar(value="Dark"), - # VAR_APPEARANCE_THEME=StringVar(value=config.APPEARANCE_THEME), + VAR_APPEARANCE_THEME=StringVar(value=config.APPEARANCE_THEME), VAR_LABEL_UI_SCALING=StringVar(value=i18n.t("config_window.ui_size.label")), VAR_DESC_UI_SCALING=None, @@ -209,6 +212,14 @@ class View(): CALLBACK_SET_UI_SCALING=None, VAR_UI_SCALING=StringVar(value=config.UI_SCALING), + VAR_LABEL_TEXTBOX_UI_SCALING=StringVar(value=i18n.t("config_window.textbox_ui_size.label")), + VAR_DESC_TEXTBOX_UI_SCALING=StringVar(value=i18n.t("config_window.textbox_ui_size.desc")), + SLIDER_RANGE_TEXTBOX_UI_SCALING=(50, 200), + CALLBACK_SET_TEXTBOX_UI_SCALING=None, + VAR_TEXTBOX_UI_SCALING=IntVar(value=config.TEXTBOX_UI_SCALING), + CALLBACK_BUTTON_PRESS_TEXTBOX_UI_SCALING=self._closeTheCoverOfMainWindow, + CALLBACK_BUTTON_RELEASE_TEXTBOX_UI_SCALING=self._openTheCoverOfMainWindow, + VAR_LABEL_FONT_FAMILY=StringVar(value=i18n.t("config_window.font_family.label")), VAR_DESC_FONT_FAMILY=None, LIST_FONT_FAMILY=self.getAvailableFonts(), @@ -253,31 +264,36 @@ class View(): CALLBACK_CHECK_MIC_THRESHOLD=None, VAR_MIC_ENERGY_THRESHOLD__SLIDER=IntVar(value=config.INPUT_MIC_ENERGY_THRESHOLD), VAR_MIC_ENERGY_THRESHOLD__ENTRY=StringVar(value=config.INPUT_MIC_ENERGY_THRESHOLD), - CALLBACK_FOCUS_OUT_MIC_ENERGY_THRESHOLD=self.setLatestConfigVariable_MicEnergyThreshold, + CALLBACK_FOCUS_OUT_MIC_ENERGY_THRESHOLD=self.callbackBindFocusOut_MicEnergyThreshold, VAR_LABEL_MIC_RECORD_TIMEOUT=StringVar(value=i18n.t("config_window.mic_record_timeout.label")), VAR_DESC_MIC_RECORD_TIMEOUT=StringVar(value=i18n.t("config_window.mic_record_timeout.desc")), CALLBACK_SET_MIC_RECORD_TIMEOUT=None, VAR_MIC_RECORD_TIMEOUT=StringVar(value=config.INPUT_MIC_RECORD_TIMEOUT), - CALLBACK_FOCUS_OUT_MIC_RECORD_TIMEOUT=self.setLatestConfigVariable_MicRecordTimeout, + CALLBACK_FOCUS_OUT_MIC_RECORD_TIMEOUT=self.callbackBindFocusOut_MicRecordTimeout, VAR_LABEL_MIC_PHRASE_TIMEOUT=StringVar(value=i18n.t("config_window.mic_phrase_timeout.label")), VAR_DESC_MIC_PHRASE_TIMEOUT=StringVar(value=i18n.t("config_window.mic_phrase_timeout.desc")), CALLBACK_SET_MIC_PHRASE_TIMEOUT=None, VAR_MIC_PHRASE_TIMEOUT=StringVar(value=config.INPUT_MIC_PHRASE_TIMEOUT), - CALLBACK_FOCUS_OUT_MIC_PHRASE_TIMEOUT=self.setLatestConfigVariable_MicPhraseTimeout, + CALLBACK_FOCUS_OUT_MIC_PHRASE_TIMEOUT=self.callbackBindFocusOut_MicPhraseTimeout, VAR_LABEL_MIC_MAX_PHRASES=StringVar(value=i18n.t("config_window.mic_max_phrase.label")), VAR_DESC_MIC_MAX_PHRASES=StringVar(value=i18n.t("config_window.mic_max_phrase.desc")), CALLBACK_SET_MIC_MAX_PHRASES=None, VAR_MIC_MAX_PHRASES=StringVar(value=config.INPUT_MIC_MAX_PHRASES), - CALLBACK_FOCUS_OUT_MIC_MAX_PHRASES=self.setLatestConfigVariable_MicMaxPhrases, + CALLBACK_FOCUS_OUT_MIC_MAX_PHRASES=self.callbackBindFocusOut_MicMaxPhrases, + + CALLBACK_ARROW_SWITCH_MIC_WORD_FILTER_LIST_OPEN=self._openMicWordFilterList, + CALLBACK_ARROW_SWITCH_MIC_WORD_FILTER_LIST_CLOSE=self._closeMicWordFilterList, VAR_LABEL_MIC_WORD_FILTER=StringVar(value=i18n.t("config_window.mic_word_filter.label")), VAR_DESC_MIC_WORD_FILTER=StringVar(value=i18n.t("config_window.mic_word_filter.desc")), + VAR_SWITCH_DESC_MIC_WORD_FILTER=StringVar(value=i18n.t("config_window.mic_word_filter.count_desc", count=len(config.INPUT_MIC_WORD_FILTER))), + VAR_LABEL_MIC_WORD_FILTER_ADD_BUTTON=StringVar(value=i18n.t("config_window.mic_word_filter.add_button_label")), CALLBACK_SET_MIC_WORD_FILTER=None, - VAR_MIC_WORD_FILTER=StringVar(value=",".join(config.INPUT_MIC_WORD_FILTER) if len(config.INPUT_MIC_WORD_FILTER) > 0 else ""), + MIC_WORD_FILTER_LIST=config.INPUT_MIC_WORD_FILTER, # Transcription Tab (Speaker) @@ -290,26 +306,26 @@ class View(): CALLBACK_CHECK_SPEAKER_THRESHOLD=None, VAR_SPEAKER_ENERGY_THRESHOLD__SLIDER=IntVar(value=config.INPUT_SPEAKER_ENERGY_THRESHOLD), VAR_SPEAKER_ENERGY_THRESHOLD__ENTRY=StringVar(value=config.INPUT_SPEAKER_ENERGY_THRESHOLD), - CALLBACK_FOCUS_OUT_SPEAKER_ENERGY_THRESHOLD=self.setLatestConfigVariable_SpeakerEnergyThreshold, + CALLBACK_FOCUS_OUT_SPEAKER_ENERGY_THRESHOLD=self.callbackBindFocusOut_SpeakerEnergyThreshold, VAR_LABEL_SPEAKER_RECORD_TIMEOUT=StringVar(value=i18n.t("config_window.speaker_record_timeout.label")), VAR_DESC_SPEAKER_RECORD_TIMEOUT=StringVar(value=i18n.t("config_window.speaker_record_timeout.desc")), CALLBACK_SET_SPEAKER_RECORD_TIMEOUT=None, VAR_SPEAKER_RECORD_TIMEOUT=StringVar(value=config.INPUT_SPEAKER_RECORD_TIMEOUT), - CALLBACK_FOCUS_OUT_SPEAKER_RECORD_TIMEOUT=self.setLatestConfigVariable_SpeakerRecordTimeout, + CALLBACK_FOCUS_OUT_SPEAKER_RECORD_TIMEOUT=self.callbackBindFocusOut_SpeakerRecordTimeout, VAR_LABEL_SPEAKER_PHRASE_TIMEOUT=StringVar(value=i18n.t("config_window.speaker_phrase_timeout.label")), VAR_DESC_SPEAKER_PHRASE_TIMEOUT=StringVar(value=i18n.t("config_window.speaker_phrase_timeout.desc")), CALLBACK_SET_SPEAKER_PHRASE_TIMEOUT=None, VAR_SPEAKER_PHRASE_TIMEOUT=StringVar(value=config.INPUT_SPEAKER_PHRASE_TIMEOUT), - CALLBACK_FOCUS_OUT_SPEAKER_PHRASE_TIMEOUT=self.setLatestConfigVariable_SpeakerPhraseTimeout, + CALLBACK_FOCUS_OUT_SPEAKER_PHRASE_TIMEOUT=self.callbackBindFocusOut_SpeakerPhraseTimeout, VAR_LABEL_SPEAKER_MAX_PHRASES=StringVar(value=i18n.t("config_window.speaker_max_phrase.label")), VAR_DESC_SPEAKER_MAX_PHRASES=StringVar(value=i18n.t("config_window.speaker_max_phrase.desc")), CALLBACK_SET_SPEAKER_MAX_PHRASES=None, VAR_SPEAKER_MAX_PHRASES=StringVar(value=config.INPUT_SPEAKER_MAX_PHRASES), - CALLBACK_FOCUS_OUT_SPEAKER_MAX_PHRASES=self.setLatestConfigVariable_SpeakerMaxPhrases, + CALLBACK_FOCUS_OUT_SPEAKER_MAX_PHRASES=self.callbackBindFocusOut_SpeakerMaxPhrases, # Others Tab @@ -332,7 +348,15 @@ class View(): VAR_LABEL_MESSAGE_FORMAT=StringVar(value=i18n.t("config_window.message_format.label")), VAR_DESC_MESSAGE_FORMAT=StringVar(value=i18n.t("config_window.message_format.desc")), CALLBACK_SET_MESSAGE_FORMAT=None, + CALLBACK_SWAP_MESSAGE_FORMAT_REQUIRED_TEXT=self._swapMessageFormatRequiredText, VAR_MESSAGE_FORMAT=StringVar(value=config.MESSAGE_FORMAT), + VAR_LABEL_EXAMPLE_TEXT_MESSAGE_FORMAT=StringVar(value=""), + VAR_ENTRY_0_MESSAGE_FORMAT=StringVar(value=""), + VAR_ENTRY_1_MESSAGE_FORMAT=StringVar(value=""), + VAR_ENTRY_2_MESSAGE_FORMAT=StringVar(value=""), + VAR_TEXT_REQUIRED_0_MESSAGE_FORMAT=StringVar(value="[message]"), + VAR_TEXT_REQUIRED_1_MESSAGE_FORMAT=StringVar(value="[translation]"), + CALLBACK_FOCUS_OUT_MESSAGE_FORMAT=self.callbackBindFocusOut_MessageFormat, VAR_LABEL_ENABLE_SEND_MESSAGE_TO_VRC=StringVar(value=i18n.t("config_window.send_message_to_vrc.label")), @@ -359,6 +383,9 @@ class View(): VAR_DESC_OSC_PORT=None, CALLBACK_SET_OSC_PORT=None, VAR_OSC_PORT=StringVar(value=config.OSC_PORT), + + VAR_LABEL_OPEN_CONFIG_FILEPATH=StringVar(value=i18n.t("config_window.open_config_filepath.label")), + VAR_DESC_OPEN_CONFIG_FILEPATH=None, ) @@ -375,6 +402,8 @@ class View(): if common_registers is not None: self.view_variable.CALLBACK_UPDATE_SOFTWARE=common_registers.get("callback_update_software", None) self.view_variable.CALLBACK_RESTART_SOFTWARE=common_registers.get("callback_restart_software", None) + self.view_variable.CALLBACK_OPEN_FILEPATH_LOGS=common_registers.get("callback_filepath_logs", None) + self.view_variable.CALLBACK_OPEN_FILEPATH_CONFIG_FILE=common_registers.get("callback_filepath_config_file", None) if window_action_registers is not None: @@ -395,6 +424,7 @@ class View(): self.view_variable.CALLBACK_SELECTED_YOUR_LANGUAGE = main_window_registers.get("callback_your_language", None) self.view_variable.CALLBACK_SELECTED_TARGET_LANGUAGE = main_window_registers.get("callback_target_language", None) main_window_registers.get("values", None) and self.updateList_selectableLanguages(main_window_registers["values"]) + self.view_variable.CALLBACK_SWAP_LANGUAGES = main_window_registers.get("callback_swap_languages", None) self.view_variable.CALLBACK_SELECTED_LANGUAGE_PRESET_TAB = main_window_registers.get("callback_selected_language_preset_tab", None) @@ -430,6 +460,7 @@ class View(): self.view_variable.CALLBACK_SET_APPEARANCE = config_window_registers.get("callback_set_appearance", None) self.view_variable.CALLBACK_SET_UI_SCALING = config_window_registers.get("callback_set_ui_scaling", None) + self.view_variable.CALLBACK_SET_TEXTBOX_UI_SCALING = config_window_registers.get("callback_set_textbox_ui_scaling", None) self.view_variable.CALLBACK_SET_FONT_FAMILY = config_window_registers.get("callback_set_font_family", None) self.view_variable.CALLBACK_SET_UI_LANGUAGE = config_window_registers.get("callback_set_ui_language", None) @@ -451,6 +482,7 @@ class View(): self.view_variable.CALLBACK_SET_MIC_PHRASE_TIMEOUT = config_window_registers.get("callback_set_mic_phrase_timeout", None) self.view_variable.CALLBACK_SET_MIC_MAX_PHRASES = config_window_registers.get("callback_set_mic_max_phrases", None) self.view_variable.CALLBACK_SET_MIC_WORD_FILTER = config_window_registers.get("callback_set_mic_word_filter", None) + self.view_variable.CALLBACK_DELETE_MIC_WORD_FILTER = config_window_registers.get("callback_delete_mic_word_filter", None) # Transcription Tab (Speaker) self.view_variable.CALLBACK_SET_SPEAKER_ENERGY_THRESHOLD = config_window_registers.get("callback_set_speaker_energy_threshold", None) @@ -478,13 +510,6 @@ class View(): self.enableConfigWindowCompactMode() vrct_gui.config_window.setting_box_compact_mode_switch_box.select() - vrct_gui._changeConfigWindowWidgetsStatus( - status="disabled", - target_names=[ - "sb__optionmenu_appearance_theme", - ] - ) - if config.CHOICE_MIC_HOST == "NoHost": self.view_variable.VAR_MIC_HOST.set("No Mic Host Detected") @@ -514,10 +539,73 @@ class View(): self.openSpeakerEnergyThresholdWidget() + self.setMessageFormatEntryWidgets(config.MESSAGE_FORMAT) + # Insert sample conversation for testing. # self._insertSampleConversationToTextbox() + def setMessageFormatEntryWidgets(self, message_format:str): + result = self.extractMessageFormat(message_format) + + if result.is_message_first is True: + self.view_variable.VAR_TEXT_REQUIRED_0_MESSAGE_FORMAT.set("[message]") + self.view_variable.VAR_TEXT_REQUIRED_1_MESSAGE_FORMAT.set("[translation]") + else: + self.view_variable.VAR_TEXT_REQUIRED_0_MESSAGE_FORMAT.set("[translation]") + self.view_variable.VAR_TEXT_REQUIRED_1_MESSAGE_FORMAT.set("[message]") + + self.view_variable.VAR_ENTRY_0_MESSAGE_FORMAT.set(result.before) + self.view_variable.VAR_ENTRY_1_MESSAGE_FORMAT.set(result.between) + self.view_variable.VAR_ENTRY_2_MESSAGE_FORMAT.set(result.after) + self.updateMessageFormat_ExampleTextWidget() + + def _swapMessageFormatRequiredText(self): + text_0 = self.view_variable.VAR_TEXT_REQUIRED_0_MESSAGE_FORMAT.get() + text_1 = self.view_variable.VAR_TEXT_REQUIRED_1_MESSAGE_FORMAT.get() + self.view_variable.VAR_TEXT_REQUIRED_0_MESSAGE_FORMAT.set(text_1) + self.view_variable.VAR_TEXT_REQUIRED_1_MESSAGE_FORMAT.set(text_0) + self.updateMessageFormat_ExampleTextWidget() + + new_message_format = self.getLatestMessageFormatFromWidget() + callFunctionIfCallable(self.view_variable.CALLBACK_SET_MESSAGE_FORMAT, new_message_format) + + + def getLatestMessageFormatFromWidget(self): + text_0 = self.view_variable.VAR_TEXT_REQUIRED_0_MESSAGE_FORMAT.get() + text_1 = self.view_variable.VAR_TEXT_REQUIRED_1_MESSAGE_FORMAT.get() + entry_0 = self.view_variable.VAR_ENTRY_0_MESSAGE_FORMAT.get() + entry_1 = self.view_variable.VAR_ENTRY_1_MESSAGE_FORMAT.get() + entry_2 = self.view_variable.VAR_ENTRY_2_MESSAGE_FORMAT.get() + return entry_0+text_0+entry_1+text_1+entry_2 + + def updateMessageFormat_ExampleTextWidget(self): + message = i18n.t("config_window.message_format.example_text", locale=config.UI_LANGUAGE) + translation_locale = "ja" if config.UI_LANGUAGE == "en" else "en" + translation = i18n.t("config_window.message_format.example_text", locale=translation_locale) + + example_message = config.MESSAGE_FORMAT.replace("[message]", message) + example_message = example_message.replace("[translation]", translation) + + self.view_variable.VAR_LABEL_EXAMPLE_TEXT_MESSAGE_FORMAT.set(example_message) + + +# GUI process + def createGUI(self): + vrct_gui._createGUI(settings=self.settings, view_variable=self.view_variable) + + @staticmethod + def showGUI(): + vrct_gui._showGUI() + + @staticmethod + def startMainLoop(): + vrct_gui._showGUI() + vrct_gui._startMainLoop() + + + +# Common @staticmethod def getAvailableFonts(): available_fonts = list(tk_font.families()) @@ -529,6 +617,8 @@ class View(): def openWebPage(url:str): webbrowser.open_new_tab(url) + +# Open Webpage Functions def openWebPage_Booth(self): self.openWebPage(config.BOOTH_URL) self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.opened_web_page_booth")) @@ -537,6 +627,16 @@ class View(): self.openWebPage(config.DOCUMENTS_URL) self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.opened_web_page_vrct_documents")) +# Widget Control + # Common + @staticmethod + def _clearEntryBox(entry_widget): + entry_widget.delete(0, CTK_END) + + def clearErrorMessage(self): + vrct_gui._clearErrorMessage() + + @staticmethod def showUpdateAvailableButton(): vrct_gui.update_available_container.grid() @@ -550,154 +650,6 @@ class View(): vrct_gui._changeMainWindowWidgetsStatus("disabled", "All") - - def foregroundOnIfForegroundEnabled(self): - if config.ENABLE_FOREGROUND: - self.foregroundOn() - - def foregroundOffIfForegroundEnabled(self): - if config.ENABLE_FOREGROUND: - self.foregroundOff() - - - @staticmethod - def foregroundOn(): - vrct_gui.attributes("-topmost", True) - - @staticmethod - def foregroundOff(): - vrct_gui.attributes("-topmost", False) - - - def _adjustUiSizeAndRestart(self): - current_percentage = int(config.UI_SCALING.replace("%","")) - target_percentage = current_percentage - 20 - if target_percentage >= 40 and str(target_percentage) + "%" in self.view_variable.LIST_UI_SCALING: - index = self.view_variable.LIST_UI_SCALING.index(str(target_percentage) + "%") - callFunctionIfCallable(self.view_variable.CALLBACK_SET_UI_SCALING, self.view_variable.LIST_UI_SCALING[index]) - callFunctionIfCallable(self.view_variable.CALLBACK_RESTART_SOFTWARE) - else: - self._hideConfirmationModal() - # ※Below 40% of the UI size is not supported, and we cannot handle it at this time. - - - - - - def _showDisplayOverUiSizeConfirmationModal(self): - self.foregroundOffIfForegroundEnabled() - - self.view_variable.VAR_LABEL_MAIN_WINDOW_COVER_MESSAGE.set("") - vrct_gui.main_window_cover.show() - - self.view_variable.CALLBACK_HIDE_CONFIRMATION_MODAL=self._hideConfirmationModal - self.view_variable.CALLBACK_ACCEPTED_CONFIRMATION_MODAL=self._adjustUiSizeAndRestart - self.view_variable.CALLBACK_DENIED_CONFIRMATION_MODAL=self._hideConfirmationModal - - self.view_variable.VAR_MESSAGE_CONFIRMATION_MODAL.set(i18n.t("main_window.confirmation_message.detected_over_ui_size", current_ui_size=config.UI_SCALING)) - self.view_variable.VAR_LABEL_CONFIRMATION_MODAL_DENY_BUTTON.set(i18n.t("main_window.confirmation_message.deny_adjust_ui_size")) - self.view_variable.VAR_LABEL_CONFIRMATION_MODAL_ACCEPT_BUTTON.set(i18n.t("main_window.confirmation_message.accept_adjust_ui_size")) - - vrct_gui.confirmation_modal.show(hide_title_bar=False, close_when_focusout=False) - - - - def _showUpdateSoftwareConfirmationModal(self): - self.foregroundOffIfForegroundEnabled() - - self.view_variable.VAR_LABEL_MAIN_WINDOW_COVER_MESSAGE.set("") - vrct_gui.main_window_cover.show() - - self.view_variable.CALLBACK_HIDE_CONFIRMATION_MODAL=self._hideConfirmationModal - self.view_variable.CALLBACK_ACCEPTED_CONFIRMATION_MODAL=self._startUpdateSoftware - self.view_variable.CALLBACK_DENIED_CONFIRMATION_MODAL=self._hideConfirmationModal - - self.view_variable.VAR_MESSAGE_CONFIRMATION_MODAL.set(i18n.t("main_window.confirmation_message.update_software")) - self.view_variable.VAR_LABEL_CONFIRMATION_MODAL_DENY_BUTTON.set(i18n.t("main_window.confirmation_message.deny_update_software")) - self.view_variable.VAR_LABEL_CONFIRMATION_MODAL_ACCEPT_BUTTON.set(i18n.t("main_window.confirmation_message.accept_update_software")) - vrct_gui.confirmation_modal.show() - - - - - - def showTheLimitOfTranslationEngineConfirmationModal(self): - self.foregroundOffIfForegroundEnabled() - - self.view_variable.VAR_LABEL_MAIN_WINDOW_COVER_MESSAGE.set("") - vrct_gui.main_window_cover.show() - - self.view_variable.CALLBACK_HIDE_CONFIRMATION_MODAL=self._hideInformationModal - self.view_variable.CALLBACK_ACCEPTED_CONFIRMATION_MODAL=self._hideInformationModal - # self.view_variable.CALLBACK_DENIED_CONFIRMATION_MODAL=self._hideConfirmationModal - - self.view_variable.VAR_MESSAGE_CONFIRMATION_MODAL.set(i18n.t("main_window.confirmation_message.translation_engine_limit_error")) - # self.view_variable.VAR_LABEL_CONFIRMATION_MODAL_DENY_BUTTON.set(i18n.t("main_window.confirmation_message.deny_update_software")) - self.view_variable.VAR_LABEL_CONFIRMATION_MODAL_ACCEPT_BUTTON.set(i18n.t("main_window.confirmation_message.accept_translation_engine_limit_error")) - vrct_gui.information_modal.show(hide_title_bar=False, close_when_focusout=False) - - - - def translationEngineLimitErrorProcess(self): - # turn off translation switch. - vrct_gui.translation_switch_box.deselect() - vrct_gui.translation_frame.markToggleManually(False) - - # disable translation feature. - vrct_gui._changeMainWindowWidgetsStatus("disabled", ["translation_switch"], to_hold_state=True) - - # print system message that mention to stopped translation feature. - view.printToTextbox_TranslationEngineLimitError() - view.showTheLimitOfTranslationEngineConfirmationModal() - - - - - - - - def _hideInformationModal(self): - vrct_gui.information_modal.hide() - vrct_gui.main_window_cover.hide() - self.foregroundOnIfForegroundEnabled() - - - def _hideConfirmationModal(self): - vrct_gui.confirmation_modal.hide() - vrct_gui.main_window_cover.hide() - self.foregroundOnIfForegroundEnabled() - - # def _deniedUpdateSoftware(self): - # self._hideConfirmationModal() - - def _startUpdateSoftware(self): - self.view_variable.VAR_MESSAGE_CONFIRMATION_MODAL.set(i18n.t("main_window.confirmation_message.updating")) - vrct_gui.confirmation_modal.hide_buttons() - vrct_gui.update() - vrct_gui.confirmation_modal.update() - callFunctionIfCallable(self.view_variable.CALLBACK_UPDATE_SOFTWARE) - - - - def _openConfigWindow(self): - self.view_variable.VAR_LABEL_MAIN_WINDOW_COVER_MESSAGE.set(i18n.t("main_window.cover_message")) - callFunctionIfCallable(self.view_variable.CALLBACK_OPEN_CONFIG_WINDOW) - vrct_gui._openConfigWindow() - - def _closeConfigWindow(self): - callFunctionIfCallable(self.view_variable.CALLBACK_CLOSE_CONFIG_WINDOW) - vrct_gui._closeConfigWindow() - - - - def _openTheCoverOfMainWindow(self): - vrct_gui.main_window_cover.show() - vrct_gui.config_window.lift() - - @staticmethod - def _closeTheCoverOfMainWindow(): - vrct_gui.main_window_cover.withdraw() - def enableMainWindowSidebarCompactMode(self): self.view_variable.IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE = True vrct_gui._enableMainWindowSidebarCompactMode() @@ -706,158 +658,19 @@ class View(): self.view_variable.IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE = False vrct_gui._disableMainWindowSidebarCompactMode() - def openSelectableLanguagesWindow_YourLanguage(self, _e): - self.view_variable.VAR_TITLE_LABEL_SELECTABLE_LANGUAGE.set(i18n.t("selectable_language_window.title_your_language")) - vrct_gui._openSelectableLanguagesWindow("your_language") - - def openSelectableLanguagesWindow_TargetLanguage(self, _e): - self.view_variable.VAR_TITLE_LABEL_SELECTABLE_LANGUAGE.set(i18n.t("selectable_language_window.title_target_language")) - vrct_gui._openSelectableLanguagesWindow("target_language") - - - def updateGuiVariableByPresetTabNo(self, tab_no:str): - self.view_variable.VAR_YOUR_LANGUAGE.set(config.SELECTED_TAB_YOUR_LANGUAGES[tab_no]) - self.view_variable.VAR_TARGET_LANGUAGE.set(config.SELECTED_TAB_TARGET_LANGUAGES[tab_no]) - - - def updateList_selectableLanguages(self, new_selectable_language_list:list): - self.view_variable.LIST_SELECTABLE_LANGUAGES = new_selectable_language_list - - - def printToTextbox_enableTranslation(self): - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.enabled_translation")) - def printToTextbox_disableTranslation(self): - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.disabled_translation")) - - def printToTextbox_enableTranscriptionSend(self): - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.enabled_voice2chatbox")) - def printToTextbox_disableTranscriptionSend(self): - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.disabled_voice2chatbox")) - - def printToTextbox_enableTranscriptionReceive(self): - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.enabled_speaker2log")) - def printToTextbox_disableTranscriptionReceive(self): - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.disabled_speaker2log")) - - def printToTextbox_enableForeground(self): - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.enabled_foreground")) - def printToTextbox_disableForeground(self): - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.disabled_foreground")) - - def printToTextbox_AuthenticationSuccess(self): - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.auth_key_success")) - def printToTextbox_AuthenticationError(self): - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.auth_key_error")) - - - def printToTextbox_TranscriptionSendNoDeviceError(self): - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.no_mic_device_detected_error")) - - def printToTextbox_TranscriptionReceiveNoDeviceError(self): - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.no_speaker_device_detected_error")) - - - def printToTextbox_TranslationEngineLimitError(self): - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.translation_engine_limit_error")) - - - # def printToTextbox_OSCError(self): [Deprecated] - # self._printToTextbox_Info("OSC is not enabled, please enable OSC and rejoin. or turn off the \"Send Message To VRChat\" setting") - - def printToTextbox_DetectedByWordFilter(self, detected_message): - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.detected_by_word_filter"), detected_message=detected_message) - - - - def printToTextbox_selectedYourLanguages(self, selected_your_language): - your_language = selected_your_language.replace("\n", " ") - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.selected_your_language", your_language=your_language)) - - def printToTextbox_selectedTargetLanguages(self, selected_target_language): - target_language = selected_target_language.replace("\n", " ") - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.selected_target_language", target_language=target_language)) - - def printToTextbox_changedLanguagePresetTab(self, tab_no:str): - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.switched_language_preset_tab", tab_no=tab_no)) - self.printToTextbox_latestSelectedLanguages() - - def printToTextbox_latestSelectedLanguages(self): - your_language = self.view_variable.VAR_YOUR_LANGUAGE.get().replace("\n", " ") - target_language = self.view_variable.VAR_TARGET_LANGUAGE.get().replace("\n", " ") - self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.latest_language_setting", your_language=your_language, target_language=target_language)) - - - @staticmethod - def _printToTextbox_Info(info_message): - vrct_gui._printToTextbox( - target_type="SYSTEM", - original_message=info_message, - # translated_message="", - ) - - - - def printToTextbox_SentMessage(self, original_message, translated_message): - self._printToTextbox_Sent(original_message, translated_message) - - @staticmethod - def _printToTextbox_Sent(original_message, translated_message): - vrct_gui._printToTextbox( - target_type="SENT", - original_message=original_message, - translated_message=translated_message, - ) - - - def printToTextbox_ReceivedMessage(self, original_message, translated_message): - self._printToTextbox_Received(original_message, translated_message) - - @staticmethod - def _printToTextbox_Received(original_message, translated_message): - vrct_gui._printToTextbox( - target_type="RECEIVED", - original_message=original_message, - translated_message=translated_message, - ) - - - @staticmethod - def getTextFromMessageBox(): - return vrct_gui.entry_message_box.get() - - @staticmethod - def clearMessageBox(): - vrct_gui.entry_message_box.delete(0, CTK_END) - - @staticmethod - def setMainWindowTransparency(transparency:float): - vrct_gui.wm_attributes("-alpha", transparency) - + # Config Window def enableConfigWindowCompactMode(self): for additional_widget in vrct_gui.config_window.additional_widgets: additional_widget.grid_remove() + self._closeMicWordFilterList() def disableConfigWindowCompactMode(self): for additional_widget in vrct_gui.config_window.additional_widgets: additional_widget.grid() + self._closeMicWordFilterList() - - def createGUI(self): - vrct_gui._createGUI(settings=self.settings, view_variable=self.view_variable) - - @staticmethod - def showGUI(): - vrct_gui._showGUI() - - @staticmethod - def startMainLoop(): - vrct_gui._showGUI() - vrct_gui._startMainLoop() - - - # Config Window def showRestartButtonIfRequired(self, locale:Union[None,str]=None): is_restart_required = not ( self.restart_required_configs_pre_data.appearance_theme == config.APPEARANCE_THEME and @@ -881,8 +694,7 @@ class View(): def _hideRestartButton(self): vrct_gui.config_window.restart_button_container.grid_remove() - def _updateActiveSettingBoxTabNo(self, active_setting_box_tab_attr_name:str): - self.view_variable.ACTIVE_SETTING_BOX_TAB_ATTR_NAME = active_setting_box_tab_attr_name + @staticmethod def setWidgetsStatus_ConfigWindowCompactModeSwitch_Disabled(): @@ -892,6 +704,8 @@ class View(): def setWidgetsStatus_ConfigWindowCompactModeSwitch_Normal(): vrct_gui.config_window.setting_box_compact_mode_switch_box.configure(state="normal") + + def openMicEnergyThresholdWidget(self): self.view_variable.VAR_LABEL_MIC_DYNAMIC_ENERGY_THRESHOLD.set(i18n.t("config_window.mic_dynamic_energy_threshold.label_for_manual")) self.view_variable.VAR_DESC_MIC_DYNAMIC_ENERGY_THRESHOLD.set(i18n.t("config_window.mic_dynamic_energy_threshold.desc_for_manual")) @@ -967,6 +781,7 @@ class View(): + def updateList_MicHost(self, new_mic_host_list:list): self.view_variable.LIST_MIC_HOST = new_mic_host_list vrct_gui.dropdown_menu_window.updateDropdownMenuValues( @@ -988,104 +803,485 @@ class View(): self.view_variable.VAR_MIC_DEVICE.set(default_selected_mic_device_name) - @staticmethod - def updateSetProgressBar_MicEnergy(new_mic_energy): - vrct_gui.config_window.sb__progressbar_x_slider__progressbar_mic_energy_threshold.set(new_mic_energy/config.MAX_MIC_ENERGY_THRESHOLD) + def updateSetProgressBar_MicEnergy(self, new_mic_energy): + self.updateProgressBar( + target_progressbar_widget=vrct_gui.config_window.sb__progressbar_x_slider__progressbar_mic_energy_threshold, + new_energy=new_mic_energy, + max_energy=config.MAX_MIC_ENERGY_THRESHOLD, + energy_threshold=config.INPUT_MIC_ENERGY_THRESHOLD, + ) + @staticmethod def initProgressBar_MicEnergy(): vrct_gui.config_window.sb__progressbar_x_slider__progressbar_mic_energy_threshold.set(0) - @staticmethod - def updateSetProgressBar_SpeakerEnergy(new_speaker_energy): - vrct_gui.config_window.sb__progressbar_x_slider__progressbar_speaker_energy_threshold.set(new_speaker_energy/config.MAX_SPEAKER_ENERGY_THRESHOLD) + def updateSetProgressBar_SpeakerEnergy(self, new_speaker_energy): + self.updateProgressBar( + target_progressbar_widget=vrct_gui.config_window.sb__progressbar_x_slider__progressbar_speaker_energy_threshold, + new_energy=new_speaker_energy, + max_energy=config.MAX_SPEAKER_ENERGY_THRESHOLD, + energy_threshold=config.INPUT_SPEAKER_ENERGY_THRESHOLD, + ) @staticmethod def initProgressBar_SpeakerEnergy(): vrct_gui.config_window.sb__progressbar_x_slider__progressbar_speaker_energy_threshold.set(0) + def updateProgressBar( + self, + target_progressbar_widget, + new_energy, + max_energy, + energy_threshold, + ): + target_progressbar_widget.set(new_energy/max_energy) + if new_energy >= energy_threshold: + target_progressbar_widget.configure(progress_color=self.settings.config_window.ctm.SB__PROGRESSBAR_X_SLIDER__PROGRESSBAR_PROGRESS_EXCEED_THRESHOLD_BG_COLOR) + else: + target_progressbar_widget.configure(progress_color=self.settings.config_window.ctm.SB__PROGRESSBAR_X_SLIDER__PROGRESSBAR_PROGRESS_BG_COLOR) + + + def _openMicWordFilterList(self): + target_widget = vrct_gui.config_window.sb__widgets["sb__arrow_switch_mic_word_filter"] + target_widget.arrow_switch_open.grid_remove() + target_widget.arrow_switch_close.grid() + + vrct_gui.config_window.sb__mic_word_filter_list.grid() + + def _closeMicWordFilterList(self): + target_widget = vrct_gui.config_window.sb__widgets["sb__arrow_switch_mic_word_filter"] + target_widget.arrow_switch_close.grid_remove() + target_widget.arrow_switch_open.grid() + + vrct_gui.config_window.sb__mic_word_filter_list.grid_remove() + + + def addValueToList_WordFilter(self, values:list): + target_widget = vrct_gui.config_window.sb__widgets["sb__add_and_delete_able_list_mic_word_filter_list"] + for t_item in target_widget.items: + if t_item.label in values: + values.remove(t_item.label) + t_item.redoFunction() + mic_word_filter_item_row_wrapper, accumulated_labels_width, last_row, last_column = target_widget.addValues( + values, + target_widget.mic_word_filter_item_row_wrapper, + target_widget.accumulated_labels_width, + target_widget.last_row, + target_widget.last_column + ) + target_widget.mic_word_filter_item_row_wrapper = mic_word_filter_item_row_wrapper + target_widget.accumulated_labels_width = accumulated_labels_width + target_widget.last_row = last_row + target_widget.last_column = last_column + + def clearEntryBox_WordFilter(self): + self._clearEntryBox(vrct_gui.config_window.sb__entry_mic_word_filter_list) + + +# Widget Control (Whole) + def foregroundOnIfForegroundEnabled(self): + if config.ENABLE_FOREGROUND: + self.foregroundOn() + + def foregroundOffIfForegroundEnabled(self): + if config.ENABLE_FOREGROUND: + self.foregroundOff() + + + @staticmethod + def foregroundOn(): + vrct_gui.attributes("-topmost", True) + + @staticmethod + def foregroundOff(): + vrct_gui.attributes("-topmost", False) + + + @staticmethod + def setMainWindowTransparency(transparency:float): + vrct_gui.wm_attributes("-alpha", transparency) + + @staticmethod + def setMainWindowTextboxUiSize(custom_font_size_scale:float): + vrct_gui.print_to_textbox.setTagsSettings(custom_font_size_scale=custom_font_size_scale) + +# Function + def _adjustUiSizeAndRestart(self): + current_percentage = int(config.UI_SCALING.replace("%","")) + target_percentage = current_percentage - 20 + if target_percentage >= 40 and str(target_percentage) + "%" in self.view_variable.LIST_UI_SCALING: + index = self.view_variable.LIST_UI_SCALING.index(str(target_percentage) + "%") + callFunctionIfCallable(self.view_variable.CALLBACK_SET_UI_SCALING, self.view_variable.LIST_UI_SCALING[index]) + callFunctionIfCallable(self.view_variable.CALLBACK_RESTART_SOFTWARE) + else: + self._hideConfirmationModal() + # ※Below 40% of the UI size is not supported, and we cannot handle it at this time. + + + + def translationEngineLimitErrorProcess(self): + # turn off translation switch. + vrct_gui.translation_switch_box.deselect() + vrct_gui.translation_frame.markToggleManually(False) + + # disable translation feature. + vrct_gui._changeMainWindowWidgetsStatus("disabled", ["translation_switch"], to_hold_state=True) + + # print system message that mention to stopped translation feature. + view.printToTextbox_TranslationEngineLimitError() + view.showTheLimitOfTranslationEngineConfirmationModal() + + + + +# Show Modal + def _showDisplayOverUiSizeConfirmationModal(self): + self.foregroundOffIfForegroundEnabled() + + self.view_variable.VAR_LABEL_MAIN_WINDOW_COVER_MESSAGE.set("") + vrct_gui.main_window_cover.show() + + self.view_variable.CALLBACK_HIDE_CONFIRMATION_MODAL=self._hideConfirmationModal + self.view_variable.CALLBACK_ACCEPTED_CONFIRMATION_MODAL=self._adjustUiSizeAndRestart + self.view_variable.CALLBACK_DENIED_CONFIRMATION_MODAL=self._hideConfirmationModal + + self.view_variable.VAR_MESSAGE_CONFIRMATION_MODAL.set(i18n.t("main_window.confirmation_message.detected_over_ui_size", current_ui_size=config.UI_SCALING)) + self.view_variable.VAR_LABEL_CONFIRMATION_MODAL_DENY_BUTTON.set(i18n.t("main_window.confirmation_message.deny_adjust_ui_size")) + self.view_variable.VAR_LABEL_CONFIRMATION_MODAL_ACCEPT_BUTTON.set(i18n.t("main_window.confirmation_message.accept_adjust_ui_size")) + + vrct_gui.confirmation_modal.show(hide_title_bar=False, close_when_focusout=False) + + + + def _showUpdateSoftwareConfirmationModal(self): + self.foregroundOffIfForegroundEnabled() + + self.view_variable.VAR_LABEL_MAIN_WINDOW_COVER_MESSAGE.set("") + vrct_gui.main_window_cover.show() + + self.view_variable.CALLBACK_HIDE_CONFIRMATION_MODAL=self._hideConfirmationModal + self.view_variable.CALLBACK_ACCEPTED_CONFIRMATION_MODAL=self._startUpdateSoftware + self.view_variable.CALLBACK_DENIED_CONFIRMATION_MODAL=self._hideConfirmationModal + + self.view_variable.VAR_MESSAGE_CONFIRMATION_MODAL.set(i18n.t("main_window.confirmation_message.update_software")) + self.view_variable.VAR_LABEL_CONFIRMATION_MODAL_DENY_BUTTON.set(i18n.t("main_window.confirmation_message.deny_update_software")) + self.view_variable.VAR_LABEL_CONFIRMATION_MODAL_ACCEPT_BUTTON.set(i18n.t("main_window.confirmation_message.accept_update_software")) + vrct_gui.confirmation_modal.show() + + + + + + def showTheLimitOfTranslationEngineConfirmationModal(self): + self.foregroundOffIfForegroundEnabled() + + self.view_variable.VAR_LABEL_MAIN_WINDOW_COVER_MESSAGE.set("") + vrct_gui.main_window_cover.show() + + self.view_variable.CALLBACK_HIDE_CONFIRMATION_MODAL=self._hideInformationModal + self.view_variable.CALLBACK_ACCEPTED_CONFIRMATION_MODAL=self._hideInformationModal + + self.view_variable.VAR_MESSAGE_CONFIRMATION_MODAL.set(i18n.t("main_window.confirmation_message.translation_engine_limit_error")) + self.view_variable.VAR_LABEL_CONFIRMATION_MODAL_ACCEPT_BUTTON.set(i18n.t("main_window.confirmation_message.accept_translation_engine_limit_error")) + vrct_gui.information_modal.show(hide_title_bar=False, close_when_focusout=False) + + + + +# Hide Modal + def _hideInformationModal(self): + vrct_gui.information_modal.hide() + vrct_gui.main_window_cover.hide() + self.foregroundOnIfForegroundEnabled() + + + def _hideConfirmationModal(self): + vrct_gui.confirmation_modal.hide() + vrct_gui.main_window_cover.hide() + self.foregroundOnIfForegroundEnabled() + + +# Process + def _startUpdateSoftware(self): + self.view_variable.VAR_MESSAGE_CONFIRMATION_MODAL.set(i18n.t("main_window.confirmation_message.updating")) + vrct_gui.confirmation_modal.hide_buttons() + vrct_gui.update() + vrct_gui.confirmation_modal.update() + callFunctionIfCallable(self.view_variable.CALLBACK_UPDATE_SOFTWARE) + + + +# Window Control + def _openConfigWindow(self): + self.view_variable.VAR_LABEL_MAIN_WINDOW_COVER_MESSAGE.set(i18n.t("main_window.cover_message")) + callFunctionIfCallable(self.view_variable.CALLBACK_OPEN_CONFIG_WINDOW) + vrct_gui._openConfigWindow() + + def _closeConfigWindow(self): + callFunctionIfCallable(self.view_variable.CALLBACK_CLOSE_CONFIG_WINDOW) + self._closeMicWordFilterList() + vrct_gui._closeConfigWindow() + +# Window Control (Main Window Cover) + def _openTheCoverOfMainWindow(self): + vrct_gui.main_window_cover.show() + vrct_gui.config_window.lift() + + @staticmethod + def _closeTheCoverOfMainWindow(): + vrct_gui.main_window_cover.withdraw() + +# Window Control (Selectable Languages Window) + def openSelectableLanguagesWindow_YourLanguage(self, _e): + self.view_variable.VAR_TITLE_LABEL_SELECTABLE_LANGUAGE.set(i18n.t("selectable_language_window.title_your_language")) + vrct_gui._openSelectableLanguagesWindow("your_language") + + def openSelectableLanguagesWindow_TargetLanguage(self, _e): + self.view_variable.VAR_TITLE_LABEL_SELECTABLE_LANGUAGE.set(i18n.t("selectable_language_window.title_target_language")) + vrct_gui._openSelectableLanguagesWindow("target_language") + + +# Update GuiVariable (view_variable) + def updateGuiVariableByPresetTabNo(self, tab_no:str): + self.view_variable.VAR_YOUR_LANGUAGE.set(config.SELECTED_TAB_YOUR_LANGUAGES[tab_no]) + self.view_variable.VAR_TARGET_LANGUAGE.set(config.SELECTED_TAB_TARGET_LANGUAGES[tab_no]) + + + def updateList_selectableLanguages(self, new_selectable_language_list:list): + self.view_variable.LIST_SELECTABLE_LANGUAGES = new_selectable_language_list + + # (Config Window Setting Box Tab) + def _updateActiveSettingBoxTabNo(self, active_setting_box_tab_attr_name:str): + self.view_variable.ACTIVE_SETTING_BOX_TAB_ATTR_NAME = active_setting_box_tab_attr_name + + +# Set GuiVariable (view_variable) def setGuiVariable_MicEnergyThreshold(self, value): self.view_variable.VAR_MIC_ENERGY_THRESHOLD__SLIDER.set(int(value)) self.view_variable.VAR_MIC_ENERGY_THRESHOLD__ENTRY.set(str(value)) - def setLatestConfigVariable_MicEnergyThreshold(self, _e=None): - self.setGuiVariable_MicEnergyThreshold(config.INPUT_MIC_ENERGY_THRESHOLD) - self.clearErrorMessage() - def setGuiVariable_SpeakerEnergyThreshold(self, value): self.view_variable.VAR_SPEAKER_ENERGY_THRESHOLD__SLIDER.set(int(value)) self.view_variable.VAR_SPEAKER_ENERGY_THRESHOLD__ENTRY.set(str(value)) - def setLatestConfigVariable_SpeakerEnergyThreshold(self, _e=None): - self.setGuiVariable_SpeakerEnergyThreshold(config.INPUT_SPEAKER_ENERGY_THRESHOLD) - self.clearErrorMessage() - - - def setGuiVariable_MicRecordTimeout(self, value, delete=False): - if delete is True: self._clearEntryBox(vrct_gui.config_window.sb__entry_mic_record_timeout) + def setGuiVariable_MicRecordTimeout(self, value): self.view_variable.VAR_MIC_RECORD_TIMEOUT.set(str(value)) - def setLatestConfigVariable_MicRecordTimeout(self, _e=None): - self.setGuiVariable_MicRecordTimeout(config.INPUT_MIC_RECORD_TIMEOUT) - self.clearErrorMessage() - - def setGuiVariable_MicPhraseTimeout(self, value, delete=False): - if delete is True: self._clearEntryBox(vrct_gui.config_window.sb__entry_mic_phrase_timeout) + def setGuiVariable_MicPhraseTimeout(self, value): self.view_variable.VAR_MIC_PHRASE_TIMEOUT.set(str(value)) - def setLatestConfigVariable_MicPhraseTimeout(self, _e=None): - self.setGuiVariable_MicPhraseTimeout(config.INPUT_MIC_PHRASE_TIMEOUT) - self.clearErrorMessage() - - def setGuiVariable_MicMaxPhrases(self, value, delete=False): - if delete is True: self._clearEntryBox(vrct_gui.config_window.sb__entry_mic_max_phrases) + def setGuiVariable_MicMaxPhrases(self, value): self.view_variable.VAR_MIC_MAX_PHRASES.set(str(value)) - def setLatestConfigVariable_MicMaxPhrases(self, _e=None): - self.setGuiVariable_MicMaxPhrases(config.INPUT_MIC_MAX_PHRASES) - self.clearErrorMessage() + def setGuiVariable_MicWordFilter_Length(self, value): + self.view_variable.VAR_SWITCH_DESC_MIC_WORD_FILTER.set(i18n.t("config_window.mic_word_filter.count_desc", count=value)) - - - def setGuiVariable_SpeakerRecordTimeout(self, value, delete=False): - if delete is True: self._clearEntryBox(vrct_gui.config_window.sb__entry_speaker_record_timeout) + def setGuiVariable_SpeakerRecordTimeout(self, value): self.view_variable.VAR_SPEAKER_RECORD_TIMEOUT.set(str(value)) - def setLatestConfigVariable_SpeakerRecordTimeout(self, _e=None): - self.setGuiVariable_SpeakerRecordTimeout(config.INPUT_SPEAKER_RECORD_TIMEOUT) - self.clearErrorMessage() - - def setGuiVariable_SpeakerPhraseTimeout(self, value, delete=False): - if delete is True: self._clearEntryBox(vrct_gui.config_window.sb__entry_speaker_phrase_timeout) + def setGuiVariable_SpeakerPhraseTimeout(self, value): self.view_variable.VAR_SPEAKER_PHRASE_TIMEOUT.set(str(value)) - def setLatestConfigVariable_SpeakerPhraseTimeout(self, _e=None): - self.setGuiVariable_SpeakerPhraseTimeout(config.INPUT_SPEAKER_PHRASE_TIMEOUT) - self.clearErrorMessage() - - def setGuiVariable_SpeakerMaxPhrases(self, value, delete=False): - if delete is True: self._clearEntryBox(vrct_gui.config_window.sb__entry_speaker_max_phrases) + def setGuiVariable_SpeakerMaxPhrases(self, value): self.view_variable.VAR_SPEAKER_MAX_PHRASES.set(str(value)) - def setLatestConfigVariable_SpeakerMaxPhrases(self, _e=None): - self.setGuiVariable_SpeakerMaxPhrases(config.INPUT_SPEAKER_MAX_PHRASES) - self.clearErrorMessage() + + + + + + def setLatestConfigVariable(self, target_name:str): + match (target_name): + case "MicEnergyThreshold": + self.setGuiVariable_MicEnergyThreshold(config.INPUT_MIC_ENERGY_THRESHOLD) + case "SpeakerEnergyThreshold": + self.setGuiVariable_SpeakerEnergyThreshold(config.INPUT_SPEAKER_ENERGY_THRESHOLD) + case "MicRecordTimeout": + self.setGuiVariable_MicRecordTimeout(config.INPUT_MIC_RECORD_TIMEOUT) + case "MicPhraseTimeout": + self.setGuiVariable_MicPhraseTimeout(config.INPUT_MIC_PHRASE_TIMEOUT) + case "MicMaxPhrases": + self.setGuiVariable_MicMaxPhrases(config.INPUT_MIC_MAX_PHRASES) + case "MicMicWordFilter": + self.setGuiVariable_MicWordFilter_Length(len(config.INPUT_MIC_WORD_FILTER)) + + case "SpeakerRecordTimeout": + self.setGuiVariable_SpeakerRecordTimeout(config.INPUT_SPEAKER_RECORD_TIMEOUT) + case "SpeakerPhraseTimeout": + self.setGuiVariable_SpeakerPhraseTimeout(config.INPUT_SPEAKER_PHRASE_TIMEOUT) + case "SpeakerMaxPhrases": + self.setGuiVariable_SpeakerMaxPhrases(config.INPUT_SPEAKER_MAX_PHRASES) + + case "MessageFormat": + self.setMessageFormatEntryWidgets(config.MESSAGE_FORMAT) + + case _: + raise ValueError(f"No matching case for target_name: {target_name}") + + +# Print To Textbox. + def printToTextbox_enableTranslation(self): + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.enabled_translation")) + def printToTextbox_disableTranslation(self): + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.disabled_translation")) + + def printToTextbox_enableTranscriptionSend(self): + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.enabled_voice2chatbox")) + def printToTextbox_disableTranscriptionSend(self): + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.disabled_voice2chatbox")) + + def printToTextbox_enableTranscriptionReceive(self): + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.enabled_speaker2log")) + def printToTextbox_disableTranscriptionReceive(self): + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.disabled_speaker2log")) + + def printToTextbox_enableForeground(self): + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.enabled_foreground")) + def printToTextbox_disableForeground(self): + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.disabled_foreground")) + + def printToTextbox_AuthenticationSuccess(self): + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.auth_key_success")) + def printToTextbox_AuthenticationError(self): + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.auth_key_error")) + + + def printToTextbox_TranscriptionSendNoDeviceError(self): + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.no_mic_device_detected_error")) + + def printToTextbox_TranscriptionReceiveNoDeviceError(self): + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.no_speaker_device_detected_error")) + + + def printToTextbox_TranslationEngineLimitError(self): + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.translation_engine_limit_error")) + + + # def printToTextbox_OSCError(self): [Deprecated] + # self._printToTextbox_Info("OSC is not enabled, please enable OSC and rejoin. or turn off the \"Send Message To VRChat\" setting") + + def printToTextbox_DetectedByWordFilter(self, detected_message): + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.detected_by_word_filter", detected_message=detected_message)) + + + + def printToTextbox_selectedYourLanguages(self, selected_your_language): + your_language = selected_your_language.replace("\n", " ") + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.selected_your_language", your_language=your_language)) + + def printToTextbox_selectedTargetLanguages(self, selected_target_language): + target_language = selected_target_language.replace("\n", " ") + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.selected_target_language", target_language=target_language)) + + def printToTextbox_changedLanguagePresetTab(self, tab_no:str): + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.switched_language_preset_tab", tab_no=tab_no)) + self.printToTextbox_latestSelectedLanguages() + + def printToTextbox_latestSelectedLanguages(self): + your_language = self.view_variable.VAR_YOUR_LANGUAGE.get().replace("\n", " ") + target_language = self.view_variable.VAR_TARGET_LANGUAGE.get().replace("\n", " ") + self._printToTextbox_Info(i18n.t("main_window.textbox_system_message.latest_language_setting", your_language=your_language, target_language=target_language)) @staticmethod - def _clearEntryBox(entry_widget): - entry_widget.delete(0, CTK_END) + def _printToTextbox_Info(info_message, **kwargs): + vrct_gui._printToTextbox( + target_type="SYSTEM", + original_message=info_message, + **kwargs, + ) + + def printToTextbox_SentMessage(self, original_message, translated_message): + self._printToTextbox_Sent(original_message, translated_message) + + @staticmethod + def _printToTextbox_Sent(original_message, translated_message): + vrct_gui._printToTextbox( + target_type="SENT", + original_message=original_message, + translated_message=translated_message, + ) + + + def printToTextbox_ReceivedMessage(self, original_message, translated_message): + self._printToTextbox_Received(original_message, translated_message) + + @staticmethod + def _printToTextbox_Received(original_message, translated_message): + vrct_gui._printToTextbox( + target_type="RECEIVED", + original_message=original_message, + translated_message=translated_message, + ) + + +# Message Box + @staticmethod + def getTextFromMessageBox(): + return vrct_gui.entry_message_box.get() + + def clearMessageBox(self): + self._clearEntryBox(vrct_gui.entry_message_box) + + + + +# Callback Bind FocusOut + def callbackBindFocusOut_MicEnergyThreshold(self, _e=None): + self.setLatestConfigVariable("MicEnergyThreshold") + self.clearErrorMessage() + + def callbackBindFocusOut_SpeakerEnergyThreshold(self, _e=None): + self.setLatestConfigVariable("SpeakerEnergyThreshold") + self.clearErrorMessage() + + + def callbackBindFocusOut_MicRecordTimeout(self, _e=None): + self.setLatestConfigVariable("MicRecordTimeout") + self.clearErrorMessage() + + def callbackBindFocusOut_MicPhraseTimeout(self, _e=None): + self.setLatestConfigVariable("MicPhraseTimeout") + self.clearErrorMessage() + + def callbackBindFocusOut_MicMaxPhrases(self, _e=None): + self.setLatestConfigVariable("MicMaxPhrases") + self.clearErrorMessage() + + + def callbackBindFocusOut_SpeakerRecordTimeout(self, _e=None): + self.setLatestConfigVariable("SpeakerRecordTimeout") + self.clearErrorMessage() + + def callbackBindFocusOut_SpeakerPhraseTimeout(self, _e=None): + self.setLatestConfigVariable("SpeakerPhraseTimeout") + self.clearErrorMessage() + + def callbackBindFocusOut_SpeakerMaxPhrases(self, _e=None): + self.setLatestConfigVariable("SpeakerMaxPhrases") + self.clearErrorMessage() + + + def callbackBindFocusOut_MessageFormat(self, _e=None): + self.setLatestConfigVariable("MessageFormat") + self.clearErrorMessage() + + + + +# Show Error Message (Config Window) def showErrorMessage_MicEnergyThreshold(self): self._showErrorMessage( vrct_gui.config_window.sb__progressbar_x_slider__entry_mic_energy_threshold, @@ -1162,27 +1358,77 @@ class View(): self._makeInvalidValueErrorMessage(i18n.t("config_window.speaker_dynamic_energy_threshold.no_device_error_message")) ) - def _showErrorMessage(self, target_widget, message): - self.view_variable.VAR_ERROR_MESSAGE.set(message) - vrct_gui._showErrorMessage(target_widget=target_widget) + + def showErrorMessage_MessageFormat(self): + self._showErrorMessage( + vrct_gui.config_window.sb__entry_message_format_2, + self._makeInvalidValueErrorMessage(i18n.t("config_window.message_format.error_message")) + ) @staticmethod def _makeInvalidValueErrorMessage(error_message): return i18n.t("config_window.common_error_message.invalid_value") + "\n" + error_message - def clearErrorMessage(self): - vrct_gui._clearErrorMessage() - - + def _showErrorMessage(self, target_widget, message): + self.view_variable.VAR_ERROR_MESSAGE.set(message) + vrct_gui._showErrorMessage(target_widget=target_widget) @staticmethod - def showSplash(): - vrct_gui.showSplash() + def extractMessageFormat(text): + import re + message_index = text.find("[message]") + translation_index = text.find("[translation]") + + result_data = SimpleNamespace( + is_message_first = True, + before = "", + between = "", + after = "", + ) + + if message_index < translation_index: + text_before_message = text[:message_index] + result_data.before = text_before_message + + match = re.search(r"\[message\](.*?)\[translation\]", text) + if match: + extracted_text = match.group(1) + result_data.between = extracted_text + + else: + raise ValueError("Invalid Message Format") + + text_after_translation = text[translation_index + len("[translation]"):] + result_data.after = text_after_translation + + + + + elif translation_index < message_index: + result_data.is_message_first = False + text_before_translation = text[:translation_index] + result_data.before = text_before_translation + + match = re.search(r"\[translation\](.*?)\[message\]", text) + if match: + extracted_text = match.group(1) + result_data.between = extracted_text + else: + raise ValueError("Invalid Message Format") + + text_after_message = text[message_index + len("[message]"):] + result_data.after = text_after_message + + else: + raise ValueError("Invalid Message Format") + + return result_data + + + + - @staticmethod - def destroySplash(): - vrct_gui.destroySplash() # These conversations are generated by ChatGPT def _insertSampleConversationToTextbox(self): diff --git a/vrct_gui/_CreateConfirmationModal.py b/vrct_gui/_CreateConfirmationModal.py index 1d7a5de4..935f0447 100644 --- a/vrct_gui/_CreateConfirmationModal.py +++ b/vrct_gui/_CreateConfirmationModal.py @@ -233,7 +233,8 @@ class _CreateConfirmationModal(CTkToplevel): self.grab_release() def focusOutFunction(self, e): - if str(e.widget) != ".!_createconfirmationmodal": return + if str(e.widget) != ".!_createconfirmationmodal": + return callFunctionIfCallable(self._view_variable.CALLBACK_HIDE_CONFIRMATION_MODAL) def _grab_set(self): diff --git a/vrct_gui/_CreateDropdownMenuWindow.py b/vrct_gui/_CreateDropdownMenuWindow.py index 948e00e1..b0f459dd 100644 --- a/vrct_gui/_CreateDropdownMenuWindow.py +++ b/vrct_gui/_CreateDropdownMenuWindow.py @@ -262,7 +262,8 @@ class _CreateDropdownMenuWindow(CTkToplevel): def show(self, dropdown_menu_widget_id): - if self.hide is False: return + if self.hide is False: + return self.wm_attributes("-alpha", 0) diff --git a/vrct_gui/_CreateErrorWindow.py b/vrct_gui/_CreateErrorWindow.py index 4b00047a..ef7ff5fb 100644 --- a/vrct_gui/_CreateErrorWindow.py +++ b/vrct_gui/_CreateErrorWindow.py @@ -80,7 +80,8 @@ class _CreateErrorWindow(CTkToplevel): def show(self, target_widget): - if self.hide is False: return + if self.hide is False: + return self.attach_widget = target_widget diff --git a/vrct_gui/_CreateSelectableLanguagesWindow.py b/vrct_gui/_CreateSelectableLanguagesWindow.py index daa369c0..8c666a20 100644 --- a/vrct_gui/_CreateSelectableLanguagesWindow.py +++ b/vrct_gui/_CreateSelectableLanguagesWindow.py @@ -178,5 +178,6 @@ class _CreateSelectableLanguagesWindow(CTkToplevel): def focusOutFunction(self, e): - if str(e.widget) != ".!_createselectablelanguageswindow": return + if str(e.widget) != ".!_createselectablelanguageswindow": + return self.vrct_gui._closeSelectableLanguagesWindow() \ No newline at end of file diff --git a/vrct_gui/_CreateWindowCover.py b/vrct_gui/_CreateWindowCover.py index 0ee3b606..600619be 100644 --- a/vrct_gui/_CreateWindowCover.py +++ b/vrct_gui/_CreateWindowCover.py @@ -18,13 +18,13 @@ class _CreateWindowCover(CTkToplevel): self.title("") self.overrideredirect(True) self.wm_attributes("-toolwindow", True) - self.configure(fg_color="black") + self.configure(fg_color=self.settings.ctm.BG_COLOR) self.protocol("WM_DELETE_WINDOW", lambda: self.withdraw()) self.grid_rowconfigure(0,weight=1) self.grid_columnconfigure(0,weight=1) - self.cover_container = CTkFrame(self, corner_radius=0, fg_color="black", width=0, height=0) + self.cover_container = CTkFrame(self, corner_radius=0, fg_color=self.settings.ctm.BG_COLOR, width=0, height=0) self.cover_container.grid(row=0, column=0, sticky="nsew") diff --git a/vrct_gui/_PrintToTextbox.py b/vrct_gui/_PrintToTextbox.py new file mode 100644 index 00000000..6d68cfdc --- /dev/null +++ b/vrct_gui/_PrintToTextbox.py @@ -0,0 +1,168 @@ +from datetime import datetime +from customtkinter import CTkFont +from .ui_utils import calculateUiSize + +class _PrintToTextbox(): + def __init__( + self, + vrct_gui, + settings, + init_scaling:float, + ): + + self.vrct_gui = vrct_gui + self.settings = settings + self.init_scaling = init_scaling + + self._DEFAULT_TEXTBOX_FIRST_INSERT_SPACING = self.settings.uism.TEXTBOX_FIRST_INSERT_SPACING + self._DEFAULT_TEXTBOX_FONT_SIZE__LABEL = self.settings.uism.TEXTBOX_FONT_SIZE__LABEL + self._DEFAULT_TEXTBOX_FONT_SIZE__TIMESTAMP = self.settings.uism.TEXTBOX_FONT_SIZE__TIMESTAMP + self._DEFAULT_TEXTBOX_FONT_SIZE__SYSTEM_TEXT_FONT = self.settings.uism.TEXTBOX_FONT_SIZE__SYSTEM_TEXT_FONT + self._DEFAULT_TEXTBOX_FONT_SIZE__SECONDARY_TEXT_FONT = self.settings.uism.TEXTBOX_FONT_SIZE__SECONDARY_TEXT_FONT + self._DEFAULT_TEXTBOX_FONT_SIZE__MAIN_TEXT_FONT = self.settings.uism.TEXTBOX_FONT_SIZE__MAIN_TEXT_FONT + + + + self.textbox_first_insert_spacing = None + self.textbox_font_size__label = None + self.textbox_font_size__timestamp = None + self.textbox_font_size__system_text_font = None + self.textbox_font_size__secondary_text_font = None + self.textbox_font_size__main_text_font = None + + + self.all_textbox_widgets = [self.vrct_gui.textbox_all, self.vrct_gui.textbox_system, self.vrct_gui.textbox_sent, self.vrct_gui.textbox_received] + + + self.setTagsSettings(self.init_scaling) + + + def printToTextbox(self, target_type, original_message=None, translated_message=None, to_print_to_textbox_all:bool=True): + self._printEachTextbox( + target_textbox=self._getTargetTextboxWidget(target_type), + print_type=target_type, + original_message=original_message, + translated_message=translated_message, + ) + + # To automatically print the same log to the textbox_all widget as well. + if to_print_to_textbox_all is True: + self._printEachTextbox( + target_textbox=self._getTargetTextboxWidget("ALL"), + print_type=target_type, + original_message=original_message, + translated_message=translated_message, + ) + + def setTagsSettings(self, custom_font_size_scale:float=1.0): + # Calculate Textbox's ui size by default size * textbox_ui_scale + self.textbox_first_insert_spacing = calculateUiSize(self._DEFAULT_TEXTBOX_FIRST_INSERT_SPACING, custom_font_size_scale) + self.textbox_font_size__label = calculateUiSize(self._DEFAULT_TEXTBOX_FONT_SIZE__LABEL, custom_font_size_scale) + self.textbox_font_size__timestamp = calculateUiSize(self._DEFAULT_TEXTBOX_FONT_SIZE__TIMESTAMP, custom_font_size_scale) + self.textbox_font_size__system_text_font = calculateUiSize(self._DEFAULT_TEXTBOX_FONT_SIZE__SYSTEM_TEXT_FONT, custom_font_size_scale) + self.textbox_font_size__secondary_text_font = calculateUiSize(self._DEFAULT_TEXTBOX_FONT_SIZE__SECONDARY_TEXT_FONT, custom_font_size_scale) + self.textbox_font_size__main_text_font = calculateUiSize(self._DEFAULT_TEXTBOX_FONT_SIZE__MAIN_TEXT_FONT, custom_font_size_scale) + + for each_textbox_widget in self.all_textbox_widgets: + self._setTagsSettings(target_textbox=each_textbox_widget) + each_textbox_widget.see("end") + + + + def _setTagsSettings(self, target_textbox): + target_textbox.tag_config("JUSTIFY_CENTER", justify="center") + target_textbox.tag_config("JUSTIFY_RIGHT", justify="right") + target_textbox.tag_config("JUSTIFY_LEFT", justify="left") + + # common tag settings + # target_textbox._textbox.tag_configure("START", spacing1=16) + target_textbox.tag_config("FIRST_INSERT_SPACING", spacing1=self.textbox_first_insert_spacing) + target_textbox._textbox.tag_configure("LABEL", font=CTkFont(family=self.settings.FONT_FAMILY, size=self.textbox_font_size__label, weight="normal")) + target_textbox._textbox.tag_configure("TIMESTAMP", font=CTkFont(family=self.settings.FONT_FAMILY, size=self.textbox_font_size__timestamp, weight="normal"), foreground=self.settings.ctm.TEXTBOX_TIMESTAMP_TEXT_COLOR) + target_textbox._textbox.tag_configure("SECONDARY_TEXT_FONT", font=CTkFont(family=self.settings.FONT_FAMILY, size=self.textbox_font_size__secondary_text_font, weight="normal")) + target_textbox._textbox.tag_configure("MAIN_TEXT_FONT", font=CTkFont(family=self.settings.FONT_FAMILY, size=self.textbox_font_size__main_text_font, weight="normal")) + + # System Tag Settings + target_textbox.tag_config("SYSTEM_TAG", foreground=self.settings.ctm.TEXTBOX_SYSTEM_TAG_TEXT_COLOR) + target_textbox.tag_config("SYSTEM_TEXT", foreground=self.settings.ctm.TEXTBOX_TEXT_SUB_COLOR) + target_textbox._textbox.tag_configure("SYSTEM_TEXT_FONT", font=CTkFont(family=self.settings.FONT_FAMILY, size=self.textbox_font_size__system_text_font, weight="normal")) + + # Sent Tag Settings + target_textbox.tag_config("SENT_TAG", foreground=self.settings.ctm.TEXTBOX_SENT_TAG_TEXT_COLOR) + target_textbox.tag_config("SENT_TEXT", foreground=self.settings.ctm.TEXTBOX_TEXT_COLOR) + target_textbox.tag_config("SENT_SUB_TEXT", foreground=self.settings.ctm.TEXTBOX_TEXT_SUB_COLOR) + + # Received Tag Settings + target_textbox.tag_config("RECEIVED_TAG", foreground=self.settings.ctm.TEXTBOX_RECEIVED_TAG_TEXT_COLOR) + target_textbox.tag_config("RECEIVED_TEXT", foreground=self.settings.ctm.TEXTBOX_TEXT_COLOR) + target_textbox.tag_config("RECEIVED_SUB_TEXT", foreground=self.settings.ctm.TEXTBOX_TEXT_SUB_COLOR) + + + def _printEachTextbox( + self, + target_textbox, + print_type, + original_message, + translated_message, + ): + now_raw_data = datetime.now() + now_hm = now_raw_data.strftime("%H:%M") + + is_only_one_message = True if original_message is None or translated_message is None or translated_message == "" else False + + FAKE_MARGIN = " " + # insert + target_textbox.configure(state="normal") + target_textbox.insert("end", "\n") + match (print_type): + case "SYSTEM": + target_textbox.insert("end", "System", ("SYSTEM_TAG", "FIRST_INSERT_SPACING", "JUSTIFY_CENTER", "LABEL")) + target_textbox.insert("end", FAKE_MARGIN+original_message+FAKE_MARGIN, ("SYSTEM_TEXT", "SYSTEM_TEXT_FONT", "JUSTIFY_CENTER")) + target_textbox.insert("end", now_hm, ("TIMESTAMP", "JUSTIFY_CENTER")) + + case "SENT": + target_textbox.insert("end", now_hm, ("TIMESTAMP", "FIRST_INSERT_SPACING", "JUSTIFY_RIGHT")) + target_textbox.insert("end", FAKE_MARGIN+"Sent", ("SENT_TAG", "LABEL")) + target_textbox.insert("end", "\n") + if is_only_one_message is False: + target_textbox.insert("end", original_message, ("SENT_SUB_TEXT", "SECONDARY_TEXT_FONT", "JUSTIFY_RIGHT")) + target_textbox.insert("end", "\n") + target_textbox.insert("end", translated_message, ("SENT_TEXT", "MAIN_TEXT_FONT", "JUSTIFY_RIGHT")) + else: + target_textbox.insert("end", original_message, ("SENT_TEXT", "MAIN_TEXT_FONT", "JUSTIFY_RIGHT")) + + case "RECEIVED": + target_textbox.insert("end", "Received", ("RECEIVED_TAG", "FIRST_INSERT_SPACING", "JUSTIFY_LEFT", "LABEL")) + target_textbox.insert("end", FAKE_MARGIN+now_hm, ("TIMESTAMP")) + if is_only_one_message is False: + target_textbox.insert("end", "\n") + target_textbox.insert("end", original_message, ("RECEIVED_SUB_TEXT", "SECONDARY_TEXT_FONT")) + target_textbox.insert("end", "\n") + target_textbox.insert("end", translated_message, ("RECEIVED_TEXT", "MAIN_TEXT_FONT", "JUSTIFY_LEFT")) + else: + target_textbox.insert("end", "\n") + target_textbox.insert("end", original_message, ("RECEIVED_TEXT", "MAIN_TEXT_FONT", "JUSTIFY_LEFT")) + + target_textbox.configure(state="disabled") + target_textbox.see("end") + + + + + + + + def _getTargetTextboxWidget(self, target_type): + match (target_type): + case "ALL": + target_textbox = self.vrct_gui.textbox_all + case "SYSTEM": + target_textbox = self.vrct_gui.textbox_system + case "SENT": + target_textbox = self.vrct_gui.textbox_sent + case "RECEIVED": + target_textbox = self.vrct_gui.textbox_received + case (_): + raise ValueError(f"No matching case for target_type: {target_type}") + + return target_textbox \ No newline at end of file diff --git a/vrct_gui/_printToTextbox.py b/vrct_gui/_printToTextbox.py deleted file mode 100644 index 943b047d..00000000 --- a/vrct_gui/_printToTextbox.py +++ /dev/null @@ -1,98 +0,0 @@ -from datetime import datetime -from customtkinter import CTkFont - -def _printToTextbox(vrct_gui, - settings, - target_type, - original_message=None, - translated_message=None, - tags=None, - disable_print_to_textbox_all:bool=False, - ): - - now_raw_data = datetime.now() - # now = now_raw_data.strftime("%H:%M:%S") - now_hm = now_raw_data.strftime("%H:%M") - # set target textbox widget - - is_only_one_message = True if original_message is None or translated_message is None or translated_message == "" else False - - match (target_type): - case "SYSTEM": - target_textbox = vrct_gui.textbox_system - case "SENT": - target_textbox = vrct_gui.textbox_sent - case "RECEIVED": - target_textbox = vrct_gui.textbox_received - case (_): - raise ValueError(f"No matching case for target_type: {target_type}") - - - def printEachTextbox(target_textbox): - target_textbox.tag_config("JUSTIFY_CENTER", justify="center") - target_textbox.tag_config("JUSTIFY_RIGHT", justify="right") - target_textbox.tag_config("JUSTIFY_LEFT", justify="left") - - # common tag settings - # target_textbox._textbox.tag_configure("START", spacing1=16) - target_textbox._textbox.tag_configure("LABEL", font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.TEXTBOX_FONT_SIZE__LABEL, weight="normal")) - target_textbox._textbox.tag_configure("TIMESTAMP", font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.TEXTBOX_FONT_SIZE__TIMESTAMP, weight="normal"), foreground=settings.ctm.TEXTBOX_TIMESTAMP_TEXT_COLOR) - target_textbox._textbox.tag_configure("SECONDARY_TEXT_FONT", font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.TEXTBOX_FONT_SIZE__SECONDARY_TEXT_FONT, weight="normal")) - target_textbox._textbox.tag_configure("MAIN_TEXT_FONT", font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.TEXTBOX_FONT_SIZE__MAIN_TEXT_FONT, weight="normal")) - - # System Tag Settings - target_textbox.tag_config("FIRST_INSERT_SPACING", spacing1=settings.uism.TEXTBOX_FIRST_INSERT_SPACING) - target_textbox.tag_config("SYSTEM_TAG", foreground=settings.ctm.TEXTBOX_SYSTEM_TAG_TEXT_COLOR) - target_textbox.tag_config("SYSTEM_TEXT", foreground=settings.ctm.TEXTBOX_TEXT_SUB_COLOR) - target_textbox._textbox.tag_configure("SYSTEM_TEXT_FONT", font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.TEXTBOX_FONT_SIZE__SYSTEM_TEXT_FONT, weight="normal")) - - # Sent Tag Settings - target_textbox.tag_config("SENT_TAG", foreground=settings.ctm.TEXTBOX_SENT_TAG_TEXT_COLOR) - target_textbox.tag_config("SENT_TEXT", foreground=settings.ctm.TEXTBOX_TEXT_COLOR) - target_textbox.tag_config("SENT_SUB_TEXT", foreground=settings.ctm.TEXTBOX_TEXT_SUB_COLOR) - - # Received Tag Settings - target_textbox.tag_config("RECEIVED_TAG", foreground=settings.ctm.TEXTBOX_RECEIVED_TAG_TEXT_COLOR) - target_textbox.tag_config("RECEIVED_TEXT", foreground=settings.ctm.TEXTBOX_TEXT_COLOR) - target_textbox.tag_config("RECEIVED_SUB_TEXT", foreground=settings.ctm.TEXTBOX_TEXT_SUB_COLOR) - - FAKE_MARGIN = " " - # insert - target_textbox.configure(state="normal") - target_textbox.insert("end", "\n") - match (target_type): - case "SYSTEM": - target_textbox.insert("end", "System", ("SYSTEM_TAG", "FIRST_INSERT_SPACING", "JUSTIFY_CENTER", "LABEL")) - target_textbox.insert("end", FAKE_MARGIN+original_message+FAKE_MARGIN, ("SYSTEM_TEXT", "SYSTEM_TEXT_FONT", "JUSTIFY_CENTER")) - target_textbox.insert("end", now_hm, ("TIMESTAMP", "JUSTIFY_CENTER")) - - case "SENT": - target_textbox.insert("end", now_hm, ("TIMESTAMP", "FIRST_INSERT_SPACING", "JUSTIFY_RIGHT")) - target_textbox.insert("end", FAKE_MARGIN+"Sent", ("SENT_TAG", "LABEL")) - target_textbox.insert("end", "\n") - if is_only_one_message is False: - target_textbox.insert("end", original_message, ("SENT_SUB_TEXT", "SECONDARY_TEXT_FONT", "JUSTIFY_RIGHT")) - target_textbox.insert("end", "\n") - target_textbox.insert("end", translated_message, ("SENT_TEXT", "MAIN_TEXT_FONT", "JUSTIFY_RIGHT")) - else: - target_textbox.insert("end", original_message, ("SENT_TEXT", "MAIN_TEXT_FONT", "JUSTIFY_RIGHT")) - - case "RECEIVED": - target_textbox.insert("end", "Received", ("RECEIVED_TAG", "FIRST_INSERT_SPACING", "JUSTIFY_LEFT", "LABEL")) - target_textbox.insert("end", FAKE_MARGIN+now_hm, ("TIMESTAMP")) - if is_only_one_message is False: - target_textbox.insert("end", "\n") - target_textbox.insert("end", original_message, ("RECEIVED_SUB_TEXT", "SECONDARY_TEXT_FONT")) - target_textbox.insert("end", "\n") - target_textbox.insert("end", translated_message, ("RECEIVED_TEXT", "MAIN_TEXT_FONT", "JUSTIFY_LEFT")) - else: - target_textbox.insert("end", "\n") - target_textbox.insert("end", original_message, ("RECEIVED_TEXT", "MAIN_TEXT_FONT", "JUSTIFY_LEFT")) - - target_textbox.configure(state="disabled") - target_textbox.see("end") - - printEachTextbox(target_textbox) - - # To automatically print the same log to the textbox_all widget as well. - if disable_print_to_textbox_all is not True: printEachTextbox(vrct_gui.textbox_all) \ No newline at end of file diff --git a/vrct_gui/config_window/widgets/createSettingBoxTopBar/_createSettingBoxTitle.py b/vrct_gui/config_window/widgets/createSettingBoxTopBar/_createSettingBoxTitle.py index 7c0ec386..199a12fb 100644 --- a/vrct_gui/config_window/widgets/createSettingBoxTopBar/_createSettingBoxTitle.py +++ b/vrct_gui/config_window/widgets/createSettingBoxTopBar/_createSettingBoxTitle.py @@ -16,9 +16,4 @@ def _createSettingBoxTitle(parent_widget, config_window, settings, view_variable 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) - - - # for fixing 1px bug - sls__box_optionmenu_wrapper_fix_1px_bug = CTkFrame(config_window.main_current_active_config_title, corner_radius=0, width=0, height=0) - sls__box_optionmenu_wrapper_fix_1px_bug.grid(row=0, column=column_num, sticky="ns") \ No newline at end of file + config_window.main_current_active_config_title.grid(row=0, column=0, padx=0, pady=settings.uism.TOP_BAR__IPADY) \ No newline at end of file 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 index f11c56b5..d8b31a39 100644 --- a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/_SettingBoxGenerator.py +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/_SettingBoxGenerator.py @@ -2,10 +2,12 @@ from functools import partial from types import SimpleNamespace from typing import Union -from customtkinter import CTkOptionMenu, CTkFont, CTkFrame, CTkLabel, CTkRadioButton, CTkEntry, CTkSlider, CTkSwitch, CTkCheckBox, CTkProgressBar +from customtkinter import CTkFont, CTkFrame, CTkLabel, CTkEntry, CTkSlider, CTkSwitch, CTkCheckBox, CTkProgressBar, CTkImage +from CTkToolTip import * -from vrct_gui.ui_utils import createButtonWithImage, getLatestWidth, createOptionMenuBox +from vrct_gui.ui_utils import createButtonWithImage, getLatestWidth, createOptionMenuBox, getLatestHeight, bindButtonFunctionAndColor from vrct_gui import vrct_gui +from utils import isEven, callFunctionIfCallable SETTING_BOX_COLUMN = 1 @@ -16,9 +18,11 @@ class _SettingBoxGenerator(): self.parent_widget = parent_widget self.settings = settings + self.MAIN_INNER_AREA_MIN_WIDTH = int(self.settings.uism.MAIN_AREA_MIN_WIDTH - self.settings.uism.SB__IPADX) + self.dropdown_menu_window = vrct_gui.vrct_gui.dropdown_menu_window - def _createSettingBoxFrame(self, sb__attr_name, for_var_label_text=None, for_var_desc_text=None): + def _createSettingBoxFrame(self, sb__attr_name, for_var_label_text=None, for_var_desc_text=None, expand_label_frame:bool=False): self.config_window.sb__widgets[sb__attr_name] = SimpleNamespace() setting_box_frame = CTkFrame(self.parent_widget, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) @@ -30,8 +34,7 @@ class _SettingBoxGenerator(): setting_box_frame_wrapper = CTkFrame(setting_box_frame, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) setting_box_frame_wrapper.grid(row=0, column=0, padx=self.settings.uism.SB__IPADX, pady=self.settings.uism.SB__IPADY, sticky="ew") - setting_box_frame_wrapper.grid_columnconfigure(0, weight=0, minsize=int(self.settings.uism.MAIN_AREA_MIN_WIDTH / 2)) - setting_box_frame_wrapper.grid_columnconfigure(2, weight=1, minsize=int(self.settings.uism.MAIN_AREA_MIN_WIDTH / 2)) + setting_box_frame_wrapper_fix_border = CTkFrame(setting_box_frame, corner_radius=0, width=0, height=0) setting_box_frame_wrapper_fix_border.grid(row=1, column=0, sticky="ew") @@ -39,10 +42,22 @@ class _SettingBoxGenerator(): setting_box_frame_wrapper_fix_border2 = CTkFrame(setting_box_frame, corner_radius=0, width=0, height=0) setting_box_frame_wrapper_fix_border2.grid(row=0, column=1, sticky="ns") - if for_var_label_text is not None: - self._setSettingBoxLabels(sb__attr_name, setting_box_frame_wrapper, for_var_label_text, for_var_desc_text) - # setting_box_item_frame = CTkFrame(setting_box_frame_wrapper, corner_radius=0, width=0, height=0, fg_color="red") + + if for_var_label_text is not None: + self._setSettingBoxLabels(sb__attr_name, setting_box_frame_wrapper, for_var_label_text, for_var_desc_text, expand_label_frame) + if expand_label_frame is True: + setting_box_frame_wrapper.grid_columnconfigure(0, weight=1, minsize=int(self.settings.uism.MAIN_AREA_MIN_WIDTH)) + setting_box_frame_wrapper.grid(columnspan=3) + return setting_box_frame + + + setting_box_frame_wrapper.grid_columnconfigure(0, weight=0, minsize=int(self.settings.uism.MAIN_AREA_MIN_WIDTH / 2)) + setting_box_frame_wrapper.grid_columnconfigure(2, weight=1, minsize=int(self.settings.uism.MAIN_AREA_MIN_WIDTH / 2)) + + + + setting_box_item_frame = CTkFrame(setting_box_frame_wrapper, corner_radius=0, width=0, height=0, fg_color=self.settings.ctm.SB__BG_COLOR) if for_var_label_text is not None: setting_box_item_frame.grid(row=0, column=2, padx=0, sticky="nsew") @@ -53,7 +68,7 @@ class _SettingBoxGenerator(): return (setting_box_frame, setting_box_item_frame) - def _setSettingBoxLabels(self, sb__attr_name, setting_box_frame_wrapper, for_var_label_text, for_var_desc_text=None): + def _setSettingBoxLabels(self, sb__attr_name, setting_box_frame_wrapper, for_var_label_text, for_var_desc_text=None, expand_label_frame:bool=False): setting_box_labels_frame = CTkFrame(setting_box_frame_wrapper, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) setting_box_labels_frame.grid(row=0, column=0, padx=0, pady=0, sticky="nsew") @@ -82,6 +97,9 @@ class _SettingBoxGenerator(): font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__DESC_FONT_SIZE, weight="normal"), text_color=self.settings.ctm.LABELS_DESC_TEXT_COLOR ) + if expand_label_frame is True: + setting_box_desc.configure(wraplength=self.settings.uism.MAIN_AREA_MIN_WIDTH) + setting_box_desc.grid(row=2, column=0, padx=0, pady=(self.settings.uism.SB__DESC_TOP_PADY,0), sticky="ew") self.config_window.additional_widgets.append(setting_box_desc) self.config_window.sb__widgets[sb__attr_name].desc_widget=setting_box_desc @@ -89,6 +107,16 @@ class _SettingBoxGenerator(): self.config_window.sb__widgets[sb__attr_name].desc_widget=None + def createSettingBox_Labels( + self, + for_var_label_text, for_var_desc_text, + labels_attr_name, + ): + + setting_box_frame= self._createSettingBoxFrame(labels_attr_name, for_var_label_text, for_var_desc_text, expand_label_frame=True) + + return setting_box_frame + def createSettingBoxDropdownMenu( @@ -226,6 +254,67 @@ class _SettingBoxGenerator(): + def createSettingBoxAutoExportMessageLogs( + self, + for_var_label_text, for_var_desc_text, + checkbox_attr_name, + checkbox_command, + button_command, + variable, + ): + + (setting_box_frame, setting_box_item_frame) = self._createSettingBoxFrame(checkbox_attr_name, for_var_label_text, for_var_desc_text) + + + + all_wrapper = CTkFrame(setting_box_item_frame, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + all_wrapper.grid(row=1, column=0, sticky="ew") + + all_wrapper.grid_columnconfigure(1, weight=1) + + + + + button_widget = createButtonWithImage( + parent_widget=all_wrapper, + button_fg_color=self.settings.ctm.SB__BUTTON_COLOR, + button_enter_color=self.settings.ctm.SB__BUTTON_HOVERED_COLOR, + button_clicked_color=self.settings.ctm.SB__BUTTON_CLICKED_COLOR, + button_image_file=self.settings.image_file.FOLDER_OPEN_ICON, + button_image_size=self.settings.uism.SB__BUTTON_ICON_SIZE, + button_ipadxy=self.settings.uism.SB__BUTTON_IPADXY, + button_command=button_command, + ) + button_widget.grid(row=0, column=0, padx=0, sticky="w") + + + + checkbox_widget = CTkCheckBox( + all_wrapper, + text=None, + width=0, + checkbox_width=self.settings.uism.SB__CHECKBOX_SIZE, + checkbox_height=self.settings.uism.SB__CHECKBOX_SIZE, + onvalue=True, + offvalue=False, + variable=variable, + command=checkbox_command, + corner_radius=self.settings.uism.SB__CHECKBOX_CORNER_RADIUS, + border_width=self.settings.uism.SB__CHECKBOX_BORDER_WIDTH, + border_color=self.settings.ctm.SB__CHECKBOX_BORDER_COLOR, + hover_color=self.settings.ctm.SB__CHECKBOX_HOVER_COLOR, + checkmark_color=self.settings.ctm.SB__CHECKBOX_CHECKMARK_COLOR, + fg_color=self.settings.ctm.SB__CHECKBOX_CHECKED_COLOR, + ) + setattr(self.config_window, checkbox_attr_name, checkbox_widget) + + checkbox_widget.grid(row=0, column=2, sticky="e") + + return setting_box_frame + + + + def createSettingBoxSlider( @@ -238,11 +327,14 @@ class _SettingBoxGenerator(): slider_number_of_steps: Union[int, None] = None, slider_bind__ButtonPress=None, - slider_bind__ButtonRelease=None + slider_bind__ButtonRelease=None, + sliderTooltipFormatter=None, ): (setting_box_frame, setting_box_item_frame) = self._createSettingBoxFrame(slider_attr_name, for_var_label_text, for_var_desc_text) + if slider_number_of_steps is None: + slider_number_of_steps = int(slider_range[1] - slider_range[0]) slider_widget = CTkSlider( setting_box_item_frame, @@ -260,11 +352,27 @@ class _SettingBoxGenerator(): ) setattr(self.config_window, slider_attr_name, slider_widget) + def getSliderValueWAfterFormatting(): + return sliderTooltipFormatter(variable.get()) if sliderTooltipFormatter else variable.get() + + + + slider_tooltip = CTkToolTip( + slider_widget, + message=getSliderValueWAfterFormatting(), + delay=0, + bg_color=self.settings.ctm.SB__SLIDER_TOOLTIP_BG_COLOR, + corner_radius=0, + text_color=self.settings.ctm.SB__SLIDER_TOOLTIP_TEXT_COLOR, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__SLIDER_TOOLTIP_FONT_SIZE, weight="normal"), + ) + slider_widget.grid(row=1, column=SETTING_BOX_COLUMN, sticky="e") if slider_bind__ButtonPress is not None: def adjusted_slider_bind__ButtonPress(_e): command(_e) + slider_tooltip.configure(message=getSliderValueWAfterFormatting()) slider_bind__ButtonPress() slider_widget.configure(command=adjusted_slider_bind__ButtonPress) @@ -430,6 +538,547 @@ class _SettingBoxGenerator(): + + + def createSettingBoxMessageFormatEntries(self, + base_entry_attr_name, + entry_textvariable_0, + entry_textvariable_1, + entry_textvariable_2, + textvariable_0, + textvariable_1, + entry_bind__Any_KeyRelease, + entry_bind__FocusOut=None, + ): + + (setting_box_frame, setting_box_item_frame) = self._createSettingBoxFrame(base_entry_attr_name) + + + all_wrapper = CTkFrame(setting_box_item_frame, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + all_wrapper.grid(row=1, column=0, sticky="ew") + + all_wrapper.grid_columnconfigure(0, weight=1) + + + example_box_wrapper = CTkFrame(all_wrapper, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + example_box_wrapper.grid(row=0, column=0, pady=self.settings.uism.SB__MESSAGE_FORMAT__ENTRIES_BOTTOM_PADY, sticky="ew") + + entries_wrapper = CTkFrame(all_wrapper, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + entries_wrapper.grid(row=1, column=0, pady=self.settings.uism.SB__MESSAGE_FORMAT__ENTRIES_BOTTOM_PADY, sticky="ew") + + swap_button_wrapper = CTkFrame(all_wrapper, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + swap_button_wrapper.grid(row=2, column=0, sticky="e") + + + + + + example_box_wrapper.grid_columnconfigure((0,2), weight=1) + example_frame_widget = CTkFrame(example_box_wrapper, corner_radius=self.settings.uism.SB__MESSAGE_FORMAT__EXAMPLE_CORNER_RADIUS, fg_color=self.settings.ctm.SB__MESSAGE_FORMAT__EXAMPLE_BG_COLOR, width=0, height=0) + example_frame_widget.grid(row=0, column=1) + + example_frame_widget.grid_rowconfigure((0,2), weight=1) + example_frame_widget.grid_columnconfigure((0,2), weight=1) + example_label_widget = CTkLabel( + example_frame_widget, + textvariable=self.view_variable.VAR_LABEL_EXAMPLE_TEXT_MESSAGE_FORMAT, + anchor="center", + justify="center", + wraplength=self.settings.uism.SB__MESSAGE_FORMAT__EXAMPLE_WRAP_LENGTH, + height=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__MESSAGE_FORMAT__REQUIRED_TEXT_FONT_SIZE, weight="normal"), + text_color=self.settings.ctm.SB__MESSAGE_FORMAT__EXAMPLE_TEXT_COLOR, + ) + example_label_widget.grid(row=1, column=1, padx=self.settings.uism.SB__MESSAGE_FORMAT__EXAMPLE_IPADXY, pady=self.settings.uism.SB__MESSAGE_FORMAT__EXAMPLE_IPADXY, sticky="ew") + + self.config_window.additional_widgets.append(example_box_wrapper) + + + + + entry_textvariables = [entry_textvariable_0, entry_textvariable_1, entry_textvariable_2] + for i in range(3): + entry_widget = CTkEntry( + entries_wrapper, + text_color=self.settings.ctm.SB__ENTRY_TEXT_COLOR, + fg_color=self.settings.ctm.SB__ENTRY_BG_COLOR, + border_color=self.settings.ctm.SB__ENTRY_BORDER_COLOR, + height=self.settings.uism.SB__MESSAGE_FORMAT__ENTRY_HEIGHT, + textvariable=entry_textvariables[i], + justify="center", + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__ENTRY_FONT_SIZE, weight="normal"), + ) + setattr(self.config_window, base_entry_attr_name + "_" + str(i), entry_widget) + + + + if entry_bind__FocusOut is not None: + entry_widget.bind("", entry_bind__FocusOut, "+") + + + label_frame_widget_0 = CTkFrame(entries_wrapper, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + + label_frame_widget_0.grid_rowconfigure((0,2), weight=1) + label_frame_widget_0.grid_columnconfigure(0, weight=1) + label_widget_0 = CTkLabel( + label_frame_widget_0, + textvariable=textvariable_0, + anchor="center", + height=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__MESSAGE_FORMAT__REQUIRED_TEXT_FONT_SIZE, weight="normal"), + text_color=self.settings.ctm.LABELS_TEXT_COLOR + ) + label_widget_0.grid(row=1, column=0, padx=0, pady=0, sticky="ew") + + + label_frame_widget_1 = CTkFrame(entries_wrapper, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + + label_frame_widget_1.grid_rowconfigure((0,2), weight=1) + label_frame_widget_1.grid_columnconfigure(0, weight=1) + label_widget_1 = CTkLabel( + label_frame_widget_1, + textvariable=textvariable_1, + anchor="center", + height=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__MESSAGE_FORMAT__REQUIRED_TEXT_FONT_SIZE, weight="normal"), + text_color=self.settings.ctm.LABELS_TEXT_COLOR + ) + label_widget_1.grid(row=1, column=0, padx=0, pady=0, sticky="ew") + + + entries_wrapper.grid_columnconfigure((0,2,4), weight=1) + entries_wrapper.grid_columnconfigure((1,3), weight=0, uniform="message_format_fixed_labels") + + entry_widget_0 = getattr(self.config_window, base_entry_attr_name+"_0") + entry_widget_1 = getattr(self.config_window, base_entry_attr_name+"_1") + entry_widget_2 = getattr(self.config_window, base_entry_attr_name+"_2") + entry_widget_0.grid(row=0, column=0, sticky="ew") + entry_widget_1.grid(row=0, column=2, sticky="ew") + entry_widget_2.grid(row=0, column=4, sticky="ew") + label_frame_widget_0.grid(row=0, column=1, padx=self.settings.uism.SB__MESSAGE_FORMAT__REQUIRED_TEXT_PADX, sticky="ew") + label_frame_widget_1.grid(row=0, column=3, padx=self.settings.uism.SB__MESSAGE_FORMAT__REQUIRED_TEXT_PADX, sticky="ew") + + def adjusted_command__for_entry_bind__Any_KeyRelease(_e): + message_format = entry_widget_0.get() + textvariable_0.get() + entry_widget_1.get() + textvariable_1.get() + entry_widget_2.get() + entry_bind__Any_KeyRelease(message_format) + + + entry_widget_0.bind("", adjusted_command__for_entry_bind__Any_KeyRelease) + entry_widget_1.bind("", adjusted_command__for_entry_bind__Any_KeyRelease) + entry_widget_2.bind("", adjusted_command__for_entry_bind__Any_KeyRelease) + + + + + + + swap_button = CTkFrame(swap_button_wrapper, corner_radius=self.settings.uism.BUTTONS_CORNER_RADIUS, fg_color=self.settings.ctm.SB__MESSAGE_FORMAT__SWAP_BUTTON_COLOR, cursor="hand2") + swap_button.grid(row=0, column=2, sticky="ew") + + + swap_button.grid_columnconfigure(0, weight=1) + swap_button_label_wrapper = CTkFrame(swap_button, corner_radius=0, fg_color=self.settings.ctm.SB__MESSAGE_FORMAT__SWAP_BUTTON_COLOR) + swap_button_label_wrapper.grid(row=0, column=0, padx=self.settings.uism.SB__MESSAGE_FORMAT__SWAP_BUTTON_IPADX, pady=self.settings.uism.SB__MESSAGE_FORMAT__SWAP_BUTTON_IPADY, sticky="ew") + + + swap_button_label_wrapper.grid_columnconfigure((0,4), weight=1) + swap_button_label_wrapper.grid_rowconfigure((0,2), weight=1) + + swap_button_label_0 = CTkLabel( + swap_button_label_wrapper, + textvariable=textvariable_0, + height=0, + corner_radius=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__MESSAGE_FORMAT__SWAP_BUTTON_FONT_SIZE, weight="normal"), + anchor="w", + text_color=self.settings.ctm.LABELS_TEXT_COLOR, + ) + swap_button_label_0.grid(row=1, column=1) + + swap_button_both_direction_arrow_img = CTkLabel( + swap_button_label_wrapper, + text=None, + height=0, + corner_radius=0, + image=CTkImage((self.settings.image_file.SWAP_ICON), size=self.settings.uism.SB__MESSAGE_FORMAT__SWAP_BUTTON_ARROWS_IMG_SIZE), + anchor="w", + text_color=self.settings.ctm.LABELS_TEXT_COLOR, + ) + swap_button_both_direction_arrow_img.grid(row=1, column=2, padx=self.settings.uism.SB__MESSAGE_FORMAT__SWAP_TEXT_PADX) + + swap_button_label_1 = CTkLabel( + swap_button_label_wrapper, + textvariable=textvariable_1, + height=0, + corner_radius=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__MESSAGE_FORMAT__SWAP_BUTTON_FONT_SIZE, weight="normal"), + anchor="w", + text_color=self.settings.ctm.LABELS_TEXT_COLOR, + ) + swap_button_label_1.grid(row=1, column=3) + + + def adjustedCommand(): + callFunctionIfCallable(self.view_variable.CALLBACK_SWAP_MESSAGE_FORMAT_REQUIRED_TEXT) + + bindButtonFunctionAndColor( + target_widgets=[ + swap_button, + swap_button_label_wrapper, + swap_button_label_0, + swap_button_both_direction_arrow_img, + swap_button_label_1, + ], + enter_color=self.settings.ctm.SB__MESSAGE_FORMAT__SWAP_BUTTON_HOVERED_COLOR, + leave_color=self.settings.ctm.SB__MESSAGE_FORMAT__SWAP_BUTTON_COLOR, + clicked_color=self.settings.ctm.SB__MESSAGE_FORMAT__SWAP_BUTTON_CLICKED_COLOR, + buttonReleasedFunction=lambda _e: adjustedCommand(), + ) + + + return setting_box_frame + + + + def createSettingBoxButtonWithImage( + self, + for_var_label_text, for_var_desc_text, + button_attr_name, + button_image, + button_command, + ): + + (setting_box_frame, setting_box_item_frame) = self._createSettingBoxFrame(button_attr_name, for_var_label_text, for_var_desc_text) + + + button_with_image_widget = createButtonWithImage( + parent_widget=setting_box_item_frame, + button_fg_color=self.settings.ctm.SB__BUTTON_COLOR, + button_enter_color=self.settings.ctm.SB__BUTTON_HOVERED_COLOR, + button_clicked_color=self.settings.ctm.SB__BUTTON_CLICKED_COLOR, + button_image_file=button_image, + button_image_size=self.settings.uism.SB__OPEN_CONFIG_FILE_BUTTON_ICON_SIZE, + button_ipadxy=self.settings.uism.SB__OPEN_CONFIG_FILE_BUTTON_IPADXY, + button_command=button_command, + ) + button_with_image_widget.grid(row=1, column=SETTING_BOX_COLUMN, sticky="e") + + return setting_box_frame + + + + + def createSettingBoxArrowSwitch( + self, + for_var_label_text, for_var_desc_text, + arrow_switch_attr_name, + open_command, + close_command, + var_switch_desc=None, + ): + + (setting_box_frame, setting_box_item_frame) = self._createSettingBoxFrame(arrow_switch_attr_name, for_var_label_text, for_var_desc_text) + + ARROW_BUTTON_COLUMN = SETTING_BOX_COLUMN + + if var_switch_desc is not None: + label_widget = CTkLabel( + setting_box_item_frame, + textvariable=var_switch_desc, + height=0, + corner_radius=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__ARROW_SWITCH_DESC_FONT_SIZE, weight="normal"), + anchor="w", + text_color=self.settings.ctm.LABELS_DESC_TEXT_COLOR, + ) + + label_widget.grid(row=1, column=SETTING_BOX_COLUMN) + ARROW_BUTTON_COLUMN = SETTING_BOX_COLUMN + 1 + + + for_opening_button_wrapper = createButtonWithImage( + parent_widget=setting_box_item_frame, + button_fg_color=self.settings.ctm.SB__BUTTON_COLOR, + button_enter_color=self.settings.ctm.SB__BUTTON_HOVERED_COLOR, + button_clicked_color=self.settings.ctm.SB__BUTTON_CLICKED_COLOR, + button_image_file=self.settings.image_file.ARROW_LEFT.rotate(270), + button_image_size=self.settings.uism.SB__BUTTON_ICON_SIZE, + button_ipadxy=self.settings.uism.SB__BUTTON_IPADXY, + button_command=open_command, + ) + for_opening_button_wrapper.grid(row=1, column=ARROW_BUTTON_COLUMN, padx=self.settings.uism.SB__ARROW_SWITCH_LEFT_PADX, sticky="e") + + self.config_window.sb__widgets[arrow_switch_attr_name].arrow_switch_open = for_opening_button_wrapper + + for_closing_button_wrapper = createButtonWithImage( + parent_widget=setting_box_item_frame, + button_fg_color=self.settings.ctm.SB__BUTTON_COLOR, + button_enter_color=self.settings.ctm.SB__BUTTON_HOVERED_COLOR, + button_clicked_color=self.settings.ctm.SB__BUTTON_CLICKED_COLOR, + button_image_file=self.settings.image_file.ARROW_LEFT.rotate(90), + button_image_size=self.settings.uism.SB__BUTTON_ICON_SIZE, + button_ipadxy=self.settings.uism.SB__BUTTON_IPADXY, + button_command=close_command, + ) + for_closing_button_wrapper.grid(row=1, column=ARROW_BUTTON_COLUMN, padx=self.settings.uism.SB__ARROW_SWITCH_LEFT_PADX, sticky="e") + for_closing_button_wrapper.grid_remove() + + self.config_window.sb__widgets[arrow_switch_attr_name].arrow_switch_close = for_closing_button_wrapper + + + return setting_box_frame + + + + # I've added it for the word filter, but it's not currently generalized. If you want to use it in the same way elsewhere, it will require refactoring. + def createSettingBoxAddAndDeleteAbleList( + self, + add_and_delete_able_list_attr_name, + entry_attr_name, + entry_width, + mic_word_filter_list, + ): + + (setting_box_frame, setting_box_item_frame) = self._createSettingBoxFrame(add_and_delete_able_list_attr_name) + + self.config_window.sb__widgets[add_and_delete_able_list_attr_name].items = [] + + + list_container = CTkFrame(setting_box_item_frame, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + list_container.grid(row=1, column=0, sticky="nsew") + + + max_width = int(self.MAIN_INNER_AREA_MIN_WIDTH - (self.settings.uism.SB__IPADX*2)) + + def addValues(mic_word_filter_list, mic_word_filter_item_row_wrapper, accumulated_labels_width, row, column): + for mic_word_filter_item in mic_word_filter_list: + mic_word_filter_item_wrapper = self._createValue(add_and_delete_able_list_attr_name, mic_word_filter_item_row_wrapper, row, column, mic_word_filter_item) + + if int(accumulated_labels_width + getLatestWidth(mic_word_filter_item_wrapper) + self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_LEFT_PADX[1]) >= max_width: + accumulated_labels_width = 0 + column = 0 + row += 1 + mic_word_filter_item_wrapper.destroy() + mic_word_filter_item_row_wrapper = self._createRowFrame(list_container, row) + mic_word_filter_item_wrapper = self._createValue(add_and_delete_able_list_attr_name, mic_word_filter_item_row_wrapper, row, column, mic_word_filter_item) + column += 1 + else: + column += 1 + + accumulated_labels_width += int(getLatestWidth(mic_word_filter_item_wrapper) + self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_LEFT_PADX[1]) + + + + return mic_word_filter_item_row_wrapper, accumulated_labels_width, row, column + + accumulated_labels_width = 0 + row=0 + column=0 + mic_word_filter_item_row_wrapper = self._createRowFrame(list_container, row) + + + mic_word_filter_list = self.view_variable.MIC_WORD_FILTER_LIST + + mic_word_filter_item_row_wrapper, accumulated_labels_width, row, column = addValues(mic_word_filter_list, mic_word_filter_item_row_wrapper, accumulated_labels_width, row, column) + + + self.config_window.sb__widgets[add_and_delete_able_list_attr_name].mic_word_filter_item_row_wrapper = mic_word_filter_item_row_wrapper + self.config_window.sb__widgets[add_and_delete_able_list_attr_name].accumulated_labels_width = accumulated_labels_width + self.config_window.sb__widgets[add_and_delete_able_list_attr_name].last_row = row + self.config_window.sb__widgets[add_and_delete_able_list_attr_name].last_column = column + self.config_window.sb__widgets[add_and_delete_able_list_attr_name].addValues = lambda values, mic_word_filter_item_row_wrapper, accumulated_labels_width, last_row, last_column: addValues(values, mic_word_filter_item_row_wrapper, accumulated_labels_width, last_row, last_column) + + + entry_and_add_button_wrapper = CTkFrame(setting_box_item_frame, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR) + entry_and_add_button_wrapper.grid(row=2, column=0, pady=(self.settings.uism.SB__IPADY, 0), sticky="ew") + + entry_and_add_button_wrapper.grid_columnconfigure((0,3), weight=1) + + + + entry_widget = CTkEntry( + entry_and_add_button_wrapper, + text_color=self.settings.ctm.SB__ENTRY_TEXT_COLOR, + fg_color=self.settings.ctm.SB__ENTRY_BG_COLOR, + border_color=self.settings.ctm.SB__ENTRY_BORDER_COLOR, + width=entry_width, + placeholder_text="AAA or AAA,BBB,CCC", + height=self.settings.uism.SB__PROGRESSBAR_X_SLIDER__ENTRY_HEIGHT, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__ENTRY_FONT_SIZE, weight="normal"), + ) + setattr(self.config_window, entry_attr_name, entry_widget) + + entry_widget.grid(row=0, column=1, sticky="ew") + + + + add_button = CTkFrame(entry_and_add_button_wrapper, corner_radius=self.settings.uism.BUTTONS_CORNER_RADIUS, fg_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_COLOR, cursor="hand2") + add_button.grid(row=0, column=2, padx=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_LEFT_PADX, sticky="ew") + + + add_button.grid_columnconfigure(0, weight=1) + add_button_label_wrapper = CTkFrame(add_button, corner_radius=0, fg_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_COLOR) + add_button_label_wrapper.grid(row=0, column=0, padx=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_IPADX, pady=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_IPADY, sticky="ew") + + add_button_label_wrapper.grid_columnconfigure((0,2), weight=1) + add_button_label = CTkLabel( + add_button_label_wrapper, + textvariable=self.view_variable.VAR_LABEL_MIC_WORD_FILTER_ADD_BUTTON, + height=0, + corner_radius=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_FONT_SIZE, weight="normal"), + anchor="w", + text_color=self.settings.ctm.LABELS_TEXT_COLOR, + ) + add_button_label.grid(row=0, column=1) + + + def adjustedCommand(): + callFunctionIfCallable(self.view_variable.CALLBACK_SET_MIC_WORD_FILTER, entry_widget.get()) + entry_widget.focus_set() + + bindButtonFunctionAndColor( + target_widgets=[ + add_button, + add_button_label_wrapper, + add_button_label, + ], + enter_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_HOVERED_COLOR, + leave_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_COLOR, + clicked_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_CLICKED_COLOR, + buttonReleasedFunction=lambda _e: adjustedCommand(), + ) + + + return setting_box_frame + + + def _createRowFrame(self, parent_widget, row): + mic_word_filter_item_row_wrapper = CTkFrame(parent_widget, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + mic_word_filter_item_row_wrapper.grid(row=row, column=0, pady=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_BOTTOM_PADY, sticky="nsew") + + return mic_word_filter_item_row_wrapper + + + + def _createValue(self, add_and_delete_able_list_attr_name, parent_row_frame, row, column, mic_word_filter_item): + mic_word_filter_item_wrapper = CTkFrame(parent_row_frame, corner_radius=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_CORNER_RADIUS, fg_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST_BG_COLOR, width=0, height=0) + mic_word_filter_item_wrapper.grid(row=0, column=column, padx=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_LEFT_PADX, sticky="nsew") + setattr(self, f"{row}_{column}", mic_word_filter_item_wrapper) + + + + mic_word_filter_item_wrapper.grid_rowconfigure((0,2), weight=1) + label_widget = CTkLabel( + mic_word_filter_item_wrapper, + text=mic_word_filter_item, + height=0, + corner_radius=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_FONT_SIZE, weight="normal"), + anchor="w", + text_color=self.settings.ctm.BASIC_TEXT_COLOR, + ) + + label_widget.grid(row=1, column=0, padx=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADX, pady=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADY) + + + if isEven(getLatestHeight(label_widget)) is False: + label_widget.grid( + pady=( + self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADY, + self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADY + 1 + ) + ) + + + if isEven(getLatestWidth(label_widget)) is False: + label_widget.grid( + padx=( + self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADX[0], + self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADX[1] + 1 + ) + ) + + + + def pressedDeleteButtonCommand(_e, delete_button, redo_button): + # overstrike true + label_widget.configure(font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_FONT_SIZE, weight="normal", overstrike=True)) + # change fg_color + mic_word_filter_item_wrapper.configure(fg_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST_DELETED_BG_COLOR) + # change button img to redo button + delete_button.grid_remove() + redo_button.grid() + # callback delete function + callFunctionIfCallable(self.view_variable.CALLBACK_DELETE_MIC_WORD_FILTER, mic_word_filter_item) + + def pressedRedoButtonCommand(_e, delete_button, redo_button): + # overstrike false + label_widget.configure(font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_FONT_SIZE, weight="normal", overstrike=False)) + # change fg_color + mic_word_filter_item_wrapper.configure(fg_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST_BG_COLOR) + # change button img to delete button + redo_button.grid_remove() + delete_button.grid() + # callback add function + callFunctionIfCallable(self.view_variable.CALLBACK_SET_MIC_WORD_FILTER, mic_word_filter_item) + + + + delete_button = createButtonWithImage( + parent_widget=mic_word_filter_item_wrapper, + button_fg_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST_BG_COLOR, + button_enter_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_HOVERED_BG_COLOR, + button_clicked_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_CLICKED_BG_COLOR, + button_image_file=self.settings.image_file.CANCEL_ICON, + button_image_size=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_IMG_SIZE, + button_ipadxy=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_IPADXY, + button_command=lambda _e: pressedDeleteButtonCommand(_e, delete_button, redo_button), + ) + delete_button.grid(row=1, column=1, padx=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_PADX, sticky="e") + + redo_button = createButtonWithImage( + parent_widget=mic_word_filter_item_wrapper, + button_fg_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST_DELETED_BG_COLOR, + button_enter_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__VALUES_DELETED_BUTTON_HOVERED_BG_COLOR, + button_clicked_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__VALUES_DELETED_BUTTON_CLICKED_BG_COLOR, + button_image_file=self.settings.image_file.REDO_ICON, + button_image_size=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_IMG_SIZE, + button_ipadxy=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_IPADXY, + button_command=lambda _e: pressedRedoButtonCommand(_e, delete_button, redo_button), + ) + redo_button.grid(row=1, column=1, padx=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_PADX, sticky="e") + redo_button.grid_remove() + + + partial_pressedRedoButtonCommand = partial(pressedRedoButtonCommand, _e=None, delete_button=delete_button, redo_button=redo_button) + item_data = SimpleNamespace( + label = mic_word_filter_item, + redoFunction = lambda: partial_pressedRedoButtonCommand(), + ) + + + items = self.config_window.sb__widgets[add_and_delete_able_list_attr_name].items + if len(items) == 0: + items.append(item_data) + else: + is_replaced = False + for i, item in enumerate(items): + if item.label == mic_word_filter_item: + items[i] = item_data + is_replaced = True + break + if is_replaced is False: + items.append(item_data) + + + return mic_word_filter_item_wrapper + + + + + + # 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.settings.ctm.SB__BG_COLOR, width=0, height=0) # self.setting_box_dropdown_menu_x_dropdown_menu.grid(row=0, column=1, padx=(0, self.settings.uism.SB__RIGHT_PADX), rowspan=2, sticky="e") diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_advanced_settings/createSettingBox_AdvancedSettings.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_advanced_settings/createSettingBox_AdvancedSettings.py index 4c6ef337..bb305ecf 100644 --- a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_advanced_settings/createSettingBox_AdvancedSettings.py +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_advanced_settings/createSettingBox_AdvancedSettings.py @@ -5,6 +5,7 @@ from .._SettingBoxGenerator import _SettingBoxGenerator def createSettingBox_AdvancedSettings(setting_box_wrapper, config_window, settings, view_variable): sbg = _SettingBoxGenerator(setting_box_wrapper, config_window, settings, view_variable) createSettingBoxEntry = sbg.createSettingBoxEntry + createSettingBoxButtonWithImage = sbg.createSettingBoxButtonWithImage def entry_ip_address_callback(value): @@ -13,6 +14,9 @@ def createSettingBox_AdvancedSettings(setting_box_wrapper, config_window, settin def entry_port_callback(value): callFunctionIfCallable(view_variable.CALLBACK_SET_OSC_PORT, value) + def open_config_filepath_callback(): + callFunctionIfCallable(view_variable.CALLBACK_OPEN_FILEPATH_CONFIG_FILE) + row=0 config_window.sb__ip_address = createSettingBoxEntry( for_var_label_text=view_variable.VAR_LABEL_OSC_IP_ADDRESS, @@ -34,5 +38,15 @@ def createSettingBox_AdvancedSettings(setting_box_wrapper, config_window, settin entry_bind__Any_KeyRelease=lambda value: entry_port_callback(value), entry_textvariable=view_variable.VAR_OSC_PORT, ) - config_window.sb__port.grid(row=row, pady=0) + config_window.sb__port.grid(row=row) row+=1 + + config_window.sb__open_config_filepath = createSettingBoxButtonWithImage( + for_var_label_text=view_variable.VAR_LABEL_OPEN_CONFIG_FILEPATH, + for_var_desc_text=view_variable.VAR_DESC_OPEN_CONFIG_FILEPATH, + button_attr_name="sb__button_open_config_filepath", + button_command=lambda _e: open_config_filepath_callback(), + button_image=settings.image_file.FOLDER_OPEN_ICON, + ) + config_window.sb__open_config_filepath.grid(row=row, pady=0) + row+=1 \ No newline at end of file diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_appearance/createSettingBox_Appearance.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_appearance/createSettingBox_Appearance.py index cc33684c..dd5f68ab 100644 --- a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_appearance/createSettingBox_Appearance.py +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_appearance/createSettingBox_Appearance.py @@ -18,6 +18,9 @@ def createSettingBox_Appearance(setting_box_wrapper, config_window, settings, vi def optionmenu_ui_scaling_callback(value): callFunctionIfCallable(view_variable.CALLBACK_SET_UI_SCALING, value) + def slider_text_box_ui_scaling_callback(value): + callFunctionIfCallable(view_variable.CALLBACK_SET_TEXTBOX_UI_SCALING, value) + def optionmenu_font_family_callback(value): callFunctionIfCallable(view_variable.CALLBACK_SET_FONT_FAMILY, value) @@ -35,6 +38,7 @@ def createSettingBox_Appearance(setting_box_wrapper, config_window, settings, vi variable=view_variable.VAR_TRANSPARENCY, slider_bind__ButtonPress=view_variable.CALLBACK_BUTTON_PRESS_TRANSPARENCY, slider_bind__ButtonRelease=view_variable.CALLBACK_BUTTON_RELEASE_TRANSPARENCY, + sliderTooltipFormatter=view_variable.CALLBACK_SLIDER_TOOLTIP_PERCENTAGE_FORMATTER, ) config_window.sb__transparency.grid(row=row) row+=1 @@ -64,6 +68,20 @@ def createSettingBox_Appearance(setting_box_wrapper, config_window, settings, vi config_window.sb__ui_scaling.grid(row=row) row+=1 + config_window.sb__textbox_uis_scaling = createSettingBoxSlider( + for_var_label_text=view_variable.VAR_LABEL_TEXTBOX_UI_SCALING, + for_var_desc_text=view_variable.VAR_DESC_TEXTBOX_UI_SCALING, + slider_attr_name="sb__slider_transparency", + slider_range=view_variable.SLIDER_RANGE_TEXTBOX_UI_SCALING, + command=lambda value: slider_text_box_ui_scaling_callback(value), + variable=view_variable.VAR_TEXTBOX_UI_SCALING, + slider_bind__ButtonPress=view_variable.CALLBACK_BUTTON_PRESS_TEXTBOX_UI_SCALING, + slider_bind__ButtonRelease=view_variable.CALLBACK_BUTTON_RELEASE_TEXTBOX_UI_SCALING, + sliderTooltipFormatter=view_variable.CALLBACK_SLIDER_TOOLTIP_PERCENTAGE_FORMATTER, + ) + config_window.sb__textbox_uis_scaling.grid(row=row) + row+=1 + config_window.sb__font_family = createSettingBoxDropdownMenu( for_var_label_text=view_variable.VAR_LABEL_FONT_FAMILY, diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/createSettingBox_Others.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/createSettingBox_Others.py index e4f46fb6..161e4bfc 100644 --- a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/createSettingBox_Others.py +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/createSettingBox_Others.py @@ -5,7 +5,9 @@ from .._SettingBoxGenerator import _SettingBoxGenerator def createSettingBox_Others(setting_box_wrapper, config_window, settings, view_variable): sbg = _SettingBoxGenerator(setting_box_wrapper, config_window, settings, view_variable) createSettingBoxCheckbox = sbg.createSettingBoxCheckbox - createSettingBoxEntry = sbg.createSettingBoxEntry + createSettingBoxAutoExportMessageLogs = sbg.createSettingBoxAutoExportMessageLogs + createSettingBox_Labels = sbg.createSettingBox_Labels + createSettingBoxMessageFormatEntries = sbg.createSettingBoxMessageFormatEntries # 元 checkbox_auto_clear_chatbox_callback @@ -18,6 +20,9 @@ def createSettingBox_Others(setting_box_wrapper, config_window, settings, view_v def checkbox_auto_export_message_logs_callback(checkbox_box_widget): callFunctionIfCallable(view_variable.CALLBACK_SET_ENABLE_AUTO_EXPORT_MESSAGE_LOGS, checkbox_box_widget.get()) + def button_auto_export_message_logs_callback(): + callFunctionIfCallable(view_variable.CALLBACK_OPEN_FILEPATH_LOGS) + def checkbox_enable_send_message_to_vrc_callback(checkbox_box_widget): callFunctionIfCallable(view_variable.CALLBACK_SET_ENABLE_SEND_MESSAGE_TO_VRC, checkbox_box_widget.get()) @@ -52,24 +57,37 @@ def createSettingBox_Others(setting_box_wrapper, config_window, settings, view_v row+=1 - config_window.sb__auto_export_message_logs = createSettingBoxCheckbox( + config_window.sb__auto_export_message_logs = createSettingBoxAutoExportMessageLogs( for_var_label_text=view_variable.VAR_LABEL_ENABLE_AUTO_EXPORT_MESSAGE_LOGS, for_var_desc_text=view_variable.VAR_DESC_ENABLE_AUTO_EXPORT_MESSAGE_LOGS, checkbox_attr_name="sb__checkbox_auto_export_message_logs", - command=lambda: checkbox_auto_export_message_logs_callback(config_window.sb__checkbox_auto_export_message_logs), + checkbox_command=lambda: checkbox_auto_export_message_logs_callback(config_window.sb__checkbox_auto_export_message_logs), + button_command=lambda _e: button_auto_export_message_logs_callback(), variable=view_variable.VAR_ENABLE_AUTO_EXPORT_MESSAGE_LOGS, ) config_window.sb__auto_export_message_logs.grid(row=row) row+=1 - config_window.sb__message_format = createSettingBoxEntry( + config_window.sb__message_format_labels = createSettingBox_Labels( for_var_label_text=view_variable.VAR_LABEL_MESSAGE_FORMAT, for_var_desc_text=view_variable.VAR_DESC_MESSAGE_FORMAT, - entry_attr_name="sb__entry_message_format", - entry_width=settings.uism.RESPONSIVE_UI_SIZE_INT_250, + labels_attr_name="sb__labels_message_format", + ) + config_window.sb__message_format_labels.grid(row=row, pady=0) + row+=1 + + config_window.sb__message_format = createSettingBoxMessageFormatEntries( + base_entry_attr_name="sb__entry_message_format", + # entry_width=settings.uism.RESPONSIVE_UI_SIZE_INT_150, + entry_textvariable_0=view_variable.VAR_ENTRY_0_MESSAGE_FORMAT, + entry_textvariable_1=view_variable.VAR_ENTRY_1_MESSAGE_FORMAT, + entry_textvariable_2=view_variable.VAR_ENTRY_2_MESSAGE_FORMAT, + textvariable_0=view_variable.VAR_TEXT_REQUIRED_0_MESSAGE_FORMAT, + textvariable_1=view_variable.VAR_TEXT_REQUIRED_1_MESSAGE_FORMAT, entry_bind__Any_KeyRelease=lambda value: entry_message_format_callback(value), - entry_textvariable=view_variable.VAR_MESSAGE_FORMAT, + # entry_textvariable=view_variable.VAR_MESSAGE_FORMAT, + entry_bind__FocusOut=view_variable.CALLBACK_FOCUS_OUT_MESSAGE_FORMAT, ) config_window.sb__message_format.grid(row=row) row+=1 diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_transcription/createSettingBox_Mic.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_transcription/createSettingBox_Mic.py index 472e5baa..d5ece1b6 100644 --- a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_transcription/createSettingBox_Mic.py +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_transcription/createSettingBox_Mic.py @@ -8,6 +8,8 @@ def createSettingBox_Mic(setting_box_wrapper, config_window, settings, view_vari createSettingBoxSwitch = sbg.createSettingBoxSwitch createSettingBoxProgressbarXSlider = sbg.createSettingBoxProgressbarXSlider createSettingBoxEntry = sbg.createSettingBoxEntry + createSettingBoxArrowSwitch = sbg.createSettingBoxArrowSwitch + createSettingBoxAddAndDeleteAbleList = sbg.createSettingBoxAddAndDeleteAbleList def checkbox_input_mic_threshold_check_callback(is_turned_on): @@ -36,6 +38,11 @@ def createSettingBox_Mic(setting_box_wrapper, config_window, settings, view_vari def entry_input_mic_max_phrases_callback(value): callFunctionIfCallable(view_variable.CALLBACK_SET_MIC_MAX_PHRASES, value) + def arrow_switch_mic_word_filter_list_open_callback(value): + callFunctionIfCallable(view_variable.CALLBACK_ARROW_SWITCH_MIC_WORD_FILTER_LIST_OPEN) + def arrow_switch_mic_word_filter_list_close_callback(value): + callFunctionIfCallable(view_variable.CALLBACK_ARROW_SWITCH_MIC_WORD_FILTER_LIST_CLOSE) + def entry_input_mic_word_filters_callback(value): callFunctionIfCallable(view_variable.CALLBACK_SET_MIC_WORD_FILTER, value) @@ -140,13 +147,24 @@ def createSettingBox_Mic(setting_box_wrapper, config_window, settings, view_vari # # __________ - config_window.sb__mic_word_filter = createSettingBoxEntry( + config_window.sb__mic_word_filter = createSettingBoxArrowSwitch( for_var_label_text=view_variable.VAR_LABEL_MIC_WORD_FILTER, for_var_desc_text=view_variable.VAR_DESC_MIC_WORD_FILTER, - entry_attr_name="sb__entry_mic_word_filter", - entry_width=settings.uism.RESPONSIVE_UI_SIZE_INT_300, - entry_bind__Any_KeyRelease=lambda value: entry_input_mic_word_filters_callback(value), - entry_textvariable=view_variable.VAR_MIC_WORD_FILTER, + arrow_switch_attr_name="sb__arrow_switch_mic_word_filter", + open_command=lambda value: arrow_switch_mic_word_filter_list_open_callback(value), + close_command=lambda value: arrow_switch_mic_word_filter_list_close_callback(value), + var_switch_desc=view_variable.VAR_SWITCH_DESC_MIC_WORD_FILTER, ) config_window.sb__mic_word_filter.grid(row=row, pady=0) + row+=1 + + config_window.sb__mic_word_filter_list = createSettingBoxAddAndDeleteAbleList( + add_and_delete_able_list_attr_name="sb__add_and_delete_able_list_mic_word_filter_list", + entry_attr_name="sb__entry_mic_word_filter_list", + entry_width=settings.uism.RESPONSIVE_UI_SIZE_INT_300, + mic_word_filter_list=view_variable.MIC_WORD_FILTER_LIST, + ) + config_window.sb__mic_word_filter_list.grid(row=row, pady=0) + # Default, close the list. + config_window.sb__mic_word_filter_list.grid_remove() row+=1 \ No newline at end of file diff --git a/vrct_gui/main_window/createMainWindowWidgets.py b/vrct_gui/main_window/createMainWindowWidgets.py index 2bcea306..54ce6a6a 100644 --- a/vrct_gui/main_window/createMainWindowWidgets.py +++ b/vrct_gui/main_window/createMainWindowWidgets.py @@ -6,7 +6,7 @@ from utils import callFunctionIfCallable from ..ui_utils import createButtonWithImage, getImagePath, bindButtonFunctionAndColor def createMainWindowWidgets(vrct_gui, settings, view_variable): - vrct_gui.protocol("WM_DELETE_WINDOW", vrct_gui._quitVRCT) + vrct_gui.protocol("WM_DELETE_WINDOW", lambda: callFunctionIfCallable(view_variable.CALLBACK_QUIT_VRCT)) vrct_gui.iconbitmap(getImagePath("vrct_logo_mark_black.ico")) @@ -68,7 +68,7 @@ def createMainWindowWidgets(vrct_gui, settings, view_variable): text=None, corner_radius=0, height=0, - image=CTkImage(settings.image_file.REFRESH_ICON.rotate(25), size=settings.uism.UPDATE_AVAILABLE_BUTTON_SIZE) + image=CTkImage(settings.image_file.REFRESH_UPDATE_ICON.rotate(25), size=settings.uism.UPDATE_AVAILABLE_BUTTON_SIZE) ) vrct_gui.update_available_icon.grid(row=1, column=0, padx=(settings.uism.UPDATE_AVAILABLE_BUTTON_IPADX, settings.uism.UPDATE_AVAILABLE_PADX_BETWEEN_LABEL_AND_ICON), pady=0) @@ -92,9 +92,9 @@ def createMainWindowWidgets(vrct_gui, settings, view_variable): vrct_gui.update_available_label, vrct_gui.update_available_icon, ], - enter_color=settings.ctm.UPDATE_AVAILABLE_BUTTON_HOVERED_BG_COLOR, - leave_color=settings.ctm.UPDATE_AVAILABLE_BUTTON_BG_COLOR, - clicked_color=settings.ctm.UPDATE_AVAILABLE_BUTTON_CLICKED_BG_COLOR, + enter_color=settings.ctm.TOP_BAR_BUTTON_HOVERED_BG_COLOR, + leave_color=settings.ctm.TOP_BAR_BUTTON_BG_COLOR, + clicked_color=settings.ctm.TOP_BAR_BUTTON_CLICKED_BG_COLOR, buttonReleasedFunction=lambda e: callFunctionIfCallable(view_variable.CALLBACK_CLICKED_UPDATE_AVAILABLE), ) @@ -105,9 +105,9 @@ def createMainWindowWidgets(vrct_gui, settings, view_variable): # 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_fg_color=settings.ctm.TOP_BAR_BUTTON_BG_COLOR, + button_enter_color=settings.ctm.TOP_BAR_BUTTON_HOVERED_BG_COLOR, + button_clicked_color=settings.ctm.TOP_BAR_BUTTON_CLICKED_BG_COLOR, button_image_file=settings.image_file.HELP_ICON, button_image_size=settings.uism.HELP_AND_INFO_BUTTON_SIZE, button_ipadxy=settings.uism.HELP_AND_INFO_BUTTON_IPADXY, diff --git a/vrct_gui/main_window/widgets/_create_sidebar/createSidebarFeatures.py b/vrct_gui/main_window/widgets/_create_sidebar/createSidebarFeatures.py index b46ab3cc..bce4113f 100644 --- a/vrct_gui/main_window/widgets/_create_sidebar/createSidebarFeatures.py +++ b/vrct_gui/main_window/widgets/_create_sidebar/createSidebarFeatures.py @@ -2,7 +2,7 @@ from functools import partial from customtkinter import CTkFont, CTkFrame, CTkLabel, CTkSwitch, CTkImage -from ....ui_utils import openImageKeepAspectRatio, retag, getLatestHeight, bindEnterAndLeaveFunction, bindButtonReleaseFunction, bindButtonPressAndReleaseFunction +from ....ui_utils import openImageKeepAspectRatio, retag, bindEnterAndLeaveFunction, bindButtonReleaseFunction, bindButtonPressAndReleaseFunction from utils import callFunctionIfCallable diff --git a/vrct_gui/main_window/widgets/_create_sidebar/createSidebarLanguagesSettings.py b/vrct_gui/main_window/widgets/_create_sidebar/createSidebarLanguagesSettings.py index 346afae5..7561e1ae 100644 --- a/vrct_gui/main_window/widgets/_create_sidebar/createSidebarLanguagesSettings.py +++ b/vrct_gui/main_window/widgets/_create_sidebar/createSidebarLanguagesSettings.py @@ -1,6 +1,6 @@ from customtkinter import CTkFont, CTkFrame, CTkLabel, CTkImage -from ....ui_utils import bindEnterAndLeaveColor, bindButtonPressColor, bindButtonReleaseFunction, switchActiveTabAndPassiveTab, switchTabsColor, createOptionMenuBox +from ....ui_utils import bindEnterAndLeaveColor, bindButtonPressColor, bindButtonReleaseFunction, switchActiveTabAndPassiveTab, switchTabsColor, createOptionMenuBox, bindButtonFunctionAndColor, bindEnterAndLeaveFunction from utils import callFunctionIfCallable @@ -226,36 +226,85 @@ def createSidebarLanguagesSettings(settings, main_window, view_variable): # Both direction arrow icon main_window.sls__arrow_direction_box = CTkFrame(main_window.sls__box_frame, corner_radius=0, fg_color=settings.ctm.SLS__BG_COLOR, width=0, height=0) - main_window.sls__arrow_direction_box.grid(row=3, column=0, pady=settings.uism.SLS__BOX_ARROWS_PADY,sticky="ew") + main_window.sls__arrow_direction_box.grid(row=3, column=0, pady=settings.uism.SLS__BOX_ARROWS_PADY, sticky="ew") - main_window.sls__arrow_direction_box.grid_columnconfigure((0,4), weight=1) + main_window.sls__arrow_direction_box.grid_columnconfigure((0,2), weight=0, minsize=settings.uism.SLS__BOX_ARROWS_SWAP_BUTTON_PADX) + main_window.sls__arrow_direction_box.grid_columnconfigure(1, weight=1) + + main_window.sls__arrow_direction_swap_box = CTkFrame(main_window.sls__arrow_direction_box, corner_radius=settings.uism.SLS__BOX_ARROWS_SWAP_BUTTON_CORNER_RADIUS, fg_color=settings.ctm.SLS__BG_COLOR, width=0, height=0, cursor="hand2") + main_window.sls__arrow_direction_swap_box.grid(row=0, column=1, ipady=settings.uism.SLS__BOX_ARROWS_SWAP_BUTTON_IPADY, sticky="ew") + + main_window.sls__arrow_direction_swap_box.grid_rowconfigure((0,2), weight=1) + main_window.sls__arrow_direction_swap_box.grid_columnconfigure(1, weight=1) main_window.sls__both_direction_up = CTkLabel( - main_window.sls__arrow_direction_box, + main_window.sls__arrow_direction_swap_box, text=None, height=0, image=CTkImage((settings.image_file.NARROW_ARROW_DOWN).rotate(180),size=settings.uism.SLS__BOX_ARROWS_IMAGE_SIZE) ) - main_window.sls__both_direction_up.grid(row=0, column=1, pady=0) + main_window.sls__both_direction_up.grid(row=1, column=0, padx=(settings.uism.SLS__BOX_ARROWS_SWAP_BUTTON_IPADX, 0), pady=0) main_window.sls__both_direction_desc = CTkLabel( - main_window.sls__arrow_direction_box, + main_window.sls__arrow_direction_swap_box, textvariable=view_variable.VAR_LABEL_BOTH_DIRECTION_DESC, height=0, font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.SLS__BOX_ARROWS_DESC_FONT_SIZE, weight="normal"), text_color=settings.ctm.SLS__BOX_ARROWS_TEXT_COLOR, ) - main_window.sls__both_direction_desc.grid(row=0, column=2, padx=settings.uism.SLS__BOX_ARROWS_DESC_PADX) + main_window.sls__both_direction_desc.grid(row=1, column=1, padx=settings.uism.SLS__BOX_ARROWS_DESC_PADX) - main_window.sls__both_direction_label_down = CTkLabel( - main_window.sls__arrow_direction_box, + main_window.sls__both_direction_down = CTkLabel( + main_window.sls__arrow_direction_swap_box, text=None, height=0, image=CTkImage((settings.image_file.NARROW_ARROW_DOWN).rotate(0),size=settings.uism.SLS__BOX_ARROWS_IMAGE_SIZE) ) - main_window.sls__both_direction_label_down.grid(row=0, column=3) + main_window.sls__both_direction_down.grid(row=1, column=2, padx=(0, settings.uism.SLS__BOX_ARROWS_SWAP_BUTTON_IPADX)) + + + + def adjustedCommand_ButtonReleased(): + callFunctionIfCallable(view_variable.CALLBACK_SWAP_LANGUAGES) + + bindButtonFunctionAndColor( + target_widgets=[ + main_window.sls__arrow_direction_swap_box, + main_window.sls__both_direction_up, + main_window.sls__both_direction_desc, + main_window.sls__both_direction_down + ], + enter_color=settings.ctm.SLS__BOX_ARROWS_SWAP_BUTTON_HOVERED_COLOR, + leave_color=settings.ctm.SLS__BG_COLOR, + clicked_color=settings.ctm.SLS__BOX_ARROWS_SWAP_BUTTON_CLICKED_COLOR, + buttonReleasedFunction=lambda _e: adjustedCommand_ButtonReleased(), + ) + + + def adjustedCommand_Entered(): + main_window.sls__both_direction_desc.configure( + textvariable=view_variable.VAR_LABEL_BOTH_DIRECTION_SWAP_BUTTON, + text_color=settings.ctm.SLS__BOX_ARROWS_SWAP_BUTTON_TEXT_COLOR, + ) + + def adjustedCommand_Leaved(): + main_window.sls__both_direction_desc.configure( + textvariable=view_variable.VAR_LABEL_BOTH_DIRECTION_DESC, + text_color=settings.ctm.SLS__BOX_ARROWS_TEXT_COLOR, + ) + + bindEnterAndLeaveFunction( + target_widgets=[ + main_window.sls__arrow_direction_swap_box, + main_window.sls__both_direction_up, + main_window.sls__both_direction_desc, + main_window.sls__both_direction_down + ], + enterFunction=lambda _e: adjustedCommand_Entered(), + leaveFunction=lambda _e: adjustedCommand_Leaved(), + ) diff --git a/vrct_gui/ui_managers/ColorThemeManager.py b/vrct_gui/ui_managers/ColorThemeManager.py index ab55e996..c9793403 100644 --- a/vrct_gui/ui_managers/ColorThemeManager.py +++ b/vrct_gui/ui_managers/ColorThemeManager.py @@ -1,485 +1,120 @@ from types import SimpleNamespace +from .Themes import _darkTheme, _lightTheme + class ColorThemeManager(): def __init__(self, theme): - self.main = SimpleNamespace() - self.config_window = SimpleNamespace() - self.selectable_language_window = SimpleNamespace() - self.main_window_cover = SimpleNamespace() - self.error_message_window = SimpleNamespace() - self.confirmation_modal = SimpleNamespace() + # base_color 100, 200, 300...900 is generated by https://m2.material.io/design/color/the-color-system.html#tools-for-picking-colors . I put the comment "Source". I used it as a source color and generated. + # and like 750, 888... is made by https://meyerweb.com/eric/tools/color-blend/#:::hex - # old one. But leave it here for now. - # 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.base_color = SimpleNamespace( + + PRIMARY_100_COLOR = "#b7ded8", + PRIMARY_150_COLOR = "#A1D4CC", + PRIMARY_200_COLOR = "#8acac0", + PRIMARY_250_COLOR = "#76BFB4", + PRIMARY_300_COLOR = "#61b4a7", + PRIMARY_350_COLOR = "#55AC9E", + PRIMARY_400_COLOR = "#48a495", # Source + PRIMARY_450_COLOR = "#429c8c", + PRIMARY_500_COLOR = "#3b9483", + PRIMARY_600_COLOR = "#368777", + PRIMARY_650_COLOR = "#347f6f", + PRIMARY_700_COLOR = "#317767", + PRIMARY_750_COLOR = "#2F6F60", + PRIMARY_800_COLOR = "#2c6759", + PRIMARY_900_COLOR = "#214b3f", + + SENT_400_COLOR = "#6197b4", # Source PRIMARY_300_COLOR #61b4a7. ANALOGOUS' Second one. + RECEIVED_300_COLOR = "#a861b4", # Source PRIMARY_300_COLOR #61b4a7. TRIADIC' Second one. + + DARK_BASIC_TEXT_COLOR = "#f2f2f2", # Icon normal color too + DARK_100_COLOR = "#f5f7fb", # THE LIGHTEST BG COLOR + DARK_200_COLOR = "#f1f2f6", + DARK_300_COLOR = "#e9eaee", + DARK_350_COLOR = "#d8d9dd", + DARK_400_COLOR = "#c7c8cc", # Icon second color + DARK_450_COLOR = "#b8b9bd", + DARK_500_COLOR = "#a9aaae", + DARK_600_COLOR = "#7f8084", + DARK_650_COLOR = "#75767a", + DARK_700_COLOR = "#6a6c6f", + DARK_725_COLOR = "#636467", + DARK_750_COLOR = "#5b5c5f", + DARK_775_COLOR = "#535457", + DARK_800_COLOR = "#4b4c4f", + DARK_825_COLOR = "#434447", + DARK_850_COLOR = "#3a3b3e", + DARK_863_COLOR = "#36373a", + DARK_875_COLOR = "#323336", + DARK_888_COLOR = "#2e2f32", + DARK_900_COLOR = "#292a2d", # Source + DARK_925_COLOR = "#242528", + DARK_950_COLOR = "#1f2022", + DARK_975_COLOR = "#1a1b1d", + DARK_1000_COLOR = "#151517", # THE DARKEST BG COLOR - # new one. - self.PRIMARY_100_COLOR = "#b7ded8" - self.PRIMARY_200_COLOR = "#8acac0" - self.PRIMARY_300_COLOR = "#61b4a7" - self.PRIMARY_400_COLOR = "#48a495" - self.PRIMARY_450_COLOR = "#429c8c" - self.PRIMARY_500_COLOR = "#3b9483" - self.PRIMARY_600_COLOR = "#368777" - self.PRIMARY_650_COLOR = "#347f6f" - self.PRIMARY_700_COLOR = "#317767" - self.PRIMARY_750_COLOR = "#2F6F60" - self.PRIMARY_800_COLOR = "#2c6759" - self.PRIMARY_900_COLOR = "#214b3f" + LIGHT_BASIC_TEXT_COLOR = "#050505", + LIGHT_100_COLOR = "#f5f7fb", # THE LIGHTEST BG COLOR + LIGHT_125_COLOR = "#F4F6FA", + LIGHT_150_COLOR = "#F2F4F8", + LIGHT_175_COLOR = "#F1F3F7", + LIGHT_200_COLOR = "#eff1f5", + LIGHT_225_COLOR = "#ECEEF2", + LIGHT_250_COLOR = "#E9EBEF", + LIGHT_275_COLOR = "#E6E8EC", + LIGHT_300_COLOR = "#e2e4e8", + LIGHT_313_COLOR = "#DEE0E4", + LIGHT_325_COLOR = "#DADCE0", + LIGHT_333_COLOR = "#D6D8DC", + LIGHT_350_COLOR = "#D1D3D7", + LIGHT_375_COLOR = "#C9CBCF", + LIGHT_400_COLOR = "#c0c2c6", + LIGHT_450_COLOR = "#B1B3B7", + LIGHT_500_COLOR = "#a2a3a7", + LIGHT_550_COLOR = "#8D8F93", + LIGHT_600_COLOR = "#787a7e", + LIGHT_700_COLOR = "#646669", # Icon second color + LIGHT_800_COLOR = "#45464a", + LIGHT_900_COLOR = "#242528", # Icon normal color + LIGHT_1000_COLOR = "#1b1b1b", # THE DARKEST BG COLOR + ) - self.DARK_100_COLOR = "#f5f7fb" - self.DARK_200_COLOR = "#f1f2f6" - self.DARK_300_COLOR = "#e9eaee" - self.DARK_350_COLOR = "#d8d9dd" - self.DARK_400_COLOR = "#c7c8cc" - self.DARK_450_COLOR = "#b8b9bd" - self.DARK_500_COLOR = "#a9aaae" - self.DARK_600_COLOR = "#7f8084" - self.DARK_650_COLOR = "#75767a" - self.DARK_700_COLOR = "#6a6c6f" - self.DARK_725_COLOR = "#636467" - self.DARK_750_COLOR = "#5b5c5f" - self.DARK_775_COLOR = "#535457" - self.DARK_800_COLOR = "#4b4c4f" - self.DARK_825_COLOR = "#434447" - self.DARK_850_COLOR = "#3a3b3e" - self.DARK_863_COLOR = "#36373a" - 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" + # It's actually meaningless to separate it from __init__. but it's just set to use the dark theme by default, so I did it just in case to change the default theme. + selected_color_theme = _darkTheme(self.base_color) + for each_key in selected_color_theme.__dict__.keys(): + setattr(self, each_key, getattr(selected_color_theme, each_key)) if theme == "Dark": - self._createDarkModeColor() + pass + elif theme == "Light": - self._createLightModeColor() + selected_color_theme = _lightTheme(self.base_color) + self._colorThemeDictsMerger(selected_color_theme) - 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_888_COLOR - self.main.TEXTBOX_BG_COLOR = self.DARK_900_COLOR - self.main.TEXTBOX_TEXT_COLOR = self.main.BASIC_TEXT_COLOR - self.main.TEXTBOX_TEXT_SUB_COLOR = self.DARK_450_COLOR - self.main.TEXTBOX_SYSTEM_TAG_TEXT_COLOR = self.PRIMARY_300_COLOR - self.main.TEXTBOX_SENT_TAG_TEXT_COLOR = "#6197b4" - self.main.TEXTBOX_RECEIVED_TAG_TEXT_COLOR = "#a861b4" - self.main.TEXTBOX_ERROR_TAG_TEXT_COLOR = "#c27583" - self.main.TEXTBOX_TIMESTAMP_TEXT_COLOR = self.DARK_600_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_925_COLOR - self.main.TEXTBOX_TAB_TEXT_ACTIVE_COLOR = self.main.BASIC_TEXT_COLOR - self.main.TEXTBOX_TAB_TEXT_PASSIVE_COLOR = self.DARK_500_COLOR + def _colorThemeDictsMerger(self, selected_color_theme): + # Each section(main, selectable_language_window, config_window...) marge to default theme. + for selected_theme_section_key in selected_color_theme.__dict__.keys(): + # Get same section data by section key from default theme. + default_theme_target_section_data = getattr(self, selected_theme_section_key) - 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 + selected_theme_section_data = getattr(selected_color_theme, selected_theme_section_key) + self._mergeNestedDicts(default_theme_target_section_data.__dict__, selected_theme_section_data.__dict__) - # Sidebar - self.main.SIDEBAR_BG_COLOR = self.DARK_850_COLOR + def _mergeNestedDicts(self, d1, d2): + for key, value in d2.items(): + if key in d1 and isinstance(d1[key], dict) and isinstance(value, dict): + self._mergeNestedDicts(d1[key], value) + else: + d1[key] = value - # Sidebar Features - self.main.SF__BG_COLOR = self.DARK_825_COLOR - self.main.SF__HOVERED_BG_COLOR = self.DARK_800_COLOR - self.main.SF__CLICKED_BG_COLOR = self.DARK_875_COLOR - self.main.SF__TEXT_DISABLED_COLOR = self.DARK_500_COLOR - - self.main.SF__SWITCH_BOX_BG_COLOR = self.DARK_775_COLOR - self.main.SF__SWITCH_BOX_HOVERED_BG_COLOR = self.DARK_725_COLOR - self.main.SF__SWITCH_BOX_CLICKED_BG_COLOR = self.DARK_825_COLOR - self.main.SF__SWITCH_BOX_ACTIVE_BG_COLOR = self.PRIMARY_500_COLOR - self.main.SF__SWITCH_BOX_ACTIVE_HOVERED_BG_COLOR = self.PRIMARY_400_COLOR - self.main.SF__SWITCH_BOX_ACTIVE_CLICKED_BG_COLOR = self.PRIMARY_700_COLOR - self.main.SF__SWITCH_BOX_DISABLE_BG_COLOR = self.PRIMARY_800_COLOR - - self.main.SF__SWITCH_BOX_BUTTON_COLOR = self.DARK_400_COLOR - # It's not working because It overrode internally. - self.main.SF__SWITCH_BOX_BUTTON_HOVERED_COLOR = self.DARK_350_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 Languages Settings - self.main.SLS__TITLE_TEXT_COLOR = self.DARK_400_COLOR - - self.main.SLS__BG_COLOR = self.DARK_800_COLOR - - self.main.SLS__PRESETS_TAB_BG_HOVERED_COLOR = self.DARK_825_COLOR - self.main.SLS__PRESETS_TAB_BG_CLICKED_COLOR = self.DARK_875_COLOR - self.main.SLS__PRESETS_TAB_BG_PASSIVE_COLOR = self.main.SIDEBAR_BG_COLOR - self.main.SLS__PRESETS_TAB_BG_ACTIVE_COLOR = self.main.SLS__BG_COLOR - self.main.SLS__PRESETS_TAB_ACTIVE_TEXT_COLOR_PASSIVE = self.DARK_600_COLOR - self.main.SLS__PRESETS_TAB_ACTIVE_TEXT_COLOR = self.main.BASIC_TEXT_COLOR - - self.main.SLS__BOX_BG_COLOR = self.DARK_825_COLOR - self.main.SLS__BOX_SECTION_TITLE_TEXT_COLOR = self.DARK_400_COLOR - self.main.SLS__BOX_ARROWS_TEXT_COLOR = self.DARK_500_COLOR - - self.main.SLS__OPTIONMENU_BG_COLOR = self.DARK_888_COLOR - self.main.SLS__OPTIONMENU_HOVERED_BG_COLOR = self.DARK_875_COLOR - self.main.SLS__OPTIONMENU_CLICKED_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_875_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.TOP_BAR_BUTTON_BG_COLOR = self.main.MAIN_BG_COLOR - self.main.TOP_BAR_BUTTON_HOVERED_BG_COLOR = self.DARK_850_COLOR - self.main.TOP_BAR_BUTTON_CLICKED_BG_COLOR = self.DARK_900_COLOR - # self.main.TOP_BAR_BUTTON_DISABLE_COLOR = self.DARK_900_COLOR - - self.main.UPDATE_AVAILABLE_BUTTON_BG_COLOR = self.main.TOP_BAR_BUTTON_BG_COLOR - self.main.UPDATE_AVAILABLE_BUTTON_HOVERED_BG_COLOR = self.main.TOP_BAR_BUTTON_HOVERED_BG_COLOR - self.main.UPDATE_AVAILABLE_BUTTON_CLICKED_BG_COLOR = self.main.TOP_BAR_BUTTON_CLICKED_BG_COLOR - # self.main.UPDATE_AVAILABLE_BUTTON_DISABLE_COLOR = self.main.TOP_BAR_BUTTON_DISABLE_COLOR - self.main.UPDATE_AVAILABLE_BUTTON_TEXT_COLOR = self.PRIMARY_300_COLOR - - self.main.HELP_AND_INFO_BUTTON_BG_COLOR = self.main.TOP_BAR_BUTTON_BG_COLOR - self.main.HELP_AND_INFO_BUTTON_HOVERED_BG_COLOR = self.main.TOP_BAR_BUTTON_HOVERED_BG_COLOR - self.main.HELP_AND_INFO_BUTTON_CLICKED_BG_COLOR = self.main.TOP_BAR_BUTTON_CLICKED_BG_COLOR - # self.main.HELP_AND_INFO_BUTTON_DISABLE_COLOR = self.main.TOP_BAR_BUTTON_DISABLE_COLOR - - - - # Selectable Language Window - self.selectable_language_window.BASIC_TEXT_COLOR = self.main.BASIC_TEXT_COLOR - - self.selectable_language_window.MAIN_BG_COLOR = self.DARK_875_COLOR - - self.selectable_language_window.GO_BACK_BUTTON_BG_COLOR = self.DARK_800_COLOR - self.selectable_language_window.GO_BACK_BUTTON_BG_HOVERED_COLOR = self.DARK_750_COLOR - self.selectable_language_window.GO_BACK_BUTTON_BG_CLICKED_COLOR = self.DARK_875_COLOR - - - self.selectable_language_window.TOP_BG_COLOR = self.main.SIDEBAR_BG_COLOR - self.selectable_language_window.TITLE_TEXT_COLOR = self.DARK_400_COLOR - self.selectable_language_window.LANGUAGE_BUTTON_BG_COLOR = self.selectable_language_window.MAIN_BG_COLOR - self.selectable_language_window.LANGUAGE_BUTTON_BG_HOVERED_COLOR = self.DARK_825_COLOR - self.selectable_language_window.LANGUAGE_BUTTON_BG_CLICKED_COLOR = self.DARK_888_COLOR - - - # Modal Window (Main Window) - self.main_window_cover.TEXT_COLOR = self.LIGHT_100_COLOR - - - self.confirmation_modal.MESSAGE_TEXT_COLOR = self.LIGHT_100_COLOR - self.confirmation_modal.FAKE_BORDER_COLOR = self.DARK_600_COLOR - self.confirmation_modal.BG_COLOR = self.DARK_800_COLOR - self.confirmation_modal.CONFIRMATION_BUTTONS_TEXT_COLOR = self.LIGHT_100_COLOR - - self.confirmation_modal.ACCEPT_BUTTON_BG_COLOR = self.PRIMARY_600_COLOR - self.confirmation_modal.ACCEPT_BUTTON_HOVERED_BG_COLOR = self.PRIMARY_450_COLOR - self.confirmation_modal.ACCEPT_BUTTON_CLICKED_BG_COLOR = self.PRIMARY_750_COLOR - self.confirmation_modal.DENY_BUTTON_BG_COLOR = self.DARK_750_COLOR - self.confirmation_modal.DENY_BUTTON_HOVERED_BG_COLOR = self.DARK_700_COLOR - self.confirmation_modal.DENY_BUTTON_CLICKED_BG_COLOR = self.DARK_825_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 - - self.config_window.LABELS_TEXT_DISABLED_COLOR = self.DARK_600_COLOR - - - # Top bar - self.config_window.TOP_BAR_BG_COLOR = self.DARK_850_COLOR - - # Restart Button - self.config_window.RESTART_BUTTON_BG_COLOR = self.PRIMARY_600_COLOR - self.config_window.RESTART_BUTTON_HOVERED_BG_COLOR = self.PRIMARY_500_COLOR - self.config_window.RESTART_BUTTON_CLICKED_BG_COLOR = self.PRIMARY_700_COLOR - - - # Compact Mode - self.config_window.COMPACT_MODE_SWITCH_BOX_BG_COLOR = self.DARK_775_COLOR - self.config_window.COMPACT_MODE_SWITCH_BOX_ACTIVE_BG_COLOR = self.PRIMARY_500_COLOR - self.config_window.COMPACT_MODE_SWITCH_BOX_BUTTON_COLOR = self.DARK_350_COLOR - self.config_window.COMPACT_MODE_SWITCH_BOX_BUTTON_HOVERED_COLOR = self.DARK_300_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__OPTIONMENU_CLICKED_BG_COLOR = self.DARK_950_COLOR - self.config_window.SB__DROPDOWN_MENU_WINDOW_BG_COLOR = self.config_window.MAIN_BG_COLOR - self.config_window.SB__DROPDOWN_MENU_WINDOW_BORDER_COLOR = self.DARK_600_COLOR - # self.config_window.SB__DROPDOWN_MENU_WINDOW_BG_COLOR = self.DARK_700_COLOR - self.config_window.SB__DROPDOWN_MENU_BG_COLOR = self.DARK_875_COLOR - self.config_window.SB__DROPDOWN_MENU_HOVERED_BG_COLOR = self.DARK_800_COLOR - self.config_window.SB__DROPDOWN_MENU_CLICKED_BG_COLOR = self.DARK_900_COLOR - - self.config_window.SB__SLIDER_BG_COLOR = self.DARK_700_COLOR - self.config_window.SB__SLIDER_PROGRESS_BG_COLOR = self.DARK_500_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.DARK_800_COLOR - self.config_window.SB__SWITCH_BOX_ACTIVE_BG_COLOR = self.PRIMARY_500_COLOR - self.config_window.SB__SWITCH_BOX_BUTTON_COLOR = self.DARK_400_COLOR - self.config_window.SB__SWITCH_BOX_BUTTON_HOVERED_COLOR = self.DARK_350_COLOR - - self.config_window.SB__CHECKBOX_BORDER_COLOR = self.DARK_600_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__ENTRY_TEXT_COLOR = self.DARK_300_COLOR - self.config_window.SB__ENTRY_BG_COLOR = self.DARK_863_COLOR - self.config_window.SB__ENTRY_BORDER_COLOR = self.DARK_775_COLOR - - - self.config_window.SB__PROGRESSBAR_X_SLIDER__PROGRESSBAR_BG_COLOR = self.DARK_800_COLOR - self.config_window.SB__PROGRESSBAR_X_SLIDER__PROGRESSBAR_PROGRESS_BG_COLOR = self.PRIMARY_400_COLOR - - self.config_window.SB__PROGRESSBAR_X_SLIDER__SLIDER_BUTTON_COLOR = self.PRIMARY_600_COLOR - self.config_window.SB__PROGRESSBAR_X_SLIDER__SLIDER_BUTTON_HOVERED_COLOR = self.PRIMARY_400_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_600_COLOR - self.config_window.SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_HOVERED_COLOR = self.PRIMARY_500_COLOR - self.config_window.SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_CLICKED_COLOR = self.PRIMARY_800_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_750_COLOR - self.config_window.SIDE_MENU_LABELS_SELECTED_TEXT_COLOR = self.PRIMARY_200_COLOR - - self.config_window.SIDE_MENU_SELECTED_MARK_ACTIVE_BG_COLOR = self.main.SF__SWITCH_BOX_ACTIVE_BG_COLOR - - self.config_window.NOW_VERSION_TEXT_COLOR = self.DARK_300_COLOR - - # Error Message Window for Config Window - # The color code [#bb4448] is a mixture of [#a9555c] and [#cc3333] (for a redder shade). - self.config_window.SB__ERROR_MESSAGE_BG_COLOR = "#bb4448" - self.config_window.SB__ERROR_MESSAGE_TEXT_COLOR = "#fff" - - - - - - - - - - # 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_600_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_400_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_350_COLOR - - # # Sidebar Features - # self.main.SF__BG_COLOR = self.LIGHT_375_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.SLS__TITLE_TEXT_COLOR = self.LIGHT_800_COLOR - - # self.main.SLS__BG_COLOR = self.LIGHT_300_COLOR - - # self.main.SLS__PRESETS_TAB_BG_HOVERED_COLOR = self.LIGHT_350_COLOR - # self.main.SLS__PRESETS_TAB_BG_CLICKED_COLOR = self.LIGHT_800_COLOR - # self.main.SLS__PRESETS_TAB_BG_PASSIVE_COLOR = self.main.SIDEBAR_BG_COLOR - # self.main.SLS__PRESETS_TAB_BG_ACTIVE_COLOR = self.main.SLS__BG_COLOR - # self.main.SLS__PRESETS_TAB_ACTIVE_TEXT_COLOR_PASSIVE = self.LIGHT_600_COLOR - # self.main.SLS__PRESETS_TAB_ACTIVE_TEXT_COLOR = self.main.BASIC_TEXT_COLOR - - # self.main.SLS__BOX_BG_COLOR = self.LIGHT_350_COLOR - # self.main.SLS__BOX_SECTION_TITLE_TEXT_COLOR = self.LIGHT_800_COLOR - # self.main.SLS__BOX_ARROWS_TEXT_COLOR = self.LIGHT_700_COLOR - - # self.main.SLS__OPTIONMENU_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_875_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 + return d1 diff --git a/vrct_gui/ui_managers/ImageFileManager.py b/vrct_gui/ui_managers/ImageFileManager.py deleted file mode 100644 index 8bb71b4a..00000000 --- a/vrct_gui/ui_managers/ImageFileManager.py +++ /dev/null @@ -1,58 +0,0 @@ -from ..ui_utils import getImageFileFromUiUtils - - -class ImageFileManager(): - def __init__(self, theme:str ="Dark"): - if theme == "Dark": - self._createDarkModeImages() - elif theme == "Light": - self._createLightModeImages() - - - def _createDarkModeImages(self): - self.VRCT_LOGO = getImageFileFromUiUtils("vrct_logo_for_dark_mode.png") - self.VRCT_LOGO_MARK = getImageFileFromUiUtils("vrct_logo_mark_white.png") - - self.TRANSLATION_ICON = getImageFileFromUiUtils("translation_icon_white.png") - self.TRANSLATION_ICON_DISABLED = getImageFileFromUiUtils("translation_icon_disabled.png") - self.MIC_ICON = getImageFileFromUiUtils("mic_icon_white.png") - self.MIC_ICON_DISABLED = getImageFileFromUiUtils("mic_icon_disabled.png") - self.HEADPHONES_ICON = getImageFileFromUiUtils("headphones_icon_white.png") - self.HEADPHONES_ICON_DISABLED = getImageFileFromUiUtils("headphones_icon_disabled.png") - self.FOREGROUND_ICON = getImageFileFromUiUtils("foreground_icon_white.png") - self.FOREGROUND_ICON_DISABLED = getImageFileFromUiUtils("foreground_icon_disabled.png") - - self.NARROW_ARROW_DOWN = getImageFileFromUiUtils("narrow_arrow_down.png") - - self.CONFIGURATION_ICON = getImageFileFromUiUtils("configuration_icon_white.png") - self.CONFIGURATION_ICON_DISABLED = getImageFileFromUiUtils("configuration_icon_disabled.png") - - self.ARROW_LEFT = getImageFileFromUiUtils("arrow_left_white.png") - self.ARROW_LEFT_DISABLED = getImageFileFromUiUtils("arrow_left_disabled.png") - - self.REFRESH_ICON = getImageFileFromUiUtils("refresh_icon.png") - self.HELP_ICON = getImageFileFromUiUtils("help_icon_white.png") - - def _createLightModeImages(self): - self.VRCT_LOGO = getImageFileFromUiUtils("vrct_logo_for_light_mode.png") - self.VRCT_LOGO_MARK = getImageFileFromUiUtils("vrct_logo_mark_black.png") - - - self.TRANSLATION_ICON = getImageFileFromUiUtils("translation_icon_white.png") - self.TRANSLATION_ICON_DISABLED = getImageFileFromUiUtils("translation_icon_disabled.png") - self.MIC_ICON = getImageFileFromUiUtils("mic_icon_white.png") - self.MIC_ICON_DISABLED = getImageFileFromUiUtils("mic_icon_disabled.png") - self.HEADPHONES_ICON = getImageFileFromUiUtils("headphones_icon_white.png") - self.HEADPHONES_ICON_DISABLED = getImageFileFromUiUtils("headphones_icon_disabled.png") - self.FOREGROUND_ICON = getImageFileFromUiUtils("foreground_icon_white.png") - self.FOREGROUND_ICON_DISABLED = getImageFileFromUiUtils("foreground_icon_disabled.png") - - self.NARROW_ARROW_DOWN = getImageFileFromUiUtils("narrow_arrow_down.png") - - self.CONFIGURATION_ICON = getImageFileFromUiUtils("configuration_icon_white.png") - self.CONFIGURATION_ICON_DISABLED = getImageFileFromUiUtils("configuration_icon_disabled.png") - - self.ARROW_LEFT = getImageFileFromUiUtils("arrow_left_white.png") - self.ARROW_LEFT_DISABLED = getImageFileFromUiUtils("arrow_left_disabled.png") - - self.HELP_ICON = getImageFileFromUiUtils("help_icon_white.png") \ No newline at end of file diff --git a/vrct_gui/ui_managers/Themes/__init__.py b/vrct_gui/ui_managers/Themes/__init__.py new file mode 100644 index 00000000..fb61579d --- /dev/null +++ b/vrct_gui/ui_managers/Themes/__init__.py @@ -0,0 +1,2 @@ +from ._darkTheme import _darkTheme +from ._lightTheme import _lightTheme \ No newline at end of file diff --git a/vrct_gui/ui_managers/Themes/_darkTheme.py b/vrct_gui/ui_managers/Themes/_darkTheme.py new file mode 100644 index 00000000..ed3c7cd8 --- /dev/null +++ b/vrct_gui/ui_managers/Themes/_darkTheme.py @@ -0,0 +1,314 @@ +from types import SimpleNamespace +from ...ui_utils import getImageFileFromUiUtils + +def _darkTheme(base_color): + theme_settings = SimpleNamespace( + main = SimpleNamespace( + # Common + BASIC_TEXT_COLOR = base_color.DARK_BASIC_TEXT_COLOR, + LABELS_TEXT_COLOR = base_color.DARK_BASIC_TEXT_COLOR, + + # Main + MAIN_BG_COLOR = base_color.DARK_888_COLOR, + + + TEXTBOX_BG_COLOR = base_color.DARK_900_COLOR, + TEXTBOX_TEXT_COLOR = base_color.DARK_BASIC_TEXT_COLOR, + TEXTBOX_TEXT_SUB_COLOR = base_color.DARK_450_COLOR, + TEXTBOX_SYSTEM_TAG_TEXT_COLOR = base_color.PRIMARY_300_COLOR, + TEXTBOX_SENT_TAG_TEXT_COLOR = base_color.SENT_400_COLOR, + TEXTBOX_RECEIVED_TAG_TEXT_COLOR = base_color.RECEIVED_300_COLOR, + # TEXTBOX_ERROR_TAG_TEXT_COLOR = "#c27583", + TEXTBOX_TIMESTAMP_TEXT_COLOR = base_color.DARK_600_COLOR, + + TEXTBOX_TAB_BG_PASSIVE_COLOR = base_color.DARK_850_COLOR, + TEXTBOX_TAB_BG_ACTIVE_COLOR = base_color.DARK_900_COLOR, + TEXTBOX_TAB_BG_HOVERED_COLOR = base_color.DARK_800_COLOR, + TEXTBOX_TAB_BG_CLICKED_COLOR = base_color.DARK_925_COLOR, + TEXTBOX_TAB_TEXT_ACTIVE_COLOR = base_color.DARK_BASIC_TEXT_COLOR, + TEXTBOX_TAB_TEXT_PASSIVE_COLOR = base_color.DARK_500_COLOR, + + TEXTBOX_ENTRY_TEXT_COLOR = base_color.DARK_300_COLOR, + TEXTBOX_ENTRY_TEXT_DISABLED_COLOR = base_color.DARK_500_COLOR, + TEXTBOX_ENTRY_BG_COLOR = base_color.DARK_875_COLOR, + TEXTBOX_ENTRY_BORDER_COLOR = base_color.DARK_750_COLOR, + TEXTBOX_ENTRY_PLACEHOLDER_COLOR = base_color.DARK_500_COLOR, + TEXTBOX_ENTRY_PLACEHOLDER_DISABLED_COLOR = base_color.DARK_700_COLOR, + + + # Sidebar + SIDEBAR_BG_COLOR = base_color.DARK_850_COLOR, + + # Sidebar Features + SF__BG_COLOR = base_color.DARK_825_COLOR, + SF__HOVERED_BG_COLOR = base_color.DARK_800_COLOR, + SF__CLICKED_BG_COLOR = base_color.DARK_875_COLOR, + SF__TEXT_DISABLED_COLOR = base_color.DARK_500_COLOR, + + SF__SWITCH_BOX_BG_COLOR = base_color.DARK_775_COLOR, + SF__SWITCH_BOX_HOVERED_BG_COLOR = base_color.DARK_725_COLOR, + SF__SWITCH_BOX_CLICKED_BG_COLOR = base_color.DARK_825_COLOR, + SF__SWITCH_BOX_ACTIVE_BG_COLOR = base_color.PRIMARY_500_COLOR, + SF__SWITCH_BOX_ACTIVE_HOVERED_BG_COLOR = base_color.PRIMARY_400_COLOR, + SF__SWITCH_BOX_ACTIVE_CLICKED_BG_COLOR = base_color.PRIMARY_700_COLOR, + SF__SWITCH_BOX_DISABLE_BG_COLOR = base_color.PRIMARY_800_COLOR, + + SF__SWITCH_BOX_BUTTON_COLOR = base_color.DARK_400_COLOR, + # It's not working because It overrode internally. + SF__SWITCH_BOX_BUTTON_HOVERED_COLOR = base_color.DARK_350_COLOR, + + SF__SELECTED_MARK_ACTIVE_BG_COLOR = base_color.PRIMARY_500_COLOR, + SF__SELECTED_MARK_ACTIVE_HOVERED_BG_COLOR = base_color.PRIMARY_400_COLOR, + SF__SELECTED_MARK_ACTIVE_CLICKED_BG_COLOR = base_color.PRIMARY_700_COLOR, + SF__SELECTED_MARK_DISABLE_BG_COLOR = base_color.PRIMARY_800_COLOR, + + + # Sidebar Languages Settings + SLS__TITLE_TEXT_COLOR = base_color.DARK_400_COLOR, + + SLS__BG_COLOR = base_color.DARK_800_COLOR, + + SLS__PRESETS_TAB_BG_HOVERED_COLOR = base_color.DARK_825_COLOR, + SLS__PRESETS_TAB_BG_CLICKED_COLOR = base_color.DARK_875_COLOR, + SLS__PRESETS_TAB_BG_PASSIVE_COLOR = base_color.DARK_850_COLOR, + SLS__PRESETS_TAB_BG_ACTIVE_COLOR = base_color.DARK_800_COLOR, + SLS__PRESETS_TAB_ACTIVE_TEXT_COLOR_PASSIVE = base_color.DARK_600_COLOR, + SLS__PRESETS_TAB_ACTIVE_TEXT_COLOR = base_color.DARK_BASIC_TEXT_COLOR, + + SLS__BOX_BG_COLOR = base_color.DARK_825_COLOR, + SLS__BOX_SECTION_TITLE_TEXT_COLOR = base_color.DARK_400_COLOR, + SLS__BOX_ARROWS_TEXT_COLOR = base_color.DARK_500_COLOR, + SLS__BOX_ARROWS_SWAP_BUTTON_TEXT_COLOR = base_color.DARK_BASIC_TEXT_COLOR, + SLS__BOX_ARROWS_SWAP_BUTTON_HOVERED_COLOR = base_color.DARK_750_COLOR, + SLS__BOX_ARROWS_SWAP_BUTTON_CLICKED_COLOR = base_color.DARK_850_COLOR, + + SLS__OPTIONMENU_BG_COLOR = base_color.DARK_888_COLOR, + SLS__OPTIONMENU_HOVERED_BG_COLOR = base_color.DARK_875_COLOR, + SLS__OPTIONMENU_CLICKED_BG_COLOR = base_color.DARK_900_COLOR, + + + CONFIG_BUTTON_BG_COLOR = base_color.DARK_850_COLOR, + CONFIG_BUTTON_HOVERED_BG_COLOR = base_color.DARK_800_COLOR, + CONFIG_BUTTON_CLICKED_BG_COLOR = base_color.DARK_875_COLOR, + + MINIMIZE_SIDEBAR_BUTTON_BG_COLOR = base_color.DARK_850_COLOR, + MINIMIZE_SIDEBAR_BUTTON_HOVERED_BG_COLOR = base_color.DARK_800_COLOR, + MINIMIZE_SIDEBAR_BUTTON_CLICKED_BG_COLOR = base_color.DARK_900_COLOR, + + + + TOP_BAR_BUTTON_BG_COLOR = base_color.DARK_888_COLOR, + TOP_BAR_BUTTON_HOVERED_BG_COLOR = base_color.DARK_850_COLOR, + TOP_BAR_BUTTON_CLICKED_BG_COLOR = base_color.DARK_900_COLOR, + + UPDATE_AVAILABLE_BUTTON_BG_COLOR = base_color.DARK_888_COLOR, + UPDATE_AVAILABLE_BUTTON_HOVERED_BG_COLOR = base_color.DARK_850_COLOR, + UPDATE_AVAILABLE_BUTTON_CLICKED_BG_COLOR = base_color.DARK_900_COLOR, + UPDATE_AVAILABLE_BUTTON_TEXT_COLOR = base_color.PRIMARY_300_COLOR, + + HELP_AND_INFO_BUTTON_BG_COLOR = base_color.DARK_888_COLOR, + HELP_AND_INFO_BUTTON_HOVERED_BG_COLOR = base_color.DARK_850_COLOR, + HELP_AND_INFO_BUTTON_CLICKED_BG_COLOR = base_color.DARK_900_COLOR, + ), + + + selectable_language_window = SimpleNamespace( + # Selectable Language Window + BASIC_TEXT_COLOR = base_color.DARK_BASIC_TEXT_COLOR, + + MAIN_BG_COLOR = base_color.DARK_875_COLOR, + + GO_BACK_BUTTON_BG_COLOR = base_color.DARK_800_COLOR, + GO_BACK_BUTTON_BG_HOVERED_COLOR = base_color.DARK_750_COLOR, + GO_BACK_BUTTON_BG_CLICKED_COLOR = base_color.DARK_875_COLOR, + + TOP_BG_COLOR = base_color.DARK_850_COLOR, + TITLE_TEXT_COLOR = base_color.DARK_400_COLOR, + LANGUAGE_BUTTON_BG_COLOR = base_color.DARK_875_COLOR, + LANGUAGE_BUTTON_BG_HOVERED_COLOR = base_color.DARK_825_COLOR, + LANGUAGE_BUTTON_BG_CLICKED_COLOR = base_color.DARK_888_COLOR, + ), + + + + # Modal Window (Main Window) + main_window_cover = SimpleNamespace( + TEXT_COLOR = base_color.DARK_BASIC_TEXT_COLOR, + BG_COLOR = "#000", + ), + + + confirmation_modal = SimpleNamespace( + MESSAGE_TEXT_COLOR = base_color.DARK_BASIC_TEXT_COLOR, + FAKE_BORDER_COLOR = base_color.DARK_600_COLOR, + BG_COLOR = base_color.DARK_800_COLOR, + CONFIRMATION_BUTTONS_TEXT_COLOR = base_color.DARK_BASIC_TEXT_COLOR, + + ACCEPT_BUTTON_BG_COLOR = base_color.PRIMARY_600_COLOR, + ACCEPT_BUTTON_HOVERED_BG_COLOR = base_color.PRIMARY_450_COLOR, + ACCEPT_BUTTON_CLICKED_BG_COLOR = base_color.PRIMARY_750_COLOR, + DENY_BUTTON_BG_COLOR = base_color.DARK_750_COLOR, + DENY_BUTTON_HOVERED_BG_COLOR = base_color.DARK_700_COLOR, + DENY_BUTTON_CLICKED_BG_COLOR = base_color.DARK_825_COLOR, + ), + + + config_window = SimpleNamespace( + # Common + BASIC_TEXT_COLOR = base_color.DARK_BASIC_TEXT_COLOR, + LABELS_TEXT_COLOR = base_color.DARK_BASIC_TEXT_COLOR, + LABELS_DESC_TEXT_COLOR = base_color.DARK_500_COLOR, + + LABELS_TEXT_DISABLED_COLOR = base_color.DARK_600_COLOR, + + SB__BUTTON_COLOR = base_color.DARK_888_COLOR, + SB__BUTTON_HOVERED_COLOR = base_color.DARK_800_COLOR, + SB__BUTTON_CLICKED_COLOR = base_color.DARK_900_COLOR, + + + # Top bar + TOP_BAR_BG_COLOR = base_color.DARK_850_COLOR, + + # Restart Button + RESTART_BUTTON_BG_COLOR = base_color.PRIMARY_600_COLOR, + RESTART_BUTTON_HOVERED_BG_COLOR = base_color.PRIMARY_500_COLOR, + RESTART_BUTTON_CLICKED_BG_COLOR = base_color.PRIMARY_700_COLOR, + + + # Compact Mode + COMPACT_MODE_SWITCH_BOX_BG_COLOR = base_color.DARK_775_COLOR, + COMPACT_MODE_SWITCH_BOX_ACTIVE_BG_COLOR = base_color.PRIMARY_500_COLOR, + COMPACT_MODE_SWITCH_BOX_BUTTON_COLOR = base_color.DARK_350_COLOR, + COMPACT_MODE_SWITCH_BOX_BUTTON_HOVERED_COLOR = base_color.DARK_300_COLOR, + + # Main + MAIN_BG_COLOR = base_color.DARK_950_COLOR, + + # This is for fake border color + SB__WRAPPER_BG_COLOR = base_color.DARK_750_COLOR, + + SB__BG_COLOR = base_color.DARK_888_COLOR, + + SB__OPTIONMENU_BG_COLOR = base_color.DARK_925_COLOR, + SB__OPTIONMENU_HOVERED_BG_COLOR = base_color.DARK_850_COLOR, + SB__OPTIONMENU_CLICKED_BG_COLOR = base_color.DARK_950_COLOR, + SB__DROPDOWN_MENU_WINDOW_BG_COLOR = base_color.DARK_950_COLOR, + SB__DROPDOWN_MENU_WINDOW_BORDER_COLOR = base_color.DARK_600_COLOR, + SB__DROPDOWN_MENU_BG_COLOR = base_color.DARK_875_COLOR, + SB__DROPDOWN_MENU_HOVERED_BG_COLOR = base_color.DARK_800_COLOR, + SB__DROPDOWN_MENU_CLICKED_BG_COLOR = base_color.DARK_900_COLOR, + + SB__SLIDER_BG_COLOR = base_color.DARK_700_COLOR, + SB__SLIDER_PROGRESS_BG_COLOR = base_color.DARK_500_COLOR, + SB__SLIDER_BUTTON_COLOR = base_color.DARK_700_COLOR, + SB__SLIDER_BUTTON_HOVERED_COLOR = base_color.DARK_600_COLOR, + SB__SLIDER_TOOLTIP_BG_COLOR = base_color.DARK_850_COLOR, + SB__SLIDER_TOOLTIP_TEXT_COLOR = base_color.DARK_200_COLOR, + + SB__SWITCH_BOX_BG_COLOR = base_color.DARK_800_COLOR, + SB__SWITCH_BOX_ACTIVE_BG_COLOR = base_color.PRIMARY_500_COLOR, + SB__SWITCH_BOX_BUTTON_COLOR = base_color.DARK_400_COLOR, + SB__SWITCH_BOX_BUTTON_HOVERED_COLOR = base_color.DARK_350_COLOR, + + SB__CHECKBOX_BORDER_COLOR = base_color.DARK_600_COLOR, + SB__CHECKBOX_HOVER_COLOR = base_color.DARK_800_COLOR, + SB__CHECKBOX_CHECKED_COLOR = base_color.PRIMARY_700_COLOR, + SB__CHECKBOX_CHECKMARK_COLOR = base_color.DARK_BASIC_TEXT_COLOR, + + SB__ENTRY_TEXT_COLOR = base_color.DARK_300_COLOR, + SB__ENTRY_BG_COLOR = base_color.DARK_863_COLOR, + SB__ENTRY_BORDER_COLOR = base_color.DARK_775_COLOR, + + + SB__PROGRESSBAR_X_SLIDER__PROGRESSBAR_BG_COLOR = base_color.DARK_800_COLOR, + SB__PROGRESSBAR_X_SLIDER__PROGRESSBAR_PROGRESS_BG_COLOR = base_color.PRIMARY_750_COLOR, + SB__PROGRESSBAR_X_SLIDER__PROGRESSBAR_PROGRESS_EXCEED_THRESHOLD_BG_COLOR = base_color.PRIMARY_400_COLOR, + + SB__PROGRESSBAR_X_SLIDER__SLIDER_BUTTON_COLOR = base_color.PRIMARY_600_COLOR, + SB__PROGRESSBAR_X_SLIDER__SLIDER_BUTTON_HOVERED_COLOR = base_color.PRIMARY_400_COLOR, + + SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_COLOR = base_color.DARK_800_COLOR, + SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_HOVERED_COLOR = base_color.DARK_700_COLOR, + SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_CLICKED_COLOR = base_color.DARK_900_COLOR, + SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_DISABLED_COLOR = base_color.DARK_850_COLOR, + + SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_COLOR = base_color.PRIMARY_600_COLOR, + SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_HOVERED_COLOR = base_color.PRIMARY_500_COLOR, + SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_CLICKED_COLOR = base_color.PRIMARY_800_COLOR, + + SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_COLOR = base_color.PRIMARY_600_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_HOVERED_COLOR = base_color.PRIMARY_500_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_CLICKED_COLOR = base_color.PRIMARY_700_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST_BG_COLOR = base_color.DARK_800_COLOR, + + SB__ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_HOVERED_BG_COLOR = base_color.DARK_750_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_CLICKED_BG_COLOR = base_color.DARK_850_COLOR, + + SB__ADD_AND_DELETE_ABLE_LIST_DELETED_BG_COLOR = base_color.DARK_850_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST__VALUES_DELETED_BUTTON_HOVERED_BG_COLOR = base_color.DARK_800_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST__VALUES_DELETED_BUTTON_CLICKED_BG_COLOR = base_color.DARK_900_COLOR, + + + SB__MESSAGE_FORMAT__EXAMPLE_BG_COLOR = "#3a4554", # from VRChat' chat display color + SB__MESSAGE_FORMAT__EXAMPLE_TEXT_COLOR = base_color.DARK_100_COLOR, + SB__MESSAGE_FORMAT__SWAP_BUTTON_COLOR = base_color.DARK_875_COLOR, + SB__MESSAGE_FORMAT__SWAP_BUTTON_HOVERED_COLOR = base_color.DARK_800_COLOR, + SB__MESSAGE_FORMAT__SWAP_BUTTON_CLICKED_COLOR = base_color.DARK_888_COLOR, + + + + + # Side menu + SIDE_MENU_BG_COLOR = base_color.DARK_950_COLOR, + + SIDE_MENU_LABELS_BG_COLOR = base_color.DARK_950_COLOR, + SIDE_MENU_LABELS_BG_FOR_FAKE_BORDER_COLOR = base_color.DARK_950_COLOR, + SIDE_MENU_LABELS_HOVERED_BG_COLOR = base_color.DARK_850_COLOR, + SIDE_MENU_LABELS_CLICKED_BG_COLOR = base_color.PRIMARY_750_COLOR, + SIDE_MENU_LABELS_SELECTED_TEXT_COLOR = base_color.PRIMARY_200_COLOR, + + SIDE_MENU_SELECTED_MARK_ACTIVE_BG_COLOR = base_color.PRIMARY_500_COLOR, + + NOW_VERSION_TEXT_COLOR = base_color.DARK_300_COLOR, + + # Error Message Window for Config Window + # The color code [#bb4448] is a mixture of [#a9555c] and [#cc3333] (for a redder shade). + SB__ERROR_MESSAGE_BG_COLOR = "#bb4448", + SB__ERROR_MESSAGE_TEXT_COLOR = "#fff", + ), + + + + image_file = SimpleNamespace( + VRCT_LOGO = getImageFileFromUiUtils("vrct_logo_for_dark_mode.png"), + VRCT_LOGO_MARK = getImageFileFromUiUtils("vrct_logo_mark_white.png"), + + TRANSLATION_ICON = getImageFileFromUiUtils("translation_icon_white.png"), + TRANSLATION_ICON_DISABLED = getImageFileFromUiUtils("translation_icon_disabled.png"), + MIC_ICON = getImageFileFromUiUtils("mic_icon_white.png"), + MIC_ICON_DISABLED = getImageFileFromUiUtils("mic_icon_disabled.png"), + HEADPHONES_ICON = getImageFileFromUiUtils("headphones_icon_white.png"), + HEADPHONES_ICON_DISABLED = getImageFileFromUiUtils("headphones_icon_disabled.png"), + FOREGROUND_ICON = getImageFileFromUiUtils("foreground_icon_white.png"), + FOREGROUND_ICON_DISABLED = getImageFileFromUiUtils("foreground_icon_disabled.png"), + + NARROW_ARROW_DOWN = getImageFileFromUiUtils("narrow_arrow_down_white.png"), + + CONFIGURATION_ICON = getImageFileFromUiUtils("configuration_icon_white.png"), + CONFIGURATION_ICON_DISABLED = getImageFileFromUiUtils("configuration_icon_disabled.png"), + + ARROW_LEFT = getImageFileFromUiUtils("arrow_left_white.png"), + ARROW_LEFT_DISABLED = getImageFileFromUiUtils("arrow_left_disabled.png"), + + REFRESH_UPDATE_ICON = getImageFileFromUiUtils("refresh_update_icon.png"), + REFRESH_ICON = getImageFileFromUiUtils("refresh_icon.png"), + HELP_ICON = getImageFileFromUiUtils("help_icon_white.png"), + + CANCEL_ICON = getImageFileFromUiUtils("cancel_icon.png"), + REDO_ICON = getImageFileFromUiUtils("redo_icon_white.png"), + SWAP_ICON = getImageFileFromUiUtils("swap_icon_white.png"), + FOLDER_OPEN_ICON = getImageFileFromUiUtils("folder_open_icon_white.png"), + ), + ) + + return theme_settings \ No newline at end of file diff --git a/vrct_gui/ui_managers/Themes/_lightTheme.py b/vrct_gui/ui_managers/Themes/_lightTheme.py new file mode 100644 index 00000000..95accf92 --- /dev/null +++ b/vrct_gui/ui_managers/Themes/_lightTheme.py @@ -0,0 +1,308 @@ +from types import SimpleNamespace +from ...ui_utils import getImageFileFromUiUtils + +def _lightTheme(base_color): + theme_settings = SimpleNamespace( + main = SimpleNamespace( + # Common + BASIC_TEXT_COLOR = base_color.LIGHT_BASIC_TEXT_COLOR, + LABELS_TEXT_COLOR = base_color.LIGHT_BASIC_TEXT_COLOR, + + # Main + MAIN_BG_COLOR = base_color.LIGHT_175_COLOR, + + + TEXTBOX_BG_COLOR = base_color.LIGHT_100_COLOR, + TEXTBOX_TEXT_COLOR = base_color.LIGHT_BASIC_TEXT_COLOR, + TEXTBOX_TEXT_SUB_COLOR = base_color.LIGHT_600_COLOR, + TEXTBOX_SYSTEM_TAG_TEXT_COLOR = base_color.PRIMARY_300_COLOR, + TEXTBOX_SENT_TAG_TEXT_COLOR = base_color.SENT_400_COLOR, + TEXTBOX_RECEIVED_TAG_TEXT_COLOR = base_color.RECEIVED_300_COLOR, + # TEXTBOX_ERROR_TAG_TEXT_COLOR = "#c27583", + TEXTBOX_TIMESTAMP_TEXT_COLOR = base_color.LIGHT_500_COLOR, + + TEXTBOX_TAB_BG_PASSIVE_COLOR = base_color.LIGHT_300_COLOR, + TEXTBOX_TAB_BG_ACTIVE_COLOR = base_color.LIGHT_125_COLOR, + TEXTBOX_TAB_BG_HOVERED_COLOR = base_color.LIGHT_250_COLOR, + TEXTBOX_TAB_BG_CLICKED_COLOR = base_color.LIGHT_100_COLOR, + TEXTBOX_TAB_TEXT_ACTIVE_COLOR = base_color.LIGHT_BASIC_TEXT_COLOR, + TEXTBOX_TAB_TEXT_PASSIVE_COLOR = base_color.LIGHT_600_COLOR, + + TEXTBOX_ENTRY_TEXT_COLOR = base_color.LIGHT_800_COLOR, + TEXTBOX_ENTRY_TEXT_DISABLED_COLOR = base_color.LIGHT_500_COLOR, + TEXTBOX_ENTRY_BG_COLOR = base_color.LIGHT_250_COLOR, + TEXTBOX_ENTRY_BORDER_COLOR = base_color.LIGHT_400_COLOR, + TEXTBOX_ENTRY_PLACEHOLDER_COLOR = base_color.LIGHT_600_COLOR, + TEXTBOX_ENTRY_PLACEHOLDER_DISABLED_COLOR = base_color.LIGHT_400_COLOR, + + + # Sidebar + SIDEBAR_BG_COLOR = base_color.LIGHT_250_COLOR, + + # Sidebar Features + SF__BG_COLOR = base_color.LIGHT_313_COLOR, + SF__HOVERED_BG_COLOR = base_color.LIGHT_333_COLOR, + SF__CLICKED_BG_COLOR = base_color.LIGHT_400_COLOR, + SF__TEXT_DISABLED_COLOR = base_color.LIGHT_600_COLOR, + + SF__SWITCH_BOX_BG_COLOR = base_color.LIGHT_375_COLOR, + SF__SWITCH_BOX_HOVERED_BG_COLOR = base_color.LIGHT_400_COLOR, + SF__SWITCH_BOX_CLICKED_BG_COLOR = base_color.LIGHT_450_COLOR, + SF__SWITCH_BOX_ACTIVE_BG_COLOR = base_color.PRIMARY_350_COLOR, + SF__SWITCH_BOX_ACTIVE_HOVERED_BG_COLOR = base_color.PRIMARY_400_COLOR, + SF__SWITCH_BOX_ACTIVE_CLICKED_BG_COLOR = base_color.PRIMARY_500_COLOR, + SF__SWITCH_BOX_DISABLE_BG_COLOR = base_color.PRIMARY_200_COLOR, + + SF__SWITCH_BOX_BUTTON_COLOR = base_color.LIGHT_150_COLOR, + # It's not working because It overrode internally. + SF__SWITCH_BOX_BUTTON_HOVERED_COLOR = base_color.LIGHT_300_COLOR, + + SF__SELECTED_MARK_ACTIVE_BG_COLOR = base_color.PRIMARY_350_COLOR, + SF__SELECTED_MARK_ACTIVE_HOVERED_BG_COLOR = base_color.PRIMARY_400_COLOR, + SF__SELECTED_MARK_ACTIVE_CLICKED_BG_COLOR = base_color.PRIMARY_500_COLOR, + SF__SELECTED_MARK_DISABLE_BG_COLOR = base_color.PRIMARY_200_COLOR, + + + # Sidebar Languages Settings + SLS__TITLE_TEXT_COLOR = base_color.LIGHT_800_COLOR, + + SLS__BG_COLOR = base_color.LIGHT_313_COLOR, + + SLS__PRESETS_TAB_BG_HOVERED_COLOR = base_color.LIGHT_300_COLOR, + SLS__PRESETS_TAB_BG_CLICKED_COLOR = base_color.LIGHT_350_COLOR, + SLS__PRESETS_TAB_BG_PASSIVE_COLOR = base_color.LIGHT_250_COLOR, + SLS__PRESETS_TAB_BG_ACTIVE_COLOR = base_color.LIGHT_313_COLOR, + SLS__PRESETS_TAB_ACTIVE_TEXT_COLOR_PASSIVE = base_color.LIGHT_400_COLOR, + SLS__PRESETS_TAB_ACTIVE_TEXT_COLOR = base_color.LIGHT_BASIC_TEXT_COLOR, + + SLS__BOX_BG_COLOR = base_color.LIGHT_333_COLOR, + SLS__BOX_SECTION_TITLE_TEXT_COLOR = base_color.LIGHT_800_COLOR, + SLS__BOX_ARROWS_TEXT_COLOR = base_color.LIGHT_700_COLOR, + SLS__BOX_ARROWS_SWAP_BUTTON_TEXT_COLOR = base_color.LIGHT_BASIC_TEXT_COLOR, + SLS__BOX_ARROWS_SWAP_BUTTON_HOVERED_COLOR = base_color.LIGHT_200_COLOR, + SLS__BOX_ARROWS_SWAP_BUTTON_CLICKED_COLOR = base_color.LIGHT_350_COLOR, + + SLS__OPTIONMENU_BG_COLOR = base_color.LIGHT_200_COLOR, + SLS__OPTIONMENU_HOVERED_BG_COLOR = base_color.LIGHT_250_COLOR, + SLS__OPTIONMENU_CLICKED_BG_COLOR = base_color.LIGHT_400_COLOR, + + + CONFIG_BUTTON_BG_COLOR = base_color.LIGHT_250_COLOR, + CONFIG_BUTTON_HOVERED_BG_COLOR = base_color.LIGHT_350_COLOR, + CONFIG_BUTTON_CLICKED_BG_COLOR = base_color.LIGHT_400_COLOR, + + MINIMIZE_SIDEBAR_BUTTON_BG_COLOR = base_color.LIGHT_250_COLOR, + MINIMIZE_SIDEBAR_BUTTON_HOVERED_BG_COLOR = base_color.LIGHT_350_COLOR, + MINIMIZE_SIDEBAR_BUTTON_CLICKED_BG_COLOR = base_color.LIGHT_400_COLOR, + + + + TOP_BAR_BUTTON_BG_COLOR = base_color.LIGHT_175_COLOR, + TOP_BAR_BUTTON_HOVERED_BG_COLOR = base_color.LIGHT_300_COLOR, + TOP_BAR_BUTTON_CLICKED_BG_COLOR = base_color.LIGHT_350_COLOR, + + UPDATE_AVAILABLE_BUTTON_TEXT_COLOR = base_color.PRIMARY_400_COLOR, + ), + + + selectable_language_window = SimpleNamespace( + # Selectable Language Window + BASIC_TEXT_COLOR = base_color.LIGHT_BASIC_TEXT_COLOR, + + MAIN_BG_COLOR = base_color.LIGHT_175_COLOR, + + GO_BACK_BUTTON_BG_COLOR = base_color.LIGHT_325_COLOR, + GO_BACK_BUTTON_BG_HOVERED_COLOR = base_color.LIGHT_400_COLOR, + GO_BACK_BUTTON_BG_CLICKED_COLOR = base_color.LIGHT_500_COLOR, + + TOP_BG_COLOR = base_color.LIGHT_250_COLOR, + TITLE_TEXT_COLOR = base_color.LIGHT_700_COLOR, + LANGUAGE_BUTTON_BG_COLOR = base_color.LIGHT_175_COLOR, + LANGUAGE_BUTTON_BG_HOVERED_COLOR = base_color.LIGHT_275_COLOR, + LANGUAGE_BUTTON_BG_CLICKED_COLOR = base_color.LIGHT_325_COLOR, + ), + + + + # Modal Window (Main Window) + main_window_cover = SimpleNamespace( + TEXT_COLOR = base_color.LIGHT_BASIC_TEXT_COLOR, + BG_COLOR = "#fff", + ), + + + confirmation_modal = SimpleNamespace( + MESSAGE_TEXT_COLOR = base_color.LIGHT_BASIC_TEXT_COLOR, + FAKE_BORDER_COLOR = base_color.LIGHT_500_COLOR, + BG_COLOR = base_color.LIGHT_350_COLOR, + CONFIRMATION_BUTTONS_TEXT_COLOR = base_color.LIGHT_BASIC_TEXT_COLOR, + + ACCEPT_BUTTON_BG_COLOR = base_color.PRIMARY_250_COLOR, + ACCEPT_BUTTON_HOVERED_BG_COLOR = base_color.PRIMARY_200_COLOR, + ACCEPT_BUTTON_CLICKED_BG_COLOR = base_color.PRIMARY_300_COLOR, + DENY_BUTTON_BG_COLOR = base_color.LIGHT_200_COLOR, + DENY_BUTTON_HOVERED_BG_COLOR = base_color.LIGHT_100_COLOR, + DENY_BUTTON_CLICKED_BG_COLOR = base_color.LIGHT_300_COLOR, + ), + + + config_window = SimpleNamespace( + # Common + BASIC_TEXT_COLOR = base_color.LIGHT_BASIC_TEXT_COLOR, + LABELS_TEXT_COLOR = base_color.LIGHT_BASIC_TEXT_COLOR, + LABELS_DESC_TEXT_COLOR = base_color.LIGHT_600_COLOR, + + LABELS_TEXT_DISABLED_COLOR = base_color.LIGHT_500_COLOR, + + SB__BUTTON_COLOR = base_color.LIGHT_100_COLOR, + SB__BUTTON_HOVERED_COLOR = base_color.LIGHT_200_COLOR, + SB__BUTTON_CLICKED_COLOR = base_color.LIGHT_300_COLOR, + + + # Top bar + TOP_BAR_BG_COLOR = base_color.LIGHT_150_COLOR, + + # Restart Button + RESTART_BUTTON_BG_COLOR = base_color.PRIMARY_300_COLOR, + RESTART_BUTTON_HOVERED_BG_COLOR = base_color.PRIMARY_250_COLOR, + RESTART_BUTTON_CLICKED_BG_COLOR = base_color.PRIMARY_400_COLOR, + + + # Compact Mode + COMPACT_MODE_SWITCH_BOX_BG_COLOR = base_color.LIGHT_500_COLOR, + COMPACT_MODE_SWITCH_BOX_ACTIVE_BG_COLOR = base_color.PRIMARY_300_COLOR, + COMPACT_MODE_SWITCH_BOX_BUTTON_COLOR = base_color.LIGHT_300_COLOR, + COMPACT_MODE_SWITCH_BOX_BUTTON_HOVERED_COLOR = base_color.LIGHT_250_COLOR, + + # Main + MAIN_BG_COLOR = base_color.LIGHT_300_COLOR, + + # This is for fake border color + SB__WRAPPER_BG_COLOR = base_color.LIGHT_400_COLOR, + + SB__BG_COLOR = base_color.LIGHT_100_COLOR, + + SB__OPTIONMENU_BG_COLOR = base_color.LIGHT_300_COLOR, + SB__OPTIONMENU_HOVERED_BG_COLOR = base_color.LIGHT_250_COLOR, + SB__OPTIONMENU_CLICKED_BG_COLOR = base_color.LIGHT_350_COLOR, + SB__DROPDOWN_MENU_WINDOW_BG_COLOR = base_color.LIGHT_300_COLOR, + SB__DROPDOWN_MENU_WINDOW_BORDER_COLOR = base_color.LIGHT_800_COLOR, + SB__DROPDOWN_MENU_BG_COLOR = base_color.LIGHT_200_COLOR, + SB__DROPDOWN_MENU_HOVERED_BG_COLOR = base_color.LIGHT_100_COLOR, + SB__DROPDOWN_MENU_CLICKED_BG_COLOR = base_color.LIGHT_300_COLOR, + + SB__SLIDER_BG_COLOR = base_color.LIGHT_400_COLOR, + SB__SLIDER_PROGRESS_BG_COLOR = base_color.LIGHT_550_COLOR, + SB__SLIDER_BUTTON_COLOR = base_color.LIGHT_500_COLOR, + SB__SLIDER_BUTTON_HOVERED_COLOR = base_color.LIGHT_600_COLOR, + SB__SLIDER_TOOLTIP_BG_COLOR = base_color.LIGHT_200_COLOR, + SB__SLIDER_TOOLTIP_TEXT_COLOR = base_color.LIGHT_800_COLOR, + + SB__SWITCH_BOX_BG_COLOR = base_color.LIGHT_400_COLOR, + SB__SWITCH_BOX_ACTIVE_BG_COLOR = base_color.PRIMARY_300_COLOR, + SB__SWITCH_BOX_BUTTON_COLOR = base_color.LIGHT_300_COLOR, + SB__SWITCH_BOX_BUTTON_HOVERED_COLOR = base_color.LIGHT_200_COLOR, + + SB__CHECKBOX_BORDER_COLOR = base_color.LIGHT_600_COLOR, + SB__CHECKBOX_HOVER_COLOR = base_color.LIGHT_350_COLOR, + SB__CHECKBOX_CHECKED_COLOR = base_color.PRIMARY_250_COLOR, + SB__CHECKBOX_CHECKMARK_COLOR = base_color.LIGHT_BASIC_TEXT_COLOR, + + SB__ENTRY_TEXT_COLOR = base_color.LIGHT_900_COLOR, + SB__ENTRY_BG_COLOR = base_color.LIGHT_300_COLOR, + SB__ENTRY_BORDER_COLOR = base_color.LIGHT_400_COLOR, + + + SB__PROGRESSBAR_X_SLIDER__PROGRESSBAR_BG_COLOR = base_color.LIGHT_350_COLOR, + SB__PROGRESSBAR_X_SLIDER__PROGRESSBAR_PROGRESS_BG_COLOR = base_color.PRIMARY_500_COLOR, + SB__PROGRESSBAR_X_SLIDER__PROGRESSBAR_PROGRESS_EXCEED_THRESHOLD_BG_COLOR = base_color.PRIMARY_300_COLOR, + + SB__PROGRESSBAR_X_SLIDER__SLIDER_BUTTON_COLOR = base_color.PRIMARY_300_COLOR, + SB__PROGRESSBAR_X_SLIDER__SLIDER_BUTTON_HOVERED_COLOR = base_color.PRIMARY_450_COLOR, + + SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_COLOR = base_color.LIGHT_300_COLOR, + SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_HOVERED_COLOR = base_color.LIGHT_250_COLOR, + SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_CLICKED_COLOR = base_color.LIGHT_350_COLOR, + SB__PROGRESSBAR_X_SLIDER__PASSIVE_BUTTON_DISABLED_COLOR = base_color.LIGHT_150_COLOR, + + SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_COLOR = base_color.PRIMARY_250_COLOR, + SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_HOVERED_COLOR = base_color.PRIMARY_300_COLOR, + SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_CLICKED_COLOR = base_color.PRIMARY_400_COLOR, + + SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_COLOR = base_color.PRIMARY_250_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_HOVERED_COLOR = base_color.PRIMARY_300_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_CLICKED_COLOR = base_color.PRIMARY_400_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST_BG_COLOR = base_color.LIGHT_300_COLOR, + + SB__ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_HOVERED_BG_COLOR = base_color.LIGHT_375_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_CLICKED_BG_COLOR = base_color.LIGHT_450_COLOR, + + SB__ADD_AND_DELETE_ABLE_LIST_DELETED_BG_COLOR = base_color.LIGHT_200_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST__VALUES_DELETED_BUTTON_HOVERED_BG_COLOR = base_color.LIGHT_300_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST__VALUES_DELETED_BUTTON_CLICKED_BG_COLOR = base_color.LIGHT_400_COLOR, + + + SB__MESSAGE_FORMAT__EXAMPLE_BG_COLOR = "#5a6b81", # from VRChat' chat display color + # source #3a4554 (800). and this one is 600 (https://m2.material.io/design/color/the-color-system.html#tools-for-picking-colors) + SB__MESSAGE_FORMAT__EXAMPLE_TEXT_COLOR = base_color.LIGHT_100_COLOR, + SB__MESSAGE_FORMAT__SWAP_BUTTON_COLOR = base_color.LIGHT_200_COLOR, + SB__MESSAGE_FORMAT__SWAP_BUTTON_HOVERED_COLOR = base_color.LIGHT_250_COLOR, + SB__MESSAGE_FORMAT__SWAP_BUTTON_CLICKED_COLOR = base_color.LIGHT_300_COLOR, + + + + + # Side menu + SIDE_MENU_BG_COLOR = base_color.LIGHT_300_COLOR, + + SIDE_MENU_LABELS_BG_COLOR = base_color.LIGHT_300_COLOR, + SIDE_MENU_LABELS_BG_FOR_FAKE_BORDER_COLOR = base_color.LIGHT_300_COLOR, + SIDE_MENU_LABELS_HOVERED_BG_COLOR = base_color.LIGHT_350_COLOR, + SIDE_MENU_LABELS_CLICKED_BG_COLOR = base_color.PRIMARY_200_COLOR, + SIDE_MENU_LABELS_SELECTED_TEXT_COLOR = base_color.PRIMARY_350_COLOR, + + SIDE_MENU_SELECTED_MARK_ACTIVE_BG_COLOR = base_color.PRIMARY_350_COLOR, + + NOW_VERSION_TEXT_COLOR = base_color.LIGHT_800_COLOR, + + # Error Message Window for Config Window + # Check DarkTheme's this part. Based on the color bb4448, used to source, and pick up the number 600 by the generator (https://m2.material.io/design/color/the-color-system.html#tools-for-picking-colors) + SB__ERROR_MESSAGE_BG_COLOR = "#cd4c4f", + SB__ERROR_MESSAGE_TEXT_COLOR = "#fff", + ), + + + + image_file = SimpleNamespace( + VRCT_LOGO = getImageFileFromUiUtils("vrct_logo_for_light_mode.png"), + VRCT_LOGO_MARK = getImageFileFromUiUtils("vrct_logo_mark_black.png"), + + TRANSLATION_ICON = getImageFileFromUiUtils("translation_icon_black.png"), + TRANSLATION_ICON_DISABLED = getImageFileFromUiUtils("translation_icon_disabled.png"), + MIC_ICON = getImageFileFromUiUtils("mic_icon_black.png"), + MIC_ICON_DISABLED = getImageFileFromUiUtils("mic_icon_disabled.png"), + HEADPHONES_ICON = getImageFileFromUiUtils("headphones_icon_black.png"), + HEADPHONES_ICON_DISABLED = getImageFileFromUiUtils("headphones_icon_disabled.png"), + FOREGROUND_ICON = getImageFileFromUiUtils("foreground_icon_black.png"), + FOREGROUND_ICON_DISABLED = getImageFileFromUiUtils("foreground_icon_disabled.png"), + + NARROW_ARROW_DOWN = getImageFileFromUiUtils("narrow_arrow_down_black.png"), + + CONFIGURATION_ICON = getImageFileFromUiUtils("configuration_icon_black.png"), + CONFIGURATION_ICON_DISABLED = getImageFileFromUiUtils("configuration_icon_disabled.png"), + + ARROW_LEFT = getImageFileFromUiUtils("arrow_left_black.png"), + ARROW_LEFT_DISABLED = getImageFileFromUiUtils("arrow_left_disabled.png"), + + REFRESH_UPDATE_ICON = getImageFileFromUiUtils("refresh_update_icon.png"), + REFRESH_ICON = getImageFileFromUiUtils("refresh_icon.png"), + HELP_ICON = getImageFileFromUiUtils("help_icon_black.png"), + + CANCEL_ICON = getImageFileFromUiUtils("cancel_icon.png"), + REDO_ICON = getImageFileFromUiUtils("redo_icon_black.png"), + SWAP_ICON = getImageFileFromUiUtils("swap_icon_black.png"), + FOLDER_OPEN_ICON = getImageFileFromUiUtils("folder_open_icon_black.png"), + ), + ) + + return theme_settings \ No newline at end of file diff --git a/vrct_gui/ui_managers/UiScalingManager.py b/vrct_gui/ui_managers/UiScalingManager.py index dc385b34..b3e7f937 100644 --- a/vrct_gui/ui_managers/UiScalingManager.py +++ b/vrct_gui/ui_managers/UiScalingManager.py @@ -1,5 +1,7 @@ from types import SimpleNamespace +from ..ui_utils import calculateUiSize + class UiScalingManager(): def __init__(self, scaling_percentage): scaling_float = int(scaling_percentage.replace("%", "")) / 100 @@ -92,7 +94,11 @@ class UiScalingManager(): self.main.SLS__BOX_OPTION_MENU_IPADY = self._calculateUiSize(2) self.main.SLS__BOX_OPTION_MENU_ARROW_IMAGE_SIZE = (self._calculateUiSize(20), self._calculateUiSize(20)) # self.main.SLS__BOX_OPTION_MENU_WIDTH = self._calculateUiSize(200) - self.main.SLS__BOX_ARROWS_PADY = self._calculateUiSize(10) + self.main.SLS__BOX_ARROWS_PADY = self._calculateUiSize(4) + self.main.SLS__BOX_ARROWS_SWAP_BUTTON_CORNER_RADIUS = self._calculateUiSize(6) + self.main.SLS__BOX_ARROWS_SWAP_BUTTON_PADX = self._calculateUiSize(20) + self.main.SLS__BOX_ARROWS_SWAP_BUTTON_IPADX = self._calculateUiSize(8) + self.main.SLS__BOX_ARROWS_SWAP_BUTTON_IPADY = self._calculateUiSize(6) self.main.SLS__BOX_ARROWS_IMAGE_SIZE = self.dupTuple(self._calculateUiSize(16)) self.main.SLS__BOX_ARROWS_DESC_FONT_SIZE = self._calculateUiSize(12) self.main.SLS__BOX_ARROWS_DESC_PADX = self._calculateUiSize(6) @@ -215,6 +221,10 @@ class UiScalingManager(): self.config_window.SB__DESC_TOP_PADY = self._calculateUiSize(2) + self.config_window.BUTTONS_CORNER_RADIUS = self._calculateUiSize(6) + # self.config_window.BUTTONS_IPADX = self._calculateUiSize(10) + # self.config_window.BUTTONS_IPADY = self._calculateUiSize(6) + self.config_window.SB__ERROR_MESSAGE_IPADX = (self._calculateUiSize(10), self._calculateUiSize(10)) self.config_window.SB__ERROR_MESSAGE_IPADY = (self._calculateUiSize(6), self._calculateUiSize(6)) self.config_window.SB__ERROR_MESSAGE_FONT_SIZE = self._calculateUiSize(14) @@ -260,6 +270,7 @@ class UiScalingManager(): self.config_window.SB__SLIDER_WIDTH = self._calculateUiSize(200) self.config_window.SB__SLIDER_HEIGHT = self._calculateUiSize(16) + self.config_window.SB__SLIDER_TOOLTIP_FONT_SIZE = self._calculateUiSize(16) self.config_window.SB__PROGRESSBAR_X_SLIDER__ENTRY_WIDTH = self.config_window.RESPONSIVE_UI_SIZE_INT_50 self.config_window.SB__PROGRESSBAR_X_SLIDER__ENTRY_HEIGHT = self.config_window.SB__ENTRY_HEIGHT @@ -271,14 +282,53 @@ class UiScalingManager(): 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) + self.config_window.SB__ARROW_SWITCH_DESC_FONT_SIZE = self._calculateUiSize(16) + self.config_window.SB__ARROW_SWITCH_LEFT_PADX = (self._calculateUiSize(20), 0) + + self.config_window.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_IPADX = self._calculateUiSize(16) + self.config_window.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_IPADY = self._calculateUiSize(6) + + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_CORNER_RADIUS = self._calculateUiSize(2) + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_LEFT_PADX = (0, self._calculateUiSize(4)) + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_BOTTOM_PADY = (0, self._calculateUiSize(4)) + + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_FONT_SIZE = self._calculateUiSize(14) + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADX = (self._calculateUiSize(8), 0) + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADY = self._calculateUiSize(6) + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_IMG_SIZE = self._calculateUiSize(14) + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_IPADXY = self._calculateUiSize(6) + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_PADX = (self._calculateUiSize(6), self._calculateUiSize(8)) + + self.config_window.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_LEFT_PADX = (self._calculateUiSize(20), 0) + self.config_window.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_FONT_SIZE = self._calculateUiSize(14) + + + self.config_window.SB__MESSAGE_FORMAT__EXAMPLE_CORNER_RADIUS = self._calculateUiSize(16) + self.config_window.SB__MESSAGE_FORMAT__EXAMPLE_IPADXY = self._calculateUiSize(10) + self.config_window.SB__MESSAGE_FORMAT__EXAMPLE_WRAP_LENGTH = self._calculateUiSize(300) + + self.config_window.SB__MESSAGE_FORMAT__ENTRY_HEIGHT = self.config_window.SB__ENTRY_HEIGHT + self.config_window.SB__MESSAGE_FORMAT__REQUIRED_TEXT_PADX = self._calculateUiSize(10) + self.config_window.SB__MESSAGE_FORMAT__REQUIRED_TEXT_FONT_SIZE = self._calculateUiSize(16) + + self.config_window.SB__MESSAGE_FORMAT__SWAP_BUTTON_ARROWS_IMG_SIZE = self.dupTuple(self._calculateUiSize(20)) + self.config_window.SB__MESSAGE_FORMAT__SWAP_BUTTON_IPADX = self._calculateUiSize(16) + self.config_window.SB__MESSAGE_FORMAT__SWAP_BUTTON_IPADY = self._calculateUiSize(6) + self.config_window.SB__MESSAGE_FORMAT__SWAP_BUTTON_FONT_SIZE = self._calculateUiSize(14) + self.config_window.SB__MESSAGE_FORMAT__SWAP_TEXT_PADX = self._calculateUiSize(10) + + self.config_window.SB__MESSAGE_FORMAT__ENTRIES_BOTTOM_PADY = (0, self._calculateUiSize(14)) + + + self.config_window.SB__BUTTON_IPADXY = self._calculateUiSize(16) + self.config_window.SB__BUTTON_ICON_SIZE = self._calculateUiSize(24) + + self.config_window.SB__OPEN_CONFIG_FILE_BUTTON_IPADXY = self._calculateUiSize(10) + self.config_window.SB__OPEN_CONFIG_FILE_BUTTON_ICON_SIZE = self._calculateUiSize(20) def _calculateUiSize(self, default_size, is_allowed_odd:bool=False, is_zero_allowed:bool=False): - size = int(default_size * self.SCALING_FLOAT) - size += 1 if not is_allowed_odd and size % 2 != 0 else 0 - if size <= 0: - size = 0 if is_zero_allowed else 1 - + size = calculateUiSize(default_size, self.SCALING_FLOAT, is_allowed_odd, is_zero_allowed) return size @staticmethod diff --git a/vrct_gui/ui_managers/__init__.py b/vrct_gui/ui_managers/__init__.py index f0dd1edb..6304cb9e 100644 --- a/vrct_gui/ui_managers/__init__.py +++ b/vrct_gui/ui_managers/__init__.py @@ -1,3 +1,2 @@ from .ColorThemeManager import ColorThemeManager -from .ImageFileManager import ImageFileManager from .UiScalingManager import UiScalingManager \ No newline at end of file diff --git a/vrct_gui/ui_utils/ui_utils.py b/vrct_gui/ui_utils/ui_utils.py index bf64a985..bd6e5a9c 100644 --- a/vrct_gui/ui_utils/ui_utils.py +++ b/vrct_gui/ui_utils/ui_utils.py @@ -42,6 +42,14 @@ def getLongestText(text_list:list): longest_text = text return longest_text +def calculateUiSize(default_size, scaling_float, is_allowed_odd:bool=False, is_zero_allowed:bool=False): + size = int(default_size * scaling_float) + size += 1 if not is_allowed_odd and size % 2 != 0 else 0 + if size <= 0: + size = 0 if is_zero_allowed else 1 + + return size + 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], "+") @@ -154,10 +162,12 @@ def createOptionMenuBox(parent_widget, optionmenu_bg_color, optionmenu_hovered_b option_menu_box = CTkFrame(parent_widget, corner_radius=6, fg_color=optionmenu_bg_color, cursor="hand2") option_menu_box.grid_rowconfigure(0, weight=1) - if optionmenu_min_height is not None: option_menu_box.grid_rowconfigure(0, minsize=optionmenu_min_height) + if optionmenu_min_height is not None: + option_menu_box.grid_rowconfigure(0, minsize=optionmenu_min_height) option_menu_box.grid_columnconfigure(0, weight=1) - if optionmenu_min_width is not None: option_menu_box.grid_columnconfigure(0, minsize=optionmenu_min_width) + if optionmenu_min_width is not None: + option_menu_box.grid_columnconfigure(0, minsize=optionmenu_min_width) optionmenu_label_wrapper = CTkFrame(option_menu_box, corner_radius=0, fg_color=optionmenu_bg_color) optionmenu_label_wrapper.grid(row=0, column=0, padx=(optionmenu_ipadx[0],0), pady=optionmenu_ipady, sticky="ew") diff --git a/vrct_gui/vrct_gui.py b/vrct_gui/vrct_gui.py index 73e3d805..a0926150 100644 --- a/vrct_gui/vrct_gui.py +++ b/vrct_gui/vrct_gui.py @@ -8,7 +8,7 @@ from ._CreateDropdownMenuWindow import _CreateDropdownMenuWindow from ._changeMainWindowWidgetsStatus import _changeMainWindowWidgetsStatus from ._changeConfigWindowWidgetsStatus import _changeConfigWindowWidgetsStatus from ._CreateConfirmationModal import _CreateConfirmationModal -from ._printToTextbox import _printToTextbox +from ._PrintToTextbox import _PrintToTextbox from .main_window import createMainWindowWidgets from .config_window import ConfigWindow @@ -133,9 +133,13 @@ class VRCT_GUI(CTk): modal_type="information" ) + self.print_to_textbox = _PrintToTextbox( + vrct_gui=self, + settings=self.settings.main, + init_scaling=(self._view_variable.VAR_TEXTBOX_UI_SCALING.get()/100) + ) + - # self.update() - # self.geometry("{}x{}".format(self.winfo_width(), self.winfo_height())) def _startMainLoop(self): @@ -174,9 +178,6 @@ class VRCT_GUI(CTk): def _openSelectableLanguagesWindow(self, selectable_language_window_type): - # print("___________________________________open____________________________________________________") - # print("your", self._view_variable.IS_OPENED_SELECTABLE_YOUR_LANGUAGE_WINDOW) - # print("target", self._view_variable.IS_OPENED_SELECTABLE_TARGET_LANGUAGE_WINDOW) if selectable_language_window_type == "your_language": if self._view_variable.IS_OPENED_SELECTABLE_YOUR_LANGUAGE_WINDOW is False: self.sls__arrow_img_your_language.configure(image=CTkImage(self.settings.main.image_file.ARROW_LEFT, size=self.settings.main.uism.SLS__BOX_OPTION_MENU_ARROW_IMAGE_SIZE)) @@ -208,9 +209,6 @@ class VRCT_GUI(CTk): self.selectable_languages_window.withdraw() - # print("______________________________________close_________________________________________________") - # print("your", self._view_variable.IS_OPENED_SELECTABLE_YOUR_LANGUAGE_WINDOW) - # print("target", self._view_variable.IS_OPENED_SELECTABLE_TARGET_LANGUAGE_WINDOW) if self._view_variable.IS_OPENED_SELECTABLE_TARGET_LANGUAGE_WINDOW is not False or self._view_variable.IS_OPENED_SELECTABLE_YOUR_LANGUAGE_WINDOW is not False: def callback(): self._view_variable.IS_OPENED_SELECTABLE_TARGET_LANGUAGE_WINDOW = False @@ -238,14 +236,10 @@ class VRCT_GUI(CTk): target_names=target_names, ) - def _printToTextbox(self, target_type, original_message=None, translated_message=None): - _printToTextbox( - vrct_gui=self, - settings=self.settings.main, + def _printToTextbox(self, target_type, **kwargs): + self.print_to_textbox.printToTextbox( target_type=target_type, - original_message=original_message, - translated_message=translated_message, - tags=target_type, + **kwargs ) def _setDefaultActiveLanguagePresetTab(self, tab_no:str): @@ -275,7 +269,7 @@ class VRCT_GUI(CTk): def _clearErrorMessage(self): try: self.error_message_window._withdraw() - except: + except Exception: pass