From 7cea7371150e6de28032827519936008592f112d Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Mon, 20 Jan 2020 06:27:01 +0100
Subject: Package examples and remove `dev-dependencies`

---
 examples/tour/src/main.rs | 794 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 794 insertions(+)
 create mode 100644 examples/tour/src/main.rs

(limited to 'examples/tour/src/main.rs')

diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs
new file mode 100644
index 00000000..43c7e50f
--- /dev/null
+++ b/examples/tour/src/main.rs
@@ -0,0 +1,794 @@
+use iced::{
+    button, scrollable, slider, text_input, Button, Checkbox, Color, Column,
+    Container, Element, HorizontalAlignment, Image, Length, Radio, Row,
+    Sandbox, Scrollable, Settings, Slider, Space, Text, TextInput,
+};
+
+pub fn main() {
+    env_logger::init();
+
+    Tour::run(Settings::default())
+}
+
+pub struct Tour {
+    steps: Steps,
+    scroll: scrollable::State,
+    back_button: button::State,
+    next_button: button::State,
+    debug: bool,
+}
+
+impl Sandbox for Tour {
+    type Message = Message;
+
+    fn new() -> Tour {
+        Tour {
+            steps: Steps::new(),
+            scroll: scrollable::State::new(),
+            back_button: button::State::new(),
+            next_button: button::State::new(),
+            debug: false,
+        }
+    }
+
+    fn title(&self) -> String {
+        format!("{} - Iced", self.steps.title())
+    }
+
+    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,
+            scroll,
+            back_button,
+            next_button,
+            ..
+        } = self;
+
+        let mut controls = Row::new();
+
+        if steps.has_previous() {
+            controls = controls.push(
+                button(back_button, "Back")
+                    .on_press(Message::BackPressed)
+                    .style(style::Button::Secondary),
+            );
+        }
+
+        controls = controls.push(Space::with_width(Length::Fill));
+
+        if steps.can_continue() {
+            controls = controls.push(
+                button(next_button, "Next")
+                    .on_press(Message::NextPressed)
+                    .style(style::Button::Primary),
+            );
+        }
+
+        let content: Element<_> = Column::new()
+            .max_width(540)
+            .spacing(20)
+            .padding(20)
+            .push(steps.view(self.debug).map(Message::StepMessage))
+            .push(controls)
+            .into();
+
+        let content = if self.debug {
+            content.explain(Color::BLACK)
+        } else {
+            content
+        };
+
+        let scrollable = Scrollable::new(scroll)
+            .push(Container::new(content).width(Length::Fill).center_x());
+
+        Container::new(scrollable)
+            .height(Length::Fill)
+            .center_y()
+            .into()
+    }
+}
+
+#[derive(Debug, Clone)]
+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::Scrollable,
+                Step::TextInput {
+                    value: String::new(),
+                    is_secure: false,
+                    state: text_input::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()
+    }
+
+    fn title(&self) -> &str {
+        self.steps[self.current].title()
+    }
+}
+
+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,
+    },
+    Scrollable,
+    TextInput {
+        value: String,
+        is_secure: bool,
+        state: text_input::State,
+    },
+    Debugger,
+    End,
+}
+
+#[derive(Debug, Clone)]
+pub enum StepMessage {
+    SliderChanged(f32),
+    LayoutChanged(Layout),
+    SpacingChanged(f32),
+    TextSizeChanged(f32),
+    TextColorChanged(Color),
+    LanguageSelected(Language),
+    ImageWidthChanged(f32),
+    InputChanged(String),
+    ToggleSecureInput(bool),
+    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;
+                }
+            }
+            StepMessage::InputChanged(new_value) => {
+                if let Step::TextInput { value, .. } = self {
+                    *value = new_value;
+                }
+            }
+            StepMessage::ToggleSecureInput(toggle) => {
+                if let Step::TextInput { is_secure, .. } = self {
+                    *is_secure = toggle;
+                }
+            }
+        };
+    }
+
+    fn title(&self) -> &str {
+        match self {
+            Step::Welcome => "Welcome",
+            Step::Radio { .. } => "Radio button",
+            Step::Slider { .. } => "Slider",
+            Step::Text { .. } => "Text",
+            Step::Image { .. } => "Image",
+            Step::RowsAndColumns { .. } => "Rows and columns",
+            Step::Scrollable => "Scrollable",
+            Step::TextInput { .. } => "Text input",
+            Step::Debugger => "Debugger",
+            Step::End => "End",
+        }
+    }
+
+    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::Scrollable => true,
+            Step::TextInput { value, .. } => !value.is_empty(),
+            Step::Debugger => true,
+            Step::End => false,
+        }
+    }
+
+    fn view(&mut self, debug: bool) -> Element<StepMessage> {
+        match self {
+            Step::Welcome => Self::welcome(),
+            Step::Radio { selection } => Self::radio(*selection),
+            Step::Slider { state, value } => Self::slider(state, *value),
+            Step::Text {
+                size_slider,
+                size,
+                color_sliders,
+                color,
+            } => Self::text(size_slider, *size, color_sliders, *color),
+            Step::Image { width, slider } => Self::image(*width, slider),
+            Step::RowsAndColumns {
+                layout,
+                spacing_slider,
+                spacing,
+            } => Self::rows_and_columns(*layout, spacing_slider, *spacing),
+            Step::Scrollable => Self::scrollable(),
+            Step::TextInput {
+                value,
+                is_secure,
+                state,
+            } => Self::text_input(value, *is_secure, state),
+            Step::Debugger => Self::debugger(debug),
+            Step::End => Self::end(),
+        }
+        .into()
+    }
+
+    fn container(title: &str) -> Column<'a, StepMessage> {
+        Column::new().spacing(20).push(Text::new(title).size(50))
+    }
+
+    fn welcome() -> Column<'a, StepMessage> {
+        Self::container("Welcome!")
+            .push(Text::new(
+                "This is 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 cross-platform 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(
+                "On native platforms, Iced provides by default a renderer \
+                 built on top of wgpu, a graphics library supporting Vulkan, \
+                 Metal, DX11, and DX12.",
+            ))
+            .push(Text::new(
+                "Additionally, this tour can also run on WebAssembly thanks \
+                 to 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())
+                    .width(Length::Fill)
+                    .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))
+                    .width(Length::Fill)
+                    .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(ferris(width))
+            .push(Slider::new(
+                slider,
+                100.0..=500.0,
+                width as f32,
+                StepMessage::ImageWidthChanged,
+            ))
+            .push(
+                Text::new(&format!("Width: {} px", width.to_string()))
+                    .width(Length::Fill)
+                    .horizontal_alignment(HorizontalAlignment::Center),
+            )
+    }
+
+    fn scrollable() -> Column<'a, StepMessage> {
+        Self::container("Scrollable")
+            .push(Text::new(
+                "Iced supports scrollable content. Try it out! Find the \
+                 button further below.",
+            ))
+            .push(
+                Text::new(
+                    "Tip: You can use the scrollbar to scroll down faster!",
+                )
+                .size(16),
+            )
+            .push(Column::new().height(Length::Units(4096)))
+            .push(
+                Text::new("You are halfway there!")
+                    .width(Length::Fill)
+                    .size(30)
+                    .horizontal_alignment(HorizontalAlignment::Center),
+            )
+            .push(Column::new().height(Length::Units(4096)))
+            .push(ferris(300))
+            .push(
+                Text::new("You made it!")
+                    .width(Length::Fill)
+                    .size(50)
+                    .horizontal_alignment(HorizontalAlignment::Center),
+            )
+    }
+
+    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(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:",
+            ))
+            .push(
+                Text::new(if value.is_empty() {
+                    "You have not typed anything yet..."
+                } else {
+                    value
+                })
+                .width(Length::Fill)
+                .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(if cfg!(target_arch = "wasm32") {
+                Element::new(
+                    Text::new("Not available on web yet!")
+                        .color([0.7, 0.7, 0.7])
+                        .horizontal_alignment(HorizontalAlignment::Center),
+                )
+            } else {
+                Element::new(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!"))
+    }
+}
+
+fn ferris<'a>(width: u16) -> Container<'a, StepMessage> {
+    Container::new(
+        // This should go away once we unify resource loading on native
+        // platforms
+        if cfg!(target_arch = "wasm32") {
+            Image::new("images/ferris.png")
+        } else {
+            Image::new(format!(
+                "{}/images/ferris.png",
+                env!("CARGO_MANIFEST_DIR")
+            ))
+        }
+        .width(Length::Units(width)),
+    )
+    .width(Length::Fill)
+    .center_x()
+}
+
+fn button<'a, Message>(
+    state: &'a mut button::State,
+    label: &str,
+) -> Button<'a, Message> {
+    Button::new(
+        state,
+        Text::new(label).horizontal_alignment(HorizontalAlignment::Center),
+    )
+    .padding(12)
+    .min_width(100)
+}
+
+#[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,
+}
+
+mod style {
+    use iced::{button, Background, Color, Vector};
+
+    pub enum Button {
+        Primary,
+        Secondary,
+    }
+
+    impl button::StyleSheet for Button {
+        fn active(&self) -> button::Style {
+            button::Style {
+                background: Some(Background::Color(match self {
+                    Button::Primary => Color::from_rgb(0.11, 0.42, 0.87),
+                    Button::Secondary => Color::from_rgb(0.5, 0.5, 0.5),
+                })),
+                border_radius: 12,
+                shadow_offset: Vector::new(1.0, 1.0),
+                text_color: Color::from_rgb8(0xEE, 0xEE, 0xEE),
+                ..button::Style::default()
+            }
+        }
+
+        fn hovered(&self) -> button::Style {
+            button::Style {
+                text_color: Color::WHITE,
+                shadow_offset: Vector::new(1.0, 2.0),
+                ..self.active()
+            }
+        }
+    }
+}
+
+// This should be gracefully handled by Iced in the future. Probably using our
+// own proc macro, or maybe the whole process is streamlined by `wasm-pack` at
+// some point.
+#[cfg(target_arch = "wasm32")]
+mod wasm {
+    use wasm_bindgen::prelude::*;
+
+    #[wasm_bindgen(start)]
+    pub fn run() {
+        super::main()
+    }
+}
-- 
cgit