use core::marker::PhantomData;
use iced_widget::{
canvas::Event,
core::{
Element, Layout, Length, Rectangle, Shell, Size, Widget,
mouse::Cursor,
renderer::Style,
widget::{Tree, tree},
},
text::Shaping,
};
use crate::renderer::Renderer;
use super::Chart;
pub struct ChartWidget<'a, Message, Theme, Renderer, C>
where
C: Chart<Message>,
{
chart: C,
width: Length,
height: Length,
shaping: Shaping,
_marker: PhantomData<&'a (Renderer, Theme, Message)>,
}
impl<'a, Message, Theme, Renderer, C> ChartWidget<'a, Message, Theme, Renderer, C>
where
C: Chart<Message> + 'a,
{
pub fn new(chart: C) -> Self {
Self {
chart,
width: Length::Fill,
height: Length::Fill,
shaping: Shaping::default(),
_marker: PhantomData,
}
}
#[must_use]
pub fn width(mut self, width: Length) -> Self {
self.width = width;
self
}
#[must_use]
pub fn height(mut self, height: Length) -> Self {
self.height = height;
self
}
#[must_use]
pub fn text_shaping(mut self, shaping: Shaping) -> Self {
self.shaping = shaping;
self
}
}
impl<Message, Theme, Renderer, C> Widget<Message, Theme, Renderer>
for ChartWidget<'_, Message, Theme, Renderer, C>
where
C: Chart<Message>,
Renderer: self::Renderer,
{
fn size(&self) -> Size<Length> {
Size::new(self.width, self.height)
}
fn tag(&self) -> tree::Tag {
struct Tag<T>(T);
tree::Tag::of::<Tag<C::State>>()
}
fn state(&self) -> tree::State {
tree::State::new(C::State::default())
}
#[inline]
fn layout(
&mut self,
_tree: &mut Tree,
_renderer: &Renderer,
limits: &iced_widget::core::layout::Limits,
) -> iced_widget::core::layout::Node {
let size = limits.resolve(self.width, self.height, Size::ZERO);
iced_widget::core::layout::Node::new(size)
}
#[inline]
fn draw(
&self,
tree: &Tree,
renderer: &mut Renderer,
_theme: &Theme,
_style: &Style,
layout: Layout<'_>,
_cursor_position: Cursor,
_viewport: &Rectangle,
) {
let state = tree.state.downcast_ref::<C::State>();
renderer.draw_chart(state, &self.chart, layout, self.shaping);
}
#[inline]
fn update(
&mut self,
tree: &mut Tree,
event: &iced_graphics::core::Event,
layout: Layout<'_>,
cursor: Cursor,
_renderer: &Renderer,
_clipboard: &mut dyn iced_widget::core::Clipboard,
shell: &mut Shell<'_, Message>,
_rectangle: &Rectangle,
) {
let bounds = layout.bounds();
let canvas_event = if matches!(event, Event::Mouse(_) | Event::Keyboard(_)) {
Some(event)
} else {
None
};
if let Some(canvas_event) = canvas_event {
let state = tree.state.downcast_mut::<C::State>();
if let (_, Some(message)) = self.chart.update(state, canvas_event, bounds, cursor) {
shell.publish(message);
}
}
}
fn mouse_interaction(
&self,
tree: &Tree,
layout: Layout<'_>,
cursor: Cursor,
_viewport: &Rectangle,
_renderer: &Renderer,
) -> iced_widget::core::mouse::Interaction {
let state = tree.state.downcast_ref::<C::State>();
let bounds = layout.bounds();
self.chart.mouse_interaction(state, bounds, cursor)
}
}
impl<'a, Message, Theme, Renderer, C> From<ChartWidget<'a, Message, Theme, Renderer, C>>
for Element<'a, Message, Theme, Renderer>
where
Message: 'a,
C: Chart<Message> + 'a,
Renderer: self::Renderer,
{
fn from(widget: ChartWidget<'a, Message, Theme, Renderer, C>) -> Self {
Element::new(widget)
}
}