summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/component/Cargo.toml10
-rw-r--r--examples/component/src/main.rs149
-rw-r--r--examples/custom_widget/src/main.rs9
-rw-r--r--examples/download_progress/Cargo.toml2
-rw-r--r--examples/download_progress/index.html12
-rw-r--r--examples/download_progress/src/download.rs103
-rw-r--r--examples/download_progress/src/main.rs20
-rw-r--r--examples/editor/src/main.rs44
-rw-r--r--examples/markdown/src/main.rs18
-rw-r--r--examples/multitouch/src/main.rs2
-rw-r--r--examples/pane_grid/src/main.rs22
-rw-r--r--examples/styling/src/main.rs10
-rw-r--r--examples/todos/src/main.rs3
-rw-r--r--examples/tour/src/main.rs10
14 files changed, 129 insertions, 285 deletions
diff --git a/examples/component/Cargo.toml b/examples/component/Cargo.toml
deleted file mode 100644
index 83b7b8a4..00000000
--- a/examples/component/Cargo.toml
+++ /dev/null
@@ -1,10 +0,0 @@
-[package]
-name = "component"
-version = "0.1.0"
-authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
-edition = "2021"
-publish = false
-
-[dependencies]
-iced.workspace = true
-iced.features = ["debug", "lazy"]
diff --git a/examples/component/src/main.rs b/examples/component/src/main.rs
deleted file mode 100644
index a5d2e508..00000000
--- a/examples/component/src/main.rs
+++ /dev/null
@@ -1,149 +0,0 @@
-use iced::widget::center;
-use iced::Element;
-
-use numeric_input::numeric_input;
-
-pub fn main() -> iced::Result {
- iced::run("Component - Iced", Component::update, Component::view)
-}
-
-#[derive(Default)]
-struct Component {
- value: Option<u32>,
-}
-
-#[derive(Debug, Clone, Copy)]
-enum Message {
- NumericInputChanged(Option<u32>),
-}
-
-impl Component {
- fn update(&mut self, message: Message) {
- match message {
- Message::NumericInputChanged(value) => {
- self.value = value;
- }
- }
- }
-
- fn view(&self) -> Element<Message> {
- center(numeric_input(self.value, Message::NumericInputChanged))
- .padding(20)
- .into()
- }
-}
-
-mod numeric_input {
- use iced::widget::{button, component, row, text, text_input, Component};
- use iced::{Center, Element, Fill, Length, Size};
-
- pub struct NumericInput<Message> {
- value: Option<u32>,
- on_change: Box<dyn Fn(Option<u32>) -> Message>,
- }
-
- pub fn numeric_input<Message>(
- value: Option<u32>,
- on_change: impl Fn(Option<u32>) -> Message + 'static,
- ) -> NumericInput<Message> {
- NumericInput::new(value, on_change)
- }
-
- #[derive(Debug, Clone)]
- pub enum Event {
- InputChanged(String),
- IncrementPressed,
- DecrementPressed,
- }
-
- impl<Message> NumericInput<Message> {
- pub fn new(
- value: Option<u32>,
- on_change: impl Fn(Option<u32>) -> Message + 'static,
- ) -> Self {
- Self {
- value,
- on_change: Box::new(on_change),
- }
- }
- }
-
- impl<Message, Theme> Component<Message, Theme> for NumericInput<Message>
- where
- Theme: text::Catalog + button::Catalog + text_input::Catalog + 'static,
- {
- type State = ();
- type Event = Event;
-
- fn update(
- &mut self,
- _state: &mut Self::State,
- event: Event,
- ) -> Option<Message> {
- match event {
- Event::IncrementPressed => Some((self.on_change)(Some(
- self.value.unwrap_or_default().saturating_add(1),
- ))),
- Event::DecrementPressed => Some((self.on_change)(Some(
- self.value.unwrap_or_default().saturating_sub(1),
- ))),
- Event::InputChanged(value) => {
- if value.is_empty() {
- Some((self.on_change)(None))
- } else {
- value
- .parse()
- .ok()
- .map(Some)
- .map(self.on_change.as_ref())
- }
- }
- }
- }
-
- fn view(&self, _state: &Self::State) -> Element<'_, Event, Theme> {
- let button = |label, on_press| {
- button(text(label).width(Fill).height(Fill).center())
- .width(40)
- .height(40)
- .on_press(on_press)
- };
-
- row![
- button("-", Event::DecrementPressed),
- text_input(
- "Type a number",
- self.value
- .as_ref()
- .map(u32::to_string)
- .as_deref()
- .unwrap_or(""),
- )
- .on_input(Event::InputChanged)
- .padding(10),
- button("+", Event::IncrementPressed),
- ]
- .align_y(Center)
- .spacing(10)
- .into()
- }
-
- fn size_hint(&self) -> Size<Length> {
- Size {
- width: Length::Fill,
- height: Length::Shrink,
- }
- }
- }
-
- impl<'a, Message, Theme> From<NumericInput<Message>>
- for Element<'a, Message, Theme>
- where
- Theme: text::Catalog + button::Catalog + text_input::Catalog + 'static,
- Message: 'a,
- {
- fn from(numeric_input: NumericInput<Message>) -> Self {
- component(numeric_input)
- }
- }
-}
diff --git a/examples/custom_widget/src/main.rs b/examples/custom_widget/src/main.rs
index dc3f74ac..58f3c54a 100644
--- a/examples/custom_widget/src/main.rs
+++ b/examples/custom_widget/src/main.rs
@@ -1,14 +1,5 @@
//! This example showcases a simple native custom widget that draws a circle.
mod circle {
- // For now, to implement a custom native widget you will need to add
- // `iced_native` and `iced_wgpu` to your dependencies.
- //
- // Then, you simply need to define your widget type and implement the
- // `iced_native::Widget` trait with the `iced_wgpu::Renderer`.
- //
- // Of course, you can choose to make the implementation renderer-agnostic,
- // if you wish to, by creating your own `Renderer` trait, which could be
- // implemented by `iced_wgpu` and other renderers.
use iced::advanced::layout::{self, Layout};
use iced::advanced::renderer;
use iced::advanced::widget::{self, Widget};
diff --git a/examples/download_progress/Cargo.toml b/examples/download_progress/Cargo.toml
index f78df529..61a1b257 100644
--- a/examples/download_progress/Cargo.toml
+++ b/examples/download_progress/Cargo.toml
@@ -12,4 +12,4 @@ iced.features = ["tokio"]
[dependencies.reqwest]
version = "0.12"
default-features = false
-features = ["rustls-tls"]
+features = ["stream", "rustls-tls"]
diff --git a/examples/download_progress/index.html b/examples/download_progress/index.html
new file mode 100644
index 00000000..c79e32c1
--- /dev/null
+++ b/examples/download_progress/index.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html lang="en" style="height: 100%">
+<head>
+ <meta charset="utf-8" content="text/html; charset=utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <title>Download_Progress - Iced</title>
+ <base data-trunk-public-url />
+</head>
+<body style="height: 100%; margin: 0">
+<link data-trunk rel="rust" href="Cargo.toml" data-wasm-opt="z" data-bin="download_progress" />
+</body>
+</html>
diff --git a/examples/download_progress/src/download.rs b/examples/download_progress/src/download.rs
index bdf57290..a8e7b404 100644
--- a/examples/download_progress/src/download.rs
+++ b/examples/download_progress/src/download.rs
@@ -1,91 +1,62 @@
-use iced::futures;
+use iced::futures::{SinkExt, Stream, StreamExt};
+use iced::stream::try_channel;
use iced::Subscription;
use std::hash::Hash;
+use std::sync::Arc;
// Just a little utility function
pub fn file<I: 'static + Hash + Copy + Send + Sync, T: ToString>(
id: I,
url: T,
-) -> iced::Subscription<(I, Progress)> {
+) -> iced::Subscription<(I, Result<Progress, Error>)> {
Subscription::run_with_id(
id,
- futures::stream::unfold(State::Ready(url.to_string()), move |state| {
- use iced::futures::FutureExt;
-
- download(id, state).map(Some)
- }),
+ download(url.to_string()).map(move |progress| (id, progress)),
)
}
-async fn download<I: Copy>(id: I, state: State) -> ((I, Progress), State) {
- match state {
- State::Ready(url) => {
- let response = reqwest::get(&url).await;
+fn download(url: String) -> impl Stream<Item = Result<Progress, Error>> {
+ try_channel(1, move |mut output| async move {
+ let response = reqwest::get(&url).await?;
+ let total = response.content_length().ok_or(Error::NoContentLength)?;
- match response {
- Ok(response) => {
- if let Some(total) = response.content_length() {
- (
- (id, Progress::Started),
- State::Downloading {
- response,
- total,
- downloaded: 0,
- },
- )
- } else {
- ((id, Progress::Errored), State::Finished)
- }
- }
- Err(_) => ((id, Progress::Errored), State::Finished),
- }
- }
- State::Downloading {
- mut response,
- total,
- downloaded,
- } => match response.chunk().await {
- Ok(Some(chunk)) => {
- let downloaded = downloaded + chunk.len() as u64;
+ let _ = output.send(Progress::Downloading { percent: 0.0 }).await;
+
+ let mut byte_stream = response.bytes_stream();
+ let mut downloaded = 0;
- let percentage = (downloaded as f32 / total as f32) * 100.0;
+ while let Some(next_bytes) = byte_stream.next().await {
+ let bytes = next_bytes?;
+ downloaded += bytes.len();
- (
- (id, Progress::Advanced(percentage)),
- State::Downloading {
- response,
- total,
- downloaded,
- },
- )
- }
- Ok(None) => ((id, Progress::Finished), State::Finished),
- Err(_) => ((id, Progress::Errored), State::Finished),
- },
- State::Finished => {
- // We do not let the stream die, as it would start a
- // new download repeatedly if the user is not careful
- // in case of errors.
- iced::futures::future::pending().await
+ let _ = output
+ .send(Progress::Downloading {
+ percent: 100.0 * downloaded as f32 / total as f32,
+ })
+ .await;
}
- }
+
+ let _ = output.send(Progress::Finished).await;
+
+ Ok(())
+ })
}
#[derive(Debug, Clone)]
pub enum Progress {
- Started,
- Advanced(f32),
+ Downloading { percent: f32 },
Finished,
- Errored,
}
-pub enum State {
- Ready(String),
- Downloading {
- response: reqwest::Response,
- total: u64,
- downloaded: u64,
- },
- Finished,
+#[derive(Debug, Clone)]
+pub enum Error {
+ RequestFailed(Arc<reqwest::Error>),
+ NoContentLength,
+}
+
+impl From<reqwest::Error> for Error {
+ fn from(error: reqwest::Error) -> Self {
+ Error::RequestFailed(Arc::new(error))
+ }
}
diff --git a/examples/download_progress/src/main.rs b/examples/download_progress/src/main.rs
index 667fb448..bcc01606 100644
--- a/examples/download_progress/src/main.rs
+++ b/examples/download_progress/src/main.rs
@@ -23,7 +23,7 @@ struct Example {
pub enum Message {
Add,
Download(usize),
- DownloadProgressed((usize, download::Progress)),
+ DownloadProgressed((usize, Result<download::Progress, download::Error>)),
}
impl Example {
@@ -114,19 +114,19 @@ impl Download {
}
}
- pub fn progress(&mut self, new_progress: download::Progress) {
+ pub fn progress(
+ &mut self,
+ new_progress: Result<download::Progress, download::Error>,
+ ) {
if let State::Downloading { progress } = &mut self.state {
match new_progress {
- download::Progress::Started => {
- *progress = 0.0;
+ Ok(download::Progress::Downloading { percent }) => {
+ *progress = percent;
}
- download::Progress::Advanced(percentage) => {
- *progress = percentage;
- }
- download::Progress::Finished => {
+ Ok(download::Progress::Finished) => {
self.state = State::Finished;
}
- download::Progress::Errored => {
+ Err(_error) => {
self.state = State::Errored;
}
}
@@ -136,7 +136,7 @@ impl Download {
pub fn subscription(&self) -> Subscription<Message> {
match self.state {
State::Downloading { .. } => {
- download::file(self.id, "https://speed.hetzner.de/100MB.bin?")
+ download::file(self.id, "https://huggingface.co/mattshumer/Reflection-Llama-3.1-70B/resolve/main/model-00001-of-00162.safetensors")
.map(Message::DownloadProgressed)
}
_ => Subscription::none(),
diff --git a/examples/editor/src/main.rs b/examples/editor/src/main.rs
index aa07b328..d55f9bdf 100644
--- a/examples/editor/src/main.rs
+++ b/examples/editor/src/main.rs
@@ -2,9 +2,9 @@ use iced::highlighter;
use iced::keyboard;
use iced::widget::{
self, button, column, container, horizontal_space, pick_list, row, text,
- text_editor, tooltip,
+ text_editor, toggler, tooltip,
};
-use iced::{Center, Element, Fill, Font, Subscription, Task, Theme};
+use iced::{Center, Element, Fill, Font, Task, Theme};
use std::ffi;
use std::io;
@@ -13,7 +13,6 @@ use std::sync::Arc;
pub fn main() -> iced::Result {
iced::application("Editor - Iced", Editor::update, Editor::view)
- .subscription(Editor::subscription)
.theme(Editor::theme)
.font(include_bytes!("../fonts/icons.ttf").as_slice())
.default_font(Font::MONOSPACE)
@@ -24,6 +23,7 @@ struct Editor {
file: Option<PathBuf>,
content: text_editor::Content,
theme: highlighter::Theme,
+ word_wrap: bool,
is_loading: bool,
is_dirty: bool,
}
@@ -32,6 +32,7 @@ struct Editor {
enum Message {
ActionPerformed(text_editor::Action),
ThemeSelected(highlighter::Theme),
+ WordWrapToggled(bool),
NewFile,
OpenFile,
FileOpened(Result<(PathBuf, Arc<String>), Error>),
@@ -46,6 +47,7 @@ impl Editor {
file: None,
content: text_editor::Content::new(),
theme: highlighter::Theme::SolarizedDark,
+ word_wrap: true,
is_loading: true,
is_dirty: false,
},
@@ -76,6 +78,11 @@ impl Editor {
Task::none()
}
+ Message::WordWrapToggled(word_wrap) => {
+ self.word_wrap = word_wrap;
+
+ Task::none()
+ }
Message::NewFile => {
if !self.is_loading {
self.file = None;
@@ -129,15 +136,6 @@ impl Editor {
}
}
- fn subscription(&self) -> Subscription<Message> {
- keyboard::on_key_press(|key, modifiers| match key.as_ref() {
- keyboard::Key::Character("s") if modifiers.command() => {
- Some(Message::SaveFile)
- }
- _ => None,
- })
- }
-
fn view(&self) -> Element<Message> {
let controls = row![
action(new_icon(), "New file", Some(Message::NewFile)),
@@ -152,6 +150,9 @@ impl Editor {
self.is_dirty.then_some(Message::SaveFile)
),
horizontal_space(),
+ toggler(self.word_wrap)
+ .label("Word Wrap")
+ .on_toggle(Message::WordWrapToggled),
pick_list(
highlighter::Theme::ALL,
Some(self.theme),
@@ -189,6 +190,11 @@ impl Editor {
text_editor(&self.content)
.height(Fill)
.on_action(Message::ActionPerformed)
+ .wrapping(if self.word_wrap {
+ text::Wrapping::Word
+ } else {
+ text::Wrapping::None
+ })
.highlight(
self.file
.as_deref()
@@ -196,7 +202,19 @@ impl Editor {
.and_then(ffi::OsStr::to_str)
.unwrap_or("rs"),
self.theme,
- ),
+ )
+ .key_binding(|key_press| {
+ match key_press.key.as_ref() {
+ keyboard::Key::Character("s")
+ if key_press.modifiers.command() =>
+ {
+ Some(text_editor::Binding::Custom(
+ Message::SaveFile,
+ ))
+ }
+ _ => text_editor::Binding::from_key_press(key_press),
+ }
+ }),
status,
]
.spacing(10)
diff --git a/examples/markdown/src/main.rs b/examples/markdown/src/main.rs
index eb51f985..5605478f 100644
--- a/examples/markdown/src/main.rs
+++ b/examples/markdown/src/main.rs
@@ -29,8 +29,7 @@ impl Markdown {
(
Self {
content: text_editor::Content::with_text(INITIAL_CONTENT),
- items: markdown::parse(INITIAL_CONTENT, theme.palette())
- .collect(),
+ items: markdown::parse(INITIAL_CONTENT).collect(),
theme,
},
widget::focus_next(),
@@ -45,11 +44,8 @@ impl Markdown {
self.content.perform(action);
if is_edit {
- self.items = markdown::parse(
- &self.content.text(),
- self.theme.palette(),
- )
- .collect();
+ self.items =
+ markdown::parse(&self.content.text()).collect();
}
}
Message::LinkClicked(link) => {
@@ -67,8 +63,12 @@ impl Markdown {
.font(Font::MONOSPACE)
.highlight("markdown", highlighter::Theme::Base16Ocean);
- let preview = markdown(&self.items, markdown::Settings::default())
- .map(Message::LinkClicked);
+ let preview = markdown(
+ &self.items,
+ markdown::Settings::default(),
+ markdown::Style::from_palette(self.theme.palette()),
+ )
+ .map(Message::LinkClicked);
row![editor, scrollable(preview).spacing(10).height(Fill)]
.spacing(10)
diff --git a/examples/multitouch/src/main.rs b/examples/multitouch/src/main.rs
index a0105a8a..d5e5dffa 100644
--- a/examples/multitouch/src/main.rs
+++ b/examples/multitouch/src/main.rs
@@ -126,7 +126,7 @@ impl canvas::Program<Message> for Multitouch {
let path = builder.build();
- let color_r = (10 % zone.0) as f32 / 20.0;
+ let color_r = (10 % (zone.0 + 1)) as f32 / 20.0;
let color_g = (10 % (zone.0 + 8)) as f32 / 20.0;
let color_b = (10 % (zone.0 + 3)) as f32 / 20.0;
diff --git a/examples/pane_grid/src/main.rs b/examples/pane_grid/src/main.rs
index f18fc5f3..67f4d27f 100644
--- a/examples/pane_grid/src/main.rs
+++ b/examples/pane_grid/src/main.rs
@@ -154,11 +154,23 @@ impl Example {
.spacing(5);
let title_bar = pane_grid::TitleBar::new(title)
- .controls(view_controls(
- id,
- total_panes,
- pane.is_pinned,
- is_maximized,
+ .controls(pane_grid::Controls::dynamic(
+ view_controls(
+ id,
+ total_panes,
+ pane.is_pinned,
+ is_maximized,
+ ),
+ button(text("X").size(14))
+ .style(button::danger)
+ .padding(3)
+ .on_press_maybe(
+ if total_panes > 1 && !pane.is_pinned {
+ Some(Message::Close(id))
+ } else {
+ None
+ },
+ ),
))
.padding(10)
.style(if is_focused {
diff --git a/examples/styling/src/main.rs b/examples/styling/src/main.rs
index 527aaa29..534f5e32 100644
--- a/examples/styling/src/main.rs
+++ b/examples/styling/src/main.rs
@@ -77,12 +77,10 @@ impl Styling {
let checkbox = checkbox("Check me!", self.checkbox_value)
.on_toggle(Message::CheckboxToggled);
- let toggler = toggler(
- String::from("Toggle me!"),
- self.toggler_value,
- Message::TogglerToggled,
- )
- .spacing(10);
+ let toggler = toggler(self.toggler_value)
+ .label("Toggle me!")
+ .on_toggle(Message::TogglerToggled)
+ .spacing(10);
let content = column![
choose_theme,
diff --git a/examples/todos/src/main.rs b/examples/todos/src/main.rs
index 86845f87..a5f7b36a 100644
--- a/examples/todos/src/main.rs
+++ b/examples/todos/src/main.rs
@@ -202,7 +202,8 @@ impl Todos {
.on_input(Message::InputChanged)
.on_submit(Message::CreateTask)
.padding(15)
- .size(30);
+ .size(30)
+ .align_x(Center);
let controls = view_controls(tasks, *filter);
let filtered_tasks =
diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs
index ee4754e6..d8c0b29a 100644
--- a/examples/tour/src/main.rs
+++ b/examples/tour/src/main.rs
@@ -357,11 +357,11 @@ impl Tour {
Self::container("Toggler")
.push("A toggler is mostly used to enable or disable something.")
.push(
- Container::new(toggler(
- "Toggle me to continue...".to_owned(),
- self.toggler,
- Message::TogglerChanged,
- ))
+ Container::new(
+ toggler(self.toggler)
+ .label("Toggle me to continue...")
+ .on_toggle(Message::TogglerChanged),
+ )
.padding([0, 40]),
)
}