Skip to content

Commit

Permalink
feat(widgets): 🎸 add fractionally widgets
Browse files Browse the repository at this point in the history
  • Loading branch information
M-Adoo committed Oct 31, 2024
1 parent 6120611 commit 59ddbe1
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Please only add new entries below the [Unreleased](#unreleased---releasedate) he
### Features

- **core**: Added the smooth widgets for transitioning the layout position and size. (#645 @M-Adoo)
- **widgets**: Added three widgets `FractionallyWidthBox`, `FractionallyHeightBox`, and `FractionallySizedBox` to enable fractional sizing of widgets. (#pr @M-Adoo)

## [0.4.0-alpha.14] - 2024-10-30

Expand Down
8 changes: 4 additions & 4 deletions core/src/test_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,16 +338,16 @@ impl LayoutCase {

let info = wnd.layout_info_by_path(path).unwrap();
if let Some(x) = x {
assert_eq!(*x, info.pos.x, "unexpected x");
assert_eq!(info.pos.x, *x, "unexpected x");
}
if let Some(y) = y {
assert_eq!(*y, info.pos.y, "unexpected y");
assert_eq!(info.pos.y, *y, "unexpected y");
}
if let Some(w) = width {
assert_eq!(*w, info.size.unwrap().width, "unexpected width");
assert_eq!(info.size.unwrap().width, *w, "unexpected width");
}
if let Some(h) = height {
assert_eq!(*h, info.size.unwrap().height, "unexpected height");
assert_eq!(info.size.unwrap().height, *h, "unexpected height");
}
}
}
Expand Down
1 change: 1 addition & 0 deletions core/src/wrap_render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ where
}
}

