mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 06:10:06 -04:00
egui_extras::Table improvements (#2369)
* Use simple `ui.interact` for the resize line * Introduce TableReizeState * Simplify some code * Add striped options to table demo * Auto-size table columns by double-clicking the resize line * Table: add option to auto-size the columns * Table: don't let column width gets too small, unless clipping is on * egui_extras: always use serde Otherwise using `get_persisted` etc is impossible, and working around that tedious. * Avoid clipping last column in a resizable table * Some better naming * Table: Use new `Column` for setting column sizes and properties Also make `clip` a per-column property * All Table:s store state for auto-sizing purposes * Customize each column wether or not it is resizable * fix some auto-sizing bugs * Fix shrinkage of adaptive column content * Rename `scroll` to `vscroll` for clarity * Add Table::scroll_to_row * scroll_to_row takes alignment * Fix bug in table sizing * Strip: turn clipping OFF by default, because it is dangerous and sucks * Add TableBody::mac_rect helper * Table: add options to control the scroll area height. * Docstring fixes * Cleanup
This commit is contained in:
@@ -2,8 +2,7 @@ use super::popup::DatePickerPopup;
|
||||
use chrono::{Date, Utc};
|
||||
use egui::{Area, Button, Frame, InnerResponse, Key, Order, RichText, Ui, Widget};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[derive(Default, Clone, serde::Deserialize, serde::Serialize)]
|
||||
pub(crate) struct DatePickerButtonState {
|
||||
pub picker_visible: bool,
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
use super::{button::DatePickerButtonState, month_data};
|
||||
use crate::{Size, StripBuilder, TableBuilder};
|
||||
use chrono::{Date, Datelike, NaiveDate, Utc, Weekday};
|
||||
|
||||
use egui::{Align, Button, Color32, ComboBox, Direction, Id, Layout, RichText, Ui, Vec2};
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
use super::{button::DatePickerButtonState, month_data};
|
||||
|
||||
use crate::{Column, Size, StripBuilder, TableBuilder};
|
||||
|
||||
#[derive(Default, Clone, serde::Deserialize, serde::Serialize)]
|
||||
struct DatePickerPopupState {
|
||||
year: i32,
|
||||
month: u32,
|
||||
@@ -243,9 +245,8 @@ impl<'a> DatePickerPopup<'a> {
|
||||
strip.cell(|ui| {
|
||||
ui.spacing_mut().item_spacing = Vec2::new(1.0, 2.0);
|
||||
TableBuilder::new(ui)
|
||||
.scroll(false)
|
||||
.clip(false)
|
||||
.columns(Size::remainder(), if self.calendar_week { 8 } else { 7 })
|
||||
.vscroll(false)
|
||||
.columns(Column::remainder(), if self.calendar_week { 8 } else { 7 })
|
||||
.header(height, |mut header| {
|
||||
if self.calendar_week {
|
||||
header.col(|ui| {
|
||||
|
||||
@@ -31,19 +31,15 @@ pub struct StripLayout<'l> {
|
||||
pub(crate) ui: &'l mut Ui,
|
||||
direction: CellDirection,
|
||||
pub(crate) rect: Rect,
|
||||
cursor: Pos2,
|
||||
pub(crate) cursor: Pos2,
|
||||
/// Keeps track of the max used position,
|
||||
/// so we know how much space we used.
|
||||
max: Pos2,
|
||||
pub(crate) clip: bool,
|
||||
cell_layout: egui::Layout,
|
||||
}
|
||||
|
||||
impl<'l> StripLayout<'l> {
|
||||
pub(crate) fn new(
|
||||
ui: &'l mut Ui,
|
||||
direction: CellDirection,
|
||||
clip: bool,
|
||||
cell_layout: egui::Layout,
|
||||
) -> Self {
|
||||
pub(crate) fn new(ui: &'l mut Ui, direction: CellDirection, cell_layout: egui::Layout) -> Self {
|
||||
let rect = ui.available_rect_before_wrap();
|
||||
let pos = rect.left_top();
|
||||
|
||||
@@ -53,7 +49,6 @@ impl<'l> StripLayout<'l> {
|
||||
rect,
|
||||
cursor: pos,
|
||||
max: pos,
|
||||
clip,
|
||||
cell_layout,
|
||||
}
|
||||
}
|
||||
@@ -92,34 +87,41 @@ impl<'l> StripLayout<'l> {
|
||||
self.set_pos(self.cell_rect(&width, &height));
|
||||
}
|
||||
|
||||
/// This is the innermost part of [`crate::Table`] and [`crate::Strip`].
|
||||
///
|
||||
/// Return the used space (`min_rect`) plus the [`Response`] of the whole cell.
|
||||
pub(crate) fn add(
|
||||
&mut self,
|
||||
clip: bool,
|
||||
striped: bool,
|
||||
width: CellSize,
|
||||
height: CellSize,
|
||||
add_contents: impl FnOnce(&mut Ui),
|
||||
) -> Response {
|
||||
let rect = self.cell_rect(&width, &height);
|
||||
let used_rect = self.cell(rect, add_contents);
|
||||
self.set_pos(rect);
|
||||
self.ui.allocate_rect(rect.union(used_rect), Sense::hover())
|
||||
}
|
||||
add_cell_contents: impl FnOnce(&mut Ui),
|
||||
) -> (Rect, Response) {
|
||||
let max_rect = self.cell_rect(&width, &height);
|
||||
|
||||
pub(crate) fn add_striped(
|
||||
&mut self,
|
||||
width: CellSize,
|
||||
height: CellSize,
|
||||
add_contents: impl FnOnce(&mut Ui),
|
||||
) -> Response {
|
||||
let rect = self.cell_rect(&width, &height);
|
||||
if striped {
|
||||
// Make sure we don't have a gap in the stripe background:
|
||||
let stripe_rect = max_rect.expand2(0.5 * self.ui.spacing().item_spacing);
|
||||
|
||||
// Make sure we don't have a gap in the stripe background:
|
||||
let rect = rect.expand2(0.5 * self.ui.spacing().item_spacing);
|
||||
self.ui
|
||||
.painter()
|
||||
.rect_filled(stripe_rect, 0.0, self.ui.visuals().faint_bg_color);
|
||||
}
|
||||
|
||||
self.ui
|
||||
.painter()
|
||||
.rect_filled(rect, 0.0, self.ui.visuals().faint_bg_color);
|
||||
let used_rect = self.cell(clip, max_rect, add_cell_contents);
|
||||
|
||||
self.add(width, height, add_contents)
|
||||
self.set_pos(max_rect);
|
||||
|
||||
let allocation_rect = if clip {
|
||||
max_rect
|
||||
} else {
|
||||
max_rect.union(used_rect)
|
||||
};
|
||||
|
||||
let response = self.ui.allocate_rect(allocation_rect, Sense::hover());
|
||||
|
||||
(used_rect, response)
|
||||
}
|
||||
|
||||
/// only needed for layouts with multiple lines, like [`Table`](crate::Table).
|
||||
@@ -144,17 +146,17 @@ impl<'l> StripLayout<'l> {
|
||||
self.ui.allocate_rect(rect, Sense::hover());
|
||||
}
|
||||
|
||||
fn cell(&mut self, rect: Rect, add_contents: impl FnOnce(&mut Ui)) -> Rect {
|
||||
fn cell(&mut self, clip: bool, rect: Rect, add_cell_contents: impl FnOnce(&mut Ui)) -> Rect {
|
||||
let mut child_ui = self.ui.child_ui(rect, self.cell_layout);
|
||||
|
||||
if self.clip {
|
||||
if clip {
|
||||
let margin = egui::Vec2::splat(self.ui.visuals().clip_rect_margin);
|
||||
let margin = margin.min(0.5 * self.ui.spacing().item_spacing);
|
||||
let clip_rect = rect.expand2(margin);
|
||||
child_ui.set_clip_rect(clip_rect.intersect(child_ui.clip_rect()));
|
||||
}
|
||||
|
||||
add_contents(&mut child_ui);
|
||||
add_cell_contents(&mut child_ui);
|
||||
child_ui.min_rect()
|
||||
}
|
||||
|
||||
|
||||
@@ -56,11 +56,11 @@ impl<'a> StripBuilder<'a> {
|
||||
ui,
|
||||
sizing: Default::default(),
|
||||
cell_layout,
|
||||
clip: true,
|
||||
clip: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Should we clip the contents of each cell? Default: `true`.
|
||||
/// Should we clip the contents of each cell? Default: `false`.
|
||||
pub fn clip(mut self, clip: bool) -> Self {
|
||||
self.clip = clip;
|
||||
self
|
||||
@@ -98,15 +98,11 @@ impl<'a> StripBuilder<'a> {
|
||||
self.ui.available_rect_before_wrap().width(),
|
||||
self.ui.spacing().item_spacing.x,
|
||||
);
|
||||
let mut layout = StripLayout::new(
|
||||
self.ui,
|
||||
CellDirection::Horizontal,
|
||||
self.clip,
|
||||
self.cell_layout,
|
||||
);
|
||||
let mut layout = StripLayout::new(self.ui, CellDirection::Horizontal, self.cell_layout);
|
||||
strip(Strip {
|
||||
layout: &mut layout,
|
||||
direction: CellDirection::Horizontal,
|
||||
clip: self.clip,
|
||||
sizes: widths,
|
||||
size_index: 0,
|
||||
});
|
||||
@@ -125,15 +121,11 @@ impl<'a> StripBuilder<'a> {
|
||||
self.ui.available_rect_before_wrap().height(),
|
||||
self.ui.spacing().item_spacing.y,
|
||||
);
|
||||
let mut layout = StripLayout::new(
|
||||
self.ui,
|
||||
CellDirection::Vertical,
|
||||
self.clip,
|
||||
self.cell_layout,
|
||||
);
|
||||
let mut layout = StripLayout::new(self.ui, CellDirection::Vertical, self.cell_layout);
|
||||
strip(Strip {
|
||||
layout: &mut layout,
|
||||
direction: CellDirection::Vertical,
|
||||
clip: self.clip,
|
||||
sizes: heights,
|
||||
size_index: 0,
|
||||
});
|
||||
@@ -146,6 +138,7 @@ impl<'a> StripBuilder<'a> {
|
||||
pub struct Strip<'a, 'b> {
|
||||
layout: &'b mut StripLayout<'a>,
|
||||
direction: CellDirection,
|
||||
clip: bool,
|
||||
sizes: Vec<f32>,
|
||||
size_index: usize,
|
||||
}
|
||||
@@ -172,7 +165,9 @@ impl<'a, 'b> Strip<'a, 'b> {
|
||||
/// Add cell contents.
|
||||
pub fn cell(&mut self, add_contents: impl FnOnce(&mut Ui)) {
|
||||
let (width, height) = self.next_cell_size();
|
||||
self.layout.add(width, height, add_contents);
|
||||
let striped = false;
|
||||
self.layout
|
||||
.add(self.clip, striped, width, height, add_contents);
|
||||
}
|
||||
|
||||
/// Add an empty cell.
|
||||
@@ -183,7 +178,7 @@ impl<'a, 'b> Strip<'a, 'b> {
|
||||
|
||||
/// Add a strip as cell.
|
||||
pub fn strip(&mut self, strip_builder: impl FnOnce(StripBuilder<'_>)) {
|
||||
let clip = self.layout.clip;
|
||||
let clip = self.clip;
|
||||
self.cell(|ui| {
|
||||
strip_builder(StripBuilder::new(ui).clip(clip));
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user