layout: Generalize traversal between rendering and input

This commit is contained in:
Ivan Molodetskikh
2024-02-04 22:10:26 +04:00
parent 7a4bb8ba8a
commit b824cf90ab
+59 -62
View File
@@ -1,5 +1,6 @@
use std::cmp::{max, min}; use std::cmp::{max, min};
use std::iter::zip; use std::iter::zip;
use std::ops::ControlFlow;
use std::rc::Rc; use std::rc::Rc;
use std::time::Duration; use std::time::Duration;
@@ -913,6 +914,45 @@ impl<W: LayoutElement> Workspace<W> {
self.column_x(self.active_column_idx) + self.view_offset self.column_x(self.active_column_idx) + self.view_offset
} }
fn with_tiles_in_render_order<'a, F, B>(&'a self, mut f: F) -> Option<B>
where
F: FnMut(&'a Tile<W>, Point<i32, Logical>) -> ControlFlow<B>,
{
let view_pos = self.view_pos();
// Start with the active window since it's drawn on top.
let col = &self.columns[self.active_column_idx];
let tile = &col.tiles[col.active_tile_idx];
let tile_pos = Point::from((
self.column_x(self.active_column_idx) - view_pos,
col.tile_y(col.active_tile_idx),
));
if let ControlFlow::Break(rv) = f(tile, tile_pos) {
return Some(rv);
}
let mut x = -view_pos;
for (col_idx, col) in self.columns.iter().enumerate() {
for (tile_idx, (tile, y)) in zip(&col.tiles, col.tile_ys()).enumerate() {
if col_idx == self.active_column_idx && tile_idx == col.active_tile_idx {
// Already handled it above.
continue;
}
let tile_pos = Point::from((x, y));
if let ControlFlow::Break(rv) = f(tile, tile_pos) {
return Some(rv);
}
}
x += col.width() + self.options.gaps;
}
None
}
pub fn window_under( pub fn window_under(
&self, &self,
pos: Point<f64, Logical>, pos: Point<f64, Logical>,
@@ -921,45 +961,18 @@ impl<W: LayoutElement> Workspace<W> {
return None; return None;
} }
let view_pos = self.view_pos(); self.with_tiles_in_render_order(|tile, tile_pos| {
let pos_within_tile = pos - tile_pos.to_f64();
// Prefer the active window since it's drawn on top. if tile.is_in_input_region(pos_within_tile) {
let col = &self.columns[self.active_column_idx]; let pos_within_surface = tile_pos + tile.buf_loc();
let active_tile = &col.tiles[col.active_tile_idx]; return ControlFlow::Break((tile.window(), Some(pos_within_surface)));
let tile_pos = Point::from(( } else if tile.is_in_activation_region(pos_within_tile) {
self.column_x(self.active_column_idx) - view_pos, return ControlFlow::Break((tile.window(), None));
col.tile_y(col.active_tile_idx),
));
let pos_within_tile = pos - tile_pos.to_f64();
if active_tile.is_in_input_region(pos_within_tile) {
let pos_within_surface = tile_pos + active_tile.buf_loc();
return Some((active_tile.window(), Some(pos_within_surface)));
} else if active_tile.is_in_activation_region(pos_within_tile) {
return Some((active_tile.window(), None));
}
let mut x = -view_pos;
for col in &self.columns {
for (tile, y) in zip(&col.tiles, col.tile_ys()) {
if tile.window() == active_tile.window() {
// Already handled it above.
continue;
}
let tile_pos = Point::from((x, y));
let pos_within_tile = pos - tile_pos.to_f64();
if tile.is_in_input_region(pos_within_tile) {
let pos_within_surface = tile_pos + tile.buf_loc();
return Some((tile.window(), Some(pos_within_surface)));
} else if tile.is_in_activation_region(pos_within_tile) {
return Some((tile.window(), None));
}
} }
x += col.width() + self.options.gaps; ControlFlow::Continue(())
} })
None
} }
pub fn toggle_width(&mut self) { pub fn toggle_width(&mut self) {
@@ -1079,36 +1092,20 @@ impl<W: LayoutElement> Workspace<W> {
.unwrap_or(Scale::from(1.)); .unwrap_or(Scale::from(1.));
let mut rv = vec![]; let mut rv = vec![];
let view_pos = self.view_pos(); let mut first = true;
// Draw the active window on top. self.with_tiles_in_render_order(|tile, tile_pos| {
let col = &self.columns[self.active_column_idx]; // Draw the window itself.
let active_tile = &col.tiles[col.active_tile_idx]; rv.extend(tile.render(renderer, tile_pos, output_scale));
let tile_pos = Point::from((
self.column_x(self.active_column_idx) - view_pos,
col.tile_y(col.active_tile_idx),
));
// Draw the window itself. // For the active tile (which comes first), draw the focus ring.
rv.extend(active_tile.render(renderer, tile_pos, output_scale)); if first {
rv.extend(self.focus_ring.render(output_scale).map(Into::into));
// Draw the focus ring. first = false;
rv.extend(self.focus_ring.render(output_scale).map(Into::into));
let mut x = -view_pos;
for col in &self.columns {
for (tile, y) in zip(&col.tiles, col.tile_ys()) {
if tile.window() == active_tile.window() {
// Already handled it above.
continue;
}
let tile_pos = Point::from((x, y));
rv.extend(tile.render(renderer, tile_pos, output_scale));
} }
x += col.width() + self.options.gaps; ControlFlow::<()>::Continue(())
} });
rv rv
} }