Added icons for flags, improvements in voice mixer

This commit is contained in:
Deniz Şafak
2025-04-30 18:45:02 +03:00
parent 04e16722e2
commit 4acf70954e
15 changed files with 61 additions and 40 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

-13
View File
@@ -102,16 +102,3 @@ SAMPLE_VOICE_TEXTS = {
"p": "Este é um exemplo da voz selecionada.",
"z": "这是所选语音的示例。",
}
# flags mapping for voice display
FLAGS = {
"a": "🇺🇸",
"b": "🇬🇧",
"e": "🇪🇸",
"f": "🇫🇷",
"h": "🇮🇳",
"i": "🇮🇹",
"j": "🇯🇵",
"p": "🇧🇷",
"z": "🇨🇳",
}
+12 -3
View File
@@ -66,7 +66,6 @@ from constants import (
GITHUB_URL,
PROGRAM_DESCRIPTION,
LANGUAGE_DESCRIPTIONS,
FLAGS,
VOICES_INTERNAL,
SUPPORTED_LANGUAGES_FOR_SUBTITLE_GENERATION,
)
@@ -560,9 +559,19 @@ class abogen(QWidget):
voice_layout.addWidget(QLabel("Select Voice:", self))
voice_row = QHBoxLayout()
self.voice_combo = QComboBox(self)
for v in VOICES_INTERNAL:
flag = FLAGS.get(v[0], "")
self.voice_combo.addItem(f"{flag} {v}", v)
# Get flag icon for this voice
lang_code = v[0]
flag_path = get_resource_path("abogen.assets.flags", f"{lang_code}.png")
icon = QIcon()
if flag_path and os.path.exists(flag_path):
icon = QIcon(flag_path)
# Add item with flag icon and voice name
self.voice_combo.addItem(icon, f"{v}", v)
self.voice_combo.setStyleSheet(
"QComboBox { min-height: 20px; padding: 6px 12px; }"
)
+6
View File
@@ -32,6 +32,12 @@ def get_resource_path(package, resource):
except (ImportError, FileNotFoundError):
pass
# Always try to resolve as a relative path from this file
parts = package.split('.')
rel_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), *parts[1:], resource)
if os.path.exists(rel_path):
return rel_path
# Fallback to local file system
try:
# Extract the subdirectory from package name (e.g., 'assets' from 'abogen.assets')
+41 -23
View File
@@ -17,11 +17,11 @@ from PyQt5.QtWidgets import (
)
from PyQt5.QtCore import Qt, QTimer, QPoint, QRect, QSize
from PyQt5.QtGui import QPixmap
from constants import VOICES_INTERNAL, FLAGS
from constants import VOICES_INTERNAL
from utils import get_resource_path
# Constants
VOICE_MIXER_WIDTH = 120
VOICE_MIXER_WIDTH = 100
SLIDER_WIDTH = 32
MIN_WINDOW_WIDTH = 600
MIN_WINDOW_HEIGHT = 400
@@ -117,11 +117,11 @@ class FlowLayout(QLayout):
class VoiceMixer(QWidget):
def __init__(
self, voice_name, language_icon, initial_status=False, initial_weight=0.0
self, voice_name, language_code, initial_status=False, initial_weight=0.0
):
super().__init__()
self.voice_name = voice_name
#self.setFixedWidth(VOICE_MIXER_WIDTH)
self.setFixedWidth(VOICE_MIXER_WIDTH)
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
# TODO Set CSS for rounded corners
@@ -130,26 +130,39 @@ class VoiceMixer(QWidget):
layout = QVBoxLayout()
# Checkbox
# Name label at the top
name = voice_name
layout.addWidget(QLabel(name), alignment=Qt.AlignCenter)
# Voice name label with gender icon
is_female = self.voice_name in VOICES_INTERNAL and self.voice_name[1] == "f"
# Icons layout (flag and gender)
icons_layout = QHBoxLayout()
icons_layout.setSpacing(3)
icons_layout.setAlignment(Qt.AlignCenter) # Center the icons horizontally
# Flag icon
flag_icon_path = get_resource_path("abogen.assets.flags", f"{language_code}.png")
gender_icon_path = get_resource_path("abogen.assets", "female.png" if is_female else "male.png")
flag_label = QLabel()
gender_label = QLabel()
flag_pixmap = QPixmap(flag_icon_path)
flag_label.setPixmap(flag_pixmap.scaled(16, 16, Qt.KeepAspectRatio, Qt.SmoothTransformation))
gender_pixmap = QPixmap(gender_icon_path)
gender_label.setPixmap(gender_pixmap.scaled(16, 16, Qt.KeepAspectRatio, Qt.SmoothTransformation))
icons_layout.addWidget(flag_label)
icons_layout.addWidget(gender_label)
# Add icons layout
layout.addLayout(icons_layout)
# Checkbox (now below icons)
self.checkbox = QCheckBox()
self.checkbox.setChecked(initial_status)
self.checkbox.stateChanged.connect(self.toggle_inputs)
layout.addWidget(self.checkbox, alignment=Qt.AlignCenter)
# Voice name label with gender icon
is_female = self.voice_name in VOICES_INTERNAL and self.voice_name[1] == "f"
gender_icon_path = get_resource_path("abogen.assets", "female.png" if is_female else "male.png")
name = voice_name[3:].capitalize()
name_layout = QHBoxLayout()
# Gender icon
pixmap = QPixmap(gender_icon_path)
if not pixmap.isNull():
gender_label = QLabel()
gender_label.setPixmap(pixmap.scaled(16, 16, Qt.KeepAspectRatio, Qt.SmoothTransformation))
name_layout.addWidget(gender_label)
name_layout.addWidget(QLabel(f"{language_icon} {name}"), alignment=Qt.AlignCenter)
layout.addLayout(name_layout)
# Spinbox and slider
self.spin_box = QDoubleSpinBox()
self.spin_box.setRange(0, 1)
@@ -212,6 +225,8 @@ class HoverLabel(QLabel):
# Create delete button
self.delete_button = QPushButton("×", self)
self.delete_button.setFixedSize(16, 16)
self.delete_button = QPushButton("×", self)
self.delete_button.setFixedSize(16, 16)
self.delete_button.setStyleSheet(
"""
QPushButton {
@@ -251,6 +266,9 @@ class VoiceFormulaDialog(QDialog):
def __init__(self, parent=None, initial_state=None):
super().__init__(parent)
self.setWindowTitle("Voice Mixer")
self.setWindowFlags(
Qt.Window | Qt.WindowCloseButtonHint | Qt.WindowMaximizeButtonHint
)
self.setMinimumSize(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT)
self.resize(INITIAL_WINDOW_WIDTH, INITIAL_WINDOW_HEIGHT)
self.voice_mixers = []
@@ -334,13 +352,13 @@ class VoiceFormulaDialog(QDialog):
def add_voices(self, initial_state):
first_enabled_voice = None
for voice in VOICES_INTERNAL:
flag = FLAGS.get(voice[0], "")
language_code = voice[0] # First character is the language code
matching_voice = next(
(item for item in initial_state if item[0] == voice), None
)
initial_status = matching_voice is not None
initial_weight = matching_voice[1] if matching_voice else 1.0
voice_mixer = self.add_voice(voice, flag, initial_status, initial_weight)
voice_mixer = self.add_voice(voice, language_code, initial_status, initial_weight)
if initial_status and first_enabled_voice is None:
first_enabled_voice = voice_mixer
@@ -350,10 +368,10 @@ class VoiceFormulaDialog(QDialog):
)
def add_voice(
self, voice_name, language_icon, initial_status=False, initial_weight=1.0
self, voice_name, language_code, initial_status=False, initial_weight=1.0
):
voice_mixer = VoiceMixer(
voice_name, language_icon, initial_status, initial_weight
voice_name, language_code, initial_status, initial_weight
)
self.voice_mixers.append(voice_mixer)
self.voice_list_layout.addWidget(voice_mixer)