diff --git a/.gitignore b/.gitignore index 678a4536..0d95c681 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ config.json memo.txt VRCT.spec *.pyc -logs/ \ No newline at end of file +logs/ +.venv/ \ No newline at end of file diff --git a/README.jp.md b/README.jp.md index 586912c5..51328196 100644 --- a/README.jp.md +++ b/README.jp.md @@ -58,7 +58,7 @@ VRCTはあなたの会話を以下でサポートをします。 - [みしゃ(misyaguzi)](https://github.com/misyaguziya) (メイン開発) - [しいな(Shiina_12siy)](https://twitter.com/Shiina_12siy) (UI/UX, UI多言語対応) - [レラ](https://github.com/soumt-r) (翻訳:韓国語) -- [どね]() (ロゴデザイン) +- [どね](https://twitter.com/done_vrc) (ロゴデザイン) --- diff --git a/README.md b/README.md index 39faab7f..5892ce75 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ Initial setup, basic functions, and other features are also described. - [みしゃ(misyaguzi)](https://github.com/misyaguziya) (Main Development) - [しいな(Shiina_12siy)](https://twitter.com/Shiina_12siy) (UI/UX, UI multilingual support) - [レラ](https://github.com/soumt-r) (Translation:Korean) -- [どね]() (Logo Design) +- [どね](https://twitter.com/done_vrc) (Logo Design) --- diff --git a/batch/update.bat b/batch/update.bat index e0e83855..09bd4acb 100644 --- a/batch/update.bat +++ b/batch/update.bat @@ -16,5 +16,5 @@ 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/config.py b/config.py index b594a1b0..4a5e355d 100644 --- a/config.py +++ b/config.py @@ -5,7 +5,6 @@ from json import load as json_load from json import dump as json_dump import tkinter as tk 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, isUniqueStrings @@ -39,6 +38,10 @@ class Config: def VERSION(self): return self._VERSION + @property + def ENABLE_SPEAKER2CHATBOX(self): + return self._ENABLE_SPEAKER2CHATBOX + @property def LOCAL_PATH(self): return self._LOCAL_PATH @@ -63,6 +66,30 @@ class Config: def DOCUMENTS_URL(self): return self._DOCUMENTS_URL + @property + def TRANSPARENCY_RANGE(self): + return self._TRANSPARENCY_RANGE + + @property + def APPEARANCE_THEME_LIST(self): + return self._APPEARANCE_THEME_LIST + + @property + def UI_SCALING_LIST(self): + return self._UI_SCALING_LIST + + @property + def TEXTBOX_UI_SCALING_RANGE(self): + return self._TEXTBOX_UI_SCALING_RANGE + + @property + def MESSAGE_BOX_RATIO_RANGE(self): + return self._MESSAGE_BOX_RATIO_RANGE + + @property + def SELECTABLE_UI_LANGUAGES_DICT(self): + return self._SELECTABLE_UI_LANGUAGES_DICT + @property def MAX_MIC_ENERGY_THRESHOLD(self): return self._MAX_MIC_ENERGY_THRESHOLD @@ -207,7 +234,7 @@ class Config: @TRANSPARENCY.setter def TRANSPARENCY(self, value): - if isinstance(value, int) and 0 <= value <= 100: + if isinstance(value, int) and self.TRANSPARENCY_RANGE[0] <= value <= self.TRANSPARENCY_RANGE[1]: self._TRANSPARENCY = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -218,7 +245,7 @@ class Config: @APPEARANCE_THEME.setter def APPEARANCE_THEME(self, value): - if value in ["Light", "Dark", "System"]: + if value in self.APPEARANCE_THEME_LIST: self._APPEARANCE_THEME = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -229,7 +256,7 @@ class Config: @UI_SCALING.setter def UI_SCALING(self, value): - if value in generatePercentageStringsList(start=40,end=200, step=10): + if value in self.UI_SCALING_LIST: self._UI_SCALING = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @@ -240,10 +267,21 @@ class Config: @TEXTBOX_UI_SCALING.setter def TEXTBOX_UI_SCALING(self, value): - if isinstance(value, int) and 50 <= value <= 200: + if isinstance(value, int) and self.TEXTBOX_UI_SCALING_RANGE[0] <= value <= self.TEXTBOX_UI_SCALING_RANGE[1]: self._TEXTBOX_UI_SCALING = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + @property + @json_serializable('MESSAGE_BOX_RATIO') + def MESSAGE_BOX_RATIO(self): + return self._MESSAGE_BOX_RATIO + + @MESSAGE_BOX_RATIO.setter + def MESSAGE_BOX_RATIO(self, value): + if isinstance(value, int) and self.MESSAGE_BOX_RATIO_RANGE[0] <= value <= self.MESSAGE_BOX_RATIO_RANGE[1]: + self._MESSAGE_BOX_RATIO = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + @property @json_serializable('FONT_FAMILY') def FONT_FAMILY(self): @@ -265,10 +303,34 @@ class Config: @UI_LANGUAGE.setter def UI_LANGUAGE(self, value): - if value in list(selectable_languages.keys()): + if value in list(self.SELECTABLE_UI_LANGUAGES_DICT.keys()): self._UI_LANGUAGE = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + @property + @json_serializable('ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY') + def ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY(self): + return self._ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY + + @ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY.setter + def ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY(self, value): + if isinstance(value, bool): + self._ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + @json_serializable('MAIN_WINDOW_GEOMETRY') + def MAIN_WINDOW_GEOMETRY(self): + return self._MAIN_WINDOW_GEOMETRY + + @MAIN_WINDOW_GEOMETRY.setter + def MAIN_WINDOW_GEOMETRY(self, value): + if isinstance(value, dict) and set(value.keys()) == set(self.MAIN_WINDOW_GEOMETRY.keys()): + for key, value in value.items(): + if isinstance(value, str): + self._MAIN_WINDOW_GEOMETRY[key] = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, self.MAIN_WINDOW_GEOMETRY) + @property @json_serializable('CHOICE_MIC_HOST') def CHOICE_MIC_HOST(self): @@ -447,19 +509,6 @@ class Config: self._AUTH_KEYS[key] = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, self.AUTH_KEYS) - @property - @json_serializable('MESSAGE_FORMAT') - def MESSAGE_FORMAT(self): - return self._MESSAGE_FORMAT - - @MESSAGE_FORMAT.setter - def MESSAGE_FORMAT(self, value): - 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) - @property @json_serializable('ENABLE_AUTO_CLEAR_MESSAGE_BOX') def ENABLE_AUTO_CLEAR_MESSAGE_BOX(self): @@ -471,6 +520,28 @@ class Config: self._ENABLE_AUTO_CLEAR_MESSAGE_BOX = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + @property + @json_serializable('ENABLE_SEND_ONLY_TRANSLATED_MESSAGES') + def ENABLE_SEND_ONLY_TRANSLATED_MESSAGES(self): + return self._ENABLE_SEND_ONLY_TRANSLATED_MESSAGES + + @ENABLE_SEND_ONLY_TRANSLATED_MESSAGES.setter + def ENABLE_SEND_ONLY_TRANSLATED_MESSAGES(self, value): + if isinstance(value, bool): + self._ENABLE_SEND_ONLY_TRANSLATED_MESSAGES = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + @json_serializable('SEND_MESSAGE_BUTTON_TYPE') + def SEND_MESSAGE_BUTTON_TYPE(self): + return self._SEND_MESSAGE_BUTTON_TYPE + + @SEND_MESSAGE_BUTTON_TYPE.setter + def SEND_MESSAGE_BUTTON_TYPE(self, value): + if isinstance(value, str): + self._SEND_MESSAGE_BUTTON_TYPE = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + @property @json_serializable('ENABLE_NOTICE_XSOVERLAY') def ENABLE_NOTICE_XSOVERLAY(self): @@ -493,17 +564,77 @@ class Config: self._ENABLE_SEND_MESSAGE_TO_VRC = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) - # [deprecated] - # @property - # @json_serializable('STARTUP_OSC_ENABLED_CHECK') - # def STARTUP_OSC_ENABLED_CHECK(self): - # return self._STARTUP_OSC_ENABLED_CHECK + @property + @json_serializable('SEND_MESSAGE_FORMAT') + def SEND_MESSAGE_FORMAT(self): + return self._SEND_MESSAGE_FORMAT + + @SEND_MESSAGE_FORMAT.setter + def SEND_MESSAGE_FORMAT(self, value): + if isinstance(value, str): + if isUniqueStrings(["[message]"], value) is False: + value = "[message]" + self._SEND_MESSAGE_FORMAT = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + @json_serializable('SEND_MESSAGE_FORMAT_WITH_T') + def SEND_MESSAGE_FORMAT_WITH_T(self): + return self._SEND_MESSAGE_FORMAT_WITH_T + + @SEND_MESSAGE_FORMAT_WITH_T.setter + def SEND_MESSAGE_FORMAT_WITH_T(self, value): + if isinstance(value, str): + if isUniqueStrings(["[message]", "[translation]"], value) is False: + value = "[message]([translation])" + self._SEND_MESSAGE_FORMAT_WITH_T = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + @json_serializable('RECEIVED_MESSAGE_FORMAT') + def RECEIVED_MESSAGE_FORMAT(self): + return self._RECEIVED_MESSAGE_FORMAT + + @RECEIVED_MESSAGE_FORMAT.setter + def RECEIVED_MESSAGE_FORMAT(self, value): + if isinstance(value, str): + if isUniqueStrings(["[message]"], value) is False: + value = "[message]" + self._RECEIVED_MESSAGE_FORMAT = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + @property + @json_serializable('RECEIVED_MESSAGE_FORMAT_WITH_T') + def RECEIVED_MESSAGE_FORMAT_WITH_T(self): + return self._RECEIVED_MESSAGE_FORMAT_WITH_T + + @RECEIVED_MESSAGE_FORMAT_WITH_T.setter + def RECEIVED_MESSAGE_FORMAT_WITH_T(self, value): + if isinstance(value, str): + if isUniqueStrings(["[message]", "[translation]"], value) is False: + value = "[message]([translation])" + self._RECEIVED_MESSAGE_FORMAT_WITH_T = value + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + + + + # Speaker2Chatbox------------------ + @property + @json_serializable('ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC') + def ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC(self): + return self._ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC + + @ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC.setter + def ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC(self, value): + if isinstance(value, bool): + if self._ENABLE_SPEAKER2CHATBOX is True: + self._ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC = value + else: + self._ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC = False + saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) + # Speaker2Chatbox------------------ + - # @STARTUP_OSC_ENABLED_CHECK.setter - # def STARTUP_OSC_ENABLED_CHECK(self, value): - # if isinstance(value, bool): - # self._STARTUP_OSC_ENABLED_CHECK = value - # saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property @json_serializable('ENABLE_LOGGER') @@ -529,7 +660,8 @@ class Config: def init_config(self): # Read Only - self._VERSION = "2.0.1" + self._VERSION = "2.0.2" + self._ENABLE_SPEAKER2CHATBOX = False # Speaker2Chatbox 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") @@ -537,6 +669,17 @@ class Config: 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" + self._TRANSPARENCY_RANGE = (50, 100) + self._APPEARANCE_THEME_LIST = ["Light", "Dark", "System"] + self._UI_SCALING_LIST = generatePercentageStringsList(start=40, end=200, step=10) + self._TEXTBOX_UI_SCALING_RANGE = (50, 200) + self._MESSAGE_BOX_RATIO_RANGE = (1, 99) + self._SELECTABLE_UI_LANGUAGES_DICT = { + "en": "English", + "ja": "日本語", + "ko": "한국어" + # If you want to add a new language and key, please append it here. + } self._MAX_MIC_ENERGY_THRESHOLD = 2000 self._MAX_SPEAKER_ENERGY_THRESHOLD = 4000 @@ -568,11 +711,19 @@ class Config: ## Config Window self._TRANSPARENCY = 100 - self._APPEARANCE_THEME = "System" + self._APPEARANCE_THEME = "Dark" self._UI_SCALING = "100%" self._TEXTBOX_UI_SCALING = 100 + self._MESSAGE_BOX_RATIO = 10 self._FONT_FAMILY = "Yu Gothic UI" self._UI_LANGUAGE = "en" + self._ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY = True + self._MAIN_WINDOW_GEOMETRY = { + "x_pos": "0", + "y_pos": "0", + "width": "870", + "height": "640", + } self._CHOICE_MIC_HOST = getDefaultInputDevice()["host"]["name"] self._CHOICE_MIC_DEVICE = getDefaultInputDevice()["device"]["name"] self._INPUT_MIC_ENERGY_THRESHOLD = 300 @@ -594,11 +745,16 @@ class Config: "Bing": None, "Google": None, } - self._MESSAGE_FORMAT = "[message]([translation])" + self._SEND_MESSAGE_FORMAT = "[message]" + self._SEND_MESSAGE_FORMAT_WITH_T = "[message]([translation])" + self._RECEIVED_MESSAGE_FORMAT = "[message]" + self._RECEIVED_MESSAGE_FORMAT_WITH_T = "[message]([translation])" self._ENABLE_AUTO_CLEAR_MESSAGE_BOX = True + self._ENABLE_SEND_ONLY_TRANSLATED_MESSAGES = False + self._SEND_MESSAGE_BUTTON_TYPE = "show" self._ENABLE_NOTICE_XSOVERLAY = False self._ENABLE_SEND_MESSAGE_TO_VRC = True - # self._STARTUP_OSC_ENABLED_CHECK = True # [deprecated] + self._ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC = False # Speaker2Chatbox self._ENABLE_LOGGER = False self._IS_CONFIG_WINDOW_COMPACT_MODE = False @@ -607,8 +763,13 @@ class Config: with open(self.PATH_CONFIG, 'r', encoding="utf-8") as fp: config = json_load(fp) + old_message_format = None for key in config.keys(): + if key == "MESSAGE_FORMAT": + old_message_format = config[key] setattr(self, key, config[key]) + if old_message_format is not None: + setattr(self, "SEND_MESSAGE_FORMAT_WITH_T", old_message_format) with open(self.PATH_CONFIG, 'w', encoding="utf-8") as fp: config = {} diff --git a/controller.py b/controller.py index d7bdc414..42f17be6 100644 --- a/controller.py +++ b/controller.py @@ -4,14 +4,16 @@ from threading import Thread from config import config from model import model from view import view -from utils import get_key_by_value, isUniqueStrings -from languages import selectable_languages +from utils import getKeyByValue, isUniqueStrings, strPctToInt +import argparse # Common def callbackUpdateSoftware(): + setMainWindowGeometry() model.updateSoftware() def callbackRestartSoftware(): + setMainWindowGeometry() model.reStartSoftware() def callbackFilepathLogs(): @@ -22,6 +24,37 @@ def callbackFilepathConfigFile(): print("callbackFilepathConfigFile", config.LOCAL_PATH.replace('/', '\\')) Popen(['explorer', config.LOCAL_PATH.replace('/', '\\')], shell=True) +def callbackQuitVrct(): + setMainWindowGeometry() + +def setMainWindowGeometry(): + PRE_SCALING_INT = strPctToInt(view.getPreUiScaling()) + NEW_SCALING_INT = strPctToInt(config.UI_SCALING) + MULTIPLY_FLOAT = (NEW_SCALING_INT / PRE_SCALING_INT) + main_window_geometry = view.getMainWindowGeometry(return_int=True) + main_window_geometry["width"] = str(int(main_window_geometry["width"] * MULTIPLY_FLOAT)) + main_window_geometry["height"] = str(int(main_window_geometry["height"] * MULTIPLY_FLOAT)) + main_window_geometry["x_pos"] = str(main_window_geometry["x_pos"]) + main_window_geometry["y_pos"] = str(main_window_geometry["y_pos"]) + config.MAIN_WINDOW_GEOMETRY = main_window_geometry + +def messageFormatter(format_type:str, translation, message): + if format_type == "RECEIVED": + FORMAT_WITH_T = config.RECEIVED_MESSAGE_FORMAT_WITH_T + FORMAT = config.RECEIVED_MESSAGE_FORMAT + elif format_type == "SEND": + FORMAT_WITH_T = config.SEND_MESSAGE_FORMAT_WITH_T + FORMAT = config.SEND_MESSAGE_FORMAT + else: + raise ValueError("format_type is not found", format_type) + + if len(translation) > 0: + osc_message = FORMAT_WITH_T.replace("[message]", message) + osc_message = osc_message.replace("[translation]", translation) + else: + osc_message = FORMAT.replace("[message]", message) + return osc_message + # func transcription send message def sendMicMessage(message): if len(message) > 0: @@ -40,13 +73,16 @@ def sendMicMessage(message): if config.ENABLE_TRANSCRIPTION_SEND is True: if config.ENABLE_SEND_MESSAGE_TO_VRC is True: - if len(translation) > 0: - osc_message = config.MESSAGE_FORMAT.replace("[message]", message) - osc_message = osc_message.replace("[translation]", translation) + if config.ENABLE_SEND_ONLY_TRANSLATED_MESSAGES is True: + if config.ENABLE_TRANSLATION is False: + osc_message = messageFormatter("SEND", "", message) + else: + osc_message = messageFormatter("SEND", "", translation) else: - osc_message = message + osc_message = messageFormatter("SEND", translation, message) model.oscSendMessage(osc_message) + view.printToTextbox_SentMessage(message, translation) if config.ENABLE_LOGGER is True: if len(translation) > 0: @@ -104,13 +140,17 @@ def receiveSpeakerMessage(message): if config.ENABLE_TRANSCRIPTION_RECEIVE is True: if config.ENABLE_NOTICE_XSOVERLAY is True: - if len(translation) > 0: - xsoverlay_message = config.MESSAGE_FORMAT.replace("[message]", message) - xsoverlay_message = xsoverlay_message.replace("[translation]", translation) - else: - xsoverlay_message = message + xsoverlay_message = messageFormatter("RECEIVED", translation, message) model.notificationXSOverlay(xsoverlay_message) + # ------------Speaker2Chatbox------------ + if config.ENABLE_SPEAKER2CHATBOX is True: + # send OSC message + if config.ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC is True: + osc_message = messageFormatter("RECEIVED", translation, message) + model.oscSendMessage(osc_message) + # ------------Speaker2Chatbox------------ + # update textbox message log (Received) view.printToTextbox_ReceivedMessage(message, translation) if config.ENABLE_LOGGER is True: @@ -170,11 +210,13 @@ def sendChatMessage(message): # send OSC message if config.ENABLE_SEND_MESSAGE_TO_VRC is True: - if len(translation) > 0: - osc_message = config.MESSAGE_FORMAT.replace("[message]", message) - osc_message = osc_message.replace("[translation]", translation) + if config.ENABLE_SEND_ONLY_TRANSLATED_MESSAGES is True: + if config.ENABLE_TRANSLATION is False: + osc_message = messageFormatter("SEND", "", message) + else: + osc_message = messageFormatter("SEND", "", translation) else: - osc_message = message + osc_message = messageFormatter("SEND", translation, message) model.oscSendMessage(osc_message) # update textbox message log (Sent) @@ -188,7 +230,7 @@ def sendChatMessage(message): if config.ENABLE_AUTO_CLEAR_MESSAGE_BOX is True: view.clearMessageBox() -def messageBoxPressKeyEnter(e): +def messageBoxPressKeyEnter(): model.oscStopSendTyping() message = view.getTextFromMessageBox() sendChatMessage(message) @@ -277,16 +319,20 @@ def callbackToggleTranscriptionSend(is_turned_on): config.ENABLE_TRANSCRIPTION_SEND = is_turned_on if config.ENABLE_TRANSCRIPTION_SEND is True: startThreadingTranscriptionSendMessage() + view.changeTranscriptionDisplayStatus("MIC_ON") else: stopThreadingTranscriptionSendMessage() + view.changeTranscriptionDisplayStatus("MIC_OFF") def callbackToggleTranscriptionReceive(is_turned_on): view.setMainWindowAllWidgetsStatusToDisabled() config.ENABLE_TRANSCRIPTION_RECEIVE = is_turned_on if config.ENABLE_TRANSCRIPTION_RECEIVE is True: startThreadingTranscriptionReceiveMessage() + view.changeTranscriptionDisplayStatus("SPEAKER_ON") else: stopThreadingTranscriptionReceiveMessage() + view.changeTranscriptionDisplayStatus("SPEAKER_OFF") def callbackToggleForeground(is_turned_on): config.ENABLE_FOREGROUND = is_turned_on @@ -319,9 +365,7 @@ def callbackCloseConfigWindow(): model.stopCheckMicEnergy() model.stopCheckSpeakerEnergy() view.initMicThresholdCheckButton() - # view.initProgressBar_MicEnergy() # ProgressBarに0をセットしたい view.initSpeakerThresholdCheckButton() - # view.initProgressBar_SpeakerEnergy() # ProgressBarに0をセットしたい if config.ENABLE_TRANSCRIPTION_SEND is True: startThreadingTranscriptionSendMessageOnCloseConfigWindow() @@ -366,7 +410,7 @@ def callbackSetAppearance(value): def callbackSetUiScaling(value): print("callbackSetUiScaling", value) config.UI_SCALING = value - new_scaling_float = int(value.replace("%", "")) / 100 + new_scaling_float = strPctToInt(value) / 100 print("callbackSetUiScaling_new_scaling_float", new_scaling_float) view.showRestartButtonIfRequired() @@ -375,6 +419,11 @@ def callbackSetTextboxUiScaling(value): config.TEXTBOX_UI_SCALING = int(value) view.setMainWindowTextboxUiSize(config.TEXTBOX_UI_SCALING/100) +def callbackSetMessageBoxRatio(value): + print("callbackSetMessageBoxRatio", int(value)) + config.MESSAGE_BOX_RATIO = int(value) + view.setMainWindowMessageBoxRatio(config.MESSAGE_BOX_RATIO) + def callbackSetFontFamily(value): print("callbackSetFontFamily", value) config.FONT_FAMILY = value @@ -382,11 +431,15 @@ def callbackSetFontFamily(value): def callbackSetUiLanguage(value): print("callbackSetUiLanguage", value) - value = get_key_by_value(selectable_languages, value) - print("callbackSetUiLanguage__after_get_key_by_value", value) + value = getKeyByValue(config.SELECTABLE_UI_LANGUAGES_DICT, value) + print("callbackSetUiLanguage__after_getKeyByValue", value) config.UI_LANGUAGE = value view.showRestartButtonIfRequired(locale=config.UI_LANGUAGE) +def callbackSetEnableRestoreMainWindowGeometry(value): + print("callbackSetEnableAutoClearMessageBox", value) + config.ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY = value + # Translation Tab def callbackSetDeeplAuthkey(value): print("callbackSetDeeplAuthkey", str(value)) @@ -408,7 +461,8 @@ def callbackSetDeeplAuthkey(value): config.AUTH_KEYS = auth_keys config.CHOICE_TRANSLATOR = model.findTranslationEngine(config.SOURCE_LANGUAGE, config.TARGET_LANGUAGE) -# Transcription Tab (Mic) +# Transcription Tab +# Transcription (Mic) def callbackSetMicHost(value): print("callbackSetMicHost", value) config.CHOICE_MIC_HOST = value @@ -539,10 +593,12 @@ def callbackDeleteMicWordFilter(value): new_input_mic_word_filter_list.remove(str(value)) config.INPUT_MIC_WORD_FILTER = new_input_mic_word_filter_list view.setLatestConfigVariable("MicMicWordFilter") + model.resetKeywordProcessor() + model.addKeywords() except Exception: print("There was no the target word in config.INPUT_MIC_WORD_FILTER") - +# Transcription (Speaker) def callbackSetSpeakerEnergyThreshold(value): print("callbackSetSpeakerEnergyThreshold", value) if value == "": @@ -566,7 +622,6 @@ def callbackSetSpeakerDynamicEnergyThreshold(value): else: view.openSpeakerEnergyThresholdWidget() - def setProgressBarSpeakerEnergy(energy): view.updateSetProgressBar_SpeakerEnergy(energy) @@ -637,6 +692,15 @@ def callbackSetEnableAutoClearMessageBox(value): print("callbackSetEnableAutoClearMessageBox", value) config.ENABLE_AUTO_CLEAR_MESSAGE_BOX = value +def callbackSetEnableSendOnlyTranslatedMessages(value): + print("callbackSetEnableSendOnlyTranslatedMessages", value) + config.ENABLE_SEND_ONLY_TRANSLATED_MESSAGES = value + +def callbackSetSendMessageButtonType(value): + print("callbackSetSendMessageButtonType", value) + config.SEND_MESSAGE_BUTTON_TYPE = value + view.changeMainWindowSendMessageButton(config.SEND_MESSAGE_BUTTON_TYPE) + def callbackSetEnableNoticeXsoverlay(value): print("callbackSetEnableNoticeXsoverlay", value) config.ENABLE_NOTICE_XSOVERLAY = value @@ -650,26 +714,60 @@ def callbackSetEnableAutoExportMessageLogs(value): else: model.stopLogger() -def callbackSetMessageFormat(value): - print("callbackSetMessageFormat", value) - if len(value) > 0: - 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) config.ENABLE_SEND_MESSAGE_TO_VRC = value -# [deprecated] -# def callbackSetStartupOscEnabledCheck(value): -# print("callbackSetStartupOscEnabledCheck", value) -# config.STARTUP_OSC_ENABLED_CHECK = value +# Others (Message Formats(Send) +def callbackSetSendMessageFormat(value): + print("callbackSetSendMessageFormat", value) + if isUniqueStrings(["[message]"], value) is True: + config.SEND_MESSAGE_FORMAT = value + view.clearErrorMessage() + view.setSendMessageFormat_EntryWidgets(config.SEND_MESSAGE_FORMAT) + else: + view.showErrorMessage_SendMessageFormat() + view.setSendMessageFormat_EntryWidgets(config.SEND_MESSAGE_FORMAT) + +def callbackSetSendMessageFormatWithT(value): + print("callbackSetSendMessageFormatWithT", value) + if len(value) > 0: + if isUniqueStrings(["[message]", "[translation]"], value) is True: + config.SEND_MESSAGE_FORMAT_WITH_T = value + view.clearErrorMessage() + view.setSendMessageFormatWithT_EntryWidgets(config.SEND_MESSAGE_FORMAT_WITH_T) + else: + view.showErrorMessage_SendMessageFormatWithT() + view.setSendMessageFormatWithT_EntryWidgets(config.SEND_MESSAGE_FORMAT_WITH_T) + +# Others (Message Formats(Received) +def callbackSetReceivedMessageFormat(value): + print("callbackSetReceivedMessageFormat", value) + if isUniqueStrings(["[message]"], value) is True: + config.RECEIVED_MESSAGE_FORMAT = value + view.clearErrorMessage() + view.setReceivedMessageFormat_EntryWidgets(config.RECEIVED_MESSAGE_FORMAT) + else: + view.showErrorMessage_ReceivedMessageFormat() + view.setReceivedMessageFormat_EntryWidgets(config.RECEIVED_MESSAGE_FORMAT) + +def callbackSetReceivedMessageFormatWithT(value): + print("callbackSetReceivedMessageFormatWithT", value) + if len(value) > 0: + if isUniqueStrings(["[message]", "[translation]"], value) is True: + config.RECEIVED_MESSAGE_FORMAT_WITH_T = value + view.clearErrorMessage() + view.setReceivedMessageFormatWithT_EntryWidgets(config.RECEIVED_MESSAGE_FORMAT_WITH_T) + else: + view.showErrorMessage_ReceivedMessageFormatWithT() + view.setReceivedMessageFormatWithT_EntryWidgets(config.RECEIVED_MESSAGE_FORMAT_WITH_T) + +# ---------------------Speaker2Chatbox--------------------- +def callbackSetEnableSendReceivedMessageToVrc(value): + print("callbackSetEnableSendReceivedMessageToVrc", value) + config.ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC = value +# ---------------------Speaker2Chatbox--------------------- + # Advanced Settings Tab def callbackSetOscIpAddress(value): @@ -684,11 +782,25 @@ def callbackSetOscPort(value): print("callbackSetOscPort", int(value)) config.OSC_PORT = int(value) + +def initSetConfigByExeArguments(): + parser = argparse.ArgumentParser() + parser.add_argument("--ip") + parser.add_argument("--port") + args = parser.parse_args() + if args.ip is not None: + config.OSC_IP_ADDRESS = str(args.ip) + view.setGuiVariable_OscIpAddress(config.OSC_IP_ADDRESS) + if args.port is not None: + config.OSC_PORT = int(args.port) + view.setGuiVariable_OscPort(config.OSC_PORT) + def createMainWindow(): # create GUI view.createGUI() # init config + initSetConfigByExeArguments() initSetLanguageAndCountry() if model.authenticationTranslator(config.CHOICE_TRANSLATOR, config.AUTH_KEYS[config.CHOICE_TRANSLATOR]) is False: @@ -702,13 +814,10 @@ def createMainWindow(): # set word filter model.addKeywords() - # check OSC started [deprecated] - # if config.STARTUP_OSC_ENABLED_CHECK is True and config.ENABLE_SEND_MESSAGE_TO_VRC is True: - # model.checkOSCStarted(view.printToTextbox_OSCError) - # check Software Updated - if model.checkSoftwareUpdated() is True: - view.showUpdateAvailableButton() + if config.ENABLE_SPEAKER2CHATBOX is False: + if model.checkSoftwareUpdated() is True: + view.showUpdateAvailableButton() # init logger if config.ENABLE_LOGGER is True: @@ -721,6 +830,7 @@ def createMainWindow(): "callback_restart_software": callbackRestartSoftware, "callback_filepath_logs": callbackFilepathLogs, "callback_filepath_config_file": callbackFilepathConfigFile, + "callback_quit_vrct": callbackQuitVrct, }, window_action_registers={ @@ -759,8 +869,10 @@ def createMainWindow(): "callback_set_appearance": callbackSetAppearance, "callback_set_ui_scaling": callbackSetUiScaling, "callback_set_textbox_ui_scaling": callbackSetTextboxUiScaling, + "callback_set_message_box_ratio": callbackSetMessageBoxRatio, "callback_set_font_family": callbackSetFontFamily, "callback_set_ui_language": callbackSetUiLanguage, + "callback_set_enable_restore_main_window_geometry": callbackSetEnableRestoreMainWindowGeometry, # Translation Tab "callback_set_deepl_authkey": callbackSetDeeplAuthkey, @@ -789,11 +901,21 @@ def createMainWindow(): # Others Tab "callback_set_enable_auto_clear_chatbox": callbackSetEnableAutoClearMessageBox, + "callback_set_send_only_translated_messages": callbackSetEnableSendOnlyTranslatedMessages, + "callback_set_send_message_button_type": callbackSetSendMessageButtonType, "callback_set_enable_notice_xsoverlay": callbackSetEnableNoticeXsoverlay, "callback_set_enable_auto_export_message_logs": callbackSetEnableAutoExportMessageLogs, - "callback_set_message_format": callbackSetMessageFormat, "callback_set_enable_send_message_to_vrc": callbackSetEnableSendMessageToVrc, - # "callback_set_startup_osc_enabled_check": callbackSetStartupOscEnabledCheck, # [deprecated] + # Others(Message Formats(Send) + "callback_set_send_message_format": callbackSetSendMessageFormat, + "callback_set_send_message_format_with_t": callbackSetSendMessageFormatWithT, + # Others(Message Formats(Received) + "callback_set_received_message_format": callbackSetReceivedMessageFormat, + "callback_set_received_message_format_with_t": callbackSetReceivedMessageFormatWithT, + + # Speaker2Chatbox---------------- + "callback_set_enable_send_received_message_to_vrc": callbackSetEnableSendReceivedMessageToVrc, + # Speaker2Chatbox---------------- # Advanced Settings Tab "callback_set_osc_ip_address": callbackSetOscIpAddress, diff --git a/img/send_message_icon_black.png b/img/send_message_icon_black.png new file mode 100644 index 00000000..e4240e56 Binary files /dev/null and b/img/send_message_icon_black.png differ diff --git a/img/send_message_icon_white.png b/img/send_message_icon_white.png new file mode 100644 index 00000000..cdead72b Binary files /dev/null and b/img/send_message_icon_white.png differ diff --git a/languages.py b/languages.py deleted file mode 100644 index 4c7b8c94..00000000 --- a/languages.py +++ /dev/null @@ -1,6 +0,0 @@ -selectable_languages = { - "en": "English", - "ja": "日本語", - "ko": "한국어(일부 지원)" - # 新しい言語とキーを追加する場合はここに追記してください -} \ No newline at end of file diff --git a/locales/en.yml b/locales/en.yml index 802d61f5..2cad19ef 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -82,6 +82,9 @@ config_window: transcription_mic: Mic transcription_speaker: Speaker others: Others + others_send_message_formats: Message Formats(Send) + others_received_message_formats: Message Formats(Received) + others_speaker2chatbox: Speaker2Chatbox advanced_settings: Advanced Settings @@ -91,7 +94,7 @@ config_window: appearance_theme: label: Theme - desc: Change the color theme. Currently. + desc: Change the color theme. ui_size: label: UI Size @@ -100,12 +103,20 @@ config_window: label: Text Box Font Size desc: You can adjust the font size used in the logs relative to the UI size. + message_box_ratio: + label: Message Box Size + desc: "You can change the size of the input message box. It is in ratio to the text box.\n*No exact calculations." + font_family: label: Font Family ui_language: label: UI Language + to_restore_main_window_geometry: + label: Remember The Main Window Position + desc: Restore the position and size of the previous window upon startup. + deepl_auth_key: label: DeepL Auth Key @@ -171,6 +182,15 @@ config_window: auto_clear_the_message_box: label: Auto Clear The Message Box + send_only_translated_messages: + label: Send Only Translated Messages + + send_message_button_type: + label: Send Message Button + hide: Hide (Use enter key to send) + show: Show + show_and_disable_enter_key: Show and disable to send when pressed enter key + notice_xsoverlay: label: Notification XSOverlay (VR Only) desc: Notify received messages by using XSOverlay's notification feature. @@ -179,16 +199,43 @@ config_window: label: Auto Export Message Logs desc: Automatically export the conversation messages as a text file. - 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 desc: There is a way to use it without sending messages to VRChat, but it is not supported. Enable this feature when you intend to send a message to VRChat. + + send_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." + example_text: This is an example sentence. Fonts, line breaks, etc. may differ from the actual display. + error_message: "The characters '[message]' cannot be used." + + send_message_format_with_t: + label: Message Format(With translation) + 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." + 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." + + received_message_format: + label: Message Format + desc: "You can change the decoration of the received message you want to send.\n[message] will be replaced with the 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]' cannot be used." + + received_message_format_with_t: + label: Message Format(With translation) + desc: It 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." + + # Note: Speaker2Chatbox localization is fine only in English. Do not translate it into other languages. + # Speaker2Chatbox + send_received_message_to_vrc: + label: Send Received Message To VRChat + desc: Send the message you received from the speaker's sound to VRChat's chatbox. However, this feature is intended for users who genuinely need it. Please consult with the developer. + # Speaker2Chatbox + + osc_ip_address: label: OSC IP Address diff --git a/locales/ja.yml b/locales/ja.yml index 516f46d5..eb937747 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -100,12 +100,20 @@ config_window: label: テキストボックス フォントサイズ desc: ログに表示されるフォントのサイズを、UIサイズを基準にして倍率を変えられます。 + message_box_ratio: + label: メッセージ入力欄のサイズ + desc: "メッセージ入力欄のサイズを変更できます。テキストボックスとの比率となっています。\n※厳密な計算はしていません。" + font_family: label: 使用フォント ui_language: label: UIの言語 / UI Language + to_restore_main_window_geometry: + label: メイン画面の位置を記憶する + desc: 起動時、前回の画面の位置とサイズを復元します。 + deepl_auth_key: label: DeepL 認証キー @@ -167,9 +175,19 @@ config_window: desc: 文字起こしされた単語数の下限値で、この数値を超えた場合のみ結果をログに表示します。 error_message: 0以上の数値を設定できます。 + auto_clear_the_message_box: label: 送信後はチャットボックスを空にする + send_only_translated_messages: + label: 翻訳後のメッセージのみ送信する + + send_message_button_type: + label: メッセージ送信ボタン + hide: 非表示 (エンターキーを使って送信) + show: 表示 + show_and_disable_enter_key: 表示し、エンターキーでの送信を無効 + notice_xsoverlay: label: XSOverlayでの通知受け取り機能を有効 (VR限定) desc: 文字起こし(受信)されたメッセージをXSOverlayの機能を使って通知として受け取れます。 @@ -178,16 +196,36 @@ config_window: label: 会話ログを自動的に保存する desc: テキストファイルとしてログがlogsフォルダ内に保存されます。 - message_format: - label: 送信するメッセージのフォーマット - desc: "VRChatで相手に実際に見えるフォーマットを変更できます。\n[message]がメッセージに置換され、[translation]が翻訳されたメッセージに置換されます。\n※XSOverlayでの通知受け取り機能でも使われます。" - example_text: これは例文です。フォントや改行箇所など、実際の表示とは異なる場合があります。 - error_message: "[message]と[translation]という文字は使えません。" - send_message_to_vrc: label: VRChatにメッセージを送信する desc: "サポート対象外ですが、VRChatにメッセージを送信せずに使う方法があります。送信したい場合、この機能を有効にする事を忘れないでください。" + + send_message_format: + label: 送信するメッセージのフォーマット + desc: "VRChatで相手に実際に見えるフォーマットを変更できます。\n[message]がメッセージに置換されます。" + example_text: これは例文です。フォントや改行箇所など、実際の表示とは異なる場合があります。 + error_message: "[message]という文字は使えません。" + + send_message_format_with_t: + label: 送信するメッセージのフォーマット(翻訳付き) + desc: "VRChatで相手に実際に見えるフォーマットを変更できます。\n[message]がメッセージに置換され、[translation]が翻訳されたメッセージに置換されます。" + example_text: これは例文です。フォントや改行箇所など、実際の表示とは異なる場合があります。 + error_message: "[message]と[translation]という文字は使えません。" + + received_message_format: + label: 送信するメッセージのフォーマット + desc: "VRChatで相手に実際に見えるフォーマットを変更できます。\n[message]がメッセージに置換されます。\n※XSOverlayでの通知受け取り機能にも使われます。" + example_text: これは例文です。フォントや改行箇所など、実際の表示とは異なる場合があります。 + error_message: "[message]という文字は使えません。" + + received_message_format_with_t: + label: 送信するメッセージのフォーマット(翻訳付き) + desc: "VRChatで相手に実際に見えるフォーマットを変更できます。\n[message]がメッセージに置換され、[translation]が翻訳されたメッセージに置換されます。\n※XSOverlayでの通知受け取り機能にも使われます。" + example_text: これは例文です。フォントや改行箇所など、実際の表示とは異なる場合があります。 + error_message: "[message]と[translation]という文字は使えません。" + + osc_ip_address: label: OSC IP Address diff --git a/locales/ko.yml b/locales/ko.yml index 9f6566ee..692abd2c 100644 --- a/locales/ko.yml +++ b/locales/ko.yml @@ -1,188 +1,239 @@ main_window: translation: 번역 - transcription_send: 마이크 -> 챗박스 - transcription_receive: 스피커 -> 로그 + transcription_send: 음성인식 (마이크) + transcription_receive: 음성인식 (스피커) foreground: 항상 위로 - # language_settings: Language Settings - # your_language: Your Language - # both_direction_desc: Translate Each Other - # target_language: Target Language + language_settings: 언어 설정 + your_language: 당신의 언어 + both_direction_desc: 양방향으로 번역 + swap_button_label: 언어 교체 + target_language: 상대방의 언어 textbox_tab_all: 전체 textbox_tab_sent: 전송 textbox_tab_received: 수신 textbox_tab_system: 시스템 - # textbox_system_message: - # enabled_translation: Translation feature is turned on. - # disabled_translation: Translation feature is turned off. - # enabled_voice2chatbox: Transcription from the microphone has started. - # disabled_voice2chatbox: Transcription from the microphone has been stopped. - # enabled_speaker2log: Transcription from the speaker has started. - # disabled_speaker2log: Transcription from the speaker has been stopped. - # enabled_foreground: The screen is fixed in the foreground. - # disabled_foreground: The foreground fixation has been released. + textbox_system_message: + enabled_translation: 번역 기능을 시작합니다. + disabled_translation: 번역 기능이 중지되었습니다. + enabled_voice2chatbox: 마이크에서의 음성인식을 시작합니다. + disabled_voice2chatbox: 마이크에서의 음성인식이 중지되었습니다. + enabled_speaker2log: 스피커에서의 음성인식을 시작합니다. + disabled_speaker2log: 스피커에서의 음성인식이 중지되었습니다. + enabled_foreground: 화면을 항상 위로 고정합니다. + disabled_foreground: 화면 고정이 해제되었습니다. - # auth_key_success: Auth key update completed. - # auth_key_error: Auth Key is incorrect or Usage limit reached. + auth_key_success: 인증키 갱신이 완료되었습니다. + auth_key_error: 인증 키가 잘못되었거나 API 사용 제한이 상한선에 도달했습니다. - # no_mic_device_detected_error: No mic device detected. - # no_speaker_device_detected_error: No speaker device detected. - # translation_engine_limit_error: It has automatically disabled the translation feature. Access has been temporarily restricted due to an excessive number of requests to the translation engine. Please wait for a while, restart VRCT, and try again. + no_mic_device_detected_error: 마이크 디바이스를 찾지 못했습니다. + no_speaker_device_detected_error: 스피커 디바이스를 찾지 못했습니다. + translation_engine_limit_error: 번역 기능이 자동으로 중지되었습니다. 번역 엔진에 대한 요청이 너무 많아 일시적으로 사용이 제한되고 있습니다. 잠시 기다렸다가 VRCT를 재부팅하고 다시 시도해 보세요. - # detected_by_word_filter: The word %{detected_message} has not been sent due to detection by the word filter. + detected_by_word_filter: 단어 필터에 등록된 단어 %{detected_message}(이)가 감지되어 전송하지 않았습니다. - # selected_your_language: "\"Your Language\" has set to %{your_language}." - # selected_target_language: "\"Target Language\" has set to %{target_language}." - # switched_language_preset_tab: Switched to Language Preset Tab No.%{tab_no}." - # latest_language_setting: "Currently, \"Your Language\" is set to %{your_language}, and \"Target Language\" is set to %{target_language}." + selected_your_language: "'당신의 언어'가 %{your_language}(으)로 설정되었습니다." + selected_target_language: "'상대방의 언어'가 %{target_language}(으)로 설정되었습니다." + switched_language_preset_tab: 언어 프리셋 번호 %{tab_no}로 전환되었습니다. + latest_language_setting: "현재 '당신의 언어'는 %{your_language}, '상대방의 언어'는 %{target_language}(으)로 설정되어 있습니다." - # opened_web_page_booth: Opened Booth page in your web browser. - # opened_web_page_vrct_documents: "Opened VRCT Documents page in your web browser.\nFor any issues, requests, or inquiries, please feel free to contact us through the links at the bottom of the documents page, the \"Contact Form,\" or via X (formerly Twitter)!" + opened_web_page_booth: 브라우저에서 Booth 페이지를 열었습니다. + opened_web_page_vrct_documents: "웹 브라우저에서 VRCT 문서 페이지가 열렸습니다.\n문제, 요청 또는 문의 사항이 있는 경우 문서 페이지 하단의 링크, '문의 양식' 또는 X(구 트위터)를 통해 언제든지 문의해 주세요!" - # update_available: New version is here! + update_available: 새로운 버전이 나왔습니다! - # cover_message: The functionality is temporarily disabled until the settings window is closed. + cover_message: 설정 화면이 닫힐 때까지 일시적으로 기능을 정지하고 있습니다. - # confirmation_message: - # update_software: "Download new version and restart automatically.\nIt'll take a while. Do it now?" - # deny_update_software: Do it later - # accept_update_software: Update and Restart - # updating: Now updating... + confirmation_message: + update_software: "새 버전을 다운로드하고 재부팅합니다. \n 조금 시간이 걸릴 수 있습니다. 지금 시작할까요?" + deny_update_software: 나중에 하기 + accept_update_software: 업데이트 및 재부팅 + updating: 업데이트 중... - # detected_over_ui_size: "Current UI Size: %{current_ui_size}\nVRCT's window size may be larger than your display size.\n* Depending on your display size, you may need to adjust it multiple times." - # deny_adjust_ui_size: "Keep it at this size" - # accept_adjust_ui_size: "Set it smaller and restart" + detected_over_ui_size: "현재 UI 크기: %{current_ui_size}\nVRCT의 창 크기가 사용자의 디스플레이 크기보다 클 수 있습니다. \n* 디스플레이 크기에 따라 여러 번 재설정해야 할 수도 있습니다." + deny_adjust_ui_size: "지금 상태를 유지" + accept_adjust_ui_size: "작게 줄이고 재부팅" - # translation_engine_limit_error: "It has automatically disabled the translation feature.\nAccess has been temporarily restricted\ndue to an excessive number of requests to the translation engine.\nPlease wait for a while, restart VRCT, and try again." - # accept_translation_engine_limit_error: Accept and close + translation_engine_limit_error: "번역 기능이 자동으로 중지되었습니다. \n번역 엔진에 대한 요청이 너무 많아 \n일시적으로 사용이 제한되었습니다. \n잠시 기다렸다가 VRCT를 재부팅한 후 다시 시도해 보십시오." + accept_translation_engine_limit_error: 확인하고 닫기 -# selectable_language_window: -# title_your_language: Select Your Language -# title_target_language: Select Target Language -# go_back_button: Go Back +selectable_language_window: + title_your_language: 당신의 언어 + title_target_language: 상대방의 언어 + go_back_button: 돌아가기 config_window: - # config_title: Settings - # compact_mode: Compact Mode - # version: version %{version} - # restart_message: Apply changes with a restart. - # common_error_message: - # invalid_value: Invalid value. + config_title: 설정 + compact_mode: 컴팩트 모드 + version: 버전 %{version} + restart_message: 재부팅하여 변경 사항을 적용합니다. + common_error_message: + invalid_value: 유효하지 않은 값입니다. side_menu_labels: - # appearance: Appearance + appearance: 모양 translation: 번역 transcription: 음성인식 transcription_mic: 마이크 transcription_speaker: 스피커 others: 기타 - # advanced_settings: Advanced Settings + others_send_message_formats: 메시지 형식 (전송) + others_received_message_formats: 메시지 형식 (수신) + others_speaker2chatbox: 스피커->챗박스 + advanced_settings: 고급 설정 transparency: label: 투명도 - # desc: Change the main window's transparency. + desc: 메인 화면의 투명도를 변경합니다. appearance_theme: label: 테마 - # desc: Change the color theme. Currently, only the Dark theme is supported. The Light theme is under development. + desc: 색상 테마를 변경합니다. ui_size: label: UI 크기 + textbox_ui_size: + label: 텍스트 박스 글자 크기 + desc: 로그에 표시되는 글자 크기의 배율을 UI 크기에 따라 변경합니다. + + message_box_ratio: + label: 메시지 입력란 크기 + desc: "메시지 입력란의 크기를 변경합니다. 텍스트 박스와의 비율로 설정되어 있습니다. \n* 정확한 계산은 하지 않았습니다." + font_family: label: 폰트 ui_language: label: UI 언어 / UI Language + to_restore_main_window_geometry: + label: 메인 화면 위치 기억 + desc: 시작 시 이전 화면의 위치와 크기를 복원합니다. + deepl_auth_key: label: DeepL 인증키 mic_host: - label: 마이크 호스트/Driver + label: 마이크 호스트/드라이버 mic_device: label: 마이크 장치 mic_dynamic_energy_threshold: - label_for_automatic: "음성 입력 최소 볼륨 (Current Setting: Automatic)" - # desc_for_automatic: "Automatically determine microphone input sensitivity." - label_for_manual: "음성 입력 최소 볼륨 (Current Setting: Manual)" - # desc_for_manual: "Manually determine the microphone input sensitivity using the slider. Press the microphone icon to input your voice and adjust the sensitivity while monitoring the volume." - # error_message: You can set it with a value between 0 to %{max}. + label_for_automatic: "음성 입력 최소 볼륨 (현재 설정: 자동)" + desc_for_automatic: "마이크의 입력 감도를 자동으로 조절합니다." + label_for_manual: "음성 입력 최소 볼륨 (현재 설정: 수동)" + desc_for_manual: "슬라이더를 움직여 입력 감도를 수동으로 조절합니다. 마이크 아이콘을 누르면 실제 음성의 볼륨을 확인하며 감도를 조절할 수 있습니다." + error_message: 0에서 %{max}까지의 숫자로만 설정할 수 있습니다. mic_record_timeout: label: 최대 무음 시간 - # desc: Detects silence and, when the specified number of seconds has passed, considers the mic input to have ended. (Second(s)) - # error_message: It cannot be greater than '%{mic_phrase_timeout_label}' with a value of 0 or more. + desc: 무음을 감지하고 설정된 시간(초)만큼의 시간이 지나면 음성 입력이 종료된 것으로 판단합니다. + error_message: 0 이상에서 '%{mic_phrase_timeout_label}'보다 클 수 없습니다. mic_phrase_timeout: label: 최대 인식 시간 - # desc: Transcription processing is performed at intervals of the specified number of seconds. - # error_message: It cannot be set lower than '%{mic_record_timeout_label}' with a value of 0 or more. + desc: 설정된 초 단위로 음성인식 처리가 이루어집니다. + error_message: 0 이상에서 '%{mic_record_timeout_label}'보다 작을 수 없습니다. mic_max_phrase: label: 최대 입력 절(phrases) 수 - # desc: It is the lower limit for the number of transcribed words, and only when this number is exceeded will the transcription results be displayed logs and send to VRChat. - # error_message: You can set a number equal to or greater than 0. + desc: 인식된 단어 수의 하한값으로, 이 수치를 초과하는 경우에만 결과를 VRChat으로 전송하고 로그에 표시합니다. + error_message: 0 이상의 숫자만 설정할 수 있습니다. mic_word_filter: label: 단어 필터 - # 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: "등록된 단어가 감지되면 해당 문장은 전송되지 않습니다. \n ',' 쉼표로 구분하면 여러 단어를 추가할 수 있습니다. \n* 중복된 단어는 등록되지 않습니다." + add_button_label: 추가 + count_desc: "현재 등록되어 있는 단어 수: %{count}" speaker_dynamic_energy_threshold: - label_for_automatic: "음성 입력 최소 볼륨 (Current Setting: Automatic)" - # desc_for_automatic: "Automatically determine speaker input sensitivity." - label_for_manual: "음성 입력 최소 볼륨 (Current Setting: Manual)" - # desc_for_manual: "Manually determine the speaker input sensitivity using the slider. Press the headphones icon to listen to the audio and adjust the sensitivity while monitoring the volume." - # error_message: You can set it with a value between 0 to %{max}. - # no_device_error_message: No speaker device detected. + label_for_automatic: "음성 입력 최소 볼륨 (현재 설정: 자동)" + desc_for_automatic: "스피커의 입력 감도를 자동으로 조절합니다." + label_for_manual: "음성 입력 최소 볼륨 (현재 설정: 수동)" + desc_for_manual: "슬라이더를 움직여 입력 감도를 수동으로 조절합니다. 헤드폰 아이콘을 누르면 실제 음성의 볼륨을 확인하며 감도를 조절할 수 있습니다." + error_message: 0에서 %{max}까지의 숫자로만 설정할 수 있습니다. + no_device_error_message: 스피커 디바이스를 찾지 못했습니다. speaker_record_timeout: label: 최대 무음 시간 - # desc: Detects silence and, when the specified number of seconds has passed, considers the speaker input to have ended. (Second(s)) - # error_message: It cannot be greater than '%{speaker_phrase_timeout_label}' with a value of 0 or more. + desc: 무음을 감지하고 설정된 시간(초)만큼의 시간이 지나면 음성 입력이 종료된 것으로 판단합니다. + error_message: 0 이상에서 '%{speaker_phrase_timeout_label}'보다 클 수 없습니다. speaker_phrase_timeout: label: 최대 인식 시간 - # desc: Transcription processing is performed at intervals of the specified number of seconds. - # error_message: It cannot be set lower than '%{speaker_record_timeout_label}' with a value of 0 or more. + desc: 설정된 초 단위로 음성인식 처리가 이루어집니다. + error_message: 0 이상에서 '%{speaker_record_timeout_label}'보다 작을 수 없습니다. speaker_max_phrase: label: 최대 입력 절(phrases) 수 - # desc: It is the lower limit for the number of transcribed words, and only when this number is exceeded will the transcription results be displayed logs. - # error_message: You can set a number equal to or greater than 0. + desc: 식된 단어 수의 하한값으로, 이 수치를 초과하는 경우에만 결과를 로그에 표시합니다. + error_message: 0 이상의 숫자만 설정할 수 있습니다. auto_clear_the_message_box: label: 챗박스 자동 삭제 - # notice_xsoverlay: - # label: Notification XSOverlay (VR Only) - # desc: Notify received messages by using XSOverlay's notification feature. + send_only_translated_messages: + label: 번역된 메시지만 전송 - # auto_export_message_logs: - # label: Auto Export Message Logs - # desc: Automatically export the conversation messages as a text file. + send_message_button_type: + label: 메시지 전송 버튼 + hide: 숨김 (Enter 키를 사용하여 전송) + show: 표시 + show_and_disable_enter_key: 표시 (Enter 키 전송 비활성화) - 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." + notice_xsoverlay: + label: XSOverlay에서 알림 수신 기능 활성화 (VR 전용) + desc: 수신된 메시지를 XSOverlay의 기능을 통해 알림으로 받아볼 수 있습니다. + + auto_export_message_logs: + label: 대화 로그 자동 저장 + desc: logs 폴더에 텍스트 파일로 로그가 저장됩니다. + + send_message_to_vrc: + label: VRChat에 메시지 전송 + desc: "VRChat에 메시지를 보내지 않고 사용할 수 있는 방법이 있지만 지원되지 않습니다. VRChat에 메시지를 보내려면 이 기능을 활성화하세요." + + + send_message_format: + label: 메시지 형식 + desc: "메시지가 실제로 보이는 형식을 변경합니다. \n[message]가 메시지로 대체됩니다." + example_text: 이것은 예문입니다. 폰트, 줄바꿈 등 실제 표시와 다를 수 있습니다. + error_message: "[message]라는 문자는 사용할 수 없습니다." + + send_message_format_with_t: + label: 메시지 형식 (번역 포함) + desc: "메시지가 실제로 보이는 형식을 변경합니다. \n[message]는 메시지로, [translation]은 번역된 메시지로 대체됩니다.\nXSOverlay의 알림에서도 사용됩니다." example_text: 예문입니다. 글꼴, 줄 바꿈 등이 실제 표시와 다를 수 있습니다. + error_message: "[message]와 [translation]이라는 문자는 사용할 수 없습니다." + + received_message_format: + label: 메시지 형식 + desc: "메시지가 실제로 보이는 형식을 변경합니다. \n[message]가 메시지로 대체됩니다." + example_text: 이것은 예문입니다. 폰트, 줄바꿈 등 실제 표시와 다를 수 있습니다. + error_message: "[message]라는 문자는 사용할 수 없습니다." + + received_message_format_with_t: + label: 메시지 형식 (번역 포함) + desc: "메시지가 실제로 보이는 형식을 변경합니다. \n[message]는 메시지로, [translation]은 번역된 메시지로 대체됩니다.\nXSOverlay의 알림에서도 사용됩니다." + example_text: 이것은 예문입니다. 폰트, 줄바꿈 등 실제 표시와 다를 수 있습니다. + error_message: "[message]와 [translation]이라는 문자는 사용할 수 없습니다." - # send_message_to_vrc: - # label: Send Message To VRChat - # desc: There is a way to use it without sending messages to VRChat, but it is not supported. Enable this feature when you intend to send a message to VRChat. osc_ip_address: label: OSC IP 주소 osc_port: - label: OSC 포트 \ No newline at end of file + label: OSC 포트 + + open_config_filepath: + label: 설정 파일 열기 \ No newline at end of file diff --git a/model.py b/model.py index bff713f4..5fbb5825 100644 --- a/model.py +++ b/model.py @@ -1,8 +1,8 @@ +import tempfile from zipfile import ZipFile from subprocess import Popen from os import makedirs as os_makedirs from os import path as os_path -from os import remove as os_remove from shutil import copyfile from datetime import datetime from logging import getLogger, FileHandler, Formatter, INFO @@ -12,6 +12,8 @@ from threading import Thread, Event from requests import get as requests_get import webbrowser +from tqdm import tqdm +from typing import Callable from flashtext import KeywordProcessor from models.translation.translation_translator import Translator from models.transcription.transcription_utils import getInputDevices, getDefaultOutputDevice @@ -265,7 +267,7 @@ class Model: return update_flag @staticmethod - def updateSoftware(restart:bool=True): + def updateSoftware(restart:bool=True, func=None): filename = 'VRCT.zip' program_name = 'VRCT.exe' folder_name = '_internal' @@ -277,14 +279,22 @@ class Model: res = requests_get(config.GITHUB_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.extractall(os_path.join(current_directory, tmp_directory_name)) - os_remove(os_path.join(current_directory, tmp_directory_name, filename)) + with tempfile.TemporaryDirectory() as tmp_path: + res = requests_get(url, stream=True) + file_size = int(res.headers.get('content-length', 0)) + pbar = tqdm(total=file_size, unit="B", unit_scale=True) + total_chunk = 0 + with open(os_path.join(tmp_path, filename), 'wb') as file: + for chunk in res.iter_content(chunk_size=1024*5): + file.write(chunk) + pbar.update(len(chunk)) + if isinstance(func, Callable): + total_chunk += len(chunk) + func(total_chunk/file_size) + pbar.close() + + with ZipFile(os_path.join(tmp_path, filename)) as zf: + zf.extractall(os_path.join(current_directory, tmp_directory_name)) copyfile(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) diff --git a/requirements.txt b/requirements.txt index 42f4be2c..bff366c5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,4 +6,5 @@ deepl == 1.15.0 flashtext == 2.7 pyyaml == 6.0.1 python-i18n == 0.3.9 -CTkToolTip == 0.8 \ No newline at end of file +CTkToolTip == 0.8 +pyinstaller==6.2.0 \ No newline at end of file diff --git a/utils.py b/utils.py index a5e38fda..6a05a08d 100644 --- a/utils.py +++ b/utils.py @@ -6,7 +6,7 @@ def getImageFile(file_name): img = Image_open(os_path.join(os_path.dirname(__file__), "img", file_name)) return img -def get_key_by_value(dictionary, value): +def getKeyByValue(dictionary, value): for key, val in dictionary.items(): if val == value: return key @@ -24,15 +24,18 @@ def makeEven(number, minus:bool=False): return number if isEven(number) else number - 1 return number if isEven(number) else number + 1 -def generatePercentageStringsList(start=40, end=200, step=10): +def generatePercentageStringsList(start:int, end:int, step:int): strings = [] for percent in range(start, end + 1, step): strings.append(f"{percent}%") return strings -def intToPercentageStringsFormatter(value:int): +def intToPctStr(value:int): return f"{value}%" +def strPctToInt(value:str): + return int(value.replace("%", "")) + def isUniqueStrings(unique_strings:Union[str, list], input_string:str, require=False): import re if isinstance(unique_strings, str): diff --git a/venv.bat b/venv.bat new file mode 100644 index 00000000..21f16485 --- /dev/null +++ b/venv.bat @@ -0,0 +1,2 @@ +python -m venv .venv +.venv/Scripts/Activate.ps1 \ No newline at end of file diff --git a/view.py b/view.py index de8b66f1..546ab972 100644 --- a/view.py +++ b/view.py @@ -5,12 +5,10 @@ from tkinter import font as tk_font import webbrowser import i18n -from languages import selectable_languages - -from customtkinter import StringVar, IntVar, BooleanVar, END as CTK_END, get_appearance_mode +from customtkinter import StringVar, IntVar, BooleanVar, get_appearance_mode from vrct_gui.ui_managers import ColorThemeManager, UiScalingManager from vrct_gui import vrct_gui -from utils import callFunctionIfCallable, generatePercentageStringsList, intToPercentageStringsFormatter +from utils import callFunctionIfCallable, intToPctStr from config import config @@ -32,6 +30,11 @@ class View(): ui_language=config.UI_LANGUAGE, ) + if config.ENABLE_SPEAKER2CHATBOX is False: + VERSION_TEXT=i18n.t("config_window.version", version=config.VERSION) + else: + VERSION_TEXT=i18n.t("config_window.version", version=config.VERSION) + " (Speaker2Chatbox)" + self.settings = SimpleNamespace() theme = get_appearance_mode() if config.APPEARANCE_THEME == "System" else config.APPEARANCE_THEME all_ctm = ColorThemeManager(theme) @@ -45,6 +48,13 @@ class View(): self.settings.main = SimpleNamespace( ctm=all_ctm.main, uism=all_uism.main, + geometry=SimpleNamespace( + width=config.MAIN_WINDOW_GEOMETRY["width"], + height=config.MAIN_WINDOW_GEOMETRY["height"], + x_pos=config.MAIN_WINDOW_GEOMETRY["x_pos"], + y_pos=config.MAIN_WINDOW_GEOMETRY["y_pos"], + ), + to_restore_main_window_geometry=config.ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY, **common_args ) @@ -84,10 +94,13 @@ class View(): CALLBACK_OPEN_FILEPATH_LOGS=None, CALLBACK_OPEN_FILEPATH_CONFIG_FILE=None, - CALLBACK_QUIT_VRCT=vrct_gui._quitVRCT, + CALLBACK_DELETE_MAIN_WINDOW=self.quitVRCT, + CALLBACK_QUIT_VRCT=None, CALLBACK_WHEN_DETECT_WINDOW_OVERED_SIZE=self._showDisplayOverUiSizeConfirmationModal, + IS_ENTRY_MESSAGE_BOX_DISABLED=False, + # Confirmation Modal CALLBACK_HIDE_CONFIRMATION_MODAL=None, CALLBACK_ACCEPTED_CONFIRMATION_MODAL=None, @@ -135,7 +148,7 @@ class View(): CALLBACK_SELECTED_LANGUAGE_PRESET_TAB=None, VAR_LABEL_YOUR_LANGUAGE=StringVar(value=i18n.t("main_window.your_language")), - VAR_YOUR_LANGUAGE = StringVar(value="Japanese\n(Japan)"), + VAR_YOUR_LANGUAGE = StringVar(value=f"{config.SOURCE_LANGUAGE}\n({config.SOURCE_COUNTRY})"), CALLBACK_OPEN_SELECTABLE_YOUR_LANGUAGE_WINDOW=None, IS_OPENED_SELECTABLE_YOUR_LANGUAGE_WINDOW=False, CALLBACK_SELECTED_YOUR_LANGUAGE=None, @@ -145,7 +158,7 @@ class View(): 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)"), + VAR_TARGET_LANGUAGE = StringVar(value=f"{config.TARGET_LANGUAGE}\n({config.TARGET_COUNTRY})"), CALLBACK_OPEN_SELECTABLE_TARGET_LANGUAGE_WINDOW=None, IS_OPENED_SELECTABLE_TARGET_LANGUAGE_WINDOW=False, CALLBACK_SELECTED_TARGET_LANGUAGE=None, @@ -172,12 +185,12 @@ class View(): ACTIVE_SETTING_BOX_TAB_ATTR_NAME="side_menu_tab_appearance", CALLBACK_SELECTED_SETTING_BOX_TAB=None, VAR_ERROR_MESSAGE=StringVar(value=""), - VAR_VERSION=StringVar(value=i18n.t("config_window.version", version=config.VERSION)), + VAR_VERSION=StringVar(value=VERSION_TEXT), VAR_CONFIG_WINDOW_TITLE=StringVar(value=i18n.t("config_window.config_title")), 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, + CALLBACK_SLIDER_TOOLTIP_PERCENTAGE_FORMATTER=intToPctStr, # Side Menu Labels @@ -194,7 +207,7 @@ class View(): # Appearance Tab VAR_LABEL_TRANSPARENCY=StringVar(value=i18n.t("config_window.transparency.label")), VAR_DESC_TRANSPARENCY=StringVar(value=i18n.t("config_window.transparency.desc")), - SLIDER_RANGE_TRANSPARENCY=(50, 100), + SLIDER_RANGE_TRANSPARENCY=config.TRANSPARENCY_RANGE, CALLBACK_SET_TRANSPARENCY=None, VAR_TRANSPARENCY=IntVar(value=config.TRANSPARENCY), CALLBACK_BUTTON_PRESS_TRANSPARENCY=self._closeTheCoverOfMainWindow, @@ -202,24 +215,32 @@ 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=["Light", "Dark", "System"], + LIST_APPEARANCE_THEME=config.APPEARANCE_THEME_LIST, CALLBACK_SET_APPEARANCE_THEME=None, 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, - LIST_UI_SCALING=generatePercentageStringsList(start=40,end=200, step=10), + LIST_UI_SCALING=config.UI_SCALING_LIST, 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), + SLIDER_RANGE_TEXTBOX_UI_SCALING=config.TEXTBOX_UI_SCALING_RANGE, 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_MESSAGE_BOX_RATIO=StringVar(value=i18n.t("config_window.message_box_ratio.label")), + VAR_DESC_MESSAGE_BOX_RATIO=StringVar(value=i18n.t("config_window.message_box_ratio.desc")), + SLIDER_RANGE_MESSAGE_BOX_RATIO=config.MESSAGE_BOX_RATIO_RANGE, + CALLBACK_SET_MESSAGE_BOX_RATIO=None, + VAR_MESSAGE_BOX_RATIO=IntVar(value=config.MESSAGE_BOX_RATIO), + CALLBACK_BUTTON_PRESS_MESSAGE_BOX_RATIO=self._closeTheCoverOfMainWindow, + CALLBACK_BUTTON_RELEASE_MESSAGE_BOX_RATIO=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(), @@ -228,10 +249,14 @@ class View(): VAR_LABEL_UI_LANGUAGE=StringVar(value=i18n.t("config_window.ui_language.label")), VAR_DESC_UI_LANGUAGE=None, - LIST_UI_LANGUAGE=list(selectable_languages.values()), + LIST_UI_LANGUAGE=list(config.SELECTABLE_UI_LANGUAGES_DICT.values()), CALLBACK_SET_UI_LANGUAGE=None, - VAR_UI_LANGUAGE=StringVar(value=selectable_languages[config.UI_LANGUAGE]), + VAR_UI_LANGUAGE=StringVar(value=config.SELECTABLE_UI_LANGUAGES_DICT[config.UI_LANGUAGE]), + VAR_LABEL_ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY=StringVar(value=i18n.t("config_window.to_restore_main_window_geometry.label")), + VAR_DESC_ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY=StringVar(value=i18n.t("config_window.to_restore_main_window_geometry.desc")), + CALLBACK_SET_ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY=None, + VAR_ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY=BooleanVar(value=config.ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY), # Translation Tab VAR_LABEL_DEEPL_AUTH_KEY=StringVar(value=i18n.t("config_window.deepl_auth_key.label")), @@ -334,6 +359,21 @@ class View(): CALLBACK_SET_ENABLE_AUTO_CLEAR_MESSAGE_BOX=None, VAR_ENABLE_AUTO_CLEAR_MESSAGE_BOX=BooleanVar(value=config.ENABLE_AUTO_CLEAR_MESSAGE_BOX), + VAR_LABEL_ENABLE_SEND_ONLY_TRANSLATED_MESSAGES=StringVar(value=i18n.t("config_window.send_only_translated_messages.label")), + VAR_DESC_ENABLE_SEND_ONLY_TRANSLATED_MESSAGES=None, + CALLBACK_SET_ENABLE_SEND_ONLY_TRANSLATED_MESSAGES=None, + VAR_ENABLE_SEND_ONLY_TRANSLATED_MESSAGES=BooleanVar(value=config.ENABLE_SEND_ONLY_TRANSLATED_MESSAGES), + + VAR_LABEL_SEND_MESSAGE_BUTTON_TYPE=StringVar(value=i18n.t("config_window.send_message_button_type.label")), + VAR_DESC_SEND_MESSAGE_BUTTON_TYPE=None, + CALLBACK_SET_SEND_MESSAGE_BUTTON_TYPE=None, + VAR_SEND_MESSAGE_BUTTON_TYPE=StringVar(value=config.SEND_MESSAGE_BUTTON_TYPE), + KEYS_VALUES_SEND_MESSAGE_BUTTON_TYPE={ + "hide": StringVar(value=i18n.t("config_window.send_message_button_type.hide")), + "show": StringVar(value=i18n.t("config_window.send_message_button_type.show")), + "show_and_disable_enter_key": StringVar(value=i18n.t("config_window.send_message_button_type.show_and_disable_enter_key")), + }, + VAR_LABEL_ENABLE_NOTICE_XSOVERLAY=StringVar(value=i18n.t("config_window.notice_xsoverlay.label")), VAR_DESC_ENABLE_NOTICE_XSOVERLAY=StringVar(value=i18n.t("config_window.notice_xsoverlay.desc")), CALLBACK_SET_ENABLE_NOTICE_XSOVERLAY=None, @@ -345,32 +385,78 @@ class View(): VAR_ENABLE_AUTO_EXPORT_MESSAGE_LOGS=BooleanVar(value=config.ENABLE_LOGGER), - 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")), VAR_DESC_ENABLE_SEND_MESSAGE_TO_VRC=StringVar(value=i18n.t("config_window.send_message_to_vrc.desc")), CALLBACK_SET_ENABLE_SEND_MESSAGE_TO_VRC=None, VAR_ENABLE_SEND_MESSAGE_TO_VRC=BooleanVar(value=config.ENABLE_SEND_MESSAGE_TO_VRC), - # [deprecated] - # VAR_LABEL_STARTUP_OSC_ENABLED_CHECK=StringVar(value=i18n.t("config_window.startup_osc_enabled_check.label")), - # VAR_DESC_STARTUP_OSC_ENABLED_CHECK=StringVar(value=i18n.t("config_window.startup_osc_enabled_check.desc")), - # CALLBACK_SET_STARTUP_OSC_ENABLED_CHECK=None, - # VAR_STARTUP_OSC_ENABLED_CHECK=BooleanVar(value=config.STARTUP_OSC_ENABLED_CHECK), + VAR_SECOND_TITLE_OTHERS_SEND_MESSAGE_FORMATS=StringVar(value=i18n.t("config_window.side_menu_labels.others_send_message_formats")), + + + VAR_LABEL_SEND_MESSAGE_FORMAT=StringVar(value=i18n.t("config_window.send_message_format.label")), + VAR_DESC_SEND_MESSAGE_FORMAT=StringVar(value=i18n.t("config_window.send_message_format.desc")), + CALLBACK_SET_SEND_MESSAGE_FORMAT=None, + VAR_SEND_MESSAGE_FORMAT=StringVar(value=config.SEND_MESSAGE_FORMAT), + VAR_LABEL_EXAMPLE_TEXT_SEND_MESSAGE_FORMAT=StringVar(value=""), + VAR_ENTRY_0_SEND_MESSAGE_FORMAT=StringVar(value=""), + VAR_ENTRY_1_SEND_MESSAGE_FORMAT=StringVar(value=""), + VAR_TEXT_REQUIRED_0_SEND_MESSAGE_FORMAT=StringVar(value="[message]"), + CALLBACK_FOCUS_OUT_SEND_MESSAGE_FORMAT=self.callbackBindFocusOut_SendMessageFormat, + + + VAR_LABEL_SEND_MESSAGE_FORMAT_WITH_T=StringVar(value=i18n.t("config_window.send_message_format_with_t.label")), + VAR_DESC_SEND_MESSAGE_FORMAT_WITH_T=StringVar(value=i18n.t("config_window.send_message_format_with_t.desc")), + CALLBACK_SET_SEND_MESSAGE_FORMAT_WITH_T=None, + CALLBACK_SWAP_SEND_MESSAGE_FORMAT_WITH_T_REQUIRED_TEXT=self._swapSendMessageFormatWithT_RequiredText, + VAR_SEND_MESSAGE_FORMAT_WITH_T=StringVar(value=config.SEND_MESSAGE_FORMAT_WITH_T), + VAR_LABEL_EXAMPLE_TEXT_SEND_MESSAGE_FORMAT_WITH_T=StringVar(value=""), + VAR_ENTRY_0_SEND_MESSAGE_FORMAT_WITH_T=StringVar(value=""), + VAR_ENTRY_1_SEND_MESSAGE_FORMAT_WITH_T=StringVar(value=""), + VAR_ENTRY_2_SEND_MESSAGE_FORMAT_WITH_T=StringVar(value=""), + VAR_TEXT_REQUIRED_0_SEND_MESSAGE_FORMAT_WITH_T=StringVar(value="[message]"), + VAR_TEXT_REQUIRED_1_SEND_MESSAGE_FORMAT_WITH_T=StringVar(value="[translation]"), + CALLBACK_FOCUS_OUT_SEND_MESSAGE_FORMAT_WITH_T=self.callbackBindFocusOut_SendMessageFormatWithT, + + + + VAR_LABEL_RECEIVED_MESSAGE_FORMAT=StringVar(value=i18n.t("config_window.received_message_format.label")), + VAR_DESC_RECEIVED_MESSAGE_FORMAT=StringVar(value=i18n.t("config_window.received_message_format.desc")), + CALLBACK_SET_RECEIVED_MESSAGE_FORMAT=None, + VAR_RECEIVED_MESSAGE_FORMAT=StringVar(value=config.RECEIVED_MESSAGE_FORMAT), + VAR_LABEL_EXAMPLE_TEXT_RECEIVED_MESSAGE_FORMAT=StringVar(value=""), + VAR_ENTRY_0_RECEIVED_MESSAGE_FORMAT=StringVar(value=""), + VAR_ENTRY_1_RECEIVED_MESSAGE_FORMAT=StringVar(value=""), + VAR_TEXT_REQUIRED_0_RECEIVED_MESSAGE_FORMAT=StringVar(value="[message]"), + CALLBACK_FOCUS_OUT_RECEIVED_MESSAGE_FORMAT=self.callbackBindFocusOut_ReceivedMessageFormat, + + + VAR_SECOND_TITLE_OTHERS_RECEIVED_MESSAGE_FORMATS=StringVar(value=i18n.t("config_window.side_menu_labels.others_received_message_formats")), + + VAR_LABEL_RECEIVED_MESSAGE_FORMAT_WITH_T=StringVar(value=i18n.t("config_window.received_message_format_with_t.label")), + VAR_DESC_RECEIVED_MESSAGE_FORMAT_WITH_T=StringVar(value=i18n.t("config_window.received_message_format_with_t.desc")), + CALLBACK_SET_RECEIVED_MESSAGE_FORMAT_WITH_T=None, + CALLBACK_SWAP_RECEIVED_MESSAGE_FORMAT_WITH_T_REQUIRED_TEXT=self._swapReceivedMessageFormatWithT_RequiredText, + VAR_RECEIVED_MESSAGE_FORMAT_WITH_T=StringVar(value=config.RECEIVED_MESSAGE_FORMAT_WITH_T), + VAR_LABEL_EXAMPLE_TEXT_RECEIVED_MESSAGE_FORMAT_WITH_T=StringVar(value=""), + VAR_ENTRY_0_RECEIVED_MESSAGE_FORMAT_WITH_T=StringVar(value=""), + VAR_ENTRY_1_RECEIVED_MESSAGE_FORMAT_WITH_T=StringVar(value=""), + VAR_ENTRY_2_RECEIVED_MESSAGE_FORMAT_WITH_T=StringVar(value=""), + VAR_TEXT_REQUIRED_0_RECEIVED_MESSAGE_FORMAT_WITH_T=StringVar(value="[message]"), + VAR_TEXT_REQUIRED_1_RECEIVED_MESSAGE_FORMAT_WITH_T=StringVar(value="[translation]"), + CALLBACK_FOCUS_OUT_RECEIVED_MESSAGE_FORMAT_WITH_T=self.callbackBindFocusOut_ReceivedMessageFormatWithT, + + + # -------------------Speaker2Chatbox----------- + VAR_SECOND_TITLE_OTHERS_SPEAKER2CHATBOX=StringVar(value=i18n.t("config_window.side_menu_labels.others_speaker2chatbox")), + + VAR_LABEL_ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC=StringVar(value=i18n.t("config_window.send_received_message_to_vrc.label")), + VAR_DESC_ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC=StringVar(value=i18n.t("config_window.send_received_message_to_vrc.desc")), + CALLBACK_SET_ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC=None, + VAR_ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC=BooleanVar(value=config.ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC), + # -------------------Speaker2Chatbox----------- + # Advanced Settings Tab @@ -404,6 +490,7 @@ class View(): 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) + self.view_variable.CALLBACK_QUIT_VRCT=common_registers.get("callback_quit_vrct", None) if window_action_registers is not None: @@ -429,9 +516,21 @@ class View(): self.view_variable.CALLBACK_SELECTED_LANGUAGE_PRESET_TAB = main_window_registers.get("callback_selected_language_preset_tab", None) + def adjustedMessageBoxReturnFunction(_e): + if self.view_variable.IS_ENTRY_MESSAGE_BOX_DISABLED is True: + return + if config.SEND_MESSAGE_BUTTON_TYPE != "show_and_disable_enter_key": + main_window_registers.get("message_box_bind_Return")() + return "break" # For deleting the next line that will be inserted when the Enter key is pressed. + def pressedSendMessageButtonFunction(_e): + main_window_registers.get("message_box_bind_Return")() + vrct_gui.entry_message_box.focus() + entry_message_box = getattr(vrct_gui, "entry_message_box") - entry_message_box.bind("", main_window_registers.get("message_box_bind_Return")) + entry_message_box.bind("", lambda _e: None) # This is to prevent message sending on Shift + Enter key press and just add a new line. + entry_message_box.bind("", adjustedMessageBoxReturnFunction) entry_message_box.bind("", main_window_registers.get("message_box_bind_Any_KeyPress")) + self.view_variable.CALLBACK_CLICKED_SEND_MESSAGE_BUTTON = pressedSendMessageButtonFunction entry_message_box.bind("", main_window_registers.get("message_box_bind_FocusIn")) @@ -461,8 +560,10 @@ 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_MESSAGE_BOX_RATIO = config_window_registers.get("callback_set_message_box_ratio", 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) + self.view_variable.CALLBACK_SET_ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY = config_window_registers.get("callback_set_enable_restore_main_window_geometry", None) # Translation Tab @@ -494,12 +595,23 @@ class View(): # Others Tab self.view_variable.CALLBACK_SET_ENABLE_AUTO_CLEAR_MESSAGE_BOX = config_window_registers.get("callback_set_enable_auto_clear_chatbox", None) + self.view_variable.CALLBACK_SET_ENABLE_SEND_ONLY_TRANSLATED_MESSAGES = config_window_registers.get("callback_set_send_only_translated_messages", None) + self.view_variable.CALLBACK_SET_SEND_MESSAGE_BUTTON_TYPE = config_window_registers.get("callback_set_send_message_button_type", None) self.view_variable.CALLBACK_SET_ENABLE_NOTICE_XSOVERLAY = config_window_registers.get("callback_set_enable_notice_xsoverlay", None) self.view_variable.CALLBACK_SET_ENABLE_AUTO_EXPORT_MESSAGE_LOGS = config_window_registers.get("callback_set_enable_auto_export_message_logs", None) - self.view_variable.CALLBACK_SET_MESSAGE_FORMAT = config_window_registers.get("callback_set_message_format", None) self.view_variable.CALLBACK_SET_ENABLE_SEND_MESSAGE_TO_VRC = config_window_registers.get("callback_set_enable_send_message_to_vrc", None) - # self.view_variable.CALLBACK_SET_STARTUP_OSC_ENABLED_CHECK = config_window_registers.get("callback_set_startup_osc_enabled_check", None) #[deprecated] + + self.view_variable.CALLBACK_SET_SEND_MESSAGE_FORMAT = config_window_registers.get("callback_set_send_message_format", None) + self.view_variable.CALLBACK_SET_SEND_MESSAGE_FORMAT_WITH_T = config_window_registers.get("callback_set_send_message_format_with_t", None) + self.view_variable.CALLBACK_SET_RECEIVED_MESSAGE_FORMAT = config_window_registers.get("callback_set_received_message_format", None) + self.view_variable.CALLBACK_SET_RECEIVED_MESSAGE_FORMAT_WITH_T = config_window_registers.get("callback_set_received_message_format_with_t", None) + + # Speaker2Chatbox---------------- + self.view_variable.CALLBACK_SET_ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC = config_window_registers.get("callback_set_enable_send_received_message_to_vrc", None) + # Speaker2Chatbox---------------- + + # Advanced Settings Tab self.view_variable.CALLBACK_SET_OSC_IP_ADDRESS = config_window_registers.get("callback_set_osc_ip_address", None) @@ -510,6 +622,7 @@ class View(): self.enableConfigWindowCompactMode() vrct_gui.config_window.setting_box_compact_mode_switch_box.select() + self.setMainWindowMessageBoxRatio(config.MESSAGE_BOX_RATIO) if config.CHOICE_MIC_HOST == "NoHost": self.view_variable.VAR_MIC_HOST.set("No Mic Host Detected") @@ -527,6 +640,13 @@ class View(): ) self.replaceMicThresholdCheckButton_Disabled() + if config.ENABLE_SPEAKER2CHATBOX is False: + vrct_gui._changeConfigWindowWidgetsStatus( + status="disabled", + target_names=[ + "sb__checkbox_enable_send_received_message_to_vrc", + ] + ) if config.INPUT_MIC_DYNAMIC_ENERGY_THRESHOLD is True: self.closeMicEnergyThresholdWidget() @@ -539,55 +659,137 @@ class View(): self.openSpeakerEnergyThresholdWidget() - self.setMessageFormatEntryWidgets(config.MESSAGE_FORMAT) + self.setSendMessageFormat_EntryWidgets(config.SEND_MESSAGE_FORMAT) + self.setSendMessageFormatWithT_EntryWidgets(config.SEND_MESSAGE_FORMAT_WITH_T) + self.setReceivedMessageFormat_EntryWidgets(config.RECEIVED_MESSAGE_FORMAT) + self.setReceivedMessageFormatWithT_EntryWidgets(config.RECEIVED_MESSAGE_FORMAT_WITH_T) # Insert sample conversation for testing. # self._insertSampleConversationToTextbox() - - def setMessageFormatEntryWidgets(self, message_format:str): +# Send Message Format + def setSendMessageFormat_EntryWidgets(self, message_format:str): result = self.extractMessageFormat(message_format) + self.view_variable.VAR_ENTRY_0_SEND_MESSAGE_FORMAT.set(result.before) + self.view_variable.VAR_ENTRY_1_SEND_MESSAGE_FORMAT.set(result.after) + self.updateSendMessageFormat_ExampleTextWidget() + + def updateSendMessageFormat_ExampleTextWidget(self): + message = i18n.t("config_window.send_message_format.example_text") + example_message = config.SEND_MESSAGE_FORMAT.replace("[message]", message) + + self.view_variable.VAR_LABEL_EXAMPLE_TEXT_SEND_MESSAGE_FORMAT.set(example_message) + + +# Send Message Format With Translation + def setSendMessageFormatWithT_EntryWidgets(self, message_format:str): + result = self.extractMessageFormatWithT(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]") + self.view_variable.VAR_TEXT_REQUIRED_0_SEND_MESSAGE_FORMAT_WITH_T.set("[message]") + self.view_variable.VAR_TEXT_REQUIRED_1_SEND_MESSAGE_FORMAT_WITH_T.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_TEXT_REQUIRED_0_SEND_MESSAGE_FORMAT_WITH_T.set("[translation]") + self.view_variable.VAR_TEXT_REQUIRED_1_SEND_MESSAGE_FORMAT_WITH_T.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() + self.view_variable.VAR_ENTRY_0_SEND_MESSAGE_FORMAT_WITH_T.set(result.before) + self.view_variable.VAR_ENTRY_1_SEND_MESSAGE_FORMAT_WITH_T.set(result.between) + self.view_variable.VAR_ENTRY_2_SEND_MESSAGE_FORMAT_WITH_T.set(result.after) + self.updateSendMessageFormatWithT_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() + def _swapSendMessageFormatWithT_RequiredText(self): + text_0 = self.view_variable.VAR_TEXT_REQUIRED_0_SEND_MESSAGE_FORMAT_WITH_T.get() + text_1 = self.view_variable.VAR_TEXT_REQUIRED_1_SEND_MESSAGE_FORMAT_WITH_T.get() + self.view_variable.VAR_TEXT_REQUIRED_0_SEND_MESSAGE_FORMAT_WITH_T.set(text_1) + self.view_variable.VAR_TEXT_REQUIRED_1_SEND_MESSAGE_FORMAT_WITH_T.set(text_0) + self.updateSendMessageFormatWithT_ExampleTextWidget() - new_message_format = self.getLatestMessageFormatFromWidget() - callFunctionIfCallable(self.view_variable.CALLBACK_SET_MESSAGE_FORMAT, new_message_format) + new_message_format = self.getLatestMessageFormatWithT_FromWidget() + callFunctionIfCallable(self.view_variable.CALLBACK_SET_SEND_MESSAGE_FORMAT_WITH_T, 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() + def getLatestMessageFormatWithT_FromWidget(self): + text_0 = self.view_variable.VAR_TEXT_REQUIRED_0_SEND_MESSAGE_FORMAT_WITH_T.get() + text_1 = self.view_variable.VAR_TEXT_REQUIRED_1_SEND_MESSAGE_FORMAT_WITH_T.get() + entry_0 = self.view_variable.VAR_ENTRY_0_SEND_MESSAGE_FORMAT_WITH_T.get() + entry_1 = self.view_variable.VAR_ENTRY_1_SEND_MESSAGE_FORMAT_WITH_T.get() + entry_2 = self.view_variable.VAR_ENTRY_2_SEND_MESSAGE_FORMAT_WITH_T.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) + def updateSendMessageFormatWithT_ExampleTextWidget(self): + message = i18n.t("config_window.send_message_format_with_t.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) + translation = i18n.t("config_window.send_message_format_with_t.example_text", locale=translation_locale) - example_message = config.MESSAGE_FORMAT.replace("[message]", message) + example_message = config.SEND_MESSAGE_FORMAT_WITH_T.replace("[message]", message) example_message = example_message.replace("[translation]", translation) - self.view_variable.VAR_LABEL_EXAMPLE_TEXT_MESSAGE_FORMAT.set(example_message) + self.view_variable.VAR_LABEL_EXAMPLE_TEXT_SEND_MESSAGE_FORMAT_WITH_T.set(example_message) + + +# Received Message Format + def setReceivedMessageFormat_EntryWidgets(self, message_format:str): + result = self.extractMessageFormat(message_format) + + self.view_variable.VAR_ENTRY_0_RECEIVED_MESSAGE_FORMAT.set(result.before) + self.view_variable.VAR_ENTRY_1_RECEIVED_MESSAGE_FORMAT.set(result.after) + self.updateReceivedMessageFormat_ExampleTextWidget() + + def updateReceivedMessageFormat_ExampleTextWidget(self): + message = i18n.t("config_window.received_message_format.example_text") + example_message = config.RECEIVED_MESSAGE_FORMAT.replace("[message]", message) + + self.view_variable.VAR_LABEL_EXAMPLE_TEXT_RECEIVED_MESSAGE_FORMAT.set(example_message) + + +# Received Message Format With Translation + def setReceivedMessageFormatWithT_EntryWidgets(self, message_format:str): + result = self.extractMessageFormatWithT(message_format) + + if result.is_message_first is True: + self.view_variable.VAR_TEXT_REQUIRED_0_RECEIVED_MESSAGE_FORMAT_WITH_T.set("[message]") + self.view_variable.VAR_TEXT_REQUIRED_1_RECEIVED_MESSAGE_FORMAT_WITH_T.set("[translation]") + else: + self.view_variable.VAR_TEXT_REQUIRED_0_RECEIVED_MESSAGE_FORMAT_WITH_T.set("[translation]") + self.view_variable.VAR_TEXT_REQUIRED_1_RECEIVED_MESSAGE_FORMAT_WITH_T.set("[message]") + + self.view_variable.VAR_ENTRY_0_RECEIVED_MESSAGE_FORMAT_WITH_T.set(result.before) + self.view_variable.VAR_ENTRY_1_RECEIVED_MESSAGE_FORMAT_WITH_T.set(result.between) + self.view_variable.VAR_ENTRY_2_RECEIVED_MESSAGE_FORMAT_WITH_T.set(result.after) + self.updateReceivedMessageFormatWithT_ExampleTextWidget() + + def _swapReceivedMessageFormatWithT_RequiredText(self): + text_0 = self.view_variable.VAR_TEXT_REQUIRED_0_RECEIVED_MESSAGE_FORMAT_WITH_T.get() + text_1 = self.view_variable.VAR_TEXT_REQUIRED_1_RECEIVED_MESSAGE_FORMAT_WITH_T.get() + self.view_variable.VAR_TEXT_REQUIRED_0_RECEIVED_MESSAGE_FORMAT_WITH_T.set(text_1) + self.view_variable.VAR_TEXT_REQUIRED_1_RECEIVED_MESSAGE_FORMAT_WITH_T.set(text_0) + self.updateReceivedMessageFormatWithT_ExampleTextWidget() + + new_message_format = self.getLatestReceivedMessageFormatWithT_FromWidget() + callFunctionIfCallable(self.view_variable.CALLBACK_SET_RECEIVED_MESSAGE_FORMAT_WITH_T, new_message_format) + + + def getLatestReceivedMessageFormatWithT_FromWidget(self): + text_0 = self.view_variable.VAR_TEXT_REQUIRED_0_RECEIVED_MESSAGE_FORMAT_WITH_T.get() + text_1 = self.view_variable.VAR_TEXT_REQUIRED_1_RECEIVED_MESSAGE_FORMAT_WITH_T.get() + entry_0 = self.view_variable.VAR_ENTRY_0_RECEIVED_MESSAGE_FORMAT_WITH_T.get() + entry_1 = self.view_variable.VAR_ENTRY_1_RECEIVED_MESSAGE_FORMAT_WITH_T.get() + entry_2 = self.view_variable.VAR_ENTRY_2_RECEIVED_MESSAGE_FORMAT_WITH_T.get() + return entry_0+text_0+entry_1+text_1+entry_2 + + def updateReceivedMessageFormatWithT_ExampleTextWidget(self): + message = i18n.t("config_window.received_message_format_with_t.example_text", locale=config.UI_LANGUAGE) + translation_locale = "ja" if config.UI_LANGUAGE == "en" else "en" + translation = i18n.t("config_window.received_message_format_with_t.example_text", locale=translation_locale) + + example_message = config.RECEIVED_MESSAGE_FORMAT_WITH_T.replace("[message]", message) + example_message = example_message.replace("[translation]", translation) + + self.view_variable.VAR_LABEL_EXAMPLE_TEXT_RECEIVED_MESSAGE_FORMAT_WITH_T.set(example_message) + + + # GUI process @@ -603,7 +805,9 @@ class View(): vrct_gui._showGUI() vrct_gui._startMainLoop() - + def quitVRCT(self): + callFunctionIfCallable(self.view_variable.CALLBACK_QUIT_VRCT) + vrct_gui._quitVRCT() # Common @staticmethod @@ -617,6 +821,25 @@ class View(): def openWebPage(url:str): webbrowser.open_new_tab(url) + @staticmethod + def getMainWindowGeometry(return_int:bool=False): + if return_int is True: + return { + "width": vrct_gui.winfo_toplevel().winfo_width(), + "height": vrct_gui.winfo_toplevel().winfo_height(), + "x_pos": vrct_gui.winfo_toplevel().winfo_x(), + "y_pos": vrct_gui.winfo_toplevel().winfo_y(), + } + + return { + "width": str(vrct_gui.winfo_toplevel().winfo_width()), + "height": str(vrct_gui.winfo_toplevel().winfo_height()), + "x_pos": str(vrct_gui.winfo_toplevel().winfo_x()), + "y_pos": str(vrct_gui.winfo_toplevel().winfo_y()), + } + + def getPreUiScaling(self): + return self.restart_required_configs_pre_data.ui_scaling # Open Webpage Functions def openWebPage_Booth(self): @@ -629,9 +852,16 @@ class View(): # Widget Control # Common + + # Note: The difference between _clearEntryBox and _clearTextBox + # idk why, but in CTkEntry and CTkTextbox, the first argument for the delete function is different. Otherwise, it throws an error. @staticmethod def _clearEntryBox(entry_widget): - entry_widget.delete(0, CTK_END) + entry_widget.delete(0, "end") + + @staticmethod + def _clearTextBox(entry_widget): + entry_widget.delete("1.0", "end") def clearErrorMessage(self): vrct_gui._clearErrorMessage() @@ -658,6 +888,17 @@ class View(): self.view_variable.IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE = False vrct_gui._disableMainWindowSidebarCompactMode() + def changeTranscriptionDisplayStatus(self, status): + match (status): + case "MIC_ON": + vrct_gui.sls__box_your_language_mic_status__enabled.place(relx=0.1, rely=0.2, anchor="center") + case "MIC_OFF": + vrct_gui.sls__box_your_language_mic_status__enabled.place_forget() + case "SPEAKER_ON": + vrct_gui.sls__box_target_language_speaker_status__enabled.place(relx=0.1, rely=0.2, anchor="center") + case "SPEAKER_OFF": + vrct_gui.sls__box_target_language_speaker_status__enabled.place_forget() + # Config Window def enableConfigWindowCompactMode(self): @@ -909,6 +1150,37 @@ class View(): def setMainWindowTextboxUiSize(custom_font_size_scale:float): vrct_gui.print_to_textbox.setTagsSettings(custom_font_size_scale=custom_font_size_scale) + def setMainWindowMessageBoxRatio(self, message_box_ratio:int): + if message_box_ratio < config.MESSAGE_BOX_RATIO_RANGE[0] or message_box_ratio > config.MESSAGE_BOX_RATIO_RANGE[1]: + raise ValueError(f"Input must be between {config.MESSAGE_BOX_RATIO_RANGE[0]} and {config.MESSAGE_BOX_RATIO_RANGE[1]} (inclusive)") + + vrct_gui.main_bg_container.grid_rowconfigure(tuple(range(config.MESSAGE_BOX_RATIO_RANGE[0], config.MESSAGE_BOX_RATIO_RANGE[1]+2)), weight=1) + textbox_ratio = int((config.MESSAGE_BOX_RATIO_RANGE[1]+1) - message_box_ratio) + message_box_row = int(textbox_ratio + 1) + message_box_rowwpan = int((config.MESSAGE_BOX_RATIO_RANGE[1]+1) - textbox_ratio) + vrct_gui.main_textbox_container.grid(row=1, rowspan=textbox_ratio, column=0, sticky="nsew") + vrct_gui.main_entry_message_container.grid(row=message_box_row, rowspan=message_box_rowwpan, column=0, sticky="nsew") + + new_send_message_button_width = int(self.settings.main.uism.SEND_MESSAGE_BUTTON_RATE_WIDTH * message_box_ratio) + + if new_send_message_button_width > self.settings.main.uism.SEND_MESSAGE_BUTTON_MAX_WIDTH: + new_send_message_button_width = self.settings.main.uism.SEND_MESSAGE_BUTTON_MAX_WIDTH + + if new_send_message_button_width < self.settings.main.uism.SEND_MESSAGE_BUTTON_MIN_WIDTH: + new_send_message_button_width = self.settings.main.uism.SEND_MESSAGE_BUTTON_MIN_WIDTH + + vrct_gui.main_send_message_button_container.grid_columnconfigure(0, weight=0, minsize=new_send_message_button_width) + + @staticmethod + def changeMainWindowSendMessageButton(status:str): + match (status): + case "hide": + vrct_gui.main_send_message_button_container.grid_remove() + vrct_gui.config_window.after(200, vrct_gui.config_window.lift) + case "show" | "show_and_disable_enter_key": + vrct_gui.main_send_message_button_container.grid() + vrct_gui.config_window.after(200, vrct_gui.config_window.lift) + # Function def _adjustUiSizeAndRestart(self): current_percentage = int(config.UI_SCALING.replace("%","")) @@ -1096,7 +1368,11 @@ class View(): self.view_variable.VAR_SPEAKER_MAX_PHRASES.set(str(value)) + def setGuiVariable_OscIpAddress(self, value): + self.view_variable.VAR_OSC_IP_ADDRESS.set(str(value)) + def setGuiVariable_OscPort(self, value): + self.view_variable.VAR_OSC_PORT.set(int(value)) @@ -1122,8 +1398,14 @@ class View(): case "SpeakerMaxPhrases": self.setGuiVariable_SpeakerMaxPhrases(config.INPUT_SPEAKER_MAX_PHRASES) - case "MessageFormat": - self.setMessageFormatEntryWidgets(config.MESSAGE_FORMAT) + case "SendMessageFormat": + self.setSendMessageFormat_EntryWidgets(config.SEND_MESSAGE_FORMAT) + case "SendMessageFormatWithT": + self.setSendMessageFormatWithT_EntryWidgets(config.SEND_MESSAGE_FORMAT_WITH_T) + case "ReceivedMessageFormat": + self.setReceivedMessageFormat_EntryWidgets(config.RECEIVED_MESSAGE_FORMAT) + case "ReceivedMessageFormatWithT": + self.setReceivedMessageFormatWithT_EntryWidgets(config.RECEIVED_MESSAGE_FORMAT_WITH_T) case _: raise ValueError(f"No matching case for target_name: {target_name}") @@ -1230,10 +1512,10 @@ class View(): # Message Box @staticmethod def getTextFromMessageBox(): - return vrct_gui.entry_message_box.get() + return vrct_gui.entry_message_box.get('1.0', "end-1c") def clearMessageBox(self): - self._clearEntryBox(vrct_gui.entry_message_box) + self._clearTextBox(vrct_gui.entry_message_box) @@ -1274,10 +1556,21 @@ class View(): self.clearErrorMessage() - def callbackBindFocusOut_MessageFormat(self, _e=None): - self.setLatestConfigVariable("MessageFormat") + def callbackBindFocusOut_SendMessageFormat(self, _e=None): + self.setLatestConfigVariable("SendMessageFormat") self.clearErrorMessage() + def callbackBindFocusOut_SendMessageFormatWithT(self, _e=None): + self.setLatestConfigVariable("SendMessageFormatWithT") + self.clearErrorMessage() + + def callbackBindFocusOut_ReceivedMessageFormat(self, _e=None): + self.setLatestConfigVariable("ReceivedMessageFormat") + self.clearErrorMessage() + + def callbackBindFocusOut_ReceivedMessageFormatWithT(self, _e=None): + self.setLatestConfigVariable("ReceivedMessageFormatWithT") + self.clearErrorMessage() @@ -1359,12 +1652,31 @@ class View(): ) - def showErrorMessage_MessageFormat(self): + def showErrorMessage_SendMessageFormat(self): self._showErrorMessage( - vrct_gui.config_window.sb__entry_message_format_2, - self._makeInvalidValueErrorMessage(i18n.t("config_window.message_format.error_message")) + vrct_gui.config_window.sb__entry_send_message_format_1, + self._makeInvalidValueErrorMessage(i18n.t("config_window.send_message_format.error_message")) ) + def showErrorMessage_SendMessageFormatWithT(self): + self._showErrorMessage( + vrct_gui.config_window.sb__entry_send_message_format_with_t_2, + self._makeInvalidValueErrorMessage(i18n.t("config_window.send_message_format_with_t.error_message")) + ) + + def showErrorMessage_ReceivedMessageFormat(self): + self._showErrorMessage( + vrct_gui.config_window.sb__entry_received_message_format_1, + self._makeInvalidValueErrorMessage(i18n.t("config_window.received_message_format.error_message")) + ) + + def showErrorMessage_ReceivedMessageFormatWithT(self): + self._showErrorMessage( + vrct_gui.config_window.sb__entry_received_message_format_with_t_2, + self._makeInvalidValueErrorMessage(i18n.t("config_window.received_message_format_with_t.error_message")) + ) + + @staticmethod def _makeInvalidValueErrorMessage(error_message): return i18n.t("config_window.common_error_message.invalid_value") + "\n" + error_message @@ -1373,9 +1685,17 @@ class View(): self.view_variable.VAR_ERROR_MESSAGE.set(message) vrct_gui._showErrorMessage(target_widget=target_widget) - @staticmethod def extractMessageFormat(text): + split_result = text.split("[message]") + result_data = SimpleNamespace( + before = split_result[0], + after = split_result[1], + ) + return result_data + + @staticmethod + def extractMessageFormatWithT(text): import re message_index = text.find("[message]") translation_index = text.find("[translation]") diff --git a/vrct_gui/_CreateConfirmationModal.py b/vrct_gui/_CreateConfirmationModal.py index 935f0447..7391a594 100644 --- a/vrct_gui/_CreateConfirmationModal.py +++ b/vrct_gui/_CreateConfirmationModal.py @@ -70,7 +70,6 @@ class _CreateConfirmationModal(CTkToplevel): if modal_type == "information": - # self.modal_buttons_wrapper.grid_columnconfigure(1, weight=1, minsize=self.settings.uism.BUTTONS_BETWEEN_PADDING) self.modal_buttons_wrapper.grid_columnconfigure((0,2), weight=1) @@ -222,6 +221,7 @@ class _CreateConfirmationModal(CTkToplevel): target_widget=self ) fadeInAnimation(self, steps=5, interval=0.005, max_alpha=1) + self.lift() self.focus_set() diff --git a/vrct_gui/_CreateDropdownMenuWindow.py b/vrct_gui/_CreateDropdownMenuWindow.py index b0f459dd..0eade683 100644 --- a/vrct_gui/_CreateDropdownMenuWindow.py +++ b/vrct_gui/_CreateDropdownMenuWindow.py @@ -1,9 +1,9 @@ from types import SimpleNamespace -from customtkinter import CTkToplevel, CTkFrame, CTkLabel, CTkFont, CTkScrollableFrame +from customtkinter import CTkToplevel, CTkFrame, CTkLabel, CTkFont from time import sleep -from .ui_utils import bindButtonReleaseFunction, bindEnterAndLeaveColor, bindButtonPressColor, getLatestHeight, applyUiScalingAndFixTheBugScrollBar, getLatestWidth, getLongestText +from .ui_utils import bindButtonReleaseFunction, bindEnterAndLeaveColor, bindButtonPressColor, getLatestHeight, applyUiScalingAndFixTheBugScrollBar, getLatestWidth, getLongestText, CustomizedCTkScrollableFrame from functools import partial from utils import isEven, makeEven @@ -121,7 +121,7 @@ class _CreateDropdownMenuWindow(CTkToplevel): BORDER_WIDTH=self.window_border_width - self.scroll_frame_container = CTkScrollableFrame( + self.scroll_frame_container = CustomizedCTkScrollableFrame( self.dropdown_menu_container, corner_radius=0, fg_color=self.window_bg_color, @@ -180,7 +180,6 @@ class _CreateDropdownMenuWindow(CTkToplevel): __dropdown_menu_value_wrapper.grid_rowconfigure((0,2), weight=1) - # __dropdown_menu_value_wrapper.grid_columnconfigure(0, weight=1) __label_widget = CTkLabel( __dropdown_menu_value_wrapper, text=longest_text, @@ -190,7 +189,6 @@ class _CreateDropdownMenuWindow(CTkToplevel): anchor="w", text_color=self.values_text_color, ) - # setattr(self, f"l", __label_widget) __label_widget.grid(row=1, column=0, padx=self.value_ipadx, pady=self.value_ipady, sticky="w") @@ -198,7 +196,7 @@ class _CreateDropdownMenuWindow(CTkToplevel): label_width = getLatestWidth(__label_widget) label_width += self.scroll_frame_container._scrollbar.winfo_width() + (self.window_border_width*2) + (self.scrollbar_ipadx[0] + self.scrollbar_ipadx[1]) if label_width > self.new_width: - additional_width = int(label_width - self.new_width) + additional_width = int(label_width - self.new_width + self.settings.uism.MARGIN_WIDTH) self.new_width += additional_width # for fixing 1px bug diff --git a/vrct_gui/_CreateSelectableLanguagesWindow.py b/vrct_gui/_CreateSelectableLanguagesWindow.py index 8c666a20..dd6c6327 100644 --- a/vrct_gui/_CreateSelectableLanguagesWindow.py +++ b/vrct_gui/_CreateSelectableLanguagesWindow.py @@ -1,9 +1,9 @@ from functools import partial -from .ui_utils import bindButtonReleaseFunction, bindEnterAndLeaveColor, bindButtonPressColor, applyUiScalingAndFixTheBugScrollBar +from .ui_utils import bindButtonReleaseFunction, bindEnterAndLeaveColor, bindButtonPressColor, applyUiScalingAndFixTheBugScrollBar, CustomizedCTkScrollableFrame from utils import callFunctionIfCallable, makeEven -from customtkinter import CTkToplevel, CTkFrame, CTkLabel, CTkFont, CTkScrollableFrame +from customtkinter import CTkToplevel, CTkFrame, CTkLabel, CTkFont class _CreateSelectableLanguagesWindow(CTkToplevel): def __init__(self, vrct_gui, settings, view_variable): @@ -116,7 +116,7 @@ class _CreateSelectableLanguagesWindow(CTkToplevel): - self.scroll_frame_container = CTkScrollableFrame(self, corner_radius=0, fg_color=self.settings.ctm.MAIN_BG_COLOR, width=self.width_new, height=self.height_new) + self.scroll_frame_container = CustomizedCTkScrollableFrame(self, corner_radius=0, fg_color=self.settings.ctm.MAIN_BG_COLOR, width=self.width_new, height=self.height_new) self.scroll_frame_container.grid(row=1, column=0, sticky="nsew") applyUiScalingAndFixTheBugScrollBar( diff --git a/vrct_gui/_CreateWindowCover.py b/vrct_gui/_CreateWindowCover.py index 600619be..2b88a3d8 100644 --- a/vrct_gui/_CreateWindowCover.py +++ b/vrct_gui/_CreateWindowCover.py @@ -56,7 +56,7 @@ class _CreateWindowCover(CTkToplevel): self.width_new = self.attach_window.winfo_width() self.height_new = self.attach_window.winfo_height() self.geometry("{}x{}+{}+{}".format(self.width_new, self.height_new, self.x_pos, self.y_pos)) - fadeInAnimation(self, steps=5, interval=0.005, max_alpha=0.5) + fadeInAnimation(self, steps=5, interval=0.005, max_alpha=0.8) diff --git a/vrct_gui/_changeConfigWindowWidgetsStatus.py b/vrct_gui/_changeConfigWindowWidgetsStatus.py index 95ebb187..b9b0f9d8 100644 --- a/vrct_gui/_changeConfigWindowWidgetsStatus.py +++ b/vrct_gui/_changeConfigWindowWidgetsStatus.py @@ -5,10 +5,13 @@ def _changeConfigWindowWidgetsStatus(config_window, settings, view_variable, sta # target_names = [] - def disableOptionmenuWidget(target_widget): + def disableLabelsWidgets(target_widget): target_widget.label_widget.configure(text_color=settings.ctm.LABELS_TEXT_DISABLED_COLOR) if target_widget.desc_widget is not None: target_widget.desc_widget.configure(text_color=settings.ctm.LABELS_TEXT_DISABLED_COLOR) + + def disableOptionmenuWidget(target_widget): + disableLabelsWidgets(target_widget) target_widget.optionmenu_label_widget.configure(text_color=settings.ctm.LABELS_TEXT_DISABLED_COLOR) target_widget.optionmenu_img_widget.configure(image=CTkImage(settings.image_file.ARROW_LEFT_DISABLED.rotate(90), size=settings.uism.SB__OPTIONMENU_IMG_SIZE)) target_widget.optionmenu_box.unbindFunction() @@ -32,6 +35,16 @@ def _changeConfigWindowWidgetsStatus(config_window, settings, view_variable, sta target_widget = config_window.sb__widgets["sb__optionmenu_appearance_theme"] disableOptionmenuWidget(target_widget) + + case "sb__checkbox_enable_send_received_message_to_vrc": + if status == "disabled": + target_widget = config_window.sb__widgets["sb__checkbox_enable_send_received_message_to_vrc"] + disableLabelsWidgets(target_widget) + config_window.sb__checkbox_enable_send_received_message_to_vrc.configure( + state="disabled", + border_color=settings.ctm.SB__CHECKBOX_BORDER_DISABLED_COLOR + ) + case _: raise ValueError(f"No matching case for target_name: {target_name}") diff --git a/vrct_gui/_changeMainWindowWidgetsStatus.py b/vrct_gui/_changeMainWindowWidgetsStatus.py index 53c29f2a..95fc38dc 100644 --- a/vrct_gui/_changeMainWindowWidgetsStatus.py +++ b/vrct_gui/_changeMainWindowWidgetsStatus.py @@ -3,7 +3,7 @@ hold_state_list=[] def _changeMainWindowWidgetsStatus(vrct_gui, settings, view_variable, status, target_names:list, to_hold_state:bool=False): global hold_state_list if target_names == "All": - target_names = ["translation_switch", "transcription_send_switch", "transcription_receive_switch", "foreground_switch", "quick_language_settings", "config_button", "minimize_sidebar_button", "entry_message_box"] + target_names = ["translation_switch", "transcription_send_switch", "transcription_receive_switch", "foreground_switch", "quick_language_settings", "config_button", "minimize_sidebar_button", "entry_message_box", "send_message_button"] for item in hold_state_list: @@ -141,11 +141,19 @@ def _changeMainWindowWidgetsStatus(vrct_gui, settings, view_variable, status, ta case "entry_message_box": if status == "disabled": - vrct_gui.entry_message_box.configure(state="disabled", placeholder_text_color=settings.ctm.TEXTBOX_ENTRY_PLACEHOLDER_DISABLED_COLOR, text_color=settings.ctm.TEXTBOX_ENTRY_TEXT_DISABLED_COLOR) + vrct_gui.entry_message_box.configure(state="disabled", text_color=settings.ctm.TEXTBOX_ENTRY_TEXT_DISABLED_COLOR) + view_variable.IS_ENTRY_MESSAGE_BOX_DISABLED = True elif status == "normal": - vrct_gui.entry_message_box.configure(state="normal", placeholder_text_color=settings.ctm.TEXTBOX_ENTRY_PLACEHOLDER_COLOR, text_color=settings.ctm.TEXTBOX_ENTRY_TEXT_COLOR) + vrct_gui.entry_message_box.configure(state="normal", text_color=settings.ctm.TEXTBOX_ENTRY_TEXT_COLOR) + view_variable.IS_ENTRY_MESSAGE_BOX_DISABLED = False + case "send_message_button": + if status == "disabled": + vrct_gui.main_send_message_button__disabled.grid() + elif status == "normal": + vrct_gui.main_send_message_button__disabled.grid_remove() + case _: raise ValueError(f"No matching case for target_name: {target_name}") diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/createSideMenuAndSettingsBoxContainers.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/createSideMenuAndSettingsBoxContainers.py index f9694a1a..30af50de 100644 --- a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/createSideMenuAndSettingsBoxContainers.py +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/createSideMenuAndSettingsBoxContainers.py @@ -1,6 +1,6 @@ -from customtkinter import CTkFrame, CTkScrollableFrame +from customtkinter import CTkFrame -from ....ui_utils import setDefaultActiveTab, applyUiScalingAndFixTheBugScrollBar +from ....ui_utils import setDefaultActiveTab, applyUiScalingAndFixTheBugScrollBar, CustomizedCTkScrollableFrame from ._addConfigSideMenuItem import _addConfigSideMenuItem from ._createSettingBoxContainer import _createSettingBoxContainer @@ -8,7 +8,7 @@ from ._createSettingBoxContainer import _createSettingBoxContainer from .setting_box_containers.setting_box_appearance import createSettingBox_Appearance from .setting_box_containers.setting_box_transcription import createSettingBox_Mic, createSettingBox_Speaker -from .setting_box_containers.setting_box_others import createSettingBox_Others +from .setting_box_containers.setting_box_others import createSettingBox_Others, createSettingBox_Others_SendMessageFormats, createSettingBox_Others_ReceivedMessageFormats, createSettingBox_Others_Additional from .setting_box_containers.setting_box_advanced_settings import createSettingBox_AdvancedSettings from .setting_box_containers.setting_box_translation import createSettingBox_Translation @@ -38,7 +38,7 @@ def createSideMenuAndSettingsBoxContainers(config_window, settings, view_variabl # Setting box container config_window.main_bg_container.grid_rowconfigure(1, weight=1) - config_window.main_setting_box_scrollable_container = CTkScrollableFrame(config_window.main_bg_container, corner_radius=0, fg_color=settings.ctm.MAIN_BG_COLOR) + config_window.main_setting_box_scrollable_container = CustomizedCTkScrollableFrame(config_window.main_bg_container, corner_radius=0, fg_color=settings.ctm.MAIN_BG_COLOR) config_window.main_setting_box_scrollable_container.grid(row=1, column=0, sticky="nsew") applyUiScalingAndFixTheBugScrollBar( @@ -106,6 +106,9 @@ def createSideMenuAndSettingsBoxContainers(config_window, settings, view_variabl "setting_box_container_attr_name": "setting_box_container_others", "setting_boxes": [ { "var_section_title": None, "setting_box": createSettingBox_Others }, + { "var_section_title": view_variable.VAR_SECOND_TITLE_OTHERS_SEND_MESSAGE_FORMATS, "setting_box": createSettingBox_Others_SendMessageFormats }, + { "var_section_title": view_variable.VAR_SECOND_TITLE_OTHERS_RECEIVED_MESSAGE_FORMATS, "setting_box": createSettingBox_Others_ReceivedMessageFormats }, + { "var_section_title": view_variable.VAR_SECOND_TITLE_OTHERS_SPEAKER2CHATBOX, "setting_box": createSettingBox_Others_Additional }, ] }, }, @@ -131,7 +134,6 @@ def createSideMenuAndSettingsBoxContainers(config_window, settings, view_variabl config_window=config_window, settings=settings, view_variable=view_variable, - # view_variable=view_variable, side_menu_settings=sm_and_sbc_setting, side_menu_row=side_menu_row, all_side_menu_tab_attr_name=all_side_menu_tab_attr_name, 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 d8b31a39..7d44a2bb 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,10 @@ from functools import partial from types import SimpleNamespace from typing import Union -from customtkinter import CTkFont, CTkFrame, CTkLabel, CTkEntry, CTkSlider, CTkSwitch, CTkCheckBox, CTkProgressBar, CTkImage +from customtkinter import CTkFont, CTkFrame, CTkLabel, CTkEntry, CTkSlider, CTkSwitch, CTkCheckBox, CTkProgressBar, CTkImage, CTkRadioButton from CTkToolTip import * -from vrct_gui.ui_utils import createButtonWithImage, getLatestWidth, createOptionMenuBox, getLatestHeight, bindButtonFunctionAndColor +from vrct_gui.ui_utils import createButtonWithImage, getLatestWidth, createOptionMenuBox, getLatestHeight, bindButtonFunctionAndColor, bindEnterAndLeaveFunction, bindButtonReleaseFunction, bindButtonPressFunction from vrct_gui import vrct_gui from utils import isEven, callFunctionIfCallable @@ -109,8 +109,9 @@ class _SettingBoxGenerator(): def createSettingBox_Labels( self, - for_var_label_text, for_var_desc_text, + for_var_label_text, labels_attr_name, + for_var_desc_text=None, ): setting_box_frame= self._createSettingBoxFrame(labels_attr_name, for_var_label_text, for_var_desc_text, expand_label_frame=True) @@ -203,7 +204,6 @@ class _SettingBoxGenerator(): variable=variable, command=command, fg_color=self.settings.ctm.SB__SWITCH_BOX_BG_COLOR, - # bg_color="red", progress_color=self.settings.ctm.SB__SWITCH_BOX_ACTIVE_BG_COLOR, button_color=self.settings.ctm.SB__SWITCH_BOX_BUTTON_COLOR, button_hover_color=self.settings.ctm.SB__SWITCH_BOX_BUTTON_HOVERED_COLOR, @@ -217,10 +217,11 @@ class _SettingBoxGenerator(): def createSettingBoxCheckbox(self, - for_var_label_text, for_var_desc_text, + for_var_label_text, checkbox_attr_name, command, variable, + for_var_desc_text=None, ): (setting_box_frame, setting_box_item_frame) = self._createSettingBoxFrame(checkbox_attr_name, for_var_label_text, for_var_desc_text) @@ -241,9 +242,6 @@ class _SettingBoxGenerator(): 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, - # fg_color=self.settings.ctm.SB__SWITCH_BOX_BG_COLOR, - # bg_color="red", - # progress_color=self.settings.ctm.SB__SWITCH_BOX_ACTIVE_BG_COLOR, ) setattr(self.config_window, checkbox_attr_name, checkbox_widget) @@ -253,6 +251,81 @@ class _SettingBoxGenerator(): + # 3 Options + def createSettingBoxRadioButtons( + self, + for_var_label_text, for_var_desc_text, + radio_button_attr_name, + variable, + command, + radiobutton_keys_values=dict, + ): + + (setting_box_frame, setting_box_item_frame) = self._createSettingBoxFrame(radio_button_attr_name, for_var_label_text, for_var_desc_text) + + row=0 + for key, value in radiobutton_keys_values.items(): + radiobutton_wrapper = CTkFrame(setting_box_item_frame, corner_radius=6, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0, cursor="hand2") + radiobutton_wrapper.grid(row=row, column=0, sticky="ew") + row+=1 + + radiobutton_wrapper.grid_rowconfigure((0,2), weight=1) + setting_box_radio_button = CTkRadioButton( + radiobutton_wrapper, + textvariable=value, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__RADIO_BUTTON_FONT_SIZE, weight="normal"), + variable=variable, + value=key, + text_color=self.settings.ctm.SB__RADIOBUTTON_TEXT_COLOR, + fg_color=self.settings.ctm.SB__RADIOBUTTON_SELECTED_COLOR, + border_color=self.settings.ctm.SB__RADIOBUTTON_BORDER_COLOR, + hover=False + ) + setting_box_radio_button.grid(row=1, column=0, padx=10, pady=10, sticky="ew") + + if key == variable.get(): + setting_box_radio_button.select() + + setting_box_radio_button._canvas.unbind("") + setting_box_radio_button._text_label.unbind("") + setting_box_radio_button._text_label.grid(padx=(10,0)) + + + def buttonPressedFunction(radiobutton_wrapper, radiobutton_widget, _e): + radiobutton_wrapper.configure(fg_color=self.settings.ctm.SB__RADIOBUTTON_BG_CLICKED_COLOR) + + def buttonReleasedFunction(radiobutton_wrapper, radiobutton_widget, _e): + radiobutton_wrapper.configure(fg_color=self.settings.ctm.SB__RADIOBUTTON_BG_HOVERED_COLOR) + radiobutton_widget.select() + command() + + def enterFunction(radiobutton_wrapper, _e): + radiobutton_wrapper.configure(fg_color=self.settings.ctm.SB__RADIOBUTTON_BG_HOVERED_COLOR) + + def leaveFunction(radiobutton_wrapper, _e): + radiobutton_wrapper.configure(fg_color=self.settings.ctm.SB__BG_COLOR) + + + bindEnterAndLeaveFunction( + target_widgets=[radiobutton_wrapper, setting_box_radio_button, setting_box_radio_button._bg_canvas], + enterFunction=partial(enterFunction, radiobutton_wrapper), + leaveFunction=partial(leaveFunction, radiobutton_wrapper) + ) + + bindButtonPressFunction( + target_widgets=[radiobutton_wrapper, setting_box_radio_button, setting_box_radio_button._bg_canvas], + buttonPressedFunction=partial(buttonPressedFunction, radiobutton_wrapper, setting_box_radio_button) + ) + + bindButtonReleaseFunction( + target_widgets=[radiobutton_wrapper, setting_box_radio_button, setting_box_radio_button._bg_canvas], + buttonReleasedFunction=partial(buttonReleasedFunction, radiobutton_wrapper, setting_box_radio_button) + ) + + + return setting_box_frame + + def createSettingBoxAutoExportMessageLogs( self, @@ -282,6 +355,7 @@ class _SettingBoxGenerator(): 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, + corner_radius=self.settings.uism.SB__BUTTON_CORNER_RADIUS, button_ipadxy=self.settings.uism.SB__BUTTON_IPADXY, button_command=button_command, ) @@ -540,13 +614,15 @@ class _SettingBoxGenerator(): - def createSettingBoxMessageFormatEntries(self, + def createSettingBoxMessageFormatEntries_WithTranslation(self, base_entry_attr_name, entry_textvariable_0, entry_textvariable_1, entry_textvariable_2, textvariable_0, textvariable_1, + example_label_textvariable, + swap_button_command, entry_bind__Any_KeyRelease, entry_bind__FocusOut=None, ): @@ -581,7 +657,7 @@ class _SettingBoxGenerator(): 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, + textvariable=example_label_textvariable, anchor="center", justify="center", wraplength=self.settings.uism.SB__MESSAGE_FORMAT__EXAMPLE_WRAP_LENGTH, @@ -717,10 +793,6 @@ class _SettingBoxGenerator(): ) 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, @@ -732,7 +804,7 @@ class _SettingBoxGenerator(): 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(), + buttonReleasedFunction=swap_button_command, ) @@ -740,6 +812,119 @@ class _SettingBoxGenerator(): + + def createSettingBoxMessageFormatEntries(self, + base_entry_attr_name, + entry_textvariable_0, + entry_textvariable_1, + textvariable_0, + example_label_textvariable, + 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") + + + + + 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=example_label_textvariable, + 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] + for i in range(2): + 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") + + + + + + entries_wrapper.grid_columnconfigure((0,2), weight=1) + entries_wrapper.grid_columnconfigure(1, weight=0) + + 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_0.grid(row=0, column=0, sticky="ew") + entry_widget_1.grid(row=0, column=2, sticky="ew") + label_frame_widget_0.grid(row=0, column=1, 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() + 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) + + + + return setting_box_frame + + + def createSettingBoxButtonWithImage( self, for_var_label_text, for_var_desc_text, @@ -757,7 +942,8 @@ class _SettingBoxGenerator(): 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_image_size=self.settings.uism.SB__BUTTON_ICON_SIZE, + corner_radius=self.settings.uism.SB__BUTTON_CORNER_RADIUS, button_ipadxy=self.settings.uism.SB__OPEN_CONFIG_FILE_BUTTON_IPADXY, button_command=button_command, ) @@ -803,6 +989,7 @@ class _SettingBoxGenerator(): 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, + corner_radius=self.settings.uism.SB__BUTTON_CORNER_RADIUS, button_ipadxy=self.settings.uism.SB__BUTTON_IPADXY, button_command=open_command, ) @@ -817,6 +1004,7 @@ class _SettingBoxGenerator(): 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, + corner_radius=self.settings.uism.SB__BUTTON_CORNER_RADIUS, button_ipadxy=self.settings.uism.SB__BUTTON_IPADXY, button_command=close_command, ) @@ -1032,6 +1220,7 @@ class _SettingBoxGenerator(): 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, + corner_radius=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_CORNER_RADIUS, button_ipadxy=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_IPADXY, button_command=lambda _e: pressedDeleteButtonCommand(_e, delete_button, redo_button), ) @@ -1044,6 +1233,7 @@ class _SettingBoxGenerator(): 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, + corner_radius=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_CORNER_RADIUS, button_ipadxy=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_IPADXY, button_command=lambda _e: pressedRedoButtonCommand(_e, delete_button, redo_button), ) @@ -1077,106 +1267,6 @@ class _SettingBoxGenerator(): - - - # 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") - - - - # # Labels - # self.optionmenu_label_left = CTkLabel( - # self.setting_box_dropdown_menu_x_dropdown_menu, - # text=kwargs["left_dropdown_menu_label"], - # font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__OPTION_MENU_FONT_SIZE, weight="normal"), - # ) - # self.optionmenu_label_left.grid(row=0, column=0) - - # self.the_space_between_optionmenu = CTkLabel( - # self.setting_box_dropdown_menu_x_dropdown_menu, - # text=None, - # ) - # self.the_space_between_optionmenu.grid(row=0, column=1) - - - # self.optionmenu_label_right = CTkLabel( - # self.setting_box_dropdown_menu_x_dropdown_menu, - # text=kwargs["right_dropdown_menu_label"], - # font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__OPTION_MENU_FONT_SIZE, weight="normal"), - # ) - # self.optionmenu_label_right.grid(row=0, column=2) - - - - # # Option menus - # self.createOption_DropdownMenu( - # setattr_obj, - # self.setting_box_dropdown_menu_x_dropdown_menu, - # kwargs["left_optionmenu_attr_name"], - # kwargs["left_dropdown_menu_attr_name"], - # dropdown_menu_values=kwargs["left_dropdown_menu_values"], - # width=150, - # command=kwargs["left_dropdown_menu_command"], - # variable=kwargs["left_dropdown_menu_variable"], - # ) - # getattr(setattr_obj, kwargs["left_optionmenu_attr_name"]).grid(row=1, column=0) - - - - # self.the_label_between_optionmenu = CTkLabel( - # self.setting_box_dropdown_menu_x_dropdown_menu, - # text="-->", - # # anchor="w", - # font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__OPTION_MENU_FONT_SIZE, weight="normal"), - # text_color=self.settings.ctm.LABELS_TEXT_COLOR - # ) - # self.the_label_between_optionmenu.grid(row=1, column=1, padx=self.settings.uism.SB__RIGHT_PADX/2) - - - # self.createOption_DropdownMenu( - # setattr_obj, - # self.setting_box_dropdown_menu_x_dropdown_menu, - # kwargs["right_optionmenu_attr_name"], - # kwargs["right_dropdown_menu_attr_name"], - # dropdown_menu_values=kwargs["right_dropdown_menu_values"], - # width=150, - # command=kwargs["right_dropdown_menu_command"], - # variable=kwargs["right_dropdown_menu_variable"], - # ) - # getattr(setattr_obj, kwargs["right_optionmenu_attr_name"]).grid(row=1, column=2) - - - - - # if setting_box_type == "radio_buttons": - # self.setting_box_radio_buttons_frame = CTkFrame(self.setting_box, corner_radius=0, width=0, height=0) - # self.setting_box_radio_buttons_frame.grid(row=0, column=1, padx=(0, self.settings.uism.SB__RIGHT_PADX), rowspan=2, sticky="e") - - # RADIO_BUTTON_RIGHT_PAD = 14 - # self.setting_box_radio_button_1 = CTkRadioButton( - # self.setting_box_radio_buttons_frame, - # text="lorem ipsum", - # font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__RADIO_BUTTON_FONT_SIZE, weight="normal") - # ) - # self.setting_box_radio_button_1.grid(row=0, column=0, padx=(0,RADIO_BUTTON_RIGHT_PAD), sticky="e") - - # self.setting_box_radio_button_2 = CTkRadioButton( - # self.setting_box_radio_buttons_frame, - # text="lorem ipsum", - # font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__RADIO_BUTTON_FONT_SIZE, weight="normal") - # ) - # self.setting_box_radio_button_2.grid(row=0, column=1, padx=(0,RADIO_BUTTON_RIGHT_PAD), sticky="e") - - # self.setting_box_radio_button_3 = CTkRadioButton( - # self.setting_box_radio_buttons_frame, - # text="lorem ipsum", - # font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__RADIO_BUTTON_FONT_SIZE, weight="normal") - # ) - # self.setting_box_radio_button_3.grid(row=0, column=2, padx=(0,RADIO_BUTTON_RIGHT_PAD), sticky="e") - - - def _createPassiveButtonForProgressbarXSlider(self, setting_box_progressbar_x_slider_frame, button_command, button_image_file): button_wrapper = createButtonWithImage( parent_widget=setting_box_progressbar_x_slider_frame, 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 dd5f68ab..615c0e4e 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 @@ -6,6 +6,7 @@ def createSettingBox_Appearance(setting_box_wrapper, config_window, settings, vi sbg = _SettingBoxGenerator(setting_box_wrapper, config_window, settings, view_variable) createSettingBoxDropdownMenu = sbg.createSettingBoxDropdownMenu createSettingBoxSlider = sbg.createSettingBoxSlider + createSettingBoxCheckbox = sbg.createSettingBoxCheckbox # 関数名は変えるかもしれない。 # テーマ変更、フォント変更時、 Widget再生成か再起動かは検討中 @@ -21,12 +22,17 @@ def createSettingBox_Appearance(setting_box_wrapper, config_window, settings, vi def slider_text_box_ui_scaling_callback(value): callFunctionIfCallable(view_variable.CALLBACK_SET_TEXTBOX_UI_SCALING, value) + def slider_message_box_ratio_callback(value): + callFunctionIfCallable(view_variable.CALLBACK_SET_MESSAGE_BOX_RATIO, value) + def optionmenu_font_family_callback(value): callFunctionIfCallable(view_variable.CALLBACK_SET_FONT_FAMILY, value) def optionmenu_ui_language_callback(value): callFunctionIfCallable(view_variable.CALLBACK_SET_UI_LANGUAGE, value) + def checkbox_enable_restore_main_window_geometry_callback(checkbox_box_widget): + callFunctionIfCallable(view_variable.CALLBACK_SET_ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY, checkbox_box_widget.get()) row=0 config_window.sb__transparency = createSettingBoxSlider( @@ -82,6 +88,19 @@ def createSettingBox_Appearance(setting_box_wrapper, config_window, settings, vi config_window.sb__textbox_uis_scaling.grid(row=row) row+=1 + config_window.sb__message_box_ratio = createSettingBoxSlider( + for_var_label_text=view_variable.VAR_LABEL_MESSAGE_BOX_RATIO, + for_var_desc_text=view_variable.VAR_DESC_MESSAGE_BOX_RATIO, + slider_attr_name="sb__slider_message_box_ratio", + slider_range=view_variable.SLIDER_RANGE_MESSAGE_BOX_RATIO, + command=lambda value: slider_message_box_ratio_callback(value), + variable=view_variable.VAR_MESSAGE_BOX_RATIO, + slider_bind__ButtonPress=view_variable.CALLBACK_BUTTON_PRESS_MESSAGE_BOX_RATIO, + slider_bind__ButtonRelease=view_variable.CALLBACK_BUTTON_RELEASE_MESSAGE_BOX_RATIO, + sliderTooltipFormatter=view_variable.CALLBACK_SLIDER_TOOLTIP_PERCENTAGE_FORMATTER, + ) + config_window.sb__message_box_ratio.grid(row=row) + row+=1 config_window.sb__font_family = createSettingBoxDropdownMenu( for_var_label_text=view_variable.VAR_LABEL_FONT_FAMILY, @@ -103,5 +122,15 @@ def createSettingBox_Appearance(setting_box_wrapper, config_window, settings, vi command=lambda value: optionmenu_ui_language_callback(value), variable=view_variable.VAR_UI_LANGUAGE, ) - config_window.sb__ui_language.grid(row=row, pady=0) + config_window.sb__ui_language.grid(row=row) + row+=1 + + config_window.sb__enable_restore_main_window_geometry = createSettingBoxCheckbox( + for_var_label_text=view_variable.VAR_LABEL_ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY, + for_var_desc_text=view_variable.VAR_DESC_ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY, + checkbox_attr_name="sb__checkbox_enable_restore_main_window_geometry", + command=lambda: checkbox_enable_restore_main_window_geometry_callback(config_window.sb__checkbox_enable_restore_main_window_geometry), + variable=view_variable.VAR_ENABLE_RESTORE_MAIN_WINDOW_GEOMETRY, + ) + config_window.sb__enable_restore_main_window_geometry.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_others/__init__.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/__init__.py index c115d627..9b7e583c 100644 --- a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/__init__.py +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/__init__.py @@ -1 +1,4 @@ -from .createSettingBox_Others import createSettingBox_Others \ No newline at end of file +from .createSettingBox_Others import createSettingBox_Others +from .createSettingBox_Others_SendMessageFormats import createSettingBox_Others_SendMessageFormats +from .createSettingBox_Others_ReceivedMessageFormats import createSettingBox_Others_ReceivedMessageFormats +from .createSettingBox_Others_Additional import createSettingBox_Others_Additional \ No newline at end of file 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 161e4bfc..bacfa71f 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,15 +5,19 @@ 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 + createSettingBoxRadioButtons = sbg.createSettingBoxRadioButtons createSettingBoxAutoExportMessageLogs = sbg.createSettingBoxAutoExportMessageLogs - createSettingBox_Labels = sbg.createSettingBox_Labels - createSettingBoxMessageFormatEntries = sbg.createSettingBoxMessageFormatEntries - # 元 checkbox_auto_clear_chatbox_callback def checkbox_auto_clear_message_box_callback(checkbox_box_widget): callFunctionIfCallable(view_variable.CALLBACK_SET_ENABLE_AUTO_CLEAR_MESSAGE_BOX, checkbox_box_widget.get()) + def checkbox_send_only_translated_messages_callback(checkbox_box_widget): + callFunctionIfCallable(view_variable.CALLBACK_SET_ENABLE_SEND_ONLY_TRANSLATED_MESSAGES, checkbox_box_widget.get()) + + def checkbox_send_message_button_type_callback(): + callFunctionIfCallable(view_variable.CALLBACK_SET_SEND_MESSAGE_BUTTON_TYPE, view_variable.VAR_SEND_MESSAGE_BUTTON_TYPE.get()) + def checkbox_notice_xsoverlay_callback(checkbox_box_widget): callFunctionIfCallable(view_variable.CALLBACK_SET_ENABLE_NOTICE_XSOVERLAY, checkbox_box_widget.get()) @@ -26,13 +30,6 @@ def createSettingBox_Others(setting_box_wrapper, config_window, settings, view_v 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()) - # [deprecated] - # def checkbox_startup_osc_enabled_check_callback(checkbox_box_widget): - # callFunctionIfCallable(view_variable.CALLBACK_SET_STARTUP_OSC_ENABLED_CHECK, checkbox_box_widget.get()) - - def entry_message_format_callback(value): - callFunctionIfCallable(view_variable.CALLBACK_SET_MESSAGE_FORMAT, value) - row=0 config_window.sb__auto_clear_message_box = createSettingBoxCheckbox( @@ -45,6 +42,26 @@ def createSettingBox_Others(setting_box_wrapper, config_window, settings, view_v config_window.sb__auto_clear_message_box.grid(row=row) row+=1 + config_window.sb__send_only_translated_messages = createSettingBoxCheckbox( + for_var_label_text=view_variable.VAR_LABEL_ENABLE_SEND_ONLY_TRANSLATED_MESSAGES, + for_var_desc_text=view_variable.VAR_DESC_ENABLE_SEND_ONLY_TRANSLATED_MESSAGES, + checkbox_attr_name="sb__checkbox_send_only_translated_messages", + command=lambda: checkbox_send_only_translated_messages_callback(config_window.sb__checkbox_send_only_translated_messages), + variable=view_variable.VAR_ENABLE_SEND_ONLY_TRANSLATED_MESSAGES, + ) + config_window.sb__send_only_translated_messages.grid(row=row) + row+=1 + + config_window.sb__send_message_button_type = createSettingBoxRadioButtons( + for_var_label_text=view_variable.VAR_LABEL_SEND_MESSAGE_BUTTON_TYPE, + for_var_desc_text=view_variable.VAR_DESC_SEND_MESSAGE_BUTTON_TYPE, + radio_button_attr_name="sb__radiobutton_send_message_button_type", + command=lambda: checkbox_send_message_button_type_callback(), + variable=view_variable.VAR_SEND_MESSAGE_BUTTON_TYPE, + radiobutton_keys_values=view_variable.KEYS_VALUES_SEND_MESSAGE_BUTTON_TYPE, + ) + config_window.sb__send_message_button_type.grid(row=row) + row+=1 config_window.sb__notice_xsoverlay = createSettingBoxCheckbox( for_var_label_text=view_variable.VAR_LABEL_ENABLE_NOTICE_XSOVERLAY, @@ -69,30 +86,6 @@ def createSettingBox_Others(setting_box_wrapper, config_window, settings, view_v row+=1 - 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, - 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_bind__FocusOut=view_variable.CALLBACK_FOCUS_OUT_MESSAGE_FORMAT, - ) - config_window.sb__message_format.grid(row=row) - row+=1 - - config_window.sb__enable_send_message_to_vrc = createSettingBoxCheckbox( for_var_label_text=view_variable.VAR_LABEL_ENABLE_SEND_MESSAGE_TO_VRC, for_var_desc_text=view_variable.VAR_DESC_ENABLE_SEND_MESSAGE_TO_VRC, @@ -101,16 +94,4 @@ def createSettingBox_Others(setting_box_wrapper, config_window, settings, view_v variable=view_variable.VAR_ENABLE_SEND_MESSAGE_TO_VRC, ) config_window.sb__enable_send_message_to_vrc.grid(row=row, pady=0) - row+=1 - - # [deprecated] - # config_window.sb__startup_osc_enabled_check = createSettingBoxCheckbox( - # for_var_label_text=view_variable.VAR_LABEL_STARTUP_OSC_ENABLED_CHECK, - # for_var_desc_text=view_variable.VAR_DESC_STARTUP_OSC_ENABLED_CHECK, - # checkbox_attr_name="sb__checkbox_startup_osc_enabled_check", - # command=lambda: checkbox_startup_osc_enabled_check_callback(config_window.sb__checkbox_startup_osc_enabled_check), - # variable=view_variable.VAR_STARTUP_OSC_ENABLED_CHECK, - # ) - # config_window.sb__startup_osc_enabled_check.grid(row=row, pady=0) - # row+=1 - + row+=1 \ No newline at end of file diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/createSettingBox_Others_Additional.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/createSettingBox_Others_Additional.py new file mode 100644 index 00000000..b7f39f91 --- /dev/null +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/createSettingBox_Others_Additional.py @@ -0,0 +1,22 @@ +from utils import callFunctionIfCallable + +from .._SettingBoxGenerator import _SettingBoxGenerator + +def createSettingBox_Others_Additional(setting_box_wrapper, config_window, settings, view_variable): + sbg = _SettingBoxGenerator(setting_box_wrapper, config_window, settings, view_variable) + createSettingBoxCheckbox = sbg.createSettingBoxCheckbox + + def checkbox_enable_send_received_message_to_vrc_callback(checkbox_box_widget): + callFunctionIfCallable(view_variable.CALLBACK_SET_ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC, checkbox_box_widget.get()) + + + row=0 + config_window.sb__enable_send_received_message_to_vrc = createSettingBoxCheckbox( + for_var_label_text=view_variable.VAR_LABEL_ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC, + for_var_desc_text=view_variable.VAR_DESC_ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC, + checkbox_attr_name="sb__checkbox_enable_send_received_message_to_vrc", + command=lambda: checkbox_enable_send_received_message_to_vrc_callback(config_window.sb__checkbox_enable_send_received_message_to_vrc), + variable=view_variable.VAR_ENABLE_SEND_RECEIVED_MESSAGE_TO_VRC, + ) + config_window.sb__enable_send_received_message_to_vrc.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_others/createSettingBox_Others_ReceivedMessageFormats.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/createSettingBox_Others_ReceivedMessageFormats.py new file mode 100644 index 00000000..0d0bbca7 --- /dev/null +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/createSettingBox_Others_ReceivedMessageFormats.py @@ -0,0 +1,65 @@ +from utils import callFunctionIfCallable + +from .._SettingBoxGenerator import _SettingBoxGenerator + +def createSettingBox_Others_ReceivedMessageFormats(setting_box_wrapper, config_window, settings, view_variable): + sbg = _SettingBoxGenerator(setting_box_wrapper, config_window, settings, view_variable) + createSettingBox_Labels = sbg.createSettingBox_Labels + createSettingBoxMessageFormatEntries = sbg.createSettingBoxMessageFormatEntries + createSettingBoxMessageFormatEntries_WithTranslation = sbg.createSettingBoxMessageFormatEntries_WithTranslation + + def entry_received_message_format_callback(value): + callFunctionIfCallable(view_variable.CALLBACK_SET_RECEIVED_MESSAGE_FORMAT, value) + + + def entry_received_message_format_with_t_callback(value): + callFunctionIfCallable(view_variable.CALLBACK_SET_RECEIVED_MESSAGE_FORMAT_WITH_T, value) + + def entry_swap_received_message_format_with_t_callback(_e): + callFunctionIfCallable(view_variable.CALLBACK_SWAP_RECEIVED_MESSAGE_FORMAT_WITH_T_REQUIRED_TEXT) + + row=0 + config_window.sb__received_message_format_labels = createSettingBox_Labels( + for_var_label_text=view_variable.VAR_LABEL_RECEIVED_MESSAGE_FORMAT, + for_var_desc_text=view_variable.VAR_DESC_RECEIVED_MESSAGE_FORMAT, + labels_attr_name="sb__labels_received_message_format", + ) + config_window.sb__received_message_format_labels.grid(row=row, pady=0) + row+=1 + + config_window.sb__received_message_format = createSettingBoxMessageFormatEntries( + base_entry_attr_name="sb__entry_received_message_format", + entry_textvariable_0=view_variable.VAR_ENTRY_0_RECEIVED_MESSAGE_FORMAT, + entry_textvariable_1=view_variable.VAR_ENTRY_1_RECEIVED_MESSAGE_FORMAT, + textvariable_0=view_variable.VAR_TEXT_REQUIRED_0_RECEIVED_MESSAGE_FORMAT, + example_label_textvariable=view_variable.VAR_LABEL_EXAMPLE_TEXT_RECEIVED_MESSAGE_FORMAT, + entry_bind__Any_KeyRelease=lambda value: entry_received_message_format_callback(value), + entry_bind__FocusOut=view_variable.CALLBACK_FOCUS_OUT_RECEIVED_MESSAGE_FORMAT, + ) + config_window.sb__received_message_format.grid(row=row) + row+=1 + + + + config_window.sb__received_message_format_with_t_labels = createSettingBox_Labels( + for_var_label_text=view_variable.VAR_LABEL_RECEIVED_MESSAGE_FORMAT_WITH_T, + for_var_desc_text=view_variable.VAR_DESC_RECEIVED_MESSAGE_FORMAT_WITH_T, + labels_attr_name="sb__labels_message_format_with_t", + ) + config_window.sb__received_message_format_with_t_labels.grid(row=row, pady=0) + row+=1 + + config_window.sb__received_message_format_with_t = createSettingBoxMessageFormatEntries_WithTranslation( + base_entry_attr_name="sb__entry_received_message_format_with_t", + entry_textvariable_0=view_variable.VAR_ENTRY_0_RECEIVED_MESSAGE_FORMAT_WITH_T, + entry_textvariable_1=view_variable.VAR_ENTRY_1_RECEIVED_MESSAGE_FORMAT_WITH_T, + entry_textvariable_2=view_variable.VAR_ENTRY_2_RECEIVED_MESSAGE_FORMAT_WITH_T, + textvariable_0=view_variable.VAR_TEXT_REQUIRED_0_RECEIVED_MESSAGE_FORMAT_WITH_T, + textvariable_1=view_variable.VAR_TEXT_REQUIRED_1_RECEIVED_MESSAGE_FORMAT_WITH_T, + example_label_textvariable=view_variable.VAR_LABEL_EXAMPLE_TEXT_RECEIVED_MESSAGE_FORMAT_WITH_T, + entry_bind__Any_KeyRelease=lambda value: entry_received_message_format_with_t_callback(value), + swap_button_command=entry_swap_received_message_format_with_t_callback, + entry_bind__FocusOut=view_variable.CALLBACK_FOCUS_OUT_RECEIVED_MESSAGE_FORMAT_WITH_T, + ) + config_window.sb__received_message_format_with_t.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_others/createSettingBox_Others_SendMessageFormats.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/createSettingBox_Others_SendMessageFormats.py new file mode 100644 index 00000000..6180ffd8 --- /dev/null +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/createSettingBox_Others_SendMessageFormats.py @@ -0,0 +1,66 @@ +from utils import callFunctionIfCallable + +from .._SettingBoxGenerator import _SettingBoxGenerator + +def createSettingBox_Others_SendMessageFormats(setting_box_wrapper, config_window, settings, view_variable): + sbg = _SettingBoxGenerator(setting_box_wrapper, config_window, settings, view_variable) + createSettingBox_Labels = sbg.createSettingBox_Labels + createSettingBoxMessageFormatEntries = sbg.createSettingBoxMessageFormatEntries + createSettingBoxMessageFormatEntries_WithTranslation = sbg.createSettingBoxMessageFormatEntries_WithTranslation + + def entry_send_message_format_callback(value): + callFunctionIfCallable(view_variable.CALLBACK_SET_SEND_MESSAGE_FORMAT, value) + + + def entry_send_message_format_with_t_callback(value): + callFunctionIfCallable(view_variable.CALLBACK_SET_SEND_MESSAGE_FORMAT_WITH_T, value) + + def entry_swap_message_format_with_t_callback(_e): + callFunctionIfCallable(view_variable.CALLBACK_SWAP_SEND_MESSAGE_FORMAT_WITH_T_REQUIRED_TEXT) + + + row=0 + config_window.sb__send_message_format_labels = createSettingBox_Labels( + for_var_label_text=view_variable.VAR_LABEL_SEND_MESSAGE_FORMAT, + for_var_desc_text=view_variable.VAR_DESC_SEND_MESSAGE_FORMAT, + labels_attr_name="sb__labels_send_message_format", + ) + config_window.sb__send_message_format_labels.grid(row=row, pady=0) + row+=1 + + config_window.sb__message_format = createSettingBoxMessageFormatEntries( + base_entry_attr_name="sb__entry_send_message_format", + entry_textvariable_0=view_variable.VAR_ENTRY_0_SEND_MESSAGE_FORMAT, + entry_textvariable_1=view_variable.VAR_ENTRY_1_SEND_MESSAGE_FORMAT, + textvariable_0=view_variable.VAR_TEXT_REQUIRED_0_SEND_MESSAGE_FORMAT, + example_label_textvariable=view_variable.VAR_LABEL_EXAMPLE_TEXT_SEND_MESSAGE_FORMAT, + entry_bind__Any_KeyRelease=lambda value: entry_send_message_format_callback(value), + entry_bind__FocusOut=view_variable.CALLBACK_FOCUS_OUT_SEND_MESSAGE_FORMAT, + ) + config_window.sb__message_format.grid(row=row) + row+=1 + + + + config_window.sb__send_message_format_with_t_labels = createSettingBox_Labels( + for_var_label_text=view_variable.VAR_LABEL_SEND_MESSAGE_FORMAT_WITH_T, + for_var_desc_text=view_variable.VAR_DESC_SEND_MESSAGE_FORMAT_WITH_T, + labels_attr_name="sb__labels_send_message_format_with_t", + ) + config_window.sb__send_message_format_with_t_labels.grid(row=row, pady=0) + row+=1 + + config_window.sb__message_format_with_t = createSettingBoxMessageFormatEntries_WithTranslation( + base_entry_attr_name="sb__entry_send_message_format_with_t", + entry_textvariable_0=view_variable.VAR_ENTRY_0_SEND_MESSAGE_FORMAT_WITH_T, + entry_textvariable_1=view_variable.VAR_ENTRY_1_SEND_MESSAGE_FORMAT_WITH_T, + entry_textvariable_2=view_variable.VAR_ENTRY_2_SEND_MESSAGE_FORMAT_WITH_T, + textvariable_0=view_variable.VAR_TEXT_REQUIRED_0_SEND_MESSAGE_FORMAT_WITH_T, + textvariable_1=view_variable.VAR_TEXT_REQUIRED_1_SEND_MESSAGE_FORMAT_WITH_T, + example_label_textvariable=view_variable.VAR_LABEL_EXAMPLE_TEXT_SEND_MESSAGE_FORMAT_WITH_T, + entry_bind__Any_KeyRelease=lambda value: entry_send_message_format_with_t_callback(value), + swap_button_command=entry_swap_message_format_with_t_callback, + entry_bind__FocusOut=view_variable.CALLBACK_FOCUS_OUT_SEND_MESSAGE_FORMAT_WITH_T, + ) + config_window.sb__message_format_with_t.grid(row=row, pady=0) + 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 54ce6a6a..c09f4bca 100644 --- a/vrct_gui/main_window/createMainWindowWidgets.py +++ b/vrct_gui/main_window/createMainWindowWidgets.py @@ -6,18 +6,16 @@ from utils import callFunctionIfCallable from ..ui_utils import createButtonWithImage, getImagePath, bindButtonFunctionAndColor def createMainWindowWidgets(vrct_gui, settings, view_variable): - vrct_gui.protocol("WM_DELETE_WINDOW", lambda: callFunctionIfCallable(view_variable.CALLBACK_QUIT_VRCT)) + vrct_gui.protocol("WM_DELETE_WINDOW", lambda: callFunctionIfCallable(view_variable.CALLBACK_DELETE_MAIN_WINDOW)) vrct_gui.iconbitmap(getImagePath("vrct_logo_mark_black.ico")) vrct_gui.title("VRCT") - # vrct_gui.minsize(200, 200) # Main Container vrct_gui.grid_columnconfigure(0, weight=1) vrct_gui.grid_rowconfigure(0, weight=1) - # vrct_gui.grid_columnconfigure(0, weight=1, minsize=settings.uism.MAIN_AREA_MIN_WIDTH) vrct_gui.configure(fg_color=settings.ctm.MAIN_BG_COLOR) @@ -122,4 +120,4 @@ def createMainWindowWidgets(vrct_gui, settings, view_variable): createTextbox(settings, vrct_gui, view_variable) - createEntryMessageBox(settings, vrct_gui) \ No newline at end of file + createEntryMessageBox(settings, vrct_gui, view_variable) \ No newline at end of file diff --git a/vrct_gui/main_window/widgets/_create_sidebar/createSidebarLanguagesSettings.py b/vrct_gui/main_window/widgets/_create_sidebar/createSidebarLanguagesSettings.py index 7561e1ae..cbe96b4e 100644 --- a/vrct_gui/main_window/widgets/_create_sidebar/createSidebarLanguagesSettings.py +++ b/vrct_gui/main_window/widgets/_create_sidebar/createSidebarLanguagesSettings.py @@ -317,4 +317,23 @@ def createSidebarLanguagesSettings(settings, main_window, view_variable): open_selectable_language_window_command=callbackOpenSelectableTargetLanguageWindow, variable=view_variable.VAR_TARGET_LANGUAGE ) - main_window.sls__box_target_language.grid(row=4, column=0, sticky="ew") \ No newline at end of file + main_window.sls__box_target_language.grid(row=4, column=0, sticky="ew") + + + + # Set Transcription ON/OFF Indicator Widgets + main_window.sls__box_your_language_mic_status__enabled = CTkLabel( + main_window.sls__box_your_language, + text=None, + height=0, + corner_radius=0, + image=CTkImage(settings.image_file.MIC_ICON_DISABLED, size=settings.uism.SLS__BOX_TRANSCRIPTION_STATUS_IMAGE_SIZE), + ) + + main_window.sls__box_target_language_speaker_status__enabled = CTkLabel( + main_window.sls__box_target_language, + text=None, + height=0, + corner_radius=0, + image=CTkImage(settings.image_file.HEADPHONES_ICON_DISABLED, size=settings.uism.SLS__BOX_TRANSCRIPTION_STATUS_IMAGE_SIZE), + ) \ No newline at end of file diff --git a/vrct_gui/main_window/widgets/create_entry_message_box.py b/vrct_gui/main_window/widgets/create_entry_message_box.py index e583234f..f49664e5 100644 --- a/vrct_gui/main_window/widgets/create_entry_message_box.py +++ b/vrct_gui/main_window/widgets/create_entry_message_box.py @@ -1,23 +1,26 @@ -from customtkinter import CTkFont, CTkFrame, CTkEntry +from customtkinter import CTkFont, CTkFrame, CTkTextbox, CTkLabel, CTkImage -def createEntryMessageBox(settings, main_window): - main_window.main_entry_message_container = CTkFrame(main_window.main_bg_container, corner_radius=0, fg_color=settings.ctm.MAIN_BG_COLOR, width=0, height=0) - main_window.main_entry_message_container.grid(row=2, column=0, sticky="ew") +from ...ui_utils import bindButtonFunctionAndColor +from utils import callFunctionIfCallable + +def createEntryMessageBox(settings, main_window, view_variable): + main_window.main_entry_message_container = CTkFrame(main_window.main_bg_container, corner_radius=settings.uism.TEXTBOX_ENTRY_CORNER_RADIUS, fg_color=settings.ctm.MAIN_BG_COLOR, width=0, height=0) + main_window.main_entry_message_container.grid(row=2, column=0, sticky="nsew") main_window.main_entry_message_container.grid_columnconfigure(0, weight=1) - main_window.entry_message_box = CTkEntry( + main_window.main_entry_message_container.grid_rowconfigure(0, weight=1) + main_window.entry_message_box = CTkTextbox( main_window.main_entry_message_container, + corner_radius=settings.uism.TEXTBOX_ENTRY_CORNER_RADIUS, border_color=settings.ctm.TEXTBOX_ENTRY_BORDER_COLOR, fg_color=settings.ctm.TEXTBOX_ENTRY_BG_COLOR, text_color=settings.ctm.TEXTBOX_ENTRY_TEXT_COLOR, - placeholder_text="Enter your message...", - placeholder_text_color=settings.ctm.TEXTBOX_ENTRY_PLACEHOLDER_COLOR, - height=settings.uism.TEXTBOX_ENTRY_HEIGHT, + border_width=settings.uism.TEXTBOX_ENTRY_BORDER_SIZE, + height=0, font=CTkFont(family=settings.FONT_FAMILY, size=settings.uism.TEXTBOX_ENTRY_FONT_SIZE, weight="normal"), ) main_window.entry_message_box.grid(row=0, column=0, padx=settings.uism.TEXTBOX_ENTRY_PADX, pady=settings.uism.TEXTBOX_ENTRY_PADY, sticky="nsew") - main_window.entry_message_box._entry.grid(padx=settings.uism.TEXTBOX_ENTRY_IPADX, pady=settings.uism.TEXTBOX_ENTRY_IPADY) def messageBoxAnyKeyPress(e): @@ -32,3 +35,58 @@ def createEntryMessageBox(settings, main_window): main_window.entry_message_box.bind("", messageBoxAnyKeyPress) + + main_window.main_send_message_button_container = CTkFrame(main_window.main_entry_message_container, corner_radius=settings.uism.SEND_MESSAGE_BUTTON_CORNER_RADIUS, fg_color=settings.ctm.SEND_MESSAGE_BUTTON_BG_COLOR, width=0, height=0) + main_window.main_send_message_button_container.grid(row=0, column=1, padx=(0, settings.uism.TEXTBOX_ENTRY_PADX), pady=settings.uism.TEXTBOX_ENTRY_PADY, sticky="nsew") + + main_window.main_send_message_button_container.grid_columnconfigure(0, weight=0, minsize=settings.uism.SEND_MESSAGE_BUTTON_MIN_WIDTH) + main_window.main_send_message_button_container.grid_rowconfigure(0, weight=1) + + + + + main_window.main_send_message_button = CTkFrame(main_window.main_send_message_button_container, corner_radius=0, fg_color=settings.ctm.SEND_MESSAGE_BUTTON_BG_COLOR, height=0, width=0) + main_window.main_send_message_button.grid(row=0, column=0, sticky="nsew") + main_window.main_send_message_button.configure(cursor="hand2") + + main_window.main_send_message_button.grid_columnconfigure((0,2), weight=1) + main_window.main_send_message_button.grid_rowconfigure((0,2), weight=1) + + main_window.main_send_message_button_image = CTkLabel( + main_window.main_send_message_button, + text=None, + height=0, + image=CTkImage((settings.image_file.SEND_MESSAGE_ICON),size=(settings.uism.SEND_MESSAGE_BUTTON_IMAGE_SIZE,settings.uism.SEND_MESSAGE_BUTTON_IMAGE_SIZE)), + ) + main_window.main_send_message_button_image.grid(row=1, column=1) + + + + bindButtonFunctionAndColor( + target_widgets=[main_window.main_send_message_button, main_window.main_send_message_button_image], + enter_color=settings.ctm.SEND_MESSAGE_BUTTON_BG_HOVERED_COLOR, + leave_color=settings.ctm.SEND_MESSAGE_BUTTON_BG_COLOR, + clicked_color=settings.ctm.SEND_MESSAGE_BUTTON_BG_CLICKED_COLOR, + buttonReleasedFunction=lambda _e: callFunctionIfCallable(view_variable.CALLBACK_CLICKED_SEND_MESSAGE_BUTTON, _e), + ) + + + + + + + main_window.main_send_message_button__disabled = CTkFrame(main_window.main_send_message_button_container, corner_radius=0, fg_color=settings.ctm.SEND_MESSAGE_BUTTON_BG_COLOR, height=0, width=0) + main_window.main_send_message_button__disabled.grid(row=0, column=0, sticky="nsew") + + main_window.main_send_message_button__disabled.grid_columnconfigure((0,2), weight=1) + main_window.main_send_message_button__disabled.grid_rowconfigure((0,2), weight=1) + + main_window.main_send_message_button_image__disabled = CTkLabel( + main_window.main_send_message_button__disabled, + text=None, + height=0, + image=CTkImage((settings.image_file.SEND_MESSAGE_ICON_DISABLED),size=(settings.uism.SEND_MESSAGE_BUTTON_IMAGE_SIZE,settings.uism.SEND_MESSAGE_BUTTON_IMAGE_SIZE)), + ) + main_window.main_send_message_button_image__disabled.grid(row=1, column=1) + + main_window.main_send_message_button__disabled.grid_remove() \ No newline at end of file diff --git a/vrct_gui/main_window/widgets/create_textbox.py b/vrct_gui/main_window/widgets/create_textbox.py index 99e977f4..b3ed7446 100644 --- a/vrct_gui/main_window/widgets/create_textbox.py +++ b/vrct_gui/main_window/widgets/create_textbox.py @@ -59,7 +59,7 @@ def createTextbox(settings, main_window, view_variable): # Text box main_window.main_bg_container.grid_rowconfigure(1, weight=1) main_window.main_textbox_container = CTkFrame(main_window.main_bg_container, corner_radius=0, fg_color=settings.ctm.MAIN_BG_COLOR, width=0, height=0) - main_window.main_textbox_container.grid(row=1, column=0, sticky="nsew") + main_window.main_textbox_container.grid(row=1, column=0, columnspan=2, sticky="nsew") main_window.main_textbox_container.grid_columnconfigure(0,weight=1) main_window.main_textbox_container.grid_rowconfigure(0,weight=1) @@ -142,6 +142,7 @@ def createTextbox(settings, main_window, view_variable): fg_color=settings.ctm.TEXTBOX_BG_COLOR, text_color="lime", # Textbox's text_color is set when printing. so this is for prevent from non-setting text_color like the gloves used in food factories are blue. wrap="word", + height=0, )) textbox_widget = getattr(main_window, textbox_setting["textbox_attr_name"]) textbox_widget.grid(row=0, column=0, padx=settings.uism.TEXTBOX_PADX, pady=0, sticky="nsew") diff --git a/vrct_gui/splash_window/SplashWindow.py b/vrct_gui/splash_window/SplashWindow.py index 96537c5e..2a2db684 100644 --- a/vrct_gui/splash_window/SplashWindow.py +++ b/vrct_gui/splash_window/SplashWindow.py @@ -12,7 +12,6 @@ class SplashWindow(CTkToplevel): sw=self.winfo_screenwidth() - # sh=self.winfo_screenheight() pw=int(sw/4) diff --git a/vrct_gui/ui_managers/Themes/_darkTheme.py b/vrct_gui/ui_managers/Themes/_darkTheme.py index ed3c7cd8..fe3c1aa9 100644 --- a/vrct_gui/ui_managers/Themes/_darkTheme.py +++ b/vrct_gui/ui_managers/Themes/_darkTheme.py @@ -35,6 +35,10 @@ def _darkTheme(base_color): TEXTBOX_ENTRY_PLACEHOLDER_COLOR = base_color.DARK_500_COLOR, TEXTBOX_ENTRY_PLACEHOLDER_DISABLED_COLOR = base_color.DARK_700_COLOR, + SEND_MESSAGE_BUTTON_BG_COLOR = base_color.DARK_850_COLOR, + SEND_MESSAGE_BUTTON_BG_HOVERED_COLOR = base_color.DARK_825_COLOR, + SEND_MESSAGE_BUTTON_BG_CLICKED_COLOR = base_color.DARK_900_COLOR, + # Sidebar SIDEBAR_BG_COLOR = base_color.DARK_850_COLOR, @@ -211,10 +215,17 @@ def _darkTheme(base_color): SB__SWITCH_BOX_BUTTON_HOVERED_COLOR = base_color.DARK_350_COLOR, SB__CHECKBOX_BORDER_COLOR = base_color.DARK_600_COLOR, + SB__CHECKBOX_BORDER_DISABLED_COLOR = base_color.DARK_800_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__RADIOBUTTON_TEXT_COLOR = base_color.DARK_300_COLOR, + SB__RADIOBUTTON_BORDER_COLOR = base_color.DARK_600_COLOR, + SB__RADIOBUTTON_SELECTED_COLOR = base_color.PRIMARY_400_COLOR, + SB__RADIOBUTTON_BG_HOVERED_COLOR = base_color.DARK_825_COLOR, + SB__RADIOBUTTON_BG_CLICKED_COLOR = base_color.DARK_900_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, @@ -300,6 +311,8 @@ def _darkTheme(base_color): ARROW_LEFT = getImageFileFromUiUtils("arrow_left_white.png"), ARROW_LEFT_DISABLED = getImageFileFromUiUtils("arrow_left_disabled.png"), + SEND_MESSAGE_ICON = getImageFileFromUiUtils("send_message_icon_white.png"), + SEND_MESSAGE_ICON_DISABLED = getImageFileFromUiUtils("send_message_icon_black.png"), REFRESH_UPDATE_ICON = getImageFileFromUiUtils("refresh_update_icon.png"), REFRESH_ICON = getImageFileFromUiUtils("refresh_icon.png"), HELP_ICON = getImageFileFromUiUtils("help_icon_white.png"), diff --git a/vrct_gui/ui_managers/Themes/_lightTheme.py b/vrct_gui/ui_managers/Themes/_lightTheme.py index 95accf92..0815e602 100644 --- a/vrct_gui/ui_managers/Themes/_lightTheme.py +++ b/vrct_gui/ui_managers/Themes/_lightTheme.py @@ -35,6 +35,10 @@ def _lightTheme(base_color): TEXTBOX_ENTRY_PLACEHOLDER_COLOR = base_color.LIGHT_600_COLOR, TEXTBOX_ENTRY_PLACEHOLDER_DISABLED_COLOR = base_color.LIGHT_400_COLOR, + SEND_MESSAGE_BUTTON_BG_COLOR = base_color.LIGHT_300_COLOR, + SEND_MESSAGE_BUTTON_BG_HOVERED_COLOR = base_color.LIGHT_325_COLOR, + SEND_MESSAGE_BUTTON_BG_CLICKED_COLOR = base_color.LIGHT_350_COLOR, + # Sidebar SIDEBAR_BG_COLOR = base_color.LIGHT_250_COLOR, @@ -204,10 +208,17 @@ def _lightTheme(base_color): SB__SWITCH_BOX_BUTTON_HOVERED_COLOR = base_color.LIGHT_200_COLOR, SB__CHECKBOX_BORDER_COLOR = base_color.LIGHT_600_COLOR, + SB__CHECKBOX_BORDER_DISABLED_COLOR = base_color.LIGHT_300_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__RADIOBUTTON_TEXT_COLOR = base_color.LIGHT_900_COLOR, + SB__RADIOBUTTON_BORDER_COLOR = base_color.LIGHT_600_COLOR, + SB__RADIOBUTTON_SELECTED_COLOR = base_color.PRIMARY_400_COLOR, + SB__RADIOBUTTON_BG_HOVERED_COLOR = base_color.LIGHT_300_COLOR, + SB__RADIOBUTTON_BG_CLICKED_COLOR = base_color.LIGHT_325_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, @@ -294,6 +305,8 @@ def _lightTheme(base_color): ARROW_LEFT = getImageFileFromUiUtils("arrow_left_black.png"), ARROW_LEFT_DISABLED = getImageFileFromUiUtils("arrow_left_disabled.png"), + SEND_MESSAGE_ICON = getImageFileFromUiUtils("send_message_icon_black.png"), + SEND_MESSAGE_ICON_DISABLED = getImageFileFromUiUtils("send_message_icon_white.png"), REFRESH_UPDATE_ICON = getImageFileFromUiUtils("refresh_update_icon.png"), REFRESH_ICON = getImageFileFromUiUtils("refresh_icon.png"), HELP_ICON = getImageFileFromUiUtils("help_icon_black.png"), diff --git a/vrct_gui/ui_managers/UiScalingManager.py b/vrct_gui/ui_managers/UiScalingManager.py index b3e7f937..2e02b1bf 100644 --- a/vrct_gui/ui_managers/UiScalingManager.py +++ b/vrct_gui/ui_managers/UiScalingManager.py @@ -50,11 +50,17 @@ class UiScalingManager(): self.main.TEXTBOX_FONT_SIZE__MAIN_TEXT_FONT = self._calculateUiSize(16) self.main.TEXTBOX_ENTRY_FONT_SIZE = self._calculateUiSize(16) + self.main.TEXTBOX_ENTRY_CORNER_RADIUS = self._calculateUiSize(4) + self.main.TEXTBOX_ENTRY_BORDER_SIZE = self._calculateUiSize(2, is_allowed_odd=True) self.main.TEXTBOX_ENTRY_HEIGHT = self._calculateUiSize(40) self.main.TEXTBOX_ENTRY_PADX = self.main.TEXTBOX_PADX self.main.TEXTBOX_ENTRY_PADY = self._calculateUiSize(10) - self.main.TEXTBOX_ENTRY_IPADX = self._calculateUiSize(14) - self.main.TEXTBOX_ENTRY_IPADY = (self._calculateUiSize(2, True), self._calculateUiSize(3, True)) + + self.main.SEND_MESSAGE_BUTTON_CORNER_RADIUS = self.main.TEXTBOX_ENTRY_CORNER_RADIUS + self.main.SEND_MESSAGE_BUTTON_IMAGE_SIZE = self._calculateUiSize(20) + self.main.SEND_MESSAGE_BUTTON_MIN_WIDTH = self._calculateUiSize(40) + self.main.SEND_MESSAGE_BUTTON_RATE_WIDTH = self._calculateUiSize(6) + self.main.SEND_MESSAGE_BUTTON_MAX_WIDTH = self._calculateUiSize(100) # Sidebar @@ -86,6 +92,9 @@ class UiScalingManager(): self.main.SLS__PRESET_TAB_NUMBER_CORNER_RADIUS = self._calculateUiSize(6) self.main.SLS__PRESET_TAB_NUMBER_ADJUSTED_HEIGHT = self._calculateUiSize(36) + self.main.SLS__BOX_TRANSCRIPTION_STATUS_IMAGE_SIZE = self.dupTuple(self._calculateUiSize(14)) + + self.main.SLS__BOX_SECTION_TITLE_FONT_SIZE = self._calculateUiSize(16) self.main.SLS__BOX_SECTION_TITLE_BOTTOM_PADY = self._calculateUiSize(10) self.main.SLS__BOX_IPADX = self._calculateUiSize(10) @@ -160,6 +169,8 @@ class UiScalingManager(): self.confirmation_modal.BUTTONS_IPADX = self._calculateUiSize(10) self.confirmation_modal.BUTTONS_IPADY = self._calculateUiSize(6) + # Dropdown Menu Window + self.config_window.MARGIN_WIDTH = self._calculateUiSize(16) # Config Window self.config_window.DEFAULT_WIDTH = self._calculateUiSize(1080) @@ -296,6 +307,7 @@ class UiScalingManager(): 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_CORNER_RADIUS = self._calculateUiSize(4) 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)) @@ -322,9 +334,9 @@ class UiScalingManager(): self.config_window.SB__BUTTON_IPADXY = self._calculateUiSize(16) self.config_window.SB__BUTTON_ICON_SIZE = self._calculateUiSize(24) + self.config_window.SB__BUTTON_CORNER_RADIUS = self.config_window.BUTTONS_CORNER_RADIUS 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): diff --git a/vrct_gui/ui_utils/CustomizedCTkScrollableFrame.py b/vrct_gui/ui_utils/CustomizedCTkScrollableFrame.py new file mode 100644 index 00000000..16b5460f --- /dev/null +++ b/vrct_gui/ui_utils/CustomizedCTkScrollableFrame.py @@ -0,0 +1,79 @@ +# Override customtkinter's CTkScrollableFrame for scrolling speed up +from customtkinter import CTkScrollableFrame, CTkFont +from typing import Union, Tuple, Optional +import sys +try: + from typing import Literal +except ImportError: + from typing_extensions import Literal + +class CustomizedCTkScrollableFrame(CTkScrollableFrame): + def __init__( + self, + master: any, + width: int = 200, + height: int = 200, + corner_radius: Optional[Union[int, str]] = None, + border_width: Optional[Union[int, str]] = None, + + bg_color: Union[str, Tuple[str, str]] = "transparent", + fg_color: Optional[Union[str, Tuple[str, str]]] = None, + border_color: Optional[Union[str, Tuple[str, str]]] = None, + scrollbar_fg_color: Optional[Union[str, Tuple[str, str]]] = None, + scrollbar_button_color: Optional[Union[str, Tuple[str, str]]] = None, + scrollbar_button_hover_color: Optional[Union[str, Tuple[str, str]]] = None, + label_fg_color: Optional[Union[str, Tuple[str, str]]] = None, + label_text_color: Optional[Union[str, Tuple[str, str]]] = None, + + label_text: str = "", + label_font: Optional[Union[tuple, CTkFont]] = None, + label_anchor: str = "center", + orientation: Literal["vertical", "horizontal"] = "vertical" + ): + + super().__init__( + master, + width, + height, + corner_radius, + border_width, + + bg_color, + fg_color, + border_color, + scrollbar_fg_color, + scrollbar_button_color, + scrollbar_button_hover_color, + label_fg_color, + label_text_color, + + label_text, + label_font, + label_anchor, + orientation, + ) + + def _mouse_wheel_all(self, event): + if self.check_if_master_is_canvas(event.widget): + if sys.platform.startswith("win"): + if self._shift_pressed: + if self._parent_canvas.xview() != (0.0, 1.0): + self._parent_canvas.xview("scroll", -int(event.delta / 6), "units") + else: + if self._parent_canvas.yview() != (0.0, 1.0): + self._parent_canvas.yview("scroll", -int(event.delta / 2), "units") + + elif sys.platform == "darwin": + if self._shift_pressed: + if self._parent_canvas.xview() != (0.0, 1.0): + self._parent_canvas.xview("scroll", -event.delta, "units") + else: + if self._parent_canvas.yview() != (0.0, 1.0): + self._parent_canvas.yview("scroll", -event.delta, "units") + else: + if self._shift_pressed: + if self._parent_canvas.xview() != (0.0, 1.0): + self._parent_canvas.xview("scroll", -event.delta, "units") + else: + if self._parent_canvas.yview() != (0.0, 1.0): + self._parent_canvas.yview("scroll", -event.delta, "units") \ No newline at end of file diff --git a/vrct_gui/ui_utils/__init__.py b/vrct_gui/ui_utils/__init__.py index bc2a1337..49ee911d 100644 --- a/vrct_gui/ui_utils/__init__.py +++ b/vrct_gui/ui_utils/__init__.py @@ -1 +1,2 @@ -from .ui_utils import * \ No newline at end of file +from .ui_utils import * +from .CustomizedCTkScrollableFrame import CustomizedCTkScrollableFrame \ No newline at end of file diff --git a/vrct_gui/vrct_gui.py b/vrct_gui/vrct_gui.py index a0926150..7c0bdc7f 100644 --- a/vrct_gui/vrct_gui.py +++ b/vrct_gui/vrct_gui.py @@ -43,11 +43,21 @@ class VRCT_GUI(CTk): def _showGUI(self): self.attributes("-alpha", 0) self.deiconify() - self.geometry("{}x{}".format( - self.settings.main.uism.MAIN_AREA_MIN_WIDTH + self.settings.main.uism.SIDEBAR_MIN_WIDTH, - self.winfo_height() - )) - setGeometryToCenterOfScreen(root_widget=self) + if self.settings.main.to_restore_main_window_geometry is True: + self.geometry("{}x{}+{}+{}".format( + self.settings.main.geometry.width, + self.settings.main.geometry.height, + self.settings.main.geometry.x_pos, + self.settings.main.geometry.y_pos, + )) + else: + self.geometry("{}x{}".format( + self.settings.main.uism.MAIN_AREA_MIN_WIDTH + self.settings.main.uism.SIDEBAR_MIN_WIDTH, + self.winfo_height() + )) + setGeometryToCenterOfScreen(root_widget=self) + + if self._view_variable.IS_MAIN_WINDOW_SIDEBAR_COMPACT_MODE is True: self._enableMainWindowSidebarCompactMode() fadeInAnimation(self, steps=5, interval=0.008)