tree: implement tile dragging
This commit is contained in:
parent
83fd9f211e
commit
132986df2a
17 changed files with 925 additions and 52 deletions
|
|
@ -17,8 +17,9 @@ use {
|
|||
state::State,
|
||||
text::TextTexture,
|
||||
tree::{
|
||||
walker::NodeVisitor, ContainingNode, Direction, FindTreeResult, FindTreeUsecase,
|
||||
FoundNode, Node, NodeId, ToplevelData, ToplevelNode, ToplevelNodeBase, WorkspaceNode,
|
||||
default_tile_drag_bounds, walker::NodeVisitor, ContainingNode, Direction,
|
||||
FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, TddType, TileDragDestination,
|
||||
ToplevelData, ToplevelNode, ToplevelNodeBase, WorkspaceNode,
|
||||
},
|
||||
utils::{
|
||||
asyncevent::AsyncEvent,
|
||||
|
|
@ -53,6 +54,15 @@ pub enum ContainerSplit {
|
|||
Vertical,
|
||||
}
|
||||
|
||||
impl ContainerSplit {
|
||||
pub fn other(self) -> Self {
|
||||
match self {
|
||||
ContainerSplit::Horizontal => ContainerSplit::Vertical,
|
||||
ContainerSplit::Vertical => ContainerSplit::Horizontal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Axis> for ContainerSplit {
|
||||
fn from(a: Axis) -> Self {
|
||||
match a {
|
||||
|
|
@ -547,6 +557,7 @@ impl ContainerNode {
|
|||
|
||||
fn pointer_move(
|
||||
self: &Rc<Self>,
|
||||
seat: &Rc<WlSeatGlobal>,
|
||||
id: CursorType,
|
||||
cursor: &CursorUser,
|
||||
x: Fixed,
|
||||
|
|
@ -574,7 +585,16 @@ impl ContainerNode {
|
|||
if let Some(op) = &seat_state.op {
|
||||
match op.kind {
|
||||
SeatOpKind::Move => {
|
||||
// todo
|
||||
if let CursorType::Seat(_) = id {
|
||||
const DRAG_DIST: i32 = 10;
|
||||
let dx = x - op.x;
|
||||
let dy = y - op.y;
|
||||
if dx * dx + dy * dy > DRAG_DIST * DRAG_DIST {
|
||||
let node = op.child.node.clone();
|
||||
drop(seats);
|
||||
seat.start_tile_drag(&node);
|
||||
}
|
||||
}
|
||||
}
|
||||
SeatOpKind::Resize {
|
||||
dist_left,
|
||||
|
|
@ -1233,20 +1253,220 @@ impl ContainerNode {
|
|||
seat.set_tl_floating(child.node.clone(), true);
|
||||
return;
|
||||
}
|
||||
seat_data.op = Some(SeatOp { child, kind })
|
||||
seat_data.op = Some(SeatOp {
|
||||
child,
|
||||
kind,
|
||||
x: seat_data.x,
|
||||
y: seat_data.y,
|
||||
})
|
||||
} else if !pressed {
|
||||
let op = seat_data.op.take().unwrap();
|
||||
seat_data.op = None;
|
||||
drop(seat_datas);
|
||||
if op.kind == SeatOpKind::Move {
|
||||
// todo
|
||||
}
|
||||
}
|
||||
|
||||
fn tile_drag_destination_mono_titles(
|
||||
self: &Rc<Self>,
|
||||
source: NodeId,
|
||||
abs_bounds: Rect,
|
||||
abs_x: i32,
|
||||
abs_y: i32,
|
||||
) -> Option<TileDragDestination> {
|
||||
let mut prev_is_source = false;
|
||||
let mut prev_center = 0;
|
||||
for child in self.children.iter() {
|
||||
if child.node.node_id() == source {
|
||||
prev_is_source = true;
|
||||
continue;
|
||||
}
|
||||
let rect = child.title_rect.get();
|
||||
let center = (rect.x1() + rect.x2()) / 2;
|
||||
if !prev_is_source {
|
||||
let rect = Rect::new(prev_center, 0, center, rect.height())?
|
||||
.move_(self.abs_x1.get(), self.abs_y1.get())
|
||||
.intersect(abs_bounds);
|
||||
if rect.contains(abs_x, abs_y) {
|
||||
return Some(TileDragDestination {
|
||||
highlight: rect,
|
||||
ty: TddType::Insert {
|
||||
container: self.clone(),
|
||||
neighbor: child.node.clone(),
|
||||
before: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
prev_center = center;
|
||||
prev_is_source = false;
|
||||
}
|
||||
if prev_is_source {
|
||||
return None;
|
||||
}
|
||||
let last = self.children.last()?;
|
||||
let rect = Rect::new(
|
||||
prev_center,
|
||||
0,
|
||||
self.width.get(),
|
||||
self.state.theme.sizes.title_height.get(),
|
||||
)?
|
||||
.move_(self.abs_x1.get(), self.abs_y1.get())
|
||||
.intersect(abs_bounds);
|
||||
if rect.contains(abs_x, abs_y) {
|
||||
return Some(TileDragDestination {
|
||||
highlight: rect,
|
||||
ty: TddType::Insert {
|
||||
container: self.clone(),
|
||||
neighbor: last.node.clone(),
|
||||
before: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn tile_drag_destination_mono(
|
||||
self: &Rc<Self>,
|
||||
mc: &ContainerChild,
|
||||
source: NodeId,
|
||||
abs_bounds: Rect,
|
||||
abs_x: i32,
|
||||
abs_y: i32,
|
||||
) -> Option<TileDragDestination> {
|
||||
let th = self.state.theme.sizes.title_height.get();
|
||||
if abs_y < self.abs_y1.get() + th {
|
||||
return self.tile_drag_destination_mono_titles(source, abs_bounds, abs_x, abs_y);
|
||||
}
|
||||
let body = self.mono_body.get();
|
||||
let bounds = body
|
||||
.move_(self.abs_x1.get(), self.abs_y1.get())
|
||||
.intersect(abs_bounds);
|
||||
return mc
|
||||
.node
|
||||
.clone()
|
||||
.tl_tile_drag_destination(source, None, bounds, abs_x, abs_y);
|
||||
}
|
||||
|
||||
pub fn tile_drag_destination(
|
||||
self: &Rc<Self>,
|
||||
source: NodeId,
|
||||
abs_bounds: Rect,
|
||||
abs_x: i32,
|
||||
abs_y: i32,
|
||||
) -> Option<TileDragDestination> {
|
||||
if source == self.node_id() {
|
||||
return None;
|
||||
}
|
||||
if let Some(mc) = self.mono_child.get() {
|
||||
return self.tile_drag_destination_mono(&mc, source, abs_bounds, abs_x, abs_y);
|
||||
}
|
||||
let mut prev_is_source = false;
|
||||
let mut prev_border_start = 0;
|
||||
let split = self.split.get();
|
||||
for child in self.children.iter() {
|
||||
if child.node.node_id() == source {
|
||||
prev_is_source = true;
|
||||
continue;
|
||||
}
|
||||
let start_drag_bounds = child.node.tl_tile_drag_bounds(split, true);
|
||||
let end_drag_bounds = child.node.tl_tile_drag_bounds(split, false);
|
||||
let body = child.body.get();
|
||||
let main_body_rect = {
|
||||
match split {
|
||||
ContainerSplit::Horizontal => Rect::new(
|
||||
body.x1() + start_drag_bounds,
|
||||
body.y1(),
|
||||
body.x2() - end_drag_bounds,
|
||||
body.y2(),
|
||||
)?,
|
||||
ContainerSplit::Vertical => Rect::new(
|
||||
body.x1(),
|
||||
body.y1() + start_drag_bounds,
|
||||
body.x2(),
|
||||
body.y2() - end_drag_bounds,
|
||||
)?,
|
||||
}
|
||||
.move_(self.abs_x1.get(), self.abs_y1.get())
|
||||
.intersect(abs_bounds)
|
||||
};
|
||||
if main_body_rect.contains(abs_x, abs_y) {
|
||||
return child.node.clone().tl_tile_drag_destination(
|
||||
source,
|
||||
Some(split),
|
||||
main_body_rect,
|
||||
abs_x,
|
||||
abs_y,
|
||||
);
|
||||
}
|
||||
if !prev_is_source {
|
||||
let left_border_rect = {
|
||||
match split {
|
||||
ContainerSplit::Horizontal => Rect::new(
|
||||
prev_border_start,
|
||||
body.y1(),
|
||||
body.x1() + start_drag_bounds,
|
||||
body.y2(),
|
||||
)?,
|
||||
ContainerSplit::Vertical => Rect::new(
|
||||
body.x1(),
|
||||
prev_border_start,
|
||||
body.x2(),
|
||||
body.y1() + start_drag_bounds,
|
||||
)?,
|
||||
}
|
||||
.move_(self.abs_x1.get(), self.abs_y1.get())
|
||||
.intersect(abs_bounds)
|
||||
};
|
||||
if left_border_rect.contains(abs_x, abs_y) {
|
||||
return Some(TileDragDestination {
|
||||
highlight: left_border_rect,
|
||||
ty: TddType::Insert {
|
||||
container: self.clone(),
|
||||
neighbor: child.node.clone(),
|
||||
before: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
prev_is_source = false;
|
||||
prev_border_start = match split {
|
||||
ContainerSplit::Horizontal => body.x2() - end_drag_bounds,
|
||||
ContainerSplit::Vertical => body.y2() - end_drag_bounds,
|
||||
};
|
||||
}
|
||||
if prev_is_source {
|
||||
return None;
|
||||
}
|
||||
let last = self.children.last()?;
|
||||
let body = last.body.get();
|
||||
let right_border_rect = match split {
|
||||
ContainerSplit::Horizontal => {
|
||||
Rect::new(prev_border_start, body.y1(), body.x2(), body.y2())?
|
||||
}
|
||||
ContainerSplit::Vertical => {
|
||||
Rect::new(body.x1(), prev_border_start, body.x2(), body.y2())?
|
||||
}
|
||||
}
|
||||
.move_(self.abs_x1.get(), self.abs_y1.get())
|
||||
.intersect(abs_bounds);
|
||||
if right_border_rect.contains(abs_x, abs_y) {
|
||||
return Some(TileDragDestination {
|
||||
highlight: right_border_rect,
|
||||
ty: TddType::Insert {
|
||||
container: self.clone(),
|
||||
neighbor: last.node.clone(),
|
||||
before: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
struct SeatOp {
|
||||
child: NodeRef<ContainerChild>,
|
||||
kind: SeatOpKind,
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
|
|
@ -1452,6 +1672,7 @@ impl Node for ContainerNode {
|
|||
fn node_on_pointer_enter(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, x: Fixed, y: Fixed) {
|
||||
// log::info!("node_on_pointer_enter");
|
||||
self.pointer_move(
|
||||
seat,
|
||||
CursorType::Seat(seat.id()),
|
||||
seat.pointer_cursor(),
|
||||
x,
|
||||
|
|
@ -1460,6 +1681,14 @@ impl Node for ContainerNode {
|
|||
);
|
||||
}
|
||||
|
||||
fn node_on_leave(&self, seat: &WlSeatGlobal) {
|
||||
let mut seats = self.cursors.borrow_mut();
|
||||
let id = CursorType::Seat(seat.id());
|
||||
if let Some(seat_state) = seats.get_mut(&id) {
|
||||
seat_state.op = None;
|
||||
}
|
||||
}
|
||||
|
||||
fn node_on_pointer_unfocus(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
// log::info!("unfocus");
|
||||
let mut seats = self.cursors.borrow_mut();
|
||||
|
|
@ -1482,6 +1711,7 @@ impl Node for ContainerNode {
|
|||
fn node_on_pointer_motion(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, x: Fixed, y: Fixed) {
|
||||
// log::info!("node_on_pointer_motion");
|
||||
self.pointer_move(
|
||||
seat,
|
||||
CursorType::Seat(seat.id()),
|
||||
seat.pointer_cursor(),
|
||||
x,
|
||||
|
|
@ -1503,7 +1733,14 @@ impl Node for ContainerNode {
|
|||
y: Fixed,
|
||||
) {
|
||||
tool.cursor().set_known(KnownCursor::Default);
|
||||
self.pointer_move(CursorType::TabletTool(tool.id), tool.cursor(), x, y, true);
|
||||
self.pointer_move(
|
||||
tool.seat(),
|
||||
CursorType::TabletTool(tool.id),
|
||||
tool.cursor(),
|
||||
x,
|
||||
y,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
fn node_on_tablet_tool_apply_changes(
|
||||
|
|
@ -1515,7 +1752,7 @@ impl Node for ContainerNode {
|
|||
y: Fixed,
|
||||
) {
|
||||
let id = CursorType::TabletTool(tool.id);
|
||||
self.pointer_move(id, tool.cursor(), x, y, false);
|
||||
self.pointer_move(tool.seat(), id, tool.cursor(), x, y, false);
|
||||
if let Some(changes) = changes {
|
||||
if let Some(pressed) = changes.down {
|
||||
self.button(id, tool.seat(), time_usec, pressed, BTN_LEFT);
|
||||
|
|
@ -1914,6 +2151,31 @@ impl ToplevelNodeBase for ContainerNode {
|
|||
fn tl_admits_children(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn tl_tile_drag_destination(
|
||||
self: Rc<Self>,
|
||||
source: NodeId,
|
||||
_split: Option<ContainerSplit>,
|
||||
abs_bounds: Rect,
|
||||
abs_x: i32,
|
||||
abs_y: i32,
|
||||
) -> Option<TileDragDestination> {
|
||||
self.tile_drag_destination(source, abs_bounds, abs_x, abs_y)
|
||||
}
|
||||
|
||||
fn tl_tile_drag_bounds(&self, split: ContainerSplit, start: bool) -> i32 {
|
||||
if split != self.split.get() {
|
||||
return default_tile_drag_bounds(self, split);
|
||||
}
|
||||
let child = match start {
|
||||
true => self.children.first(),
|
||||
false => self.children.last(),
|
||||
};
|
||||
let Some(child) = child else {
|
||||
return 0;
|
||||
};
|
||||
child.node.tl_tile_drag_bounds(split, start) / 2
|
||||
}
|
||||
}
|
||||
|
||||
fn direction_to_split(dir: Direction) -> (ContainerSplit, bool) {
|
||||
|
|
@ -1925,3 +2187,118 @@ fn direction_to_split(dir: Direction) -> (ContainerSplit, bool) {
|
|||
Direction::Unspecified => (ContainerSplit::Horizontal, true),
|
||||
}
|
||||
}
|
||||
|
||||
fn tile_drag_destination_in_mono(
|
||||
tl: Rc<dyn ToplevelNode>,
|
||||
abs_bounds: Rect,
|
||||
abs_x: i32,
|
||||
abs_y: i32,
|
||||
) -> TileDragDestination {
|
||||
let mut x1 = abs_bounds.x1();
|
||||
let mut x2 = abs_bounds.x2();
|
||||
let mut y1 = abs_bounds.y1();
|
||||
let mut y2 = abs_bounds.y2();
|
||||
let dx = (x2 - x1) / 3;
|
||||
let dy = (y2 - y1) / 3;
|
||||
let mut split_before = true;
|
||||
let mut split = ContainerSplit::Horizontal;
|
||||
if abs_x < x1 + dx {
|
||||
x2 = x1 + dx;
|
||||
} else if abs_x > x2 - dx {
|
||||
split_before = false;
|
||||
x1 = x2 - dx;
|
||||
} else {
|
||||
split = ContainerSplit::Vertical;
|
||||
x1 += dx;
|
||||
x2 -= dx;
|
||||
if abs_y < y1 + dy {
|
||||
y2 = y1 + dy;
|
||||
} else if abs_y > y2 - dy {
|
||||
split_before = false;
|
||||
y1 = y2 - dy;
|
||||
} else {
|
||||
let rect = Rect::new_unchecked(x1, y1 + dy, x2, y2 - dy);
|
||||
return TileDragDestination {
|
||||
highlight: rect,
|
||||
ty: TddType::Replace(tl),
|
||||
};
|
||||
}
|
||||
}
|
||||
let rect = Rect::new_unchecked(x1, y1, x2, y2);
|
||||
TileDragDestination {
|
||||
highlight: rect,
|
||||
ty: TddType::Split {
|
||||
node: tl,
|
||||
split,
|
||||
before: split_before,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn tile_drag_destination_in_split(
|
||||
tl: Rc<dyn ToplevelNode>,
|
||||
split: ContainerSplit,
|
||||
abs_bounds: Rect,
|
||||
mut abs_x: i32,
|
||||
mut abs_y: i32,
|
||||
) -> TileDragDestination {
|
||||
let mut x1 = abs_bounds.x1();
|
||||
let mut x2 = abs_bounds.x2();
|
||||
let mut y1 = abs_bounds.y1();
|
||||
let mut y2 = abs_bounds.y2();
|
||||
macro_rules! swap {
|
||||
() => {
|
||||
if split == ContainerSplit::Horizontal {
|
||||
mem::swap(&mut x1, &mut y1);
|
||||
mem::swap(&mut x2, &mut y2);
|
||||
mem::swap(&mut abs_x, &mut abs_y);
|
||||
}
|
||||
};
|
||||
}
|
||||
swap!();
|
||||
let mut split_before = false;
|
||||
let mut split_after = false;
|
||||
let dx = (x2 - x1) / 3;
|
||||
if abs_x < x1 + dx {
|
||||
split_before = true;
|
||||
x2 = x1 + dx;
|
||||
} else if abs_x < x2 - dx {
|
||||
x1 += dx;
|
||||
x2 -= dx;
|
||||
} else {
|
||||
split_after = true;
|
||||
x1 = x2 - dx;
|
||||
}
|
||||
swap!();
|
||||
let rect = Rect::new(x1, y1, x2, y2).unwrap();
|
||||
let ty = if split_before || split_after {
|
||||
TddType::Split {
|
||||
node: tl,
|
||||
split: split.other(),
|
||||
before: split_before,
|
||||
}
|
||||
} else {
|
||||
TddType::Replace(tl)
|
||||
};
|
||||
TileDragDestination {
|
||||
highlight: rect,
|
||||
ty,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_tile_drag_destination(
|
||||
tl: Rc<dyn ToplevelNode>,
|
||||
source: NodeId,
|
||||
split: Option<ContainerSplit>,
|
||||
abs_bounds: Rect,
|
||||
abs_x: i32,
|
||||
abs_y: i32,
|
||||
) -> Option<TileDragDestination> {
|
||||
if tl.node_id() == source {
|
||||
return None;
|
||||
}
|
||||
Some(match split {
|
||||
None => tile_drag_destination_in_mono(tl, abs_bounds, abs_x, abs_y),
|
||||
Some(s) => tile_drag_destination_in_split(tl, s, abs_bounds, abs_x, abs_y),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use {
|
|||
state::State,
|
||||
tree::{
|
||||
walker::NodeVisitor, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId,
|
||||
OutputNode, StackedNode,
|
||||
OutputNode, StackedNode, TileDragDestination,
|
||||
},
|
||||
utils::{copyhashmap::CopyHashMap, linkedlist::LinkedList},
|
||||
},
|
||||
|
|
@ -83,6 +83,21 @@ impl DisplayNode {
|
|||
state.damage(self.extents.get());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tile_drag_destination(
|
||||
&self,
|
||||
source: NodeId,
|
||||
x: i32,
|
||||
y: i32,
|
||||
) -> Option<TileDragDestination> {
|
||||
for output in self.outputs.lock().values() {
|
||||
let pos = output.node_absolute_position();
|
||||
if pos.contains(x, y) {
|
||||
return output.tile_drag_destination(source, x, y);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for DisplayNode {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use {
|
|||
text::TextTexture,
|
||||
tree::{
|
||||
walker::NodeVisitor, ContainingNode, Direction, FindTreeResult, FindTreeUsecase,
|
||||
FoundNode, Node, NodeId, StackedNode, ToplevelNode, WorkspaceNode,
|
||||
FoundNode, Node, NodeId, StackedNode, TileDragDestination, ToplevelNode, WorkspaceNode,
|
||||
},
|
||||
utils::{
|
||||
asyncevent::AsyncEvent, clonecell::CloneCell, double_click_state::DoubleClickState,
|
||||
|
|
@ -528,6 +528,26 @@ impl FloatNode {
|
|||
self.set_workspace(&ws);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tile_drag_destination(
|
||||
self: &Rc<Self>,
|
||||
source: NodeId,
|
||||
abs_x: i32,
|
||||
abs_y: i32,
|
||||
) -> Option<TileDragDestination> {
|
||||
let child = self.child.get()?;
|
||||
let theme = &self.state.theme.sizes;
|
||||
let bw = theme.border_width.get();
|
||||
let th = theme.title_height.get();
|
||||
let pos = self.position.get();
|
||||
let body = Rect::new(
|
||||
pos.x1() + bw,
|
||||
pos.y1() + bw + th + 1,
|
||||
pos.x2() - bw,
|
||||
pos.y2() - bw,
|
||||
)?;
|
||||
child.tl_tile_drag_destination(source, None, body, abs_x, abs_y)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for FloatNode {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ use {
|
|||
text::TextTexture,
|
||||
tree::{
|
||||
walker::NodeVisitor, Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node,
|
||||
NodeId, StackedNode, WorkspaceNode,
|
||||
NodeId, StackedNode, TddType, TileDragDestination, WorkspaceNode,
|
||||
},
|
||||
utils::{
|
||||
asyncevent::AsyncEvent, clonecell::CloneCell, copyhashmap::CopyHashMap,
|
||||
|
|
@ -522,6 +522,10 @@ impl OutputNode {
|
|||
return ws;
|
||||
}
|
||||
}
|
||||
self.generate_workspace()
|
||||
}
|
||||
|
||||
pub fn generate_workspace(self: &Rc<Self>) -> Rc<WorkspaceNode> {
|
||||
let name = 'name: {
|
||||
for i in 1.. {
|
||||
let name = i.to_string();
|
||||
|
|
@ -937,6 +941,85 @@ impl OutputNode {
|
|||
};
|
||||
self.global.connector.connector.set_tearing_enabled(enabled);
|
||||
}
|
||||
|
||||
pub fn tile_drag_destination(
|
||||
self: &Rc<Self>,
|
||||
source: NodeId,
|
||||
x_abs: i32,
|
||||
y_abs: i32,
|
||||
) -> Option<TileDragDestination> {
|
||||
if self.state.lock.locked.get() {
|
||||
return None;
|
||||
}
|
||||
for stacked in self.state.root.stacked.rev_iter() {
|
||||
let Some(float) = stacked.deref().clone().node_into_float() else {
|
||||
continue;
|
||||
};
|
||||
if !float.node_visible() {
|
||||
continue;
|
||||
}
|
||||
let pos = float.node_absolute_position();
|
||||
if !pos.contains(x_abs, y_abs) {
|
||||
continue;
|
||||
}
|
||||
return float.tile_drag_destination(source, x_abs, y_abs);
|
||||
}
|
||||
let rect = self.non_exclusive_rect.get();
|
||||
if !rect.contains(x_abs, y_abs) {
|
||||
return None;
|
||||
}
|
||||
let Some(ws) = self.workspace.get() else {
|
||||
return Some(TileDragDestination {
|
||||
highlight: rect,
|
||||
ty: TddType::NewWorkspace {
|
||||
output: self.clone(),
|
||||
},
|
||||
});
|
||||
};
|
||||
if ws.fullscreen.is_some() {
|
||||
return None;
|
||||
}
|
||||
let th = self.state.theme.sizes.title_height.get();
|
||||
if y_abs < rect.y1() + th + 1 {
|
||||
let rd = &*self.render_data.borrow();
|
||||
let (x, _) = rect.translate(x_abs, y_abs);
|
||||
let mut last_x2 = 0;
|
||||
for t in &rd.titles {
|
||||
if x < t.x2 {
|
||||
return Some(TileDragDestination {
|
||||
highlight: Rect::new_sized(rect.x1() + t.x1, rect.y1(), t.x2 - t.x1, th)?,
|
||||
ty: TddType::MoveToWorkspace {
|
||||
workspace: t.ws.clone(),
|
||||
},
|
||||
});
|
||||
}
|
||||
last_x2 = t.x2;
|
||||
}
|
||||
return Some(TileDragDestination {
|
||||
highlight: Rect::new_sized(
|
||||
rect.x1() + last_x2,
|
||||
rect.y1(),
|
||||
rect.x2() - last_x2,
|
||||
th,
|
||||
)?,
|
||||
ty: TddType::MoveToNewWorkspace {
|
||||
output: self.clone(),
|
||||
},
|
||||
});
|
||||
}
|
||||
let thp1 = self.state.theme.sizes.title_height.get() + 1;
|
||||
let rect = Rect::new(rect.x1(), rect.y1() + thp1, rect.x2(), rect.y2())?;
|
||||
if !rect.contains(x_abs, y_abs) {
|
||||
return None;
|
||||
}
|
||||
let Some(c) = ws.container.get() else {
|
||||
return Some(TileDragDestination {
|
||||
highlight: rect,
|
||||
ty: TddType::NewContainer { workspace: ws },
|
||||
});
|
||||
};
|
||||
c.tile_drag_destination(source, rect, x_abs, y_abs)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OutputTitle {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ use {
|
|||
state::State,
|
||||
text::TextTexture,
|
||||
tree::{
|
||||
Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeVisitor,
|
||||
default_tile_drag_destination, ContainerSplit, Direction, FindTreeResult,
|
||||
FindTreeUsecase, FoundNode, Node, NodeId, NodeVisitor, TileDragDestination,
|
||||
ToplevelData, ToplevelNode, ToplevelNodeBase,
|
||||
},
|
||||
utils::{
|
||||
|
|
@ -62,6 +63,17 @@ impl PlaceholderNode {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn new_empty(state: &Rc<State>) -> Self {
|
||||
Self {
|
||||
id: state.node_ids.next(),
|
||||
toplevel: ToplevelData::new(state, String::new(), None),
|
||||
destroyed: Default::default(),
|
||||
update_textures_scheduled: Default::default(),
|
||||
state: state.clone(),
|
||||
textures: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_destroyed(&self) -> bool {
|
||||
self.destroyed.get()
|
||||
}
|
||||
|
|
@ -222,4 +234,15 @@ impl ToplevelNodeBase for PlaceholderNode {
|
|||
fn tl_admits_children(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn tl_tile_drag_destination(
|
||||
self: Rc<Self>,
|
||||
source: NodeId,
|
||||
split: Option<ContainerSplit>,
|
||||
abs_bounds: Rect,
|
||||
x: i32,
|
||||
y: i32,
|
||||
) -> Option<TileDragDestination> {
|
||||
default_tile_drag_destination(self, source, split, abs_bounds, x, y)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,10 @@ use {
|
|||
},
|
||||
rect::Rect,
|
||||
state::State,
|
||||
tree::{ContainingNode, Direction, Node, OutputNode, PlaceholderNode, WorkspaceNode},
|
||||
tree::{
|
||||
ContainerNode, ContainerSplit, ContainingNode, Direction, Node, NodeId, OutputNode,
|
||||
PlaceholderNode, WorkspaceNode,
|
||||
},
|
||||
utils::{
|
||||
clonecell::CloneCell,
|
||||
copyhashmap::CopyHashMap,
|
||||
|
|
@ -202,6 +205,20 @@ pub trait ToplevelNodeBase: Node {
|
|||
}
|
||||
|
||||
fn tl_admits_children(&self) -> bool;
|
||||
|
||||
fn tl_tile_drag_destination(
|
||||
self: Rc<Self>,
|
||||
source: NodeId,
|
||||
split: Option<ContainerSplit>,
|
||||
abs_bounds: Rect,
|
||||
abs_x: i32,
|
||||
abs_y: i32,
|
||||
) -> Option<TileDragDestination>;
|
||||
|
||||
fn tl_tile_drag_bounds(&self, split: ContainerSplit, start: bool) -> i32 {
|
||||
let _ = start;
|
||||
default_tile_drag_bounds(self, split)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FullscreenedData {
|
||||
|
|
@ -532,3 +549,42 @@ impl ToplevelData {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TileDragDestination {
|
||||
pub highlight: Rect,
|
||||
pub ty: TddType,
|
||||
}
|
||||
|
||||
pub enum TddType {
|
||||
Replace(Rc<dyn ToplevelNode>),
|
||||
Split {
|
||||
node: Rc<dyn ToplevelNode>,
|
||||
split: ContainerSplit,
|
||||
before: bool,
|
||||
},
|
||||
Insert {
|
||||
container: Rc<ContainerNode>,
|
||||
neighbor: Rc<dyn ToplevelNode>,
|
||||
before: bool,
|
||||
},
|
||||
NewWorkspace {
|
||||
output: Rc<OutputNode>,
|
||||
},
|
||||
NewContainer {
|
||||
workspace: Rc<WorkspaceNode>,
|
||||
},
|
||||
MoveToWorkspace {
|
||||
workspace: Rc<WorkspaceNode>,
|
||||
},
|
||||
MoveToNewWorkspace {
|
||||
output: Rc<OutputNode>,
|
||||
},
|
||||
}
|
||||
|
||||
pub fn default_tile_drag_bounds<T: ToplevelNodeBase + ?Sized>(t: &T, split: ContainerSplit) -> i32 {
|
||||
const FACTOR: i32 = 5;
|
||||
match split {
|
||||
ContainerSplit::Horizontal => t.node_absolute_position().width() / FACTOR,
|
||||
ContainerSplit::Vertical => t.node_absolute_position().height() / FACTOR,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue