diff --git a/src/island.rs b/src/island.rs index d5ebfd5..0d66172 100644 --- a/src/island.rs +++ b/src/island.rs @@ -388,7 +388,8 @@ pub fn pill_face(monitor: &str, small: f32) -> Rectangle { let h = c::pill::height(); let player = shown(&media, island.selected.as_deref()); - let width = mix(c::pill::width(), small_width_for(player.is_some(), &art.path), small); + let small_w = small_width_for(player.is_some(), &art.path); + let width = mix(c::pill::width(), small_w, small); let live = player.is_some() && focused_monitor().as_deref().is_none_or(|name| name == monitor); let spectrum = live.then(Spectrum::read); @@ -398,21 +399,27 @@ pub fn pill_face(monitor: &str, small: f32) -> Rectangle { amane::request_frame(); } - let face = if small < 0.5 { + /* + * the pill's face fades out, then the small one in: they swap halfway, or with nothing + * playing as soon as the shape gets too narrow for the words, so these never vanish while seen + */ + let turn = if player.is_some() { 0.5 } else { ((c::pill::width() - idle_room()) / (c::pill::width() - small_w).max(1.0)).clamp(0.05, 0.5) }; + + let face = if small < turn { let big = match player { Some(player) => compact(player, playing(player, &island), &art.path, levels, width), None => idle_face(width), }; - veiled(big, width, h, h / 2.0, 1.0 - 2.0 * small, &colors) + veiled(big, width, h, h / 2.0, 1.0 - small / turn, &colors) } else { let little: Box = match player { Some(_) if !art.path.is_empty() => Box::new(cover(&art.path, h - 10.0, 1.5, false)), Some(player) => Box::new(pill_levels(playing(player, &island), levels)), - None => Box::new(icon(Glyph::Note, 15.0, theme::now().accent)), + None => Box::new(icon(Glyph::Note, IDLE_NOTE, theme::now().accent)), }; - veiled(Rectangle::new().width(width).height(h).align_child(Center, Center).child(Stack::new(vec![little])), width, h, h / 2.0, 2.0 * small - 1.0, &colors) + veiled(Rectangle::new().width(width).height(h).align_child(Center, Center).child(Stack::new(vec![little])), width, h, h / 2.0, (small - turn) / (1.0 - turn), &colors) }; surface::shell(width, h, h / 2.0, &colors, 0.0, face) @@ -668,12 +675,30 @@ fn idle(colors: &[Color; 3]) -> Rectangle { surface::shell(c::pill::width(), c::pill::height(), c::pill::height() / 2.0, colors, 0.0, idle_face(c::pill::width())) } +/* + * a note and "Nothing playing", centred. the words only where they fit with half the + * pill's height to spare at each end, else the note alone: an elided text takes the whole + * width, which put the note against the rim, and a pill narrower than the words did too + */ fn idle_face(width: f32) -> Rectangle { - Rectangle::new() - .width(width) - .height(c::pill::height()) - .align_child(Center, Center) - .child(Row::new(children![icon(Glyph::Note, 15.0, theme::now().accent), Text::new("Nothing playing").size(text::body()).color(theme::now().dim).elide()]).gap(8.0).align(Center)) + let note = icon(Glyph::Note, IDLE_NOTE, theme::now().accent); + let row = if idle_room() <= width { Row::new(children![note, idle_words()]) } else { Row::new(children![note]) }; + + Rectangle::new().width(width).height(c::pill::height()).align_child(Center, Center).child(row.gap(8.0).align(Center)) +} + +const IDLE_NOTE: f32 = 15.0; + +fn idle_words() -> Text { + Text::new("Nothing playing").size(text::body()).color(theme::now().dim) +} + +// the width the note and the words need, with half the pill's height to spare at each end +fn idle_room() -> f32 { + match idle_words().width() { + amane::Size::Fixed(words) => IDLE_NOTE + 8.0 + words + c::pill::height(), + amane::Size::Parent => f32::MAX, + } } // the pill, `width` wide: cover, title, the player's live levels