tile: Add to support resize tile from left and top side. (#756)

This commit is contained in:
Jason Lee 2025-03-31 19:35:02 +08:00 committed by GitHub
parent 9d3b673c96
commit c310afadc6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -58,8 +58,18 @@ impl Render for DragMoving {
}
}
#[derive(Clone, PartialEq)]
enum ResizeSide {
Left,
Right,
Top,
Bottom,
BottomRight,
}
#[derive(Clone)]
pub struct DragResizing(EntityId);
impl Render for DragResizing {
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
Empty
@ -68,18 +78,11 @@ impl Render for DragResizing {
#[derive(Clone)]
struct ResizeDrag {
axis: ResizeAxis,
side: ResizeSide,
last_position: Point<Pixels>,
last_bounds: Bounds<Pixels>,
}
#[derive(Clone, PartialEq)]
enum ResizeAxis {
Horizontal,
Vertical,
Both,
}
/// TileItem is a moveable and resizable panel that can be added to a Tiles view.
#[derive(Clone)]
pub struct TileItem {
@ -296,42 +299,49 @@ impl Tiles {
}
}
fn resize_width(&mut self, new_width: Pixels, _: &mut Window, cx: &mut Context<'_, Self>) {
fn resize(
&mut self,
new_x: Option<Pixels>,
new_y: Option<Pixels>,
new_width: Option<Pixels>,
new_height: Option<Pixels>,
_: &mut Window,
cx: &mut Context<'_, Self>,
) {
if let Some(index) = self.resizing_index {
if let Some(item) = self.panels.get_mut(index) {
let previous_bounds = item.bounds;
let final_width = round_to_nearest_ten(new_width, cx);
let final_x = if let Some(x) = new_x {
round_to_nearest_ten(x, cx)
} else {
previous_bounds.origin.x
};
let final_y = if let Some(y) = new_y {
round_to_nearest_ten(y, cx)
} else {
previous_bounds.origin.y
};
let final_width = if let Some(width) = new_width {
round_to_nearest_ten(width, cx)
} else {
previous_bounds.size.width
};
// Only push to history if width has changed
if final_width != item.bounds.size.width {
let final_height = if let Some(height) = new_height {
round_to_nearest_ten(height, cx)
} else {
previous_bounds.size.height
};
// Only push to history if size has changed
if final_width != item.bounds.size.width
|| final_height != item.bounds.size.height
|| final_x != item.bounds.origin.x
|| final_y != item.bounds.origin.y
{
item.bounds.origin.x = final_x;
item.bounds.origin.y = final_y;
item.bounds.size.width = final_width;
// Only push if not during history operations
if !self.history.ignore {
self.history.push(TileChange {
tile_id: item.panel.view().entity_id(),
old_bounds: Some(previous_bounds),
new_bounds: Some(item.bounds),
old_order: None,
new_order: None,
version: 0,
});
}
}
cx.notify();
}
}
}
fn resize_height(&mut self, new_height: Pixels, _: &mut Window, cx: &mut Context<'_, Self>) {
if let Some(index) = self.resizing_index {
if let Some(item) = self.panels.get_mut(index) {
let previous_bounds = item.bounds;
let final_height = round_to_nearest_ten(new_height, cx);
// Only push to history if height has changed
if final_height != item.bounds.size.height {
item.bounds.size.height = final_height;
// Only push if not during history operations
@ -539,14 +549,14 @@ impl Tiles {
let mut elements = Vec::new();
// Right resize handle
// Left resize handle
elements.push(if !is_occluded(&right_handle_bounds) {
div()
.id("right-resize-handle")
.id("left-resize-handle")
.cursor_ew_resize()
.absolute()
.top_0()
.right(handle_offset)
.left(handle_offset)
.w(HANDLE_SIZE)
.h(panel_bounds.size.height)
.on_mouse_down(
@ -555,7 +565,7 @@ impl Tiles {
move |this, event: &MouseDownEvent, window, cx| {
let last_position = event.position;
let drag_data = ResizeDrag {
axis: ResizeAxis::Horizontal,
side: ResizeSide::Left,
last_position,
last_bounds: panel_bounds,
};
@ -578,16 +588,141 @@ impl Tiles {
return;
}
if let Some(ref drag_data) = this.resizing_drag_data {
if drag_data.axis != ResizeAxis::Horizontal {
return;
}
let pos = e.event.position;
let delta = pos.x - drag_data.last_position.x;
let new_width = (drag_data.last_bounds.size.width + delta)
.max(MINIMUM_SIZE.width);
this.resize_width(new_width, window, cx);
let Some(ref drag_data) = this.resizing_drag_data else {
return;
};
if drag_data.side != ResizeSide::Left {
return;
}
let pos = e.event.position;
let delta = drag_data.last_position.x - pos.x;
let new_x = (drag_data.last_bounds.origin.x - delta).max(px(0.0));
let size_delta = drag_data.last_bounds.origin.x - new_x;
let new_width = (drag_data.last_bounds.size.width + size_delta)
.max(MINIMUM_SIZE.width);
this.resize(Some(new_x), None, Some(new_width), None, window, cx);
}
},
))
.into_any_element()
} else {
div().into_any_element()
});
// Right resize handle
elements.push(if !is_occluded(&right_handle_bounds) {
div()
.id("right-resize-handle")
.cursor_ew_resize()
.absolute()
.top_0()
.right(handle_offset)
.w(HANDLE_SIZE)
.h(panel_bounds.size.height)
.on_mouse_down(
MouseButton::Left,
cx.listener({
move |this, event: &MouseDownEvent, window, cx| {
let last_position = event.position;
let drag_data = ResizeDrag {
side: ResizeSide::Right,
last_position,
last_bounds: panel_bounds,
};
this.update_resizing_drag(drag_data, window, cx);
if let Some((_, new_ix)) = this.bring_to_front(this.resizing_index, cx)
{
this.resizing_index = Some(new_ix);
}
}
}),
)
.on_drag(DragResizing(entity_id), |drag, _, _, cx| {
cx.stop_propagation();
cx.new(|_| drag.clone())
})
.on_drag_move(cx.listener(
move |this, e: &DragMoveEvent<DragResizing>, window, cx| match e.drag(cx) {
DragResizing(id) => {
if *id != entity_id {
return;
}
let Some(ref drag_data) = this.resizing_drag_data else {
return;
};
if drag_data.side != ResizeSide::Right {
return;
}
let pos = e.event.position;
let delta = pos.x - drag_data.last_position.x;
let new_width =
(drag_data.last_bounds.size.width + delta).max(MINIMUM_SIZE.width);
this.resize(None, None, Some(new_width), None, window, cx);
}
},
))
.into_any_element()
} else {
div().into_any_element()
});
// Top resize handle
elements.push(if !is_occluded(&bottom_handle_bounds) {
div()
.id("top-resize-handle")
.cursor_ns_resize()
.absolute()
.left(px(0.0))
.top(handle_offset)
.w(panel_bounds.size.width)
.h(HANDLE_SIZE)
.on_mouse_down(
MouseButton::Left,
cx.listener({
move |this, event: &MouseDownEvent, window, cx| {
let last_position = event.position;
let drag_data = ResizeDrag {
side: ResizeSide::Top,
last_position,
last_bounds: panel_bounds,
};
this.update_resizing_drag(drag_data, window, cx);
if let Some((_, new_ix)) = this.bring_to_front(this.resizing_index, cx)
{
this.resizing_index = Some(new_ix);
}
}
}),
)
.on_drag(DragResizing(entity_id), |drag, _, _, cx| {
cx.stop_propagation();
cx.new(|_| drag.clone())
})
.on_drag_move(cx.listener(
move |this, e: &DragMoveEvent<DragResizing>, window, cx| match e.drag(cx) {
DragResizing(id) => {
if *id != entity_id {
return;
}
let Some(ref drag_data) = this.resizing_drag_data else {
return;
};
if drag_data.side != ResizeSide::Top {
return;
}
let pos = e.event.position;
let delta = drag_data.last_position.y - pos.y;
let new_y = (drag_data.last_bounds.origin.y - delta).max(px(0.));
let size_delta = drag_data.last_position.y - new_y;
let new_height = (drag_data.last_bounds.size.height + size_delta)
.max(MINIMUM_SIZE.width);
this.resize(None, Some(new_y), None, Some(new_height), window, cx);
}
},
))
@ -612,7 +747,7 @@ impl Tiles {
move |this, event: &MouseDownEvent, window, cx| {
let last_position = event.position;
let drag_data = ResizeDrag {
axis: ResizeAxis::Vertical,
side: ResizeSide::Bottom,
last_position,
last_bounds: panel_bounds,
};
@ -635,13 +770,19 @@ impl Tiles {
return;
}
if let Some(ref drag_data) = this.resizing_drag_data {
let pos = e.event.position;
let delta = pos.y - drag_data.last_position.y;
let new_height = (drag_data.last_bounds.size.height + delta)
.max(MINIMUM_SIZE.width);
this.resize_height(new_height, window, cx);
let Some(ref drag_data) = this.resizing_drag_data else {
return;
};
if drag_data.side != ResizeSide::Bottom {
return;
}
let pos = e.event.position;
let delta = pos.y - drag_data.last_position.y;
let new_height =
(drag_data.last_bounds.size.height + delta).max(MINIMUM_SIZE.width);
this.resize(None, None, None, Some(new_height), window, cx);
}
},
))
@ -675,7 +816,7 @@ impl Tiles {
move |this, event: &MouseDownEvent, window, cx| {
let last_position = event.position;
let drag_data = ResizeDrag {
axis: ResizeAxis::Both,
side: ResizeSide::BottomRight,
last_position,
last_bounds: panel_bounds,
};
@ -700,22 +841,31 @@ impl Tiles {
return;
}
if let Some(ref drag_data) = this.resizing_drag_data {
if drag_data.axis != ResizeAxis::Both {
return;
}
let pos = e.event.position;
let delta_x = pos.x - drag_data.last_position.x;
let delta_y = pos.y - drag_data.last_position.y;
let new_width = (drag_data.last_bounds.size.width
+ delta_x)
.max(MINIMUM_SIZE.width);
let new_height = (drag_data.last_bounds.size.height
+ delta_y)
.max(MINIMUM_SIZE.height);
this.resize_height(new_height, window, cx);
this.resize_width(new_width, window, cx);
let Some(ref drag_data) = this.resizing_drag_data else {
return;
};
if drag_data.side != ResizeSide::BottomRight {
return;
}
let pos = e.event.position;
let delta_x = pos.x - drag_data.last_position.x;
let delta_y = pos.y - drag_data.last_position.y;
let new_width = (drag_data.last_bounds.size.width
+ delta_x)
.max(MINIMUM_SIZE.width);
let new_height = (drag_data.last_bounds.size.height
+ delta_y)
.max(MINIMUM_SIZE.height);
this.resize(
None,
None,
Some(new_width),
Some(new_height),
window,
cx,
);
}
}
},