@@ -4,19 +4,18 @@ use crate::{
ActiveTheme as _, AnyElement, App, Button, ButtonCommon as _, ButtonStyle, Color, Component,
ComponentScope, Context, Div, DraggedColumn, ElementId, FixedWidth as _, FluentBuilder as _,
HeaderResizeInfo, Indicator, InteractiveElement, IntoElement, ParentElement, Pixels,
- RESIZE_COLUMN_WIDTH, RESIZE_DIVIDER_WIDTH, 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,
+ RESIZE_DIVIDER_WIDTH, 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_column_resize_divider,
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,
+ AbsoluteLength, DefiniteLength, DragMoveEvent, Entity, EntityId, FocusHandle, Length,
+ ListHorizontalSizingBehavior, ListSizingBehavior, ListState, Point, ScrollHandle, Stateful,
+ UniformListScrollHandle, WeakEntity, list, transparent_black, uniform_list,
};
pub mod table_row;
@@ -707,71 +706,27 @@ fn render_resize_handles_resizable(
} else {
accumulated_px
};
- let resize_behavior = Rc::clone(&resize_behavior);
- let columns_state = columns_state.clone();
- let divider = window.with_id(col_idx, |window| {
- let mut resize_divider = div()
- .id(col_idx)
- .absolute()
- .top_0()
- .left(divider_left)
- .w(px(RESIZE_DIVIDER_WIDTH))
- .h_full()
- .bg(cx.theme().colors().border.opacity(0.8));
-
- let mut resize_handle = div()
- .id("column-resize-handle")
- .absolute()
- .left_neg_0p5()
- .w(px(RESIZE_COLUMN_WIDTH))
- .h_full();
-
- if resize_behavior[col_idx].is_resizable() {
- let is_highlighted = window.use_state(cx, |_window, _cx| false);
-
- resize_divider = resize_divider.when(*is_highlighted.read(cx), |div| {
- div.bg(cx.theme().colors().border_focused)
+ let divider = div().id(col_idx).absolute().top_0().left(divider_left);
+ let entity_id = columns_state.entity_id();
+ let on_reset: Rc<dyn Fn(&mut Window, &mut App)> = {
+ let columns_state = columns_state.clone();
+ Rc::new(move |_window, cx| {
+ columns_state.update(cx, |state, cx| {
+ state.reset_column_to_initial_width(col_idx);
+ cx.notify();
});
-
- resize_handle = resize_handle
- .on_hover({
- let is_highlighted = is_highlighted.clone();
- move |&was_hovered, _, cx| is_highlighted.write(cx, was_hovered)
- })
- .cursor_col_resize()
- .on_click({
- let columns_state = columns_state.clone();
- move |event: &ClickEvent, _window, cx| {
- if event.click_count() >= 2 {
- columns_state.update(cx, |state, cx| {
- state.reset_column_to_initial_width(col_idx);
- cx.notify();
- });
- }
- cx.stop_propagation();
- }
- })
- .on_drag(
- DraggedColumn {
- col_idx,
- state_id: columns_state.entity_id(),
- },
- {
- let is_highlighted = is_highlighted.clone();
- move |_, _offset, _window, cx| {
- is_highlighted.write(cx, true);
- cx.new(|_cx| Empty)
- }
- },
- )
- .on_drop::<DraggedColumn>(move |_, _, cx| {
- is_highlighted.write(cx, false);
- });
- }
-
- resize_divider.child(resize_handle).into_any_element()
- });
- dividers.push(divider);
+ })
+ };
+ dividers.push(render_column_resize_divider(
+ divider,
+ col_idx,
+ resize_behavior[col_idx].is_resizable(),
+ entity_id,
+ on_reset,
+ None,
+ window,
+ cx,
+ ));
}
}
@@ -2,7 +2,7 @@ use std::rc::Rc;
use gpui::{
AbsoluteLength, AppContext as _, Bounds, DefiniteLength, DragMoveEvent, Empty, Entity,
- EntityId, Length, WeakEntity,
+ EntityId, Length, Stateful, WeakEntity,
};
use itertools::intersperse_with;
@@ -442,74 +442,35 @@ pub fn render_redistributable_columns_resize_handles(
let columns_state = columns_state.clone();
column_ix += 1;
- window.with_id(current_column_ix, |window| {
- let mut resize_divider = div()
- .id(current_column_ix)
- .relative()
- .top_0()
- .w(px(RESIZE_DIVIDER_WIDTH))
- .h_full()
- .bg(cx.theme().colors().border.opacity(0.8));
-
- let mut resize_handle = div()
- .id("column-resize-handle")
- .absolute()
- .left_neg_0p5()
- .w(px(RESIZE_COLUMN_WIDTH))
- .h_full();
-
- if resize_behavior[current_column_ix].is_resizable() {
- let is_highlighted = window.use_state(cx, |_window, _cx| false);
-
- resize_divider = resize_divider.when(*is_highlighted.read(cx), |div| {
- div.bg(cx.theme().colors().border_focused)
- });
-
- resize_handle = resize_handle
- .on_hover({
- let is_highlighted = is_highlighted.clone();
- move |&was_hovered, _, cx| is_highlighted.write(cx, was_hovered)
- })
- .cursor_col_resize()
- .on_click({
- let columns_state = columns_state.clone();
- move |event, window, cx| {
- if event.click_count() >= 2 {
- columns_state.update(cx, |columns, cx| {
- columns.reset_column_to_initial_width(
- current_column_ix,
- window,
- );
- cx.notify();
- });
- }
-
- cx.stop_propagation();
- }
- })
- .on_drag(
- DraggedColumn {
- col_idx: current_column_ix,
- state_id: columns_state.entity_id(),
- },
- {
- let is_highlighted = is_highlighted.clone();
- move |_, _offset, _window, cx| {
- is_highlighted.write(cx, true);
- cx.new(|_cx| Empty)
- }
- },
- )
- .on_drop::<DraggedColumn>(move |_, _, cx| {
- is_highlighted.write(cx, false);
- columns_state.update(cx, |state, _| {
- state.commit_preview();
- });
+ {
+ let divider = div().id(current_column_ix).relative().top_0();
+ let entity_id = columns_state.entity_id();
+ let on_reset: Rc<dyn Fn(&mut Window, &mut App)> = {
+ let columns_state = columns_state.clone();
+ Rc::new(move |window, cx| {
+ columns_state.update(cx, |columns, cx| {
+ columns.reset_column_to_initial_width(current_column_ix, window);
+ cx.notify();
});
- }
-
- resize_divider.child(resize_handle).into_any_element()
- })
+ })
+ };
+ let on_drag_end: Option<Rc<dyn Fn(&mut App)>> = {
+ let columns_state = columns_state.clone();
+ Some(Rc::new(move |cx| {
+ columns_state.update(cx, |state, _| state.commit_preview());
+ }))
+ };
+ render_column_resize_divider(
+ divider,
+ current_column_ix,
+ resize_behavior[current_column_ix].is_resizable(),
+ entity_id,
+ on_reset,
+ on_drag_end,
+ window,
+ cx,
+ )
+ }
},
);
@@ -522,6 +483,83 @@ pub fn render_redistributable_columns_resize_handles(
.into_any_element()
}
+/// Builds a single column resize divider with an interactive drag handle.
+///
+/// The caller provides:
+/// - `divider`: a pre-positioned divider element (with absolute or relative positioning)
+/// - `col_idx`: which column this divider is for
+/// - `is_resizable`: whether the column supports resizing
+/// - `entity_id`: the `EntityId` of the owning column state (for the drag payload)
+/// - `on_reset`: called on double-click to reset the column to its initial width
+/// - `on_drag_end`: called when the drag ends (e.g. to commit preview widths)
+pub(crate) fn render_column_resize_divider(
+ divider: Stateful<Div>,
+ col_idx: usize,
+ is_resizable: bool,
+ entity_id: EntityId,
+ on_reset: Rc<dyn Fn(&mut Window, &mut App)>,
+ on_drag_end: Option<Rc<dyn Fn(&mut App)>>,
+ window: &mut Window,
+ cx: &mut App,
+) -> AnyElement {
+ window.with_id(col_idx, |window| {
+ let mut resize_divider = divider.w(px(RESIZE_DIVIDER_WIDTH)).h_full().bg(cx
+ .theme()
+ .colors()
+ .border
+ .opacity(0.8));
+
+ let mut resize_handle = div()
+ .id("column-resize-handle")
+ .absolute()
+ .left_neg_0p5()
+ .w(px(RESIZE_COLUMN_WIDTH))
+ .h_full();
+
+ if is_resizable {
+ let is_highlighted = window.use_state(cx, |_window, _cx| false);
+
+ resize_divider = resize_divider.when(*is_highlighted.read(cx), |div| {
+ div.bg(cx.theme().colors().border_focused)
+ });
+
+ resize_handle = resize_handle
+ .on_hover({
+ let is_highlighted = is_highlighted.clone();
+ move |&was_hovered, _, cx| is_highlighted.write(cx, was_hovered)
+ })
+ .cursor_col_resize()
+ .on_click(move |event, window, cx| {
+ if event.click_count() >= 2 {
+ on_reset(window, cx);
+ }
+ cx.stop_propagation();
+ })
+ .on_drag(
+ DraggedColumn {
+ col_idx,
+ state_id: entity_id,
+ },
+ {
+ let is_highlighted = is_highlighted.clone();
+ move |_, _offset, _window, cx| {
+ is_highlighted.write(cx, true);
+ cx.new(|_cx| Empty)
+ }
+ },
+ )
+ .on_drop::<DraggedColumn>(move |_, _, cx| {
+ is_highlighted.write(cx, false);
+ if let Some(on_drag_end) = &on_drag_end {
+ on_drag_end(cx);
+ }
+ });
+ }
+
+ resize_divider.child(resize_handle).into_any_element()
+ })
+}
+
fn resize_spacer(width: Length) -> Div {
div().w(width).h_full()
}