Skip to content

Commit d5b92aa

Browse files
committed
Add types and methods for intrinsic sizing protocol
1 parent 2db986f commit d5b92aa

File tree

3 files changed

+76
-2
lines changed

3 files changed

+76
-2
lines changed

crates/yakui-core/src/layout/mod.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ use crate::event::EventInterest;
1010
use crate::geometry::{Constraints, Rect};
1111
use crate::id::WidgetId;
1212
use crate::input::{InputState, MouseInterest};
13-
use crate::widget::LayoutContext;
13+
use crate::types::Axis;
14+
use crate::widget::{IntrinsicSizeContext, LayoutContext};
1415

1516
/// Contains information on how each widget in the DOM is laid out and what
1617
/// events they're interested in.
@@ -199,6 +200,18 @@ impl LayoutDom {
199200
size
200201
}
201202

203+
/// Calculates the intrinsic size of the given widget along the given axis.
204+
pub fn intrinsic_size(&self, dom: &Dom, id: WidgetId, axis: Axis) -> f32 {
205+
dom.enter(id);
206+
let dom_node = dom.get(id).unwrap();
207+
208+
let context = IntrinsicSizeContext { dom, layout: self };
209+
let size = dom_node.widget.intrinsic_size(context, axis);
210+
211+
dom.exit(id);
212+
size
213+
}
214+
202215
/// Enables clipping for the currently active widget.
203216
pub fn enable_clipping(&mut self, dom: &Dom) {
204217
self.clip_stack.push(dom.current());

crates/yakui-core/src/types.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,21 @@ impl Pivot {
256256
pub const BOTTOM_CENTER: Self = Self::new(0.5, 1.0);
257257
pub const BOTTOM_RIGHT: Self = Self::new(1.0, 1.0);
258258
}
259+
260+
/// Defines an axis usable by the UI.
261+
#[allow(missing_docs)]
262+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
263+
pub enum Axis {
264+
X,
265+
Y,
266+
}
267+
268+
impl Axis {
269+
/// Return the component of a [`Vec2`] that matches this axis.
270+
pub fn select(self, v: Vec2) -> f32 {
271+
match self {
272+
Axis::X => v.x,
273+
Axis::Y => v.y,
274+
}
275+
}
276+
}

crates/yakui-core/src/widget.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ use crate::dom::Dom;
99
use crate::event::EventResponse;
1010
use crate::event::{EventInterest, WidgetEvent};
1111
use crate::geometry::{Constraints, FlexFit};
12+
use crate::id::WidgetId;
1213
use crate::input::{InputState, NavDirection};
1314
use crate::layout::LayoutDom;
1415
use crate::paint::PaintDom;
15-
use crate::{Flow, WidgetId};
16+
use crate::types::{Axis, Flow};
1617

1718
/// Trait that's automatically implemented for all widget props.
1819
///
@@ -38,6 +39,26 @@ impl<'dom> LayoutContext<'dom> {
3839
self.layout
3940
.calculate(self.dom, self.input, widget, constraints)
4041
}
42+
43+
/// Calculates the intrinsic size for the given widget on the given axis.
44+
pub fn intrinsic_size(&self, widget: WidgetId, axis: Axis) -> f32 {
45+
self.layout.intrinsic_size(self.dom, widget, axis)
46+
}
47+
}
48+
49+
/// Information available to a widget during the layout phase.
50+
#[non_exhaustive]
51+
#[allow(missing_docs)]
52+
pub struct IntrinsicSizeContext<'dom> {
53+
pub dom: &'dom Dom,
54+
pub layout: &'dom LayoutDom,
55+
}
56+
57+
impl<'dom> IntrinsicSizeContext<'dom> {
58+
/// Calculates the intrinsic size for the given widget on the given axis.
59+
pub fn intrinsic_size(&self, widget: WidgetId, axis: Axis) -> f32 {
60+
self.layout.intrinsic_size(self.dom, widget, axis)
61+
}
4162
}
4263

4364
/// Information available to a widget during the paint phase.
@@ -134,6 +155,21 @@ pub trait Widget: 'static + fmt::Debug {
134155
constraints.constrain_min(size)
135156
}
136157

158+
/// Tells the intrinsic size on one axis of the object, which is its size
159+
/// along that axis if the widget were given unbounded constraints on the
160+
/// other axis.
161+
fn intrinsic_size(&self, ctx: IntrinsicSizeContext<'_>, axis: Axis) -> f32 {
162+
let node = ctx.dom.get_current();
163+
let mut size: f32 = 0.0;
164+
165+
for &child in &node.children {
166+
let child_size = ctx.intrinsic_size(child, axis);
167+
size = size.max(child_size);
168+
}
169+
170+
size
171+
}
172+
137173
/// Paint the widget based on its current state.
138174
///
139175
/// The default implementation will paint all of the widget's children.
@@ -180,6 +216,9 @@ pub trait ErasedWidget: Any + fmt::Debug {
180216
/// See [`Widget::layout`].
181217
fn layout(&self, ctx: LayoutContext<'_>, constraints: Constraints) -> Vec2;
182218

219+
/// See [`Widget::intrinsic_size`].
220+
fn intrinsic_size(&self, ctx: IntrinsicSizeContext<'_>, axis: Axis) -> f32;
221+
183222
/// See [`Widget::flex`].
184223
fn flex(&self) -> (u32, FlexFit);
185224

@@ -207,6 +246,10 @@ where
207246
<T as Widget>::layout(self, ctx, constraints)
208247
}
209248

249+
fn intrinsic_size(&self, ctx: IntrinsicSizeContext<'_>, axis: Axis) -> f32 {
250+
<T as Widget>::intrinsic_size(self, ctx, axis)
251+
}
252+
210253
fn flex(&self) -> (u32, FlexFit) {
211254
<T as Widget>::flex(self)
212255
}

0 commit comments

Comments
 (0)