Deploy context menu when clicking on split icon
This commit is contained in:
parent
c87efb0dbc
commit
9677db9f8f
7 changed files with 100 additions and 46 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -6934,6 +6934,7 @@ dependencies = [
|
||||||
"client",
|
"client",
|
||||||
"clock",
|
"clock",
|
||||||
"collections",
|
"collections",
|
||||||
|
"context_menu",
|
||||||
"futures",
|
"futures",
|
||||||
"gpui",
|
"gpui",
|
||||||
"language",
|
"language",
|
||||||
|
|
3
assets/icons/split.svg
Normal file
3
assets/icons/split.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="12" height="10" viewBox="0 0 12 10" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10.8 0.800476C11.4619 0.800476 12 1.33766 12 2.00048V8.00048C12 8.66235 11.4619 9.20048 10.8 9.20048H1.2C0.537188 9.20048 0 8.66235 0 8.00048V2.00048C0 1.33766 0.537188 0.800476 1.2 0.800476H10.8ZM3.6 2.00048H1.2V8.00048H3.6V2.00048ZM4.8 8.00048H7.2V2.00048H4.8V8.00048ZM10.8 2.00048H8.4V8.00048H10.8V2.00048Z" fill="#8B8792"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 441 B |
|
@ -277,6 +277,8 @@ impl ContextMenu {
|
||||||
.boxed(),
|
.boxed(),
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
.contained()
|
||||||
|
.with_margin_left(style.keystroke_margin)
|
||||||
.boxed(),
|
.boxed(),
|
||||||
)
|
)
|
||||||
.contained()
|
.contained()
|
||||||
|
|
|
@ -242,6 +242,7 @@ pub struct ContextMenu {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub container: ContainerStyle,
|
pub container: ContainerStyle,
|
||||||
pub item: Interactive<ContextMenuItem>,
|
pub item: Interactive<ContextMenuItem>,
|
||||||
|
pub keystroke_margin: f32,
|
||||||
pub separator: ContainerStyle,
|
pub separator: ContainerStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ test-support = ["client/test-support", "project/test-support", "settings/test-su
|
||||||
client = { path = "../client" }
|
client = { path = "../client" }
|
||||||
clock = { path = "../clock" }
|
clock = { path = "../clock" }
|
||||||
collections = { path = "../collections" }
|
collections = { path = "../collections" }
|
||||||
|
context_menu = { path = "../context_menu" }
|
||||||
gpui = { path = "../gpui" }
|
gpui = { path = "../gpui" }
|
||||||
language = { path = "../language" }
|
language = { path = "../language" }
|
||||||
menu = { path = "../menu" }
|
menu = { path = "../menu" }
|
||||||
|
|
|
@ -2,11 +2,15 @@ use super::{ItemHandle, SplitDirection};
|
||||||
use crate::{toolbar::Toolbar, Item, WeakItemHandle, Workspace};
|
use crate::{toolbar::Toolbar, Item, WeakItemHandle, Workspace};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use collections::{HashMap, HashSet, VecDeque};
|
use collections::{HashMap, HashSet, VecDeque};
|
||||||
|
use context_menu::{ContextMenu, ContextMenuItem};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions,
|
actions,
|
||||||
elements::*,
|
elements::*,
|
||||||
geometry::{rect::RectF, vector::vec2f},
|
geometry::{
|
||||||
|
rect::RectF,
|
||||||
|
vector::{vec2f, Vector2F},
|
||||||
|
},
|
||||||
impl_actions, impl_internal_actions,
|
impl_actions, impl_internal_actions,
|
||||||
platform::{CursorStyle, NavigationDirection},
|
platform::{CursorStyle, NavigationDirection},
|
||||||
AppContext, AsyncAppContext, Entity, ModelHandle, MutableAppContext, PromptLevel, Quad,
|
AppContext, AsyncAppContext, Entity, ModelHandle, MutableAppContext, PromptLevel, Quad,
|
||||||
|
@ -55,8 +59,13 @@ pub struct GoForward {
|
||||||
pub pane: Option<WeakViewHandle<Pane>>,
|
pub pane: Option<WeakViewHandle<Pane>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub struct DeploySplitMenu {
|
||||||
|
position: Vector2F,
|
||||||
|
}
|
||||||
|
|
||||||
impl_actions!(pane, [GoBack, GoForward, ActivateItem]);
|
impl_actions!(pane, [GoBack, GoForward, ActivateItem]);
|
||||||
impl_internal_actions!(pane, [CloseItem]);
|
impl_internal_actions!(pane, [CloseItem, DeploySplitMenu]);
|
||||||
|
|
||||||
const MAX_NAVIGATION_HISTORY_LEN: usize = 1024;
|
const MAX_NAVIGATION_HISTORY_LEN: usize = 1024;
|
||||||
|
|
||||||
|
@ -87,6 +96,7 @@ pub fn init(cx: &mut MutableAppContext) {
|
||||||
cx.add_action(|pane: &mut Pane, _: &SplitUp, cx| pane.split(SplitDirection::Up, cx));
|
cx.add_action(|pane: &mut Pane, _: &SplitUp, cx| pane.split(SplitDirection::Up, cx));
|
||||||
cx.add_action(|pane: &mut Pane, _: &SplitRight, cx| pane.split(SplitDirection::Right, cx));
|
cx.add_action(|pane: &mut Pane, _: &SplitRight, cx| pane.split(SplitDirection::Right, cx));
|
||||||
cx.add_action(|pane: &mut Pane, _: &SplitDown, cx| pane.split(SplitDirection::Down, cx));
|
cx.add_action(|pane: &mut Pane, _: &SplitDown, cx| pane.split(SplitDirection::Down, cx));
|
||||||
|
cx.add_action(Pane::deploy_split_menu);
|
||||||
cx.add_action(|workspace: &mut Workspace, _: &ReopenClosedItem, cx| {
|
cx.add_action(|workspace: &mut Workspace, _: &ReopenClosedItem, cx| {
|
||||||
Pane::reopen_closed_item(workspace, cx).detach();
|
Pane::reopen_closed_item(workspace, cx).detach();
|
||||||
});
|
});
|
||||||
|
@ -129,6 +139,7 @@ pub struct Pane {
|
||||||
autoscroll: bool,
|
autoscroll: bool,
|
||||||
nav_history: Rc<RefCell<NavHistory>>,
|
nav_history: Rc<RefCell<NavHistory>>,
|
||||||
toolbar: ViewHandle<Toolbar>,
|
toolbar: ViewHandle<Toolbar>,
|
||||||
|
split_menu: ViewHandle<ContextMenu>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ItemNavHistory {
|
pub struct ItemNavHistory {
|
||||||
|
@ -169,6 +180,7 @@ pub struct NavigationEntry {
|
||||||
impl Pane {
|
impl Pane {
|
||||||
pub fn new(cx: &mut ViewContext<Self>) -> Self {
|
pub fn new(cx: &mut ViewContext<Self>) -> Self {
|
||||||
let handle = cx.weak_handle();
|
let handle = cx.weak_handle();
|
||||||
|
let split_menu = cx.add_view(|cx| ContextMenu::new(cx));
|
||||||
Self {
|
Self {
|
||||||
items: Vec::new(),
|
items: Vec::new(),
|
||||||
active_item_index: 0,
|
active_item_index: 0,
|
||||||
|
@ -182,6 +194,7 @@ impl Pane {
|
||||||
pane: handle.clone(),
|
pane: handle.clone(),
|
||||||
})),
|
})),
|
||||||
toolbar: cx.add_view(|_| Toolbar::new(handle)),
|
toolbar: cx.add_view(|_| Toolbar::new(handle)),
|
||||||
|
split_menu,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -786,6 +799,21 @@ impl Pane {
|
||||||
cx.emit(Event::Split(direction));
|
cx.emit(Event::Split(direction));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deploy_split_menu(&mut self, action: &DeploySplitMenu, cx: &mut ViewContext<Self>) {
|
||||||
|
self.split_menu.update(cx, |menu, cx| {
|
||||||
|
menu.show(
|
||||||
|
action.position,
|
||||||
|
vec![
|
||||||
|
ContextMenuItem::item("Split Right", SplitRight),
|
||||||
|
ContextMenuItem::item("Split Left", SplitLeft),
|
||||||
|
ContextMenuItem::item("Split Up", SplitUp),
|
||||||
|
ContextMenuItem::item("Split Down", SplitDown),
|
||||||
|
],
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn toolbar(&self) -> &ViewHandle<Toolbar> {
|
pub fn toolbar(&self) -> &ViewHandle<Toolbar> {
|
||||||
&self.toolbar
|
&self.toolbar
|
||||||
}
|
}
|
||||||
|
@ -959,15 +987,21 @@ impl View for Pane {
|
||||||
|
|
||||||
let this = cx.handle();
|
let this = cx.handle();
|
||||||
|
|
||||||
|
Stack::new()
|
||||||
|
.with_child(
|
||||||
EventHandler::new(if let Some(active_item) = self.active_item() {
|
EventHandler::new(if let Some(active_item) = self.active_item() {
|
||||||
Flex::column()
|
Flex::column()
|
||||||
.with_child(
|
.with_child(
|
||||||
Flex::row()
|
Flex::row()
|
||||||
.with_child(self.render_tabs(cx).flex(1., true).named("tabs"))
|
.with_child(self.render_tabs(cx).flex(1., true).named("tabs"))
|
||||||
.with_child(
|
.with_child(
|
||||||
MouseEventHandler::new::<SplitIcon, _, _>(0, cx, |mouse_state, cx| {
|
MouseEventHandler::new::<SplitIcon, _, _>(
|
||||||
|
0,
|
||||||
|
cx,
|
||||||
|
|mouse_state, cx| {
|
||||||
let theme = &cx.global::<Settings>().theme.workspace;
|
let theme = &cx.global::<Settings>().theme.workspace;
|
||||||
let style = theme.pane_button.style_for(mouse_state, false);
|
let style =
|
||||||
|
theme.pane_button.style_for(mouse_state, false);
|
||||||
Svg::new("icons/split.svg")
|
Svg::new("icons/split.svg")
|
||||||
.with_color(style.color)
|
.with_color(style.color)
|
||||||
.constrained()
|
.constrained()
|
||||||
|
@ -980,8 +1014,12 @@ impl View for Pane {
|
||||||
.with_height(style.button_width)
|
.with_height(style.button_width)
|
||||||
.aligned()
|
.aligned()
|
||||||
.boxed()
|
.boxed()
|
||||||
})
|
},
|
||||||
|
)
|
||||||
.with_cursor_style(CursorStyle::PointingHand)
|
.with_cursor_style(CursorStyle::PointingHand)
|
||||||
|
.on_mouse_down(|position, cx| {
|
||||||
|
cx.dispatch_action(DeploySplitMenu { position });
|
||||||
|
})
|
||||||
.boxed(),
|
.boxed(),
|
||||||
)
|
)
|
||||||
.constrained()
|
.constrained()
|
||||||
|
@ -997,12 +1035,19 @@ impl View for Pane {
|
||||||
.on_navigate_mouse_down(move |direction, cx| {
|
.on_navigate_mouse_down(move |direction, cx| {
|
||||||
let this = this.clone();
|
let this = this.clone();
|
||||||
match direction {
|
match direction {
|
||||||
NavigationDirection::Back => cx.dispatch_action(GoBack { pane: Some(this) }),
|
NavigationDirection::Back => {
|
||||||
NavigationDirection::Forward => cx.dispatch_action(GoForward { pane: Some(this) }),
|
cx.dispatch_action(GoBack { pane: Some(this) })
|
||||||
|
}
|
||||||
|
NavigationDirection::Forward => {
|
||||||
|
cx.dispatch_action(GoForward { pane: Some(this) })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
})
|
})
|
||||||
|
.boxed(),
|
||||||
|
)
|
||||||
|
.with_child(ChildView::new(&self.split_menu).boxed())
|
||||||
.named("pane")
|
.named("pane")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,13 +8,14 @@ export default function contextMenu(theme: Theme) {
|
||||||
padding: 6,
|
padding: 6,
|
||||||
shadow: popoverShadow(theme),
|
shadow: popoverShadow(theme),
|
||||||
border: border(theme, "primary"),
|
border: border(theme, "primary"),
|
||||||
|
keystrokeMargin: 30,
|
||||||
item: {
|
item: {
|
||||||
padding: { left: 4, right: 4, top: 2, bottom: 2 },
|
padding: { left: 4, right: 4, top: 2, bottom: 2 },
|
||||||
cornerRadius: 6,
|
cornerRadius: 6,
|
||||||
label: text(theme, "sans", "secondary", { size: "sm" }),
|
label: text(theme, "sans", "secondary", { size: "sm" }),
|
||||||
keystroke: {
|
keystroke: {
|
||||||
margin: { left: 60 },
|
...text(theme, "sans", "muted", { size: "sm", weight: "bold" }),
|
||||||
...text(theme, "sans", "muted", { size: "sm", weight: "bold" })
|
padding: { left: 3, right: 3 }
|
||||||
},
|
},
|
||||||
hover: {
|
hover: {
|
||||||
background: backgroundColor(theme, 300, "hovered"),
|
background: backgroundColor(theme, 300, "hovered"),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue