Skip to content

Commit

Permalink
feat: image operations
Browse files Browse the repository at this point in the history
  • Loading branch information
edfloreshz committed Nov 25, 2024
1 parent 630612a commit bf808af
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 6 deletions.
25 changes: 25 additions & 0 deletions core/src/widget/operation.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//! Query or update internal widget state.
pub mod focusable;
pub mod image;
pub mod scrollable;
pub mod search_id;
pub mod text_input;

pub use focusable::Focusable;
pub use image::Image;
pub use scrollable::Scrollable;
pub use text_input::TextInput;

Expand Down Expand Up @@ -47,6 +49,9 @@ pub trait Operation<T = ()>: Send {
/// Operates on a widget that has text input.
fn text_input(&mut self, _state: &mut dyn TextInput, _id: Option<&Id>) {}

/// Operates on a widget that displays an image.
fn image(&mut self, _state: &mut dyn Image, _id: Option<&Id>) {}

/// Operates on a custom widget.
fn custom(&mut self, _state: &mut dyn Any, _id: Option<&Id>) {}

Expand Down Expand Up @@ -94,6 +99,10 @@ where
self.as_mut().text_input(state, id);
}

fn image(&mut self, state: &mut dyn Image, id: Option<&Id>) {
self.as_mut().image(state, id);
}

fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
self.as_mut().custom(state, id);
}
Expand Down Expand Up @@ -176,6 +185,10 @@ where
self.operation.text_input(state, id);
}

fn image(&mut self, state: &mut dyn Image, id: Option<&Id>) {
self.operation.image(state, id);
}

fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
self.operation.custom(state, id);
}
Expand Down Expand Up @@ -266,6 +279,10 @@ where
self.operation.text_input(state, id);
}

fn image(&mut self, state: &mut dyn Image, id: Option<&Id>) {
self.operation.image(state, id);
}

fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
self.operation.custom(state, id);
}
Expand Down Expand Up @@ -301,6 +318,10 @@ where
self.operation.text_input(state, id);
}

fn image(&mut self, state: &mut dyn Image, id: Option<&Id>) {
self.operation.image(state, id);
}

fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
self.operation.custom(state, id);
}
Expand Down Expand Up @@ -387,6 +408,10 @@ where
self.operation.text_input(state, id);
}

fn image(&mut self, state: &mut dyn Image, id: Option<&Id>) {
self.operation.image(state, id);
}

fn custom(&mut self, state: &mut dyn std::any::Any, id: Option<&Id>) {
self.operation.custom(state, id);
}
Expand Down
42 changes: 42 additions & 0 deletions core/src/widget/operation/image.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//! Operate on widgets that display an image.
use crate::widget::Id;

use crate::image::Handle;

use super::Operation;

/// The internal state of a widget that displays an image.
pub trait Image {
/// Sets the handle of the image.
fn set_handle(&mut self, handle: Handle);
}

/// Produces an [`Operation`] that sets the handle of the widget with the given [`Id`].
pub fn set_handle<T>(target: Id, handle: Handle) -> impl Operation<T> {
struct SetHandle {
target: Id,
handle: Handle,
}

impl<T> Operation<T> for SetHandle {
fn image(&mut self, state: &mut dyn Image, id: Option<&Id>) {
match id {
Some(id) if id == &self.target => {
state.set_handle(self.handle.clone());
}
_ => println!("Invalid id for image widget: {:?}", id),
}
}

fn container(
&mut self,
_id: Option<&Id>,
_bounds: crate::Rectangle,
operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
) {
operate_on_children(self);
}
}

SetHandle { target, handle }
}
75 changes: 69 additions & 6 deletions widget/src/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
//! ```
//! <img src="https://github.com/iced-rs/iced/blob/9712b319bb7a32848001b96bd84977430f14b623/examples/resources/ferris.png?raw=true" width="300">
pub mod viewer;
use iced_runtime::core::widget::operation;
use iced_runtime::core::widget::tree;
use iced_runtime::core::widget::Id;
pub use viewer::Viewer;

Expand Down Expand Up @@ -101,6 +103,12 @@ impl<'a, Handle> Image<'a, Handle> {
}
}

/// Sets the [`Id`] of the [`TextInput`].
pub fn id(mut self, id: Id) -> Self {
self.id = id;
self
}

/// Sets the border radius of the image.
pub fn border_radius(mut self, border_radius: [f32; 4]) -> Self {
self.border_radius = border_radius;
Expand Down Expand Up @@ -185,7 +193,8 @@ impl<'a, Handle> Image<'a, Handle> {
}

/// Computes the layout of an [`Image`].
pub fn layout<Renderer, Handle>(
pub fn layout<Renderer, Handle: 'static>(
tree: &mut Tree,
renderer: &Renderer,
limits: &layout::Limits,
handle: &Handle,
Expand All @@ -198,6 +207,13 @@ pub fn layout<Renderer, Handle>(
where
Renderer: image::Renderer<Handle = Handle>,
{
let state = tree.state.downcast_ref::<State<Handle>>();
let handle = if let Some(state_handle) = &state.handle {
state_handle
} else {
handle
};

// The raw w/h of the underlying image
let image_size = renderer.measure_image(handle);
let image_size =
Expand Down Expand Up @@ -229,6 +245,7 @@ where

/// Draws an [`Image`]
pub fn draw<Renderer, Handle>(
tree: &Tree,
renderer: &mut Renderer,
layout: Layout<'_>,
handle: &Handle,
Expand All @@ -239,8 +256,15 @@ pub fn draw<Renderer, Handle>(
border_radius: [f32; 4],
) where
Renderer: image::Renderer<Handle = Handle>,
Handle: Clone,
Handle: Clone + 'static,
{
let state = tree.state.downcast_ref::<State<Handle>>();
let handle = if let Some(state_handle) = &state.handle {
state_handle
} else {
handle
};

let Size { width, height } = renderer.measure_image(handle);
let image_size = Size::new(width as f32, height as f32);
let rotated_size = rotation.apply(image_size);
Expand Down Expand Up @@ -296,7 +320,7 @@ impl<'a, Message, Theme, Renderer, Handle> Widget<Message, Theme, Renderer>
for Image<'a, Handle>
where
Renderer: image::Renderer<Handle = Handle>,
Handle: Clone,
Handle: Clone + 'static,
{
fn size(&self) -> Size<Length> {
Size {
Expand All @@ -307,11 +331,12 @@ where

fn layout(
&self,
_tree: &mut Tree,
tree: &mut Tree,
renderer: &Renderer,
limits: &layout::Limits,
) -> layout::Node {
layout(
tree,
renderer,
limits,
&self.handle,
Expand All @@ -323,9 +348,20 @@ where
)
}

fn operate(
&self,
tree: &mut Tree,
_layout: Layout<'_>,
_renderer: &Renderer,
operation: &mut dyn operation::Operation,
) {
let state = tree.state.downcast_mut::<State>();
operation.image(state, Some(&self.id));
}

fn draw(
&self,
_state: &Tree,
tree: &Tree,
renderer: &mut Renderer,
_theme: &Theme,
_style: &renderer::Style,
Expand All @@ -334,6 +370,7 @@ where
_viewport: &Rectangle,
) {
draw(
tree,
renderer,
layout,
&self.handle,
Expand Down Expand Up @@ -404,15 +441,41 @@ where
fn set_id(&mut self, id: Id) {
self.id = id;
}

fn state(&self) -> tree::State {
tree::State::new(State::<Handle>::new())
}
}

/// The state of a [`Image`].
#[derive(Debug, Default, Clone)]
pub struct State<Handle = image::Handle> {
handle: Option<Handle>,
}

impl<Handle> State<Handle> {
pub fn new() -> Self {
Self { handle: None }
}

pub fn set_handle(&mut self, handle: Handle) {
self.handle = Some(handle);
}
}

impl<'a, Message, Theme, Renderer, Handle> From<Image<'a, Handle>>
for Element<'a, Message, Theme, Renderer>
where
Renderer: image::Renderer<Handle = Handle>,
Handle: Clone + 'a,
Handle: Clone + 'static,
{
fn from(image: Image<'a, Handle>) -> Element<'a, Message, Theme, Renderer> {
Element::new(image)
}
}

impl operation::Image for State {
fn set_handle(&mut self, handle: image::Handle) {
State::set_handle(self, handle);
}
}

0 comments on commit bf808af

Please sign in to comment.