panel: Support custom style for the panel title (#220)
This commit is contained in:
parent
e1d6b3aaed
commit
d6015f636c
4 changed files with 66 additions and 6 deletions
|
|
@ -94,6 +94,7 @@ impl StoryWorkspace {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -105,6 +106,7 @@ impl StoryWorkspace {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -116,6 +118,7 @@ impl StoryWorkspace {
|
||||||
Some(Placement::Bottom),
|
Some(Placement::Bottom),
|
||||||
Some(px(200.)),
|
Some(px(200.)),
|
||||||
true,
|
true,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -127,6 +130,7 @@ impl StoryWorkspace {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -138,6 +142,7 @@ impl StoryWorkspace {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -149,6 +154,7 @@ impl StoryWorkspace {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -160,6 +166,7 @@ impl StoryWorkspace {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -171,6 +178,7 @@ impl StoryWorkspace {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -182,6 +190,7 @@ impl StoryWorkspace {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -193,6 +202,7 @@ impl StoryWorkspace {
|
||||||
Some(Placement::Bottom),
|
Some(Placement::Bottom),
|
||||||
Some(px(200.)),
|
Some(px(200.)),
|
||||||
true,
|
true,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -204,6 +214,7 @@ impl StoryWorkspace {
|
||||||
Some(Placement::Bottom),
|
Some(Placement::Bottom),
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
|
Some(cx.theme().muted),
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -223,6 +234,7 @@ impl StoryWorkspace {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -234,6 +246,7 @@ impl StoryWorkspace {
|
||||||
Some(Placement::Bottom),
|
Some(Placement::Bottom),
|
||||||
Some(px(200.)),
|
Some(px(200.)),
|
||||||
true,
|
true,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -245,6 +258,7 @@ impl StoryWorkspace {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -256,6 +270,7 @@ impl StoryWorkspace {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -267,6 +282,7 @@ impl StoryWorkspace {
|
||||||
Some(Placement::Bottom),
|
Some(Placement::Bottom),
|
||||||
None,
|
None,
|
||||||
true,
|
true,
|
||||||
|
None,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,17 +38,19 @@ pub use webview_story::WebViewStory;
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, div, prelude::FluentBuilder as _, px, AnyView, AppContext, Div, EventEmitter,
|
actions, div, prelude::FluentBuilder as _, px, AnyView, AppContext, Div, EventEmitter,
|
||||||
FocusableView, InteractiveElement, IntoElement, ParentElement, Pixels, Render, SharedString,
|
FocusableView, Hsla, InteractiveElement, IntoElement, ParentElement, Pixels, Render,
|
||||||
StatefulInteractiveElement, Styled as _, View, ViewContext, VisualContext, WindowContext,
|
SharedString, StatefulInteractiveElement, Styled as _, View, ViewContext, VisualContext,
|
||||||
|
WindowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ui::{
|
use ui::{
|
||||||
divider::Divider,
|
divider::Divider,
|
||||||
dock::{Panel, PanelEvent, TabPanel},
|
dock::{Panel, PanelEvent, TabPanel, TitleStyle},
|
||||||
h_flex,
|
h_flex,
|
||||||
label::Label,
|
label::Label,
|
||||||
notification::Notification,
|
notification::Notification,
|
||||||
popup_menu::PopupMenu,
|
popup_menu::PopupMenu,
|
||||||
|
theme::ActiveTheme,
|
||||||
v_flex, ContextModal, Placement,
|
v_flex, ContextModal, Placement,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -80,6 +82,7 @@ pub fn section(title: impl IntoElement, cx: &WindowContext) -> Div {
|
||||||
pub struct StoryContainer {
|
pub struct StoryContainer {
|
||||||
focus_handle: gpui::FocusHandle,
|
focus_handle: gpui::FocusHandle,
|
||||||
name: SharedString,
|
name: SharedString,
|
||||||
|
title_bg: Option<Hsla>,
|
||||||
description: SharedString,
|
description: SharedString,
|
||||||
width: Option<gpui::Pixels>,
|
width: Option<gpui::Pixels>,
|
||||||
height: Option<gpui::Pixels>,
|
height: Option<gpui::Pixels>,
|
||||||
|
|
@ -106,6 +109,7 @@ impl StoryContainer {
|
||||||
Self {
|
Self {
|
||||||
focus_handle,
|
focus_handle,
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
|
title_bg: None,
|
||||||
description: description.into(),
|
description: description.into(),
|
||||||
width: None,
|
width: None,
|
||||||
height: None,
|
height: None,
|
||||||
|
|
@ -123,13 +127,18 @@ impl StoryContainer {
|
||||||
placement: Option<Placement>,
|
placement: Option<Placement>,
|
||||||
size: Option<Pixels>,
|
size: Option<Pixels>,
|
||||||
closeable: bool,
|
closeable: bool,
|
||||||
|
title_bg: Option<Hsla>,
|
||||||
cx: &mut WindowContext,
|
cx: &mut WindowContext,
|
||||||
) {
|
) {
|
||||||
let name = name.into();
|
let name = name.into();
|
||||||
let description = description.into();
|
let description = description.into();
|
||||||
|
|
||||||
tab_panel.update(cx, |panel, cx| {
|
tab_panel.update(cx, |panel, cx| {
|
||||||
let view = cx.new_view(|cx| Self::new(name, description, closeable, cx).story(story));
|
let view = cx.new_view(|cx| {
|
||||||
|
Self::new(name, description, closeable, cx)
|
||||||
|
.story(story)
|
||||||
|
.title_bg(title_bg)
|
||||||
|
});
|
||||||
if let Some(placement) = placement {
|
if let Some(placement) = placement {
|
||||||
panel.add_panel_at(Arc::new(view.clone()), placement, size, cx);
|
panel.add_panel_at(Arc::new(view.clone()), placement, size, cx);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -154,6 +163,11 @@ impl StoryContainer {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn title_bg(mut self, title_bg: Option<Hsla>) -> Self {
|
||||||
|
self.title_bg = title_bg;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn on_action_panel_info(&mut self, _: &PanelInfo, cx: &mut ViewContext<Self>) {
|
fn on_action_panel_info(&mut self, _: &PanelInfo, cx: &mut ViewContext<Self>) {
|
||||||
struct Info;
|
struct Info;
|
||||||
let note = Notification::new(format!("You have clicked panel info on: {}", self.name))
|
let note = Notification::new(format!("You have clicked panel info on: {}", self.name))
|
||||||
|
|
@ -167,6 +181,17 @@ impl Panel for StoryContainer {
|
||||||
self.name.clone()
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn title_style(&self, cx: &WindowContext) -> Option<TitleStyle> {
|
||||||
|
if let Some(bg) = self.title_bg {
|
||||||
|
Some(TitleStyle {
|
||||||
|
background: bg,
|
||||||
|
foreground: cx.theme().foreground,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn closeable(&self, _cx: &WindowContext) -> bool {
|
fn closeable(&self, _cx: &WindowContext) -> bool {
|
||||||
self.closeable
|
self.closeable
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,26 @@
|
||||||
use gpui::{AnyView, EventEmitter, FocusableView, SharedString, View, WindowContext};
|
use gpui::{AnyView, EventEmitter, FocusableView, Hsla, SharedString, View, WindowContext};
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
|
|
||||||
use crate::popup_menu::PopupMenu;
|
use crate::popup_menu::PopupMenu;
|
||||||
|
|
||||||
use super::PanelEvent;
|
use super::PanelEvent;
|
||||||
|
|
||||||
|
pub struct TitleStyle {
|
||||||
|
pub background: Hsla,
|
||||||
|
pub foreground: Hsla,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Panel: EventEmitter<PanelEvent> + FocusableView {
|
pub trait Panel: EventEmitter<PanelEvent> + FocusableView {
|
||||||
/// The title of the panel, default is `None`.
|
/// The title of the panel, default is `None`.
|
||||||
fn title(&self, _cx: &WindowContext) -> SharedString {
|
fn title(&self, _cx: &WindowContext) -> SharedString {
|
||||||
t!("Dock.Unnamed").into()
|
t!("Dock.Unnamed").into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The theme of the panel title, default is `None`.
|
||||||
|
fn title_style(&self, _cx: &WindowContext) -> Option<TitleStyle> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether the panel can be closed, default is `true`.
|
/// Whether the panel can be closed, default is `true`.
|
||||||
fn closeable(&self, _cx: &WindowContext) -> bool {
|
fn closeable(&self, _cx: &WindowContext) -> bool {
|
||||||
true
|
true
|
||||||
|
|
@ -23,9 +33,10 @@ pub trait Panel: EventEmitter<PanelEvent> + FocusableView {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PanelView: 'static + Send + Sync {
|
pub trait PanelView: 'static + Send + Sync {
|
||||||
/// The title of the panel, default is `None`.
|
|
||||||
fn title(&self, _cx: &WindowContext) -> SharedString;
|
fn title(&self, _cx: &WindowContext) -> SharedString;
|
||||||
|
|
||||||
|
fn title_style(&self, _cx: &WindowContext) -> Option<TitleStyle>;
|
||||||
|
|
||||||
fn closeable(&self, cx: &WindowContext) -> bool;
|
fn closeable(&self, cx: &WindowContext) -> bool;
|
||||||
|
|
||||||
fn popup_menu(&self, menu: PopupMenu, cx: &WindowContext) -> PopupMenu;
|
fn popup_menu(&self, menu: PopupMenu, cx: &WindowContext) -> PopupMenu;
|
||||||
|
|
@ -38,6 +49,10 @@ impl<T: Panel> PanelView for View<T> {
|
||||||
self.read(cx).title(cx)
|
self.read(cx).title(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn title_style(&self, cx: &WindowContext) -> Option<TitleStyle> {
|
||||||
|
self.read(cx).title_style(cx)
|
||||||
|
}
|
||||||
|
|
||||||
fn closeable(&self, cx: &WindowContext) -> bool {
|
fn closeable(&self, cx: &WindowContext) -> bool {
|
||||||
self.read(cx).closeable(cx)
|
self.read(cx).closeable(cx)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -242,12 +242,16 @@ impl TabPanel {
|
||||||
if self.panels.len() == 1 {
|
if self.panels.len() == 1 {
|
||||||
let panel = self.panels.get(0).unwrap();
|
let panel = self.panels.get(0).unwrap();
|
||||||
let title = panel.title(cx);
|
let title = panel.title(cx);
|
||||||
|
let title_style = panel.title_style(cx);
|
||||||
|
|
||||||
return h_flex()
|
return h_flex()
|
||||||
.justify_between()
|
.justify_between()
|
||||||
.items_center()
|
.items_center()
|
||||||
.line_height(rems(1.0))
|
.line_height(rems(1.0))
|
||||||
.pr_3()
|
.pr_3()
|
||||||
|
.when_some(title_style, |this, theme| {
|
||||||
|
this.bg(theme.background).text_color(theme.foreground)
|
||||||
|
})
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.id("tab")
|
.id("tab")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue