add sound info
This commit is contained in:
parent
c57ff8024d
commit
399357dc95
19
screens/setting/eq_screen.py
Normal file
19
screens/setting/eq_screen.py
Normal file
@ -0,0 +1,19 @@
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QFont
|
||||
from PySide6.QtWidgets import QWidget, QLabel, QVBoxLayout
|
||||
|
||||
|
||||
class EqualizerScreen(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
root = QVBoxLayout(self)
|
||||
root.setContentsMargins(0, 0, 0, 0)
|
||||
root.setSpacing(0)
|
||||
|
||||
root.addStretch(1)
|
||||
label = QLabel("Эквалайзер\n(в разработке)")
|
||||
label.setObjectName("EqPlaceholder")
|
||||
label.setAlignment(Qt.AlignCenter)
|
||||
label.setFont(QFont("", 18, 700))
|
||||
root.addWidget(label)
|
||||
root.addStretch(1)
|
||||
248
screens/setting/sound_screen.py
Normal file
248
screens/setting/sound_screen.py
Normal file
@ -0,0 +1,248 @@
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtGui import QFont
|
||||
from PySide6.QtWidgets import (
|
||||
QWidget,
|
||||
QLabel,
|
||||
QVBoxLayout,
|
||||
QHBoxLayout,
|
||||
QPushButton,
|
||||
QSlider,
|
||||
QButtonGroup,
|
||||
QScrollArea,
|
||||
QScroller,
|
||||
)
|
||||
|
||||
|
||||
class SoundScreen(QWidget):
|
||||
def __init__(self, on_eq):
|
||||
super().__init__()
|
||||
self._on_eq = on_eq
|
||||
|
||||
root = QVBoxLayout(self)
|
||||
root.setContentsMargins(0, 0, 0, 0)
|
||||
root.setSpacing(12)
|
||||
|
||||
scroll = QScrollArea()
|
||||
scroll.setWidgetResizable(True)
|
||||
scroll.setFrameShape(QScrollArea.NoFrame)
|
||||
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
|
||||
scroller = QScroller.scroller(scroll.viewport())
|
||||
scroller.grabGesture(
|
||||
scroll.viewport(),
|
||||
QScroller.LeftMouseButtonGesture
|
||||
)
|
||||
|
||||
content = QWidget()
|
||||
content_layout = QVBoxLayout(content)
|
||||
content_layout.setContentsMargins(0, 0, 0, 0)
|
||||
content_layout.setSpacing(12)
|
||||
|
||||
content_layout.addWidget(self._build_volume_card())
|
||||
content_layout.addWidget(self._build_premute_card())
|
||||
content_layout.addWidget(self._build_ducking_card())
|
||||
content_layout.addWidget(self._build_balance_card())
|
||||
content_layout.addWidget(self._build_tone_card())
|
||||
content_layout.addWidget(self._build_eq_card())
|
||||
content_layout.addStretch(1)
|
||||
|
||||
scroll.setWidget(content)
|
||||
root.addWidget(scroll, 1)
|
||||
|
||||
def _build_volume_card(self) -> QWidget:
|
||||
card, body = _card("Громкость")
|
||||
body.addWidget(
|
||||
_slider_row(
|
||||
"Базовая громкость",
|
||||
0,
|
||||
100,
|
||||
60,
|
||||
lambda v: f"{v}%",
|
||||
)
|
||||
)
|
||||
return card
|
||||
|
||||
def _build_premute_card(self) -> QWidget:
|
||||
card, body = _card("Премут")
|
||||
body.addWidget(_toggle_row("Премут", checked=False))
|
||||
body.addWidget(
|
||||
_slider_row(
|
||||
"Громкость премут",
|
||||
0,
|
||||
100,
|
||||
10,
|
||||
lambda v: f"{v}%",
|
||||
)
|
||||
)
|
||||
return card
|
||||
|
||||
def _build_ducking_card(self) -> QWidget:
|
||||
card, body = _card("Ducking")
|
||||
body.addWidget(_toggle_row("Ducking", checked=True))
|
||||
body.addWidget(
|
||||
_slider_row(
|
||||
"Громкость при Ducking",
|
||||
0,
|
||||
100,
|
||||
35,
|
||||
lambda v: f"{v}%",
|
||||
)
|
||||
)
|
||||
return card
|
||||
|
||||
def _build_balance_card(self) -> QWidget:
|
||||
card, body = _card("Баланс и фейдер")
|
||||
body.addWidget(
|
||||
_slider_row(
|
||||
"Баланс L/R",
|
||||
-50,
|
||||
50,
|
||||
0,
|
||||
_format_balance,
|
||||
)
|
||||
)
|
||||
body.addWidget(
|
||||
_slider_row(
|
||||
"Фейдер F/R",
|
||||
-50,
|
||||
50,
|
||||
0,
|
||||
_format_fader,
|
||||
)
|
||||
)
|
||||
return card
|
||||
|
||||
def _build_tone_card(self) -> QWidget:
|
||||
card, body = _card("Тон")
|
||||
row = QWidget()
|
||||
row.setObjectName("SoundToneRow")
|
||||
layout = QHBoxLayout(row)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.setSpacing(10)
|
||||
|
||||
group = QButtonGroup(row)
|
||||
group.setExclusive(True)
|
||||
|
||||
for idx, label in enumerate(("Тёплый", "Нейтральный", "Яркий")):
|
||||
btn = QPushButton(label)
|
||||
btn.setObjectName("SoundToneBtn")
|
||||
btn.setCheckable(True)
|
||||
btn.setMinimumHeight(40)
|
||||
btn.setFont(QFont("", 13, 600))
|
||||
if idx == 1:
|
||||
btn.setChecked(True)
|
||||
group.addButton(btn)
|
||||
layout.addWidget(btn, 1)
|
||||
|
||||
body.addWidget(row)
|
||||
return card
|
||||
|
||||
def _build_eq_card(self) -> QWidget:
|
||||
card, body = _card("Эквалайзер")
|
||||
btn = QPushButton("Открыть эквалайзер")
|
||||
btn.setObjectName("SoundEqBtn")
|
||||
btn.setMinimumHeight(48)
|
||||
btn.setFont(QFont("", 14, 700))
|
||||
btn.clicked.connect(self._on_eq)
|
||||
body.addWidget(btn)
|
||||
return card
|
||||
|
||||
|
||||
def _card(title: str) -> tuple[QWidget, QVBoxLayout]:
|
||||
card = QWidget()
|
||||
card.setObjectName("SoundCard")
|
||||
layout = QVBoxLayout(card)
|
||||
layout.setContentsMargins(14, 12, 14, 12)
|
||||
layout.setSpacing(10)
|
||||
|
||||
header = QLabel(title)
|
||||
header.setObjectName("SoundCardTitle")
|
||||
header.setFont(QFont("", 14, 700))
|
||||
|
||||
layout.addWidget(header)
|
||||
return card, layout
|
||||
|
||||
|
||||
def _toggle_row(label: str, checked: bool) -> QWidget:
|
||||
row = QWidget()
|
||||
row.setObjectName("SoundToggleRow")
|
||||
layout = QHBoxLayout(row)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.setSpacing(12)
|
||||
|
||||
lbl = QLabel(label)
|
||||
lbl.setFont(QFont("", 13, 600))
|
||||
|
||||
btn = QPushButton("Выкл")
|
||||
btn.setObjectName("SoundToggle")
|
||||
btn.setCheckable(True)
|
||||
btn.setChecked(checked)
|
||||
btn.setMinimumHeight(36)
|
||||
btn.setMinimumWidth(86)
|
||||
btn.setFont(QFont("", 12, 700))
|
||||
|
||||
def _sync_text(is_checked: bool):
|
||||
btn.setText("Вкл" if is_checked else "Выкл")
|
||||
|
||||
btn.toggled.connect(_sync_text)
|
||||
_sync_text(btn.isChecked())
|
||||
|
||||
layout.addWidget(lbl)
|
||||
layout.addStretch(1)
|
||||
layout.addWidget(btn)
|
||||
return row
|
||||
|
||||
|
||||
def _slider_row(
|
||||
label: str,
|
||||
minimum: int,
|
||||
maximum: int,
|
||||
value: int,
|
||||
formatter,
|
||||
) -> QWidget:
|
||||
row = QWidget()
|
||||
row.setObjectName("SoundSliderRow")
|
||||
layout = QVBoxLayout(row)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.setSpacing(6)
|
||||
|
||||
header = QWidget()
|
||||
header_layout = QHBoxLayout(header)
|
||||
header_layout.setContentsMargins(0, 0, 0, 0)
|
||||
header_layout.setSpacing(8)
|
||||
|
||||
lbl = QLabel(label)
|
||||
lbl.setFont(QFont("", 13, 600))
|
||||
val = QLabel(formatter(value))
|
||||
val.setObjectName("SoundValue")
|
||||
val.setFont(QFont("", 12, 600))
|
||||
val.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
|
||||
|
||||
header_layout.addWidget(lbl)
|
||||
header_layout.addStretch(1)
|
||||
header_layout.addWidget(val)
|
||||
|
||||
slider = QSlider(Qt.Horizontal)
|
||||
slider.setObjectName("SoundSlider")
|
||||
slider.setRange(minimum, maximum)
|
||||
slider.setValue(value)
|
||||
slider.valueChanged.connect(lambda v: val.setText(formatter(v)))
|
||||
|
||||
layout.addWidget(header)
|
||||
layout.addWidget(slider)
|
||||
return row
|
||||
|
||||
|
||||
def _format_balance(value: int) -> str:
|
||||
if value == 0:
|
||||
return "Центр"
|
||||
side = "L" if value < 0 else "R"
|
||||
return f"{side} {abs(value)}"
|
||||
|
||||
|
||||
def _format_fader(value: int) -> str:
|
||||
if value == 0:
|
||||
return "Центр"
|
||||
side = "F" if value < 0 else "R"
|
||||
return f"{side} {abs(value)}"
|
||||
@ -15,6 +15,8 @@ from PySide6.QtWidgets import QScroller
|
||||
from screens.setting.bluetooth_screen import BluetoothScreen
|
||||
from screens.setting.about_screen import build_about_screen
|
||||
from screens.setting.dev_screen import build_dev_screen
|
||||
from screens.setting.sound_screen import SoundScreen
|
||||
from screens.setting.eq_screen import EqualizerScreen
|
||||
|
||||
|
||||
class SettingsRow(QPushButton):
|
||||
@ -105,7 +107,7 @@ class SettingsScreen(QWidget):
|
||||
)
|
||||
bt_row = bt_rows.get("Bluetooth")
|
||||
|
||||
self._add_section(
|
||||
display_rows = self._add_section(
|
||||
content_layout,
|
||||
"Дисплей и звук",
|
||||
[
|
||||
@ -113,6 +115,7 @@ class SettingsScreen(QWidget):
|
||||
("Звук", "Громкость, эквалайзер"),
|
||||
],
|
||||
)
|
||||
sound_row = display_rows.get("Звук")
|
||||
|
||||
system_rows = self._add_section(
|
||||
content_layout,
|
||||
@ -132,10 +135,14 @@ class SettingsScreen(QWidget):
|
||||
self._dev_screen = build_dev_screen(self._exit_app)
|
||||
self._about_screen = build_about_screen()
|
||||
self._bt_screen = BluetoothScreen(self._show_list)
|
||||
self._eq_screen = EqualizerScreen()
|
||||
self._sound_screen = SoundScreen(self._show_equalizer)
|
||||
self.stack.addWidget(self._list_screen)
|
||||
self.stack.addWidget(self._dev_screen)
|
||||
self.stack.addWidget(self._about_screen)
|
||||
self.stack.addWidget(self._bt_screen)
|
||||
self.stack.addWidget(self._sound_screen)
|
||||
self.stack.addWidget(self._eq_screen)
|
||||
|
||||
if dev_row is not None:
|
||||
dev_row.clicked.connect(self._show_dev)
|
||||
@ -143,6 +150,8 @@ class SettingsScreen(QWidget):
|
||||
about_row.clicked.connect(self._show_about)
|
||||
if bt_row is not None:
|
||||
bt_row.clicked.connect(self._show_bluetooth)
|
||||
if sound_row is not None:
|
||||
sound_row.clicked.connect(self._show_sound)
|
||||
self._show_list()
|
||||
|
||||
def _add_section(
|
||||
@ -183,6 +192,14 @@ class SettingsScreen(QWidget):
|
||||
def show_list(self):
|
||||
self._show_list()
|
||||
|
||||
def _show_sound(self):
|
||||
self.stack.setCurrentWidget(self._sound_screen)
|
||||
self.view_changed.emit("Звук", True)
|
||||
|
||||
def _show_equalizer(self):
|
||||
self.stack.setCurrentWidget(self._eq_screen)
|
||||
self.view_changed.emit("Эквалайзер", True)
|
||||
|
||||
def _exit_app(self):
|
||||
app = QApplication.instance()
|
||||
if app is not None:
|
||||
|
||||
@ -46,6 +46,46 @@ QMenu::item:selected { background: #F3F4F6; }
|
||||
#SettingsChevron { color: rgba(107,114,128,0.95); }
|
||||
#SettingsRowTitle, #SettingsRowSub, #SettingsChevron { background: transparent; }
|
||||
|
||||
#SoundCard {
|
||||
background: #FFFFFF;
|
||||
border-radius: 14px;
|
||||
border: 1px solid #E5E7EB;
|
||||
}
|
||||
#SoundCardTitle { color: rgba(55,65,81,0.9); }
|
||||
#SoundValue { color: rgba(107,114,128,0.95); }
|
||||
#SoundSlider::groove:horizontal { height: 8px; background: #E5E7EB; border-radius: 4px; }
|
||||
#SoundSlider::handle:horizontal { width: 18px; margin: -6px 0; background: #111827; border-radius: 9px; }
|
||||
#SoundToggle {
|
||||
background: #F3F4F6;
|
||||
color: #111827;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #E5E7EB;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
#SoundToggle:checked {
|
||||
background: #111827;
|
||||
color: #FFFFFF;
|
||||
border: 1px solid #111827;
|
||||
}
|
||||
#SoundToneBtn {
|
||||
background: #FFFFFF;
|
||||
color: #111827;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #E5E7EB;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
#SoundToneBtn:checked { background: #E5E7EB; }
|
||||
#SoundEqBtn {
|
||||
background: #FFFFFF;
|
||||
color: #111827;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #E5E7EB;
|
||||
padding: 8px 14px;
|
||||
text-align: left;
|
||||
}
|
||||
#SoundEqBtn:hover { background: #F9FAFB; }
|
||||
#EqPlaceholder { color: rgba(107,114,128,0.95); }
|
||||
|
||||
#SettingsBackBtn {
|
||||
background: #FFFFFF;
|
||||
border-radius: 12px;
|
||||
|
||||
@ -43,6 +43,43 @@ QMenu::item:selected { background: #1B2330; }
|
||||
#SettingsChevron { color: rgba(138,147,166,0.95); }
|
||||
#SettingsRowTitle, #SettingsRowSub, #SettingsChevron { background: transparent; }
|
||||
|
||||
#SoundCard {
|
||||
background: #141A22;
|
||||
border-radius: 14px;
|
||||
}
|
||||
#SoundCardTitle { color: rgba(138,147,166,0.95); }
|
||||
#SoundValue { color: rgba(138,147,166,0.95); }
|
||||
#SoundSlider::groove:horizontal { height: 8px; background: #1B2330; border-radius: 4px; }
|
||||
#SoundSlider::handle:horizontal { width: 18px; margin: -6px 0; background: #E6EAF0; border-radius: 9px; }
|
||||
#SoundToggle {
|
||||
background: #1B2330;
|
||||
color: #E6EAF0;
|
||||
border-radius: 10px;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
#SoundToggle:checked {
|
||||
background: #E6EAF0;
|
||||
color: #0B0E11;
|
||||
}
|
||||
#SoundToneBtn {
|
||||
background: #141A22;
|
||||
color: #E6EAF0;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #1B2330;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
#SoundToneBtn:checked { background: #2A3A52; }
|
||||
#SoundEqBtn {
|
||||
background: #141A22;
|
||||
color: #E6EAF0;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #1B2330;
|
||||
padding: 8px 14px;
|
||||
text-align: left;
|
||||
}
|
||||
#SoundEqBtn:hover { background: #1B2330; }
|
||||
#EqPlaceholder { color: rgba(138,147,166,0.95); }
|
||||
|
||||
#SettingsBackBtn {
|
||||
background: #141A22;
|
||||
border-radius: 12px;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user