Inform toolbars when active item changes

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Max Brunsfeld 2022-01-27 12:58:21 -08:00
parent bebde782fa
commit 05e20ca72b
4 changed files with 148 additions and 31 deletions

1
Cargo.lock generated
View file

@ -1725,6 +1725,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"editor", "editor",
"gpui", "gpui",
"postage",
"workspace", "workspace",
] ]

View file

@ -10,3 +10,4 @@ path = "src/find.rs"
editor = { path = "../editor" } editor = { path = "../editor" }
gpui = { path = "../gpui" } gpui = { path = "../gpui" }
workspace = { path = "../workspace" } workspace = { path = "../workspace" }
postage = { version = "0.4.1", features = ["futures-traits"] }

View file

@ -1,8 +1,11 @@
use editor::{Editor, EditorSettings};
use gpui::{ use gpui::{
action, color::Color, elements::*, keymap::Binding, Entity, MutableAppContext, RenderContext, action, elements::*, keymap::Binding, Entity, MutableAppContext, RenderContext, View,
View, ViewContext, ViewContext, ViewHandle,
}; };
use workspace::Workspace; use postage::watch;
use std::sync::Arc;
use workspace::{ItemViewHandle, Settings, Toolbar, Workspace};
action!(Deploy); action!(Deploy);
@ -15,7 +18,11 @@ pub fn init(cx: &mut MutableAppContext) {
cx.add_action(FindBar::deploy); cx.add_action(FindBar::deploy);
} }
struct FindBar; struct FindBar {
settings: watch::Receiver<Settings>,
query_editor: ViewHandle<Editor>,
active_editor: Option<ViewHandle<Editor>>,
}
impl Entity for FindBar { impl Entity for FindBar {
type Event = (); type Event = ();
@ -27,19 +34,65 @@ impl View for FindBar {
} }
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox { fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
Empty::new() ChildView::new(&self.query_editor)
.contained() .contained()
.with_background_color(Color::red()) .with_style(self.settings.borrow().theme.selector.input_editor.container)
.constrained()
.with_height(30.)
.boxed() .boxed()
} }
} }
impl FindBar { impl Toolbar for FindBar {
fn deploy(workspace: &mut Workspace, _: &Deploy, cx: &mut ViewContext<Workspace>) { fn active_item_changed(
workspace &mut self,
.active_pane() item: Option<Box<dyn ItemViewHandle>>,
.update(cx, |pane, cx| pane.show_toolbar(cx, |_| FindBar)); cx: &mut ViewContext<Self>,
) -> bool {
self.active_editor = item.and_then(|item| item.act_as::<Editor>(cx));
self.active_editor.is_some()
}
}
impl FindBar {
fn new(settings: watch::Receiver<Settings>, cx: &mut ViewContext<Self>) -> Self {
let query_editor = cx.add_view(|cx| {
Editor::single_line(
{
let settings = settings.clone();
Arc::new(move |_| {
let settings = settings.borrow();
EditorSettings {
style: settings.theme.selector.input_editor.as_editor(),
tab_size: settings.tab_size,
soft_wrap: editor::SoftWrap::None,
}
})
},
cx,
)
});
cx.subscribe(&query_editor, Self::on_query_editor_event)
.detach();
Self {
query_editor,
active_editor: None,
settings,
}
}
fn deploy(workspace: &mut Workspace, _: &Deploy, cx: &mut ViewContext<Workspace>) {
let settings = workspace.settings();
workspace.active_pane().update(cx, |pane, cx| {
pane.show_toolbar(cx, |cx| FindBar::new(settings, cx));
if let Some(toolbar) = pane.active_toolbar() {
cx.focus(toolbar);
}
});
}
fn cancel(workspace: &mut Workspace, _: &Cancel, cx: &mut ViewContext<Workspace>) {
workspace
.active_pane()
.update(cx, |pane, cx| pane.hide_toolbar(cx));
} }
} }

View file

