add checkbox to widget example (#568)

This PR adds another widget to the widgets example, and also draws boxes
around each widget to separate them visually. I wanted to use flex wrap
to display them, but I don't think that's implemented yet in Xilem, and
the layout I did use isn't bad.

It also provides a simple example of the use of `Adapt`

---------

Co-authored-by: Daniel McNab <36049421+DJMcNab@users.noreply.github.com>
This commit is contained in:
Richard Dodd 2024-09-13 15:48:49 +01:00 committed by GitHub
parent c563029372
commit c1da921af5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 64 additions and 17 deletions

View File

@ -7,50 +7,95 @@ use masonry::dpi::LogicalSize;
use masonry::event_loop_runner::{EventLoop, EventLoopBuilder};
use winit::error::EventLoopError;
use winit::window::Window;
use xilem::view::{button, checkbox, flex, label, progress_bar, FlexSpacer};
use xilem::{WidgetView, Xilem};
use xilem::core::adapt;
use xilem::view::{button, checkbox, flex, flex_item, progress_bar, sized_box, Axis, FlexSpacer};
use xilem::{Color, WidgetView, Xilem};
const SPACER_WIDTH: f64 = 10.;
/// The state of the entire application.
///
/// This is owned by Xilem, used to construct the view tree, and updated by event handlers.
struct WidgetGallery {
progress: Option<f64>,
checked: bool,
}
fn app_logic(data: &mut WidgetGallery) -> impl WidgetView<WidgetGallery> {
fn progress_bar_view(data: Option<f64>) -> impl WidgetView<Option<f64>> {
flex((
label("this 'widgets' example currently only has 1 widget"),
FlexSpacer::Flex(1.),
progress_bar(data.progress),
progress_bar(data),
checkbox(
"set indeterminate progress",
data.progress.is_none(),
|state: &mut WidgetGallery, checked| {
data.is_none(),
|state: &mut Option<f64>, checked| {
if checked {
state.progress = None;
*state = None;
} else {
state.progress = Some(0.5);
*state = Some(0.5);
}
},
),
button("change progress", |state: &mut WidgetGallery| {
match state.progress {
button("change progress", |state: &mut Option<f64>| match state {
Some(ref mut v) => *v = (*v + 0.1).rem_euclid(1.),
None => state.progress = Some(0.5),
}
None => *state = Some(0.5),
}),
FlexSpacer::Flex(1.),
))
}
fn checkbox_view(data: bool) -> impl WidgetView<bool> {
checkbox("a simple checkbox", data, |data, new_state| {
*data = new_state;
})
}
/// Wrap `inner` in a box with a border
fn border_box<State: 'static, Action: 'static>(
inner: impl WidgetView<State, Action>,
) -> impl WidgetView<State, Action> {
sized_box(
flex((
FlexSpacer::Flex(1.),
flex((FlexSpacer::Flex(1.), inner, FlexSpacer::Flex(1.))),
FlexSpacer::Flex(1.),
))
.direction(Axis::Horizontal),
)
.border(Color::WHITE, 2.)
.width(450.)
.height(200.)
}
/// Top-level view
fn app_logic(data: &mut WidgetGallery) -> impl WidgetView<WidgetGallery> {
// Use a `sized_box` to pad the window contents
sized_box(
flex((
adapt(
flex_item(border_box(progress_bar_view(data.progress)), 1.),
|data: &mut WidgetGallery, thunk| thunk.call(&mut data.progress),
),
adapt(
flex_item(border_box(checkbox_view(data.checked)), 1.),
|data: &mut WidgetGallery, thunk| thunk.call(&mut data.checked),
),
))
.gap(SPACER_WIDTH)
.direction(Axis::Horizontal),
)
.border(Color::TRANSPARENT, SPACER_WIDTH)
}
fn run(event_loop: EventLoopBuilder) -> Result<(), EventLoopError> {
// Set up the initial state of the app
let data = WidgetGallery {
progress: Some(0.5),
checked: false,
};
// Instantiate and run the UI using the passed event loop.
let app = Xilem::new(data, app_logic);
let min_window_size = LogicalSize::new(300., 200.);
let window_size = LogicalSize::new(450., 300.);
let window_size = LogicalSize::new(650., 500.);
let window_attributes = Window::default_attributes()
.with_title("Xilem Widgets")
.with_resizable(true)

View File

@ -1,6 +1,8 @@
// Copyright 2024 the Xilem Authors
// SPDX-License-Identifier: Apache-2.0
//! Views for the widgets which are built-in to Masonry. These are the primitives your Xilem app's view tree will generally be constructed from.
mod task;
pub use task::*;