Start work on combining both header states

Anthony Eid created

Change summary

crates/git_graph/src/git_graph.rs                   |   4 
crates/ui/src/components/data_table.rs              | 101 +++++---------
crates/ui/src/components/redistributable_columns.rs |  46 ++++++
3 files changed, 78 insertions(+), 73 deletions(-)

Detailed changes

crates/git_graph/src/git_graph.rs 🔗

@@ -2556,7 +2556,8 @@ impl Render for GitGraph {
                     this.child(self.render_loading_spinner(cx))
                 })
         } else {
-            let header_resize_info = HeaderResizeInfo::from_state(&self.column_widths, cx);
+            let header_resize_info =
+                HeaderResizeInfo::from_redistributable(&self.column_widths, cx);
             let header_context = TableRenderContext::for_column_widths(
                 Some(self.column_widths.read(cx).widths_to_render()),
                 true,
@@ -2599,7 +2600,6 @@ impl Render for GitGraph {
                             ),
                             header_context,
                             Some(header_resize_info),
-                            None,
                             Some(self.column_widths.entity_id()),
                             cx,
                         ))

crates/ui/src/components/data_table.rs 🔗

@@ -1,22 +1,22 @@
 use std::{ops::Range, rc::Rc};
 
-use gpui::{
-    AbsoluteLength, AppContext as _, ClickEvent, DefiniteLength, DragMoveEvent, Empty, Entity,
-    EntityId, FocusHandle, Length, ListHorizontalSizingBehavior, ListSizingBehavior, ListState,
-    Point, ScrollHandle, Stateful, UniformListScrollHandle, WeakEntity, list, transparent_black,
-    uniform_list,
-};
 use crate::{
     ActiveTheme as _, AnyElement, App, Button, ButtonCommon as _, ButtonStyle, Color, Component,
     ComponentScope, Context, Div, ElementId, FixedWidth as _, FluentBuilder as _, HeaderResizeInfo,
     Indicator, InteractiveElement, IntoElement, ParentElement, Pixels, RedistributableColumnsState,
     RegisterComponent, RenderOnce, ScrollAxes, ScrollableHandle, Scrollbars, SharedString,
     StatefulInteractiveElement, Styled, StyledExt as _, StyledTypography, TableResizeBehavior,
-    Window, WithScrollbar, bind_redistributable_columns, div, example_group_with_title, h_flex,
-    px, render_redistributable_columns_resize_handles, single_example,
+    Window, WithScrollbar, bind_redistributable_columns, div, example_group_with_title, h_flex, px,
+    render_redistributable_columns_resize_handles, single_example,
     table_row::{IntoTableRow as _, TableRow},
     v_flex,
 };
+use gpui::{
+    AbsoluteLength, AppContext as _, ClickEvent, DefiniteLength, DragMoveEvent, Empty, Entity,
+    EntityId, FocusHandle, Length, ListHorizontalSizingBehavior, ListSizingBehavior, ListState,
+    Point, ScrollHandle, Stateful, UniformListScrollHandle, WeakEntity, list, transparent_black,
+    uniform_list,
+};
 
 pub mod table_row;
 #[cfg(test)]
@@ -91,7 +91,7 @@ impl ResizableColumnsState {
         cx.notify();
     }
 
-    pub fn on_double_click(&mut self, col_idx: usize, _window: &mut Window) {
+    pub fn reset_column_to_initial_width(&mut self, col_idx: usize) {
         self.widths[col_idx] = self.initial_widths[col_idx];
     }
 
@@ -111,12 +111,6 @@ impl ResizableColumnsState {
     }
 }
 
