181 lines
7.0 KiB
Python
181 lines
7.0 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 row of boxes keeps one GAP before, between and
|
|
after its controls, and the panel fills the rest.
|
|
"""
|
|
|
|
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_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_playlist_list(qapp, tmp_path):
|
|
# Edge to edge with the list below it, scrollbar included, with bare
|
|
# window to the left of both.
|
|
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()
|
|
button = window.sidebar.library_button
|
|
assert _gx(button) == _gx(lists)
|
|
assert _gx(button, button.width()) == _gx(lists, lists.width())
|
|
|
|
|
|
def test_header_row_items_share_one_floor(qapp, tmp_path):
|
|
from lintunes.gui.transport import HeaderRow
|
|
window = _window(qapp, tmp_path)
|
|
row = window._transport._header_row
|
|
floor = row.height() - HeaderRow.BOTTOM
|
|
|
|
def bottom(widget):
|
|
return widget.mapTo(row, QPoint(0, widget.height())).y()
|
|
|
|
assert bottom(window.sidebar.library_button) == floor
|
|
assert bottom(window._library_view._search) == 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 - HeaderRow.LIFT)) <= 1
|
|
|
|
|
|
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_fills_what_the_gaps_leave(qapp, tmp_path):
|
|
window = _window(qapp, tmp_path, width=1920)
|
|
bar = window._transport
|
|
wide = bar._now_playing.width()
|
|
window.resize(1280, 500)
|
|
qapp.processEvents()
|
|
assert wide - bar._now_playing.width() == 640
|
|
window.resize(800, 500)
|
|
qapp.processEvents()
|
|
assert bar._now_playing.width() >= NOW_PLAYING_MIN
|
|
bpm = bar._bpm_button.parentWidget()
|
|
assert bar._now_playing.geometry().right() < bpm.geometry().left()
|
|
assert bpm.geometry().right() < bar.width()
|
|
|
|
|
|
def test_lists_have_bare_window_on_both_sides(qapp, tmp_path):
|
|
from lintunes.gui.sidebar import SIDEBAR_INSET
|
|
window = _window(qapp, tmp_path)
|
|
lists, view = window.sidebar.list_area, window._library_view
|
|
assert _gx(lists) - _gx(window) == SIDEBAR_INSET
|
|
assert _gx(window, window.width()) - _gx(view, view.width()) == SIDEBAR_INSET
|
|
|
|
|
|
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 GAP
|
|
window = _window(qapp, tmp_path)
|
|
bar = window._transport
|
|
for width in (900, 1280, 1920):
|
|
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:])]
|
|
# The same GAP everywhere, ends included, at every width.
|
|
left_end, right_end = edges[0][0], bar.width() - 1 - edges[-1][1]
|
|
assert gaps + [left_end, right_end] == [GAP] * 7
|
|
|
|
|
|
def test_gap_between_playlists_and_songs_matches_left_inset(qapp, tmp_path):
|
|
from lintunes.gui.sidebar import SIDEBAR_INSET
|
|
window = _window(qapp, tmp_path)
|
|
lists = window._sidebar.list_area
|
|
left = _x(lists, window)
|
|
gap = _x(window._content, window) - (left + lists.width())
|
|
assert left == gap == SIDEBAR_INSET
|