1use core::marker::PhantomData;
8
9use iced_widget::{
10 canvas::Event,
11 core::{
12 event,
13 mouse::Cursor,
14 renderer::Style,
15 widget::{tree, Tree},
16 Element, Layout, Length, Rectangle, Shell, Size, Widget,
17 },
18 text::Shaping,
19};
20
21use crate::renderer::Renderer;
22
23use super::Chart;
24
25pub struct ChartWidget<'a, Message, Theme, Renderer, C>
27where
28 C: Chart<Message>,
29{
30 chart: C,
31 width: Length,
32 height: Length,
33 shaping: Shaping,
34 _marker: PhantomData<&'a (Renderer, Theme, Message)>,
35}
36
37impl<'a, Message, Theme, Renderer, C> ChartWidget<'a, Message, Theme, Renderer, C>
38where
39 C: Chart<Message> + 'a,
40{
41 pub fn new(chart: C) -> Self {
43 Self {
44 chart,
45 width: Length::Fill,
46 height: Length::Fill,
47 shaping: Default::default(),
48 _marker: Default::default(),
49 }
50 }
51
52 pub fn width(mut self, width: Length) -> Self {
54 self.width = width;
55 self
56 }
57
58 pub fn height(mut self, height: Length) -> Self {
60 self.height = height;
61 self
62 }
63
64 pub fn text_shaping(mut self, shaping: Shaping) -> Self {
66 self.shaping = shaping;
67 self
68 }
69}
70
71impl<'a, Message, Theme, Renderer, C> Widget<Message, Theme, Renderer>
72 for ChartWidget<'a, Message, Theme, Renderer, C>
73where
74 C: Chart<Message>,
75 Renderer: self::Renderer,
76{
77 fn size(&self) -> Size<Length> {
78 Size::new(self.width, self.height)
79 }
80
81 fn tag(&self) -> tree::Tag {
82 struct Tag<T>(T);
83 tree::Tag::of::<Tag<C::State>>()
84 }
85
86 fn state(&self) -> tree::State {
87 tree::State::new(C::State::default())
88 }
89
90 #[inline]
91 fn layout(
92 &self,
93 _tree: &mut Tree,
94 _renderer: &Renderer,
95 limits: &iced_widget::core::layout::Limits,
96 ) -> iced_widget::core::layout::Node {
97 let size = limits.resolve(self.width, self.height, Size::ZERO);
98 iced_widget::core::layout::Node::new(size)
99 }
100
101 #[inline]
102 fn draw(
103 &self,
104 tree: &Tree,
105 renderer: &mut Renderer,
106 _theme: &Theme,
107 _style: &Style,
108 layout: Layout<'_>,
109 _cursor_position: Cursor,
110 _viewport: &Rectangle,
111 ) {
112 let state = tree.state.downcast_ref::<C::State>();
113 renderer.draw_chart(state, &self.chart, layout, self.shaping);
114 }
115
116 #[inline]
117 fn on_event(
118 &mut self,
119 tree: &mut Tree,
120 event: iced_widget::core::Event,
121 layout: Layout<'_>,
122 cursor: Cursor,
123 _renderer: &Renderer,
124 _clipboard: &mut dyn iced_widget::core::Clipboard,
125 shell: &mut Shell<'_, Message>,
126 _rectangle: &Rectangle,
127 ) -> event::Status {
128 let bounds = layout.bounds();
129 let canvas_event = match event {
130 iced_widget::core::Event::Mouse(mouse_event) => Some(Event::Mouse(mouse_event)),
131 iced_widget::core::Event::Keyboard(keyboard_event) => {
132 Some(Event::Keyboard(keyboard_event))
133 }
134 _ => None,
135 };
136 if let Some(canvas_event) = canvas_event {
137 let state = tree.state.downcast_mut::<C::State>();
138
139 let (event_status, message) = self.chart.update(state, canvas_event, bounds, cursor);
140
141 if let Some(message) = message {
142 shell.publish(message);
143 }
144 return event_status;
145 }
146 event::Status::Ignored
147 }
148
149 fn mouse_interaction(
150 &self,
151 tree: &Tree,
152 layout: Layout<'_>,
153 cursor: Cursor,
154 _viewport: &Rectangle,
155 _renderer: &Renderer,
156 ) -> iced_widget::core::mouse::Interaction {
157 let state = tree.state.downcast_ref::<C::State>();
158 let bounds = layout.bounds();
159 self.chart.mouse_interaction(state, bounds, cursor)
160 }
161}
162
163impl<'a, Message, Theme, Renderer, C> From<ChartWidget<'a, Message, Theme, Renderer, C>>
164 for Element<'a, Message, Theme, Renderer>
165where
166 Message: 'a,
167 C: Chart<Message> + 'a,
168 Renderer: self::Renderer,
169{
170 fn from(widget: ChartWidget<'a, Message, Theme, Renderer, C>) -> Self {
171 Element::new(widget)
172 }
173}