panel: per-element interactibility
This commit is contained in:
@@ -1,26 +1,26 @@
|
||||
use glam::{Vec2, vec2};
|
||||
use glam::{vec2, Vec2};
|
||||
use std::sync::Arc;
|
||||
use testbed::{Testbed, testbed_any::TestbedAny};
|
||||
use testbed::{testbed_any::TestbedAny, Testbed};
|
||||
use timestep::Timestep;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use tracing_subscriber::filter::LevelFilter;
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
use tracing_subscriber::util::SubscriberInitExt;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use vulkan::init_window;
|
||||
use vulkano::{
|
||||
Validated, VulkanError,
|
||||
command_buffer::CommandBufferUsage,
|
||||
format::Format,
|
||||
image::{ImageUsage, view::ImageView},
|
||||
image::{view::ImageView, ImageUsage},
|
||||
swapchain::{
|
||||
CompositeAlpha, PresentMode, Surface, SurfaceInfo, Swapchain, SwapchainCreateInfo,
|
||||
SwapchainPresentInfo, acquire_next_image,
|
||||
acquire_next_image, CompositeAlpha, PresentMode, Surface, SurfaceInfo, Swapchain,
|
||||
SwapchainCreateInfo, SwapchainPresentInfo,
|
||||
},
|
||||
sync::GpuFuture,
|
||||
Validated, VulkanError,
|
||||
};
|
||||
use wgui::{
|
||||
event::{MouseButtonIndex, MouseDownEvent, MouseMotionEvent, MouseUpEvent, MouseWheelEvent},
|
||||
gfx::{WGfx, cmd::WGfxClearMode},
|
||||
gfx::{cmd::WGfxClearMode, WGfx},
|
||||
renderer_vk::{self},
|
||||
};
|
||||
use winit::{
|
||||
@@ -32,7 +32,7 @@ use winit::{
|
||||
use crate::{
|
||||
rate_limiter::RateLimiter,
|
||||
testbed::{
|
||||
TestbedUpdateParams, testbed_dashboard::TestbedDashboard, testbed_generic::TestbedGeneric,
|
||||
testbed_dashboard::TestbedDashboard, testbed_generic::TestbedGeneric, TestbedUpdateParams,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -128,7 +128,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
event: WindowEvent::MouseWheel { delta, .. },
|
||||
..
|
||||
} => match delta {
|
||||
MouseScrollDelta::LineDelta(x, y) => testbed
|
||||
MouseScrollDelta::LineDelta(x, y) => {
|
||||
testbed
|
||||
.layout()
|
||||
.borrow_mut()
|
||||
.push_event(
|
||||
@@ -140,8 +141,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
&mut (),
|
||||
&mut (),
|
||||
)
|
||||
.unwrap(),
|
||||
MouseScrollDelta::PixelDelta(pos) => testbed
|
||||
.unwrap();
|
||||
}
|
||||
MouseScrollDelta::PixelDelta(pos) => {
|
||||
testbed
|
||||
.layout()
|
||||
.borrow_mut()
|
||||
.push_event(
|
||||
@@ -153,7 +156,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
&mut (),
|
||||
&mut (),
|
||||
)
|
||||
.unwrap(),
|
||||
.unwrap();
|
||||
}
|
||||
},
|
||||
Event::WindowEvent {
|
||||
event: WindowEvent::MouseInput { state, button, .. },
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
animation::{Animation, AnimationEasing},
|
||||
components::{self, Component, ComponentBase, ComponentTrait, InitData, tooltip::ComponentTooltip},
|
||||
components::{self, tooltip::ComponentTooltip, Component, ComponentBase, ComponentTrait, InitData},
|
||||
drawing::{self, Boundary, Color},
|
||||
event::{CallbackDataCommon, EventListenerCollection, EventListenerID, EventListenerKind},
|
||||
i18n::Translation,
|
||||
@@ -10,10 +10,10 @@ use crate::{
|
||||
util::centered_matrix,
|
||||
},
|
||||
widget::{
|
||||
ConstructEssentials, EventResult, WidgetData,
|
||||
label::{WidgetLabel, WidgetLabelParams},
|
||||
rectangle::{WidgetRectangle, WidgetRectangleParams},
|
||||
util::WLength,
|
||||
ConstructEssentials, EventResult, WidgetData,
|
||||
},
|
||||
};
|
||||
use glam::{Mat4, Vec3};
|
||||
|
||||
@@ -8,14 +8,14 @@ use std::{
|
||||
use crate::{
|
||||
animation::Animations,
|
||||
components::{Component, InitData},
|
||||
drawing::{self, ANSI_BOLD_CODE, ANSI_RESET_CODE, Boundary, push_scissor_stack, push_transform_stack},
|
||||
drawing::{self, push_scissor_stack, push_transform_stack, Boundary, ANSI_BOLD_CODE, ANSI_RESET_CODE},
|
||||
event::{self, CallbackDataCommon, EventAlterables},
|
||||
globals::WguiGlobals,
|
||||
widget::{self, EventParams, EventResult, WidgetObj, WidgetState, div::WidgetDiv},
|
||||
widget::{self, div::WidgetDiv, EventParams, EventResult, WidgetObj, WidgetState},
|
||||
};
|
||||
|
||||
use glam::{Vec2, vec2};
|
||||
use slotmap::{HopSlotMap, SecondaryMap, new_key_type};
|
||||
use glam::{vec2, Vec2};
|
||||
use slotmap::{new_key_type, HopSlotMap, SecondaryMap};
|
||||
use taffy::{NodeId, TaffyTree, TraversePartialTree};
|
||||
|
||||
new_key_type! {
|
||||
@@ -328,26 +328,21 @@ impl Layout {
|
||||
)
|
||||
}
|
||||
|
||||
fn push_event_children<U1: 'static, U2: 'static>(
|
||||
fn push_event_children<'a, U1: 'static, U2: 'static>(
|
||||
&self,
|
||||
parent_node_id: taffy::NodeId,
|
||||
event: &event::Event,
|
||||
event_result: &mut EventResult,
|
||||
alterables: &mut EventAlterables,
|
||||
user_data: &mut (&mut U1, &mut U2),
|
||||
user_data: &mut (&'a mut U1, &'a mut U2),
|
||||
reverse: bool,
|
||||
) -> anyhow::Result<EventResult> {
|
||||
let mut event_result = EventResult::Pass;
|
||||
|
||||
) -> anyhow::Result<()> {
|
||||
let count = self.state.tree.child_count(parent_node_id);
|
||||
|
||||
let mut iter = |idx: usize| -> anyhow::Result<bool> {
|
||||
let child_id = self.state.tree.get_child_id(parent_node_id, idx);
|
||||
let child_result = self.push_event_widget(child_id, event, alterables, user_data, false)?;
|
||||
if child_result != EventResult::Pass {
|
||||
event_result = child_result;
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(false)
|
||||
self.push_event_widget(child_id, event, event_result, alterables, user_data, false)?;
|
||||
Ok(!event_result.can_propagate())
|
||||
};
|
||||
|
||||
if reverse {
|
||||
@@ -364,17 +359,18 @@ impl Layout {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(event_result)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn push_event_widget<U1: 'static, U2: 'static>(
|
||||
fn push_event_widget<'a, U1: 'static, U2: 'static>(
|
||||
&self,
|
||||
node_id: taffy::NodeId,
|
||||
event: &event::Event,
|
||||
event_result: &mut EventResult,
|
||||
alterables: &mut EventAlterables,
|
||||
user_data: &mut (&mut U1, &mut U2),
|
||||
user_data: &mut (&'a mut U1, &'a mut U2),
|
||||
is_root_node: bool,
|
||||
) -> anyhow::Result<EventResult> {
|
||||
) -> anyhow::Result<()> {
|
||||
let l = self.state.tree.layout(node_id)?;
|
||||
let Some(widget_id) = self.state.tree.get_node_context(node_id).copied() else {
|
||||
anyhow::bail!("invalid widget ID");
|
||||
@@ -410,9 +406,9 @@ impl Layout {
|
||||
let reverse_iter = is_root_node;
|
||||
|
||||
// check children first
|
||||
let mut evt_result = self.push_event_children(node_id, event, alterables, user_data, reverse_iter)?;
|
||||
self.push_event_children(node_id, event, event_result, alterables, user_data, reverse_iter)?;
|
||||
|
||||
if evt_result == EventResult::Pass {
|
||||
if event_result.can_propagate() {
|
||||
let mut params = EventParams {
|
||||
state: &self.state,
|
||||
layout: l,
|
||||
@@ -421,10 +417,7 @@ impl Layout {
|
||||
style,
|
||||
};
|
||||
|
||||
let this_evt_result = widget.process_event(widget_id, node_id, event, user_data, &mut params)?;
|
||||
if this_evt_result != EventResult::Pass {
|
||||
evt_result = this_evt_result;
|
||||
}
|
||||
widget.process_event(widget_id, node_id, event, event_result, user_data, &mut params)?;
|
||||
}
|
||||
|
||||
if scissor_pushed {
|
||||
@@ -432,7 +425,7 @@ impl Layout {
|
||||
}
|
||||
alterables.transform_stack.pop();
|
||||
|
||||
Ok(evt_result)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub const fn check_toggle_needs_redraw(&mut self) -> bool {
|
||||
@@ -458,12 +451,19 @@ impl Layout {
|
||||
event: &event::Event,
|
||||
user1: &mut U1,
|
||||
user2: &mut U2,
|
||||
) -> anyhow::Result<()> {
|
||||
) -> anyhow::Result<EventResult> {
|
||||
let mut alterables = EventAlterables::default();
|
||||
let _event_result =
|
||||
self.push_event_widget(self.tree_root_node, event, &mut alterables, &mut (user1, user2), true)?;
|
||||
let mut event_result = EventResult::NoHit;
|
||||
self.push_event_widget(
|
||||
self.tree_root_node,
|
||||
event,
|
||||
&mut event_result,
|
||||
&mut alterables,
|
||||
&mut (user1, user2),
|
||||
true,
|
||||
)?;
|
||||
self.process_alterables(alterables)?;
|
||||
Ok(())
|
||||
Ok(event_result)
|
||||
}
|
||||
|
||||
pub fn new(globals: WguiGlobals, params: &LayoutParams) -> anyhow::Result<Self> {
|
||||
@@ -485,7 +485,10 @@ impl Layout {
|
||||
&mut state.widgets,
|
||||
&mut state.nodes,
|
||||
None, // no parent
|
||||
WidgetDiv::create(),
|
||||
WidgetState {
|
||||
interactable: false,
|
||||
..WidgetDiv::create()
|
||||
},
|
||||
taffy::Style {
|
||||
size,
|
||||
..Default::default()
|
||||
@@ -497,7 +500,10 @@ impl Layout {
|
||||
&mut state.widgets,
|
||||
&mut state.nodes,
|
||||
Some(tree_root_node),
|
||||
WidgetDiv::create(),
|
||||
WidgetState {
|
||||
interactable: false,
|
||||
..WidgetDiv::create()
|
||||
},
|
||||
taffy::Style {
|
||||
size,
|
||||
..Default::default()
|
||||
|
||||
@@ -8,7 +8,7 @@ mod widget_rectangle;
|
||||
mod widget_sprite;
|
||||
|
||||
use crate::{
|
||||
assets::{AssetPath, AssetPathOwned, normalize_path},
|
||||
assets::{normalize_path, AssetPath, AssetPathOwned},
|
||||
components::{Component, ComponentWeak},
|
||||
drawing::{self},
|
||||
globals::WguiGlobals,
|
||||
@@ -782,6 +782,14 @@ fn parse_widget_universal(ctx: &mut ParserContext, widget_id: WidgetID, attribs:
|
||||
// Attach a specific widget to name-ID map (just like getElementById)
|
||||
ctx.insert_id(&pair.value, widget_id);
|
||||
}
|
||||
"interactable" => {
|
||||
if let Ok(0) = &pair.value.parse::<i32>() {
|
||||
log::info!("setting {widget_id:?} to noninteractable.");
|
||||
ctx.layout.state.widgets.get(widget_id).unwrap().state().interactable = false;
|
||||
} else {
|
||||
print_invalid_attrib(&pair.attrib, &pair.value);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
layout::WidgetID,
|
||||
parser::{AttribPair, ParserContext, ParserFile, parse_children, parse_widget_universal, style::parse_style},
|
||||
parser::{parse_children, parse_widget_universal, style::parse_style, AttribPair, ParserContext, ParserFile},
|
||||
widget::div::WidgetDiv,
|
||||
};
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::{
|
||||
globals::Globals,
|
||||
i18n::{I18n, Translation},
|
||||
layout::WidgetID,
|
||||
renderer_vk::text::{FONT_SYSTEM, TextStyle},
|
||||
renderer_vk::text::{TextStyle, FONT_SYSTEM},
|
||||
};
|
||||
|
||||
use super::{WidgetObj, WidgetState};
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::{
|
||||
drawing::{self, PrimitiveExtent},
|
||||
event::{
|
||||
self, CallbackData, CallbackDataCommon, CallbackMetadata, Event, EventAlterables, EventListenerCollection,
|
||||
EventListenerKind::{InternalStateChange, MouseEnter, MouseLeave, MouseMotion, MousePress, MouseRelease},
|
||||
EventListenerKind::{self, InternalStateChange, MouseLeave},
|
||||
MouseWheelEvent,
|
||||
},
|
||||
layout::{Layout, LayoutState, WidgetID},
|
||||
@@ -78,6 +78,7 @@ pub struct WidgetState {
|
||||
pub data: WidgetData,
|
||||
pub obj: Box<dyn WidgetObj>,
|
||||
pub event_listeners: EventListenerCollection,
|
||||
pub interactable: bool,
|
||||
}
|
||||
|
||||
impl WidgetState {
|
||||
@@ -100,6 +101,7 @@ impl WidgetState {
|
||||
},
|
||||
obj,
|
||||
event_listeners: EventListenerCollection::default(),
|
||||
interactable: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,10 +166,27 @@ pub struct EventParams<'a> {
|
||||
pub layout: &'a taffy::Layout,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd)]
|
||||
pub enum EventResult {
|
||||
Pass, // widget acknowledged it and allows the event to pass further
|
||||
Consumed, // widget triggered an action, do not pass further
|
||||
NoHit, // event was pushed but has not found a listener (yet)
|
||||
Pass, // widget acknowledged it and allows the event to propagate further
|
||||
Consumed, // widget triggered an action, do not propagate further
|
||||
}
|
||||
|
||||
impl EventResult {
|
||||
#[must_use]
|
||||
pub const fn can_propagate(self) -> bool {
|
||||
!matches!(self, EventResult::Consumed)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn merge(self, other: Self) -> Self {
|
||||
if self > other {
|
||||
self
|
||||
} else {
|
||||
other
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_scroll_enabled(style: &taffy::Style) -> (bool, bool) {
|
||||
@@ -212,30 +231,46 @@ impl dyn WidgetObj {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! call_event {
|
||||
($self:ident, $widget_id:ident, $node_id:ident, $params:ident, $kind:ident, $u1:ty, $u2:ty, $user_data:expr, $metadata:expr) => {
|
||||
for listener in $self.event_listeners.iter_filtered::<$u1, $u2>($kind) {
|
||||
let mut data = CallbackData {
|
||||
obj: $self.obj.as_mut(),
|
||||
widget_data: &mut $self.data,
|
||||
$widget_id,
|
||||
$node_id,
|
||||
metadata: $metadata,
|
||||
};
|
||||
|
||||
let mut common = CallbackDataCommon {
|
||||
state: $params.state,
|
||||
alterables: $params.alterables,
|
||||
};
|
||||
let result = listener.call_with(&mut common, &mut data, $user_data)?;
|
||||
if result == EventResult::Consumed {
|
||||
return Ok(EventResult::Consumed);
|
||||
}
|
||||
}
|
||||
};
|
||||
struct InvokeData<'a, 'b, U1: 'static, U2: 'static> {
|
||||
widget_id: WidgetID,
|
||||
node_id: taffy::NodeId,
|
||||
event_result: &'a mut EventResult,
|
||||
user_data: &'a mut (&'b mut U1, &'b mut U2),
|
||||
params: &'a mut EventParams<'a>,
|
||||
}
|
||||
|
||||
impl WidgetState {
|
||||
fn invoke_listeners<U1: 'static, U2: 'static>(
|
||||
&mut self,
|
||||
call_data: &mut InvokeData<'_, '_, U1, U2>,
|
||||
kind: event::EventListenerKind,
|
||||
metadata: CallbackMetadata,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut data = CallbackData {
|
||||
obj: self.obj.as_mut(),
|
||||
widget_data: &mut self.data,
|
||||
widget_id: call_data.widget_id,
|
||||
node_id: call_data.node_id,
|
||||
metadata,
|
||||
};
|
||||
|
||||
let mut common = CallbackDataCommon {
|
||||
state: call_data.params.state,
|
||||
alterables: call_data.params.alterables,
|
||||
};
|
||||
|
||||
for listener in self.event_listeners.iter_filtered::<U1, U2>(kind) {
|
||||
let new_result = listener.call_with(&mut common, &mut data, call_data.user_data)?;
|
||||
// Consider all listeners on this widget, even if we had a Consume.
|
||||
// Store the highest value for return.
|
||||
*call_data.event_result = call_data.event_result.merge(new_result);
|
||||
if !call_data.event_result.can_propagate() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_scroll_shift_smooth(&self, info: &ScrollbarInfo, l: &taffy::Layout, timestep_alpha: f32) -> (Vec2, bool) {
|
||||
let currently_animating = self.data.scrolling_cur != self.data.scrolling_cur_prev;
|
||||
|
||||
@@ -384,53 +419,48 @@ impl WidgetState {
|
||||
true
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
pub fn process_event<'a, U1: 'static, U2: 'static>(
|
||||
pub fn process_event<'a, 'b, U1: 'static, U2: 'static>(
|
||||
&mut self,
|
||||
widget_id: WidgetID,
|
||||
node_id: taffy::NodeId,
|
||||
event: &Event,
|
||||
user_data: &mut (&mut U1, &mut U2),
|
||||
event_result: &'a mut EventResult,
|
||||
user_data: &'a mut (&'b mut U1, &'b mut U2),
|
||||
params: &'a mut EventParams<'a>,
|
||||
) -> anyhow::Result<EventResult> {
|
||||
) -> anyhow::Result<()> {
|
||||
let hovered = event.test_mouse_within_transform(params.alterables.transform_stack.get());
|
||||
|
||||
let mut invoke_data = InvokeData {
|
||||
widget_id,
|
||||
node_id,
|
||||
event_result,
|
||||
user_data,
|
||||
params,
|
||||
};
|
||||
|
||||
match &event {
|
||||
Event::MouseDown(e) => {
|
||||
if hovered && self.data.set_device_pressed(e.device, true) {
|
||||
call_event!(
|
||||
self,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MousePress,
|
||||
U1,
|
||||
U2,
|
||||
user_data,
|
||||
self.invoke_listeners(
|
||||
&mut invoke_data,
|
||||
EventListenerKind::MousePress,
|
||||
CallbackMetadata::MouseButton(event::MouseButton {
|
||||
index: e.index,
|
||||
pos: e.pos
|
||||
})
|
||||
);
|
||||
pos: e.pos,
|
||||
}),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Event::MouseUp(e) => {
|
||||
if self.data.set_device_pressed(e.device, false) {
|
||||
call_event!(
|
||||
self,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseRelease,
|
||||
U1,
|
||||
U2,
|
||||
user_data,
|
||||
self.invoke_listeners(
|
||||
&mut invoke_data,
|
||||
EventListenerKind::MouseRelease,
|
||||
CallbackMetadata::MouseButton(event::MouseButton {
|
||||
index: e.index,
|
||||
pos: e.pos,
|
||||
})
|
||||
);
|
||||
}),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Event::MouseMotion(e) => {
|
||||
@@ -438,79 +468,42 @@ impl WidgetState {
|
||||
|
||||
if hover_state_changed {
|
||||
if self.data.is_hovered() {
|
||||
call_event!(
|
||||
self,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseEnter,
|
||||
U1,
|
||||
U2,
|
||||
user_data,
|
||||
CallbackMetadata::None
|
||||
);
|
||||
self.invoke_listeners(&mut invoke_data, EventListenerKind::MouseEnter, CallbackMetadata::None)?;
|
||||
} else {
|
||||
call_event!(
|
||||
self,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseLeave,
|
||||
U1,
|
||||
U2,
|
||||
user_data,
|
||||
CallbackMetadata::None
|
||||
);
|
||||
self.invoke_listeners(&mut invoke_data, EventListenerKind::MouseLeave, CallbackMetadata::None)?;
|
||||
}
|
||||
} else if hovered {
|
||||
self.invoke_listeners(
|
||||
&mut invoke_data,
|
||||
EventListenerKind::MouseMotion,
|
||||
CallbackMetadata::MousePosition(event::MousePosition { pos: e.pos }),
|
||||
)?;
|
||||
|
||||
call_event!(
|
||||
self,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseMotion,
|
||||
U1,
|
||||
U2,
|
||||
user_data,
|
||||
CallbackMetadata::MousePosition(event::MousePosition { pos: e.pos })
|
||||
);
|
||||
if self.interactable {
|
||||
*invoke_data.event_result = invoke_data.event_result.merge(EventResult::Pass);
|
||||
}
|
||||
}
|
||||
}
|
||||
Event::MouseWheel(e) => {
|
||||
if hovered && self.process_wheel(params, e) {
|
||||
return Ok(EventResult::Consumed);
|
||||
if hovered && self.process_wheel(invoke_data.params, e) {
|
||||
*invoke_data.event_result = EventResult::Consumed;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Event::MouseLeave(e) => {
|
||||
if self.data.set_device_hovered(e.device, false) {
|
||||
call_event!(
|
||||
self,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
MouseLeave,
|
||||
U1,
|
||||
U2,
|
||||
user_data,
|
||||
CallbackMetadata::None
|
||||
);
|
||||
self.invoke_listeners(&mut invoke_data, MouseLeave, CallbackMetadata::None)?;
|
||||
}
|
||||
}
|
||||
Event::InternalStateChange(e) => {
|
||||
call_event!(
|
||||
self,
|
||||
widget_id,
|
||||
node_id,
|
||||
params,
|
||||
self.invoke_listeners(
|
||||
&mut invoke_data,
|
||||
InternalStateChange,
|
||||
U1,
|
||||
U2,
|
||||
user_data,
|
||||
CallbackMetadata::Custom(e.metadata)
|
||||
);
|
||||
CallbackMetadata::Custom(e.metadata),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Ok(EventResult::Pass)
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ use crate::{
|
||||
drawing::{self, PrimitiveExtent},
|
||||
layout::WidgetID,
|
||||
renderer_vk::text::{
|
||||
DEFAULT_METRICS, FONT_SYSTEM,
|
||||
custom_glyph::{CustomGlyph, CustomGlyphData},
|
||||
DEFAULT_METRICS, FONT_SYSTEM,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<div width="400" height="200">
|
||||
<div width="460" height="260" padding="30" interactable="0">
|
||||
<rectangle width="100%" height="100%" padding="4" box_sizing="content_box" flex_wrap="wrap" flex_direction="column" gap="4" color="~bg_color">
|
||||
<div width="100%" flex_direction="row">
|
||||
<Device src="watch/hmd.svg" size="40" device="0" />
|
||||
@@ -64,13 +64,13 @@
|
||||
</div>
|
||||
</div>
|
||||
<div width="100%" flex_direction="row">
|
||||
<Button macro="button_style" _press="::DashToggle" tooltip="Toggle dashboard" tooltip_side="top">
|
||||
<Button macro="button_style" _press="::DashToggle" tooltip="Dashboard" tooltip_side="top">
|
||||
<sprite color="~set_color" width="40" height="40" src="watch/home.svg" />
|
||||
</Button>
|
||||
<div id="sets">
|
||||
<!-- Will populate <Set> tags at runtime -->
|
||||
</div>
|
||||
<Button macro="button_style" _press="::EditToggle" tooltip="Edit sets" tooltip_side="top">
|
||||
<Button macro="button_style" _press="::EditToggle" tooltip="Edit mode" tooltip_side="top">
|
||||
<sprite color="~set_color" width="40" height="40" src="watch/edit.svg" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -15,6 +15,13 @@ use crate::windowing::{OverlayID, OverlaySelector};
|
||||
|
||||
use super::task::{TaskContainer, TaskType};
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct HoverResult {
|
||||
pub haptics: Option<Haptics>,
|
||||
/// If true, the laster shows at this position and no further raycasting will be done.
|
||||
pub consume: bool,
|
||||
}
|
||||
|
||||
pub struct TrackedDevice {
|
||||
pub soc: Option<f32>,
|
||||
pub charging: bool,
|
||||
@@ -307,7 +314,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines, clippy::cognitive_complexity)]
|
||||
fn interact_hand<O>(
|
||||
idx: usize,
|
||||
overlays: &mut OverlayWindowManager<O>,
|
||||
@@ -316,6 +322,7 @@ fn interact_hand<O>(
|
||||
where
|
||||
O: Default,
|
||||
{
|
||||
// already grabbing, ignore everything else
|
||||
let mut pointer = &mut app.input_state.pointers[idx];
|
||||
if let Some(grab_data) = pointer.interaction.grabbed {
|
||||
if let Some(grabbed) = overlays.mut_by_id(grab_data.grabbed_id) {
|
||||
@@ -327,45 +334,29 @@ where
|
||||
return (0.1, None);
|
||||
}
|
||||
|
||||
let Some(mut hit) = pointer.get_nearest_hit(overlays) else {
|
||||
if let Some(hovered_id) = pointer.interaction.hovered_id.take() {
|
||||
if let Some(hovered) = overlays.mut_by_id(hovered_id) {
|
||||
hovered.config.backend.on_left(app, idx);
|
||||
}
|
||||
pointer = &mut app.input_state.pointers[idx];
|
||||
pointer.interaction.hovered_id = None;
|
||||
}
|
||||
if !pointer.now.click
|
||||
&& pointer.before.click
|
||||
&& let Some(clicked_id) = pointer.interaction.clicked_id.take()
|
||||
&& let Some(clicked) = overlays.mut_by_id(clicked_id)
|
||||
{
|
||||
let hit = PointerHit {
|
||||
pointer: pointer.idx,
|
||||
overlay: clicked_id,
|
||||
mode: pointer.interaction.mode,
|
||||
..Default::default()
|
||||
};
|
||||
clicked.config.backend.on_pointer(app, &hit, false);
|
||||
}
|
||||
let hovered_id = pointer.interaction.hovered_id.take();
|
||||
let (Some(mut hit), haptics) = get_nearest_hit(idx, overlays, app) else {
|
||||
handle_no_hit(idx, hovered_id, overlays, app);
|
||||
return (0.0, None); // no hit
|
||||
};
|
||||
|
||||
if let Some(hovered_id) = pointer.interaction.hovered_id
|
||||
// focus change
|
||||
if let Some(hovered_id) = hovered_id
|
||||
&& hovered_id != hit.overlay
|
||||
&& let Some(old_hovered) = overlays.mut_by_id(hovered_id)
|
||||
{
|
||||
if Some(pointer.idx) == old_hovered.primary_pointer {
|
||||
if old_hovered.primary_pointer.is_some_and(|i| i == idx) {
|
||||
old_hovered.primary_pointer = None;
|
||||
}
|
||||
log::debug!("{} on_left (focus changed)", old_hovered.config.name);
|
||||
old_hovered.config.backend.on_left(app, idx);
|
||||
pointer = &mut app.input_state.pointers[idx];
|
||||
}
|
||||
|
||||
let Some(hovered) = overlays.mut_by_id(hit.overlay) else {
|
||||
log::warn!("Hit overlay {:?} does not exist", hit.overlay);
|
||||
return (0.0, None); // no hit
|
||||
};
|
||||
|
||||
pointer = &mut app.input_state.pointers[idx];
|
||||
pointer.interaction.hovered_id = Some(hit.overlay);
|
||||
|
||||
if let Some(primary_pointer) = hovered.primary_pointer {
|
||||
@@ -383,6 +374,7 @@ where
|
||||
|
||||
let hovered_state = hovered.config.active_state.as_mut().unwrap();
|
||||
|
||||
// grab
|
||||
if pointer.now.grab && !pointer.before.grab && hovered_state.grabbable {
|
||||
update_focus(
|
||||
&mut app.hid_provider.keyboard_focus,
|
||||
@@ -400,16 +392,68 @@ where
|
||||
);
|
||||
}
|
||||
|
||||
// Pass mouse motion events only if not scrolling
|
||||
// (allows scrolling on all Chromium-based applications)
|
||||
let haptics = hovered.config.backend.on_hover(app, &hit);
|
||||
handle_scroll(&hit, hovered, app);
|
||||
|
||||
pointer = &mut app.input_state.pointers[idx];
|
||||
// click / release
|
||||
let pointer = &mut app.input_state.pointers[hit.pointer];
|
||||
if pointer.now.click && !pointer.before.click {
|
||||
pointer.interaction.clicked_id = Some(hit.overlay);
|
||||
update_focus(
|
||||
&mut app.hid_provider.keyboard_focus,
|
||||
&hovered.config.keyboard_focus,
|
||||
);
|
||||
hovered.config.backend.on_pointer(app, &hit, true);
|
||||
} else if !pointer.now.click && pointer.before.click {
|
||||
// send release event to overlay that was originally clicked
|
||||
if let Some(clicked_id) = pointer.interaction.clicked_id.take() {
|
||||
if let Some(clicked) = overlays.mut_by_id(clicked_id) {
|
||||
clicked.config.backend.on_pointer(app, &hit, false);
|
||||
}
|
||||
} else {
|
||||
hovered.config.backend.on_pointer(app, &hit, false);
|
||||
}
|
||||
}
|
||||
|
||||
(hit.dist, haptics)
|
||||
}
|
||||
|
||||
fn handle_no_hit<O>(
|
||||
pointer_idx: usize,
|
||||
hovered_id: Option<OverlayID>,
|
||||
overlays: &mut OverlayWindowManager<O>,
|
||||
app: &mut AppState,
|
||||
) {
|
||||
if let Some(hovered_id) = hovered_id
|
||||
&& let Some(hovered) = overlays.mut_by_id(hovered_id)
|
||||
{
|
||||
log::debug!("{} on_left (no hit)", hovered.config.name);
|
||||
hovered.config.backend.on_left(app, pointer_idx);
|
||||
}
|
||||
|
||||
// in case click released while not aiming at anything
|
||||
// send release event to overlay that was originally clicked
|
||||
let pointer = &mut app.input_state.pointers[pointer_idx];
|
||||
if !pointer.now.click
|
||||
&& pointer.before.click
|
||||
&& let Some(clicked_id) = pointer.interaction.clicked_id.take()
|
||||
&& let Some(clicked) = overlays.mut_by_id(clicked_id)
|
||||
{
|
||||
let hit = PointerHit {
|
||||
pointer: pointer.idx,
|
||||
overlay: clicked_id,
|
||||
mode: pointer.interaction.mode,
|
||||
..Default::default()
|
||||
};
|
||||
clicked.config.backend.on_pointer(app, &hit, false);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_scroll<O>(hit: &PointerHit, hovered: &mut OverlayWindowData<O>, app: &mut AppState) {
|
||||
let pointer = &mut app.input_state.pointers[hit.pointer];
|
||||
if pointer.now.scroll_x.abs() > 0.1 || pointer.now.scroll_y.abs() > 0.1 {
|
||||
let scroll_x = pointer.now.scroll_x;
|
||||
let scroll_y = pointer.now.scroll_y;
|
||||
if app.input_state.pointers[1 - idx]
|
||||
if app.input_state.pointers[1 - hit.pointer]
|
||||
.interaction
|
||||
.grabbed
|
||||
.is_some_and(|x| x.grabbed_id == hit.overlay)
|
||||
@@ -437,33 +481,21 @@ where
|
||||
.backend
|
||||
.on_scroll(app, &hit, scroll_y, scroll_x);
|
||||
}
|
||||
pointer = &mut app.input_state.pointers[idx];
|
||||
}
|
||||
}
|
||||
|
||||
if pointer.now.click && !pointer.before.click {
|
||||
pointer.interaction.clicked_id = Some(hit.overlay);
|
||||
update_focus(
|
||||
&mut app.hid_provider.keyboard_focus,
|
||||
&hovered.config.keyboard_focus,
|
||||
);
|
||||
hovered.config.backend.on_pointer(app, &hit, true);
|
||||
} else if !pointer.now.click && pointer.before.click {
|
||||
if let Some(clicked_id) = pointer.interaction.clicked_id.take() {
|
||||
if let Some(clicked) = overlays.mut_by_id(clicked_id) {
|
||||
clicked.config.backend.on_pointer(app, &hit, false);
|
||||
}
|
||||
} else {
|
||||
hovered.config.backend.on_pointer(app, &hit, false);
|
||||
}
|
||||
}
|
||||
(hit.dist, haptics)
|
||||
}
|
||||
|
||||
impl Pointer {
|
||||
fn get_nearest_hit<O>(&mut self, overlays: &mut OverlayWindowManager<O>) -> Option<PointerHit>
|
||||
fn get_nearest_hit<O>(
|
||||
pointer_idx: usize,
|
||||
overlays: &mut OverlayWindowManager<O>,
|
||||
app: &mut AppState,
|
||||
) -> (Option<PointerHit>, Option<Haptics>)
|
||||
where
|
||||
O: Default,
|
||||
{
|
||||
let pointer = &mut app.input_state.pointers[pointer_idx];
|
||||
let ray_origin = pointer.pose;
|
||||
let mode = pointer.interaction.mode;
|
||||
|
||||
let mut hits: SmallVec<[RayHit; 8]> = smallvec!();
|
||||
|
||||
for (id, overlay) in overlays.iter() {
|
||||
@@ -474,17 +506,17 @@ impl Pointer {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(hit) = self.ray_test(
|
||||
if let Some(hit) = ray_test(
|
||||
&ray_origin,
|
||||
id,
|
||||
&overlay_state.transform,
|
||||
overlay_state.curvature.as_ref(),
|
||||
) {
|
||||
if hit.dist.is_infinite() || hit.dist.is_nan() {
|
||||
continue;
|
||||
}
|
||||
if hit.dist.is_finite() {
|
||||
hits.push(hit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hits.sort_by(|a, b| a.dist.total_cmp(&b.dist));
|
||||
|
||||
@@ -505,19 +537,25 @@ impl Pointer {
|
||||
continue;
|
||||
}
|
||||
|
||||
return Some(PointerHit {
|
||||
pointer: self.idx,
|
||||
let hit = PointerHit {
|
||||
pointer: pointer_idx,
|
||||
overlay: hit.overlay,
|
||||
mode: self.interaction.mode,
|
||||
mode,
|
||||
primary: false,
|
||||
uv,
|
||||
dist: hit.dist,
|
||||
});
|
||||
};
|
||||
|
||||
let result = overlay.config.backend.on_hover(app, &hit);
|
||||
if result.consume {
|
||||
return (Some(hit), result.haptics);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
(None, None)
|
||||
}
|
||||
|
||||
impl Pointer {
|
||||
fn start_grab(
|
||||
&mut self,
|
||||
id: OverlayID,
|
||||
@@ -608,23 +646,24 @@ impl Pointer {
|
||||
log::debug!("Hand {}: dropped {}", idx, overlay.config.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ray_test(
|
||||
&self,
|
||||
ray_origin: &Affine3A,
|
||||
overlay: OverlayID,
|
||||
transform: &Affine3A,
|
||||
overlay_pose: &Affine3A,
|
||||
curvature: Option<&f32>,
|
||||
) -> Option<RayHit> {
|
||||
let (dist, local_pos) = curvature.map_or_else(
|
||||
|| {
|
||||
Some(raycast_plane(
|
||||
&self.pose,
|
||||
&ray_origin,
|
||||
Vec3A::NEG_Z,
|
||||
transform,
|
||||
overlay_pose,
|
||||
Vec3A::NEG_Z,
|
||||
))
|
||||
},
|
||||
|curvature| raycast_cylinder(&self.pose, Vec3A::NEG_Z, transform, *curvature),
|
||||
|curvature| raycast_cylinder(ray_origin, Vec3A::NEG_Z, overlay_pose, *curvature),
|
||||
)?;
|
||||
|
||||
if dist < 0.0 {
|
||||
@@ -634,12 +673,11 @@ impl Pointer {
|
||||
|
||||
Some(RayHit {
|
||||
overlay,
|
||||
global_pos: self.pose.transform_point3a(Vec3A::NEG_Z * dist),
|
||||
global_pos: ray_origin.transform_point3a(Vec3A::NEG_Z * dist),
|
||||
local_pos,
|
||||
dist,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn raycast_plane(
|
||||
source: &Affine3A,
|
||||
|
||||
@@ -22,7 +22,7 @@ use vulkano::{
|
||||
};
|
||||
use wgui::gfx::WGfx;
|
||||
|
||||
use crate::backend::input::{Haptics, PointerHit};
|
||||
use crate::backend::input::{HoverResult, PointerHit};
|
||||
use crate::graphics::CommandBuffers;
|
||||
use crate::state::AppState;
|
||||
use crate::windowing::backend::{FrameMeta, OverlayBackend, ShouldRender};
|
||||
@@ -206,8 +206,8 @@ impl OverlayBackend for LineBackend {
|
||||
})
|
||||
}
|
||||
|
||||
fn on_hover(&mut self, _: &mut AppState, _: &PointerHit) -> Option<Haptics> {
|
||||
None
|
||||
fn on_hover(&mut self, _: &mut AppState, _: &PointerHit) -> HoverResult {
|
||||
HoverResult::default()
|
||||
}
|
||||
fn on_left(&mut self, _: &mut AppState, _: usize) {}
|
||||
fn on_pointer(&mut self, _: &mut AppState, _: &PointerHit, _: bool) {}
|
||||
|
||||
@@ -15,11 +15,11 @@ use wgui::{
|
||||
layout::{Layout, LayoutParams, WidgetID},
|
||||
parser::ParserState,
|
||||
renderer_vk::context::Context as WguiContext,
|
||||
widget::{label::WidgetLabel, rectangle::WidgetRectangle},
|
||||
widget::{label::WidgetLabel, rectangle::WidgetRectangle, EventResult},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
backend::input::{Haptics, PointerHit, PointerMode},
|
||||
backend::input::{Haptics, HoverResult, PointerHit, PointerMode},
|
||||
graphics::{CommandBuffers, ExtentExt},
|
||||
state::AppState,
|
||||
windowing::backend::{ui_transform, FrameMeta, OverlayBackend, ShouldRender},
|
||||
@@ -150,9 +150,13 @@ impl<S: 'static> GuiPanel<S> {
|
||||
self.layout.update(MAX_SIZE_VEC2, 0.0)
|
||||
}
|
||||
|
||||
pub fn push_event(&mut self, app: &mut AppState, event: &WguiEvent) {
|
||||
if let Err(e) = self.layout.push_event(event, app, &mut self.state) {
|
||||
pub fn push_event(&mut self, app: &mut AppState, event: &WguiEvent) -> EventResult {
|
||||
match self.layout.push_event(event, app, &mut self.state) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
log::error!("Failed to push event: {e:?}");
|
||||
EventResult::NoHit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,23 +270,28 @@ impl<S: 'static> OverlayBackend for GuiPanel<S> {
|
||||
self.push_event(app, &e);
|
||||
}
|
||||
|
||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option<Haptics> {
|
||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> HoverResult {
|
||||
let e = &WguiEvent::MouseMotion(MouseMotionEvent {
|
||||
pos: hit.uv * self.layout.content_size,
|
||||
device: hit.pointer,
|
||||
});
|
||||
self.push_event(app, &e);
|
||||
let result = self.push_event(app, &e);
|
||||
|
||||
self.layout
|
||||
HoverResult {
|
||||
consume: result != EventResult::NoHit,
|
||||
haptics: self
|
||||
.layout
|
||||
.check_toggle_haptics_triggered()
|
||||
.then_some(Haptics {
|
||||
intensity: 0.1,
|
||||
duration: 0.01,
|
||||
frequency: 5.0,
|
||||
})
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn on_left(&mut self, app: &mut AppState, pointer: usize) {
|
||||
log::info!("panel: on left");
|
||||
let e = WguiEvent::MouseLeave(MouseLeaveEvent { device: pointer });
|
||||
self.push_event(app, &e);
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@ use wgui::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
backend::input::{Haptics, PointerHit},
|
||||
backend::input::{HoverResult, PointerHit},
|
||||
graphics::CommandBuffers,
|
||||
gui::panel::GuiPanel,
|
||||
state::AppState,
|
||||
subsystem::hid::{ALT, CTRL, KeyModifier, META, SHIFT, SUPER, VirtualKey},
|
||||
subsystem::hid::{KeyModifier, VirtualKey, ALT, CTRL, META, SHIFT, SUPER},
|
||||
windowing::backend::{FrameMeta, OverlayBackend, ShouldRender},
|
||||
};
|
||||
|
||||
@@ -75,7 +75,7 @@ impl OverlayBackend for KeyboardBackend {
|
||||
fn on_left(&mut self, app: &mut AppState, pointer: usize) {
|
||||
self.panel.on_left(app, pointer);
|
||||
}
|
||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option<Haptics> {
|
||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> HoverResult {
|
||||
self.panel.on_hover(app, hit)
|
||||
}
|
||||
fn get_interaction_transform(&mut self) -> Option<glam::Affine2> {
|
||||
|
||||
@@ -10,7 +10,7 @@ use wlx_capture::pipewire::{pipewire_select_screen, PipewireCapture, PipewireSel
|
||||
|
||||
use crate::{
|
||||
backend::{
|
||||
input::{Haptics, PointerHit},
|
||||
input::{HoverResult, PointerHit},
|
||||
task::TaskType,
|
||||
},
|
||||
graphics::CommandBuffers,
|
||||
@@ -130,8 +130,11 @@ impl OverlayBackend for MirrorBackend {
|
||||
self.renderer.as_mut().and_then(ScreenBackend::frame_meta)
|
||||
}
|
||||
|
||||
fn on_hover(&mut self, _: &mut AppState, _: &PointerHit) -> Option<Haptics> {
|
||||
None
|
||||
fn on_hover(&mut self, _: &mut AppState, _: &PointerHit) -> HoverResult {
|
||||
HoverResult {
|
||||
consume: true,
|
||||
..HoverResult::default()
|
||||
}
|
||||
}
|
||||
fn on_left(&mut self, _: &mut AppState, _: usize) {}
|
||||
fn on_pointer(&mut self, _: &mut AppState, _: &PointerHit, _: bool) {}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
use std::{
|
||||
sync::{Arc, LazyLock, atomic::AtomicU64},
|
||||
sync::{atomic::AtomicU64, Arc, LazyLock},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use glam::{Affine2, Vec2, vec2};
|
||||
use glam::{vec2, Affine2, Vec2};
|
||||
use vulkano::image::view::ImageView;
|
||||
use wlx_capture::{WlxCapture, frame::Transform};
|
||||
use wlx_capture::{frame::Transform, WlxCapture};
|
||||
|
||||
use crate::{
|
||||
backend::input::{Haptics, PointerHit, PointerMode},
|
||||
backend::input::{HoverResult, PointerHit, PointerMode},
|
||||
graphics::{CommandBuffers, ExtentExt},
|
||||
state::AppState,
|
||||
subsystem::hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT},
|
||||
windowing::backend::{FrameMeta, OverlayBackend, ShouldRender},
|
||||
};
|
||||
|
||||
use super::capture::{ScreenPipeline, WlxCaptureIn, WlxCaptureOut, receive_callback};
|
||||
use super::capture::{receive_callback, ScreenPipeline, WlxCaptureIn, WlxCaptureOut};
|
||||
|
||||
const CURSOR_SIZE: f32 = 16. / 1440.;
|
||||
|
||||
@@ -211,7 +211,7 @@ impl OverlayBackend for ScreenBackend {
|
||||
self.meta
|
||||
}
|
||||
|
||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option<Haptics> {
|
||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> HoverResult {
|
||||
#[cfg(debug_assertions)]
|
||||
log::trace!("Hover: {:?}", hit.uv);
|
||||
if can_move()
|
||||
@@ -222,7 +222,10 @@ impl OverlayBackend for ScreenBackend {
|
||||
app.hid_provider.inner.mouse_move(pos);
|
||||
set_next_move(u64::from(app.session.config.mouse_move_interval_ms));
|
||||
}
|
||||
None
|
||||
HoverResult {
|
||||
consume: true,
|
||||
..HoverResult::default()
|
||||
}
|
||||
}
|
||||
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool) {
|
||||
let btn = match hit.mode {
|
||||
|
||||
@@ -17,7 +17,7 @@ use wlx_capture::frame::{DmabufFrame, FourCC, FrameFormat, FramePlane};
|
||||
|
||||
use crate::{
|
||||
backend::{
|
||||
input::{self},
|
||||
input::{self, HoverResult},
|
||||
task::TaskType,
|
||||
wayvr::{
|
||||
self, display,
|
||||
@@ -716,11 +716,7 @@ impl OverlayBackend for WayVRBackend {
|
||||
})
|
||||
}
|
||||
|
||||
fn on_hover(
|
||||
&mut self,
|
||||
_app: &mut state::AppState,
|
||||
hit: &input::PointerHit,
|
||||
) -> Option<input::Haptics> {
|
||||
fn on_hover(&mut self, _app: &mut state::AppState, hit: &input::PointerHit) -> HoverResult {
|
||||
let ctx = self.context.borrow();
|
||||
|
||||
let wayvr = &mut ctx.wayvr.borrow_mut();
|
||||
@@ -737,7 +733,10 @@ impl OverlayBackend for WayVRBackend {
|
||||
.send_mouse_move(ctx.display, x as u32, y as u32);
|
||||
}
|
||||
|
||||
wayvr.pending_haptics.take()
|
||||
HoverResult {
|
||||
haptics: wayvr.pending_haptics.take(),
|
||||
consume: true,
|
||||
}
|
||||
}
|
||||
|
||||
fn on_left(&mut self, _app: &mut state::AppState, _pointer: usize) {
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||
use vulkano::{format::Format, image::view::ImageView};
|
||||
|
||||
use crate::{
|
||||
backend::input::{Haptics, PointerHit},
|
||||
backend::input::{HoverResult, PointerHit},
|
||||
graphics::CommandBuffers,
|
||||
state::AppState,
|
||||
};
|
||||
@@ -48,7 +48,7 @@ pub trait OverlayBackend {
|
||||
/// Must be true if should_render was also true on the same frame.
|
||||
fn frame_meta(&mut self) -> Option<FrameMeta>;
|
||||
|
||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> Option<Haptics>;
|
||||
fn on_hover(&mut self, app: &mut AppState, hit: &PointerHit) -> HoverResult;
|
||||
fn on_left(&mut self, app: &mut AppState, pointer: usize);
|
||||
fn on_pointer(&mut self, app: &mut AppState, hit: &PointerHit, pressed: bool);
|
||||
fn on_scroll(&mut self, app: &mut AppState, hit: &PointerHit, delta_y: f32, delta_x: f32);
|
||||
|
||||
@@ -91,7 +91,9 @@ where
|
||||
|
||||
Ok(me)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> OverlayWindowManager<T> {
|
||||
pub fn mut_by_selector(
|
||||
&mut self,
|
||||
selector: &OverlaySelector,
|
||||
|
||||
@@ -63,10 +63,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> OverlayWindowData<T>
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
impl<T> OverlayWindowData<T> {
|
||||
pub fn init(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
||||
//TODO: load state?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user