use std::fmt::Display; use gpui::{ App, Context, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement, KeyContext, ModifiersChangedEvent, MouseButton, ParentElement, Rems, Render, Styled, Subscription, WeakEntity, Window, actions, rems,};use project::git_store::Repository;use ui::{ FluentBuilder, ToggleButtonGroup, ToggleButtonGroupStyle, ToggleButtonSimple, Tooltip, prelude::*,};use workspace::{ModalView, Workspace, pane}; use crate::branch_picker::{self, BranchList, DeleteBranch, FilterRemotes};use crate::stash_picker::{self, DropStashItem, ShowStashItem, StashList};use crate::worktree_picker::{ self, DeleteWorktree, WorktreeFromDefault, WorktreeFromDefaultOnWindow, WorktreeList,}; actions!( git_picker, [ActivateBranchesTab, ActivateWorktreesTab, ActivateStashTab,]); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]pub enum GitPickerTab { Branches, Worktrees, Stash,} impl Display for GitPickerTab { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let label = match self { GitPickerTab::Branches => "Branches", GitPickerTab::Worktrees => "Worktrees", GitPickerTab::Stash => "Stash", }; write!(f, "{}", label) }} pub struct GitPicker { tab: GitPickerTab, workspace: WeakEntity<Workspace>, repository: Option<Entity<Repository>>, width: Rems, branch_list: Option<Entity<BranchList>>, worktree_list: Option<Entity<WorktreeList>>, stash_list: Option<Entity<StashList>>, _subscriptions: Vec<Subscription>, popover_style: bool,} impl GitPicker { pub fn new( workspace: WeakEntity<Workspace>, repository: Option<Entity<Repository>>, initial_tab: GitPickerTab, width: Rems, window: &mut Window, cx: &mut Context<Self>, ) -> Self { Self::new_internal(workspace, repository, initial_tab, width, false, window, cx) } fn new_internal( workspace: WeakEntity<Workspace>, repository: Option<Entity<Repository>>, initial_tab: GitPickerTab, width: Rems, popover_style: bool, window: &mut Window, cx: &mut Context<Self>, ) -> Self { let mut this = Self { tab: initial_tab, workspace, repository, width, branch_list: None, worktree_list: None, stash_list: None, _subscriptions: Vec::new(), popover_style, }; this.ensure_active_picker(window, cx); this } fn ensure_active_picker(&mut self, window: &mut Window, cx: &mut Context<Self>) { match self.tab { GitPickerTab::Branches => { self.ensure_branch_list(window, cx); } GitPickerTab::Worktrees => { self.ensure_worktree_list(window, cx); } GitPickerTab::Stash => { self.ensure_stash_list(window, cx); } } } fn ensure_branch_list( &mut self, window: &mut Window, cx: &mut Context<Self>, ) -> Entity<BranchList> { if self.branch_list.is_none() { let branch_list = cx.new(|cx| { branch_picker::create_embedded( self.workspace.clone(), self.repository.clone(), self.width, window, cx, ) }); let subscription = cx.subscribe(&branch_list, |this, _, _: &DismissEvent, cx| { if this.tab == GitPickerTab::Branches { cx.emit(DismissEvent); } }); self._subscriptions.push(subscription); self.branch_list = Some(branch_list); } self.branch_list.clone().unwrap() } fn ensure_worktree_list( &mut self, window: &mut Window, cx: &mut Context<Self>, ) -> Entity<WorktreeList> { if self.worktree_list.is_none() { let worktree_list = cx.new(|cx| { worktree_picker::create_embedded( self.repository.clone(), self.workspace.clone(), self.width, window, cx, ) }); let subscription = cx.subscribe(&worktree_list, |this, _, _: &DismissEvent, cx| { if this.tab == GitPickerTab::Worktrees { cx.emit(DismissEvent); } }); self._subscriptions.push(subscription); self.worktree_list = Some(worktree_list); } self.worktree_list.clone().unwrap() } fn ensure_stash_list( &mut self, window: &mut Window, cx: &mut Context<Self>, ) -> Entity<StashList> { if self.stash_list.is_none() { let stash_list = cx.new(|cx| { stash_picker::create_embedded( self.repository.clone(), self.workspace.clone(), self.width, window, cx, ) }); let subscription = cx.subscribe(&stash_list, |this, _, _: &DismissEvent, cx| { if this.tab == GitPickerTab::Stash { cx.emit(DismissEvent); } }); self._subscriptions.push(subscription); self.stash_list = Some(stash_list); } self.stash_list.clone().unwrap() } fn activate_next_tab(&mut self, window: &mut Window, cx: &mut Context<Self>) { self.tab = match self.tab { GitPickerTab::Branches => GitPickerTab::Worktrees, GitPickerTab::Worktrees => GitPickerTab::Stash, GitPickerTab::Stash => GitPickerTab::Branches, }; self.ensure_active_picker(window, cx); self.focus_active_picker(window, cx); cx.notify(); } fn activate_previous_tab(&mut self, window: &mut Window, cx: &mut Context<Self>) { self.tab = match self.tab { GitPickerTab::Branches => GitPickerTab::Stash, GitPickerTab::Worktrees => GitPickerTab::Branches, GitPickerTab::Stash => GitPickerTab::Worktrees, }; self.ensure_active_picker(window, cx); self.focus_active_picker(window, cx); cx.notify(); } fn focus_active_picker(&self, window: &mut Window, cx: &mut App) { match self.tab { GitPickerTab::Branches => { if let Some(branch_list) = &self.branch_list { branch_list.focus_handle(cx).focus(window, cx); } } GitPickerTab::Worktrees => { if let Some(worktree_list) = &self.worktree_list { worktree_list.focus_handle(cx).focus(window, cx); } } GitPickerTab::Stash => { if let Some(stash_list) = &self.stash_list { stash_list.focus_handle(cx).focus(window, cx); } } } } fn render_tab_bar(&self, cx: &mut Context<Self>) -> impl IntoElement { let focus_handle = self.focus_handle(cx); let branches_focus_handle = focus_handle.clone(); let worktrees_focus_handle = focus_handle.clone(); let stash_focus_handle = focus_handle; h_flex().p_2().pb_0p5().w_full().child( ToggleButtonGroup::single_row( "git-picker-tabs", [ ToggleButtonSimple::new( GitPickerTab::Branches.to_string(), cx.listener(|this, _, window, cx| { this.tab = GitPickerTab::Branches; this.ensure_active_picker(window, cx); this.focus_active_picker(window, cx); cx.notify(); }), ) .tooltip(move |_, cx| { Tooltip::for_action_in( "Toggle Branch Picker", &ActivateBranchesTab, &branches_focus_handle, cx, ) }), ToggleButtonSimple::new( GitPickerTab::Worktrees.to_string(), cx.listener(|this, _, window, cx| { this.tab = GitPickerTab::Worktrees; this.ensure_active_picker(window, cx); this.focus_active_picker(window, cx); cx.notify(); }), ) .tooltip(move |_, cx| { Tooltip::for_action_in( "Toggle Worktree Picker", &ActivateWorktreesTab, &worktrees_focus_handle, cx, ) }), ToggleButtonSimple::new( GitPickerTab::Stash.to_string(), cx.listener(|this, _, window, cx| { this.tab = GitPickerTab::Stash; this.ensure_active_picker(window, cx); this.focus_active_picker(window, cx); cx.notify(); }), ) .tooltip(move |_, cx| { Tooltip::for_action_in( "Toggle Stash Picker", &ActivateStashTab, &stash_focus_handle, cx, ) }), ], ) .label_size(LabelSize::Default) .style(ToggleButtonGroupStyle::Outlined) .auto_width() .selected_index(match self.tab { GitPickerTab::Branches => 0, GitPickerTab::Worktrees => 1, GitPickerTab::Stash => 2, }), ) } fn render_active_picker( &mut self, window: &mut Window, cx: &mut Context<Self>, ) -> impl IntoElement { match self.tab { GitPickerTab::Branches => { let branch_list = self.ensure_branch_list(window, cx); branch_list.into_any_element() } GitPickerTab::Worktrees => { let worktree_list = self.ensure_worktree_list(window, cx); worktree_list.into_any_element() } GitPickerTab::Stash => { let stash_list = self.ensure_stash_list(window, cx); stash_list.into_any_element() } } } fn handle_modifiers_changed( &mut self, ev: &ModifiersChangedEvent, window: &mut Window, cx: &mut Context<Self>, ) { match self.tab { GitPickerTab::Branches => { if let Some(branch_list) = &self.branch_list { branch_list.update(cx, |list, cx| { list.handle_modifiers_changed(ev, window, cx); }); } } GitPickerTab::Worktrees => { if let Some(worktree_list) = &self.worktree_list { worktree_list.update(cx, |list, cx| { list.handle_modifiers_changed(ev, window, cx); }); } } GitPickerTab::Stash => { if let Some(stash_list) = &self.stash_list { stash_list.update(cx, |list, cx| { list.handle_modifiers_changed(ev, window, cx); }); } } } } fn handle_delete_branch( &mut self, _: &DeleteBranch, window: &mut Window, cx: &mut Context<Self>, ) { if let Some(branch_list) = &self.branch_list { branch_list.update(cx, |list, cx| { list.handle_delete(&DeleteBranch, window, cx); }); } } fn handle_filter_remotes( &mut self, _: &FilterRemotes, window: &mut Window, cx: &mut Context<Self>, ) { if let Some(branch_list) = &self.branch_list { branch_list.update(cx, |list, cx| { list.handle_filter(&FilterRemotes, window, cx); }); } } fn handle_worktree_from_default( &mut self, _: &WorktreeFromDefault, window: &mut Window, cx: &mut Context<Self>, ) { if let Some(worktree_list) = &self.worktree_list { worktree_list.update(cx, |list, cx| { list.handle_new_worktree(false, window, cx); }); } } fn handle_worktree_from_default_on_window( &mut self, _: &WorktreeFromDefaultOnWindow, window: &mut Window, cx: &mut Context<Self>, ) { if let Some(worktree_list) = &self.worktree_list { worktree_list.update(cx, |list, cx| { list.handle_new_worktree(true, window, cx); }); } } fn handle_worktree_delete( &mut self, _: &DeleteWorktree, window: &mut Window, cx: &mut Context<Self>, ) { if let Some(worktree_list) = &self.worktree_list { worktree_list.update(cx, |list, cx| { list.handle_delete(&DeleteWorktree, window, cx); }); } } fn handle_drop_stash( &mut self, _: &DropStashItem, window: &mut Window, cx: &mut Context<Self>, ) { if let Some(stash_list) = &self.stash_list { stash_list.update(cx, |list, cx| { list.handle_drop_stash(&DropStashItem, window, cx); }); } } fn handle_show_stash( &mut self, _: &ShowStashItem, window: &mut Window, cx: &mut Context<Self>, ) { if let Some(stash_list) = &self.stash_list { stash_list.update(cx, |list, cx| { list.handle_show_stash(&ShowStashItem, window, cx); }); } }} impl ModalView for GitPicker {}impl EventEmitter<DismissEvent> for GitPicker {} impl Focusable for GitPicker { fn focus_handle(&self, cx: &App) -> FocusHandle { match self.tab { GitPickerTab::Branches => { if let Some(branch_list) = &self.branch_list { return branch_list.focus_handle(cx); } } GitPickerTab::Worktrees => { if let Some(worktree_list) = &self.worktree_list { return worktree_list.focus_handle(cx); } } GitPickerTab::Stash => { if let Some(stash_list) = &self.stash_list { return stash_list.focus_handle(cx); } } } cx.focus_handle() }} impl Render for GitPicker { fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { v_flex() .occlude() .w(self.width) .elevation_3(cx) .overflow_hidden() .when(self.popover_style, |el| { el.on_mouse_down_out(cx.listener(|_, _, _, cx| { cx.emit(DismissEvent); })) }) .key_context({ let mut key_context = KeyContext::new_with_defaults(); key_context.add("Pane"); key_context.add("GitPicker"); match self.tab { GitPickerTab::Branches => key_context.add("GitBranchSelector"), GitPickerTab::Worktrees => key_context.add("GitWorktreeSelector"), GitPickerTab::Stash => key_context.add("StashList"), } key_context }) .on_mouse_down(MouseButton::Left, |_, _, cx| {Lines 1–500 of 626. Load more
use std::fmt::Display; use gpui::{ App, Context, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement, KeyContext, ModifiersChangedEvent, MouseButton, ParentElement, Rems, Render, Styled, Subscription, WeakEntity, Window, actions, rems, }; use project::git_store::Repository; use ui::{ FluentBuilder, ToggleButtonGroup, ToggleButtonGroupStyle, ToggleButtonSimple, Tooltip, prelude::*, }; use workspace::{ModalView, Workspace, pane}; use crate::branch_picker::{self, BranchList, DeleteBranch, FilterRemotes}; use crate::stash_picker::{self, DropStashItem, ShowStashItem, StashList}; use crate::worktree_picker::{ self, DeleteWorktree, WorktreeFromDefault, WorktreeFromDefaultOnWindow, WorktreeList, }; actions!( git_picker, [ActivateBranchesTab, ActivateWorktreesTab, ActivateStashTab,] ); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum GitPickerTab { Branches, Worktrees, Stash, } impl Display for GitPickerTab { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let label = match self { GitPickerTab::Branches => "Branches", GitPickerTab::Worktrees => "Worktrees", GitPickerTab::Stash => "Stash", }; write!(f, "{}", label) } } pub struct GitPicker { tab: GitPickerTab, workspace: WeakEntity<Workspace>, repository: Option<Entity<Repository>>, width: Rems, branch_list: Option<Entity<BranchList>>, worktree_list: Option<Entity<WorktreeList>>, stash_list: Option<Entity<StashList>>, _subscriptions: Vec<Subscription>, popover_style: bool, } impl GitPicker { pub fn new( workspace: WeakEntity<Workspace>, repository: Option<Entity<Repository>>, initial_tab: GitPickerTab, width: Rems, window: &mut Window, cx: &mut Context<Self>, ) -> Self { Self::new_internal(workspace, repository, initial_tab, width, false, window, cx) } fn new_internal( workspace: WeakEntity<Workspace>, repository: Option<Entity<Repository>>, initial_tab: GitPickerTab, width: Rems, popover_style: bool, window: &mut Window, cx: &mut Context<Self>, ) -> Self { let mut this = Self { tab: initial_tab, workspace, repository, width, branch_list: None, worktree_list: None, stash_list: None, _subscriptions: Vec::new(), popover_style, }; this.ensure_active_picker(window, cx); this } fn ensure_active_picker(&mut self, window: &mut Window, cx: &mut Context<Self>) { match self.tab { GitPickerTab::Branches => { self.ensure_branch_list(window, cx); } GitPickerTab::Worktrees => { self.ensure_worktree_list(window, cx); } GitPickerTab::Stash => { self.ensure_stash_list(window, cx); } } } fn ensure_branch_list( &mut self, window: &mut Window, cx: &mut Context<Self>, ) -> Entity<BranchList> { if self.branch_list.is_none() { let branch_list = cx.new(|cx| { branch_picker::create_embedded( self.workspace.clone(), self.repository.clone(), self.width, window, cx, ) }); let subscription = cx.subscribe(&branch_list, |this, _, _: &DismissEvent, cx| { if this.tab == GitPickerTab::Branches { cx.emit(DismissEvent); } }); self._subscriptions.push(subscription); self.branch_list = Some(branch_list); } self.branch_list.clone().unwrap() } fn ensure_worktree_list( &mut self, window: &mut Window, cx: &mut Context<Self>, ) -> Entity<WorktreeList> { if self.worktree_list.is_none() { let worktree_list = cx.new(|cx| { worktree_picker::create_embedded( self.repository.clone(), self.workspace.clone(), self.width, window, cx, ) }); let subscription = cx.subscribe(&worktree_list, |this, _, _: &DismissEvent, cx| { if this.tab == GitPickerTab::Worktrees { cx.emit(DismissEvent); } }); self._subscriptions.push(subscription); self.worktree_list = Some(worktree_list); } self.worktree_list.clone().unwrap() } fn ensure_stash_list( &mut self, window: &mut Window, cx: &mut Context<Self>, ) -> Entity<StashList> { if self.stash_list.is_none() { let stash_list = cx.new(|cx| { stash_picker::create_embedded( self.repository.clone(), self.workspace.clone(), self.width, window, cx, ) }); let subscription = cx.subscribe(&stash_list, |this, _, _: &DismissEvent, cx| { if this.tab == GitPickerTab::Stash { cx.emit(DismissEvent); } }); self._subscriptions.push(subscription); self.stash_list = Some(stash_list); } self.stash_list.clone().unwrap() } fn activate_next_tab(&mut self, window: &mut Window, cx: &mut Context<Self>) { self.tab = match self.tab { GitPickerTab::Branches => GitPickerTab::Worktrees, GitPickerTab::Worktrees => GitPickerTab::Stash, GitPickerTab::Stash => GitPickerTab::Branches, }; self.ensure_active_picker(window, cx); self.focus_active_picker(window, cx); cx.notify(); } fn activate_previous_tab(&mut self, window: &mut Window, cx: &mut Context<Self>) { self.tab = match self.tab { GitPickerTab::Branches => GitPickerTab::Stash, GitPickerTab::Worktrees => GitPickerTab::Branches, GitPickerTab::Stash => GitPickerTab::Worktrees, }; self.ensure_active_picker(window, cx); self.focus_active_picker(window, cx); cx.notify(); } fn focus_active_picker(&self, window: &mut Window, cx: &mut App) { match self.tab { GitPickerTab::Branches => { if let Some(branch_list) = &self.branch_list { branch_list.focus_handle(cx).focus(window, cx); } } GitPickerTab::Worktrees => { if let Some(worktree_list) = &self.worktree_list { worktree_list.focus_handle(cx).focus(window, cx); } } GitPickerTab::Stash => { if let Some(stash_list) = &self.stash_list { stash_list.focus_handle(cx).focus(window, cx); } } } } fn render_tab_bar(&self, cx: &mut Context<Self>) -> impl IntoElement { let focus_handle = self.focus_handle(cx); let branches_focus_handle = focus_handle.clone(); let worktrees_focus_handle = focus_handle.clone(); let stash_focus_handle = focus_handle; h_flex().p_2().pb_0p5().w_full().child( ToggleButtonGroup::single_row( "git-picker-tabs", [ ToggleButtonSimple::new( GitPickerTab::Branches.to_string(), cx.listener(|this, _, window, cx| { this.tab = GitPickerTab::Branches; this.ensure_active_picker(window, cx); this.focus_active_picker(window, cx); cx.notify(); }), ) .tooltip(move |_, cx| { Tooltip::for_action_in( "Toggle Branch Picker", &ActivateBranchesTab, &branches_focus_handle, cx, ) }), ToggleButtonSimple::new( GitPickerTab::Worktrees.to_string(), cx.listener(|this, _, window, cx| { this.tab = GitPickerTab::Worktrees; this.ensure_active_picker(window, cx); this.focus_active_picker(window, cx); cx.notify(); }), ) .tooltip(move |_, cx| { Tooltip::for_action_in( "Toggle Worktree Picker", &ActivateWorktreesTab, &worktrees_focus_handle, cx, ) }), ToggleButtonSimple::new( GitPickerTab::Stash.to_string(), cx.listener(|this, _, window, cx| { this.tab = GitPickerTab::Stash; this.ensure_active_picker(window, cx); this.focus_active_picker(window, cx); cx.notify(); }), ) .tooltip(move |_, cx| { Tooltip::for_action_in( "Toggle Stash Picker", &ActivateStashTab, &stash_focus_handle, cx, ) }), ], ) .label_size(LabelSize::Default) .style(ToggleButtonGroupStyle::Outlined) .auto_width() .selected_index(match self.tab { GitPickerTab::Branches => 0, GitPickerTab::Worktrees => 1, GitPickerTab::Stash => 2, }), ) } fn render_active_picker( &mut self, window: &mut Window, cx: &mut Context<Self>, ) -> impl IntoElement { match self.tab { GitPickerTab::Branches => { let branch_list = self.ensure_branch_list(window, cx); branch_list.into_any_element() } GitPickerTab::Worktrees => { let worktree_list = self.ensure_worktree_list(window, cx); worktree_list.into_any_element() } GitPickerTab::Stash => { let stash_list = self.ensure_stash_list(window, cx); stash_list.into_any_element() } } } fn handle_modifiers_changed( &mut self, ev: &ModifiersChangedEvent, window: &mut Window, cx: &mut Context<Self>, ) { match self.tab { GitPickerTab::Branches => { if let Some(branch_list) = &self.branch_list { branch_list.update(cx, |list, cx| { list.handle_modifiers_changed(ev, window, cx); }); } } GitPickerTab::Worktrees => { if let Some(worktree_list) = &self.worktree_list { worktree_list.update(cx, |list, cx| { list.handle_modifiers_changed(ev, window, cx); }); } } GitPickerTab::Stash => { if let Some(stash_list) = &self.stash_list { stash_list.update(cx, |list, cx| { list.handle_modifiers_changed(ev, window, cx); }); } } } } fn handle_delete_branch( &mut self, _: &DeleteBranch, window: &mut Window, cx: &mut Context<Self>, ) { if let Some(branch_list) = &self.branch_list { branch_list.update(cx, |list, cx| { list.handle_delete(&DeleteBranch, window, cx); }); } } fn handle_filter_remotes( &mut self, _: &FilterRemotes, window: &mut Window, cx: &mut Context<Self>, ) { if let Some(branch_list) = &self.branch_list { branch_list.update(cx, |list, cx| { list.handle_filter(&FilterRemotes, window, cx); }); } } fn handle_worktree_from_default( &mut self, _: &WorktreeFromDefault, window: &mut Window, cx: &mut Context<Self>, ) { if let Some(worktree_list) = &self.worktree_list { worktree_list.update(cx, |list, cx| { list.handle_new_worktree(false, window, cx); }); } } fn handle_worktree_from_default_on_window( &mut self, _: &WorktreeFromDefaultOnWindow, window: &mut Window, cx: &mut Context<Self>, ) { if let Some(worktree_list) = &self.worktree_list { worktree_list.update(cx, |list, cx| { list.handle_new_worktree(true, window, cx); }); } } fn handle_worktree_delete( &mut self, _: &DeleteWorktree, window: &mut Window, cx: &mut Context<Self>, ) { if let Some(worktree_list) = &self.worktree_list { worktree_list.update(cx, |list, cx| { list.handle_delete(&DeleteWorktree, window, cx); }); } } fn handle_drop_stash( &mut self, _: &DropStashItem, window: &mut Window, cx: &mut Context<Self>, ) { if let Some(stash_list) = &self.stash_list { stash_list.update(cx, |list, cx| { list.handle_drop_stash(&DropStashItem, window, cx); }); } } fn handle_show_stash( &mut self, _: &ShowStashItem, window: &mut Window, cx: &mut Context<Self>, ) { if let Some(stash_list) = &self.stash_list { stash_list.update(cx, |list, cx| { list.handle_show_stash(&ShowStashItem, window, cx); }); } } } impl ModalView for GitPicker {} impl EventEmitter<DismissEvent> for GitPicker {} impl Focusable for GitPicker { fn focus_handle(&self, cx: &App) -> FocusHandle { match self.tab { GitPickerTab::Branches => { if let Some(branch_list) = &self.branch_list { return branch_list.focus_handle(cx); } } GitPickerTab::Worktrees => { if let Some(worktree_list) = &self.worktree_list { return worktree_list.focus_handle(cx); } } GitPickerTab::Stash => { if let Some(stash_list) = &self.stash_list { return stash_list.focus_handle(cx); } } } cx.focus_handle() } } impl Render for GitPicker { fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { v_flex() .occlude() .w(self.width) .elevation_3(cx) .overflow_hidden() .when(self.popover_style, |el| { el.on_mouse_down_out(cx.listener(|_, _, _, cx| { cx.emit(DismissEvent); })) }) .key_context({ let mut key_context = KeyContext::new_with_defaults(); key_context.add("Pane"); key_context.add("GitPicker"); match self.tab { GitPickerTab::Branches => key_context.add("GitBranchSelector"), GitPickerTab::Worktrees => key_context.add("GitWorktreeSelector"), GitPickerTab::Stash => key_context.add("StashList"), } key_context }) .on_mouse_down(MouseButton::Left, |_, _, cx| {