Allowing dragging tabs onto panes and pane edges (#3641)
This commit is contained in:
@@ -740,7 +740,7 @@ impl Interactivity {
|
||||
if style
|
||||
.background
|
||||
.as_ref()
|
||||
.is_some_and(|fill| fill.color().is_some_and(|color| !color.is_transparent()))
|
||||
.is_some_and(|fill| fill.color().is_some())
|
||||
{
|
||||
cx.with_z_index(style.z_index.unwrap_or(0), |cx| cx.add_opaque_layer(bounds))
|
||||
}
|
||||
@@ -1120,78 +1120,84 @@ impl Interactivity {
|
||||
let mut style = Style::default();
|
||||
style.refine(&self.base_style);
|
||||
|
||||
if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
|
||||
if let Some(in_focus_style) = self.in_focus_style.as_ref() {
|
||||
if focus_handle.within_focused(cx) {
|
||||
style.refine(in_focus_style);
|
||||
cx.with_z_index(style.z_index.unwrap_or(0), |cx| {
|
||||
if let Some(focus_handle) = self.tracked_focus_handle.as_ref() {
|
||||
if let Some(in_focus_style) = self.in_focus_style.as_ref() {
|
||||
if focus_handle.within_focused(cx) {
|
||||
style.refine(in_focus_style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(focus_style) = self.focus_style.as_ref() {
|
||||
if focus_handle.is_focused(cx) {
|
||||
style.refine(focus_style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(bounds) = bounds {
|
||||
let mouse_position = cx.mouse_position();
|
||||
if let Some(group_hover) = self.group_hover_style.as_ref() {
|
||||
if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
|
||||
if group_bounds.contains(&mouse_position)
|
||||
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
|
||||
{
|
||||
style.refine(&group_hover.style);
|
||||
if let Some(focus_style) = self.focus_style.as_ref() {
|
||||
if focus_handle.is_focused(cx) {
|
||||
style.refine(focus_style);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(hover_style) = self.hover_style.as_ref() {
|
||||
if bounds
|
||||
.intersect(&cx.content_mask().bounds)
|
||||
.contains(&mouse_position)
|
||||
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
|
||||
{
|
||||
style.refine(hover_style);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(drag) = cx.active_drag.take() {
|
||||
for (state_type, group_drag_style) in &self.group_drag_over_styles {
|
||||
if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) {
|
||||
if *state_type == drag.view.entity_type()
|
||||
&& group_bounds.contains(&mouse_position)
|
||||
if let Some(bounds) = bounds {
|
||||
let mouse_position = cx.mouse_position();
|
||||
if let Some(group_hover) = self.group_hover_style.as_ref() {
|
||||
if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
|
||||
if group_bounds.contains(&mouse_position)
|
||||
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
|
||||
{
|
||||
style.refine(&group_drag_style.style);
|
||||
style.refine(&group_hover.style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (state_type, drag_over_style) in &self.drag_over_styles {
|
||||
if *state_type == drag.view.entity_type()
|
||||
&& bounds
|
||||
.intersect(&cx.content_mask().bounds)
|
||||
.contains(&mouse_position)
|
||||
if let Some(hover_style) = self.hover_style.as_ref() {
|
||||
if bounds
|
||||
.intersect(&cx.content_mask().bounds)
|
||||
.contains(&mouse_position)
|
||||
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
|
||||
{
|
||||
style.refine(drag_over_style);
|
||||
style.refine(hover_style);
|
||||
}
|
||||
}
|
||||
|
||||
cx.active_drag = Some(drag);
|
||||
}
|
||||
}
|
||||
if let Some(drag) = cx.active_drag.take() {
|
||||
for (state_type, group_drag_style) in &self.group_drag_over_styles {
|
||||
if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) {
|
||||
if *state_type == drag.view.entity_type()
|
||||
&& group_bounds.contains(&mouse_position)
|
||||
{
|
||||
style.refine(&group_drag_style.style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let clicked_state = element_state.clicked_state.borrow();
|
||||
if clicked_state.group {
|
||||
if let Some(group) = self.group_active_style.as_ref() {
|
||||
style.refine(&group.style)
|
||||
}
|
||||
}
|
||||
for (state_type, drag_over_style) in &self.drag_over_styles {
|
||||
if *state_type == drag.view.entity_type()
|
||||
&& bounds
|
||||
.intersect(&cx.content_mask().bounds)
|
||||
.contains(&mouse_position)
|
||||
&& cx.was_top_layer_under_active_drag(
|
||||
&mouse_position,
|
||||
cx.stacking_order(),
|
||||
)
|
||||
{
|
||||
style.refine(drag_over_style);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(active_style) = self.active_style.as_ref() {
|
||||
if clicked_state.element {
|
||||
style.refine(active_style)
|
||||
cx.active_drag = Some(drag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let clicked_state = element_state.clicked_state.borrow();
|
||||
if clicked_state.group {
|
||||
if let Some(group) = self.group_active_style.as_ref() {
|
||||
style.refine(&group.style)
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(active_style) = self.active_style.as_ref() {
|
||||
if clicked_state.element {
|
||||
style.refine(active_style)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
style
|
||||
}
|
||||
|
||||
@@ -1759,6 +1759,34 @@ impl Pane {
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
|
||||
fn handle_split_tab_drop(
|
||||
&mut self,
|
||||
dragged_tab: &View<DraggedTab>,
|
||||
split_direction: SplitDirection,
|
||||
cx: &mut ViewContext<'_, Pane>,
|
||||
) {
|
||||
let dragged_tab = dragged_tab.read(cx);
|
||||
let item_id = dragged_tab.item_id;
|
||||
let from_pane = dragged_tab.pane.clone();
|
||||
let to_pane = cx.view().clone();
|
||||
self.workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
cx.defer(move |workspace, cx| {
|
||||
let item = from_pane
|
||||
.read(cx)
|
||||
.items()
|
||||
.find(|item| item.item_id() == item_id)
|
||||
.map(|item| item.boxed_clone());
|
||||
if let Some(item) = item {
|
||||
if let Some(item) = item.clone_on_split(workspace.database_id(), cx) {
|
||||
workspace.split_item(split_direction, item, cx);
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
}
|
||||
|
||||
impl FocusableView for Pane {
|
||||
@@ -1852,7 +1880,54 @@ impl Render for Pane {
|
||||
.child(self.render_tab_bar(cx))
|
||||
.child(self.toolbar.clone())
|
||||
.child(if let Some(item) = self.active_item() {
|
||||
div().flex().flex_1().child(item.to_any())
|
||||
let mut drag_target_color = cx.theme().colors().text;
|
||||
drag_target_color.a = 0.5;
|
||||
|
||||
div()
|
||||
.flex()
|
||||
.flex_1()
|
||||
.relative()
|
||||
.child(item.to_any())
|
||||
.child(
|
||||
div()
|
||||
.absolute()
|
||||
.full()
|
||||
.z_index(1)
|
||||
.drag_over::<DraggedTab>(|style| style.bg(drag_target_color))
|
||||
.on_drop(cx.listener(
|
||||
move |this, dragged_tab: &View<DraggedTab>, cx| {
|
||||
this.handle_tab_drop(dragged_tab, this.active_item_index(), cx)
|
||||
},
|
||||
)),
|
||||
)
|
||||
.children(
|
||||
[
|
||||
(SplitDirection::Up, 2),
|
||||
(SplitDirection::Down, 2),
|
||||
(SplitDirection::Left, 3),
|
||||
(SplitDirection::Right, 3),
|
||||
]
|
||||
.into_iter()
|
||||
.map(|(direction, z_index)| {
|
||||
let div = div()
|
||||
.absolute()
|
||||
.z_index(z_index)
|
||||
.invisible()
|
||||
.bg(drag_target_color)
|
||||
.drag_over::<DraggedTab>(|style| style.visible())
|
||||
.on_drop(cx.listener(
|
||||
move |this, dragged_tab: &View<DraggedTab>, cx| {
|
||||
this.handle_split_tab_drop(dragged_tab, direction, cx)
|
||||
},
|
||||
));
|
||||
match direction {
|
||||
SplitDirection::Up => div.top_0().left_0().right_0().h_32(),
|
||||
SplitDirection::Down => div.left_0().bottom_0().right_0().h_32(),
|
||||
SplitDirection::Left => div.top_0().left_0().bottom_0().w_32(),
|
||||
SplitDirection::Right => div.top_0().bottom_0().right_0().w_32(),
|
||||
}
|
||||
}),
|
||||
)
|
||||
} else {
|
||||
h_stack()
|
||||
.items_center()
|
||||
|
||||
Reference in New Issue
Block a user