mirror of
https://github.com/danbulant/mangui
synced 2026-07-05 19:00:35 +00:00
update dependencies, add sort of busy loop
This commit is contained in:
parent
7609ab3de3
commit
8d6cecdfb1
4 changed files with 679 additions and 250 deletions
814
Cargo.lock
generated
814
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -7,9 +7,9 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
femtovg = "0.7.1"
|
femtovg = "0.7.1"
|
||||||
glutin = "0.30.10"
|
glutin = "0.31.0"
|
||||||
raw-window-handle = "0.5.0"
|
raw-window-handle = "0.5.0"
|
||||||
winit = { version = "0.28.7", default-features = false }
|
winit = { version = "0.29.2" }
|
||||||
glutin-winit = "0.3.0"
|
glutin-winit = "0.4.2"
|
||||||
taffy = "0.3.16"
|
taffy = "0.3.16"
|
||||||
weak-table = "0.3.2"
|
weak-table = "0.3.2"
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use std::ops::{AddAssign, Add, SubAssign, Sub};
|
use std::ops::{AddAssign, Add, SubAssign, Sub};
|
||||||
|
|
||||||
use taffy::{prelude::Size, style::Dimension, geometry::Point};
|
use taffy::{prelude::Size, style::Dimension, geometry::Point};
|
||||||
use winit::event::ElementState;
|
use winit::{event::ElementState, keyboard::{Key, KeyCode, ModifiersState}};
|
||||||
pub use winit::event::{TouchPhase, MouseScrollDelta, DeviceId, ModifiersState, VirtualKeyCode, ScanCode, MouseButton};
|
pub use winit::event::{TouchPhase, MouseScrollDelta, DeviceId, Modifiers, MouseButton};
|
||||||
|
|
||||||
use crate::SharedNode;
|
use crate::SharedNode;
|
||||||
pub mod handler;
|
pub mod handler;
|
||||||
|
|
@ -62,16 +62,16 @@ pub enum InnerEvent {
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct KeyboardEvent {
|
pub struct KeyboardEvent {
|
||||||
/// Logical location ("it's effect") of the key
|
/// Logical location ("it's effect") of the key
|
||||||
pub key: Option<VirtualKeyCode>,
|
pub key: Option<Key>,
|
||||||
/// Physical location of the key
|
/// Physical location of the key
|
||||||
pub code: ScanCode,
|
pub code: KeyCode,
|
||||||
|
|
||||||
// altKey: bool,
|
// altKey: bool,
|
||||||
// ctrlKey: bool,
|
// ctrlKey: bool,
|
||||||
// metaKey: bool,
|
// metaKey: bool,
|
||||||
// shiftKey: bool,
|
// shiftKey: bool,
|
||||||
/// modifier keys pressed (alt, ctrl, shift or meta/logo/windows)
|
/// modifier keys pressed (alt, ctrl, shift or meta/logo/windows)
|
||||||
pub modifiers: ModifiersState,
|
pub modifiers: Modifiers,
|
||||||
|
|
||||||
// repeat: bool,
|
// repeat: bool,
|
||||||
// char_code: u32,
|
// char_code: u32,
|
||||||
|
|
@ -94,7 +94,7 @@ pub struct MouseEvent {
|
||||||
// metaKey: bool,
|
// metaKey: bool,
|
||||||
// shiftKey: bool,
|
// shiftKey: bool,
|
||||||
/// modifier keys pressed (alt, ctrl, shift or meta/logo/windows)
|
/// modifier keys pressed (alt, ctrl, shift or meta/logo/windows)
|
||||||
pub modifiers: ModifiersState,
|
pub modifiers: Modifiers,
|
||||||
|
|
||||||
/// The location of the mouse relative to window
|
/// The location of the mouse relative to window
|
||||||
pub client: Location,
|
pub client: Location,
|
||||||
|
|
@ -194,19 +194,19 @@ impl Into<Size<Dimension>> for Location {
|
||||||
impl MouseEvent {
|
impl MouseEvent {
|
||||||
/// Returns `true` if the shift key is pressed.
|
/// Returns `true` if the shift key is pressed.
|
||||||
pub fn shift(&self) -> bool {
|
pub fn shift(&self) -> bool {
|
||||||
self.modifiers.intersects(ModifiersState::SHIFT)
|
self.modifiers.state().intersects(ModifiersState::SHIFT)
|
||||||
}
|
}
|
||||||
/// Returns `true` if the control key is pressed.
|
/// Returns `true` if the control key is pressed.
|
||||||
pub fn ctrl(&self) -> bool {
|
pub fn ctrl(&self) -> bool {
|
||||||
self.modifiers.intersects(ModifiersState::CTRL)
|
self.modifiers.state().intersects(ModifiersState::CONTROL)
|
||||||
}
|
}
|
||||||
/// Returns `true` if the alt key is pressed.
|
/// Returns `true` if the alt key is pressed.
|
||||||
pub fn alt(&self) -> bool {
|
pub fn alt(&self) -> bool {
|
||||||
self.modifiers.intersects(ModifiersState::ALT)
|
self.modifiers.state().intersects(ModifiersState::ALT)
|
||||||
}
|
}
|
||||||
/// Returns `true` if the logo key is pressed.
|
/// Returns `true` if the logo key is pressed.
|
||||||
pub fn logo(&self) -> bool {
|
pub fn logo(&self) -> bool {
|
||||||
self.modifiers.intersects(ModifiersState::LOGO)
|
self.modifiers.state().intersects(ModifiersState::SUPER)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn button_to_buttons(button: MouseButton) -> u8 {
|
pub fn button_to_buttons(button: MouseButton) -> u8 {
|
||||||
|
|
@ -214,7 +214,9 @@ impl MouseEvent {
|
||||||
MouseButton::Left => 1,
|
MouseButton::Left => 1,
|
||||||
MouseButton::Right => 2,
|
MouseButton::Right => 2,
|
||||||
MouseButton::Middle => 4,
|
MouseButton::Middle => 4,
|
||||||
MouseButton::Other(n) => 1 << n
|
MouseButton::Back => 8,
|
||||||
|
MouseButton::Forward => 16,
|
||||||
|
MouseButton::Other(n) => 1 << (n + 4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ 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 std::time::Duration;
|
||||||
|
|
||||||
use events::{Location, MouseValue, NodeEvent, MouseEvent};
|
use events::{Location, MouseValue, NodeEvent, MouseEvent};
|
||||||
use femtovg::renderer::OpenGl;
|
use femtovg::renderer::OpenGl;
|
||||||
|
|
@ -11,7 +12,7 @@ use glutin::{context::PossiblyCurrentContext, display::Display};
|
||||||
use glutin_winit::DisplayBuilder;
|
use glutin_winit::DisplayBuilder;
|
||||||
use nodes::{get_element_at, run_event_handlers, run_single_event_handlers};
|
use nodes::{get_element_at, run_event_handlers, run_single_event_handlers};
|
||||||
use raw_window_handle::HasRawWindowHandle;
|
use raw_window_handle::HasRawWindowHandle;
|
||||||
use winit::event::{Event, WindowEvent, ModifiersState, DeviceId};
|
use winit::event::{Event, WindowEvent, Modifiers, 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};
|
||||||
|
|
@ -40,10 +41,14 @@ type WeakNode = Weak<RwLock<dyn Node>>;
|
||||||
type NodePtr = Option<Vec<WeakNode>>;
|
type NodePtr = Option<Vec<WeakNode>>;
|
||||||
type NodeLayoutMap = PtrWeakKeyHashMap<Weak<RwLock<dyn Node>>, taffy::node::Node>;
|
type NodeLayoutMap = PtrWeakKeyHashMap<Weak<RwLock<dyn Node>>, taffy::node::Node>;
|
||||||
|
|
||||||
pub fn run_event_loop(root_node: SharedNode) -> ! {
|
pub fn run_event_loop(root_node: SharedNode) -> () {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new().unwrap();
|
||||||
let (buffer_context, gl_display, window, surface) = create_window(&event_loop);
|
let (buffer_context, gl_display, window, surface) = create_window(&event_loop);
|
||||||
|
|
||||||
|
if let Err(res) = surface.set_swap_interval(&buffer_context, glutin::surface::SwapInterval::Wait(NonZeroU32::new(1).unwrap())) {
|
||||||
|
dbg!("Could not set swap interval (vsync)", res);
|
||||||
|
}
|
||||||
|
|
||||||
let renderer = unsafe { OpenGl::new_from_function_cstr(|s| gl_display.get_proc_address(s) as *const _) }
|
let renderer = unsafe { OpenGl::new_from_function_cstr(|s| gl_display.get_proc_address(s) as *const _) }
|
||||||
.expect("Cannot create renderer");
|
.expect("Cannot create renderer");
|
||||||
|
|
||||||
|
|
@ -72,11 +77,11 @@ pub fn run_event_loop(root_node: SharedNode) -> ! {
|
||||||
|
|
||||||
let mut should_recompute = true;
|
let mut should_recompute = true;
|
||||||
|
|
||||||
let mut modifiers = ModifiersState::default();
|
let mut modifiers = Modifiers::default();
|
||||||
let focus_path: Option<Vec<WeakNode>> = None;
|
let focus_path: Option<Vec<WeakNode>> = None;
|
||||||
let mut mouse_values: HashMap<DeviceId, MouseValue> = HashMap::new();
|
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| match event {
|
||||||
Event::WindowEvent { event, .. } => match event {
|
Event::WindowEvent { event, .. } => match event {
|
||||||
WindowEvent::MouseWheel { device_id, delta, phase, .. } => {},
|
WindowEvent::MouseWheel { device_id, delta, phase, .. } => {},
|
||||||
WindowEvent::CursorMoved { device_id, position, .. } => {
|
WindowEvent::CursorMoved { device_id, position, .. } => {
|
||||||
|
|
@ -162,7 +167,7 @@ pub fn run_event_loop(root_node: SharedNode) -> ! {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
WindowEvent::ModifiersChanged(new_modifiers) => { modifiers = new_modifiers; },
|
WindowEvent::ModifiersChanged(new_modifiers) => { modifiers = new_modifiers; },
|
||||||
WindowEvent::KeyboardInput { device_id, input, is_synthetic } => {},
|
WindowEvent::KeyboardInput { device_id, event, is_synthetic } => {},
|
||||||
WindowEvent::MouseInput { device_id, state, button, .. } => {
|
WindowEvent::MouseInput { device_id, state, button, .. } => {
|
||||||
let mouse_value = mouse_values.get(&device_id);
|
let mouse_value = mouse_values.get(&device_id);
|
||||||
let mut mouse_value = match mouse_value {
|
let mut mouse_value = match mouse_value {
|
||||||
|
|
@ -206,7 +211,7 @@ pub fn run_event_loop(root_node: SharedNode) -> ! {
|
||||||
None => {}
|
None => {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
WindowEvent::CloseRequested => target.exit(),
|
||||||
WindowEvent::Resized(size) => {
|
WindowEvent::Resized(size) => {
|
||||||
let width: NonZeroU32 = NonZeroU32::new(size.width).unwrap();
|
let width: NonZeroU32 = NonZeroU32::new(size.width).unwrap();
|
||||||
let height: NonZeroU32 = NonZeroU32::new(size.height).unwrap();
|
let height: NonZeroU32 = NonZeroU32::new(size.height).unwrap();
|
||||||
|
|
@ -218,41 +223,51 @@ pub fn run_event_loop(root_node: SharedNode) -> ! {
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
should_recompute = true;
|
should_recompute = true;
|
||||||
},
|
},
|
||||||
|
WindowEvent::RedrawRequested => {
|
||||||
|
if should_recompute {
|
||||||
|
layout_recursively(&root, &mut context);
|
||||||
|
let src_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>();
|
||||||
|
context.node_layout.remove_expired();
|
||||||
|
let dst_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>();
|
||||||
|
for src_node in src_nodes {
|
||||||
|
if !dst_nodes.contains(&src_node) {
|
||||||
|
context.taffy.remove(src_node).unwrap();
|
||||||
|
dbg!("Removed node", src_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (node, taffy_node) in context.node_layout.iter() {
|
||||||
|
let node = node.read().unwrap();
|
||||||
|
let node_style = node.style();
|
||||||
|
context.taffy.set_style(*taffy_node, node_style.layout.to_owned()).unwrap();
|
||||||
|
}
|
||||||
|
context.taffy.compute_layout(*context.node_layout.get(&root).unwrap(), Size::MAX_CONTENT).unwrap();
|
||||||
|
should_recompute = false;
|
||||||
|
// Additional optimizations could be done here
|
||||||
|
// - When setting styles, check that the styles aren't the same (taffy doesn't do that and instead always mark it as dirty)
|
||||||
|
// - taffy seems to always recompute (maybe internally checks dirtyness, I didn't look into it that much)
|
||||||
|
// - the weakmap dance (src_nodes, dst_nodes) could be avoided by changing the weakmap used
|
||||||
|
// (weakmap removes keys when you attempt to read them, we could change it so that we could iterate on them and remove them in one go)
|
||||||
|
// could perhaps be a significant boost regarding memory usage (and performance) during large layout changes
|
||||||
|
// dbg!("recomputed");
|
||||||
|
}
|
||||||
|
// dbg!(&root);
|
||||||
|
render(&buffer_context, &surface, &window, &mut context, &root);
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
Event::RedrawRequested(_) => {
|
Event::NewEvents(_) => {
|
||||||
if should_recompute {
|
if let Some(monitor) = window.current_monitor() {
|
||||||
layout_recursively(&root, &mut context);
|
if let Some(refresh_rate) = monitor.refresh_rate_millihertz() {
|
||||||
let src_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>();
|
// dbg!(refresh_rate);
|
||||||
context.node_layout.remove_expired();
|
// some leeway before vsync
|
||||||
let dst_nodes = context.node_layout.values().map(|v| v.to_owned()).collect::<Vec<_>>();
|
target.set_control_flow(ControlFlow::wait_duration(Duration::from_millis(1000 / refresh_rate as u64 - 100/refresh_rate as u64)));
|
||||||
for src_node in src_nodes {
|
window.request_redraw();
|
||||||
if !dst_nodes.contains(&src_node) {
|
|
||||||
context.taffy.remove(src_node).unwrap();
|
|
||||||
dbg!("Removed node", src_node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (node, taffy_node) in context.node_layout.iter() {
|
|
||||||
let node = node.read().unwrap();
|
|
||||||
let node_style = node.style();
|
|
||||||
context.taffy.set_style(*taffy_node, node_style.layout.to_owned()).unwrap();
|
|
||||||
}
|
|
||||||
context.taffy.compute_layout(*context.node_layout.get(&root).unwrap(), Size::MAX_CONTENT).unwrap();
|
|
||||||
should_recompute = false;
|
|
||||||
// Additional optimizations could be done here
|
|
||||||
// - When setting styles, check that the styles aren't the same (taffy doesn't do that and instead always mark it as dirty)
|
|
||||||
// - taffy seems to always recompute (maybe internally checks dirtyness, I didn't look into it that much)
|
|
||||||
// - the weakmap dance (src_nodes, dst_nodes) could be avoided by changing the weakmap used
|
|
||||||
// (weakmap removes keys when you attempt to read them, we could change it so that we could iterate on them and remove them in one go)
|
|
||||||
// could perhaps be a significant boost regarding memory usage (and performance) during large layout changes
|
|
||||||
// dbg!("recomputed");
|
|
||||||
}
|
}
|
||||||
// dbg!(&root);
|
|
||||||
render(&buffer_context, &surface, &window, &mut context, &root);
|
|
||||||
},
|
},
|
||||||
// In the future, window should be created after resuming from suspend (for android support)
|
// In the future, window should be created after resuming from suspend (for android support)
|
||||||
_ => {}
|
_ => {}
|
||||||
})
|
}).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// I have no idea if there's a better way to do this in rust...
|
/// I have no idea if there's a better way to do this in rust...
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue