diff options
Diffstat (limited to 'examples')
-rw-r--r-- | examples/events/src/main.rs | 47 | ||||
-rw-r--r-- | examples/game_of_life/src/main.rs | 13 | ||||
-rw-r--r-- | examples/game_of_life/src/preset.rs | 13 | ||||
-rw-r--r-- | examples/game_of_life/src/style.rs | 1 | ||||
-rw-r--r-- | examples/integration/src/scene.rs | 11 | ||||
-rw-r--r-- | examples/menu/Cargo.toml | 10 | ||||
-rw-r--r-- | examples/menu/src/main.rs | 117 | ||||
-rw-r--r-- | examples/pane_grid/src/main.rs | 108 | ||||
-rw-r--r-- | examples/pick_list/src/main.rs | 9 | ||||
-rw-r--r-- | examples/pokedex/src/main.rs | 5 | ||||
-rw-r--r-- | examples/scrollable/Cargo.toml | 2 | ||||
-rw-r--r-- | examples/scrollable/src/main.rs | 107 | ||||
-rw-r--r-- | examples/styling/src/main.rs | 75 | ||||
-rw-r--r-- | examples/tour/src/main.rs | 32 | ||||
-rw-r--r-- | examples/url_handler/Cargo.toml | 10 | ||||
-rw-r--r-- | examples/url_handler/src/main.rs | 73 |
16 files changed, 569 insertions, 64 deletions
diff --git a/examples/events/src/main.rs b/examples/events/src/main.rs index 18e6364b..446c190b 100644 --- a/examples/events/src/main.rs +++ b/examples/events/src/main.rs @@ -1,22 +1,30 @@ use iced::{ - executor, Align, Application, Checkbox, Clipboard, Column, Command, - Container, Element, Length, Settings, Subscription, Text, + button, executor, Align, Application, Button, Checkbox, Clipboard, Column, + Command, Container, Element, HorizontalAlignment, Length, Settings, + Subscription, Text, }; +use iced_native::{window, Event}; pub fn main() -> iced::Result { - Events::run(Settings::default()) + Events::run(Settings { + exit_on_close_request: false, + ..Settings::default() + }) } #[derive(Debug, Default)] struct Events { last: Vec<iced_native::Event>, enabled: bool, + exit: button::State, + should_exit: bool, } #[derive(Debug, Clone)] enum Message { EventOccurred(iced_native::Event), Toggled(bool), + Exit, } impl Application for Events { @@ -38,27 +46,35 @@ impl Application for Events { _clipboard: &mut Clipboard, ) -> Command<Message> { match message { - Message::EventOccurred(event) => { + Message::EventOccurred(event) if self.enabled => { self.last.push(event); if self.last.len() > 5 { let _ = self.last.remove(0); } } + Message::EventOccurred(event) => { + if let Event::Window(window::Event::CloseRequested) = event { + self.should_exit = true; + } + } Message::Toggled(enabled) => { self.enabled = enabled; } + Message::Exit => { + self.should_exit = true; + } }; Command::none() } fn subscription(&self) -> Subscription<Message> { - if self.enabled { - iced_native::subscription::events().map(Message::EventOccurred) - } else { - Subscription::none() - } + iced_native::subscription::events().map(Message::EventOccurred) + } + + fn should_exit(&self) -> bool { + self.should_exit } fn view(&mut self) -> Element<Message> { @@ -75,11 +91,22 @@ impl Application for Events { Message::Toggled, ); + let exit = Button::new( + &mut self.exit, + Text::new("Exit") + .width(Length::Fill) + .horizontal_alignment(HorizontalAlignment::Center), + ) + .width(Length::Units(100)) + .padding(10) + .on_press(Message::Exit); + let content = Column::new() .align_items(Align::Center) .spacing(20) .push(events) - .push(toggle); + .push(toggle) + .push(exit); Container::new(content) .width(Length::Fill) diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs index 64599163..c3e16e8b 100644 --- a/examples/game_of_life/src/main.rs +++ b/examples/game_of_life/src/main.rs @@ -6,9 +6,11 @@ mod style; use grid::Grid; use iced::button::{self, Button}; use iced::executor; +use iced::menu::{self, Menu}; use iced::pick_list::{self, PickList}; use iced::slider::{self, Slider}; use iced::time; +use iced::window; use iced::{ Align, Application, Checkbox, Clipboard, Column, Command, Container, Element, Length, Row, Settings, Subscription, Text, @@ -19,6 +21,10 @@ use std::time::{Duration, Instant}; pub fn main() -> iced::Result { GameOfLife::run(Settings { antialiasing: true, + window: window::Settings { + position: window::Position::Centered, + ..window::Settings::default() + }, ..Settings::default() }) } @@ -128,6 +134,13 @@ impl Application for GameOfLife { } } + fn menu(&self) -> Menu<Message> { + Menu::with_entries(vec![menu::Entry::dropdown( + "Presets", + Preset::menu().map(Message::PresetPicked), + )]) + } + fn view(&mut self) -> Element<Message> { let version = self.version; let selected_speed = self.next_speed.unwrap_or(self.speed); diff --git a/examples/game_of_life/src/preset.rs b/examples/game_of_life/src/preset.rs index 05157b6a..1c199a72 100644 --- a/examples/game_of_life/src/preset.rs +++ b/examples/game_of_life/src/preset.rs @@ -1,3 +1,5 @@ +use iced::menu::{self, Menu}; + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Preset { Custom, @@ -26,6 +28,17 @@ pub static ALL: &[Preset] = &[ ]; impl Preset { + pub fn menu() -> Menu<Self> { + Menu::with_entries( + ALL.iter() + .copied() + .map(|preset| { + menu::Entry::item(preset.to_string(), None, preset) + }) + .collect(), + ) + } + pub fn life(self) -> Vec<(isize, isize)> { #[rustfmt::skip] let cells = match self { diff --git a/examples/game_of_life/src/style.rs b/examples/game_of_life/src/style.rs index 6605826f..be9a0e96 100644 --- a/examples/game_of_life/src/style.rs +++ b/examples/game_of_life/src/style.rs @@ -171,6 +171,7 @@ impl pick_list::StyleSheet for PickList { }, border_radius: 2.0, icon_size: 0.5, + ..pick_list::Style::default() } } diff --git a/examples/integration/src/scene.rs b/examples/integration/src/scene.rs index 36c0a41d..3e8277c8 100644 --- a/examples/integration/src/scene.rs +++ b/examples/integration/src/scene.rs @@ -20,8 +20,8 @@ impl Scene { ) -> wgpu::RenderPass<'a> { encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: None, - color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { - attachment: target, + color_attachments: &[wgpu::RenderPassColorAttachment { + view: target, resolve_target: None, ops: wgpu::Operations { load: wgpu::LoadOp::Clear({ @@ -75,15 +75,16 @@ fn build_pipeline(device: &wgpu::Device) -> wgpu::RenderPipeline { entry_point: "main", targets: &[wgpu::ColorTargetState { format: wgpu::TextureFormat::Bgra8UnormSrgb, - color_blend: wgpu::BlendState::REPLACE, - alpha_blend: wgpu::BlendState::REPLACE, + blend: Some(wgpu::BlendState { + color: wgpu::BlendComponent::REPLACE, + alpha: wgpu::BlendComponent::REPLACE, + }), write_mask: wgpu::ColorWrite::ALL, }], }), primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleList, front_face: wgpu::FrontFace::Ccw, - cull_mode: wgpu::CullMode::None, ..Default::default() }, depth_stencil: None, diff --git a/examples/menu/Cargo.toml b/examples/menu/Cargo.toml new file mode 100644 index 00000000..44597734 --- /dev/null +++ b/examples/menu/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "menu" +version = "0.1.0" +authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] +edition = "2018" +publish = false + +[dependencies] +iced = { path = "../.." } +iced_native = { path = "../../native" }
\ No newline at end of file diff --git a/examples/menu/src/main.rs b/examples/menu/src/main.rs new file mode 100644 index 00000000..7403713c --- /dev/null +++ b/examples/menu/src/main.rs @@ -0,0 +1,117 @@ +use iced::menu::{self, Menu}; +use iced::{ + executor, Application, Clipboard, Command, Container, Element, Length, + Settings, Text, +}; +use iced_native::keyboard::{Hotkey, KeyCode, Modifiers}; + +pub fn main() -> iced::Result { + App::run(Settings::default()) +} + +#[derive(Debug, Default)] +struct App { + selected: Option<Entry>, +} + +#[derive(Debug, Clone)] +enum Entry { + One, + Two, + Three, + A, + B, + C, +} + +#[derive(Debug, Clone)] +enum Message { + MenuActivated(Entry), +} + +impl Application for App { + type Executor = executor::Default; + type Message = Message; + type Flags = (); + + fn new(_flags: ()) -> (App, Command<Message>) { + (App::default(), Command::none()) + } + + fn title(&self) -> String { + String::from("Menu - Iced") + } + + fn menu(&self) -> Menu<Message> { + let alt = Modifiers::ALT; + let ctrl_shift = Modifiers::CTRL | Modifiers::SHIFT; + + Menu::with_entries(vec![ + menu::Entry::dropdown( + "First", + Menu::with_entries(vec![ + menu::Entry::item( + "One", + Hotkey::new(alt, KeyCode::F1), + Message::MenuActivated(Entry::One), + ), + menu::Entry::item( + "Two", + Hotkey::new(alt, KeyCode::F2), + Message::MenuActivated(Entry::Two), + ), + menu::Entry::Separator, + menu::Entry::item( + "Three", + Hotkey::new(alt, KeyCode::F3), + Message::MenuActivated(Entry::Three), + ), + ]), + ), + menu::Entry::dropdown( + "Second", + Menu::with_entries(vec![ + menu::Entry::item( + "A", + Hotkey::new(ctrl_shift, KeyCode::A), + Message::MenuActivated(Entry::A), + ), + menu::Entry::item( + "B", + Hotkey::new(ctrl_shift, KeyCode::B), + Message::MenuActivated(Entry::B), + ), + menu::Entry::Separator, + menu::Entry::item( + "C", + Hotkey::new(ctrl_shift, KeyCode::C), + Message::MenuActivated(Entry::C), + ), + ]), + ), + ]) + } + + fn update( + &mut self, + message: Message, + _clipboard: &mut Clipboard, + ) -> Command<Message> { + match message { + Message::MenuActivated(entry) => self.selected = Some(entry), + } + + Command::none() + } + + fn view(&mut self) -> Element<Message> { + Container::new( + Text::new(format!("Selected {:?}", self.selected)).size(48), + ) + .width(Length::Fill) + .height(Length::Fill) + .center_x() + .center_y() + .into() + } +} diff --git a/examples/pane_grid/src/main.rs b/examples/pane_grid/src/main.rs index 4b87a568..3bd8aa25 100644 --- a/examples/pane_grid/src/main.rs +++ b/examples/pane_grid/src/main.rs @@ -11,7 +11,7 @@ pub fn main() -> iced::Result { } struct Example { - panes: pane_grid::State<Content>, + panes: pane_grid::State<Pane>, panes_created: usize, focus: Option<pane_grid::Pane>, } @@ -24,6 +24,7 @@ enum Message { Clicked(pane_grid::Pane), Dragged(pane_grid::DragEvent), Resized(pane_grid::ResizeEvent), + TogglePin(pane_grid::Pane), Close(pane_grid::Pane), CloseFocused, } @@ -34,7 +35,7 @@ impl Application for Example { type Flags = (); fn new(_flags: ()) -> (Self, Command<Message>) { - let (panes, _) = pane_grid::State::new(Content::new(0)); + let (panes, _) = pane_grid::State::new(Pane::new(0)); ( Example { @@ -60,7 +61,7 @@ impl Application for Example { let result = self.panes.split( axis, &pane, - Content::new(self.panes_created), + Pane::new(self.panes_created), ); if let Some((pane, _)) = result { @@ -74,7 +75,7 @@ impl Application for Example { let result = self.panes.split( axis, &pane, - Content::new(self.panes_created), + Pane::new(self.panes_created), ); if let Some((pane, _)) = result { @@ -106,6 +107,12 @@ impl Application for Example { self.panes.swap(&pane, &target); } Message::Dragged(_) => {} + Message::TogglePin(pane) => { + if let Some(Pane { is_pinned, .. }) = self.panes.get_mut(&pane) + { + *is_pinned = !*is_pinned; + } + } Message::Close(pane) => { if let Some((_, sibling)) = self.panes.close(&pane) { self.focus = Some(sibling); @@ -113,8 +120,14 @@ impl Application for Example { } Message::CloseFocused => { if let Some(pane) = self.focus { - if let Some((_, sibling)) = self.panes.close(&pane) { - self.focus = Some(sibling); + if let Some(Pane { is_pinned, .. }) = self.panes.get(&pane) + { + if !is_pinned { + if let Some((_, sibling)) = self.panes.close(&pane) + { + self.focus = Some(sibling); + } + } } } } @@ -133,7 +146,7 @@ impl Application for Example { Event::Keyboard(keyboard::Event::KeyPressed { modifiers, key_code, - }) if modifiers.is_command_pressed() => handle_hotkey(key_code), + }) if modifiers.command() => handle_hotkey(key_code), _ => None, } }) @@ -143,12 +156,20 @@ impl Application for Example { let focus = self.focus; let total_panes = self.panes.len(); - let pane_grid = PaneGrid::new(&mut self.panes, |pane, content| { - let is_focused = focus == Some(pane); + let pane_grid = PaneGrid::new(&mut self.panes, |id, pane| { + let is_focused = focus == Some(id); + + let text = if pane.is_pinned { "Unpin" } else { "Pin" }; + let pin_button = + Button::new(&mut pane.pin_button, Text::new(text).size(14)) + .on_press(Message::TogglePin(id)) + .style(style::Button::Pin) + .padding(3); let title = Row::with_children(vec![ + pin_button.into(), Text::new("Pane").into(), - Text::new(content.id.to_string()) + Text::new(pane.content.id.to_string()) .color(if is_focused { PANE_ID_COLOR_FOCUSED } else { @@ -159,12 +180,17 @@ impl Application for Example { .spacing(5); let title_bar = pane_grid::TitleBar::new(title) + .controls(pane.controls.view(id, total_panes, pane.is_pinned)) .padding(10) .style(style::TitleBar { is_focused }); - pane_grid::Content::new(content.view(pane, total_panes)) - .title_bar(title_bar) - .style(style::Pane { is_focused }) + pane_grid::Content::new(pane.content.view( + id, + total_panes, + pane.is_pinned, + )) + .title_bar(title_bar) + .style(style::Pane { is_focused }) }) .width(Length::Fill) .height(Length::Fill) @@ -212,6 +238,13 @@ fn handle_hotkey(key_code: keyboard::KeyCode) -> Option<Message> { } } +struct Pane { + pub is_pinned: bool, + pub pin_button: button::State, + pub content: Content, + pub controls: Controls, +} + struct Content { id: usize, scroll: scrollable::State, @@ -220,6 +253,21 @@ struct Content { close: button::State, } +struct Controls { + close: button::State, +} + +impl Pane { + fn new(id: usize) -> Self { + Self { + is_pinned: false, + pin_button: button::State::new(), + content: Content::new(id), + controls: Controls::new(), + } + } +} + impl Content { fn new(id: usize) -> Self { Content { @@ -234,6 +282,7 @@ impl Content { &mut self, pane: pane_grid::Pane, total_panes: usize, + is_pinned: bool, ) -> Element<Message> { let Content { scroll, @@ -273,7 +322,7 @@ impl Content { style::Button::Primary, )); - if total_panes > 1 { + if total_panes > 1 && !is_pinned { controls = controls.push(button( close, "Close", @@ -297,7 +346,32 @@ impl Content { } } +impl Controls { + fn new() -> Self { + Self { + close: button::State::new(), + } + } + + pub fn view( + &mut self, + pane: pane_grid::Pane, + total_panes: usize, + is_pinned: bool, + ) -> Element<Message> { + let mut button = + Button::new(&mut self.close, Text::new("Close").size(14)) + .style(style::Button::Control) + .padding(3); + if total_panes > 1 && !is_pinned { + button = button.on_press(Message::Close(pane)); + } + button.into() + } +} + mod style { + use crate::PANE_ID_COLOR_FOCUSED; use iced::{button, container, Background, Color, Vector}; const SURFACE: Color = Color::from_rgb( @@ -359,6 +433,8 @@ mod style { pub enum Button { Primary, Destructive, + Control, + Pin, } impl button::StyleSheet for Button { @@ -368,6 +444,8 @@ mod style { Button::Destructive => { (None, Color::from_rgb8(0xFF, 0x47, 0x47)) } + Button::Control => (Some(PANE_ID_COLOR_FOCUSED), Color::WHITE), + Button::Pin => (Some(ACTIVE), Color::WHITE), }; button::Style { @@ -388,6 +466,8 @@ mod style { a: 0.2, ..active.text_color }), + Button::Control => Some(PANE_ID_COLOR_FOCUSED), + Button::Pin => Some(HOVERED), }; button::Style { diff --git a/examples/pick_list/src/main.rs b/examples/pick_list/src/main.rs index 68662602..1eec9791 100644 --- a/examples/pick_list/src/main.rs +++ b/examples/pick_list/src/main.rs @@ -11,7 +11,7 @@ pub fn main() -> iced::Result { struct Example { scroll: scrollable::State, pick_list: pick_list::State<Language>, - selected_language: Language, + selected_language: Option<Language>, } #[derive(Debug, Clone, Copy)] @@ -33,7 +33,7 @@ impl Sandbox for Example { fn update(&mut self, message: Message) { match message { Message::LanguageSelected(language) => { - self.selected_language = language; + self.selected_language = Some(language); } } } @@ -42,9 +42,10 @@ impl Sandbox for Example { let pick_list = PickList::new( &mut self.pick_list, &Language::ALL[..], - Some(self.selected_language), + self.selected_language, Message::LanguageSelected, - ); + ) + .placeholder("Choose a language..."); let mut content = Scrollable::new(&mut self.scroll) .width(Length::Fill) diff --git a/examples/pokedex/src/main.rs b/examples/pokedex/src/main.rs index d2f1bb62..da1d5d5d 100644 --- a/examples/pokedex/src/main.rs +++ b/examples/pokedex/src/main.rs @@ -213,7 +213,10 @@ impl Pokemon { } async fn fetch_image(id: u16) -> Result<image::Handle, reqwest::Error> { - let url = format!("https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{}.png", id); + let url = format!( + "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/{}.png", + id + ); #[cfg(not(target_arch = "wasm32"))] { diff --git a/examples/scrollable/Cargo.toml b/examples/scrollable/Cargo.toml index 12753fb6..08502458 100644 --- a/examples/scrollable/Cargo.toml +++ b/examples/scrollable/Cargo.toml @@ -6,4 +6,4 @@ edition = "2018" publish = false [dependencies] -iced = { path = "../.." } +iced = { path = "../..", features = ["debug"] } diff --git a/examples/scrollable/src/main.rs b/examples/scrollable/src/main.rs index 8dd2e20c..3416b83d 100644 --- a/examples/scrollable/src/main.rs +++ b/examples/scrollable/src/main.rs @@ -1,8 +1,8 @@ mod style; use iced::{ - scrollable, Column, Container, Element, Length, Radio, Row, Rule, Sandbox, - Scrollable, Settings, Space, Text, + button, scrollable, Button, Column, Container, Element, Length, + ProgressBar, Radio, Row, Rule, Sandbox, Scrollable, Settings, Space, Text, }; pub fn main() -> iced::Result { @@ -17,6 +17,9 @@ struct ScrollableDemo { #[derive(Debug, Clone)] enum Message { ThemeChanged(style::Theme), + ScrollToTop(usize), + ScrollToBottom(usize), + Scrolled(usize, f32), } impl Sandbox for ScrollableDemo { @@ -36,6 +39,25 @@ impl Sandbox for ScrollableDemo { fn update(&mut self, message: Message) { match message { Message::ThemeChanged(theme) => self.theme = theme, + Message::ScrollToTop(i) => { + if let Some(variant) = self.variants.get_mut(i) { + variant.scrollable.snap_to(0.0); + + variant.latest_offset = 0.0; + } + } + Message::ScrollToBottom(i) => { + if let Some(variant) = self.variants.get_mut(i) { + variant.scrollable.snap_to(1.0); + + variant.latest_offset = 1.0; + } + } + Message::Scrolled(i, offset) => { + if let Some(variant) = self.variants.get_mut(i) { + variant.latest_offset = offset; + } + } } } @@ -62,13 +84,28 @@ impl Sandbox for ScrollableDemo { let scrollable_row = Row::with_children( variants .iter_mut() - .map(|variant| { - let mut scrollable = Scrollable::new(&mut variant.state) - .padding(10) - .width(Length::Fill) - .height(Length::Fill) - .style(*theme) - .push(Text::new(variant.title)); + .enumerate() + .map(|(i, variant)| { + let mut scrollable = + Scrollable::new(&mut variant.scrollable) + .padding(10) + .spacing(10) + .width(Length::Fill) + .height(Length::Fill) + .on_scroll(move |offset| { + Message::Scrolled(i, offset) + }) + .style(*theme) + .push(Text::new(variant.title)) + .push( + Button::new( + &mut variant.scroll_to_bottom, + Text::new("Scroll to bottom"), + ) + .width(Length::Fill) + .padding(10) + .on_press(Message::ScrollToBottom(i)), + ); if let Some(scrollbar_width) = variant.scrollbar_width { scrollable = scrollable @@ -108,12 +145,31 @@ impl Sandbox for ScrollableDemo { .push(Space::with_height(Length::Units(1200))) .push(Text::new("Middle")) .push(Space::with_height(Length::Units(1200))) - .push(Text::new("The End.")); - - Container::new(scrollable) + .push(Text::new("The End.")) + .push( + Button::new( + &mut variant.scroll_to_top, + Text::new("Scroll to top"), + ) + .width(Length::Fill) + .padding(10) + .on_press(Message::ScrollToTop(i)), + ); + + Column::new() .width(Length::Fill) .height(Length::Fill) - .style(*theme) + .spacing(10) + .push( + Container::new(scrollable) + .width(Length::Fill) + .height(Length::Fill) + .style(*theme), + ) + .push(ProgressBar::new( + 0.0..=1.0, + variant.latest_offset, + )) .into() }) .collect(), @@ -142,10 +198,13 @@ impl Sandbox for ScrollableDemo { /// A version of a scrollable struct Variant { title: &'static str, - state: scrollable::State, + scrollable: scrollable::State, + scroll_to_top: button::State, + scroll_to_bottom: button::State, scrollbar_width: Option<u16>, scrollbar_margin: Option<u16>, scroller_width: Option<u16>, + latest_offset: f32, } impl Variant { @@ -153,31 +212,43 @@ impl Variant { vec![ Self { title: "Default Scrollbar", - state: scrollable::State::new(), + scrollable: scrollable::State::new(), + scroll_to_top: button::State::new(), + scroll_to_bottom: button::State::new(), scrollbar_width: None, scrollbar_margin: None, scroller_width: None, + latest_offset: 0.0, }, Self { title: "Slimmed & Margin", - state: scrollable::State::new(), + scrollable: scrollable::State::new(), + scroll_to_top: button::State::new(), + scroll_to_bottom: button::State::new(), scrollbar_width: Some(4), scrollbar_margin: Some(3), scroller_width: Some(4), + latest_offset: 0.0, }, Self { title: "Wide Scroller", - state: scrollable::State::new(), + scrollable: scrollable::State::new(), + scroll_to_top: button::State::new(), + scroll_to_bottom: button::State::new(), scrollbar_width: Some(4), scrollbar_margin: None, scroller_width: Some(10), + latest_offset: 0.0, }, Self { title: "Narrow Scroller", - state: scrollable::State::new(), + scrollable: scrollable::State::new(), + scroll_to_top: button::State::new(), + scroll_to_bottom: button::State::new(), scrollbar_width: Some(10), scrollbar_margin: None, scroller_width: Some(4), + latest_offset: 0.0, }, ] } diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs index 8975fd9a..7bc49281 100644 --- a/examples/styling/src/main.rs +++ b/examples/styling/src/main.rs @@ -1,7 +1,7 @@ use iced::{ button, scrollable, slider, text_input, Align, Button, Checkbox, Column, Container, Element, Length, ProgressBar, Radio, Row, Rule, Sandbox, - Scrollable, Settings, Slider, Space, Text, TextInput, + Scrollable, Settings, Slider, Space, Text, TextInput, Toggler, }; pub fn main() -> iced::Result { @@ -17,7 +17,8 @@ struct Styling { button: button::State, slider: slider::State, slider_value: f32, - toggle_value: bool, + checkbox_value: bool, + toggler_value: bool, } #[derive(Debug, Clone)] @@ -27,6 +28,7 @@ enum Message { ButtonPressed, SliderChanged(f32), CheckboxToggled(bool), + TogglerToggled(bool), } impl Sandbox for Styling { @@ -44,9 +46,10 @@ impl Sandbox for Styling { match message { Message::ThemeChanged(theme) => self.theme = theme, Message::InputChanged(value) => self.input_value = value, - Message::ButtonPressed => (), + Message::ButtonPressed => {} Message::SliderChanged(value) => self.slider_value = value, - Message::CheckboxToggled(value) => self.toggle_value = value, + Message::CheckboxToggled(value) => self.checkbox_value = value, + Message::TogglerToggled(value) => self.toggler_value = value, } } @@ -101,11 +104,19 @@ impl Sandbox for Styling { .push(Text::new("You did it!")); let checkbox = Checkbox::new( - self.toggle_value, - "Toggle me!", + self.checkbox_value, + "Check me!", Message::CheckboxToggled, ) - .width(Length::Fill) + .style(self.theme); + + let toggler = Toggler::new( + self.toggler_value, + String::from("Toggle me!"), + Message::TogglerToggled, + ) + .width(Length::Shrink) + .spacing(10) .style(self.theme); let content = Column::new() @@ -124,7 +135,13 @@ impl Sandbox for Styling { .align_items(Align::Center) .push(scrollable) .push(Rule::vertical(38).style(self.theme)) - .push(checkbox), + .push( + Column::new() + .width(Length::Shrink) + .spacing(20) + .push(checkbox) + .push(toggler), + ), ); Container::new(content) @@ -140,7 +157,7 @@ impl Sandbox for Styling { mod style { use iced::{ button, checkbox, container, progress_bar, radio, rule, scrollable, - slider, text_input, + slider, text_input, toggler, }; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -231,6 +248,15 @@ mod style { } } + impl From<Theme> for Box<dyn toggler::StyleSheet> { + fn from(theme: Theme) -> Self { + match theme { + Theme::Light => Default::default(), + Theme::Dark => dark::Toggler.into(), + } + } + } + impl From<Theme> for Box<dyn rule::StyleSheet> { fn from(theme: Theme) -> Self { match theme { @@ -269,7 +295,7 @@ mod style { mod dark { use iced::{ button, checkbox, container, progress_bar, radio, rule, scrollable, - slider, text_input, Color, + slider, text_input, toggler, Color, }; const SURFACE: Color = Color::from_rgb( @@ -520,6 +546,35 @@ mod style { } } + pub struct Toggler; + + impl toggler::StyleSheet for Toggler { + fn active(&self, is_active: bool) -> toggler::Style { + toggler::Style { + background: if is_active { ACTIVE } else { SURFACE }, + background_border: None, + foreground: if is_active { Color::WHITE } else { ACTIVE }, + foreground_border: None, + } + } + + fn hovered(&self, is_active: bool) -> toggler::Style { + toggler::Style { + background: if is_active { ACTIVE } else { SURFACE }, + background_border: None, + foreground: if is_active { + Color { + a: 0.5, + ..Color::WHITE + } + } else { + Color { a: 0.5, ..ACTIVE } + }, + foreground_border: None, + } + } + } + pub struct Rule; impl rule::StyleSheet for Rule { diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs index e8755d39..1215f83d 100644 --- a/examples/tour/src/main.rs +++ b/examples/tour/src/main.rs @@ -1,7 +1,7 @@ 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, + Sandbox, Scrollable, Settings, Slider, Space, Text, TextInput, Toggler, }; pub fn main() -> iced::Result { @@ -135,6 +135,9 @@ impl Steps { color: Color::BLACK, }, Step::Radio { selection: None }, + Step::Toggler { + can_continue: false, + }, Step::Image { width: 300, slider: slider::State::new(), @@ -206,6 +209,9 @@ enum Step { Radio { selection: Option<Language>, }, + Toggler { + can_continue: bool, + }, Image { width: u16, slider: slider::State, @@ -232,6 +238,7 @@ pub enum StepMessage { InputChanged(String), ToggleSecureInput(bool), DebugToggled(bool), + TogglerChanged(bool), } impl<'a> Step { @@ -287,6 +294,11 @@ impl<'a> Step { *is_secure = toggle; } } + StepMessage::TogglerChanged(value) => { + if let Step::Toggler { can_continue, .. } = self { + *can_continue = value; + } + } }; } @@ -294,6 +306,7 @@ impl<'a> Step { match self { Step::Welcome => "Welcome", Step::Radio { .. } => "Radio button", + Step::Toggler { .. } => "Toggler", Step::Slider { .. } => "Slider", Step::Text { .. } => "Text", Step::Image { .. } => "Image", @@ -309,6 +322,7 @@ impl<'a> Step { match self { Step::Welcome => true, Step::Radio { selection } => *selection == Some(Language::Rust), + Step::Toggler { can_continue } => *can_continue, Step::Slider { .. } => true, Step::Text { .. } => true, Step::Image { .. } => true, @@ -324,6 +338,7 @@ impl<'a> Step { match self { Step::Welcome => Self::welcome(), Step::Radio { selection } => Self::radio(*selection), + Step::Toggler { can_continue } => Self::toggler(*can_continue), Step::Slider { state, value } => Self::slider(state, *value), Step::Text { size_slider, @@ -545,6 +560,21 @@ impl<'a> Step { )) } + fn toggler(can_continue: bool) -> Column<'a, StepMessage> { + Self::container("Toggler") + .push(Text::new( + "A toggler is mostly used to enable or disable something.", + )) + .push( + Container::new(Toggler::new( + can_continue, + String::from("Toggle me to continue..."), + StepMessage::TogglerChanged, + )) + .padding([0, 40]), + ) + } + fn image( width: u16, slider: &'a mut slider::State, diff --git a/examples/url_handler/Cargo.toml b/examples/url_handler/Cargo.toml new file mode 100644 index 00000000..911b2f25 --- /dev/null +++ b/examples/url_handler/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "url_handler" +version = "0.1.0" +authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"] +edition = "2018" +publish = false + +[dependencies] +iced = { path = "../.." } +iced_native = { path = "../../native" }
\ No newline at end of file diff --git a/examples/url_handler/src/main.rs b/examples/url_handler/src/main.rs new file mode 100644 index 00000000..f14e5227 --- /dev/null +++ b/examples/url_handler/src/main.rs @@ -0,0 +1,73 @@ +use iced::{ + executor, Application, Clipboard, Command, Container, Element, Length, + Settings, Subscription, Text, +}; +use iced_native::{ + event::{MacOS, PlatformSpecific}, + Event, +}; + +pub fn main() -> iced::Result { + App::run(Settings::default()) +} + +#[derive(Debug, Default)] +struct App { + url: Option<String>, +} + +#[derive(Debug, Clone)] +enum Message { + EventOccurred(iced_native::Event), +} + +impl Application for App { + type Executor = executor::Default; + type Message = Message; + type Flags = (); + + fn new(_flags: ()) -> (App, Command<Message>) { + (App::default(), Command::none()) + } + + fn title(&self) -> String { + String::from("Url - Iced") + } + + fn update( + &mut self, + message: Message, + _clipboard: &mut Clipboard, + ) -> Command<Message> { + match message { + Message::EventOccurred(event) => { + if let Event::PlatformSpecific(PlatformSpecific::MacOS( + MacOS::ReceivedUrl(url), + )) = event + { + self.url = Some(url); + } + } + }; + + Command::none() + } + + fn subscription(&self) -> Subscription<Message> { + iced_native::subscription::events().map(Message::EventOccurred) + } + + fn view(&mut self) -> Element<Message> { + let content = match &self.url { + Some(url) => Text::new(format!("{}", url)), + None => Text::new("No URL received yet!"), + }; + + Container::new(content.size(48)) + .width(Length::Fill) + .height(Length::Fill) + .center_x() + .center_y() + .into() + } +} |