use super::{AxisInfo, Margins, SizeRules};
use crate::cast::Conv;
use crate::geom::{Rect, Size};
use crate::layout::AlignHints;
use crate::theme::SizeCx;
use crate::util::WidgetHierarchy;
use crate::{Node, Tile};
use log::trace;
pub trait RulesSolver {
type Storage: Clone;
type ChildInfo;
fn for_child<CR: FnOnce(AxisInfo) -> SizeRules>(
&mut self,
storage: &mut Self::Storage,
child_info: Self::ChildInfo,
child_rules: CR,
);
fn finish(self, storage: &mut Self::Storage) -> SizeRules;
}
pub trait RulesSetter {
type Storage: Clone;
type ChildInfo;
fn child_rect(&mut self, storage: &mut Self::Storage, child_info: Self::ChildInfo) -> Rect;
}
pub fn solve_size_rules<W: Tile + ?Sized>(
widget: &mut W,
cx: &mut SizeCx,
x_size: Option<i32>,
y_size: Option<i32>,
) {
trace!(
"solve_size_rules({}, _, {:?}, {:?})",
widget.identify(),
x_size,
y_size
);
widget.size_rules(cx, AxisInfo::new(false, y_size));
widget.size_rules(cx, AxisInfo::new(true, x_size));
}
#[derive(Default)]
pub struct SolveCache {
min: Size,
ideal: Size,
margins: Margins,
last_width: i32,
}
impl SolveCache {
pub fn min(&self, inner_margin: bool) -> Size {
if inner_margin {
self.margins.pad(self.min)
} else {
self.min
}
}
pub fn ideal(&self, inner_margin: bool) -> Size {
if inner_margin {
self.margins.pad(self.ideal)
} else {
self.ideal
}
}
pub fn margins(&self) -> Margins {
self.margins
}
pub fn find_constraints(&mut self, mut widget: Node<'_>, cx: &mut SizeCx) {
let start = std::time::Instant::now();
let w = widget.size_rules(cx, AxisInfo::new(false, None));
let h = widget.size_rules(cx, AxisInfo::new(true, Some(w.ideal_size())));
self.min = Size(w.min_size(), h.min_size());
self.ideal = Size(w.ideal_size(), h.ideal_size());
self.margins = Margins::hv(w.margins(), h.margins());
log::trace!(
target: "kas_perf::layout", "find_constraints: {}μs",
start.elapsed().as_micros(),
);
log::debug!(
"find_constraints: min={:?}, ideal={:?}, margins={:?}",
&self.min,
&self.ideal,
&self.margins
);
self.last_width = self.ideal.0;
}
pub fn apply_rect(
&mut self,
mut widget: Node<'_>,
cx: &mut SizeCx,
mut rect: Rect,
inner_margin: bool,
) {
let start = std::time::Instant::now();
let mut width = rect.size.0;
if inner_margin {
width -= self.margins.sum_horiz();
}
if width != self.last_width {
let h = widget.size_rules(cx, AxisInfo::new(true, Some(width)));
self.min.1 = h.min_size();
self.ideal.1 = h.ideal_size();
self.margins.vert = h.margins();
self.last_width = width;
}
if inner_margin {
rect.pos += Size::conv((self.margins.horiz.0, self.margins.vert.0));
rect.size.0 = width;
rect.size.1 -= self.margins.sum_vert();
}
widget.set_rect(cx, rect, AlignHints::NONE);
log::trace!(target: "kas_perf::layout", "apply_rect: {}μs", start.elapsed().as_micros());
}
pub fn print_widget_heirarchy(&mut self, widget: &dyn Tile) {
let rect = widget.rect();
let hier = WidgetHierarchy::new(widget, None);
log::trace!(
target: "kas_core::layout::hierarchy",
"apply_rect: rect={rect:?}:{hier}",
);
}
}