From 7fda80a25e7e41e180d19593a31a6828f9186af5 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 15 Mar 2024 11:23:36 +0000 Subject: [PATCH 1/2] Pass AlignHints to set_rect, not size_rules Minor changes to alignment: - ProgressBar, ScrollBar and Slider always stretch on their primary axis - Alignment hints are no longer passed to scroll-bar controls and grips --- crates/kas-core/src/core/layout.rs | 16 ++- crates/kas-core/src/core/node.rs | 12 +-- crates/kas-core/src/decorations.rs | 8 +- crates/kas-core/src/event/cx/config.rs | 8 +- crates/kas-core/src/hidden.rs | 14 +-- crates/kas-core/src/layout/align.rs | 23 ++++- crates/kas-core/src/layout/mod.rs | 66 +----------- crates/kas-core/src/layout/size_types.rs | 7 +- crates/kas-core/src/layout/sizer.rs | 19 ++-- crates/kas-core/src/layout/visitor.rs | 101 +++++++------------ crates/kas-core/src/root.rs | 24 ++--- crates/kas-core/src/theme/dimensions.rs | 2 - crates/kas-core/src/theme/text.rs | 13 --- crates/kas-macros/src/make_layout.rs | 3 +- crates/kas-macros/src/widget.rs | 6 +- crates/kas-resvg/src/canvas.rs | 5 +- crates/kas-resvg/src/svg.rs | 5 +- crates/kas-view/src/list_view.rs | 10 +- crates/kas-view/src/matrix_view.rs | 10 +- crates/kas-widgets/src/adapt/adapt_events.rs | 6 +- crates/kas-widgets/src/adapt/align.rs | 19 ++-- crates/kas-widgets/src/check_box.rs | 11 +- crates/kas-widgets/src/edit.rs | 20 ++-- crates/kas-widgets/src/grid.rs | 4 +- crates/kas-widgets/src/grip.rs | 2 +- crates/kas-widgets/src/image.rs | 5 +- crates/kas-widgets/src/label.rs | 16 +-- crates/kas-widgets/src/list.rs | 4 +- crates/kas-widgets/src/menu/menubar.rs | 7 +- crates/kas-widgets/src/menu/submenu.rs | 15 +-- crates/kas-widgets/src/progress.rs | 17 ++-- crates/kas-widgets/src/radio_box.rs | 12 +-- crates/kas-widgets/src/scroll.rs | 4 +- crates/kas-widgets/src/scroll_bar.rs | 31 +++--- crates/kas-widgets/src/scroll_label.rs | 6 +- crates/kas-widgets/src/scroll_text.rs | 6 +- crates/kas-widgets/src/slider.rs | 19 ++-- crates/kas-widgets/src/spinner.rs | 4 +- crates/kas-widgets/src/splitter.rs | 14 ++- crates/kas-widgets/src/stack.rs | 10 +- crates/kas-widgets/src/tab_stack.rs | 4 +- crates/kas-widgets/src/text.rs | 8 +- examples/clock.rs | 2 +- examples/mandlebrot/mandlebrot.rs | 2 +- examples/proxy.rs | 5 +- 45 files changed, 254 insertions(+), 351 deletions(-) diff --git a/crates/kas-core/src/core/layout.rs b/crates/kas-core/src/core/layout.rs index e73b1de47..86edb77a1 100644 --- a/crates/kas-core/src/core/layout.rs +++ b/crates/kas-core/src/core/layout.rs @@ -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}; @@ -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 @@ -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 } diff --git a/crates/kas-core/src/core/node.rs b/crates/kas-core/src/core/node.rs index 14d3f00b0..d1245b1fc 100644 --- a/crates/kas-core/src/core/node.rs +++ b/crates/kas-core/src/core/node.rs @@ -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}; @@ -25,7 +25,7 @@ trait NodeT { fn for_child_node(&mut self, index: usize, f: Box) + '_>); 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) -> Option; fn find_id(&mut self, coord: Coord) -> Option; @@ -73,8 +73,8 @@ impl<'a, T> NodeT for (&'a mut dyn Widget, &'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) -> Option { @@ -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 diff --git a/crates/kas-core/src/decorations.rs b/crates/kas-core/src/decorations.rs index 91f38a51f..fdcd4cd3d 100644 --- a/crates/kas-core/src/decorations.rs +++ b/crates/kas-core/src/decorations.rs @@ -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) { diff --git a/crates/kas-core/src/event/cx/config.rs b/crates/kas-core/src/event/cx/config.rs index 6c1255e5c..4d80415c9 100644 --- a/crates/kas-core/src/event/cx/config.rs +++ b/crates/kas-core/src/event/cx/config.rs @@ -140,7 +140,13 @@ impl<'a> ConfigCx<'a> { /// /// Call [`text_configure`][Self::text_configure] before this method. #[inline] - pub fn text_set_size(&self, text: &mut Text, size: Size) { + pub fn text_set_size( + &self, + text: &mut Text, + size: Size, + align: AlignPair, + ) { + text.set_align(align.into()); text.set_bounds(size.cast()); text.prepare().expect("not configured"); } diff --git a/crates/kas-core/src/hidden.rs b/crates/kas-core/src/hidden.rs index e6ba8fa26..b67015a55 100644 --- a/crates/kas-core/src/hidden.rs +++ b/crates/kas-core/src/hidden.rs @@ -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}; @@ -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) { @@ -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] diff --git a/crates/kas-core/src/layout/align.rs b/crates/kas-core/src/layout/align.rs index 20014a20f..b978de7f5 100644 --- a/crates/kas-core/src/layout/align.rs +++ b/crates/kas-core/src/layout/align.rs @@ -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 @@ -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) } } diff --git a/crates/kas-core/src/layout/mod.rs b/crates/kas-core/src/layout/mod.rs index 7398c94c5..fbc8c077d 100644 --- a/crates/kas-core/src/layout/mod.rs +++ b/crates/kas-core/src/layout/mod.rs @@ -67,7 +67,6 @@ pub struct AxisInfo { vertical: bool, has_fixed: bool, other_axis: i32, - align: Option, } impl AxisInfo { @@ -75,22 +74,14 @@ impl AxisInfo { /// /// This method is *usually* not required by user code. #[inline] - pub fn new(vertical: bool, fixed: Option, align: Option) -> Self { + pub fn new(vertical: bool, fixed: Option) -> 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 { @@ -103,61 +94,6 @@ impl AxisInfo { !self.vertical } - /// Get align parameter - #[inline] - pub fn align(self) -> Option { - self.align - } - - /// Set align parameter - #[inline] - pub fn set_align(&mut self, align: Option) { - 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 { diff --git a/crates/kas-core/src/layout/size_types.rs b/crates/kas-core/src/layout/size_types.rs index 00257f53d..5797e060d 100644 --- a/crates/kas-core/src/layout/size_types.rs +++ b/crates/kas-core/src/layout/size_types.rs @@ -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, } } @@ -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 { @@ -283,7 +280,7 @@ impl PixmapScaling { } } - self.align.aligned_rect(size, rect) + align.aligned_rect(size, rect) } } diff --git a/crates/kas-core/src/layout/sizer.rs b/crates/kas-core/src/layout/sizer.rs index 9224d0790..f94f64404 100644 --- a/crates/kas-core/src/layout/sizer.rs +++ b/crates/kas-core/src/layout/sizer.rs @@ -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}; @@ -76,11 +77,9 @@ pub fn solve_size_rules( sizer: SizeCx, x_size: Option, y_size: Option, - h_align: Option, - v_align: Option, ) { - 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 @@ -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()); @@ -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(); @@ -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; diff --git a/crates/kas-core/src/layout/visitor.rs b/crates/kas-core/src/layout/visitor.rs index f2d1f1f96..2f5f2cbb8 100644 --- a/crates/kas-core/src/layout/visitor.rs +++ b/crates/kas-core/src/layout/visitor.rs @@ -8,7 +8,7 @@ // Methods have to take `&mut self` #![allow(clippy::wrong_self_convention)] -use super::{AlignHints, AlignPair, AxisInfo, SizeRules}; +use super::{AlignHints, AxisInfo, SizeRules}; use super::{GridCellInfo, GridDimensions, GridSetter, GridSolver, GridStorage}; use super::{RowSetter, RowSolver, RowStorage}; use super::{RulesSetter, RulesSolver}; @@ -36,7 +36,7 @@ pub trait Visitable { /// /// The caller is expected to set `self.core.rect = rect;`. /// In other respects, this functions identically to [`Layout::set_rect`]. - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect); + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints); /// Translate a coordinate to an [`Id`] /// @@ -220,11 +220,11 @@ impl Visitor { /// The caller is expected to set `self.core.rect = rect;`. /// In other respects, this functions identically to [`Layout::set_rect`]. #[inline] - pub fn set_rect(mut self, cx: &mut ConfigCx, rect: Rect) { - self.set_rect_(cx, rect); + pub fn set_rect(mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + self.set_rect_(cx, rect, hints); } - 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); } /// Translate a coordinate to an [`Id`] @@ -260,8 +260,8 @@ impl Visitable for Visitor { self.size_rules_(sizer, axis) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { - self.set_rect_(cx, rect); + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + self.set_rect_(cx, rect, hints); } fn find_id(&mut self, coord: Coord) -> Option { @@ -282,8 +282,8 @@ impl<'a> Visitable for Single<'a> { self.widget.size_rules(sizer, axis) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { - self.widget.set_rect(cx, rect); + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + self.widget.set_rect(cx, rect, hints); } fn find_id(&mut self, coord: Coord) -> Option { @@ -302,12 +302,12 @@ struct Align { impl Visitable for Align { fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules { - self.child - .size_rules(sizer, axis.with_align_hints(self.hints)) + self.child.size_rules(sizer, axis) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { - self.child.set_rect(cx, rect); + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + let hints = self.hints.combine(hints); + self.child.set_rect(cx, rect, hints); } fn find_id(&mut self, coord: Coord) -> Option { @@ -327,12 +327,18 @@ struct Pack<'a, C: Visitable> { impl<'a, C: Visitable> Visitable for Pack<'a, C> { fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules { - self.storage - .child_size_rules(self.hints, axis, |axis| self.child.size_rules(sizer, axis)) + let rules = self.child.size_rules(sizer, axis); + self.storage.size.set_component(axis, rules.ideal_size()); + rules } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { - self.child.set_rect(cx, self.storage.aligned_rect(rect)); + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + let rect = self + .hints + .combine(hints) + .complete_default() + .aligned_rect(self.storage.size, rect); + self.child.set_rect(cx, rect, hints); } fn find_id(&mut self, coord: Coord) -> Option { @@ -367,8 +373,8 @@ impl Visitable for Margins { child_rules } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { - self.child.set_rect(cx, rect); + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + self.child.set_rect(cx, rect, hints); } fn find_id(&mut self, coord: Coord) -> Option { @@ -395,13 +401,13 @@ impl<'a, C: Visitable> Visitable for Frame<'a, C> { .size_rules(sizer, axis, child_rules, self.style) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { self.storage.rect = rect; let child_rect = Rect { pos: rect.pos + self.storage.offset, size: rect.size - self.storage.size, }; - self.child.set_rect(cx, child_rect); + self.child.set_rect(cx, child_rect, hints); } fn find_id(&mut self, coord: Coord) -> Option { @@ -421,21 +427,20 @@ struct Button<'a, C: Visitable> { } impl<'a, C: Visitable> Visitable for Button<'a, C> { - fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules { - let child_rules = self - .child - .size_rules(sizer.re(), self.storage.child_axis_centered(axis)); + fn size_rules(&mut self, sizer: SizeCx, mut axis: AxisInfo) -> SizeRules { + axis.sub_other(self.storage.size.extract(axis.flipped())); + let child_rules = self.child.size_rules(sizer.re(), axis); self.storage .size_rules(sizer, axis, child_rules, FrameStyle::Button) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, _: AlignHints) { self.storage.rect = rect; let child_rect = Rect { pos: rect.pos + self.storage.offset, size: rect.size - self.storage.size, }; - self.child.set_rect(cx, child_rect); + self.child.set_rect(cx, child_rect, AlignHints::CENTER); } fn find_id(&mut self, _: Coord) -> Option { @@ -475,13 +480,13 @@ where solver.finish(self.data) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { let dim = (self.direction, self.children.len()); let mut setter = RowSetter::, _>::new(rect, dim, self.data); for i in 0..self.children.len() { if let Some(child) = self.children.get_item(i) { - child.set_rect(cx, setter.child_rect(self.data, i)); + child.set_rect(cx, setter.child_rect(self.data, i), hints); } } } @@ -526,10 +531,10 @@ where rules } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { for i in 0..self.children.len() { if let Some(child) = self.children.get_item(i) { - child.set_rect(cx, rect); + child.set_rect(cx, rect, hints); } } } @@ -581,11 +586,11 @@ where solver.finish(self.data) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { let mut setter = GridSetter::, Vec<_>, _>::new(rect, self.dim, self.data); for i in 0..self.children.len() { if let Some((info, child)) = self.children.get_info_item(i) { - child.set_rect(cx, setter.child_rect(self.data, info)); + child.set_rect(cx, setter.child_rect(self.data, info), hints); } } } @@ -614,29 +619,8 @@ where /// Layout storage for pack #[derive(Clone, Default, Debug)] pub struct PackStorage { - align: AlignPair, size: Size, } -impl PackStorage { - /// Calculate child's [`SizeRules`] - pub fn child_size_rules( - &mut self, - hints: AlignHints, - axis: AxisInfo, - size_child: impl FnOnce(AxisInfo) -> SizeRules, - ) -> SizeRules { - let axis = axis.with_align_hints(hints); - self.align.set_component(axis, axis.align_or_default()); - let rules = size_child(axis); - self.size.set_component(axis, rules.ideal_size()); - rules - } - - /// Align rect - pub fn aligned_rect(&self, rect: Rect) -> Rect { - self.align.aligned_rect(self.size, rect) - } -} /// Layout storage for frame #[derive(Clone, Default, Debug)] @@ -659,13 +643,6 @@ impl FrameStorage { axis } - /// Calculate child's "other axis" size, forcing center-alignment of content - pub fn child_axis_centered(&self, mut axis: AxisInfo) -> AxisInfo { - axis.sub_other(self.size.extract(axis.flipped())); - axis.set_align(Some(super::Align::Center)); - axis - } - /// Generate [`SizeRules`] pub fn size_rules( &mut self, diff --git a/crates/kas-core/src/root.rs b/crates/kas-core/src/root.rs index 2207437ba..dfd8502f5 100644 --- a/crates/kas-core/src/root.rs +++ b/crates/kas-core/src/root.rs @@ -10,7 +10,7 @@ use crate::decorations::{Border, Decorations, TitleBar}; use crate::dir::Directional; use crate::event::{ConfigCx, Event, EventCx, IsUsed, ResizeDirection, Scroll, Unused, Used}; use crate::geom::{Coord, Offset, Rect, Size}; -use crate::layout::{self, AxisInfo, SizeRules}; +use crate::layout::{self, AlignHints, AxisInfo, SizeRules}; use crate::theme::{DrawCx, FrameStyle, SizeCx}; use crate::{Action, Events, Icon, Id, Layout, LayoutExt, Widget}; use kas_macros::impl_scope; @@ -118,7 +118,7 @@ impl_scope! { } } - 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; // Calculate position and size for nw, ne, and inner portions: let s_nw: Size = self.dec_offset.cast(); @@ -128,22 +128,22 @@ impl_scope! { let mut p_in = p_nw + self.dec_offset; let p_se = p_in + s_in; - self.b_w.set_rect(cx, Rect::new(Coord(p_nw.0, p_in.1), Size(s_nw.0, s_in.1))); - self.b_e.set_rect(cx, Rect::new(Coord(p_se.0, p_in.1), Size(s_se.0, s_in.1))); - self.b_n.set_rect(cx, Rect::new(Coord(p_in.0, p_nw.1), Size(s_in.0, s_nw.1))); - self.b_s.set_rect(cx, Rect::new(Coord(p_in.0, p_se.1), Size(s_in.0, s_se.1))); - self.b_nw.set_rect(cx, Rect::new(p_nw, s_nw)); - self.b_ne.set_rect(cx, Rect::new(Coord(p_se.0, p_nw.1), Size(s_se.0, s_nw.1))); - self.b_se.set_rect(cx, Rect::new(p_se, s_se)); - self.b_sw.set_rect(cx, Rect::new(Coord(p_nw.0, p_se.1), Size(s_nw.0, s_se.1))); + self.b_w.set_rect(cx, Rect::new(Coord(p_nw.0, p_in.1), Size(s_nw.0, s_in.1)), hints); + self.b_e.set_rect(cx, Rect::new(Coord(p_se.0, p_in.1), Size(s_se.0, s_in.1)), hints); + self.b_n.set_rect(cx, Rect::new(Coord(p_in.0, p_nw.1), Size(s_in.0, s_nw.1)), hints); + self.b_s.set_rect(cx, Rect::new(Coord(p_in.0, p_se.1), Size(s_in.0, s_se.1)), hints); + self.b_nw.set_rect(cx, Rect::new(p_nw, s_nw), hints); + self.b_ne.set_rect(cx, Rect::new(Coord(p_se.0, p_nw.1), Size(s_se.0, s_nw.1)), hints); + self.b_se.set_rect(cx, Rect::new(p_se, s_se), hints); + self.b_sw.set_rect(cx, Rect::new(Coord(p_nw.0, p_se.1), Size(s_nw.0, s_se.1)), hints); if self.bar_h > 0 { let bar_size = Size(s_in.0, self.bar_h); - self.title_bar.set_rect(cx, Rect::new(p_in, bar_size)); + self.title_bar.set_rect(cx, Rect::new(p_in, bar_size), hints); p_in.1 += self.bar_h; s_in -= Size(0, self.bar_h); } - self.inner.set_rect(cx, Rect::new(p_in, s_in)); + self.inner.set_rect(cx, Rect::new(p_in, s_in), hints); } fn find_id(&mut self, _: Coord) -> Option { diff --git a/crates/kas-core/src/theme/dimensions.rs b/crates/kas-core/src/theme/dimensions.rs index e8fca731c..849448363 100644 --- a/crates/kas-core/src/theme/dimensions.rs +++ b/crates/kas-core/src/theme/dimensions.rs @@ -347,8 +347,6 @@ impl ThemeSize for Window { }; let margins = (margin, margin); - text.set_align_from_axis(axis); - let wrap = class.multi_line(); if axis.is_horizontal() { diff --git a/crates/kas-core/src/theme/text.rs b/crates/kas-core/src/theme/text.rs index 54e83062e..1e1818e6c 100644 --- a/crates/kas-core/src/theme/text.rs +++ b/crates/kas-core/src/theme/text.rs @@ -8,7 +8,6 @@ use super::TextClass; #[allow(unused)] use super::{DrawCx, SizeCx}; #[allow(unused)] use crate::event::ConfigCx; -use crate::layout::AxisInfo; use crate::text::fonts::{FaceId, FontId, InvalidFontId}; use crate::text::format::{EditableText, FormattableText}; use crate::text::*; @@ -722,9 +721,6 @@ pub trait SizableText { /// Configure text fn configure(&mut self) -> Result<(), InvalidFontId>; - /// Set alignment from an axis - fn set_align_from_axis(&mut self, axis: AxisInfo); - /// Measure required width, up to some `max_width` fn measure_width(&mut self, max_width: f32) -> Result; @@ -742,15 +738,6 @@ impl SizableText for Text { Text::configure(self) } - fn set_align_from_axis(&mut self, axis: AxisInfo) { - let align = axis.align_or_default(); - if axis.is_horizontal() { - self.align.0 = align; - } else { - self.align.1 = align; - } - } - fn measure_width(&mut self, max_width: f32) -> Result { Text::measure_width(self, max_width) } diff --git a/crates/kas-macros/src/make_layout.rs b/crates/kas-macros/src/make_layout.rs index 5d1d5d59f..f4482f86c 100644 --- a/crates/kas-macros/src/make_layout.rs +++ b/crates/kas-macros/src/make_layout.rs @@ -189,12 +189,13 @@ impl Tree { &mut self, cx: &mut ::kas::event::ConfigCx, rect: ::kas::geom::Rect, + hints: ::kas::layout::AlignHints, ) { #[cfg(debug_assertions)] #core_path.status.set_rect(&#core_path.id); #core_path.rect = rect; - ::kas::layout::LayoutVisitor::layout_visitor(self).set_rect(cx, rect); + ::kas::layout::LayoutVisitor::layout_visitor(self).set_rect(cx, rect, hints); } fn find_id(&mut self, coord: ::kas::geom::Coord) -> Option<::kas::Id> { diff --git a/crates/kas-macros/src/widget.rs b/crates/kas-macros/src/widget.rs index 8196453f2..ce3ebb811 100644 --- a/crates/kas-macros/src/widget.rs +++ b/crates/kas-macros/src/widget.rs @@ -560,8 +560,9 @@ pub fn widget(attr_span: Span, mut args: WidgetArgs, scope: &mut Scope) -> Resul &mut self, cx: &mut ::kas::event::ConfigCx, rect: ::kas::geom::Rect, + hints: ::kas::layout::AlignHints, ) { - self.#inner.set_rect(cx, rect); + self.#inner.set_rect(cx, rect, hints); } }; fn_nav_next = Some(quote! { @@ -759,7 +760,7 @@ pub fn widget(attr_span: Span, mut args: WidgetArgs, scope: &mut Scope) -> Resul }); set_rect = quote! { #core_path.rect = rect; - ::kas::layout::LayoutVisitor::layout_visitor(self).set_rect(cx, rect); + ::kas::layout::LayoutVisitor::layout_visitor(self).set_rect(cx, rect, hints); }; find_id = quote! { use ::kas::{Layout, LayoutExt, layout::LayoutVisitor}; @@ -792,6 +793,7 @@ pub fn widget(attr_span: Span, mut args: WidgetArgs, scope: &mut Scope) -> Resul &mut self, cx: &mut ::kas::event::ConfigCx, rect: ::kas::geom::Rect, + hints: ::kas::layout::AlignHints, ) { #[cfg(debug_assertions)] #core_path.status.set_rect(&#core_path.id); diff --git a/crates/kas-resvg/src/canvas.rs b/crates/kas-resvg/src/canvas.rs index a17d17adf..9552d1b27 100644 --- a/crates/kas-resvg/src/canvas.rs +++ b/crates/kas-resvg/src/canvas.rs @@ -163,9 +163,10 @@ impl_scope! { self.scaling.size_rules(sizer, axis) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + let align = hints.complete_default(); let scale_factor = cx.size_cx().scale_factor(); - self.core.rect = self.scaling.align_rect(rect, scale_factor); + self.core.rect = self.scaling.align_rect(rect, align, scale_factor); let size = self.core.rect.size.cast(); if let Some(fut) = self.inner.resize(size) { diff --git a/crates/kas-resvg/src/svg.rs b/crates/kas-resvg/src/svg.rs index 9dc0b302c..7995cadb4 100644 --- a/crates/kas-resvg/src/svg.rs +++ b/crates/kas-resvg/src/svg.rs @@ -242,9 +242,10 @@ impl_scope! { self.scaling.size_rules(sizer, axis) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + let align = hints.complete_default(); let scale_factor = cx.size_cx().scale_factor(); - self.core.rect = self.scaling.align_rect(rect, scale_factor); + self.core.rect = self.scaling.align_rect(rect, align, scale_factor); let size: (u32, u32) = self.core.rect.size.cast(); if let Some(fut) = self.inner.resize(size) { diff --git a/crates/kas-view/src/list_view.rs b/crates/kas-view/src/list_view.rs index 2c14acc92..6776ad010 100644 --- a/crates/kas-view/src/list_view.rs +++ b/crates/kas-view/src/list_view.rs @@ -345,8 +345,6 @@ impl_scope! { cx.size_cx(), Some(self.child_size.0), Some(self.child_size.1), - self.align_hints.horiz, - self.align_hints.vert, ); w.key = Some(key); } else { @@ -355,7 +353,7 @@ impl_scope! { } else if let Some(item) = data.borrow(&key) { cx.update(w.widget.as_node(item.borrow())); } - w.widget.set_rect(cx, solver.rect(i)); + w.widget.set_rect(cx, solver.rect(i), self.align_hints); } if count < solver.cur_len { @@ -462,7 +460,7 @@ impl_scope! { } size }); - axis = AxisInfo::new(axis.is_vertical(), other, axis.align()); + axis = AxisInfo::new(axis.is_vertical(), other); self.child_size_min = i32::MAX; let mut rules = SizeRules::EMPTY; @@ -492,12 +490,12 @@ impl_scope! { let (rules, offset, size) = frame.surround(rules); self.frame_offset.set_component(axis, offset); self.frame_size.set_component(axis, size); - self.align_hints.set_component(axis, axis.align()); rules } - 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; + self.align_hints = hints; // Widgets need configuring and updating: do so by updating self. self.cur_len = 0; // hack: prevent drawing in the mean-time diff --git a/crates/kas-view/src/matrix_view.rs b/crates/kas-view/src/matrix_view.rs index ece12ba97..71a862732 100644 --- a/crates/kas-view/src/matrix_view.rs +++ b/crates/kas-view/src/matrix_view.rs @@ -300,8 +300,6 @@ impl_scope! { cx.size_cx(), Some(self.child_size.0), Some(self.child_size.1), - self.align_hints.horiz, - self.align_hints.vert, ); } else { w.key = None; // disables drawing and clicking @@ -309,7 +307,7 @@ impl_scope! { } else if let Some(item) = data.borrow(&key) { cx.update(w.widget.as_node(item.borrow())); } - w.widget.set_rect(cx, solver.rect(ci, ri)); + w.widget.set_rect(cx, solver.rect(ci, ri), self.align_hints); } } @@ -403,7 +401,7 @@ impl_scope! { .min(self.child_size_ideal.extract(other_axis)) .max(self.child_size_min.extract(other_axis)) }); - axis = AxisInfo::new(axis.is_vertical(), other, axis.align()); + axis = AxisInfo::new(axis.is_vertical(), other); let mut child_size_min = i32::MAX; let mut rules = SizeRules::EMPTY; @@ -433,12 +431,12 @@ impl_scope! { let (rules, offset, size) = frame.surround(rules); self.frame_offset.set_component(axis, offset); self.frame_size.set_component(axis, size); - self.align_hints.set_component(axis, axis.align()); rules } - 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; + self.align_hints = hints; // Widgets need configuring and updating: do so by updating self. self.cur_len = (0, 0); // hack: prevent drawing in the mean-time diff --git a/crates/kas-widgets/src/adapt/adapt_events.rs b/crates/kas-widgets/src/adapt/adapt_events.rs index 917c0b471..09b537a1d 100644 --- a/crates/kas-widgets/src/adapt/adapt_events.rs +++ b/crates/kas-widgets/src/adapt/adapt_events.rs @@ -9,7 +9,7 @@ use super::{AdaptConfigCx, AdaptEventCx}; use kas::autoimpl; use kas::event::{ConfigCx, Event, EventCx, IsUsed}; use kas::geom::{Coord, Offset, Rect}; -use kas::layout::{AxisInfo, SizeRules}; +use kas::layout::{AlignHints, AxisInfo, SizeRules}; use kas::theme::{DrawCx, SizeCx}; #[allow(unused)] use kas::Events; use kas::{Id, Layout, LayoutExt, NavAdvance, Node, Widget}; @@ -242,8 +242,8 @@ impl Layout for AdaptEvents { } #[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] diff --git a/crates/kas-widgets/src/adapt/align.rs b/crates/kas-widgets/src/adapt/align.rs index 8e3db887a..2edf37398 100644 --- a/crates/kas-widgets/src/adapt/align.rs +++ b/crates/kas-widgets/src/adapt/align.rs @@ -6,7 +6,6 @@ //! Alignment use kas::dir::Directions; -use kas::layout::PackStorage; use kas::prelude::*; use kas::theme::MarginStyle; @@ -37,8 +36,8 @@ impl_scope! { } impl Layout for Self { - fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules { - self.inner.size_rules(sizer, axis.with_align_hints(self.hints)) + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + self.inner.set_rect(cx, rect, self.hints.combine(hints)); } } } @@ -61,24 +60,28 @@ impl_scope! { /// /// Use [`Action::RESIZE`] to apply changes. pub hints: AlignHints, - storage: PackStorage, + size: Size, } impl Self { /// Construct #[inline] pub fn new(inner: W, hints: AlignHints) -> Self { - Pack { inner, hints, storage: PackStorage::default() } + Pack { inner, hints, size: Size::ZERO } } } impl Layout for Self { fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules { - self.storage.child_size_rules(self.hints, axis, |axis| self.inner.size_rules(sizer, axis)) + let rules = self.inner.size_rules(sizer, axis); + self.size.set_component(axis, rules.ideal_size()); + rules } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { - self.inner.set_rect(cx, self.storage.aligned_rect(rect)); + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + let align = self.hints.combine(hints).complete_default(); + let rect = align.aligned_rect(self.size, rect); + self.inner.set_rect(cx, rect, hints); } } } diff --git a/crates/kas-widgets/src/check_box.rs b/crates/kas-widgets/src/check_box.rs index f0c5b335b..b7b60b6a2 100644 --- a/crates/kas-widgets/src/check_box.rs +++ b/crates/kas-widgets/src/check_box.rs @@ -22,7 +22,6 @@ impl_scope! { }] pub struct CheckBox { core: widget_core!(), - align: AlignPair, state: bool, editable: bool, last_change: Option, @@ -52,12 +51,11 @@ impl_scope! { impl Layout for Self { fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules { - self.align.set_component(axis, axis.align_or_center()); sizer.feature(Feature::CheckBox, axis) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { - let rect = cx.align_feature(Feature::CheckBox, rect, self.align); + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + let rect = cx.align_feature(Feature::CheckBox, rect, hints.complete_center()); self.core.rect = rect; } @@ -74,7 +72,6 @@ impl_scope! { pub fn new(state_fn: impl Fn(&ConfigCx, &A) -> bool + 'static) -> Self { CheckBox { core: Default::default(), - align: Default::default(), state: false, editable: true, last_change: None, @@ -188,9 +185,9 @@ impl_scope! { } impl Layout for Self { - 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; - self.layout_visitor().set_rect(cx, rect); + self.layout_visitor().set_rect(cx, rect, hints); let dir = self.direction(); shrink_to_text(&mut self.core.rect, dir, &self.label); } diff --git a/crates/kas-widgets/src/edit.rs b/crates/kas-widgets/src/edit.rs index eba7bf20b..3efac0e96 100644 --- a/crates/kas-widgets/src/edit.rs +++ b/crates/kas-widgets/src/edit.rs @@ -375,7 +375,7 @@ impl_scope! { rules } - fn set_rect(&mut self, cx: &mut ConfigCx, outer_rect: Rect) { + fn set_rect(&mut self, cx: &mut ConfigCx, outer_rect: Rect, hints: AlignHints) { self.core.rect = outer_rect; let mut rect = outer_rect; rect.pos += self.frame_offset; @@ -389,9 +389,9 @@ impl_scope! { bar_rect = Rect::new(Coord(x0, rect.pos.1), Size(bar_width, rect.size.1)); rect.size.0 = (rect.size.0 - bar_width - self.inner_margin).max(0); } - self.bar.set_rect(cx, bar_rect); + self.bar.set_rect(cx, bar_rect, AlignHints::NONE); - self.inner.set_rect(cx, rect); + self.inner.set_rect(cx, rect, hints); self.inner.set_outer_rect(outer_rect, FrameStyle::EditBox); self.update_scroll_bar(cx); } @@ -672,21 +672,13 @@ impl_scope! { impl Layout for Self { fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules { - let mut align = self.text.align(); let (min, ideal) = if axis.is_horizontal() { - align.0 = axis.align_or_default(); let dpem = sizer.dpem(); ((self.width.0 * dpem).cast_ceil(), (self.width.1 * dpem).cast_ceil()) } else { - align.1 = if self.multi_line() { - axis.align_or_default() - } else { - axis.align_or_center() - }; let height = sizer.line_height(self.class()); (self.lines.0 * height, self.lines.1 * height) }; - self.text.set_align(align.into()); let margins = sizer.text_margins().extract(axis); let stretch = if axis.is_horizontal() || self.multi_line() { Stretch::High @@ -696,10 +688,12 @@ impl_scope! { SizeRules::new(min, ideal, margins, stretch) } - 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; self.outer_rect = rect; - cx.text_set_size(&mut self.text, rect.size); + let v_align = if self.multi_line() { Align::Default } else { Align::Center }; + let align = hints.complete(Align::Default, v_align); + cx.text_set_size(&mut self.text, rect.size, align); self.text_size = Vec2::from(self.text.bounding_box().unwrap().1).cast_ceil(); self.view_offset = self.view_offset.min(self.max_scroll_offset()); } diff --git a/crates/kas-widgets/src/grid.rs b/crates/kas-widgets/src/grid.rs index fdff8334b..0fe98d701 100644 --- a/crates/kas-widgets/src/grid.rs +++ b/crates/kas-widgets/src/grid.rs @@ -90,12 +90,12 @@ impl_scope! { solver.finish(&mut self.layout) } - 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; let mut setter = GridSetter::, Vec<_>, _>::new(rect, self.dim, &mut self.layout); for n in 0..self.widgets.len() { if let Some((info, child)) = self.widgets.cell_info(n).zip(self.widgets.get_mut_layout(n)) { - child.set_rect(cx, setter.child_rect(&mut self.layout, info)); + child.set_rect(cx, setter.child_rect(&mut self.layout, info), hints); } } } diff --git a/crates/kas-widgets/src/grip.rs b/crates/kas-widgets/src/grip.rs index 6a746f838..0ee802e98 100644 --- a/crates/kas-widgets/src/grip.rs +++ b/crates/kas-widgets/src/grip.rs @@ -83,7 +83,7 @@ impl_scope! { SizeRules::EMPTY } - fn set_rect(&mut self, _: &mut ConfigCx, rect: Rect) { + fn set_rect(&mut self, _: &mut ConfigCx, rect: Rect, _: AlignHints) { self.track = rect; } diff --git a/crates/kas-widgets/src/image.rs b/crates/kas-widgets/src/image.rs index 3530cc277..829d33fd1 100644 --- a/crates/kas-widgets/src/image.rs +++ b/crates/kas-widgets/src/image.rs @@ -156,9 +156,10 @@ impl_scope! { self.scaling.size_rules(sizer, axis) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + let align = hints.complete_default(); let scale_factor = cx.size_cx().scale_factor(); - self.core.rect = self.scaling.align_rect(rect, scale_factor); + self.core.rect = self.scaling.align_rect(rect, align, scale_factor); } fn draw(&mut self, mut draw: DrawCx) { diff --git a/crates/kas-widgets/src/label.rs b/crates/kas-widgets/src/label.rs index ed9722b3c..2c4425cb1 100644 --- a/crates/kas-widgets/src/label.rs +++ b/crates/kas-widgets/src/label.rs @@ -120,14 +120,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); } #[cfg(feature = "min_spec")] @@ -293,14 +293,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) { diff --git a/crates/kas-widgets/src/list.rs b/crates/kas-widgets/src/list.rs index 8c68387db..90b8a7c0c 100644 --- a/crates/kas-widgets/src/list.rs +++ b/crates/kas-widgets/src/list.rs @@ -107,13 +107,13 @@ impl_scope! { solver.finish(&mut self.layout) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { let dim = (self.direction, self.widgets.len()); let mut setter = RowSetter::, _>::new(rect, dim, &mut self.layout); for n in 0..self.widgets.len() { if let Some(child) = self.widgets.get_mut_layout(n) { - child.set_rect(cx, setter.child_rect(&mut self.layout, n)); + child.set_rect(cx, setter.child_rect(&mut self.layout, n), hints); } } } diff --git a/crates/kas-widgets/src/menu/menubar.rs b/crates/kas-widgets/src/menu/menubar.rs index 993276d2f..9db0649cd 100644 --- a/crates/kas-widgets/src/menu/menubar.rs +++ b/crates/kas-widgets/src/menu/menubar.rs @@ -70,7 +70,7 @@ impl_scope! { self.widgets.get(index).map(|w| w.as_layout()) } - fn size_rules(&mut self, sizer: SizeCx, mut axis: AxisInfo) -> SizeRules { + fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules { // Unusual behaviour: children's SizeRules are padded with a frame, // but the frame does not adjust the children's rects. @@ -87,13 +87,14 @@ impl_scope! { solver.finish(&mut self.layout_store) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, _: AlignHints) { self.core.rect = rect; let dim = (self.direction, self.widgets.len()); let mut setter = RowSetter::, _>::new(rect, dim, &mut self.layout_store); + let hints = AlignHints::CENTER; for (n, child) in self.widgets.iter_mut().enumerate() { - child.set_rect(cx, setter.child_rect(&mut self.layout_store, n)); + child.set_rect(cx, setter.child_rect(&mut self.layout_store, n), hints); } } diff --git a/crates/kas-widgets/src/menu/submenu.rs b/crates/kas-widgets/src/menu/submenu.rs index bf986c32a..e378e4469 100644 --- a/crates/kas-widgets/src/menu/submenu.rs +++ b/crates/kas-widgets/src/menu/submenu.rs @@ -299,9 +299,10 @@ impl_scope! { solver.finish(store) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, _: AlignHints) { self.core.rect = rect; let store = &mut self.store; + let hints = AlignHints::NONE; let mut setter = layout::GridSetter::, Vec<_>, _>::new(rect, self.dim, store); // Assumption: frame inner margin is at least as large as content margins @@ -326,28 +327,28 @@ impl_scope! { let row = u32::conv(row); let child_rect = setter.child_rect(store, menu_view_row_info(row)); // Note: we are required to call child.set_rect even if sub_items are used - child.set_rect(cx, child_rect); + child.set_rect(cx, child_rect, hints); if let Some(items) = child.sub_items() { if let Some(w) = items.toggle { let info = layout::GridCellInfo::new(0, row); - w.set_rect(cx, subtract_frame(setter.child_rect(store, info))); + w.set_rect(cx, subtract_frame(setter.child_rect(store, info)), hints); } if let Some(w) = items.icon { let info = layout::GridCellInfo::new(1, row); - w.set_rect(cx, subtract_frame(setter.child_rect(store, info))); + w.set_rect(cx, subtract_frame(setter.child_rect(store, info)), hints); } if let Some(w) = items.label { let info = layout::GridCellInfo::new(2, row); - w.set_rect(cx, subtract_frame(setter.child_rect(store, info))); + w.set_rect(cx, subtract_frame(setter.child_rect(store, info)), hints); } if let Some(w) = items.label2 { let info = layout::GridCellInfo::new(3, row); - w.set_rect(cx, subtract_frame(setter.child_rect(store, info))); + w.set_rect(cx, subtract_frame(setter.child_rect(store, info)), hints); } if let Some(w) = items.submenu { let info = layout::GridCellInfo::new(4, row); - w.set_rect(cx, subtract_frame(setter.child_rect(store, info))); + w.set_rect(cx, subtract_frame(setter.child_rect(store, info)), hints); } } } diff --git a/crates/kas-widgets/src/progress.rs b/crates/kas-widgets/src/progress.rs index b9e39c27f..bf2b7942b 100644 --- a/crates/kas-widgets/src/progress.rs +++ b/crates/kas-widgets/src/progress.rs @@ -16,7 +16,6 @@ impl_scope! { #[widget] pub struct ProgressBar { core: widget_core!(), - align: AlignPair, direction: D, value: f32, value_fn: Box f32>, @@ -55,7 +54,6 @@ impl_scope! { pub fn new_dir(value_fn: impl Fn(&ConfigCx, &A) -> f32 + 'static, direction: D) -> Self { ProgressBar { core: Default::default(), - align: Default::default(), direction, value: 0.0, value_fn: Box::new(value_fn), @@ -71,18 +69,15 @@ impl_scope! { impl Layout for Self { fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules { - self.align.set_component( - axis, - match axis.is_vertical() == self.direction.is_vertical() { - false => axis.align_or_center(), - true => axis.align_or_stretch(), - }, - ); sizer.feature(Feature::ProgressBar(self.direction()), axis) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { - let rect = cx.align_feature(Feature::ProgressBar(self.direction()), rect, self.align); + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + let align = match self.direction.is_vertical() { + false => AlignPair::new(Align::Stretch, hints.vert.unwrap_or(Align::Center)), + true => AlignPair::new(hints.horiz.unwrap_or(Align::Center), Align::Stretch), + }; + let rect = cx.align_feature(Feature::ProgressBar(self.direction()), rect, align); self.core.rect = rect; } diff --git a/crates/kas-widgets/src/radio_box.rs b/crates/kas-widgets/src/radio_box.rs index b417ab79e..700629547 100644 --- a/crates/kas-widgets/src/radio_box.rs +++ b/crates/kas-widgets/src/radio_box.rs @@ -22,7 +22,6 @@ impl_scope! { }] pub struct RadioBox { core: widget_core!(), - align: AlignPair, state: bool, last_change: Option, state_fn: Box bool>, @@ -51,12 +50,12 @@ impl_scope! { impl Layout for Self { fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules { - self.align.set_component(axis, axis.align_or_center()); sizer.feature(Feature::RadioBox, axis) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { - let rect = cx.align_feature(Feature::RadioBox, rect, self.align); + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + let align = hints.complete_center(); + let rect = cx.align_feature(Feature::RadioBox, rect, align); self.core.rect = rect; } @@ -73,7 +72,6 @@ impl_scope! { pub fn new(state_fn: impl Fn(&ConfigCx, &A) -> bool + 'static) -> Self { RadioBox { core: Default::default(), - align: Default::default(), state: false, last_change: None, state_fn: Box::new(state_fn), @@ -148,9 +146,9 @@ impl_scope! { } impl Layout for Self { - 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; - self.layout_visitor().set_rect(cx, rect); + self.layout_visitor().set_rect(cx, rect, hints); let dir = self.direction(); crate::check_box::shrink_to_text(&mut self.core.rect, dir, &self.label); } diff --git a/crates/kas-widgets/src/scroll.rs b/crates/kas-widgets/src/scroll.rs index bf01a51f6..36089f352 100644 --- a/crates/kas-widgets/src/scroll.rs +++ b/crates/kas-widgets/src/scroll.rs @@ -108,11 +108,11 @@ impl_scope! { rules } - 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; let child_size = (rect.size - self.frame_size).max(self.min_child_size); let child_rect = Rect::new(rect.pos + self.offset, child_size); - self.inner.set_rect(cx, child_rect); + self.inner.set_rect(cx, child_rect, hints); let _ = self .scroll .set_sizes(rect.size, child_size + self.frame_size); diff --git a/crates/kas-widgets/src/scroll_bar.rs b/crates/kas-widgets/src/scroll_bar.rs index 3f4610483..0ad1dcda7 100644 --- a/crates/kas-widgets/src/scroll_bar.rs +++ b/crates/kas-widgets/src/scroll_bar.rs @@ -32,7 +32,6 @@ impl_scope! { #[widget(hover_highlight = true;)] pub struct ScrollBar { core: widget_core!(), - align: AlignPair, direction: D, // Terminology assumes vertical orientation: min_grip_len: i32, // units: px @@ -84,7 +83,6 @@ impl_scope! { pub fn new_dir(direction: D) -> Self { ScrollBar { core: Default::default(), - align: Default::default(), direction, min_grip_len: 0, grip_len: 0, @@ -276,21 +274,18 @@ impl_scope! { impl Layout for Self { fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules { - self.align.set_component( - axis, - match axis.is_vertical() == self.direction.is_vertical() { - false => axis.align_or_center(), - true => axis.align_or_stretch(), - }, - ); let _ = self.grip.size_rules(sizer.re(), axis); sizer.feature(Feature::ScrollBar(self.direction()), axis) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { - let rect = cx.align_feature(Feature::ScrollBar(self.direction()), rect, self.align); + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + let align = match self.direction.is_vertical() { + false => AlignPair::new(Align::Stretch, hints.vert.unwrap_or(Align::Center)), + true => AlignPair::new(hints.horiz.unwrap_or(Align::Center), Align::Stretch), + }; + let rect = cx.align_feature(Feature::ScrollBar(self.direction()), rect, align); self.core.rect = rect; - self.grip.set_rect(cx, rect); + self.grip.set_rect(cx, rect, AlignHints::NONE); self.min_grip_len = cx.size_cx().grip_len(); let _ = self.update_widgets(); } @@ -478,7 +473,7 @@ impl_scope! { rules } - 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; let pos = rect.pos; let mut child_size = rect.size; @@ -495,25 +490,25 @@ impl_scope! { } let child_rect = Rect::new(pos, child_size); - self.inner.set_rect(cx, child_rect); + self.inner.set_rect(cx, child_rect, hints); let max_scroll_offset = self.inner.max_scroll_offset(); if self.show_bars.0 { let pos = Coord(pos.0, rect.pos2().1 - bar_width); let size = Size::new(child_size.0, bar_width); - self.horiz_bar.set_rect(cx, Rect { pos, size }); + self.horiz_bar.set_rect(cx, Rect { pos, size }, AlignHints::NONE); let _ = self.horiz_bar.set_limits(max_scroll_offset.0, rect.size.0); } else { - self.horiz_bar.set_rect(cx, Rect::ZERO); + self.horiz_bar.set_rect(cx, Rect::ZERO, AlignHints::NONE); } if self.show_bars.1 { let pos = Coord(rect.pos2().0 - bar_width, pos.1); let size = Size::new(bar_width, self.core.rect.size.1); - self.vert_bar.set_rect(cx, Rect { pos, size }); + self.vert_bar.set_rect(cx, Rect { pos, size }, AlignHints::NONE); let _ = self.vert_bar.set_limits(max_scroll_offset.1, rect.size.1); } else { - self.vert_bar.set_rect(cx, Rect::ZERO); + self.vert_bar.set_rect(cx, Rect::ZERO, AlignHints::NONE); } } diff --git a/crates/kas-widgets/src/scroll_label.rs b/crates/kas-widgets/src/scroll_label.rs index 42d597106..8ab499299 100644 --- a/crates/kas-widgets/src/scroll_label.rs +++ b/crates/kas-widgets/src/scroll_label.rs @@ -45,9 +45,9 @@ impl_scope! { rules } - fn set_rect(&mut self, cx: &mut ConfigCx, mut rect: Rect) { + fn set_rect(&mut self, cx: &mut ConfigCx, mut rect: Rect, hints: AlignHints) { self.core.rect = rect; - cx.text_set_size(&mut self.text, rect.size); + cx.text_set_size(&mut self.text, rect.size, hints.complete_default()); self.text_size = Vec2::from(self.text.bounding_box().unwrap().1).cast_ceil(); let max_offset = self.max_scroll_offset(); @@ -56,7 +56,7 @@ impl_scope! { let w = cx.size_cx().scroll_bar_width().min(rect.size.0); rect.pos.0 += rect.size.0 - w; rect.size.0 = w; - self.bar.set_rect(cx, rect); + self.bar.set_rect(cx, rect, AlignHints::NONE); let _ = self.bar.set_limits(max_offset.1, rect.size.1); self.bar.set_value(cx, self.view_offset.1); } diff --git a/crates/kas-widgets/src/scroll_text.rs b/crates/kas-widgets/src/scroll_text.rs index 4ec14a546..b48b07a49 100644 --- a/crates/kas-widgets/src/scroll_text.rs +++ b/crates/kas-widgets/src/scroll_text.rs @@ -45,9 +45,9 @@ impl_scope! { rules } - fn set_rect(&mut self, cx: &mut ConfigCx, mut rect: Rect) { + fn set_rect(&mut self, cx: &mut ConfigCx, mut rect: Rect, hints: AlignHints) { self.core.rect = rect; - cx.text_set_size(&mut self.text, rect.size); + cx.text_set_size(&mut self.text, rect.size, hints.complete_default()); self.text_size = Vec2::from(self.text.bounding_box().unwrap().1).cast_ceil(); let max_offset = self.max_scroll_offset(); @@ -56,7 +56,7 @@ impl_scope! { let w = cx.size_cx().scroll_bar_width().min(rect.size.0); rect.pos.0 += rect.size.0 - w; rect.size.0 = w; - self.bar.set_rect(cx, rect); + self.bar.set_rect(cx, rect, AlignHints::NONE); let _ = self.bar.set_limits(max_offset.1, rect.size.1); self.bar.set_value(cx, self.view_offset.1); } diff --git a/crates/kas-widgets/src/slider.rs b/crates/kas-widgets/src/slider.rs index c4dd60a80..e94a98ff2 100644 --- a/crates/kas-widgets/src/slider.rs +++ b/crates/kas-widgets/src/slider.rs @@ -113,7 +113,6 @@ impl_scope! { }] pub struct Slider { core: widget_core!(), - align: AlignPair, direction: D, // Terminology assumes vertical orientation: range: (T, T), @@ -195,7 +194,6 @@ impl_scope! { let value = *range.start(); Slider { core: Default::default(), - align: Default::default(), direction, range: range.into_inner(), step: T::default_step(), @@ -296,21 +294,18 @@ impl_scope! { impl Layout for Self { fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules { - self.align.set_component( - axis, - match axis.is_vertical() == self.direction.is_vertical() { - false => axis.align_or_center(), - true => axis.align_or_stretch(), - }, - ); let _ = self.grip.size_rules(sizer.re(), axis); sizer.feature(Feature::Slider(self.direction()), axis) } - fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect) { - let rect = cx.align_feature(Feature::Slider(self.direction()), rect, self.align); + fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) { + let align = match self.direction.is_vertical() { + false => AlignPair::new(Align::Stretch, hints.vert.unwrap_or(Align::Center)), + true => AlignPair::new(hints.horiz.unwrap_or(Align::Center), Align::Stretch), + }; + let rect = cx.align_feature(Feature::Slider(self.direction()), rect, align); self.core.rect = rect; - self.grip.set_rect(cx, rect); + self.grip.set_rect(cx, rect, AlignHints::NONE); let mut size = rect.size; size.set_component(self.direction, cx.size_cx().grip_len()); let _ = self.grip.set_size_and_offset(size, self.offset()); diff --git a/crates/kas-widgets/src/spinner.rs b/crates/kas-widgets/src/spinner.rs index d44ffbf93..2e886caa7 100644 --- a/crates/kas-widgets/src/spinner.rs +++ b/crates/kas-widgets/src/spinner.rs @@ -279,9 +279,9 @@ impl_scope! { } impl Layout for Self { - 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; - self.layout_visitor().set_rect(cx, rect); + self.layout_visitor().set_rect(cx, rect, hints); self.edit.set_outer_rect(rect, FrameStyle::EditBox); } diff --git a/crates/kas-widgets/src/splitter.rs b/crates/kas-widgets/src/splitter.rs index 75551ad60..e8683e5c4 100644 --- a/crates/kas-widgets/src/splitter.rs +++ b/crates/kas-widgets/src/splitter.rs @@ -23,6 +23,7 @@ impl_scope! { #[widget] pub struct Splitter { core: widget_core!(), + align_hints: AlignHints, widgets: C, grips: Vec, data: layout::DynRowStorage, @@ -89,6 +90,7 @@ impl_scope! { grips.resize_with(widgets.len().saturating_sub(1), GripPart::new); Splitter { core: Default::default(), + align_hints: AlignHints::NONE, widgets, grips, data: Default::default(), @@ -177,8 +179,9 @@ impl_scope! { solver.finish(&mut self.data) } - 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; + self.align_hints = hints; self.size_solved = true; if self.widgets.is_empty() { return; @@ -192,7 +195,7 @@ impl_scope! { loop { assert!(n < self.widgets.len()); if let Some(w) = self.widgets.get_mut_layout(n) { - w.set_rect(cx, setter.child_rect(&mut self.data, n << 1)); + w.set_rect(cx, setter.child_rect(&mut self.data, n << 1), hints); } if n >= self.grips.len() { @@ -202,7 +205,7 @@ impl_scope! { // TODO(opt): calculate all maximal sizes simultaneously let index = (n << 1) + 1; let track = setter.maximal_rect_of(&mut self.data, index); - self.grips[n].set_rect(cx, track); + self.grips[n].set_rect(cx, track, AlignHints::NONE); let grip = setter.child_rect(&mut self.data, index); let _ = self.grips[n].set_size_and_offset(grip.size, grip.pos - track.pos); @@ -321,7 +324,8 @@ impl Splitter { loop { assert!(n < self.widgets.len()); if let Some(w) = self.widgets.get_mut_layout(n) { - w.set_rect(cx, setter.child_rect(&mut self.data, n << 1)); + let rect = setter.child_rect(&mut self.data, n << 1); + w.set_rect(cx, rect, self.align_hints); } if n >= self.grips.len() { @@ -330,7 +334,7 @@ impl Splitter { let index = (n << 1) + 1; let track = self.grips[n].track(); - self.grips[n].set_rect(cx, track); + self.grips[n].set_rect(cx, track, AlignHints::NONE); let grip = setter.child_rect(&mut self.data, index); let _ = self.grips[n].set_size_and_offset(grip.size, grip.pos - track.pos); diff --git a/crates/kas-widgets/src/stack.rs b/crates/kas-widgets/src/stack.rs index 0098baea6..1aa47a0c5 100644 --- a/crates/kas-widgets/src/stack.rs +++ b/crates/kas-widgets/src/stack.rs @@ -47,6 +47,7 @@ impl_scope! { #[widget] pub struct Stack { core: widget_core!(), + align_hints: AlignHints, widgets: Vec<(W, State)>, active: usize, size_limit: usize, @@ -109,11 +110,12 @@ impl_scope! { } } - 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; + self.align_hints = hints; if let Some(entry) = self.widgets.get_mut(self.active) { debug_assert_eq!(entry.1, State::Sized); - entry.0.set_rect(cx, rect); + entry.0.set_rect(cx, rect, hints); } } @@ -295,7 +297,7 @@ impl Stack { cx.resize(self); } else { debug_assert_eq!(entry.1, State::Sized); - entry.0.set_rect(cx, self.core.rect); + entry.0.set_rect(cx, self.core.rect, self.align_hints); cx.region_moved(); } } else { @@ -347,7 +349,7 @@ impl Stack { if let Some(entry) = self.widgets.get_mut(index) { cx.configure(entry.0.as_node(data), id); let Size(w, h) = self.core.rect.size; - solve_size_rules(&mut entry.0, cx.size_cx(), Some(w), Some(h), None, None); + solve_size_rules(&mut entry.0, cx.size_cx(), Some(w), Some(h)); entry.1 = State::Sized; } } diff --git a/crates/kas-widgets/src/tab_stack.rs b/crates/kas-widgets/src/tab_stack.rs index 85b44be55..65ccfc25f 100644 --- a/crates/kas-widgets/src/tab_stack.rs +++ b/crates/kas-widgets/src/tab_stack.rs @@ -52,10 +52,10 @@ impl_scope! { Visitor::frame(&mut self.frame, label, FrameStyle::Tab).size_rules(sizer, 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; let label = Visitor::single(&mut self.label); - Visitor::frame(&mut self.frame, label, FrameStyle::Tab).set_rect(cx, rect) + Visitor::frame(&mut self.frame, label, FrameStyle::Tab).set_rect(cx, rect, hints) } fn find_id(&mut self, coord: Coord) -> Option { diff --git a/crates/kas-widgets/src/text.rs b/crates/kas-widgets/src/text.rs index 5ddcef33f..b3bb295ed 100644 --- a/crates/kas-widgets/src/text.rs +++ b/crates/kas-widgets/src/text.rs @@ -105,14 +105,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); } #[cfg(feature = "min_spec")] diff --git a/examples/clock.rs b/examples/clock.rs index 51b6f88dc..52bec47d2 100644 --- a/examples/clock.rs +++ b/examples/clock.rs @@ -47,7 +47,7 @@ impl_scope! { } #[inline] - fn set_rect(&mut self, _: &mut ConfigCx, rect: Rect) { + fn set_rect(&mut self, _: &mut ConfigCx, rect: Rect, _: AlignHints) { // Force to square let size = rect.size.0.min(rect.size.1); let size = Size::splat(size); diff --git a/examples/mandlebrot/mandlebrot.rs b/examples/mandlebrot/mandlebrot.rs index 76f3bc922..89c0c2def 100644 --- a/examples/mandlebrot/mandlebrot.rs +++ b/examples/mandlebrot/mandlebrot.rs @@ -336,7 +336,7 @@ impl_scope! { } #[inline] - fn set_rect(&mut self, _: &mut ConfigCx, rect: Rect) { + fn set_rect(&mut self, _: &mut ConfigCx, rect: Rect, _: AlignHints) { self.core.rect = rect; let size = DVec2::conv(rect.size); let rel_width = DVec2(size.0 / size.1, 1.0); diff --git a/examples/proxy.rs b/examples/proxy.rs index d8f29d563..53c45bb55 100644 --- a/examples/proxy.rs +++ b/examples/proxy.rs @@ -69,9 +69,10 @@ impl_scope! { SizeRules::fixed_scaled(100.0, 10.0, sizer.scale_factor()) } - 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.loading_text, rect.size); + let align = hints.complete(Align::Default, Align::Center); + cx.text_set_size(&mut self.loading_text, rect.size, align); } fn draw(&mut self, mut draw: DrawCx) { From b2fddfedcda50fbbe5a45919c759fe8daf8bddde Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 15 Mar 2024 12:00:26 +0000 Subject: [PATCH 2/2] MenuBar: append greedy spacer --- crates/kas-widgets/src/menu/menubar.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/kas-widgets/src/menu/menubar.rs b/crates/kas-widgets/src/menu/menubar.rs index 9db0649cd..11a98a22a 100644 --- a/crates/kas-widgets/src/menu/menubar.rs +++ b/crates/kas-widgets/src/menu/menubar.rs @@ -74,8 +74,8 @@ impl_scope! { // Unusual behaviour: children's SizeRules are padded with a frame, // but the frame does not adjust the children's rects. - axis.set_default_align(Align::Center); - let dim = (self.direction, self.widgets.len()); + let len = self.widgets.len(); + let dim = (self.direction, len + 1); let mut solver = RowSolver::new(axis, dim, &mut self.layout_store); let frame_rules = sizer.frame(FrameStyle::MenuEntry, axis); for (n, child) in self.widgets.iter_mut().enumerate() { @@ -84,12 +84,13 @@ impl_scope! { frame_rules.surround(rules).0 }); } + solver.for_child(&mut self.layout_store, len, |_| SizeRules::EMPTY.with_stretch(Stretch::Maximize)); solver.finish(&mut self.layout_store) } fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, _: AlignHints) { self.core.rect = rect; - let dim = (self.direction, self.widgets.len()); + let dim = (self.direction, self.widgets.len() + 1); let mut setter = RowSetter::, _>::new(rect, dim, &mut self.layout_store); let hints = AlignHints::CENTER;