More table improvements (#1440)
* Clip by default * Fix some spacing bugs * datepicker: look nicer in light mode * datepicker: show month names * Table: don't allow resize of last column if it is Size::Remainder
This commit is contained in:
parent
c029f25c13
commit
5dff1e42c6
7 changed files with 173 additions and 128 deletions
|
@ -31,14 +31,14 @@ impl super::View for StripDemo {
|
||||||
.size(Size::relative(0.5).at_least(60.0))
|
.size(Size::relative(0.5).at_least(60.0))
|
||||||
.size(Size::exact(10.0))
|
.size(Size::exact(10.0))
|
||||||
.vertical(|mut strip| {
|
.vertical(|mut strip| {
|
||||||
strip.cell_clip(|ui| {
|
strip.cell(|ui| {
|
||||||
ui.painter()
|
ui.painter()
|
||||||
.rect_filled(ui.available_rect_before_wrap(), 0.0, Color32::BLUE);
|
.rect_filled(ui.available_rect_before_wrap(), 0.0, Color32::BLUE);
|
||||||
ui.label("Full width and 50px height");
|
ui.label("Full width and 50px height");
|
||||||
});
|
});
|
||||||
strip.strip(|builder| {
|
strip.strip(|builder| {
|
||||||
builder.sizes(Size::remainder(), 2).horizontal(|mut strip| {
|
builder.sizes(Size::remainder(), 2).horizontal(|mut strip| {
|
||||||
strip.cell_clip(|ui| {
|
strip.cell(|ui| {
|
||||||
ui.painter().rect_filled(
|
ui.painter().rect_filled(
|
||||||
ui.available_rect_before_wrap(),
|
ui.available_rect_before_wrap(),
|
||||||
0.0,
|
0.0,
|
||||||
|
@ -49,7 +49,7 @@ impl super::View for StripDemo {
|
||||||
strip.strip(|builder| {
|
strip.strip(|builder| {
|
||||||
builder.sizes(Size::remainder(), 3).vertical(|mut strip| {
|
builder.sizes(Size::remainder(), 3).vertical(|mut strip| {
|
||||||
strip.empty();
|
strip.empty();
|
||||||
strip.cell_clip(|ui| {
|
strip.cell(|ui| {
|
||||||
ui.painter().rect_filled(
|
ui.painter().rect_filled(
|
||||||
ui.available_rect_before_wrap(),
|
ui.available_rect_before_wrap(),
|
||||||
0.0,
|
0.0,
|
||||||
|
@ -76,7 +76,7 @@ impl super::View for StripDemo {
|
||||||
.size(Size::remainder())
|
.size(Size::remainder())
|
||||||
.vertical(|mut strip| {
|
.vertical(|mut strip| {
|
||||||
strip.empty();
|
strip.empty();
|
||||||
strip.cell_clip(|ui| {
|
strip.cell(|ui| {
|
||||||
ui.painter().rect_filled(
|
ui.painter().rect_filled(
|
||||||
ui.available_rect_before_wrap(),
|
ui.available_rect_before_wrap(),
|
||||||
0.0,
|
0.0,
|
||||||
|
@ -87,7 +87,7 @@ impl super::View for StripDemo {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
strip.empty();
|
strip.empty();
|
||||||
strip.cell_clip(|ui| {
|
strip.cell(|ui| {
|
||||||
ui.painter().rect_filled(
|
ui.painter().rect_filled(
|
||||||
ui.available_rect_before_wrap(),
|
ui.available_rect_before_wrap(),
|
||||||
0.0,
|
0.0,
|
||||||
|
@ -97,7 +97,7 @@ impl super::View for StripDemo {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
strip.cell_clip(|ui| {
|
strip.cell(|ui| {
|
||||||
ui.vertical_centered(|ui| {
|
ui.vertical_centered(|ui| {
|
||||||
ui.add(crate::__egui_github_link_file!());
|
ui.add(crate::__egui_github_link_file!());
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use egui::TextStyle;
|
||||||
use egui_extras::{Size, StripBuilder, TableBuilder};
|
use egui_extras::{Size, StripBuilder, TableBuilder};
|
||||||
|
|
||||||
/// Shows off a table with dynamic layout
|
/// Shows off a table with dynamic layout
|
||||||
|
@ -35,7 +36,7 @@ impl super::View for TableDemo {
|
||||||
.size(Size::remainder()) // for the table
|
.size(Size::remainder()) // for the table
|
||||||
.size(Size::exact(10.0)) // for the source code link
|
.size(Size::exact(10.0)) // for the source code link
|
||||||
.vertical(|mut strip| {
|
.vertical(|mut strip| {
|
||||||
strip.cell_clip(|ui| {
|
strip.cell(|ui| {
|
||||||
self.table_ui(ui);
|
self.table_ui(ui);
|
||||||
});
|
});
|
||||||
strip.cell(|ui| {
|
strip.cell(|ui| {
|
||||||
|
@ -49,57 +50,70 @@ impl super::View for TableDemo {
|
||||||
|
|
||||||
impl TableDemo {
|
impl TableDemo {
|
||||||
fn table_ui(&mut self, ui: &mut egui::Ui) {
|
fn table_ui(&mut self, ui: &mut egui::Ui) {
|
||||||
|
let text_height = TextStyle::Body.resolve(ui.style()).size;
|
||||||
|
|
||||||
TableBuilder::new(ui)
|
TableBuilder::new(ui)
|
||||||
.striped(true)
|
.striped(true)
|
||||||
.column(Size::initial(60.0).at_least(40.0))
|
.column(Size::initial(60.0).at_least(40.0))
|
||||||
.column(Size::remainder().at_least(60.0))
|
|
||||||
.column(Size::initial(60.0).at_least(40.0))
|
.column(Size::initial(60.0).at_least(40.0))
|
||||||
|
.column(Size::remainder().at_least(60.0))
|
||||||
.resizable(self.resizable)
|
.resizable(self.resizable)
|
||||||
.header(20.0, |mut header| {
|
.header(20.0, |mut header| {
|
||||||
header.col_clip(|ui| {
|
header.col(|ui| {
|
||||||
ui.heading("Left");
|
ui.centered_and_justified(|ui| {
|
||||||
|
ui.heading("Row");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
header.col_clip(|ui| {
|
header.col(|ui| {
|
||||||
ui.heading("Middle");
|
ui.centered_and_justified(|ui| {
|
||||||
|
ui.heading("Clock");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
header.col_clip(|ui| {
|
header.col(|ui| {
|
||||||
ui.heading("Right");
|
ui.centered_and_justified(|ui| {
|
||||||
|
ui.heading("Content");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.body(|mut body| {
|
.body(|mut body| {
|
||||||
if self.virtual_scroll {
|
if self.virtual_scroll {
|
||||||
body.rows(20.0, 100_000, |index, mut row| {
|
body.rows(text_height, 100_000, |row_index, mut row| {
|
||||||
row.col_clip(|ui| {
|
row.col(|ui| {
|
||||||
ui.label(index.to_string());
|
ui.label(row_index.to_string());
|
||||||
});
|
});
|
||||||
row.col_clip(|ui| {
|
row.col(|ui| {
|
||||||
|
ui.label(clock_emoji(row_index));
|
||||||
|
});
|
||||||
|
row.col(|ui| {
|
||||||
ui.add(
|
ui.add(
|
||||||
egui::Label::new("virtual scroll, easily with thousands of rows!")
|
egui::Label::new("Thousands of rows of even height").wrap(false),
|
||||||
.wrap(false),
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
row.col_clip(|ui| {
|
|
||||||
ui.label(index.to_string());
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
for i in 0..20 {
|
for row_index in 0..20 {
|
||||||
let thick = i % 4 == 0;
|
let thick = row_index % 6 == 0;
|
||||||
let height = if thick { 25.0 } else { 15.0 };
|
let row_height = if thick { 30.0 } else { 18.0 };
|
||||||
body.row(height, |mut row| {
|
body.row(row_height, |mut row| {
|
||||||
row.col_clip(|ui| {
|
row.col(|ui| {
|
||||||
ui.label(i.to_string());
|
ui.centered_and_justified(|ui| {
|
||||||
|
ui.label(row_index.to_string());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
row.col_clip(|ui| {
|
row.col(|ui| {
|
||||||
ui.style_mut().wrap = Some(false);
|
ui.centered_and_justified(|ui| {
|
||||||
if thick {
|
ui.label(clock_emoji(row_index));
|
||||||
ui.heading("Extra thick row");
|
});
|
||||||
} else {
|
|
||||||
ui.label("Normal row");
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
row.col_clip(|ui| {
|
row.col(|ui| {
|
||||||
ui.label(i.to_string());
|
ui.centered_and_justified(|ui| {
|
||||||
|
ui.style_mut().wrap = Some(false);
|
||||||
|
if thick {
|
||||||
|
ui.heading("Extra thick row");
|
||||||
|
} else {
|
||||||
|
ui.label("Normal row");
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -107,3 +121,9 @@ impl TableDemo {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clock_emoji(row_index: usize) -> String {
|
||||||
|
char::from_u32(0x1f550 + row_index as u32 % 24)
|
||||||
|
.unwrap()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use super::{button::DatePickerButtonState, month_data};
|
use super::{button::DatePickerButtonState, month_data};
|
||||||
use crate::{Size, StripBuilder, TableBuilder};
|
use crate::{Size, StripBuilder, TableBuilder};
|
||||||
use chrono::{Date, Datelike, NaiveDate, Utc, Weekday};
|
use chrono::{Date, Datelike, NaiveDate, Utc, Weekday};
|
||||||
use egui::{Align, Button, Color32, ComboBox, Direction, Id, Label, Layout, RichText, Ui, Vec2};
|
use egui::{Align, Button, Color32, ComboBox, Direction, Id, Layout, RichText, Ui, Vec2};
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||||
|
@ -55,6 +55,7 @@ impl<'a> DatePickerPopup<'a> {
|
||||||
let spacing = 2.0;
|
let spacing = 2.0;
|
||||||
ui.spacing_mut().item_spacing = Vec2::splat(spacing);
|
ui.spacing_mut().item_spacing = Vec2::splat(spacing);
|
||||||
StripBuilder::new(ui)
|
StripBuilder::new(ui)
|
||||||
|
.clip(false)
|
||||||
.sizes(
|
.sizes(
|
||||||
Size::exact(height),
|
Size::exact(height),
|
||||||
match (self.combo_boxes, self.arrows) {
|
match (self.combo_boxes, self.arrows) {
|
||||||
|
@ -70,7 +71,7 @@ impl<'a> DatePickerPopup<'a> {
|
||||||
.size(Size::exact(height))
|
.size(Size::exact(height))
|
||||||
.vertical(|mut strip| {
|
.vertical(|mut strip| {
|
||||||
if self.combo_boxes {
|
if self.combo_boxes {
|
||||||
strip.strip_clip(|builder| {
|
strip.strip(|builder| {
|
||||||
builder.sizes(Size::remainder(), 3).horizontal(|mut strip| {
|
builder.sizes(Size::remainder(), 3).horizontal(|mut strip| {
|
||||||
strip.cell(|ui| {
|
strip.cell(|ui| {
|
||||||
ComboBox::from_id_source("date_picker_year")
|
ComboBox::from_id_source("date_picker_year")
|
||||||
|
@ -94,14 +95,14 @@ impl<'a> DatePickerPopup<'a> {
|
||||||
});
|
});
|
||||||
strip.cell(|ui| {
|
strip.cell(|ui| {
|
||||||
ComboBox::from_id_source("date_picker_month")
|
ComboBox::from_id_source("date_picker_month")
|
||||||
.selected_text(popup_state.month.to_string())
|
.selected_text(month_name(popup_state.month))
|
||||||
.show_ui(ui, |ui| {
|
.show_ui(ui, |ui| {
|
||||||
for month in 1..=12 {
|
for month in 1..=12 {
|
||||||
if ui
|
if ui
|
||||||
.selectable_value(
|
.selectable_value(
|
||||||
&mut popup_state.month,
|
&mut popup_state.month,
|
||||||
month,
|
month,
|
||||||
month.to_string(),
|
month_name(month),
|
||||||
)
|
)
|
||||||
.changed()
|
.changed()
|
||||||
{
|
{
|
||||||
|
@ -236,6 +237,7 @@ impl<'a> DatePickerPopup<'a> {
|
||||||
ui.spacing_mut().item_spacing = Vec2::new(1.0, 2.0);
|
ui.spacing_mut().item_spacing = Vec2::new(1.0, 2.0);
|
||||||
TableBuilder::new(ui)
|
TableBuilder::new(ui)
|
||||||
.scroll(false)
|
.scroll(false)
|
||||||
|
.clip(false)
|
||||||
.columns(Size::remainder(), if self.calendar_week { 8 } else { 7 })
|
.columns(Size::remainder(), if self.calendar_week { 8 } else { 7 })
|
||||||
.header(height, |mut header| {
|
.header(height, |mut header| {
|
||||||
if self.calendar_week {
|
if self.calendar_week {
|
||||||
|
@ -243,7 +245,7 @@ impl<'a> DatePickerPopup<'a> {
|
||||||
ui.with_layout(
|
ui.with_layout(
|
||||||
Layout::centered_and_justified(Direction::TopDown),
|
Layout::centered_and_justified(Direction::TopDown),
|
||||||
|ui| {
|
|ui| {
|
||||||
ui.add(Label::new("Week"));
|
ui.label("Week");
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -255,7 +257,7 @@ impl<'a> DatePickerPopup<'a> {
|
||||||
ui.with_layout(
|
ui.with_layout(
|
||||||
Layout::centered_and_justified(Direction::TopDown),
|
Layout::centered_and_justified(Direction::TopDown),
|
||||||
|ui| {
|
|ui| {
|
||||||
ui.add(Label::new(name));
|
ui.label(name);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -266,7 +268,7 @@ impl<'a> DatePickerPopup<'a> {
|
||||||
body.row(height, |mut row| {
|
body.row(height, |mut row| {
|
||||||
if self.calendar_week {
|
if self.calendar_week {
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
ui.add(Label::new(week.number.to_string()));
|
ui.label(week.number.to_string());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for day in week.days {
|
for day in week.days {
|
||||||
|
@ -274,7 +276,6 @@ impl<'a> DatePickerPopup<'a> {
|
||||||
ui.with_layout(
|
ui.with_layout(
|
||||||
Layout::top_down_justified(Align::Center),
|
Layout::top_down_justified(Align::Center),
|
||||||
|ui| {
|
|ui| {
|
||||||
//TODO: Colors from egui style
|
|
||||||
let fill_color = if popup_state.year
|
let fill_color = if popup_state.year
|
||||||
== day.year()
|
== day.year()
|
||||||
&& popup_state.month == day.month()
|
&& popup_state.month == day.month()
|
||||||
|
@ -284,25 +285,51 @@ impl<'a> DatePickerPopup<'a> {
|
||||||
} else if day.weekday() == Weekday::Sat
|
} else if day.weekday() == Weekday::Sat
|
||||||
|| day.weekday() == Weekday::Sun
|
|| day.weekday() == Weekday::Sun
|
||||||
{
|
{
|
||||||
Color32::DARK_RED
|
if ui.visuals().dark_mode {
|
||||||
|
Color32::DARK_RED
|
||||||
|
} else {
|
||||||
|
Color32::LIGHT_RED
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Color32::BLACK
|
ui.visuals().extreme_bg_color
|
||||||
};
|
|
||||||
let text_color = if day == today {
|
|
||||||
Color32::RED
|
|
||||||
} else if day.month() == popup_state.month {
|
|
||||||
Color32::WHITE
|
|
||||||
} else {
|
|
||||||
Color32::from_gray(80)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let button = Button::new(
|
let mut text_color = ui
|
||||||
RichText::new(day.day().to_string())
|
.visuals()
|
||||||
|
.widgets
|
||||||
|
.inactive
|
||||||
|
.text_color();
|
||||||
|
|
||||||
|
if day.month() != popup_state.month {
|
||||||
|
text_color =
|
||||||
|
text_color.linear_multiply(0.5);
|
||||||
|
};
|
||||||
|
|
||||||
|
let button_response = ui.add(
|
||||||
|
Button::new(
|
||||||
|
RichText::new(
|
||||||
|
day.day().to_string(),
|
||||||
|
)
|
||||||
.color(text_color),
|
.color(text_color),
|
||||||
)
|
)
|
||||||
.fill(fill_color);
|
.fill(fill_color),
|
||||||
|
);
|
||||||
|
|
||||||
if ui.add(button).clicked() {
|
if day == today {
|
||||||
|
// Encircle today's date
|
||||||
|
let stroke = ui
|
||||||
|
.visuals()
|
||||||
|
.widgets
|
||||||
|
.inactive
|
||||||
|
.fg_stroke;
|
||||||
|
ui.painter().circle_stroke(
|
||||||
|
button_response.rect.center(),
|
||||||
|
8.0,
|
||||||
|
stroke,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if button_response.clicked() {
|
||||||
popup_state.year = day.year();
|
popup_state.year = day.year();
|
||||||
popup_state.month = day.month();
|
popup_state.month = day.month();
|
||||||
popup_state.day = day.day();
|
popup_state.day = day.day();
|
||||||
|
@ -361,3 +388,21 @@ impl<'a> DatePickerPopup<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn month_name(i: u32) -> &'static str {
|
||||||
|
match i {
|
||||||
|
1 => "January",
|
||||||
|
2 => "February",
|
||||||
|
3 => "March",
|
||||||
|
4 => "April",
|
||||||
|
5 => "May",
|
||||||
|
6 => "June",
|
||||||
|
7 => "July",
|
||||||
|
8 => "August",
|
||||||
|
9 => "September",
|
||||||
|
10 => "October",
|
||||||
|
11 => "November",
|
||||||
|
12 => "December",
|
||||||
|
_ => panic!("Unknown month: {}", i),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -31,10 +31,11 @@ pub struct StripLayout<'l> {
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
cursor: Pos2,
|
cursor: Pos2,
|
||||||
max: Pos2,
|
max: Pos2,
|
||||||
|
pub(crate) clip: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'l> StripLayout<'l> {
|
impl<'l> StripLayout<'l> {
|
||||||
pub(crate) fn new(ui: &'l mut Ui, direction: CellDirection) -> Self {
|
pub(crate) fn new(ui: &'l mut Ui, direction: CellDirection, clip: bool) -> Self {
|
||||||
let rect = ui.available_rect_before_wrap();
|
let rect = ui.available_rect_before_wrap();
|
||||||
let pos = rect.left_top();
|
let pos = rect.left_top();
|
||||||
|
|
||||||
|
@ -44,6 +45,7 @@ impl<'l> StripLayout<'l> {
|
||||||
cursor: pos,
|
cursor: pos,
|
||||||
max: pos,
|
max: pos,
|
||||||
direction,
|
direction,
|
||||||
|
clip,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,11 +91,10 @@ impl<'l> StripLayout<'l> {
|
||||||
&mut self,
|
&mut self,
|
||||||
width: CellSize,
|
width: CellSize,
|
||||||
height: CellSize,
|
height: CellSize,
|
||||||
clip: bool,
|
|
||||||
add_contents: impl FnOnce(&mut Ui),
|
add_contents: impl FnOnce(&mut Ui),
|
||||||
) -> Response {
|
) -> Response {
|
||||||
let rect = self.cell_rect(&width, &height);
|
let rect = self.cell_rect(&width, &height);
|
||||||
let used_rect = self.cell(rect, clip, add_contents);
|
let used_rect = self.cell(rect, add_contents);
|
||||||
self.set_pos(rect);
|
self.set_pos(rect);
|
||||||
self.ui.allocate_rect(rect.union(used_rect), Sense::hover())
|
self.ui.allocate_rect(rect.union(used_rect), Sense::hover())
|
||||||
}
|
}
|
||||||
|
@ -102,7 +103,6 @@ impl<'l> StripLayout<'l> {
|
||||||
&mut self,
|
&mut self,
|
||||||
width: CellSize,
|
width: CellSize,
|
||||||
height: CellSize,
|
height: CellSize,
|
||||||
clip: bool,
|
|
||||||
add_contents: impl FnOnce(&mut Ui),
|
add_contents: impl FnOnce(&mut Ui),
|
||||||
) -> Response {
|
) -> Response {
|
||||||
let rect = self.cell_rect(&width, &height);
|
let rect = self.cell_rect(&width, &height);
|
||||||
|
@ -114,7 +114,7 @@ impl<'l> StripLayout<'l> {
|
||||||
.painter()
|
.painter()
|
||||||
.rect_filled(rect, 0.0, self.ui.visuals().faint_bg_color);
|
.rect_filled(rect, 0.0, self.ui.visuals().faint_bg_color);
|
||||||
|
|
||||||
self.add(width, height, clip, add_contents)
|
self.add(width, height, add_contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// only needed for layouts with multiple lines, like [`Table`].
|
/// only needed for layouts with multiple lines, like [`Table`].
|
||||||
|
@ -131,10 +131,10 @@ impl<'l> StripLayout<'l> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cell(&mut self, rect: Rect, clip: bool, add_contents: impl FnOnce(&mut Ui)) -> Rect {
|
fn cell(&mut self, rect: Rect, add_contents: impl FnOnce(&mut Ui)) -> Rect {
|
||||||
let mut child_ui = self.ui.child_ui(rect, *self.ui.layout());
|
let mut child_ui = self.ui.child_ui(rect, *self.ui.layout());
|
||||||
|
|
||||||
if clip {
|
if self.clip {
|
||||||
let mut clip_rect = child_ui.clip_rect();
|
let mut clip_rect = child_ui.clip_rect();
|
||||||
clip_rect.min = clip_rect.min.max(rect.min);
|
clip_rect.min = clip_rect.min.max(rect.min);
|
||||||
clip_rect.max = clip_rect.max.min(rect.max);
|
clip_rect.max = clip_rect.max.min(rect.max);
|
||||||
|
|
|
@ -40,6 +40,7 @@ use egui::{Response, Ui};
|
||||||
pub struct StripBuilder<'a> {
|
pub struct StripBuilder<'a> {
|
||||||
ui: &'a mut Ui,
|
ui: &'a mut Ui,
|
||||||
sizing: Sizing,
|
sizing: Sizing,
|
||||||
|
clip: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StripBuilder<'a> {
|
impl<'a> StripBuilder<'a> {
|
||||||
|
@ -47,7 +48,17 @@ impl<'a> StripBuilder<'a> {
|
||||||
pub fn new(ui: &'a mut Ui) -> Self {
|
pub fn new(ui: &'a mut Ui) -> Self {
|
||||||
let sizing = Sizing::new();
|
let sizing = Sizing::new();
|
||||||
|
|
||||||
Self { ui, sizing }
|
Self {
|
||||||
|
ui,
|
||||||
|
sizing,
|
||||||
|
clip: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Should we clip the contents of each cell? Default: `true`.
|
||||||
|
pub fn clip(mut self, clip: bool) -> Self {
|
||||||
|
self.clip = clip;
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add size hint for one column/row.
|
/// Add size hint for one column/row.
|
||||||
|
@ -76,7 +87,7 @@ impl<'a> StripBuilder<'a> {
|
||||||
self.ui.available_rect_before_wrap().width() - self.ui.spacing().item_spacing.x,
|
self.ui.available_rect_before_wrap().width() - self.ui.spacing().item_spacing.x,
|
||||||
self.ui.spacing().item_spacing.x,
|
self.ui.spacing().item_spacing.x,
|
||||||
);
|
);
|
||||||
let mut layout = StripLayout::new(self.ui, CellDirection::Horizontal);
|
let mut layout = StripLayout::new(self.ui, CellDirection::Horizontal, self.clip);
|
||||||
strip(Strip {
|
strip(Strip {
|
||||||
layout: &mut layout,
|
layout: &mut layout,
|
||||||
direction: CellDirection::Horizontal,
|
direction: CellDirection::Horizontal,
|
||||||
|
@ -97,7 +108,7 @@ impl<'a> StripBuilder<'a> {
|
||||||
self.ui.available_rect_before_wrap().height() - self.ui.spacing().item_spacing.y,
|
self.ui.available_rect_before_wrap().height() - self.ui.spacing().item_spacing.y,
|
||||||
self.ui.spacing().item_spacing.y,
|
self.ui.spacing().item_spacing.y,
|
||||||
);
|
);
|
||||||
let mut layout = StripLayout::new(self.ui, CellDirection::Vertical);
|
let mut layout = StripLayout::new(self.ui, CellDirection::Vertical, self.clip);
|
||||||
strip(Strip {
|
strip(Strip {
|
||||||
layout: &mut layout,
|
layout: &mut layout,
|
||||||
direction: CellDirection::Vertical,
|
direction: CellDirection::Vertical,
|
||||||
|
@ -136,35 +147,18 @@ impl<'a, 'b> Strip<'a, 'b> {
|
||||||
self.layout.empty(width, height);
|
self.layout.empty(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cell_impl(&mut self, clip: bool, add_contents: impl FnOnce(&mut Ui)) {
|
/// Add cell contents.
|
||||||
let (width, height) = self.next_cell_size();
|
|
||||||
self.layout.add(width, height, clip, add_contents);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add cell, content is wrapped
|
|
||||||
pub fn cell(&mut self, add_contents: impl FnOnce(&mut Ui)) {
|
pub fn cell(&mut self, add_contents: impl FnOnce(&mut Ui)) {
|
||||||
self.cell_impl(false, add_contents);
|
let (width, height) = self.next_cell_size();
|
||||||
}
|
self.layout.add(width, height, add_contents);
|
||||||
|
|
||||||
/// Add cell, content is clipped
|
|
||||||
pub fn cell_clip(&mut self, add_contents: impl FnOnce(&mut Ui)) {
|
|
||||||
self.cell_impl(true, add_contents);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn strip_impl(&mut self, clip: bool, strip_builder: impl FnOnce(StripBuilder<'_>)) {
|
|
||||||
self.cell_impl(clip, |ui| {
|
|
||||||
strip_builder(StripBuilder::new(ui));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add strip as cell
|
/// Add strip as cell
|
||||||
pub fn strip(&mut self, strip_builder: impl FnOnce(StripBuilder<'_>)) {
|
pub fn strip(&mut self, strip_builder: impl FnOnce(StripBuilder<'_>)) {
|
||||||
self.strip_impl(false, strip_builder);
|
let clip = self.layout.clip;
|
||||||
}
|
self.cell(|ui| {
|
||||||
|
strip_builder(StripBuilder::new(ui).clip(clip));
|
||||||
/// Add strip as cell, content is clipped
|
});
|
||||||
pub fn strip_clip(&mut self, strip_builder: impl FnOnce(StripBuilder<'_>)) {
|
|
||||||
self.strip_impl(true, strip_builder);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ use egui::{Response, Ui};
|
||||||
/// row.col(|ui| {
|
/// row.col(|ui| {
|
||||||
/// ui.label("first row growing cell");
|
/// ui.label("first row growing cell");
|
||||||
/// });
|
/// });
|
||||||
/// row.col_clip(|ui| {
|
/// row.col(|ui| {
|
||||||
/// ui.button("action");
|
/// ui.button("action");
|
||||||
/// });
|
/// });
|
||||||
/// });
|
/// });
|
||||||
|
@ -53,6 +53,7 @@ pub struct TableBuilder<'a> {
|
||||||
scroll: bool,
|
scroll: bool,
|
||||||
striped: bool,
|
striped: bool,
|
||||||
resizable: bool,
|
resizable: bool,
|
||||||
|
clip: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TableBuilder<'a> {
|
impl<'a> TableBuilder<'a> {
|
||||||
|
@ -65,6 +66,7 @@ impl<'a> TableBuilder<'a> {
|
||||||
scroll: true,
|
scroll: true,
|
||||||
striped: false,
|
striped: false,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
|
clip: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +96,12 @@ impl<'a> TableBuilder<'a> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Should we clip the contents of each cell? Default: `true`.
|
||||||
|
pub fn clip(mut self, clip: bool) -> Self {
|
||||||
|
self.clip = clip;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Add size hint for column
|
/// Add size hint for column
|
||||||
pub fn column(mut self, width: Size) -> Self {
|
pub fn column(mut self, width: Size) -> Self {
|
||||||
self.sizing.add(width);
|
self.sizing.add(width);
|
||||||
|
@ -127,6 +135,7 @@ impl<'a> TableBuilder<'a> {
|
||||||
scroll,
|
scroll,
|
||||||
striped,
|
striped,
|
||||||
resizable,
|
resizable,
|
||||||
|
clip,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let resize_id = resizable.then(|| ui.id().with("__table_resize"));
|
let resize_id = resizable.then(|| ui.id().with("__table_resize"));
|
||||||
|
@ -141,13 +150,12 @@ impl<'a> TableBuilder<'a> {
|
||||||
let table_top = ui.cursor().top();
|
let table_top = ui.cursor().top();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut layout = StripLayout::new(ui, CellDirection::Horizontal);
|
let mut layout = StripLayout::new(ui, CellDirection::Horizontal, clip);
|
||||||
header(TableRow {
|
header(TableRow {
|
||||||
layout: &mut layout,
|
layout: &mut layout,
|
||||||
widths: &widths,
|
widths: &widths,
|
||||||
striped: false,
|
striped: false,
|
||||||
height,
|
height,
|
||||||
clicked: false,
|
|
||||||
});
|
});
|
||||||
layout.allocate_rect();
|
layout.allocate_rect();
|
||||||
}
|
}
|
||||||
|
@ -161,6 +169,7 @@ impl<'a> TableBuilder<'a> {
|
||||||
widths,
|
widths,
|
||||||
scroll,
|
scroll,
|
||||||
striped,
|
striped,
|
||||||
|
clip,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,6 +186,7 @@ impl<'a> TableBuilder<'a> {
|
||||||
scroll,
|
scroll,
|
||||||
striped,
|
striped,
|
||||||
resizable,
|
resizable,
|
||||||
|
clip,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let resize_id = resizable.then(|| ui.id().with("__table_resize"));
|
let resize_id = resizable.then(|| ui.id().with("__table_resize"));
|
||||||
|
@ -199,6 +209,7 @@ impl<'a> TableBuilder<'a> {
|
||||||
widths,
|
widths,
|
||||||
scroll,
|
scroll,
|
||||||
striped,
|
striped,
|
||||||
|
clip,
|
||||||
}
|
}
|
||||||
.body(body);
|
.body(body);
|
||||||
}
|
}
|
||||||
|
@ -216,6 +227,7 @@ pub struct Table<'a> {
|
||||||
widths: Vec<f32>,
|
widths: Vec<f32>,
|
||||||
scroll: bool,
|
scroll: bool,
|
||||||
striped: bool,
|
striped: bool,
|
||||||
|
clip: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Table<'a> {
|
impl<'a> Table<'a> {
|
||||||
|
@ -233,6 +245,7 @@ impl<'a> Table<'a> {
|
||||||
widths,
|
widths,
|
||||||
scroll,
|
scroll,
|
||||||
striped,
|
striped,
|
||||||
|
clip,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let avail_rect = ui.available_rect_before_wrap();
|
let avail_rect = ui.available_rect_before_wrap();
|
||||||
|
@ -242,7 +255,7 @@ impl<'a> Table<'a> {
|
||||||
egui::ScrollArea::new([false, scroll])
|
egui::ScrollArea::new([false, scroll])
|
||||||
.auto_shrink([true; 2])
|
.auto_shrink([true; 2])
|
||||||
.show(ui, move |ui| {
|
.show(ui, move |ui| {
|
||||||
let layout = StripLayout::new(ui, CellDirection::Horizontal);
|
let layout = StripLayout::new(ui, CellDirection::Horizontal, clip);
|
||||||
|
|
||||||
body(TableBody {
|
body(TableBody {
|
||||||
layout,
|
layout,
|
||||||
|
@ -355,7 +368,6 @@ impl<'a> TableBody<'a> {
|
||||||
widths: &self.widths,
|
widths: &self.widths,
|
||||||
striped: false,
|
striped: false,
|
||||||
height: skip_height,
|
height: skip_height,
|
||||||
clicked: false,
|
|
||||||
}
|
}
|
||||||
.col(|_| ()); // advances the cursor
|
.col(|_| ()); // advances the cursor
|
||||||
}
|
}
|
||||||
|
@ -372,7 +384,6 @@ impl<'a> TableBody<'a> {
|
||||||
widths: &self.widths,
|
widths: &self.widths,
|
||||||
striped: self.striped && idx % 2 == 0,
|
striped: self.striped && idx % 2 == 0,
|
||||||
height,
|
height,
|
||||||
clicked: false,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -385,7 +396,6 @@ impl<'a> TableBody<'a> {
|
||||||
widths: &self.widths,
|
widths: &self.widths,
|
||||||
striped: false,
|
striped: false,
|
||||||
height: skip_height,
|
height: skip_height,
|
||||||
clicked: false,
|
|
||||||
}
|
}
|
||||||
.col(|_| ()); // advances the cursor
|
.col(|_| ()); // advances the cursor
|
||||||
}
|
}
|
||||||
|
@ -398,7 +408,6 @@ impl<'a> TableBody<'a> {
|
||||||
widths: &self.widths,
|
widths: &self.widths,
|
||||||
striped: self.striped && self.row_nr % 2 == 0,
|
striped: self.striped && self.row_nr % 2 == 0,
|
||||||
height,
|
height,
|
||||||
clicked: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
self.row_nr += 1;
|
self.row_nr += 1;
|
||||||
|
@ -418,26 +427,11 @@ pub struct TableRow<'a, 'b> {
|
||||||
widths: &'b [f32],
|
widths: &'b [f32],
|
||||||
striped: bool,
|
striped: bool,
|
||||||
height: f32,
|
height: f32,
|
||||||
clicked: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> TableRow<'a, 'b> {
|
impl<'a, 'b> TableRow<'a, 'b> {
|
||||||
/// Check if row was clicked
|
/// Add the contents of a column.
|
||||||
pub fn clicked(&self) -> bool {
|
|
||||||
self.clicked
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add column, content is wrapped
|
|
||||||
pub fn col(&mut self, add_contents: impl FnOnce(&mut Ui)) -> Response {
|
pub fn col(&mut self, add_contents: impl FnOnce(&mut Ui)) -> Response {
|
||||||
self.column(false, add_contents)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add column, content is clipped
|
|
||||||
pub fn col_clip(&mut self, add_contents: impl FnOnce(&mut Ui)) -> Response {
|
|
||||||
self.column(true, add_contents)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn column(&mut self, clip: bool, add_contents: impl FnOnce(&mut Ui)) -> Response {
|
|
||||||
assert!(
|
assert!(
|
||||||
!self.widths.is_empty(),
|
!self.widths.is_empty(),
|
||||||
"Tried using more table columns than available."
|
"Tried using more table columns than available."
|
||||||
|
@ -448,19 +442,11 @@ impl<'a, 'b> TableRow<'a, 'b> {
|
||||||
let width = CellSize::Absolute(width);
|
let width = CellSize::Absolute(width);
|
||||||
let height = CellSize::Absolute(self.height);
|
let height = CellSize::Absolute(self.height);
|
||||||
|
|
||||||
let response;
|
|
||||||
|
|
||||||
if self.striped {
|
if self.striped {
|
||||||
response = self.layout.add_striped(width, height, clip, add_contents);
|
self.layout.add_striped(width, height, add_contents)
|
||||||
} else {
|
} else {
|
||||||
response = self.layout.add(width, height, clip, add_contents);
|
self.layout.add(width, height, add_contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
if response.clicked() {
|
|
||||||
self.clicked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
response
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue