From 749722fca6eb9c85901e80060583559317f2af79 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 7 Dec 2019 05:47:14 +0100 Subject: Add `custom_widget` example It showcases how to build a simple native custom widget that draws a circle. --- examples/custom_widget.rs | 149 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 examples/custom_widget.rs (limited to 'examples') diff --git a/examples/custom_widget.rs b/examples/custom_widget.rs new file mode 100644 index 00000000..d51753e2 --- /dev/null +++ b/examples/custom_widget.rs @@ -0,0 +1,149 @@ +//! This example showcases a simple native custom widget that draws a circle. +mod circle { + // For now, to implement a custom native widget you will need to add + // `iced_native` and `iced_wgpu` to your dependencies. + // + // Then, you simply need to define your widget type and implement the + // `iced_native::Widget` trait with the `iced_wgpu::Renderer`. + // + // Of course, you can choose to make the implementation renderer-agnostic, + // if you wish to, by creating your own `Renderer` trait, which could be + // implemented by `iced_wgpu` and other renderers. + use iced_native::{ + layout, Background, Color, Element, Hasher, Layout, Length, + MouseCursor, Point, Size, Widget, + }; + use iced_wgpu::{Primitive, Renderer}; + + pub struct Circle { + radius: u16, + } + + impl Circle { + pub fn new(radius: u16) -> Self { + Self { radius } + } + } + + impl Widget for Circle { + fn width(&self) -> Length { + Length::Shrink + } + + fn height(&self) -> Length { + Length::Shrink + } + + fn layout( + &self, + _renderer: &Renderer, + limits: &layout::Limits, + ) -> layout::Node { + let size = limits + .width(Length::Units(self.radius * 2)) + .height(Length::Units(self.radius * 2)) + .resolve(Size::ZERO); + + layout::Node::new(size) + } + + fn hash_layout(&self, state: &mut Hasher) { + use std::hash::Hash; + + self.radius.hash(state); + } + + fn draw( + &self, + _renderer: &mut Renderer, + layout: Layout<'_>, + _cursor_position: Point, + ) -> (Primitive, MouseCursor) { + let bounds = layout.bounds(); + + ( + Primitive::Quad { + bounds, + background: Background::Color(Color::BLACK), + border_radius: self.radius, + }, + MouseCursor::OutOfBounds, + ) + } + } + + impl<'a, Message> Into> for Circle { + fn into(self) -> Element<'a, Message, Renderer> { + Element::new(self) + } + } +} + +use circle::Circle; +use iced::{ + slider, Align, Column, Container, Element, Length, Sandbox, Settings, + Slider, Text, +}; + +pub fn main() { + Example::run(Settings::default()) +} + +struct Example { + radius: u16, + slider: slider::State, +} + +#[derive(Debug, Clone, Copy)] +enum Message { + RadiusChanged(f32), +} + +impl Sandbox for Example { + type Message = Message; + + fn new() -> Self { + Example { + radius: 50, + slider: slider::State::new(), + } + } + + fn title(&self) -> String { + String::from("Custom widget - Iced") + } + + fn update(&mut self, message: Message) { + match message { + Message::RadiusChanged(radius) => { + self.radius = radius.round() as u16; + } + } + } + + fn view(&mut self) -> Element { + let content = Column::new() + .padding(20) + .spacing(20) + .max_width(500) + .align_items(Align::Center) + .push(Circle::new(self.radius)) + .push( + Text::new(format!("Radius: {}", self.radius.to_string())) + .width(Length::Shrink), + ) + .push(Slider::new( + &mut self.slider, + 1.0..=100.0, + f32::from(self.radius), + Message::RadiusChanged, + )); + + Container::new(content) + .width(Length::Fill) + .height(Length::Fill) + .center_x() + .center_y() + .into() + } +} -- cgit From cdee847cea47b84568048ff8f48194a24dab80f1 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 7 Dec 2019 07:19:05 +0100 Subject: Showcase new `TextInput::password` in `tour` --- examples/tour.rs | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) (limited to 'examples') diff --git a/examples/tour.rs b/examples/tour.rs index b06fbc37..77ed21ab 100644 --- a/examples/tour.rs +++ b/examples/tour.rs @@ -140,6 +140,7 @@ impl Steps { Step::Scrollable, Step::TextInput { value: String::new(), + is_secure: false, state: text_input::State::new(), }, Step::Debugger, @@ -210,6 +211,7 @@ enum Step { Scrollable, TextInput { value: String, + is_secure: bool, state: text_input::State, }, Debugger, @@ -226,6 +228,7 @@ pub enum StepMessage { LanguageSelected(Language), ImageWidthChanged(f32), InputChanged(String), + ToggleSecureInput(bool), DebugToggled(bool), } @@ -277,6 +280,12 @@ impl<'a> Step { *value = new_value; } } + + StepMessage::ToggleSecureInput(toggle) => { + if let Step::TextInput { is_secure, .. } = self { + *is_secure = toggle; + } + } }; } @@ -328,7 +337,11 @@ impl<'a> Step { spacing, } => Self::rows_and_columns(*layout, spacing_slider, *spacing), Step::Scrollable => Self::scrollable(), - Step::TextInput { value, state } => Self::text_input(value, state), + Step::TextInput { + value, + is_secure, + state, + } => Self::text_input(value, *is_secure, state), Step::Debugger => Self::debugger(debug), Step::End => Self::end(), } @@ -582,22 +595,31 @@ impl<'a> Step { fn text_input( value: &str, + is_secure: bool, state: &'a mut text_input::State, ) -> Column<'a, StepMessage> { + let text_input = TextInput::new( + state, + "Type something to continue...", + value, + StepMessage::InputChanged, + ) + .padding(10) + .size(30); Self::container("Text input") .push(Text::new( "Use a text input to ask for different kinds of information.", )) - .push( - TextInput::new( - state, - "Type something to continue...", - value, - StepMessage::InputChanged, - ) - .padding(10) - .size(30), - ) + .push(if is_secure { + text_input.password() + } else { + text_input + }) + .push(Checkbox::new( + is_secure, + "Enable password mode", + StepMessage::ToggleSecureInput, + )) .push(Text::new( "A text input produces a message every time it changes. It is \ very easy to keep track of its contents:", -- cgit From f5d316490898d4a5a27d9f5f9bb68796f5278c70 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 7 Dec 2019 07:46:31 +0100 Subject: Simplify `custom_widget` example --- examples/custom_widget.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'examples') diff --git a/examples/custom_widget.rs b/examples/custom_widget.rs index d51753e2..cf2f7792 100644 --- a/examples/custom_widget.rs +++ b/examples/custom_widget.rs @@ -37,14 +37,12 @@ mod circle { fn layout( &self, _renderer: &Renderer, - limits: &layout::Limits, + _limits: &layout::Limits, ) -> layout::Node { - let size = limits - .width(Length::Units(self.radius * 2)) - .height(Length::Units(self.radius * 2)) - .resolve(Size::ZERO); - - layout::Node::new(size) + layout::Node::new(Size::new( + f32::from(self.radius) * 2.0, + f32::from(self.radius) * 2.0, + )) } fn hash_layout(&self, state: &mut Hasher) { @@ -59,11 +57,9 @@ mod circle { layout: Layout<'_>, _cursor_position: Point, ) -> (Primitive, MouseCursor) { - let bounds = layout.bounds(); - ( Primitive::Quad { - bounds, + bounds: layout.bounds(), background: Background::Color(Color::BLACK), border_radius: self.radius, }, -- cgit From a7694e0112d45cffa0d25e3f19fc0289c3804c47 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sun, 8 Dec 2019 06:24:47 +0100 Subject: Update native `CHANGELOG` --- examples/tour.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'examples') diff --git a/examples/tour.rs b/examples/tour.rs index 77ed21ab..da05b396 100644 --- a/examples/tour.rs +++ b/examples/tour.rs @@ -280,7 +280,6 @@ impl<'a> Step { *value = new_value; } } - StepMessage::ToggleSecureInput(toggle) => { if let Step::TextInput { is_secure, .. } = self { *is_secure = toggle; -- cgit