@ -81,14 +81,27 @@ pub struct Pane {
active_item_index: usize, active_item_index: usize,
settings: watch::Receiver<Settings>, settings: watch::Receiver<Settings>,
nav_history: Rc<RefCell<NavHistory>>, nav_history: Rc<RefCell<NavHistory>>,
toolbars: HashMap<TypeId, AnyViewHandle>, toolbars: HashMap<TypeId, Box<dyn ToolbarHandle>>,
active_toolbar: Option<AnyViewHandle>, active_toolbar_type: Option<TypeId>,
active_toolbar_visible: bool,
} }
// #[derive(Debug, Eq, PartialEq)] pub trait Toolbar: View {
// pub struct State { fn active_item_changed(
// pub tabs: Vec<TabState>, &mut self,
// } item: Option<Box<dyn ItemViewHandle>>,
cx: &mut ViewContext<Self>,
) -> bool;
}
trait ToolbarHandle {
fn active_item_changed(
&self,
item: Option<Box<dyn ItemViewHandle>>,
cx: &mut MutableAppContext,
) -> bool;
fn to_any(&self) -> AnyViewHandle;
}
pub struct ItemNavHistory { pub struct ItemNavHistory {
history: Rc<RefCell<NavHistory>>, history: Rc<RefCell<NavHistory>>,
@ -129,7 +142,8 @@ impl Pane {
settings, settings,
nav_history: Default::default(), nav_history: Default::default(),
toolbars: Default::default(), toolbars: Default::default(),
active_toolbar: Default::default(), active_toolbar_type: Default::default(),
active_toolbar_visible: false,
} }
} }
@ -301,6 +315,7 @@ impl Pane {
if prev_active_item_ix != self.active_item_index { if prev_active_item_ix != self.active_item_index {
self.item_views[prev_active_item_ix].1.deactivated(cx); self.item_views[prev_active_item_ix].1.deactivated(cx);
} }
self.update_active_toolbar(cx);
self.focus_active_item(cx); self.focus_active_item(cx);
cx.notify(); cx.notify();
} }
@ -354,15 +369,18 @@ impl Pane {
true true
} }
}); });
self.active_item_index = cmp::min( self.activate_item(
self.active_item_index, cmp::min(
self.item_views.len().saturating_sub(1), self.active_item_index,
self.item_views.len().saturating_sub(1),
),
cx,
); );
if self.item_views.is_empty() { if self.item_views.is_empty() {
self.update_active_toolbar(cx);
cx.emit(Event::Remove); cx.emit(Event::Remove);
} }
cx.notify();
} }
fn focus_active_item(&mut self, cx: &mut ViewContext<Self>) { fn focus_active_item(&mut self, cx: &mut ViewContext<Self>) {
@ -378,16 +396,46 @@ impl Pane {
pub fn show_toolbar<F, V>(&mut self, cx: &mut ViewContext<Self>, build_toolbar: F) pub fn show_toolbar<F, V>(&mut self, cx: &mut ViewContext<Self>, build_toolbar: F)
where where
F: FnOnce(&mut ViewContext<V>) -> V, F: FnOnce(&mut ViewContext<V>) -> V,
V: View, V: Toolbar,
{ {
let handle = self let type_id = TypeId::of::<V>();
.toolbars let active_item = self.active_item();
.entry(TypeId::of::<V>()) self.toolbars
.or_insert_with(|| cx.add_view(build_toolbar).into()); .entry(type_id)
self.active_toolbar = Some(handle.clone()); .or_insert_with(|| Box::new(cx.add_view(build_toolbar)));
self.active_toolbar_type = Some(type_id);
self.active_toolbar_visible = self.toolbars[&type_id].active_item_changed(active_item, cx);
cx.notify(); cx.notify();
} }
pub fn hide_toolbar(&mut self, cx: &mut ViewContext<Self>) {
self.active_toolbar_type = None;
self.active_toolbar_visible = false;
self.focus_active_item(cx);
cx.notify();
}
pub fn active_toolbar(&self) -> Option<AnyViewHandle> {
let type_id = self.active_toolbar_type?;
let toolbar = self.toolbars.get(&type_id)?;
if self.active_toolbar_visible {
Some(toolbar.to_any())
} else {
None
}
}
fn update_active_toolbar(&mut self, cx: &mut ViewContext<Self>) {
if let Some(type_id) = self.active_toolbar_type {
if let Some(toolbar) = self.toolbars.get(&type_id) {
self.active_toolbar_visible = toolbar.active_item_changed(
Some(self.item_views[self.active_item_index].1.clone()),
cx,
);
}
}
}
fn render_tabs(&self, cx: &mut RenderContext<Self>) -> ElementBox { fn render_tabs(&self, cx: &mut RenderContext<Self>) -> ElementBox {
let settings = self.settings.borrow(); let settings = self.settings.borrow();
let theme = &settings.theme; let theme = &settings.theme;
@ -540,7 +588,7 @@ impl View for Pane {
Flex::column() Flex::column()
.with_child(self.render_tabs(cx)) .with_child(self.render_tabs(cx))
.with_children( .with_children(
self.active_toolbar self.active_toolbar()
.as_ref() .as_ref()
.map(|view| ChildView::new(view).boxed()), .map(|view| ChildView::new(view).boxed()),
) )
@ -556,6 +604,20 @@ impl View for Pane {
} }
} }
impl<T: Toolbar> ToolbarHandle for ViewHandle<T> {
fn active_item_changed(
&self,
item: Option<Box<dyn ItemViewHandle>>,
cx: &mut MutableAppContext,
) -> bool {
self.update(cx, |this, cx| this.active_item_changed(item, cx))
}
fn to_any(&self) -> AnyViewHandle {
self.into()
}
}
impl ItemNavHistory { impl ItemNavHistory {
pub fn new<T: ItemView>(history: Rc<RefCell<NavHistory>>, item_view: &ViewHandle<T>) -> Self { pub fn new<T: ItemView>(history: Rc<RefCell<NavHistory>>, item_view: &ViewHandle<T>) -> Self {
Self { Self {