-/// Info passed to `render_table_header` for resizable-column double-click reset.
-pub struct ResizableHeaderInfo {
-    pub entity: WeakEntity<ResizableColumnsState>,
-    pub resize_behavior: TableRow<TableResizeBehavior>,
-}
-
 struct UniformListData {
     render_list_of_rows_fn:
         Box<dyn Fn(Range<usize>, &mut Window, &mut App) -> Vec<UncheckedTableRow<AnyElement>>>,
@@ -282,9 +276,11 @@ impl ColumnWidthConfig {
             } => Some(entity.read(cx).widths_to_render()),
             ColumnWidthConfig::Resizable(entity) => {
                 let state = entity.read(cx);
-                Some(state.widths.map_cloned(|abs| {
-                    Length::Definite(DefiniteLength::Absolute(abs))
-                }))
+                Some(
+                    state
+                        .widths
+                        .map_cloned(|abs| Length::Definite(DefiniteLength::Absolute(abs))),
+                )
             }
         }
     }
@@ -313,7 +309,11 @@ impl ColumnWidthConfig {
     }
 
     /// ListHorizontalSizingBehavior for uniform_list.
-    pub fn list_horizontal_sizing(&self, window: &Window, cx: &App) -> ListHorizontalSizingBehavior {
+    pub fn list_horizontal_sizing(
+        &self,
+        window: &Window,
+        cx: &App,
+    ) -> ListHorizontalSizingBehavior {
         match self {
             ColumnWidthConfig::Resizable(_) => ListHorizontalSizingBehavior::FitList,
             _ => match self.table_width(window, cx) {
@@ -591,7 +591,6 @@ pub fn render_table_header(
     headers: TableRow<impl IntoElement>,
     table_context: TableRenderContext,
     resize_info: Option<HeaderResizeInfo>,
-    resizable_info: Option<ResizableHeaderInfo>,
     entity_id: Option<EntityId>,
     cx: &mut App,
 ) -> impl IntoElement {
@@ -634,29 +633,7 @@ pub fn render_table_header(
                             if info.resize_behavior[header_idx].is_resizable() {
                                 this.on_click(move |event, window, cx| {
                                     if event.click_count() > 1 {
-                                        info.columns_state
-                                            .update(cx, |column, _| {
-                                                column.reset_column_to_initial_width(
-                                                    header_idx, window,
-                                                );
-                                            })
-                                            .ok();
-                                    }
-                                })
-                            } else {
-                                this
-                            }
-                        })
-                        .when_some(resizable_info.as_ref(), |this, info| {
-                            if info.resize_behavior[header_idx].is_resizable() {
-                                let entity = info.entity.clone();
-                                this.on_click(move |event: &ClickEvent, window, cx| {
-                                    if event.click_count() > 1 {
-                                        entity
-                                            .update(cx, |state, _| {
-                                                state.on_double_click(header_idx, window);
-                                            })
-                                            .ok();
+                                        info.reset_column(header_idx, window, cx);
                                     }
                                 })
                             } else {
@@ -770,10 +747,11 @@ fn render_resize_handles_resizable(
                         .cursor_col_resize()
                         .on_click({
                             let columns_state = columns_state.clone();
-                            move |event: &ClickEvent, window, cx| {
+                            move |event: &ClickEvent, _window, cx| {
                                 if event.click_count() >= 2 {
-                                    columns_state.update(cx, |state, _| {
-                                        state.on_double_click(col_idx, window);
+                                    columns_state.update(cx, |state, cx| {
+                                        state.reset_column_to_initial_width(col_idx);
+                                        cx.notify();
                                     });
                                 }
                                 cx.stop_propagation();
@@ -816,19 +794,11 @@ impl RenderOnce for Table {
                 .as_ref()
                 .and_then(|_| match &self.column_width_config {
                     ColumnWidthConfig::Redistributable { columns_state, .. } => {
-                        Some(HeaderResizeInfo::from_state(columns_state, cx))
+                        Some(HeaderResizeInfo::from_redistributable(columns_state, cx))
+                    }
+                    ColumnWidthConfig::Resizable(entity) => {
+                        Some(HeaderResizeInfo::from_resizable(entity, cx))
                     }
-                    _ => None,
-                });
-
-        let resizable_header_info =
-            interaction_state
-                .as_ref()
-                .and_then(|_| match &self.column_width_config {
-                    ColumnWidthConfig::Resizable(entity) => Some(ResizableHeaderInfo {
-                        entity: entity.downgrade(),
-                        resize_behavior: entity.read(cx).resize_behavior.clone(),
-                    }),
                     _ => None,
                 });
 
@@ -886,7 +856,6 @@ impl RenderOnce for Table {
                     headers,
                     table_context.clone(),
                     header_resize_info,
-                    resizable_header_info,
                     interaction_state.as_ref().map(Entity::entity_id),
                     cx,
                 ))
@@ -1011,14 +980,12 @@ impl RenderOnce for Table {
                     .child(table);
                 h_scroll_container.style().restrict_scroll_to_axis = Some(true);
 
-                let outer = table_wrapper
-                    .child(h_scroll_container)
-                    .custom_scrollbars(
-                        Scrollbars::new(ScrollAxes::Horizontal)
-                            .tracked_scroll_handle(&state.read(cx).horizontal_scroll_handle),
-                        window,
-                        cx,
-                    );
+                let outer = table_wrapper.child(h_scroll_container).custom_scrollbars(
+                    Scrollbars::new(ScrollAxes::Horizontal)
+                        .tracked_scroll_handle(&state.read(cx).horizontal_scroll_handle),
+                    window,
+                    cx,
+                );
 
                 let scrollbars = state
                     .read(cx)

crates/ui/src/components/redistributable_columns.rs 🔗

@@ -6,7 +6,10 @@ use gpui::{
 };
 use itertools::intersperse_with;
 
-use super::data_table::table_row::{IntoTableRow as _, TableRow};
+use super::data_table::{
+    ResizableColumnsState,
+    table_row::{IntoTableRow as _, TableRow},
+};
 use crate::{
     ActiveTheme as _, AnyElement, App, Context, Div, FluentBuilder as _, InteractiveElement,
     IntoElement, ParentElement, Pixels, StatefulInteractiveElement, Styled, Window, div, h_flex,
@@ -40,20 +43,55 @@ impl TableResizeBehavior {
     }
 }
 
+#[derive(Clone)]
+pub(crate) enum ColumnsStateRef {
+    Redistributable(WeakEntity<RedistributableColumnsState>),
+    Resizable(WeakEntity<ResizableColumnsState>),
+}
+
 #[derive(Clone)]
 pub struct HeaderResizeInfo {
-    pub columns_state: WeakEntity<RedistributableColumnsState>,
+    pub(crate) columns_state: ColumnsStateRef,
     pub resize_behavior: TableRow<TableResizeBehavior>,
 }
 
 impl HeaderResizeInfo {
-    pub fn from_state(columns_state: &Entity<RedistributableColumnsState>, cx: &App) -> Self {
+    pub fn from_redistributable(
+        columns_state: &Entity<RedistributableColumnsState>,
+        cx: &App,
+    ) -> Self {
+        let resize_behavior = columns_state.read(cx).resize_behavior().clone();
+        Self {
+            columns_state: ColumnsStateRef::Redistributable(columns_state.downgrade()),
+            resize_behavior,
+        }
+    }
+
+    pub fn from_resizable(columns_state: &Entity<ResizableColumnsState>, cx: &App) -> Self {
         let resize_behavior = columns_state.read(cx).resize_behavior().clone();
         Self {
-            columns_state: columns_state.downgrade(),
+            columns_state: ColumnsStateRef::Resizable(columns_state.downgrade()),
             resize_behavior,
         }
     }
+
+    pub fn reset_column(&self, col_idx: usize, window: &mut Window, cx: &mut App) {
+        match &self.columns_state {
+            ColumnsStateRef::Redistributable(weak) => {
+                weak.update(cx, |state, _| {
+                    state.reset_column_to_initial_width(col_idx, window);
+                })
+                .ok();
+            }
+            ColumnsStateRef::Resizable(weak) => {
+                weak.update(cx, |state, cx| {
+                    state.reset_column_to_initial_width(col_idx);
+                    cx.notify();
+                })
+                .ok();
+            }
+        }
+    }
 }
 
 pub struct RedistributableColumnsState {