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