Permanent fix to repeat MouseRegion Tag failure in Workspace

Polish tab bar buttons

Co-Authored-By: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
K Simmons 2022-09-09 17:29:52 -07:00
parent 69ecbb644d
commit 6b26965074
33 changed files with 542 additions and 545 deletions

View file

@ -1,7 +1,8 @@
use super::{ItemHandle, SplitDirection};
use crate::{
dock::MoveDock, toolbar::Toolbar, Item, NewFile, NewSearch, NewTerminal, WeakItemHandle,
Workspace,
dock::{MoveDock, ToggleDock},
toolbar::Toolbar,
Item, NewFile, NewSearch, NewTerminal, WeakItemHandle, Workspace,
};
use anyhow::Result;
use collections::{HashMap, HashSet, VecDeque};
@ -18,7 +19,7 @@ use gpui::{
},
impl_actions, impl_internal_actions,
platform::{CursorStyle, NavigationDirection},
AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, EventContext,
Action, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, EventContext,
ModelHandle, MouseButton, MutableAppContext, PromptLevel, Quad, RenderContext, Task, View,
ViewContext, ViewHandle, WeakViewHandle,
};
@ -204,8 +205,8 @@ pub struct Pane {
autoscroll: bool,
nav_history: Rc<RefCell<NavHistory>>,
toolbar: ViewHandle<Toolbar>,
context_menu: ViewHandle<ContextMenu>,
is_dock: bool,
tab_bar_context_menu: ViewHandle<ContextMenu>,
docked: Option<DockAnchor>,
}
pub struct ItemNavHistory {
@ -255,7 +256,7 @@ pub enum ReorderBehavior {
}
impl Pane {
pub fn new(is_dock: bool, cx: &mut ViewContext<Self>) -> Self {
pub fn new(docked: Option<DockAnchor>, cx: &mut ViewContext<Self>) -> Self {
let handle = cx.weak_handle();
let context_menu = cx.add_view(ContextMenu::new);
Self {
@ -273,8 +274,8 @@ impl Pane {
pane: handle.clone(),
})),
toolbar: cx.add_view(|_| Toolbar::new(handle)),
context_menu,
is_dock,
tab_bar_context_menu: context_menu,
docked,
}
}
@ -283,6 +284,11 @@ impl Pane {
cx.notify();
}
pub fn set_docked(&mut self, docked: Option<DockAnchor>, cx: &mut ViewContext<Self>) {
self.docked = docked;
cx.notify();
}
pub fn nav_history_for_item<T: Item>(&self, item: &ViewHandle<T>) -> ItemNavHistory {
ItemNavHistory {
history: self.nav_history.clone(),
@ -983,9 +989,10 @@ impl Pane {
}
fn deploy_split_menu(&mut self, action: &DeploySplitMenu, cx: &mut ViewContext<Self>) {
self.context_menu.update(cx, |menu, cx| {
self.tab_bar_context_menu.update(cx, |menu, cx| {
menu.show(
action.position,
AnchorCorner::TopRight,
vec![
ContextMenuItem::item("Split Right", SplitRight),
ContextMenuItem::item("Split Left", SplitLeft),
@ -998,9 +1005,10 @@ impl Pane {
}
fn deploy_dock_menu(&mut self, action: &DeployDockMenu, cx: &mut ViewContext<Self>) {
self.context_menu.update(cx, |menu, cx| {
self.tab_bar_context_menu.update(cx, |menu, cx| {
menu.show(
action.position,
AnchorCorner::TopRight,
vec![
ContextMenuItem::item("Move Dock Right", MoveDock(DockAnchor::Right)),
ContextMenuItem::item("Move Dock Bottom", MoveDock(DockAnchor::Bottom)),
@ -1012,9 +1020,10 @@ impl Pane {
}
fn deploy_new_menu(&mut self, action: &DeployNewMenu, cx: &mut ViewContext<Self>) {
self.context_menu.update(cx, |menu, cx| {
self.tab_bar_context_menu.update(cx, |menu, cx| {
menu.show(
action.position,
AnchorCorner::TopRight,
vec![
ContextMenuItem::item("New File", NewFile),
ContextMenuItem::item("New Terminal", NewTerminal),
@ -1047,7 +1056,7 @@ impl Pane {
enum Tab {}
enum Filler {}
let pane = cx.handle();
MouseEventHandler::new::<Tabs, _, _>(0, cx, |_, cx| {
MouseEventHandler::<Tabs>::new(0, cx, |_, cx| {
let autoscroll = if mem::take(&mut self.autoscroll) {
Some(self.active_item_index)
} else {
@ -1068,7 +1077,7 @@ impl Pane {
let tab_active = ix == self.active_item_index;
row.add_child({
MouseEventHandler::new::<Tab, _, _>(ix, cx, {
MouseEventHandler::<Tab>::new(ix, cx, {
let item = item.clone();
let pane = pane.clone();
let detail = detail.clone();
@ -1143,7 +1152,7 @@ impl Pane {
// the filler
let filler_style = theme.workspace.tab_bar.tab_style(pane_active, false);
row.add_child(
MouseEventHandler::new::<Filler, _, _>(0, cx, |mouse_state, cx| {
MouseEventHandler::<Filler>::new(0, cx, |mouse_state, cx| {
let mut filler = Empty::new()
.contained()
.with_style(filler_style.container)
@ -1265,17 +1274,13 @@ impl Pane {
let item_id = item.id();
enum TabCloseButton {}
let icon = Svg::new("icons/x_mark_thin_8.svg");
MouseEventHandler::new::<TabCloseButton, _, _>(
item_id,
cx,
|mouse_state, _| {
if mouse_state.hovered {
icon.with_color(tab_style.icon_close_active).boxed()
} else {
icon.with_color(tab_style.icon_close).boxed()
}
},
)
MouseEventHandler::<TabCloseButton>::new(item_id, cx, |mouse_state, _| {
if mouse_state.hovered {
icon.with_color(tab_style.icon_close_active).boxed()
} else {
icon.with_color(tab_style.icon_close).boxed()
}
})
.with_padding(Padding::uniform(4.))
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, {
@ -1351,132 +1356,132 @@ impl View for Pane {
}
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
enum SplitIcon {}
let this = cx.handle();
let is_dock = self.is_dock;
enum MouseNavigationHandler {}
Stack::new()
.with_child(
EventHandler::new(if let Some(active_item) = self.active_item() {
Flex::column()
.with_child({
let mut tab_row = Flex::row()
.with_child(self.render_tab_bar(cx).flex(1., true).named("tabs"));
MouseEventHandler::<MouseNavigationHandler>::new(0, cx, |_, cx| {
if let Some(active_item) = self.active_item() {
Flex::column()
.with_child({
let mut tab_row = Flex::row().with_child(
self.render_tab_bar(cx).flex(1., true).named("tabs"),
);
if self.is_active {
tab_row.add_children([
MouseEventHandler::new::<SplitIcon, _, _>(
0,
cx,
|mouse_state, cx| {
let theme =
&cx.global::<Settings>().theme.workspace.tab_bar;
let style =
theme.pane_button.style_for(mouse_state, false);
Svg::new("icons/plus_12.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)
.aligned()
.boxed()
},
if self.is_active {
tab_row.add_child(
Flex::row()
// New menu
.with_child(tab_bar_button(
0,
"icons/plus_12.svg",
cx,
|position| DeployNewMenu { position },
))
.with_child(
self.docked
.map(|anchor| {
// Add the dock menu button if this pane is a dock
let dock_icon = match anchor {
DockAnchor::Right => {
"icons/dock_right_12.svg"
}
DockAnchor::Bottom => {
"icons/dock_bottom_12.svg"
}
DockAnchor::Expanded => {
"icons/dock_modal_12.svg"
}
};
tab_bar_button(
2,
dock_icon,
cx,
|position| DeployDockMenu { position },
)
})
.unwrap_or_else(|| {
// Add the split menu if this pane is not a dock
tab_bar_button(
1,
"icons/split_12.svg",
cx,
|position| DeployNewMenu { position },
)
}),
)
// Add the close dock button if this pane is a dock
.with_children(self.docked.map(|_| {
tab_bar_button(3, "icons/x_mark_12.svg", cx, |_| {
ToggleDock
})
}))
.contained()
.with_style(
cx.global::<Settings>()
.theme
.workspace
.tab_bar
.pane_button
.default
.container,
)
.boxed(),
)
.with_cursor_style(CursorStyle::PointingHand)
.on_down(MouseButton::Left, |e, cx| {
cx.dispatch_action(DeployNewMenu {
position: e.region.lower_right(),
});
})
.boxed(),
MouseEventHandler::new::<SplitIcon, _, _>(
1,
cx,
|mouse_state, cx| {
let theme =
&cx.global::<Settings>().theme.workspace.tab_bar;
let style =
theme.pane_button.style_for(mouse_state, false);
Svg::new("icons/split_12.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)
.aligned()
.boxed()
},
}
tab_row
.constrained()
.with_height(
cx.global::<Settings>().theme.workspace.tab_bar.height,
)
.with_cursor_style(CursorStyle::PointingHand)
.on_down(MouseButton::Left, move |e, cx| {
if is_dock {
cx.dispatch_action(DeployDockMenu {
position: e.region.lower_right(),
});
} else {
cx.dispatch_action(DeploySplitMenu {
position: e.region.lower_right(),
});
}
})
.boxed(),
])
}
tab_row
.constrained()
.with_height(cx.global::<Settings>().theme.workspace.tab_bar.height)
.named("tab bar")
})
.with_child(ChildView::new(&self.toolbar).boxed())
.with_child(ChildView::new(active_item).flex(1., true).boxed())
.boxed()
} else {
enum EmptyPane {}
let theme = cx.global::<Settings>().theme.clone();
MouseEventHandler::new::<EmptyPane, _, _>(0, cx, |_, _| {
Empty::new()
.contained()
.with_background_color(theme.workspace.background)
.named("tab bar")
})
.with_child(ChildView::new(&self.toolbar).boxed())
.with_child(ChildView::new(active_item).flex(1., true).boxed())
.boxed()
})
.on_down(MouseButton::Left, |_, cx| {
cx.focus_parent_view();
})
.on_up(MouseButton::Left, {
let pane = this.clone();
move |_, cx: &mut EventContext| Pane::handle_dropped_item(&pane, 0, cx)
})
.boxed()
})
.on_navigate_mouse_down(move |direction, cx| {
let this = this.clone();
match direction {
NavigationDirection::Back => {
cx.dispatch_action(GoBack { pane: Some(this) })
}
NavigationDirection::Forward => {
cx.dispatch_action(GoForward { pane: Some(this) })
}
}
} else {
enum EmptyPane {}
let theme = cx.global::<Settings>().theme.clone();
true
MouseEventHandler::<EmptyPane>::new(0, cx, |_, _| {
Empty::new()
.contained()
.with_background_color(theme.workspace.background)
.boxed()
})
.on_down(MouseButton::Left, |_, cx| {
cx.focus_parent_view();
})
.on_up(MouseButton::Left, {
let pane = this.clone();
move |_, cx: &mut EventContext| Pane::handle_dropped_item(&pane, 0, cx)
})
.boxed()
}
})
.on_down(MouseButton::Navigate(NavigationDirection::Back), {
let this = this.clone();
move |_, cx| {
cx.dispatch_action(GoBack {
pane: Some(this.clone()),
});
}
})
.on_down(MouseButton::Navigate(NavigationDirection::Forward), {
let this = this.clone();
move |_, cx| {
cx.dispatch_action(GoForward {
pane: Some(this.clone()),
})
}
})
.boxed(),
)
.with_child(ChildView::new(&self.context_menu).boxed())
.with_child(ChildView::new(&self.tab_bar_context_menu).boxed())
.named("pane")
}
@ -1498,6 +1503,36 @@ impl View for Pane {
}
}
fn tab_bar_button<A: Action>(
index: usize,
icon: &'static str,
cx: &mut RenderContext<Pane>,
action_builder: impl 'static + Fn(Vector2F) -> A,
) -> ElementBox {
enum TabBarButton {}
MouseEventHandler::<TabBarButton>::new(index, cx, |mouse_state, cx| {
let theme = &cx.global::<Settings>().theme.workspace.tab_bar;
let style = theme.pane_button.style_for(mouse_state, false);
Svg::new(icon)
.with_color(style.color)
.constrained()
.with_width(style.icon_width)
.aligned()
.contained()
.constrained()
.with_width(style.button_width)
.with_height(style.button_width)
.aligned()
.boxed()
})
.with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, move |e, cx| {
cx.dispatch_action(action_builder(e.region.lower_right()));
})
.boxed()
}
impl ItemNavHistory {
pub fn push<D: 'static + Any>(&self, data: Option<D>, cx: &mut MutableAppContext) {
self.history.borrow_mut().push(data, self.item.clone(), cx);