use gpui::{Empty, canvas};
use super::{Pane, PaneEvent};
use crate::{
IconButton, IconButtonShape, IconName, IconSize, Tab, TabBar, TabCloseSide, TabPosition,
prelude::*,
};
fn debug_wrap(id: impl Into<ElementId>, selector: String, child: IconButton) -> impl IntoElement {
div().id(id).debug_selector(move || selector).child(child)
}
#[derive(Clone, Copy)]
struct TabDragPayload {
from_idx: usize,
}
impl Render for Pane {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let active_idx = self.active_idx;
let active_id = self.tabs.get(active_idx).map(|(id, _)| *id);
if let (Some(bounds), Some(id)) = (self.content_bounds.get(), active_id) {
if self.notified_resize.get() != Some((id, bounds)) {
self.notified_resize.set(Some((id, bounds)));
self.tabs[active_idx].1.on_resize(bounds, cx);
}
}
let mut tab_bar = TabBar::new("pane-tab-bar");
let tab_count = self.tabs.len();
for ix in 0..tab_count {
let tab_id = self.tabs[ix].0;
let title = self.tabs[ix].1.title();
let selected = ix == active_idx && self.focused;
let position = if ix == 0 {
TabPosition::First
} else if ix == tab_count - 1 {
TabPosition::Last
} else {
TabPosition::Middle(ix.cmp(&active_idx))
};
let hover_group = SharedString::from(format!("pane-tab-{}", tab_id.0));
let close_ib = IconButton::new(("pane-tab-close", tab_id.0), IconName::Close)
.icon_size(IconSize::Small)
.icon_color(Color::Muted)
.shape(IconButtonShape::Square)
.size(ButtonSize::None)
.on_click(cx.listener(move |this, _, _, cx| {
this.close_tab(ix, cx);
}))
.visible_on_hover(hover_group.clone());
let close_button = debug_wrap(
("pane-tab-close-wrap", tab_id.0),
format!("PANE-TAB-CLOSE-{}", tab_id.0),
close_ib,
);
let tab = Tab::new(("pane-tab", tab_id.0))
.group(hover_group)
.toggle_state(selected)
.position(position)
.close_side(TabCloseSide::End)
.end_slot(close_button)
.child(Label::new(title).size(LabelSize::Small))
.on_click(cx.listener(move |this, _, _, cx| {
this.activate(ix, cx);
}))
.on_drag(TabDragPayload { from_idx: ix }, |_, _, _, cx| {
cx.new(|_| Empty)
})
.drag_over::<TabDragPayload>(|style, _, _, _| style.opacity(0.5))
.on_drop(cx.listener(move |this, payload: &TabDragPayload, _, cx| {
this.reorder(payload.from_idx, ix, cx);
}));
tab_bar = tab_bar.child(tab);
}
tab_bar = tab_bar.end_child(debug_wrap(
"pane-add-tab-wrap",
"PANE-ADD-TAB".to_string(),
IconButton::new("pane-add-tab", IconName::Plus)
.icon_size(IconSize::XSmall)
.on_click(cx.listener(|this, _, _, cx| {
let content = (this.new_tab_factory)();
this.add_tab(content, cx);
})),
));
tab_bar = tab_bar.end_child(debug_wrap(
"pane-close-wrap",
"PANE-CLOSE".to_string(),
IconButton::new("pane-close", IconName::Close)
.icon_size(IconSize::XSmall)
.on_click(cx.listener(|_, _, _, cx| {
cx.emit(PaneEvent::CloseRequested);
})),
));
let content = self
.tabs
.get(active_idx)
.map(|(_, content)| content.render(true, window, cx));
let measure = self.content_bounds.clone();
v_flex().id("pane").size_full().child(tab_bar).child(
div()
.relative()
.flex_1()
.min_h_0()
.overflow_hidden()
.child(
canvas(
move |bounds, _, _| measure.set(Some(bounds)),
|_, _, _, _| {},
)
.absolute()
.size_full(),
)
.children(content),
)
}
}