Skip to content

Commit

Permalink
Merge pull request #447 from kas-gui/work1
Browse files Browse the repository at this point in the history
Pass AlignHints to set_rect, not size_rules
  • Loading branch information
dhardy authored Apr 24, 2024
2 parents a403cbc + b2fddfe commit 8873845
Show file tree
Hide file tree
Showing 45 changed files with 258 additions and 354 deletions.
16 changes: 7 additions & 9 deletions crates/kas-core/src/core/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use crate::event::ConfigCx;
use crate::geom::{Coord, Offset, Rect};
use crate::layout::{AxisInfo, SizeRules};
use crate::layout::{AlignHints, AxisInfo, SizeRules};
use crate::theme::{DrawCx, SizeCx};
use crate::util::IdentifyWidget;
use crate::{HasId, Id};
Expand Down Expand Up @@ -168,12 +168,10 @@ pub trait Layout {
/// outside of its assigned `rect` and to not function as normal.
///
/// The assigned `rect` may be larger than the widget's size requirements,
/// regardless of the [`Stretch`] policy used. If the widget should never
/// stretch, it must align itself.
/// Example: the `CheckBox` widget uses an [`AlignPair`] (set from
/// `size_rules`'s [`AxisInfo`]) and uses [`ConfigCx::align_feature`].
/// Another example: `Label` uses a `Text` object which handles alignment
/// internally.
/// regardless of the [`Stretch`] policy used: containers divide up space
/// based on children's [`SizeRules`] but do not attempt to align content
/// when excess space is available. Instead, content is responsible for
/// aligning itself using the provided `hints` and/or local information.
///
/// Required: [`Self::size_rules`] is called for both axes before this
/// method is called, and that this method has been called *after* the last
Expand All @@ -184,8 +182,8 @@ pub trait Layout {
/// field of `widget_core!()` to the input `rect`.
///
/// [`Stretch`]: crate::layout::Stretch
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) {
let _ = (cx, rect);
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
let _ = (cx, rect, hints);
unimplemented!() // make rustdoc show that this is a provided method
}

Expand Down
12 changes: 6 additions & 6 deletions crates/kas-core/src/core/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use super::Widget;
use crate::event::{ConfigCx, Event, EventCx, IsUsed};
use crate::geom::{Coord, Rect};
use crate::layout::{AxisInfo, SizeRules};
use crate::layout::{AlignHints, AxisInfo, SizeRules};
use crate::theme::{DrawCx, SizeCx};
use crate::{Id, Layout, NavAdvance};

Expand All @@ -25,7 +25,7 @@ trait NodeT {
fn for_child_node(&mut self, index: usize, f: Box<dyn FnOnce(Node<'_>) + '_>);

fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules;
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect);
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints);

fn nav_next(&self, reverse: bool, from: Option<usize>) -> Option<usize>;
fn find_id(&mut self, coord: Coord) -> Option<Id>;
Expand Down Expand Up @@ -73,8 +73,8 @@ impl<'a, T> NodeT for (&'a mut dyn Widget<Data = T>, &'a T) {
fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules {
self.0.size_rules(sizer, axis)
}
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) {
self.0.set_rect(cx, rect);
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
self.0.set_rect(cx, rect, hints);
}

fn nav_next(&self, reverse: bool, from: Option<usize>) -> Option<usize> {
Expand Down Expand Up @@ -293,8 +293,8 @@ impl<'a> Node<'a> {
}

/// Set size and position
pub(crate) fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) {
self.0.set_rect(cx, rect);
pub(crate) fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
self.0.set_rect(cx, rect, hints);
}

/// Navigation in spatial order
Expand Down
8 changes: 4 additions & 4 deletions crates/kas-core/src/decorations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,14 @@ impl_scope! {
}

