From 495985f449e46b24e6b734d3aa9e135a779a8b77 Mon Sep 17 00:00:00 2001 From: pml68 Date: Sun, 13 Apr 2025 03:40:38 +0200 Subject: refactor: move `material_theme` and `iced_drop` into separate crates dir --- crates/iced_drop/src/widget/droppable.rs | 574 ++++++++++++++++++++++++++ crates/iced_drop/src/widget/operation.rs | 1 + crates/iced_drop/src/widget/operation/drop.rs | 88 ++++ 3 files changed, 663 insertions(+) create mode 100644 crates/iced_drop/src/widget/droppable.rs create mode 100644 crates/iced_drop/src/widget/operation.rs create mode 100644 crates/iced_drop/src/widget/operation/drop.rs (limited to 'crates/iced_drop/src/widget') diff --git a/crates/iced_drop/src/widget/droppable.rs b/crates/iced_drop/src/widget/droppable.rs new file mode 100644 index 0000000..947cf5b --- /dev/null +++ b/crates/iced_drop/src/widget/droppable.rs @@ -0,0 +1,574 @@ +//! Encapsulates a widget that can be dragged and dropped. +use std::fmt::Debug; +use std::vec; + +use iced::advanced::widget::{Operation, Tree, Widget}; +use iced::advanced::{self, Layout, layout, mouse, overlay, renderer}; +use iced::{Element, Point, Rectangle, Size, Vector}; + +/// An element that can be dragged and dropped on a [`DropZone`] +pub struct Droppable< + 'a, + Message, + Theme = iced::Theme, + Renderer = iced::Renderer, +> where + Message: Clone, + Renderer: renderer::Renderer, +{ + content: Element<'a, Message, Theme, Renderer>, + id: Option, + on_click: Option, + on_drop: Option Message + 'a>>, + on_drag: Option Message + 'a>>, + on_cancel: Option, + drag_mode: Option<(bool, bool)>, + drag_overlay: bool, + drag_hide: bool, + drag_center: bool, + drag_size: Option, + reset_delay: usize, + status: Option, +} + +impl<'a, Message, Theme, Renderer> Droppable<'a, Message, Theme, Renderer> +where + Message: Clone, + Renderer: renderer::Renderer, +{ + /// Creates a new [`Droppable`]. + pub fn new( + content: impl Into>, + ) -> Self { + Self { + content: content.into(), + id: None, + on_click: None, + on_drop: None, + on_drag: None, + on_cancel: None, + drag_mode: Some((true, true)), + drag_overlay: true, + drag_hide: false, + drag_center: false, + drag_size: None, + reset_delay: 0, + status: None, + } + } + + /// Sets the unique identifier of the [`Droppable`]. + pub fn id(mut self, id: iced::advanced::widget::Id) -> Self { + self.id = Some(id); + self + } + + /// Sets the message that will be produced when the [`Droppable`] is clicked. + pub fn on_click(mut self, message: Message) -> Self { + self.on_click = Some(message); + self + } + + /// Sets the message that will be produced when the [`Droppable`] is dropped on a [`DropZone`]. + /// + /// Unless this is set, the [`Droppable`] will be disabled. + pub fn on_drop(mut self, message: F) -> Self + where + F: Fn(Point, Rectangle) -> Message + 'a, + { + self.on_drop = Some(Box::new(message)); + self + } + + /// Sets the message that will be produced when the [`Droppable`] is dragged. + pub fn on_drag(mut self, message: F) -> Self + where + F: Fn(Point, Rectangle) -> Message + 'a, + { + self.on_drag = Some(Box::new(message)); + self + } + + /// Sets the message that will be produced when the user right clicks while dragging the [`Droppable`]. + pub fn on_cancel(mut self, message: Message) -> Self { + self.on_cancel = Some(message); + self + } + + /// Sets whether the [`Droppable`] should be drawn under the cursor while dragging. + pub fn drag_overlay(mut self, drag_overlay: bool) -> Self { + self.drag_overlay = drag_overlay; + self + } + + /// Sets whether the [`Droppable`] should be hidden while dragging. + pub fn drag_hide(mut self, drag_hide: bool) -> Self { + self.drag_hide = drag_hide; + self + } + + /// Sets whether the [`Droppable`] should be centered on the cursor while dragging. + pub fn drag_center(mut self, drag_center: bool) -> Self { + self.drag_center = drag_center; + self + } + + // Sets whether the [`Droppable`] can be dragged along individual axes. + pub fn drag_mode(mut self, drag_x: bool, drag_y: bool) -> Self { + self.drag_mode = Some((drag_x, drag_y)); + self + } + + /// Sets whether the [`Droppable`] should be be resized to a given size while dragging. + pub fn drag_size(mut self, hide_size: Size) -> Self { + self.drag_size = Some(hide_size); + self + } + + /// Sets the number of frames/layout calls to wait before resetting the size of the [`Droppable`] after dropping. + /// + /// This is useful for cases where the [`Droppable`] is being moved to a new location after some widget operation. + /// In this case, the [`Droppable`] will mainting the 'drag_size' for the given number of frames before resetting to its original size. + /// This prevents the [`Droppable`] from 'jumping' back to its original size before the new location is rendered which + /// prevents flickering. + /// + /// Warning: this should only be set if there's is some noticeble flickering when the [`Droppable`] is dropped. That is, if the + /// [`Droppable`] returns to its original size before it's moved to it's new location. + pub fn reset_delay(mut self, reset_delay: usize) -> Self { + self.reset_delay = reset_delay; + self + } +} + +impl<'a, Message, Theme, Renderer> Widget + for Droppable<'a, Message, Theme, Renderer> +where + Message: Clone, + Renderer: renderer::Renderer, +{ + fn state(&self) -> iced::advanced::widget::tree::State { + advanced::widget::tree::State::new(State::default()) + } + + fn tag(&self) -> iced::advanced::widget::tree::Tag { + advanced::widget::tree::Tag::of::() + } + + fn children(&self) -> Vec { + vec![advanced::widget::Tree::new(&self.content)] + } + + fn diff(&self, tree: &mut iced::advanced::widget::Tree) { + tree.diff_children(std::slice::from_ref(&self.content)) + } + + fn size(&self) -> iced::Size { + self.content.as_widget().size() + } + + fn update( + &mut self, + tree: &mut iced::advanced::widget::Tree, + event: &iced::Event, + layout: iced::advanced::Layout<'_>, + cursor: iced::advanced::mouse::Cursor, + _renderer: &Renderer, + _clipboard: &mut dyn iced::advanced::Clipboard, + shell: &mut iced::advanced::Shell<'_, Message>, + _viewport: &iced::Rectangle, + ) { + // handle the on event of the content first, in case that the droppable is nested + self.content.as_widget_mut().update( + &mut tree.children[0], + event, + layout, + cursor, + _renderer, + _clipboard, + shell, + _viewport, + ); + // this should really only be captured if the droppable is nested or it contains some other + // widget that captures the event + if shell.is_event_captured() { + return; + } + + if let Some(on_drop) = self.on_drop.as_deref() { + let state = tree.state.downcast_mut::(); + if let iced::Event::Mouse(mouse) = event { + match mouse { + mouse::Event::ButtonPressed(btn) => { + if *btn == mouse::Button::Left + && cursor.is_over(layout.bounds()) + { + // select the droppable and store the position of the widget before dragging + state.action = + Action::Select(cursor.position().unwrap()); + let bounds = layout.bounds(); + state.widget_pos = bounds.position(); + state.overlay_bounds.width = bounds.width; + state.overlay_bounds.height = bounds.height; + + if let Some(on_click) = self.on_click.clone() { + shell.publish(on_click); + } + shell.capture_event(); + } else if *btn == mouse::Button::Right { + if let Action::Drag(_, _) = state.action { + shell.invalidate_layout(); + state.action = Action::None; + if let Some(on_cancel) = self.on_cancel.clone() + { + shell.publish(on_cancel); + } + } + } + } + mouse::Event::CursorMoved { mut position } => match state + .action + { + Action::Select(start) | Action::Drag(start, _) => { + // calculate the new position of the widget after dragging + + if let Some((drag_x, drag_y)) = self.drag_mode { + position = Point { + x: if drag_x { + position.x + } else { + start.x + }, + y: if drag_y { + position.y + } else { + start.y + }, + }; + } + + state.action = Action::Drag(start, position); + // update the position of the overlay since the cursor was moved + if self.drag_center { + state.overlay_bounds.x = position.x + - state.overlay_bounds.width / 2.0; + state.overlay_bounds.y = position.y + - state.overlay_bounds.height / 2.0; + } else { + state.overlay_bounds.x = + state.widget_pos.x + position.x - start.x; + state.overlay_bounds.y = + state.widget_pos.y + position.y - start.y; + } + // send on drag msg + if let Some(on_drag) = self.on_drag.as_deref() { + let message = + (on_drag)(position, state.overlay_bounds); + shell.publish(message); + } + + shell.request_redraw(); + } + _ => (), + }, + mouse::Event::ButtonReleased(mouse::Button::Left) => { + match state.action { + Action::Select(_) => { + state.action = Action::None; + } + Action::Drag(_, current) => { + // send on drop msg + let message = + (on_drop)(current, state.overlay_bounds); + shell.publish(message); + + if self.reset_delay == 0 { + state.action = Action::None; + } else { + state.action = + Action::Wait(self.reset_delay); + } + } + _ => (), + } + } + _ => {} + } + } + } + + let current_status = if cursor.is_over(layout.bounds()) { + if self.on_drop.is_none() { + Status::Disabled + } else { + let state = tree.state.downcast_ref::(); + + if let Action::Drag(_, _) = state.action { + Status::Dragged + } else { + Status::Hovered + } + } + } else { + Status::Active + }; + + if let iced::Event::Window(iced::window::Event::RedrawRequested(_now)) = + event + { + self.status = Some(current_status); + } else if self.status.is_some_and(|status| status != current_status) { + shell.request_redraw(); + } + } + + fn layout( + &self, + tree: &mut iced::advanced::widget::Tree, + renderer: &Renderer, + limits: &iced::advanced::layout::Limits, + ) -> iced::advanced::layout::Node { + let state: &mut State = tree.state.downcast_mut::(); + let content_node = self.content.as_widget().layout( + &mut tree.children[0], + renderer, + limits, + ); + + // Adjust the size of the original widget if it's being dragged or we're wating to reset the size + if let Some(new_size) = self.drag_size { + match state.action { + Action::Drag(_, _) => { + return iced::advanced::layout::Node::with_children( + new_size, + content_node.children().to_vec(), + ); + } + Action::Wait(reveal_index) => { + if reveal_index <= 1 { + state.action = Action::None; + } else { + state.action = Action::Wait(reveal_index - 1); + } + + return iced::advanced::layout::Node::with_children( + new_size, + content_node.children().to_vec(), + ); + } + _ => (), + } + } + + content_node + } + + fn operate( + &self, + tree: &mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + operation: &mut dyn Operation, + ) { + let state = tree.state.downcast_mut::(); + operation.custom(self.id.as_ref(), layout.bounds(), state); + operation.container( + self.id.as_ref(), + layout.bounds(), + &mut |operation| { + self.content.as_widget().operate( + &mut tree.children[0], + layout, + renderer, + operation, + ); + }, + ); + } + + fn draw( + &self, + tree: &iced::advanced::widget::Tree, + renderer: &mut Renderer, + theme: &Theme, + style: &renderer::Style, + layout: iced::advanced::Layout<'_>, + cursor: iced::advanced::mouse::Cursor, + viewport: &iced::Rectangle, + ) { + let state: &State = tree.state.downcast_ref::(); + if let Action::Drag(_, _) = state.action { + if self.drag_hide { + return; + } + } + + self.content.as_widget().draw( + &tree.children[0], + renderer, + theme, + style, + layout, + cursor, + &viewport, + ); + } + + fn overlay<'b>( + &'b mut self, + tree: &'b mut Tree, + layout: Layout<'_>, + renderer: &Renderer, + _translation: Vector, + ) -> Option> { + let state: &mut State = tree.state.downcast_mut::(); + if self.drag_overlay { + if let Action::Drag(_, _) = state.action { + return Some(overlay::Element::new(Box::new(Overlay { + content: &self.content, + tree: &mut tree.children[0], + overlay_bounds: state.overlay_bounds, + }))); + } + } + self.content.as_widget_mut().overlay( + &mut tree.children[0], + layout, + renderer, + _translation, + ) + } + + fn mouse_interaction( + &self, + tree: &iced::advanced::widget::Tree, + layout: iced::advanced::Layout<'_>, + cursor: iced::advanced::mouse::Cursor, + _viewport: &iced::Rectangle, + _renderer: &Renderer, + ) -> iced::advanced::mouse::Interaction { + let child_interact = self.content.as_widget().mouse_interaction( + &tree.children[0], + layout, + cursor, + _viewport, + _renderer, + ); + + if child_interact != mouse::Interaction::default() { + return child_interact; + } + + let state = tree.state.downcast_ref::(); + + if self.on_drop.is_none() && cursor.is_over(layout.bounds()) { + return mouse::Interaction::NotAllowed; + } + + if let Action::Drag(_, _) = state.action { + return mouse::Interaction::Grabbing; + } + + if cursor.is_over(layout.bounds()) { + return mouse::Interaction::Pointer; + } + + mouse::Interaction::default() + } +} + +impl<'a, Message, Theme, Renderer> From> + for Element<'a, Message, Theme, Renderer> +where + Message: 'a + Clone, + Theme: 'a, + Renderer: 'a + renderer::Renderer, +{ + fn from( + droppable: Droppable<'a, Message, Theme, Renderer>, + ) -> Element<'a, Message, Theme, Renderer> { + Element::new(droppable) + } +} + +#[derive(Default, Clone, Copy, PartialEq, Debug)] +pub struct State { + widget_pos: Point, + overlay_bounds: Rectangle, + action: Action, +} + +#[derive(Default, Clone, Copy, PartialEq, Debug)] +pub enum Status { + #[default] + Active, + Hovered, + Dragged, + Disabled, +} + +#[derive(Default, Clone, Copy, PartialEq, Debug)] +pub enum Action { + #[default] + None, + /// (point clicked) + Select(Point), + /// (start pos, current pos) + Drag(Point, Point), + /// (frames to wait) + Wait(usize), +} + +struct Overlay<'a, 'b, Message, Theme, Renderer> +where + Renderer: renderer::Renderer, +{ + content: &'b Element<'a, Message, Theme, Renderer>, + tree: &'b mut advanced::widget::Tree, + overlay_bounds: Rectangle, +} + +impl<'a, 'b, Message, Theme, Renderer> + overlay::Overlay + for Overlay<'a, 'b, Message, Theme, Renderer> +where + Renderer: renderer::Renderer, +{ + fn layout(&mut self, renderer: &Renderer, _bounds: Size) -> layout::Node { + Widget::::layout( + self.content.as_widget(), + self.tree, + renderer, + &layout::Limits::new(Size::ZERO, self.overlay_bounds.size()), + ) + .move_to(self.overlay_bounds.position()) + } + + fn draw( + &self, + renderer: &mut Renderer, + theme: &Theme, + inherited_style: &renderer::Style, + layout: Layout<'_>, + cursor_position: mouse::Cursor, + ) { + Widget::::draw( + self.content.as_widget(), + self.tree, + renderer, + theme, + inherited_style, + layout, + cursor_position, + &Rectangle::with_size(Size::INFINITY), + ); + } + + fn is_over( + &self, + _layout: Layout<'_>, + _renderer: &Renderer, + _cursor_position: Point, + ) -> bool { + false + } +} diff --git a/crates/iced_drop/src/widget/operation.rs b/crates/iced_drop/src/widget/operation.rs new file mode 100644 index 0000000..3d7dcff --- /dev/null +++ b/crates/iced_drop/src/widget/operation.rs @@ -0,0 +1 @@ +pub mod drop; diff --git a/crates/iced_drop/src/widget/operation/drop.rs b/crates/iced_drop/src/widget/operation/drop.rs new file mode 100644 index 0000000..ead412c --- /dev/null +++ b/crates/iced_drop/src/widget/operation/drop.rs @@ -0,0 +1,88 @@ +use iced::advanced::widget::operation::{Outcome, Scrollable}; +use iced::advanced::widget::{Id, Operation}; +use iced::{Rectangle, Vector}; + +/// Produces an [`Operation`] that will find the drop zones that pass a filter on the zone's bounds. +/// For any drop zone to be considered, the Element must have some Id. +/// If `options` is `None`, all drop zones will be considered. +/// Depth determines how how deep into nested drop zones to go. +/// If 'depth' is `None`, nested dropzones will be fully explored +pub fn find_zones( + filter: F, + options: Option>, + depth: Option, +) -> impl Operation> +where + F: Fn(&Rectangle) -> bool + Send + 'static, +{ + struct FindDropZone { + filter: F, + options: Option>, + zones: Vec<(Id, Rectangle)>, + max_depth: Option, + c_depth: usize, + offset: Vector, + } + + impl Operation> for FindDropZone + where + F: Fn(&Rectangle) -> bool + Send + 'static, + { + fn container( + &mut self, + id: Option<&Id>, + bounds: iced::Rectangle, + operate_on_children: &mut dyn FnMut( + &mut dyn Operation>, + ), + ) { + match id { + Some(id) => { + let is_option = match &self.options { + Some(options) => options.contains(id), + None => true, + }; + let bounds = bounds - self.offset; + if is_option && (self.filter)(&bounds) { + self.c_depth += 1; + self.zones.push((id.clone(), bounds)); + } + } + None => (), + } + let goto_next = match &self.max_depth { + Some(m_depth) => self.c_depth < *m_depth, + None => true, + }; + if goto_next { + operate_on_children(self); + } + } + + fn finish(&self) -> Outcome> { + Outcome::Some(self.zones.clone()) + } + + fn scrollable( + &mut self, + _id: Option<&Id>, + bounds: Rectangle, + _content_bounds: Rectangle, + translation: Vector, + _state: &mut dyn Scrollable, + ) { + if (self.filter)(&bounds) { + self.offset = self.offset + translation; + } + } + } + + FindDropZone { + filter, + options, + zones: vec![], + max_depth: depth, + c_depth: 0, + offset: Vector { x: 0.0, y: 0.0 }, + } +} -- cgit v1.2.3 From 3bdd724119eb2dbcb2480e441cd13f82575c6536 Mon Sep 17 00:00:00 2001 From: pml68 Date: Sat, 26 Apr 2025 13:17:58 +0200 Subject: feat(material_theme): implement `image::Catalog` (under feature flag) --- Cargo.lock | 89 +++++++++++++++++--------------- crates/iced_drop/src/widget/droppable.rs | 2 + crates/material_theme/Cargo.toml | 2 + crates/material_theme/src/image.rs | 21 ++++++++ crates/material_theme/src/lib.rs | 2 + theme_test/src/main.rs | 4 +- 6 files changed, 78 insertions(+), 42 deletions(-) create mode 100644 crates/material_theme/src/image.rs (limited to 'crates/iced_drop/src/widget') diff --git a/Cargo.lock b/Cargo.lock index fd31403..9154eb4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -51,7 +51,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "once_cell", "version_check", "zerocopy 0.7.35", @@ -657,9 +657,9 @@ checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" [[package]] name = "cc" -version = "1.2.19" +version = "1.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a" dependencies = [ "jobserver", "libc", @@ -1592,9 +1592,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -1941,7 +1941,7 @@ dependencies = [ [[package]] name = "iced" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "iced_core", "iced_debug", @@ -1958,7 +1958,7 @@ dependencies = [ [[package]] name = "iced_anim" version = "0.2.1" -source = "git+https://github.com/pml68/iced_anim#0c833c0943493c8fc22a60e138785e4c688ef8d8" +source = "git+https://github.com/pml68/iced_anim#c881a8a9c49b0536f4ee3c236ec24285eabc0d76" dependencies = [ "iced", "iced_anim_derive", @@ -1967,7 +1967,7 @@ dependencies = [ [[package]] name = "iced_anim_derive" version = "0.2.0" -source = "git+https://github.com/pml68/iced_anim#0c833c0943493c8fc22a60e138785e4c688ef8d8" +source = "git+https://github.com/pml68/iced_anim#c881a8a9c49b0536f4ee3c236ec24285eabc0d76" dependencies = [ "quote", "syn", @@ -1976,7 +1976,7 @@ dependencies = [ [[package]] name = "iced_beacon" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "bincode", "futures", @@ -2017,7 +2017,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "bitflags 2.9.0", "bytes", @@ -2046,7 +2046,7 @@ dependencies = [ [[package]] name = "iced_debug" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "iced_beacon", "iced_core", @@ -2056,7 +2056,7 @@ dependencies = [ [[package]] name = "iced_devtools" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "iced_debug", "iced_program", @@ -2066,7 +2066,7 @@ dependencies = [ [[package]] name = "iced_dialog" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced_dialog?branch=iced%2Fpersonal#6e901c21dbb259d337ed1ad2054da3862172b8b3" +source = "git+https://github.com/pml68/iced_dialog?branch=iced%2Fpersonal#57388a202159052ccc771bfb537bd46e8f3b9e70" dependencies = [ "iced_core", "iced_widget", @@ -2096,7 +2096,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "futures", "iced_core", @@ -2110,7 +2110,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "bitflags 2.9.0", "bytemuck", @@ -2131,7 +2131,7 @@ dependencies = [ [[package]] name = "iced_program" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "iced_graphics", "iced_runtime", @@ -2140,7 +2140,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2152,7 +2152,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "bytes", "iced_core", @@ -2165,7 +2165,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "bytemuck", "cosmic-text", @@ -2182,7 +2182,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "bitflags 2.9.0", "bytemuck", @@ -2203,7 +2203,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "iced_renderer", "iced_runtime", @@ -2221,7 +2221,7 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.14.0-dev" -source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#b6433c4637ddf4697154feeb14c66e06200e4e1b" +source = "git+https://github.com/pml68/iced?branch=feat%2Frehighlight-on-redraw#64d4a365f3eb25f716c0632316d46d82bfe818c6" dependencies = [ "iced_debug", "iced_program", @@ -3636,7 +3636,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.24", + "zerocopy 0.8.25", ] [[package]] @@ -3806,7 +3806,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -3940,7 +3940,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror 1.0.69", ] @@ -4060,7 +4060,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.16", "libc", "untrusted", "windows-sys 0.52.0", @@ -4943,9 +4943,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" dependencies = [ "bytes", "futures-core", @@ -4956,9 +4956,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "900f6c86a685850b1bc9f6223b20125115ee3f31e01207d81655bbcc0aea9231" dependencies = [ "serde", "serde_spanned", @@ -4968,26 +4968,33 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "10558ed0bd2a1562e630926a2d1f0b98c827da99fabd3fe20920a59642504485" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28391a4201ba7eb1984cfeb6862c0b3ea2cfe23332298967c749dddc0d6cd976" + [[package]] name = "tower" version = "0.5.2" @@ -6136,9 +6143,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +checksum = "6cb8234a863ea0e8cd7284fcdd4f145233eb00fee02bbdd9861aec44e6477bc5" dependencies = [ "memchr", ] @@ -6384,11 +6391,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "zerocopy-derive 0.8.24", + "zerocopy-derive 0.8.25", ] [[package]] @@ -6404,9 +6411,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", diff --git a/crates/iced_drop/src/widget/droppable.rs b/crates/iced_drop/src/widget/droppable.rs index 947cf5b..196464a 100644 --- a/crates/iced_drop/src/widget/droppable.rs +++ b/crates/iced_drop/src/widget/droppable.rs @@ -418,6 +418,7 @@ where tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, + _viewport: &iced::Rectangle, _translation: Vector, ) -> Option> { let state: &mut State = tree.state.downcast_mut::(); @@ -434,6 +435,7 @@ where &mut tree.children[0], layout, renderer, + _viewport, _translation, ) } diff --git a/crates/material_theme/Cargo.toml b/crates/material_theme/Cargo.toml index 941bc3e..30de38b 100644 --- a/crates/material_theme/Cargo.toml +++ b/crates/material_theme/Cargo.toml @@ -21,6 +21,8 @@ animate = ["dep:iced_anim"] dialog = ["dep:iced_dialog"] # Provides support for the markdown widget. markdown = ["iced_widget/markdown"] +# Provides support for the image widget. +image = ["iced_widget/image"] # Provides support for the SVG widget. svg = ["iced_widget/svg"] # Provides support for the QR code widget. diff --git a/crates/material_theme/src/image.rs b/crates/material_theme/src/image.rs new file mode 100644 index 0000000..de5942a --- /dev/null +++ b/crates/material_theme/src/image.rs @@ -0,0 +1,21 @@ +use iced_widget::core::{Background, Border, Color, border}; +use iced_widget::image::{Catalog, Style, StyleFn}; + +use super::Theme; +use crate::utils::{elevation, shadow_from_elevation}; + +impl Catalog for Theme { + type Class<'a> = StyleFn<'a, Self>; + + fn default<'a>() -> Self::Class<'a> { + Box::new(default) + } + + fn style(&self, class: &Self::Class<'_>) -> Style { + class(self) + } +} + +pub fn default(_theme: &Theme) -> Style { + Style::default() +} diff --git a/crates/material_theme/src/lib.rs b/crates/material_theme/src/lib.rs index 569b06c..1b4f90e 100644 --- a/crates/material_theme/src/lib.rs +++ b/crates/material_theme/src/lib.rs @@ -9,6 +9,8 @@ pub mod combo_box; pub mod container; #[cfg(feature = "dialog")] pub mod dialog; +#[cfg(feature = "image")] +pub mod image; #[cfg(feature = "markdown")] pub mod markdown; pub mod menu; diff --git a/theme_test/src/main.rs b/theme_test/src/main.rs index 7ec7f15..b4a7731 100644 --- a/theme_test/src/main.rs +++ b/theme_test/src/main.rs @@ -1,6 +1,7 @@ use iced::widget::{ button, center, checkbox, column, container, horizontal_rule, pane_grid, - pick_list, radio, row, slider, text_editor, text_input, toggler, + pick_list, progress_bar, radio, row, slider, text_editor, text_input, + toggler, }; use iced::{Element, Length}; use iced_anim::{Animated, Animation, Event}; @@ -238,6 +239,7 @@ impl State { .height(Length::Shrink), slider(0.0..=100.0, self.value, Message::Slider) .step(0.1), + progress_bar(0.0..=100.0, self.value), horizontal_rule(1), // Toggler toggler(self.is_checked) -- cgit v1.2.3