summaryrefslogtreecommitdiffstats
path: root/examples/stopwatch
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-01-20 06:27:01 +0100
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-01-20 06:27:01 +0100
commit7cea7371150e6de28032827519936008592f112d (patch)
tree3bfd82272094ef69493de622af6c9b06389a7c27 /examples/stopwatch
parent04086a90c9e933ebfb42de378054e1115b33529d (diff)
downloadiced-7cea7371150e6de28032827519936008592f112d.tar.gz
iced-7cea7371150e6de28032827519936008592f112d.tar.bz2
iced-7cea7371150e6de28032827519936008592f112d.zip
Package examples and remove `dev-dependencies`
Diffstat (limited to 'examples/stopwatch')
-rw-r--r--examples/stopwatch/Cargo.toml12
-rw-r--r--examples/stopwatch/src/main.rs206
2 files changed, 218 insertions, 0 deletions
diff --git a/examples/stopwatch/Cargo.toml b/examples/stopwatch/Cargo.toml
new file mode 100644
index 00000000..1dae3b83
--- /dev/null
+++ b/examples/stopwatch/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "stopwatch"
+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" }
+iced_futures = { path = "../../futures", features = ["async-std"] }
+async-std = { version = "1.0", features = ["unstable"] }
diff --git a/examples/stopwatch/src/main.rs b/examples/stopwatch/src/main.rs
new file mode 100644
index 00000000..d84c4817
--- /dev/null
+++ b/examples/stopwatch/src/main.rs
@@ -0,0 +1,206 @@
+use iced::{
+ button, Align, Application, Button, Column, Command, Container, Element,
+ HorizontalAlignment, Length, Row, Settings, Subscription, Text,
+};
+use std::time::{Duration, Instant};
+
+pub fn main() {
+ Stopwatch::run(Settings::default())
+}
+
+struct Stopwatch {
+ duration: Duration,
+ state: State,
+ toggle: button::State,
+ reset: button::State,
+}
+
+enum State {
+ Idle,
+ Ticking { last_tick: Instant },
+}
+
+#[derive(Debug, Clone)]
+enum Message {
+ Toggle,
+ Reset,
+ Tick(Instant),
+}
+
+impl Application for Stopwatch {
+ type Executor = iced_futures::executor::AsyncStd;
+ type Message = Message;
+
+ fn new() -> (Stopwatch, Command<Message>) {
+ (
+ Stopwatch {
+ duration: Duration::default(),
+ state: State::Idle,
+ toggle: button::State::new(),
+ reset: button::State::new(),
+ },
+ Command::none(),
+ )
+ }
+
+ fn title(&self) -> String {
+ String::from("Stopwatch - Iced")
+ }
+
+ fn update(&mut self, message: Message) -> Command<Message> {
+ match message {
+ Message::Toggle => match self.state {
+ State::Idle => {
+ self.state = State::Ticking {
+ last_tick: Instant::now(),
+ };
+ }
+ State::Ticking { .. } => {
+ self.state = State::Idle;
+ }
+ },
+ Message::Tick(now) => match &mut self.state {
+ State::Ticking { last_tick } => {
+ self.duration += now - *last_tick;
+ *last_tick = now;
+ }
+ _ => {}
+ },
+ Message::Reset => {
+ self.duration = Duration::default();
+ }
+ }
+
+ Command::none()
+ }
+
+ fn subscription(&self) -> Subscription<Message> {
+ match self.state {
+ State::Idle => Subscription::none(),
+ State::Ticking { .. } => {
+ time::every(Duration::from_millis(10)).map(Message::Tick)
+ }
+ }
+ }
+
+ fn view(&mut self) -> Element<Message> {
+ const MINUTE: u64 = 60;
+ const HOUR: u64 = 60 * MINUTE;
+
+ let seconds = self.duration.as_secs();
+
+ let duration = Text::new(format!(
+ "{:0>2}:{:0>2}:{:0>2}.{:0>2}",
+ seconds / HOUR,
+ (seconds % HOUR) / MINUTE,
+ seconds % MINUTE,
+ self.duration.subsec_millis() / 10,
+ ))
+ .size(40);
+
+ let button = |state, label, style| {
+ Button::new(
+ state,
+ Text::new(label)
+ .horizontal_alignment(HorizontalAlignment::Center),
+ )
+ .min_width(80)
+ .padding(10)
+ .style(style)
+ };
+
+ let toggle_button = {
+ let (label, color) = match self.state {
+ State::Idle => ("Start", style::Button::Primary),
+ State::Ticking { .. } => ("Stop", style::Button::Destructive),
+ };
+
+ button(&mut self.toggle, label, color).on_press(Message::Toggle)
+ };
+
+ let reset_button =
+ button(&mut self.reset, "Reset", style::Button::Secondary)
+ .on_press(Message::Reset);
+
+ let controls = Row::new()
+ .spacing(20)
+ .push(toggle_button)
+ .push(reset_button);
+
+ let content = Column::new()
+ .align_items(Align::Center)
+ .spacing(20)
+ .push(duration)
+ .push(controls);
+
+ Container::new(content)
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .center_x()
+ .center_y()
+ .into()
+ }
+}
+
+mod time {
+ use iced::futures;
+
+ pub fn every(
+ duration: std::time::Duration,
+ ) -> iced::Subscription<std::time::Instant> {
+ iced::Subscription::from_recipe(Every(duration))
+ }
+
+ struct Every(std::time::Duration);
+
+ impl<H, I> iced_native::subscription::Recipe<H, I> for Every
+ where
+ H: std::hash::Hasher,
+ {
+ type Output = std::time::Instant;
+
+ fn hash(&self, state: &mut H) {
+ use std::hash::Hash;
+
+ std::any::TypeId::of::<Self>().hash(state);
+ self.0.hash(state);
+ }
+
+ fn stream(
+ self: Box<Self>,
+ _input: futures::stream::BoxStream<'static, I>,
+ ) -> futures::stream::BoxStream<'static, Self::Output> {
+ use futures::stream::StreamExt;
+
+ async_std::stream::interval(self.0)
+ .map(|_| std::time::Instant::now())
+ .boxed()
+ }
+ }
+}
+
+mod style {
+ use iced::{button, Background, Color, Vector};
+
+ pub enum Button {
+ Primary,
+ Secondary,
+ Destructive,
+ }
+
+ 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),
+ Button::Destructive => Color::from_rgb(0.8, 0.2, 0.2),
+ })),
+ border_radius: 12,
+ shadow_offset: Vector::new(1.0, 1.0),
+ text_color: Color::WHITE,
+ ..button::Style::default()
+ }
+ }
+ }
+}