#[macro_export]
macro_rules! impl_compose_child_for_wrap_render {
($name:ty) => {
impl<'c> ComposeChild<'c> for $name {
Expand Down
2 changes: 2 additions & 0 deletions widgets/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ pub use stack::*;
pub mod only_sized_by_parent;
pub use only_sized_by_parent::OnlySizedByParent;
pub use ribir_core::builtin_widgets::container::Container;
mod fractionally;
pub use fractionally::*;
178 changes: 178 additions & 0 deletions widgets/src/layout/fractionally.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
use ribir_core::{prelude::*, wrap_render::WrapRender};

/// This widget resizes its child to occupy a fraction of the total available
/// space.
///
/// Alternatively, it can function as an empty box, occupying a fraction of the
/// total available space.
#[derive(Declare)]
pub struct FractionallySizedBox {
pub width_factor: f32,
pub height_factor: f32,
}

/// This widget sizes its child to occupy a fraction of the total available
/// space along the x-axis.
///
/// Alternatively, it can act as an empty box, occupying a fraction of the
/// x-axis space while extending along the y-axis.
#[derive(Declare)]
pub struct FractionallyWidthBox {
pub factor: f32,
}

/// This widget sizes its child to occupy a fraction of the total available
/// space along the y-axis.
///
/// Alternatively, it can act as an empty box, occupying a fraction of the
/// y-axis space while extending along the x-axis.
#[derive(Declare)]
pub struct FractionallyHeightBox {
pub factor: f32,
}

// implementation for FractionallySizedBox
impl Render for FractionallySizedBox {
fn perform_layout(&self, clamp: BoxClamp, _: &mut LayoutCtx) -> Size { self.size(clamp) }
}

ribir_core::impl_compose_child_for_wrap_render!(FractionallySizedBox);

impl WrapRender for FractionallySizedBox {
fn perform_layout(&self, clamp: BoxClamp, host: &dyn Render, ctx: &mut LayoutCtx) -> Size {
let size = self.size(clamp);
host.perform_layout(BoxClamp::fixed_size(size), ctx)
}
}

impl FractionallySizedBox {
fn size(&self, clamp: BoxClamp) -> Size {
let w_factor = self.width_factor.clamp(0., 1.);
let h_factor = self.height_factor.clamp(0., 1.);
let size = Size::new(clamp.max.width * w_factor, clamp.max.height * h_factor);
clamp.clamp(size)
}
}

// implementation for FractionallyWidthBox
impl Render for FractionallyWidthBox {
fn perform_layout(&self, clamp: BoxClamp, _: &mut LayoutCtx) -> Size {
let width = self.width(clamp);
Size::new(width, clamp.max.height)
}
}

ribir_core::impl_compose_child_for_wrap_render!(FractionallyWidthBox);

impl WrapRender for FractionallyWidthBox {
fn perform_layout(&self, clamp: BoxClamp, host: &dyn Render, ctx: &mut LayoutCtx) -> Size {
let width = self.width(clamp);
host.perform_layout(clamp.with_fixed_width(width), ctx)
}
}

impl FractionallyWidthBox {
fn width(&self, clamp: BoxClamp) -> f32 {
let factor = self.factor.clamp(0., 1.);
let width = clamp.max.width * factor;
width.clamp(clamp.min.width, clamp.max.width)
}
}
// implementation for FractionallyHeightBox

impl Render for FractionallyHeightBox {
fn perform_layout(&self, clamp: BoxClamp, _: &mut LayoutCtx) -> Size {
let height = self.height(clamp);
Size::new(clamp.max.width, height)
}
}

ribir_core::impl_compose_child_for_wrap_render!(FractionallyHeightBox);

impl WrapRender for FractionallyHeightBox {
fn perform_layout(&self, clamp: BoxClamp, host: &dyn Render, ctx: &mut LayoutCtx) -> Size {
let height = self.height(clamp);
host.perform_layout(clamp.with_fixed_height(height), ctx)
}
}

impl FractionallyHeightBox {
fn height(&self, clamp: BoxClamp) -> f32 {
let factor = self.factor.clamp(0., 1.);
let height = clamp.max.height * factor;
height.clamp(clamp.min.height, clamp.max.height)
}
}

#[cfg(test)]
mod tests {
use ribir_core::test_helper::*;
use ribir_dev_helper::*;

use super::*;

widget_layout_test! {
fractionally_sized_box,
WidgetTester::new(fn_widget! {
@FractionallySizedBox {
width_factor: 0.5, height_factor: 0.5,
}
})
.with_wnd_size(Size::new(100., 100.)),
LayoutCase::default().with_size(Size::new(50., 50.))
}

widget_layout_test! {
fractionally_sized_box_with_child,
WidgetTester::new(fn_widget! {
@FractionallySizedBox {
width_factor: 0., height_factor: 1.2,
@ { Void }
}
})
.with_wnd_size(Size::new(100., 100.)),
LayoutCase::default().with_size(Size::new(0., 100.))
}

widget_layout_test! {
fractionally_width_box,
WidgetTester::new(fn_widget! {
@FractionallyWidthBox { factor: 0.5 }
})
.with_wnd_size(Size::new(100., 100.)),
LayoutCase::default().with_size(Size::new(50., 100.))
}

widget_layout_test! {
fractionally_width_box_with_child,
WidgetTester::new(fn_widget! {
@FractionallyWidthBox {
factor: 0.5,
@ { Void }
}
})
.with_wnd_size(Size::new(100., 100.)),
LayoutCase::default().with_size(Size::new(50., 0.))
}

widget_layout_test! {
fractionally_height_box,
WidgetTester::new(fn_widget! {
@FractionallyHeightBox { factor: 0.5 }
})
.with_wnd_size(Size::new(100., 100.)),
LayoutCase::default().with_size(Size::new(100., 50.))
}

widget_layout_test! {
fractionally_height_box_with_child,
WidgetTester::new(fn_widget! {
@FractionallyHeightBox {
factor: 0.5,
@ { Void }
}
})
.with_wnd_size(Size::new(100., 100.)),
LayoutCase::default().with_size(Size::new(0., 50.))
}
}

0 comments on commit 59ddbe1

Please sign in to comment.