impl Layout for Self {
fn size_rules(&mut self, sizer: SizeCx, mut axis: AxisInfo) -> SizeRules {
axis.set_default_align_hv(Align::Center, Align::Center);
fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules {
sizer.text_rules(&mut self.text, axis)
}

fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) {
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
self.core.rect = rect;
cx.text_set_size(&mut self.text, rect.size);
let align = hints.complete(Align::Center, Align::Center);
cx.text_set_size(&mut self.text, rect.size, align);
}

fn draw(&mut self, mut draw: DrawCx) {
Expand Down
8 changes: 7 additions & 1 deletion crates/kas-core/src/event/cx/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,13 @@ impl<'a> ConfigCx<'a> {
///
/// Call [`text_configure`][Self::text_configure] before this method.
#[inline]
pub fn text_set_size<T: FormattableText>(&self, text: &mut Text<T>, size: Size) {
pub fn text_set_size<T: FormattableText>(
&self,
text: &mut Text<T>,
size: Size,
align: AlignPair,
) {
text.set_align(align.into());
text.set_bounds(size.cast());
text.prepare().expect("not configured");
}
Expand Down
14 changes: 7 additions & 7 deletions crates/kas-core/src/hidden.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use crate::classes::HasStr;
use crate::event::{ConfigCx, Event, EventCx, IsUsed};
use crate::geom::{Coord, Offset, Rect};
use crate::layout::{Align, AxisInfo, SizeRules};
use crate::layout::{Align, AlignHints, AxisInfo, SizeRules};
use crate::theme::{DrawCx, SizeCx, Text, TextClass};
use crate::{Events, Id, Layout, NavAdvance, Node, Widget};
use kas_macros::{autoimpl, impl_scope};
Expand Down Expand Up @@ -45,14 +45,14 @@ impl_scope! {

impl Layout for Self {
#[inline]
fn size_rules(&mut self, sizer: SizeCx, mut axis: AxisInfo) -> SizeRules {
axis.set_default_align_hv(Align::Default, Align::Center);
fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules {
sizer.text_rules(&mut self.text, axis)
}

fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) {
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
self.core.rect = rect;
cx.text_set_size(&mut self.text, rect.size);
let align = hints.complete(Align::Default, Align::Center);
cx.text_set_size(&mut self.text, rect.size, align);
}

fn draw(&mut self, mut draw: DrawCx) {
Expand Down Expand Up @@ -135,8 +135,8 @@ impl_scope! {
}

#[inline]
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) {
self.inner.set_rect(cx, rect);
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
self.inner.set_rect(cx, rect, hints);
}

#[inline]
Expand Down
23 changes: 20 additions & 3 deletions crates/kas-core/src/layout/align.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,20 @@ impl AlignHints {
(self.horiz.unwrap_or(horiz), self.vert.unwrap_or(vert))
}

/// Complete via default alignments
/// Complete, using specified alignments as defaults
pub fn complete(&self, horiz: Align, vert: Align) -> AlignPair {
AlignPair::new(self.horiz.unwrap_or(horiz), self.vert.unwrap_or(vert))
}

/// Complete, using [`Align::Default`] as defaults
pub fn complete_default(&self) -> AlignPair {
self.complete(Align::Default, Align::Default)
}

/// Complete, using [`Align::Center`] as defaults
pub fn complete_center(&self) -> AlignPair {
self.complete(Align::Center, Align::Center)
}
}

/// Provides alignment information on both axes along with ideal size
Expand Down Expand Up @@ -180,10 +190,17 @@ impl AlignPair {
}
}

impl From<(Align, Align)> for AlignHints {
#[inline]
fn from((h, v): (Align, Align)) -> Self {
AlignHints::new(Some(h), Some(v))
}
}

impl From<(Align, Align)> for AlignPair {
#[inline]
fn from(p: (Align, Align)) -> Self {
AlignPair::new(p.0, p.1)
fn from((h, v): (Align, Align)) -> Self {
AlignPair::new(h, v)
}
}

Expand Down
66 changes: 1 addition & 65 deletions crates/kas-core/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,30 +67,21 @@ pub struct AxisInfo {
vertical: bool,
has_fixed: bool,
other_axis: i32,
align: Option<Align>,
}

impl AxisInfo {
/// Construct with direction and an optional value for the other axis
///
/// This method is *usually* not required by user code.
#[inline]
pub fn new(vertical: bool, fixed: Option<i32>, align: Option<Align>) -> Self {
pub fn new(vertical: bool, fixed: Option<i32>) -> Self {
AxisInfo {
vertical,
has_fixed: fixed.is_some(),
other_axis: fixed.unwrap_or(0),
align,
}
}

/// Construct a copy using the given alignment hints
#[inline]
pub fn with_align_hints(mut self, hints: AlignHints) -> Self {
self.align = hints.extract(self).or(self.align);
self
}

/// True if the current axis is vertical
#[inline]
pub fn is_vertical(self) -> bool {
Expand All @@ -103,61 +94,6 @@ impl AxisInfo {
!self.vertical
}

/// Get align parameter
#[inline]
pub fn align(self) -> Option<Align> {
self.align
}

/// Set align parameter
#[inline]
pub fn set_align(&mut self, align: Option<Align>) {
self.align = align;
}

/// Set default alignment
///
/// If the optional alignment parameter is `None`, replace with `align`.
#[inline]
pub fn set_default_align(&mut self, align: Align) {
if self.align.is_none() {
self.align = Some(align);
}
}

/// Set default alignment
///
/// If the optional alignment parameter is `None`, replace with either
/// `horiz` or `vert` depending on this axis' orientation.
#[inline]
pub fn set_default_align_hv(&mut self, horiz: Align, vert: Align) {
if self.align.is_none() {
if self.is_horizontal() {
self.align = Some(horiz);
} else {
self.align = Some(vert);
}
}
}

/// Get align parameter, defaulting to [`Align::Default`]
#[inline]
pub fn align_or_default(self) -> Align {
self.align.unwrap_or(Align::Default)
}

/// Get align parameter, defaulting to [`Align::Center`]
#[inline]
pub fn align_or_center(self) -> Align {
self.align.unwrap_or(Align::Center)
}

/// Get align parameter, defaulting to [`Align::Stretch`]
#[inline]
pub fn align_or_stretch(self) -> Align {
self.align.unwrap_or(Align::Stretch)
}

/// Size of other axis, if fixed
#[inline]
pub fn other(&self) -> Option<i32> {
Expand Down
7 changes: 2 additions & 5 deletions crates/kas-core/src/layout/size_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,6 @@ impl_scope! {
///
/// If is `None`, max size is limited to ideal size.
pub stretch: Stretch,
/// Alignment (set by `Self::size_rules`)
align: AlignPair,
}
}

Expand All @@ -256,14 +254,13 @@ impl PixmapScaling {
.size
.to_physical(scale_factor * self.ideal_factor)
.extract(axis);
self.align.set_component(axis, axis.align_or_center());
SizeRules::new(min, ideal, margins, self.stretch)
}

/// Constrains and aligns within `rect`
///
/// The resulting size is then aligned using the `align` hints, defaulting to centered.
pub fn align_rect(&mut self, rect: Rect, scale_factor: f32) -> Rect {
pub fn align_rect(&mut self, rect: Rect, align: AlignPair, scale_factor: f32) -> Rect {
let mut size = rect.size;

if self.stretch == Stretch::None {
Expand All @@ -283,7 +280,7 @@ impl PixmapScaling {
}
}

self.align.aligned_rect(size, rect)
align.aligned_rect(size, rect)
}
}

Expand Down
19 changes: 9 additions & 10 deletions crates/kas-core/src/layout/sizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@

//! Layout solver
use super::{Align, AxisInfo, Margins, SizeRules};
use super::{AxisInfo, Margins, SizeRules};
use crate::cast::Conv;
use crate::event::ConfigCx;
use crate::geom::{Rect, Size};
use crate::layout::AlignHints;
use crate::theme::SizeCx;
use crate::util::WidgetHierarchy;
use crate::{Layout, Node};
Expand Down Expand Up @@ -76,11 +77,9 @@ pub fn solve_size_rules<W: Layout + ?Sized>(
sizer: SizeCx,
x_size: Option<i32>,
y_size: Option<i32>,
h_align: Option<Align>,
v_align: Option<Align>,
) {
widget.size_rules(sizer.re(), AxisInfo::new(false, y_size, h_align));
widget.size_rules(sizer.re(), AxisInfo::new(true, x_size, v_align));
widget.size_rules(sizer.re(), AxisInfo::new(false, y_size));
widget.size_rules(sizer.re(), AxisInfo::new(true, x_size));
}

/// Size solver
Expand Down Expand Up @@ -137,8 +136,8 @@ impl SolveCache {
pub fn find_constraints(mut widget: Node<'_>, sizer: SizeCx) -> Self {
let start = std::time::Instant::now();

let w = widget.size_rules(sizer.re(), AxisInfo::new(false, None, None));
let h = widget.size_rules(sizer.re(), AxisInfo::new(true, Some(w.ideal_size()), None));
let w = widget.size_rules(sizer.re(), AxisInfo::new(false, None));
let h = widget.size_rules(sizer.re(), AxisInfo::new(true, Some(w.ideal_size())));

let min = Size(w.min_size(), h.min_size());
let ideal = Size(w.ideal_size(), h.ideal_size());
Expand Down Expand Up @@ -197,14 +196,14 @@ impl SolveCache {
// internal layout solving.
if self.refresh_rules || width != self.last_width {
if self.refresh_rules {
let w = widget.size_rules(cx.size_cx(), AxisInfo::new(false, None, None));
let w = widget.size_rules(cx.size_cx(), AxisInfo::new(false, None));
self.min.0 = w.min_size();
self.ideal.0 = w.ideal_size();
self.margins.horiz = w.margins();
width = rect.size.0 - self.margins.sum_horiz();
}

let h = widget.size_rules(cx.size_cx(), AxisInfo::new(true, Some(width), None));
let h = widget.size_rules(cx.size_cx(), AxisInfo::new(true, Some(width)));
self.min.1 = h.min_size();
self.ideal.1 = h.ideal_size();
self.margins.vert = h.margins();
Expand All @@ -216,7 +215,7 @@ impl SolveCache {
rect.size.0 = width;
rect.size.1 -= self.margins.sum_vert();
}
widget.set_rect(cx, rect);
widget.set_rect(cx, rect, AlignHints::NONE);

log::trace!(target: "kas_perf::layout", "apply_rect: {}μs", start.elapsed().as_micros());
self.refresh_rules = false;
Expand Down
Loading

0 comments on commit 8873845

Please sign in to comment.