From c3e94afd8c7266400e56fe8ad8d6340e72be43a5 Mon Sep 17 00:00:00 2001 From: genusistimelord Date: Wed, 26 Jul 2023 15:28:32 -0400 Subject: [PATCH] updated Date widget to latest iced --- .vscode/launch.json | 18 ++ Cargo.toml | 8 +- examples/date_picker/src/main.rs | 124 ++++++---- src/native/date_picker.rs | 104 ++++----- src/native/helpers.rs | 13 +- src/native/mod.rs | 2 +- src/native/overlay/date_picker.rs | 364 +++++++++++++++--------------- src/native/spinner.rs | 48 ++-- 8 files changed, 369 insertions(+), 312 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 4f35e916..cee075f9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -364,5 +364,23 @@ "args": [], "cwd": "${workspaceFolder}" }, + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'spinner'", + "cargo": { + "args": [ + "build", + "--bin=spinner", + "--package=spinner" + ], + "filter": { + "name": "spinner", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, ] } \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index fac76934..f6a275f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ default = [ "badge", "card", "number_input", - #"date_picker", + "date_picker", "color_picker", "floating_element", "icon_text", @@ -54,7 +54,7 @@ default = [ #"menu", "quad", "context_menu", - #"spinner", + "spinner", #"cupertino", ] @@ -94,7 +94,7 @@ members = [ # "examples/cupertino/cupertino_slider", #"examples/cupertino/cupertino_spinner", #"examples/cupertino/cupertino_switch", - #"examples/date_picker", + "examples/date_picker", "examples/floating_element", "examples/floating_element_anchors", "examples/grid", @@ -109,7 +109,7 @@ members = [ "examples/split", "examples/split_scroller", #"examples/menu", - #"examples/spinner", + "examples/spinner", "examples/context_menu" ] diff --git a/examples/date_picker/src/main.rs b/examples/date_picker/src/main.rs index 41d74a93..1789603e 100644 --- a/examples/date_picker/src/main.rs +++ b/examples/date_picker/src/main.rs @@ -1,6 +1,7 @@ use iced::{ - widget::{Button, Container, Row, Text}, - Alignment, Element, Length, Sandbox, Settings, + alignment, font, + widget::{container, text, Button, Container, Row, Text}, + Alignment, Application, Command, Element, Length, Settings, Theme, }; use iced_aw::{date_picker::Date, helpers::date_picker}; @@ -14,65 +15,108 @@ enum Message { ChooseDate, SubmitDate(Date), CancelDate, + Loaded(Result<(), String>), + FontLoaded(Result<(), font::Error>), } -struct DatePickerExample { +enum DatePickerExample { + Loading, + Loaded(State), +} + +struct State { date: Date, show_picker: bool, } -impl Sandbox for DatePickerExample { +async fn load() -> Result<(), String> { + Ok(()) +} + +impl Application for DatePickerExample { type Message = Message; + type Theme = Theme; + type Executor = iced::executor::Default; + type Flags = (); - fn new() -> Self { - DatePickerExample { - date: Date::today(), - show_picker: false, - } + fn new(_flags: ()) -> (DatePickerExample, Command) { + ( + DatePickerExample::Loading, + Command::batch(vec![ + font::load(iced_aw::graphics::icons::ICON_FONT_BYTES).map(Message::FontLoaded), + Command::perform(load(), Message::Loaded), + ]), + ) } fn title(&self) -> String { String::from("DatePicker example") } - fn update(&mut self, message: Self::Message) { - match message { - Message::ChooseDate => { - //self.state.reset(); - self.show_picker = true; - } - Message::SubmitDate(date) => { - self.date = date; - self.show_picker = false; - } - Message::CancelDate => { - self.show_picker = false; + fn update(&mut self, message: Self::Message) -> Command { + match self { + DatePickerExample::Loading => { + if let Message::Loaded(_) = message { + *self = DatePickerExample::Loaded(State { + date: Date::today(), + show_picker: false, + }) + } } + DatePickerExample::Loaded(state) => match message { + Message::ChooseDate => { + state.show_picker = true; + } + Message::SubmitDate(date) => { + state.date = date; + state.show_picker = false; + } + Message::CancelDate => { + state.show_picker = false; + } + _ => {} + }, } + + Command::none() } fn view(&self) -> Element<'_, Self::Message> { - let but = Button::new(Text::new("Set Date")).on_press(Message::ChooseDate); + match self { + DatePickerExample::Loading => container( + text("Loading...") + .horizontal_alignment(alignment::Horizontal::Center) + .size(50), + ) + .width(Length::Fill) + .height(Length::Fill) + .center_y() + .center_x() + .into(), + DatePickerExample::Loaded(state) => { + let but = Button::new(Text::new("Set Date")).on_press(Message::ChooseDate); - let datepicker = date_picker( - self.show_picker, - self.date, - but, - Message::CancelDate, - Message::SubmitDate, - ); + let datepicker = date_picker( + state.show_picker, + state.date, + but, + Message::CancelDate, + Message::SubmitDate, + ); - let row = Row::new() - .align_items(Alignment::Center) - .spacing(10) - .push(datepicker) - .push(Text::new(format!("Date: {}", self.date,))); + let row = Row::new() + .align_items(Alignment::Center) + .spacing(10) + .push(datepicker) + .push(Text::new(format!("Date: {}", state.date,))); - Container::new(row) - .center_x() - .center_y() - .width(Length::Fill) - .height(Length::Fill) - .into() + Container::new(row) + .center_x() + .center_y() + .width(Length::Fill) + .height(Length::Fill) + .into() + } + } } } diff --git a/src/native/date_picker.rs b/src/native/date_picker.rs index 92012c04..41446a11 100644 --- a/src/native/date_picker.rs +++ b/src/native/date_picker.rs @@ -3,12 +3,22 @@ //! *This API requires the following crate features to be activated: `date_picker`* use chrono::Local; -use iced_graphics::{Backend, Renderer}; -use iced_native::widget::button; -use iced_native::widget::tree::{self, Tag}; -use iced_native::widget::Tree; -use iced_native::{event, mouse, Clipboard, Event, Layout, Point, Rectangle, Shell}; -use iced_native::{Element, Widget}; +use iced_widget::{ + button, container, + core::{ + self, event, + layout::{Limits, Node}, + mouse::{self, Cursor}, + renderer, + widget::{ + self, + tree::{Tag, Tree}, + }, + Clipboard, Element, Event, Layout, Length, Point, Rectangle, Shell, Widget, + }, + renderer::Renderer, + text, +}; pub use crate::core::date::Date; @@ -43,10 +53,9 @@ use super::overlay::date_picker::{self, DatePickerOverlay, DatePickerOverlayButt /// ); /// ``` #[allow(missing_debug_implementations)] -pub struct DatePicker<'a, Message, B, Theme> +pub struct DatePicker<'a, Message, Theme> where Message: Clone, - B: Backend + iced_graphics::backend::Text, Theme: StyleSheet + button::StyleSheet, { /// Show the picker. @@ -54,7 +63,7 @@ where /// The date to show. date: Date, /// The underlying element. - underlay: Element<'a, Message, Renderer>, + underlay: Element<'a, Message, Renderer>, /// The message that is send if the cancel button of the [`DatePickerOverlay`](DatePickerOverlay) is pressed. on_cancel: Message, /// The function that produces a message when the submit button of the [`DatePickerOverlay`](DatePickerOverlay) is pressed. @@ -62,19 +71,14 @@ where /// The style of the [`DatePickerOverlay`](DatePickerOverlay). style: ::Style, /// The buttons of the overlay. - overlay_state: Element<'a, Message, Renderer>, + overlay_state: Element<'a, Message, Renderer>, //button_style: ::Style, // clone not satisfied } -impl<'a, Message, B, Theme> DatePicker<'a, Message, B, Theme> +impl<'a, Message, Theme> DatePicker<'a, Message, Theme> where Message: 'a + Clone, - B: 'a + Backend + iced_graphics::backend::Text, - Theme: 'a - + StyleSheet - + button::StyleSheet - + iced_style::text::StyleSheet - + iced_style::container::StyleSheet, + Theme: 'a + StyleSheet + button::StyleSheet + text::StyleSheet + container::StyleSheet, { /// Creates a new [`DatePicker`](DatePicker) wrapping around the given underlay. /// @@ -95,7 +99,7 @@ where on_submit: F, ) -> Self where - U: Into>>, + U: Into>>, F: 'static + Fn(Date) -> Message, { Self { @@ -149,22 +153,17 @@ impl State { } } -impl<'a, Message, B, Theme> Widget> - for DatePicker<'a, Message, B, Theme> +impl<'a, Message, Theme> Widget> for DatePicker<'a, Message, Theme> where Message: 'static + Clone, - B: 'a + Backend + iced_graphics::backend::Text, - Theme: StyleSheet - + button::StyleSheet - + iced_style::text::StyleSheet - + iced_style::container::StyleSheet, + Theme: StyleSheet + button::StyleSheet + text::StyleSheet + container::StyleSheet, { fn tag(&self) -> Tag { Tag::of::() } - fn state(&self) -> tree::State { - tree::State::new(State::new(self.date)) + fn state(&self) -> widget::tree::State { + widget::tree::State::new(State::new(self.date)) } fn children(&self) -> Vec { @@ -175,19 +174,15 @@ where tree.diff_children(&[&self.underlay, &self.overlay_state]); } - fn width(&self) -> iced_native::Length { + fn width(&self) -> Length { self.underlay.as_widget().width() } - fn height(&self) -> iced_native::Length { + fn height(&self) -> Length { self.underlay.as_widget().width() } - fn layout( - &self, - renderer: &Renderer, - limits: &iced_native::layout::Limits, - ) -> iced_native::layout::Node { + fn layout(&self, renderer: &Renderer, limits: &Limits) -> Node { self.underlay.as_widget().layout(renderer, limits) } @@ -196,19 +191,21 @@ where state: &mut Tree, event: Event, layout: Layout<'_>, - cursor_position: Point, - renderer: &Renderer, + cursor: Cursor, + renderer: &Renderer, clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, + viewport: &Rectangle, ) -> event::Status { self.underlay.as_widget_mut().on_event( &mut state.children[0], event, layout, - cursor_position, + cursor, renderer, clipboard, shell, + viewport, ) } @@ -216,14 +213,14 @@ where &self, state: &Tree, layout: Layout<'_>, - cursor_position: Point, + cursor: Cursor, viewport: &Rectangle, - renderer: &Renderer, + renderer: &Renderer, ) -> mouse::Interaction { self.underlay.as_widget().mouse_interaction( &state.children[0], layout, - cursor_position, + cursor, viewport, renderer, ) @@ -231,12 +228,12 @@ where fn draw( &self, - state: &iced_native::widget::Tree, - renderer: &mut Renderer, + state: &Tree, + renderer: &mut Renderer, theme: &Theme, - style: &iced_native::renderer::Style, + style: &renderer::Style, layout: Layout<'_>, - cursor_position: Point, + cursor: Cursor, viewport: &Rectangle, ) { self.underlay.as_widget().draw( @@ -245,7 +242,7 @@ where theme, style, layout, - cursor_position, + cursor, viewport, ); } @@ -254,8 +251,8 @@ where &'b mut self, state: &'b mut Tree, layout: Layout<'_>, - renderer: &Renderer, - ) -> Option>> { + renderer: &Renderer, + ) -> Option>> { let picker_state: &mut State = state.state.downcast_mut(); if !self.show_picker { @@ -283,18 +280,13 @@ where } } -impl<'a, Message, B, Theme> From> - for Element<'a, Message, Renderer> +impl<'a, Message, Theme> From> + for Element<'a, Message, Renderer> where Message: 'static + Clone, - B: 'a + Backend + iced_graphics::backend::Text, - Theme: 'a - + StyleSheet - + button::StyleSheet - + iced_style::text::StyleSheet - + iced_style::container::StyleSheet, + Theme: 'a + StyleSheet + button::StyleSheet + text::StyleSheet + container::StyleSheet, { - fn from(date_picker: DatePicker<'a, Message, B, Theme>) -> Self { + fn from(date_picker: DatePicker<'a, Message, Theme>) -> Self { Element::new(date_picker) } } diff --git a/src/native/helpers.rs b/src/native/helpers.rs index 1eb47894..a1409e0f 100644 --- a/src/native/helpers.rs +++ b/src/native/helpers.rs @@ -150,21 +150,20 @@ where #[cfg(feature = "date_picker")] /// Shortcut helper to create a ``ColorPicker`` Widget. -pub fn date_picker<'a, Message, B, Theme, F>( +pub fn date_picker<'a, Message, Theme, F>( show_picker: bool, date: impl Into, - underlay: impl Into>>, + underlay: impl Into>>, on_cancel: Message, on_submit: F, -) -> crate::DatePicker<'a, Message, B, Theme> +) -> crate::DatePicker<'a, Message, Theme> where Message: 'a + Clone, - B: 'a + iced_graphics::Backend + iced_graphics::backend::Text, Theme: 'a + crate::style::date_picker::StyleSheet - + iced_style::button::StyleSheet - + iced_style::text::StyleSheet - + iced_style::container::StyleSheet, + + iced_widget::button::StyleSheet + + iced_widget::text::StyleSheet + + iced_widget::container::StyleSheet, F: 'static + Fn(crate::core::date::Date) -> Message, { crate::DatePicker::new(show_picker, date, underlay, on_cancel, on_submit) diff --git a/src/native/mod.rs b/src/native/mod.rs index d0273939..6d71462b 100644 --- a/src/native/mod.rs +++ b/src/native/mod.rs @@ -122,7 +122,7 @@ pub mod spinner; #[cfg(feature = "spinner")] /// A spinner widget, a circle spinning around the center of the widget. -pub type Spinner = spinner::Spinner>; +pub type Spinner = spinner::Spinner; #[cfg(feature = "context_menu")] pub mod context_menu; diff --git a/src/native/overlay/date_picker.rs b/src/native/overlay/date_picker.rs index 9f91f24d..a4177fa5 100644 --- a/src/native/overlay/date_picker.rs +++ b/src/native/overlay/date_picker.rs @@ -4,17 +4,24 @@ use std::collections::HashMap; use chrono::{Datelike, Local, NaiveDate}; -use iced_graphics::{Backend, Renderer}; -use iced_native::{ - alignment::{Horizontal, Vertical}, - event, keyboard, - layout::{self, Limits}, - mouse, overlay, renderer, - text::Renderer as _, - touch, - widget::{Button, Column, Container, Row, Text, Tree}, - Alignment, Clipboard, Color, Element, Event, Layout, Length, Padding, Point, Rectangle, - Renderer as _, Shell, Size, Widget, + +use iced_widget::{ + button, container, + core::{ + self, + alignment::{Horizontal, Vertical}, + event, keyboard, + layout::{Limits, Node}, + mouse::{self, Cursor}, + overlay, renderer, + text::Renderer as _, + touch, + widget::tree::Tree, + Alignment, Clipboard, Color, Element, Event, Layout, Length, Overlay, Padding, Point, + Rectangle, Renderer as _, Shell, Size, Widget, + }, + renderer::Renderer, + text, Button, Column, Container, Row, Text, }; use crate::{ @@ -41,18 +48,17 @@ const BUTTON_SPACING: f32 = 5.0; /// The overlay of the [`DatePicker`](crate::native::DatePicker). #[allow(missing_debug_implementations)] -pub struct DatePickerOverlay<'a, Message, B, Theme> +pub struct DatePickerOverlay<'a, Message, Theme> where Message: Clone, - B: Backend, - Theme: StyleSheet + iced_style::button::StyleSheet, + Theme: StyleSheet + button::StyleSheet, { /// The state of the [`DatePickerOverlay`](DatePickerOverlay). state: &'a mut State, /// The cancel button of the [`DatePickerOverlay`](DatePickerOverlay). - cancel_button: Button<'a, Message, Renderer>, + cancel_button: Button<'a, Message, Renderer>, /// The submit button of the [`DatePickerOverlay`](DatePickerOverlay). - submit_button: Button<'a, Message, Renderer>, + submit_button: Button<'a, Message, Renderer>, /// The function that produces a message when the submit button of the [`DatePickerOverlay`](DatePickerOverlay) is pressed. on_submit: &'a dyn Fn(Date) -> Message, /// The position of the [`DatePickerOverlay`](DatePickerOverlay). @@ -63,15 +69,10 @@ where tree: &'a mut Tree, } -impl<'a, Message, B, Theme> DatePickerOverlay<'a, Message, B, Theme> +impl<'a, Message, Theme> DatePickerOverlay<'a, Message, Theme> where Message: 'static + Clone, - B: 'a + Backend + iced_graphics::backend::Text, - Theme: 'a - + StyleSheet - + iced_style::button::StyleSheet - + iced_style::text::StyleSheet - + iced_style::container::StyleSheet, + Theme: 'a + StyleSheet + button::StyleSheet + text::StyleSheet + container::StyleSheet, { /// Creates a new [`DatePickerOverlay`](DatePickerOverlay) on the given /// position. @@ -90,11 +91,9 @@ where state: overlay_state, cancel_button: Button::new(IconText::new(Icon::X).width(Length::Fill)) .width(Length::Fill) - //.style(button_style.clone()) .on_press(on_cancel.clone()), submit_button: Button::new(IconText::new(Icon::Check).width(Length::Fill)) .width(Length::Fill) - //.style(button_style) .on_press(on_cancel), // Sending a fake message on_submit, position, @@ -106,7 +105,7 @@ where /// Turn this [`DatePickerOverlay`](DatePickerOverlay) into an overlay /// [`Element`](overlay::Element). #[must_use] - pub fn overlay(self) -> overlay::Element<'a, Message, Renderer> { + pub fn overlay(self) -> overlay::Element<'a, Message, Renderer> { overlay::Element::new(self.position, Box::new(self)) } @@ -125,9 +124,9 @@ where &mut self, event: &Event, layout: Layout<'_>, - cursor_position: Point, + cursor: Cursor, _messages: &mut Shell, - _renderer: &Renderer, + _renderer: &Renderer, _clipboard: &mut dyn Clipboard, ) -> event::Status { let mut children = layout.children(); @@ -156,14 +155,14 @@ where match event { Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) | Event::Touch(touch::Event::FingerPressed { .. }) => { - if month_layout.bounds().contains(cursor_position) { + if cursor.is_over(month_layout.bounds()) { self.state.focus = Focus::Month; } - if left_bounds.contains(cursor_position) { + if cursor.is_over(left_bounds) { self.state.date = crate::core::date::pred_month(self.state.date); status = event::Status::Captured; - } else if right_bounds.contains(cursor_position) { + } else if cursor.is_over(right_bounds) { self.state.date = crate::core::date::succ_month(self.state.date); status = event::Status::Captured; } @@ -193,14 +192,14 @@ where match event { Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) | Event::Touch(touch::Event::FingerPressed { .. }) => { - if year_layout.bounds().contains(cursor_position) { + if cursor.is_over(year_layout.bounds()) { self.state.focus = Focus::Year; } - if left_bounds.contains(cursor_position) { + if cursor.is_over(left_bounds) { self.state.date = crate::core::date::pred_year(self.state.date); status = event::Status::Captured; - } else if right_bounds.contains(cursor_position) { + } else if cursor.is_over(right_bounds) { self.state.date = crate::core::date::succ_year(self.state.date); status = event::Status::Captured; } @@ -216,9 +215,9 @@ where &mut self, event: &Event, layout: Layout<'_>, - cursor_position: Point, + cursor: Cursor, _messages: &mut Shell, - _renderer: &Renderer, + _renderer: &Renderer, _clipboard: &mut dyn Clipboard, ) -> event::Status { let mut children = layout.children(); @@ -232,14 +231,14 @@ where match event { Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) | Event::Touch(touch::Event::FingerPressed { .. }) => { - if layout.bounds().contains(cursor_position) { + if cursor.is_over(layout.bounds()) { self.state.focus = Focus::Day; } 'outer: for (y, row) in children.enumerate() { for (x, label) in row.children().enumerate() { let bounds = label.bounds(); - if bounds.contains(cursor_position) { + if cursor.is_over(bounds) { let (day, is_in_month) = crate::core::date::position_to_day( x, y, @@ -280,9 +279,9 @@ where &mut self, event: &Event, _layout: Layout<'_>, - _cursor_position: Point, + _cursor: Cursor, _messages: &mut Shell, - _renderer: &Renderer, + _renderer: &Renderer, _clipboard: &mut dyn Clipboard, ) -> event::Status { if self.state.focus == Focus::None { @@ -356,24 +355,13 @@ where } } -impl<'a, Message, B, Theme> iced_native::Overlay> - for DatePickerOverlay<'a, Message, B, Theme> +impl<'a, Message, Theme> Overlay> for DatePickerOverlay<'a, Message, Theme> where Message: 'static + Clone, - B: 'a + Backend + iced_graphics::backend::Text, - Theme: 'a - + StyleSheet - + iced_style::button::StyleSheet - + iced_style::text::StyleSheet - + iced_style::container::StyleSheet, + Theme: 'a + StyleSheet + button::StyleSheet + text::StyleSheet + container::StyleSheet, { #[allow(clippy::too_many_lines)] - fn layout( - &self, - renderer: &Renderer, - bounds: iced_graphics::Size, - position: Point, - ) -> iced_native::layout::Node { + fn layout(&self, renderer: &Renderer, bounds: Size, position: Point) -> Node { let limits = Limits::new(Size::ZERO, bounds) .pad(Padding::from(PADDING)) .width(Length::Fill) @@ -390,7 +378,7 @@ where // Month/Year let font_size = renderer.default_size(); - let month_year = Row::<(), Renderer>::new() + let month_year = Row::<(), Renderer>::new() .width(Length::Fill) .spacing(SPACING) .push( @@ -399,22 +387,30 @@ where .push( Container::new( Row::new() // Left Month arrow - .width(Length::Fixed(font_size)), + .width(Length::Shrink) + .push( + Text::new(char::from(Icon::CaretLeftFill).to_string()) + .size(font_size + 1.0) + .font(ICON_FONT), + ), ) - .height(Length::Fill) - .max_height(font_size), + .height(Length::Shrink), ) .push( // Month - Text::new("") + Text::new("October") .width(Length::Fill) - .height(Length::Fixed(font_size)), + .height(Length::Shrink), ) .push( // Right Month arrow - Container::new(Row::new().width(Length::Fixed(font_size))) - .height(Length::Fill) - .max_height(font_size), + Container::new( + Text::new(char::from(Icon::CaretRightFill).to_string()) + .size(font_size + 1.0) + .font(ICON_FONT), + ) + .height(Length::Shrink) + .width(Length::Shrink), ), ) .push( @@ -423,26 +419,38 @@ where .push( Container::new( Row::new() // Left Year arrow - .width(Length::Fixed(font_size)), + .width(Length::Shrink) + .push( + Text::new(char::from(Icon::CaretLeftFill).to_string()) + .size(font_size + 1.0) + .font(ICON_FONT), + ), ) - .height(Length::Fill) - .max_height(font_size), + .height(Length::Shrink) + .width(Length::Shrink), ) .push( // Year - Text::new("") - .width(Length::Fill) - .height(Length::Fixed(font_size)), + Text::new("9999").width(Length::Fill).height(Length::Shrink), ) .push( // Right Year arrow - Container::new(Row::new().width(Length::Fixed(font_size))) - .height(Length::Fill) - .max_height(font_size), + Container::new( + Row::new() + .width(Length::Shrink) + .height(Length::Shrink) + .push( + Text::new(char::from(Icon::CaretRightFill).to_string()) + .size(font_size + 1.0) + .font(ICON_FONT), + ), + ) + .height(Length::Shrink) + .width(Length::Shrink), ), ); - let days = Container::<(), Renderer>::new((0..7).fold( + let days = Container::<(), Renderer>::new((0..7).fold( Column::new().width(Length::Fill).height(Length::Fill), |column, _y| { column.push( @@ -453,10 +461,14 @@ where .padding(DAY_CELL_PADDING), |row, _x| { row.push( - Container::new(Row::new().width(Length::Fill).height(Length::Fill)) - .width(Length::Fill) - .height(Length::Fill) - .max_height(font_size), + Container::new( + Row::new() + .width(Length::Shrink) + .height(Length::Shrink) + .push(Text::new("31").size(font_size)), + ) + .width(Length::Fill) + .height(Length::Shrink), ) }, ), @@ -467,7 +479,7 @@ where .height(Length::Fill) .center_y(); - let mut col = Column::<(), Renderer>::new() + let mut col = Column::<(), Renderer>::new() .spacing(SPACING) .align_items(Alignment::Center) .push(month_year) @@ -501,7 +513,7 @@ where y: submit_button.bounds().y + col.bounds().height + PADDING + SPACING, }); - let mut node = layout::Node::with_children( + let mut node = Node::with_children( Size::new( col.bounds().width + (2.0 * PADDING), col.bounds().height + cancel_button.bounds().height + (2.0 * PADDING) + SPACING, @@ -518,13 +530,13 @@ where &mut self, event: Event, layout: Layout<'_>, - cursor_position: Point, - renderer: &Renderer, + cursor: Cursor, + renderer: &Renderer, clipboard: &mut dyn Clipboard, shell: &mut Shell, ) -> event::Status { if event::Status::Captured - == self.on_event_keyboard(&event, layout, cursor_position, shell, renderer, clipboard) + == self.on_event_keyboard(&event, layout, cursor, shell, renderer, clipboard) { return event::Status::Captured; } @@ -543,7 +555,7 @@ where let month_year_status = self.on_event_month_year( &event, month_year_layout, - cursor_position, + cursor, shell, renderer, clipboard, @@ -556,14 +568,8 @@ where .children() .next() .expect("Native: Layout should have a days table layout"); - let days_status = self.on_event_days( - &event, - days_layout, - cursor_position, - shell, - renderer, - clipboard, - ); + let days_status = + self.on_event_days(&event, days_layout, cursor, shell, renderer, clipboard); // ----------- Buttons ------------------------ let cancel_button_layout = children @@ -574,10 +580,11 @@ where &mut self.tree.children[0], event.clone(), cancel_button_layout, - cursor_position, + cursor, renderer, clipboard, shell, + &layout.bounds(), ); let submit_button_layout = children @@ -590,10 +597,11 @@ where &mut self.tree.children[1], event, submit_button_layout, - cursor_position, + cursor, renderer, clipboard, &mut Shell::new(&mut fake_messages), + &layout.bounds(), ); if !fake_messages.is_empty() { @@ -609,9 +617,9 @@ where fn mouse_interaction( &self, layout: Layout<'_>, - cursor_position: Point, - viewport: &iced_graphics::Rectangle, - renderer: &Renderer, + cursor: Cursor, + viewport: &Rectangle, + renderer: &Renderer, ) -> mouse::Interaction { let mouse_interaction = mouse::Interaction::default(); @@ -633,7 +641,7 @@ where .next() .expect("Graphics: Layout should have a year layout"); - let f = |layout: iced_native::Layout<'_>| { + let f = |layout: Layout<'_>| { let mut children = layout.children(); let left_bounds = children @@ -648,8 +656,8 @@ where let mut mouse_interaction = mouse::Interaction::default(); - let left_arrow_hovered = left_bounds.contains(cursor_position); - let right_arrow_hovered = right_bounds.contains(cursor_position); + let left_arrow_hovered = cursor.is_over(left_bounds); + let right_arrow_hovered = cursor.is_over(right_bounds); if left_arrow_hovered || right_arrow_hovered { mouse_interaction = mouse_interaction.max(mouse::Interaction::Pointer); @@ -677,7 +685,7 @@ where for label in row.children() { let bounds = label.bounds(); - let mouse_over = bounds.contains(cursor_position); + let mouse_over = cursor.is_over(bounds); if mouse_over { table_mouse_interaction = table_mouse_interaction.max(mouse::Interaction::Pointer); @@ -693,7 +701,7 @@ where let cancel_button_mouse_interaction = self.cancel_button.mouse_interaction( &self.tree.children[0], cancel_button_layout, - cursor_position, + cursor, viewport, renderer, ); @@ -705,7 +713,7 @@ where let submit_button_mouse_interaction = self.submit_button.mouse_interaction( &self.tree.children[1], submit_button_layout, - cursor_position, + cursor, viewport, renderer, ); @@ -720,11 +728,11 @@ where fn draw( &self, - renderer: &mut Renderer, - theme: & as iced_native::Renderer>::Theme, - style: &iced_native::renderer::Style, + renderer: &mut Renderer, + theme: &Theme, + style: &renderer::Style, layout: Layout<'_>, - cursor_position: Point, + cursor: Cursor, ) { let bounds = layout.bounds(); let mut children = layout.children(); @@ -746,7 +754,7 @@ where if self.state.focus == Focus::Overlay { style_state = style_state.max(StyleState::Focused); } - if bounds.contains(cursor_position) { + if cursor.is_over(bounds) { style_state = style_state.max(StyleState::Hovered); } @@ -771,7 +779,7 @@ where month_year_layout, &self.month_as_string(), &self.year_as_string(), - cursor_position, + cursor.position().unwrap_or_default(), &style_sheet, self.state.focus, ); @@ -788,7 +796,7 @@ where renderer, days_layout, self.state.date, - cursor_position, + cursor.position().unwrap_or_default(), &style_sheet, self.state.focus, ); @@ -804,7 +812,7 @@ where theme, style, cancel_button_layout, - cursor_position, + cursor, &bounds, ); @@ -818,7 +826,7 @@ where theme, style, submit_button_layout, - cursor_position, + cursor, &bounds, ); @@ -883,27 +891,21 @@ impl Default for State { /// Just a workaround to pass the button states from the tree to the overlay #[allow(missing_debug_implementations)] -pub struct DatePickerOverlayButtons<'a, Message, B, Theme> +pub struct DatePickerOverlayButtons<'a, Message, Theme> where Message: Clone, - B: Backend, - Theme: StyleSheet + iced_style::button::StyleSheet, + Theme: StyleSheet + button::StyleSheet, { /// The cancel button of the [`DatePickerOverlay`](DatePickerOverlay). - cancel_button: Element<'a, Message, Renderer>, + cancel_button: Element<'a, Message, Renderer>, /// The submit button of the [`DatePickerOverlay`](DatePickerOverlay). - submit_button: Element<'a, Message, Renderer>, + submit_button: Element<'a, Message, Renderer>, } -impl<'a, Message, B, Theme> Default for DatePickerOverlayButtons<'a, Message, B, Theme> +impl<'a, Message, Theme> Default for DatePickerOverlayButtons<'a, Message, Theme> where Message: 'a + Clone, - B: 'a + Backend + iced_graphics::backend::Text, - Theme: 'a - + StyleSheet - + iced_style::button::StyleSheet - + iced_style::text::StyleSheet - + iced_style::container::StyleSheet, + Theme: 'a + StyleSheet + button::StyleSheet + text::StyleSheet + container::StyleSheet, { fn default() -> Self { Self { @@ -914,12 +916,11 @@ where } #[allow(clippy::unimplemented)] -impl<'a, Message, B, Theme> iced_native::Widget> - for DatePickerOverlayButtons<'a, Message, B, Theme> +impl<'a, Message, Theme> Widget> + for DatePickerOverlayButtons<'a, Message, Theme> where Message: Clone, - B: Backend, - Theme: StyleSheet + iced_style::button::StyleSheet + iced_style::container::StyleSheet, + Theme: StyleSheet + button::StyleSheet + container::StyleSheet, { fn children(&self) -> Vec { vec![ @@ -940,36 +941,31 @@ where unimplemented!("This should never be reached!") } - fn layout( - &self, - _renderer: &Renderer, - _limits: &iced_native::layout::Limits, - ) -> iced_native::layout::Node { + fn layout(&self, _renderer: &Renderer, _limits: &Limits) -> Node { unimplemented!("This should never be reached!") } fn draw( &self, _state: &Tree, - _renderer: &mut Renderer, - _theme: & as iced_native::Renderer>::Theme, + _renderer: &mut Renderer, + _theme: &Theme, _style: &renderer::Style, _layout: Layout<'_>, - _cursor_position: Point, + _cursor: Cursor, _viewport: &Rectangle, ) { unimplemented!("This should never be reached!") } } -impl<'a, Message, B, Theme> From> - for Element<'a, Message, Renderer> +impl<'a, Message, Theme> From> + for Element<'a, Message, Renderer> where Message: 'a + Clone, - B: 'a + Backend, - Theme: 'a + StyleSheet + iced_style::button::StyleSheet + iced_style::container::StyleSheet, + Theme: 'a + StyleSheet + button::StyleSheet + container::StyleSheet, { - fn from(overlay: DatePickerOverlayButtons<'a, Message, B, Theme>) -> Self { + fn from(overlay: DatePickerOverlayButtons<'a, Message, Theme>) -> Self { Self::new(overlay) } } @@ -1035,17 +1031,17 @@ impl Default for Focus { } /// Draws the month/year row -fn month_year( - renderer: &mut Renderer, - layout: iced_native::Layout<'_>, +fn month_year( + renderer: &mut Renderer, + layout: Layout<'_>, month: &str, year: &str, - cursor_position: iced_graphics::Point, + cursor: Point, //style: &Style, style: &HashMap, focus: Focus, ) where - Renderer: iced_native::Renderer + iced_native::text::Renderer, + Theme: StyleSheet + button::StyleSheet + container::StyleSheet + text::StyleSheet, { let mut children = layout.children(); @@ -1056,7 +1052,7 @@ fn month_year( .next() .expect("Graphics: Layout should have a year layout"); - let mut f = |layout: iced_native::Layout<'_>, text: &str, target: Focus| { + let mut f = |layout: Layout<'_>, text: &str, target: Focus| { let style_state = if focus == target { StyleState::Focused } else { @@ -1078,8 +1074,8 @@ fn month_year( .expect("Graphics: Layout should have a right arrow layout") .bounds(); - let left_arrow_hovered = left_bounds.contains(cursor_position); - let right_arrow_hovered = right_bounds.contains(cursor_position); + let left_arrow_hovered = left_bounds.contains(cursor); + let right_arrow_hovered = right_bounds.contains(cursor); if style_state == StyleState::Focused { renderer.fill_quad( @@ -1109,14 +1105,14 @@ fn month_year( let mut buffer = [0; 4]; // Left caret - renderer.fill_text(iced_native::text::Text { + renderer.fill_text(core::text::Text { content: char::from(Icon::CaretLeftFill).encode_utf8(&mut buffer), bounds: Rectangle { x: left_bounds.center_x(), y: left_bounds.center_y(), ..left_bounds }, - size: left_bounds.height + if left_arrow_hovered { 5.0 } else { 0.0 }, + size: renderer.default_size() + if left_arrow_hovered { 1.0 } else { 0.0 }, color: style .get(&style_state) .expect("Style Sheet not found.") @@ -1124,35 +1120,39 @@ fn month_year( font: ICON_FONT, horizontal_alignment: Horizontal::Center, vertical_alignment: Vertical::Center, + line_height: text::LineHeight::Relative(1.3), + shaping: text::Shaping::Advanced, }); // Text - renderer.fill_text(iced_native::text::Text { + renderer.fill_text(core::text::Text { content: text, bounds: Rectangle { x: center_bounds.center_x(), y: center_bounds.center_y(), ..center_bounds }, - size: center_bounds.height, + size: renderer.default_size(), color: style .get(&style_state) .expect("Style Sheet not found.") .text_color, - font: iced_graphics::Font::default(), + font: renderer.default_font(), horizontal_alignment: Horizontal::Center, vertical_alignment: Vertical::Center, + line_height: text::LineHeight::Relative(1.3), + shaping: text::Shaping::Basic, }); // Right caret - renderer.fill_text(iced_native::text::Text { + renderer.fill_text(core::text::Text { content: char::from(Icon::CaretRightFill).encode_utf8(&mut buffer), bounds: Rectangle { x: right_bounds.center_x(), y: right_bounds.center_y(), ..right_bounds }, - size: right_bounds.height + if right_arrow_hovered { 5.0 } else { 0.0 }, + size: renderer.default_size() + if right_arrow_hovered { 1.0 } else { 0.0 }, color: style .get(&style_state) .expect("Style Sheet not found.") @@ -1160,6 +1160,8 @@ fn month_year( font: ICON_FONT, horizontal_alignment: Horizontal::Center, vertical_alignment: Vertical::Center, + line_height: text::LineHeight::Relative(1.3), + shaping: text::Shaping::Advanced, }); }; @@ -1171,16 +1173,16 @@ fn month_year( } /// Draws the days -fn days( - renderer: &mut Renderer, - layout: iced_native::Layout<'_>, +fn days( + renderer: &mut Renderer, + layout: Layout<'_>, date: chrono::NaiveDate, - cursor_position: iced_graphics::Point, + cursor: Point, //style: &Style, style: &HashMap, focus: Focus, ) where - Renderer: iced_native::Renderer + iced_native::text::Renderer, + Theme: StyleSheet + button::StyleSheet + container::StyleSheet + text::StyleSheet, { let mut children = layout.children(); @@ -1189,50 +1191,52 @@ fn days( .expect("Graphics: Layout should have a day labels layout"); day_labels(renderer, day_labels_layout, style, focus); - day_table(renderer, &mut children, date, cursor_position, style, focus); + day_table(renderer, &mut children, date, cursor, style, focus); } /// Draws the day labels -fn day_labels( - renderer: &mut Renderer, - layout: iced_native::Layout<'_>, +fn day_labels( + renderer: &mut Renderer, + layout: Layout<'_>, style: &HashMap, _focus: Focus, ) where - Renderer: iced_native::Renderer + iced_native::text::Renderer, + Theme: StyleSheet + button::StyleSheet + container::StyleSheet + text::StyleSheet, { for (i, label) in layout.children().enumerate() { let bounds = label.bounds(); - renderer.fill_text(iced_native::text::Text { + renderer.fill_text(core::text::Text { content: &crate::core::date::WEEKDAY_LABELS[i], bounds: Rectangle { x: bounds.center_x(), y: bounds.center_y(), ..bounds }, - size: bounds.height + 5.0, + size: renderer.default_size(), color: style .get(&StyleState::Active) .expect("Style Sheet not found.") .text_color, - font: Default::default(), + font: renderer.default_font(), horizontal_alignment: Horizontal::Center, vertical_alignment: Vertical::Center, + line_height: text::LineHeight::Relative(1.3), + shaping: text::Shaping::Basic, }); } } /// Draws the day table -fn day_table( - renderer: &mut Renderer, - children: &mut dyn Iterator>, +fn day_table( + renderer: &mut Renderer, + children: &mut dyn Iterator>, date: chrono::NaiveDate, - cursor_position: iced_graphics::Point, + cursor: Point, style: &HashMap, focus: Focus, ) where - Renderer: iced_native::Renderer + iced_native::text::Renderer, + Theme: StyleSheet + button::StyleSheet + container::StyleSheet + text::StyleSheet, { for (y, row) in children.enumerate() { for (x, label) in row.children().enumerate() { @@ -1240,7 +1244,7 @@ fn day_table( let (number, is_in_month) = crate::core::date::position_to_day(x, y, date.year(), date.month()); - let mouse_over = bounds.contains(cursor_position); + let mouse_over = bounds.contains(cursor); let selected = date.day() == number as u32 && is_in_month == IsInMonth::Same; @@ -1287,18 +1291,14 @@ fn day_table( ); } - renderer.fill_text(iced_native::text::Text { + renderer.fill_text(core::text::Text { content: &format!("{number:02}"), // Todo: is there some way of static format as this has a fixed size? bounds: Rectangle { x: bounds.center_x(), y: bounds.center_y(), ..bounds }, - size: if bounds.width < bounds.height { - bounds.width - } else { - bounds.height - }, + size: renderer.default_size(), color: if is_in_month == IsInMonth::Same { style .get(&style_state) @@ -1310,9 +1310,11 @@ fn day_table( .expect("Style Sheet not found.") .text_attenuated_color }, - font: iced_graphics::Font::default(), + font: renderer.default_font(), horizontal_alignment: Horizontal::Center, vertical_alignment: Vertical::Center, + line_height: text::LineHeight::Relative(1.3), + shaping: text::Shaping::Basic, }); } } diff --git a/src/native/spinner.rs b/src/native/spinner.rs index c3b5f6aa..4abeb12a 100644 --- a/src/native/spinner.rs +++ b/src/native/spinner.rs @@ -1,13 +1,19 @@ //! A spinner to suggest something is loading. -use iced_native::event::Status; -use iced_native::layout::{Limits, Node}; -use iced_native::renderer::Style; -use iced_native::widget::tree::{State, Tag}; -use iced_native::widget::Tree; -use iced_native::{renderer, Layout, Widget}; -use iced_native::{window, Clipboard, Color, Element, Event, Length, Point, Rectangle, Shell}; -use iced_native::{Size, Vector}; +use iced_widget::core::{ + self, + event::Status, + layout::{Limits, Node}, + mouse::Cursor, + renderer, + widget::{ + tree::{State, Tag}, + Tree, + }, + window, Clipboard, Color, Element, Event, Layout, Length, Rectangle, Shell, Size, Vector, + Widget, +}; + use std::marker::PhantomData; use std::time::{Duration, Instant}; @@ -15,9 +21,9 @@ use crate::style::spinner::StyleSheet; /// A spinner widget, a circle spinning around the center of the widget. #[allow(missing_debug_implementations)] -pub struct Spinner +pub struct Spinner where - Renderer: iced_native::Renderer, + Renderer: core::Renderer, Renderer::Theme: StyleSheet, { /// The width of the [`Spinner`](Spinner). @@ -34,7 +40,7 @@ where impl Default for Spinner where - Renderer: iced_native::Renderer, + Renderer: core::Renderer, Renderer::Theme: StyleSheet, { fn default() -> Self { @@ -50,7 +56,7 @@ where impl Spinner where - Renderer: iced_native::Renderer, + Renderer: core::Renderer, Renderer::Theme: StyleSheet, { /// Creates a new [`Spinner`] widget. @@ -90,12 +96,7 @@ fn is_visible(bounds: &Rectangle) -> bool { bounds.width > 0.0 && bounds.height > 0.0 } -fn fill_circle( - renderer: &mut impl iced_native::Renderer, - position: Vector, - radius: f32, - color: Color, -) { +fn fill_circle(renderer: &mut impl core::Renderer, position: Vector, radius: f32, color: Color) { renderer.fill_quad( renderer::Quad { bounds: Rectangle { @@ -114,7 +115,7 @@ fn fill_circle( impl Widget for Spinner where - Renderer: iced_native::Renderer, + Renderer: core::Renderer, Renderer::Theme: StyleSheet, { fn width(&self) -> Length { @@ -139,9 +140,9 @@ where state: &Tree, renderer: &mut Renderer, _theme: &Renderer::Theme, - style: &Style, + style: &renderer::Style, layout: Layout<'_>, - _cursor_position: Point, + _cursor: Cursor, _viewport: &Rectangle, ) { let bounds = layout.bounds(); @@ -183,10 +184,11 @@ where state: &mut Tree, event: Event, layout: Layout<'_>, - _cursor_position: Point, + _cursor: Cursor, _renderer: &Renderer, _clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, + _viewport: &Rectangle, ) -> Status { const FRAMES_PER_SECOND: u64 = 60; @@ -223,7 +225,7 @@ where impl<'a, Message, Renderer> From> for Element<'a, Message, Renderer> where - Renderer: iced_native::Renderer + 'a, + Renderer: core::Renderer + 'a, Renderer::Theme: StyleSheet, { fn from(spinner: Spinner) -> Self {