Automatically include current view id in element state ids

Max Brunsfeld created

Change summary

crates/chat_panel/src/chat_panel.rs             |  26 +--
crates/contacts_panel/src/contacts_panel.rs     |   7 
crates/diagnostics/src/items.rs                 |   2 
crates/editor/src/editor.rs                     |  41 ++----
crates/find/src/find.rs                         |  29 ++--
crates/gpui/src/app.rs                          | 118 ++++++++----------
crates/gpui/src/elements/mouse_event_handler.rs |  12 -
crates/gpui/src/presenter.rs                    |  10 +
crates/gpui/src/views/select.rs                 |   6 
crates/project_panel/src/project_panel.rs       |   2 
crates/workspace/src/pane.rs                    |   4 
crates/workspace/src/sidebar.rs                 |  41 ++----
crates/workspace/src/workspace.rs               |   4 
13 files changed, 130 insertions(+), 172 deletions(-)

Detailed changes

crates/chat_panel/src/chat_panel.rs 🔗

@@ -325,21 +325,17 @@ impl ChatPanel {
         enum SignInPromptLabel {}
 
         Align::new(
-            MouseEventHandler::new::<SignInPromptLabel, _, _, _>(
-                cx.view_id(),
-                cx,
-                |mouse_state, _| {
-                    Label::new(
-                        "Sign in to use chat".to_string(),
-                        if mouse_state.hovered {
-                            theme.chat_panel.hovered_sign_in_prompt.clone()
-                        } else {
-                            theme.chat_panel.sign_in_prompt.clone()
-                        },
-                    )
-                    .boxed()
-                },
-            )
+            MouseEventHandler::new::<SignInPromptLabel, _, _>(0, cx, |mouse_state, _| {
+                Label::new(
+                    "Sign in to use chat".to_string(),
+                    if mouse_state.hovered {
+                        theme.chat_panel.hovered_sign_in_prompt.clone()
+                    } else {
+                        theme.chat_panel.sign_in_prompt.clone()
+                    },
+                )
+                .boxed()
+            })
             .with_cursor_style(CursorStyle::PointingHand)
             .on_click(move |cx| {
                 let rpc = rpc.clone();

crates/contacts_panel/src/contacts_panel.rs 🔗

@@ -27,7 +27,6 @@ impl ContactsPanel {
                 1000.,
                 {
                     let app_state = app_state.clone();
-                    let view_id = cx.view_id();
                     move |ix, cx| {
                         let user_store = app_state.user_store.read(cx);
                         let contacts = user_store.contacts().clone();
@@ -36,7 +35,6 @@ impl ContactsPanel {
                             &contacts[ix],
                             current_user_id,
                             app_state.clone(),
-                            view_id,
                             cx,
                         )
                     }
@@ -58,7 +56,6 @@ impl ContactsPanel {
         collaborator: &Contact,
         current_user_id: Option<u64>,
         app_state: Arc<AppState>,
-        view_id: usize,
         cx: &mut LayoutContext,
     ) -> ElementBox {
         let theme = &app_state.settings.borrow().theme.contacts_panel;
@@ -159,8 +156,8 @@ impl ContactsPanel {
                                 let is_shared = project.is_shared;
                                 let app_state = app_state.clone();
 
-                                MouseEventHandler::new::<ContactsPanel, _, _, _>(
-                                    (view_id, project_id as usize),
+                                MouseEventHandler::new::<ContactsPanel, _, _>(
+                                    project_id as usize,
                                     cx,
                                     |mouse_state, _| {
                                         let style = match (project.is_shared, mouse_state.hovered) {

crates/diagnostics/src/items.rs 🔗

@@ -57,7 +57,7 @@ impl View for DiagnosticSummary {
         let theme = &self.settings.borrow().theme.project_diagnostics;
 
         let in_progress = self.in_progress;
-        MouseEventHandler::new::<Tag, _, _, _>(cx.view_id(), cx, |_, _| {
+        MouseEventHandler::new::<Tag, _, _>(0, cx, |_, _| {
             if in_progress {
                 Label::new(
                     "Checking... ".to_string(),

crates/editor/src/editor.rs 🔗

@@ -523,7 +523,6 @@ impl ContextMenu {
 }
 
 struct CompletionsMenu {
-    editor_id: usize,
     id: CompletionId,
     initial_position: Anchor,
     buffer: ModelHandle<Buffer>,
@@ -561,7 +560,6 @@ impl CompletionsMenu {
         let settings = build_settings(cx);
         let completions = self.completions.clone();
         let matches = self.matches.clone();
-        let editor_id = self.editor_id;
         let selected_item = self.selected_item;
         UniformList::new(self.list.clone(), matches.len(), move |range, items, cx| {
             let settings = build_settings(cx);
@@ -570,8 +568,8 @@ impl CompletionsMenu {
                 let completion = &completions[mat.candidate_id];
                 let item_ix = start_ix + ix;
                 items.push(
-                    MouseEventHandler::new::<CompletionTag, _, _, _>(
-                        (editor_id, mat.candidate_id),
+                    MouseEventHandler::new::<CompletionTag, _, _>(
+                        mat.candidate_id,
                         cx,
                         |state, _| {
                             let item_style = if item_ix == selected_item {
@@ -668,7 +666,6 @@ impl CompletionsMenu {
 
 #[derive(Clone)]
 struct CodeActionsMenu {
-    editor_id: usize,
     actions: Arc<[CodeAction]>,
     buffer: ModelHandle<Buffer>,
     selected_item: usize,
@@ -705,7 +702,6 @@ impl CodeActionsMenu {
 
         let settings = build_settings(cx);
         let actions = self.actions.clone();
-        let editor_id = self.editor_id;
         let selected_item = self.selected_item;
         let element =
             UniformList::new(self.list.clone(), actions.len(), move |range, items, cx| {
@@ -714,28 +710,21 @@ impl CodeActionsMenu {
                 for (ix, action) in actions[range].iter().enumerate() {
                     let item_ix = start_ix + ix;
                     items.push(
-                        MouseEventHandler::new::<ActionTag, _, _, _>(
-                            (editor_id, item_ix),
-                            cx,
-                            |state, _| {
-                                let item_style = if item_ix == selected_item {
-                                    settings.style.autocomplete.selected_item
-                                } else if state.hovered {
-                                    settings.style.autocomplete.hovered_item
-                                } else {
-                                    settings.style.autocomplete.item
-                                };
-
-                                Text::new(
-                                    action.lsp_action.title.clone(),
-                                    settings.style.text.clone(),
-                                )
+                        MouseEventHandler::new::<ActionTag, _, _>(item_ix, cx, |state, _| {
+                            let item_style = if item_ix == selected_item {
+                                settings.style.autocomplete.selected_item
+                            } else if state.hovered {
+                                settings.style.autocomplete.hovered_item
+                            } else {
+                                settings.style.autocomplete.item
+                            };
+
+                            Text::new(action.lsp_action.title.clone(), settings.style.text.clone())
                                 .with_soft_wrap(false)
                                 .contained()
                                 .with_style(item_style)
                                 .boxed()
-                            },
-                        )
+                        })
                         .with_cursor_style(CursorStyle::PointingHand)
                         .on_mouse_down(move |cx| {
                             cx.dispatch_action(ConfirmCodeAction(Some(item_ix)));
@@ -1948,7 +1937,6 @@ impl Editor {
                 }
 
                 let mut menu = CompletionsMenu {
-                    editor_id: this.id(),
                     id,
                     initial_position: position,
                     match_candidates: completions
@@ -2131,7 +2119,6 @@ impl Editor {
                         if let Some((buffer, actions)) = this.available_code_actions.clone() {
                             this.show_context_menu(
                                 ContextMenu::CodeActions(CodeActionsMenu {
-                                    editor_id: this.handle.id(),
                                     buffer,
                                     actions,
                                     selected_item: Default::default(),
@@ -2277,7 +2264,7 @@ impl Editor {
             enum Tag {}
             let style = (self.build_settings)(cx).style;
             Some(
-                MouseEventHandler::new::<Tag, _, _, _>(cx.view_id(), cx, |_, _| {
+                MouseEventHandler::new::<Tag, _, _>(0, cx, |_, _| {
                     Svg::new("icons/zap.svg")
                         .with_color(style.code_actions_indicator)
                         .boxed()

crates/find/src/find.rs 🔗

@@ -227,7 +227,7 @@ impl FindBar {
     ) -> ElementBox {
         let theme = &self.settings.borrow().theme.find;
         let is_active = self.is_mode_enabled(mode);
-        MouseEventHandler::new::<Self, _, _, _>((cx.view_id(), mode as usize), cx, |state, _| {
+        MouseEventHandler::new::<Self, _, _>(mode as usize, cx, |state, _| {
             let style = match (is_active, state.hovered) {
                 (false, false) => &theme.mode_button,
                 (false, true) => &theme.hovered_mode_button,
@@ -251,21 +251,18 @@ impl FindBar {
         cx: &mut RenderContext<Self>,
     ) -> ElementBox {
         let theme = &self.settings.borrow().theme.find;
-        MouseEventHandler::new::<Self, _, _, _>(
-            (cx.view_id(), 10 + direction as usize),
-            cx,
-            |state, _| {
-                let style = if state.hovered {
-                    &theme.hovered_mode_button
-                } else {
-                    &theme.mode_button
-                };
-                Label::new(icon.to_string(), style.text.clone())
-                    .contained()
-                    .with_style(style.container)
-                    .boxed()
-            },
-        )
+        enum NavButton {}
+        MouseEventHandler::new::<NavButton, _, _>(direction as usize, cx, |state, _| {
+            let style = if state.hovered {
+                &theme.hovered_mode_button
+            } else {
+                &theme.mode_button
+            };
+            Label::new(icon.to_string(), style.text.clone())
+                .contained()
+                .with_style(style.container)
+                .boxed()
+        })
         .on_click(move |cx| cx.dispatch_action(GoToMatch(direction)))
         .with_cursor_style(CursorStyle::PointingHand)
         .boxed()

crates/gpui/src/app.rs 🔗

@@ -116,6 +116,26 @@ pub trait UpdateView {
         T: View;
 }
 
+pub trait ElementStateContext: DerefMut<Target = MutableAppContext> {
+    fn current_view_id(&self) -> usize;
+
+    fn element_state<Tag: 'static, T: 'static + Default>(
+        &mut self,
+        element_id: usize,
+    ) -> ElementStateHandle<T> {
+        let id = ElementStateId {
+            view_id: self.current_view_id(),
+            element_id,
+            tag: TypeId::of::<Tag>(),
+        };
+        self.cx
+            .element_states
+            .entry(id)
+            .or_insert_with(|| Box::new(T::default()));
+        ElementStateHandle::new(id, self.frame_count, &self.cx.ref_counts)
+    }
+}
+
 pub trait Action: 'static + AnyAction {
     type Argument: 'static + Clone;
 }
@@ -1414,23 +1434,6 @@ impl MutableAppContext {
         })
     }
 
-    pub fn element_state<Tag: 'static, T: 'static + Default>(
-        &mut self,
-        id: ElementStateId,
-    ) -> ElementStateHandle<T> {
-        let key = (TypeId::of::<Tag>(), id);
-        self.cx
-            .element_states
-            .entry(key)
-            .or_insert_with(|| Box::new(T::default()));
-        ElementStateHandle::new(
-            TypeId::of::<Tag>(),
-            id,
-            self.frame_count,
-            &self.cx.ref_counts,
-        )
-    }
-
     fn remove_dropped_entities(&mut self) {
         loop {
             let (dropped_models, dropped_views, dropped_element_states) =
@@ -1850,7 +1853,7 @@ pub struct AppContext {
     models: HashMap<usize, Box<dyn AnyModel>>,
     views: HashMap<(usize, usize), Box<dyn AnyView>>,
     windows: HashMap<usize, Window>,
-    element_states: HashMap<(TypeId, ElementStateId), Box<dyn Any>>,
+    element_states: HashMap<ElementStateId, Box<dyn Any>>,
     background: Arc<executor::Background>,
     ref_counts: Arc<Mutex<RefCounts>>,
     font_cache: Arc<FontCache>,
@@ -2607,6 +2610,12 @@ impl<V: View> ReadView for RenderContext<'_, V> {
     }
 }
 
+impl<V: View> ElementStateContext for RenderContext<'_, V> {
+    fn current_view_id(&self) -> usize {
+        self.view_id
+    }
+}
+
 impl<M> AsRef<AppContext> for ViewContext<'_, M> {
     fn as_ref(&self) -> &AppContext {
         &self.app.cx
@@ -2687,6 +2696,12 @@ impl<V: View> UpdateView for ViewContext<'_, V> {
     }
 }
 
+impl<V: View> ElementStateContext for ViewContext<'_, V> {
+    fn current_view_id(&self) -> usize {
+        self.view_id
+    }
+}
+
 pub trait Handle<T> {
     type Weak: 'static;
     fn id(&self) -> usize;
@@ -3430,41 +3445,24 @@ impl<T> Hash for WeakViewHandle<T> {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub struct ElementStateId(usize, usize);
-
-impl From<usize> for ElementStateId {
-    fn from(id: usize) -> Self {
-        Self(id, 0)
-    }
-}
-
-impl From<(usize, usize)> for ElementStateId {
-    fn from(id: (usize, usize)) -> Self {
-        Self(id.0, id.1)
-    }
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct ElementStateId {
+    view_id: usize,
+    element_id: usize,
+    tag: TypeId,
 }
 
 pub struct ElementStateHandle<T> {
     value_type: PhantomData<T>,
-    tag_type_id: TypeId,
     id: ElementStateId,
     ref_counts: Weak<Mutex<RefCounts>>,
 }
 
 impl<T: 'static> ElementStateHandle<T> {
-    fn new(
-        tag_type_id: TypeId,
-        id: ElementStateId,
-        frame_id: usize,
-        ref_counts: &Arc<Mutex<RefCounts>>,
-    ) -> Self {
-        ref_counts
-            .lock()
-            .inc_element_state(tag_type_id, id, frame_id);
+    fn new(id: ElementStateId, frame_id: usize, ref_counts: &Arc<Mutex<RefCounts>>) -> Self {
+        ref_counts.lock().inc_element_state(id, frame_id);
         Self {
             value_type: PhantomData,
-            tag_type_id,
             id,
             ref_counts: Arc::downgrade(ref_counts),
         }
@@ -3472,7 +3470,7 @@ impl<T: 'static> ElementStateHandle<T> {
 
     pub fn read<'a>(&self, cx: &'a AppContext) -> &'a T {
         cx.element_states
-            .get(&(self.tag_type_id, self.id))
+            .get(&self.id)
             .unwrap()
             .downcast_ref()
             .unwrap()
@@ -3482,17 +3480,12 @@ impl<T: 'static> ElementStateHandle<T> {
     where
         C: DerefMut<Target = MutableAppContext>,
     {
-        let mut element_state = cx
-            .deref_mut()
-            .cx
-            .element_states
-            .remove(&(self.tag_type_id, self.id))
-            .unwrap();
+        let mut element_state = cx.deref_mut().cx.element_states.remove(&self.id).unwrap();
         let result = f(element_state.downcast_mut().unwrap(), cx);
         cx.deref_mut()
             .cx
             .element_states
-            .insert((self.tag_type_id, self.id), element_state);
+            .insert(self.id, element_state);
         result
     }
 }
@@ -3500,9 +3493,7 @@ impl<T: 'static> ElementStateHandle<T> {
 impl<T> Drop for ElementStateHandle<T> {
     fn drop(&mut self) {
         if let Some(ref_counts) = self.ref_counts.upgrade() {
-            ref_counts
-                .lock()
-                .dec_element_state(self.tag_type_id, self.id);
+            ref_counts.lock().dec_element_state(self.id);
         }
     }
 }
@@ -3600,10 +3591,10 @@ impl Drop for Subscription {
 #[derive(Default)]
 struct RefCounts {
     entity_counts: HashMap<usize, usize>,
-    element_state_counts: HashMap<(TypeId, ElementStateId), ElementStateRefCount>,
+    element_state_counts: HashMap<ElementStateId, ElementStateRefCount>,
     dropped_models: HashSet<usize>,
     dropped_views: HashSet<(usize, usize)>,
-    dropped_element_states: HashSet<(TypeId, ElementStateId)>,
+    dropped_element_states: HashSet<ElementStateId>,
 }
 
 struct ElementStateRefCount {
@@ -3634,8 +3625,8 @@ impl RefCounts {
         }
     }
 
-    fn inc_element_state(&mut self, tag_type_id: TypeId, id: ElementStateId, frame_id: usize) {
-        match self.element_state_counts.entry((tag_type_id, id)) {
+    fn inc_element_state(&mut self, id: ElementStateId, frame_id: usize) {
+        match self.element_state_counts.entry(id) {
             Entry::Occupied(mut entry) => {
                 let entry = entry.get_mut();
                 if entry.frame_id == frame_id || entry.ref_count >= 2 {
@@ -3649,7 +3640,7 @@ impl RefCounts {
                     ref_count: 1,
                     frame_id,
                 });
-                self.dropped_element_states.remove(&(tag_type_id, id));
+                self.dropped_element_states.remove(&id);
             }
         }
     }
@@ -3672,13 +3663,12 @@ impl RefCounts {
         }
     }
 
-    fn dec_element_state(&mut self, tag_type_id: TypeId, id: ElementStateId) {
-        let key = (tag_type_id, id);
-        let entry = self.element_state_counts.get_mut(&key).unwrap();
+    fn dec_element_state(&mut self, id: ElementStateId) {
+        let entry = self.element_state_counts.get_mut(&id).unwrap();
         entry.ref_count -= 1;
         if entry.ref_count == 0 {
-            self.element_state_counts.remove(&key);
-            self.dropped_element_states.insert(key);
+            self.element_state_counts.remove(&id);
+            self.dropped_element_states.insert(id);
         }
     }
 
@@ -3691,7 +3681,7 @@ impl RefCounts {
     ) -> (
         HashSet<usize>,
         HashSet<(usize, usize)>,
-        HashSet<(TypeId, ElementStateId)>,
+        HashSet<ElementStateId>,
     ) {
         (
             std::mem::take(&mut self.dropped_models),

crates/gpui/src/elements/mouse_event_handler.rs 🔗

@@ -5,11 +5,10 @@ use crate::{
         vector::{vec2f, Vector2F},
     },
     platform::CursorStyle,
-    CursorStyleHandle, DebugContext, Element, ElementBox, ElementStateHandle, ElementStateId,
-    Event, EventContext, LayoutContext, MutableAppContext, PaintContext, SizeConstraint,
+    CursorStyleHandle, DebugContext, Element, ElementBox, ElementStateContext, ElementStateHandle,
+    Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
 };
 use serde_json::json;
-use std::ops::DerefMut;
 
 pub struct MouseEventHandler {
     state: ElementStateHandle<MouseState>,
@@ -30,14 +29,13 @@ pub struct MouseState {
 }
 
 impl MouseEventHandler {
-    pub fn new<Tag, F, C, Id>(id: Id, cx: &mut C, render_child: F) -> Self
+    pub fn new<Tag, C, F>(id: usize, cx: &mut C, render_child: F) -> Self
     where
         Tag: 'static,
+        C: ElementStateContext,
         F: FnOnce(&MouseState, &mut C) -> ElementBox,
-        C: DerefMut<Target = MutableAppContext>,
-        Id: Into<ElementStateId>,
     {
-        let state_handle = cx.element_state::<Tag, _>(id.into());
+        let state_handle = cx.element_state::<Tag, _>(id);
         let child = state_handle.update(cx, |state, cx| render_child(state, cx));
         Self {
             state: state_handle,

crates/gpui/src/presenter.rs 🔗

@@ -7,8 +7,8 @@ use crate::{
     platform::Event,
     text_layout::TextLayoutCache,
     Action, AnyAction, AnyModelHandle, AnyViewHandle, AnyWeakModelHandle, AssetCache, ElementBox,
-    Entity, FontSystem, ModelHandle, ReadModel, ReadView, Scene, UpgradeModelHandle,
-    UpgradeViewHandle, View, ViewHandle, WeakModelHandle, WeakViewHandle,
+    ElementStateContext, Entity, FontSystem, ModelHandle, ReadModel, ReadView, Scene,
+    UpgradeModelHandle, UpgradeViewHandle, View, ViewHandle, WeakModelHandle, WeakViewHandle,
 };
 use pathfinder_geometry::vector::{vec2f, Vector2F};
 use serde_json::json;
@@ -292,6 +292,12 @@ impl<'a> UpgradeViewHandle for LayoutContext<'a> {
     }
 }
 
+impl<'a> ElementStateContext for LayoutContext<'a> {
+    fn current_view_id(&self) -> usize {
+        *self.view_stack.last().unwrap()
+    }
+}
+
 pub struct PaintContext<'a> {
     rendered_views: &'a mut HashMap<usize, ElementBox>,
     pub scene: &'a mut Scene,

crates/gpui/src/views/select.rs 🔗

@@ -104,7 +104,7 @@ impl View for Select {
             Default::default()
         };
         let mut result = Flex::column().with_child(
-            MouseEventHandler::new::<Header, _, _, _>(self.handle.id(), cx, |mouse_state, cx| {
+            MouseEventHandler::new::<Header, _, _>(self.handle.id(), cx, |mouse_state, cx| {
                 Container::new((self.render_item)(
                     self.selected_item_ix,
                     ItemType::Header,
@@ -132,8 +132,8 @@ impl View for Select {
                                     let selected_item_ix = this.selected_item_ix;
                                     range.end = range.end.min(this.item_count);
                                     items.extend(range.map(|ix| {
-                                        MouseEventHandler::new::<Item, _, _, _>(
-                                            (handle.id(), ix),
+                                        MouseEventHandler::new::<Item, _, _>(
+                                            ix,
                                             cx,
                                             |mouse_state, cx| {
                                                 (handle.read(cx).render_item)(

crates/project_panel/src/project_panel.rs 🔗

@@ -476,7 +476,7 @@ impl ProjectPanel {
         cx: &mut ViewContext<Self>,
     ) -> ElementBox {
         let is_dir = details.is_dir;
-        MouseEventHandler::new::<Self, _, _, _>((cx.view_id(), entry.entry_id), cx, |state, _| {
+        MouseEventHandler::new::<Self, _, _>(entry.entry_id, cx, |state, _| {
             let style = match (details.is_selected, state.hovered) {
                 (false, false) => &theme.entry,
                 (false, true) => &theme.hovered_entry,

crates/workspace/src/pane.rs 🔗

@@ -466,7 +466,7 @@ impl Pane {
         let theme = &settings.theme;
 
         enum Tabs {}
-        let tabs = MouseEventHandler::new::<Tabs, _, _, _>(cx.view_id(), cx, |mouse_state, cx| {
+        let tabs = MouseEventHandler::new::<Tabs, _, _>(0, cx, |mouse_state, cx| {
             let mut row = Flex::row();
             for (ix, (_, item_view)) in self.item_views.iter().enumerate() {
                 let is_active = ix == self.active_item_index;
@@ -543,7 +543,7 @@ impl Pane {
                                             let item_id = item_view.id();
                                             enum TabCloseButton {}
                                             let icon = Svg::new("icons/x.svg");
-                                            MouseEventHandler::new::<TabCloseButton, _, _, _>(
+                                            MouseEventHandler::new::<TabCloseButton, _, _>(
                                                 item_id,
                                                 cx,
                                                 |mouse_state, _| {

crates/workspace/src/sidebar.rs 🔗

@@ -83,26 +83,22 @@ impl Sidebar {
                             &theme.item
                         };
                         enum SidebarButton {}
-                        MouseEventHandler::new::<SidebarButton, _, _, _>(
-                            item.view.id(),
-                            cx,
-                            |_, _| {
-                                ConstrainedBox::new(
-                                    Align::new(
-                                        ConstrainedBox::new(
-                                            Svg::new(item.icon_path)
-                                                .with_color(theme.icon_color)
-                                                .boxed(),
-                                        )
-                                        .with_height(theme.icon_size)
-                                        .boxed(),
+                        MouseEventHandler::new::<SidebarButton, _, _>(item.view.id(), cx, |_, _| {
+                            ConstrainedBox::new(
+                                Align::new(
+                                    ConstrainedBox::new(
+                                        Svg::new(item.icon_path)
+                                            .with_color(theme.icon_color)
+                                            .boxed(),
                                     )
+                                    .with_height(theme.icon_size)
                                     .boxed(),
                                 )
-                                .with_height(theme.height)
-                                .boxed()
-                            },
-                        )
+                                .boxed(),
+                            )
+                            .with_height(theme.height)
+                            .boxed()
+                        })
                         .with_cursor_style(CursorStyle::PointingHand)
                         .on_mouse_down(move |cx| {
                             cx.dispatch_action(ToggleSidebarItem(SidebarItemId {
@@ -161,7 +157,7 @@ impl Sidebar {
     ) -> ElementBox {
         let width = self.width.clone();
         let side = self.side;
-        MouseEventHandler::new::<Self, _, _, _>((cx.view_id(), self.side.id()), cx, |_, _| {
+        MouseEventHandler::new::<Self, _, _>(side as usize, cx, |_, _| {
             Container::new(Empty::new().boxed())
                 .with_style(self.theme(settings).resize_handle)
                 .boxed()
@@ -184,12 +180,3 @@ impl Sidebar {
         .boxed()
     }
 }
-
-impl Side {
-    fn id(self) -> usize {
-        match self {
-            Side::Left => 0,
-            Side::Right => 1,
-        }
-    }
-}

crates/workspace/src/workspace.rs 🔗

@@ -1191,7 +1191,7 @@ impl Workspace {
         if let Some(avatar) = user.and_then(|user| user.avatar.clone()) {
             self.render_avatar(avatar, replica_id, theme)
         } else {
-            MouseEventHandler::new::<Authenticate, _, _, _>(cx.view_id(), cx, |state, _| {
+            MouseEventHandler::new::<Authenticate, _, _>(0, cx, |state, _| {
                 let style = if state.hovered {
                     &theme.workspace.titlebar.hovered_sign_in_prompt
                 } else {
@@ -1252,7 +1252,7 @@ impl Workspace {
                 theme.workspace.titlebar.share_icon_color
             };
             Some(
-                MouseEventHandler::new::<Share, _, _, _>(cx.view_id(), cx, |_, _| {
+                MouseEventHandler::new::<Share, _, _>(0, cx, |_, _| {
                     Align::new(
                         ConstrainedBox::new(
                             Svg::new("icons/broadcast-24.svg").with_color(color).boxed(),