feat: added sound effects support to themes
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
This commit is contained in:
@ -9,12 +9,13 @@
|
||||
- [Metadata](#metadata)
|
||||
- [Screenshots](#screenshots)
|
||||
- [Fonts and Icons](#fonts-and-icons)
|
||||
- [Sound Effects](#sound-effects)
|
||||
|
||||
---
|
||||
|
||||
## 📖 Overview
|
||||
|
||||
Themes in `PortProtonQT` allow customizing the UI appearance. Themes are stored under:
|
||||
Themes in `PortProtonQT` allow customizing the UI appearance and sounds. Themes are stored under:
|
||||
|
||||
- `~/.local/share/PortProtonQT/themes`.
|
||||
|
||||
@ -34,6 +35,12 @@ Create a `styles.py` in the theme root. It should define variables or functions
|
||||
|
||||
**Example:**
|
||||
```python
|
||||
# Sound effects mapping
|
||||
SOUNDS = {
|
||||
"app_start": "app_start.wav", # Application startup
|
||||
"app_exit": "app_exit.wav", # Application exit
|
||||
}
|
||||
|
||||
def custom_button_style(color1, color2):
|
||||
return f"""
|
||||
QPushButton {{
|
||||
@ -69,3 +76,19 @@ Folder: `images/screenshots/` — place UI screenshots there.
|
||||
- Icons: `images/icons/*.svg/.png`
|
||||
|
||||
---
|
||||
|
||||
## 🔊 Sound Effects (optional)
|
||||
|
||||
Folder: `sounds/` — place interface sound effects here.
|
||||
|
||||
Supported formats:
|
||||
- `.wav` - Wave audio files
|
||||
|
||||
Available sound events:
|
||||
- Interface sounds:
|
||||
- `app_start.wav` - Application startup
|
||||
- `app_exit.wav` - Application exit
|
||||
|
||||
If a sound file is missing in a custom theme, the default sound from the standard theme will be used.
|
||||
|
||||
---
|
||||
|
@ -9,12 +9,13 @@
|
||||
- [Метаинформация](#метаинформация)
|
||||
- [Скриншоты](#скриншоты)
|
||||
- [Шрифты и иконки](#шрифты-и-иконки)
|
||||
- [Звуковые эффекты](#звуковые-эффекты)
|
||||
|
||||
---
|
||||
|
||||
## 📖 Обзор
|
||||
|
||||
Темы в `PortProtonQT` позволяют изменить внешний вид интерфейса. Все темы хранятся в папке:
|
||||
Темы в `PortProtonQT` позволяют изменить внешний вид интерфейса и звуковое оформление. Все темы хранятся в папке:
|
||||
|
||||
- `~/.local/share/PortProtonQT/themes`.
|
||||
|
||||
@ -32,8 +33,14 @@ mkdir -p ~/.local/share/PortProtonQT/themes/my_custom_theme
|
||||
|
||||
Создайте `styles.py` в корне темы. В нём определите переменные и/или функции, возвращающие CSS-оформление.
|
||||
|
||||
**Пример функции:**
|
||||
**Пример:**
|
||||
```python
|
||||
# Карта звуковых эффектов
|
||||
SOUNDS = {
|
||||
"app_start": "app_start.wav", # Запуск приложения
|
||||
"app_exit": "app_exit.wav", # Закрытие приложения
|
||||
}
|
||||
|
||||
def custom_button_style(color1, color2):
|
||||
return f"""
|
||||
QPushButton {{
|
||||
@ -69,3 +76,19 @@ description = Описание вашей темы.
|
||||
- Иконки: `images/icons/*.svg/.png`
|
||||
|
||||
---
|
||||
|
||||
## 🔊 Звуковые эффекты (опционально)
|
||||
|
||||
Папка: `sounds/` — звуковые эффекты интерфейса.
|
||||
|
||||
Поддерживаемые форматы:
|
||||
- `.wav` - Wave аудио файлы
|
||||
|
||||
Доступные звуковые события:
|
||||
- Звуки интерфейса:
|
||||
- `app_start.wav` - Запуск приложения
|
||||
- `app_exit.wav` - Закрытие приложения
|
||||
|
||||
Если звуковой файл отсутствует в пользовательской теме, будет использован звук из стандартной темы.
|
||||
|
||||
---
|
||||
|
@ -220,6 +220,13 @@ class MainWindow(QMainWindow):
|
||||
self.resize(width, height)
|
||||
else:
|
||||
self.showNormal()
|
||||
|
||||
self._startup_sound = self.theme_manager.get_sound(default_styles.SOUNDS["app_start"])
|
||||
self._exit_sound = self.theme_manager.get_sound(default_styles.SOUNDS["app_exit"])
|
||||
|
||||
if self._startup_sound:
|
||||
self._startup_sound.play()
|
||||
|
||||
@Slot(list)
|
||||
def on_games_loaded(self, games: list[tuple]):
|
||||
self.games = games
|
||||
@ -2253,5 +2260,11 @@ class MainWindow(QMainWindow):
|
||||
self.checkProcessTimer.deleteLater()
|
||||
self.checkProcessTimer = None
|
||||
|
||||
QApplication.quit()
|
||||
event.accept()
|
||||
# Воспроизводим звук закрытия
|
||||
if self._exit_sound:
|
||||
self._exit_sound.play()
|
||||
# Небольшая задержка перед закрытием, чтобы звук успел проиграться
|
||||
QTimer.singleShot(100, lambda: event.accept())
|
||||
event.ignore()
|
||||
else:
|
||||
event.accept()
|
||||
|
@ -3,6 +3,8 @@ import os
|
||||
from portprotonqt.logger import get_logger
|
||||
from PySide6.QtSvg import QSvgRenderer
|
||||
from PySide6.QtGui import QIcon, QColor, QFontDatabase, QPixmap, QPainter
|
||||
from PySide6.QtCore import QUrl
|
||||
from PySide6.QtMultimedia import QSoundEffect
|
||||
|
||||
from portprotonqt.config_utils import save_theme_to_config, load_theme_metainfo
|
||||
|
||||
@ -226,7 +228,7 @@ class ThemeManager:
|
||||
|
||||
# Если иконка всё равно не найдена
|
||||
if not icon_path or not os.path.exists(icon_path):
|
||||
logger.error(f"Предупреждение: иконка '{icon_name}' не найдена")
|
||||
logger.warning(f"icon '{icon_name}' not found")
|
||||
return QIcon() if not as_path else None
|
||||
|
||||
if as_path:
|
||||
@ -284,3 +286,67 @@ class ThemeManager:
|
||||
break
|
||||
|
||||
return image_path
|
||||
|
||||
def get_sound(self, sound_name, theme_name=None):
|
||||
"""
|
||||
Возвращает QSoundEffect для звука из папки sounds текущей темы.
|
||||
Если не найден, проверяет стандартную тему.
|
||||
Поддерживает форматы .wav
|
||||
|
||||
:param sound_name: Имя звукового файла (с расширением или без)
|
||||
:param theme_name: Имя темы (опционально)
|
||||
:return: QSoundEffect объект или None если звук не найден
|
||||
"""
|
||||
sound_path = None
|
||||
theme_name = theme_name or self.current_theme_name
|
||||
supported_extensions = ['.wav']
|
||||
|
||||
has_extension = any(sound_name.lower().endswith(ext) for ext in supported_extensions)
|
||||
base_name = sound_name if has_extension else sound_name
|
||||
|
||||
# Поиск звука в папке текущей темы
|
||||
for themes_dir in THEMES_DIRS:
|
||||
theme_folder = os.path.join(str(themes_dir), str(theme_name))
|
||||
sounds_folder = os.path.join(theme_folder, "sounds")
|
||||
|
||||
# Если передано имя с расширением, проверяем только этот файл
|
||||
if has_extension:
|
||||
candidate = os.path.join(sounds_folder, str(base_name))
|
||||
if os.path.exists(candidate):
|
||||
sound_path = candidate
|
||||
break
|
||||
else:
|
||||
# Проверяем все поддерживаемые расширения
|
||||
for ext in supported_extensions:
|
||||
candidate = os.path.join(sounds_folder, str(base_name) + str(ext))
|
||||
if os.path.exists(candidate):
|
||||
sound_path = candidate
|
||||
break
|
||||
if sound_path:
|
||||
break
|
||||
|
||||
# Если не нашли – используем стандартную тему
|
||||
if not sound_path:
|
||||
base_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
standard_sounds_folder = os.path.join(base_dir, "themes", "standart", "sounds")
|
||||
|
||||
# Аналогично проверяем в стандартной теме
|
||||
if has_extension:
|
||||
sound_path = os.path.join(standard_sounds_folder, base_name)
|
||||
if not os.path.exists(sound_path):
|
||||
sound_path = None
|
||||
else:
|
||||
for ext in supported_extensions:
|
||||
candidate = os.path.join(standard_sounds_folder, base_name + ext)
|
||||
if os.path.exists(candidate):
|
||||
sound_path = candidate
|
||||
break
|
||||
|
||||
# Если звук всё равно не найден
|
||||
if not sound_path or not os.path.exists(sound_path):
|
||||
logger.warning(f"Sound '{sound_name}' not found")
|
||||
return None
|
||||
|
||||
sound = QSoundEffect()
|
||||
sound.setSource(QUrl.fromLocalFile(sound_path))
|
||||
return sound
|
||||
|
@ -8,6 +8,12 @@ current_theme_name = read_theme_from_config()
|
||||
favoriteLabelSize = 48, 48
|
||||
pixmapsScaledSize = 60, 60
|
||||
|
||||
# ЗВУКОВЫЕ ЭФФЕКТЫ
|
||||
SOUNDS = {
|
||||
"app_start": "app_start.wav", # Запуск приложения
|
||||
"app_exit": "app_exit.wav", # Закрытие приложения
|
||||
}
|
||||
|
||||
GAME_CARD_ANIMATION = {
|
||||
# Ширина обводки карточки в состоянии покоя (без наведения или фокуса).
|
||||
# Влияет на толщину рамки вокруг карточки, когда она не выделена.
|
||||
|
@ -8,6 +8,12 @@ current_theme_name = read_theme_from_config()
|
||||
favoriteLabelSize = 48, 48
|
||||
pixmapsScaledSize = 60, 60
|
||||
|
||||
# ЗВУКОВЫЕ ЭФФЕКТЫ
|
||||
SOUNDS = {
|
||||
"app_start": "app_start.wav", # Запуск приложения
|
||||
"app_exit": "app_exit.wav", # Закрытие приложения
|
||||
}
|
||||
|
||||
# VARS
|
||||
font_family = "Play"
|
||||
font_size_a = "16px"
|
||||
|
Reference in New Issue
Block a user