198 lines
7 KiB
Rust
198 lines
7 KiB
Rust
use std::rc::Rc;
|
|
|
|
use gpui::{
|
|
AnyElement, App, AppContext, Context, Corner, Entity, FocusHandle, InteractiveElement as _,
|
|
IntoElement, MouseButton, ParentElement as _, Render, SharedString, Styled as _, Subscription,
|
|
Window, div, px,
|
|
};
|
|
use gpui_component::{
|
|
ActiveTheme as _, ContextModal as _, IconName, PixelsExt, Sizable as _, Theme, TitleBar,
|
|
badge::Badge,
|
|
button::{Button, ButtonVariants as _},
|
|
menu::AppMenuBar,
|
|
menu::DropdownMenu as _,
|
|
scroll::ScrollbarShow,
|
|
};
|
|
|
|
use crate::{SelectFont, SelectRadius, SelectScrollbarShow, app_menus};
|
|
|
|
pub struct AppTitleBar {
|
|
app_menu_bar: Entity<AppMenuBar>,
|
|
font_size_selector: Entity<FontSizeSelector>,
|
|
child: Rc<dyn Fn(&mut Window, &mut App) -> AnyElement>,
|
|
_subscriptions: Vec<Subscription>,
|
|
}
|
|
|
|
impl AppTitleBar {
|
|
pub fn new(
|
|
title: impl Into<SharedString>,
|
|
window: &mut Window,
|
|
cx: &mut Context<Self>,
|
|
) -> Self {
|
|
app_menus::init(title, cx);
|
|
|
|
let font_size_selector = cx.new(|cx| FontSizeSelector::new(window, cx));
|
|
let app_menu_bar = AppMenuBar::new(window, cx);
|
|
|
|
Self {
|
|
app_menu_bar,
|
|
font_size_selector,
|
|
child: Rc::new(|_, _| div().into_any_element()),
|
|
_subscriptions: vec![],
|
|
}
|
|
}
|
|
|
|
pub fn child<F, E>(mut self, f: F) -> Self
|
|
where
|
|
E: IntoElement,
|
|
F: Fn(&mut Window, &mut App) -> E + 'static,
|
|
{
|
|
self.child = Rc::new(move |window, cx| f(window, cx).into_any_element());
|
|
self
|
|
}
|
|
}
|
|
|
|
impl Render for AppTitleBar {
|
|
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
|
let notifications_count = window.notifications(cx).len();
|
|
|
|
TitleBar::new()
|
|
// left side
|
|
.child(div().flex().items_center().child(self.app_menu_bar.clone()))
|
|
.child(
|
|
div()
|
|
.flex()
|
|
.items_center()
|
|
.justify_end()
|
|
.px_2()
|
|
.gap_2()
|
|
.on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
|
|
.child((self.child.clone())(window, cx))
|
|
.child(self.font_size_selector.clone())
|
|
.child(
|
|
Button::new("github")
|
|
.icon(IconName::GitHub)
|
|
.small()
|
|
.ghost()
|
|
.on_click(|_, _, cx| {
|
|
cx.open_url("https://github.com/longbridge/gpui-component")
|
|
}),
|
|
)
|
|
.child(
|
|
div().relative().child(
|
|
Badge::new().count(notifications_count).max(99).child(
|
|
Button::new("bell")
|
|
.small()
|
|
.ghost()
|
|
.compact()
|
|
.icon(IconName::Bell),
|
|
),
|
|
),
|
|
),
|
|
)
|
|
}
|
|
}
|
|
|
|
struct FontSizeSelector {
|
|
focus_handle: FocusHandle,
|
|
}
|
|
|
|
impl FontSizeSelector {
|
|
pub fn new(_: &mut Window, cx: &mut Context<Self>) -> Self {
|
|
Self {
|
|
focus_handle: cx.focus_handle(),
|
|
}
|
|
}
|
|
|
|
fn on_select_font(
|
|
&mut self,
|
|
font_size: &SelectFont,
|
|
window: &mut Window,
|
|
cx: &mut Context<Self>,
|
|
) {
|
|
Theme::global_mut(cx).font_size = px(font_size.0 as f32);
|
|
window.refresh();
|
|
}
|
|
|
|
fn on_select_radius(
|
|
&mut self,
|
|
radius: &SelectRadius,
|
|
window: &mut Window,
|
|
cx: &mut Context<Self>,
|
|
) {
|
|
Theme::global_mut(cx).radius = px(radius.0 as f32);
|
|
window.refresh();
|
|
}
|
|
|
|
fn on_select_scrollbar_show(
|
|
&mut self,
|
|
show: &SelectScrollbarShow,
|
|
window: &mut Window,
|
|
cx: &mut Context<Self>,
|
|
) {
|
|
Theme::global_mut(cx).scrollbar_show = show.0;
|
|
window.refresh();
|
|
}
|
|
}
|
|
|
|
impl Render for FontSizeSelector {
|
|
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
|
let focus_handle = self.focus_handle.clone();
|
|
let font_size = cx.theme().font_size.as_f32() as i32;
|
|
let radius = cx.theme().radius.as_f32() as i32;
|
|
let scroll_show = cx.theme().scrollbar_show;
|
|
|
|
div()
|
|
.id("font-size-selector")
|
|
.track_focus(&focus_handle)
|
|
.on_action(cx.listener(Self::on_select_font))
|
|
.on_action(cx.listener(Self::on_select_radius))
|
|
.on_action(cx.listener(Self::on_select_scrollbar_show))
|
|
.child(
|
|
Button::new("btn")
|
|
.small()
|
|
.ghost()
|
|
.icon(IconName::Settings2)
|
|
.dropdown_menu(move |this, _, _| {
|
|
this.scrollable(true)
|
|
.max_h(px(480.))
|
|
.label("Font Size")
|
|
.menu_with_check("Large", font_size == 18, Box::new(SelectFont(18)))
|
|
.menu_with_check(
|
|
"Medium (default)",
|
|
font_size == 16,
|
|
Box::new(SelectFont(16)),
|
|
)
|
|
.menu_with_check("Small", font_size == 14, Box::new(SelectFont(14)))
|
|
.separator()
|
|
.label("Border Radius")
|
|
.menu_with_check("8px", radius == 8, Box::new(SelectRadius(8)))
|
|
.menu_with_check(
|
|
"6px (default)",
|
|
radius == 6,
|
|
Box::new(SelectRadius(6)),
|
|
)
|
|
.menu_with_check("4px", radius == 4, Box::new(SelectRadius(4)))
|
|
.menu_with_check("0px", radius == 0, Box::new(SelectRadius(0)))
|
|
.separator()
|
|
.label("Scrollbar")
|
|
.menu_with_check(
|
|
"Scrolling to show",
|
|
scroll_show == ScrollbarShow::Scrolling,
|
|
Box::new(SelectScrollbarShow(ScrollbarShow::Scrolling)),
|
|
)
|
|
.menu_with_check(
|
|
"Hover to show",
|
|
scroll_show == ScrollbarShow::Hover,
|
|
Box::new(SelectScrollbarShow(ScrollbarShow::Hover)),
|
|
)
|
|
.menu_with_check(
|
|
"Always show",
|
|
scroll_show == ScrollbarShow::Always,
|
|
Box::new(SelectScrollbarShow(ScrollbarShow::Always)),
|
|
)
|
|
})
|
|
.anchor(Corner::TopRight),
|
|
)
|
|
}
|
|
}
|