Esc closes the config window; a removed empty workspace closes up during the switch
Hyprland drops an empty workspace the moment it's left, so its number vanished and the row jumped before the disc slid. Its slot now stays for the slide, shrinking and fading, and the pill narrows with it.
This commit is contained in:
+7
-1
@@ -3,7 +3,7 @@ use std::collections::HashMap;
|
||||
use std::process::Command;
|
||||
|
||||
use amane::{
|
||||
Center, Color, Column, Cursor, End, Full, Padding, Rectangle, Row, ScrollArea, Service, SpaceBetween, Stack, Start, Text, TextInput, Weight, Widget, Window, children, close_window, open_window, window_size,
|
||||
Center, Color, Column, Cursor, End, Full, Key, Padding, Rectangle, Row, ScrollArea, Service, SpaceBetween, Stack, Start, Text, TextInput, Weight, Widget, Window, children, close_window, open_window, window_size,
|
||||
};
|
||||
|
||||
use crate::config::{self, Kind, Opt};
|
||||
@@ -283,6 +283,12 @@ pub fn view() -> Window {
|
||||
.title(TITLE)
|
||||
.size(1100.0, 760.0)
|
||||
.resizable(true)
|
||||
// Escape closes it, also from a field (a typed value only applies on Enter)
|
||||
.on_key(|key| {
|
||||
if key == Key::Escape {
|
||||
close_window(NAME);
|
||||
}
|
||||
})
|
||||
.child(
|
||||
Rectangle::new()
|
||||
.width(width)
|
||||
|
||||
+47
-14
@@ -60,7 +60,27 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
|
||||
.collect();
|
||||
|
||||
let count = here.len() as f32;
|
||||
let width = 2.0 * pill::inset() + count * pill::slot() + (count - 1.0).max(0.0) * pill::slot_gap();
|
||||
let step = pill::slot() + pill::slot_gap();
|
||||
|
||||
// ease in and out, with a slight stretch in the middle like a drop of ink
|
||||
let eased = |t: f32| t * t * (3.0 - 2.0 * t);
|
||||
|
||||
/*
|
||||
* hyprland removes an empty workspace the moment it's left. its slot stays for the
|
||||
* slide, fading and closing up, so the row and the pill narrow with the disc's move
|
||||
* instead of jumping first: (where it was, its label, how much of it is left, 1 to 0)
|
||||
*/
|
||||
let gone = switched.filter(|(from, _)| *from > 0 && here.iter().all(|workspace| workspace.id() != *from)).map(|(from, t)| {
|
||||
let at = here.iter().filter(|workspace| i64::from(workspace.index()) < from).count();
|
||||
|
||||
(at, from.to_string(), 1.0 - eased(t))
|
||||
});
|
||||
|
||||
let left = gone.as_ref().map_or(0.0, |(_, _, left)| *left);
|
||||
let width = 2.0 * pill::inset() + count * pill::slot() + (count - 1.0).max(0.0) * pill::slot_gap() + left * step;
|
||||
|
||||
// the window keeps the ghost's full room while it closes, so it isn't resized every frame
|
||||
let room = if gone.is_some() { width + (1.0 - left) * step } else { width };
|
||||
|
||||
let window = |window_w: f32| {
|
||||
LayerWindow::new()
|
||||
@@ -83,27 +103,26 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
|
||||
let tray = if peeking { None } else { tray::pill(&monitor.name, pill::left() + width + pill::tray_gap()) };
|
||||
let tray_w = tray.as_ref().map_or(0.0, |(_, tray_w)| pill::tray_gap() + tray_w);
|
||||
|
||||
let window = window(pill::left() + width + tray_w + island_pill::shadow());
|
||||
let window = window(pill::left() + room + tray_w + island_pill::shadow());
|
||||
|
||||
let mut slots: Vec<Box<dyn Widget>> = Vec::new();
|
||||
|
||||
/*
|
||||
* the focused workspace's accent is one disc under the row, so a change slides it from
|
||||
* the workspace before to this one (edge.rs times it); the slots themselves stay clear
|
||||
* the workspace before to this one (edge.rs times it); the slots themselves stay clear.
|
||||
* slots are placed by x in one stack, after a closing ghost by what's left of it
|
||||
*/
|
||||
let theme = theme::now();
|
||||
let slot_x = |index: usize| index as f32 * (pill::slot() + pill::slot_gap());
|
||||
let slot_x = |index: usize| index as f32 * step + gone.as_ref().filter(|(at, _, _)| index >= *at).map_or(0.0, |_| left * step);
|
||||
|
||||
let focused_at = here.iter().position(|workspace| workspace.focused());
|
||||
let came_from = switched.and_then(|(from, t)| here.iter().position(|workspace| workspace.id() == from).map(|at| (at, t)));
|
||||
let came_from = switched.and_then(|(from, t)| match &gone {
|
||||
Some((at, _, _)) => Some((*at as f32 * step, t)),
|
||||
None => here.iter().position(|workspace| workspace.id() == from).map(|at| (slot_x(at), t)),
|
||||
});
|
||||
|
||||
let highlight_x = match (focused_at, came_from) {
|
||||
(Some(to), Some((from, t))) => {
|
||||
// ease in and out, with a slight stretch in the middle like a drop of ink
|
||||
let eased = t * t * (3.0 - 2.0 * t);
|
||||
|
||||
Some(mix(slot_x(from), slot_x(to), eased))
|
||||
}
|
||||
(Some(to), Some((from_x, t))) => Some(mix(from_x, slot_x(to), eased(t))),
|
||||
(Some(to), None) => Some(slot_x(to)),
|
||||
_ => None,
|
||||
};
|
||||
@@ -114,7 +133,20 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
|
||||
amane::request_frame();
|
||||
}
|
||||
|
||||
for workspace in &here {
|
||||
// the ghost: its number shrinking into the gap it leaves
|
||||
if let Some((at, label, left)) = &gone {
|
||||
slots.push(Box::new(
|
||||
Rectangle::new()
|
||||
.width(pill::slot())
|
||||
.height(pill::slot())
|
||||
.align_child(Center, Center)
|
||||
.scale(*left)
|
||||
.translate(*at as f32 * step - (1.0 - left) * pill::slot() / 2.0, 0.0)
|
||||
.child(Text::new(label.as_str()).size(text::body()).color(Color::blend(CLEAR, theme.dim, *left))),
|
||||
));
|
||||
}
|
||||
|
||||
for (at, workspace) in here.iter().enumerate() {
|
||||
let id = workspace.id();
|
||||
let lit = hover.0.get(&id).map_or(0.0, Animation::value);
|
||||
|
||||
@@ -148,20 +180,21 @@ pub fn view(monitor: &Monitor) -> LayerWindow {
|
||||
.cursor(Pointer)
|
||||
.on_hover(move |inside| hovering(id, inside))
|
||||
.on_click(move |_| focus(id))
|
||||
.translate(slot_x(at), 0.0)
|
||||
.child(Text::new(label).size(text::body()).weight(weight).color(color)),
|
||||
));
|
||||
}
|
||||
|
||||
let row_w = width - 2.0 * pill::inset();
|
||||
|
||||
// the disc under the focused slot, a little wider while it's on its way
|
||||
// the disc under the focused slot, a little wider while it's on its way, then the slots over it
|
||||
let mut layers: Vec<Box<dyn Widget>> = Vec::new();
|
||||
|
||||
if let Some(x) = highlight_x {
|
||||
layers.push(Box::new(Rectangle::new().width(pill::slot() + stretch).height(pill::slot()).radius(Full).fill(theme.accent).translate(x - stretch / 2.0, 0.0)));
|
||||
}
|
||||
|
||||
layers.push(Box::new(Row::new(slots).gap(pill::slot_gap()).align(Center)));
|
||||
layers.extend(slots);
|
||||
|
||||
let pill = Rectangle::new()
|
||||
.width(width)
|
||||
|
||||
Reference in New Issue
Block a user