From dd5edbc6ee791c7c4323ff4f02c21bc470d0a537 Mon Sep 17 00:00:00 2001 From: hatoo Date: Wed, 8 Jan 2020 23:42:42 +0900 Subject: Rename filename --- examples/bezier_tool.rs | 311 ++++++++++++++++++++++++++++++++++++++++++++++++ examples/paint.rs | 311 ------------------------------------------------ 2 files changed, 311 insertions(+), 311 deletions(-) create mode 100644 examples/bezier_tool.rs delete mode 100644 examples/paint.rs diff --git a/examples/bezier_tool.rs b/examples/bezier_tool.rs new file mode 100644 index 00000000..6f99ebe2 --- /dev/null +++ b/examples/bezier_tool.rs @@ -0,0 +1,311 @@ +//! This example showcases a simple native custom widget that renders arbitrary +//! path with `lyon`. +mod bezier { + // 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::{ + input, layout, Clipboard, Element, Event, Hasher, Layout, Length, + MouseCursor, Point, Size, Vector, Widget, + }; + use iced_wgpu::{ + triangle::{Mesh2D, Vertex2D}, + Primitive, Renderer, + }; + use lyon::tessellation::{ + basic_shapes, BuffersBuilder, StrokeAttributes, StrokeOptions, + StrokeTessellator, VertexBuffers, + }; + use std::sync::Arc; + + pub struct Bezier<'a, Message> { + pending_points: &'a [Point], + // [from, to, ctrl] + bezier_points: &'a [[Point; 3]], + on_click: Box Message>, + } + + impl<'a, Message> Bezier<'a, Message> { + pub fn new( + bezier_points: &'a [[Point; 3]], + pending_points: &'a [Point], + on_click: F, + ) -> Self + where + F: 'static + Fn(Point) -> Message, + { + assert!(pending_points.len() < 3); + + Self { + bezier_points, + pending_points, + on_click: Box::new(on_click), + } + } + } + + impl<'a, Message> Widget for Bezier<'a, Message> { + fn width(&self) -> Length { + Length::Fill + } + + fn height(&self) -> Length { + Length::Fill + } + + fn layout( + &self, + _renderer: &Renderer, + limits: &layout::Limits, + ) -> layout::Node { + let size = limits + .height(Length::Fill) + .width(Length::Fill) + .resolve(Size::ZERO); + layout::Node::new(size) + } + + fn draw( + &self, + _renderer: &mut Renderer, + layout: Layout<'_>, + cursor_position: Point, + ) -> (Primitive, MouseCursor) { + let mut buffer: VertexBuffers = VertexBuffers::new(); + let mut path_builder = lyon::path::Path::builder(); + + let bounds = layout.bounds(); + + // Draw rectangle border with lyon. + basic_shapes::stroke_rectangle( + &lyon::math::Rect::new( + lyon::math::Point::new(bounds.x + 0.5, bounds.y + 0.5), + lyon::math::Size::new( + bounds.width - 1.0, + bounds.height - 1.0, + ), + ), + &StrokeOptions::default().with_line_width(1.0), + &mut BuffersBuilder::new( + &mut buffer, + |pos: lyon::math::Point, _: StrokeAttributes| Vertex2D { + position: pos.to_array(), + color: [0.0, 0.0, 0.0, 1.0], + }, + ), + ) + .unwrap(); + + for pts in self.bezier_points { + path_builder.move_to(lyon::math::Point::new( + pts[0].x + bounds.x, + pts[0].y + bounds.y, + )); + + path_builder.quadratic_bezier_to( + lyon::math::Point::new( + pts[2].x + bounds.x, + pts[2].y + bounds.y, + ), + lyon::math::Point::new( + pts[1].x + bounds.x, + pts[1].y + bounds.y, + ), + ); + } + + match self.pending_points.len() { + 0 => {} + 1 => { + path_builder.move_to(lyon::math::Point::new( + self.pending_points[0].x + bounds.x, + self.pending_points[0].y + bounds.y, + )); + path_builder.line_to(lyon::math::Point::new( + cursor_position.x, + cursor_position.y, + )); + } + 2 => { + path_builder.move_to(lyon::math::Point::new( + self.pending_points[0].x + bounds.x, + self.pending_points[0].y + bounds.y, + )); + path_builder.quadratic_bezier_to( + lyon::math::Point::new( + cursor_position.x, + cursor_position.y, + ), + lyon::math::Point::new( + self.pending_points[1].x + bounds.x, + self.pending_points[1].y + bounds.y, + ), + ); + } + _ => { + unreachable!(); + } + } + + let mut tessellator = StrokeTessellator::new(); + + // Draw strokes with lyon. + tessellator + .tessellate( + &path_builder.build(), + &StrokeOptions::default().with_line_width(3.0), + &mut BuffersBuilder::new( + &mut buffer, + |pos: lyon::math::Point, _: StrokeAttributes| { + Vertex2D { + position: pos.to_array(), + color: [0.0, 0.0, 0.0, 1.0], + } + }, + ), + ) + .unwrap(); + + ( + Primitive::Clip { + bounds, + offset: Vector::new(0, 0), + content: Box::new(Primitive::Mesh2D(Arc::new(Mesh2D { + vertices: buffer.vertices, + indices: buffer.indices, + }))), + }, + MouseCursor::OutOfBounds, + ) + } + + fn hash_layout(&self, _state: &mut Hasher) {} + + fn on_event( + &mut self, + event: Event, + layout: Layout<'_>, + cursor_position: Point, + messages: &mut Vec, + _renderer: &Renderer, + _clipboard: Option<&dyn Clipboard>, + ) { + let bounds = layout.bounds(); + match event { + Event::Mouse(input::mouse::Event::Input { state, .. }) => { + if state == input::ButtonState::Pressed + && bounds.contains(cursor_position) + { + messages.push((self.on_click)(Point::new( + cursor_position.x - bounds.x, + cursor_position.y - bounds.y, + ))); + } + } + _ => {} + } + } + } + + impl<'a, Message> Into> for Bezier<'a, Message> + where + Message: 'static, + { + fn into(self) -> Element<'a, Message, Renderer> { + Element::new(self) + } + } +} + +use bezier::Bezier; +use iced::{ + button, Align, Button, Color, Column, Container, Element, Length, Sandbox, + Settings, Text, +}; +use iced_native::Point; + +pub fn main() { + Example::run(Settings::default()) +} + +#[derive(Default)] +struct Example { + bezier_points: Vec<[Point; 3]>, + pending_points: Vec, + button_state: button::State, +} + +#[derive(Debug, Clone, Copy)] +enum Message { + AddPoint(Point), + Clear, +} + +impl Sandbox for Example { + type Message = Message; + + fn new() -> Self { + Example::default() + } + + fn title(&self) -> String { + String::from("Bezier tool - Iced") + } + + fn update(&mut self, message: Message) { + match message { + Message::AddPoint(point) => { + self.pending_points.push(point); + if self.pending_points.len() == 3 { + self.bezier_points.push([ + self.pending_points[0], + self.pending_points[1], + self.pending_points[2], + ]); + self.pending_points.clear(); + } + } + Message::Clear => { + self.bezier_points.clear(); + self.pending_points.clear(); + } + } + } + + fn view(&mut self) -> Element { + let content = Column::new() + .padding(20) + .spacing(20) + .align_items(Align::Center) + .push( + Text::new("Bezier tool example") + .width(Length::Shrink) + .size(50), + ) + .push(Bezier::new( + self.bezier_points.as_slice(), + self.pending_points.as_slice(), + Message::AddPoint, + )) + .push( + Button::new(&mut self.button_state, Text::new("Clear")) + .padding(8) + .background(Color::from_rgb(0.5, 0.5, 0.5)) + .border_radius(4) + .on_press(Message::Clear), + ); + + Container::new(content) + .width(Length::Fill) + .height(Length::Fill) + .center_x() + .center_y() + .into() + } +} diff --git a/examples/paint.rs b/examples/paint.rs deleted file mode 100644 index 6f99ebe2..00000000 --- a/examples/paint.rs +++ /dev/null @@ -1,311 +0,0 @@ -//! This example showcases a simple native custom widget that renders arbitrary -//! path with `lyon`. -mod bezier { - // 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::{ - input, layout, Clipboard, Element, Event, Hasher, Layout, Length, - MouseCursor, Point, Size, Vector, Widget, - }; - use iced_wgpu::{ - triangle::{Mesh2D, Vertex2D}, - Primitive, Renderer, - }; - use lyon::tessellation::{ - basic_shapes, BuffersBuilder, StrokeAttributes, StrokeOptions, - StrokeTessellator, VertexBuffers, - }; - use std::sync::Arc; - - pub struct Bezier<'a, Message> { - pending_points: &'a [Point], - // [from, to, ctrl] - bezier_points: &'a [[Point; 3]], - on_click: Box Message>, - } - - impl<'a, Message> Bezier<'a, Message> { - pub fn new( - bezier_points: &'a [[Point; 3]], - pending_points: &'a [Point], - on_click: F, - ) -> Self - where - F: 'static + Fn(Point) -> Message, - { - assert!(pending_points.len() < 3); - - Self { - bezier_points, - pending_points, - on_click: Box::new(on_click), - } - } - } - - impl<'a, Message> Widget for Bezier<'a, Message> { - fn width(&self) -> Length { - Length::Fill - } - - fn height(&self) -> Length { - Length::Fill - } - - fn layout( - &self, - _renderer: &Renderer, - limits: &layout::Limits, - ) -> layout::Node { - let size = limits - .height(Length::Fill) - .width(Length::Fill) - .resolve(Size::ZERO); - layout::Node::new(size) - } - - fn draw( - &self, - _renderer: &mut Renderer, - layout: Layout<'_>, - cursor_position: Point, - ) -> (Primitive, MouseCursor) { - let mut buffer: VertexBuffers = VertexBuffers::new(); - let mut path_builder = lyon::path::Path::builder(); - - let bounds = layout.bounds(); - - // Draw rectangle border with lyon. - basic_shapes::stroke_rectangle( - &lyon::math::Rect::new( - lyon::math::Point::new(bounds.x + 0.5, bounds.y + 0.5), - lyon::math::Size::new( - bounds.width - 1.0, - bounds.height - 1.0, - ), - ), - &StrokeOptions::default().with_line_width(1.0), - &mut BuffersBuilder::new( - &mut buffer, - |pos: lyon::math::Point, _: StrokeAttributes| Vertex2D { - position: pos.to_array(), - color: [0.0, 0.0, 0.0, 1.0], - }, - ), - ) - .unwrap(); - - for pts in self.bezier_points { - path_builder.move_to(lyon::math::Point::new( - pts[0].x + bounds.x, - pts[0].y + bounds.y, - )); - - path_builder.quadratic_bezier_to( - lyon::math::Point::new( - pts[2].x + bounds.x, - pts[2].y + bounds.y, - ), - lyon::math::Point::new( - pts[1].x + bounds.x, - pts[1].y + bounds.y, - ), - ); - } - - match self.pending_points.len() { - 0 => {} - 1 => { - path_builder.move_to(lyon::math::Point::new( - self.pending_points[0].x + bounds.x, - self.pending_points[0].y + bounds.y, - )); - path_builder.line_to(lyon::math::Point::new( - cursor_position.x, - cursor_position.y, - )); - } - 2 => { - path_builder.move_to(lyon::math::Point::new( - self.pending_points[0].x + bounds.x, - self.pending_points[0].y + bounds.y, - )); - path_builder.quadratic_bezier_to( - lyon::math::Point::new( - cursor_position.x, - cursor_position.y, - ), - lyon::math::Point::new( - self.pending_points[1].x + bounds.x, - self.pending_points[1].y + bounds.y, - ), - ); - } - _ => { - unreachable!(); - } - } - - let mut tessellator = StrokeTessellator::new(); - - // Draw strokes with lyon. - tessellator - .tessellate( - &path_builder.build(), - &StrokeOptions::default().with_line_width(3.0), - &mut BuffersBuilder::new( - &mut buffer, - |pos: lyon::math::Point, _: StrokeAttributes| { - Vertex2D { - position: pos.to_array(), - color: [0.0, 0.0, 0.0, 1.0], - } - }, - ), - ) - .unwrap(); - - ( - Primitive::Clip { - bounds, - offset: Vector::new(0, 0), - content: Box::new(Primitive::Mesh2D(Arc::new(Mesh2D { - vertices: buffer.vertices, - indices: buffer.indices, - }))), - }, - MouseCursor::OutOfBounds, - ) - } - - fn hash_layout(&self, _state: &mut Hasher) {} - - fn on_event( - &mut self, - event: Event, - layout: Layout<'_>, - cursor_position: Point, - messages: &mut Vec, - _renderer: &Renderer, - _clipboard: Option<&dyn Clipboard>, - ) { - let bounds = layout.bounds(); - match event { - Event::Mouse(input::mouse::Event::Input { state, .. }) => { - if state == input::ButtonState::Pressed - && bounds.contains(cursor_position) - { - messages.push((self.on_click)(Point::new( - cursor_position.x - bounds.x, - cursor_position.y - bounds.y, - ))); - } - } - _ => {} - } - } - } - - impl<'a, Message> Into> for Bezier<'a, Message> - where - Message: 'static, - { - fn into(self) -> Element<'a, Message, Renderer> { - Element::new(self) - } - } -} - -use bezier::Bezier; -use iced::{ - button, Align, Button, Color, Column, Container, Element, Length, Sandbox, - Settings, Text, -}; -use iced_native::Point; - -pub fn main() { - Example::run(Settings::default()) -} - -#[derive(Default)] -struct Example { - bezier_points: Vec<[Point; 3]>, - pending_points: Vec, - button_state: button::State, -} - -#[derive(Debug, Clone, Copy)] -enum Message { - AddPoint(Point), - Clear, -} - -impl Sandbox for Example { - type Message = Message; - - fn new() -> Self { - Example::default() - } - - fn title(&self) -> String { - String::from("Bezier tool - Iced") - } - - fn update(&mut self, message: Message) { - match message { - Message::AddPoint(point) => { - self.pending_points.push(point); - if self.pending_points.len() == 3 { - self.bezier_points.push([ - self.pending_points[0], - self.pending_points[1], - self.pending_points[2], - ]); - self.pending_points.clear(); - } - } - Message::Clear => { - self.bezier_points.clear(); - self.pending_points.clear(); - } - } - } - - fn view(&mut self) -> Element { - let content = Column::new() - .padding(20) - .spacing(20) - .align_items(Align::Center) - .push( - Text::new("Bezier tool example") - .width(Length::Shrink) - .size(50), - ) - .push(Bezier::new( - self.bezier_points.as_slice(), - self.pending_points.as_slice(), - Message::AddPoint, - )) - .push( - Button::new(&mut self.button_state, Text::new("Clear")) - .padding(8) - .background(Color::from_rgb(0.5, 0.5, 0.5)) - .border_radius(4) - .on_press(Message::Clear), - ); - - Container::new(content) - .width(Length::Fill) - .height(Length::Fill) - .center_x() - .center_y() - .into() - } -} -- cgit