yoda: fisheye magnification for dock hover (phase B v2 / c)
Replaces the binary 1.3× hover with a true gaussian bell curve — the hovered icon still peaks at ~1.35×, but the ±1 neighbours also bulge noticeably, ±2 a bit, and ±3+ relax to 1.0×. Footprint ~5 icons wide, matching the macOS Dock fisheye feel. Implementation in fn icon_scale_for(id): - Reads the hovered icon's and the current icon's bounds from self.rectangles (already populated by the existing RectangleTracker subscription — no new plumbing). - Distance = |this_center - hovered_center| along the panel's long axis (horizontal for Top/Bottom anchors, vertical for Left/Right). - sigma = hovered_extent * 1.4 so the bell's half-width matches one icon width (neighbors clearly pulled, far icons untouched). - scale = 1.0 + PEAK * exp(-(d/sigma)²) with PEAK = 0.35. - Falls back to binary 1.35×/1.0× when rectangle data isn't populated yet (first render / resize) — visibly responsive even before the tracker catches up. No widget signature changes vs v1, just a smarter formula. All five as_icon call sites already pass the result of icon_scale_for so this update propagates everywhere. Still on the TODO list: smooth animation (b). Right now icon→icon transitions snap instantly; a smoothed_hover_center + tick subscription would lerp it. Deferred to a follow-up commit.
This commit is contained in:
parent
d090e60370
commit
8fc11581ad
1 changed files with 53 additions and 6 deletions
|
|
@ -688,15 +688,62 @@ impl CosmicAppList {
|
|||
.collect::<Vec<_>>();
|
||||
}
|
||||
|
||||
/// Yoda: macOS-Tahoe-style hover magnification. Returns the icon
|
||||
/// size multiplier for a given dock item — 1.3× when the pointer
|
||||
/// is over it, 1.0× otherwise. Called from the view() icon builders.
|
||||
/// Yoda: macOS-Tahoe fisheye-style magnification. Returns the
|
||||
/// per-icon size multiplier based on the distance (in pixels) from
|
||||
/// the currently hovered icon's center to this icon's center.
|
||||
///
|
||||
/// Uses a gaussian bell curve so the hovered icon peaks at
|
||||
/// 1.0 + PEAK, immediate neighbors still bulge noticeably, and icons
|
||||
/// further away relax back to 1.0× — that's the smooth neighbour
|
||||
/// deformation people associate with the macOS Dock.
|
||||
///
|
||||
/// Falls back to binary 1.3×/1.0× when the rectangle tracker hasn't
|
||||
/// populated yet (first render, or just after layout changes).
|
||||
fn icon_scale_for(&self, id: &DockItemId) -> f32 {
|
||||
if self.hovered_dock_item.as_ref() == Some(id) {
|
||||
1.3
|
||||
const PEAK: f32 = 0.35;
|
||||
// sigma expressed in multiples of the hovered icon's size —
|
||||
// 1.4 means the ±1 neighbors sit ~0.7σ away and still bulge
|
||||
// visibly, while ±3+ has collapsed to ~1.0× (fisheye footprint
|
||||
// close to 5 icons wide, Tahoe-ish).
|
||||
const SIGMA_FACTOR: f32 = 1.4;
|
||||
|
||||
let Some(hovered_id) = self.hovered_dock_item.as_ref() else {
|
||||
return 1.0;
|
||||
};
|
||||
|
||||
// Without tracker data we can't compute distance — still peak on
|
||||
// the hovered one so something visibly responds immediately.
|
||||
let (Some(hovered_rect), Some(this_rect)) =
|
||||
(self.rectangles.get(hovered_id), self.rectangles.get(id))
|
||||
else {
|
||||
return if id == hovered_id { 1.0 + PEAK } else { 1.0 };
|
||||
};
|
||||
|
||||
let is_horizontal = matches!(
|
||||
self.core.applet.anchor,
|
||||
PanelAnchor::Top | PanelAnchor::Bottom
|
||||
);
|
||||
let hovered_center = if is_horizontal {
|
||||
hovered_rect.x + hovered_rect.width / 2.0
|
||||
} else {
|
||||
1.0
|
||||
hovered_rect.y + hovered_rect.height / 2.0
|
||||
};
|
||||
let this_center = if is_horizontal {
|
||||
this_rect.x + this_rect.width / 2.0
|
||||
} else {
|
||||
this_rect.y + this_rect.height / 2.0
|
||||
};
|
||||
let distance = (this_center - hovered_center).abs();
|
||||
let icon_extent = if is_horizontal {
|
||||
hovered_rect.width
|
||||
} else {
|
||||
hovered_rect.height
|
||||
}
|
||||
.max(1.0);
|
||||
let sigma = icon_extent * SIGMA_FACTOR;
|
||||
// exp(-t²) bell curve, t = distance / sigma
|
||||
let t = distance / sigma;
|
||||
1.0 + PEAK * (-t * t).exp()
|
||||
}
|
||||
|
||||
fn is_on_current_monitor_and_workspace(&self, toplevel_info: &ToplevelInfo) -> bool {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue