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
}
}