#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 設置分頁組件 ============ 專門處理應用設置的分頁組件。 """ from PySide6.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QLabel, QGroupBox, QComboBox, QRadioButton, QButtonGroup, QMessageBox, QCheckBox ) from PySide6.QtCore import Signal from ...i18n import t, get_i18n_manager class SettingsTab(QWidget): """設置分頁組件""" language_changed = Signal() layout_mode_change_requested = Signal(bool) # 佈局模式變更請求信號 def __init__(self, combined_mode: bool, config_manager, parent=None): super().__init__(parent) self.combined_mode = combined_mode self.config_manager = config_manager self.i18n = get_i18n_manager() self._setup_ui() def _setup_ui(self) -> None: """設置用戶介面""" layout = QVBoxLayout(self) layout.setSpacing(16) layout.setContentsMargins(16, 16, 16, 16) # === 語言設置區域 === self.language_group = QGroupBox(t('settings.language.title')) self.language_group.setObjectName('language_group') language_layout = QVBoxLayout(self.language_group) language_layout.setSpacing(12) language_layout.setContentsMargins(16, 16, 16, 16) # 語言選擇器 language_row = QHBoxLayout() self.language_label = QLabel(t('settings.language.selector')) self.language_label.setStyleSheet("font-weight: bold; color: #e0e0e0; font-size: 14px;") language_row.addWidget(self.language_label) self.language_selector = QComboBox() self.language_selector.setMinimumWidth(180) self.language_selector.setMinimumHeight(35) self.language_selector.setStyleSheet(""" QComboBox { background-color: #404040; border: 1px solid #606060; border-radius: 4px; padding: 8px 12px; color: #e0e0e0; font-size: 14px; } QComboBox:hover { border-color: #0078d4; } QComboBox::drop-down { border: none; width: 25px; } QComboBox::down-arrow { image: none; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 7px solid #e0e0e0; margin-right: 6px; } QComboBox QAbstractItemView { background-color: #404040; border: 1px solid #606060; selection-background-color: #0078d4; color: #e0e0e0; font-size: 14px; } """) # 填充語言選項和連接信號 self._populate_language_selector() self.language_selector.currentIndexChanged.connect(self._on_language_changed) language_row.addWidget(self.language_selector) language_row.addStretch() language_layout.addLayout(language_row) # 語言說明 self.language_description_label = QLabel(t('settings.language.description')) self.language_description_label.setStyleSheet("color: #9e9e9e; font-size: 12px; margin-top: 8px;") self.language_description_label.setWordWrap(True) language_layout.addWidget(self.language_description_label) layout.addWidget(self.language_group) # === 界面佈局設置區域 === self.layout_group = QGroupBox(t('settings.layout.title')) self.layout_group.setObjectName('layout_group') layout_layout = QVBoxLayout(self.layout_group) layout_layout.setSpacing(12) layout_layout.setContentsMargins(16, 16, 16, 16) # 佈局模式選擇 self.layout_button_group = QButtonGroup() # 分離模式 self.separate_mode_radio = QRadioButton(t('settings.layout.separateMode')) self.separate_mode_radio.setChecked(not self.combined_mode) self.separate_mode_radio.setStyleSheet("font-size: 14px; font-weight: bold; color: #e0e0e0;") self.layout_button_group.addButton(self.separate_mode_radio, 0) layout_layout.addWidget(self.separate_mode_radio) self.separate_desc_label = QLabel(t('settings.layout.separateModeDescription')) self.separate_desc_label.setStyleSheet("color: #9e9e9e; font-size: 12px; margin-left: 20px; margin-bottom: 8px;") self.separate_desc_label.setWordWrap(True) layout_layout.addWidget(self.separate_desc_label) # 合併模式 self.combined_mode_radio = QRadioButton(t('settings.layout.combinedMode')) self.combined_mode_radio.setChecked(self.combined_mode) self.combined_mode_radio.setStyleSheet("font-size: 14px; font-weight: bold; color: #e0e0e0;") self.layout_button_group.addButton(self.combined_mode_radio, 1) layout_layout.addWidget(self.combined_mode_radio) self.combined_desc_label = QLabel(t('settings.layout.combinedModeDescription')) self.combined_desc_label.setStyleSheet("color: #9e9e9e; font-size: 12px; margin-left: 20px; margin-bottom: 8px;") self.combined_desc_label.setWordWrap(True) layout_layout.addWidget(self.combined_desc_label) # 連接佈局模式變更信號 self.layout_button_group.buttonToggled.connect(self._on_layout_mode_changed) layout.addWidget(self.layout_group) # === 視窗定位設置區域 === self.window_group = QGroupBox(t('settings.window.title')) self.window_group.setObjectName('window_group') window_layout = QVBoxLayout(self.window_group) window_layout.setSpacing(12) window_layout.setContentsMargins(16, 16, 16, 16) # 總是在主螢幕中心顯示視窗選項 self.always_center_checkbox = QCheckBox(t('settings.window.alwaysCenter')) self.always_center_checkbox.setChecked(self.config_manager.get_always_center_window()) self.always_center_checkbox.setStyleSheet("font-size: 14px; font-weight: bold; color: #e0e0e0;") self.always_center_checkbox.stateChanged.connect(self._on_always_center_changed) window_layout.addWidget(self.always_center_checkbox) self.center_desc_label = QLabel(t('settings.window.alwaysCenterDescription')) self.center_desc_label.setStyleSheet("color: #9e9e9e; font-size: 12px; margin-left: 20px; margin-bottom: 8px;") self.center_desc_label.setWordWrap(True) window_layout.addWidget(self.center_desc_label) layout.addWidget(self.window_group) layout.addStretch() def _populate_language_selector(self) -> None: """填充語言選擇器""" # 保存當前選擇 current_lang = self.i18n.get_current_language() # 暫時斷開信號連接,避免觸發語言變更事件 try: self.language_selector.currentIndexChanged.disconnect() except RuntimeError: pass # 如果沒有連接則忽略 # 清空並重新填充 self.language_selector.clear() for lang_code in self.i18n.get_supported_languages(): display_name = self.i18n.get_language_display_name(lang_code) self.language_selector.addItem(display_name, lang_code) # 設置當前選中的語言 for i in range(self.language_selector.count()): if self.language_selector.itemData(i) == current_lang: self.language_selector.setCurrentIndex(i) break # 重新連接信號 self.language_selector.currentIndexChanged.connect(self._on_language_changed) def _on_language_changed(self, index: int) -> None: """處理語言變更""" lang_code = self.language_selector.itemData(index) if lang_code and self.i18n.set_language(lang_code): # 發送語言變更信號 self.language_changed.emit() def _on_layout_mode_changed(self, button, checked: bool) -> None: """處理佈局模式變更""" if not checked: # 只處理選中的按鈕 return # 確定新的模式 new_combined_mode = button == self.combined_mode_radio if new_combined_mode != self.combined_mode: # 提示用戶需要重新創建界面 reply = QMessageBox.question( self, t('app.layoutChangeTitle'), t('app.layoutChangeMessage'), QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes ) if reply == QMessageBox.Yes: # 用戶確認變更,發送佈局模式變更請求 self.combined_mode = new_combined_mode self.layout_mode_change_requested.emit(self.combined_mode) else: # 用戶選擇不重新載入,恢復原來的選項 if self.combined_mode: self.combined_mode_radio.setChecked(True) else: self.separate_mode_radio.setChecked(True) def _on_always_center_changed(self, state: int) -> None: """處理視窗定位設置變更""" always_center = state == 2 # Qt.Checked = 2 self.config_manager.set_always_center_window(always_center) def update_texts(self) -> None: """更新界面文字(用於語言切換)""" # 更新GroupBox標題 self.language_group.setTitle(t('settings.language.title')) self.layout_group.setTitle(t('settings.layout.title')) self.window_group.setTitle(t('settings.window.title')) # 更新標籤文字 self.language_label.setText(t('settings.language.selector')) self.language_description_label.setText(t('settings.language.description')) # 更新佈局設置文字 self.separate_mode_radio.setText(t('settings.layout.separateMode')) self.combined_mode_radio.setText(t('settings.layout.combinedMode')) # 更新佈局描述文字 self.separate_desc_label.setText(t('settings.layout.separateModeDescription')) self.combined_desc_label.setText(t('settings.layout.combinedModeDescription')) # 更新視窗設置文字 self.always_center_checkbox.setText(t('settings.window.alwaysCenter')) self.center_desc_label.setText(t('settings.window.alwaysCenterDescription')) # 重新填充語言選擇器 self._populate_language_selector() # 重新設置勾選狀態,確保設置被正確保持 self.always_center_checkbox.setChecked(self.config_manager.get_always_center_window()) def set_layout_mode(self, combined_mode: bool) -> None: """設置佈局模式""" self.combined_mode = combined_mode if combined_mode: self.combined_mode_radio.setChecked(True) else: self.separate_mode_radio.setChecked(True)