update sidebar
This commit is contained in:
+94
-49
@@ -25,6 +25,7 @@ pub struct Tab {
|
||||
children: Vec<AnyElement>,
|
||||
pub(super) disabled: bool,
|
||||
pub(super) selected: bool,
|
||||
pub(super) segmented: bool,
|
||||
on_click: Option<Rc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
|
||||
}
|
||||
|
||||
@@ -69,6 +70,7 @@ impl Default for Tab {
|
||||
children: Vec::new(),
|
||||
disabled: false,
|
||||
selected: false,
|
||||
segmented: false,
|
||||
prefix: None,
|
||||
suffix: None,
|
||||
on_click: None,
|
||||
@@ -132,6 +134,12 @@ impl Tab {
|
||||
self.tab_bar_prefix = Some(tab_bar_prefix);
|
||||
self
|
||||
}
|
||||
|
||||
/// Render the tab as a segment inside a segmented control.
|
||||
pub(crate) fn segmented(mut self, segmented: bool) -> Self {
|
||||
self.segmented = segmented;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl ParentElement for Tab {
|
||||
@@ -167,74 +175,111 @@ impl Styled for Tab {
|
||||
|
||||
impl RenderOnce for Tab {
|
||||
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let fg = if self.disabled {
|
||||
let Self {
|
||||
ix,
|
||||
base,
|
||||
label,
|
||||
icon,
|
||||
prefix,
|
||||
suffix,
|
||||
children,
|
||||
disabled,
|
||||
selected,
|
||||
segmented,
|
||||
on_click,
|
||||
..
|
||||
} = self;
|
||||
|
||||
let fg = if disabled {
|
||||
cx.theme().text_muted
|
||||
} else if self.selected {
|
||||
} else if selected {
|
||||
cx.theme().tab_active_foreground
|
||||
} else {
|
||||
cx.theme().tab_foreground
|
||||
};
|
||||
|
||||
self.base
|
||||
.id(self.ix)
|
||||
.flex()
|
||||
.flex_wrap()
|
||||
.gap_1()
|
||||
let content = h_flex()
|
||||
.flex_1()
|
||||
.map(|this| {
|
||||
if segmented {
|
||||
this.h(px(24.))
|
||||
} else {
|
||||
this.h(px(30.))
|
||||
}
|
||||
})
|
||||
.line_height(relative(1.))
|
||||
.whitespace_nowrap()
|
||||
.items_center()
|
||||
.flex_shrink_0()
|
||||
.h(TABBAR_HEIGHT)
|
||||
.relative()
|
||||
.justify_center()
|
||||
.overflow_hidden()
|
||||
.when(segmented, |this| this.px_1())
|
||||
.when(!segmented, |this| this.flex_shrink_0().px_3())
|
||||
.map(|this| match icon {
|
||||
Some(icon) => this.w(px(38.)).child(icon.size_4()),
|
||||
None => this
|
||||
.map(|this| match label {
|
||||
Some(label) => this.child(label),
|
||||
None => this,
|
||||
})
|
||||
.children(children),
|
||||
});
|
||||
|
||||
base.id(ix)
|
||||
.flex()
|
||||
.items_center()
|
||||
.text_color(fg)
|
||||
.text_sm()
|
||||
.when_some(self.prefix, |this, prefix| this.child(prefix))
|
||||
.child(
|
||||
h_flex()
|
||||
.when(segmented, |this| {
|
||||
this.text_xs()
|
||||
.flex_1()
|
||||
.h(px(30.))
|
||||
.line_height(relative(1.))
|
||||
.whitespace_nowrap()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.overflow_hidden()
|
||||
.h(px(24.))
|
||||
.rounded(cx.theme().radius)
|
||||
.when(selected && !disabled, |this| {
|
||||
this.bg(cx.theme().tab_active_background)
|
||||
.when(cx.theme().shadow, |this| this.shadow_sm())
|
||||
})
|
||||
.when(!selected && !disabled, |this| {
|
||||
this.hover(|this| this.bg(cx.theme().tab_hover_background))
|
||||
})
|
||||
})
|
||||
.when(!segmented, |this| {
|
||||
this.text_sm()
|
||||
.flex_wrap()
|
||||
.gap_1()
|
||||
.flex_shrink_0()
|
||||
.px_3()
|
||||
.map(|this| match self.icon {
|
||||
Some(icon) => this.w(px(38.)).child(icon.size_4()),
|
||||
None => this
|
||||
.map(|this| match self.label {
|
||||
Some(label) => this.child(label),
|
||||
None => this,
|
||||
})
|
||||
.children(self.children),
|
||||
}),
|
||||
)
|
||||
.when_some(self.suffix, |this, suffix| {
|
||||
.h(TABBAR_HEIGHT)
|
||||
.relative()
|
||||
.overflow_hidden()
|
||||
})
|
||||
.when_some(prefix, |this, prefix| this.child(prefix))
|
||||
.child(content)
|
||||
.when_some(suffix, |this, suffix| {
|
||||
this.child(div().pr_2().child(suffix))
|
||||
})
|
||||
.on_mouse_down(MouseButton::Left, |_ev, _window, cx| {
|
||||
cx.stop_propagation();
|
||||
})
|
||||
.when(!self.disabled, |this| {
|
||||
this.when_some(self.on_click.clone(), |this, on_click| {
|
||||
.when(!disabled, |this| {
|
||||
this.when_some(on_click, |this, on_click| {
|
||||
this.on_click(move |event, window, cx| on_click(event, window, cx))
|
||||
})
|
||||
})
|
||||
.child(
|
||||
div()
|
||||
.absolute()
|
||||
.bottom_0()
|
||||
.left_0()
|
||||
.right_0()
|
||||
.h_0p5()
|
||||
.when(self.selected && !self.disabled, |this| {
|
||||
this.bg(cx.theme().element_active)
|
||||
})
|
||||
.when(!self.selected && !self.disabled, |this| {
|
||||
this.invisible().group_hover("", |this| {
|
||||
this.visible().bg(cx.theme().secondary_background)
|
||||
.when(!segmented, |this| {
|
||||
this.child(
|
||||
div()
|
||||
.absolute()
|
||||
.bottom_0()
|
||||
.left_0()
|
||||
.right_0()
|
||||
.h_0p5()
|
||||
.when(selected && !disabled, |this| {
|
||||
this.bg(cx.theme().element_active)
|
||||
})
|
||||
}),
|
||||
)
|
||||
.when(!selected && !disabled, |this| {
|
||||
this.invisible().group_hover("", |this| {
|
||||
this.visible().bg(cx.theme().secondary_background)
|
||||
})
|
||||
}),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use gpui::{
|
||||
Window, div, px,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use theme::ActiveTheme;
|
||||
|
||||
use super::Tab;
|
||||
use crate::button::{Button, ButtonVariants as _};
|
||||
@@ -25,6 +26,7 @@ pub struct TabBar {
|
||||
last_empty_space: AnyElement,
|
||||
selected_index: Option<usize>,
|
||||
menu: bool,
|
||||
segmented: bool,
|
||||
#[allow(clippy::type_complexity)]
|
||||
on_click: Option<Rc<dyn Fn(&usize, &mut Window, &mut App) + 'static>>,
|
||||
}
|
||||
@@ -43,9 +45,16 @@ impl TabBar {
|
||||
selected_index: None,
|
||||
on_click: None,
|
||||
menu: false,
|
||||
segmented: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Render the tabs as a segmented control inside a pill-shaped track.
|
||||
pub fn segmented(mut self, segmented: bool) -> Self {
|
||||
self.segmented = segmented;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set whether to show the menu button when tabs overflow, default is false.
|
||||
pub fn menu(mut self, menu: bool) -> Self {
|
||||
self.menu = menu;
|
||||
@@ -113,10 +122,11 @@ impl Styled for TabBar {
|
||||
}
|
||||
|
||||
impl RenderOnce for TabBar {
|
||||
fn render(self, _: &mut Window, _cx: &mut App) -> impl IntoElement {
|
||||
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let mut item_labels = Vec::new();
|
||||
let selected_index = self.selected_index;
|
||||
let on_click = self.on_click.clone();
|
||||
let segmented = self.segmented;
|
||||
|
||||
self.base
|
||||
.group("tab-bar")
|
||||
@@ -124,22 +134,28 @@ impl RenderOnce for TabBar {
|
||||
.flex()
|
||||
.items_center()
|
||||
.refine_style(&self.style)
|
||||
.when(segmented, |this| {
|
||||
this.bg(cx.theme().tab_background)
|
||||
.p_0p5()
|
||||
.rounded(cx.theme().radius)
|
||||
})
|
||||
.when_some(self.prefix, |this, prefix| this.child(prefix))
|
||||
.child(
|
||||
h_flex()
|
||||
.id("tabs")
|
||||
.flex_1()
|
||||
.overflow_x_scroll()
|
||||
.when(!segmented, |this| this.overflow_x_scroll())
|
||||
.when_some(self.scroll_handle, |this, scroll_handle| {
|
||||
this.track_scroll(&scroll_handle)
|
||||
})
|
||||
.gap(px(0.))
|
||||
.gap_1()
|
||||
.children(self.children.into_iter().enumerate().map(|(ix, child)| {
|
||||
item_labels.push((child.label.clone(), child.disabled));
|
||||
let tab_bar_prefix = child.tab_bar_prefix.unwrap_or(true);
|
||||
child
|
||||
.ix(ix)
|
||||
.tab_bar_prefix(tab_bar_prefix)
|
||||
.segmented(segmented)
|
||||
.when_some(self.selected_index, |this, selected_ix| {
|
||||
this.selected(selected_ix == ix)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user