Add to support Table column resizing. (#75)
https://github.com/user-attachments/assets/d56f2cd7-df08-437b-9eea-849d68094e1f
This commit is contained in:
parent
11034ec2ac
commit
79958fc95c
3 changed files with 276 additions and 92 deletions
|
|
@ -1,13 +1,12 @@
|
|||
|
||||
use fake::Fake;
|
||||
use gpui::{
|
||||
ParentElement, Render, SharedString, Styled, View, ViewContext,
|
||||
VisualContext as _, WindowContext,
|
||||
ParentElement, Pixels, Render, SharedString, Styled, View, ViewContext, VisualContext as _,
|
||||
WindowContext,
|
||||
};
|
||||
use ui::{
|
||||
checkbox::Checkbox,
|
||||
h_flex,
|
||||
table::{Table, TableDelegate},
|
||||
table::{Table, TableDelegate, TableEvent},
|
||||
v_flex, Selectable, Selection,
|
||||
};
|
||||
|
||||
|
|
@ -97,7 +96,7 @@ impl TableDelegate for CustomerTableDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
fn col_width(&self, col_ix: usize) -> Option<f32> {
|
||||
fn col_width(&self, col_ix: usize) -> Option<Pixels> {
|
||||
match col_ix {
|
||||
0 => Some(50.0),
|
||||
1 => Some(220.0),
|
||||
|
|
@ -115,6 +114,15 @@ impl TableDelegate for CustomerTableDelegate {
|
|||
13 => Some(90.0),
|
||||
_ => None,
|
||||
}
|
||||
.map(Pixels::from)
|
||||
}
|
||||
|
||||
fn can_resize_col(&self, col_ix: usize) -> bool {
|
||||
return col_ix > 1;
|
||||
}
|
||||
|
||||
fn on_col_widths_changed(&mut self, col_widths: Vec<Option<Pixels>>) {
|
||||
println!("Col widths changed: {:?}", col_widths);
|
||||
}
|
||||
|
||||
fn render_td(&self, row_ix: usize, col_ix: usize) -> impl gpui::IntoElement {
|
||||
|
|
@ -156,6 +164,9 @@ impl TableStory {
|
|||
fn new(cx: &mut ViewContext<Self>) -> Self {
|
||||
let delegate = CustomerTableDelegate::new(2000);
|
||||
let table = cx.new_view(|cx| Table::new(delegate, cx));
|
||||
|
||||
cx.subscribe(&table, Self::on_table_event).detach();
|
||||
|
||||
Self { table }
|
||||
}
|
||||
|
||||
|
|
@ -166,6 +177,21 @@ impl TableStory {
|
|||
cx.notify();
|
||||
});
|
||||
}
|
||||
|
||||
fn on_table_event(
|
||||
&mut self,
|
||||
_: View<Table<CustomerTableDelegate>>,
|
||||
event: &TableEvent,
|
||||
_cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
match event {
|
||||
TableEvent::ColWidthsChanged(col_widths) => {
|
||||
println!("Col widths changed: {:?}", col_widths)
|
||||
}
|
||||
TableEvent::SelectCol(ix) => println!("Select col: {}", ix),
|
||||
TableEvent::SelectRow(ix) => println!("Select row: {}", ix),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for TableStory {
|
||||
|
|
|
|||
|
|
@ -3,14 +3,15 @@ use std::{cell::Cell, rc::Rc};
|
|||
use crate::{
|
||||
h_flex,
|
||||
scroll::{ScrollableAxis, ScrollableMask, Scrollbar, ScrollbarState},
|
||||
theme::{ActiveTheme, Colorize},
|
||||
theme::ActiveTheme,
|
||||
v_flex,
|
||||
};
|
||||
use gpui::{
|
||||
actions, div, prelude::FluentBuilder as _, px, uniform_list, AppContext, Div, FocusHandle,
|
||||
FocusableView, InteractiveElement as _, IntoElement, KeyBinding, MouseButton,
|
||||
ParentElement as _, Render, ScrollHandle, SharedString, StatefulInteractiveElement as _,
|
||||
Styled, UniformListScrollHandle, ViewContext, WindowContext,
|
||||
actions, canvas, div, prelude::FluentBuilder as _, px, uniform_list, AppContext, Bounds, Div,
|
||||
DragMoveEvent, EntityId, EventEmitter, FocusHandle, FocusableView, InteractiveElement as _,
|
||||
IntoElement, KeyBinding, MouseButton, ParentElement as _, Pixels, Render, ScrollHandle,
|
||||
SharedString, StatefulInteractiveElement as _, Styled, UniformListScrollHandle, ViewContext,
|
||||
VisualContext as _, WindowContext,
|
||||
};
|
||||
|
||||
actions!(
|
||||
|
|
@ -36,15 +37,26 @@ pub fn init(cx: &mut AppContext) {
|
|||
}
|
||||
|
||||
struct ColGroup {
|
||||
width: Option<f32>,
|
||||
width: Option<Pixels>,
|
||||
bounds: Bounds<Pixels>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Render)]
|
||||
pub struct DragCol(pub (EntityId, usize));
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
enum SelectionState {
|
||||
Column,
|
||||
Row,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum TableEvent {
|
||||
SelectRow(usize),
|
||||
SelectCol(usize),
|
||||
ColWidthsChanged(Vec<Option<Pixels>>),
|
||||
}
|
||||
|
||||
pub struct Table<D: TableDelegate> {
|
||||
focus_handle: FocusHandle,
|
||||
delegate: D,
|
||||
|
|
@ -57,6 +69,9 @@ pub struct Table<D: TableDelegate> {
|
|||
selection_state: SelectionState,
|
||||
selected_row: Option<usize>,
|
||||
selected_col: Option<usize>,
|
||||
|
||||
/// The column index that is being resized.
|
||||
resizing_col: Option<usize>,
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
|
|
@ -76,10 +91,12 @@ pub trait TableDelegate: Sized + 'static {
|
|||
|
||||
/// Returns the width of the column at the given index.
|
||||
/// Return None, use auto width.
|
||||
fn col_width(&self, col_ix: usize) -> Option<f32>;
|
||||
///
|
||||
/// This is only called when the table initializes.
|
||||
fn col_width(&self, col_ix: usize) -> Option<Pixels>;
|
||||
|
||||
/// Set the width of the column at the given index.
|
||||
fn on_col_width_changed(&mut self, col_ix: usize, width: Option<f32>) {}
|
||||
/// When the column has resized, this method is called.
|
||||
fn on_col_widths_changed(&mut self, col_widths: Vec<Option<Pixels>>) {}
|
||||
|
||||
/// Render the header cell at the given column index, default to the column name.
|
||||
fn render_th(&self, col_ix: usize) -> impl IntoElement {
|
||||
|
|
@ -114,9 +131,10 @@ where
|
|||
selection_state: SelectionState::Row,
|
||||
selected_row: None,
|
||||
selected_col: None,
|
||||
resizing_col: None,
|
||||
};
|
||||
|
||||
this.update_col_groups(cx);
|
||||
this.prepare_col_groups(cx);
|
||||
this
|
||||
}
|
||||
|
||||
|
|
@ -128,38 +146,42 @@ where
|
|||
&mut self.delegate
|
||||
}
|
||||
|
||||
fn update_col_groups(&mut self, cx: &mut ViewContext<Self>) {
|
||||
fn prepare_col_groups(&mut self, cx: &mut ViewContext<Self>) {
|
||||
self.col_groups = (0..self.delegate.cols_count())
|
||||
.map(|col_ix| ColGroup {
|
||||
width: self.delegate.col_width(col_ix),
|
||||
bounds: Bounds::default(),
|
||||
})
|
||||
.collect();
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn scroll_to_selected_row(&mut self, _cx: &mut ViewContext<Self>) {
|
||||
fn set_selected_row(&mut self, row_ix: usize, cx: &mut ViewContext<Self>) {
|
||||
self.selection_state = SelectionState::Row;
|
||||
self.selected_row = Some(row_ix);
|
||||
if let Some(row_ix) = self.selected_row {
|
||||
self.vertical_scroll_handle.scroll_to_item(row_ix);
|
||||
}
|
||||
cx.emit(TableEvent::SelectRow(row_ix));
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn scroll_to_selected_column(&mut self, cx: &mut ViewContext<Self>) {
|
||||
fn set_selected_col(&mut self, col_ix: usize, cx: &mut ViewContext<Self>) {
|
||||
self.selection_state = SelectionState::Column;
|
||||
self.selected_col = Some(col_ix);
|
||||
if let Some(col_ix) = self.selected_col {
|
||||
self.horizontal_scroll_handle.scroll_to_item(col_ix);
|
||||
cx.notify();
|
||||
}
|
||||
cx.emit(TableEvent::SelectCol(col_ix));
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn on_row_click(&mut self, row_ix: usize, cx: &mut ViewContext<Self>) {
|
||||
self.selection_state = SelectionState::Row;
|
||||
self.selected_row = Some(row_ix);
|
||||
self.scroll_to_selected_row(cx);
|
||||
self.set_selected_row(row_ix, cx)
|
||||
}
|
||||
|
||||
fn on_col_head_click(&mut self, col_ix: usize, cx: &mut ViewContext<Self>) {
|
||||
self.selection_state = SelectionState::Column;
|
||||
self.selected_col = Some(col_ix);
|
||||
self.scroll_to_selected_column(cx);
|
||||
self.set_selected_col(col_ix, cx)
|
||||
}
|
||||
|
||||
fn action_cancel(&mut self, _: &Cancel, cx: &mut ViewContext<Self>) {
|
||||
|
|
@ -170,72 +192,63 @@ where
|
|||
}
|
||||
|
||||
fn action_select_prev(&mut self, _: &SelectPrev, cx: &mut ViewContext<Self>) {
|
||||
let selected_row = self.selected_row.unwrap_or(0);
|
||||
let mut selected_row = self.selected_row.unwrap_or(0);
|
||||
let rows_count = self.delegate.rows_count();
|
||||
if selected_row > 0 {
|
||||
self.selected_row = Some(selected_row - 1);
|
||||
selected_row = selected_row - 1;
|
||||
} else {
|
||||
if self.delegate.can_loop_select() {
|
||||
self.selected_row = Some(rows_count - 1);
|
||||
selected_row = rows_count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
self.selection_state = SelectionState::Row;
|
||||
self.scroll_to_selected_row(cx);
|
||||
cx.notify();
|
||||
self.set_selected_row(selected_row, cx);
|
||||
}
|
||||
|
||||
fn action_select_next(&mut self, _: &SelectNext, cx: &mut ViewContext<Self>) {
|
||||
let selected_row = self.selected_row.unwrap_or(0);
|
||||
let mut selected_row = self.selected_row.unwrap_or(0);
|
||||
if selected_row < self.delegate.rows_count() - 1 {
|
||||
self.selected_row = Some(selected_row + 1);
|
||||
selected_row += 1;
|
||||
} else {
|
||||
if self.delegate.can_loop_select() {
|
||||
self.selected_row = Some(0);
|
||||
selected_row = 0;
|
||||
}
|
||||
}
|
||||
|
||||
self.selection_state = SelectionState::Row;
|
||||
self.scroll_to_selected_row(cx);
|
||||
cx.notify();
|
||||
self.set_selected_row(selected_row, cx);
|
||||
}
|
||||
|
||||
fn action_select_prev_column(&mut self, _: &SelectPrevColumn, cx: &mut ViewContext<Self>) {
|
||||
let selected_col = self.selected_col.unwrap_or(0);
|
||||
fn action_select_prev_col(&mut self, _: &SelectPrevColumn, cx: &mut ViewContext<Self>) {
|
||||
let mut selected_col = self.selected_col.unwrap_or(0);
|
||||
let cols_count = self.delegate.cols_count();
|
||||
if selected_col > 0 {
|
||||
self.selected_col = Some(selected_col - 1);
|
||||
selected_col -= 1;
|
||||
} else {
|
||||
if self.delegate.can_loop_select() {
|
||||
self.selected_col = Some(cols_count - 1);
|
||||
selected_col = cols_count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
self.selection_state = SelectionState::Column;
|
||||
self.scroll_to_selected_column(cx);
|
||||
cx.notify();
|
||||
self.set_selected_col(selected_col, cx);
|
||||
}
|
||||
|
||||
fn action_select_next_column(&mut self, _: &SelectNextColumn, cx: &mut ViewContext<Self>) {
|
||||
let selected_col = self.selected_col.unwrap_or(0);
|
||||
fn action_select_next_col(&mut self, _: &SelectNextColumn, cx: &mut ViewContext<Self>) {
|
||||
let mut selected_col = self.selected_col.unwrap_or(0);
|
||||
if selected_col < self.delegate.cols_count() - 1 {
|
||||
self.selected_col = Some(selected_col + 1);
|
||||
selected_col += 1;
|
||||
} else {
|
||||
if self.delegate.can_loop_select() {
|
||||
self.selected_col = Some(0);
|
||||
selected_col = 0;
|
||||
}
|
||||
}
|
||||
|
||||
self.selection_state = SelectionState::Column;
|
||||
self.scroll_to_selected_column(cx);
|
||||
cx.notify();
|
||||
self.set_selected_col(selected_col, cx);
|
||||
}
|
||||
|
||||
fn render_cell(&self, col_ix: usize, _cx: &mut ViewContext<Self>) -> Div {
|
||||
let col_width = self.col_groups[col_ix].width;
|
||||
|
||||
div()
|
||||
.when_some(col_width, |this, width| this.w(px(width)))
|
||||
.when_some(col_width, |this, width| this.w(width))
|
||||
.overflow_hidden()
|
||||
.whitespace_nowrap()
|
||||
.py_1()
|
||||
|
|
@ -245,9 +258,9 @@ where
|
|||
/// Show Column selection style, when the column is selected and the selection state is Column.
|
||||
fn col_wrap(&self, col_ix: usize, cx: &mut ViewContext<Self>) -> Div {
|
||||
if self.selected_col == Some(col_ix) && self.selection_state == SelectionState::Column {
|
||||
div().bg(cx.theme().accent.opacity(0.5))
|
||||
h_flex().bg(cx.theme().table_active)
|
||||
} else {
|
||||
div()
|
||||
h_flex()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -270,6 +283,142 @@ where
|
|||
)),
|
||||
)
|
||||
}
|
||||
|
||||
fn render_resize_handle(&self, ix: usize, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
const HANDLE_SIZE: Pixels = px(3.);
|
||||
|
||||
if !self.delegate.can_resize_col(ix) {
|
||||
return div().into_any_element();
|
||||
}
|
||||
|
||||
let group_id: SharedString = format!("resizable-handle-{}", ix).into();
|
||||
let is_resizing = self.resizing_col == Some(ix);
|
||||
|
||||
h_flex()
|
||||
.id(("resizable-handle", ix))
|
||||
.group(group_id.clone())
|
||||
.occlude()
|
||||
.cursor_col_resize()
|
||||
.h_full()
|
||||
.w(HANDLE_SIZE)
|
||||
.ml(-(HANDLE_SIZE))
|
||||
.justify_end()
|
||||
.items_center()
|
||||
.child(
|
||||
div()
|
||||
.h_full()
|
||||
.h_5()
|
||||
.justify_center()
|
||||
.bg(cx.theme().border)
|
||||
.when(is_resizing, |this| this.bg(cx.theme().drag_border))
|
||||
.group_hover(group_id, |this| this.bg(cx.theme().drag_border))
|
||||
.w(px(1.)),
|
||||
)
|
||||
.hover(|this| this.bg(cx.theme().drag_border))
|
||||
.when(is_resizing, |this| this.bg(cx.theme().drag_border))
|
||||
.on_drag_move(cx.listener(
|
||||
move |view, e: &DragMoveEvent<DragCol>, cx| match e.drag(cx) {
|
||||
DragCol((entity_id, ix)) => {
|
||||
if cx.entity_id() != *entity_id {
|
||||
return;
|
||||
}
|
||||
|
||||
// sync col widths into real widths
|
||||
for (_, col_group) in view.col_groups.iter_mut().enumerate() {
|
||||
col_group.width = Some(col_group.bounds.size.width);
|
||||
}
|
||||
|
||||
let ix = *ix;
|
||||
view.resizing_col = Some(ix);
|
||||
|
||||
let col_group = view.col_groups.get(ix).expect("BUG: invalid col index");
|
||||
view.resize_cols(
|
||||
ix,
|
||||
e.event.position.x - HANDLE_SIZE - col_group.bounds.left(),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
},
|
||||
))
|
||||
.on_drag(DragCol((cx.entity_id(), ix)), |drag, cx| {
|
||||
cx.stop_propagation();
|
||||
cx.new_view(|_| drag.clone())
|
||||
})
|
||||
.on_mouse_up_out(
|
||||
MouseButton::Left,
|
||||
cx.listener(|view, _, cx| {
|
||||
if view.resizing_col.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
view.resizing_col = None;
|
||||
|
||||
let new_widths = view.col_groups.iter().map(|g| g.width).collect();
|
||||
cx.emit(TableEvent::ColWidthsChanged(new_widths));
|
||||
cx.notify();
|
||||
}),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// The `ix`` is the index of the col to resize,
|
||||
/// and the `size` is the new size for the col.
|
||||
fn resize_cols(&mut self, ix: usize, size: Pixels, cx: &mut ViewContext<Self>) {
|
||||
const MIN_WIDTH: Pixels = px(10.0);
|
||||
if !self.delegate.can_resize_col(ix) {
|
||||
return;
|
||||
}
|
||||
let size = size.floor();
|
||||
|
||||
let old_width = self.col_groups[ix].width.unwrap_or_default();
|
||||
let new_width = size;
|
||||
if new_width < MIN_WIDTH {
|
||||
return;
|
||||
}
|
||||
let changed_width = new_width - old_width;
|
||||
// If change size is less than 1px, do nothing.
|
||||
if changed_width > px(-1.0) && changed_width < px(1.0) {
|
||||
return;
|
||||
}
|
||||
self.col_groups[ix].width = Some(new_width);
|
||||
|
||||
// Resize next col, table not need to resize the right cols.
|
||||
// let next_width = self.col_groups[ix + 1].width.unwrap_or_default();
|
||||
// let next_width = (next_width - changed_width).max(MIN_WIDTH);
|
||||
// self.col_groups[ix + 1].width = Some(next_width);
|
||||
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
/// Render the column header.
|
||||
/// The children must be one by one items.
|
||||
/// Becuase the horizontal scroll handle will use the child_item_bounds to
|
||||
/// calculate the item position for itself's `scroll_to_item` method.
|
||||
fn render_th(&self, col_ix: usize, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
self.col_wrap(col_ix, cx)
|
||||
.child(
|
||||
self.render_cell(col_ix, cx)
|
||||
.on_mouse_down(
|
||||
MouseButton::Left,
|
||||
cx.listener(move |this, _, cx| {
|
||||
this.on_col_head_click(col_ix, cx);
|
||||
}),
|
||||
)
|
||||
.child(self.delegate.render_th(col_ix)),
|
||||
)
|
||||
// resize handle
|
||||
.child(self.render_resize_handle(col_ix, cx))
|
||||
// to save the bounds of this col.
|
||||
.child({
|
||||
let view = cx.view().clone();
|
||||
canvas(
|
||||
move |bounds, cx| view.update(cx, |r, _| r.col_groups[col_ix].bounds = bounds),
|
||||
|_, _, _| {},
|
||||
)
|
||||
.absolute()
|
||||
.size_full()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> FocusableView for Table<D>
|
||||
|
|
@ -281,6 +430,8 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<D> EventEmitter<TableEvent> for Table<D> where D: TableDelegate {}
|
||||
|
||||
impl<D> Render for Table<D>
|
||||
where
|
||||
D: TableDelegate,
|
||||
|
|
@ -291,11 +442,13 @@ where
|
|||
let horizontal_scroll_handle = self.horizontal_scroll_handle.clone();
|
||||
let cols_count: usize = self.delegate.cols_count();
|
||||
let rows_count = self.delegate.rows_count();
|
||||
let selected_bg = cx.theme().accent.opacity(0.8);
|
||||
let hover_bg = cx.theme().accent.opacity(0.5);
|
||||
|
||||
fn tr(cx: &mut WindowContext) -> Div {
|
||||
h_flex().gap_1().border_color(cx.theme().border)
|
||||
fn last_empty_col(_: &mut WindowContext) -> Div {
|
||||
h_flex().w(px(100.)).h_full().flex_shrink_0()
|
||||
}
|
||||
|
||||
fn tr(_: &mut WindowContext) -> Div {
|
||||
h_flex()
|
||||
}
|
||||
|
||||
let inner_table = v_flex()
|
||||
|
|
@ -305,8 +458,8 @@ where
|
|||
.on_action(cx.listener(Self::action_cancel))
|
||||
.on_action(cx.listener(Self::action_select_next))
|
||||
.on_action(cx.listener(Self::action_select_prev))
|
||||
.on_action(cx.listener(Self::action_select_next_column))
|
||||
.on_action(cx.listener(Self::action_select_prev_column))
|
||||
.on_action(cx.listener(Self::action_select_next_col))
|
||||
.on_action(cx.listener(Self::action_select_prev_col))
|
||||
.size_full()
|
||||
.overflow_hidden()
|
||||
.child(
|
||||
|
|
@ -314,7 +467,6 @@ where
|
|||
.flex_grow()
|
||||
.h_10()
|
||||
.w_full()
|
||||
.shadow_sm()
|
||||
.border_b_1()
|
||||
.border_color(cx.theme().border)
|
||||
.child(
|
||||
|
|
@ -322,30 +474,22 @@ where
|
|||
let horizontal_scroll_handle = horizontal_scroll_handle.clone();
|
||||
move |table, _, cx| {
|
||||
// Columns
|
||||
vec![tr(cx)
|
||||
tr(cx)
|
||||
.id("table-head")
|
||||
.w_full()
|
||||
.h_10()
|
||||
.overflow_scroll()
|
||||
.track_scroll(&horizontal_scroll_handle)
|
||||
// The children must be one by one items.
|
||||
// Becuase the horizontal scroll handle will use the child_item_bounds to
|
||||
// calculate the item position for itself's `scroll_to_item` method.
|
||||
.children(table.col_groups.iter().enumerate().map(
|
||||
|(col_ix, _)| {
|
||||
table.col_wrap(col_ix, cx).child(
|
||||
table
|
||||
.render_cell(col_ix, cx)
|
||||
.on_mouse_down(
|
||||
MouseButton::Left,
|
||||
cx.listener(move |this, _, cx| {
|
||||
this.on_col_head_click(col_ix, cx);
|
||||
}),
|
||||
)
|
||||
.child(table.delegate.render_th(col_ix)),
|
||||
)
|
||||
},
|
||||
))
|
||||
.flex_1()]
|
||||
.bg(cx.theme().table_head)
|
||||
.children(
|
||||
table
|
||||
.col_groups
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(col_ix, _)| table.render_th(col_ix, cx)),
|
||||
)
|
||||
.child(last_empty_col(cx))
|
||||
.map(|this| vec![this])
|
||||
}
|
||||
})
|
||||
.size_full(),
|
||||
|
|
@ -361,6 +505,17 @@ where
|
|||
tr(cx)
|
||||
.id(("table-row", row_ix))
|
||||
.w_full()
|
||||
.when(row_ix > 0, |this| this.border_t_1())
|
||||
.when(row_ix % 2 == 0, |this| {
|
||||
this.bg(cx.theme().table_even)
|
||||
})
|
||||
.hover(|this| {
|
||||
if table.selected_row.is_some() {
|
||||
this
|
||||
} else {
|
||||
this.bg(cx.theme().table_hover)
|
||||
}
|
||||
})
|
||||
.children((0..cols_count).map(|col_ix| {
|
||||
table
|
||||
.col_wrap(col_ix, cx) // Make the row scroll sync with the horizontal_scroll_handle to support horizontal scrolling.
|
||||
|
|
@ -376,20 +531,13 @@ where
|
|||
),
|
||||
)
|
||||
}))
|
||||
.when(row_ix > 0, |this| this.border_t_1())
|
||||
.hover(|this| {
|
||||
if table.selected_row.is_some() {
|
||||
this
|
||||
} else {
|
||||
this.bg(hover_bg)
|
||||
}
|
||||
})
|
||||
.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(selected_bg),
|
||||
|this| this.bg(cx.theme().table_active),
|
||||
)
|
||||
})
|
||||
.on_mouse_down(
|
||||
|
|
@ -415,7 +563,7 @@ where
|
|||
.rounded_md()
|
||||
.border_1()
|
||||
.border_color(cx.theme().border)
|
||||
.bg(cx.theme().card)
|
||||
.bg(cx.theme().table)
|
||||
.child(inner_table)
|
||||
.children(self.render_scrollbar(cx))
|
||||
.child(ScrollableMask::new(
|
||||
|
|
|
|||
|
|
@ -331,6 +331,11 @@ pub struct Theme {
|
|||
pub slider_thumb: Hsla,
|
||||
pub list_item_active: Hsla,
|
||||
pub list_item_hover: Hsla,
|
||||
pub table: Hsla,
|
||||
pub table_even: Hsla,
|
||||
pub table_head: Hsla,
|
||||
pub table_active: Hsla,
|
||||
pub table_hover: Hsla,
|
||||
}
|
||||
|
||||
impl Global for Theme {}
|
||||
|
|
@ -398,6 +403,11 @@ impl From<Colors> for Theme {
|
|||
slider_thumb: colors.background,
|
||||
list_item_active: colors.secondary_active,
|
||||
list_item_hover: colors.secondary,
|
||||
table_head: colors.secondary.opacity(0.5),
|
||||
table: colors.background,
|
||||
table_even: colors.secondary.opacity(0.3),
|
||||
table_active: colors.secondary_active,
|
||||
table_hover: colors.secondary_active.opacity(0.7),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue