Added icons to context menu

This commit is contained in:
Mikayla Maki 2022-08-03 16:47:41 -07:00
parent bf0ec13e65
commit 96cc6d5ce5
6 changed files with 93 additions and 44 deletions

View file

@ -26,15 +26,17 @@ pub enum ContextMenuItem {
Item { Item {
label: String, label: String,
action: Box<dyn Action>, action: Box<dyn Action>,
icon: Option<String>,
}, },
Separator, Separator,
} }
impl ContextMenuItem { impl ContextMenuItem {
pub fn item(label: impl ToString, action: impl 'static + Action) -> Self { pub fn item(label: impl ToString, icon: Option<&str>, action: impl 'static + Action) -> Self {
Self::Item { Self::Item {
label: label.to_string(), label: label.to_string(),
action: Box::new(action), action: Box::new(action),
icon: icon.map(|item| item.to_string()),
} }
} }
@ -254,14 +256,31 @@ impl ContextMenu {
Flex::column() Flex::column()
.with_children(self.items.iter().enumerate().map(|(ix, item)| { .with_children(self.items.iter().enumerate().map(|(ix, item)| {
match item { match item {
ContextMenuItem::Item { label, .. } => { ContextMenuItem::Item { label, icon, .. } => {
let style = style let style = style
.item .item
.style_for(Default::default(), Some(ix) == self.selected_index); .style_for(Default::default(), Some(ix) == self.selected_index);
Label::new(label.to_string(), style.label.clone()) let mut line = Flex::row();
.contained() if let Some(_) = icon {
.with_style(style.container) line.add_child(
.boxed() Empty::new()
.constrained()
.with_width(style.icon_width)
.boxed(),
);
}
line.add_child(
Label::new(label.to_string(), style.label.clone())
.contained()
.with_style(style.container)
.with_margin_left(if icon.is_some() {
style.icon_spacing
} else {
0.
})
.boxed(),
);
line.boxed()
} }
ContextMenuItem::Separator => Empty::new() ContextMenuItem::Separator => Empty::new()
.collapsed() .collapsed()
@ -314,27 +333,50 @@ impl ContextMenu {
Flex::column() Flex::column()
.with_children(self.items.iter().enumerate().map(|(ix, item)| { .with_children(self.items.iter().enumerate().map(|(ix, item)| {
match item { match item {
ContextMenuItem::Item { label, action } => { ContextMenuItem::Item {
label,
action,
icon,
} => {
let action = action.boxed_clone(); let action = action.boxed_clone();
MouseEventHandler::new::<MenuItem, _, _>(ix, cx, |state, _| { MouseEventHandler::new::<MenuItem, _, _>(ix, cx, |state, _| {
let style = let style =
style.item.style_for(state, Some(ix) == self.selected_index); style.item.style_for(state, Some(ix) == self.selected_index);
Flex::row()
.with_child( let mut line = Flex::row();
Label::new(label.to_string(), style.label.clone()).boxed(), if let Some(icon_file) = icon {
line.add_child(
Svg::new(format!("icons/{}", icon_file))
.with_color(style.label.color)
.constrained()
.with_width(style.icon_width)
.aligned()
.boxed(),
) )
.with_child({ }
KeystrokeLabel::new(
action.boxed_clone(), line.with_child(
style.keystroke.container, Label::new(label.to_string(), style.label.clone())
style.keystroke.text.clone(), .contained()
) .with_margin_left(if icon.is_some() {
.flex_float() style.icon_spacing
.boxed() } else {
}) 0.
.contained() })
.with_style(style.container) .boxed(),
)
.with_child({
KeystrokeLabel::new(
action.boxed_clone(),
style.keystroke.container,
style.keystroke.text.clone(),
)
.flex_float()
.boxed() .boxed()
})
.contained()
.with_style(style.container)
.boxed()
}) })
.with_cursor_style(CursorStyle::PointingHand) .with_cursor_style(CursorStyle::PointingHand)
.on_click(MouseButton::Left, move |_, cx| { .on_click(MouseButton::Left, move |_, cx| {

View file

@ -48,12 +48,13 @@ pub fn deploy_context_menu(
menu.show( menu.show(
position, position,
vec![ vec![
ContextMenuItem::item("Rename Symbol", Rename), ContextMenuItem::item("Rename Symbol", None, Rename),
ContextMenuItem::item("Go To Definition", GoToDefinition), ContextMenuItem::item("Go To Definition", None, GoToDefinition),
ContextMenuItem::item("Go To Type Definition", GoToTypeDefinition), ContextMenuItem::item("Go To Type Definition", None, GoToTypeDefinition),
ContextMenuItem::item("Find All References", FindAllReferences), ContextMenuItem::item("Find All References", None, FindAllReferences),
ContextMenuItem::item( ContextMenuItem::item(
"Code Actions", "Code Actions",
None,
ToggleCodeActions { ToggleCodeActions {
deployed_from_indicator: false, deployed_from_indicator: false,
}, },

View file

@ -269,30 +269,32 @@ impl ProjectPanel {
if !project.is_remote() { if !project.is_remote() {
menu_entries.push(ContextMenuItem::item( menu_entries.push(ContextMenuItem::item(
"Add Folder to Project", "Add Folder to Project",
None,
workspace::AddFolderToProject, workspace::AddFolderToProject,
)); ));
if is_root { if is_root {
menu_entries.push(ContextMenuItem::item( menu_entries.push(ContextMenuItem::item(
"Remove from Project", "Remove from Project",
None,
workspace::RemoveWorktreeFromProject(worktree_id), workspace::RemoveWorktreeFromProject(worktree_id),
)); ));
} }
} }
menu_entries.push(ContextMenuItem::item("New File", AddFile)); menu_entries.push(ContextMenuItem::item("New File", None, AddFile));
menu_entries.push(ContextMenuItem::item("New Folder", AddDirectory)); menu_entries.push(ContextMenuItem::item("New Folder", None, AddDirectory));
menu_entries.push(ContextMenuItem::Separator); menu_entries.push(ContextMenuItem::Separator);
menu_entries.push(ContextMenuItem::item("Copy", Copy)); menu_entries.push(ContextMenuItem::item("Copy", None, Copy));
menu_entries.push(ContextMenuItem::item("Copy Path", CopyPath)); menu_entries.push(ContextMenuItem::item("Copy Path", None, CopyPath));
menu_entries.push(ContextMenuItem::item("Cut", Cut)); menu_entries.push(ContextMenuItem::item("Cut", None, Cut));
if let Some(clipboard_entry) = self.clipboard_entry { if let Some(clipboard_entry) = self.clipboard_entry {
if clipboard_entry.worktree_id() == worktree.id() { if clipboard_entry.worktree_id() == worktree.id() {
menu_entries.push(ContextMenuItem::item("Paste", Paste)); menu_entries.push(ContextMenuItem::item("Paste", None, Paste));
} }
} }
menu_entries.push(ContextMenuItem::Separator); menu_entries.push(ContextMenuItem::Separator);
menu_entries.push(ContextMenuItem::item("Rename", Rename)); menu_entries.push(ContextMenuItem::item("Rename", None, Rename));
if !is_root { if !is_root {
menu_entries.push(ContextMenuItem::item("Delete", Delete)); menu_entries.push(ContextMenuItem::item("Delete", None, Delete));
} }
} }

View file

@ -267,6 +267,8 @@ pub struct ContextMenuItem {
pub container: ContainerStyle, pub container: ContainerStyle,
pub label: TextStyle, pub label: TextStyle,
pub keystroke: ContainedText, pub keystroke: ContainedText,
pub icon_width: f32,
pub icon_spacing: f32,
} }
#[derive(Debug, Deserialize, Default)] #[derive(Debug, Deserialize, Default)]

View file

@ -147,7 +147,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>, context_menu: ViewHandle<ContextMenu>,
} }
pub struct ItemNavHistory { pub struct ItemNavHistory {
@ -203,7 +203,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, context_menu: split_menu,
} }
} }
@ -837,14 +837,14 @@ impl Pane {
} }
fn deploy_split_menu(&mut self, action: &DeploySplitMenu, cx: &mut ViewContext<Self>) { fn deploy_split_menu(&mut self, action: &DeploySplitMenu, cx: &mut ViewContext<Self>) {
self.split_menu.update(cx, |menu, cx| { self.context_menu.update(cx, |menu, cx| {
menu.show( menu.show(
action.position, action.position,
vec![ vec![
ContextMenuItem::item("Split Right", SplitRight), ContextMenuItem::item("Split Right", None, SplitRight),
ContextMenuItem::item("Split Left", SplitLeft), ContextMenuItem::item("Split Left", None, SplitLeft),
ContextMenuItem::item("Split Up", SplitUp), ContextMenuItem::item("Split Up", None, SplitUp),
ContextMenuItem::item("Split Down", SplitDown), ContextMenuItem::item("Split Down", None, SplitDown),
], ],
cx, cx,
); );
@ -852,12 +852,12 @@ impl Pane {
} }
fn deploy_new_menu(&mut self, action: &DeployNewMenu, cx: &mut ViewContext<Self>) { fn deploy_new_menu(&mut self, action: &DeployNewMenu, cx: &mut ViewContext<Self>) {
self.split_menu.update(cx, |menu, cx| { self.context_menu.update(cx, |menu, cx| {
menu.show( menu.show(
action.position, action.position,
vec![ vec![
ContextMenuItem::item("New File", NewFile), ContextMenuItem::item("New File", Some("circle_info_12.svg"), NewFile),
ContextMenuItem::item("New Terminal", NewTerminal), ContextMenuItem::item("New Terminal", Some("terminal_12.svg"), NewTerminal),
], ],
cx, cx,
); );
@ -1204,7 +1204,7 @@ impl View for Pane {
}) })
.boxed(), .boxed(),
) )
.with_child(ChildView::new(&self.split_menu).boxed()) .with_child(ChildView::new(&self.context_menu).boxed())
.named("pane") .named("pane")
} }

View file

@ -16,6 +16,8 @@ export default function contextMenu(theme: Theme) {
border: border(theme, "primary"), border: border(theme, "primary"),
keystrokeMargin: 30, keystrokeMargin: 30,
item: { item: {
iconSpacing: 8,
iconWidth: 14,
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", "primary", { size: "sm" }), label: text(theme, "sans", "primary", { size: "sm" }),