Skip to content

Commit

Permalink
Add pivot to reflow (SecondHalfGames#144)
Browse files Browse the repository at this point in the history
allows attaching the reflowed element anywhere from the anchor point
  • Loading branch information
Uriopass committed Jun 30, 2024
1 parent f9d7f04 commit 3697538
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 12 deletions.
37 changes: 37 additions & 0 deletions crates/yakui-core/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,40 @@ impl Alignment {
pub const BOTTOM_CENTER: Self = Self::new(0.5, 1.0);
pub const BOTTOM_RIGHT: Self = Self::new(1.0, 1.0);
}

/// Defines a reference point for a widget.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Pivot {
x: f32,
y: f32,
}

impl Pivot {
/// Create a new `Pivot` given an anchor point.
///
/// `0.0, 0.0` is the top left corner of the widget, while `1.0, 1.0` is
/// the bottom right corner.
pub const fn new(x: f32, y: f32) -> Self {
Self { x, y }
}

/// Returns the point for a pivot value.
pub const fn as_vec2(&self) -> Vec2 {
Vec2::new(self.x, self.y)
}
}

#[allow(missing_docs)]
impl Pivot {
pub const TOP_LEFT: Self = Self::new(0.0, 0.0);
pub const TOP_CENTER: Self = Self::new(0.5, 0.0);
pub const TOP_RIGHT: Self = Self::new(1.0, 0.0);

pub const CENTER_LEFT: Self = Self::new(0.0, 0.5);
pub const CENTER: Self = Self::new(0.5, 0.5);
pub const CENTER_RIGHT: Self = Self::new(1.0, 0.5);

pub const BOTTOM_LEFT: Self = Self::new(0.0, 1.0);
pub const BOTTOM_CENTER: Self = Self::new(0.5, 1.0);
pub const BOTTOM_RIGHT: Self = Self::new(1.0, 1.0);
}
5 changes: 3 additions & 2 deletions crates/yakui-widgets/src/shorthand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::borrow::Cow;

use yakui_core::geometry::{Color, Constraints, Dim2, Vec2};
use yakui_core::widget::PaintContext;
use yakui_core::{Alignment, ManagedTextureId, Response, TextureId};
use yakui_core::{Alignment, ManagedTextureId, Pivot, Response, TextureId};

use crate::widgets::{
Align, AlignResponse, Button, ButtonResponse, Canvas, CanvasResponse, Checkbox,
Expand Down Expand Up @@ -170,10 +170,11 @@ pub fn slider(value: f64, min: f64, max: f64) -> Response<SliderResponse> {
/// See [Reflow].
pub fn reflow(
anchor: Alignment,
pivot: Pivot,
offset: Dim2,
children: impl FnOnce(),
) -> Response<ReflowResponse> {
Reflow::new(anchor, offset).show(children)
Reflow::new(anchor, pivot, offset).show(children)
}

/// See [Opaque].
Expand Down
20 changes: 16 additions & 4 deletions crates/yakui-widgets/src/widgets/reflow.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use yakui_core::geometry::{Constraints, Dim2, Vec2};
use yakui_core::widget::{LayoutContext, Widget};
use yakui_core::{Alignment, Flow, Response};
use yakui_core::{Alignment, Flow, Pivot, Response};

use crate::util::widget_children;

Expand All @@ -12,12 +12,17 @@ or table layouts.
#[non_exhaustive]
pub struct Reflow {
pub anchor: Alignment,
pub pivot: Pivot,
pub offset: Dim2,
}

impl Reflow {
pub fn new(anchor: Alignment, offset: Dim2) -> Self {
Self { anchor, offset }
pub fn new(anchor: Alignment, pivot: Pivot, offset: Dim2) -> Self {
Self {
anchor,
pivot,
offset,
}
}

pub fn show<F: FnOnce()>(self, children: F) -> Response<ReflowResponse> {
Expand All @@ -40,6 +45,7 @@ impl Widget for ReflowWidget {
Self {
props: Reflow {
anchor: Alignment::TOP_LEFT,
pivot: Pivot::TOP_LEFT,
offset: Dim2::ZERO,
},
}
Expand All @@ -58,8 +64,14 @@ impl Widget for ReflowWidget {

fn layout(&self, mut ctx: LayoutContext<'_>, _constraints: Constraints) -> Vec2 {
let node = ctx.dom.get_current();
let mut size = Vec2::ZERO;
for &child in &node.children {
size = size.max(ctx.calculate_layout(child, Constraints::none()));
}

let pivot_offset = -size * self.props.pivot.as_vec2();
for &child in &node.children {
ctx.calculate_layout(child, Constraints::none());
ctx.layout.set_pos(child, pivot_offset);
}

Vec2::ZERO
Expand Down
15 changes: 10 additions & 5 deletions crates/yakui-widgets/tests/snapshot.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use yakui::{Constraints, CrossAxisAlignment, Dim2, MainAxisAlignment, MainAxisSize, Vec2};
use yakui_core::geometry::Color;
use yakui_core::Alignment;
use yakui_core::{Alignment, Pivot};
use yakui_test::{run, Test};
use yakui_widgets::widgets::{Button, List, Pad, UnconstrainedBox};
use yakui_widgets::{
Expand Down Expand Up @@ -351,13 +351,18 @@ fn row_reflow() {
colored_box(Color::RED, [50.0, 50.0]);
colored_box(Color::GREEN, [50.0, 50.0]);

reflow(Alignment::BOTTOM_RIGHT, Dim2::ZERO, || {
reflow(Alignment::BOTTOM_RIGHT, Pivot::TOP_LEFT, Dim2::ZERO, || {
colored_box(Color::BLUE, [100.0, 50.0]);
});

reflow(Alignment::BOTTOM_RIGHT, Dim2::pixels(0.0, 50.0), || {
colored_box(Color::WHITE, [100.0, 100.0]);
});
reflow(
Alignment::BOTTOM_RIGHT,
Pivot::TOP_LEFT,
Dim2::pixels(0.0, 50.0),
|| {
colored_box(Color::WHITE, [100.0, 100.0]);
},
);
});
});
});
Expand Down
3 changes: 2 additions & 1 deletion crates/yakui/examples/dropdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

use yakui::widgets::Layer;
use yakui::{align, button, column, reflow, use_state, widgets::Pad, Alignment, Dim2};
use yakui_core::Pivot;

pub fn run() {
let open = use_state(|| false);
Expand All @@ -25,7 +26,7 @@ pub fn run() {
if open.get() {
Pad::ZERO.show(|| {
Layer::new().show(|| {
reflow(Alignment::BOTTOM_LEFT, Dim2::ZERO, || {
reflow(Alignment::BOTTOM_LEFT, Pivot::TOP_LEFT, Dim2::ZERO, || {
column(|| {
let current = selected.get();
for (i, option) in options.iter().enumerate() {
Expand Down

0 comments on commit 3697538

Please sign in to comment.