table: Set fixed height to table head to fix some case table head disappear bug. (#300)

Closes #299 

- Improved sort icon to better color.
- Improved table story.
- Disable `horizontal_scroll_handle.scroll_to_item` on select_col, there
have a bug need to fix.
This commit is contained in:
Jason Lee 2024-10-03 10:14:44 +08:00 committed by GitHub
parent 494e6d15f3
commit ce10a0340c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 128 additions and 61 deletions

View file

@ -2,9 +2,11 @@ use std::time::{self, Duration};
use fake::{Fake, Faker};
use gpui::{
div, AnyElement, ClickEvent, IntoElement, ParentElement, Pixels, Render, SharedString, Styled,
Timer, View, ViewContext, VisualContext as _, WindowContext,
div, impl_actions, AnyElement, ClickEvent, InteractiveElement, IntoElement, ParentElement,
Pixels, Render, SharedString, Styled, Timer, View, ViewContext, VisualContext as _,
WindowContext,
};
use serde::Deserialize;
use ui::{
button::{Button, ButtonStyled},
checkbox::Checkbox,
@ -12,11 +14,17 @@ use ui::{
indicator::Indicator,
input::{InputEvent, TextInput},
label::Label,
popup_menu::PopupMenuExt,
prelude::FluentBuilder as _,
table::{ColFixed, ColSort, Table, TableDelegate, TableEvent},
v_flex, Selectable, Sizable, Size,
};
#[derive(Clone, PartialEq, Eq, Deserialize)]
struct ChangeSize(Size);
impl_actions!(table_story, [ChangeSize]);
#[derive(Clone, Debug, Default)]
struct Stock {
id: usize,
@ -166,6 +174,7 @@ struct StockTableDelegate {
col_sort: bool,
col_selection: bool,
loading: bool,
fixed_cols: bool,
is_eof: bool,
}
@ -232,6 +241,7 @@ impl StockTableDelegate {
col_order: true,
col_sort: true,
col_selection: true,
fixed_cols: false,
loading: false,
is_eof: false,
}
@ -250,9 +260,10 @@ impl StockTableDelegate {
let right_num = ((val - val.floor()) * 1000.).floor() as i32;
let this = if right_num % 3 == 0 {
this.text_color(ui::red_600()).bg(ui::red_50())
this.text_color(ui::red_600()).bg(ui::red_50().opacity(0.6))
} else if right_num % 3 == 1 {
this.text_color(ui::green_600()).bg(ui::green_50())
this.text_color(ui::green_600())
.bg(ui::green_50().opacity(0.6))
} else {
this
};
@ -287,6 +298,10 @@ impl TableDelegate for StockTableDelegate {
}
fn col_fixed(&self, col_ix: usize) -> Option<ui::table::ColFixed> {
if !self.fixed_cols {
return None;
}
if col_ix < 4 {
Some(ColFixed::Left)
} else {
@ -548,40 +563,35 @@ impl TableStory {
}
fn toggle_loop_selection(&mut self, checked: &bool, cx: &mut ViewContext<Self>) {
let table = self.table.clone();
table.update(cx, |table, cx| {
self.table.update(cx, |table, cx| {
table.delegate_mut().loop_selection = *checked;
cx.notify();
});
}
fn toggle_col_resize(&mut self, checked: &bool, cx: &mut ViewContext<Self>) {
let table = self.table.clone();
table.update(cx, |table, cx| {
self.table.update(cx, |table, cx| {
table.delegate_mut().col_resize = *checked;
cx.notify();
});
}
fn toggle_col_order(&mut self, checked: &bool, cx: &mut ViewContext<Self>) {
let table = self.table.clone();
table.update(cx, |table, cx| {
self.table.update(cx, |table, cx| {
table.delegate_mut().col_order = *checked;
cx.notify();
});
}
fn toggle_col_sort(&mut self, checked: &bool, cx: &mut ViewContext<Self>) {
let table = self.table.clone();
table.update(cx, |table, cx| {
self.table.update(cx, |table, cx| {
table.delegate_mut().col_sort = *checked;
cx.notify();
});
}
fn toggle_col_selection(&mut self, checked: &bool, cx: &mut ViewContext<Self>) {
let table = self.table.clone();
table.update(cx, |table, cx| {
self.table.update(cx, |table, cx| {
table.delegate_mut().col_selection = *checked;
cx.notify();
});
@ -590,24 +600,24 @@ impl TableStory {
fn toggle_stripe(&mut self, checked: &bool, cx: &mut ViewContext<Self>) {
self.stripe = *checked;
let stripe = self.stripe;
let table = self.table.clone();
table.update(cx, |table, cx| {
self.table.update(cx, |table, cx| {
table.set_stripe(stripe, cx);
cx.notify();
});
}
fn toggle_size(&mut self, _: &ClickEvent, cx: &mut ViewContext<Self>) {
self.size = match self.size {
Size::XSmall => Size::Small,
Size::Small => Size::Medium,
Size::Medium => Size::Large,
Size::Large => Size::XSmall,
_ => Size::default(),
};
fn toggle_fixed_cols(&mut self, checked: &bool, cx: &mut ViewContext<Self>) {
self.table.update(cx, |table, cx| {
table.set_size(self.size, cx);
table.delegate_mut().fixed_cols = *checked;
table.refresh(cx);
cx.notify();
});
}
fn on_change_size(&mut self, a: &ChangeSize, cx: &mut ViewContext<Self>) {
self.size = a.0;
self.table.update(cx, |table, cx| {
table.set_size(a.0, cx);
});
}
@ -635,14 +645,46 @@ impl TableStory {
impl Render for TableStory {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl gpui::IntoElement {
let delegate = self.table.read(cx).delegate();
let size = self.size;
v_flex()
.on_action(cx.listener(Self::on_change_size))
.size_full()
.text_sm()
.gap_2()
.child(
h_flex()
.items_center()
.gap_2()
.gap_3()
.flex_wrap()
.child(
Button::new("size")
.compact()
.outline()
.label(format!("size: {:?}", self.size))
.popup_menu(move |menu, cx| {
menu.menu_with_check(
"Large",
size == Size::Large,
Box::new(ChangeSize(Size::Large)),
)
.menu_with_check(
"Medium",
size == Size::Medium,
Box::new(ChangeSize(Size::Medium)),
)
.menu_with_check(
"Small",
size == Size::Small,
Box::new(ChangeSize(Size::Small)),
)
.menu_with_check(
"XSmall",
size == Size::XSmall,
Box::new(ChangeSize(Size::XSmall)),
)
}),
)
.child(
Checkbox::new("loop-selection")
.label("Loop Selection")
@ -680,12 +722,10 @@ impl Render for TableStory {
.on_click(cx.listener(Self::toggle_stripe)),
)
.child(
Button::new("size")
.small()
.compact()
.outline()
.label(format!("size: {:?}", self.size))
.on_click(cx.listener(Self::toggle_size)),
Checkbox::new("fixed-cols")
.label("Fixed Columns")
.selected(delegate.fixed_cols)
.on_click(cx.listener(Self::toggle_fixed_cols)),
)
.child(
Checkbox::new("refresh-data")

View file

@ -5,6 +5,7 @@ use crate::{
theme::ActiveTheme,
};
use gpui::{div, px, Axis, Div, Element, EntityId, FocusHandle, Pixels, Styled, WindowContext};
use serde::{Deserialize, Serialize};
/// Returns a `Div` as horizontal flex layout.
pub fn h_flex() -> Div {
@ -133,7 +134,7 @@ pub trait StyledExt: Styled + Sized {
impl<E: Styled> StyledExt for E {}
/// A size for elements.
#[derive(Clone, Default, Copy, PartialEq, Eq, Debug)]
#[derive(Clone, Default, Copy, PartialEq, Eq, Debug, Deserialize, Serialize)]
pub enum Size {
Size(Pixels),
XSmall,

View file

@ -336,9 +336,9 @@ where
self.selected_col = Some(col_ix);
if let Some(col_ix) = self.selected_col {
// TODO: Fix scroll to selected col, this was not working after fixed col.
if self.col_groups[col_ix].fixed.is_none() {
self.horizontal_scroll_handle.scroll_to_item(col_ix);
}
// if self.col_groups[col_ix].fixed.is_none() {
// self.horizontal_scroll_handle.scroll_to_item(col_ix);
// }
}
cx.emit(TableEvent::SelectCol(col_ix));
cx.notify();
@ -426,8 +426,8 @@ where
.whitespace_nowrap()
.map(|this| match self.size {
Size::XSmall => this.text_sm().py_0p5().px_1(),
Size::Small => this.text_sm().py_1().px_1p5(),
Size::Large => this.py_1p5().px_3(),
Size::Small => this.text_sm().py(px(3.)).px_1p5(),
Size::Large => this.py_2().px_3(),
_ => this.py_1().px_2(),
})
}
@ -658,10 +658,10 @@ where
let sort = sort.unwrap();
let icon = match sort {
ColSort::Ascending => IconName::SortAscending,
ColSort::Descending => IconName::SortDescending,
ColSort::Default => IconName::ChevronsUpDown,
let (icon, is_on) = match sort {
ColSort::Ascending => (IconName::SortAscending, true),
ColSort::Descending => (IconName::SortDescending, true),
ColSort::Default => (IconName::ChevronsUpDown, false),
};
Some(
@ -671,8 +671,12 @@ where
.ml_2()
.p(px(2.))
.rounded_sm()
.hover(|this| this.bg(cx.theme().secondary))
.active(|this| this.bg(cx.theme().secondary_active))
.map(|this| match is_on {
true => this,
false => this.opacity(0.5),
})
.hover(|this| this.bg(cx.theme().secondary).opacity(7.))
.active(|this| this.bg(cx.theme().secondary_active).opacity(1.))
.on_mouse_down(MouseButton::Left, |_, cx| cx.stop_propagation())
.on_click(cx.listener(move |table, _, cx| table.perform_sort(col_ix, cx)))
.child(
@ -787,31 +791,45 @@ where
) -> impl IntoElement {
let view = cx.view().clone();
let horizontal_scroll_handle = self.horizontal_scroll_handle.clone();
let fixed_cols_count = self
.col_groups
.iter()
.filter(|col| col.fixed.is_some())
.count();
h_flex()
.w_full()
.map(|this| match self.size {
Size::Large => this.h_10(),
Size::Small => this.h(px(30.)),
Size::XSmall => this.h(px(26.)),
_ => this.h_8(),
})
.flex_shrink_0()
.border_b_1()
.border_color(cx.theme().border)
.child(
.text_color(cx.theme().table_head_foreground)
.when(fixed_cols_count > 0, |this| {
// Render left fixed columns
h_flex()
.id("table-head-fixed-left")
.h_full()
.bg(cx.theme().table_head)
.border_r_1()
.border_color(cx.theme().border)
.children(
self.col_groups
.iter()
.filter(|col| col.fixed == Some(ColFixed::Left))
.enumerate()
.map(|(col_ix, _)| self.render_th(col_ix, cx)),
),
)
this.child(
h_flex()
.id("table-head-fixed-left")
.h_full()
.bg(cx.theme().table_head)
.border_r_1()
.border_color(cx.theme().border)
.children(
self.col_groups
.iter()
.filter(|col| col.fixed == Some(ColFixed::Left))
.enumerate()
.map(|(col_ix, _)| self.render_th(col_ix, cx)),
),
)
})
.child(
// Render other normal columns
uniform_list(view.clone(), "table-uniform-list-head", 1, {
uniform_list(view.clone(), "table-head-uniform-list", 1, {
let horizontal_scroll_handle = horizontal_scroll_handle.clone();
let view = view.clone();
move |table, _, cx| {
@ -856,6 +874,12 @@ where
.map(|this| vec![this])
}
})
.map(|this| match self.size {
Size::Large => this.h_10(),
Size::Small => this.h(px(30.)),
Size::XSmall => this.h(px(26.)),
_ => this.h_8(),
})
.h_full()
.flex_1(),
)

View file

@ -315,6 +315,7 @@ pub struct Theme {
pub table: Hsla,
pub table_even: Hsla,
pub table_head: Hsla,
pub table_head_foreground: Hsla,
pub table_row_border: Hsla,
pub table_active: Hsla,
pub table_hover: Hsla,
@ -398,6 +399,7 @@ impl From<Colors> for Theme {
table_active: colors.list_active,
table_hover: colors.list_active.opacity(0.8),
table_row_border: colors.border.opacity(0.5),
table_head_foreground: colors.foreground.opacity(0.7),
link: colors.link,
link_hover: colors.link.lighten(0.2),
link_active: colors.link.darken(0.2),