dock: Add zoomable support to Panel. (#269)
This commit is contained in:
parent
1e44b5659f
commit
2d6f478512
6 changed files with 85 additions and 9 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue