diff options
Diffstat (limited to 'examples/tour')
| -rw-r--r-- | examples/tour/Cargo.toml | 23 | ||||
| -rw-r--r-- | examples/tour/src/iced_ggez.rs | 6 | ||||
| -rw-r--r-- | examples/tour/src/iced_ggez/renderer.rs | 77 | ||||
| -rw-r--r-- | examples/tour/src/iced_ggez/renderer/button.rs | 154 | ||||
| -rw-r--r-- | examples/tour/src/iced_ggez/renderer/checkbox.rs | 94 | ||||
| -rw-r--r-- | examples/tour/src/iced_ggez/renderer/debugger.rs | 32 | ||||
| -rw-r--r-- | examples/tour/src/iced_ggez/renderer/image.rs | 76 | ||||
| -rw-r--r-- | examples/tour/src/iced_ggez/renderer/radio.rs | 92 | ||||
| -rw-r--r-- | examples/tour/src/iced_ggez/renderer/slider.rs | 93 | ||||
| -rw-r--r-- | examples/tour/src/iced_ggez/renderer/text.rs | 110 | ||||
| -rw-r--r-- | examples/tour/src/iced_ggez/widget.rs | 12 | ||||
| -rw-r--r-- | examples/tour/src/lib.rs | 11 | ||||
| -rw-r--r-- | examples/tour/src/main.rs | 712 | ||||
| -rw-r--r-- | examples/tour/src/tour.rs | 563 | ||||
| -rw-r--r-- | examples/tour/src/web.rs | 33 | ||||
| -rw-r--r-- | examples/tour/src/widget.rs | 5 | 
16 files changed, 548 insertions, 1545 deletions
| diff --git a/examples/tour/Cargo.toml b/examples/tour/Cargo.toml index 2c79cbf7..8b3d7765 100644 --- a/examples/tour/Cargo.toml +++ b/examples/tour/Cargo.toml @@ -8,26 +8,5 @@ repository = "https://github.com/hecrj/iced"  edition = "2018"  publish = false -[lib] -crate-type = ["cdylib", "rlib"] - -[[bin]] -name = "main" -path = "src/main.rs" -  [dependencies] -futures-preview = "=0.3.0-alpha.18" - -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] -iced_native = { version = "0.1.0-alpha", path = "../../native" } -# A personal `ggez` fork that introduces a `FontCache` type to measure text -# efficiently and fixes HiDPI issues. -ggez = { version = "0.5", git = "https://github.com/hecrj/ggez.git" } -env_logger = "0.6" - -[target.'cfg(target_arch = "wasm32")'.dependencies] -iced_web = { path = "../../web" } -wasm-bindgen = "0.2.50" -log = "0.4" -console_error_panic_hook = "0.1.6" -console_log = "0.1.2" +iced = { version = "0.1.0-alpha.1", path = "../.." } diff --git a/examples/tour/src/iced_ggez.rs b/examples/tour/src/iced_ggez.rs deleted file mode 100644 index 4a9c0ef4..00000000 --- a/examples/tour/src/iced_ggez.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod renderer; -mod widget; - -pub use renderer::Cache as ImageCache; -pub use renderer::Renderer; -pub use widget::*; diff --git a/examples/tour/src/iced_ggez/renderer.rs b/examples/tour/src/iced_ggez/renderer.rs deleted file mode 100644 index c0e6d559..00000000 --- a/examples/tour/src/iced_ggez/renderer.rs +++ /dev/null @@ -1,77 +0,0 @@ -mod button; -mod checkbox; -mod debugger; -mod image; -mod radio; -mod slider; -mod text; - -use ggez::graphics::{ -    self, spritebatch::SpriteBatch, Font, Image, MeshBuilder, -}; -use ggez::Context; - -pub use image::Cache; - -pub struct Renderer<'a> { -    pub context: &'a mut Context, -    pub images: &'a mut image::Cache, -    pub sprites: SpriteBatch, -    pub spritesheet: Image, -    pub font: Font, -    font_size: f32, -    debug_mesh: Option<MeshBuilder>, -} - -impl<'a> Renderer<'a> { -    pub fn new( -        context: &'a mut Context, -        images: &'a mut image::Cache, -        spritesheet: Image, -        font: Font, -    ) -> Renderer<'a> { -        Renderer { -            context, -            images, -            sprites: SpriteBatch::new(spritesheet.clone()), -            spritesheet, -            font, -            font_size: 20.0, -            debug_mesh: None, -        } -    } - -    pub fn flush(&mut self) { -        graphics::draw( -            self.context, -            &self.sprites, -            graphics::DrawParam::default(), -        ) -        .expect("Draw sprites"); - -        graphics::draw_queued_text( -            self.context, -            graphics::DrawParam::default(), -            Default::default(), -            graphics::FilterMode::Linear, -        ) -        .expect("Draw text"); - -        if let Some(debug_mesh) = self.debug_mesh.take() { -            let mesh = -                debug_mesh.build(self.context).expect("Build debug mesh"); - -            graphics::draw(self.context, &mesh, graphics::DrawParam::default()) -                .expect("Draw debug mesh"); -        } -    } -} - -pub fn into_color(color: iced_native::Color) -> graphics::Color { -    graphics::Color { -        r: color.r, -        g: color.g, -        b: color.b, -        a: color.a, -    } -} diff --git a/examples/tour/src/iced_ggez/renderer/button.rs b/examples/tour/src/iced_ggez/renderer/button.rs deleted file mode 100644 index 78a5de07..00000000 --- a/examples/tour/src/iced_ggez/renderer/button.rs +++ /dev/null @@ -1,154 +0,0 @@ -use super::Renderer; -use ggez::graphics::{ -    self, Align, Color, DrawParam, Rect, Scale, Text, TextFragment, WHITE, -}; -use iced_native::{button, Button, Layout, Length, MouseCursor, Node, Style}; - -const LEFT: Rect = Rect { -    x: 0.0, -    y: 34.0, -    w: 6.0, -    h: 49.0, -}; - -const BACKGROUND: Rect = Rect { -    x: LEFT.w, -    y: LEFT.y, -    w: 1.0, -    h: LEFT.h, -}; - -const RIGHT: Rect = Rect { -    x: LEFT.h - LEFT.w, -    y: LEFT.y, -    w: LEFT.w, -    h: LEFT.h, -}; - -impl button::Renderer for Renderer<'_> { -    fn node<Message>(&self, button: &Button<'_, Message>) -> Node { -        let style = Style::default() -            .width(button.width) -            .height(Length::Units(LEFT.h as u16)) -            .min_width(Length::Units(100)) -            .align_self(button.align_self); - -        Node::new(style) -    } - -    fn draw<Message>( -        &mut self, -        button: &Button<'_, Message>, -        layout: Layout<'_>, -        cursor_position: iced_native::Point, -    ) -> MouseCursor { -        let mut bounds = layout.bounds(); -        let mouse_over = bounds.contains(cursor_position); - -        let mut state_offset = 0.0; - -        if mouse_over { -            if button.state.is_pressed() { -                bounds.y += 4.0; -                state_offset = RIGHT.x + RIGHT.w; -            } else { -                bounds.y -= 1.0; -            } -        } - -        let class_index = match button.class { -            button::Class::Primary => 0, -            button::Class::Secondary => 1, -            button::Class::Positive => 2, -        }; - -        let width = self.spritesheet.width() as f32; -        let height = self.spritesheet.height() as f32; - -        self.sprites.add(DrawParam { -            src: Rect { -                x: (LEFT.x + state_offset) / width, -                y: (LEFT.y + class_index as f32 * LEFT.h) / height, -                w: LEFT.w / width, -                h: LEFT.h / height, -            }, -            dest: ggez::mint::Point2 { -                x: bounds.x, -                y: bounds.y, -            }, -            ..DrawParam::default() -        }); - -        self.sprites.add(DrawParam { -            src: Rect { -                x: (BACKGROUND.x + state_offset) / width, -                y: (BACKGROUND.y + class_index as f32 * BACKGROUND.h) / height, -                w: BACKGROUND.w / width, -                h: BACKGROUND.h / height, -            }, -            dest: ggez::mint::Point2 { -                x: bounds.x + LEFT.w, -                y: bounds.y, -            }, -            scale: ggez::mint::Vector2 { -                x: bounds.width - LEFT.w - RIGHT.w, -                y: 1.0, -            }, -            ..DrawParam::default() -        }); - -        self.sprites.add(DrawParam { -            src: Rect { -                x: (RIGHT.x + state_offset) / width, -                y: (RIGHT.y + class_index as f32 * RIGHT.h) / height, -                w: RIGHT.w / width, -                h: RIGHT.h / height, -            }, -            dest: ggez::mint::Point2 { -                x: bounds.x + bounds.width - RIGHT.w, -                y: bounds.y, -            }, -            ..DrawParam::default() -        }); - -        let mut text = Text::new(TextFragment { -            text: button.label.clone(), -            font: Some(self.font), -            scale: Some(Scale { x: 20.0, y: 20.0 }), -            ..Default::default() -        }); - -        text.set_bounds( -            ggez::mint::Point2 { -                x: bounds.width, -                y: bounds.height, -            }, -            Align::Center, -        ); - -        graphics::queue_text( -            self.context, -            &text, -            ggez::mint::Point2 { -                x: bounds.x, -                y: bounds.y + BACKGROUND.h / 4.0, -            }, -            Some(if mouse_over { -                WHITE -            } else { -                Color { -                    r: 0.9, -                    g: 0.9, -                    b: 0.9, -                    a: 1.0, -                } -            }), -        ); - -        if mouse_over { -            MouseCursor::Pointer -        } else { -            MouseCursor::OutOfBounds -        } -    } -} diff --git a/examples/tour/src/iced_ggez/renderer/checkbox.rs b/examples/tour/src/iced_ggez/renderer/checkbox.rs deleted file mode 100644 index 807185d9..00000000 --- a/examples/tour/src/iced_ggez/renderer/checkbox.rs +++ /dev/null @@ -1,94 +0,0 @@ -use super::Renderer; - -use ggez::graphics::{DrawParam, Rect}; -use iced_native::{ -    checkbox, text, Align, Checkbox, Column, Layout, Length, MouseCursor, Node, -    Row, Text, Widget, -}; - -const SPRITE: Rect = Rect { -    x: 98.0, -    y: 0.0, -    w: 28.0, -    h: 28.0, -}; - -impl checkbox::Renderer for Renderer<'_> -where -    Self: text::Renderer, -{ -    fn node<Message>(&mut self, checkbox: &Checkbox<Message>) -> Node { -        Row::<(), Self>::new() -            .spacing(15) -            .align_items(Align::Center) -            .push( -                Column::new() -                    .width(Length::Units(SPRITE.w as u16)) -                    .height(Length::Units(SPRITE.h as u16)), -            ) -            .push(Text::new(&checkbox.label)) -            .node(self) -    } - -    fn draw<Message>( -        &mut self, -        checkbox: &Checkbox<Message>, -        layout: Layout<'_>, -        cursor_position: iced_native::Point, -    ) -> MouseCursor { -        let bounds = layout.bounds(); -        let children: Vec<_> = layout.children().collect(); -        let text_bounds = children[1].bounds(); - -        let mut text = Text::new(&checkbox.label); - -        if let Some(label_color) = checkbox.label_color { -            text = text.color(label_color); -        } - -        text::Renderer::draw(self, &text, children[1]); - -        let mouse_over = bounds.contains(cursor_position) -            || text_bounds.contains(cursor_position); - -        let width = self.spritesheet.width() as f32; -        let height = self.spritesheet.height() as f32; - -        self.sprites.add(DrawParam { -            src: Rect { -                x: (SPRITE.x + (if mouse_over { SPRITE.w } else { 0.0 })) -                    / width, -                y: SPRITE.y / height, -                w: SPRITE.w / width, -                h: SPRITE.h / height, -            }, -            dest: ggez::mint::Point2 { -                x: bounds.x, -                y: bounds.y, -            }, -            ..DrawParam::default() -        }); - -        if checkbox.is_checked { -            self.sprites.add(DrawParam { -                src: Rect { -                    x: (SPRITE.x + SPRITE.w * 2.0) / width, -                    y: SPRITE.y / height, -                    w: SPRITE.w / width, -                    h: SPRITE.h / height, -                }, -                dest: ggez::mint::Point2 { -                    x: bounds.x, -                    y: bounds.y, -                }, -                ..DrawParam::default() -            }); -        } - -        if mouse_over { -            MouseCursor::Pointer -        } else { -            MouseCursor::OutOfBounds -        } -    } -} diff --git a/examples/tour/src/iced_ggez/renderer/debugger.rs b/examples/tour/src/iced_ggez/renderer/debugger.rs deleted file mode 100644 index ffb658af..00000000 --- a/examples/tour/src/iced_ggez/renderer/debugger.rs +++ /dev/null @@ -1,32 +0,0 @@ -use super::{into_color, Renderer}; -use ggez::graphics::{DrawMode, MeshBuilder, Rect}; - -impl iced_native::renderer::Debugger for Renderer<'_> { -    fn explain( -        &mut self, -        layout: &iced_native::Layout<'_>, -        color: iced_native::Color, -    ) { -        let bounds = layout.bounds(); - -        let mut debug_mesh = -            self.debug_mesh.take().unwrap_or(MeshBuilder::new()); - -        debug_mesh.rectangle( -            DrawMode::stroke(1.0), -            Rect { -                x: bounds.x, -                y: bounds.y, -                w: bounds.width, -                h: bounds.height, -            }, -            into_color(color), -        ); - -        self.debug_mesh = Some(debug_mesh); - -        for child in layout.children() { -            self.explain(&child, color); -        } -    } -} diff --git a/examples/tour/src/iced_ggez/renderer/image.rs b/examples/tour/src/iced_ggez/renderer/image.rs deleted file mode 100644 index b12b65c3..00000000 --- a/examples/tour/src/iced_ggez/renderer/image.rs +++ /dev/null @@ -1,76 +0,0 @@ -use super::Renderer; - -use ggez::{graphics, nalgebra}; -use iced_native::{image, Image, Layout, Length, Style}; - -pub struct Cache { -    images: std::collections::HashMap<String, graphics::Image>, -} - -impl Cache { -    pub fn new() -> Self { -        Self { -            images: std::collections::HashMap::new(), -        } -    } - -    fn get<'a>( -        &mut self, -        name: &'a str, -        context: &mut ggez::Context, -    ) -> graphics::Image { -        if let Some(image) = self.images.get(name) { -            return image.clone(); -        } - -        let mut image = graphics::Image::new(context, &format!("/{}", name)) -            .expect("Load ferris image"); - -        image.set_filter(graphics::FilterMode::Linear); - -        self.images.insert(name.to_string(), image.clone()); - -        image -    } -} - -impl<'a> image::Renderer<&'a str> for Renderer<'_> { -    fn node(&mut self, image: &Image<&'a str>) -> iced_native::Node { -        let ggez_image = self.images.get(image.handle, self.context); - -        let aspect_ratio = -            ggez_image.width() as f32 / ggez_image.height() as f32; - -        let mut style = Style::default().align_self(image.align_self); - -        style = match (image.width, image.height) { -            (Length::Units(width), _) => style.width(image.width).height( -                Length::Units((width as f32 / aspect_ratio).round() as u16), -            ), -            (_, _) => style -                .width(Length::Units(ggez_image.width())) -                .height(Length::Units(ggez_image.height())), -        }; - -        iced_native::Node::new(style) -    } - -    fn draw(&mut self, image: &Image<&'a str>, layout: Layout<'_>) { -        let image = self.images.get(image.handle, self.context); -        let bounds = layout.bounds(); - -        // We should probably use batches to draw images efficiently and keep -        // draw side-effect free, but this is good enough for the example. -        graphics::draw( -            self.context, -            &image, -            graphics::DrawParam::new() -                .dest(nalgebra::Point2::new(bounds.x, bounds.y)) -                .scale(nalgebra::Vector2::new( -                    bounds.width / image.width() as f32, -                    bounds.height / image.height() as f32, -                )), -        ) -        .expect("Draw image"); -    } -} diff --git a/examples/tour/src/iced_ggez/renderer/radio.rs b/examples/tour/src/iced_ggez/renderer/radio.rs deleted file mode 100644 index dbd29ecd..00000000 --- a/examples/tour/src/iced_ggez/renderer/radio.rs +++ /dev/null @@ -1,92 +0,0 @@ -use super::Renderer; - -use ggez::graphics::{DrawParam, Rect}; -use iced_native::{ -    radio, text, Align, Column, Layout, Length, MouseCursor, Node, Point, -    Radio, Row, Text, Widget, -}; - -const SPRITE: Rect = Rect { -    x: 98.0, -    y: 28.0, -    w: 28.0, -    h: 28.0, -}; - -impl radio::Renderer for Renderer<'_> -where -    Self: text::Renderer, -{ -    fn node<Message>(&mut self, radio: &Radio<Message>) -> Node { -        Row::<(), Self>::new() -            .spacing(15) -            .align_items(Align::Center) -            .push( -                Column::new() -                    .width(Length::Units(SPRITE.w as u16)) -                    .height(Length::Units(SPRITE.h as u16)), -            ) -            .push(Text::new(&radio.label)) -            .node(self) -    } - -    fn draw<Message>( -        &mut self, -        radio: &Radio<Message>, -        layout: Layout<'_>, -        cursor_position: Point, -    ) -> MouseCursor { -        let children: Vec<_> = layout.children().collect(); - -        let mut text = Text::new(&radio.label); - -        if let Some(label_color) = radio.label_color { -            text = text.color(label_color); -        } - -        text::Renderer::draw(self, &text, children[1]); - -        let bounds = layout.bounds(); -        let mouse_over = bounds.contains(cursor_position); - -        let width = self.spritesheet.width() as f32; -        let height = self.spritesheet.height() as f32; - -        self.sprites.add(DrawParam { -            src: Rect { -                x: (SPRITE.x + (if mouse_over { SPRITE.w } else { 0.0 })) -                    / width, -                y: SPRITE.y / height, -                w: SPRITE.w / width, -                h: SPRITE.h / height, -            }, -            dest: ggez::mint::Point2 { -                x: bounds.x, -                y: bounds.y, -            }, -            ..DrawParam::default() -        }); - -        if radio.is_selected { -            self.sprites.add(DrawParam { -                src: Rect { -                    x: (SPRITE.x + SPRITE.w * 2.0) / width, -                    y: SPRITE.y / height, -                    w: SPRITE.w / width, -                    h: SPRITE.h / height, -                }, -                dest: ggez::mint::Point2 { -                    x: bounds.x, -                    y: bounds.y, -                }, -                ..DrawParam::default() -            }); -        } - -        if mouse_over { -            MouseCursor::Pointer -        } else { -            MouseCursor::OutOfBounds -        } -    } -} diff --git a/examples/tour/src/iced_ggez/renderer/slider.rs b/examples/tour/src/iced_ggez/renderer/slider.rs deleted file mode 100644 index 60c40c55..00000000 --- a/examples/tour/src/iced_ggez/renderer/slider.rs +++ /dev/null @@ -1,93 +0,0 @@ -use super::Renderer; - -use ggez::graphics::{DrawParam, Rect}; -use iced_native::{ -    slider, Layout, Length, MouseCursor, Node, Point, Slider, Style, -}; - -const RAIL: Rect = Rect { -    x: 98.0, -    y: 56.0, -    w: 1.0, -    h: 4.0, -}; - -const MARKER: Rect = Rect { -    x: RAIL.x + 28.0, -    y: RAIL.y, -    w: 16.0, -    h: 24.0, -}; - -impl slider::Renderer for Renderer<'_> { -    fn node<Message>(&self, slider: &Slider<'_, Message>) -> Node { -        let style = Style::default() -            .width(slider.width) -            .height(Length::Units(25)) -            .min_width(Length::Units(100)); - -        Node::new(style) -    } - -    fn draw<Message>( -        &mut self, -        slider: &Slider<'_, Message>, -        layout: Layout<'_>, -        cursor_position: Point, -    ) -> MouseCursor { -        let bounds = layout.bounds(); -        let width = self.spritesheet.width() as f32; -        let height = self.spritesheet.height() as f32; - -        self.sprites.add(DrawParam { -            src: Rect { -                x: RAIL.x / width, -                y: RAIL.y / height, -                w: RAIL.w / width, -                h: RAIL.h / height, -            }, -            dest: ggez::mint::Point2 { -                x: bounds.x + MARKER.w as f32 / 2.0, -                y: bounds.y + 12.5, -            }, -            scale: ggez::mint::Vector2 { -                x: bounds.width - MARKER.w as f32, -                y: 1.0, -            }, -            ..DrawParam::default() -        }); - -        let (range_start, range_end) = slider.range.clone().into_inner(); - -        let marker_offset = (bounds.width - MARKER.w as f32) -            * ((slider.value - range_start) -                / (range_end - range_start).max(1.0)); - -        let mouse_over = bounds.contains(cursor_position); -        let is_active = slider.state.is_dragging() || mouse_over; - -        self.sprites.add(DrawParam { -            src: Rect { -                x: (MARKER.x + (if is_active { MARKER.w } else { 0.0 })) -                    / width, -                y: MARKER.y / height, -                w: MARKER.w / width, -                h: MARKER.h / height, -            }, -            dest: ggez::mint::Point2 { -                x: bounds.x + marker_offset.round(), -                y: bounds.y -                    + (if slider.state.is_dragging() { 2.0 } else { 0.0 }), -            }, -            ..DrawParam::default() -        }); - -        if slider.state.is_dragging() { -            MouseCursor::Grabbing -        } else if mouse_over { -            MouseCursor::Grab -        } else { -            MouseCursor::OutOfBounds -        } -    } -} diff --git a/examples/tour/src/iced_ggez/renderer/text.rs b/examples/tour/src/iced_ggez/renderer/text.rs deleted file mode 100644 index b51cc220..00000000 --- a/examples/tour/src/iced_ggez/renderer/text.rs +++ /dev/null @@ -1,110 +0,0 @@ -use super::{into_color, Renderer}; -use ggez::graphics::{self, mint, Align, Scale, Text, TextFragment}; - -use iced_native::{text, Layout, Node, Style}; -use std::cell::RefCell; -use std::f32; - -impl text::Renderer for Renderer<'_> { -    fn node(&self, text: &iced_native::Text) -> Node { -        let font = self.font; -        let font_cache = graphics::font_cache(self.context); -        let content = String::from(&text.content); - -        // TODO: Investigate why stretch tries to measure this MANY times -        // with every ancestor's bounds. -        // Bug? Using the library wrong? I should probably open an issue on -        // the stretch repository. -        // I noticed that the first measure is the one that matters in -        // practice. Here, we use a RefCell to store the cached measurement. -        let measure = RefCell::new(None); -        let size = text.size.map(f32::from).unwrap_or(self.font_size); - -        let style = Style::default().width(text.width); - -        iced_native::Node::with_measure(style, move |bounds| { -            let mut measure = measure.borrow_mut(); - -            if measure.is_none() { -                let bounds = ( -                    match bounds.width { -                        iced_native::Number::Undefined => f32::INFINITY, -                        iced_native::Number::Defined(w) => w, -                    }, -                    match bounds.height { -                        iced_native::Number::Undefined => f32::INFINITY, -                        iced_native::Number::Defined(h) => h, -                    }, -                ); - -                let mut text = Text::new(TextFragment { -                    text: content.clone(), -                    font: Some(font), -                    scale: Some(Scale { x: size, y: size }), -                    ..Default::default() -                }); - -                text.set_bounds( -                    mint::Point2 { -                        x: bounds.0, -                        y: bounds.1, -                    }, -                    Align::Left, -                ); - -                let (width, height) = font_cache.dimensions(&text); - -                let size = iced_native::Size { -                    width: width as f32, -                    height: height as f32, -                }; - -                // If the text has no width boundary we avoid caching as the -                // layout engine may just be measuring text in a row. -                if bounds.0 == f32::INFINITY { -                    return size; -                } else { -                    *measure = Some(size); -                } -            } - -            measure.unwrap() -        }) -    } - -    fn draw(&mut self, text: &iced_native::Text, layout: Layout<'_>) { -        let size = text.size.map(f32::from).unwrap_or(self.font_size); -        let bounds = layout.bounds(); - -        let mut ggez_text = Text::new(TextFragment { -            text: text.content.clone(), -            font: Some(self.font), -            scale: Some(Scale { x: size, y: size }), -            ..Default::default() -        }); - -        ggez_text.set_bounds( -            mint::Point2 { -                x: bounds.width, -                y: bounds.height, -            }, -            match text.horizontal_alignment { -                text::HorizontalAlignment::Left => graphics::Align::Left, -                text::HorizontalAlignment::Center => graphics::Align::Center, -                text::HorizontalAlignment::Right => graphics::Align::Right, -            }, -        ); - -        graphics::queue_text( -            self.context, -            &ggez_text, -            mint::Point2 { -                x: bounds.x, -                y: bounds.y, -            }, -            text.color -                .or(Some(iced_native::Color::BLACK)) -                .map(into_color), -        ); -    } -} diff --git a/examples/tour/src/iced_ggez/widget.rs b/examples/tour/src/iced_ggez/widget.rs deleted file mode 100644 index 948f9fc6..00000000 --- a/examples/tour/src/iced_ggez/widget.rs +++ /dev/null @@ -1,12 +0,0 @@ -use super::Renderer; - -pub use iced_native::{ -    button, slider, text, Align, Button, Checkbox, Color, Length, Radio, -    Slider, Text, -}; - -pub type Image<'a> = iced_native::Image<&'a str>; - -pub type Column<'a, Message> = iced_native::Column<'a, Message, Renderer<'a>>; -pub type Row<'a, Message> = iced_native::Row<'a, Message, Renderer<'a>>; -pub type Element<'a, Message> = iced_native::Element<'a, Message, Renderer<'a>>; diff --git a/examples/tour/src/lib.rs b/examples/tour/src/lib.rs deleted file mode 100644 index eb41fcd9..00000000 --- a/examples/tour/src/lib.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub mod tour; - -pub use tour::{Message, Tour}; - -mod widget; - -#[cfg(target_arch = "wasm32")] -mod web; - -#[cfg(not(target_arch = "wasm32"))] -pub mod iced_ggez; diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs index a34d3298..5017041a 100644 --- a/examples/tour/src/main.rs +++ b/examples/tour/src/main.rs @@ -1,191 +1,573 @@ -use iced_tour::{iced_ggez, Tour}; - -use ggez; -use ggez::event; -use ggez::filesystem; -use ggez::graphics; -use ggez::input::mouse; - -pub fn main() -> ggez::GameResult { -    env_logger::init(); - -    let (context, event_loop) = { -        &mut ggez::ContextBuilder::new("iced", "ggez") -            .window_mode(ggez::conf::WindowMode { -                width: 1280.0, -                height: 1024.0, -                resizable: true, -                ..ggez::conf::WindowMode::default() -            }) -            .build()? -    }; - -    filesystem::mount( -        context, -        std::path::Path::new(env!("CARGO_MANIFEST_DIR")), -        true, -    ); - -    let state = &mut Game::new(context)?; - -    event::run(context, event_loop, state) -} +use iced::{ +    button, slider, text::HorizontalAlignment, Align, Button, Checkbox, Color, +    Column, Element, Image, Length, Radio, Row, Slider, Text, UserInterface, +}; -struct Game { -    spritesheet: graphics::Image, -    font: graphics::Font, -    images: iced_ggez::ImageCache, -    tour: Tour, +pub fn main() { +    let tour = Tour::new(); -    events: Vec<iced_native::Event>, -    cache: Option<iced_native::Cache>, +    tour.run();  } -impl Game { -    fn new(context: &mut ggez::Context) -> ggez::GameResult<Game> { -        graphics::set_default_filter(context, graphics::FilterMode::Nearest); - -        Ok(Game { -            spritesheet: graphics::Image::new(context, "/resources/ui.png") -                .unwrap(), -            font: graphics::Font::new(context, "/resources/Roboto-Regular.ttf") -                .unwrap(), -            images: iced_ggez::ImageCache::new(), -            tour: Tour::new(), +pub struct Tour { +    steps: Steps, +    back_button: button::State, +    next_button: button::State, +    debug: bool, +} -            events: Vec::new(), -            cache: Some(iced_native::Cache::default()), -        }) +impl Tour { +    pub fn new() -> Tour { +        Tour { +            steps: Steps::new(), +            back_button: button::State::new(), +            next_button: button::State::new(), +            debug: false, +        }      }  } -impl event::EventHandler for Game { -    fn update(&mut self, _ctx: &mut ggez::Context) -> ggez::GameResult { -        Ok(()) -    } - -    fn mouse_button_down_event( -        &mut self, -        _context: &mut ggez::Context, -        _button: mouse::MouseButton, -        _x: f32, -        _y: f32, -    ) { -        self.events.push(iced_native::Event::Mouse( -            iced_native::input::mouse::Event::Input { -                state: iced_native::input::ButtonState::Pressed, -                button: iced_native::input::mouse::Button::Left, // TODO: Map `button` -            }, -        )); -    } - -    fn mouse_button_up_event( -        &mut self, -        _context: &mut ggez::Context, -        _button: mouse::MouseButton, -        _x: f32, -        _y: f32, -    ) { -        self.events.push(iced_native::Event::Mouse( -            iced_native::input::mouse::Event::Input { -                state: iced_native::input::ButtonState::Released, -                button: iced_native::input::mouse::Button::Left, // TODO: Map `button` -            }, -        )); -    } - -    fn mouse_motion_event( -        &mut self, -        _context: &mut ggez::Context, -        x: f32, -        y: f32, -        _dx: f32, -        _dy: f32, -    ) { -        self.events.push(iced_native::Event::Mouse( -            iced_native::input::mouse::Event::CursorMoved { x, y }, -        )); -    } - -    fn resize_event( -        &mut self, -        context: &mut ggez::Context, -        width: f32, -        height: f32, -    ) { -        graphics::set_screen_coordinates( -            context, -            graphics::Rect { -                x: 0.0, -                y: 0.0, -                w: width, -                h: height, -            }, -        ) -        .expect("Set screen coordinates"); -    } - -    fn draw(&mut self, context: &mut ggez::Context) -> ggez::GameResult { -        graphics::clear(context, graphics::WHITE); - -        let screen = graphics::screen_coordinates(context); - -        let (messages, cursor) = { -            let view = self.tour.view(); - -            let content = iced_ggez::Column::new() -                .width(iced_native::Length::Units(screen.w as u16)) -                .height(iced_native::Length::Units(screen.h as u16)) -                .padding(20) -                .align_items(iced_native::Align::Center) -                .justify_content(iced_native::Justify::Center) -                .push(view); - -            let renderer = &mut iced_ggez::Renderer::new( -                context, -                &mut self.images, -                self.spritesheet.clone(), -                self.font, +impl UserInterface for Tour { +    type Message = Message; + +    fn update(&mut self, event: Message) { +        match event { +            Message::BackPressed => { +                self.steps.go_back(); +            } +            Message::NextPressed => { +                self.steps.advance(); +            } +            Message::StepMessage(step_msg) => { +                self.steps.update(step_msg, &mut self.debug); +            } +        } +    } + +    fn view(&mut self) -> Element<Message> { +        let Tour { +            steps, +            back_button, +            next_button, +            .. +        } = self; + +        let mut controls = Row::new(); + +        if steps.has_previous() { +            controls = controls.push( +                Button::new(back_button, "Back") +                    .on_press(Message::BackPressed) +                    .class(button::Class::Secondary),              ); +        } + +        controls = controls.push(Column::new()); -            let mut ui = iced_native::UserInterface::build( -                content, -                self.cache.take().unwrap(), -                renderer, +        if steps.can_continue() { +            controls = controls.push( +                Button::new(next_button, "Next").on_press(Message::NextPressed),              ); +        } -            let messages = ui.update(self.events.drain(..)); -            let cursor = ui.draw(renderer); +        let element: Element<_> = Column::new() +            .max_width(Length::Units(500)) +            .spacing(20) +            .push(steps.view(self.debug).map(Message::StepMessage)) +            .push(controls) +            .into(); -            self.cache = Some(ui.into_cache()); +        if self.debug { +            element.explain(Color::BLACK) +        } else { +            element +        } +    } +} -            renderer.flush(); +#[derive(Debug, Clone, Copy)] +pub enum Message { +    BackPressed, +    NextPressed, +    StepMessage(StepMessage), +} -            (messages, cursor) -        }; +struct Steps { +    steps: Vec<Step>, +    current: usize, +} -        for message in messages { -            self.tour.update(message); +impl Steps { +    fn new() -> Steps { +        Steps { +            steps: vec![ +                Step::Welcome, +                Step::Slider { +                    state: slider::State::new(), +                    value: 50, +                }, +                Step::RowsAndColumns { +                    layout: Layout::Row, +                    spacing_slider: slider::State::new(), +                    spacing: 20, +                }, +                Step::Text { +                    size_slider: slider::State::new(), +                    size: 30, +                    color_sliders: [slider::State::new(); 3], +                    color: Color::BLACK, +                }, +                Step::Radio { selection: None }, +                Step::Image { +                    width: 300, +                    slider: slider::State::new(), +                }, +                Step::Debugger, +                Step::End, +            ], +            current: 0,          } +    } -        let cursor_type = into_cursor_type(cursor); +    fn update(&mut self, msg: StepMessage, debug: &mut bool) { +        self.steps[self.current].update(msg, debug); +    } + +    fn view(&mut self, debug: bool) -> Element<StepMessage> { +        self.steps[self.current].view(debug) +    } + +    fn advance(&mut self) { +        if self.can_continue() { +            self.current += 1; +        } +    } -        if mouse::cursor_type(context) != cursor_type { -            mouse::set_cursor_type(context, cursor_type); +    fn go_back(&mut self) { +        if self.has_previous() { +            self.current -= 1;          } +    } -        graphics::present(context)?; -        Ok(()) +    fn has_previous(&self) -> bool { +        self.current > 0      } + +    fn can_continue(&self) -> bool { +        self.current + 1 < self.steps.len() +            && self.steps[self.current].can_continue() +    } +} + +enum Step { +    Welcome, +    Slider { +        state: slider::State, +        value: u16, +    }, +    RowsAndColumns { +        layout: Layout, +        spacing_slider: slider::State, +        spacing: u16, +    }, +    Text { +        size_slider: slider::State, +        size: u16, +        color_sliders: [slider::State; 3], +        color: Color, +    }, +    Radio { +        selection: Option<Language>, +    }, +    Image { +        width: u16, +        slider: slider::State, +    }, +    Debugger, +    End, +} + +#[derive(Debug, Clone, Copy)] +pub enum StepMessage { +    SliderChanged(f32), +    LayoutChanged(Layout), +    SpacingChanged(f32), +    TextSizeChanged(f32), +    TextColorChanged(Color), +    LanguageSelected(Language), +    ImageWidthChanged(f32), +    DebugToggled(bool),  } -fn into_cursor_type(cursor: iced_native::MouseCursor) -> mouse::MouseCursor { -    match cursor { -        iced_native::MouseCursor::OutOfBounds => mouse::MouseCursor::Default, -        iced_native::MouseCursor::Idle => mouse::MouseCursor::Default, -        iced_native::MouseCursor::Pointer => mouse::MouseCursor::Hand, -        iced_native::MouseCursor::Working => mouse::MouseCursor::Progress, -        iced_native::MouseCursor::Grab => mouse::MouseCursor::Grab, -        iced_native::MouseCursor::Grabbing => mouse::MouseCursor::Grabbing, +impl<'a> Step { +    fn update(&mut self, msg: StepMessage, debug: &mut bool) { +        match msg { +            StepMessage::DebugToggled(value) => { +                if let Step::Debugger = self { +                    *debug = value; +                } +            } +            StepMessage::LanguageSelected(language) => { +                if let Step::Radio { selection } = self { +                    *selection = Some(language); +                } +            } +            StepMessage::SliderChanged(new_value) => { +                if let Step::Slider { value, .. } = self { +                    *value = new_value.round() as u16; +                } +            } +            StepMessage::TextSizeChanged(new_size) => { +                if let Step::Text { size, .. } = self { +                    *size = new_size.round() as u16; +                } +            } +            StepMessage::TextColorChanged(new_color) => { +                if let Step::Text { color, .. } = self { +                    *color = new_color; +                } +            } +            StepMessage::LayoutChanged(new_layout) => { +                if let Step::RowsAndColumns { layout, .. } = self { +                    *layout = new_layout; +                } +            } +            StepMessage::SpacingChanged(new_spacing) => { +                if let Step::RowsAndColumns { spacing, .. } = self { +                    *spacing = new_spacing.round() as u16; +                } +            } +            StepMessage::ImageWidthChanged(new_width) => { +                if let Step::Image { width, .. } = self { +                    *width = new_width.round() as u16; +                } +            } +        }; +    } + +    fn can_continue(&self) -> bool { +        match self { +            Step::Welcome => true, +            Step::Radio { selection } => *selection == Some(Language::Rust), +            Step::Slider { .. } => true, +            Step::Text { .. } => true, +            Step::Image { .. } => true, +            Step::RowsAndColumns { .. } => true, +            Step::Debugger => true, +            Step::End => false, +        } +    } + +    fn view(&mut self, debug: bool) -> Element<StepMessage> { +        match self { +            Step::Welcome => Self::welcome().into(), +            Step::Radio { selection } => Self::radio(*selection).into(), +            Step::Slider { state, value } => Self::slider(state, *value).into(), +            Step::Text { +                size_slider, +                size, +                color_sliders, +                color, +            } => Self::text(size_slider, *size, color_sliders, *color).into(), +            Step::Image { width, slider } => Self::image(*width, slider).into(), +            Step::RowsAndColumns { +                layout, +                spacing_slider, +                spacing, +            } => { +                Self::rows_and_columns(*layout, spacing_slider, *spacing).into() +            } +            Step::Debugger => Self::debugger(debug).into(), +            Step::End => Self::end().into(), +        }      } + +    fn container(title: &str) -> Column<'a, StepMessage> { +        Column::new() +            .spacing(20) +            .align_items(Align::Stretch) +            .push(Text::new(title).size(50)) +    } + +    fn welcome() -> Column<'a, StepMessage> { +        Self::container("Welcome!") +            .push(Text::new( +                "This a simple tour meant to showcase a bunch of widgets that \ +                 can be easily implemented on top of Iced.", +            )) +            .push(Text::new( +                "Iced is a renderer-agnostic GUI library for Rust focused on \ +                 simplicity and type-safety. It is heavily inspired by Elm.", +            )) +            .push(Text::new( +                "It was originally born as part of Coffee, an opinionated \ +                 2D game engine for Rust.", +            )) +            .push(Text::new( +                "Iced does not provide a built-in renderer. This example runs \ +                 on WebAssembly using dodrio, an experimental VDOM library \ +                 for Rust.", +            )) +            .push(Text::new( +                "You will need to interact with the UI in order to reach the \ +                 end!", +            )) +    } + +    fn slider( +        state: &'a mut slider::State, +        value: u16, +    ) -> Column<'a, StepMessage> { +        Self::container("Slider") +            .push(Text::new( +                "A slider allows you to smoothly select a value from a range \ +                 of values.", +            )) +            .push(Text::new( +                "The following slider lets you choose an integer from \ +                 0 to 100:", +            )) +            .push(Slider::new( +                state, +                0.0..=100.0, +                value as f32, +                StepMessage::SliderChanged, +            )) +            .push( +                Text::new(&value.to_string()) +                    .horizontal_alignment(HorizontalAlignment::Center), +            ) +    } + +    fn rows_and_columns( +        layout: Layout, +        spacing_slider: &'a mut slider::State, +        spacing: u16, +    ) -> Column<'a, StepMessage> { +        let row_radio = Radio::new( +            Layout::Row, +            "Row", +            Some(layout), +            StepMessage::LayoutChanged, +        ); + +        let column_radio = Radio::new( +            Layout::Column, +            "Column", +            Some(layout), +            StepMessage::LayoutChanged, +        ); + +        let layout_section: Element<_> = match layout { +            Layout::Row => Row::new() +                .spacing(spacing) +                .push(row_radio) +                .push(column_radio) +                .into(), +            Layout::Column => Column::new() +                .spacing(spacing) +                .push(row_radio) +                .push(column_radio) +                .into(), +        }; + +        let spacing_section = Column::new() +            .spacing(10) +            .push(Slider::new( +                spacing_slider, +                0.0..=80.0, +                spacing as f32, +                StepMessage::SpacingChanged, +            )) +            .push( +                Text::new(&format!("{} px", spacing)) +                    .horizontal_alignment(HorizontalAlignment::Center), +            ); + +        Self::container("Rows and columns") +            .spacing(spacing) +            .push(Text::new( +                "Iced uses a layout model based on flexbox to position UI \ +                 elements.", +            )) +            .push(Text::new( +                "Rows and columns can be used to distribute content \ +                 horizontally or vertically, respectively.", +            )) +            .push(layout_section) +            .push(Text::new( +                "You can also easily change the spacing between elements:", +            )) +            .push(spacing_section) +    } + +    fn text( +        size_slider: &'a mut slider::State, +        size: u16, +        color_sliders: &'a mut [slider::State; 3], +        color: Color, +    ) -> Column<'a, StepMessage> { +        let size_section = Column::new() +            .padding(20) +            .spacing(20) +            .push(Text::new("You can change its size:")) +            .push( +                Text::new(&format!("This text is {} pixels", size)).size(size), +            ) +            .push(Slider::new( +                size_slider, +                10.0..=70.0, +                size as f32, +                StepMessage::TextSizeChanged, +            )); + +        let [red, green, blue] = color_sliders; +        let color_section = Column::new() +            .padding(20) +            .spacing(20) +            .push(Text::new("And its color:")) +            .push(Text::new(&format!("{:?}", color)).color(color)) +            .push( +                Row::new() +                    .spacing(10) +                    .push(Slider::new(red, 0.0..=1.0, color.r, move |r| { +                        StepMessage::TextColorChanged(Color { r, ..color }) +                    })) +                    .push(Slider::new(green, 0.0..=1.0, color.g, move |g| { +                        StepMessage::TextColorChanged(Color { g, ..color }) +                    })) +                    .push(Slider::new(blue, 0.0..=1.0, color.b, move |b| { +                        StepMessage::TextColorChanged(Color { b, ..color }) +                    })), +            ); + +        Self::container("Text") +            .push(Text::new( +                "Text is probably the most essential widget for your UI. \ +                 It will try to adapt to the dimensions of its container.", +            )) +            .push(size_section) +            .push(color_section) +    } + +    fn radio(selection: Option<Language>) -> Column<'a, StepMessage> { +        let question = Column::new() +            .padding(20) +            .spacing(10) +            .push(Text::new("Iced is written in...").size(24)) +            .push(Language::all().iter().cloned().fold( +                Column::new().padding(10).spacing(20), +                |choices, language| { +                    choices.push(Radio::new( +                        language, +                        language.into(), +                        selection, +                        StepMessage::LanguageSelected, +                    )) +                }, +            )); + +        Self::container("Radio button") +            .push(Text::new( +                "A radio button is normally used to represent a choice... \ +                 Surprise test!", +            )) +            .push(question) +            .push(Text::new( +                "Iced works very well with iterators! The list above is \ +                 basically created by folding a column over the different \ +                 choices, creating a radio button for each one of them!", +            )) +    } + +    fn image( +        width: u16, +        slider: &'a mut slider::State, +    ) -> Column<'a, StepMessage> { +        Self::container("Image") +            .push(Text::new("An image that tries to keep its aspect ratio.")) +            .push( +                Image::new("resources/ferris.png") +                    .width(Length::Units(width)) +                    .align_self(Align::Center), +            ) +            .push(Slider::new( +                slider, +                100.0..=500.0, +                width as f32, +                StepMessage::ImageWidthChanged, +            )) +            .push( +                Text::new(&format!("Width: {} px", width.to_string())) +                    .horizontal_alignment(HorizontalAlignment::Center), +            ) +    } + +    fn debugger(debug: bool) -> Column<'a, StepMessage> { +        Self::container("Debugger") +            .push(Text::new( +                "You can ask Iced to visually explain the layouting of the \ +                 different elements comprising your UI!", +            )) +            .push(Text::new( +                "Give it a shot! Check the following checkbox to be able to \ +                 see element boundaries.", +            )) +            .push(Checkbox::new( +                debug, +                "Explain layout", +                StepMessage::DebugToggled, +            )) +            .push(Text::new("Feel free to go back and take a look.")) +    } + +    fn end() -> Column<'a, StepMessage> { +        Self::container("You reached the end!") +            .push(Text::new( +                "This tour will be updated as more features are added.", +            )) +            .push(Text::new("Make sure to keep an eye on it!")) +    } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Language { +    Rust, +    Elm, +    Ruby, +    Haskell, +    C, +    Other, +} + +impl Language { +    fn all() -> [Language; 6] { +        [ +            Language::C, +            Language::Elm, +            Language::Ruby, +            Language::Haskell, +            Language::Rust, +            Language::Other, +        ] +    } +} + +impl From<Language> for &str { +    fn from(language: Language) -> &'static str { +        match language { +            Language::Rust => "Rust", +            Language::Elm => "Elm", +            Language::Ruby => "Ruby", +            Language::Haskell => "Haskell", +            Language::C => "C", +            Language::Other => "Other", +        } +    } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Layout { +    Row, +    Column,  } diff --git a/examples/tour/src/tour.rs b/examples/tour/src/tour.rs deleted file mode 100644 index 04740fce..00000000 --- a/examples/tour/src/tour.rs +++ /dev/null @@ -1,563 +0,0 @@ -use crate::widget::{ -    button, slider, text::HorizontalAlignment, Align, Button, Checkbox, Color, -    Column, Element, Image, Length, Radio, Row, Slider, Text, -}; - -pub struct Tour { -    steps: Steps, -    back_button: button::State, -    next_button: button::State, -    debug: bool, -} - -impl Tour { -    pub fn new() -> Tour { -        Tour { -            steps: Steps::new(), -            back_button: button::State::new(), -            next_button: button::State::new(), -            debug: false, -        } -    } - -    pub fn update(&mut self, event: Message) { -        match event { -            Message::BackPressed => { -                self.steps.go_back(); -            } -            Message::NextPressed => { -                self.steps.advance(); -            } -            Message::StepMessage(step_msg) => { -                self.steps.update(step_msg, &mut self.debug); -            } -        } -    } - -    pub fn view(&mut self) -> Element<Message> { -        let Tour { -            steps, -            back_button, -            next_button, -            .. -        } = self; - -        let mut controls = Row::new(); - -        if steps.has_previous() { -            controls = controls.push( -                Button::new(back_button, "Back") -                    .on_press(Message::BackPressed) -                    .class(button::Class::Secondary), -            ); -        } - -        controls = controls.push(Column::new()); - -        if steps.can_continue() { -            controls = controls.push( -                Button::new(next_button, "Next").on_press(Message::NextPressed), -            ); -        } - -        let element: Element<_> = Column::new() -            .max_width(Length::Units(500)) -            .spacing(20) -            .push(steps.view(self.debug).map(Message::StepMessage)) -            .push(controls) -            .into(); - -        if self.debug { -            element.explain(Color::BLACK) -        } else { -            element -        } -    } -} - -#[derive(Debug, Clone, Copy)] -pub enum Message { -    BackPressed, -    NextPressed, -    StepMessage(StepMessage), -} - -struct Steps { -    steps: Vec<Step>, -    current: usize, -} - -impl Steps { -    fn new() -> Steps { -        Steps { -            steps: vec![ -                Step::Welcome, -                Step::Slider { -                    state: slider::State::new(), -                    value: 50, -                }, -                Step::RowsAndColumns { -                    layout: Layout::Row, -                    spacing_slider: slider::State::new(), -                    spacing: 20, -                }, -                Step::Text { -                    size_slider: slider::State::new(), -                    size: 30, -                    color_sliders: [slider::State::new(); 3], -                    color: Color::BLACK, -                }, -                Step::Radio { selection: None }, -                Step::Image { -                    width: 300, -                    slider: slider::State::new(), -                }, -                Step::Debugger, -                Step::End, -            ], -            current: 0, -        } -    } - -    fn update(&mut self, msg: StepMessage, debug: &mut bool) { -        self.steps[self.current].update(msg, debug); -    } - -    fn view(&mut self, debug: bool) -> Element<StepMessage> { -        self.steps[self.current].view(debug) -    } - -    fn advance(&mut self) { -        if self.can_continue() { -            self.current += 1; -        } -    } - -    fn go_back(&mut self) { -        if self.has_previous() { -            self.current -= 1; -        } -    } - -    fn has_previous(&self) -> bool { -        self.current > 0 -    } - -    fn can_continue(&self) -> bool { -        self.current + 1 < self.steps.len() -            && self.steps[self.current].can_continue() -    } -} - -enum Step { -    Welcome, -    Slider { -        state: slider::State, -        value: u16, -    }, -    RowsAndColumns { -        layout: Layout, -        spacing_slider: slider::State, -        spacing: u16, -    }, -    Text { -        size_slider: slider::State, -        size: u16, -        color_sliders: [slider::State; 3], -        color: Color, -    }, -    Radio { -        selection: Option<Language>, -    }, -    Image { -        width: u16, -        slider: slider::State, -    }, -    Debugger, -    End, -} - -#[derive(Debug, Clone, Copy)] -pub enum StepMessage { -    SliderChanged(f32), -    LayoutChanged(Layout), -    SpacingChanged(f32), -    TextSizeChanged(f32), -    TextColorChanged(Color), -    LanguageSelected(Language), -    ImageWidthChanged(f32), -    DebugToggled(bool), -} - -impl<'a> Step { -    fn update(&mut self, msg: StepMessage, debug: &mut bool) { -        match msg { -            StepMessage::DebugToggled(value) => { -                if let Step::Debugger = self { -                    *debug = value; -                } -            } -            StepMessage::LanguageSelected(language) => { -                if let Step::Radio { selection } = self { -                    *selection = Some(language); -                } -            } -            StepMessage::SliderChanged(new_value) => { -                if let Step::Slider { value, .. } = self { -                    *value = new_value.round() as u16; -                } -            } -            StepMessage::TextSizeChanged(new_size) => { -                if let Step::Text { size, .. } = self { -                    *size = new_size.round() as u16; -                } -            } -            StepMessage::TextColorChanged(new_color) => { -                if let Step::Text { color, .. } = self { -                    *color = new_color; -                } -            } -            StepMessage::LayoutChanged(new_layout) => { -                if let Step::RowsAndColumns { layout, .. } = self { -                    *layout = new_layout; -                } -            } -            StepMessage::SpacingChanged(new_spacing) => { -                if let Step::RowsAndColumns { spacing, .. } = self { -                    *spacing = new_spacing.round() as u16; -                } -            } -            StepMessage::ImageWidthChanged(new_width) => { -                if let Step::Image { width, .. } = self { -                    *width = new_width.round() as u16; -                } -            } -        }; -    } - -    fn can_continue(&self) -> bool { -        match self { -            Step::Welcome => true, -            Step::Radio { selection } => *selection == Some(Language::Rust), -            Step::Slider { .. } => true, -            Step::Text { .. } => true, -            Step::Image { .. } => true, -            Step::RowsAndColumns { .. } => true, -            Step::Debugger => true, -            Step::End => false, -        } -    } - -    fn view(&mut self, debug: bool) -> Element<StepMessage> { -        match self { -            Step::Welcome => Self::welcome().into(), -            Step::Radio { selection } => Self::radio(*selection).into(), -            Step::Slider { state, value } => Self::slider(state, *value).into(), -            Step::Text { -                size_slider, -                size, -                color_sliders, -                color, -            } => Self::text(size_slider, *size, color_sliders, *color).into(), -            Step::Image { width, slider } => Self::image(*width, slider).into(), -            Step::RowsAndColumns { -                layout, -                spacing_slider, -                spacing, -            } => { -                Self::rows_and_columns(*layout, spacing_slider, *spacing).into() -            } -            Step::Debugger => Self::debugger(debug).into(), -            Step::End => Self::end().into(), -        } -    } - -    fn container(title: &str) -> Column<'a, StepMessage> { -        Column::new() -            .spacing(20) -            .align_items(Align::Stretch) -            .push(Text::new(title).size(50)) -    } - -    fn welcome() -> Column<'a, StepMessage> { -        Self::container("Welcome!") -            .push(Text::new( -                "This a simple tour meant to showcase a bunch of widgets that \ -                 can be easily implemented on top of Iced.", -            )) -            .push(Text::new( -                "Iced is a renderer-agnostic GUI library for Rust focused on \ -                 simplicity and type-safety. It is heavily inspired by Elm.", -            )) -            .push(Text::new( -                "It was originally born as part of Coffee, an opinionated \ -                 2D game engine for Rust.", -            )) -            .push(Text::new( -                "Iced does not provide a built-in renderer. This example runs \ -                 on WebAssembly using dodrio, an experimental VDOM library \ -                 for Rust.", -            )) -            .push(Text::new( -                "You will need to interact with the UI in order to reach the \ -                 end!", -            )) -    } - -    fn slider( -        state: &'a mut slider::State, -        value: u16, -    ) -> Column<'a, StepMessage> { -        Self::container("Slider") -            .push(Text::new( -                "A slider allows you to smoothly select a value from a range \ -                 of values.", -            )) -            .push(Text::new( -                "The following slider lets you choose an integer from \ -                 0 to 100:", -            )) -            .push(Slider::new( -                state, -                0.0..=100.0, -                value as f32, -                StepMessage::SliderChanged, -            )) -            .push( -                Text::new(&value.to_string()) -                    .horizontal_alignment(HorizontalAlignment::Center), -            ) -    } - -    fn rows_and_columns( -        layout: Layout, -        spacing_slider: &'a mut slider::State, -        spacing: u16, -    ) -> Column<'a, StepMessage> { -        let row_radio = Radio::new( -            Layout::Row, -            "Row", -            Some(layout), -            StepMessage::LayoutChanged, -        ); - -        let column_radio = Radio::new( -            Layout::Column, -            "Column", -            Some(layout), -            StepMessage::LayoutChanged, -        ); - -        let layout_section: Element<_> = match layout { -            Layout::Row => Row::new() -                .spacing(spacing) -                .push(row_radio) -                .push(column_radio) -                .into(), -            Layout::Column => Column::new() -                .spacing(spacing) -                .push(row_radio) -                .push(column_radio) -                .into(), -        }; - -        let spacing_section = Column::new() -            .spacing(10) -            .push(Slider::new( -                spacing_slider, -                0.0..=80.0, -                spacing as f32, -                StepMessage::SpacingChanged, -            )) -            .push( -                Text::new(&format!("{} px", spacing)) -                    .horizontal_alignment(HorizontalAlignment::Center), -            ); - -        Self::container("Rows and columns") -            .spacing(spacing) -            .push(Text::new( -                "Iced uses a layout model based on flexbox to position UI \ -                 elements.", -            )) -            .push(Text::new( -                "Rows and columns can be used to distribute content \ -                 horizontally or vertically, respectively.", -            )) -            .push(layout_section) -            .push(Text::new( -                "You can also easily change the spacing between elements:", -            )) -            .push(spacing_section) -    } - -    fn text( -        size_slider: &'a mut slider::State, -        size: u16, -        color_sliders: &'a mut [slider::State; 3], -        color: Color, -    ) -> Column<'a, StepMessage> { -        let size_section = Column::new() -            .padding(20) -            .spacing(20) -            .push(Text::new("You can change its size:")) -            .push( -                Text::new(&format!("This text is {} pixels", size)).size(size), -            ) -            .push(Slider::new( -                size_slider, -                10.0..=70.0, -                size as f32, -                StepMessage::TextSizeChanged, -            )); - -        let [red, green, blue] = color_sliders; -        let color_section = Column::new() -            .padding(20) -            .spacing(20) -            .push(Text::new("And its color:")) -            .push(Text::new(&format!("{:?}", color)).color(color)) -            .push( -                Row::new() -                    .spacing(10) -                    .push(Slider::new(red, 0.0..=1.0, color.r, move |r| { -                        StepMessage::TextColorChanged(Color { r, ..color }) -                    })) -                    .push(Slider::new(green, 0.0..=1.0, color.g, move |g| { -                        StepMessage::TextColorChanged(Color { g, ..color }) -                    })) -                    .push(Slider::new(blue, 0.0..=1.0, color.b, move |b| { -                        StepMessage::TextColorChanged(Color { b, ..color }) -                    })), -            ); - -        Self::container("Text") -            .push(Text::new( -                "Text is probably the most essential widget for your UI. \ -                 It will try to adapt to the dimensions of its container.", -            )) -            .push(size_section) -            .push(color_section) -    } - -    fn radio(selection: Option<Language>) -> Column<'a, StepMessage> { -        let question = Column::new() -            .padding(20) -            .spacing(10) -            .push(Text::new("Iced is written in...").size(24)) -            .push(Language::all().iter().cloned().fold( -                Column::new().padding(10).spacing(20), -                |choices, language| { -                    choices.push(Radio::new( -                        language, -                        language.into(), -                        selection, -                        StepMessage::LanguageSelected, -                    )) -                }, -            )); - -        Self::container("Radio button") -            .push(Text::new( -                "A radio button is normally used to represent a choice... \ -                 Surprise test!", -            )) -            .push(question) -            .push(Text::new( -                "Iced works very well with iterators! The list above is \ -                 basically created by folding a column over the different \ -                 choices, creating a radio button for each one of them!", -            )) -    } - -    fn image( -        width: u16, -        slider: &'a mut slider::State, -    ) -> Column<'a, StepMessage> { -        Self::container("Image") -            .push(Text::new("An image that tries to keep its aspect ratio.")) -            .push( -                Image::new("resources/ferris.png") -                    .width(Length::Units(width)) -                    .align_self(Align::Center), -            ) -            .push(Slider::new( -                slider, -                100.0..=500.0, -                width as f32, -                StepMessage::ImageWidthChanged, -            )) -            .push( -                Text::new(&format!("Width: {} px", width.to_string())) -                    .horizontal_alignment(HorizontalAlignment::Center), -            ) -    } - -    fn debugger(debug: bool) -> Column<'a, StepMessage> { -        Self::container("Debugger") -            .push(Text::new( -                "You can ask Iced to visually explain the layouting of the \ -                 different elements comprising your UI!", -            )) -            .push(Text::new( -                "Give it a shot! Check the following checkbox to be able to \ -                 see element boundaries.", -            )) -            .push(Checkbox::new( -                debug, -                "Explain layout", -                StepMessage::DebugToggled, -            )) -            .push(Text::new("Feel free to go back and take a look.")) -    } - -    fn end() -> Column<'a, StepMessage> { -        Self::container("You reached the end!") -            .push(Text::new( -                "This tour will be updated as more features are added.", -            )) -            .push(Text::new("Make sure to keep an eye on it!")) -    } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Language { -    Rust, -    Elm, -    Ruby, -    Haskell, -    C, -    Other, -} - -impl Language { -    fn all() -> [Language; 6] { -        [ -            Language::C, -            Language::Elm, -            Language::Ruby, -            Language::Haskell, -            Language::Rust, -            Language::Other, -        ] -    } -} - -impl From<Language> for &str { -    fn from(language: Language) -> &'static str { -        match language { -            Language::Rust => "Rust", -            Language::Elm => "Elm", -            Language::Ruby => "Ruby", -            Language::Haskell => "Haskell", -            Language::C => "C", -            Language::Other => "Other", -        } -    } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Layout { -    Row, -    Column, -} diff --git a/examples/tour/src/web.rs b/examples/tour/src/web.rs deleted file mode 100644 index a0a3060f..00000000 --- a/examples/tour/src/web.rs +++ /dev/null @@ -1,33 +0,0 @@ -use futures::Future; -use iced_web::UserInterface; -use wasm_bindgen::prelude::*; - -use crate::tour::{self, Tour}; - -#[wasm_bindgen(start)] -pub fn run() { -    console_error_panic_hook::set_once(); -    console_log::init_with_level(log::Level::Trace) -        .expect("Initialize logging"); - -    let tour = Tour::new(); - -    tour.run(); -} - -impl iced_web::UserInterface for Tour { -    type Message = tour::Message; - -    fn update( -        &mut self, -        message: tour::Message, -    ) -> Option<Box<dyn Future<Output = tour::Message>>> { -        self.update(message); - -        None -    } - -    fn view(&mut self) -> iced_web::Element<tour::Message> { -        self.view() -    } -} diff --git a/examples/tour/src/widget.rs b/examples/tour/src/widget.rs deleted file mode 100644 index 9c2c4d5b..00000000 --- a/examples/tour/src/widget.rs +++ /dev/null @@ -1,5 +0,0 @@ -#[cfg(target_arch = "wasm32")] -pub use iced_web::*; - -#[cfg(not(target_arch = "wasm32"))] -pub use crate::iced_ggez::*; | 
