Merge remote-tracking branch 'origin/main' into cache

# Conflicts:
#	crates/copilot/src/sign_in.rs
#	crates/gpui/src/window.rs
#	crates/workspace/src/pane_group.rs
This commit is contained in:
Antonio Scandurra 2024-01-10 22:57:47 +01:00
commit 1c260e6dfd
216 changed files with 4218 additions and 2389 deletions

View file

@ -28,7 +28,7 @@ pub trait Panel: FocusableView + EventEmitter<PanelEvent> {
fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext<Self>);
fn size(&self, cx: &WindowContext) -> Pixels;
fn set_size(&mut self, size: Option<Pixels>, cx: &mut ViewContext<Self>);
fn icon(&self, cx: &WindowContext) -> Option<ui::Icon>;
fn icon(&self, cx: &WindowContext) -> Option<ui::IconName>;
fn icon_tooltip(&self, cx: &WindowContext) -> Option<&'static str>;
fn toggle_action(&self) -> Box<dyn Action>;
fn icon_label(&self, _: &WindowContext) -> Option<String> {
@ -52,7 +52,7 @@ pub trait PanelHandle: Send + Sync {
fn set_active(&self, active: bool, cx: &mut WindowContext);
fn size(&self, cx: &WindowContext) -> Pixels;
fn set_size(&self, size: Option<Pixels>, cx: &mut WindowContext);
fn icon(&self, cx: &WindowContext) -> Option<ui::Icon>;
fn icon(&self, cx: &WindowContext) -> Option<ui::IconName>;
fn icon_tooltip(&self, cx: &WindowContext) -> Option<&'static str>;
fn toggle_action(&self, cx: &WindowContext) -> Box<dyn Action>;
fn icon_label(&self, cx: &WindowContext) -> Option<String>;
@ -104,7 +104,7 @@ where
self.update(cx, |this, cx| this.set_size(size, cx))
}
fn icon(&self, cx: &WindowContext) -> Option<ui::Icon> {
fn icon(&self, cx: &WindowContext) -> Option<ui::IconName> {
self.read(cx).icon(cx)
}
@ -167,15 +167,6 @@ impl DockPosition {
}
}
// todo!()
// fn to_resize_handle_side(self) -> HandleSide {
// match self {
// Self::Left => HandleSide::Right,
// Self::Bottom => HandleSide::Top,
// Self::Right => HandleSide::Left,
// }
// }
pub fn axis(&self) -> Axis {
match self {
Self::Left | Self::Right => Axis::Horizontal,
@ -186,8 +177,6 @@ impl DockPosition {
struct PanelEntry {
panel: Arc<dyn PanelHandle>,
// todo!()
// context_menu: View<ContextMenu>,
_subscriptions: [Subscription; 2],
}
@ -265,12 +254,6 @@ impl Dock {
self.is_open
}
// todo!()
// pub fn has_focus(&self, cx: &WindowContext) -> bool {
// self.visible_panel()
// .map_or(false, |panel| panel.has_focus(cx))
// }
pub fn panel<T: Panel>(&self) -> Option<View<T>> {
self.panel_entries
.iter()
@ -395,7 +378,6 @@ impl Dock {
})
.ok();
}
// todo!() we do not use this event in the production code (even in zed1), remove it
PanelEvent::Activate => {
if let Some(ix) = this
.panel_entries
@ -418,16 +400,8 @@ impl Dock {
}),
];
// todo!()
// let dock_view_id = cx.view_id();
self.panel_entries.push(PanelEntry {
panel: Arc::new(panel),
// todo!()
// context_menu: cx.add_view(|cx| {
// let mut menu = ContextMenu::new(dock_view_id, cx);
// menu.set_position_mode(OverlayPositionMode::Local);
// menu
// }),
_subscriptions: subscriptions,
});
cx.notify()
@ -619,7 +593,6 @@ impl PanelButtons {
impl Render for PanelButtons {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
// todo!()
let dock = self.dock.read(cx);
let active_index = dock.active_panel_index;
let is_open = dock.is_open;
@ -775,7 +748,7 @@ pub mod test {
self.size = size.unwrap_or(px(300.));
}
fn icon(&self, _: &WindowContext) -> Option<ui::Icon> {
fn icon(&self, _: &WindowContext) -> Option<ui::IconName> {
None
}

View file

@ -60,7 +60,13 @@ impl ClosePosition {
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
pub struct ItemSettingsContent {
/// Whether to show the Git file status on a tab item.
///
/// Default: true
git_status: Option<bool>,
/// Position of the close button in a tab.
///
/// Default: right
close_position: Option<ClosePosition>,
}

View file

@ -101,6 +101,10 @@ impl ModalLayer {
let active_modal = self.active_modal.as_ref()?;
active_modal.modal.view().downcast::<V>().ok()
}
pub fn has_active_modal(&self) -> bool {
self.active_modal.is_some()
}
}
impl Render for ModalLayer {

View file

@ -2,14 +2,12 @@ use crate::{Toast, Workspace};
use collections::HashMap;
use gpui::{
AnyView, AppContext, AsyncWindowContext, DismissEvent, Entity, EntityId, EventEmitter, Render,
View, ViewContext, VisualContext,
Task, View, ViewContext, VisualContext, WindowContext,
};
use std::{any::TypeId, ops::DerefMut};
pub fn init(cx: &mut AppContext) {
cx.set_global(NotificationTracker::new());
// todo!()
// simple_message_notification::init(cx);
}
pub trait Notification: EventEmitter<DismissEvent> + Render {}
@ -175,7 +173,7 @@ pub mod simple_message_notification {
};
use std::sync::Arc;
use ui::prelude::*;
use ui::{h_stack, v_stack, Button, Icon, IconElement, Label, StyledExt};
use ui::{h_stack, v_stack, Button, Icon, IconName, Label, StyledExt};
pub struct MessageNotification {
message: SharedString,
@ -230,7 +228,7 @@ pub mod simple_message_notification {
.child(
div()
.id("cancel")
.child(IconElement::new(Icon::Close))
.child(Icon::new(IconName::Close))
.cursor_pointer()
.on_click(cx.listener(|this, _, cx| this.dismiss(cx))),
),
@ -247,105 +245,6 @@ pub mod simple_message_notification {
}))
}
}
// todo!()
// impl View for MessageNotification {
// fn ui_name() -> &'static str {
// "MessageNotification"
// }
// fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> gpui::AnyElement<Self> {
// let theme = theme::current(cx).clone();
// let theme = &theme.simple_message_notification;
// enum MessageNotificationTag {}
// let click_message = self.click_message.clone();
// let message = match &self.message {
// NotificationMessage::Text(text) => {
// Text::new(text.to_owned(), theme.message.text.clone()).into_any()
// }
// NotificationMessage::Element(e) => e(theme.message.text.clone(), cx),
// };
// let on_click = self.on_click.clone();
// let has_click_action = on_click.is_some();
// Flex::column()
// .with_child(
// Flex::row()
// .with_child(
// message
// .contained()
// .with_style(theme.message.container)
// .aligned()
// .top()
// .left()
// .flex(1., true),
// )
// .with_child(
// MouseEventHandler::new::<Cancel, _>(0, cx, |state, _| {
// let style = theme.dismiss_button.style_for(state);
// Svg::new("icons/x.svg")
// .with_color(style.color)
// .constrained()
// .with_width(style.icon_width)
// .aligned()
// .contained()
// .with_style(style.container)
// .constrained()
// .with_width(style.button_width)
// .with_height(style.button_width)
// })
// .with_padding(Padding::uniform(5.))
// .on_click(MouseButton::Left, move |_, this, cx| {
// this.dismiss(&Default::default(), cx);
// })
// .with_cursor_style(CursorStyle::PointingHand)
// .aligned()
// .constrained()
// .with_height(cx.font_cache().line_height(theme.message.text.font_size))
// .aligned()
// .top()
// .flex_float(),
// ),
// )
// .with_children({
// click_message
// .map(|click_message| {
// MouseEventHandler::new::<MessageNotificationTag, _>(
// 0,
// cx,
// |state, _| {
// let style = theme.action_message.style_for(state);
// Flex::row()
// .with_child(
// Text::new(click_message, style.text.clone())
// .contained()
// .with_style(style.container),
// )
// .contained()
// },
// )
// .on_click(MouseButton::Left, move |_, this, cx| {
// if let Some(on_click) = on_click.as_ref() {
// on_click(cx);
// this.dismiss(&Default::default(), cx);
// }
// })
// // Since we're not using a proper overlay, we have to capture these extra events
// .on_down(MouseButton::Left, |_, _, _| {})
// .on_up(MouseButton::Left, |_, _, _| {})
// .with_cursor_style(if has_click_action {
// CursorStyle::PointingHand
// } else {
// CursorStyle::Arrow
// })
// })
// .into_iter()
// })
// .into_any()
// }
// }
}
pub trait NotifyResultExt {
@ -393,3 +292,18 @@ where
}
}
}
pub trait NotifyTaskExt {
fn detach_and_notify_err(self, cx: &mut WindowContext);
}
impl<R, E> NotifyTaskExt for Task<Result<R, E>>
where
E: std::fmt::Debug + 'static,
R: 'static,
{
fn detach_and_notify_err(self, cx: &mut WindowContext) {
cx.spawn(|mut cx| async move { self.await.notify_async_err(&mut cx) })
.detach();
}
}

View file

@ -31,8 +31,8 @@ use std::{
use theme::ThemeSettings;
use ui::{
prelude::*, right_click_menu, ButtonSize, Color, Icon, IconButton, IconSize, Indicator, Label,
Tab, TabBar, TabPosition, Tooltip,
prelude::*, right_click_menu, ButtonSize, Color, IconButton, IconName, IconSize, Indicator,
Label, Tab, TabBar, TabPosition, Tooltip,
};
use ui::{v_stack, ContextMenu};
use util::{maybe, truncate_and_remove_front, ResultExt};
@ -242,87 +242,6 @@ pub struct DraggedTab {
pub is_active: bool,
}
// pub struct DraggedItem {
// pub handle: Box<dyn ItemHandle>,
// pub pane: WeakView<Pane>,
// }
// pub enum ReorderBehavior {
// None,
// MoveAfterActive,
// MoveToIndex(usize),
// }
// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
// enum TabBarContextMenuKind {
// New,
// Split,
// }
// struct TabBarContextMenu {
// kind: TabBarContextMenuKind,
// handle: View<ContextMenu>,
// }
// impl TabBarContextMenu {
// fn handle_if_kind(&self, kind: TabBarContextMenuKind) -> Option<View<ContextMenu>> {
// if self.kind == kind {
// return Some(self.handle.clone());
// }
// None
// }
// }
// #[allow(clippy::too_many_arguments)]
// fn nav_button<A: Action, F: 'static + Fn(&mut Pane, &mut ViewContext<Pane>)>(
// svg_path: &'static str,
// style: theme::Interactive<theme2::IconButton>,
// nav_button_height: f32,
// tooltip_style: TooltipStyle,
// enabled: bool,
// on_click: F,
// tooltip_action: A,
// action_name: &str,
// cx: &mut ViewContext<Pane>,
// ) -> AnyElement<Pane> {
// MouseEventHandler::new::<A, _>(0, cx, |state, _| {
// let style = if enabled {
// style.style_for(state)
// } else {
// style.disabled_style()
// };
// Svg::new(svg_path)
// .with_color(style.color)
// .constrained()
// .with_width(style.icon_width)
// .aligned()
// .contained()
// .with_style(style.container)
// .constrained()
// .with_width(style.button_width)
// .with_height(nav_button_height)
// .aligned()
// .top()
// })
// .with_cursor_style(if enabled {
// CursorStyle::PointingHand
// } else {
// CursorStyle::default()
// })
// .on_click(MouseButton::Left, move |_, toolbar, cx| {
// on_click(toolbar, cx)
// })
// .with_tooltip::<A>(
// 0,
// action_name.to_string(),
// Some(Box::new(tooltip_action)),
// tooltip_style,
// cx,
// )
// .contained()
// .into_any_named("nav button")
// }
impl EventEmitter<Event> for Pane {}
impl Pane {
@ -333,13 +252,6 @@ impl Pane {
can_drop_predicate: Option<Arc<dyn Fn(&dyn Any, &mut WindowContext) -> bool + 'static>>,
cx: &mut ViewContext<Self>,
) -> Self {
// todo!("context menu")
// let pane_view_id = cx.view_id();
// let context_menu = cx.build_view(|cx| ContextMenu::new(pane_view_id, cx));
// context_menu.update(cx, |menu, _| {
// menu.set_position_mode(OverlayPositionMode::Local)
// });
//
let focus_handle = cx.focus_handle();
let subscriptions = vec![
@ -370,11 +282,6 @@ impl Pane {
split_item_menu: None,
tab_bar_scroll_handle: ScrollHandle::new(),
drag_split_direction: None,
// tab_bar_context_menu: TabBarContextMenu {
// kind: TabBarContextMenuKind::New,
// handle: context_menu,
// },
// tab_context_menu: cx.build_view(|_| ContextMenu::new(pane_view_id, cx)),
workspace,
project,
can_drop_predicate,
@ -384,7 +291,7 @@ impl Pane {
h_stack()
.gap_2()
.child(
IconButton::new("plus", Icon::Plus)
IconButton::new("plus", IconName::Plus)
.icon_size(IconSize::Small)
.icon_color(Color::Muted)
.on_click(cx.listener(|pane, _, cx| {
@ -406,7 +313,7 @@ impl Pane {
el.child(Self::render_menu_overlay(new_item_menu))
})
.child(
IconButton::new("split", Icon::Split)
IconButton::new("split", IconName::Split)
.icon_size(IconSize::Small)
.icon_color(Color::Muted)
.on_click(cx.listener(|pane, _, cx| {
@ -427,11 +334,11 @@ impl Pane {
)
.child({
let zoomed = pane.is_zoomed();
IconButton::new("toggle_zoom", Icon::Maximize)
IconButton::new("toggle_zoom", IconName::Maximize)
.icon_size(IconSize::Small)
.icon_color(Color::Muted)
.selected(zoomed)
.selected_icon(Icon::Minimize)
.selected_icon(IconName::Minimize)
.on_click(cx.listener(|pane, _, cx| {
pane.toggle_zoom(&crate::ToggleZoom, cx);
}))
@ -450,7 +357,6 @@ impl Pane {
}
pub fn has_focus(&self, cx: &WindowContext) -> bool {
// todo!(); // inline this manually
self.focus_handle.contains_focused(cx)
}
@ -1570,7 +1476,7 @@ impl Pane {
})
.start_slot::<Indicator>(indicator)
.end_slot(
IconButton::new("close tab", Icon::Close)
IconButton::new("close tab", IconName::Close)
.icon_color(Color::Muted)
.size(ButtonSize::None)
.icon_size(IconSize::XSmall)
@ -1676,7 +1582,7 @@ impl Pane {
h_stack()
.gap_2()
.child(
IconButton::new("navigate_backward", Icon::ArrowLeft)
IconButton::new("navigate_backward", IconName::ArrowLeft)
.icon_size(IconSize::Small)
.on_click({
let view = cx.view().clone();
@ -1686,7 +1592,7 @@ impl Pane {
.tooltip(|cx| Tooltip::for_action("Go Back", &GoBack, cx)),
)
.child(
IconButton::new("navigate_forward", Icon::ArrowRight)
IconButton::new("navigate_forward", IconName::ArrowRight)
.icon_size(IconSize::Small)
.on_click({
let view = cx.view().clone();

View file

@ -12,7 +12,7 @@ use serde::Deserialize;
use std::sync::Arc;
use ui::{prelude::*, Button};
const HANDLE_HITBOX_SIZE: f32 = 10.0; //todo!(change this back to 4)
pub const HANDLE_HITBOX_SIZE: f32 = 4.0;
const HORIZONTAL_MIN_SIZE: f32 = 80.;
const VERTICAL_MIN_SIZE: f32 = 100.;
@ -268,15 +268,6 @@ impl Member {
)
})
.into_any()
// let el = div()
// .flex()
// .flex_1()
// .gap_px()
// .w_full()
// .h_full()
// .bg(cx.theme().colors().editor)
// .children();
}
Member::Axis(axis) => axis
.render(
@ -487,6 +478,7 @@ impl PaneAxis {
basis,
self.flexes.clone(),
self.bounding_boxes.clone(),
cx.view().downgrade(),
)
.children(self.members.iter().enumerate().map(|(ix, member)| {
if member.contains(active_pane) {
@ -575,21 +567,28 @@ mod element {
use gpui::{
px, relative, Along, AnyElement, Axis, Bounds, CursorStyle, Element, InteractiveBounds,
IntoElement, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point,
Size, Style, WindowContext,
Size, Style, WeakView, WindowContext,
};
use parking_lot::Mutex;
use settings::Settings;
use smallvec::SmallVec;
use ui::prelude::*;
use util::ResultExt;
use crate::Workspace;
use crate::WorkspaceSettings;
use super::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE};
const DIVIDER_SIZE: f32 = 1.0;
pub fn pane_axis(
pub(super) fn pane_axis(
axis: Axis,
basis: usize,
flexes: Arc<Mutex<Vec<f32>>>,
bounding_boxes: Arc<Mutex<Vec<Option<Bounds<Pixels>>>>>,
workspace: WeakView<Workspace>,
) -> PaneAxisElement {
PaneAxisElement {
axis,
@ -598,6 +597,7 @@ mod element {
bounding_boxes,
children: SmallVec::new(),
active_pane_ix: None,
workspace,
}
}
@ -608,6 +608,7 @@ mod element {
bounding_boxes: Arc<Mutex<Vec<Option<Bounds<Pixels>>>>>,
children: SmallVec<[AnyElement; 2]>,
active_pane_ix: Option<usize>,
workspace: WeakView<Workspace>,
}
impl PaneAxisElement {
@ -623,6 +624,7 @@ mod element {
axis: Axis,
child_start: Point<Pixels>,
container_size: Size<Pixels>,
workspace: WeakView<Workspace>,
cx: &mut WindowContext,
) {
let min_size = match axis {
@ -696,8 +698,9 @@ mod element {
proposed_current_pixel_change -= current_pixel_change;
}
// todo!(schedule serialize)
// workspace.schedule_serialize(cx);
workspace
.update(cx, |this, cx| this.schedule_serialize(cx))
.log_err();
cx.refresh();
}
@ -708,6 +711,7 @@ mod element {
ix: usize,
pane_bounds: Bounds<Pixels>,
axis_bounds: Bounds<Pixels>,
workspace: WeakView<Workspace>,
cx: &mut WindowContext,
) {
let handle_bounds = Bounds {
@ -742,24 +746,39 @@ mod element {
cx.on_mouse_event({
let dragged_handle = dragged_handle.clone();
move |e: &MouseDownEvent, phase, _cx| {
let flexes = flexes.clone();
let workspace = workspace.clone();
move |e: &MouseDownEvent, phase, cx| {
if phase.bubble() && handle_bounds.contains(&e.position) {
dragged_handle.replace(Some(ix));
if e.click_count >= 2 {
let mut borrow = flexes.lock();
*borrow = vec![1.; borrow.len()];
workspace
.update(cx, |this, cx| this.schedule_serialize(cx))
.log_err();
cx.refresh();
}
}
}
});
cx.on_mouse_event(move |e: &MouseMoveEvent, phase, cx| {
let dragged_handle = dragged_handle.borrow();
if phase.bubble() && *dragged_handle == Some(ix) {
Self::compute_resize(
&flexes,
e,
ix,
axis,
pane_bounds.origin,
axis_bounds.size,
cx,
)
cx.on_mouse_event({
let workspace = workspace.clone();
move |e: &MouseMoveEvent, phase, cx| {
let dragged_handle = dragged_handle.borrow();
if phase.bubble() && *dragged_handle == Some(ix) {
Self::compute_resize(
&flexes,
e,
ix,
axis,
pane_bounds.origin,
axis_bounds.size,
workspace.clone(),
cx,
)
}
}
});
});
@ -808,20 +827,39 @@ mod element {
debug_assert!(flexes.len() == len);
debug_assert!(flex_values_in_bounds(flexes.as_slice()));
let magnification_value = WorkspaceSettings::get(None, cx).active_pane_magnification;
let active_pane_magnification = if magnification_value == 1. {
None
} else {
Some(magnification_value)
};
let total_flex = if let Some(flex) = active_pane_magnification {
self.children.len() as f32 - 1. + flex
} else {
len as f32
};
let mut origin = bounds.origin;
let space_per_flex = bounds.size.along(self.axis) / len as f32;
let space_per_flex = bounds.size.along(self.axis) / total_flex;
let mut bounding_boxes = self.bounding_boxes.lock();
bounding_boxes.clear();
for (ix, child) in self.children.iter_mut().enumerate() {
//todo!(active_pane_magnification)
// If using active pane magnification, need to switch to using
// 1 for all non-active panes, and then the magnification for the
// active pane.
let child_flex = active_pane_magnification
.map(|magnification| {
if self.active_pane_ix == Some(ix) {
magnification
} else {
1.
}
})
.unwrap_or_else(|| flexes[ix]);
let child_size = bounds
.size
.apply_along(self.axis, |_| space_per_flex * flexes[ix]);
.apply_along(self.axis, |_| space_per_flex * child_flex);
let child_bounds = Bounds {
origin,
@ -831,19 +869,23 @@ mod element {
cx.with_z_index(0, |cx| {
child.draw(origin, child_size.into(), cx);
});
cx.with_z_index(1, |cx| {
if ix < len - 1 {
Self::push_handle(
self.flexes.clone(),
state.clone(),
self.axis,
ix,
child_bounds,
bounds,
cx,
);
}
});
if active_pane_magnification.is_none() {
cx.with_z_index(1, |cx| {
if ix < len - 1 {
Self::push_handle(
self.flexes.clone(),
state.clone(),
self.axis,
ix,
child_bounds,
bounds,
self.workspace.clone(),
cx,
);
}
});
}
origin = origin.apply_along(self.axis, |val| val + child_size.along(self.axis));
}

View file

@ -1,8 +1,8 @@
use std::{any::Any, sync::Arc};
use gpui::{
AnyView, AppContext, EventEmitter, Subscription, Task, View, ViewContext, WeakView,
WindowContext,
AnyView, AnyWeakView, AppContext, EventEmitter, Subscription, Task, View, ViewContext,
WeakView, WindowContext,
};
use project::search::SearchQuery;
@ -127,7 +127,6 @@ pub trait SearchableItemHandle: ItemHandle {
) -> Option<usize>;
}
// todo!("here is where we need to use AnyWeakView");
impl<T: SearchableItem> SearchableItemHandle for View<T> {
fn downgrade(&self) -> Box<dyn WeakSearchableItemHandle> {
Box::new(self.downgrade())
@ -249,7 +248,7 @@ impl Eq for Box<dyn SearchableItemHandle> {}
pub trait WeakSearchableItemHandle: WeakItemHandle {
fn upgrade(&self, cx: &AppContext) -> Option<Box<dyn SearchableItemHandle>>;
// fn into_any(self) -> AnyWeakView;
fn into_any(self) -> AnyWeakView;
}
impl<T: SearchableItem> WeakSearchableItemHandle for WeakView<T> {
@ -257,9 +256,9 @@ impl<T: SearchableItem> WeakSearchableItemHandle for WeakView<T> {
Some(Box::new(self.upgrade()?))
}
// fn into_any(self) -> AnyView {
// self.into_any()
// }
fn into_any(self) -> AnyWeakView {
self.into()
}
}
impl PartialEq for Box<dyn WeakSearchableItemHandle> {

View file

@ -12,7 +12,7 @@ use gpui::{
WindowContext,
};
use std::sync::{Arc, Weak};
use ui::{h_stack, prelude::*, Icon, IconElement, Label};
use ui::{h_stack, prelude::*, Icon, IconName, Label};
pub enum Event {
Close,
@ -100,7 +100,7 @@ impl Item for SharedScreen {
) -> gpui::AnyElement {
h_stack()
.gap_1()
.child(IconElement::new(Icon::Screen))
.child(Icon::new(IconName::Screen))
.child(
Label::new(format!("{}'s screen", self.user.github_login)).color(if selected {
Color::Default

View file

@ -133,82 +133,6 @@ impl Render for Toolbar {
}
}
// todo!()
// impl View for Toolbar {
// fn ui_name() -> &'static str {
// "Toolbar"
// }
// fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
// let theme = &theme::current(cx).workspace.toolbar;
// let mut primary_left_items = Vec::new();
// let mut primary_right_items = Vec::new();
// let mut secondary_item = None;
// let spacing = theme.item_spacing;
// let mut primary_items_row_count = 1;
// for (item, position) in &self.items {
// match *position {
// ToolbarItemLocation::Hidden => {}
// ToolbarItemLocation::PrimaryLeft { flex } => {
// primary_items_row_count = primary_items_row_count.max(item.row_count(cx));
// let left_item = ChildView::new(item.as_any(), cx).aligned();
// if let Some((flex, expanded)) = flex {
// primary_left_items.push(left_item.flex(flex, expanded).into_any());
// } else {
// primary_left_items.push(left_item.into_any());
// }
// }
// ToolbarItemLocation::PrimaryRight { flex } => {
// primary_items_row_count = primary_items_row_count.max(item.row_count(cx));
// let right_item = ChildView::new(item.as_any(), cx).aligned().flex_float();
// if let Some((flex, expanded)) = flex {
// primary_right_items.push(right_item.flex(flex, expanded).into_any());
// } else {
// primary_right_items.push(right_item.into_any());
// }
// }
// ToolbarItemLocation::Secondary => {
// secondary_item = Some(
// ChildView::new(item.as_any(), cx)
// .constrained()
// .with_height(theme.height * item.row_count(cx) as f32)
// .into_any(),
// );
// }
// }
// }
// let container_style = theme.container;
// let height = theme.height * primary_items_row_count as f32;
// let mut primary_items = Flex::row().with_spacing(spacing);
// primary_items.extend(primary_left_items);
// primary_items.extend(primary_right_items);
// let mut toolbar = Flex::column();
// if !primary_items.is_empty() {
// toolbar.add_child(primary_items.constrained().with_height(height));
// }
// if let Some(secondary_item) = secondary_item {
// toolbar.add_child(secondary_item);
// }
// if toolbar.is_empty() {
// toolbar.into_any_named("toolbar")
// } else {
// toolbar
// .contained()
// .with_style(container_style)
// .into_any_named("toolbar")
// }
// }
// }
impl Toolbar {
pub fn new() -> Self {
Self {
@ -312,10 +236,3 @@ impl<T: ToolbarItemView> ToolbarItemViewHandle for View<T> {
self.read(cx).row_count(cx)
}
}
// todo!()
// impl From<&dyn ToolbarItemViewHandle> for AnyViewHandle {
// fn from(val: &dyn ToolbarItemViewHandle) -> Self {
// val.as_any().clone()
// }
// }

View file

@ -26,12 +26,12 @@ use futures::{
};
use gpui::{
actions, canvas, div, impl_actions, point, size, Action, AnyElement, AnyModel, AnyView,
AnyWeakView, AnyWindowHandle, AppContext, AsyncAppContext, AsyncWindowContext, BorrowWindow,
Bounds, Context, Div, DragMoveEvent, Element, Entity, EntityId, EventEmitter, FocusHandle,
FocusableView, GlobalPixels, InteractiveElement, IntoElement, KeyContext, LayoutId,
ManagedView, Model, ModelContext, ParentElement, PathPromptOptions, Pixels, Point, PromptLevel,
Render, Size, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView,
WindowBounds, WindowContext, WindowHandle, WindowOptions,
AnyWeakView, AppContext, AsyncAppContext, AsyncWindowContext, BorrowWindow, Bounds, Context,
Div, DragMoveEvent, Element, Entity, EntityId, EventEmitter, FocusHandle, FocusableView,
GlobalPixels, InteractiveElement, IntoElement, KeyContext, LayoutId, ManagedView, Model,
ModelContext, ParentElement, PathPromptOptions, Pixels, Point, PromptLevel, Render, Size,
Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds,
WindowContext, WindowHandle, WindowOptions,
};
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
use itertools::Itertools;
@ -537,7 +537,7 @@ impl Workspace {
})
.detach();
cx.on_blur_window(|this, cx| {
cx.on_focus_lost(|this, cx| {
let focus_handle = this.focus_handle(cx);
cx.focus(&focus_handle);
})
@ -852,6 +852,10 @@ impl Workspace {
&self.right_dock
}
pub fn is_edited(&self) -> bool {
self.window_edited
}
pub fn add_panel<T: Panel>(&mut self, panel: View<T>, cx: &mut ViewContext<Self>) {
let dock = match panel.position(cx) {
DockPosition::Left => &self.left_dock,
@ -943,10 +947,8 @@ impl Workspace {
cx: &mut ViewContext<Workspace>,
) -> Task<Result<()>> {
let to_load = if let Some(pane) = pane.upgrade() {
// todo!("focus")
// cx.focus(&pane);
pane.update(cx, |pane, cx| {
pane.focus(cx);
loop {
// Retrieve the weak item handle from the history.
let entry = pane.nav_history_mut().pop(mode, cx)?;
@ -1145,7 +1147,6 @@ impl Workspace {
quitting: bool,
cx: &mut ViewContext<Self>,
) -> Task<Result<bool>> {
//todo!(saveing)
let active_call = self.active_call().cloned();
let window = cx.window_handle();
@ -1631,8 +1632,7 @@ impl Workspace {
});
}
// todo!("focus")
// cx.focus_self();
cx.focus_self();
cx.notify();
self.serialize_workspace(cx);
}
@ -1697,27 +1697,6 @@ impl Workspace {
None
}
// todo!("implement zoom")
#[allow(unused)]
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.zoom_out(cx));
self.bottom_dock.update(cx, |dock, cx| dock.zoom_out(cx));
self.right_dock.update(cx, |dock, cx| dock.zoom_out(cx));
self.zoomed = None;
self.zoomed_position = None;
cx.notify();
}
// #[cfg(any(test, feature = "test-support"))]
// pub fn zoomed_view(&self, cx: &AppContext) -> Option<AnyViewHandle> {
// self.zoomed.and_then(|view| view.upgrade(cx))
// }
fn dismiss_zoomed_items_to_reveal(
&mut self,
dock_to_reveal: Option<DockPosition>,
@ -2080,7 +2059,7 @@ impl Workspace {
_ => bounding_box.center(),
};
let distance_to_next = 8.; //todo(pane dividers styling)
let distance_to_next = pane_group::HANDLE_HITBOX_SIZE;
let target = match direction {
SplitDirection::Left => {
@ -2992,7 +2971,6 @@ impl Workspace {
cx.notify();
}
#[allow(unused)]
fn schedule_serialize(&mut self, cx: &mut ViewContext<Self>) {
self._schedule_serialize = Some(cx.spawn(|this, mut cx| async move {
cx.background_executor()
@ -3386,6 +3364,10 @@ impl Workspace {
div
}
pub fn has_active_modal(&self, cx: &WindowContext<'_>) -> bool {
self.modal_layer.read(cx).has_active_modal()
}
pub fn active_modal<V: ManagedView + 'static>(
&mut self,
cx: &ViewContext<Self>,
@ -4034,34 +4016,34 @@ pub fn join_channel(
return anyhow::Ok(());
}
if requesting_window.is_some() {
return anyhow::Ok(());
}
// find an existing workspace to focus and show call controls
let mut active_window = activate_any_workspace_window(&mut cx);
let mut active_window =
requesting_window.or_else(|| activate_any_workspace_window(&mut cx));
if active_window.is_none() {
// no open workspaces, make one to show the error in (blergh)
cx.update(|cx| Workspace::new_local(vec![], app_state.clone(), requesting_window, cx))?
let (window_handle, _) = cx
.update(|cx| {
Workspace::new_local(vec![], app_state.clone(), requesting_window, cx)
})?
.await?;
active_window = Some(window_handle);
}
active_window = activate_any_workspace_window(&mut cx);
let Some(active_window) = active_window else {
return anyhow::Ok(());
};
if let Err(err) = result {
active_window
.update(&mut cx, |_, cx| {
cx.prompt(
PromptLevel::Critical,
&format!("Failed to join channel: {}", err),
&["Ok"],
)
})?
.await
.ok();
log::error!("failed to join channel: {}", err);
if let Some(active_window) = active_window {
active_window
.update(&mut cx, |_, cx| {
cx.prompt(
PromptLevel::Critical,
&format!("Failed to join channel: {}", err),
&["Ok"],
)
})?
.await
.ok();
}
}
// return ok, we showed the error to the user.
@ -4079,19 +4061,17 @@ pub async fn get_any_active_workspace(
cx.update(|cx| Workspace::new_local(vec![], app_state.clone(), None, cx))?
.await?;
}
activate_any_workspace_window(&mut cx)
.context("could not open zed")?
.downcast::<Workspace>()
.context("could not open zed workspace window")
activate_any_workspace_window(&mut cx).context("could not open zed")
}
fn activate_any_workspace_window(cx: &mut AsyncAppContext) -> Option<AnyWindowHandle> {
fn activate_any_workspace_window(cx: &mut AsyncAppContext) -> Option<WindowHandle<Workspace>> {
cx.update(|cx| {
for window in cx.windows() {
let is_workspace = window.downcast::<Workspace>().is_some();
if is_workspace {
window.update(cx, |_, cx| cx.activate_window()).ok();
return Some(window);
if let Some(workspace_window) = window.downcast::<Workspace>() {
workspace_window
.update(cx, |_, cx| cx.activate_window())
.ok();
return Some(workspace_window);
}
}
None

View file

@ -12,35 +12,39 @@ pub struct WorkspaceSettings {
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
pub struct WorkspaceSettingsContent {
/// Scale by which to zoom the active pane.
/// When set to 1.0, the active pane has the same size as others,
/// but when set to a larger value, the active pane takes up more space.
///
/// Default: `1.0`
pub active_pane_magnification: Option<f32>,
/// Whether or not to prompt the user to confirm before closing the application.
///
/// Default: false
pub confirm_quit: Option<bool>,
/// Whether or not to show the call status icon in the status bar.
///
/// Default: true
pub show_call_status_icon: Option<bool>,
/// When to automatically save edited buffers.
///
/// Default: off
pub autosave: Option<AutosaveSetting>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum AutosaveSetting {
/// Disable autosave.
Off,
/// Save after inactivity period of `milliseconds`.
AfterDelay { milliseconds: u64 },
/// Autosave when focus changes.
OnFocusChange,
/// Autosave when the active window changes.
OnWindowChange,
}
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
pub struct GitSettings {
pub git_gutter: Option<GitGutterSetting>,
pub gutter_debounce: Option<u64>,
}
#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum GitGutterSetting {
#[default]
TrackedFiles,
Hide,
}
impl Settings for WorkspaceSettings {
const KEY: Option<&'static str> = None;