From 44baaa84b8e645c5c54299b6f9d35e728fa0d465 Mon Sep 17 00:00:00 2001 From: Sakamoto Shiina <68018796+ShiinaSakamoto@users.noreply.github.com> Date: Sun, 5 Nov 2023 08:03:52 +0900 Subject: [PATCH] =?UTF-8?q?[Update]=20Message=20Format:=20UI=E6=94=B9?= =?UTF-8?q?=E5=96=84=E3=80=81[message]=E3=82=84[translation]=E3=81=AA?= =?UTF-8?q?=E3=81=A9=E5=BF=85=E9=A0=88=E3=81=AA=E3=82=82=E3=81=AE=E3=81=AF?= =?UTF-8?q?=E5=9B=BA=E5=AE=9A(=E5=85=A5=E3=82=8C=E6=9B=BF=E3=81=88?= =?UTF-8?q?=E5=8F=AF=E8=83=BD)=E3=81=97=E3=80=81=E3=83=A6=E3=83=BC?= =?UTF-8?q?=E3=82=B6=E3=83=BC=E3=81=AF=E7=B7=A8=E9=9B=86=E3=81=A7=E3=81=8D?= =?UTF-8?q?=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB=E3=80=82=E4=B8=8D?= =?UTF-8?q?=E5=AE=8C=E5=85=A8=E3=81=AA=E6=B0=97=E3=81=AF=E3=81=97=E3=81=A6?= =?UTF-8?q?=E3=81=84=E3=82=8B=E3=81=8C=E3=80=81=E8=A1=A8=E7=A4=BA=E3=81=AE?= =?UTF-8?q?=E4=BE=8B=E3=82=92=E8=BF=BD=E5=8A=A0=E3=81=97=E3=80=81=E7=9B=B4?= =?UTF-8?q?=E6=84=9F=E7=9A=84=E3=81=AB=E3=83=A1=E3=83=83=E3=82=BB=E3=83=BC?= =?UTF-8?q?=E3=82=B8=E3=83=95=E3=82=A9=E3=83=BC=E3=83=9E=E3=83=83=E3=83=88?= =?UTF-8?q?=E3=82=92=E4=BD=BF=E3=81=88=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controller.py | 1 + img/refresh_icon.png | Bin 1487 -> 1443 bytes img/refresh_update_icon.png | Bin 0 -> 1487 bytes img/swap_icon.png | Bin 0 -> 13436 bytes locales/en.yml | 1 + locales/ja.yml | 3 +- locales/ko.yml | 1 + view.py | 106 ++++++++ .../_SettingBoxGenerator.py | 244 +++++++++++++++++- .../createSettingBox_Others.py | 22 +- .../main_window/createMainWindowWidgets.py | 2 +- vrct_gui/ui_managers/Themes/_darkTheme.py | 9 + vrct_gui/ui_managers/UiScalingManager.py | 19 ++ 13 files changed, 393 insertions(+), 15 deletions(-) create mode 100644 img/refresh_update_icon.png create mode 100644 img/swap_icon.png diff --git a/controller.py b/controller.py index f3f2d7c1..4842196b 100644 --- a/controller.py +++ b/controller.py @@ -628,6 +628,7 @@ def callbackSetMessageFormat(value): print("callbackSetMessageFormat", value) if len(value) > 0: config.MESSAGE_FORMAT = value + view.setMessageFormatEntryWidgets(config.MESSAGE_FORMAT) def callbackSetEnableSendMessageToVrc(value): print("callbackSetEnableSendMessageToVrc", value) diff --git a/img/refresh_icon.png b/img/refresh_icon.png index c5acad15a2097d399ea98438bb784d5d25bde461..408bc2a65bc002ebe87de1bf5da9a72e1dcc4f65 100644 GIT binary patch delta 1403 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 OL5vjv-lfaghyM>Eb8cV& literal 0 HcmV?d00001 diff --git a/locales/en.yml b/locales/en.yml index 7eee5744..0a77d70d 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -181,6 +181,7 @@ config_window: message_format: label: Message Format desc: "You can change the decoration of the message you want to send.\n[message] will be replaced with the message, and [translation] will be replaced with the translated message.\nIt will be used in Notification XSOverlay too." + example_text: This is an example sentence. Fonts, line breaks, etc. may differ from the actual display. send_message_to_vrc: label: Send Message To VRChat diff --git a/locales/ja.yml b/locales/ja.yml index b662a3eb..a73b4e8e 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -179,7 +179,8 @@ config_window: message_format: label: 送信するメッセージのフォーマット - desc: "VRChatで相手に実際に見えるフォーマットを変更できます。\n[message]がメッセージに置換され、\n[translation]が翻訳されたメッセージに置換されます。\n※XSOverlayでの通知受け取り機能でも使われます。" + desc: "VRChatで相手に実際に見えるフォーマットを変更できます。\n[message]がメッセージに置換され、[translation]が翻訳されたメッセージに置換されます。\n※XSOverlayでの通知受け取り機能でも使われます。" + example_text: これは例文です。フォントや改行箇所など、実際の表示とは異なる場合があります。 send_message_to_vrc: label: VRChatにメッセージを送信する diff --git a/locales/ko.yml b/locales/ko.yml index ad08942f..fa8cc2b2 100644 --- a/locales/ko.yml +++ b/locales/ko.yml @@ -175,6 +175,7 @@ config_window: message_format: label: 전송 형식 # desc: "You can change the decoration of the message you want to send.\n[message] will be replaced with the message, and [translation] will be replaced with the translated message.\nIt will be used in Notification XSOverlay too." + example_text: 예문입니다. 글꼴, 줄 바꿈 등이 실제 표시와 다를 수 있습니다. # send_message_to_vrc: # label: Send Message To VRChat diff --git a/view.py b/view.py index ac1d0739..09267802 100644 --- a/view.py +++ b/view.py @@ -347,7 +347,14 @@ class View(): VAR_LABEL_MESSAGE_FORMAT=StringVar(value=i18n.t("config_window.message_format.label")), VAR_DESC_MESSAGE_FORMAT=StringVar(value=i18n.t("config_window.message_format.desc")), CALLBACK_SET_MESSAGE_FORMAT=None, + CALLBACK_SWAP_MESSAGE_FORMAT_REQUIRED_TEXT=self._swapMessageFormatRequiredText, VAR_MESSAGE_FORMAT=StringVar(value=config.MESSAGE_FORMAT), + VAR_LABEL_EXAMPLE_TEXT_MESSAGE_FORMAT=StringVar(value=""), + VAR_ENTRY_0_MESSAGE_FORMAT=StringVar(value=""), + VAR_ENTRY_1_MESSAGE_FORMAT=StringVar(value=""), + VAR_ENTRY_2_MESSAGE_FORMAT=StringVar(value=""), + VAR_TEXT_REQUIRED_0_MESSAGE_FORMAT=StringVar(value="[message]"), + VAR_TEXT_REQUIRED_1_MESSAGE_FORMAT=StringVar(value="[translation]"), VAR_LABEL_ENABLE_SEND_MESSAGE_TO_VRC=StringVar(value=i18n.t("config_window.send_message_to_vrc.label")), @@ -531,10 +538,56 @@ class View(): self.openSpeakerEnergyThresholdWidget() + self.setMessageFormatEntryWidgets(config.MESSAGE_FORMAT) + # Insert sample conversation for testing. # self._insertSampleConversationToTextbox() + def setMessageFormatEntryWidgets(self, message_format:str): + result = self.extractMessageFormat(message_format) + + if result.is_message_first is True: + self.view_variable.VAR_TEXT_REQUIRED_0_MESSAGE_FORMAT.set("[message]") + self.view_variable.VAR_TEXT_REQUIRED_1_MESSAGE_FORMAT.set("[translation]") + else: + self.view_variable.VAR_TEXT_REQUIRED_0_MESSAGE_FORMAT.set("[translation]") + self.view_variable.VAR_TEXT_REQUIRED_1_MESSAGE_FORMAT.set("[message]") + + self.view_variable.VAR_ENTRY_0_MESSAGE_FORMAT.set(result.before) + self.view_variable.VAR_ENTRY_1_MESSAGE_FORMAT.set(result.between) + self.view_variable.VAR_ENTRY_2_MESSAGE_FORMAT.set(result.after) + self.updateMessageFormat_ExampleTextWidget() + + def _swapMessageFormatRequiredText(self): + text_0 = self.view_variable.VAR_TEXT_REQUIRED_0_MESSAGE_FORMAT.get() + text_1 = self.view_variable.VAR_TEXT_REQUIRED_1_MESSAGE_FORMAT.get() + self.view_variable.VAR_TEXT_REQUIRED_0_MESSAGE_FORMAT.set(text_1) + self.view_variable.VAR_TEXT_REQUIRED_1_MESSAGE_FORMAT.set(text_0) + self.updateMessageFormat_ExampleTextWidget() + + new_message_format = self.getLatestMessageFormatFromWidget() + callFunctionIfCallable(self.view_variable.CALLBACK_SET_MESSAGE_FORMAT, new_message_format) + + + def getLatestMessageFormatFromWidget(self): + text_0 = self.view_variable.VAR_TEXT_REQUIRED_0_MESSAGE_FORMAT.get() + text_1 = self.view_variable.VAR_TEXT_REQUIRED_1_MESSAGE_FORMAT.get() + entry_0 = self.view_variable.VAR_ENTRY_0_MESSAGE_FORMAT.get() + entry_1 = self.view_variable.VAR_ENTRY_1_MESSAGE_FORMAT.get() + entry_2 = self.view_variable.VAR_ENTRY_2_MESSAGE_FORMAT.get() + return entry_0+text_0+entry_1+text_1+entry_2 + + def updateMessageFormat_ExampleTextWidget(self): + message = i18n.t("config_window.message_format.example_text", locale=config.UI_LANGUAGE) + translation_locale = "ja" if config.UI_LANGUAGE == "en" else "en" + translation = i18n.t("config_window.message_format.example_text", locale=translation_locale) + + example_message = config.MESSAGE_FORMAT.replace("[message]", message) + example_message = example_message.replace("[translation]", translation) + + self.view_variable.VAR_LABEL_EXAMPLE_TEXT_MESSAGE_FORMAT.set(example_message) + # GUI process def createGUI(self): @@ -1308,6 +1361,59 @@ class View(): vrct_gui._showErrorMessage(target_widget=target_widget) + @staticmethod + def extractMessageFormat(text): + import re + message_index = text.find("[message]") + translation_index = text.find("[translation]") + + result_data = SimpleNamespace( + is_message_first = True, + before = "", + between = "", + after = "", + ) + + if message_index < translation_index: + text_before_message = text[:message_index] + result_data.before = text_before_message + + match = re.search(r"\[message\](.*?)\[translation\]", text) + if match: + extracted_text = match.group(1) + result_data.between = extracted_text + + else: + raise ValueError("Invalid Message Format") + + text_after_translation = text[translation_index + len("[translation]"):] + result_data.after = text_after_translation + + + + + elif translation_index < message_index: + result_data.is_message_first = False + text_before_translation = text[:translation_index] + result_data.before = text_before_translation + + match = re.search(r"\[translation\](.*?)\[message\]", text) + if match: + extracted_text = match.group(1) + result_data.between = extracted_text + else: + raise ValueError("Invalid Message Format") + + text_after_message = text[message_index + len("[message]"):] + result_data.after = text_after_message + + else: + raise ValueError("Invalid Message Format") + + return result_data + + + 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 8a7f3622..82693501 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,7 +2,7 @@ from functools import partial from types import SimpleNamespace from typing import Union -from customtkinter import CTkOptionMenu, CTkFont, CTkFrame, CTkLabel, CTkRadioButton, CTkEntry, CTkSlider, CTkSwitch, CTkCheckBox, CTkProgressBar +from customtkinter import CTkOptionMenu, CTkFont, CTkFrame, CTkLabel, CTkRadioButton, CTkEntry, CTkSlider, CTkSwitch, CTkCheckBox, CTkProgressBar, CTkImage from CTkToolTip import * from vrct_gui.ui_utils import createButtonWithImage, getLatestWidth, createOptionMenuBox, getLatestHeight, bindButtonFunctionAndColor @@ -22,7 +22,7 @@ class _SettingBoxGenerator(): self.dropdown_menu_window = vrct_gui.vrct_gui.dropdown_menu_window - def _createSettingBoxFrame(self, sb__attr_name, for_var_label_text=None, for_var_desc_text=None): + def _createSettingBoxFrame(self, sb__attr_name, for_var_label_text=None, for_var_desc_text=None, expand_label_frame:bool=False): self.config_window.sb__widgets[sb__attr_name] = SimpleNamespace() setting_box_frame = CTkFrame(self.parent_widget, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) @@ -34,8 +34,7 @@ class _SettingBoxGenerator(): setting_box_frame_wrapper = CTkFrame(setting_box_frame, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) setting_box_frame_wrapper.grid(row=0, column=0, padx=self.settings.uism.SB__IPADX, pady=self.settings.uism.SB__IPADY, sticky="ew") - setting_box_frame_wrapper.grid_columnconfigure(0, weight=0, minsize=int(self.settings.uism.MAIN_AREA_MIN_WIDTH / 2)) - setting_box_frame_wrapper.grid_columnconfigure(2, weight=1, minsize=int(self.settings.uism.MAIN_AREA_MIN_WIDTH / 2)) + setting_box_frame_wrapper_fix_border = CTkFrame(setting_box_frame, corner_radius=0, width=0, height=0) setting_box_frame_wrapper_fix_border.grid(row=1, column=0, sticky="ew") @@ -43,10 +42,22 @@ class _SettingBoxGenerator(): setting_box_frame_wrapper_fix_border2 = CTkFrame(setting_box_frame, corner_radius=0, width=0, height=0) setting_box_frame_wrapper_fix_border2.grid(row=0, column=1, sticky="ns") - if for_var_label_text is not None: - self._setSettingBoxLabels(sb__attr_name, setting_box_frame_wrapper, for_var_label_text, for_var_desc_text) - # setting_box_item_frame = CTkFrame(setting_box_frame_wrapper, corner_radius=0, width=0, height=0, fg_color="red") + + if for_var_label_text is not None: + self._setSettingBoxLabels(sb__attr_name, setting_box_frame_wrapper, for_var_label_text, for_var_desc_text, expand_label_frame) + if expand_label_frame is True: + setting_box_frame_wrapper.grid_columnconfigure(0, weight=1, minsize=int(self.settings.uism.MAIN_AREA_MIN_WIDTH)) + setting_box_frame_wrapper.grid(columnspan=3) + return setting_box_frame + + + setting_box_frame_wrapper.grid_columnconfigure(0, weight=0, minsize=int(self.settings.uism.MAIN_AREA_MIN_WIDTH / 2)) + setting_box_frame_wrapper.grid_columnconfigure(2, weight=1, minsize=int(self.settings.uism.MAIN_AREA_MIN_WIDTH / 2)) + + + + setting_box_item_frame = CTkFrame(setting_box_frame_wrapper, corner_radius=0, width=0, height=0, fg_color=self.settings.ctm.SB__BG_COLOR) if for_var_label_text is not None: setting_box_item_frame.grid(row=0, column=2, padx=0, sticky="nsew") @@ -57,7 +68,7 @@ class _SettingBoxGenerator(): return (setting_box_frame, setting_box_item_frame) - def _setSettingBoxLabels(self, sb__attr_name, setting_box_frame_wrapper, for_var_label_text, for_var_desc_text=None): + def _setSettingBoxLabels(self, sb__attr_name, setting_box_frame_wrapper, for_var_label_text, for_var_desc_text=None, expand_label_frame:bool=False): setting_box_labels_frame = CTkFrame(setting_box_frame_wrapper, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) setting_box_labels_frame.grid(row=0, column=0, padx=0, pady=0, sticky="nsew") @@ -86,6 +97,9 @@ class _SettingBoxGenerator(): font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__DESC_FONT_SIZE, weight="normal"), text_color=self.settings.ctm.LABELS_DESC_TEXT_COLOR ) + if expand_label_frame is True: + setting_box_desc.configure(wraplength=self.settings.uism.MAIN_AREA_MIN_WIDTH) + setting_box_desc.grid(row=2, column=0, padx=0, pady=(self.settings.uism.SB__DESC_TOP_PADY,0), sticky="ew") self.config_window.additional_widgets.append(setting_box_desc) self.config_window.sb__widgets[sb__attr_name].desc_widget=setting_box_desc @@ -93,6 +107,16 @@ class _SettingBoxGenerator(): self.config_window.sb__widgets[sb__attr_name].desc_widget=None + def createSettingBox_Labels( + self, + for_var_label_text, for_var_desc_text, + labels_attr_name, + ): + + setting_box_frame= self._createSettingBoxFrame(labels_attr_name, for_var_label_text, for_var_desc_text, expand_label_frame=True) + + return setting_box_frame + def createSettingBoxDropdownMenu( @@ -452,6 +476,210 @@ class _SettingBoxGenerator(): return setting_box_frame + + + + def createSettingBoxMessageFormatEntries(self, + base_entry_attr_name, + entry_textvariable_0, + entry_textvariable_1, + entry_textvariable_2, + textvariable_0, + textvariable_1, + entry_bind__Any_KeyRelease, + entry_bind__FocusOut=None, + ): + + (setting_box_frame, setting_box_item_frame) = self._createSettingBoxFrame(base_entry_attr_name) + + + all_wrapper = CTkFrame(setting_box_item_frame, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + all_wrapper.grid(row=1, column=0, sticky="ew") + + all_wrapper.grid_columnconfigure(0, weight=1) + + + example_box_wrapper = CTkFrame(all_wrapper, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + example_box_wrapper.grid(row=0, column=0, pady=self.settings.uism.SB__MESSAGE_FORMAT__ENTRIES_BOTTOM_PADY, sticky="ew") + + entries_wrapper = CTkFrame(all_wrapper, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + entries_wrapper.grid(row=1, column=0, pady=self.settings.uism.SB__MESSAGE_FORMAT__ENTRIES_BOTTOM_PADY, sticky="ew") + + swap_button_wrapper = CTkFrame(all_wrapper, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + swap_button_wrapper.grid(row=2, column=0, sticky="e") + + + + + + example_box_wrapper.grid_columnconfigure((0,2), weight=1) + example_frame_widget = CTkFrame(example_box_wrapper, corner_radius=self.settings.uism.SB__MESSAGE_FORMAT__EXAMPLE_CORNER_RADIUS, fg_color=self.settings.ctm.SB__MESSAGE_FORMAT__EXAMPLE_BG_COLOR, width=0, height=0) + example_frame_widget.grid(row=0, column=1) + + example_frame_widget.grid_rowconfigure((0,2), weight=1) + example_frame_widget.grid_columnconfigure((0,2), weight=1) + example_label_widget = CTkLabel( + example_frame_widget, + textvariable=self.view_variable.VAR_LABEL_EXAMPLE_TEXT_MESSAGE_FORMAT, + anchor="center", + justify="center", + wraplength=self.settings.uism.SB__MESSAGE_FORMAT__EXAMPLE_WRAP_LENGTH, + height=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__MESSAGE_FORMAT__REQUIRED_TEXT_FONT_SIZE, weight="normal"), + text_color=self.settings.ctm.LABELS_TEXT_COLOR, + ) + example_label_widget.grid(row=1, column=1, padx=self.settings.uism.SB__MESSAGE_FORMAT__EXAMPLE_IPADXY, pady=self.settings.uism.SB__MESSAGE_FORMAT__EXAMPLE_IPADXY, sticky="ew") + + self.config_window.additional_widgets.append(example_box_wrapper) + + + + + entry_textvariables = [entry_textvariable_0, entry_textvariable_1, entry_textvariable_2] + for i in range(3): + entry_widget = CTkEntry( + entries_wrapper, + text_color=self.settings.ctm.SB__ENTRY_TEXT_COLOR, + fg_color=self.settings.ctm.SB__ENTRY_BG_COLOR, + border_color=self.settings.ctm.SB__ENTRY_BORDER_COLOR, + height=self.settings.uism.SB__MESSAGE_FORMAT__ENTRY_HEIGHT, + textvariable=entry_textvariables[i], + justify="center", + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__ENTRY_FONT_SIZE, weight="normal"), + ) + setattr(self.config_window, base_entry_attr_name + str(i), entry_widget) + + + + if entry_bind__FocusOut is not None: + entry_widget.bind("", entry_bind__FocusOut, "+") + + + label_frame_widget_0 = CTkFrame(entries_wrapper, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + + label_frame_widget_0.grid_rowconfigure((0,2), weight=1) + label_frame_widget_0.grid_columnconfigure(0, weight=1) + label_widget_0 = CTkLabel( + label_frame_widget_0, + textvariable=textvariable_0, + anchor="center", + height=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__MESSAGE_FORMAT__REQUIRED_TEXT_FONT_SIZE, weight="normal"), + text_color=self.settings.ctm.LABELS_TEXT_COLOR + ) + label_widget_0.grid(row=1, column=0, padx=0, pady=0, sticky="ew") + + + label_frame_widget_1 = CTkFrame(entries_wrapper, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + + label_frame_widget_1.grid_rowconfigure((0,2), weight=1) + label_frame_widget_1.grid_columnconfigure(0, weight=1) + label_widget_1 = CTkLabel( + label_frame_widget_1, + textvariable=textvariable_1, + anchor="center", + height=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__MESSAGE_FORMAT__REQUIRED_TEXT_FONT_SIZE, weight="normal"), + text_color=self.settings.ctm.LABELS_TEXT_COLOR + ) + label_widget_1.grid(row=1, column=0, padx=0, pady=0, sticky="ew") + + + entries_wrapper.grid_columnconfigure((0,2,4), weight=1) + entries_wrapper.grid_columnconfigure((1,3), weight=0, uniform="message_format_fixed_labels") + + entry_widget_0 = getattr(self.config_window, base_entry_attr_name+"0") + entry_widget_1 = getattr(self.config_window, base_entry_attr_name+"1") + entry_widget_2 = getattr(self.config_window, base_entry_attr_name+"2") + entry_widget_0.grid(row=0, column=0, sticky="ew") + entry_widget_1.grid(row=0, column=2, sticky="ew") + entry_widget_2.grid(row=0, column=4, sticky="ew") + label_frame_widget_0.grid(row=0, column=1, padx=self.settings.uism.SB__MESSAGE_FORMAT__REQUIRED_TEXT_PADX, sticky="ew") + label_frame_widget_1.grid(row=0, column=3, padx=self.settings.uism.SB__MESSAGE_FORMAT__REQUIRED_TEXT_PADX, sticky="ew") + + def adjusted_command__for_entry_bind__Any_KeyRelease(_e): + message_format = entry_widget_0.get() + textvariable_0.get() + entry_widget_1.get() + textvariable_1.get() + entry_widget_2.get() + entry_bind__Any_KeyRelease(message_format) + + + entry_widget_0.bind("", adjusted_command__for_entry_bind__Any_KeyRelease) + entry_widget_1.bind("", adjusted_command__for_entry_bind__Any_KeyRelease) + entry_widget_2.bind("", adjusted_command__for_entry_bind__Any_KeyRelease) + + + + + + + swap_button = CTkFrame(swap_button_wrapper, corner_radius=self.settings.uism.BUTTONS_CORNER_RADIUS, fg_color=self.settings.ctm.SB__MESSAGE_FORMAT__SWAP_BUTTON_COLOR, cursor="hand2") + swap_button.grid(row=0, column=2, sticky="ew") + + + swap_button.grid_columnconfigure(0, weight=1) + swap_button_label_wrapper = CTkFrame(swap_button, corner_radius=0, fg_color=self.settings.ctm.SB__MESSAGE_FORMAT__SWAP_BUTTON_COLOR) + swap_button_label_wrapper.grid(row=0, column=0, padx=self.settings.uism.SB__MESSAGE_FORMAT__SWAP_BUTTON_IPADX, pady=self.settings.uism.SB__MESSAGE_FORMAT__SWAP_BUTTON_IPADY, sticky="ew") + + + swap_button_label_wrapper.grid_columnconfigure((0,4), weight=1) + swap_button_label_wrapper.grid_rowconfigure((0,2), weight=1) + + swap_button_label_0 = CTkLabel( + swap_button_label_wrapper, + textvariable=textvariable_0, + height=0, + corner_radius=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__MESSAGE_FORMAT__SWAP_BUTTON_FONT_SIZE, weight="normal"), + anchor="w", + text_color=self.settings.ctm.LABELS_TEXT_COLOR, + ) + swap_button_label_0.grid(row=1, column=1) + + swap_button_both_direction_arrow_img = CTkLabel( + swap_button_label_wrapper, + text=None, + height=0, + corner_radius=0, + image=CTkImage((self.settings.image_file.SWAP_ICON), size=self.settings.uism.SB__MESSAGE_FORMAT__SWAP_BUTTON_ARROWS_IMG_SIZE), + anchor="w", + text_color=self.settings.ctm.LABELS_TEXT_COLOR, + ) + swap_button_both_direction_arrow_img.grid(row=1, column=2, padx=self.settings.uism.SB__MESSAGE_FORMAT__SWAP_TEXT_PADX) + + swap_button_label_1 = CTkLabel( + swap_button_label_wrapper, + textvariable=textvariable_1, + height=0, + corner_radius=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__MESSAGE_FORMAT__SWAP_BUTTON_FONT_SIZE, weight="normal"), + anchor="w", + text_color=self.settings.ctm.LABELS_TEXT_COLOR, + ) + swap_button_label_1.grid(row=1, column=3) + + + def adjustedCommand(): + callFunctionIfCallable(self.view_variable.CALLBACK_SWAP_MESSAGE_FORMAT_REQUIRED_TEXT) + + bindButtonFunctionAndColor( + target_widgets=[ + swap_button, + swap_button_label_wrapper, + swap_button_label_0, + swap_button_both_direction_arrow_img, + swap_button_label_1, + ], + enter_color=self.settings.ctm.SB__MESSAGE_FORMAT__SWAP_BUTTON_HOVERED_COLOR, + leave_color=self.settings.ctm.SB__MESSAGE_FORMAT__SWAP_BUTTON_COLOR, + clicked_color=self.settings.ctm.SB__MESSAGE_FORMAT__SWAP_BUTTON_CLICKED_COLOR, + buttonReleasedFunction=lambda _e: adjustedCommand(), + ) + + + return setting_box_frame + + + + def createSettingBoxArrowSwitch( self, for_var_label_text, for_var_desc_text, diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/createSettingBox_Others.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/createSettingBox_Others.py index e4f46fb6..241d33c6 100644 --- a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/createSettingBox_Others.py +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_others/createSettingBox_Others.py @@ -5,7 +5,8 @@ from .._SettingBoxGenerator import _SettingBoxGenerator def createSettingBox_Others(setting_box_wrapper, config_window, settings, view_variable): sbg = _SettingBoxGenerator(setting_box_wrapper, config_window, settings, view_variable) createSettingBoxCheckbox = sbg.createSettingBoxCheckbox - createSettingBoxEntry = sbg.createSettingBoxEntry + createSettingBox_Labels = sbg.createSettingBox_Labels + createSettingBoxMessageFormatEntries = sbg.createSettingBoxMessageFormatEntries # 元 checkbox_auto_clear_chatbox_callback @@ -63,13 +64,24 @@ def createSettingBox_Others(setting_box_wrapper, config_window, settings, view_v row+=1 - config_window.sb__message_format = createSettingBoxEntry( + config_window.sb__message_format_labels = createSettingBox_Labels( for_var_label_text=view_variable.VAR_LABEL_MESSAGE_FORMAT, for_var_desc_text=view_variable.VAR_DESC_MESSAGE_FORMAT, - entry_attr_name="sb__entry_message_format", - entry_width=settings.uism.RESPONSIVE_UI_SIZE_INT_250, + labels_attr_name="sb__labels_message_format", + ) + config_window.sb__message_format_labels.grid(row=row, pady=0) + row+=1 + + config_window.sb__message_format = createSettingBoxMessageFormatEntries( + base_entry_attr_name="sb__entry_message_format", + # entry_width=settings.uism.RESPONSIVE_UI_SIZE_INT_150, + entry_textvariable_0=view_variable.VAR_ENTRY_0_MESSAGE_FORMAT, + entry_textvariable_1=view_variable.VAR_ENTRY_1_MESSAGE_FORMAT, + entry_textvariable_2=view_variable.VAR_ENTRY_2_MESSAGE_FORMAT, + textvariable_0=view_variable.VAR_TEXT_REQUIRED_0_MESSAGE_FORMAT, + textvariable_1=view_variable.VAR_TEXT_REQUIRED_1_MESSAGE_FORMAT, entry_bind__Any_KeyRelease=lambda value: entry_message_format_callback(value), - entry_textvariable=view_variable.VAR_MESSAGE_FORMAT, + # entry_textvariable=view_variable.VAR_MESSAGE_FORMAT, ) config_window.sb__message_format.grid(row=row) row+=1 diff --git a/vrct_gui/main_window/createMainWindowWidgets.py b/vrct_gui/main_window/createMainWindowWidgets.py index 088a3075..65661216 100644 --- a/vrct_gui/main_window/createMainWindowWidgets.py +++ b/vrct_gui/main_window/createMainWindowWidgets.py @@ -68,7 +68,7 @@ def createMainWindowWidgets(vrct_gui, settings, view_variable): text=None, corner_radius=0, height=0, - image=CTkImage(settings.image_file.REFRESH_ICON.rotate(25), size=settings.uism.UPDATE_AVAILABLE_BUTTON_SIZE) + image=CTkImage(settings.image_file.REFRESH_UPDATE_ICON.rotate(25), size=settings.uism.UPDATE_AVAILABLE_BUTTON_SIZE) ) vrct_gui.update_available_icon.grid(row=1, column=0, padx=(settings.uism.UPDATE_AVAILABLE_BUTTON_IPADX, settings.uism.UPDATE_AVAILABLE_PADX_BETWEEN_LABEL_AND_ICON), pady=0) diff --git a/vrct_gui/ui_managers/Themes/_darkTheme.py b/vrct_gui/ui_managers/Themes/_darkTheme.py index 2522608a..21296d03 100644 --- a/vrct_gui/ui_managers/Themes/_darkTheme.py +++ b/vrct_gui/ui_managers/Themes/_darkTheme.py @@ -246,6 +246,13 @@ def _darkTheme(base_color): SB__ADD_AND_DELETE_ABLE_LIST__VALUES_DELETED_BUTTON_CLICKED_BG_COLOR = base_color.DARK_900_COLOR, + SB__MESSAGE_FORMAT__EXAMPLE_BG_COLOR = "#3a4554", # from VRChat' chat display color + SB__MESSAGE_FORMAT__SWAP_BUTTON_COLOR = base_color.DARK_875_COLOR, + SB__MESSAGE_FORMAT__SWAP_BUTTON_HOVERED_COLOR = base_color.DARK_800_COLOR, + SB__MESSAGE_FORMAT__SWAP_BUTTON_CLICKED_COLOR = base_color.DARK_888_COLOR, + + + # Side menu SIDE_MENU_BG_COLOR = base_color.DARK_950_COLOR, @@ -289,11 +296,13 @@ def _darkTheme(base_color): ARROW_LEFT = getImageFileFromUiUtils("arrow_left_white.png"), ARROW_LEFT_DISABLED = getImageFileFromUiUtils("arrow_left_disabled.png"), + REFRESH_UPDATE_ICON = getImageFileFromUiUtils("refresh_update_icon.png"), REFRESH_ICON = getImageFileFromUiUtils("refresh_icon.png"), HELP_ICON = getImageFileFromUiUtils("help_icon_white.png"), CANCEL_ICON = getImageFileFromUiUtils("cancel_icon.png"), REDO_ICON = getImageFileFromUiUtils("redo_white.png"), + SWAP_ICON = getImageFileFromUiUtils("swap_icon.png"), ), ) diff --git a/vrct_gui/ui_managers/UiScalingManager.py b/vrct_gui/ui_managers/UiScalingManager.py index 9a1ad1c2..70b2fa95 100644 --- a/vrct_gui/ui_managers/UiScalingManager.py +++ b/vrct_gui/ui_managers/UiScalingManager.py @@ -302,6 +302,25 @@ class UiScalingManager(): self.config_window.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_LEFT_PADX = (self._calculateUiSize(20), 0) self.config_window.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_FONT_SIZE = self._calculateUiSize(14) + + self.config_window.SB__MESSAGE_FORMAT__EXAMPLE_CORNER_RADIUS = self._calculateUiSize(16) + self.config_window.SB__MESSAGE_FORMAT__EXAMPLE_IPADXY = self._calculateUiSize(10) + self.config_window.SB__MESSAGE_FORMAT__EXAMPLE_WRAP_LENGTH = self._calculateUiSize(300) + + self.config_window.SB__MESSAGE_FORMAT__ENTRY_HEIGHT = self.config_window.SB__ENTRY_HEIGHT + self.config_window.SB__MESSAGE_FORMAT__REQUIRED_TEXT_PADX = self._calculateUiSize(10) + self.config_window.SB__MESSAGE_FORMAT__REQUIRED_TEXT_FONT_SIZE = self._calculateUiSize(16) + + self.config_window.SB__MESSAGE_FORMAT__SWAP_BUTTON_ARROWS_IMG_SIZE = self.dupTuple(self._calculateUiSize(20)) + self.config_window.SB__MESSAGE_FORMAT__SWAP_BUTTON_IPADX = self._calculateUiSize(16) + self.config_window.SB__MESSAGE_FORMAT__SWAP_BUTTON_IPADY = self._calculateUiSize(6) + self.config_window.SB__MESSAGE_FORMAT__SWAP_BUTTON_FONT_SIZE = self._calculateUiSize(14) + self.config_window.SB__MESSAGE_FORMAT__SWAP_TEXT_PADX = self._calculateUiSize(10) + + self.config_window.SB__MESSAGE_FORMAT__ENTRIES_BOTTOM_PADY = (0, self._calculateUiSize(14)) + + + def _calculateUiSize(self, default_size, is_allowed_odd:bool=False, is_zero_allowed:bool=False): size = calculateUiSize(default_size, self.SCALING_FLOAT, is_allowed_odd, is_zero_allowed) return size