update deps
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
|
||||
### Changed
|
||||
|
||||
- Migrate the GPUI foundation to the published `gpui-pre` crates and GPUI Kit 0.6, off the zed and gpui-component git pins
|
||||
|
||||
### Fixed
|
||||
|
||||
### Removed
|
||||
|
||||
Generated
+560
-514
File diff suppressed because it is too large
Load Diff
+5
-7
@@ -9,15 +9,13 @@ edition = "2024"
|
||||
publish = false
|
||||
|
||||
[workspace.dependencies]
|
||||
# GPUI
|
||||
gpui = { git = "https://github.com/zed-industries/zed" }
|
||||
gpui_platform = { git = "https://github.com/zed-industries/zed", features = ["font-kit", "x11", "wayland"] }
|
||||
gpui_tokio = { git = "https://github.com/zed-industries/zed" }
|
||||
reqwest_client = { git = "https://github.com/zed-industries/zed" }
|
||||
gpui = { package = "gpui-pre", version = "0.3.6" }
|
||||
gpui_platform = { package = "gpui-pre-platform", version = "0.3.6", features = ["font-kit", "x11", "wayland"] }
|
||||
reqwest_client = { package = "gpui-pre-reqwest-client", version = "0.3.6" }
|
||||
|
||||
# GPUI Kit
|
||||
gpui-component = { git = "https://github.com/longbridge/gpui-component", rev = "39c2c86dbee7ad445591462f8675f74082e10828", features = ["tree-sitter-languages"], }
|
||||
gpui-base = { git = "https://github.com/longbridge/gpui-component", rev = "39c2c86dbee7ad445591462f8675f74082e10828" }
|
||||
gpui-component = { version = "0.6.6", features = ["tree-sitter-languages"] }
|
||||
gpui-base = "0.6.6"
|
||||
|
||||
dock = { path = "crates/dock" }
|
||||
settings = { path = "crates/settings" }
|
||||
|
||||
@@ -11,22 +11,19 @@ use gpui::{
|
||||
};
|
||||
use gpui_base::dock::{
|
||||
DockArea, DockAreaRenderer, DockContext, DockEvent, DockPlacement, NodeId, PanelState,
|
||||
PanelView, TabGroupRenderer, TilesRenderer,
|
||||
PanelView, TabGroupRenderer,
|
||||
};
|
||||
use gpui_base::resize_handle;
|
||||
use gpui_component::scroll::ScrollbarMode;
|
||||
use gpui_component::{ActiveTheme as _, Side};
|
||||
|
||||
use crate::invalid_panel::InvalidPanel;
|
||||
use crate::panel_handle;
|
||||
use crate::tab_panel::SignedTabGroupSkin;
|
||||
use crate::tiles::SignedTilesSkin;
|
||||
use crate::{TAB_BAR_HEIGHT, panel_handle};
|
||||
|
||||
/// State the skin shares with its per-container renderers.
|
||||
pub(crate) struct SkinShared {
|
||||
area: WeakEntity<DockArea>,
|
||||
toggle_button_visible: Cell<bool>,
|
||||
tiles_scrollbar_mode: Cell<Option<ScrollbarMode>>,
|
||||
/// The dock whose resize handle is being dragged, if any. Only one can be.
|
||||
resizing_dock: Cell<Option<DockPlacement>>,
|
||||
}
|
||||
@@ -40,10 +37,6 @@ impl SkinShared {
|
||||
self.toggle_button_visible.get()
|
||||
}
|
||||
|
||||
pub(crate) fn tiles_scrollbar_mode(&self) -> Option<ScrollbarMode> {
|
||||
self.tiles_scrollbar_mode.get()
|
||||
}
|
||||
|
||||
pub(crate) fn resizing_dock(&self) -> &Cell<Option<DockPlacement>> {
|
||||
&self.resizing_dock
|
||||
}
|
||||
@@ -73,7 +66,6 @@ impl SignedDockSkin {
|
||||
shared: Rc::new(SkinShared {
|
||||
area: cx.weak_entity(),
|
||||
toggle_button_visible: Cell::new(true),
|
||||
tiles_scrollbar_mode: Cell::new(None),
|
||||
resizing_dock: Cell::new(None),
|
||||
}),
|
||||
})
|
||||
@@ -92,16 +84,6 @@ impl SignedDockSkin {
|
||||
self.shared.toggle_button_visible.set(visible);
|
||||
self.shared.notify(cx);
|
||||
}
|
||||
|
||||
/// When a tiles canvas shows its scrollbar. `None` follows the theme.
|
||||
pub fn tiles_scrollbar_mode(&self) -> Option<ScrollbarMode> {
|
||||
self.shared.tiles_scrollbar_mode()
|
||||
}
|
||||
|
||||
pub fn set_tiles_scrollbar_mode(&self, mode: Option<ScrollbarMode>, cx: &mut App) {
|
||||
self.shared.tiles_scrollbar_mode.set(mode);
|
||||
self.shared.notify(cx);
|
||||
}
|
||||
}
|
||||
|
||||
/// Payload a dock's resize handle drags.
|
||||
@@ -154,16 +136,10 @@ impl DockAreaRenderer for SignedDockSkin {
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> AnyElement {
|
||||
let placement = dock.placement();
|
||||
|
||||
div()
|
||||
.flex()
|
||||
.size_full()
|
||||
.relative()
|
||||
// A closed bottom dock keeps a strip, and that strip is the tab bar.
|
||||
.when(!dock.is_open() && placement.is_bottom(), |this| {
|
||||
this.h(TAB_BAR_HEIGHT)
|
||||
})
|
||||
.child(content)
|
||||
.child(self.render_resize_handle(dock, window, cx))
|
||||
.child(DockResizeTracker {
|
||||
@@ -190,10 +166,6 @@ impl DockAreaRenderer for SignedDockSkin {
|
||||
fn tab_group_renderer(&self) -> Rc<dyn TabGroupRenderer> {
|
||||
Rc::new(SignedTabGroupSkin::new(self.shared().clone()))
|
||||
}
|
||||
|
||||
fn tiles_renderer(&self) -> Rc<dyn TilesRenderer> {
|
||||
Rc::new(SignedTilesSkin::new(self.shared().clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl SignedDockSkin {
|
||||
|
||||
@@ -6,7 +6,6 @@ use gpui_base::dock::PanelView;
|
||||
mod dock_area;
|
||||
mod invalid_panel;
|
||||
mod tab_panel;
|
||||
mod tiles;
|
||||
mod window_controls;
|
||||
|
||||
pub use dock_area::SignedDockSkin;
|
||||
|
||||
@@ -30,6 +30,10 @@ use crate::{TAB_BAR_HEIGHT, t, window_controls};
|
||||
/// The drag preview's size, reported to base for the drop placeholder.
|
||||
const DRAG_PREVIEW_SIZE: gpui::Size<gpui::Pixels> = size(px(96.), px(30.));
|
||||
|
||||
/// The key a collapsed dock's stand-in tab bar is tagged with, so a test can
|
||||
/// measure that it fits the strip base reserves. A no-op outside test builds.
|
||||
const COLLAPSED_TAB_BAR_SELECTOR: &str = "signed-dock-collapsed-tab-bar";
|
||||
|
||||
/// A panel's title, or its registered name when the panel has no handle.
|
||||
pub(crate) fn panel_title(
|
||||
panel: &Arc<dyn BasePanelView>,
|
||||
@@ -84,7 +88,6 @@ fn left_top_group(node: &PaneNode) -> Option<NodeId> {
|
||||
match node.kind() {
|
||||
PaneRef::Tabs { .. } => Some(node.id()),
|
||||
PaneRef::Split { children, .. } => children.first().and_then(left_top_group),
|
||||
PaneRef::Tiles { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +101,6 @@ fn right_top_group(node: &PaneNode) -> Option<NodeId> {
|
||||
gpui::Axis::Horizontal => children.last(),
|
||||
}
|
||||
.and_then(right_top_group),
|
||||
PaneRef::Tiles { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -709,7 +711,16 @@ impl TabGroupRenderer for SignedTabGroupSkin {
|
||||
.child(
|
||||
Tabs::new("tab-bar")
|
||||
.px(px(-1.))
|
||||
.h(TAB_BAR_HEIGHT)
|
||||
// A collapsed group stands in for a closed bottom dock,
|
||||
// which base gives only its reserved strip. The bar keeps
|
||||
// its own height there rather than the title-bar height,
|
||||
// so it fits instead of being clipped away.
|
||||
.when(!collapsed, |this| this.h(TAB_BAR_HEIGHT))
|
||||
// Only a collapsed (bottom) dock tags its bar, so the
|
||||
// selector is unique when a test measures it.
|
||||
.when(collapsed, |this| {
|
||||
this.debug_selector(|| COLLAPSED_TAB_BAR_SELECTOR.to_string())
|
||||
})
|
||||
.flex()
|
||||
.items_center()
|
||||
.text_color(cx.theme().tab_foreground)
|
||||
@@ -833,3 +844,112 @@ impl TabGroupRenderer for SignedTabGroupSkin {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use gpui::{
|
||||
App, AppContext as _, Context, Empty, EventEmitter, FocusHandle, Focusable, IntoElement,
|
||||
Render, TestAppContext, Window, px,
|
||||
};
|
||||
use gpui_base::dock::{DockArea, DockLayout, DockPlacement, PanelEvent};
|
||||
|
||||
use super::COLLAPSED_TAB_BAR_SELECTOR;
|
||||
use crate::{BasePanel, Panel, SignedDockSkin, panel_handle};
|
||||
|
||||
struct Probe {
|
||||
focus_handle: FocusHandle,
|
||||
}
|
||||
|
||||
impl Probe {
|
||||
fn new(cx: &mut Context<Self>) -> Self {
|
||||
Self {
|
||||
focus_handle: cx.focus_handle(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BasePanel for Probe {
|
||||
fn panel_name(&self) -> &'static str {
|
||||
"Probe"
|
||||
}
|
||||
}
|
||||
|
||||
impl Panel for Probe {
|
||||
fn title(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
||||
"Probe"
|
||||
}
|
||||
}
|
||||
|
||||
impl EventEmitter<PanelEvent> for Probe {}
|
||||
|
||||
impl Focusable for Probe {
|
||||
fn focus_handle(&self, _: &App) -> FocusHandle {
|
||||
self.focus_handle.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for Probe {
|
||||
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
||||
Empty
|
||||
}
|
||||
}
|
||||
|
||||
/// Base reserves only `gpui_base::dock::CLOSED_BOTTOM_STRIP` for a closed
|
||||
/// bottom dock, so the tab bar drawn in place of one has to shrink to that
|
||||
/// height; at the full title-bar height its bottom was clipped away.
|
||||
#[gpui::test]
|
||||
fn a_collapsed_bottom_dock_bar_fits_the_reserved_strip(cx: &mut TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
gpui_component::init(cx);
|
||||
});
|
||||
let (area, cx) = cx.add_window_view(|window, cx| {
|
||||
let skin = SignedDockSkin::new(cx);
|
||||
DockArea::new("test", None, window, cx).with_renderer(skin)
|
||||
});
|
||||
|
||||
cx.update(|window, cx| {
|
||||
let center = cx.new(Probe::new);
|
||||
let bottom = cx.new(Probe::new);
|
||||
area.update(cx, |area, cx| {
|
||||
area.set_center(
|
||||
DockLayout::tabs().panel_view(panel_handle(center), cx),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
area.set_dock(
|
||||
DockPlacement::Bottom,
|
||||
DockLayout::tabs().panel_view(panel_handle(bottom), cx),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
});
|
||||
cx.run_until_parked();
|
||||
cx.update(|window, cx| window.draw(cx).clear(cx));
|
||||
|
||||
// Open, nothing is collapsed, so no bar carries the selector.
|
||||
assert!(cx.debug_bounds(COLLAPSED_TAB_BAR_SELECTOR).is_none());
|
||||
|
||||
cx.update(|window, cx| {
|
||||
area.update(cx, |area, cx| {
|
||||
area.toggle_dock(DockPlacement::Bottom, window, cx);
|
||||
});
|
||||
});
|
||||
cx.run_until_parked();
|
||||
cx.update(|window, cx| window.draw(cx).clear(cx));
|
||||
|
||||
let bounds = cx
|
||||
.debug_bounds(COLLAPSED_TAB_BAR_SELECTOR)
|
||||
.expect("a collapsed bottom dock draws its stand-in tab bar");
|
||||
// `gpui_base::dock::CLOSED_BOTTOM_STRIP`, which the engine does not
|
||||
// re-export. The bar used to be `TAB_BAR_HEIGHT` here and its bottom was
|
||||
// clipped away; it now has to fit inside what base reserves.
|
||||
let reserved_strip = px(29.);
|
||||
assert!(
|
||||
bounds.size.height <= reserved_strip,
|
||||
"the collapsed bar is {}px tall, more than the {}px strip base reserves",
|
||||
bounds.size.height,
|
||||
reserved_strip,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,388 +0,0 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use gpui::prelude::FluentBuilder as _;
|
||||
use gpui::{
|
||||
AnyElement, App, AppContext as _, Context, Div, DragMoveEvent, Empty, InteractiveElement as _,
|
||||
IntoElement, MouseButton, MouseDownEvent, ParentElement as _, Pixels, Render, ScrollHandle,
|
||||
Size, Stateful, StatefulInteractiveElement as _, Styled as _, Window, div, px,
|
||||
};
|
||||
use gpui_base::dock::{
|
||||
DRAG_BAR_HEIGHT, HANDLE_SIZE, NodeId, ResizeSide, TileContext, TilesRenderer,
|
||||
};
|
||||
use gpui_component::button::{Button, ButtonVariants as _};
|
||||
use gpui_component::dock::PanelHandle;
|
||||
use gpui_component::menu::{DropdownMenu as _, PopupMenuItem};
|
||||
use gpui_component::scroll::Scrollbar;
|
||||
use gpui_component::{
|
||||
ActiveTheme as _, Icon, IconName, Selectable as _, Sizable as _, h_flex, v_flex,
|
||||
};
|
||||
|
||||
use crate::dock_area::SkinShared;
|
||||
use crate::t;
|
||||
use crate::tab_panel::panel_title;
|
||||
|
||||
/// How far a resize handle sticks out past the tile's edge.
|
||||
const HANDLE_OFFSET: Pixels = px(-4.);
|
||||
|
||||
/// The payload a tile drag carries, so one canvas ignores another's drags.
|
||||
#[derive(Clone)]
|
||||
struct DragMoving(NodeId);
|
||||
|
||||
impl Render for DragMoving {
|
||||
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
||||
Empty
|
||||
}
|
||||
}
|
||||
|
||||
/// The payload a tile resize carries, for the same reason.
|
||||
#[derive(Clone)]
|
||||
struct DragResizing(NodeId);
|
||||
|
||||
impl Render for DragResizing {
|
||||
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
||||
Empty
|
||||
}
|
||||
}
|
||||
|
||||
/// One tiles canvas's appearance.
|
||||
/// Built once per container, so its scroll position belongs to the canvas it scrolls.
|
||||
pub(crate) struct SignedTilesSkin {
|
||||
shared: Rc<SkinShared>,
|
||||
scroll_handle: ScrollHandle,
|
||||
}
|
||||
|
||||
impl SignedTilesSkin {
|
||||
pub(crate) fn new(shared: Rc<SkinShared>) -> Self {
|
||||
Self {
|
||||
shared,
|
||||
scroll_handle: ScrollHandle::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn resize_handle(
|
||||
&self,
|
||||
tile: &TileContext,
|
||||
id: &'static str,
|
||||
side: ResizeSide,
|
||||
build: impl FnOnce(Stateful<Div>) -> Stateful<Div>,
|
||||
) -> Stateful<Div> {
|
||||
let node = tile.node();
|
||||
|
||||
build(div().id(id).absolute())
|
||||
.on_mouse_down(MouseButton::Left, {
|
||||
let tile = tile.clone();
|
||||
move |event: &MouseDownEvent, window, cx| {
|
||||
tile.begin_resize(side, event.position, window, cx);
|
||||
cx.stop_propagation();
|
||||
}
|
||||
})
|
||||
.on_drag(DragResizing(node), |drag, _, _, cx| {
|
||||
cx.stop_propagation();
|
||||
cx.new(|_| drag.clone())
|
||||
})
|
||||
.on_drag_move({
|
||||
let tile = tile.clone();
|
||||
move |event: &DragMoveEvent<DragResizing>, window, cx| {
|
||||
if event.drag(cx).0 != node {
|
||||
return;
|
||||
}
|
||||
tile.resize_to(event.event.position, window, cx);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// The trailing controls of a tile's title bar, zoom, close and the ellipsis menu.
|
||||
/// They use click handlers, the zoom and close actions target a focused tab group.
|
||||
fn render_tile_controls(
|
||||
&self,
|
||||
tile: &TileContext,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> impl IntoElement {
|
||||
let handle = PanelHandle::of(tile.panel());
|
||||
let control = handle.and_then(|handle| handle.zoom_control(cx));
|
||||
let zoomed = tile.is_zoomed();
|
||||
let toolbar_zoom =
|
||||
tile.is_zoomable() && control.is_some_and(|control| control.toolbar_visible());
|
||||
let menu_zoom = tile.is_zoomable() && control.is_some_and(|control| control.menu_visible());
|
||||
let closable = tile.is_closable();
|
||||
let buttons = handle.and_then(|handle| handle.toolbar_buttons(window, cx));
|
||||
let panel = handle.map(|handle| handle.panel());
|
||||
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.flex_shrink_0()
|
||||
.occlude()
|
||||
.when_some(buttons, |this, buttons| {
|
||||
this.children(
|
||||
buttons
|
||||
.into_iter()
|
||||
.map(|button| button.xsmall().ghost().tab_stop(false)),
|
||||
)
|
||||
})
|
||||
.when_some(
|
||||
match (zoomed, toolbar_zoom) {
|
||||
(true, _) => Some(("zoom-out", IconName::Minimize, t("Dock.Zoom Out"))),
|
||||
(false, true) => Some(("zoom-in", IconName::Maximize, t("Dock.Zoom In"))),
|
||||
(false, false) => None,
|
||||
},
|
||||
|this, (id, icon, tooltip)| {
|
||||
this.child(
|
||||
Button::new(id)
|
||||
.icon(icon)
|
||||
.xsmall()
|
||||
.ghost()
|
||||
.tab_stop(false)
|
||||
.tooltip(tooltip)
|
||||
.selected(zoomed)
|
||||
.on_click({
|
||||
let tile = tile.clone();
|
||||
move |_, window, cx| tile.toggle_zoom(window, cx)
|
||||
}),
|
||||
)
|
||||
},
|
||||
)
|
||||
.child(
|
||||
Button::new("menu")
|
||||
.icon(IconName::Ellipsis)
|
||||
.xsmall()
|
||||
.ghost()
|
||||
.tab_stop(false)
|
||||
.dropdown_menu({
|
||||
let tile = tile.clone();
|
||||
move |menu, window, cx| {
|
||||
menu.when_some(panel.clone(), |menu, panel| {
|
||||
panel.dropdown_menu(menu, window, cx)
|
||||
})
|
||||
.separator()
|
||||
.item(
|
||||
PopupMenuItem::new(match zoomed {
|
||||
true => t("Dock.Zoom Out"),
|
||||
false => t("Dock.Zoom In"),
|
||||
})
|
||||
.disabled(!menu_zoom && !zoomed)
|
||||
.on_click({
|
||||
let tile = tile.clone();
|
||||
move |_, window, cx| tile.toggle_zoom(window, cx)
|
||||
}),
|
||||
)
|
||||
.when(closable, |menu| {
|
||||
menu.separator()
|
||||
.item(PopupMenuItem::new(t("Dock.Close")).on_click({
|
||||
let tile = tile.clone();
|
||||
move |_, window, cx| tile.close(window, cx)
|
||||
}))
|
||||
})
|
||||
}
|
||||
})
|
||||
.anchor(gpui::Anchor::TopRight),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl TilesRenderer for SignedTilesSkin {
|
||||
fn frame(&self, _: &mut Window, cx: &mut App) -> Stateful<Div> {
|
||||
div()
|
||||
.id("tiles")
|
||||
.relative()
|
||||
.size_full()
|
||||
.bg(cx.theme().tokens.tiles)
|
||||
.track_scroll(&self.scroll_handle)
|
||||
.overflow_scroll()
|
||||
}
|
||||
|
||||
fn tile_frame(&self, tile: &TileContext, _: &mut Window, cx: &mut App) -> Stateful<Div> {
|
||||
v_flex()
|
||||
.id(("tile", tile.panel_id().as_u64()))
|
||||
.occlude()
|
||||
.overflow_hidden()
|
||||
.bg(cx.theme().tokens.background)
|
||||
.border_1()
|
||||
.border_color(cx.theme().border)
|
||||
.rounded(cx.theme().tile_radius)
|
||||
// Room for the title bar, which overlays the top padding.
|
||||
// Base draws the panel as a plain child, this keeps them apart.
|
||||
.pt(DRAG_BAR_HEIGHT)
|
||||
// Base stores no bounds on a zoomed tile, the skin decides how it fills the dock.
|
||||
.when(tile.is_zoomed(), |this| this.size_full())
|
||||
.on_mouse_down(MouseButton::Left, {
|
||||
let tile = tile.clone();
|
||||
move |_, window, cx| tile.bring_to_front(window, cx)
|
||||
})
|
||||
// A gesture can end anywhere, so both mouse-up hooks run.
|
||||
// Each is a no-op unless this tile is the one that moved.
|
||||
.on_mouse_up(MouseButton::Left, {
|
||||
let tile = tile.clone();
|
||||
move |_, window, cx| {
|
||||
tile.end_move(window, cx);
|
||||
tile.end_resize(window, cx);
|
||||
}
|
||||
})
|
||||
.on_mouse_up_out(MouseButton::Left, {
|
||||
let tile = tile.clone();
|
||||
move |_, window, cx| {
|
||||
tile.end_move(window, cx);
|
||||
tile.end_resize(window, cx);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn render_drag_bar(&self, tile: &TileContext, window: &mut Window, cx: &mut App) -> AnyElement {
|
||||
let node = tile.node();
|
||||
let handle = PanelHandle::of(tile.panel());
|
||||
let title_style = handle.and_then(|handle| handle.title_style(cx));
|
||||
|
||||
h_flex()
|
||||
.id("drag-bar")
|
||||
.absolute()
|
||||
.top_0()
|
||||
.left_0()
|
||||
.w_full()
|
||||
.h(DRAG_BAR_HEIGHT)
|
||||
.items_center()
|
||||
.gap_1()
|
||||
.pl_3()
|
||||
.pr_2()
|
||||
.when_some(title_style, |this, style| {
|
||||
this.bg(style.background).text_color(style.foreground)
|
||||
})
|
||||
.child(
|
||||
div()
|
||||
.flex_1()
|
||||
.min_w_16()
|
||||
.overflow_hidden()
|
||||
.text_ellipsis()
|
||||
.whitespace_nowrap()
|
||||
.child(panel_title(tile.panel(), window, cx)),
|
||||
)
|
||||
.children(handle.and_then(|handle| handle.title_suffix(window, cx)))
|
||||
.child(self.render_tile_controls(tile, window, cx))
|
||||
// A zoomed tile is not at its stored bounds, so moving it would mean nothing.
|
||||
.when(!tile.is_zoomed(), |this| {
|
||||
this.cursor_grab()
|
||||
.on_mouse_down(MouseButton::Left, {
|
||||
let tile = tile.clone();
|
||||
move |event: &MouseDownEvent, window, cx| {
|
||||
tile.begin_move(event.position, window, cx);
|
||||
}
|
||||
})
|
||||
.on_drag(DragMoving(node), |drag, _, _, cx| {
|
||||
cx.stop_propagation();
|
||||
cx.new(|_| drag.clone())
|
||||
})
|
||||
.on_drag_move({
|
||||
let tile = tile.clone();
|
||||
move |event: &DragMoveEvent<DragMoving>, window, cx| {
|
||||
if event.drag(cx).0 != node {
|
||||
return;
|
||||
}
|
||||
tile.move_to(event.event.position, window, cx);
|
||||
}
|
||||
})
|
||||
})
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn render_resize_handles(
|
||||
&self,
|
||||
tile: &TileContext,
|
||||
_: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> AnyElement {
|
||||
let bounds = tile.bounds();
|
||||
|
||||
// A passive full-tile box, so handles sit against the tile, not its flow neighbours.
|
||||
// It registers no interaction, so it does not shadow the panel underneath.
|
||||
div()
|
||||
.absolute()
|
||||
.top_0()
|
||||
.left_0()
|
||||
.size_full()
|
||||
.child(
|
||||
self.resize_handle(tile, "left-resize-handle", ResizeSide::Left, |this| {
|
||||
this.cursor_ew_resize()
|
||||
.top_0()
|
||||
.left(HANDLE_OFFSET)
|
||||
.w(HANDLE_SIZE)
|
||||
.h(bounds.size.height)
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
self.resize_handle(tile, "right-resize-handle", ResizeSide::Right, |this| {
|
||||
this.cursor_ew_resize()
|
||||
.top_0()
|
||||
.right(HANDLE_OFFSET)
|
||||
.w(HANDLE_SIZE)
|
||||
.h(bounds.size.height)
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
self.resize_handle(tile, "top-resize-handle", ResizeSide::Top, |this| {
|
||||
this.cursor_ns_resize()
|
||||
.left_0()
|
||||
.top(HANDLE_OFFSET)
|
||||
.w(bounds.size.width)
|
||||
.h(HANDLE_SIZE)
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
self.resize_handle(tile, "bottom-resize-handle", ResizeSide::Bottom, |this| {
|
||||
this.cursor_ns_resize()
|
||||
.left_0()
|
||||
.bottom(HANDLE_OFFSET)
|
||||
.w(bounds.size.width)
|
||||
.h(HANDLE_SIZE)
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
Icon::new(IconName::ResizeCorner)
|
||||
.size_3()
|
||||
.absolute()
|
||||
.right(px(1.))
|
||||
.bottom(px(1.))
|
||||
.text_color(cx.theme().muted_foreground.opacity(0.5)),
|
||||
)
|
||||
.child(self.resize_handle(
|
||||
tile,
|
||||
"corner-resize-handle",
|
||||
ResizeSide::BottomRight,
|
||||
|this| {
|
||||
this.cursor_nwse_resize()
|
||||
.right(HANDLE_OFFSET)
|
||||
.bottom(HANDLE_OFFSET)
|
||||
.size_3()
|
||||
},
|
||||
))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Gives the tile's panel `size_full`, base draws it as a plain child otherwise.
|
||||
fn panel_frame(&self, tile: &TileContext, _: &mut Window, _: &mut App) -> Stateful<Div> {
|
||||
h_flex()
|
||||
.id(("tile-panel", tile.panel_id().as_u64()))
|
||||
.overflow_hidden()
|
||||
.size_full()
|
||||
}
|
||||
|
||||
/// The canvas scrollbar, as an overlay.
|
||||
/// Placed inside the frame it would end up underneath every tile.
|
||||
fn render_overlay(
|
||||
&self,
|
||||
content: Size<Pixels>,
|
||||
_: &mut Window,
|
||||
_: &mut App,
|
||||
) -> Option<AnyElement> {
|
||||
Some(
|
||||
Scrollbar::new(&self.scroll_handle)
|
||||
.scroll_size(content)
|
||||
.when_some(self.shared.tiles_scrollbar_mode(), |this, mode| {
|
||||
this.mode(mode)
|
||||
})
|
||||
.into_any_element(),
|
||||
)
|
||||
}
|
||||
|
||||
fn grid_size(&self, cx: &App) -> Pixels {
|
||||
cx.theme().tile_grid_size
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user