v0.31.6: album art inside the playlists' frame; text and playhead lifted 2px
The playlist list and the album art under it share one frame (the list's own style, drawn around both), and the no-art placeholder is a shade lighter than that frame line so the line still reads around it. The playlist name, times and playhead sit 2px up (HeaderRow.LIFT), on the Library button's bottom line by eye. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
"""LinTunes — iTunes-style music library manager and player for Linux."""
|
||||
|
||||
__version__ = "0.31.5"
|
||||
__version__ = "0.31.6"
|
||||
|
||||
+20
-6
@@ -2,6 +2,7 @@ from PyQt6.QtWidgets import (
|
||||
QWidget, QVBoxLayout, QPushButton, QTreeWidget, QTreeWidgetItem, QMenu,
|
||||
QInputDialog, QMessageBox, QAbstractItemView, QLineEdit, QApplication,
|
||||
QHBoxLayout, QListWidget, QListWidgetItem, QStackedWidget, QSizePolicy,
|
||||
QFrame,
|
||||
)
|
||||
from PyQt6.QtCore import Qt, QTimer, QPoint, pyqtSignal
|
||||
from PyQt6.QtGui import QBrush, QPainter, QPalette, QPixmap
|
||||
@@ -75,17 +76,28 @@ class SidebarPanel(QWidget):
|
||||
self.header = top
|
||||
top.header_owner = self
|
||||
|
||||
# The playlists and the album art under them are one group inside
|
||||
# one frame — the list's own frame, drawn around both, so the art
|
||||
# sits within it rather than hanging below.
|
||||
group = QFrame()
|
||||
self._lists = QStackedWidget()
|
||||
self.tree = PlaylistTree(manager)
|
||||
self._lists.addWidget(self.tree)
|
||||
self.friend_list = FriendPlaylistList()
|
||||
self._lists.addWidget(self.friend_list)
|
||||
layout.addWidget(self._lists, stretch=1)
|
||||
# What the header row lines the Library button up with.
|
||||
self.list_area = self._lists
|
||||
|
||||
group.setFrameShape(self.tree.frameShape())
|
||||
group.setFrameShadow(self.tree.frameShadow())
|
||||
for view in (self.tree, self.friend_list):
|
||||
view.setFrameShape(QFrame.Shape.NoFrame)
|
||||
inner = QVBoxLayout(group)
|
||||
inner.setContentsMargins(0, 0, 0, 0)
|
||||
inner.setSpacing(0)
|
||||
inner.addWidget(self._lists, stretch=1)
|
||||
self.art = SidebarArt(player)
|
||||
layout.addWidget(self.art)
|
||||
inner.addWidget(self.art)
|
||||
layout.addWidget(group, stretch=1)
|
||||
# What the header row lines the Library button up with.
|
||||
self.list_area = group
|
||||
|
||||
self.library_button.clicked.connect(self._on_library_clicked)
|
||||
self.tree.playlist_selected.connect(self._on_playlist_selected)
|
||||
@@ -305,7 +317,9 @@ class SidebarArt(QWidget):
|
||||
|
||||
def paintEvent(self, event):
|
||||
painter = QPainter(self)
|
||||
painter.fillRect(self.rect(), self.palette().mid().color())
|
||||
# A shade lighter than mid: the sidebar group's frame line is drawn
|
||||
# in mid, and would vanish into a placeholder of the same gray.
|
||||
painter.fillRect(self.rect(), self.palette().mid().color().lighter(112))
|
||||
if self._pixmap is None or self._pixmap.isNull():
|
||||
return
|
||||
scaled = self._pixmap.scaled(
|
||||
|
||||
@@ -276,6 +276,10 @@ class HeaderRow(QWidget):
|
||||
# lists: every item in the row stands on one floor, BOTTOM px up.
|
||||
TOP_PAD = 2
|
||||
BOTTOM = 5
|
||||
# Text and the playhead have no hard bottom edge, so on the floor itself
|
||||
# they read as sitting lower than the Library button beside them; this
|
||||
# lifts them onto the button's bottom line by eye.
|
||||
LIFT = 2
|
||||
|
||||
def __init__(self, seek: QWidget, parent=None):
|
||||
super().__init__(parent)
|
||||
@@ -336,7 +340,7 @@ class HeaderRow(QWidget):
|
||||
self.seek.layout().invalidate()
|
||||
self.seek.setGeometry(seek_left, self.TOP_PAD,
|
||||
max(0, panel.right() + 1 - seek_left),
|
||||
box_h + drop)
|
||||
box_h + drop - self.LIFT)
|
||||
header = self.view_header
|
||||
if header is not None:
|
||||
width = max(0, seek_left - self.GAP - content_left)
|
||||
@@ -344,7 +348,7 @@ class HeaderRow(QWidget):
|
||||
header.setAlignment(Qt.AlignmentFlag.AlignLeft
|
||||
| Qt.AlignmentFlag.AlignBottom)
|
||||
header.setGeometry(content_left, self.TOP_PAD, width,
|
||||
box_h + self._drop(header))
|
||||
box_h + self._drop(header) - self.LIFT)
|
||||
else:
|
||||
header.setGeometry(content_left, self.TOP_PAD, width, box_h)
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ def test_library_button_spans_the_playlist_list(qapp, tmp_path):
|
||||
window = _window(qapp, tmp_path)
|
||||
header = window.sidebar.header
|
||||
lists = window.sidebar.list_area
|
||||
# The frame around the playlists takes in the album art too.
|
||||
assert window.sidebar.art.parentWidget() is lists
|
||||
assert header.parentWidget() is not window.sidebar
|
||||
assert _gx(header) == _gx(lists) > _gx(window)
|
||||
assert header.width() == lists.width()
|
||||
@@ -71,12 +73,13 @@ def test_header_row_items_share_one_floor(qapp, tmp_path):
|
||||
|
||||
assert bottom(window.sidebar.library_button) == floor
|
||||
assert bottom(window._library_view._search) == floor
|
||||
assert bottom(window._transport._slider) == floor
|
||||
# Text and the playhead sit LIFT px up, on the button's bottom line by eye.
|
||||
assert bottom(window._transport._slider) == floor - HeaderRow.LIFT
|
||||
window._show_playlist("abcd1234")
|
||||
qapp.processEvents()
|
||||
label = window._playlist_view.header
|
||||
baseline = bottom(label) - label.fontMetrics().descent()
|
||||
assert abs(baseline - floor) <= 1
|
||||
assert abs(baseline - (floor - HeaderRow.LIFT)) <= 1
|
||||
|
||||
|
||||
def test_search_then_title_sit_where_the_view_starts(qapp, tmp_path):
|
||||
|
||||
Reference in New Issue
Block a user