ZoomControl: owner-driven mode for content zoom

This commit is contained in:
ZacharyZhang-NY committed 2026-10-08 21:08:58 -04:00
1 parent 62dff57b85
commit 69265b4fd4
2 files changed
+57 -4

No files matched your search

+1 -1
View File
@@ -24,7 +24,7 @@ pub use dialogs::{AboutDialog, SplashScreen};
pub use frame::ResizeBorder;
pub use native::{TrayIcon, TrayItem, dock_badge, set_dock_badge};
pub(crate) use status::connectivity_dot;
pub use status::{Connectivity, OfflineIndicator, ZoomControl};
pub use status::{Connectivity, OfflineIndicator, ZoomControl, ZoomStep};
pub use switcher::WindowSwitcher;
pub use tabs::{TabBar, WindowTab};
pub use update::{UpdateBanner, UpdateDialog, UpdateState};
+56 -3
View File
@@ -1,4 +1,4 @@
use std::time::Duration;
use std::{rc::Rc, time::Duration};
use gpui::{
Animation, AnimationExt, AnyElement, App, ElementId, IntoElement, ParentElement, RenderOnce,
@@ -165,15 +165,32 @@ fn step(current: u32, direction: i8) -> Option<u32> {
}
}
/// Minus, percentage, plus. Scales the window's rem size, and all it holds.
/// A press on a `ZoomControl` its owner handles.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ZoomStep {
Out,
In,
Reset,
}
type OnZoom = Rc<dyn Fn(ZoomStep, &mut Window, &mut App)>;
/// Minus, percentage, plus. Scales the window's rem size, and all it holds, unless an owner zooms its own content.
#[derive(IntoElement)]
pub struct ZoomControl {
id: ElementId,
owned: Option<(u32, OnZoom)>,
}
impl ZoomControl {
pub fn new(id: impl Into<ElementId>) -> Self {
Self { id: id.into() }
Self { id: id.into(), owned: None }
}
/// Shows `percent` and hands each press to `on_zoom`.
pub fn owned(mut self, percent: u32, on_zoom: impl Fn(ZoomStep, &mut Window, &mut App) + 'static) -> Self {
self.owned = Some((percent, Rc::new(on_zoom)));
self
}
}
@@ -187,6 +204,9 @@ fn apply(percent: u32, window: &mut Window, cx: &mut App) {
impl RenderOnce for ZoomControl {
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
let theme = cx.theme();
if let Some((percent, on_zoom)) = self.owned {
return owned(self.id, percent, on_zoom, cx).into_any_element();
}
let percent = (window.rem_size() / theme.base_rem() * 100.0).round() as u32;
let (down, up) = (step(percent, -1), step(percent, 1));
div()
@@ -226,9 +246,42 @@ impl RenderOnce for ZoomControl {
button.on_click(move |_, window, cx| apply(next, window, cx))
}),
)
.into_any_element()
}
}
/// The owner's zoom: its percent, its steps.
fn owned(id: ElementId, percent: u32, on_zoom: OnZoom, cx: &App) -> impl IntoElement {
let theme = cx.theme();
let press = |step: ZoomStep| {
let on_zoom = on_zoom.clone();
move |_: &gpui::ClickEvent, window: &mut Window, cx: &mut App| on_zoom(step, window, cx)
};
div()
.id(id)
.flex()
.flex_none()
.items_center()
.gap_0p5()
.child(IconButton::new("zoom-out", IconName::ZoomOut).size(ControlSize::Sm).on_click(press(ZoomStep::Out)))
.child(
div()
.id("zoom-reset")
.flex()
.items_center()
.justify_center()
.min_w(theme.control_height(ControlSize::Lg) * 1.5)
.h(theme.control_height(ControlSize::Sm))
.rounded_full()
.cursor_pointer()
.hover(|style| style.bg(theme.colors.hover))
.on_click(press(ZoomStep::Reset))
.child(AnimatedNumber::new("zoom-value", percent as f64).size(TextSize::Sm))
.child(div().text_size(theme.text_size(TextSize::Sm)).child("%")),
)
.child(IconButton::new("zoom-in", IconName::ZoomIn).size(ControlSize::Sm).on_click(press(ZoomStep::In)))
}
#[cfg(test)]
mod tests {
use super::step;