Add and use TwoRowColToplevelLayout

This tries to find a split point in the list of toplevels to maximize
the scale factor when calling `RowColToplevelLayout` twice. If it
doesn't get a better scale factor, it just uses a single row/column.

Some things don't seem quite right, but the existing layout is not
perfect, and this can help.

Without the added cross axis spacing, there's overlap, so there may be
something wrong with the requested sizes...
This commit is contained in:
Ian Douglas Scott 2025-03-31 11:47:50 -07:00 committed by Ian Douglas Scott
parent 1fd7a86ecc
commit 7ab1f93acf
3 changed files with 77 additions and 3 deletions

View file

@ -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<Msg>(children: Vec<cosmic::Element<Msg>>) -> Toplevels<Msg> {
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<cosmic::Element<'a, Msg>>,
_msg: PhantomData<Msg>,
}

View file

@ -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> {

View file

@ -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<Length> {
AxisSize {
main: Length::Fill,
cross: Length::Shrink,
}
}
fn layout(
&self,
max_limit: AxisSize,
toplevels: &[LayoutToplevel<'_, AxisSize>],
) -> impl Iterator<Item = AxisRectangle> {
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))
}
}