use std::any::{Any, TypeId};
use std::collections::{BinaryHeap, VecDeque};
#[cfg(feature = "clipboard")]
use std::error::Error;
use std::rc::Rc;
use hashbrown::{HashMap, HashSet};
use vizia_storage::{LayoutTreeIterator, TreeIterator};
use vizia_window::WindowPosition;
use crate::animation::{AnimId, Interpolator};
use crate::cache::CachedData;
use crate::events::{TimedEvent, TimedEventHandle, TimerState, ViewHandler};
use crate::model::ModelDataStore;
use crate::prelude::*;
use crate::resource::ResourceManager;
use crate::tree::{focus_backward, focus_forward, is_navigatable};
use vizia_input::MouseState;
use skia_safe::Matrix;
use crate::text::TextContext;
#[cfg(feature = "clipboard")]
use copypasta::ClipboardProvider;
use super::{LocalizationContext, DARK_THEME, LIGHT_THEME};
pub struct EventContext<'a> {
pub(crate) current: Entity,
pub(crate) captured: &'a mut Entity,
pub(crate) focused: &'a mut Entity,
pub(crate) hovered: &'a Entity,
pub(crate) triggered: &'a mut Entity,
pub(crate) style: &'a mut Style,
pub(crate) entity_identifiers: &'a HashMap<String, Entity>,
pub cache: &'a mut CachedData,
pub(crate) tree: &'a Tree<Entity>,
pub(crate) data: &'a mut HashMap<Entity, ModelDataStore>,
pub(crate) views: &'a mut HashMap<Entity, Box<dyn ViewHandler>>,
pub(crate) listeners:
&'a mut HashMap<Entity, Box<dyn Fn(&mut dyn ViewHandler, &mut EventContext, &mut Event)>>,
pub(crate) resource_manager: &'a mut ResourceManager,
pub(crate) text_context: &'a mut TextContext,
pub(crate) modifiers: &'a Modifiers,
pub(crate) mouse: &'a MouseState<Entity>,
pub(crate) event_queue: &'a mut VecDeque<Event>,
pub(crate) event_schedule: &'a mut BinaryHeap<TimedEvent>,
pub(crate) next_event_id: &'a mut usize,
pub(crate) timers: &'a mut Vec<TimerState>,
pub(crate) running_timers: &'a mut BinaryHeap<TimerState>,
cursor_icon_locked: &'a mut bool,
#[cfg(feature = "clipboard")]
clipboard: &'a mut Box<dyn ClipboardProvider>,
pub(crate) event_proxy: &'a mut Option<Box<dyn crate::context::EventProxy>>,
pub(crate) ignore_default_theme: &'a bool,
pub(crate) drop_data: &'a mut Option<DropData>,
pub windows: &'a mut HashMap<Entity, WindowState>,
}
macro_rules! get_length_property {
(
$(#[$meta:meta])*
$name:ident
) => {
$(#[$meta])*
pub fn $name(&self) -> f32 {
if let Some(length) = self.style.$name.get(self.current) {
let bounds = self.bounds();
let px = length.to_pixels(bounds.w.min(bounds.h), self.scale_factor());
return px.round();
}
0.0
}
};
}
impl<'a> EventContext<'a> {
pub fn new(cx: &'a mut Context) -> Self {
Self {
current: cx.current,
captured: &mut cx.captured,
focused: &mut cx.focused,
hovered: &cx.hovered,
triggered: &mut cx.triggered,
entity_identifiers: &cx.entity_identifiers,
style: &mut cx.style,
cache: &mut cx.cache,
tree: &cx.tree,
data: &mut cx.data,
views: &mut cx.views,
listeners: &mut cx.listeners,
resource_manager: &mut cx.resource_manager,
text_context: &mut cx.text_context,
modifiers: &cx.modifiers,
mouse: &cx.mouse,
event_queue: &mut cx.event_queue,
event_schedule: &mut cx.event_schedule,
next_event_id: &mut cx.next_event_id,
timers: &mut cx.timers,
running_timers: &mut cx.running_timers,
cursor_icon_locked: &mut cx.cursor_icon_locked,
#[cfg(feature = "clipboard")]
clipboard: &mut cx.clipboard,
event_proxy: &mut cx.event_proxy,
ignore_default_theme: &cx.ignore_default_theme,
drop_data: &mut cx.drop_data,
windows: &mut cx.windows,
}
}
pub fn new_with_current(cx: &'a mut Context, current: Entity) -> Self {
Self {
current,
captured: &mut cx.captured,
focused: &mut cx.focused,
hovered: &cx.hovered,
triggered: &mut cx.triggered,
entity_identifiers: &cx.entity_identifiers,
style: &mut cx.style,
cache: &mut cx.cache,
tree: &cx.tree,
data: &mut cx.data,
views: &mut cx.views,
listeners: &mut cx.listeners,
resource_manager: &mut cx.resource_manager,
text_context: &mut cx.text_context,
modifiers: &cx.modifiers,
mouse: &cx.mouse,
event_queue: &mut cx.event_queue,
event_schedule: &mut cx.event_schedule,
next_event_id: &mut cx.next_event_id,
timers: &mut cx.timers,
running_timers: &mut cx.running_timers,
cursor_icon_locked: &mut cx.cursor_icon_locked,
#[cfg(feature = "clipboard")]
clipboard: &mut cx.clipboard,
event_proxy: &mut cx.event_proxy,
ignore_default_theme: &cx.ignore_default_theme,
drop_data: &mut cx.drop_data,
windows: &mut cx.windows,
}
}
pub fn get_view<V: View>(&self) -> Option<&V> {
self.views.get(&self.current).and_then(|view| view.downcast_ref::<V>())
}
pub fn close_window(&mut self) {
if let Some(state) = self.windows.get_mut(&self.current) {
state.should_close = true;
}
}
pub fn window_position(&self) -> WindowPosition {
let parent_window = self.parent_window().unwrap_or(Entity::root());
if let Some(state) = self.windows.get(&parent_window) {
return state.position;
}
WindowPosition::new(0, 0)
}
pub fn window_size(&self) -> WindowSize {
let parent_window = self.parent_window().unwrap_or(Entity::root());
let bounds = self.cache.get_bounds(parent_window);
WindowSize::new(bounds.width() as u32, bounds.height() as u32)
}
pub fn resolve_entity_identifier(&self, id: &str) -> Option<Entity> {
self.entity_identifiers.get(id).cloned()
}
pub fn current(&self) -> Entity {
self.current
}
pub fn modifiers(&self) -> &Modifiers {
self.modifiers
}
pub fn mouse(&self) -> &MouseState<Entity> {
self.mouse
}
pub fn nth_child(&self, n: usize) -> Option<Entity> {
self.tree.get_child(self.current, n)
}
pub fn last_child(&self) -> Option<Entity> {
self.tree.get_last_child(self.current).copied()
}
pub fn with_current<T>(&mut self, entity: Entity, f: impl FnOnce(&mut Self) -> T) -> T {
let prev = self.current();
self.current = entity;
let ret = (f)(self);
self.current = prev;
ret
}
pub fn has_drop_data(&self) -> bool {
self.drop_data.is_some()
}
pub fn bounds(&self) -> BoundingBox {
self.cache.get_bounds(self.current)
}
pub fn set_bounds(&mut self, bounds: BoundingBox) {
self.cache.set_bounds(self.current, bounds);
}
pub fn scale_factor(&self) -> f32 {
self.style.dpi_factor as f32
}
pub fn logical_to_physical(&self, logical: f32) -> f32 {
self.style.logical_to_physical(logical)
}
pub fn physical_to_logical(&self, physical: f32) -> f32 {
self.style.physical_to_logical(physical)
}
pub fn clip_region(&self) -> BoundingBox {
let bounds = self.bounds();
let overflowx = self.style.overflowx.get(self.current).copied().unwrap_or_default();
let overflowy = self.style.overflowy.get(self.current).copied().unwrap_or_default();
let scale = self.scale_factor();
let clip_bounds = self
.style
.clip_path
.get(self.current)
.map(|clip| match clip {
ClipPath::Auto => bounds,
ClipPath::Shape(rect) => bounds.shrink_sides(
rect.3.to_pixels(bounds.w, scale),
rect.0.to_pixels(bounds.h, scale),
rect.1.to_pixels(bounds.w, scale),
rect.2.to_pixels(bounds.h, scale),
),
})
.unwrap_or(bounds);
let root_bounds: BoundingBox =
BoundingBox { x: -f32::MAX / 2.0, y: -f32::MAX / 2.0, w: f32::MAX, h: f32::MAX };
match (overflowx, overflowy) {
(Overflow::Visible, Overflow::Visible) => root_bounds,
(Overflow::Hidden, Overflow::Visible) => {
let left = clip_bounds.left();
let right = clip_bounds.right();
let top = root_bounds.top();
let bottom = root_bounds.bottom();
BoundingBox::from_min_max(left, top, right, bottom)
}
(Overflow::Visible, Overflow::Hidden) => {
let left = root_bounds.left();
let right = root_bounds.right();
let top = clip_bounds.top();
let bottom = clip_bounds.bottom();
BoundingBox::from_min_max(left, top, right, bottom)
}
(Overflow::Hidden, Overflow::Hidden) => clip_bounds,
}
}
pub fn transform(&self) -> Matrix {
let bounds = self.bounds();
let scale_factor = self.scale_factor();
let mut origin = self
.style
.transform_origin
.get(self.current)
.map(|transform_origin| {
let mut origin = Matrix::translate(bounds.top_left());
let offset = transform_origin.as_transform(bounds, scale_factor);
origin = offset * origin;
origin
})
.unwrap_or(Matrix::translate(bounds.center()));
let mut transform = origin;
origin = origin.invert().unwrap();
if let Some(translate) = self.style.translate.get(self.current) {
transform = transform * translate.as_transform(bounds, scale_factor);
}
if let Some(rotate) = self.style.rotate.get(self.current) {
transform = transform * rotate.as_transform(bounds, scale_factor);
}
if let Some(scale) = self.style.scale.get(self.current) {
transform = transform * scale.as_transform(bounds, scale_factor);
}
if let Some(transforms) = self.style.transform.get(self.current) {
if let Some(animation_state) = self.style.transform.get_active_animation(self.current) {
if let Some(start) = animation_state.keyframes.first() {
if let Some(end) = animation_state.keyframes.last() {
let start_transform = start.value.as_transform(bounds, scale_factor);
let end_transform = end.value.as_transform(bounds, scale_factor);
let t = animation_state.t;
let animated_transform =
Matrix::interpolate(&start_transform, &end_transform, t);
transform = transform * animated_transform;
}
}
} else {
transform = transform * transforms.as_transform(bounds, scale_factor);
}
}
transform = transform * origin;
transform
}
pub fn play_animation(&mut self, anim_id: impl AnimId, duration: Duration, delay: Duration) {
if let Some(animation_id) = anim_id.get(self) {
self.style.enqueue_animation(self.current, animation_id, duration, delay);
}
}
pub fn play_animation_for(
&mut self,
anim_id: impl AnimId,
target: &str,
duration: Duration,
delay: Duration,
) {
if let Some(target_entity) = self.resolve_entity_identifier(target) {
if let Some(animation_id) = anim_id.get(self) {
self.style.enqueue_animation(target_entity, animation_id, duration, delay)
}
}
}
pub fn is_animating(&self, anim_id: impl AnimId) -> bool {
if let Some(animation_id) = anim_id.get(self) {
return self.style.is_animating(self.current, animation_id);
}
false
}
pub fn add_listener<F, W>(&mut self, listener: F)
where
W: View,
F: 'static + Fn(&mut W, &mut EventContext, &mut Event),
{
self.listeners.insert(
self.current,
Box::new(move |event_handler, context, event| {
if let Some(widget) = event_handler.downcast_mut::<W>() {
(listener)(widget, context, event);
}
}),
);
}
pub fn set_language(&mut self, lang: LanguageIdentifier) {
if let Some(mut model_data_store) = self.data.remove(&Entity::root()) {
if let Some(model) = model_data_store.models.get_mut(&TypeId::of::<Environment>()) {
model.event(self, &mut Event::new(EnvironmentEvent::SetLocale(lang)));
}
self.data.insert(Entity::root(), model_data_store);
}
}
pub fn capture(&mut self) {
*self.captured = self.current;
}
pub fn release(&mut self) {
if self.current == *self.captured {
*self.captured = Entity::null();
}
}
fn set_focus_pseudo_classes(&mut self, focused: Entity, enabled: bool, focus_visible: bool) {
if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(focused) {
pseudo_classes.set(PseudoClassFlags::FOCUS, enabled);
if !enabled || focus_visible {
pseudo_classes.set(PseudoClassFlags::FOCUS_VISIBLE, enabled);
}
}
for ancestor in focused.parent_iter(self.tree) {
let entity = ancestor;
if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(entity) {
pseudo_classes.set(PseudoClassFlags::FOCUS_WITHIN, enabled);
}
}
}
pub fn focus_with_visibility(&mut self, focus_visible: bool) {
let old_focus = self.focused();
let new_focus = self.current();
self.set_focus_pseudo_classes(old_focus, false, focus_visible);
if self.current() != self.focused() {
self.emit_to(old_focus, WindowEvent::FocusOut);
self.emit_to(new_focus, WindowEvent::FocusIn);
*self.focused = self.current();
}
self.set_focus_pseudo_classes(new_focus, true, focus_visible);
self.needs_restyle();
}
pub fn focus(&mut self) {
let focused = self.focused();
let old_focus_visible = self
.style
.pseudo_classes
.get_mut(focused)
.filter(|class| class.contains(PseudoClassFlags::FOCUS_VISIBLE))
.is_some();
self.focus_with_visibility(old_focus_visible)
}
pub fn focus_next(&mut self) {
let lock_focus_to = self.tree.lock_focus_within(*self.focused);
let next_focused = if let Some(next_focused) =
focus_forward(self.tree, self.style, *self.focused, lock_focus_to)
{
next_focused
} else {
TreeIterator::full(self.tree)
.find(|node| is_navigatable(self.tree, self.style, *node, lock_focus_to))
.unwrap_or(Entity::root())
};
if next_focused != *self.focused {
self.event_queue.push_back(
Event::new(WindowEvent::FocusOut).target(*self.focused).origin(Entity::root()),
);
self.event_queue.push_back(
Event::new(WindowEvent::FocusIn).target(next_focused).origin(Entity::root()),
);
if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(*self.triggered) {
pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
}
self.needs_restyle();
*self.triggered = Entity::null();
}
}
pub fn focus_prev(&mut self) {
let lock_focus_to = self.tree.lock_focus_within(*self.focused);
let prev_focused = if let Some(prev_focused) =
focus_backward(self.tree, self.style, *self.focused, lock_focus_to)
{
prev_focused
} else {
TreeIterator::full(self.tree)
.filter(|node| is_navigatable(self.tree, self.style, *node, lock_focus_to))
.next_back()
.unwrap_or(Entity::root())
};
if prev_focused != *self.focused {
self.event_queue.push_back(
Event::new(WindowEvent::FocusOut).target(*self.focused).origin(Entity::root()),
);
self.event_queue.push_back(
Event::new(WindowEvent::FocusIn).target(prev_focused).origin(Entity::root()),
);
if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(*self.triggered) {
pseudo_classes.set(PseudoClassFlags::ACTIVE, false);
}
self.needs_restyle();
*self.triggered = Entity::null();
}
}
pub fn hovered(&self) -> Entity {
*self.hovered
}
pub fn focused(&self) -> Entity {
*self.focused
}
pub fn is_hovered(&self) -> bool {
self.hovered() == self.current
}
pub fn is_active(&self) -> bool {
if let Some(pseudo_classes) = self.style.pseudo_classes.get(self.current) {
pseudo_classes.contains(PseudoClassFlags::ACTIVE)
} else {
false
}
}
pub fn is_over(&self) -> bool {
if let Some(pseudo_classes) = self.style.pseudo_classes.get(self.current) {
pseudo_classes.contains(PseudoClassFlags::OVER)
} else {
false
}
}
pub fn is_focused(&self) -> bool {
self.focused() == self.current
}
pub fn is_draggable(&self) -> bool {
self.style
.abilities
.get(self.current)
.map(|abilities| abilities.contains(Abilities::DRAGGABLE))
.unwrap_or_default()
}
pub fn is_disabled(&self) -> bool {
self.style.disabled.get(self.current()).cloned().unwrap_or_default()
}
pub fn is_checked(&self) -> bool {
if let Some(pseudo_classes) = self.style.pseudo_classes.get(self.current) {
pseudo_classes.contains(PseudoClassFlags::CHECKED)
} else {
false
}
}
pub fn is_read_only(&self) -> bool {
if let Some(pseudo_classes) = self.style.pseudo_classes.get(self.current) {
pseudo_classes.contains(PseudoClassFlags::READ_ONLY)
} else {
false
}
}
pub fn lock_cursor_icon(&mut self) {
*self.cursor_icon_locked = true;
}
pub fn unlock_cursor_icon(&mut self) {
*self.cursor_icon_locked = false;
let hovered = *self.hovered;
let cursor = self.style.cursor.get(hovered).cloned().unwrap_or_default();
self.emit(WindowEvent::SetCursor(cursor));
}
pub fn is_cursor_icon_locked(&self) -> bool {
*self.cursor_icon_locked
}
pub fn set_drop_data(&mut self, data: impl Into<DropData>) {
*self.drop_data = Some(data.into())
}
#[cfg(feature = "clipboard")]
pub fn get_clipboard(&mut self) -> Result<String, Box<dyn Error + Send + Sync + 'static>> {
self.clipboard.get_contents()
}
#[cfg(feature = "clipboard")]
pub fn set_clipboard(
&mut self,
text: String,
) -> Result<(), Box<dyn Error + Send + Sync + 'static>> {
self.clipboard.set_contents(text)
}
pub fn toggle_class(&mut self, class_name: &str, applied: bool) {
let current = self.current();
if let Some(class_list) = self.style.classes.get_mut(current) {
if applied {
class_list.insert(class_name.to_string());
} else {
class_list.remove(class_name);
}
} else if applied {
let mut class_list = HashSet::new();
class_list.insert(class_name.to_string());
self.style.classes.insert(current, class_list);
}
self.needs_restyle();
}
pub fn environment(&self) -> &Environment {
self.data::<Environment>().unwrap()
}
pub fn set_theme_mode(&mut self, theme_mode: ThemeMode) {
if !self.ignore_default_theme {
match theme_mode {
ThemeMode::LightMode => {
self.resource_manager.themes[2] = String::from(LIGHT_THEME);
}
ThemeMode::DarkMode => {
self.resource_manager.themes[2] = String::from(DARK_THEME);
}
}
}
}
pub fn needs_redraw(&mut self) {
let parent_window = self.tree.get_parent_window(self.current).unwrap_or(Entity::root());
if let Some(window_state) = self.windows.get_mut(&parent_window) {
window_state.redraw_list.insert(self.current);
}
}
pub fn needs_relayout(&mut self) {
self.style.needs_relayout();
self.needs_redraw();
}
pub fn needs_restyle(&mut self) {
self.style.restyle.insert(self.current).unwrap();
let iter = if let Some(parent) = self.tree.get_layout_parent(self.current) {
LayoutTreeIterator::subtree(self.tree, parent)
} else {
LayoutTreeIterator::subtree(self.tree, self.current)
};
for descendant in iter {
self.style.restyle.insert(descendant).unwrap();
}
self.style.needs_restyle(self.current);
}
pub fn reload_styles(&mut self) -> Result<(), std::io::Error> {
if self.resource_manager.themes.is_empty() && self.resource_manager.styles.is_empty() {
return Ok(());
}
self.style.remove_rules();
self.style.clear_style_rules();
let mut overall_theme = String::new();
for theme in self.resource_manager.themes.iter() {
overall_theme += theme;
}
for style_string in self.resource_manager.styles.iter().flat_map(|style| style.get_style())
{
overall_theme += &style_string;
}
self.style.parse_theme(&overall_theme);
for entity in self.tree.into_iter() {
self.style.needs_restyle(entity);
self.style.needs_relayout();
self.style.needs_text_update(entity);
}
Ok(())
}
pub fn spawn<F>(&self, target: F)
where
F: 'static + Send + FnOnce(&mut ContextProxy),
{
let mut cxp = ContextProxy {
current: self.current,
event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
};
std::thread::spawn(move || target(&mut cxp));
}
pub fn get_proxy(&self) -> ContextProxy {
ContextProxy {
current: self.current,
event_proxy: self.event_proxy.as_ref().map(|p| p.make_clone()),
}
}
pub fn modify<V: View>(&mut self, f: impl FnOnce(&mut V)) {
if let Some(view) = self
.views
.get_mut(&self.current)
.and_then(|view_handler| view_handler.downcast_mut::<V>())
{
(f)(view);
}
}
pub fn background_color(&mut self) -> Color {
self.style.background_color.get(self.current).copied().unwrap_or_default()
}
pub fn set_id(&mut self, id: &str) {
self.style.ids.insert(self.current, id.to_string())
}
pub fn set_hover(&mut self, flag: bool) {
let current = self.current();
if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(current) {
pseudo_classes.set(PseudoClassFlags::HOVER, flag);
}
self.needs_restyle();
}
pub fn set_active(&mut self, active: bool) {
if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(self.current) {
pseudo_classes.set(PseudoClassFlags::ACTIVE, active);
}
self.needs_restyle();
}
pub fn set_read_only(&mut self, flag: bool) {
let current = self.current();
if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(current) {
pseudo_classes.set(PseudoClassFlags::READ_ONLY, flag);
}
self.needs_restyle();
}
pub fn set_read_write(&mut self, flag: bool) {
let current = self.current();
if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(current) {
pseudo_classes.set(PseudoClassFlags::READ_WRITE, flag);
}
self.needs_restyle();
}
pub fn set_checked(&mut self, flag: bool) {
let current = self.current();
if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(current) {
pseudo_classes.set(PseudoClassFlags::CHECKED, flag);
}
self.needs_restyle();
}
pub fn set_valid(&mut self, flag: bool) {
let current = self.current();
if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(current) {
pseudo_classes.set(PseudoClassFlags::VALID, flag);
pseudo_classes.set(PseudoClassFlags::INVALID, !flag);
}
self.needs_restyle();
}
pub fn set_placeholder_shown(&mut self, flag: bool) {
let current = self.current();
if let Some(pseudo_classes) = self.style.pseudo_classes.get_mut(current) {
pseudo_classes.set(PseudoClassFlags::PLACEHOLDER_SHOWN, flag);
}
self.needs_restyle();
}
pub fn is_valid(&self) -> bool {
self.style
.pseudo_classes
.get(self.current)
.map(|pseudo_classes| pseudo_classes.contains(PseudoClassFlags::VALID))
.unwrap_or_default()
}
pub fn is_placeholder_shown(&self) -> bool {
self.style
.pseudo_classes
.get(self.current)
.map(|pseudo_classes| pseudo_classes.contains(PseudoClassFlags::PLACEHOLDER_SHOWN))
.unwrap_or_default()
}
pub fn set_name(&mut self, name: &str) {
self.style.name.insert(self.current, name.to_string());
}
pub fn set_role(&mut self, role: Role) {
self.style.role.insert(self.current, role);
}
pub fn set_default_action_verb(&mut self, default_action_verb: DefaultActionVerb) {
self.style.default_action_verb.insert(self.current, default_action_verb);
}
pub fn set_live(&mut self, live: Live) {
self.style.live.insert(self.current, live);
}
pub fn labelled_by(&mut self, id: &str) {
if let Some(entity) = self.resolve_entity_identifier(id) {
self.style.labelled_by.insert(self.current, entity);
}
}
pub fn set_hidden(&mut self, hidden: bool) {
self.style.hidden.insert(self.current, hidden)
}
pub fn text_value(&mut self, text: &str) {
self.style.text_value.insert(self.current, text.to_string());
}
pub fn numeric_value(&mut self, value: f64) {
self.style.numeric_value.insert(self.current, value);
}
pub fn set_display(&mut self, display: Display) {
self.style.display.insert(self.current, display);
}
pub fn set_visibility(&mut self, visibility: Visibility) {
self.style.visibility.insert(self.current, visibility);
}
pub fn set_opacity(&mut self, opacity: f32) {
self.style.opacity.insert(self.current, Opacity(opacity));
}
pub fn set_z_index(&mut self, z_index: i32) {
self.style.z_index.insert(self.current, z_index);
}
pub fn set_clip_path(&mut self, clip_path: ClipPath) {
self.style.clip_path.insert(self.current, clip_path);
}
pub fn set_overflowx(&mut self, overflowx: impl Into<Overflow>) {
self.style.overflowx.insert(self.current, overflowx.into());
}
pub fn set_overflowy(&mut self, overflowy: impl Into<Overflow>) {
self.style.overflowy.insert(self.current, overflowy.into());
}
pub fn set_transform(&mut self, transform: impl Into<Vec<Transform>>) {
self.style.transform.insert(self.current, transform.into());
}
pub fn set_transform_origin(&mut self, transform_origin: Translate) {
self.style.transform_origin.insert(self.current, transform_origin);
}
pub fn set_translate(&mut self, translate: impl Into<Translate>) {
self.style.translate.insert(self.current, translate.into());
}
pub fn set_rotate(&mut self, angle: impl Into<Angle>) {
self.style.rotate.insert(self.current, angle.into());
}
pub fn set_scale(&mut self, scale: impl Into<Scale>) {
self.style.scale.insert(self.current, scale.into());
}
pub fn set_backdrop_filter(&mut self, filter: Filter) {
self.style.backdrop_filter.insert(self.current, filter);
}
pub fn set_background_color(&mut self, background_color: Color) {
self.style.background_color.insert(self.current, background_color);
self.needs_redraw();
}
pub fn set_width(&mut self, width: Units) {
self.style.width.insert(self.current, width);
self.needs_relayout();
self.needs_redraw();
}
pub fn set_height(&mut self, height: Units) {
self.style.height.insert(self.current, height);
self.needs_relayout();
self.needs_redraw();
}
pub fn set_max_height(&mut self, height: Units) {
self.style.max_height.insert(self.current, height);
self.needs_relayout();
self.needs_redraw();
}
pub fn set_left(&mut self, left: Units) {
self.style.left.insert(self.current, left);
self.needs_relayout();
self.needs_redraw();
}
pub fn set_top(&mut self, left: Units) {
self.style.top.insert(self.current, left);
self.needs_relayout();
self.needs_redraw();
}
pub fn set_right(&mut self, left: Units) {
self.style.right.insert(self.current, left);
self.needs_relayout();
self.needs_redraw();
}
pub fn set_bottom(&mut self, left: Units) {
self.style.bottom.insert(self.current, left);
self.needs_relayout();
self.needs_redraw();
}
pub fn set_text(&mut self, text: &str) {
self.style.text.insert(self.current, text.to_owned());
self.style.needs_text_update(self.current);
self.needs_relayout();
self.needs_redraw();
}
pub fn set_pointer_events(&mut self, pointer_events: impl Into<PointerEvents>) {
self.style.pointer_events.insert(self.current, pointer_events.into());
}
get_length_property!(
border_width
);
pub fn font_size(&self) -> f32 {
self.logical_to_physical(
self.style.font_size.get(self.current).copied().map(|f| f.0).unwrap_or(16.0),
)
}
pub fn add_timer(
&mut self,
interval: Duration,
duration: Option<Duration>,
callback: impl Fn(&mut EventContext, TimerAction) + 'static,
) -> Timer {
let id = Timer(self.timers.len());
self.timers.push(TimerState {
entity: Entity::root(),
id,
time: Instant::now(),
interval,
duration,
start_time: Instant::now(),
callback: Rc::new(callback),
ticking: false,
stopping: false,
});
id
}
pub fn start_timer(&mut self, timer: Timer) {
let current = self.current;
if !self.timer_is_running(timer) {
let timer_state = self.timers[timer.0].clone();
self.running_timers.push(timer_state);
}
self.modify_timer(timer, |timer_state| {
let now = Instant::now();
timer_state.start_time = now;
timer_state.time = now;
timer_state.entity = current;
timer_state.ticking = false;
timer_state.stopping = false;
});
}
pub fn modify_timer(&mut self, timer: Timer, timer_function: impl Fn(&mut TimerState)) {
while let Some(next_timer_state) = self.running_timers.peek() {
if next_timer_state.id == timer {
let mut timer_state = self.running_timers.pop().unwrap();
(timer_function)(&mut timer_state);
self.running_timers.push(timer_state);
return;
}
}
for pending_timer in self.timers.iter_mut() {
if pending_timer.id == timer {
(timer_function)(pending_timer);
}
}
}
pub fn query_timer<T>(
&mut self,
timer: Timer,
timer_function: impl Fn(&TimerState) -> T,
) -> Option<T> {
while let Some(next_timer_state) = self.running_timers.peek() {
if next_timer_state.id == timer {
let timer_state = self.running_timers.pop().unwrap();
let t = (timer_function)(&timer_state);
self.running_timers.push(timer_state);
return Some(t);
}
}
for pending_timer in self.timers.iter() {
if pending_timer.id == timer {
return Some(timer_function(pending_timer));
}
}
None
}
pub fn timer_is_running(&mut self, timer: Timer) -> bool {
for timer_state in self.running_timers.iter() {
if timer_state.id == timer {
return true;
}
}
false
}
pub fn stop_timer(&mut self, timer: Timer) {
let mut running_timers = self.running_timers.clone();
for timer_state in running_timers.iter() {
if timer_state.id == timer {
self.with_current(timer_state.entity, |cx| {
(timer_state.callback)(cx, TimerAction::Stop);
});
}
}
*self.running_timers =
running_timers.drain().filter(|timer_state| timer_state.id != timer).collect();
}
}
impl<'a> DataContext for EventContext<'a> {
fn data<T: 'static>(&self) -> Option<&T> {
if let Some(t) = <dyn Any>::downcast_ref::<T>(&()) {
return Some(t);
}
for entity in self.current.parent_iter(self.tree) {
if let Some(model_data_store) = self.data.get(&entity) {
if let Some(model) = model_data_store.models.get(&TypeId::of::<T>()) {
return model.downcast_ref::<T>();
}
}
if let Some(view_handler) = self.views.get(&entity) {
if let Some(data) = view_handler.downcast_ref::<T>() {
return Some(data);
}
}
}
None
}
fn as_context(&self) -> Option<LocalizationContext<'_>> {
Some(LocalizationContext::from_event_context(self))
}
}
impl<'a> EmitContext for EventContext<'a> {
fn emit<M: Any + Send>(&mut self, message: M) {
self.event_queue.push_back(
Event::new(message)
.target(self.current)
.origin(self.current)
.propagate(Propagation::Up),
);
}
fn emit_to<M: Any + Send>(&mut self, target: Entity, message: M) {
self.event_queue.push_back(
Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
);
}
fn emit_custom(&mut self, event: Event) {
self.event_queue.push_back(event);
}
fn schedule_emit<M: Any + Send>(&mut self, message: M, at: Instant) -> TimedEventHandle {
self.schedule_emit_custom(
Event::new(message)
.target(self.current)
.origin(self.current)
.propagate(Propagation::Up),
at,
)
}
fn schedule_emit_to<M: Any + Send>(
&mut self,
target: Entity,
message: M,
at: Instant,
) -> TimedEventHandle {
self.schedule_emit_custom(
Event::new(message).target(target).origin(self.current).propagate(Propagation::Direct),
at,
)
}
fn schedule_emit_custom(&mut self, event: Event, at: Instant) -> TimedEventHandle {
let handle = TimedEventHandle(*self.next_event_id);
self.event_schedule.push(TimedEvent { event, time: at, ident: handle });
*self.next_event_id += 1;
handle
}
fn cancel_scheduled(&mut self, handle: TimedEventHandle) {
*self.event_schedule =
self.event_schedule.drain().filter(|item| item.ident != handle).collect();
}
}
pub trait TreeProps {
fn parent(&self) -> Entity;
fn first_child(&self) -> Entity;
fn parent_window(&self) -> Option<Entity>;
}
impl<'a> TreeProps for EventContext<'a> {
fn parent(&self) -> Entity {
self.tree.get_layout_parent(self.current).unwrap()
}
fn first_child(&self) -> Entity {
self.tree.get_layout_first_child(self.current).unwrap()
}
fn parent_window(&self) -> Option<Entity> {
self.tree.get_parent_window(self.current)
}
}