mirror of https://github.com/linebender/xilem
Create a `View` for `SizedBox` (#398)
![image](https://github.com/linebender/xilem/assets/36049421/9b1cccc2-15d9-48dc-aca8-eddeb32dfac5) I have chosen not to set the background and border properties, as those are moreso styling properties - in our current state, we seem to be much preferring only specifying layout values
This commit is contained in:
parent
d6af6a6ef7
commit
7d62b16a19
|
@ -83,6 +83,18 @@ impl SizedBox {
|
|||
}
|
||||
}
|
||||
|
||||
/// Construct container with child in a pod, and both width and height not set.
|
||||
pub fn new_pod(child: WidgetPod<Box<dyn Widget>>) -> Self {
|
||||
Self {
|
||||
child: Some(child),
|
||||
width: None,
|
||||
height: None,
|
||||
background: None,
|
||||
border: None,
|
||||
corner_radius: RoundedRectRadii::from_single_radius(0.0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct container without child, and both width and height not set.
|
||||
///
|
||||
/// If the widget is unchanged, it will render nothing, which can be useful if you want to draw a
|
||||
|
@ -165,6 +177,18 @@ impl SizedBox {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set the width directly. Intended for toolkits abstracting over `SizedBox`
|
||||
pub fn raw_width(mut self, value: Option<f64>) -> Self {
|
||||
self.width = value;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the height directly. Intended for toolkits abstracting over `SizedBox`
|
||||
pub fn raw_height(mut self, value: Option<f64>) -> Self {
|
||||
self.height = value;
|
||||
self
|
||||
}
|
||||
|
||||
// TODO - child()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,31 @@
|
|||
// Copyright 2024 the Xilem Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use masonry::widget::{CrossAxisAlignment, MainAxisAlignment};
|
||||
use masonry::{
|
||||
widget::{CrossAxisAlignment, MainAxisAlignment},
|
||||
ArcStr,
|
||||
};
|
||||
use winit::error::EventLoopError;
|
||||
use xilem::{
|
||||
view::{button, flex, label},
|
||||
view::{button, flex, label, sized_box},
|
||||
EventLoop, WidgetView, Xilem,
|
||||
};
|
||||
|
||||
/// A component to make a bigger than usual button
|
||||
fn big_button(
|
||||
label: impl Into<ArcStr>,
|
||||
callback: impl Fn(&mut i32) + Send + Sync + 'static,
|
||||
) -> impl WidgetView<i32> {
|
||||
sized_box(button(label, callback)).width(40.).height(40.)
|
||||
}
|
||||
|
||||
fn app_logic(data: &mut i32) -> impl WidgetView<i32> {
|
||||
flex((
|
||||
button("-", |data| {
|
||||
big_button("-", |data| {
|
||||
*data -= 1;
|
||||
}),
|
||||
label(format!("count: {}", data)),
|
||||
button("+", |data| {
|
||||
big_button("+", |data| {
|
||||
*data += 1;
|
||||
}),
|
||||
))
|
||||
|
|
|
@ -10,6 +10,9 @@ pub use checkbox::*;
|
|||
mod flex;
|
||||
pub use flex::*;
|
||||
|
||||
mod sized_box;
|
||||
pub use sized_box::*;
|
||||
|
||||
mod label;
|
||||
pub use label::*;
|
||||
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
// Copyright 2024 the Xilem Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use masonry::widget;
|
||||
|
||||
use crate::{
|
||||
core::{Mut, View, ViewId},
|
||||
Pod, ViewCtx, WidgetView,
|
||||
};
|
||||
|
||||
/// A widget with predefined size.
|
||||
///
|
||||
/// This widget forces its child to have a specific width and/or height (assuming values are permitted by
|
||||
/// this widget's parent). If either the width or height is not set, this widget will size itself
|
||||
/// to match the child's size in that dimension.
|
||||
pub fn sized_box<State, Action, V>(inner: V) -> SizedBox<V>
|
||||
where
|
||||
V: WidgetView<State, Action>,
|
||||
{
|
||||
SizedBox {
|
||||
inner,
|
||||
height: None,
|
||||
width: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SizedBox<V> {
|
||||
inner: V,
|
||||
width: Option<f64>,
|
||||
height: Option<f64>,
|
||||
}
|
||||
|
||||
impl<V> SizedBox<V> {
|
||||
/// Set container's width.
|
||||
pub fn width(mut self, width: f64) -> Self {
|
||||
self.width = Some(width);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set container's height.
|
||||
pub fn height(mut self, height: f64) -> Self {
|
||||
self.height = Some(height);
|
||||
self
|
||||
}
|
||||
|
||||
/// Expand container to fit the parent.
|
||||
///
|
||||
/// Only call this method if you want your widget to occupy all available
|
||||
/// space. If you only care about expanding in one of width or height, use
|
||||
/// [`expand_width`] or [`expand_height`] instead.
|
||||
///
|
||||
/// [`expand_height`]: Self::expand_height
|
||||
/// [`expand_width`]: Self::expand_width
|
||||
pub fn expand(mut self) -> Self {
|
||||
self.width = Some(f64::INFINITY);
|
||||
self.height = Some(f64::INFINITY);
|
||||
self
|
||||
}
|
||||
|
||||
/// Expand the container on the x-axis.
|
||||
///
|
||||
/// This will force the child to have maximum width.
|
||||
pub fn expand_width(mut self) -> Self {
|
||||
self.width = Some(f64::INFINITY);
|
||||
self
|
||||
}
|
||||
|
||||
/// Expand the container on the y-axis.
|
||||
///
|
||||
/// This will force the child to have maximum height.
|
||||
pub fn expand_height(mut self) -> Self {
|
||||
self.height = Some(f64::INFINITY);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, State, Action> View<State, Action, ViewCtx> for SizedBox<V>
|
||||
where
|
||||
V: WidgetView<State, Action>,
|
||||
{
|
||||
type Element = Pod<widget::SizedBox>;
|
||||
type ViewState = V::ViewState;
|
||||
|
||||
fn build(&self, ctx: &mut ViewCtx) -> (Self::Element, Self::ViewState) {
|
||||
let (child, child_state) = self.inner.build(ctx);
|
||||
let widget = widget::SizedBox::new_pod(child.inner.boxed())
|
||||
.raw_width(self.width)
|
||||
.raw_height(self.height);
|
||||
(Pod::new(widget), child_state)
|
||||
}
|
||||
|
||||
fn rebuild<'el>(
|
||||
&self,
|
||||
prev: &Self,
|
||||
view_state: &mut Self::ViewState,
|
||||
ctx: &mut ViewCtx,
|
||||
mut element: Mut<'el, Self::Element>,
|
||||
) -> Mut<'el, Self::Element> {
|
||||
if self.width != prev.width {
|
||||
match self.width {
|
||||
Some(width) => element.set_width(width),
|
||||
None => element.unset_width(),
|
||||
}
|
||||
}
|
||||
if self.height != prev.height {
|
||||
match self.height {
|
||||
Some(height) => element.set_height(height),
|
||||
None => element.unset_height(),
|
||||
}
|
||||
}
|
||||
{
|
||||
let mut child = element
|
||||
.child_mut()
|
||||
.expect("We only create SizedBox with a child");
|
||||
self.inner
|
||||
.rebuild(&prev.inner, view_state, ctx, child.downcast());
|
||||
}
|
||||
element
|
||||
}
|
||||
|
||||
fn teardown(
|
||||
&self,
|
||||
view_state: &mut Self::ViewState,
|
||||
ctx: &mut ViewCtx,
|
||||
mut element: Mut<'_, Self::Element>,
|
||||
) {
|
||||
let mut child = element
|
||||
.child_mut()
|
||||
.expect("We only create SizedBox with a child");
|
||||
self.inner.teardown(view_state, ctx, child.downcast());
|
||||
}
|
||||
|
||||
fn message(
|
||||
&self,
|
||||
view_state: &mut Self::ViewState,
|
||||
id_path: &[ViewId],
|
||||
message: xilem_core::DynMessage,
|
||||
app_state: &mut State,
|
||||
) -> crate::MessageResult<Action> {
|
||||
self.inner.message(view_state, id_path, message, app_state)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue