Implement Widget::mouse_interaction for PaneGrid

... and fix rendering of drag interaction in `PaneGrid` by
introducing an explicit `with_translation` method to `Renderer`
and simplifying the `with_layer` and `Clip` primitive.
This commit is contained in:
Héctor Ramón Jiménez 2021-10-25 16:16:35 +07:00
parent 41394b4e90
commit 4a11cbd994
No known key found for this signature in database
GPG key ID: 140CC052C94F138E
11 changed files with 167 additions and 66 deletions

View file

@ -175,11 +175,7 @@ impl<'a> Layer<'a> {
}); });
} }
} }
Primitive::Clip { Primitive::Clip { bounds, content } => {
bounds,
offset,
content,
} => {
let layer = &mut layers[current_layer]; let layer = &mut layers[current_layer];
let translated_bounds = *bounds + translation; let translated_bounds = *bounds + translation;
@ -192,8 +188,7 @@ impl<'a> Layer<'a> {
Self::process_primitive( Self::process_primitive(
layers, layers,
translation translation,
- Vector::new(offset.x as f32, offset.y as f32),
content, content,
layers.len() - 1, layers.len() - 1,
); );

View file

@ -66,8 +66,6 @@ pub enum Primitive {
Clip { Clip {
/// The bounds of the clip /// The bounds of the clip
bounds: Rectangle, bounds: Rectangle,
/// The offset transformation of the clip
offset: Vector<u32>,
/// The content of the clip /// The content of the clip
content: Box<Primitive>, content: Box<Primitive>,
}, },

View file

@ -51,12 +51,7 @@ where
layout layout
} }
fn with_layer( fn with_layer(&mut self, bounds: Rectangle, f: impl FnOnce(&mut Self)) {
&mut self,
bounds: Rectangle,
offset: Vector<u32>,
f: impl FnOnce(&mut Self),
) {
let current_primitives = let current_primitives =
std::mem::replace(&mut self.primitives, Vec::new()); std::mem::replace(&mut self.primitives, Vec::new());
@ -67,7 +62,27 @@ where
self.primitives.push(Primitive::Clip { self.primitives.push(Primitive::Clip {
bounds, bounds,
offset, content: Box::new(Primitive::Group {
primitives: layer_primitives,
}),
});
}
fn with_translation(
&mut self,
translation: Vector,
f: impl FnOnce(&mut Self),
) {
let current_primitives =
std::mem::replace(&mut self.primitives, Vec::new());
f(self);
let layer_primitives =
std::mem::replace(&mut self.primitives, current_primitives);
self.primitives.push(Primitive::Translate {
translation,
content: Box::new(Primitive::Group { content: Box::new(Primitive::Group {
primitives: layer_primitives, primitives: layer_primitives,
}), }),

View file

@ -46,10 +46,11 @@ pub trait Renderer: Sized {
element.layout(self, limits) element.layout(self, limits)
} }
fn with_layer( fn with_layer(&mut self, bounds: Rectangle, f: impl FnOnce(&mut Self));
fn with_translation(
&mut self, &mut self,
bounds: Rectangle, translation: Vector,
offset: Vector<u32>,
f: impl FnOnce(&mut Self), f: impl FnOnce(&mut Self),
); );

View file

@ -1,4 +1,3 @@
use crate::pane_grid;
use crate::progress_bar; use crate::progress_bar;
use crate::renderer::{self, Renderer}; use crate::renderer::{self, Renderer};
use crate::text; use crate::text;
@ -19,10 +18,11 @@ impl Null {
} }
impl Renderer for Null { impl Renderer for Null {
fn with_layer( fn with_layer(&mut self, _bounds: Rectangle, _f: impl FnOnce(&mut Self)) {}
fn with_translation(
&mut self, &mut self,
_bounds: Rectangle, _translation: Vector,
_offset: Vector<u32>,
_f: impl FnOnce(&mut Self), _f: impl FnOnce(&mut Self),
) { ) {
} }

View file

@ -3,7 +3,7 @@ use crate::layout;
use crate::mouse; use crate::mouse;
use crate::overlay; use crate::overlay;
use crate::renderer; use crate::renderer;
use crate::{Clipboard, Element, Layout, Point, Rectangle, Size, Vector}; use crate::{Clipboard, Element, Layout, Point, Rectangle, Size};
use std::hash::Hasher; use std::hash::Hasher;
@ -359,18 +359,14 @@ where
let overlay_bounds = layer.layout.bounds(); let overlay_bounds = layer.layout.bounds();
renderer.with_layer( renderer.with_layer(overlay_bounds, |renderer| {
overlay_bounds, overlay.draw(
Vector::new(0, 0), renderer,
|renderer| { &renderer::Style::default(),
overlay.draw( Layout::new(&layer.layout),
renderer, cursor_position,
&renderer::Style::default(), );
Layout::new(&layer.layout), });
cursor_position,
);
},
);
self.overlay = Some(layer); self.overlay = Some(layer);

View file

@ -471,6 +471,33 @@ where
.fold(event_status, event::Status::merge) .fold(event_status, event::Status::merge)
} }
fn mouse_interaction(
&self,
layout: Layout<'_>,
viewport: &Rectangle,
cursor_position: Point,
) -> mouse::Interaction {
if self.state.picked_pane().is_some() {
return mouse::Interaction::Grab;
}
if let Some((_, axis)) = self.state.picked_split() {
return match axis {
Axis::Horizontal => mouse::Interaction::ResizingHorizontally,
Axis::Vertical => mouse::Interaction::ResizingVertically,
};
}
self.elements
.iter()
.zip(layout.children())
.map(|((_pane, content), layout)| {
content.mouse_interaction(layout, viewport, cursor_position)
})
.max()
.unwrap_or_default()
}
fn draw( fn draw(
&self, &self,
renderer: &mut Renderer, renderer: &mut Renderer,
@ -543,22 +570,22 @@ where
Some((dragging, origin)) if *id == dragging => { Some((dragging, origin)) if *id == dragging => {
let bounds = layout.bounds(); let bounds = layout.bounds();
renderer.with_layer( renderer.with_translation(
Rectangle { cursor_position
x: cursor_position.x - origin.x, - Point::new(
y: cursor_position.y - origin.y, bounds.x + origin.x,
width: bounds.width + 0.5, bounds.y + origin.y,
height: bounds.height + 0.5, ),
},
Vector::new(0, 0),
|renderer| { |renderer| {
pane.draw( renderer.with_layer(bounds, |renderer| {
renderer, pane.draw(
style, renderer,
layout, style,
pane_cursor_position, layout,
viewport, pane_cursor_position,
); viewport,
);
});
}, },
); );
} }

View file

@ -1,6 +1,7 @@
use crate::container; use crate::container;
use crate::event::{self, Event}; use crate::event::{self, Event};
use crate::layout; use crate::layout;
use crate::mouse;
use crate::overlay; use crate::overlay;
use crate::pane_grid::TitleBar; use crate::pane_grid::TitleBar;
use crate::renderer; use crate::renderer;
@ -194,6 +195,41 @@ where
event_status.merge(body_status) event_status.merge(body_status)
} }
pub(crate) fn mouse_interaction(
&self,
layout: Layout<'_>,
viewport: &Rectangle,
cursor_position: Point,
) -> mouse::Interaction {
let mut children = layout.children();
let (body_layout, title_bar_interaction) =
if let Some(title_bar) = &self.title_bar {
let title_bar_layout = children.next().unwrap();
let is_over_pick_area = title_bar
.is_over_pick_area(title_bar_layout, cursor_position);
if is_over_pick_area {
return mouse::Interaction::Grab;
}
let mouse_interaction = title_bar.mouse_interaction(
title_bar_layout,
viewport,
cursor_position,
);
(children.next().unwrap(), mouse_interaction)
} else {
(children.next().unwrap(), mouse::Interaction::default())
};
self.body
.mouse_interaction(body_layout, viewport, cursor_position)
.max(title_bar_interaction)
}
pub(crate) fn hash_layout(&self, state: &mut Hasher) { pub(crate) fn hash_layout(&self, state: &mut Hasher) {
if let Some(title_bar) = &self.title_bar { if let Some(title_bar) = &self.title_bar {
title_bar.hash_layout(state); title_bar.hash_layout(state);

View file

@ -1,6 +1,7 @@
use crate::container; use crate::container;
use crate::event::{self, Event}; use crate::event::{self, Event};
use crate::layout; use crate::layout;
use crate::mouse;
use crate::overlay; use crate::overlay;
use crate::renderer; use crate::renderer;
use crate::{ use crate::{
@ -249,6 +250,35 @@ where
control_status.merge(title_status) control_status.merge(title_status)
} }
pub(crate) fn mouse_interaction(
&self,
layout: Layout<'_>,
viewport: &Rectangle,
cursor_position: Point,
) -> mouse::Interaction {
let mut children = layout.children();
let padded = children.next().unwrap();
let mut children = padded.children();
let title_layout = children.next().unwrap();
let title_interaction = self.content.mouse_interaction(
title_layout,
viewport,
cursor_position,
);
if let Some(controls) = &self.controls {
let controls_layout = children.next().unwrap();
controls
.mouse_interaction(controls_layout, viewport, cursor_position)
.max(title_interaction)
} else {
title_interaction
}
}
pub(crate) fn overlay( pub(crate) fn overlay(
&mut self, &mut self,
layout: Layout<'_>, layout: Layout<'_>,

View file

@ -485,15 +485,20 @@ where
}; };
if let Some(scrollbar) = scrollbar { if let Some(scrollbar) = scrollbar {
renderer.with_layer(bounds, Vector::new(0, offset), |renderer| { renderer.with_layer(bounds, |renderer| {
self.content.draw( renderer.with_translation(
renderer, Vector::new(0.0, -(offset as f32)),
style, |renderer| {
content_layout, self.content.draw(
cursor_position, renderer,
&Rectangle { style,
y: bounds.y + offset as f32, content_layout,
..bounds cursor_position,
&Rectangle {
y: bounds.y + offset as f32,
..bounds
},
);
}, },
); );
}); });
@ -509,7 +514,7 @@ where
let is_scrollbar_visible = let is_scrollbar_visible =
style.background.is_some() || style.border_width > 0.0; style.background.is_some() || style.border_width > 0.0;
renderer.with_layer(bounds, Vector::new(0, 0), |renderer| { renderer.with_layer(bounds, |renderer| {
if is_scrollbar_visible { if is_scrollbar_visible {
renderer.fill_rectangle(renderer::Quad { renderer.fill_rectangle(renderer::Quad {
bounds: scrollbar.bounds, bounds: scrollbar.bounds,

View file

@ -751,11 +751,9 @@ where
}; };
if text_width > text_bounds.width { if text_width > text_bounds.width {
renderer.with_layer( renderer.with_layer(text_bounds, |renderer| {
text_bounds, renderer.with_translation(Vector::new(-offset, 0.0), render)
Vector::new(offset as u32, 0), });
render,
);
} else { } else {
render(renderer); render(renderer);
} }