use std::sync::Arc; use gpui::{ div, prelude::FluentBuilder, px, rems, AnchorCorner, AppContext, DefiniteLength, DismissEvent, DragMoveEvent, Empty, EventEmitter, FocusHandle, FocusableView, InteractiveElement as _, IntoElement, ParentElement, Pixels, Render, ScrollHandle, StatefulInteractiveElement, Styled, View, ViewContext, VisualContext as _, WeakView, WindowContext, }; use rust_i18n::t; use crate::{ button::{Button, ButtonStyled as _}, dock::DockItemInfo, h_flex, popup_menu::{PopupMenu, PopupMenuExt}, tab::{Tab, TabBar}, theme::ActiveTheme, v_flex, AxisExt, IconName, Placement, Selectable, Sizable, }; use super::{ ClosePanel, DockArea, DockItemState, Panel, PanelEvent, PanelView, StackPanel, ToggleZoom, }; #[derive(Clone, Copy)] struct TabState { closeable: bool, zoomable: bool, draggable: bool, droppable: bool, } #[derive(Clone)] pub(crate) struct DragPanel { pub(crate) panel: Arc, pub(crate) tab_panel: View, } impl DragPanel { pub(crate) fn new(panel: Arc, tab_panel: View) -> Self { Self { panel, tab_panel } } } impl Render for DragPanel { fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { div() .id("drag-panel") .cursor_grab() .py_1() .px_3() .w_24() .overflow_hidden() .whitespace_nowrap() .border_1() .border_color(cx.theme().border) .rounded_md() .text_color(cx.theme().tab_foreground) .bg(cx.theme().tab_active) .opacity(0.75) .child(self.panel.title(cx)) } } pub struct TabPanel { focus_handle: FocusHandle, dock_area: WeakView, /// The stock_panel can be None, if is None, that means the panels can't be split or move stack_panel: Option>, pub(crate) panels: Vec>, pub(crate) active_ix: usize, /// If this is true, the Panel closeable will follow the active panel's closeable, /// otherwise this TabPanel will not able to close pub(crate) closeable: bool, tab_bar_scroll_handle: ScrollHandle, is_zoomed: bool, is_collapsed: bool, /// When drag move, will get the placement of the panel to be split will_split_placement: Option, } impl Panel for TabPanel { fn panel_name(&self) -> &'static str { "TabPanel" } fn title(&self, cx: &WindowContext) -> gpui::AnyElement { self.active_panel() .map(|panel| panel.title(cx)) .unwrap_or("Empty Tab".into_any_element()) } fn closeable(&self, cx: &WindowContext) -> bool { if !self.closeable { return false; } self.active_panel() .map(|panel| panel.closeable(cx)) .unwrap_or(false) } fn zoomable(&self, cx: &WindowContext) -> bool { self.active_panel() .map(|panel| panel.zoomable(cx)) .unwrap_or(false) } fn collapsible(&self, cx: &WindowContext) -> bool { self.active_panel() .map(|panel| panel.collapsible(cx)) .unwrap_or(false) } fn popup_menu(&self, menu: PopupMenu, cx: &WindowContext) -> PopupMenu { if let Some(panel) = self.active_panel() { panel.popup_menu(menu, cx) } else { menu } } fn toolbar_buttons(&self, cx: &WindowContext) -> Vec