Eliminate GPUI View, ViewContext, and WindowContext types (#22632)
There's still a bit more work to do on this, but this PR is compiling (with warnings) after eliminating the key types. When the tasks below are complete, this will be the new narrative for GPUI: - `Entity<T>` - This replaces `View<T>`/`Model<T>`. It represents a unit of state, and if `T` implements `Render`, then `Entity<T>` implements `Element`. - `&mut App` This replaces `AppContext` and represents the app. - `&mut Context<T>` This replaces `ModelContext` and derefs to `App`. It is provided by the framework when updating an entity. - `&mut Window` Broken out of `&mut WindowContext` which no longer exists. Every method that once took `&mut WindowContext` now takes `&mut Window, &mut App` and every method that took `&mut ViewContext<T>` now takes `&mut Window, &mut Context<T>` Not pictured here are the two other failed attempts. It's been quite a month! Tasks: - [x] Remove `View`, `ViewContext`, `WindowContext` and thread through `Window` - [x] [@cole-miller @mikayla-maki] Redraw window when entities change - [x] [@cole-miller @mikayla-maki] Get examples and Zed running - [x] [@cole-miller @mikayla-maki] Fix Zed rendering - [x] [@mikayla-maki] Fix todo! macros and comments - [x] Fix a bug where the editor would not be redrawn because of view caching - [x] remove publicness window.notify() and replace with `AppContext::notify` - [x] remove `observe_new_window_models`, replace with `observe_new_models` with an optional window - [x] Fix a bug where the project panel would not be redrawn because of the wrong refresh() call being used - [x] Fix the tests - [x] Fix warnings by eliminating `Window` params or using `_` - [x] Fix conflicts - [x] Simplify generic code where possible - [x] Rename types - [ ] Update docs ### issues post merge - [x] Issues switching between normal and insert mode - [x] Assistant re-rendering failure - [x] Vim test failures - [x] Mac build issue Release Notes: - N/A --------- Co-authored-by: Antonio Scandurra <me@as-cii.com> Co-authored-by: Cole Miller <cole@zed.dev> Co-authored-by: Mikayla <mikayla@zed.dev> Co-authored-by: Joseph <joseph@zed.dev> Co-authored-by: max <max@zed.dev> Co-authored-by: Michael Sloan <michael@zed.dev> Co-authored-by: Mikayla Maki <mikaylamaki@Mikaylas-MacBook-Pro.local> Co-authored-by: Mikayla <mikayla.c.maki@gmail.com> Co-authored-by: joão <joao@zed.dev>
This commit is contained in:
parent
21b4a0d50e
commit
6fca1d2b0b
648 changed files with 36248 additions and 28208 deletions
|
@ -3,10 +3,9 @@ use crate::{status_bar::StatusItemView, Workspace};
|
|||
use crate::{DraggedDock, Event, Pane};
|
||||
use client::proto;
|
||||
use gpui::{
|
||||
deferred, div, px, Action, AnyView, AppContext, Axis, Corner, Entity, EntityId, EventEmitter,
|
||||
FocusHandle, FocusableView, IntoElement, KeyContext, MouseButton, MouseDownEvent, MouseUpEvent,
|
||||
ParentElement, Render, SharedString, StyleRefinement, Styled, Subscription, View, ViewContext,
|
||||
VisualContext, WeakView, WindowContext,
|
||||
deferred, div, px, Action, AnyView, App, Axis, Context, Corner, Entity, EntityId, EventEmitter,
|
||||
FocusHandle, Focusable, IntoElement, KeyContext, MouseButton, MouseDownEvent, MouseUpEvent,
|
||||
ParentElement, Render, SharedString, StyleRefinement, Styled, Subscription, WeakEntity, Window,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -26,28 +25,28 @@ pub enum PanelEvent {
|
|||
|
||||
pub use proto::PanelId;
|
||||
|
||||
pub trait Panel: FocusableView + EventEmitter<PanelEvent> {
|
||||
pub trait Panel: Focusable + EventEmitter<PanelEvent> + Render + Sized {
|
||||
fn persistent_name() -> &'static str;
|
||||
fn position(&self, cx: &WindowContext) -> DockPosition;
|
||||
fn position(&self, window: &Window, cx: &App) -> DockPosition;
|
||||
fn position_is_valid(&self, position: DockPosition) -> bool;
|
||||
fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext<Self>);
|
||||
fn size(&self, cx: &WindowContext) -> Pixels;
|
||||
fn set_size(&mut self, size: Option<Pixels>, cx: &mut ViewContext<Self>);
|
||||
fn icon(&self, cx: &WindowContext) -> Option<ui::IconName>;
|
||||
fn icon_tooltip(&self, cx: &WindowContext) -> Option<&'static str>;
|
||||
fn set_position(&mut self, position: DockPosition, window: &mut Window, cx: &mut Context<Self>);
|
||||
fn size(&self, window: &Window, cx: &App) -> Pixels;
|
||||
fn set_size(&mut self, size: Option<Pixels>, window: &mut Window, cx: &mut Context<Self>);
|
||||
fn icon(&self, window: &Window, cx: &App) -> Option<ui::IconName>;
|
||||
fn icon_tooltip(&self, window: &Window, cx: &App) -> Option<&'static str>;
|
||||
fn toggle_action(&self) -> Box<dyn Action>;
|
||||
fn icon_label(&self, _: &WindowContext) -> Option<String> {
|
||||
fn icon_label(&self, _window: &Window, _: &App) -> Option<String> {
|
||||
None
|
||||
}
|
||||
fn is_zoomed(&self, _cx: &WindowContext) -> bool {
|
||||
fn is_zoomed(&self, _window: &Window, _cx: &App) -> bool {
|
||||
false
|
||||
}
|
||||
fn starts_open(&self, _cx: &WindowContext) -> bool {
|
||||
fn starts_open(&self, _window: &Window, _cx: &App) -> bool {
|
||||
false
|
||||
}
|
||||
fn set_zoomed(&mut self, _zoomed: bool, _cx: &mut ViewContext<Self>) {}
|
||||
fn set_active(&mut self, _active: bool, _cx: &mut ViewContext<Self>) {}
|
||||
fn pane(&self) -> Option<View<Pane>> {
|
||||
fn set_zoomed(&mut self, _zoomed: bool, _window: &mut Window, _cx: &mut Context<Self>) {}
|
||||
fn set_active(&mut self, _active: bool, _window: &mut Window, _cx: &mut Context<Self>) {}
|
||||
fn pane(&self) -> Option<Entity<Pane>> {
|
||||
None
|
||||
}
|
||||
fn remote_id() -> Option<proto::PanelId> {
|
||||
|
@ -59,25 +58,25 @@ pub trait Panel: FocusableView + EventEmitter<PanelEvent> {
|
|||
pub trait PanelHandle: Send + Sync {
|
||||
fn panel_id(&self) -> EntityId;
|
||||
fn persistent_name(&self) -> &'static str;
|
||||
fn position(&self, cx: &WindowContext) -> DockPosition;
|
||||
fn position_is_valid(&self, position: DockPosition, cx: &WindowContext) -> bool;
|
||||
fn set_position(&self, position: DockPosition, cx: &mut WindowContext);
|
||||
fn is_zoomed(&self, cx: &WindowContext) -> bool;
|
||||
fn set_zoomed(&self, zoomed: bool, cx: &mut WindowContext);
|
||||
fn set_active(&self, active: bool, cx: &mut WindowContext);
|
||||
fn position(&self, window: &Window, cx: &App) -> DockPosition;
|
||||
fn position_is_valid(&self, position: DockPosition, cx: &App) -> bool;
|
||||
fn set_position(&self, position: DockPosition, window: &mut Window, cx: &mut App);
|
||||
fn is_zoomed(&self, window: &Window, cx: &App) -> bool;
|
||||
fn set_zoomed(&self, zoomed: bool, window: &mut Window, cx: &mut App);
|
||||
fn set_active(&self, active: bool, window: &mut Window, cx: &mut App);
|
||||
fn remote_id(&self) -> Option<proto::PanelId>;
|
||||
fn pane(&self, cx: &WindowContext) -> Option<View<Pane>>;
|
||||
fn size(&self, cx: &WindowContext) -> Pixels;
|
||||
fn set_size(&self, size: Option<Pixels>, cx: &mut WindowContext);
|
||||
fn icon(&self, cx: &WindowContext) -> Option<ui::IconName>;
|
||||
fn icon_tooltip(&self, cx: &WindowContext) -> Option<&'static str>;
|
||||
fn toggle_action(&self, cx: &WindowContext) -> Box<dyn Action>;
|
||||
fn icon_label(&self, cx: &WindowContext) -> Option<String>;
|
||||
fn focus_handle(&self, cx: &AppContext) -> FocusHandle;
|
||||
fn pane(&self, cx: &App) -> Option<Entity<Pane>>;
|
||||
fn size(&self, window: &Window, cx: &App) -> Pixels;
|
||||
fn set_size(&self, size: Option<Pixels>, window: &mut Window, cx: &mut App);
|
||||
fn icon(&self, window: &Window, cx: &App) -> Option<ui::IconName>;
|
||||
fn icon_tooltip(&self, window: &Window, cx: &App) -> Option<&'static str>;
|
||||
fn toggle_action(&self, window: &Window, cx: &App) -> Box<dyn Action>;
|
||||
fn icon_label(&self, window: &Window, cx: &App) -> Option<String>;
|
||||
fn panel_focus_handle(&self, cx: &App) -> FocusHandle;
|
||||
fn to_any(&self) -> AnyView;
|
||||
fn activation_priority(&self, cx: &AppContext) -> u32;
|
||||
fn move_to_next_position(&self, cx: &mut WindowContext) {
|
||||
let current_position = self.position(cx);
|
||||
fn activation_priority(&self, cx: &App) -> u32;
|
||||
fn move_to_next_position(&self, window: &mut Window, cx: &mut App) {
|
||||
let current_position = self.position(window, cx);
|
||||
let next_position = [
|
||||
DockPosition::Left,
|
||||
DockPosition::Bottom,
|
||||
|
@ -89,11 +88,11 @@ pub trait PanelHandle: Send + Sync {
|
|||
.nth(1)
|
||||
.unwrap_or(DockPosition::Left);
|
||||
|
||||
self.set_position(next_position, cx);
|
||||
self.set_position(next_position, window, cx);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PanelHandle for View<T>
|
||||
impl<T> PanelHandle for Entity<T>
|
||||
where
|
||||
T: Panel,
|
||||
{
|
||||
|
@ -105,31 +104,31 @@ where
|
|||
T::persistent_name()
|
||||
}
|
||||
|
||||
fn position(&self, cx: &WindowContext) -> DockPosition {
|
||||
self.read(cx).position(cx)
|
||||
fn position(&self, window: &Window, cx: &App) -> DockPosition {
|
||||
self.read(cx).position(window, cx)
|
||||
}
|
||||
|
||||
fn position_is_valid(&self, position: DockPosition, cx: &WindowContext) -> bool {
|
||||
fn position_is_valid(&self, position: DockPosition, cx: &App) -> bool {
|
||||
self.read(cx).position_is_valid(position)
|
||||
}
|
||||
|
||||
fn set_position(&self, position: DockPosition, cx: &mut WindowContext) {
|
||||
self.update(cx, |this, cx| this.set_position(position, cx))
|
||||
fn set_position(&self, position: DockPosition, window: &mut Window, cx: &mut App) {
|
||||
self.update(cx, |this, cx| this.set_position(position, window, cx))
|
||||
}
|
||||
|
||||
fn is_zoomed(&self, cx: &WindowContext) -> bool {
|
||||
self.read(cx).is_zoomed(cx)
|
||||
fn is_zoomed(&self, window: &Window, cx: &App) -> bool {
|
||||
self.read(cx).is_zoomed(window, cx)
|
||||
}
|
||||
|
||||
fn set_zoomed(&self, zoomed: bool, cx: &mut WindowContext) {
|
||||
self.update(cx, |this, cx| this.set_zoomed(zoomed, cx))
|
||||
fn set_zoomed(&self, zoomed: bool, window: &mut Window, cx: &mut App) {
|
||||
self.update(cx, |this, cx| this.set_zoomed(zoomed, window, cx))
|
||||
}
|
||||
|
||||
fn set_active(&self, active: bool, cx: &mut WindowContext) {
|
||||
self.update(cx, |this, cx| this.set_active(active, cx))
|
||||
fn set_active(&self, active: bool, window: &mut Window, cx: &mut App) {
|
||||
self.update(cx, |this, cx| this.set_active(active, window, cx))
|
||||
}
|
||||
|
||||
fn pane(&self, cx: &WindowContext) -> Option<View<Pane>> {
|
||||
fn pane(&self, cx: &App) -> Option<Entity<Pane>> {
|
||||
self.read(cx).pane()
|
||||
}
|
||||
|
||||
|
@ -137,39 +136,39 @@ where
|
|||
T::remote_id()
|
||||
}
|
||||
|
||||
fn size(&self, cx: &WindowContext) -> Pixels {
|
||||
self.read(cx).size(cx)
|
||||
fn size(&self, window: &Window, cx: &App) -> Pixels {
|
||||
self.read(cx).size(window, cx)
|
||||
}
|
||||
|
||||
fn set_size(&self, size: Option<Pixels>, cx: &mut WindowContext) {
|
||||
self.update(cx, |this, cx| this.set_size(size, cx))
|
||||
fn set_size(&self, size: Option<Pixels>, window: &mut Window, cx: &mut App) {
|
||||
self.update(cx, |this, cx| this.set_size(size, window, cx))
|
||||
}
|
||||
|
||||
fn icon(&self, cx: &WindowContext) -> Option<ui::IconName> {
|
||||
self.read(cx).icon(cx)
|
||||
fn icon(&self, window: &Window, cx: &App) -> Option<ui::IconName> {
|
||||
self.read(cx).icon(window, cx)
|
||||
}
|
||||
|
||||
fn icon_tooltip(&self, cx: &WindowContext) -> Option<&'static str> {
|
||||
self.read(cx).icon_tooltip(cx)
|
||||
fn icon_tooltip(&self, window: &Window, cx: &App) -> Option<&'static str> {
|
||||
self.read(cx).icon_tooltip(window, cx)
|
||||
}
|
||||
|
||||
fn toggle_action(&self, cx: &WindowContext) -> Box<dyn Action> {
|
||||
fn toggle_action(&self, _: &Window, cx: &App) -> Box<dyn Action> {
|
||||
self.read(cx).toggle_action()
|
||||
}
|
||||
|
||||
fn icon_label(&self, cx: &WindowContext) -> Option<String> {
|
||||
self.read(cx).icon_label(cx)
|
||||
fn icon_label(&self, window: &Window, cx: &App) -> Option<String> {
|
||||
self.read(cx).icon_label(window, cx)
|
||||
}
|
||||
|
||||
fn to_any(&self) -> AnyView {
|
||||
self.clone().into()
|
||||
}
|
||||
|
||||
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
|
||||
fn panel_focus_handle(&self, cx: &App) -> FocusHandle {
|
||||
self.read(cx).focus_handle(cx).clone()
|
||||
}
|
||||
|
||||
fn activation_priority(&self, cx: &AppContext) -> u32 {
|
||||
fn activation_priority(&self, cx: &App) -> u32 {
|
||||
self.read(cx).activation_priority()
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +184,7 @@ impl From<&dyn PanelHandle> for AnyView {
|
|||
pub struct Dock {
|
||||
position: DockPosition,
|
||||
panel_entries: Vec<PanelEntry>,
|
||||
workspace: WeakView<Workspace>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
is_open: bool,
|
||||
active_panel_index: Option<usize>,
|
||||
focus_handle: FocusHandle,
|
||||
|
@ -194,8 +193,8 @@ pub struct Dock {
|
|||
_subscriptions: [Subscription; 2],
|
||||
}
|
||||
|
||||
impl FocusableView for Dock {
|
||||
fn focus_handle(&self, _: &AppContext) -> FocusHandle {
|
||||
impl Focusable for Dock {
|
||||
fn focus_handle(&self, _: &App) -> FocusHandle {
|
||||
self.focus_handle.clone()
|
||||
}
|
||||
}
|
||||
|
@ -231,19 +230,24 @@ struct PanelEntry {
|
|||
}
|
||||
|
||||
pub struct PanelButtons {
|
||||
dock: View<Dock>,
|
||||
dock: Entity<Dock>,
|
||||
}
|
||||
|
||||
impl Dock {
|
||||
pub fn new(position: DockPosition, cx: &mut ViewContext<Workspace>) -> View<Self> {
|
||||
pub fn new(
|
||||
position: DockPosition,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Workspace>,
|
||||
) -> Entity<Self> {
|
||||
let focus_handle = cx.focus_handle();
|
||||
let workspace = cx.view().clone();
|
||||
let dock = cx.new_view(|cx: &mut ViewContext<Self>| {
|
||||
let focus_subscription = cx.on_focus(&focus_handle, |dock, cx| {
|
||||
if let Some(active_entry) = dock.active_panel_entry() {
|
||||
active_entry.panel.focus_handle(cx).focus(cx)
|
||||
}
|
||||
});
|
||||
let workspace = cx.model().clone();
|
||||
let dock = cx.new(|cx| {
|
||||
let focus_subscription =
|
||||
cx.on_focus(&focus_handle, window, |dock: &mut Dock, window, cx| {
|
||||
if let Some(active_entry) = dock.active_panel_entry() {
|
||||
active_entry.panel.panel_focus_handle(cx).focus(window)
|
||||
}
|
||||
});
|
||||
let zoom_subscription = cx.subscribe(&workspace, |dock, workspace, e: &Event, cx| {
|
||||
if matches!(e, Event::ZoomChanged) {
|
||||
let is_zoomed = workspace.read(cx).zoomed.is_some();
|
||||
|
@ -263,16 +267,16 @@ impl Dock {
|
|||
}
|
||||
});
|
||||
|
||||
cx.on_focus_in(&focus_handle, {
|
||||
cx.on_focus_in(&focus_handle, window, {
|
||||
let dock = dock.downgrade();
|
||||
move |workspace, cx| {
|
||||
move |workspace, window, cx| {
|
||||
let Some(dock) = dock.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let Some(panel) = dock.read(cx).active_panel() else {
|
||||
return;
|
||||
};
|
||||
if panel.is_zoomed(cx) {
|
||||
if panel.is_zoomed(window, cx) {
|
||||
workspace.zoomed = Some(panel.to_any().downgrade());
|
||||
workspace.zoomed_position = Some(position);
|
||||
} else {
|
||||
|
@ -280,16 +284,16 @@ impl Dock {
|
|||
workspace.zoomed_position = None;
|
||||
}
|
||||
cx.emit(Event::ZoomChanged);
|
||||
workspace.dismiss_zoomed_items_to_reveal(Some(position), cx);
|
||||
workspace.update_active_view_for_followers(cx)
|
||||
workspace.dismiss_zoomed_items_to_reveal(Some(position), window, cx);
|
||||
workspace.update_active_view_for_followers(window, cx)
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
cx.observe(&dock, move |workspace, dock, cx| {
|
||||
cx.observe_in(&dock, window, move |workspace, dock, window, cx| {
|
||||
if dock.read(cx).is_open() {
|
||||
if let Some(panel) = dock.read(cx).active_panel() {
|
||||
if panel.is_zoomed(cx) {
|
||||
if panel.is_zoomed(window, cx) {
|
||||
workspace.zoomed = Some(panel.to_any().downgrade());
|
||||
workspace.zoomed_position = Some(position);
|
||||
cx.emit(Event::ZoomChanged);
|
||||
|
@ -316,7 +320,7 @@ impl Dock {
|
|||
self.is_open
|
||||
}
|
||||
|
||||
pub fn panel<T: Panel>(&self) -> Option<View<T>> {
|
||||
pub fn panel<T: Panel>(&self) -> Option<Entity<T>> {
|
||||
self.panel_entries
|
||||
.iter()
|
||||
.find_map(|entry| entry.panel.to_any().clone().downcast().ok())
|
||||
|
@ -328,11 +332,7 @@ impl Dock {
|
|||
.position(|entry| entry.panel.to_any().downcast::<T>().is_ok())
|
||||
}
|
||||
|
||||
pub fn panel_index_for_persistent_name(
|
||||
&self,
|
||||
ui_name: &str,
|
||||
_cx: &AppContext,
|
||||
) -> Option<usize> {
|
||||
pub fn panel_index_for_persistent_name(&self, ui_name: &str, _cx: &App) -> Option<usize> {
|
||||
self.panel_entries
|
||||
.iter()
|
||||
.position(|entry| entry.panel.persistent_name() == ui_name)
|
||||
|
@ -349,64 +349,71 @@ impl Dock {
|
|||
.and_then(|index| self.panel_entries.get(index))
|
||||
}
|
||||
|
||||
pub(crate) fn set_open(&mut self, open: bool, cx: &mut ViewContext<Self>) {
|
||||
pub(crate) fn set_open(&mut self, open: bool, window: &mut Window, cx: &mut Context<Self>) {
|
||||
if open != self.is_open {
|
||||
self.is_open = open;
|
||||
if let Some(active_panel) = self.active_panel_entry() {
|
||||
active_panel.panel.set_active(open, cx);
|
||||
active_panel.panel.set_active(open, window, cx);
|
||||
}
|
||||
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_panel_zoomed(&mut self, panel: &AnyView, zoomed: bool, cx: &mut ViewContext<Self>) {
|
||||
pub fn set_panel_zoomed(
|
||||
&mut self,
|
||||
panel: &AnyView,
|
||||
zoomed: bool,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
for entry in &mut self.panel_entries {
|
||||
if entry.panel.panel_id() == panel.entity_id() {
|
||||
if zoomed != entry.panel.is_zoomed(cx) {
|
||||
entry.panel.set_zoomed(zoomed, cx);
|
||||
if zoomed != entry.panel.is_zoomed(window, cx) {
|
||||
entry.panel.set_zoomed(zoomed, window, cx);
|
||||
}
|
||||
} else if entry.panel.is_zoomed(cx) {
|
||||
entry.panel.set_zoomed(false, cx);
|
||||
} else if entry.panel.is_zoomed(window, cx) {
|
||||
entry.panel.set_zoomed(false, window, cx);
|
||||
}
|
||||
}
|
||||
|
||||
self.workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
workspace.serialize_workspace(cx);
|
||||
workspace.serialize_workspace(window, cx);
|
||||
})
|
||||
.ok();
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub fn zoom_out(&mut self, cx: &mut ViewContext<Self>) {
|
||||
pub fn zoom_out(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
for entry in &mut self.panel_entries {
|
||||
if entry.panel.is_zoomed(cx) {
|
||||
entry.panel.set_zoomed(false, cx);
|
||||
if entry.panel.is_zoomed(window, cx) {
|
||||
entry.panel.set_zoomed(false, window, cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn add_panel<T: Panel>(
|
||||
&mut self,
|
||||
panel: View<T>,
|
||||
workspace: WeakView<Workspace>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
panel: Entity<T>,
|
||||
workspace: WeakEntity<Workspace>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> usize {
|
||||
let subscriptions = [
|
||||
cx.observe(&panel, |_, _, cx| cx.notify()),
|
||||
cx.observe_global::<SettingsStore>({
|
||||
cx.observe_global_in::<SettingsStore>(window, {
|
||||
let workspace = workspace.clone();
|
||||
let panel = panel.clone();
|
||||
|
||||
move |this, cx| {
|
||||
let new_position = panel.read(cx).position(cx);
|
||||
move |this, window, cx| {
|
||||
let new_position = panel.read(cx).position(window, cx);
|
||||
if new_position == this.position {
|
||||
return;
|
||||
}
|
||||
|
||||
let Ok(new_dock) = workspace.update(cx, |workspace, cx| {
|
||||
if panel.is_zoomed(cx) {
|
||||
if panel.is_zoomed(window, cx) {
|
||||
workspace.zoomed_position = Some(new_position);
|
||||
}
|
||||
match new_position {
|
||||
|
@ -424,65 +431,72 @@ impl Dock {
|
|||
active_panel.panel_id() == Entity::entity_id(&panel)
|
||||
});
|
||||
|
||||
this.remove_panel(&panel, cx);
|
||||
this.remove_panel(&panel, window, cx);
|
||||
|
||||
new_dock.update(cx, |new_dock, cx| {
|
||||
new_dock.remove_panel(&panel, cx);
|
||||
let index = new_dock.add_panel(panel.clone(), workspace.clone(), cx);
|
||||
new_dock.remove_panel(&panel, window, cx);
|
||||
let index =
|
||||
new_dock.add_panel(panel.clone(), workspace.clone(), window, cx);
|
||||
if was_visible {
|
||||
new_dock.set_open(true, cx);
|
||||
new_dock.activate_panel(index, cx);
|
||||
new_dock.set_open(true, window, cx);
|
||||
new_dock.activate_panel(index, window, cx);
|
||||
}
|
||||
});
|
||||
}
|
||||
}),
|
||||
cx.subscribe(&panel, move |this, panel, event, cx| match event {
|
||||
PanelEvent::ZoomIn => {
|
||||
this.set_panel_zoomed(&panel.to_any(), true, cx);
|
||||
if !panel.focus_handle(cx).contains_focused(cx) {
|
||||
cx.focus_view(&panel);
|
||||
}
|
||||
workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
workspace.zoomed = Some(panel.downgrade().into());
|
||||
workspace.zoomed_position = Some(panel.read(cx).position(cx));
|
||||
cx.emit(Event::ZoomChanged);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
PanelEvent::ZoomOut => {
|
||||
this.set_panel_zoomed(&panel.to_any(), false, cx);
|
||||
workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
if workspace.zoomed_position == Some(this.position) {
|
||||
workspace.zoomed = None;
|
||||
workspace.zoomed_position = None;
|
||||
cx.subscribe_in(
|
||||
&panel,
|
||||
window,
|
||||
move |this, panel, event, window, cx| match event {
|
||||
PanelEvent::ZoomIn => {
|
||||
this.set_panel_zoomed(&panel.to_any(), true, window, cx);
|
||||
if !PanelHandle::panel_focus_handle(panel, cx).contains_focused(window, cx)
|
||||
{
|
||||
window.focus(&panel.focus_handle(cx));
|
||||
}
|
||||
workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
workspace.zoomed = Some(panel.downgrade().into());
|
||||
workspace.zoomed_position =
|
||||
Some(panel.read(cx).position(window, cx));
|
||||
cx.emit(Event::ZoomChanged);
|
||||
}
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
PanelEvent::Activate => {
|
||||
if let Some(ix) = this
|
||||
.panel_entries
|
||||
.iter()
|
||||
.position(|entry| entry.panel.panel_id() == Entity::entity_id(&panel))
|
||||
{
|
||||
this.set_open(true, cx);
|
||||
this.activate_panel(ix, cx);
|
||||
cx.focus_view(&panel);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
PanelEvent::Close => {
|
||||
if this
|
||||
.visible_panel()
|
||||
.map_or(false, |p| p.panel_id() == Entity::entity_id(&panel))
|
||||
{
|
||||
this.set_open(false, cx);
|
||||
PanelEvent::ZoomOut => {
|
||||
this.set_panel_zoomed(&panel.to_any(), false, window, cx);
|
||||
workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
if workspace.zoomed_position == Some(this.position) {
|
||||
workspace.zoomed = None;
|
||||
workspace.zoomed_position = None;
|
||||
cx.emit(Event::ZoomChanged);
|
||||
}
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}),
|
||||
PanelEvent::Activate => {
|
||||
if let Some(ix) = this
|
||||
.panel_entries
|
||||
.iter()
|
||||
.position(|entry| entry.panel.panel_id() == Entity::entity_id(panel))
|
||||
{
|
||||
this.set_open(true, window, cx);
|
||||
this.activate_panel(ix, window, cx);
|
||||
window.focus(&panel.read(cx).focus_handle(cx));
|
||||
}
|
||||
}
|
||||
PanelEvent::Close => {
|
||||
if this
|
||||
.visible_panel()
|
||||
.map_or(false, |p| p.panel_id() == Entity::entity_id(panel))
|
||||
{
|
||||
this.set_open(false, window, cx);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
let index = match self
|
||||
|
@ -506,36 +520,41 @@ impl Dock {
|
|||
},
|
||||
);
|
||||
|
||||
self.restore_state(cx);
|
||||
if panel.read(cx).starts_open(cx) {
|
||||
self.activate_panel(index, cx);
|
||||
self.set_open(true, cx);
|
||||
self.restore_state(window, cx);
|
||||
if panel.read(cx).starts_open(window, cx) {
|
||||
self.activate_panel(index, window, cx);
|
||||
self.set_open(true, window, cx);
|
||||
}
|
||||
|
||||
cx.notify();
|
||||
index
|
||||
}
|
||||
|
||||
pub fn restore_state(&mut self, cx: &mut ViewContext<Self>) -> bool {
|
||||
pub fn restore_state(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
|
||||
if let Some(serialized) = self.serialized_dock.clone() {
|
||||
if let Some(active_panel) = serialized.active_panel {
|
||||
if let Some(idx) = self.panel_index_for_persistent_name(active_panel.as_str(), cx) {
|
||||
self.activate_panel(idx, cx);
|
||||
self.activate_panel(idx, window, cx);
|
||||
}
|
||||
}
|
||||
|
||||
if serialized.zoom {
|
||||
if let Some(panel) = self.active_panel() {
|
||||
panel.set_zoomed(true, cx)
|
||||
panel.set_zoomed(true, window, cx)
|
||||
}
|
||||
}
|
||||
self.set_open(serialized.visible, cx);
|
||||
self.set_open(serialized.visible, window, cx);
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn remove_panel<T: Panel>(&mut self, panel: &View<T>, cx: &mut ViewContext<Self>) {
|
||||
pub fn remove_panel<T: Panel>(
|
||||
&mut self,
|
||||
panel: &Entity<T>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if let Some(panel_ix) = self
|
||||
.panel_entries
|
||||
.iter()
|
||||
|
@ -548,7 +567,7 @@ impl Dock {
|
|||
}
|
||||
std::cmp::Ordering::Equal => {
|
||||
self.active_panel_index = None;
|
||||
self.set_open(false, cx);
|
||||
self.set_open(false, window, cx);
|
||||
}
|
||||
std::cmp::Ordering::Greater => {}
|
||||
}
|
||||
|
@ -562,15 +581,15 @@ impl Dock {
|
|||
self.panel_entries.len()
|
||||
}
|
||||
|
||||
pub fn activate_panel(&mut self, panel_ix: usize, cx: &mut ViewContext<Self>) {
|
||||
pub fn activate_panel(&mut self, panel_ix: usize, window: &mut Window, cx: &mut Context<Self>) {
|
||||
if Some(panel_ix) != self.active_panel_index {
|
||||
if let Some(active_panel) = self.active_panel_entry() {
|
||||
active_panel.panel.set_active(false, cx);
|
||||
active_panel.panel.set_active(false, window, cx);
|
||||
}
|
||||
|
||||
self.active_panel_index = Some(panel_ix);
|
||||
if let Some(active_panel) = self.active_panel_entry() {
|
||||
active_panel.panel.set_active(true, cx);
|
||||
active_panel.panel.set_active(true, window, cx);
|
||||
}
|
||||
|
||||
cx.notify();
|
||||
|
@ -595,35 +614,41 @@ impl Dock {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn zoomed_panel(&self, cx: &WindowContext) -> Option<Arc<dyn PanelHandle>> {
|
||||
pub fn zoomed_panel(&self, window: &Window, cx: &App) -> Option<Arc<dyn PanelHandle>> {
|
||||
let entry = self.visible_entry()?;
|
||||
if entry.panel.is_zoomed(cx) {
|
||||
if entry.panel.is_zoomed(window, cx) {
|
||||
Some(entry.panel.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn panel_size(&self, panel: &dyn PanelHandle, cx: &WindowContext) -> Option<Pixels> {
|
||||
pub fn panel_size(&self, panel: &dyn PanelHandle, window: &Window, cx: &App) -> Option<Pixels> {
|
||||
self.panel_entries
|
||||
.iter()
|
||||
.find(|entry| entry.panel.panel_id() == panel.panel_id())
|
||||
.map(|entry| entry.panel.size(cx))
|
||||
.map(|entry| entry.panel.size(window, cx))
|
||||
}
|
||||
|
||||
pub fn active_panel_size(&self, cx: &WindowContext) -> Option<Pixels> {
|
||||
pub fn active_panel_size(&self, window: &Window, cx: &App) -> Option<Pixels> {
|
||||
if self.is_open {
|
||||
self.active_panel_entry().map(|entry| entry.panel.size(cx))
|
||||
self.active_panel_entry()
|
||||
.map(|entry| entry.panel.size(window, cx))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resize_active_panel(&mut self, size: Option<Pixels>, cx: &mut ViewContext<Self>) {
|
||||
pub fn resize_active_panel(
|
||||
&mut self,
|
||||
size: Option<Pixels>,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if let Some(entry) = self.active_panel_entry() {
|
||||
let size = size.map(|size| size.max(RESIZE_HANDLE_SIZE).round());
|
||||
|
||||
entry.panel.set_size(size, cx);
|
||||
entry.panel.set_size(size, window, cx);
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
@ -643,44 +668,44 @@ impl Dock {
|
|||
dispatch_context
|
||||
}
|
||||
|
||||
pub fn clamp_panel_size(&mut self, max_size: Pixels, cx: &mut WindowContext) {
|
||||
pub fn clamp_panel_size(&mut self, max_size: Pixels, window: &mut Window, cx: &mut App) {
|
||||
let max_size = px((max_size.0 - RESIZE_HANDLE_SIZE.0).abs());
|
||||
for panel in self.panel_entries.iter().map(|entry| &entry.panel) {
|
||||
if panel.size(cx) > max_size {
|
||||
panel.set_size(Some(max_size.max(RESIZE_HANDLE_SIZE)), cx);
|
||||
if panel.size(window, cx) > max_size {
|
||||
panel.set_size(Some(max_size.max(RESIZE_HANDLE_SIZE)), window, cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for Dock {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let dispatch_context = Self::dispatch_context();
|
||||
if let Some(entry) = self.visible_entry() {
|
||||
let size = entry.panel.size(cx);
|
||||
let size = entry.panel.size(window, cx);
|
||||
|
||||
let position = self.position;
|
||||
let create_resize_handle = || {
|
||||
let handle = div()
|
||||
.id("resize-handle")
|
||||
.on_drag(DraggedDock(position), |dock, _, cx| {
|
||||
.on_drag(DraggedDock(position), |dock, _, _, cx| {
|
||||
cx.stop_propagation();
|
||||
cx.new_view(|_| dock.clone())
|
||||
cx.new(|_| dock.clone())
|
||||
})
|
||||
.on_mouse_down(
|
||||
MouseButton::Left,
|
||||
cx.listener(|_, _: &MouseDownEvent, cx| {
|
||||
cx.listener(|_, _: &MouseDownEvent, _, cx| {
|
||||
cx.stop_propagation();
|
||||
}),
|
||||
)
|
||||
.on_mouse_up(
|
||||
MouseButton::Left,
|
||||
cx.listener(|dock, e: &MouseUpEvent, cx| {
|
||||
cx.listener(|dock, e: &MouseUpEvent, window, cx| {
|
||||
if e.click_count == 2 {
|
||||
dock.resize_active_panel(None, cx);
|
||||
dock.resize_active_panel(None, window, cx);
|
||||
dock.workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
workspace.serialize_workspace(cx);
|
||||
workspace.serialize_workspace(window, cx);
|
||||
})
|
||||
.ok();
|
||||
cx.stop_propagation();
|
||||
|
@ -758,14 +783,14 @@ impl Render for Dock {
|
|||
}
|
||||
|
||||
impl PanelButtons {
|
||||
pub fn new(dock: View<Dock>, cx: &mut ViewContext<Self>) -> Self {
|
||||
pub fn new(dock: Entity<Dock>, cx: &mut Context<Self>) -> Self {
|
||||
cx.observe(&dock, |_, _, cx| cx.notify()).detach();
|
||||
Self { dock }
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for PanelButtons {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let dock = self.dock.read(cx);
|
||||
let active_index = dock.active_panel_index;
|
||||
let is_open = dock.is_open;
|
||||
|
@ -781,8 +806,8 @@ impl Render for PanelButtons {
|
|||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, entry)| {
|
||||
let icon = entry.panel.icon(cx)?;
|
||||
let icon_tooltip = entry.panel.icon_tooltip(cx)?;
|
||||
let icon = entry.panel.icon(window, cx)?;
|
||||
let icon_tooltip = entry.panel.icon_tooltip(window, cx)?;
|
||||
let name = entry.panel.persistent_name();
|
||||
let panel = entry.panel.clone();
|
||||
|
||||
|
@ -795,21 +820,21 @@ impl Render for PanelButtons {
|
|||
|
||||
(action, tooltip)
|
||||
} else {
|
||||
let action = entry.panel.toggle_action(cx);
|
||||
let action = entry.panel.toggle_action(window, cx);
|
||||
|
||||
(action, icon_tooltip.into())
|
||||
};
|
||||
|
||||
Some(
|
||||
right_click_menu(name)
|
||||
.menu(move |cx| {
|
||||
.menu(move |window, cx| {
|
||||
const POSITIONS: [DockPosition; 3] = [
|
||||
DockPosition::Left,
|
||||
DockPosition::Right,
|
||||
DockPosition::Bottom,
|
||||
];
|
||||
|
||||
ContextMenu::build(cx, |mut menu, cx| {
|
||||
ContextMenu::build(window, cx, |mut menu, _, cx| {
|
||||
for position in POSITIONS {
|
||||
if position != dock_position
|
||||
&& panel.position_is_valid(position, cx)
|
||||
|
@ -818,8 +843,8 @@ impl Render for PanelButtons {
|
|||
menu = menu.entry(
|
||||
format!("Dock {}", position.label()),
|
||||
None,
|
||||
move |cx| {
|
||||
panel.set_position(position, cx);
|
||||
move |window, cx| {
|
||||
panel.set_position(position, window, cx);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -835,10 +860,12 @@ impl Render for PanelButtons {
|
|||
.toggle_state(is_active_button)
|
||||
.on_click({
|
||||
let action = action.boxed_clone();
|
||||
move |_, cx| cx.dispatch_action(action.boxed_clone())
|
||||
move |_, window, cx| {
|
||||
window.dispatch_action(action.boxed_clone(), cx)
|
||||
}
|
||||
})
|
||||
.tooltip(move |cx| {
|
||||
Tooltip::for_action(tooltip.clone(), &*action, cx)
|
||||
.tooltip(move |window, cx| {
|
||||
Tooltip::for_action(tooltip.clone(), &*action, window, cx)
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
@ -852,7 +879,8 @@ impl StatusItemView for PanelButtons {
|
|||
fn set_active_pane_item(
|
||||
&mut self,
|
||||
_active_pane_item: Option<&dyn crate::ItemHandle>,
|
||||
_cx: &mut ViewContext<Self>,
|
||||
_window: &mut Window,
|
||||
_cx: &mut Context<Self>,
|
||||
) {
|
||||
// Nothing to do, panel buttons don't depend on the active center item
|
||||
}
|
||||
|
@ -861,7 +889,7 @@ impl StatusItemView for PanelButtons {
|
|||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub mod test {
|
||||
use super::*;
|
||||
use gpui::{actions, div, ViewContext, WindowContext};
|
||||
use gpui::{actions, div, App, Context, Window};
|
||||
|
||||
pub struct TestPanel {
|
||||
pub position: DockPosition,
|
||||
|
@ -875,7 +903,7 @@ pub mod test {
|
|||
impl EventEmitter<PanelEvent> for TestPanel {}
|
||||
|
||||
impl TestPanel {
|
||||
pub fn new(position: DockPosition, cx: &mut WindowContext) -> Self {
|
||||
pub fn new(position: DockPosition, cx: &mut App) -> Self {
|
||||
Self {
|
||||
position,
|
||||
zoomed: false,
|
||||
|
@ -887,7 +915,7 @@ pub mod test {
|
|||
}
|
||||
|
||||
impl Render for TestPanel {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
div().id("test").track_focus(&self.focus_handle(cx))
|
||||
}
|
||||
}
|
||||
|
@ -897,7 +925,7 @@ pub mod test {
|
|||
"TestPanel"
|
||||
}
|
||||
|
||||
fn position(&self, _: &WindowContext) -> super::DockPosition {
|
||||
fn position(&self, _window: &Window, _: &App) -> super::DockPosition {
|
||||
self.position
|
||||
}
|
||||
|
||||
|
@ -905,24 +933,24 @@ pub mod test {
|
|||
true
|
||||
}
|
||||
|
||||
fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext<Self>) {
|
||||
fn set_position(&mut self, position: DockPosition, _: &mut Window, cx: &mut Context<Self>) {
|
||||
self.position = position;
|
||||
cx.update_global::<SettingsStore, _>(|_, _| {});
|
||||
}
|
||||
|
||||
fn size(&self, _: &WindowContext) -> Pixels {
|
||||
fn size(&self, _window: &Window, _: &App) -> Pixels {
|
||||
self.size
|
||||
}
|
||||
|
||||
fn set_size(&mut self, size: Option<Pixels>, _: &mut ViewContext<Self>) {
|
||||
fn set_size(&mut self, size: Option<Pixels>, _window: &mut Window, _: &mut Context<Self>) {
|
||||
self.size = size.unwrap_or(px(300.));
|
||||
}
|
||||
|
||||
fn icon(&self, _: &WindowContext) -> Option<ui::IconName> {
|
||||
fn icon(&self, _window: &Window, _: &App) -> Option<ui::IconName> {
|
||||
None
|
||||
}
|
||||
|
||||
fn icon_tooltip(&self, _cx: &WindowContext) -> Option<&'static str> {
|
||||
fn icon_tooltip(&self, _window: &Window, _cx: &App) -> Option<&'static str> {
|
||||
None
|
||||
}
|
||||
|
||||
|
@ -930,15 +958,15 @@ pub mod test {
|
|||
ToggleTestPanel.boxed_clone()
|
||||
}
|
||||
|
||||
fn is_zoomed(&self, _: &WindowContext) -> bool {
|
||||
fn is_zoomed(&self, _window: &Window, _: &App) -> bool {
|
||||
self.zoomed
|
||||
}
|
||||
|
||||
fn set_zoomed(&mut self, zoomed: bool, _cx: &mut ViewContext<Self>) {
|
||||
fn set_zoomed(&mut self, zoomed: bool, _window: &mut Window, _cx: &mut Context<Self>) {
|
||||
self.zoomed = zoomed;
|
||||
}
|
||||
|
||||
fn set_active(&mut self, active: bool, _cx: &mut ViewContext<Self>) {
|
||||
fn set_active(&mut self, active: bool, _window: &mut Window, _cx: &mut Context<Self>) {
|
||||
self.active = active;
|
||||
}
|
||||
|
||||
|
@ -947,8 +975,8 @@ pub mod test {
|
|||
}
|
||||
}
|
||||
|
||||
impl FocusableView for TestPanel {
|
||||
fn focus_handle(&self, _cx: &AppContext) -> FocusHandle {
|
||||
impl Focusable for TestPanel {
|
||||
fn focus_handle(&self, _cx: &App) -> FocusHandle {
|
||||
self.focus_handle.clone()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue