toplevel_layout: Add AxisToplevelLayout helper
This commit is contained in:
parent
1342e37ad6
commit
b5d2eed726
5 changed files with 136 additions and 66 deletions
|
|
@ -65,6 +65,7 @@ impl<Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for Toplevels<'_, Msg> {
|
||||||
.zip(tree.children.iter_mut())
|
.zip(tree.children.iter_mut())
|
||||||
.zip(assigned_rects)
|
.zip(assigned_rects)
|
||||||
.map(|((child, tree), assigned_rect)| {
|
.map(|((child, tree), assigned_rect)| {
|
||||||
|
dbg!(assigned_rect);
|
||||||
let child_limits = layout::Limits::new(Size::ZERO, assigned_rect.size());
|
let child_limits = layout::Limits::new(Size::ZERO, assigned_rect.size());
|
||||||
let layout = child.as_widget().layout(tree, renderer, &child_limits);
|
let layout = child.as_widget().layout(tree, renderer, &child_limits);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
use cosmic::iced::{advanced::layout::flex::Axis, Length, Point, Rectangle, Size};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use super::{LayoutToplevel, ToplevelLayout};
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct AxisPoint {
|
||||||
|
pub main: f32,
|
||||||
|
pub cross: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AxisPoint {
|
||||||
|
fn pack(self, axis: &Axis) -> Point {
|
||||||
|
match axis {
|
||||||
|
Axis::Horizontal => Point::new(self.main, self.cross),
|
||||||
|
Axis::Vertical => Point::new(self.cross, self.main),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct AxisSize<T = f32> {
|
||||||
|
pub main: T,
|
||||||
|
pub cross: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> AxisSize<T> {
|
||||||
|
fn unpack(axis: &Axis, size: Size<T>) -> Self {
|
||||||
|
match axis {
|
||||||
|
Axis::Horizontal => AxisSize {
|
||||||
|
main: size.width,
|
||||||
|
cross: size.height,
|
||||||
|
},
|
||||||
|
Axis::Vertical => AxisSize {
|
||||||
|
main: size.height,
|
||||||
|
cross: size.width,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pack(self, axis: &Axis) -> Size<T> {
|
||||||
|
match axis {
|
||||||
|
Axis::Horizontal => Size::new(self.main, self.cross),
|
||||||
|
Axis::Vertical => Size::new(self.cross, self.main),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct AxisRectangle {
|
||||||
|
pub origin: AxisPoint,
|
||||||
|
pub size: AxisSize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AxisRectangle {
|
||||||
|
pub fn new(origin: AxisPoint, size: AxisSize) -> Self {
|
||||||
|
Self { origin, size }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pack(self, axis: &Axis) -> Rectangle {
|
||||||
|
Rectangle::new(self.origin.pack(axis), self.size.pack(axis))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper to implement [`ToplevelLayout`] for layouts based on an `[Axis]`,
|
||||||
|
/// that care only about main vs cross, and not width/height.
|
||||||
|
pub trait AxisToplevelLayout {
|
||||||
|
fn axis(&self) -> &Axis;
|
||||||
|
fn size(&self) -> AxisSize<Length>;
|
||||||
|
fn layout(
|
||||||
|
&self,
|
||||||
|
max_limit: AxisSize,
|
||||||
|
toplevels: Vec<LayoutToplevel<'_, AxisSize>>,
|
||||||
|
) -> impl Iterator<Item = AxisRectangle>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AxisToplevelLayout> ToplevelLayout for T {
|
||||||
|
fn size(&self) -> Size<Length> {
|
||||||
|
self.size().pack(self.axis())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout(
|
||||||
|
&self,
|
||||||
|
max_limit: Size,
|
||||||
|
toplevels: &[LayoutToplevel<'_>],
|
||||||
|
) -> impl Iterator<Item = Rectangle> {
|
||||||
|
let max_limit = AxisSize::unpack(self.axis(), max_limit);
|
||||||
|
let toplevels = toplevels
|
||||||
|
.into_iter()
|
||||||
|
.map(|t| LayoutToplevel {
|
||||||
|
preferred_size: AxisSize::unpack(self.axis(), t.preferred_size),
|
||||||
|
_phantom_data: PhantomData,
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
self.layout(max_limit, toplevels)
|
||||||
|
.map(|rect| rect.pack(self.axis()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,15 +4,15 @@
|
||||||
use cosmic::iced::{Length, Rectangle, Size};
|
use cosmic::iced::{Length, Rectangle, Size};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
mod axis_toplevel_layout;
|
||||||
mod row_col_toplevel_layout;
|
mod row_col_toplevel_layout;
|
||||||
mod utils;
|
|
||||||
pub(crate) use row_col_toplevel_layout::RowColToplevelLayout;
|
pub(crate) use row_col_toplevel_layout::RowColToplevelLayout;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct LayoutToplevel<'a> {
|
pub(crate) struct LayoutToplevel<'a, S = Size> {
|
||||||
//toplevel: &'a crate::Toplevel,
|
//toplevel: &'a crate::Toplevel,
|
||||||
/// Preferred size of the child widget, if it fill the parent container
|
/// Preferred size of the child widget, if it fill the parent container
|
||||||
pub preferred_size: Size,
|
pub preferred_size: S,
|
||||||
pub _phantom_data: PhantomData<&'a crate::Toplevel>,
|
pub _phantom_data: PhantomData<&'a crate::Toplevel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
use cosmic::iced::{advanced::layout::flex::Axis, Length, Point, Rectangle, Size};
|
use cosmic::iced::{advanced::layout::flex::Axis, Length};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use super::{utils::AxisExt, LayoutToplevel, ToplevelLayout};
|
use super::{
|
||||||
|
axis_toplevel_layout::{AxisPoint, AxisRectangle, AxisSize, AxisToplevelLayout},
|
||||||
|
LayoutToplevel,
|
||||||
|
};
|
||||||
|
|
||||||
pub(crate) struct RowColToplevelLayout {
|
pub(crate) struct RowColToplevelLayout {
|
||||||
pub axis: Axis,
|
pub axis: Axis,
|
||||||
|
|
@ -9,57 +13,55 @@ pub(crate) struct RowColToplevelLayout {
|
||||||
|
|
||||||
impl RowColToplevelLayout {
|
impl RowColToplevelLayout {
|
||||||
// Get total requested main axis length if widget could have all the space
|
// Get total requested main axis length if widget could have all the space
|
||||||
fn requested_main_total(&self, toplevels: &[LayoutToplevel<'_>]) -> f32 {
|
fn requested_main_total(&self, toplevels: &[LayoutToplevel<'_, AxisSize>]) -> f32 {
|
||||||
let total_spacing = self.spacing as usize * (toplevels.len().saturating_sub(1)).max(0);
|
let total_spacing = self.spacing as usize * (toplevels.len().saturating_sub(1)).max(0);
|
||||||
toplevels
|
toplevels.iter().map(|t| t.preferred_size.main).sum::<f32>() + total_spacing as f32
|
||||||
.iter()
|
|
||||||
.map(|t| self.axis.main(t.preferred_size))
|
|
||||||
.sum::<f32>()
|
|
||||||
+ total_spacing as f32
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToplevelLayout for RowColToplevelLayout {
|
impl AxisToplevelLayout for RowColToplevelLayout {
|
||||||
fn size(&self) -> Size<Length> {
|
fn axis(&self) -> &Axis {
|
||||||
match self.axis {
|
&self.axis
|
||||||
Axis::Horizontal => Size {
|
}
|
||||||
width: Length::Fill,
|
|
||||||
height: Length::Shrink,
|
fn size(&self) -> AxisSize<Length> {
|
||||||
},
|
AxisSize {
|
||||||
Axis::Vertical => Size {
|
main: Length::Fill,
|
||||||
width: Length::Shrink,
|
cross: Length::Shrink,
|
||||||
height: Length::Fill,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
max_limit: Size,
|
max_limit: AxisSize,
|
||||||
toplevels: &[LayoutToplevel<'_>],
|
toplevels: Vec<LayoutToplevel<'_, AxisSize>>,
|
||||||
) -> impl Iterator<Item = Rectangle> {
|
) -> impl Iterator<Item = AxisRectangle> {
|
||||||
let requested_main_total = self.requested_main_total(toplevels);
|
let requested_main_total = self.requested_main_total(&toplevels);
|
||||||
let scale_factor = (self.axis.main(max_limit) / requested_main_total).min(1.0);
|
let scale_factor = (max_limit.main / requested_main_total).min(1.0);
|
||||||
let max_cross = self.axis.cross(max_limit);
|
|
||||||
|
|
||||||
// Add padding to center if total requested size doesn't fill available space
|
// Add padding to center if total requested size doesn't fill available space
|
||||||
let padding = (self.axis.main(max_limit) - requested_main_total).max(0.) / 2.;
|
let padding = (max_limit.main - requested_main_total).max(0.) / 2.;
|
||||||
|
|
||||||
let mut total_main = padding;
|
let mut total_main = padding;
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
toplevels.iter().map(move |child| {
|
toplevels.into_iter().map(move |child| {
|
||||||
let requested_main = self.axis.main(child.preferred_size);
|
|
||||||
if !first {
|
if !first {
|
||||||
total_main += self.spacing as f32;
|
total_main += self.spacing as f32;
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
let max_main = requested_main * scale_factor;
|
let max_main = child.preferred_size.main * scale_factor;
|
||||||
|
|
||||||
let (width, height) = self.axis.pack(max_main, max_cross);
|
let main = total_main;
|
||||||
let (x, y) = self.axis.pack(total_main, 0.0);
|
|
||||||
total_main += max_main;
|
total_main += max_main;
|
||||||
Rectangle::new(Point::new(x, y), Size::new(width, height))
|
|
||||||
|
AxisRectangle::new(
|
||||||
|
AxisPoint { main, cross: 0.0 },
|
||||||
|
AxisSize {
|
||||||
|
main: max_main,
|
||||||
|
cross: max_limit.cross,
|
||||||
|
},
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
use cosmic::iced::{advanced::layout::flex::Axis, Size};
|
|
||||||
|
|
||||||
// Duplicate of private methods
|
|
||||||
pub(super) trait AxisExt {
|
|
||||||
fn main(&self, size: Size) -> f32;
|
|
||||||
fn cross(&self, size: Size) -> f32;
|
|
||||||
fn pack(&self, main: f32, cross: f32) -> (f32, f32);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AxisExt for Axis {
|
|
||||||
fn main(&self, size: Size) -> f32 {
|
|
||||||
match self {
|
|
||||||
Axis::Horizontal => size.width,
|
|
||||||
Axis::Vertical => size.height,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cross(&self, size: Size) -> f32 {
|
|
||||||
match self {
|
|
||||||
Axis::Horizontal => size.height,
|
|
||||||
Axis::Vertical => size.width,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pack(&self, main: f32, cross: f32) -> (f32, f32) {
|
|
||||||
match self {
|
|
||||||
Axis::Horizontal => (main, cross),
|
|
||||||
Axis::Vertical => (cross, main),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue