floating mouse tiling: add corner tiling, implement designs

This commit is contained in:
Ryan Brue 2024-03-21 11:39:16 -05:00 committed by Victoria Brekenfeld
parent fc2173d028
commit 3837e56382
2 changed files with 121 additions and 68 deletions

View file

@ -4,7 +4,7 @@ use crate::{
backend::render::{ backend::render::{
cursor::{CursorShape, CursorState}, cursor::{CursorShape, CursorState},
element::AsGlowRenderer, element::AsGlowRenderer,
IndicatorShader, Key, Usage, BackdropShader, IndicatorShader, Key, Usage,
}, },
shell::{ shell::{
element::{ element::{
@ -147,21 +147,36 @@ impl MoveGrabState {
}; };
let snapping_indicator = match &self.snapping_zone { let snapping_indicator = match &self.snapping_zone {
Some(t) => vec![IndicatorShader::element( Some(t) => {
renderer, let base_color = theme.palette.neutral_9;
Key::Window(Usage::SnappingIndicator, self.window.clone()), let overlay_geometry = t.overlay_geometry(non_exclusive_geometry);
t.overlay_geometry(non_exclusive_geometry), vec![
4, CosmicMappedRenderElement::from(IndicatorShader::element(
8, renderer,
0.5, Key::Window(Usage::SnappingIndicator, self.window.clone()),
output_scale.x, overlay_geometry,
[ 3,
active_window_hint.red, theme.radius_s()[0] as u8, // TODO: Fix once shaders support 4 corner radii customization
active_window_hint.green, 1.0,
active_window_hint.blue, output_scale.x,
], [
) active_window_hint.red,
.into()], active_window_hint.green,
active_window_hint.blue,
],
))
.into(),
CosmicMappedRenderElement::from(BackdropShader::element(
renderer,
Key::Window(Usage::SnappingIndicator, self.window.clone()),
t.overlay_geometry(non_exclusive_geometry),
theme.radius_s()[0], // TODO: Fix once shaders support 4 corner radii customization
0.4,
[base_color.red, base_color.green, base_color.blue],
))
.into(),
]
}
None => vec![], None => vec![],
}; };
@ -227,40 +242,48 @@ unsafe impl<T> Send for NotSend<T> {}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum SnappingZone { pub enum SnappingZone {
TopMaxim, Maximize,
TopSnap, Top,
TopLeft,
Left, Left,
Right, BottomLeft,
Bottom, Bottom,
BottomRight,
Right,
TopRight,
} }
const SNAPPING_RANGE: i32 = 12; const SNAP_RANGE: i32 = 32;
const SNAP_RANGE_TOP: i32 = 24;
impl SnappingZone { impl SnappingZone {
pub fn contains( pub fn contains(
&self, &self,
point: Point<i32, Logical>, point: Point<i32, Local>,
non_exclusive_geometry: Rectangle<i32, Logical>, output_geometry: Rectangle<i32, Local>,
output_geometry: Rectangle<i32, Logical>,
) -> bool { ) -> bool {
if !output_geometry.contains(point) { if !output_geometry.contains(point) {
return false; return false;
} }
let top_zone_32 = point.y < output_geometry.loc.y + SNAP_RANGE;
let top_zone_56 = point.y < output_geometry.loc.y + SNAP_RANGE + SNAP_RANGE_TOP;
let left_zone = point.x < output_geometry.loc.x + SNAP_RANGE;
let right_zone = point.x > output_geometry.loc.x + output_geometry.size.w - SNAP_RANGE;
let bottom_zone = point.y > output_geometry.loc.y + output_geometry.size.h - SNAP_RANGE;
let left_6th = point.x < output_geometry.loc.x + (output_geometry.size.w / 6);
let right_6th = point.x > output_geometry.loc.x + (output_geometry.size.w * 5 / 6);
let top_4th = point.y < output_geometry.loc.y + (output_geometry.size.h / 4);
let bottom_4th = point.y > output_geometry.loc.y + (output_geometry.size.h * 3 / 4);
match self { match self {
SnappingZone::TopMaxim => point.y < non_exclusive_geometry.loc.y + SNAPPING_RANGE, SnappingZone::Maximize => top_zone_32 && !left_6th && !right_6th,
SnappingZone::TopSnap => { SnappingZone::Top => top_zone_56 && !top_zone_32 && !left_6th && !right_6th,
point.y < non_exclusive_geometry.loc.y + SNAPPING_RANGE * 2 SnappingZone::TopLeft => (top_zone_56 && left_6th) || (left_zone && top_4th),
&& point.y >= non_exclusive_geometry.loc.y + SNAPPING_RANGE SnappingZone::Left => left_zone && !top_4th && !bottom_4th,
} SnappingZone::BottomLeft => (bottom_zone && left_6th) || (left_zone && bottom_4th),
SnappingZone::Bottom => { SnappingZone::Bottom => bottom_zone && !left_6th && !right_6th,
point.y SnappingZone::BottomRight => (bottom_zone && right_6th) || (right_zone && bottom_4th),
> non_exclusive_geometry.loc.y + non_exclusive_geometry.size.h - SNAPPING_RANGE SnappingZone::Right => right_zone && !top_4th && !bottom_4th,
} SnappingZone::TopRight => (top_zone_56 && right_6th) || (right_zone && top_4th),
SnappingZone::Left => point.x < non_exclusive_geometry.loc.x + SNAPPING_RANGE,
SnappingZone::Right => {
point.x
> non_exclusive_geometry.loc.x + non_exclusive_geometry.size.w - SNAPPING_RANGE
}
} }
} }
pub fn overlay_geometry( pub fn overlay_geometry(
@ -268,11 +291,23 @@ impl SnappingZone {
non_exclusive_geometry: Rectangle<i32, Logical>, non_exclusive_geometry: Rectangle<i32, Logical>,
) -> Rectangle<i32, Local> { ) -> Rectangle<i32, Local> {
match self { match self {
SnappingZone::TopMaxim => non_exclusive_geometry.as_local(), SnappingZone::Maximize => non_exclusive_geometry.as_local(),
SnappingZone::TopSnap => TiledCorners::Top.relative_geometry(non_exclusive_geometry), SnappingZone::Top => TiledCorners::Top.relative_geometry(non_exclusive_geometry),
SnappingZone::TopLeft => {
TiledCorners::TopLeft.relative_geometry(non_exclusive_geometry)
}
SnappingZone::Left => TiledCorners::Left.relative_geometry(non_exclusive_geometry), SnappingZone::Left => TiledCorners::Left.relative_geometry(non_exclusive_geometry),
SnappingZone::Right => TiledCorners::Right.relative_geometry(non_exclusive_geometry), SnappingZone::BottomLeft => {
TiledCorners::BottomLeft.relative_geometry(non_exclusive_geometry)
}
SnappingZone::Bottom => TiledCorners::Bottom.relative_geometry(non_exclusive_geometry), SnappingZone::Bottom => TiledCorners::Bottom.relative_geometry(non_exclusive_geometry),
SnappingZone::BottomRight => {
TiledCorners::BottomRight.relative_geometry(non_exclusive_geometry)
}
SnappingZone::Right => TiledCorners::Right.relative_geometry(non_exclusive_geometry),
SnappingZone::TopRight => {
TiledCorners::TopRight.relative_geometry(non_exclusive_geometry)
}
} }
} }
} }
@ -377,24 +412,27 @@ impl PointerGrab<State> for MoveGrab {
// Check for overlapping with zones // Check for overlapping with zones
if grab_state.previous == ManagedLayer::Floating { if grab_state.previous == ManagedLayer::Floating {
let non_exclusive_geometry = { let output_geometry = current_output.geometry().to_local(&current_output);
let layers = layer_map_for_output(&current_output);
layers.non_exclusive_zone()
};
let total_geometry = current_output.geometry().as_logical();
grab_state.snapping_zone = vec![ grab_state.snapping_zone = vec![
SnappingZone::TopMaxim, SnappingZone::Maximize,
SnappingZone::TopSnap, SnappingZone::Top,
SnappingZone::TopLeft,
SnappingZone::Left, SnappingZone::Left,
SnappingZone::Right, SnappingZone::BottomLeft,
SnappingZone::Bottom, SnappingZone::Bottom,
SnappingZone::BottomRight,
SnappingZone::Right,
SnappingZone::TopRight,
] ]
.iter() .iter()
.find(|&x| { .find(|&x| {
x.contains( x.contains(
handle.current_location().to_i32_floor(), handle
non_exclusive_geometry, .current_location()
total_geometry, .as_global()
.to_local(&current_output)
.to_i32_floor(),
output_geometry,
) )
}) })
.cloned(); .cloned();
@ -667,23 +705,37 @@ impl Drop for MoveGrab {
if previous == ManagedLayer::Floating { if previous == ManagedLayer::Floating {
if let Some(sz) = grab_state.snapping_zone { if let Some(sz) = grab_state.snapping_zone {
if sz == SnappingZone::TopMaxim { if sz == SnappingZone::Maximize {
state.common.shell.maximize_toggle(&window, &seat); state.common.shell.maximize_toggle(&window, &seat);
} else { } else {
let direction = match sz { let directions = match sz {
SnappingZone::TopSnap => Direction::Up, SnappingZone::Maximize => vec![],
SnappingZone::Bottom => Direction::Down, SnappingZone::Top => vec![Direction::Up],
SnappingZone::Left => Direction::Left, SnappingZone::TopLeft => {
SnappingZone::Right => Direction::Right, vec![Direction::Up, Direction::Left]
_ => Direction::Up, }
SnappingZone::Left => vec![Direction::Left],
SnappingZone::BottomLeft => {
vec![Direction::Down, Direction::Left]
}
SnappingZone::Bottom => vec![Direction::Down],
SnappingZone::BottomRight => {
vec![Direction::Down, Direction::Right]
}
SnappingZone::Right => vec![Direction::Right],
SnappingZone::TopRight => {
vec![Direction::Up, Direction::Right]
}
}; };
workspace.floating_layer.move_element( for direction in directions {
direction, workspace.floating_layer.move_element(
&seat, direction,
ManagedLayer::Floating, &seat,
theme, ManagedLayer::Floating,
&window, &theme,
); &window,
);
}
} }
} }
} }

View file

@ -899,13 +899,14 @@ impl FloatingLayout {
direction: Direction, direction: Direction,
seat: &Seat<State>, seat: &Seat<State>,
layer: ManagedLayer, layer: ManagedLayer,
theme: cosmic::Theme, theme: &cosmic::Theme,
element: &CosmicMapped, element: &CosmicMapped,
) -> MoveResult { ) -> MoveResult {
match element.handle_move(direction) { match element.handle_move(direction) {
StackMoveResult::Handled => MoveResult::Done, StackMoveResult::Handled => MoveResult::Done,
StackMoveResult::MoveOut(surface, loop_handle) => { StackMoveResult::MoveOut(surface, loop_handle) => {
let mapped: CosmicMapped = CosmicWindow::new(surface, loop_handle, theme).into(); let mapped: CosmicMapped =
CosmicWindow::new(surface, loop_handle, theme.clone()).into();
let output = seat.active_output(); let output = seat.active_output();
let pos = self.space.element_geometry(element).unwrap().loc let pos = self.space.element_geometry(element).unwrap().loc
+ match direction { + match direction {
@ -1084,7 +1085,7 @@ impl FloatingLayout {
return MoveResult::None; return MoveResult::None;
}; };
self.move_element(direction, seat, layer, theme, &focused.clone()) self.move_element(direction, seat, layer, &theme, &focused.clone())
} }
pub fn mapped(&self) -> impl Iterator<Item = &CosmicMapped> { pub fn mapped(&self) -> impl Iterator<Item = &CosmicMapped> {