Fix join widgets not handling large sizes

This commit is contained in:
Joscha 2023-02-19 02:09:41 +01:00
parent b1c276ec38
commit 8f155dc6a2

View file

@ -51,8 +51,7 @@ use super::{Either2, Either3, Either4, Either5, Either6, Either7};
// removes all segments that are at least as small as their allotment. It then // removes all segments that are at least as small as their allotment. It then
// resizes the remaining segments to their allotments. // resizes the remaining segments to their allotments.
// TODO Handle overflows and other sizing issues correctly #[derive(Debug)]
struct Segment { struct Segment {
size: u16, size: u16,
weight: f32, weight: f32,
@ -74,13 +73,24 @@ impl Segment {
} }
} }
fn total_size(segments: &[Segment]) -> u16 {
let mut total = 0_u16;
for segment in segments {
total = total.saturating_add(segment.size);
}
total
}
fn total_weight(segments: &[&mut Segment]) -> f32 {
segments.iter().map(|s| s.weight).sum()
}
fn balance(segments: &mut [Segment], available: u16) { fn balance(segments: &mut [Segment], available: u16) {
if segments.is_empty() { if segments.is_empty() {
return; return;
} }
let total_size = segments.iter().map(|s| s.size).sum::<u16>(); match total_size(segments).cmp(&available) {
match total_size.cmp(&available) {
Ordering::Less => grow(segments, available), Ordering::Less => grow(segments, available),
Ordering::Greater => shrink(segments, available), Ordering::Greater => shrink(segments, available),
Ordering::Equal => {} Ordering::Equal => {}
@ -90,13 +100,13 @@ fn balance(segments: &mut [Segment], available: u16) {
} }
fn grow(segments: &mut [Segment], mut available: u16) { fn grow(segments: &mut [Segment], mut available: u16) {
assert!(available > segments.iter().map(|s| s.size).sum::<u16>()); assert!(available > total_size(segments));
let mut segments = segments.iter_mut().collect::<Vec<_>>(); let mut segments = segments.iter_mut().collect::<Vec<_>>();
// Repeatedly remove all segments that do not need to grow, i. e. that are // Repeatedly remove all segments that do not need to grow, i. e. that are
// at least as large as their allotment. // at least as large as their allotment.
loop { loop {
let mut total_weight = segments.iter().map(|s| s.weight).sum::<f32>(); let mut total_weight = total_weight(&segments);
// If there are no segments with a weight > 0, space is distributed // If there are no segments with a weight > 0, space is distributed
// evenly among all remaining segments. // evenly among all remaining segments.
@ -149,13 +159,13 @@ fn grow(segments: &mut [Segment], mut available: u16) {
} }
fn shrink(segments: &mut [Segment], mut available: u16) { fn shrink(segments: &mut [Segment], mut available: u16) {
assert!(available < segments.iter().map(|s| s.size).sum::<u16>()); assert!(available < total_size(segments));
let mut segments = segments.iter_mut().collect::<Vec<_>>(); let mut segments = segments.iter_mut().collect::<Vec<_>>();
// Repeatedly remove all segments that do not need to shrink, i. e. that are // Repeatedly remove all segments that do not need to shrink, i. e. that are
// at least as small as their allotment. // at least as small as their allotment.
loop { loop {
let mut total_weight = segments.iter().map(|s| s.weight).sum::<f32>(); let mut total_weight = total_weight(&segments);
// If there are no segments with a weight > 0, space is distributed // If there are no segments with a weight > 0, space is distributed
// evenly among all remaining segments. // evenly among all remaining segments.
@ -258,20 +268,20 @@ where
} }
balance(&mut balanced_segments, max_width); balance(&mut balanced_segments, max_width);
let mut width = 0; let mut width = 0_u16;
let mut height = 0; let mut height = 0_u16;
for (segment, balanced) in self.segments.iter().zip(balanced_segments.into_iter()) { for (segment, balanced) in self.segments.iter().zip(balanced_segments.into_iter()) {
let size = segment.inner.size(frame, Some(balanced.size), max_height)?; let size = segment.inner.size(frame, Some(balanced.size), max_height)?;
width += size.width; width = width.saturating_add(size.width);
height = height.max(size.height); height = height.max(size.height);
} }
Ok(Size::new(width, height)) Ok(Size::new(width, height))
} else { } else {
let mut width = 0; let mut width = 0_u16;
let mut height = 0; let mut height = 0_u16;
for segment in &self.segments { for segment in &self.segments {
let size = segment.inner.size(frame, max_width, max_height)?; let size = segment.inner.size(frame, max_width, max_height)?;
width += size.width; width = width.saturating_add(size.width);
height = height.max(size.height); height = height.max(size.height);
} }
Ok(Size::new(width, height)) Ok(Size::new(width, height))
@ -324,23 +334,23 @@ where
} }
balance(&mut balanced_segments, max_width); balance(&mut balanced_segments, max_width);
let mut width = 0; let mut width = 0_u16;
let mut height = 0; let mut height = 0_u16;
for (segment, balanced) in self.segments.iter().zip(balanced_segments.into_iter()) { for (segment, balanced) in self.segments.iter().zip(balanced_segments.into_iter()) {
let size = segment let size = segment
.inner .inner
.size(frame, Some(balanced.size), max_height) .size(frame, Some(balanced.size), max_height)
.await?; .await?;
width += size.width; width = width.saturating_add(size.width);
height = height.max(size.height); height = height.max(size.height);
} }
Ok(Size::new(width, height)) Ok(Size::new(width, height))
} else { } else {
let mut width = 0; let mut width = 0_u16;
let mut height = 0; let mut height = 0_u16;
for segment in &self.segments { for segment in &self.segments {
let size = segment.inner.size(frame, max_width, max_height).await?; let size = segment.inner.size(frame, max_width, max_height).await?;
width += size.width; width = width.saturating_add(size.width);
height = height.max(size.height); height = height.max(size.height);
} }
Ok(Size::new(width, height)) Ok(Size::new(width, height))
@ -399,21 +409,21 @@ where
} }
balance(&mut balanced_segments, max_height); balance(&mut balanced_segments, max_height);
let mut width = 0; let mut width = 0_u16;
let mut height = 0; let mut height = 0_u16;
for (segment, balanced) in self.segments.iter().zip(balanced_segments.into_iter()) { for (segment, balanced) in self.segments.iter().zip(balanced_segments.into_iter()) {
let size = segment.inner.size(frame, max_width, Some(balanced.size))?; let size = segment.inner.size(frame, max_width, Some(balanced.size))?;
width = width.max(size.width); width = width.max(size.width);
height += size.height; height = height.saturating_add(size.height);
} }
Ok(Size::new(width, height)) Ok(Size::new(width, height))
} else { } else {
let mut width = 0; let mut width = 0_u16;
let mut height = 0; let mut height = 0_u16;
for segment in &self.segments { for segment in &self.segments {
let size = segment.inner.size(frame, max_width, max_height)?; let size = segment.inner.size(frame, max_width, max_height)?;
width = width.max(size.width); width = width.max(size.width);
height += size.height; height = height.saturating_add(size.height);
} }
Ok(Size::new(width, height)) Ok(Size::new(width, height))
} }
@ -465,24 +475,24 @@ where
} }
balance(&mut balanced_segments, max_height); balance(&mut balanced_segments, max_height);
let mut width = 0; let mut width = 0_u16;
let mut height = 0; let mut height = 0_u16;
for (segment, balanced) in self.segments.iter().zip(balanced_segments.into_iter()) { for (segment, balanced) in self.segments.iter().zip(balanced_segments.into_iter()) {
let size = segment let size = segment
.inner .inner
.size(frame, max_width, Some(balanced.size)) .size(frame, max_width, Some(balanced.size))
.await?; .await?;
width = width.max(size.width); width = width.max(size.width);
height += size.height; height = height.saturating_add(size.height);
} }
Ok(Size::new(width, height)) Ok(Size::new(width, height))
} else { } else {
let mut width = 0; let mut width = 0_u16;
let mut height = 0; let mut height = 0_u16;
for segment in &self.segments { for segment in &self.segments {
let size = segment.inner.size(frame, max_width, max_height).await?; let size = segment.inner.size(frame, max_width, max_height).await?;
width = width.max(size.width); width = width.max(size.width);
height += size.height; height = height.saturating_add(size.height);
} }
Ok(Size::new(width, height)) Ok(Size::new(width, height))
} }