Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow resize in both direcitons on Meta+Right click #860

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 93 additions & 76 deletions src/shell/layout/tiling/grabs/resize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ impl PointerTarget<State> for ResizeForkTarget {
data.common.event_loop_handle.insert_idle(move |state| {
let pointer = seat.get_pointer().unwrap();
let location = pointer.current_location();
let (left_node_idx, right_node_idx) = match orientation {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left and right? Shouldn't this be left and up?

Orientation::Horizontal => (Some((node, left_up_idx)), None),
Orientation::Vertical => (None, Some((node, left_up_idx))),
};
pointer.set_grab(
state,
ResizeForkGrab::new(
Expand All @@ -92,9 +96,8 @@ impl PointerTarget<State> for ResizeForkTarget {
location,
}),
location.as_global(),
node,
left_up_idx,
orientation,
left_node_idx,
right_node_idx,
output,
ReleaseMode::NoMouseButtons,
),
Expand Down Expand Up @@ -137,6 +140,10 @@ impl TouchTarget<State> for ResizeForkTarget {
let location = event.location;
data.common.event_loop_handle.insert_idle(move |state| {
let touch = seat.get_touch().unwrap();
let (left_node_idx, right_node_idx) = match orientation {
Orientation::Horizontal => (Some((node, left_up_idx)), None),
Orientation::Vertical => (None, Some((node, left_up_idx))),
};
touch.set_grab(
state,
ResizeForkGrab::new(
Expand All @@ -146,9 +153,8 @@ impl TouchTarget<State> for ResizeForkTarget {
location,
}),
location.as_global(),
node,
left_up_idx,
orientation,
left_node_idx,
right_node_idx,
output,
ReleaseMode::NoMouseButtons,
),
Expand Down Expand Up @@ -183,34 +189,33 @@ pub struct ResizeForkGrab {
start_data: GrabStartData,
last_loc: Point<f64, Global>,
old_tree: Option<Tree<Data>>,
accumulated_delta: f64,
node: NodeId,
accumulated_delta_left: f64,
accumulated_delta_up: f64,
left_node_idx: Option<(NodeId, usize)>,
up_node_idx: Option<(NodeId, usize)>,
output: WeakOutput,
left_up_idx: usize,
orientation: Orientation,
release: ReleaseMode,
}

impl ResizeForkGrab {
pub fn new(
start_data: GrabStartData,
pointer_loc: Point<f64, Global>,
node: NodeId,
idx: usize,
orientation: Orientation,
left_node_idx: Option<(NodeId, usize)>,
up_node_idx: Option<(NodeId, usize)>,
output: WeakOutput,
release: ReleaseMode,
) -> ResizeForkGrab {
ResizeForkGrab {
start_data,
last_loc: pointer_loc,
old_tree: None,
accumulated_delta: 0.0,
node,
output,
left_up_idx: idx,
orientation,
accumulated_delta_left: 0.0,
accumulated_delta_up: 0.0,
left_node_idx,
up_node_idx,
release,
output,
}
}
}
Expand Down Expand Up @@ -253,7 +258,8 @@ impl ResizeForkGrab {

if !equal {
*old_tree = tree.copy_clone();
self.accumulated_delta = 0.0;
self.accumulated_delta_left = 0.0;
self.accumulated_delta_up = 0.0;
} else {
*tree = old_tree.copy_clone();
}
Expand All @@ -262,66 +268,22 @@ impl ResizeForkGrab {
*x = Some(tree.copy_clone());
}
};
if tree.get(&self.node).is_ok() {
let delta = match self.orientation {
Orientation::Vertical => delta.x,
Orientation::Horizontal => delta.y,
}
.round();
self.accumulated_delta += delta;

// check that we are still alive
let mut iter = tree
.children_ids(&self.node)
.unwrap()
.skip(self.left_up_idx);
let first_elem = iter.next();
let second_elem = iter.next();
if first_elem.is_none() || second_elem.is_none() {
return true;
};

match tree.get_mut(&self.node).unwrap().data_mut() {
Data::Group {
sizes, orientation, ..
} => {
if sizes[self.left_up_idx] + sizes[self.left_up_idx + 1]
< match orientation {
Orientation::Vertical => 720,
Orientation::Horizontal => 480,
}
{
return false;
};

let old_size = sizes[self.left_up_idx];
sizes[self.left_up_idx] = (old_size
+ self.accumulated_delta.round() as i32)
.max(if self.orientation == Orientation::Vertical {
360
} else {
240
});
let diff = old_size - sizes[self.left_up_idx];
let next_size = sizes[self.left_up_idx + 1] + diff;
sizes[self.left_up_idx + 1] =
next_size.max(if self.orientation == Orientation::Vertical {
360
} else {
240
});
let next_diff = next_size - sizes[self.left_up_idx + 1];
sizes[self.left_up_idx] += next_diff;
}
_ => unreachable!(),
}
self.accumulated_delta_left += delta.x.round();
self.accumulated_delta_up += delta.y.round();

self.last_loc = location.as_global();
let blocker = TilingLayout::update_positions(&output, tree, gaps);
tiling_layer.pending_blockers.extend(blocker);
} else {
return true;
if let Some((left_node, left_idx)) = &self.left_node_idx {
perform_fork_grab_resize(tree, left_node, *left_idx, self.accumulated_delta_left);
}
if let Some((up_node, up_idx)) = &self.up_node_idx {
perform_fork_grab_resize(tree, up_node, *up_idx, self.accumulated_delta_up);
}

self.last_loc = location.as_global();
let blocker = TilingLayout::update_positions(&output, tree, gaps);
tiling_layer.pending_blockers.extend(blocker);
} else {
return true;
}
false
}
Expand Down Expand Up @@ -557,3 +519,58 @@ impl TouchGrab<State> for ResizeForkGrab {

fn unset(&mut self, _data: &mut State) {}
}

fn perform_fork_grab_resize(
tree: &mut Tree<Data>,
node: &NodeId,
left_up_idx: usize,
delta: f64,
) -> bool {
if tree.get(&node).is_ok() {
// check that we are still alive
let mut iter = tree.children_ids(node).unwrap().skip(left_up_idx);
let first_elem = iter.next();
let second_elem = iter.next();
if first_elem.is_none() || second_elem.is_none() {
return true;
};

let node = tree.get_mut(node).unwrap();

match node.data_mut() {
Data::Group {
sizes, orientation, ..
} => {
if sizes[left_up_idx] + sizes[left_up_idx + 1]
< match orientation {
Orientation::Vertical => 720,
Orientation::Horizontal => 480,
}
{
return false;
};

let old_size = sizes[left_up_idx];
sizes[left_up_idx] = (old_size + delta.round() as i32).max(
if *orientation == Orientation::Vertical {
360
} else {
240
},
);
let diff = old_size - sizes[left_up_idx];
let next_size = sizes[left_up_idx + 1] + diff;
sizes[left_up_idx + 1] = next_size.max(if *orientation == Orientation::Vertical {
360
} else {
240
});
let next_diff = next_size - sizes[left_up_idx + 1];
sizes[left_up_idx] += next_diff;
}
_ => unreachable!(),
};
}

return true;
}
104 changes: 81 additions & 23 deletions src/shell/layout/tiling/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2463,41 +2463,74 @@ impl TilingLayout {
edges
}

// Returns (left_node_idx, up_node_idx)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should just create a struct definition for the return type at this point, so we can name these fields.

pub fn resize_request(
&self,
mut node_id: NodeId,
window_node_id: NodeId,
edge: ResizeEdge,
) -> Option<(NodeId, usize, Orientation)> {
) -> (Option<(NodeId, usize)>, Option<(NodeId, usize)>) {
let tree = self.tree();
// need to find two NodeIds and associated index
// that indicate the groups and then the index that needs to be resized inside each one
// the one that's closer to the root is the "upper" one, and the one closer to the hovered window is the "lower" one

while let Some(group_id) = tree.get(&node_id).unwrap().parent().cloned() {
let orientation = tree.get(&group_id).unwrap().data().orientation();
let node_idx = tree
.children_ids(&group_id)
let mut try_lower_node_id = window_node_id;
while let Some(try_lower_group_id) = tree.get(&try_lower_node_id).unwrap().parent().cloned()
{
let orientation = tree.get(&try_lower_group_id).unwrap().data().orientation();
let lower_node_idx_in_group = tree
.children_ids(&try_lower_group_id)
.unwrap()
.position(|id| id == &node_id)
.position(|id| id == &try_lower_node_id)
.unwrap();
let total = tree.children_ids(&group_id).unwrap().count();
if orientation == Orientation::Vertical {
if node_idx > 0 && edge.contains(ResizeEdge::LEFT) {
return Some((group_id, node_idx - 1, orientation));
}
if node_idx < total - 1 && edge.contains(ResizeEdge::RIGHT) {
return Some((group_id, node_idx, orientation));
}
} else {
if node_idx > 0 && edge.contains(ResizeEdge::TOP) {
return Some((group_id, node_idx - 1, orientation));
}
if node_idx < total - 1 && edge.contains(ResizeEdge::BOTTOM) {
return Some((group_id, node_idx, orientation));
let lower_total = tree.children_ids(&try_lower_group_id).unwrap().count();

if let Some(left_up_idx) =
resize_edge_to_left_up_idx(orientation, lower_node_idx_in_group, lower_total, edge)
{
let lower_node_idx = Some((try_lower_group_id.clone(), left_up_idx)); // found a lower group id!

// need to find closest parent that
// 1. is the opposite orientation as the lower group we found
// 2. can be resized in the direction we want
let mut try_upper_node_id = try_lower_group_id;
let mut parent_left_up_node_idx = None;
while let Some(try_upper_group_id) =
tree.get(&try_upper_node_id).unwrap().parent().cloned()
{
// ensure meets condition (1)
if tree.get(&try_upper_group_id).unwrap().data().orientation() != orientation {
let upper_node_idx_in_group = tree
.children_ids(&try_upper_group_id)
.unwrap()
.position(|id| id == &try_upper_node_id)
.unwrap();
let upper_total = tree.children_ids(&try_upper_group_id).unwrap().count();

// ensure meets condition (2)
if let Some(idx) = resize_edge_to_left_up_idx(
!orientation,
upper_node_idx_in_group,
upper_total,
edge,
) {
parent_left_up_node_idx = Some((try_upper_group_id.clone(), idx)); // found an upper group id!
break;
}
}
try_upper_node_id = try_upper_group_id;
}

return match orientation {
Orientation::Horizontal => (parent_left_up_node_idx, lower_node_idx),
Orientation::Vertical => (lower_node_idx, parent_left_up_node_idx),
};
}

node_id = group_id;
try_lower_node_id = try_lower_group_id;
}

None
(None, None)
}

pub fn resize(
Expand Down Expand Up @@ -5413,3 +5446,28 @@ fn scale_to_center<C>(
)
}
}

fn resize_edge_to_left_up_idx(
orientation: Orientation,
node_idx: usize,
total: usize,
edge: ResizeEdge,
) -> Option<usize> {
if orientation == Orientation::Vertical {
if node_idx > 0 && edge.contains(ResizeEdge::LEFT) {
return Some(node_idx - 1);
}
if node_idx < total - 1 && edge.contains(ResizeEdge::RIGHT) {
return Some(node_idx);
}
} else {
if node_idx > 0 && edge.contains(ResizeEdge::TOP) {
return Some(node_idx - 1);
}
if node_idx < total - 1 && edge.contains(ResizeEdge::BOTTOM) {
return Some(node_idx);
}
}

None
}
Loading