Draft nodes for missing widgets
This commit is contained in:
parent
8834772fa7
commit
655978f480
16 changed files with 191 additions and 36 deletions
|
|
@ -38,9 +38,12 @@ use crate::{
|
||||||
///
|
///
|
||||||
/// 
|
/// 
|
||||||
pub struct Checkbox<Color, Message> {
|
pub struct Checkbox<Color, Message> {
|
||||||
is_checked: bool,
|
/// Whether the checkbox is checked or not
|
||||||
on_toggle: Box<dyn Fn(bool) -> Message>,
|
pub is_checked: bool,
|
||||||
label: String,
|
/// Toggle message to fire
|
||||||
|
pub on_toggle: Box<dyn Fn(bool) -> Message>,
|
||||||
|
/// The label of the checkbox
|
||||||
|
pub label: String,
|
||||||
label_color: Option<Color>,
|
label_color: Option<Color>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,11 @@ use std::hash::Hash;
|
||||||
/// let image = Image::new(my_handle);
|
/// let image = Image::new(my_handle);
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Image<I> {
|
pub struct Image<I> {
|
||||||
image: I,
|
/// The image handle
|
||||||
|
pub image: I,
|
||||||
source: Option<Rectangle<u16>>,
|
source: Option<Rectangle<u16>>,
|
||||||
width: Option<u16>,
|
/// The width of the image
|
||||||
|
pub width: Option<u16>,
|
||||||
height: Option<u16>,
|
height: Option<u16>,
|
||||||
style: Style,
|
style: Style,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,9 +47,12 @@ use std::hash::Hash;
|
||||||
///
|
///
|
||||||
/// 
|
/// 
|
||||||
pub struct Radio<Color, Message> {
|
pub struct Radio<Color, Message> {
|
||||||
is_selected: bool,
|
/// Whether the radio button is selected or not
|
||||||
on_click: Message,
|
pub is_selected: bool,
|
||||||
label: String,
|
/// The message to produce when the radio button is clicked
|
||||||
|
pub on_click: Message,
|
||||||
|
/// The label of the radio button
|
||||||
|
pub label: String,
|
||||||
label_color: Option<Color>,
|
label_color: Option<Color>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
//! [`State`]: struct.State.html
|
//! [`State`]: struct.State.html
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::input::{mouse, ButtonState};
|
use crate::input::{mouse, ButtonState};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -42,9 +43,12 @@ use crate::{
|
||||||
/// 
|
/// 
|
||||||
pub struct Slider<'a, Message> {
|
pub struct Slider<'a, Message> {
|
||||||
state: &'a mut State,
|
state: &'a mut State,
|
||||||
range: RangeInclusive<f32>,
|
/// The range of the slider
|
||||||
value: f32,
|
pub range: RangeInclusive<f32>,
|
||||||
on_change: Box<dyn Fn(f32) -> Message>,
|
/// The current value of the slider
|
||||||
|
pub value: f32,
|
||||||
|
/// The function to produce messages on change
|
||||||
|
pub on_change: Rc<Box<dyn Fn(f32) -> Message>>,
|
||||||
style: Style,
|
style: Style,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,7 +89,7 @@ impl<'a, Message> Slider<'a, Message> {
|
||||||
state,
|
state,
|
||||||
value: value.max(*range.start()).min(*range.end()),
|
value: value.max(*range.start()).min(*range.end()),
|
||||||
range,
|
range,
|
||||||
on_change: Box::new(on_change),
|
on_change: Rc::new(Box::new(on_change)),
|
||||||
style: Style::default().min_width(100).fill_width(),
|
style: Style::default().min_width(100).fill_width(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ maintenance = { status = "actively-developed" }
|
||||||
iced = { version = "0.1.0-alpha", path = ".." }
|
iced = { version = "0.1.0-alpha", path = ".." }
|
||||||
dodrio = "0.1.0"
|
dodrio = "0.1.0"
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
|
wasm-bindgen = "0.2.50"
|
||||||
|
|
||||||
[dependencies.web-sys]
|
[dependencies.web-sys]
|
||||||
version = "0.3.27"
|
version = "0.3.27"
|
||||||
|
|
@ -25,4 +26,8 @@ features = [
|
||||||
"console",
|
"console",
|
||||||
"Document",
|
"Document",
|
||||||
"HtmlElement",
|
"HtmlElement",
|
||||||
|
"HtmlInputElement",
|
||||||
|
"Event",
|
||||||
|
"EventTarget",
|
||||||
|
"InputEvent",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
|
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
|
||||||
<title>Tour - Iced Web</title>
|
<title>Web Tour - Iced</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
|
|
|
||||||
1
web/examples/tour/resources/ferris.png
Symbolic link
1
web/examples/tour/resources/ferris.png
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
../../../../examples/resources/ferris.png
|
||||||
|
|
@ -295,8 +295,8 @@ impl<'a> Step {
|
||||||
))
|
))
|
||||||
.push(Text::new(
|
.push(Text::new(
|
||||||
"Iced does not provide a built-in renderer. This example runs \
|
"Iced does not provide a built-in renderer. This example runs \
|
||||||
on a fairly simple renderer built on top of ggez, another \
|
on WebAssembly using dodrio, an experimental VDOM library \
|
||||||
game library.",
|
for Rust.",
|
||||||
))
|
))
|
||||||
.push(Text::new(
|
.push(Text::new(
|
||||||
"You will need to interact with the UI in order to reach the \
|
"You will need to interact with the UI in order to reach the \
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,5 @@ pub trait Widget<Message> {
|
||||||
&self,
|
&self,
|
||||||
bump: &'b bumpalo::Bump,
|
bump: &'b bumpalo::Bump,
|
||||||
_bus: &Bus<Message>,
|
_bus: &Bus<Message>,
|
||||||
) -> dodrio::Node<'b> {
|
) -> dodrio::Node<'b>;
|
||||||
use dodrio::builder::*;
|
|
||||||
|
|
||||||
div(bump).children(vec![text("WIP")]).finish()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{Bus, Element, Widget};
|
use crate::{Bus, Element, Widget};
|
||||||
use dodrio::bumpalo;
|
|
||||||
|
|
||||||
pub use iced::button::{Class, State};
|
pub use iced::button::{Class, State};
|
||||||
|
|
||||||
|
use dodrio::bumpalo;
|
||||||
|
|
||||||
pub type Button<'a, Message> = iced::Button<'a, Message>;
|
pub type Button<'a, Message> = iced::Button<'a, Message>;
|
||||||
|
|
||||||
impl<'a, Message> Widget<Message> for Button<'a, Message>
|
impl<'a, Message> Widget<Message> for Button<'a, Message>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,45 @@
|
||||||
use crate::{Color, Element, Widget};
|
use crate::{Bus, Color, Element, Widget};
|
||||||
|
|
||||||
|
use dodrio::bumpalo;
|
||||||
|
|
||||||
pub type Checkbox<Message> = iced::Checkbox<Color, Message>;
|
pub type Checkbox<Message> = iced::Checkbox<Color, Message>;
|
||||||
|
|
||||||
impl<Message> Widget<Message> for Checkbox<Message> {}
|
impl<Message> Widget<Message> for Checkbox<Message>
|
||||||
|
where
|
||||||
|
Message: 'static + Copy,
|
||||||
|
{
|
||||||
|
fn node<'b>(
|
||||||
|
&self,
|
||||||
|
bump: &'b bumpalo::Bump,
|
||||||
|
bus: &Bus<Message>,
|
||||||
|
) -> dodrio::Node<'b> {
|
||||||
|
use dodrio::builder::*;
|
||||||
|
|
||||||
|
let checkbox_label = bumpalo::format!(in bump, "{}", self.label);
|
||||||
|
|
||||||
|
let event_bus = bus.clone();
|
||||||
|
let msg = (self.on_toggle)(!self.is_checked);
|
||||||
|
|
||||||
|
label(bump)
|
||||||
|
.children(vec![
|
||||||
|
input(bump)
|
||||||
|
.attr("type", "checkbox")
|
||||||
|
.bool_attr("checked", self.is_checked)
|
||||||
|
.on("click", move |root, vdom, _event| {
|
||||||
|
event_bus.publish(msg, root);
|
||||||
|
|
||||||
|
vdom.schedule_render();
|
||||||
|
})
|
||||||
|
.finish(),
|
||||||
|
text(checkbox_label.into_bump_str()),
|
||||||
|
])
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, Message> From<Checkbox<Message>> for Element<'a, Message>
|
impl<'a, Message> From<Checkbox<Message>> for Element<'a, Message>
|
||||||
where
|
where
|
||||||
Message: 'static,
|
Message: 'static + Copy,
|
||||||
{
|
{
|
||||||
fn from(checkbox: Checkbox<Message>) -> Element<'a, Message> {
|
fn from(checkbox: Checkbox<Message>) -> Element<'a, Message> {
|
||||||
Element::new(checkbox)
|
Element::new(checkbox)
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,10 @@ impl<'a, Message> Widget<Message> for Column<'a, Message> {
|
||||||
.map(|element| element.widget.node(bump, publish))
|
.map(|element| element.widget.node(bump, publish))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
div(bump).children(children).finish()
|
div(bump)
|
||||||
|
.attr("style", "display: flex; flex-direction: column")
|
||||||
|
.children(children)
|
||||||
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,29 @@
|
||||||
use crate::{Element, Widget};
|
use crate::{Bus, Element, Widget};
|
||||||
|
|
||||||
|
use dodrio::bumpalo;
|
||||||
|
|
||||||
pub type Image<'a> = iced::Image<&'a str>;
|
pub type Image<'a> = iced::Image<&'a str>;
|
||||||
|
|
||||||
impl<'a, Message> Widget<Message> for Image<'a> {}
|
impl<'a, Message> Widget<Message> for Image<'a> {
|
||||||
|
fn node<'b>(
|
||||||
|
&self,
|
||||||
|
bump: &'b bumpalo::Bump,
|
||||||
|
_bus: &Bus<Message>,
|
||||||
|
) -> dodrio::Node<'b> {
|
||||||
|
use dodrio::builder::*;
|
||||||
|
|
||||||
|
let src = bumpalo::format!(in bump, "{}", self.image);
|
||||||
|
|
||||||
|
let mut image = img(bump).attr("src", src.into_bump_str());
|
||||||
|
|
||||||
|
if let Some(width) = self.width {
|
||||||
|
let width = bumpalo::format!(in bump, "{}", width);
|
||||||
|
image = image.attr("width", width.into_bump_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
image.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, Message> From<Image<'a>> for Element<'a, Message> {
|
impl<'a, Message> From<Image<'a>> for Element<'a, Message> {
|
||||||
fn from(image: Image<'a>) -> Element<'a, Message> {
|
fn from(image: Image<'a>) -> Element<'a, Message> {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,46 @@
|
||||||
use crate::{Color, Element, Widget};
|
use crate::{Bus, Color, Element, Widget};
|
||||||
|
|
||||||
|
use dodrio::bumpalo;
|
||||||
|
|
||||||
pub type Radio<Message> = iced::Radio<Color, Message>;
|
pub type Radio<Message> = iced::Radio<Color, Message>;
|
||||||
|
|
||||||
impl<Message> Widget<Message> for Radio<Message> {}
|
impl<Message> Widget<Message> for Radio<Message>
|
||||||
|
where
|
||||||
|
Message: 'static + Copy,
|
||||||
|
{
|
||||||
|
fn node<'b>(
|
||||||
|
&self,
|
||||||
|
bump: &'b bumpalo::Bump,
|
||||||
|
bus: &Bus<Message>,
|
||||||
|
) -> dodrio::Node<'b> {
|
||||||
|
use dodrio::builder::*;
|
||||||
|
|
||||||
|
let radio_label = bumpalo::format!(in bump, "{}", self.label);
|
||||||
|
|
||||||
|
let event_bus = bus.clone();
|
||||||
|
let on_click = self.on_click;
|
||||||
|
|
||||||
|
label(bump)
|
||||||
|
.attr("style", "display: block")
|
||||||
|
.children(vec![
|
||||||
|
input(bump)
|
||||||
|
.attr("type", "radio")
|
||||||
|
.bool_attr("checked", self.is_selected)
|
||||||
|
.on("click", move |root, vdom, _event| {
|
||||||
|
event_bus.publish(on_click, root);
|
||||||
|
|
||||||
|
vdom.schedule_render();
|
||||||
|
})
|
||||||
|
.finish(),
|
||||||
|
text(radio_label.into_bump_str()),
|
||||||
|
])
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, Message> From<Radio<Message>> for Element<'a, Message>
|
impl<'a, Message> From<Radio<Message>> for Element<'a, Message>
|
||||||
where
|
where
|
||||||
Message: 'static,
|
Message: 'static + Copy,
|
||||||
{
|
{
|
||||||
fn from(radio: Radio<Message>) -> Element<'a, Message> {
|
fn from(radio: Radio<Message>) -> Element<'a, Message> {
|
||||||
Element::new(radio)
|
Element::new(radio)
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,10 @@ impl<'a, Message> Widget<Message> for Row<'a, Message> {
|
||||||
.map(|element| element.widget.node(bump, publish))
|
.map(|element| element.widget.node(bump, publish))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
div(bump).children(children).finish()
|
div(bump)
|
||||||
|
.attr("style", "display: flex; flex-direction: row")
|
||||||
|
.children(children)
|
||||||
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,61 @@
|
||||||
use crate::{Element, Widget};
|
use crate::{Bus, Element, Widget};
|
||||||
|
|
||||||
pub use iced::slider::State;
|
use dodrio::bumpalo;
|
||||||
|
|
||||||
pub type Slider<'a, Message> = iced::Slider<'a, Message>;
|
pub type Slider<'a, Message> = iced::Slider<'a, Message>;
|
||||||
|
|
||||||
impl<'a, Message> Widget<Message> for Slider<'a, Message> {}
|
pub use iced::slider::State;
|
||||||
|
|
||||||
|
impl<'a, Message> Widget<Message> for Slider<'a, Message>
|
||||||
|
where
|
||||||
|
Message: 'static + Copy,
|
||||||
|
{
|
||||||
|
fn node<'b>(
|
||||||
|
&self,
|
||||||
|
bump: &'b bumpalo::Bump,
|
||||||
|
bus: &Bus<Message>,
|
||||||
|
) -> dodrio::Node<'b> {
|
||||||
|
use dodrio::builder::*;
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
|
||||||
|
let (start, end) = self.range.clone().into_inner();
|
||||||
|
|
||||||
|
let min = bumpalo::format!(in bump, "{}", start);
|
||||||
|
let max = bumpalo::format!(in bump, "{}", end);
|
||||||
|
let value = bumpalo::format!(in bump, "{}", self.value);
|
||||||
|
|
||||||
|
let on_change = self.on_change.clone();
|
||||||
|
let event_bus = bus.clone();
|
||||||
|
|
||||||
|
// TODO: Make `step` configurable
|
||||||
|
label(bump)
|
||||||
|
.children(vec![input(bump)
|
||||||
|
.attr("type", "range")
|
||||||
|
.attr("step", "0.01")
|
||||||
|
.attr("min", min.into_bump_str())
|
||||||
|
.attr("max", max.into_bump_str())
|
||||||
|
.attr("value", value.into_bump_str())
|
||||||
|
.on("input", move |root, vdom, event| {
|
||||||
|
let slider = match event.target().and_then(|t| {
|
||||||
|
t.dyn_into::<web_sys::HtmlInputElement>().ok()
|
||||||
|
}) {
|
||||||
|
None => return,
|
||||||
|
Some(slider) => slider,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(value) = slider.value().parse::<f32>() {
|
||||||
|
event_bus.publish(on_change(value), root);
|
||||||
|
vdom.schedule_render();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finish()])
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, Message> From<Slider<'a, Message>> for Element<'a, Message>
|
impl<'a, Message> From<Slider<'a, Message>> for Element<'a, Message>
|
||||||
where
|
where
|
||||||
Message: 'static,
|
Message: 'static + Copy,
|
||||||
{
|
{
|
||||||
fn from(slider: Slider<'a, Message>) -> Element<'a, Message> {
|
fn from(slider: Slider<'a, Message>) -> Element<'a, Message> {
|
||||||
Element::new(slider)
|
Element::new(slider)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue