Skip to content

Commit

Permalink
Add types and methods for intrinsic sizing protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
LPGhatguy committed Oct 21, 2024
1 parent 2db986f commit d658969
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 2 deletions.
19 changes: 18 additions & 1 deletion crates/yakui-core/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use crate::event::EventInterest;
use crate::geometry::{Constraints, Rect};
use crate::id::WidgetId;
use crate::input::{InputState, MouseInterest};
use crate::widget::LayoutContext;
use crate::types::Axis;
use crate::widget::{IntrinsicSizeContext, LayoutContext};

/// Contains information on how each widget in the DOM is laid out and what
/// events they're interested in.
Expand Down Expand Up @@ -199,6 +200,22 @@ impl LayoutDom {
size
}

/// Calculates the intrinsic size of the given widget along the given axis.
pub fn intrinsic_size(&self, dom: &Dom, id: WidgetId, axis: Axis) -> f32 {
dom.enter(id);
let dom_node = dom.get(id).unwrap();

let context = IntrinsicSizeContext { dom, layout: self };

let size = match axis {
Axis::X => dom_node.widget.intrinsic_width(context),
Axis::Y => dom_node.widget.intrinsic_height(context),
};

dom.exit(id);
size
}

/// Enables clipping for the currently active widget.
pub fn enable_clipping(&mut self, dom: &Dom) {
self.clip_stack.push(dom.current());
Expand Down
8 changes: 8 additions & 0 deletions crates/yakui-core/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,11 @@ impl Pivot {
pub const BOTTOM_CENTER: Self = Self::new(0.5, 1.0);
pub const BOTTOM_RIGHT: Self = Self::new(1.0, 1.0);
}

/// Defines an axis usable by the UI.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Axis {
X,
Y,
}
75 changes: 74 additions & 1 deletion crates/yakui-core/src/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ use crate::dom::Dom;
use crate::event::EventResponse;
use crate::event::{EventInterest, WidgetEvent};
use crate::geometry::{Constraints, FlexFit};
use crate::id::WidgetId;
use crate::input::{InputState, NavDirection};
use crate::layout::LayoutDom;
use crate::paint::PaintDom;
use crate::{Flow, WidgetId};
use crate::types::{Axis, Flow};

/// Trait that's automatically implemented for all widget props.
///
Expand All @@ -38,6 +39,36 @@ impl<'dom> LayoutContext<'dom> {
self.layout
.calculate(self.dom, self.input, widget, constraints)
}

/// Calculate the intrinsic width for the given widget.
pub fn intrinsic_width(&mut self, widget: WidgetId) -> f32 {
self.layout.intrinsic_size(self.dom, widget, Axis::X)
}

/// Calculate the intrinsic height for the given widget.
pub fn intrinsic_height(&mut self, widget: WidgetId) -> f32 {
self.layout.intrinsic_size(self.dom, widget, Axis::Y)
}
}

/// Information available to a widget during the layout phase.
#[non_exhaustive]
#[allow(missing_docs)]
pub struct IntrinsicSizeContext<'dom> {
pub dom: &'dom Dom,
pub layout: &'dom LayoutDom,
}

impl<'dom> IntrinsicSizeContext<'dom> {
/// Calculate the intrinsic width for the given widget.
pub fn intrinsic_width(&self, widget: WidgetId) -> f32 {
self.layout.intrinsic_size(self.dom, widget, Axis::X)
}

/// Calculate the intrinsic height for the given widget.
pub fn intrinsic_height(&self, widget: WidgetId) -> f32 {
self.layout.intrinsic_size(self.dom, widget, Axis::Y)
}
}

/// Information available to a widget during the paint phase.
Expand Down Expand Up @@ -134,6 +165,34 @@ pub trait Widget: 'static + fmt::Debug {
constraints.constrain_min(size)
}

/// Tells the intrinsic width of the object, which is its width if the
/// widget were given unbounded constraints.
fn intrinsic_width(&self, ctx: IntrinsicSizeContext<'_>) -> f32 {
let node = ctx.dom.get_current();
let mut width: f32 = 0.0;

for &child in &node.children {
let child_width = ctx.intrinsic_width(child);
width = width.max(child_width);
}

width
}

/// Tells the intrinsic height of the object, which is its height if the
/// widget were given unbounded constraints.
fn intrinsic_height(&self, ctx: IntrinsicSizeContext<'_>) -> f32 {
let node = ctx.dom.get_current();
let mut height: f32 = 0.0;

for &child in &node.children {
let child_height = ctx.intrinsic_height(child);
height = height.max(child_height);
}

height
}

/// Paint the widget based on its current state.
///
/// The default implementation will paint all of the widget's children.
Expand Down Expand Up @@ -180,6 +239,12 @@ pub trait ErasedWidget: Any + fmt::Debug {
/// See [`Widget::layout`].
fn layout(&self, ctx: LayoutContext<'_>, constraints: Constraints) -> Vec2;

/// See [`Widget::intrinsic_width`].
fn intrinsic_width(&self, ctx: IntrinsicSizeContext<'_>) -> f32;

/// See [`Widget::intrinsic_height`].
fn intrinsic_height(&self, ctx: IntrinsicSizeContext<'_>) -> f32;

/// See [`Widget::flex`].
fn flex(&self) -> (u32, FlexFit);

Expand Down Expand Up @@ -207,6 +272,14 @@ where
<T as Widget>::layout(self, ctx, constraints)
}

fn intrinsic_width(&self, ctx: IntrinsicSizeContext<'_>) -> f32 {
<T as Widget>::intrinsic_width(self, ctx)
}

fn intrinsic_height(&self, ctx: IntrinsicSizeContext<'_>) -> f32 {
<T as Widget>::intrinsic_height(self, ctx)
}

fn flex(&self) -> (u32, FlexFit) {
<T as Widget>::flex(self)
}
Expand Down

0 comments on commit d658969

Please sign in to comment.