The now-playing panel (and the seek row under it) caps at 700px, up from 560. The top row gets one equal gap before, between and after its controls, capped at 28px; past that the extra splits between the two ends, so the row sits centered instead of spreading out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
135 lines
5.1 KiB
Python
135 lines
5.1 KiB
Python
"""Round 69: the header row moves up into the seek row's band.
|
|
|
|
The Library button, the view's header (search box or playlist name) and the
|
|
seek row share one row under the transport boxes: the Library button as wide
|
|
as the sidebar, the header where the view starts, the seek row exactly under
|
|
the now-playing panel. The panel stops at NOW_PLAYING_MAX and the gaps between
|
|
the controls share what's left.
|
|
"""
|
|
|
|
from PyQt6.QtCore import QPoint
|
|
|
|
from lintunes.gui.fit_label import FitLabel
|
|
from lintunes.gui.main_window import MainWindow
|
|
from lintunes.gui.transport import NOW_PLAYING_MAX, NOW_PLAYING_MIN
|
|
from lintunes.library_manager import LibraryManager
|
|
from lintunes.models.library import Library
|
|
from lintunes.models.playlist import Playlist
|
|
from lintunes.models.track import Track
|
|
from lintunes.preferences import Preferences
|
|
|
|
|
|
def _window(qapp, tmp_path, width=1280):
|
|
library = Library(tracks={1: Track(track_id=1, name="One")})
|
|
library.playlists["abcd1234"] = Playlist(
|
|
persistent_id="abcd1234", name="Road Trip", track_ids=[1])
|
|
window = MainWindow(LibraryManager(library, tmp_path), Preferences(tmp_path))
|
|
window.resize(width, 500)
|
|
window.show()
|
|
qapp.processEvents()
|
|
return window
|
|
|
|
|
|
def _x(widget, window, x=0):
|
|
return widget.mapTo(window, QPoint(x, 0)).x()
|
|
|
|
|
|
def _gx(widget, x=0):
|
|
return widget.mapToGlobal(QPoint(x, 0)).x()
|
|
|
|
|
|
def test_startup_still_opens_on_the_library(qapp, tmp_path):
|
|
# The moved Library button fell to the end of the focus chain, the tree
|
|
# took the first focus and selected its first playlist.
|
|
window = _window(qapp, tmp_path)
|
|
assert window._content.currentWidget() is window._library_view
|
|
assert window._sidebar.library_button.isChecked()
|
|
|
|
|
|
def test_library_button_spans_the_sidebar(qapp, tmp_path):
|
|
window = _window(qapp, tmp_path)
|
|
header = window.sidebar.header
|
|
assert header.parentWidget() is not window.sidebar
|
|
assert _gx(header) == _gx(window.sidebar)
|
|
assert header.width() == window.sidebar.width()
|
|
|
|
|
|
def test_search_then_title_sit_where_the_view_starts(qapp, tmp_path):
|
|
window = _window(qapp, tmp_path)
|
|
search_strip = window._library_view.header
|
|
assert search_strip.isVisible()
|
|
assert _gx(search_strip) == _gx(window._content)
|
|
|
|
window._show_playlist("abcd1234")
|
|
qapp.processEvents()
|
|
label = window._playlist_view.header
|
|
assert label.isVisible() and label.full_text() == "Road Trip"
|
|
assert _gx(label) == _gx(window._content)
|
|
# The search strip went home to its view, hidden.
|
|
assert not search_strip.isVisible()
|
|
assert search_strip.parentWidget() is window._library_view
|
|
|
|
|
|
def test_header_row_shares_the_seek_band(qapp, tmp_path):
|
|
window = _window(qapp, tmp_path)
|
|
bar = window._transport
|
|
panel = bar._now_playing
|
|
seek = bar._slider.parentWidget()
|
|
# Under the panel, edge to edge, and level with the Library button.
|
|
assert _gx(seek) == _gx(panel)
|
|
assert seek.width() == panel.width()
|
|
library = window.sidebar.library_button
|
|
row = bar._header_row
|
|
assert row.geometry().top() > panel.geometry().bottom()
|
|
assert library.mapTo(bar, QPoint()).y() >= row.geometry().top()
|
|
|
|
|
|
def test_panel_caps_and_gaps_take_the_rest(qapp, tmp_path):
|
|
window = _window(qapp, tmp_path, width=1600)
|
|
bar = window._transport
|
|
assert bar._now_playing.width() == NOW_PLAYING_MAX
|
|
window.resize(800, 500)
|
|
qapp.processEvents()
|
|
assert NOW_PLAYING_MIN <= bar._now_playing.width() < NOW_PLAYING_MAX
|
|
bpm = bar._bpm_button.parentWidget()
|
|
assert bar._now_playing.geometry().right() < bpm.geometry().left()
|
|
assert bpm.geometry().right() < bar.width()
|
|
|
|
|
|
def test_views_seek_row_never_overlaps_the_header(qapp, tmp_path):
|
|
window = _window(qapp, tmp_path, width=800)
|
|
strip = window._library_view.header
|
|
seek = window._transport._slider.parentWidget()
|
|
assert _gx(strip, strip.width()) <= _gx(seek)
|
|
|
|
|
|
def test_long_name_shrinks_then_elides(qapp):
|
|
label = FitLabel()
|
|
base = label.font().pointSize()
|
|
label.resize(120, 30)
|
|
label.setText("A short one")
|
|
assert label.text() == "A short one"
|
|
label.setText("An Extraordinarily Long Playlist Name That Goes On Forever")
|
|
assert label.font().pointSize() >= base - 2
|
|
assert label.text().endswith("…")
|
|
assert label.toolTip() == label.full_text()
|
|
|
|
|
|
def test_row_is_knolled_with_equal_gaps_and_ends(qapp, tmp_path):
|
|
from lintunes.gui.transport import MAX_GAP, MIN_GAP
|
|
window = _window(qapp, tmp_path)
|
|
bar = window._transport
|
|
for width in (900, 1280, 1800):
|
|
window.resize(width, 500)
|
|
qapp.processEvents()
|
|
row = [bar._prev_btn.parentWidget(), bar._shuffle_btn.parentWidget(),
|
|
bar._visualizer, bar._volume_slider, bar._now_playing,
|
|
bar._bpm_button.parentWidget()]
|
|
edges = [(w.geometry().left(), w.geometry().right()) for w in row]
|
|
gaps = [b[0] - a[1] - 1 for a, b in zip(edges, edges[1:])]
|
|
assert max(gaps) - min(gaps) <= 1
|
|
assert MIN_GAP <= gaps[0] <= MAX_GAP
|
|
left_end, right_end = edges[0][0], bar.width() - 1 - edges[-1][1]
|
|
assert abs(left_end - right_end) <= 1
|
|
assert left_end >= gaps[0] - 1
|