dock: Add zoomable support to Panel. (#269)

This commit is contained in:
Jason Lee 2024-09-24 22:37:29 +08:00 committed by GitHub
parent 1e44b5659f
commit 2d6f478512
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 85 additions and 9 deletions

View file

@ -36,6 +36,10 @@ impl super::Story for IconStory {
fn new_view(cx: &mut WindowContext) -> View<impl gpui::FocusableView> {
Self::view(cx)
}
fn zoomable() -> bool {
false
}
}
impl gpui::FocusableView for IconStory {

View file

@ -67,10 +67,12 @@ pub fn init(cx: &mut AppContext) {
};
let view = cx.new_view(|cx| {
let (title, description, story) = story_state.to_story(cx);
let (title, description, closeable, zoomable, story) = story_state.to_story(cx);
let mut container = StoryContainer::new(cx).story(story, story_state.story_klass);
container.name = title.into();
container.description = description.into();
container.closeable = closeable;
container.zoomable = zoomable;
container
});
Box::new(view)
@ -106,6 +108,7 @@ pub struct StoryContainer {
story: Option<AnyView>,
story_klass: Option<SharedString>,
closeable: bool,
zoomable: bool,
}
#[derive(Debug)]
@ -125,6 +128,9 @@ pub trait Story: FocusableView {
fn closeable() -> bool {
true
}
fn zoomable() -> bool {
true
}
fn title_bg() -> Option<Hsla> {
None
}
@ -147,10 +153,10 @@ impl StoryContainer {
story: None,
story_klass: None,
closeable: true,
zoomable: true,
}
}
#[allow(clippy::too_many_arguments)]
pub fn panel<S: Story>(cx: &mut WindowContext) -> View<Self> {
let name = S::title();
let description = S::description();
@ -162,6 +168,7 @@ impl StoryContainer {
let mut story = Self::new(cx).story(story.into(), story_klass);
story.focus_handle = focus_handle;
story.closeable = S::closeable();
story.zoomable = S::zoomable();
story.name = name.into();
story.description = description.into();
story.title_bg = S::title_bg();
@ -211,12 +218,17 @@ impl StoryState {
serde_json::from_value(value).unwrap()
}
fn to_story(&self, cx: &mut WindowContext) -> (&'static str, &'static str, AnyView) {
fn to_story(
&self,
cx: &mut WindowContext,
) -> (&'static str, &'static str, bool, bool, AnyView) {
macro_rules! story {
($klass:tt) => {
(
$klass::title(),
$klass::description(),
$klass::closeable(),
$klass::zoomable(),
$klass::view(cx).into(),
)
};
@ -271,6 +283,10 @@ impl Panel for StoryContainer {
self.closeable
}
fn zoomable(&self, _cx: &WindowContext) -> bool {
self.zoomable
}
fn popup_menu(&self, menu: PopupMenu, _cx: &WindowContext) -> PopupMenu {
menu.track_focus(&self.focus_handle)
.menu("Info", Box::new(PanelInfo))

View file

@ -383,6 +383,10 @@ impl super::Story for TableStory {
fn new_view(cx: &mut WindowContext) -> View<impl gpui::FocusableView> {
Self::view(cx)
}
fn closeable() -> bool {
false
}
}
impl gpui::FocusableView for TableStory {

View file

@ -36,6 +36,10 @@ impl super::Story for TooltipStory {
fn new_view(cx: &mut WindowContext) -> View<impl gpui::FocusableView> {
Self::view(cx)
}
fn zoomable() -> bool {
false
}
}
impl gpui::FocusableView for TooltipStory {
fn focus_handle(&self, _: &gpui::AppContext) -> gpui::FocusHandle {

View file

@ -44,6 +44,16 @@ pub trait Panel: EventEmitter<PanelEvent> + FocusableView {
true
}
/// Return true if the panel is zoomable, default is `false`.
fn zoomable(&self, _cx: &WindowContext) -> bool {
true
}
/// Return true if the panel is collapsable, default is `false`.
fn collapsible(&self, _cx: &WindowContext) -> bool {
false
}
/// The addition popup menu of the panel, default is `None`.
fn popup_menu(&self, this: PopupMenu, _cx: &WindowContext) -> PopupMenu {
this
@ -56,11 +66,14 @@ pub trait Panel: EventEmitter<PanelEvent> + FocusableView {
}
pub trait PanelView: 'static + Send + Sync {
fn panel_name(&self, _cx: &WindowContext) -> &'static str;
fn title(&self, _cx: &WindowContext) -> AnyElement;
fn title_style(&self, _cx: &WindowContext) -> Option<TitleStyle>;
fn closeable(&self, cx: &WindowContext) -> bool;
fn zoomable(&self, cx: &WindowContext) -> bool;
fn collapsible(&self, cx: &WindowContext) -> bool;
fn popup_menu(&self, menu: PopupMenu, cx: &WindowContext) -> PopupMenu;
@ -72,6 +85,9 @@ pub trait PanelView: 'static + Send + Sync {
}
impl<T: Panel> PanelView for View<T> {
fn panel_name(&self, cx: &WindowContext) -> &'static str {
self.read(cx).panel_name()
}
fn title(&self, cx: &WindowContext) -> AnyElement {
self.read(cx).title(cx)
}
@ -84,6 +100,14 @@ impl<T: Panel> PanelView for View<T> {
self.read(cx).closeable(cx)
}
fn zoomable(&self, cx: &WindowContext) -> bool {
self.read(cx).zoomable(cx)
}
fn collapsible(&self, cx: &WindowContext) -> bool {
self.read(cx).collapsible(cx)
}
fn popup_menu(&self, menu: PopupMenu, cx: &WindowContext) -> PopupMenu {
self.read(cx).popup_menu(menu, cx)
}

View file

@ -85,6 +85,18 @@ impl Panel for TabPanel {
.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)
@ -140,6 +152,12 @@ impl TabPanel {
/// Add a panel to the end of the tabs
pub fn add_panel(&mut self, panel: Arc<dyn PanelView>, cx: &mut ViewContext<Self>) {
assert_ne!(
panel.panel_name(cx),
"StackPanel",
"can not allows add `StackPanel` to `TabPanel`"
);
if self
.panels
.iter()
@ -228,8 +246,10 @@ impl TabPanel {
}
fn render_menu_button(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let is_zoomed = self.is_zoomed;
let closeable = self.closeable(cx);
let zoomable = self.zoomable(cx);
let is_zoomed = self.is_zoomed && zoomable;
let view = cx.view().clone();
let build_popup_menu = move |this, cx: &WindowContext| view.read(cx).popup_menu(this, cx);
@ -256,14 +276,14 @@ impl TabPanel {
.ghost()
.popup_menu(move |this, cx| {
build_popup_menu(this, cx)
.menu(
if is_zoomed {
.when(zoomable, |this| {
let name = if is_zoomed {
t!("Dock.Zoom Out")
} else {
t!("Dock.Zoom In")
},
Box::new(ToggleZoom),
)
};
this.separator().menu(name, Box::new(ToggleZoom))
})
.when(closeable, |this| {
this.separator()
.menu(t!("Dock.Close"), Box::new(ClosePanel))
@ -581,6 +601,10 @@ impl TabPanel {
}
fn on_action_toggle_zoom(&mut self, _: &ToggleZoom, cx: &mut ViewContext<Self>) {
if !self.zoomable(cx) {
return;
}
if !self.is_zoomed {
cx.emit(PanelEvent::ZoomIn)
} else {