Skip to content

Commit d16025c

Browse files
authored
gui: introduce ClickableMixin (#787)
1. click the accordion header can fold/unfold contents 2. click the cover label to show/hide nowplaying overlay (demo)
1 parent 95091e8 commit d16025c

File tree

5 files changed

+100
-21
lines changed

5 files changed

+100
-21
lines changed

feeluown/gui/helpers.py

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,10 @@
2525
from contextlib import contextmanager
2626
from typing import TypeVar, List, Optional, Generic, Union, cast, TYPE_CHECKING
2727

28-
try:
29-
# helper module should work in no-window mode
30-
from PyQt5.QtCore import QModelIndex, QSize, Qt, pyqtSignal, QSortFilterProxyModel, \
31-
QAbstractListModel
32-
from PyQt5.QtGui import QPalette, QFontMetrics, QColor, QPainter
33-
from PyQt5.QtWidgets import QApplication, QScrollArea, QWidget
34-
except ImportError:
35-
pass
28+
from PyQt5.QtCore import QModelIndex, QSize, Qt, pyqtSignal, QSortFilterProxyModel, \
29+
QAbstractListModel, QPoint
30+
from PyQt5.QtGui import QPalette, QFontMetrics, QColor, QPainter, QMouseEvent
31+
from PyQt5.QtWidgets import QApplication, QScrollArea, QWidget
3632

3733
from feeluown.utils.aio import run_afn, run_fn
3834
from feeluown.utils.reader import AsyncReader, Reader
@@ -574,6 +570,43 @@ def secondary_text_color(palette: QPalette):
574570
return non_text_color
575571

576572

573+
class ClickableMixin:
574+
clicked = pyqtSignal()
575+
576+
def __init__(self, **kwargs):
577+
super().__init__(**kwargs) # Cooperative multi-inheritance.
578+
579+
self._down = False
580+
581+
def mousePressEvent(self, e: QMouseEvent):
582+
if e.button() != Qt.LeftButton:
583+
# Call super.mousePressEvent because the concrete class may do sth inside it.
584+
super().mousePressEvent(e)
585+
return
586+
if self._hit_button(e.pos()):
587+
self._down = True
588+
e.accept()
589+
else:
590+
super().mousePressEvent(e)
591+
592+
def mouseReleaseEvent(self, e: QMouseEvent):
593+
if e.button() != Qt.LeftButton or not self._down:
594+
super().mouseReleaseEvent(e)
595+
return
596+
self._down = False
597+
if self._hit_button(e.pos()):
598+
self.clicked.emit()
599+
e.accept()
600+
else:
601+
super().mouseReleaseEvent(e)
602+
603+
def _hit_button(self, pos: QPoint):
604+
return self.rect().contains(pos)
605+
606+
def set_down(self, down: bool):
607+
self._down = down
608+
609+
577610
# https://ethanschoonover.com/solarized/
578611
SOLARIZED_COLORS = {
579612
'yellow': '#b58900',

feeluown/gui/ui.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from feeluown.gui.uimain.page_view import RightPanel
1212
from feeluown.gui.uimain.player_bar import TopPanel
1313
from feeluown.gui.uimain.playlist_overlay import PlaylistOverlay
14+
from feeluown.gui.uimain.nowplaying_overlay import NowplayingOverlay
1415

1516
logger = logging.getLogger(__name__)
1617

@@ -39,6 +40,7 @@ def __init__(self, app):
3940
self.toolbar = self.bottom_panel = self.right_panel.bottom_panel
4041
self.mpv_widget = MpvOpenGLWidget(self._app)
4142
self.playlist_overlay = PlaylistOverlay(app, parent=app)
43+
self.nowplaying_overlay = NowplayingOverlay(app, parent=app)
4244

4345
# alias
4446
self.magicbox = self.bottom_panel.magicbox
@@ -64,6 +66,7 @@ def _setup_ui(self):
6466
self._splitter.addWidget(self.right_panel)
6567
self._message_line.hide()
6668
self.playlist_overlay.hide()
69+
self.nowplaying_overlay.hide()
6770

6871
self.right_panel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
6972

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from typing import TYPE_CHECKING, cast
2+
3+
from PyQt5.QtCore import QEvent
4+
from PyQt5.QtGui import QResizeEvent, QKeySequence
5+
from PyQt5.QtWidgets import QWidget, QShortcut
6+
7+
if TYPE_CHECKING:
8+
from feeluown.app.gui_app import GuiApp
9+
10+
11+
class NowplayingOverlay(QWidget):
12+
"""
13+
TODO
14+
"""
15+
16+
def __init__(self, app: 'GuiApp', parent=None):
17+
super().__init__(parent=parent)
18+
self._app = app
19+
self._app.installEventFilter(self)
20+
21+
QShortcut(QKeySequence.Cancel, self).activated.connect(self.hide)
22+
23+
self.setStyleSheet('background: pink')
24+
25+
def show(self):
26+
self.resize(self._app.size())
27+
super().show()
28+
29+
def eventFilter(self, obj, event):
30+
if self.isVisible() and obj is self._app and event.type() == QEvent.Resize:
31+
event = cast(QResizeEvent, event)
32+
print('resize', event.size(), self.size())
33+
self.resize(event.size())
34+
return False

feeluown/gui/uimain/player_bar.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,19 @@
1414
LineSongLabel, MediaButtons, LyricButton, WatchButton, LikeButton,
1515
MVButton, PlaylistButton, SongSourceTag,
1616
)
17-
from feeluown.gui.helpers import IS_MACOS
17+
from feeluown.gui.helpers import IS_MACOS, ClickableMixin
1818

1919
if TYPE_CHECKING:
2020
from feeluown.app.gui_app import GuiApp
2121

2222
logger = logging.getLogger(__name__)
2323

2424

25+
class ClickableCover(ClickableMixin, CoverLabelV2):
26+
def __init__(self, app, **kwargs):
27+
super().__init__(app=app, **kwargs)
28+
29+
2530
class PlayerControlPanel(QFrame):
2631

2732
def __init__(self, app: 'GuiApp', parent=None):
@@ -69,7 +74,7 @@ def __init__(self, *args, **kwargs):
6974
self.song_title_label.setAlignment(Qt.AlignCenter)
7075
self.song_source_label = SongSourceTag(self._app, parent=self)
7176

72-
self.cover_label = CoverLabelV2(app)
77+
self.cover_label = ClickableCover(app)
7378
self.duration_label = DurationLabel(app, parent=self)
7479
self.position_label = ProgressLabel(app, parent=self)
7580

@@ -82,6 +87,7 @@ def __init__(self, *args, **kwargs):
8287
player = self._app.player
8388
player.metadata_changed.connect(self.on_metadata_changed, aioqueue=True)
8489
player.volume_changed.connect(self.volume_btn.on_volume_changed)
90+
self.cover_label.clicked.connect(self.show_nowplaying_overlay)
8591

8692
self._setup_ui()
8793

@@ -185,6 +191,10 @@ def on_metadata_changed(self, metadata):
185191
else:
186192
self.cover_label.show_img(None)
187193

194+
def show_nowplaying_overlay(self):
195+
self._app.ui.nowplaying_overlay.show()
196+
self._app.ui.nowplaying_overlay.raise_()
197+
188198

189199
class TopPanel(QFrame):
190200
def __init__(self, app, parent=None):

feeluown/gui/widgets/accordion.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
1-
from PyQt5.QtCore import pyqtSignal
21
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QHBoxLayout
32

43
from feeluown.gui.widgets.textbtn import TextButton
4+
from feeluown.gui.helpers import ClickableMixin
55

66

7-
class ClickableHeader(QWidget):
7+
class ClickableHeader(ClickableMixin, QWidget):
88
btn_text_fold = '△'
99
btn_text_unfold = '▼'
1010

11-
clicked = pyqtSignal()
12-
1311
def __init__(self, header, checked=False, *args, **kwargs):
1412
super().__init__(*args, **kwargs)
1513

14+
self._is_checked = False
15+
1616
self.inner_header = header
17-
self.btn = TextButton(self._get_btn_text(checked))
18-
self.btn.setCheckable(True)
19-
self.btn.setChecked(checked)
17+
self.btn = TextButton(self._get_btn_text(self._is_checked))
2018

2119
self._layout = QHBoxLayout(self)
2220
self._layout.setContentsMargins(0, 0, 0, 0)
@@ -25,11 +23,12 @@ def __init__(self, header, checked=False, *args, **kwargs):
2523
self._layout.addStretch(0)
2624
self._layout.addWidget(self.btn)
2725

28-
self.btn.clicked.connect(self.toggle)
26+
self.btn.clicked.connect(self.clicked.emit)
27+
self.clicked.connect(self.toggle)
2928

30-
def toggle(self, checked):
31-
self.clicked.emit()
32-
self.btn.setText(self._get_btn_text(checked))
29+
def toggle(self):
30+
self._is_checked = not self._is_checked
31+
self.btn.setText(self._get_btn_text(self._is_checked))
3332

3433
def _get_btn_text(self, checked):
3534
return self.btn_text_unfold if checked else self.btn_text_fold

0 commit comments

Comments
 (0)