mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-23 18:32:17 +00:00
Implement zooming for panes and docks
This commit is contained in:
parent
c03e470fe6
commit
adf361b374
5 changed files with 122 additions and 63 deletions
|
@ -220,7 +220,7 @@
|
|||
"alt-cmd-c": "search::ToggleCaseSensitive",
|
||||
"alt-cmd-w": "search::ToggleWholeWord",
|
||||
"alt-cmd-r": "search::ToggleRegex",
|
||||
"shift-escape": "pane::ToggleZoom"
|
||||
"shift-escape": "workspace::ToggleZoom"
|
||||
}
|
||||
},
|
||||
// Bindings from VS Code
|
||||
|
|
|
@ -33,11 +33,8 @@ use crate::{
|
|||
rect::RectF,
|
||||
vector::{vec2f, Vector2F},
|
||||
},
|
||||
json,
|
||||
platform::MouseButton,
|
||||
scene::MouseDown,
|
||||
Action, EventContext, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext,
|
||||
WeakViewHandle, WindowContext,
|
||||
json, Action, LayoutContext, SceneBuilder, SizeConstraint, View, ViewContext, WeakViewHandle,
|
||||
WindowContext,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use collections::HashMap;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{StatusItemView, Workspace};
|
||||
use crate::{StatusItemView, ToggleZoom, Workspace};
|
||||
use context_menu::{ContextMenu, ContextMenuItem};
|
||||
use gpui::{
|
||||
elements::*, impl_actions, platform::CursorStyle, platform::MouseButton, AnyViewHandle,
|
||||
|
@ -10,7 +10,7 @@ use settings::Settings;
|
|||
use std::rc::Rc;
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
cx.capture_action(Dock::toggle_zoom);
|
||||
cx.add_action(Dock::toggle_zoom);
|
||||
}
|
||||
|
||||
pub trait Panel: View {
|
||||
|
@ -98,6 +98,10 @@ impl From<&dyn PanelHandle> for AnyViewHandle {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum Event {
|
||||
ZoomIn,
|
||||
}
|
||||
|
||||
pub struct Dock {
|
||||
position: DockPosition,
|
||||
panel_entries: Vec<PanelEntry>,
|
||||
|
@ -141,6 +145,7 @@ struct PanelEntry {
|
|||
panel: Rc<dyn PanelHandle>,
|
||||
size: f32,
|
||||
context_menu: ViewHandle<ContextMenu>,
|
||||
zoomed: bool,
|
||||
_subscriptions: [Subscription; 2],
|
||||
}
|
||||
|
||||
|
@ -187,6 +192,25 @@ impl Dock {
|
|||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn set_zoomed(&mut self, zoomed: bool, cx: &mut ViewContext<Self>) {
|
||||
for (ix, entry) in self.panel_entries.iter_mut().enumerate() {
|
||||
if ix == self.active_panel_index && entry.panel.can_zoom(cx) {
|
||||
entry.zoomed = zoomed;
|
||||
} else {
|
||||
entry.zoomed = false;
|
||||
}
|
||||
}
|
||||
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn toggle_zoom(&mut self, _: &ToggleZoom, cx: &mut ViewContext<Self>) {
|
||||
cx.propagate_action();
|
||||
if !self.active_entry().map_or(false, |entry| entry.zoomed) {
|
||||
cx.emit(Event::ZoomIn);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_panel<T: Panel>(&mut self, panel: ViewHandle<T>, cx: &mut ViewContext<Self>) {
|
||||
let subscriptions = [
|
||||
cx.observe(&panel, |_, _, cx| cx.notify()),
|
||||
|
@ -214,6 +238,7 @@ impl Dock {
|
|||
self.panel_entries.push(PanelEntry {
|
||||
panel: Rc::new(panel),
|
||||
size,
|
||||
zoomed: false,
|
||||
context_menu: cx.add_view(|cx| {
|
||||
let mut menu = ContextMenu::new(dock_view_id, cx);
|
||||
menu.set_position_mode(OverlayPositionMode::Local);
|
||||
|
@ -260,10 +285,22 @@ impl Dock {
|
|||
}
|
||||
|
||||
pub fn active_panel(&self) -> Option<&Rc<dyn PanelHandle>> {
|
||||
let entry = self.active_entry()?;
|
||||
Some(&entry.panel)
|
||||
}
|
||||
|
||||
fn active_entry(&self) -> Option<&PanelEntry> {
|
||||
if self.is_open {
|
||||
self.panel_entries
|
||||
.get(self.active_panel_index)
|
||||
.map(|entry| &entry.panel)
|
||||
self.panel_entries.get(self.active_panel_index)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zoomed_panel(&self) -> Option<AnyViewHandle> {
|
||||
let entry = self.active_entry()?;
|
||||
if entry.zoomed {
|
||||
Some(entry.panel.as_any().clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -305,7 +342,7 @@ impl Dock {
|
|||
}
|
||||
|
||||
impl Entity for Dock {
|
||||
type Event = ();
|
||||
type Event = Event;
|
||||
}
|
||||
|
||||
impl View for Dock {
|
||||
|
@ -314,18 +351,22 @@ impl View for Dock {
|
|||
}
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
|
||||
if let Some(active_panel) = self.active_panel() {
|
||||
let size = self.active_panel_size().unwrap();
|
||||
let style = &cx.global::<Settings>().theme.workspace.dock;
|
||||
ChildView::new(active_panel.as_any(), cx)
|
||||
.contained()
|
||||
.with_style(style.container)
|
||||
.resizable(
|
||||
self.position.to_resize_handle_side(),
|
||||
size,
|
||||
|dock: &mut Self, size, cx| dock.resize_active_panel(size, cx),
|
||||
)
|
||||
.into_any()
|
||||
if let Some(active_entry) = self.active_entry() {
|
||||
if active_entry.zoomed {
|
||||
Empty::new().into_any()
|
||||
} else {
|
||||
let size = self.active_panel_size().unwrap();
|
||||
let style = &cx.global::<Settings>().theme.workspace.dock;
|
||||
ChildView::new(active_entry.panel.as_any(), cx)
|
||||
.contained()
|
||||
.with_style(style.container)
|
||||
.resizable(
|
||||
self.position.to_resize_handle_side(),
|
||||
size,
|
||||
|dock: &mut Self, size, cx| dock.resize_active_panel(size, cx),
|
||||
)
|
||||
.into_any()
|
||||
}
|
||||
} else {
|
||||
Empty::new().into_any()
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@ mod dragged_item_receiver;
|
|||
|
||||
use super::{ItemHandle, SplitDirection};
|
||||
use crate::{
|
||||
item::WeakItemHandle, toolbar::Toolbar, Item, NewFile, NewSearch, NewTerminal, Workspace,
|
||||
item::WeakItemHandle, toolbar::Toolbar, Item, NewFile, NewSearch, NewTerminal, ToggleZoom,
|
||||
Workspace,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use collections::{HashMap, HashSet, VecDeque};
|
||||
|
@ -69,7 +70,6 @@ actions!(
|
|||
SplitUp,
|
||||
SplitRight,
|
||||
SplitDown,
|
||||
ToggleZoom,
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -135,7 +135,6 @@ pub enum Event {
|
|||
ChangeItemTitle,
|
||||
Focus,
|
||||
ZoomIn,
|
||||
ZoomOut,
|
||||
}
|
||||
|
||||
pub struct Pane {
|
||||
|
@ -662,9 +661,8 @@ impl Pane {
|
|||
}
|
||||
|
||||
pub fn toggle_zoom(&mut self, _: &ToggleZoom, cx: &mut ViewContext<Self>) {
|
||||
if self.zoomed {
|
||||
cx.emit(Event::ZoomOut);
|
||||
} else {
|
||||
cx.propagate_action();
|
||||
if !self.zoomed {
|
||||
cx.emit(Event::ZoomIn);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,7 +119,8 @@ actions!(
|
|||
NewSearch,
|
||||
Feedback,
|
||||
Restart,
|
||||
Welcome
|
||||
Welcome,
|
||||
ToggleZoom,
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -181,6 +182,7 @@ pub type WorkspaceId = i64;
|
|||
impl_actions!(workspace, [ActivatePane]);
|
||||
|
||||
pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
|
||||
dock::init(cx);
|
||||
pane::init(cx);
|
||||
notifications::init(cx);
|
||||
|
||||
|
@ -230,6 +232,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
|
|||
},
|
||||
);
|
||||
cx.add_action(Workspace::toggle_panel);
|
||||
cx.add_action(Workspace::toggle_zoom);
|
||||
cx.add_action(Workspace::focus_center);
|
||||
cx.add_action(|workspace: &mut Workspace, _: &ActivatePreviousPane, cx| {
|
||||
workspace.activate_previous_pane(cx)
|
||||
|
@ -441,7 +444,6 @@ pub struct Workspace {
|
|||
weak_self: WeakViewHandle<Self>,
|
||||
remote_entity_subscription: Option<client::Subscription>,
|
||||
modal: Option<AnyViewHandle>,
|
||||
zoomed: Option<AnyViewHandle>,
|
||||
center: PaneGroup,
|
||||
left_dock: ViewHandle<Dock>,
|
||||
bottom_dock: ViewHandle<Dock>,
|
||||
|
@ -593,7 +595,7 @@ impl Workspace {
|
|||
active_call = Some((call, subscriptions));
|
||||
}
|
||||
|
||||
let subscriptions = vec![
|
||||
let mut subscriptions = vec![
|
||||
cx.observe_fullscreen(|_, _, cx| cx.notify()),
|
||||
cx.observe_window_activation(Self::on_window_activation_changed),
|
||||
cx.observe_window_bounds(move |_, mut bounds, display, cx| {
|
||||
|
@ -613,24 +615,14 @@ impl Workspace {
|
|||
.spawn(DB.set_window_bounds(workspace_id, bounds, display))
|
||||
.detach_and_log_err(cx);
|
||||
}),
|
||||
cx.observe(&left_dock, |this, _, cx| {
|
||||
this.serialize_workspace(cx);
|
||||
cx.notify();
|
||||
}),
|
||||
cx.observe(&bottom_dock, |this, _, cx| {
|
||||
this.serialize_workspace(cx);
|
||||
cx.notify();
|
||||
}),
|
||||
cx.observe(&right_dock, |this, _, cx| {
|
||||
this.serialize_workspace(cx);
|
||||
cx.notify();
|
||||
}),
|
||||
];
|
||||
subscriptions.extend(Self::register_dock(&left_dock, cx));
|
||||
subscriptions.extend(Self::register_dock(&bottom_dock, cx));
|
||||
subscriptions.extend(Self::register_dock(&right_dock, cx));
|
||||
|
||||
let mut this = Workspace {
|
||||
weak_self: weak_handle.clone(),
|
||||
modal: None,
|
||||
zoomed: None,
|
||||
center: PaneGroup::new(center_pane.clone()),
|
||||
panes: vec![center_pane.clone()],
|
||||
panes_by_item: Default::default(),
|
||||
|
@ -1305,14 +1297,16 @@ impl Workspace {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn zoom_in(&mut self, view: AnyViewHandle, cx: &mut ViewContext<Self>) {
|
||||
self.zoomed = Some(view);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn zoom_out(&mut self, cx: &mut ViewContext<Self>) {
|
||||
self.zoomed.take();
|
||||
cx.notify();
|
||||
fn zoomed(&self, cx: &AppContext) -> Option<AnyViewHandle> {
|
||||
self.left_dock
|
||||
.read(cx)
|
||||
.zoomed_panel()
|
||||
.or(self.bottom_dock.read(cx).zoomed_panel())
|
||||
.or(self.right_dock.read(cx).zoomed_panel())
|
||||
.or_else(|| {
|
||||
let pane = self.panes.iter().find(|pane| pane.read(cx).is_zoomed())?;
|
||||
Some(pane.clone().into_any())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn items<'a>(
|
||||
|
@ -1470,11 +1464,46 @@ impl Workspace {
|
|||
cx.notify();
|
||||
}
|
||||
|
||||
fn toggle_zoom(&mut self, _: &ToggleZoom, cx: &mut ViewContext<Self>) {
|
||||
// Any time the zoom is toggled we will zoom out all panes and docks. Then,
|
||||
// the dock or pane that was zoomed will emit an event to zoom itself back in.
|
||||
self.zoom_out(cx);
|
||||
}
|
||||
|
||||
fn zoom_out(&mut self, cx: &mut ViewContext<Self>) {
|
||||
for pane in &self.panes {
|
||||
pane.update(cx, |pane, cx| pane.set_zoomed(false, cx));
|
||||
}
|
||||
|
||||
self.left_dock
|
||||
.update(cx, |dock, cx| dock.set_zoomed(false, cx));
|
||||
self.bottom_dock
|
||||
.update(cx, |dock, cx| dock.set_zoomed(false, cx));
|
||||
self.right_dock
|
||||
.update(cx, |dock, cx| dock.set_zoomed(false, cx));
|
||||
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn focus_center(&mut self, _: &menu::Cancel, cx: &mut ViewContext<Self>) {
|
||||
cx.focus_self();
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn register_dock(dock: &ViewHandle<Dock>, cx: &mut ViewContext<Self>) -> [Subscription; 2] {
|
||||
[
|
||||
cx.observe(dock, |this, _, cx| {
|
||||
this.serialize_workspace(cx);
|
||||
cx.notify();
|
||||
}),
|
||||
cx.subscribe(dock, |_, dock, event, cx| {
|
||||
dock.update(cx, |dock, cx| match event {
|
||||
dock::Event::ZoomIn => dock.set_zoomed(true, cx),
|
||||
})
|
||||
}),
|
||||
]
|
||||
}
|
||||
|
||||
fn add_pane(&mut self, cx: &mut ViewContext<Self>) -> ViewHandle<Pane> {
|
||||
let pane =
|
||||
cx.add_view(|cx| Pane::new(self.weak_handle(), self.app_state.background_actions, cx));
|
||||
|
@ -1699,13 +1728,7 @@ impl Workspace {
|
|||
}
|
||||
pane::Event::ZoomIn => {
|
||||
pane.update(cx, |pane, cx| pane.set_zoomed(true, cx));
|
||||
self.zoom_in(pane.into_any(), cx);
|
||||
}
|
||||
pane::Event::ZoomOut => {
|
||||
if self.zoomed.as_ref().map_or(false, |zoomed| *zoomed == pane) {
|
||||
pane.update(cx, |pane, cx| pane.set_zoomed(false, cx));
|
||||
self.zoom_out(cx);
|
||||
}
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2757,10 +2780,10 @@ impl View for Workspace {
|
|||
})
|
||||
.with_child(Overlay::new(
|
||||
Stack::new()
|
||||
.with_children(self.zoomed.as_ref().map(|zoomed| {
|
||||
.with_children(self.zoomed(cx).map(|zoomed| {
|
||||
enum ZoomBackground {}
|
||||
|
||||
ChildView::new(zoomed, cx)
|
||||
ChildView::new(&zoomed, cx)
|
||||
.contained()
|
||||
.with_style(theme.workspace.zoomed_foreground)
|
||||
.aligned()
|
||||
|
|
Loading…
Reference in a new issue