Fix hover state when element is occluded
This commit is contained in:
parent
ccfc4fc0b9
commit
17b5f9294c
2 changed files with 54 additions and 12 deletions
|
@ -755,6 +755,14 @@ impl Interactivity {
|
||||||
) {
|
) {
|
||||||
let style = self.compute_style(Some(bounds), element_state, cx);
|
let style = self.compute_style(Some(bounds), element_state, cx);
|
||||||
|
|
||||||
|
if style
|
||||||
|
.background
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|fill| fill.color().is_some_and(|color| !color.is_transparent()))
|
||||||
|
{
|
||||||
|
cx.with_z_index(style.z_index.unwrap_or(0), |cx| cx.add_opaque_layer(bounds))
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(mouse_cursor) = style.mouse_cursor {
|
if let Some(mouse_cursor) = style.mouse_cursor {
|
||||||
let hovered = bounds.contains_point(&cx.mouse_position());
|
let hovered = bounds.contains_point(&cx.mouse_position());
|
||||||
if hovered {
|
if hovered {
|
||||||
|
@ -1098,19 +1106,21 @@ impl Interactivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if self.hover_style.is_some() {
|
if self.hover_style.is_some() {
|
||||||
if bounds.contains_point(&mouse_position) {
|
if bounds
|
||||||
// eprintln!("div hovered {bounds:?} {mouse_position:?}");
|
.intersect(&cx.content_mask().bounds)
|
||||||
style.refine(&self.hover_style);
|
.contains_point(&mouse_position)
|
||||||
} else {
|
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
|
||||||
// eprintln!("div NOT hovered {bounds:?} {mouse_position:?}");
|
{
|
||||||
|
style.refine(&self.hover_style);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
if let Some(drag) = cx.active_drag.take() {
|
if let Some(drag) = cx.active_drag.take() {
|
||||||
for (state_type, group_drag_style) in &self.group_drag_over_styles {
|
for (state_type, group_drag_style) in &self.group_drag_over_styles {
|
||||||
if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) {
|
if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) {
|
||||||
if *state_type == drag.view.entity_type()
|
if *state_type == drag.view.entity_type()
|
||||||
|
// todo!() needs to handle cx.content_mask() and cx.is_top()
|
||||||
&& group_bounds.contains_point(&mouse_position)
|
&& group_bounds.contains_point(&mouse_position)
|
||||||
{
|
{
|
||||||
style.refine(&group_drag_style.style);
|
style.refine(&group_drag_style.style);
|
||||||
|
@ -1120,7 +1130,10 @@ impl Interactivity {
|
||||||
|
|
||||||
for (state_type, drag_over_style) in &self.drag_over_styles {
|
for (state_type, drag_over_style) in &self.drag_over_styles {
|
||||||
if *state_type == drag.view.entity_type()
|
if *state_type == drag.view.entity_type()
|
||||||
&& bounds.contains_point(&mouse_position)
|
&& bounds
|
||||||
|
.intersect(&cx.content_mask().bounds)
|
||||||
|
.contains_point(&mouse_position)
|
||||||
|
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
|
||||||
{
|
{
|
||||||
style.refine(drag_over_style);
|
style.refine(drag_over_style);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::{
|
||||||
VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
|
VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Context as _, Result};
|
use anyhow::{anyhow, Context as _, Result};
|
||||||
use collections::HashMap;
|
use collections::{BTreeMap, HashMap};
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::{mpsc, oneshot},
|
channel::{mpsc, oneshot},
|
||||||
|
@ -39,8 +39,8 @@ use util::ResultExt;
|
||||||
|
|
||||||
/// A global stacking order, which is created by stacking successive z-index values.
|
/// A global stacking order, which is created by stacking successive z-index values.
|
||||||
/// Each z-index will always be interpreted in the context of its parent z-index.
|
/// Each z-index will always be interpreted in the context of its parent z-index.
|
||||||
#[derive(Deref, DerefMut, Ord, PartialOrd, Eq, PartialEq, Clone, Default)]
|
#[derive(Deref, DerefMut, Ord, PartialOrd, Eq, PartialEq, Clone, Default, Debug)]
|
||||||
pub(crate) struct StackingOrder(pub(crate) SmallVec<[u32; 16]>);
|
pub struct StackingOrder(pub(crate) SmallVec<[u32; 16]>);
|
||||||
|
|
||||||
/// Represents the two different phases when dispatching events.
|
/// Represents the two different phases when dispatching events.
|
||||||
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
@ -243,7 +243,8 @@ pub(crate) struct Frame {
|
||||||
pub(crate) dispatch_tree: DispatchTree,
|
pub(crate) dispatch_tree: DispatchTree,
|
||||||
pub(crate) focus_listeners: Vec<AnyFocusListener>,
|
pub(crate) focus_listeners: Vec<AnyFocusListener>,
|
||||||
pub(crate) scene_builder: SceneBuilder,
|
pub(crate) scene_builder: SceneBuilder,
|
||||||
z_index_stack: StackingOrder,
|
pub(crate) depth_map: BTreeMap<StackingOrder, Bounds<Pixels>>,
|
||||||
|
pub(crate) z_index_stack: StackingOrder,
|
||||||
content_mask_stack: Vec<ContentMask<Pixels>>,
|
content_mask_stack: Vec<ContentMask<Pixels>>,
|
||||||
element_offset_stack: Vec<Point<Pixels>>,
|
element_offset_stack: Vec<Point<Pixels>>,
|
||||||
}
|
}
|
||||||
|
@ -257,6 +258,7 @@ impl Frame {
|
||||||
focus_listeners: Vec::new(),
|
focus_listeners: Vec::new(),
|
||||||
scene_builder: SceneBuilder::default(),
|
scene_builder: SceneBuilder::default(),
|
||||||
z_index_stack: StackingOrder::default(),
|
z_index_stack: StackingOrder::default(),
|
||||||
|
depth_map: Default::default(),
|
||||||
content_mask_stack: Vec::new(),
|
content_mask_stack: Vec::new(),
|
||||||
element_offset_stack: Vec::new(),
|
element_offset_stack: Vec::new(),
|
||||||
}
|
}
|
||||||
|
@ -806,6 +808,32 @@ impl<'a> WindowContext<'a> {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Called during painting to track which z-index is on top at each pixel position
|
||||||
|
pub fn add_opaque_layer(&mut self, bounds: Bounds<Pixels>) {
|
||||||
|
let stacking_order = self.window.current_frame.z_index_stack.clone();
|
||||||
|
self.window
|
||||||
|
.current_frame
|
||||||
|
.depth_map
|
||||||
|
.insert(stacking_order, bounds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the top-most opaque layer painted over this point was part of the
|
||||||
|
/// same layer as the given stacking order.
|
||||||
|
pub fn was_top_layer(&self, point: &Point<Pixels>, level: &StackingOrder) -> bool {
|
||||||
|
for (stack, bounds) in self.window.previous_frame.depth_map.iter() {
|
||||||
|
if bounds.contains_point(point) {
|
||||||
|
return level.starts_with(stack) || stack.starts_with(level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Called during painting to get the current stacking order.
|
||||||
|
pub fn stacking_order(&self) -> &StackingOrder {
|
||||||
|
&self.window.current_frame.z_index_stack
|
||||||
|
}
|
||||||
|
|
||||||
/// Paint one or more drop shadows into the scene for the current frame at the current z-index.
|
/// Paint one or more drop shadows into the scene for the current frame at the current z-index.
|
||||||
pub fn paint_shadows(
|
pub fn paint_shadows(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -1153,6 +1181,7 @@ impl<'a> WindowContext<'a> {
|
||||||
frame.mouse_listeners.values_mut().for_each(Vec::clear);
|
frame.mouse_listeners.values_mut().for_each(Vec::clear);
|
||||||
frame.focus_listeners.clear();
|
frame.focus_listeners.clear();
|
||||||
frame.dispatch_tree.clear();
|
frame.dispatch_tree.clear();
|
||||||
|
frame.depth_map.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dispatch a mouse or keyboard event on the window.
|
/// Dispatch a mouse or keyboard event on the window.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue