diff --git a/config.py b/config.py index afd25f43..90896694 100644 --- a/config.py +++ b/config.py @@ -346,7 +346,7 @@ class Config: @INPUT_MIC_WORD_FILTER.setter def INPUT_MIC_WORD_FILTER(self, value): if type(value) is list: - self._INPUT_MIC_WORD_FILTER = value + self._INPUT_MIC_WORD_FILTER = sorted(set(value), key=value.index) saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) @property diff --git a/controller.py b/controller.py index f3ee030d..f3f2d7c1 100644 --- a/controller.py +++ b/controller.py @@ -487,19 +487,40 @@ def callbackSetMicMaxPhrases(value): except: view.showErrorMessage_MicMaxPhrases() -def callbackSetMicWordFilter(value): - print("callbackSetMicWordFilter", value) - word_filter = str(value) - word_filter = [w.strip() for w in word_filter.split(",") if len(w.strip()) > 0] - word_filter = ",".join(word_filter) - print("callbackSetMicWordFilter_afterSplitting", word_filter) - if len(word_filter) > 0: - config.INPUT_MIC_WORD_FILTER = word_filter.split(",") - else: - config.INPUT_MIC_WORD_FILTER = [] +def callbackSetMicWordFilter(values): + print("callbackSetMicWordFilter", values) + values = str(values) + values = [w.strip() for w in values.split(",") if len(w.strip()) > 0] + # Copy the list + new_input_mic_word_filter_list = config.INPUT_MIC_WORD_FILTER + new_added_value = [] + for value in values: + if value in new_input_mic_word_filter_list: + # If the value is already in the list, do nothing. + pass + else: + new_input_mic_word_filter_list.append(value) + new_added_value.append(value) + config.INPUT_MIC_WORD_FILTER = new_input_mic_word_filter_list + + view.addValueToList_WordFilter(new_added_value) + view.clearEntryBox_WordFilter() + view.setLatestConfigVariable("MicMicWordFilter") + model.resetKeywordProcessor() model.addKeywords() +def callbackDeleteMicWordFilter(value): + print("callbackDeleteMicWordFilter", value) + try: + new_input_mic_word_filter_list = config.INPUT_MIC_WORD_FILTER + new_input_mic_word_filter_list.remove(str(value)) + config.INPUT_MIC_WORD_FILTER = new_input_mic_word_filter_list + view.setLatestConfigVariable("MicMicWordFilter") + except: + print("There was no the target word in config.INPUT_MIC_WORD_FILTER") + + def callbackSetSpeakerEnergyThreshold(value): print("callbackSetSpeakerEnergyThreshold", value) if value == "": return @@ -718,6 +739,7 @@ def createMainWindow(): "callback_set_mic_phrase_timeout": callbackSetMicPhraseTimeout, "callback_set_mic_max_phrases": callbackSetMicMaxPhrases, "callback_set_mic_word_filter": callbackSetMicWordFilter, + "callback_delete_mic_word_filter": callbackDeleteMicWordFilter, # Transcription Tab (Speaker) "callback_set_speaker_energy_threshold": callbackSetSpeakerEnergyThreshold, diff --git a/img/cancel_icon.png b/img/cancel_icon.png new file mode 100644 index 00000000..aa6c386e Binary files /dev/null and b/img/cancel_icon.png differ diff --git a/img/redo_white.png b/img/redo_white.png new file mode 100644 index 00000000..2a27e302 Binary files /dev/null and b/img/redo_white.png differ diff --git a/locales/en.yml b/locales/en.yml index 3af662cf..7eee5744 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -138,7 +138,9 @@ config_window: mic_word_filter: label: Mic Word Filter - desc: "It will not send the sentence if the word(s) included in the set list of words.\nHow to set: e.g. AAA,BBB,CCC" + desc: "If a registered word is detected, the text will not be sent. To add multiple words at once, separate them with a \",\" (comma). \n*Duplicate words will not be registered." + add_button_label: Add + count_desc: "Current registered word count: %{count}" speaker_dynamic_energy_threshold: diff --git a/locales/ja.yml b/locales/ja.yml index e608c2b2..b662a3eb 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -138,7 +138,9 @@ config_window: mic_word_filter: label: ワードフィルター - desc: "設定された単語を検出すると、その文章は送信されません。\n設定の例: AAA,BBB,CCC" + desc: "登録された単語を検出すると、その文章は送信されません。\n「,」カンマで区切ると、まとめて複数の単語を追加できます。\n※重複した単語は登録されません。" + add_button_label: 追加 + count_desc: "現在登録されている単語数: %{count}" speaker_dynamic_energy_threshold: diff --git a/view.py b/view.py index 1565aefa..ac1d0739 100644 --- a/view.py +++ b/view.py @@ -284,10 +284,15 @@ class View(): VAR_MIC_MAX_PHRASES=StringVar(value=config.INPUT_MIC_MAX_PHRASES), CALLBACK_FOCUS_OUT_MIC_MAX_PHRASES=self.callbackBindFocusOut_MicMaxPhrases, + CALLBACK_ARROW_SWITCH_MIC_WORD_FILTER_LIST_OPEN=self._openMicWordFilterList, + CALLBACK_ARROW_SWITCH_MIC_WORD_FILTER_LIST_CLOSE=self._closeMicWordFilterList, + VAR_LABEL_MIC_WORD_FILTER=StringVar(value=i18n.t("config_window.mic_word_filter.label")), VAR_DESC_MIC_WORD_FILTER=StringVar(value=i18n.t("config_window.mic_word_filter.desc")), + VAR_SWITCH_DESC_MIC_WORD_FILTER=StringVar(value=i18n.t("config_window.mic_word_filter.count_desc", count=len(config.INPUT_MIC_WORD_FILTER))), + VAR_LABEL_MIC_WORD_FILTER_ADD_BUTTON=StringVar(value=i18n.t("config_window.mic_word_filter.add_button_label")), CALLBACK_SET_MIC_WORD_FILTER=None, - VAR_MIC_WORD_FILTER=StringVar(value=",".join(config.INPUT_MIC_WORD_FILTER) if len(config.INPUT_MIC_WORD_FILTER) > 0 else ""), + MIC_WORD_FILTER_LIST=config.INPUT_MIC_WORD_FILTER, # Transcription Tab (Speaker) @@ -462,6 +467,7 @@ class View(): self.view_variable.CALLBACK_SET_MIC_PHRASE_TIMEOUT = config_window_registers.get("callback_set_mic_phrase_timeout", None) self.view_variable.CALLBACK_SET_MIC_MAX_PHRASES = config_window_registers.get("callback_set_mic_max_phrases", None) self.view_variable.CALLBACK_SET_MIC_WORD_FILTER = config_window_registers.get("callback_set_mic_word_filter", None) + self.view_variable.CALLBACK_DELETE_MIC_WORD_FILTER = config_window_registers.get("callback_delete_mic_word_filter", None) # Transcription Tab (Speaker) self.view_variable.CALLBACK_SET_SPEAKER_ENERGY_THRESHOLD = config_window_registers.get("callback_set_speaker_energy_threshold", None) @@ -603,10 +609,12 @@ class View(): def enableConfigWindowCompactMode(self): for additional_widget in vrct_gui.config_window.additional_widgets: additional_widget.grid_remove() + self._closeMicWordFilterList() def disableConfigWindowCompactMode(self): for additional_widget in vrct_gui.config_window.additional_widgets: additional_widget.grid() + self._closeMicWordFilterList() def showRestartButtonIfRequired(self, locale:Union[None,str]=None): @@ -783,6 +791,43 @@ class View(): + def _openMicWordFilterList(self): + target_widget = vrct_gui.config_window.sb__widgets["sb__arrow_switch_mic_word_filter"] + target_widget.arrow_switch_open.grid_remove() + target_widget.arrow_switch_close.grid() + + vrct_gui.config_window.sb__mic_word_filter_list.grid() + + def _closeMicWordFilterList(self): + target_widget = vrct_gui.config_window.sb__widgets["sb__arrow_switch_mic_word_filter"] + target_widget.arrow_switch_close.grid_remove() + target_widget.arrow_switch_open.grid() + + vrct_gui.config_window.sb__mic_word_filter_list.grid_remove() + + + def addValueToList_WordFilter(self, values:list): + target_widget = vrct_gui.config_window.sb__widgets["sb__add_and_delete_able_list_mic_word_filter_list"] + for t_item in target_widget.items: + if t_item.label in values: + values.remove(t_item.label) + t_item.redoFunction() + mic_word_filter_item_row_wrapper, accumulated_labels_width, last_row, last_column = target_widget.addValues( + values, + target_widget.mic_word_filter_item_row_wrapper, + target_widget.accumulated_labels_width, + target_widget.last_row, + target_widget.last_column + ) + target_widget.mic_word_filter_item_row_wrapper = mic_word_filter_item_row_wrapper + target_widget.accumulated_labels_width = accumulated_labels_width + target_widget.last_row = last_row + target_widget.last_column = last_column + + def clearEntryBox_WordFilter(self): + self._clearEntryBox(vrct_gui.config_window.sb__entry_mic_word_filter_list) + + # Widget Control (Whole) def foregroundOnIfForegroundEnabled(self): if config.ENABLE_FOREGROUND: @@ -924,6 +969,7 @@ class View(): def _closeConfigWindow(self): callFunctionIfCallable(self.view_variable.CALLBACK_CLOSE_CONFIG_WINDOW) + self._closeMicWordFilterList() vrct_gui._closeConfigWindow() # Window Control (Main Window Cover) @@ -981,7 +1027,8 @@ class View(): def setGuiVariable_MicMaxPhrases(self, value): self.view_variable.VAR_MIC_MAX_PHRASES.set(str(value)) - + def setGuiVariable_MicWordFilter_Length(self, value): + self.view_variable.VAR_SWITCH_DESC_MIC_WORD_FILTER.set(i18n.t("config_window.mic_word_filter.count_desc", count=value)) def setGuiVariable_SpeakerRecordTimeout(self, value): self.view_variable.VAR_SPEAKER_RECORD_TIMEOUT.set(str(value)) @@ -1011,6 +1058,9 @@ class View(): self.setGuiVariable_MicPhraseTimeout(config.INPUT_MIC_PHRASE_TIMEOUT) case "MicMaxPhrases": self.setGuiVariable_MicMaxPhrases(config.INPUT_MIC_MAX_PHRASES) + case "MicMicWordFilter": + self.setGuiVariable_MicWordFilter_Length(len(config.INPUT_MIC_WORD_FILTER)) + case "SpeakerRecordTimeout": self.setGuiVariable_SpeakerRecordTimeout(config.INPUT_SPEAKER_RECORD_TIMEOUT) case "SpeakerPhraseTimeout": 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 d996fb2e..8a7f3622 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 @@ -5,8 +5,9 @@ from typing import Union from customtkinter import CTkOptionMenu, CTkFont, CTkFrame, CTkLabel, CTkRadioButton, CTkEntry, CTkSlider, CTkSwitch, CTkCheckBox, CTkProgressBar from CTkToolTip import * -from vrct_gui.ui_utils import createButtonWithImage, getLatestWidth, createOptionMenuBox +from vrct_gui.ui_utils import createButtonWithImage, getLatestWidth, createOptionMenuBox, getLatestHeight, bindButtonFunctionAndColor from vrct_gui import vrct_gui +from utils import isEven, callFunctionIfCallable SETTING_BOX_COLUMN = 1 @@ -17,6 +18,8 @@ class _SettingBoxGenerator(): self.parent_widget = parent_widget self.settings = settings + self.MAIN_INNER_AREA_MIN_WIDTH = int(self.settings.uism.MAIN_AREA_MIN_WIDTH - self.settings.uism.SB__IPADX) + self.dropdown_menu_window = vrct_gui.vrct_gui.dropdown_menu_window def _createSettingBoxFrame(self, sb__attr_name, for_var_label_text=None, for_var_desc_text=None): @@ -449,6 +452,315 @@ class _SettingBoxGenerator(): return setting_box_frame + def createSettingBoxArrowSwitch( + self, + for_var_label_text, for_var_desc_text, + arrow_switch_attr_name, + open_command, + close_command, + var_switch_desc=None, + ): + + (setting_box_frame, setting_box_item_frame) = self._createSettingBoxFrame(arrow_switch_attr_name, for_var_label_text, for_var_desc_text) + + ARROW_BUTTON_COLUMN = SETTING_BOX_COLUMN + + if var_switch_desc is not None: + label_widget = CTkLabel( + setting_box_item_frame, + textvariable=var_switch_desc, + height=0, + corner_radius=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__ARROW_SWITCH_DESC_FONT_SIZE, weight="normal"), + anchor="w", + text_color=self.settings.ctm.LABELS_DESC_TEXT_COLOR, + ) + + label_widget.grid(row=1, column=SETTING_BOX_COLUMN) + ARROW_BUTTON_COLUMN = SETTING_BOX_COLUMN + 1 + + + for_opening_button_wrapper = createButtonWithImage( + parent_widget=setting_box_item_frame, + button_fg_color=self.settings.ctm.SB__ARROW_SWITCH_BUTTON_COLOR, + button_enter_color=self.settings.ctm.SB__ARROW_SWITCH_BUTTON_HOVERED_COLOR, + button_clicked_color=self.settings.ctm.SB__ARROW_SWITCH_BUTTON_CLICKED_COLOR, + button_image_file=self.settings.image_file.ARROW_LEFT.rotate(270), + button_image_size=self.settings.uism.SB__ARROW_SWITCH_BUTTON_ICON_SIZE, + button_ipadxy=self.settings.uism.SB__ARROW_SWITCH_BUTTON_IPADXY, + button_command=open_command, + ) + for_opening_button_wrapper.grid(row=1, column=ARROW_BUTTON_COLUMN, padx=self.settings.uism.SB__ARROW_SWITCH_LEFT_PADX, sticky="e") + + self.config_window.sb__widgets[arrow_switch_attr_name].arrow_switch_open = for_opening_button_wrapper + + for_closing_button_wrapper = createButtonWithImage( + parent_widget=setting_box_item_frame, + button_fg_color=self.settings.ctm.SB__ARROW_SWITCH_BUTTON_COLOR, + button_enter_color=self.settings.ctm.SB__ARROW_SWITCH_BUTTON_HOVERED_COLOR, + button_clicked_color=self.settings.ctm.SB__ARROW_SWITCH_BUTTON_CLICKED_COLOR, + button_image_file=self.settings.image_file.ARROW_LEFT.rotate(90), + button_image_size=self.settings.uism.SB__ARROW_SWITCH_BUTTON_ICON_SIZE, + button_ipadxy=self.settings.uism.SB__ARROW_SWITCH_BUTTON_IPADXY, + button_command=close_command, + ) + for_closing_button_wrapper.grid(row=1, column=ARROW_BUTTON_COLUMN, padx=self.settings.uism.SB__ARROW_SWITCH_LEFT_PADX, sticky="e") + for_closing_button_wrapper.grid_remove() + + self.config_window.sb__widgets[arrow_switch_attr_name].arrow_switch_close = for_closing_button_wrapper + + + return setting_box_frame + + + + # I've added it for the word filter, but it's not currently generalized. If you want to use it in the same way elsewhere, it will require refactoring. + def createSettingBoxAddAndDeleteAbleList( + self, + add_and_delete_able_list_attr_name, + entry_attr_name, + entry_width, + mic_word_filter_list, + ): + + (setting_box_frame, setting_box_item_frame) = self._createSettingBoxFrame(add_and_delete_able_list_attr_name) + + self.config_window.sb__widgets[add_and_delete_able_list_attr_name].items = [] + + + list_container = CTkFrame(setting_box_item_frame, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + list_container.grid(row=1, column=0, sticky="nsew") + + + max_width = int(self.MAIN_INNER_AREA_MIN_WIDTH - (self.settings.uism.SB__IPADX*2)) + + def addValues(mic_word_filter_list, mic_word_filter_item_row_wrapper, accumulated_labels_width, row, column): + for mic_word_filter_item in mic_word_filter_list: + mic_word_filter_item_wrapper = self._createValue(add_and_delete_able_list_attr_name, mic_word_filter_item_row_wrapper, row, column, mic_word_filter_item) + + if int(accumulated_labels_width + getLatestWidth(mic_word_filter_item_wrapper) + self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_LEFT_PADX[1]) >= max_width: + accumulated_labels_width = 0 + column = 0 + row += 1 + mic_word_filter_item_wrapper.destroy() + mic_word_filter_item_row_wrapper = self._createRowFrame(list_container, row) + mic_word_filter_item_wrapper = self._createValue(add_and_delete_able_list_attr_name, mic_word_filter_item_row_wrapper, row, column, mic_word_filter_item) + column += 1 + else: + column += 1 + + accumulated_labels_width += int(getLatestWidth(mic_word_filter_item_wrapper) + self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_LEFT_PADX[1]) + + + + return mic_word_filter_item_row_wrapper, accumulated_labels_width, row, column + + accumulated_labels_width = 0 + row=0 + column=0 + mic_word_filter_item_row_wrapper = self._createRowFrame(list_container, row) + + + mic_word_filter_list = self.view_variable.MIC_WORD_FILTER_LIST + + mic_word_filter_item_row_wrapper, accumulated_labels_width, row, column = addValues(mic_word_filter_list, mic_word_filter_item_row_wrapper, accumulated_labels_width, row, column) + + + self.config_window.sb__widgets[add_and_delete_able_list_attr_name].mic_word_filter_item_row_wrapper = mic_word_filter_item_row_wrapper + self.config_window.sb__widgets[add_and_delete_able_list_attr_name].accumulated_labels_width = accumulated_labels_width + self.config_window.sb__widgets[add_and_delete_able_list_attr_name].last_row = row + self.config_window.sb__widgets[add_and_delete_able_list_attr_name].last_column = column + self.config_window.sb__widgets[add_and_delete_able_list_attr_name].addValues = lambda values, mic_word_filter_item_row_wrapper, accumulated_labels_width, last_row, last_column: addValues(values, mic_word_filter_item_row_wrapper, accumulated_labels_width, last_row, last_column) + + + entry_and_add_button_wrapper = CTkFrame(setting_box_item_frame, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR) + entry_and_add_button_wrapper.grid(row=2, column=0, pady=(self.settings.uism.SB__IPADY, 0), sticky="ew") + + entry_and_add_button_wrapper.grid_columnconfigure((0,3), weight=1) + + + + entry_widget = CTkEntry( + entry_and_add_button_wrapper, + text_color=self.settings.ctm.SB__ENTRY_TEXT_COLOR, + fg_color=self.settings.ctm.SB__ENTRY_BG_COLOR, + border_color=self.settings.ctm.SB__ENTRY_BORDER_COLOR, + width=entry_width, + placeholder_text="AAA or AAA,BBB,CCC", + height=self.settings.uism.SB__PROGRESSBAR_X_SLIDER__ENTRY_HEIGHT, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.SB__ENTRY_FONT_SIZE, weight="normal"), + ) + setattr(self.config_window, entry_attr_name, entry_widget) + + entry_widget.grid(row=0, column=1, sticky="ew") + + + + add_button = CTkFrame(entry_and_add_button_wrapper, corner_radius=self.settings.uism.BUTTONS_CORNER_RADIUS, fg_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_COLOR, cursor="hand2") + add_button.grid(row=0, column=2, padx=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_LEFT_PADX, sticky="ew") + + + add_button.grid_columnconfigure(0, weight=1) + add_button_label_wrapper = CTkFrame(add_button, corner_radius=0, fg_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_COLOR) + add_button_label_wrapper.grid(row=0, column=0, padx=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_IPADX, pady=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_IPADY, sticky="ew") + + add_button_label_wrapper.grid_columnconfigure((0,2), weight=1) + add_button_label = CTkLabel( + add_button_label_wrapper, + textvariable=self.view_variable.VAR_LABEL_MIC_WORD_FILTER_ADD_BUTTON, + height=0, + corner_radius=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_FONT_SIZE, weight="normal"), + anchor="w", + text_color=self.settings.ctm.LABELS_TEXT_COLOR, + ) + add_button_label.grid(row=0, column=1) + + + def adjustedCommand(): + callFunctionIfCallable(self.view_variable.CALLBACK_SET_MIC_WORD_FILTER, entry_widget.get()) + entry_widget.focus_set() + + bindButtonFunctionAndColor( + target_widgets=[ + add_button, + add_button_label_wrapper, + add_button_label, + ], + enter_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_HOVERED_COLOR, + leave_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_COLOR, + clicked_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_CLICKED_COLOR, + buttonReleasedFunction=lambda _e: adjustedCommand(), + ) + + + return setting_box_frame + + + def _createRowFrame(self, parent_widget, row): + mic_word_filter_item_row_wrapper = CTkFrame(parent_widget, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) + mic_word_filter_item_row_wrapper.grid(row=row, column=0, pady=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_BOTTOM_PADY, sticky="nsew") + + return mic_word_filter_item_row_wrapper + + + + def _createValue(self, add_and_delete_able_list_attr_name, parent_row_frame, row, column, mic_word_filter_item): + mic_word_filter_item_wrapper = CTkFrame(parent_row_frame, corner_radius=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_CORNER_RADIUS, fg_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST_BG_COLOR, width=0, height=0) + mic_word_filter_item_wrapper.grid(row=0, column=column, padx=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_LEFT_PADX, sticky="nsew") + setattr(self, f"{row}_{column}", mic_word_filter_item_wrapper) + + + + mic_word_filter_item_wrapper.grid_rowconfigure((0,2), weight=1) + label_widget = CTkLabel( + mic_word_filter_item_wrapper, + text=mic_word_filter_item, + height=0, + corner_radius=0, + font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_FONT_SIZE, weight="normal"), + anchor="w", + text_color=self.settings.ctm.BASIC_TEXT_COLOR, + ) + + label_widget.grid(row=1, column=0, padx=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADX, pady=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADY) + + + if isEven(getLatestHeight(label_widget)) is False: + label_widget.grid( + pady=( + self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADY, + self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADY + 1 + ) + ) + + + if isEven(getLatestWidth(label_widget)) is False: + label_widget.grid( + padx=( + self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADX[0], + self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADX[1] + 1 + ) + ) + + + + def pressedDeleteButtonCommand(_e, delete_button, redo_button): + # overstrike true + label_widget.configure(font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_FONT_SIZE, weight="normal", overstrike=True)) + # change fg_color + mic_word_filter_item_wrapper.configure(fg_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST_DELETED_BG_COLOR) + # change button img to redo button + delete_button.grid_remove() + redo_button.grid() + # callback delete function + callFunctionIfCallable(self.view_variable.CALLBACK_DELETE_MIC_WORD_FILTER, mic_word_filter_item) + + def pressedRedoButtonCommand(_e, delete_button, redo_button): + # overstrike false + label_widget.configure(font=CTkFont(family=self.settings.FONT_FAMILY, size=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_FONT_SIZE, weight="normal", overstrike=False)) + # change fg_color + mic_word_filter_item_wrapper.configure(fg_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST_BG_COLOR) + # change button img to delete button + redo_button.grid_remove() + delete_button.grid() + # callback add function + callFunctionIfCallable(self.view_variable.CALLBACK_SET_MIC_WORD_FILTER, mic_word_filter_item) + + + + delete_button = createButtonWithImage( + parent_widget=mic_word_filter_item_wrapper, + button_fg_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST_BG_COLOR, + button_enter_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_HOVERED_BG_COLOR, + button_clicked_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_CLICKED_BG_COLOR, + button_image_file=self.settings.image_file.CANCEL_ICON, + button_image_size=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_IMG_SIZE, + button_ipadxy=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_IPADXY, + button_command=lambda _e: pressedDeleteButtonCommand(_e, delete_button, redo_button), + ) + delete_button.grid(row=1, column=1, padx=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_PADX, sticky="e") + + redo_button = createButtonWithImage( + parent_widget=mic_word_filter_item_wrapper, + button_fg_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST_DELETED_BG_COLOR, + button_enter_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__VALUES_DELETED_BUTTON_HOVERED_BG_COLOR, + button_clicked_color=self.settings.ctm.SB__ADD_AND_DELETE_ABLE_LIST__VALUES_DELETED_BUTTON_CLICKED_BG_COLOR, + button_image_file=self.settings.image_file.REDO_ICON, + button_image_size=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_IMG_SIZE, + button_ipadxy=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_IPADXY, + button_command=lambda _e: pressedRedoButtonCommand(_e, delete_button, redo_button), + ) + redo_button.grid(row=1, column=1, padx=self.settings.uism.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_PADX, sticky="e") + redo_button.grid_remove() + + + partial_pressedRedoButtonCommand = partial(pressedRedoButtonCommand, _e=None, delete_button=delete_button, redo_button=redo_button) + item_data = SimpleNamespace( + label = mic_word_filter_item, + redoFunction = lambda: partial_pressedRedoButtonCommand(), + ) + + + items = self.config_window.sb__widgets[add_and_delete_able_list_attr_name].items + if len(items) == 0: + items.append(item_data) + else: + is_replaced = False + for i, item in enumerate(items): + if item.label == mic_word_filter_item: + items[i] = item_data + is_replaced = True + break + if is_replaced is False: items.append(item_data) + + + return mic_word_filter_item_wrapper + + + + + # if setting_box_type == "dropdown_menu_x_dropdown_menu": # self.setting_box_dropdown_menu_x_dropdown_menu = CTkFrame(self.setting_box, corner_radius=0, fg_color=self.settings.ctm.SB__BG_COLOR, width=0, height=0) diff --git a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_transcription/createSettingBox_Mic.py b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_transcription/createSettingBox_Mic.py index 472e5baa..d5ece1b6 100644 --- a/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_transcription/createSettingBox_Mic.py +++ b/vrct_gui/config_window/widgets/createSideMenuAndSettingsBoxContainers/setting_box_containers/setting_box_transcription/createSettingBox_Mic.py @@ -8,6 +8,8 @@ def createSettingBox_Mic(setting_box_wrapper, config_window, settings, view_vari createSettingBoxSwitch = sbg.createSettingBoxSwitch createSettingBoxProgressbarXSlider = sbg.createSettingBoxProgressbarXSlider createSettingBoxEntry = sbg.createSettingBoxEntry + createSettingBoxArrowSwitch = sbg.createSettingBoxArrowSwitch + createSettingBoxAddAndDeleteAbleList = sbg.createSettingBoxAddAndDeleteAbleList def checkbox_input_mic_threshold_check_callback(is_turned_on): @@ -36,6 +38,11 @@ def createSettingBox_Mic(setting_box_wrapper, config_window, settings, view_vari def entry_input_mic_max_phrases_callback(value): callFunctionIfCallable(view_variable.CALLBACK_SET_MIC_MAX_PHRASES, value) + def arrow_switch_mic_word_filter_list_open_callback(value): + callFunctionIfCallable(view_variable.CALLBACK_ARROW_SWITCH_MIC_WORD_FILTER_LIST_OPEN) + def arrow_switch_mic_word_filter_list_close_callback(value): + callFunctionIfCallable(view_variable.CALLBACK_ARROW_SWITCH_MIC_WORD_FILTER_LIST_CLOSE) + def entry_input_mic_word_filters_callback(value): callFunctionIfCallable(view_variable.CALLBACK_SET_MIC_WORD_FILTER, value) @@ -140,13 +147,24 @@ def createSettingBox_Mic(setting_box_wrapper, config_window, settings, view_vari # # __________ - config_window.sb__mic_word_filter = createSettingBoxEntry( + config_window.sb__mic_word_filter = createSettingBoxArrowSwitch( for_var_label_text=view_variable.VAR_LABEL_MIC_WORD_FILTER, for_var_desc_text=view_variable.VAR_DESC_MIC_WORD_FILTER, - entry_attr_name="sb__entry_mic_word_filter", - entry_width=settings.uism.RESPONSIVE_UI_SIZE_INT_300, - entry_bind__Any_KeyRelease=lambda value: entry_input_mic_word_filters_callback(value), - entry_textvariable=view_variable.VAR_MIC_WORD_FILTER, + arrow_switch_attr_name="sb__arrow_switch_mic_word_filter", + open_command=lambda value: arrow_switch_mic_word_filter_list_open_callback(value), + close_command=lambda value: arrow_switch_mic_word_filter_list_close_callback(value), + var_switch_desc=view_variable.VAR_SWITCH_DESC_MIC_WORD_FILTER, ) config_window.sb__mic_word_filter.grid(row=row, pady=0) + row+=1 + + config_window.sb__mic_word_filter_list = createSettingBoxAddAndDeleteAbleList( + add_and_delete_able_list_attr_name="sb__add_and_delete_able_list_mic_word_filter_list", + entry_attr_name="sb__entry_mic_word_filter_list", + entry_width=settings.uism.RESPONSIVE_UI_SIZE_INT_300, + mic_word_filter_list=view_variable.MIC_WORD_FILTER_LIST, + ) + config_window.sb__mic_word_filter_list.grid(row=row, pady=0) + # Default, close the list. + config_window.sb__mic_word_filter_list.grid_remove() row+=1 \ No newline at end of file diff --git a/vrct_gui/ui_managers/Themes/_darkTheme.py b/vrct_gui/ui_managers/Themes/_darkTheme.py index 8cadde2c..2522608a 100644 --- a/vrct_gui/ui_managers/Themes/_darkTheme.py +++ b/vrct_gui/ui_managers/Themes/_darkTheme.py @@ -229,6 +229,24 @@ def _darkTheme(base_color): SB__PROGRESSBAR_X_SLIDER__ACTIVE_BUTTON_CLICKED_COLOR = base_color.PRIMARY_800_COLOR, + SB__ARROW_SWITCH_BUTTON_COLOR = base_color.DARK_888_COLOR, + SB__ARROW_SWITCH_BUTTON_HOVERED_COLOR = base_color.DARK_800_COLOR, + SB__ARROW_SWITCH_BUTTON_CLICKED_COLOR = base_color.DARK_900_COLOR, + + SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_COLOR = base_color.PRIMARY_600_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_HOVERED_COLOR = base_color.PRIMARY_500_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_CLICKED_COLOR = base_color.PRIMARY_700_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST_BG_COLOR = base_color.DARK_800_COLOR, + + SB__ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_HOVERED_BG_COLOR = base_color.DARK_750_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_CLICKED_BG_COLOR = base_color.DARK_850_COLOR, + + SB__ADD_AND_DELETE_ABLE_LIST_DELETED_BG_COLOR = base_color.DARK_850_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST__VALUES_DELETED_BUTTON_HOVERED_BG_COLOR = base_color.DARK_800_COLOR, + SB__ADD_AND_DELETE_ABLE_LIST__VALUES_DELETED_BUTTON_CLICKED_BG_COLOR = base_color.DARK_900_COLOR, + + + # Side menu SIDE_MENU_BG_COLOR = base_color.DARK_950_COLOR, @@ -273,6 +291,9 @@ def _darkTheme(base_color): 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"), ), ) diff --git a/vrct_gui/ui_managers/UiScalingManager.py b/vrct_gui/ui_managers/UiScalingManager.py index fae26c79..9a1ad1c2 100644 --- a/vrct_gui/ui_managers/UiScalingManager.py +++ b/vrct_gui/ui_managers/UiScalingManager.py @@ -217,6 +217,10 @@ class UiScalingManager(): self.config_window.SB__DESC_TOP_PADY = self._calculateUiSize(2) + self.config_window.BUTTONS_CORNER_RADIUS = self._calculateUiSize(6) + # self.config_window.BUTTONS_IPADX = self._calculateUiSize(10) + # self.config_window.BUTTONS_IPADY = self._calculateUiSize(6) + self.config_window.SB__ERROR_MESSAGE_IPADX = (self._calculateUiSize(10), self._calculateUiSize(10)) self.config_window.SB__ERROR_MESSAGE_IPADY = (self._calculateUiSize(6), self._calculateUiSize(6)) self.config_window.SB__ERROR_MESSAGE_FONT_SIZE = self._calculateUiSize(14) @@ -276,6 +280,28 @@ class UiScalingManager(): + self.config_window.SB__ARROW_SWITCH_BUTTON_IPADXY = self._calculateUiSize(16) + self.config_window.SB__ARROW_SWITCH_BUTTON_ICON_SIZE = self._calculateUiSize(24) + self.config_window.SB__ARROW_SWITCH_DESC_FONT_SIZE = self._calculateUiSize(16) + self.config_window.SB__ARROW_SWITCH_LEFT_PADX = (self._calculateUiSize(20), 0) + + self.config_window.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_IPADX = self._calculateUiSize(16) + self.config_window.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_IPADY = self._calculateUiSize(6) + + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_CORNER_RADIUS = self._calculateUiSize(2) + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_LEFT_PADX = (0, self._calculateUiSize(4)) + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_BOTTOM_PADY = (0, self._calculateUiSize(4)) + + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_FONT_SIZE = self._calculateUiSize(14) + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADX = (self._calculateUiSize(8), 0) + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_TEXT_IPADY = self._calculateUiSize(6) + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_IMG_SIZE = self._calculateUiSize(14) + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_IPADXY = self._calculateUiSize(6) + self.config_window.ADD_AND_DELETE_ABLE_LIST__VALUES_ACTION_BUTTON_PADX = (self._calculateUiSize(6), self._calculateUiSize(8)) + + self.config_window.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_LEFT_PADX = (self._calculateUiSize(20), 0) + self.config_window.ADD_AND_DELETE_ABLE_LIST__ADD_BUTTON_FONT_SIZE = self._calculateUiSize(14) + 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