diff --git a/src/widgets/toplevels/mod.rs b/src/widgets/toplevels/mod.rs index 356f681..b92df11 100644 --- a/src/widgets/toplevels/mod.rs +++ b/src/widgets/toplevels/mod.rs @@ -11,19 +11,19 @@ use cosmic::iced::{ use std::marker::PhantomData; mod toplevel_layout; -use toplevel_layout::{LayoutToplevel, RowColToplevelLayout, ToplevelLayout}; +use toplevel_layout::{LayoutToplevel, ToplevelLayout, TwoRowColToplevelLayout}; pub fn toplevels(children: Vec>) -> Toplevels { Toplevels { // TODO configurable - layout: RowColToplevelLayout::new(Axis::Horizontal, 16), + layout: TwoRowColToplevelLayout::new(Axis::Horizontal, 16), children, _msg: PhantomData, } } pub struct Toplevels<'a, Msg> { - layout: RowColToplevelLayout, + layout: TwoRowColToplevelLayout, children: Vec>, _msg: PhantomData, } diff --git a/src/widgets/toplevels/toplevel_layout/mod.rs b/src/widgets/toplevels/toplevel_layout/mod.rs index e0cc75d..481f623 100644 --- a/src/widgets/toplevels/toplevel_layout/mod.rs +++ b/src/widgets/toplevels/toplevel_layout/mod.rs @@ -7,6 +7,8 @@ use std::marker::PhantomData; mod axis_toplevel_layout; mod row_col_toplevel_layout; pub(crate) use row_col_toplevel_layout::RowColToplevelLayout; +mod two_row_col_toplevel_layout; +pub(crate) use two_row_col_toplevel_layout::TwoRowColToplevelLayout; #[derive(Debug)] pub(crate) struct LayoutToplevel<'a, S = Size> { diff --git a/src/widgets/toplevels/toplevel_layout/two_row_col_toplevel_layout.rs b/src/widgets/toplevels/toplevel_layout/two_row_col_toplevel_layout.rs new file mode 100644 index 0000000..25ab152 --- /dev/null +++ b/src/widgets/toplevels/toplevel_layout/two_row_col_toplevel_layout.rs @@ -0,0 +1,72 @@ +use cosmic::iced::{advanced::layout::flex::Axis, Length}; + +use super::{ + axis_toplevel_layout::{AxisPoint, AxisRectangle, AxisSize, AxisToplevelLayout}, + row_col_toplevel_layout::RowColToplevelLayout, + LayoutToplevel, +}; + +pub(crate) struct TwoRowColToplevelLayout(RowColToplevelLayout); + +impl TwoRowColToplevelLayout { + pub fn new(axis: Axis, spacing: u32) -> Self { + Self(RowColToplevelLayout::new(axis, spacing)) + } +} + +impl AxisToplevelLayout for TwoRowColToplevelLayout { + fn axis(&self) -> &Axis { + &self.0.axis + } + + fn size(&self) -> AxisSize { + AxisSize { + main: Length::Fill, + cross: Length::Shrink, + } + } + + fn layout( + &self, + max_limit: AxisSize, + toplevels: &[LayoutToplevel<'_, AxisSize>], + ) -> impl Iterator { + let requested_main_total = self.0.requested_main_total(&toplevels); + let scale_factor = self.0.scale_factor(max_limit, toplevels); + + let half_max_limit = AxisSize { + main: max_limit.main, + cross: max_limit.cross / 2. - self.0.spacing as f32, + }; + + // See if two row layout is better + // TODO not a good fix if there is a large window and many smaller ones? + if requested_main_total > max_limit.main && toplevels.len() > 1 { + // decide best way to partition list + let (split_point, two_row_scale_factor) = (1..toplevels.len()) + .map(|i| { + let (top_row, bottom_row) = toplevels.split_at(i); + let top_scale_factor = self.0.scale_factor(half_max_limit, top_row); + let bottom_scale_factor = self.0.scale_factor(half_max_limit, bottom_row); + (i, top_scale_factor.min(bottom_scale_factor)) + }) + .max_by(|(_, scale1), (_, scale2)| scale1.total_cmp(scale2)) + .unwrap(); + // Better layout + if two_row_scale_factor > scale_factor { + // TODO padding + let row1 = self.0.layout(half_max_limit, &toplevels[..split_point]); + let row2 = self + .0 + .layout(half_max_limit, &toplevels[split_point..]) + .map(move |mut rect| { + rect.origin.cross += max_limit.cross / 2. + self.0.spacing as f32; + rect + }); + return itertools::Either::Left(row1.chain(row2)); + } + } + + itertools::Either::Right(self.0.layout(max_limit, toplevels)) + } +}