Skip to content

Commit

Permalink
gui: introduce ClickableMixin (#787)
Browse files Browse the repository at this point in the history
1. click the accordion header can fold/unfold contents
2. click the cover label to show/hide nowplaying overlay (demo)
  • Loading branch information
cosven authored Jan 29, 2024
1 parent 95091e8 commit d16025c
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 21 deletions.
49 changes: 41 additions & 8 deletions feeluown/gui/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,10 @@
from contextlib import contextmanager
from typing import TypeVar, List, Optional, Generic, Union, cast, TYPE_CHECKING

try:
# helper module should work in no-window mode
from PyQt5.QtCore import QModelIndex, QSize, Qt, pyqtSignal, QSortFilterProxyModel, \
QAbstractListModel
from PyQt5.QtGui import QPalette, QFontMetrics, QColor, QPainter
from PyQt5.QtWidgets import QApplication, QScrollArea, QWidget
except ImportError:
pass
from PyQt5.QtCore import QModelIndex, QSize, Qt, pyqtSignal, QSortFilterProxyModel, \
QAbstractListModel, QPoint
from PyQt5.QtGui import QPalette, QFontMetrics, QColor, QPainter, QMouseEvent
from PyQt5.QtWidgets import QApplication, QScrollArea, QWidget

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


class ClickableMixin:
clicked = pyqtSignal()

def __init__(self, **kwargs):
super().__init__(**kwargs) # Cooperative multi-inheritance.

self._down = False

def mousePressEvent(self, e: QMouseEvent):
if e.button() != Qt.LeftButton:
# Call super.mousePressEvent because the concrete class may do sth inside it.
super().mousePressEvent(e)
return
if self._hit_button(e.pos()):
self._down = True
e.accept()
else:
super().mousePressEvent(e)

def mouseReleaseEvent(self, e: QMouseEvent):
if e.button() != Qt.LeftButton or not self._down:
super().mouseReleaseEvent(e)
return
self._down = False
if self._hit_button(e.pos()):
self.clicked.emit()
e.accept()
else:
super().mouseReleaseEvent(e)

def _hit_button(self, pos: QPoint):
return self.rect().contains(pos)

def set_down(self, down: bool):
self._down = down


# https://ethanschoonover.com/solarized/
SOLARIZED_COLORS = {
'yellow': '#b58900',
Expand Down
3 changes: 3 additions & 0 deletions feeluown/gui/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from feeluown.gui.uimain.page_view import RightPanel
from feeluown.gui.uimain.player_bar import TopPanel
from feeluown.gui.uimain.playlist_overlay import PlaylistOverlay
from feeluown.gui.uimain.nowplaying_overlay import NowplayingOverlay

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -39,6 +40,7 @@ def __init__(self, app):
self.toolbar = self.bottom_panel = self.right_panel.bottom_panel
self.mpv_widget = MpvOpenGLWidget(self._app)
self.playlist_overlay = PlaylistOverlay(app, parent=app)
self.nowplaying_overlay = NowplayingOverlay(app, parent=app)

# alias
self.magicbox = self.bottom_panel.magicbox
Expand All @@ -64,6 +66,7 @@ def _setup_ui(self):
self._splitter.addWidget(self.right_panel)
self._message_line.hide()
self.playlist_overlay.hide()
self.nowplaying_overlay.hide()

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

Expand Down
34 changes: 34 additions & 0 deletions feeluown/gui/uimain/nowplaying_overlay.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from typing import TYPE_CHECKING, cast

from PyQt5.QtCore import QEvent
from PyQt5.QtGui import QResizeEvent, QKeySequence
from PyQt5.QtWidgets import QWidget, QShortcut

if TYPE_CHECKING:
from feeluown.app.gui_app import GuiApp


class NowplayingOverlay(QWidget):
"""
TODO
"""

def __init__(self, app: 'GuiApp', parent=None):
super().__init__(parent=parent)
self._app = app
self._app.installEventFilter(self)

QShortcut(QKeySequence.Cancel, self).activated.connect(self.hide)

self.setStyleSheet('background: pink')

def show(self):
self.resize(self._app.size())
super().show()

def eventFilter(self, obj, event):
if self.isVisible() and obj is self._app and event.type() == QEvent.Resize:
event = cast(QResizeEvent, event)
print('resize', event.size(), self.size())
self.resize(event.size())
return False
14 changes: 12 additions & 2 deletions feeluown/gui/uimain/player_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,19 @@
LineSongLabel, MediaButtons, LyricButton, WatchButton, LikeButton,
MVButton, PlaylistButton, SongSourceTag,
)
from feeluown.gui.helpers import IS_MACOS
from feeluown.gui.helpers import IS_MACOS, ClickableMixin

if TYPE_CHECKING:
from feeluown.app.gui_app import GuiApp

logger = logging.getLogger(__name__)


class ClickableCover(ClickableMixin, CoverLabelV2):
def __init__(self, app, **kwargs):
super().__init__(app=app, **kwargs)


class PlayerControlPanel(QFrame):

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

self.cover_label = CoverLabelV2(app)
self.cover_label = ClickableCover(app)
self.duration_label = DurationLabel(app, parent=self)
self.position_label = ProgressLabel(app, parent=self)

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

self._setup_ui()

Expand Down Expand Up @@ -185,6 +191,10 @@ def on_metadata_changed(self, metadata):
else:
self.cover_label.show_img(None)

def show_nowplaying_overlay(self):
self._app.ui.nowplaying_overlay.show()
self._app.ui.nowplaying_overlay.raise_()


class TopPanel(QFrame):
def __init__(self, app, parent=None):
Expand Down
21 changes: 10 additions & 11 deletions feeluown/gui/widgets/accordion.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QHBoxLayout

from feeluown.gui.widgets.textbtn import TextButton
from feeluown.gui.helpers import ClickableMixin


class ClickableHeader(QWidget):
class ClickableHeader(ClickableMixin, QWidget):
btn_text_fold = '△'
btn_text_unfold = '▼'

clicked = pyqtSignal()

def __init__(self, header, checked=False, *args, **kwargs):
super().__init__(*args, **kwargs)

self._is_checked = False

self.inner_header = header
self.btn = TextButton(self._get_btn_text(checked))
self.btn.setCheckable(True)
self.btn.setChecked(checked)
self.btn = TextButton(self._get_btn_text(self._is_checked))

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

self.btn.clicked.connect(self.toggle)
self.btn.clicked.connect(self.clicked.emit)
self.clicked.connect(self.toggle)

def toggle(self, checked):
self.clicked.emit()
self.btn.setText(self._get_btn_text(checked))
def toggle(self):
self._is_checked = not self._is_checked
self.btn.setText(self._get_btn_text(self._is_checked))

def _get_btn_text(self, checked):
return self.btn_text_unfold if checked else self.btn_text_fold
Expand Down

0 comments on commit d16025c

Please sign in to comment.