Drag and drop tabs working. all known bugs fixed
This commit is contained in:
parent
0a97a9c0fd
commit
042ece00b1
8 changed files with 142 additions and 46 deletions
|
@ -24,6 +24,8 @@ pub struct ContainerStyle {
|
|||
pub padding: Padding,
|
||||
#[serde(rename = "background")]
|
||||
pub background_color: Option<Color>,
|
||||
#[serde(rename = "overlay")]
|
||||
pub overlay_color: Option<Color>,
|
||||
#[serde(default)]
|
||||
pub border: Border,
|
||||
#[serde(default)]
|
||||
|
@ -119,6 +121,11 @@ impl Container {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn with_overlay_color(mut self, color: Color) -> Self {
|
||||
self.style.overlay_color = Some(color);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_border(mut self, border: Border) -> Self {
|
||||
self.style.border = border;
|
||||
self
|
||||
|
@ -245,7 +252,7 @@ impl Element for Container {
|
|||
cx.scene.push_layer(None);
|
||||
cx.scene.push_quad(Quad {
|
||||
bounds: quad_bounds,
|
||||
background: Default::default(),
|
||||
background: self.style.overlay_color,
|
||||
border: self.style.border,
|
||||
corner_radius: self.style.corner_radius,
|
||||
});
|
||||
|
@ -264,6 +271,17 @@ impl Element for Container {
|
|||
self.style.border.top_width(),
|
||||
);
|
||||
self.child.paint(child_origin, visible_bounds, cx);
|
||||
|
||||
if self.style.overlay_color.is_some() {
|
||||
cx.scene.push_layer(None);
|
||||
cx.scene.push_quad(Quad {
|
||||
bounds: quad_bounds,
|
||||
background: self.style.overlay_color,
|
||||
border: Default::default(),
|
||||
corner_radius: 0.,
|
||||
});
|
||||
cx.scene.pop_layer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ pub struct MouseEventHandler {
|
|||
discriminant: (TypeId, usize),
|
||||
cursor_style: Option<CursorStyle>,
|
||||
handlers: HandlerSet,
|
||||
hoverable: bool,
|
||||
padding: Padding,
|
||||
}
|
||||
|
||||
|
@ -35,6 +36,7 @@ impl MouseEventHandler {
|
|||
cursor_style: None,
|
||||
discriminant: (TypeId::of::<Tag>(), id),
|
||||
handlers: Default::default(),
|
||||
hoverable: true,
|
||||
padding: Default::default(),
|
||||
}
|
||||
}
|
||||
|
@ -119,6 +121,11 @@ impl MouseEventHandler {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn with_hoverable(mut self, is_hoverable: bool) -> Self {
|
||||
self.hoverable = is_hoverable;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_padding(mut self, padding: Padding) -> Self {
|
||||
self.padding = padding;
|
||||
self
|
||||
|
@ -160,12 +167,15 @@ impl Element for MouseEventHandler {
|
|||
});
|
||||
}
|
||||
|
||||
cx.scene.push_mouse_region(MouseRegion::from_handlers(
|
||||
cx.current_view_id(),
|
||||
Some(self.discriminant),
|
||||
hit_bounds,
|
||||
self.handlers.clone(),
|
||||
));
|
||||
cx.scene.push_mouse_region(
|
||||
MouseRegion::from_handlers(
|
||||
cx.current_view_id(),
|
||||
Some(self.discriminant),
|
||||
hit_bounds,
|
||||
self.handlers.clone(),
|
||||
)
|
||||
.with_hoverable(self.hoverable),
|
||||
);
|
||||
|
||||
self.child.paint(bounds.origin(), visible_bounds, cx);
|
||||
}
|
||||
|
|
|
@ -245,17 +245,21 @@ impl Presenter {
|
|||
// MDN says that browsers handle this by starting from 'the most
|
||||
// specific ancestor element that contained both [positions]'
|
||||
// So we need to store the overlapping regions on mouse down.
|
||||
self.clicked_regions = self
|
||||
.mouse_regions
|
||||
.iter()
|
||||
.filter_map(|(region, _)| {
|
||||
region
|
||||
.bounds
|
||||
.contains_point(e.position)
|
||||
.then(|| region.clone())
|
||||
})
|
||||
.collect();
|
||||
self.clicked_button = Some(e.button);
|
||||
|
||||
// If there is already clicked_button stored, don't replace it.
|
||||
if self.clicked_button.is_none() {
|
||||
self.clicked_regions = self
|
||||
.mouse_regions
|
||||
.iter()
|
||||
.filter_map(|(region, _)| {
|
||||
region
|
||||
.bounds
|
||||
.contains_point(e.position)
|
||||
.then(|| region.clone())
|
||||
})
|
||||
.collect();
|
||||
self.clicked_button = Some(e.button);
|
||||
}
|
||||
|
||||
events_to_send.push(MouseRegionEvent::Down(DownRegionEvent {
|
||||
region: Default::default(),
|
||||
|
@ -337,13 +341,18 @@ impl Presenter {
|
|||
|
||||
// GPUI elements are arranged by depth but sibling elements can register overlapping
|
||||
// mouse regions. As such, hover events are only fired on overlapping elements which
|
||||
// are at the same depth as the deepest element which overlaps with the mouse.
|
||||
// are at the same depth as the topmost element which overlaps with the mouse.
|
||||
|
||||
match ®ion_event {
|
||||
MouseRegionEvent::Hover(_) => {
|
||||
let mut top_most_depth = None;
|
||||
let mouse_position = self.mouse_position.clone();
|
||||
for (region, depth) in self.mouse_regions.iter().rev() {
|
||||
// Allow mouse regions to appear transparent to hovers
|
||||
if !region.hoverable {
|
||||
continue;
|
||||
}
|
||||
|
||||
let contains_mouse = region.bounds.contains_point(mouse_position);
|
||||
|
||||
if contains_mouse && top_most_depth.is_none() {
|
||||
|
@ -359,26 +368,30 @@ impl Presenter {
|
|||
//Ensure that hover entrance events aren't sent twice
|
||||
if self.hovered_region_ids.insert(region_id) {
|
||||
valid_regions.push(region.clone());
|
||||
invalidated_views.insert(region.view_id);
|
||||
}
|
||||
} else {
|
||||
// Ensure that hover exit events aren't sent twice
|
||||
if self.hovered_region_ids.remove(®ion_id) {
|
||||
valid_regions.push(region.clone());
|
||||
invalidated_views.insert(region.view_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseRegionEvent::Click(e) => {
|
||||
// Clear presenter state
|
||||
let clicked_regions =
|
||||
std::mem::replace(&mut self.clicked_regions, Vec::new());
|
||||
self.clicked_button = None;
|
||||
if e.button == self.clicked_button.unwrap() {
|
||||
// Clear clicked regions and clicked button
|
||||
let clicked_regions =
|
||||
std::mem::replace(&mut self.clicked_regions, Vec::new());
|
||||
self.clicked_button = None;
|
||||
|
||||
// Find regions which still overlap with the mouse since the last MouseDown happened
|
||||
for clicked_region in clicked_regions.into_iter().rev() {
|
||||
if clicked_region.bounds.contains_point(e.position) {
|
||||
valid_regions.push(clicked_region);
|
||||
// Find regions which still overlap with the mouse since the last MouseDown happened
|
||||
for clicked_region in clicked_regions.into_iter().rev() {
|
||||
if clicked_region.bounds.contains_point(e.position) {
|
||||
valid_regions.push(clicked_region);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ pub struct MouseRegion {
|
|||
pub discriminant: Option<(TypeId, usize)>,
|
||||
pub bounds: RectF,
|
||||
pub handlers: HandlerSet,
|
||||
pub hoverable: bool,
|
||||
}
|
||||
|
||||
impl MouseRegion {
|
||||
|
@ -35,6 +36,7 @@ impl MouseRegion {
|
|||
discriminant,
|
||||
bounds,
|
||||
handlers,
|
||||
hoverable: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,6 +50,7 @@ impl MouseRegion {
|
|||
discriminant,
|
||||
bounds,
|
||||
handlers: HandlerSet::capture_all(),
|
||||
hoverable: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,6 +123,11 @@ impl MouseRegion {
|
|||
self.handlers = self.handlers.on_move(handler);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_hoverable(mut self, is_hoverable: bool) -> Self {
|
||||
self.hoverable = is_hoverable;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue