1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-02 06:40:06 -04:00

Table resize (#1438)

* Let 1D strips fill up parent width/height
* Add Strip + Table + DatePicker to egui_extras changelog
* Expose some dragging- and pointer related context/memory methods
* Make tables resizable
This commit is contained in:
Emil Ernerfeldt
2022-04-01 12:01:00 +02:00
committed by GitHub
parent a52bbade45
commit 21c32a18d8
12 changed files with 323 additions and 159 deletions

View File

@@ -1,26 +1,84 @@
/// Size hint for table column/strip cell
/// Size hint for table column/strip cell.
#[derive(Clone, Debug, Copy)]
pub enum Size {
/// Absolute size in points
Absolute(f32),
/// Relative size relative to all available space. Values must be in range `0.0..=1.0`
Relative(f32),
/// [`Size::Relative`] with a minimum size in points
RelativeMinimum {
/// Relative size relative to all available space. Values must be in range `0.0..=1.0`
relative: f32,
/// Absolute minimum size in points
minimum: f32,
},
/// Multiple remainders each get the same space
Remainder,
/// [`Size::Remainder`] with a minimum size in points
RemainderMinimum(f32),
/// Absolute size in points, with a given range of allowed sizes to resize within.
Absolute { initial: f32, range: (f32, f32) },
/// Relative size relative to all available space.
Relative { fraction: f32, range: (f32, f32) },
/// Multiple remainders each get the same space.
Remainder { range: (f32, f32) },
}
impl Size {
/// Exactly this big, with no room for resize.
pub fn exact(points: f32) -> Self {
Self::Absolute {
initial: points,
range: (points, points),
}
}
/// Initially this big, but can resize.
pub fn initial(points: f32) -> Self {
Self::Absolute {
initial: points,
range: (0.0, f32::INFINITY),
}
}
/// Relative size relative to all available space. Values must be in range `0.0..=1.0`.
pub fn relative(fraction: f32) -> Self {
egui::egui_assert!(0.0 <= fraction && fraction <= 1.0);
Self::Relative {
fraction,
range: (0.0, f32::INFINITY),
}
}
/// Multiple remainders each get the same space.
pub fn remainder() -> Self {
Self::Remainder {
range: (0.0, f32::INFINITY),
}
}
/// Won't shrink below this size (in points).
pub fn at_least(mut self, minimum: f32) -> Self {
match &mut self {
Self::Absolute { range, .. }
| Self::Relative { range, .. }
| Self::Remainder { range, .. } => {
range.0 = minimum;
}
}
self
}
/// Won't grow above this size (in points).
pub fn at_most(mut self, maximum: f32) -> Self {
match &mut self {
Self::Absolute { range, .. }
| Self::Relative { range, .. }
| Self::Remainder { range, .. } => {
range.1 = maximum;
}
}
self
}
/// Allowed range of movement (in points), if in a resizable [`Table`].
pub fn range(self) -> (f32, f32) {
match self {
Self::Absolute { range, .. }
| Self::Relative { range, .. }
| Self::Remainder { range, .. } => range,
}
}
}
#[derive(Clone)]
pub struct Sizing {
sizes: Vec<Size>,
pub(crate) sizes: Vec<Size>,
}
impl Sizing {
@@ -32,24 +90,21 @@ impl Sizing {
self.sizes.push(size);
}
pub fn into_lengths(self, length: f32, spacing: f32) -> Vec<f32> {
pub fn to_lengths(&self, length: f32, spacing: f32) -> Vec<f32> {
let mut remainders = 0;
let sum_non_remainder = self
.sizes
.iter()
.map(|size| match size {
Size::Absolute(absolute) => *absolute,
Size::Relative(relative) => {
assert!(*relative > 0.0, "Below 0.0 is not allowed.");
assert!(*relative <= 1.0, "Above 1.0 is not allowed.");
length * relative
.map(|&size| match size {
Size::Absolute { initial, .. } => initial,
Size::Relative {
fraction,
range: (min, max),
} => {
assert!(0.0 <= fraction && fraction <= 1.0);
(length * fraction).clamp(min, max)
}
Size::RelativeMinimum { relative, minimum } => {
assert!(*relative > 0.0, "Below 0.0 is not allowed.");
assert!(*relative <= 1.0, "Above 1.0 is not allowed.");
minimum.max(length * relative)
}
Size::Remainder | Size::RemainderMinimum(..) => {
Size::Remainder { .. } => {
remainders += 1;
0.0
}
@@ -62,10 +117,10 @@ impl Sizing {
} else {
let mut remainder_length = length - sum_non_remainder;
let avg_remainder_length = 0.0f32.max(remainder_length / remainders as f32).floor();
self.sizes.iter().for_each(|size| {
if let Size::RemainderMinimum(minimum) = size {
if *minimum > avg_remainder_length {
remainder_length -= minimum;
self.sizes.iter().for_each(|&size| {
if let Size::Remainder { range: (min, _max) } = size {
if avg_remainder_length < min {
remainder_length -= min;
remainders -= 1;
}
}
@@ -78,13 +133,14 @@ impl Sizing {
};
self.sizes
.into_iter()
.map(|size| match size {
Size::Absolute(absolute) => absolute,
Size::Relative(relative) => length * relative,
Size::RelativeMinimum { relative, minimum } => minimum.max(length * relative),
Size::Remainder => avg_remainder_length,
Size::RemainderMinimum(minimum) => minimum.max(avg_remainder_length),
.iter()
.map(|&size| match size {
Size::Absolute { initial, .. } => initial,
Size::Relative {
fraction,
range: (min, max),
} => (length * fraction).clamp(min, max),
Size::Remainder { range: (min, max) } => avg_remainder_length.clamp(min, max),
})
.collect()
}
@@ -98,23 +154,16 @@ impl From<Vec<Size>> for Sizing {
#[test]
fn test_sizing() {
let sizing: Sizing = vec![Size::RemainderMinimum(20.0), Size::Remainder].into();
assert_eq!(sizing.clone().into_lengths(50.0, 0.0), vec![25.0, 25.0]);
assert_eq!(sizing.clone().into_lengths(30.0, 0.0), vec![20.0, 10.0]);
assert_eq!(sizing.clone().into_lengths(20.0, 0.0), vec![20.0, 0.0]);
assert_eq!(sizing.clone().into_lengths(10.0, 0.0), vec![20.0, 0.0]);
assert_eq!(sizing.into_lengths(20.0, 10.0), vec![20.0, 0.0]);
let sizing: Sizing = vec![Size::remainder().at_least(20.0), Size::remainder()].into();
assert_eq!(sizing.to_lengths(50.0, 0.0), vec![25.0, 25.0]);
assert_eq!(sizing.to_lengths(30.0, 0.0), vec![20.0, 10.0]);
assert_eq!(sizing.to_lengths(20.0, 0.0), vec![20.0, 0.0]);
assert_eq!(sizing.to_lengths(10.0, 0.0), vec![20.0, 0.0]);
assert_eq!(sizing.to_lengths(20.0, 10.0), vec![20.0, 0.0]);
let sizing: Sizing = vec![
Size::RelativeMinimum {
relative: 0.5,
minimum: 10.0,
},
Size::Absolute(10.0),
]
.into();
assert_eq!(sizing.clone().into_lengths(50.0, 0.0), vec![25.0, 10.0]);
assert_eq!(sizing.clone().into_lengths(30.0, 0.0), vec![15.0, 10.0]);
assert_eq!(sizing.clone().into_lengths(20.0, 0.0), vec![10.0, 10.0]);
assert_eq!(sizing.into_lengths(10.0, 0.0), vec![10.0, 10.0]);
let sizing: Sizing = vec![Size::relative(0.5).at_least(10.0), Size::exact(10.0)].into();
assert_eq!(sizing.to_lengths(50.0, 0.0), vec![25.0, 10.0]);
assert_eq!(sizing.to_lengths(30.0, 0.0), vec![15.0, 10.0]);
assert_eq!(sizing.to_lengths(20.0, 0.0), vec![10.0, 10.0]);
assert_eq!(sizing.to_lengths(10.0, 0.0), vec![10.0, 10.0]);
}