mirror of
https://github.com/danbulant/mangui
synced 2026-07-08 04:10:44 +00:00
BROKEN: tonights progress
This commit is contained in:
parent
b84a8fba38
commit
5d53e10a32
5 changed files with 379 additions and 17 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
use std::sync::{RwLock, Arc};
|
use std::sync::{RwLock, Arc};
|
||||||
|
|
||||||
use mangui::{self, nodes::{layout::Layout, self, Style, TaffyStyle}, taffy::{self, prelude::Size, style::Dimension}, femtovg::{Paint, Color}, CurrentRenderer, SharedNode};
|
use mangui::{self, nodes::{layout::Layout, self, Style, TaffyStyle}, taffy::{self, prelude::Size, style::Dimension}, femtovg::{Paint, Color}, SharedNode};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut root = Layout::<CurrentRenderer>::new();
|
let mut root = Layout::default();
|
||||||
root.style.layout.display = taffy::style::Display::Flex;
|
root.style.layout.display = taffy::style::Display::Flex;
|
||||||
root.style.layout.flex_direction = taffy::style::FlexDirection::Row;
|
root.style.layout.flex_direction = taffy::style::FlexDirection::Row;
|
||||||
root.children.push(Arc::new(RwLock::new(nodes::primitives::Rectangle {
|
root.children.push(Arc::new(RwLock::new(nodes::primitives::Rectangle {
|
||||||
|
|
@ -81,7 +81,7 @@ fn main() {
|
||||||
fill: Paint::color(Color::rgb(0, 0, 255)),
|
fill: Paint::color(Color::rgb(0, 0, 255)),
|
||||||
radius: 0.
|
radius: 0.
|
||||||
})));
|
})));
|
||||||
let groot: SharedNode<CurrentRenderer> = Arc::new(RwLock::new(root));
|
let groot: SharedNode = Arc::new(RwLock::new(root));
|
||||||
|
|
||||||
mangui::run_event_loop(groot);
|
mangui::run_event_loop(groot);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
231
ui/src/events/mod.rs
Normal file
231
ui/src/events/mod.rs
Normal file
|
|
@ -0,0 +1,231 @@
|
||||||
|
use std::ops::{AddAssign, Add, SubAssign, Sub};
|
||||||
|
|
||||||
|
use taffy::{prelude::Size, style::Dimension, geometry::Point};
|
||||||
|
use winit::event::ElementState;
|
||||||
|
pub use winit::event::{TouchPhase, MouseScrollDelta, DeviceId, ModifiersState, VirtualKeyCode, ScanCode, MouseButton};
|
||||||
|
|
||||||
|
use crate::SharedNode;
|
||||||
|
|
||||||
|
pub struct NodeEvent {
|
||||||
|
/// Target node of event.
|
||||||
|
pub target: SharedNode,
|
||||||
|
/// Path to the target - target will be the last item in the path.
|
||||||
|
pub path: Vec<SharedNode>,
|
||||||
|
/// Actual event
|
||||||
|
pub event: InnerEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Different event types that can be sent to a node.
|
||||||
|
pub enum InnerEvent {
|
||||||
|
Wheel {
|
||||||
|
phase: TouchPhase,
|
||||||
|
delta: MouseScrollDelta,
|
||||||
|
mouse: MouseEvent
|
||||||
|
},
|
||||||
|
/// Mouse enter event is fired when the mouse enters the target node or any of its children, and bubbles
|
||||||
|
MouseEnter(MouseEvent),
|
||||||
|
/// Mouse over event is fired when the mouse enters the target node, but not its children, and does not bubble
|
||||||
|
MouseOver(MouseEvent),
|
||||||
|
/// Mouse leave event is fired when the mouse leaves the target node or any of its children, and bubbles
|
||||||
|
MouseLeave(MouseEvent),
|
||||||
|
/// Mouse out event is fired when the mouse leaves the target node, but not its children, and does not bubble
|
||||||
|
MouseOut(MouseEvent),
|
||||||
|
/// Mouse moved
|
||||||
|
MouseMove(MouseEvent),
|
||||||
|
/// Mouse button pressed
|
||||||
|
MouseDown(MouseEvent),
|
||||||
|
/// Mouse button released
|
||||||
|
MouseUp(MouseEvent),
|
||||||
|
/// Mouse button clicked - fired after clicking and releasing a button without changing the target element
|
||||||
|
Click(MouseEvent),
|
||||||
|
/// Mouse secondary button (usually right) clicked
|
||||||
|
ContextMenu(MouseEvent),
|
||||||
|
/// Mouse tertiary button (usually middle or scroll wheel) clicked
|
||||||
|
AuxClick(MouseEvent),
|
||||||
|
/// Focus event is fired only on the target node and does not bubble
|
||||||
|
Focus,
|
||||||
|
/// Blur event is fired only on the target node and does not bubble
|
||||||
|
Blur,
|
||||||
|
/// Same as [InnerEvent::Focus] but bubbles
|
||||||
|
FocusIn,
|
||||||
|
/// Same as [InnerEvent::Blur] but bubbles
|
||||||
|
FocusOut,
|
||||||
|
/// Key pressed
|
||||||
|
KeyDown(KeyboardEvent),
|
||||||
|
/// Key released
|
||||||
|
KeyUp(KeyboardEvent),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct KeyboardEvent {
|
||||||
|
/// Logical location ("it's effect") of the key
|
||||||
|
pub key: Option<VirtualKeyCode>,
|
||||||
|
/// Physical location of the key
|
||||||
|
pub code: ScanCode,
|
||||||
|
|
||||||
|
// altKey: bool,
|
||||||
|
// ctrlKey: bool,
|
||||||
|
// metaKey: bool,
|
||||||
|
// shiftKey: bool,
|
||||||
|
/// modifier keys pressed (alt, ctrl, shift or meta/logo/windows)
|
||||||
|
pub modifiers: ModifiersState,
|
||||||
|
|
||||||
|
// repeat: bool,
|
||||||
|
// char_code: u32,
|
||||||
|
// key_code: u32,
|
||||||
|
// which: u32,
|
||||||
|
/// DeviceId as passed by winit. An opaque, only useful when comparing with other events.
|
||||||
|
pub device: DeviceId
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MouseEvent {
|
||||||
|
/// The button which fired the event (if any)
|
||||||
|
pub button: Option<MouseButton>,
|
||||||
|
/// The buttons which are currently pressed as a bitmask.
|
||||||
|
/// Use [MouseEvent::button_to_buttons] to convert a single button to a bitmask.
|
||||||
|
pub buttons: u8,
|
||||||
|
|
||||||
|
// altKey: bool,
|
||||||
|
// ctrlKey: bool,
|
||||||
|
// metaKey: bool,
|
||||||
|
// shiftKey: bool,
|
||||||
|
/// modifier keys pressed (alt, ctrl, shift or meta/logo/windows)
|
||||||
|
pub modifiers: ModifiersState,
|
||||||
|
|
||||||
|
/// The location of the mouse relative to window
|
||||||
|
pub client: Location,
|
||||||
|
|
||||||
|
/// The location of the mouse relative to last event
|
||||||
|
pub movement: Location,
|
||||||
|
|
||||||
|
/// The location of the mouse relative to the target node (not the current node!)
|
||||||
|
/// For the first event, this will be 0, 0
|
||||||
|
pub offset: Location,
|
||||||
|
|
||||||
|
/// DeviceId as passed by winit. An opaque, only useful when comparing with other events.
|
||||||
|
pub device: DeviceId
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default, Debug, PartialEq)]
|
||||||
|
pub struct Location {
|
||||||
|
pub x: f32,
|
||||||
|
pub y: f32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddAssign for Location {
|
||||||
|
fn add_assign(&mut self, rhs: Self) {
|
||||||
|
self.x += rhs.x;
|
||||||
|
self.y += rhs.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Location {
|
||||||
|
pub fn new(x: f32, y: f32) -> Self {
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(f32, f32)> for Location {
|
||||||
|
fn from((x, y): (f32, f32)) -> Self {
|
||||||
|
Self { x, y }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(f64, f64)> for Location {
|
||||||
|
fn from((x, y): (f64, f64)) -> Self {
|
||||||
|
Self { x: x as f32, y: y as f32 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Point<f32>> for Location {
|
||||||
|
fn from(point: Point<f32>) -> Self {
|
||||||
|
Self { x: point.x, y: point.y }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add for Location {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x + rhs.x,
|
||||||
|
y: self.y + rhs.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubAssign for Location {
|
||||||
|
fn sub_assign(&mut self, rhs: Self) {
|
||||||
|
self.x -= rhs.x;
|
||||||
|
self.y -= rhs.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub for Location {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn sub(self, rhs: Self) -> Self::Output {
|
||||||
|
Self {
|
||||||
|
x: self.x - rhs.x,
|
||||||
|
y: self.y - rhs.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<(f32, f32)> for Location {
|
||||||
|
fn into(self) -> (f32, f32) {
|
||||||
|
(self.x, self.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Size<Dimension>> for Location {
|
||||||
|
fn into(self) -> Size<Dimension> {
|
||||||
|
Size {
|
||||||
|
width: Dimension::Points(self.x as f32),
|
||||||
|
height: Dimension::Points(self.y as f32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MouseEvent {
|
||||||
|
/// Returns `true` if the shift key is pressed.
|
||||||
|
pub fn shift(&self) -> bool {
|
||||||
|
self.modifiers.intersects(ModifiersState::SHIFT)
|
||||||
|
}
|
||||||
|
/// Returns `true` if the control key is pressed.
|
||||||
|
pub fn ctrl(&self) -> bool {
|
||||||
|
self.modifiers.intersects(ModifiersState::CTRL)
|
||||||
|
}
|
||||||
|
/// Returns `true` if the alt key is pressed.
|
||||||
|
pub fn alt(&self) -> bool {
|
||||||
|
self.modifiers.intersects(ModifiersState::ALT)
|
||||||
|
}
|
||||||
|
/// Returns `true` if the logo key is pressed.
|
||||||
|
pub fn logo(&self) -> bool {
|
||||||
|
self.modifiers.intersects(ModifiersState::LOGO)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn button_to_buttons(button: MouseButton) -> u8 {
|
||||||
|
match button {
|
||||||
|
MouseButton::Left => 1,
|
||||||
|
MouseButton::Right => 2,
|
||||||
|
MouseButton::Middle => 4,
|
||||||
|
MouseButton::Other(n) => 1 << n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub(crate) struct MouseValue {
|
||||||
|
pub last_location: Location,
|
||||||
|
pub buttons: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MouseValue {
|
||||||
|
fn update_buttons(&mut self, button: MouseButton, state: ElementState) {
|
||||||
|
let buttons = MouseEvent::button_to_buttons(button);
|
||||||
|
match state {
|
||||||
|
ElementState::Pressed => self.buttons |= buttons,
|
||||||
|
ElementState::Released => self.buttons &= !buttons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
108
ui/src/lib.rs
108
ui/src/lib.rs
|
|
@ -1,14 +1,17 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::num::NonZeroU32;
|
use std::num::NonZeroU32;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::{Arc, RwLock, Weak};
|
use std::sync::{Arc, RwLock, Weak};
|
||||||
|
|
||||||
|
use events::{Location, MouseValue, NodeEvent, MouseEvent};
|
||||||
use femtovg::renderer::OpenGl;
|
use femtovg::renderer::OpenGl;
|
||||||
use femtovg::{Canvas, Color};
|
use femtovg::{Canvas, Color};
|
||||||
use glutin::surface::Surface;
|
use glutin::surface::Surface;
|
||||||
use glutin::{context::PossiblyCurrentContext, display::Display};
|
use glutin::{context::PossiblyCurrentContext, display::Display};
|
||||||
use glutin_winit::DisplayBuilder;
|
use glutin_winit::DisplayBuilder;
|
||||||
|
use nodes::get_element_at;
|
||||||
use raw_window_handle::HasRawWindowHandle;
|
use raw_window_handle::HasRawWindowHandle;
|
||||||
use winit::event::{Event, WindowEvent};
|
use winit::event::{Event, WindowEvent, ModifiersState, DeviceId};
|
||||||
use winit::event_loop::{ControlFlow, EventLoop};
|
use winit::event_loop::{ControlFlow, EventLoop};
|
||||||
use winit::window::WindowBuilder;
|
use winit::window::WindowBuilder;
|
||||||
use winit::{dpi::PhysicalSize, window::Window};
|
use winit::{dpi::PhysicalSize, window::Window};
|
||||||
|
|
@ -27,6 +30,7 @@ use weak_table::PtrWeakKeyHashMap;
|
||||||
use crate::nodes::{layout_recursively, Node, render_recursively, RenderContext};
|
use crate::nodes::{layout_recursively, Node, render_recursively, RenderContext};
|
||||||
|
|
||||||
pub mod nodes;
|
pub mod nodes;
|
||||||
|
pub mod events;
|
||||||
pub use taffy;
|
pub use taffy;
|
||||||
pub use femtovg;
|
pub use femtovg;
|
||||||
|
|
||||||
|
|
@ -68,11 +72,101 @@ pub fn run_event_loop(root_node: SharedNode) -> ! {
|
||||||
|
|
||||||
let mut should_recompute = true;
|
let mut should_recompute = true;
|
||||||
|
|
||||||
|
let mut modifiers = ModifiersState::default();
|
||||||
|
let focus_path: Option<Vec<WeakNode>> = None;
|
||||||
|
let mut mouse_values: HashMap<DeviceId, MouseValue> = HashMap::new();
|
||||||
|
|
||||||
event_loop.run(move |event, _target, control_flow| match event {
|
event_loop.run(move |event, _target, control_flow| match event {
|
||||||
Event::WindowEvent { event, .. } => match event {
|
Event::WindowEvent { event, .. } => match event {
|
||||||
// WindowEvent::CursorMoved { position, .. } => {
|
WindowEvent::MouseWheel { device_id, delta, phase, .. } => {},
|
||||||
// window.request_redraw();
|
WindowEvent::CursorMoved { device_id, position, .. } => {
|
||||||
// }
|
let mouse_value = mouse_values.get(&device_id);
|
||||||
|
let (movement, location, buttons) = match mouse_value {
|
||||||
|
Some(mouse_value) => {
|
||||||
|
let location = (position.x, position.y).into();
|
||||||
|
let movement = location - mouse_value.last_location;
|
||||||
|
mouse_values.insert(device_id, MouseValue {
|
||||||
|
last_location: location,
|
||||||
|
buttons: mouse_value.buttons
|
||||||
|
});
|
||||||
|
(movement, location, mouse_value.buttons)
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
let location = (position.x, position.y).into();
|
||||||
|
let movement = Location::new(0., 0.);
|
||||||
|
let value = MouseValue {
|
||||||
|
last_location: location,
|
||||||
|
buttons: 0
|
||||||
|
};
|
||||||
|
mouse_values.insert(device_id, value);
|
||||||
|
(movement, location, Default::default())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let path = get_element_at(&root, &context, location);
|
||||||
|
|
||||||
|
if let Some(path) = path {
|
||||||
|
let target_layout = context.node_layout.get(path.last().unwrap());
|
||||||
|
let target_layout = match target_layout {
|
||||||
|
Some(target_layout) => target_layout,
|
||||||
|
None => { return; }
|
||||||
|
};
|
||||||
|
let target_layout = taffy.layout(target_layout.to_owned()).unwrap();
|
||||||
|
let event = NodeEvent {
|
||||||
|
target: path.last().unwrap().clone(),
|
||||||
|
path: path.clone(),
|
||||||
|
event: events::InnerEvent::MouseMove(MouseEvent {
|
||||||
|
button: None,
|
||||||
|
buttons,
|
||||||
|
client: location,
|
||||||
|
movement,
|
||||||
|
device: device_id,
|
||||||
|
modifiers,
|
||||||
|
offset: location - target_layout.location.into()
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
WindowEvent::DroppedFile(path) => {},
|
||||||
|
WindowEvent::HoveredFile(path) => {},
|
||||||
|
WindowEvent::HoveredFileCancelled => {},
|
||||||
|
WindowEvent::Focused(focused) => {
|
||||||
|
match &focus_path {
|
||||||
|
Some(path) => {
|
||||||
|
let strong_focus_path: Option<Vec<SharedNode>> = convert_vec_option_to_option_vec(path.iter().map(|weak| weak.upgrade()).collect());
|
||||||
|
if matches!(strong_focus_path, None) { return; }
|
||||||
|
let strong_focus_path = strong_focus_path.unwrap();
|
||||||
|
if strong_focus_path.len() == 0 { return; }
|
||||||
|
|
||||||
|
let focus_event = NodeEvent {
|
||||||
|
target: strong_focus_path.last().unwrap().clone(),
|
||||||
|
path: strong_focus_path.clone(),
|
||||||
|
event: if focused { events::InnerEvent::Focus } else { events::InnerEvent::Blur }
|
||||||
|
};
|
||||||
|
strong_focus_path.last().unwrap().write().unwrap().on_event(&focus_event.event);
|
||||||
|
|
||||||
|
let focus_event = NodeEvent {
|
||||||
|
target: strong_focus_path.last().unwrap().clone(),
|
||||||
|
path: strong_focus_path.clone(),
|
||||||
|
event: if focused { events::InnerEvent::FocusIn } else { events::InnerEvent::FocusOut }
|
||||||
|
};
|
||||||
|
|
||||||
|
for node in strong_focus_path.iter().rev() {
|
||||||
|
node.write().unwrap().on_event(&focus_event.event);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
WindowEvent::ModifiersChanged(new_modifiers) => { modifiers = new_modifiers; },
|
||||||
|
WindowEvent::KeyboardInput { device_id, input, is_synthetic } => {},
|
||||||
|
WindowEvent::MouseInput { device_id, state, button, .. } => {
|
||||||
|
let mouse_value = mouse_values.get(&device_id);
|
||||||
|
let mouse_value = match mouse_value {
|
||||||
|
Some(mouse_value) => mouse_value,
|
||||||
|
None => { return; } // Mouse move should be fired first
|
||||||
|
};
|
||||||
|
},
|
||||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||||
WindowEvent::Resized(size) => {
|
WindowEvent::Resized(size) => {
|
||||||
let width: NonZeroU32 = NonZeroU32::new(size.width).unwrap();
|
let width: NonZeroU32 = NonZeroU32::new(size.width).unwrap();
|
||||||
|
|
@ -122,6 +216,12 @@ pub fn run_event_loop(root_node: SharedNode) -> ! {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// I have no idea if there's a better way to do this in rust...
|
||||||
|
/// Found via ChatGPT (the only piece of code by chatgpt itself in this whole project as of now)
|
||||||
|
fn convert_vec_option_to_option_vec<T>(vec: Vec<Option<T>>) -> Option<Vec<T>> {
|
||||||
|
vec.into_iter().collect::<Option<Vec<T>>>()
|
||||||
|
}
|
||||||
|
|
||||||
fn create_window(event_loop: &EventLoop<()>) -> (PossiblyCurrentContext, Display, Window, Surface<WindowSurface>) {
|
fn create_window(event_loop: &EventLoop<()>) -> (PossiblyCurrentContext, Display, Window, Surface<WindowSurface>) {
|
||||||
let window_builder = WindowBuilder::new()
|
let window_builder = WindowBuilder::new()
|
||||||
.with_inner_size(PhysicalSize::new(1000., 600.))
|
.with_inner_size(PhysicalSize::new(1000., 600.))
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,19 @@
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use femtovg::Renderer;
|
use crate::nodes::{Node, NodeChildren, Style};
|
||||||
use crate::nodes::{Node, NodeChildren, Overflow, Style};
|
use taffy::style::Dimension;
|
||||||
use taffy::style::{Style as TaffyStyle, Dimension};
|
|
||||||
|
|
||||||
|
/// A simple layout node which contains children.
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
|
|
||||||
pub struct Layout {
|
pub struct Layout {
|
||||||
pub style: Style,
|
pub style: Style,
|
||||||
pub children: NodeChildren
|
pub children: NodeChildren
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Layout {
|
impl Layout {
|
||||||
pub fn new() -> Layout {
|
pub fn new(children: NodeChildren) -> Layout {
|
||||||
Layout {
|
Layout {
|
||||||
style: Style {
|
style: Style::default(),
|
||||||
layout: TaffyStyle::default(),
|
children
|
||||||
overflow: Overflow::Visible
|
|
||||||
},
|
|
||||||
children: NodeChildren::new()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use femtovg::{Canvas, Color};
|
||||||
use taffy::layout::Layout;
|
use taffy::layout::Layout;
|
||||||
pub use taffy::style::Style as TaffyStyle;
|
pub use taffy::style::Style as TaffyStyle;
|
||||||
use taffy::Taffy;
|
use taffy::Taffy;
|
||||||
|
use crate::events::Location;
|
||||||
use crate::{NodeLayoutMap, NodePtr, CurrentRenderer};
|
use crate::{NodeLayoutMap, NodePtr, CurrentRenderer};
|
||||||
|
|
||||||
type SharedTNode = Arc<RwLock<dyn Node>>;
|
type SharedTNode = Arc<RwLock<dyn Node>>;
|
||||||
|
|
@ -67,6 +68,40 @@ pub trait Node: Debug {
|
||||||
/// Is an optional function instead of another trait because of missing support for trait upcasting
|
/// Is an optional function instead of another trait because of missing support for trait upcasting
|
||||||
// TODO: When rust supports trait upcasting, make this a trait
|
// TODO: When rust supports trait upcasting, make this a trait
|
||||||
fn resize(&mut self, _width: f32, _height: f32) {}
|
fn resize(&mut self, _width: f32, _height: f32) {}
|
||||||
|
|
||||||
|
/// Called when an event happens on the node. This is called after the children have been called.
|
||||||
|
/// Beware! Events include a path and target with [Arc<RwLock<Node>>]s, but you already have a write lock for this node!
|
||||||
|
/// Remember to check if the node is the same as self, and if it is, use self instead of the node in the path to prevent deadlocks!
|
||||||
|
fn on_event(&mut self, _event: &crate::events::InnerEvent) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_element_at(node: &SharedTNode, context: &RenderContext, location: Location) -> Option<Vec<SharedTNode>> {
|
||||||
|
let children = node.read().unwrap().children();
|
||||||
|
let taffy_node = context.node_layout.get(node);
|
||||||
|
let taffy_node = match taffy_node {
|
||||||
|
Some(taffy_node) => taffy_node,
|
||||||
|
None => { return None }
|
||||||
|
};
|
||||||
|
let layout = *context.taffy.layout(*taffy_node).unwrap();
|
||||||
|
|
||||||
|
if layout.location.x <= location.x && layout.location.y <= location.y && layout.location.x + layout.size.width >= location.x && layout.location.y + layout.size.height >= location.y {
|
||||||
|
match children {
|
||||||
|
None => {
|
||||||
|
Some(vec![node.clone()])
|
||||||
|
},
|
||||||
|
Some(children) => {
|
||||||
|
let mut result = vec![node.clone()];
|
||||||
|
for child in children {
|
||||||
|
if let Some(mut path) = get_element_at(child, context, location) {
|
||||||
|
result.append(&mut path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layout_recursively(node: &SharedTNode, context: &mut RenderContext) -> taffy::node::Node {
|
pub fn layout_recursively(node: &SharedTNode, context: &mut RenderContext) -> taffy::node::Node {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue