table: Render table stripe on background even there is no enough rows (#256)

<img width="1202" alt="image"
src="https://github.com/user-attachments/assets/57a744c3-673a-4118-ba97-03837b0b9390">

- And add `flex_shrink_0` to table head.

Fix https://github.com/huacnlee/gpui-component/issues/160

---------

Co-authored-by: Jason Lee <huacnlee@gmail.com>
This commit is contained in:
xda 2024-09-24 23:07:27 +09:00 committed by GitHub
parent 2a331fcb79
commit 1e44b5659f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -284,6 +284,11 @@ where
cx.notify(); cx.notify();
} }
fn scroll_to_row(&mut self, row_ix: usize, cx: &mut ViewContext<Self>) {
self.vertical_scroll_handle.scroll_to_item(row_ix);
cx.notify();
}
fn set_selected_row(&mut self, row_ix: usize, cx: &mut ViewContext<Self>) { fn set_selected_row(&mut self, row_ix: usize, cx: &mut ViewContext<Self>) {
self.selection_state = SelectionState::Row; self.selection_state = SelectionState::Row;
self.selected_row = Some(row_ix); self.selected_row = Some(row_ix);
@ -737,6 +742,28 @@ where
let cols_count: usize = self.delegate.cols_count(); let cols_count: usize = self.delegate.cols_count();
let rows_count = self.delegate.rows_count(); let rows_count = self.delegate.rows_count();
let row_height = self.vertical_scroll_handle.0.borrow().last_item_height;
let total_height = self
.vertical_scroll_handle
.0
.borrow()
.base_handle
.bounds()
.size
.height;
// Calculate the extra rows needed to fill the table for stripe style.
let mut extra_rows_needed = 0;
if let Some(row_height) = row_height {
if row_height > px(0.) {
let actual_height = row_height * rows_count as f32;
let remaining_height = total_height - actual_height;
if remaining_height > px(0.) {
extra_rows_needed = (remaining_height / row_height).ceil() as usize;
}
}
}
fn last_empty_col(_: &mut WindowContext) -> Div { fn last_empty_col(_: &mut WindowContext) -> Div {
h_flex().w(px(100.)).h_full().flex_shrink_0() h_flex().w(px(100.)).h_full().flex_shrink_0()
} }
@ -761,6 +788,7 @@ where
.flex_grow() .flex_grow()
.h_10() .h_10()
.w_full() .w_full()
.flex_shrink_0()
.border_b_1() .border_b_1()
.border_color(cx.theme().border) .border_color(cx.theme().border)
.child( .child(
@ -795,70 +823,128 @@ where
} else { } else {
this.child( this.child(
h_flex().id("table-body").flex_grow().size_full().child( h_flex().id("table-body").flex_grow().size_full().child(
uniform_list(view, "table-uniform-list", rows_count, { uniform_list(
let horizontal_scroll_handle = horizontal_scroll_handle.clone(); view,
move |table, visible_range, cx| { "table-uniform-list",
table.load_more(visible_range.clone(), cx); rows_count + extra_rows_needed,
{
let horizontal_scroll_handle = horizontal_scroll_handle.clone();
move |table, visible_range, cx| {
table.load_more(visible_range.clone(), cx);
visible_range if visible_range.end > rows_count {
.map(|row_ix| { table.scroll_to_row(
table std::cmp::min(visible_range.start, rows_count - 1),
.delegate cx,
.render_tr(row_ix, cx) );
.id(("table-row", row_ix)) }
.w_full()
.when(row_ix > 0, |this| { // Render fake rows to fill the table
this.border_t_1() visible_range
.border_color(cx.theme().border) .map(|row_ix| {
}) // Render real rows for available data
.when(table.stripe && row_ix % 2 != 0, |this| { if row_ix < rows_count {
this.bg(cx.theme().table_even)
})
.hover(|this| {
if table.selected_row == Some(row_ix) {
this
} else {
this.bg(cx.theme().table_hover)
}
})
.children((0..cols_count).map(|col_ix| {
table table
.col_wrap(col_ix, cx) // Make the row scroll sync with the horizontal_scroll_handle to support horizontal scrolling. .delegate
.left(horizontal_scroll_handle.offset().x) .render_tr(row_ix, cx)
.child( .id(("table-row", row_ix))
.w_full()
.when(row_ix > 0, |this| {
this.border_t_1()
.border_color(cx.theme().border)
})
.when(
table.stripe && row_ix % 2 != 0,
|this| this.bg(cx.theme().table_even),
)
.hover(|this| {
if table.selected_row == Some(row_ix) {
this
} else {
this.bg(cx.theme().table_hover)
}
})
.children((0..cols_count).map(|col_ix| {
table table
.render_cell(col_ix, cx) // Make the row scroll sync with the horizontal_scroll_handle to support horizontal scrolling.
.flex_shrink_0() .col_wrap(col_ix, cx)
.left(
horizontal_scroll_handle
.offset()
.x,
)
.child( .child(
table.delegate.render_td( table
row_ix, col_ix, cx, .render_cell(col_ix, cx)
), .flex_shrink_0()
), .child(
table
.delegate
.render_td(
row_ix, col_ix,
cx,
),
),
)
}))
.child(last_empty_col(cx))
// Row selected style
.when_some(
table.selected_row,
|this, selected_row| {
this.when(
row_ix == selected_row
&& table.selection_state
== SelectionState::Row,
|this| {
this.bg(cx
.theme()
.table_active)
},
)
},
) )
})) .on_mouse_down(
.child(last_empty_col(cx)) MouseButton::Left,
// Row selected style cx.listener(move |this, _, cx| {
.when_some( this.on_row_click(row_ix, cx);
table.selected_row, }),
|this, selected_row| {
this.when(
row_ix == selected_row
&& table.selection_state
== SelectionState::Row,
|this| this.bg(cx.theme().table_active),
) )
}, } else {
) // Render fake rows to fill the rest table space
.on_mouse_down( table
MouseButton::Left, .delegate
cx.listener(move |this, _, cx| { .render_tr(row_ix, cx)
this.on_row_click(row_ix, cx); .id(("table-row-fake", row_ix))
}), .w_full()
) .h_full()
}) .border_t_1()
.collect::<Vec<_>>() .border_color(cx.theme().border)
} .when(
}) table.stripe && row_ix % 2 != 0,
|this| this.bg(cx.theme().table_even),
)
.children((0..cols_count).map(|col_ix| {
h_flex()
.left(
horizontal_scroll_handle
.offset()
.x,
)
.child(
table
.render_cell(col_ix, cx)
.flex_shrink_0()
.child(div().size_full()),
)
}))
.child(last_empty_col(cx))
}
})
.collect::<Vec<_>>()
}
},
)
.flex_grow() .flex_grow()
.size_full() .size_full()
.with_sizing_behavior(gpui::ListSizingBehavior::Auto) .with_sizing_behavior(gpui::ListSizingBehavior::Auto)