diff --git a/winehelper_gui.py b/winehelper_gui.py index d5e1c92..c85f5ae 100644 --- a/winehelper_gui.py +++ b/winehelper_gui.py @@ -13,7 +13,7 @@ from functools import partial from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QTabWidget, QTabBar, QTextEdit, QFileDialog, QMessageBox, QLineEdit, QCheckBox, QStackedWidget, QScrollArea, QFormLayout, QGroupBox, QRadioButton, QComboBox, QListWidget, QListWidgetItem, QGridLayout, QFrame, QDialog, QTextBrowser, QInputDialog, QDialogButtonBox, QSystemTrayIcon, QMenu) -from PyQt5.QtCore import Qt, QProcess, QSize, QTimer, QProcessEnvironment, QPropertyAnimation, QEasingCurve +from PyQt5.QtCore import Qt, QProcess, QSize, QTimer, QProcessEnvironment, QPropertyAnimation, QEasingCurve, pyqtSignal from PyQt5.QtGui import QIcon, QFont, QTextCursor, QPixmap, QPainter, QCursor from PyQt5.QtNetwork import QLocalServer, QLocalSocket @@ -428,6 +428,8 @@ class WinetricksManagerDialog(QDialog): "Для переустановки компонента: Выделите его в списке и нажмите кнопку «Переустановить»." ) + installation_complete = pyqtSignal() + def __init__(self, prefix_path, winetricks_path, parent=None, wine_executable=None): super().__init__(parent) self.prefix_path = prefix_path @@ -617,12 +619,33 @@ class WinetricksManagerDialog(QDialog): self._log(f"--- Предупреждение: не удалось прочитать {log_path}: {e} ---") return installed_verbs - def _parse_winetricks_list_output(self, output, installed_verbs, list_widget): + def _parse_winetricks_list_output(self, output, installed_verbs, list_widget, category): """Парсит вывод 'winetricks list' и заполняет QListWidget.""" # Regex, который обрабатывает строки как с префиксом статуса '[ ]', так и без него. # 1. `(?:\[(.)]\s+)?` - опциональная группа для статуса (напр. '[x]'). # 2. `([^\s]+)` - имя компонента (без пробелов). # 3. `(.*)` - оставшаяся часть строки (описание). + + # Определяем шаблоны для фильтрации на основе категории + dlls_blacklist_pattern = None + fonts_blacklist_pattern = None + settings_blacklist_pattern = None + + if category == 'dlls': + # Исключаем d3d*, directx9, dont_use, dxvk*, vkd3d*, galliumnine, faudio*, Foundation + dlls_blacklist_pattern = re.compile( + r'^(d3d|directx9|dont_use|dxvk|vkd3d|galliumnine|faudio|foundation)', re.IGNORECASE + ) + elif category == 'fonts': + fonts_blacklist_pattern = re.compile( + r'^(dont_use)', re.IGNORECASE + ) + elif category == 'settings': + # Исключаем vista*, alldlls, autostart_*, bad*, good*, win*, videomemory*, vd=*, isolate_home + settings_blacklist_pattern = re.compile( + r'^(vista|alldlls|autostart_|bad|good|win|videomemory|vd=|isolate_home)', re.IGNORECASE + ) + line_re = re.compile(r"^\s*(?:\[(.)]\s+)?([^\s]+)\s*(.*)") found_items = False @@ -643,6 +666,14 @@ class WinetricksManagerDialog(QDialog): if '/' in name or '\\' in name or name.lower() in ('executing', 'using', 'warning:') or name.endswith(':'): continue + # Применяем фильтры для черных списков + if dlls_blacklist_pattern and dlls_blacklist_pattern.search(name): + continue + if fonts_blacklist_pattern and fonts_blacklist_pattern.search(name): + continue + if settings_blacklist_pattern and settings_blacklist_pattern.search(name): + continue + is_checked = name in installed_verbs item_text = f"{name.ljust(27)}{description.strip()}" item = QListWidgetItem(item_text) @@ -681,7 +712,7 @@ class WinetricksManagerDialog(QDialog): self._log("--------------------------------------------------", "red") else: installed_verbs = self._parse_winetricks_log() - found_items = self._parse_winetricks_list_output(output, installed_verbs, list_widget) + found_items = self._parse_winetricks_list_output(output, installed_verbs, list_widget, category) if from_cache is None: # Только если мы не читали из кэша # Сохраняем успешный результат в кэш @@ -856,6 +887,7 @@ class WinetricksManagerDialog(QDialog): # Перезагружаем данные, чтобы обновить состояние self.initial_states.clear() self.load_all_categories() + self.installation_complete.emit() self.installation_finished = True def closeEvent(self, event): @@ -2601,19 +2633,39 @@ class WineHelperGUI(QMainWindow): self.esync_button.blockSignals(False) self.fsync_button.blockSignals(False) + # --- Чтение и отображение установленных компонентов Winetricks --- + winetricks_log_path = os.path.join(Var.USER_WORK_PATH, "prefixes", prefix_name, "winetricks.log") + installed_verbs = [] + if os.path.exists(winetricks_log_path): + try: + with open(winetricks_log_path, 'r', encoding='utf-8') as f: + for line in f: + verb = line.split('#', 1)[0].strip() + if verb: + installed_verbs.append(verb) + except IOError as e: + print(f"Ошибка чтения winetricks.log: {e}") + + # Фильтруем служебные компоненты, чтобы не засорять вывод + verbs_to_ignore = { + 'isolate_home', 'winxp', 'win7', 'win10', 'win11', + 'vista', 'win2k', 'win2k3', 'win2k8', 'win8', 'win81', + 'workaround', 'internal' + } + display_verbs = sorted([v for v in installed_verbs if v not in verbs_to_ignore]) + # Карта для красивого отображения известных переменных display_map = { "WINEPREFIX": ("Путь", lambda v: v), "WINEARCH": ("Архитектура", lambda v: "64-bit" if v == "win64" else "32-bit"), "WH_WINE_USE": ("Версия Wine", lambda v: "Системная" if v == "system" else v), - "BASE_PFX": ("Тип", lambda v: 'Чистый' if v == "none" else 'С рекомендуемыми библиотеками'), "DXVK_VER": ("Версия DXVK", lambda v: v if v else "Не установлено"), "VKD3D_VER": ("Версия VKD3D", lambda v: v if v else "Не установлено"), "WINEESYNC": ("ESync", lambda v: "Включен" if v == "1" else "Выключен"), "WINEFSYNC": ("FSync", lambda v: "Включен" if v == "1" else "Выключен"), "WH_XDG_OPEN": ("Ассоциации файлов", lambda v: v if v and v != "0" else "Не заданы"), } - display_order = ["WINEPREFIX", "WINEARCH", "WH_WINE_USE", "BASE_PFX", "DXVK_VER", "VKD3D_VER", "WINEESYNC", "WINEFSYNC", "WH_XDG_OPEN"] + display_order = ["WINEPREFIX", "WINEARCH", "WH_WINE_USE", "DXVK_VER", "VKD3D_VER", "WINEESYNC", "WINEFSYNC", "WH_XDG_OPEN"] html_content = f'
'
html_content += f"Имя: {html.escape(prefix_name)}
"
@@ -2635,6 +2687,15 @@ class WineHelperGUI(QMainWindow):
html_content += "
Дополнительные параметры:
"
html_content += other_vars_html
+ html_content += "
Компоненты (Winetricks): "
+ if display_verbs:
+ # Используем span вместо div, чтобы избежать лишних отступов
+ html_content += ''
+ html_content += ", ".join(html.escape(v) for v in display_verbs)
+ html_content += ''
+ else:
+ html_content += "Не установлены"
+
html_content += "