1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
//! Views are used to visually present model data and to act as controls which, when interacted with, send events to mutate model data.
//!
//! # Example
//! The `Label` view is used to display a text string:
//!
//! ```no_run
//! # use vizia_core::prelude::*;
//! # use vizia_winit::application::Application;
//! Application::new(|cx|{
//!     Label::new(cx, "Hello World");
//! })
//! .run();
//! ```

use crate::accessibility::IntoNode;
use crate::model::ModelDataStore;
use crate::prelude::*;
use crate::systems::get_access_node;
use std::any::Any;
mod handle;
pub use handle::Handle;

use crate::events::ViewHandler;
use accesskit::{NodeBuilder, TreeUpdate};

/// A view is any object which can be displayed on the screen.
///
/// # Creating a Custom View
///
/// To create a custom view, first define a struct with any view-specific state.
/// ```
/// # use vizia_core::prelude::*;
/// pub struct CustomView {
///     count: i32,
/// }
/// ```
///
/// Next, implement the constructor for the custom view. Typically, the constructor will take `&mut Context` as the first argument
/// and return a [`Handle`] to the view.
/// ```
/// # use vizia_core::prelude::*;
/// pub struct CustomView {
///     count: i32,
/// }
///
/// impl CustomView {
///     pub fn new(cx: &mut Context, count: i32) -> Handle<Self> {
///         Self {
///             count,
///         }.build(cx, |cx|{
///             // If we want the view to contain other views we can build those here.
///         })
///     }
/// }
///
/// # impl View for CustomView {}
/// ```
///
/// The `build` method above is provided by the `View` trait, which we must implement for any custom view.
/// ```
/// # use vizia_core::prelude::*;
/// pub struct CustomView {
///     count: i32,
/// }
///
/// impl CustomView {
///     pub fn new(cx: &mut Context, count: i32) -> Handle<Self> {
///         Self {
///             count,
///         }.build(cx, |cx|{
///             // If we want the view to contain other views we can build those here.
///         })
///     }
/// }
///
/// impl View for CustomView {
///
/// }
/// ```
///
/// The `View` trait contains methods, which can be optionally overridden, for assigning an element name, handling events, and performing custom drawing.
pub trait View: 'static + Sized {
    /// Builds the view into the tree and returns a handle which can be used to apply style and layout modifiers to the view.
    ///
    /// Typically this method is called within the constructor of a view, for example:
    /// ```
    /// # use vizia_core::prelude::*;
    /// pub struct CustomView{}
    ///
    /// impl CustomView {
    ///     pub fn new(cx: &mut Context) -> Handle<Self> {
    ///         Self{}.build(cx, |_|{})
    ///     }
    /// }
    /// # impl View for CustomView {}
    /// ```
    /// The `content` closure allows for a view to be built from other views. For example, a custom view could encapsulate a
    /// pair of labels:
    /// ```
    /// # use vizia_core::prelude::*;
    /// pub struct CustomView{}
    ///
    /// impl CustomView {
    ///     pub fn new(cx: &mut Context) -> Handle<Self> {
    ///         Self{}.build(cx, |cx|{
    ///             Label::new(cx, "Hello");
    ///             Label::new(cx, "World");
    ///         })
    ///     }
    /// }
    /// # impl View for CustomView {}
    /// ```
    fn build<F>(self, cx: &mut Context, content: F) -> Handle<Self>
    where
        F: FnOnce(&mut Context),
    {
        let id = cx.entity_manager.create();
        let current = cx.current();
        cx.tree.add(id, current).expect("Failed to add to tree");
        cx.cache.add(id);
        cx.style.add(id);
        cx.needs_redraw(id);
        cx.views.insert(id, Box::new(self));
        let parent_id = cx.tree.get_layout_parent(id).unwrap();
        let parent_node_id = parent_id.accesskit_id();
        let node_id = id.accesskit_id();

        let mut access_context = AccessContext {
            current: id,
            tree: &cx.tree,
            cache: &cx.cache,
            style: &cx.style,
            text_context: &mut cx.text_context,
        };

        if let Some(parent_node) = get_access_node(&mut access_context, &mut cx.views, parent_id) {
            let parent_node = parent_node.node_builder.build();
            let node = NodeBuilder::default().build();

            cx.tree_updates.push(Some(TreeUpdate {
                nodes: vec![(parent_node_id, parent_node), (node_id, node)],
                tree: None,
                focus: cx.focused.accesskit_id(),
            }));
        }

        cx.data.insert(id, ModelDataStore::default());

        let handle = Handle { current: id, entity: id, p: Default::default(), cx };

        handle.cx.with_current(handle.entity, content);

        handle
    }

    /// Specifies a name for the view type which can be used as an element selector in css.
    ///
    /// # Example
    /// ```
    /// # use vizia_core::prelude::*;
    /// pub struct CustomView{}
    ///
    /// impl CustomView {
    ///     pub fn new(cx: &mut Context) -> Handle<Self> {
    ///         Self{}.build(cx, |_|{})
    ///     }
    /// }
    ///
    /// impl View for CustomView {
    ///     fn element(&self) -> Option<&'static str> {
    ///         Some("custom_view")
    ///     }
    /// }
    /// ```
    /// Then in css:
    /// ```css
    /// custom_view {
    ///     background-color: red;
    /// }
    /// ```
    fn element(&self) -> Option<&'static str> {
        None
    }

    /// Handles any events received by the view.
    ///
    /// # Example
    /// ```
    /// # use vizia_core::prelude::*;
    /// pub struct CustomView{}
    ///
    /// impl CustomView {
    ///     pub fn new(cx: &mut Context) -> Handle<Self> {
    ///         Self{}.build(cx, |_|{})
    ///     }
    /// }
    ///
    /// impl View for CustomView {
    ///     fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
    ///         event.map(|window_event, meta| match window_event{
    ///             WindowEvent::MouseDown(_) => {
    ///                 if meta.target == cx.current() {
    ///                     // Emit a `WindowClose` event when this view is clicked on.
    ///                     cx.emit(WindowEvent::WindowClose);
    ///                 }
    ///             }
    ///
    ///             _=> {}
    ///         });
    ///     }
    /// }
    /// ```
    #[allow(unused_variables)]
    fn event(&mut self, cx: &mut EventContext, event: &mut Event) {}

    /// Provides custom drawing for the view.
    ///
    /// Usually the look of a view is determined by the style and layout properties of the view. However, the `draw` method of
    /// the `View` trait can be used to provide completely custom drawing for the view. The properties of the view can be accessed
    /// through the provided [`DrawContext`] and the provided [`Canvas`] can be used to draw custom paths.
    ///
    /// # Example
    /// ```
    /// # use vizia_core::prelude::*;
    /// # use vizia_core::vg;
    /// pub struct CustomView{}
    ///
    /// impl CustomView {
    ///     pub fn new(cx: &mut Context) -> Handle<Self> {
    ///         Self{}.build(cx, |_|{})
    ///     }
    /// }
    ///
    /// impl View for CustomView {
    ///     fn draw(&self, cx: &mut DrawContext, canvas: &mut Canvas) {
    ///         // Get the bounding box of the current view.
    ///         let bounds = cx.bounds();
    ///
    ///         // Create a new `Path` from the `vg` module.
    ///         let mut path = vg::Path::new();
    ///         // Add a rectangle to the path with the dimensions of the view bounds.
    ///         path.rect(bounds.x, bounds.y, bounds.w, bounds.h);
    ///         // Fill the path onto the canvas with a red color.
    ///         canvas.fill_path(&mut path, &vg::Paint::color(Color::red().into()));
    ///     }
    /// }
    /// ```
    fn draw(&self, cx: &mut DrawContext, canvas: &Canvas) {
        let bounds = cx.bounds();

        //Skip widgets with no width or no height
        if bounds.w == 0.0 || bounds.h == 0.0 {
            return;
        }
        // cx.draw_backdrop_filter(canvas, &mut path);

        cx.draw_background(canvas);
        cx.draw_shadows(canvas);

        cx.draw_border(canvas);

        // cx.draw_inset_shadows(canvas, &mut path);

        cx.draw_outline(canvas);

        // cx.draw_text_and_selection(canvas);

        cx.draw_text(canvas);
    }

    #[allow(unused_variables)]
    fn accessibility(&self, cx: &mut AccessContext, node: &mut AccessNode) {}
}

impl<T: View> ViewHandler for T
where
    T: std::marker::Sized + View + 'static,
{
    fn element(&self) -> Option<&'static str> {
        <T as View>::element(self)
    }

    fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
        <T as View>::event(self, cx, event);
    }

    fn draw(&self, cx: &mut DrawContext, canvas: &Canvas) {
        <T as View>::draw(self, cx, canvas);
    }

    fn accessibility(&self, cx: &mut AccessContext, node: &mut AccessNode) {
        <T as View>::accessibility(self, cx, node);
    }

    fn as_any_ref(&self) -> &dyn Any {
        self
    }

    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}