Add sidebars

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Max Brunsfeld
2021-08-20 13:51:52 -07:00
co-authored by Nathan Sobo
parent a7ac37a318
commit b88b3e7657
10 changed files with 243 additions and 35 deletions
+1
View File
@@ -7,6 +7,7 @@ mod fuzzy;
pub mod language;
pub mod menus;
mod operation_queue;
pub mod project_browser;
pub mod rpc;
pub mod settings;
mod sum_tree;
+19
View File
@@ -0,0 +1,19 @@
use gpui::{elements::Empty, Element, Entity, View};
pub struct ProjectBrowser;
pub enum Event {}
impl Entity for ProjectBrowser {
type Event = Event;
}
impl View for ProjectBrowser {
fn ui_name() -> &'static str {
"ProjectBrowser"
}
fn render(&self, _: &gpui::RenderContext<'_, Self>) -> gpui::ElementBox {
Empty::new().boxed()
}
}
+8
View File
@@ -33,6 +33,9 @@ pub struct Theme {
pub workspace: Workspace,
pub tab: Tab,
pub active_tab: Tab,
pub sidebar: ContainerStyle,
pub sidebar_icon: SidebarIcon,
pub active_sidebar_icon: SidebarIcon,
pub selector: Selector,
pub editor: Editor,
#[serde(deserialize_with = "deserialize_syntax_theme")]
@@ -72,6 +75,11 @@ pub struct Tab {
pub icon_conflict: Color,
}
#[derive(Debug, Default, Deserialize)]
pub struct SidebarIcon {
pub color: Color,
}
#[derive(Debug, Default, Deserialize)]
pub struct Selector {
#[serde(flatten)]
+76 -10
View File
@@ -1,10 +1,12 @@
pub mod pane;
pub mod pane_group;
pub mod sidebar;
use crate::{
editor::{Buffer, Editor},
fs::Fs,
language::LanguageRegistry,
project_browser::ProjectBrowser,
rpc,
settings::Settings,
worktree::{File, Worktree},
@@ -25,6 +27,7 @@ use log::error;
pub use pane::*;
pub use pane_group::*;
use postage::watch;
use sidebar::{Side, Sidebar};
use smol::prelude::*;
use std::{
collections::{hash_map::Entry, HashMap, HashSet},
@@ -46,6 +49,10 @@ pub fn init(cx: &mut MutableAppContext) {
cx.add_action("workspace:new_file", Workspace::open_new_file);
cx.add_action("workspace:share_worktree", Workspace::share_worktree);
cx.add_action("workspace:join_worktree", Workspace::join_worktree);
cx.add_action(
"workspace:toggle_sidebar_item",
Workspace::toggle_sidebar_item,
);
cx.add_bindings(vec![
Binding::new("cmd-s", "workspace:save", None),
Binding::new("cmd-alt-i", "workspace:debug_elements", None),
@@ -318,12 +325,6 @@ impl Clone for Box<dyn ItemHandle> {
}
}
#[derive(Debug)]
pub struct State {
pub modal: Option<usize>,
pub center: PaneGroup,
}
pub struct Workspace {
pub settings: watch::Receiver<Settings>,
languages: Arc<LanguageRegistry>,
@@ -331,6 +332,8 @@ pub struct Workspace {
fs: Arc<dyn Fs>,
modal: Option<AnyViewHandle>,
center: PaneGroup,
left_sidebar: Sidebar,
right_sidebar: Sidebar,
panes: Vec<ViewHandle<Pane>>,
active_pane: ViewHandle<Pane>,
worktrees: HashSet<ModelHandle<Worktree>>,
@@ -350,6 +353,19 @@ impl Workspace {
});
cx.focus(&pane);
let mut left_sidebar = Sidebar::new(Side::Left);
left_sidebar.add_item(
"icons/folder-tree-16.svg",
cx.add_view(|_| ProjectBrowser).into(),
);
let mut right_sidebar = Sidebar::new(Side::Right);
right_sidebar.add_item(
"icons/comment-16.svg",
cx.add_view(|_| ProjectBrowser).into(),
);
right_sidebar.add_item("icons/user-16.svg", cx.add_view(|_| ProjectBrowser).into());
Workspace {
modal: None,
center: PaneGroup::new(pane.id()),
@@ -359,6 +375,8 @@ impl Workspace {
languages: app_state.languages.clone(),
rpc: app_state.rpc.clone(),
fs: app_state.fs.clone(),
left_sidebar,
right_sidebar,
worktrees: Default::default(),
items: Default::default(),
loading_items: Default::default(),
@@ -724,6 +742,19 @@ impl Workspace {
}
}
pub fn toggle_sidebar_item(
&mut self,
(side, item_ix): &(Side, usize),
cx: &mut ViewContext<Self>,
) {
let sidebar = match side {
Side::Left => &mut self.left_sidebar,
Side::Right => &mut self.right_sidebar,
};
sidebar.toggle_item(*item_ix);
cx.notify();
}
pub fn debug_elements(&mut self, _: &(), cx: &mut ViewContext<Self>) {
match to_string_pretty(&cx.debug_elements()) {
Ok(json) => {
@@ -892,12 +923,47 @@ impl View for Workspace {
"Workspace"
}
fn render(&self, _: &RenderContext<Self>) -> ElementBox {
fn render(&self, cx: &RenderContext<Self>) -> ElementBox {
let settings = self.settings.borrow();
Container::new(
Stack::new()
.with_child(self.center.render())
.with_children(self.modal.as_ref().map(|m| ChildView::new(m.id()).boxed()))
Flex::column()
.with_child(
ConstrainedBox::new(Empty::new().boxed())
.with_height(cx.titlebar_height)
.named("titlebar"),
)
.with_child(
Expanded::new(
1.0,
Stack::new()
.with_child({
let mut content = Flex::row();
content.add_child(self.left_sidebar.render(&settings, cx));
if let Some(panel) = self.left_sidebar.active_item() {
content.add_child(
ConstrainedBox::new(ChildView::new(panel.id()).boxed())
.with_width(200.0)
.named("left panel"),
);
}
content.add_child(Expanded::new(1.0, self.center.render()).boxed());
if let Some(panel) = self.right_sidebar.active_item() {
content.add_child(
ConstrainedBox::new(ChildView::new(panel.id()).boxed())
.with_width(200.0)
.named("right panel"),
);
}
content.add_child(self.right_sidebar.render(&settings, cx));
content.boxed()
})
.with_children(
self.modal.as_ref().map(|m| ChildView::new(m.id()).boxed()),
)
.boxed(),
)
.boxed(),
)
.boxed(),
)
.with_background_color(settings.theme.workspace.background)
+93
View File
@@ -0,0 +1,93 @@
use crate::Settings;
use gpui::{
elements::{
Align, ConstrainedBox, Container, Flex, MouseEventHandler, ParentElement as _, Svg,
},
AnyViewHandle, AppContext, Element as _, ElementBox,
};
pub struct Sidebar {
side: Side,
items: Vec<Item>,
active_item_ix: Option<usize>,
}
#[derive(Clone, Copy)]
pub enum Side {
Left,
Right,
}
struct Item {
icon_path: &'static str,
view: AnyViewHandle,
}
impl Sidebar {
pub fn new(side: Side) -> Self {
Self {
side,
items: Default::default(),
active_item_ix: None,
}
}
pub fn add_item(&mut self, icon_path: &'static str, view: AnyViewHandle) {
self.items.push(Item { icon_path, view });
}
pub fn toggle_item(&mut self, item_ix: usize) {
if self.active_item_ix == Some(item_ix) {
self.active_item_ix = None;
} else {
self.active_item_ix = Some(item_ix)
}
}
pub fn active_item(&self) -> Option<&AnyViewHandle> {
self.active_item_ix
.and_then(|ix| self.items.get(ix))
.map(|item| &item.view)
}
pub fn render(&self, settings: &Settings, cx: &AppContext) -> ElementBox {
let side = self.side;
let line_height = cx.font_cache().line_height(
cx.font_cache().default_font(settings.ui_font_family),
settings.ui_font_size,
);
Container::new(
Flex::column()
.with_children(self.items.iter().enumerate().map(|(item_ix, item)| {
let theme = if Some(item_ix) == self.active_item_ix {
&settings.theme.active_sidebar_icon
} else {
&settings.theme.sidebar_icon
};
enum SidebarButton {}
MouseEventHandler::new::<SidebarButton, _>(item.view.id(), cx, |_| {
ConstrainedBox::new(
Align::new(
ConstrainedBox::new(
Svg::new(item.icon_path).with_color(theme.color).boxed(),
)
.with_height(line_height)
.boxed(),
)
.boxed(),
)
.with_height(line_height + 16.0)
.boxed()
})
.on_click(move |cx| {
cx.dispatch_action("workspace:toggle_sidebar_item", (side, item_ix))
})
.boxed()
}))
.boxed(),
)
.with_style(&settings.theme.sidebar)
.boxed()
}
}