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:
Nathan Sobo 2025-01-25 20:02:45 -07:00 committed by GitHub
parent 21b4a0d50e
commit 6fca1d2b0b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
648 changed files with 36248 additions and 28208 deletions

View file

@ -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()
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
use gpui::{AnyView, DismissEvent, FocusHandle, ManagedView, Subscription, View};
use gpui::{AnyView, DismissEvent, Entity, FocusHandle, Focusable as _, ManagedView, Subscription};
use ui::prelude::*;
pub enum DismissDecision {
@ -7,7 +7,11 @@ pub enum DismissDecision {
}
pub trait ModalView: ManagedView {
fn on_before_dismiss(&mut self, _: &mut ViewContext<Self>) -> DismissDecision {
fn on_before_dismiss(
&mut self,
_window: &mut Window,
_: &mut Context<Self>,
) -> DismissDecision {
DismissDecision::Dismiss(true)
}
@ -17,21 +21,21 @@ pub trait ModalView: ManagedView {
}
trait ModalViewHandle {
fn on_before_dismiss(&mut self, cx: &mut WindowContext) -> DismissDecision;
fn on_before_dismiss(&mut self, window: &mut Window, cx: &mut App) -> DismissDecision;
fn view(&self) -> AnyView;
fn fade_out_background(&self, cx: &WindowContext) -> bool;
fn fade_out_background(&self, cx: &mut App) -> bool;
}
impl<V: ModalView> ModalViewHandle for View<V> {
fn on_before_dismiss(&mut self, cx: &mut WindowContext) -> DismissDecision {
self.update(cx, |this, cx| this.on_before_dismiss(cx))
impl<V: ModalView> ModalViewHandle for Entity<V> {
fn on_before_dismiss(&mut self, window: &mut Window, cx: &mut App) -> DismissDecision {
self.update(cx, |this, cx| this.on_before_dismiss(window, cx))
}
fn view(&self) -> AnyView {
self.clone().into()
}
fn fade_out_background(&self, cx: &WindowContext) -> bool {
fn fade_out_background(&self, cx: &mut App) -> bool {
self.read(cx).fade_out_background()
}
}
@ -62,23 +66,23 @@ impl ModalLayer {
}
}
pub fn toggle_modal<V, B>(&mut self, cx: &mut ViewContext<Self>, build_view: B)
pub fn toggle_modal<V, B>(&mut self, window: &mut Window, cx: &mut Context<Self>, build_view: B)
where
V: ModalView,
B: FnOnce(&mut ViewContext<V>) -> V,
B: FnOnce(&mut Window, &mut Context<V>) -> V,
{
if let Some(active_modal) = &self.active_modal {
let is_close = active_modal.modal.view().downcast::<V>().is_ok();
let did_close = self.hide_modal(cx);
let did_close = self.hide_modal(window, cx);
if is_close || !did_close {
return;
}
}
let new_modal = cx.new_view(build_view);
self.show_modal(new_modal, cx);
let new_modal = cx.new(|cx| build_view(window, cx));
self.show_modal(new_modal, window, cx);
}
fn show_modal<V>(&mut self, new_modal: View<V>, cx: &mut ViewContext<Self>)
fn show_modal<V>(&mut self, new_modal: Entity<V>, window: &mut Window, cx: &mut Context<Self>)
where
V: ModalView,
{
@ -86,31 +90,35 @@ impl ModalLayer {
self.active_modal = Some(ActiveModal {
modal: Box::new(new_modal.clone()),
_subscriptions: [
cx.subscribe(&new_modal, |this, _, _: &DismissEvent, cx| {
this.hide_modal(cx);
}),
cx.on_focus_out(&focus_handle, |this, _event, cx| {
cx.subscribe_in(
&new_modal,
window,
|this, _, _: &DismissEvent, window, cx| {
this.hide_modal(window, cx);
},
),
cx.on_focus_out(&focus_handle, window, |this, _event, window, cx| {
if this.dismiss_on_focus_lost {
this.hide_modal(cx);
this.hide_modal(window, cx);
}
}),
],
previous_focus_handle: cx.focused(),
previous_focus_handle: window.focused(cx),
focus_handle,
});
cx.defer(move |_, cx| {
cx.focus_view(&new_modal);
cx.defer_in(window, move |_, window, cx| {
window.focus(&new_modal.focus_handle(cx));
});
cx.notify();
}
fn hide_modal(&mut self, cx: &mut ViewContext<Self>) -> bool {
fn hide_modal(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
let Some(active_modal) = self.active_modal.as_mut() else {
self.dismiss_on_focus_lost = false;
return false;
};
match active_modal.modal.on_before_dismiss(cx) {
match active_modal.modal.on_before_dismiss(window, cx) {
DismissDecision::Dismiss(dismiss) => {
self.dismiss_on_focus_lost = !dismiss;
if !dismiss {
@ -125,8 +133,8 @@ impl ModalLayer {
if let Some(active_modal) = self.active_modal.take() {
if let Some(previous_focus) = active_modal.previous_focus_handle {
if active_modal.focus_handle.contains_focused(cx) {
previous_focus.focus(cx);
if active_modal.focus_handle.contains_focused(window, cx) {
previous_focus.focus(window);
}
}
cx.notify();
@ -134,7 +142,7 @@ impl ModalLayer {
true
}
pub fn active_modal<V>(&self) -> Option<View<V>>
pub fn active_modal<V>(&self) -> Option<Entity<V>>
where
V: 'static,
{
@ -148,7 +156,7 @@ impl ModalLayer {
}
impl Render for ModalLayer {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let Some(active_modal) = &self.active_modal else {
return div();
};
@ -163,8 +171,8 @@ impl Render for ModalLayer {
background.fade_out(0.2);
el.bg(background)
.occlude()
.on_mouse_down_out(cx.listener(|this, _, cx| {
this.hide_modal(cx);
.on_mouse_down_out(cx.listener(|this, _, window, cx| {
this.hide_modal(window, cx);
}))
})
.child(

View file

@ -1,17 +1,16 @@
use crate::{Toast, Workspace};
use anyhow::Context;
use anyhow::Context as _;
use anyhow::{anyhow, Result};
use gpui::{
svg, AnyView, AppContext, AsyncWindowContext, ClipboardItem, DismissEvent, EventEmitter,
Global, PromptLevel, Render, ScrollHandle, Task, View, ViewContext, VisualContext,
WindowContext,
svg, AnyView, App, AppContext as _, AsyncWindowContext, ClipboardItem, Context, DismissEvent,
Entity, EventEmitter, Global, PromptLevel, Render, ScrollHandle, Task,
};
use std::rc::Rc;
use std::{any::TypeId, time::Duration};
use ui::{prelude::*, Tooltip};
use util::ResultExt;
pub fn init(cx: &mut AppContext) {
pub fn init(cx: &mut App) {
cx.set_global(GlobalAppNotifications {
app_notifications: Vec::new(),
})
@ -59,8 +58,8 @@ impl Workspace {
pub fn show_notification<V: Notification>(
&mut self,
id: NotificationId,
cx: &mut ViewContext<Self>,
build_notification: impl FnOnce(&mut ViewContext<Self>) -> View<V>,
cx: &mut Context<Self>,
build_notification: impl FnOnce(&mut Context<Self>) -> Entity<V>,
) {
self.show_notification_without_handling_dismiss_events(&id, cx, |cx| {
let notification = build_notification(cx);
@ -83,8 +82,8 @@ impl Workspace {
pub(crate) fn show_notification_without_handling_dismiss_events(
&mut self,
id: &NotificationId,
cx: &mut ViewContext<Self>,
build_notification: impl FnOnce(&mut ViewContext<Self>) -> AnyView,
cx: &mut Context<Self>,
build_notification: impl FnOnce(&mut Context<Self>) -> AnyView,
) {
self.dismiss_notification(id, cx);
self.notifications
@ -92,20 +91,20 @@ impl Workspace {
cx.notify();
}
pub fn show_error<E>(&mut self, err: &E, cx: &mut ViewContext<Self>)
pub fn show_error<E>(&mut self, err: &E, cx: &mut Context<Self>)
where
E: std::fmt::Debug + std::fmt::Display,
{
self.show_notification(workspace_error_notification_id(), cx, |cx| {
cx.new_view(|_cx| ErrorMessagePrompt::new(format!("Error: {err}")))
cx.new(|_| ErrorMessagePrompt::new(format!("Error: {err}")))
});
}
pub fn show_portal_error(&mut self, err: String, cx: &mut ViewContext<Self>) {
pub fn show_portal_error(&mut self, err: String, cx: &mut Context<Self>) {
struct PortalError;
self.show_notification(NotificationId::unique::<PortalError>(), cx, |cx| {
cx.new_view(|_cx| {
cx.new(|_| {
ErrorMessagePrompt::new(err.to_string()).with_link_button(
"See docs",
"https://zed.dev/docs/linux#i-cant-open-any-files",
@ -114,7 +113,7 @@ impl Workspace {
});
}
pub fn dismiss_notification(&mut self, id: &NotificationId, cx: &mut ViewContext<Self>) {
pub fn dismiss_notification(&mut self, id: &NotificationId, cx: &mut Context<Self>) {
self.notifications.retain(|(existing_id, _)| {
if existing_id == id {
cx.notify();
@ -125,15 +124,15 @@ impl Workspace {
});
}
pub fn show_toast(&mut self, toast: Toast, cx: &mut ViewContext<Self>) {
pub fn show_toast(&mut self, toast: Toast, cx: &mut Context<Self>) {
self.dismiss_notification(&toast.id, cx);
self.show_notification(toast.id.clone(), cx, |cx| {
cx.new_view(|_cx| match toast.on_click.as_ref() {
cx.new(|_| match toast.on_click.as_ref() {
Some((click_msg, on_click)) => {
let on_click = on_click.clone();
simple_message_notification::MessageNotification::new(toast.msg.clone())
.with_click_message(click_msg.clone())
.on_click(move |cx| on_click(cx))
.on_click(move |window, cx| on_click(window, cx))
}
None => simple_message_notification::MessageNotification::new(toast.msg.clone()),
})
@ -153,16 +152,16 @@ impl Workspace {
}
}
pub fn dismiss_toast(&mut self, id: &NotificationId, cx: &mut ViewContext<Self>) {
pub fn dismiss_toast(&mut self, id: &NotificationId, cx: &mut Context<Self>) {
self.dismiss_notification(id, cx);
}
pub fn clear_all_notifications(&mut self, cx: &mut ViewContext<Self>) {
pub fn clear_all_notifications(&mut self, cx: &mut Context<Self>) {
self.notifications.clear();
cx.notify();
}
pub fn show_initial_notifications(&mut self, cx: &mut ViewContext<Self>) {
pub fn show_initial_notifications(&mut self, cx: &mut Context<Self>) {
// Allow absence of the global so that tests don't need to initialize it.
let app_notifications = cx
.try_global::<GlobalAppNotifications>()
@ -190,7 +189,7 @@ impl LanguageServerPrompt {
}
}
async fn select_option(this: View<Self>, ix: usize, mut cx: AsyncWindowContext) {
async fn select_option(this: Entity<Self>, ix: usize, mut cx: AsyncWindowContext) {
util::maybe!(async move {
let potential_future = this.update(&mut cx, |this, _| {
this.request.take().map(|request| request.respond(ix))
@ -211,7 +210,7 @@ impl LanguageServerPrompt {
}
impl Render for LanguageServerPrompt {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let Some(request) = &self.request else {
return div().id("language_server_prompt_notification");
};
@ -227,7 +226,7 @@ impl Render for LanguageServerPrompt {
.group("language_server_prompt_notification")
.occlude()
.w_full()
.max_h(vh(0.8, cx))
.max_h(vh(0.8, window))
.elevation_3(cx)
.overflow_y_scroll()
.track_scroll(&self.scroll_handle)
@ -251,30 +250,32 @@ impl Render for LanguageServerPrompt {
IconButton::new("copy", IconName::Copy)
.on_click({
let message = request.message.clone();
move |_, cx| {
move |_, _, cx| {
cx.write_to_clipboard(
ClipboardItem::new_string(message.clone()),
)
}
})
.tooltip(|cx| Tooltip::text("Copy Description", cx)),
.tooltip(Tooltip::text("Copy Description")),
)
.child(IconButton::new("close", IconName::Close).on_click(
cx.listener(|_, _, cx| cx.emit(gpui::DismissEvent)),
cx.listener(|_, _, _, cx| cx.emit(gpui::DismissEvent)),
)),
),
)
.child(Label::new(request.message.to_string()).size(LabelSize::Small))
.children(request.actions.iter().enumerate().map(|(ix, action)| {
let this_handle = cx.view().clone();
let this_handle = cx.model().clone();
Button::new(ix, action.title.clone())
.size(ButtonSize::Large)
.on_click(move |_, cx| {
.on_click(move |_, window, cx| {
let this_handle = this_handle.clone();
cx.spawn(|cx| async move {
LanguageServerPrompt::select_option(this_handle, ix, cx).await
})
.detach()
window
.spawn(cx, |cx| async move {
LanguageServerPrompt::select_option(this_handle, ix, cx)
.await
})
.detach()
})
})),
)
@ -315,7 +316,7 @@ impl ErrorMessagePrompt {
}
impl Render for ErrorMessagePrompt {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
h_flex()
.id("error_message_prompt_notification")
.occlude()
@ -334,7 +335,7 @@ impl Render for ErrorMessagePrompt {
.justify_between()
.child(
svg()
.size(cx.text_style().font_size)
.size(window.text_style().font_size)
.flex_none()
.mr_2()
.mt(px(-2.0))
@ -344,8 +345,9 @@ impl Render for ErrorMessagePrompt {
}),
)
.child(
ui::IconButton::new("close", ui::IconName::Close)
.on_click(cx.listener(|_, _, cx| cx.emit(gpui::DismissEvent))),
ui::IconButton::new("close", ui::IconName::Close).on_click(
cx.listener(|_, _, _, cx| cx.emit(gpui::DismissEvent)),
),
),
)
.child(
@ -360,7 +362,7 @@ impl Render for ErrorMessagePrompt {
elm.child(
div().mt_2().child(
ui::Button::new("error_message_prompt_notification_button", label)
.on_click(move |_, cx| cx.open_url(&url)),
.on_click(move |_, _, cx| cx.open_url(&url)),
),
)
}),
@ -375,16 +377,15 @@ pub mod simple_message_notification {
use gpui::{
div, AnyElement, DismissEvent, EventEmitter, ParentElement, Render, SharedString, Styled,
ViewContext,
};
use ui::prelude::*;
pub struct MessageNotification {
content: Box<dyn Fn(&mut ViewContext<Self>) -> AnyElement>,
on_click: Option<Arc<dyn Fn(&mut ViewContext<Self>)>>,
build_content: Box<dyn Fn(&mut Window, &mut Context<Self>) -> AnyElement>,
on_click: Option<Arc<dyn Fn(&mut Window, &mut Context<Self>)>>,
click_message: Option<SharedString>,
secondary_click_message: Option<SharedString>,
secondary_on_click: Option<Arc<dyn Fn(&mut ViewContext<Self>)>>,
secondary_on_click: Option<Arc<dyn Fn(&mut Window, &mut Context<Self>)>>,
}
impl EventEmitter<DismissEvent> for MessageNotification {}
@ -395,15 +396,15 @@ pub mod simple_message_notification {
S: Into<SharedString>,
{
let message = message.into();
Self::new_from_builder(move |_| Label::new(message.clone()).into_any_element())
Self::new_from_builder(move |_, _| Label::new(message.clone()).into_any_element())
}
pub fn new_from_builder<F>(content: F) -> MessageNotification
where
F: 'static + Fn(&mut ViewContext<Self>) -> AnyElement,
F: 'static + Fn(&mut Window, &mut Context<Self>) -> AnyElement,
{
Self {
content: Box::new(content),
build_content: Box::new(content),
on_click: None,
click_message: None,
secondary_on_click: None,
@ -421,7 +422,7 @@ pub mod simple_message_notification {
pub fn on_click<F>(mut self, on_click: F) -> Self
where
F: 'static + Fn(&mut ViewContext<Self>),
F: 'static + Fn(&mut Window, &mut Context<Self>),
{
self.on_click = Some(Arc::new(on_click));
self
@ -437,19 +438,19 @@ pub mod simple_message_notification {
pub fn on_secondary_click<F>(mut self, on_click: F) -> Self
where
F: 'static + Fn(&mut ViewContext<Self>),
F: 'static + Fn(&mut Window, &mut Context<Self>),
{
self.secondary_on_click = Some(Arc::new(on_click));
self
}
pub fn dismiss(&mut self, cx: &mut ViewContext<Self>) {
pub fn dismiss(&mut self, cx: &mut Context<Self>) {
cx.emit(DismissEvent);
}
}
impl Render for MessageNotification {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
v_flex()
.p_3()
.gap_2()
@ -459,10 +460,10 @@ pub mod simple_message_notification {
.gap_4()
.justify_between()
.items_start()
.child(div().max_w_96().child((self.content)(cx)))
.child(div().max_w_96().child((self.build_content)(window, cx)))
.child(
IconButton::new("close", IconName::Close)
.on_click(cx.listener(|this, _, cx| this.dismiss(cx))),
.on_click(cx.listener(|this, _, _, cx| this.dismiss(cx))),
),
)
.child(
@ -475,9 +476,9 @@ pub mod simple_message_notification {
.icon_position(IconPosition::Start)
.icon_size(IconSize::Small)
.icon_color(Color::Success)
.on_click(cx.listener(|this, _, cx| {
.on_click(cx.listener(|this, _, window, cx| {
if let Some(on_click) = this.on_click.as_ref() {
(on_click)(cx)
(on_click)(window, cx)
};
this.dismiss(cx)
}))
@ -489,9 +490,9 @@ pub mod simple_message_notification {
.icon_position(IconPosition::Start)
.icon_size(IconSize::Small)
.icon_color(Color::Error)
.on_click(cx.listener(|this, _, cx| {
.on_click(cx.listener(|this, _, window, cx| {
if let Some(on_click) = this.secondary_on_click.as_ref() {
(on_click)(cx)
(on_click)(window, cx)
};
this.dismiss(cx)
}))
@ -505,7 +506,7 @@ pub mod simple_message_notification {
struct GlobalAppNotifications {
app_notifications: Vec<(
NotificationId,
Rc<dyn Fn(&mut ViewContext<Workspace>) -> AnyView>,
Rc<dyn Fn(&mut Context<Workspace>) -> AnyView>,
)>,
}
@ -515,7 +516,7 @@ impl GlobalAppNotifications {
pub fn insert(
&mut self,
id: NotificationId,
build_notification: Rc<dyn Fn(&mut ViewContext<Workspace>) -> AnyView>,
build_notification: Rc<dyn Fn(&mut Context<Workspace>) -> AnyView>,
) {
self.remove(&id);
self.app_notifications.push((id, build_notification))
@ -532,11 +533,11 @@ impl GlobalAppNotifications {
/// exist. If the notification is dismissed within any workspace, it will be removed from all.
pub fn show_app_notification<V: Notification + 'static>(
id: NotificationId,
cx: &mut AppContext,
build_notification: impl Fn(&mut ViewContext<Workspace>) -> View<V> + 'static,
cx: &mut App,
build_notification: impl Fn(&mut Context<Workspace>) -> Entity<V> + 'static,
) -> Result<()> {
// Handle dismiss events by removing the notification from all workspaces.
let build_notification: Rc<dyn Fn(&mut ViewContext<Workspace>) -> AnyView> = Rc::new({
let build_notification: Rc<dyn Fn(&mut Context<Workspace>) -> AnyView> = Rc::new({
let id = id.clone();
move |cx| {
let notification = build_notification(cx);
@ -559,7 +560,7 @@ pub fn show_app_notification<V: Notification + 'static>(
for window in cx.windows() {
if let Some(workspace_window) = window.downcast::<Workspace>() {
let notify_result = workspace_window.update(cx, |workspace, cx| {
let notify_result = workspace_window.update(cx, |workspace, _window, cx| {
workspace.show_notification_without_handling_dismiss_events(&id, cx, |cx| {
build_notification(cx)
});
@ -585,7 +586,7 @@ pub fn show_app_notification<V: Notification + 'static>(
}
}
pub fn dismiss_app_notification(id: &NotificationId, cx: &mut AppContext) {
pub fn dismiss_app_notification(id: &NotificationId, cx: &mut App) {
cx.global_mut::<GlobalAppNotifications>().remove(id);
for window in cx.windows() {
if let Some(workspace_window) = window.downcast::<Workspace>() {
@ -593,7 +594,7 @@ pub fn dismiss_app_notification(id: &NotificationId, cx: &mut AppContext) {
// This spawn is necessary in order to dismiss the notification on which the click
// occurred, because in that case we're already in the middle of an update.
cx.spawn(move |mut cx| async move {
workspace_window.update(&mut cx, |workspace, cx| {
workspace_window.update(&mut cx, |workspace, _window, cx| {
workspace.dismiss_notification(&id, cx)
})
})
@ -605,16 +606,13 @@ pub fn dismiss_app_notification(id: &NotificationId, cx: &mut AppContext) {
pub trait NotifyResultExt {
type Ok;
fn notify_err(
self,
workspace: &mut Workspace,
cx: &mut ViewContext<Workspace>,
) -> Option<Self::Ok>;
fn notify_err(self, workspace: &mut Workspace, cx: &mut Context<Workspace>)
-> Option<Self::Ok>;
fn notify_async_err(self, cx: &mut AsyncWindowContext) -> Option<Self::Ok>;
/// Notifies the active workspace if there is one, otherwise notifies all workspaces.
fn notify_app_err(self, cx: &mut AppContext) -> Option<Self::Ok>;
fn notify_app_err(self, cx: &mut App) -> Option<Self::Ok>;
}
impl<T, E> NotifyResultExt for std::result::Result<T, E>
@ -623,7 +621,7 @@ where
{
type Ok = T;
fn notify_err(self, workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) -> Option<T> {
fn notify_err(self, workspace: &mut Workspace, cx: &mut Context<Workspace>) -> Option<T> {
match self {
Ok(value) => Some(value),
Err(err) => {
@ -639,7 +637,7 @@ where
Ok(value) => Some(value),
Err(err) => {
log::error!("{err:?}");
cx.update_root(|view, cx| {
cx.update_root(|view, _, cx| {
if let Ok(workspace) = view.downcast::<Workspace>() {
workspace.update(cx, |workspace, cx| workspace.show_error(&err, cx))
}
@ -650,7 +648,7 @@ where
}
}
fn notify_app_err(self, cx: &mut AppContext) -> Option<T> {
fn notify_app_err(self, cx: &mut App) -> Option<T> {
match self {
Ok(value) => Some(value),
Err(err) => {
@ -659,7 +657,7 @@ where
show_app_notification(workspace_error_notification_id(), cx, {
let message = message.clone();
move |cx| {
cx.new_view({
cx.new({
let message = message.clone();
move |_cx| ErrorMessagePrompt::new(message)
})
@ -674,7 +672,7 @@ where
}
pub trait NotifyTaskExt {
fn detach_and_notify_err(self, cx: &mut WindowContext);
fn detach_and_notify_err(self, window: &mut Window, cx: &mut App);
}
impl<R, E> NotifyTaskExt for Task<std::result::Result<R, E>>
@ -682,8 +680,12 @@ where
E: std::fmt::Debug + std::fmt::Display + Sized + 'static,
R: 'static,
{
fn detach_and_notify_err(self, cx: &mut WindowContext) {
cx.spawn(|mut cx| async move { self.await.notify_async_err(&mut cx) })
fn detach_and_notify_err(self, window: &mut Window, cx: &mut App) {
window
.spawn(
cx,
|mut cx| async move { self.await.notify_async_err(&mut cx) },
)
.detach();
}
}
@ -692,15 +694,17 @@ pub trait DetachAndPromptErr<R> {
fn prompt_err(
self,
msg: &str,
cx: &mut WindowContext,
f: impl FnOnce(&anyhow::Error, &mut WindowContext) -> Option<String> + 'static,
window: &Window,
cx: &App,
f: impl FnOnce(&anyhow::Error, &mut Window, &mut App) -> Option<String> + 'static,
) -> Task<Option<R>>;
fn detach_and_prompt_err(
self,
msg: &str,
cx: &mut WindowContext,
f: impl FnOnce(&anyhow::Error, &mut WindowContext) -> Option<String> + 'static,
window: &Window,
cx: &App,
f: impl FnOnce(&anyhow::Error, &mut Window, &mut App) -> Option<String> + 'static,
);
}
@ -711,17 +715,19 @@ where
fn prompt_err(
self,
msg: &str,
cx: &mut WindowContext,
f: impl FnOnce(&anyhow::Error, &mut WindowContext) -> Option<String> + 'static,
window: &Window,
cx: &App,
f: impl FnOnce(&anyhow::Error, &mut Window, &mut App) -> Option<String> + 'static,
) -> Task<Option<R>> {
let msg = msg.to_owned();
cx.spawn(|mut cx| async move {
window.spawn(cx, |mut cx| async move {
let result = self.await;
if let Err(err) = result.as_ref() {
log::error!("{err:?}");
if let Ok(prompt) = cx.update(|cx| {
let detail = f(err, cx).unwrap_or_else(|| format!("{err}. Please try again."));
cx.prompt(PromptLevel::Critical, &msg, Some(&detail), &["Ok"])
if let Ok(prompt) = cx.update(|window, cx| {
let detail =
f(err, window, cx).unwrap_or_else(|| format!("{err}. Please try again."));
window.prompt(PromptLevel::Critical, &msg, Some(&detail), &["Ok"], cx)
}) {
prompt.await.ok();
}
@ -734,9 +740,10 @@ where
fn detach_and_prompt_err(
self,
msg: &str,
cx: &mut WindowContext,
f: impl FnOnce(&anyhow::Error, &mut WindowContext) -> Option<String> + 'static,
window: &Window,
cx: &App,
f: impl FnOnce(&anyhow::Error, &mut Window, &mut App) -> Option<String> + 'static,
) {
self.prompt_err(msg, cx, f).detach();
self.prompt_err(msg, window, cx, f).detach();
}
}

File diff suppressed because it is too large Load diff

View file

@ -8,8 +8,8 @@ use call::{ActiveCall, ParticipantLocation};
use client::proto::PeerId;
use collections::HashMap;
use gpui::{
point, size, Along, AnyView, AnyWeakView, Axis, Bounds, IntoElement, Model, MouseButton,
Pixels, Point, StyleRefinement, View, ViewContext,
point, size, Along, AnyView, AnyWeakView, Axis, Bounds, Context, Entity, IntoElement,
MouseButton, Pixels, Point, StyleRefinement, Window,
};
use parking_lot::Mutex;
use project::Project;
@ -36,7 +36,7 @@ impl PaneGroup {
Self { root }
}
pub fn new(pane: View<Pane>) -> Self {
pub fn new(pane: Entity<Pane>) -> Self {
Self {
root: Member::Pane(pane),
}
@ -44,8 +44,8 @@ impl PaneGroup {
pub fn split(
&mut self,
old_pane: &View<Pane>,
new_pane: &View<Pane>,
old_pane: &Entity<Pane>,
new_pane: &Entity<Pane>,
direction: SplitDirection,
) -> Result<()> {
match &mut self.root {
@ -61,14 +61,14 @@ impl PaneGroup {
}
}
pub fn bounding_box_for_pane(&self, pane: &View<Pane>) -> Option<Bounds<Pixels>> {
pub fn bounding_box_for_pane(&self, pane: &Entity<Pane>) -> Option<Bounds<Pixels>> {
match &self.root {
Member::Pane(_) => None,
Member::Axis(axis) => axis.bounding_box_for_pane(pane),
}
}
pub fn pane_at_pixel_position(&self, coordinate: Point<Pixels>) -> Option<&View<Pane>> {
pub fn pane_at_pixel_position(&self, coordinate: Point<Pixels>) -> Option<&Entity<Pane>> {
match &self.root {
Member::Pane(pane) => Some(pane),
Member::Axis(axis) => axis.pane_at_pixel_position(coordinate),
@ -79,7 +79,7 @@ impl PaneGroup {
/// - Ok(true) if it found and removed a pane
/// - Ok(false) if it found but did not remove the pane
/// - Err(_) if it did not find the pane
pub fn remove(&mut self, pane: &View<Pane>) -> Result<bool> {
pub fn remove(&mut self, pane: &Entity<Pane>) -> Result<bool> {
match &mut self.root {
Member::Pane(_) => Ok(false),
Member::Axis(axis) => {
@ -93,7 +93,7 @@ impl PaneGroup {
pub fn resize(
&mut self,
pane: &View<Pane>,
pane: &Entity<Pane>,
direction: Axis,
amount: Pixels,
bounds: &Bounds<Pixels>,
@ -115,7 +115,7 @@ impl PaneGroup {
};
}
pub fn swap(&mut self, from: &View<Pane>, to: &View<Pane>) {
pub fn swap(&mut self, from: &Entity<Pane>, to: &Entity<Pane>) {
match &mut self.root {
Member::Pane(_) => {}
Member::Axis(axis) => axis.swap(from, to),
@ -125,13 +125,14 @@ impl PaneGroup {
#[allow(clippy::too_many_arguments)]
pub fn render(
&self,
project: &Model<Project>,
project: &Entity<Project>,
follower_states: &HashMap<PeerId, FollowerState>,
active_call: Option<&Model<ActiveCall>>,
active_pane: &View<Pane>,
active_call: Option<&Entity<ActiveCall>>,
active_pane: &Entity<Pane>,
zoomed: Option<&AnyWeakView>,
app_state: &Arc<AppState>,
cx: &mut ViewContext<Workspace>,
window: &mut Window,
cx: &mut Context<Workspace>,
) -> impl IntoElement {
self.root.render(
project,
@ -141,26 +142,27 @@ impl PaneGroup {
active_pane,
zoomed,
app_state,
window,
cx,
)
}
pub fn panes(&self) -> Vec<&View<Pane>> {
pub fn panes(&self) -> Vec<&Entity<Pane>> {
let mut panes = Vec::new();
self.root.collect_panes(&mut panes);
panes
}
pub fn first_pane(&self) -> View<Pane> {
pub fn first_pane(&self) -> Entity<Pane> {
self.root.first_pane()
}
pub fn find_pane_in_direction(
&mut self,
active_pane: &View<Pane>,
active_pane: &Entity<Pane>,
direction: SplitDirection,
cx: &WindowContext,
) -> Option<&View<Pane>> {
cx: &App,
) -> Option<&Entity<Pane>> {
let bounding_box = self.bounding_box_for_pane(active_pane)?;
let cursor = active_pane.read(cx).pixel_position_of_cursor(cx);
let center = match cursor {
@ -191,11 +193,11 @@ impl PaneGroup {
#[derive(Debug, Clone)]
pub enum Member {
Axis(PaneAxis),
Pane(View<Pane>),
Pane(Entity<Pane>),
}
impl Member {
fn new_axis(old_pane: View<Pane>, new_pane: View<Pane>, direction: SplitDirection) -> Self {
fn new_axis(old_pane: Entity<Pane>, new_pane: Entity<Pane>, direction: SplitDirection) -> Self {
use Axis::*;
use SplitDirection::*;
@ -212,14 +214,14 @@ impl Member {
Member::Axis(PaneAxis::new(axis, members))
}
fn contains(&self, needle: &View<Pane>) -> bool {
fn contains(&self, needle: &Entity<Pane>) -> bool {
match self {
Member::Axis(axis) => axis.members.iter().any(|member| member.contains(needle)),
Member::Pane(pane) => pane == needle,
}
}
fn first_pane(&self) -> View<Pane> {
fn first_pane(&self) -> Entity<Pane> {
match self {
Member::Axis(axis) => axis.members[0].first_pane(),
Member::Pane(pane) => pane.clone(),
@ -229,14 +231,15 @@ impl Member {
#[allow(clippy::too_many_arguments)]
pub fn render(
&self,
project: &Model<Project>,
project: &Entity<Project>,
basis: usize,
follower_states: &HashMap<PeerId, FollowerState>,
active_call: Option<&Model<ActiveCall>>,
active_pane: &View<Pane>,
active_call: Option<&Entity<ActiveCall>>,
active_pane: &Entity<Pane>,
zoomed: Option<&AnyWeakView>,
app_state: &Arc<AppState>,
cx: &mut ViewContext<Workspace>,
window: &mut Window,
cx: &mut Context<Workspace>,
) -> impl IntoElement {
match self {
Member::Pane(pane) => {
@ -349,7 +352,7 @@ impl Member {
|this, (leader_project_id, leader_user_id)| {
this.cursor_pointer().on_mouse_down(
MouseButton::Left,
cx.listener(move |this, _, cx| {
cx.listener(move |this, _, _, cx| {
crate::join_in_room_project(
leader_project_id,
leader_user_id,
@ -374,13 +377,14 @@ impl Member {
active_pane,
zoomed,
app_state,
window,
cx,
)
.into_any(),
}
}
fn collect_panes<'a>(&'a self, panes: &mut Vec<&'a View<Pane>>) {
fn collect_panes<'a>(&'a self, panes: &mut Vec<&'a Entity<Pane>>) {
match self {
Member::Axis(axis) => {
for member in &axis.members {
@ -428,8 +432,8 @@ impl PaneAxis {
fn split(
&mut self,
old_pane: &View<Pane>,
new_pane: &View<Pane>,
old_pane: &Entity<Pane>,
new_pane: &Entity<Pane>,
direction: SplitDirection,
) -> Result<()> {
for (mut idx, member) in self.members.iter_mut().enumerate() {
@ -460,7 +464,7 @@ impl PaneAxis {
Err(anyhow!("Pane not found"))
}
fn remove(&mut self, pane_to_remove: &View<Pane>) -> Result<Option<Member>> {
fn remove(&mut self, pane_to_remove: &Entity<Pane>) -> Result<Option<Member>> {
let mut found_pane = false;
let mut remove_member = None;
for (idx, member) in self.members.iter_mut().enumerate() {
@ -513,7 +517,7 @@ impl PaneAxis {
fn resize(
&mut self,
pane: &View<Pane>,
pane: &Entity<Pane>,
axis: Axis,
amount: Pixels,
bounds: &Bounds<Pixels>,
@ -621,7 +625,7 @@ impl PaneAxis {
Some(true)
}
fn swap(&mut self, from: &View<Pane>, to: &View<Pane>) {
fn swap(&mut self, from: &Entity<Pane>, to: &Entity<Pane>) {
for member in self.members.iter_mut() {
match member {
Member::Axis(axis) => axis.swap(from, to),
@ -636,7 +640,7 @@ impl PaneAxis {
}
}
fn bounding_box_for_pane(&self, pane: &View<Pane>) -> Option<Bounds<Pixels>> {
fn bounding_box_for_pane(&self, pane: &Entity<Pane>) -> Option<Bounds<Pixels>> {
debug_assert!(self.members.len() == self.bounding_boxes.lock().len());
for (idx, member) in self.members.iter().enumerate() {
@ -656,7 +660,7 @@ impl PaneAxis {
None
}
fn pane_at_pixel_position(&self, coordinate: Point<Pixels>) -> Option<&View<Pane>> {
fn pane_at_pixel_position(&self, coordinate: Point<Pixels>) -> Option<&Entity<Pane>> {
debug_assert!(self.members.len() == self.bounding_boxes.lock().len());
let bounding_boxes = self.bounding_boxes.lock();
@ -677,14 +681,15 @@ impl PaneAxis {
#[allow(clippy::too_many_arguments)]
fn render(
&self,
project: &Model<Project>,
project: &Entity<Project>,
basis: usize,
follower_states: &HashMap<PeerId, FollowerState>,
active_call: Option<&Model<ActiveCall>>,
active_pane: &View<Pane>,
active_call: Option<&Entity<ActiveCall>>,
active_pane: &Entity<Pane>,
zoomed: Option<&AnyWeakView>,
app_state: &Arc<AppState>,
cx: &mut ViewContext<Workspace>,
window: &mut Window,
cx: &mut Context<Workspace>,
) -> gpui::AnyElement {
debug_assert!(self.members.len() == self.flexes.lock().len());
let mut active_pane_ix = None;
@ -694,7 +699,7 @@ impl PaneAxis {
basis,
self.flexes.clone(),
self.bounding_boxes.clone(),
cx.view().downgrade(),
cx.model().downgrade(),
)
.children(self.members.iter().enumerate().map(|(ix, member)| {
if member.contains(active_pane) {
@ -709,6 +714,7 @@ impl PaneAxis {
active_pane,
zoomed,
app_state,
window,
cx,
)
.into_any_element()
@ -742,14 +748,14 @@ impl SplitDirection {
[Self::Up, Self::Down, Self::Left, Self::Right]
}
pub fn vertical(cx: &WindowContext) -> Self {
pub fn vertical(cx: &mut App) -> Self {
match WorkspaceSettings::get_global(cx).pane_split_direction_vertical {
PaneSplitDirectionVertical::Left => SplitDirection::Left,
PaneSplitDirectionVertical::Right => SplitDirection::Right,
}
}
pub fn horizontal(cx: &WindowContext) -> Self {
pub fn horizontal(cx: &mut App) -> Self {
match WorkspaceSettings::get_global(cx).pane_split_direction_horizontal {
PaneSplitDirectionHorizontal::Down => SplitDirection::Down,
PaneSplitDirectionHorizontal::Up => SplitDirection::Up,
@ -814,9 +820,9 @@ mod element {
use std::{cell::RefCell, iter, rc::Rc, sync::Arc};
use gpui::{
px, relative, size, Along, AnyElement, Axis, Bounds, Element, GlobalElementId, IntoElement,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, Size, Style,
WeakView, WindowContext,
px, relative, size, Along, AnyElement, App, Axis, Bounds, Element, GlobalElementId,
IntoElement, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point,
Size, Style, WeakEntity, Window,
};
use gpui::{CursorStyle, Hitbox};
use parking_lot::Mutex;
@ -838,7 +844,7 @@ mod element {
basis: usize,
flexes: Arc<Mutex<Vec<f32>>>,
bounding_boxes: Arc<Mutex<Vec<Option<Bounds<Pixels>>>>>,
workspace: WeakView<Workspace>,
workspace: WeakEntity<Workspace>,
) -> PaneAxisElement {
PaneAxisElement {
axis,
@ -858,7 +864,7 @@ mod element {
bounding_boxes: Arc<Mutex<Vec<Option<Bounds<Pixels>>>>>,
children: SmallVec<[AnyElement; 2]>,
active_pane_ix: Option<usize>,
workspace: WeakView<Workspace>,
workspace: WeakEntity<Workspace>,
}
pub struct PaneAxisLayout {
@ -891,8 +897,9 @@ mod element {
axis: Axis,
child_start: Point<Pixels>,
container_size: Size<Pixels>,
workspace: WeakView<Workspace>,
cx: &mut WindowContext,
workspace: WeakEntity<Workspace>,
window: &mut Window,
cx: &mut App,
) {
let min_size = match axis {
Axis::Horizontal => px(HORIZONTAL_MIN_SIZE),
@ -966,17 +973,18 @@ mod element {
}
workspace
.update(cx, |this, cx| this.serialize_workspace(cx))
.update(cx, |this, cx| this.serialize_workspace(window, cx))
.log_err();
cx.stop_propagation();
cx.refresh();
window.refresh();
}
#[allow(clippy::too_many_arguments)]
fn layout_handle(
axis: Axis,
pane_bounds: Bounds<Pixels>,
cx: &mut WindowContext,
window: &mut Window,
_cx: &mut App,
) -> PaneAxisHandleLayout {
let handle_bounds = Bounds {
origin: pane_bounds.origin.apply_along(axis, |origin| {
@ -994,7 +1002,7 @@ mod element {
};
PaneAxisHandleLayout {
hitbox: cx.insert_hitbox(handle_bounds, true),
hitbox: window.insert_hitbox(handle_bounds, true),
divider_bounds,
}
}
@ -1019,7 +1027,8 @@ mod element {
fn request_layout(
&mut self,
_global_id: Option<&GlobalElementId>,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) -> (gpui::LayoutId, Self::RequestLayoutState) {
let style = Style {
flex_grow: 1.,
@ -1028,7 +1037,7 @@ mod element {
size: size(relative(1.).into(), relative(1.).into()),
..Style::default()
};
(cx.request_layout(style, None), ())
(window.request_layout(style, None, cx), ())
}
fn prepaint(
@ -1036,9 +1045,10 @@ mod element {
global_id: Option<&GlobalElementId>,
bounds: Bounds<Pixels>,
_state: &mut Self::RequestLayoutState,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) -> PaneAxisLayout {
let dragged_handle = cx.with_element_state::<Rc<RefCell<Option<usize>>>, _>(
let dragged_handle = window.with_element_state::<Rc<RefCell<Option<usize>>>, _>(
global_id.unwrap(),
|state, _cx| {
let state = state.unwrap_or_else(|| Rc::new(RefCell::new(None)));
@ -1093,8 +1103,8 @@ mod element {
};
bounding_boxes.push(Some(child_bounds));
child.layout_as_root(child_size.into(), cx);
child.prepaint_at(origin, cx);
child.layout_as_root(child_size.into(), window, cx);
child.prepaint_at(origin, window, cx);
origin = origin.apply_along(self.axis, |val| val + child_size.along(self.axis));
layout.children.push(PaneAxisChildLayout {
@ -1106,8 +1116,12 @@ mod element {
for (ix, child_layout) in layout.children.iter_mut().enumerate() {
if active_pane_magnification.is_none() && ix < len - 1 {
child_layout.handle =
Some(Self::layout_handle(self.axis, child_layout.bounds, cx));
child_layout.handle = Some(Self::layout_handle(
self.axis,
child_layout.bounds,
window,
cx,
));
}
}
@ -1120,10 +1134,11 @@ mod element {
bounds: gpui::Bounds<ui::prelude::Pixels>,
_: &mut Self::RequestLayoutState,
layout: &mut Self::PrepaintState,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) {
for child in &mut layout.children {
child.element.paint(cx);
child.element.paint(window, cx);
}
let overlay_opacity = WorkspaceSettings::get(None, cx)
@ -1158,12 +1173,12 @@ mod element {
};
if overlay_opacity.is_some() && self.active_pane_ix != Some(ix) {
cx.paint_quad(gpui::fill(overlay_bounds, overlay_background));
window.paint_quad(gpui::fill(overlay_bounds, overlay_background));
}
if let Some(border) = overlay_border {
if self.active_pane_ix == Some(ix) {
cx.paint_quad(gpui::quad(
window.paint_quad(gpui::quad(
overlay_bounds,
0.,
gpui::transparent_black(),
@ -1179,40 +1194,40 @@ mod element {
Axis::Vertical => CursorStyle::ResizeRow,
Axis::Horizontal => CursorStyle::ResizeColumn,
};
cx.set_cursor_style(cursor_style, &handle.hitbox);
cx.paint_quad(gpui::fill(
window.set_cursor_style(cursor_style, &handle.hitbox);
window.paint_quad(gpui::fill(
handle.divider_bounds,
cx.theme().colors().pane_group_border,
));
cx.on_mouse_event({
window.on_mouse_event({
let dragged_handle = layout.dragged_handle.clone();
let flexes = self.flexes.clone();
let workspace = self.workspace.clone();
let handle_hitbox = handle.hitbox.clone();
move |e: &MouseDownEvent, phase, cx| {
if phase.bubble() && handle_hitbox.is_hovered(cx) {
move |e: &MouseDownEvent, phase, window, cx| {
if phase.bubble() && handle_hitbox.is_hovered(window) {
dragged_handle.replace(Some(ix));
if e.click_count >= 2 {
let mut borrow = flexes.lock();
*borrow = vec![1.; borrow.len()];
workspace
.update(cx, |this, cx| this.serialize_workspace(cx))
.update(cx, |this, cx| this.serialize_workspace(window, cx))
.log_err();
cx.refresh();
window.refresh();
}
cx.stop_propagation();
}
}
});
cx.on_mouse_event({
window.on_mouse_event({
let workspace = self.workspace.clone();
let dragged_handle = layout.dragged_handle.clone();
let flexes = self.flexes.clone();
let child_bounds = child.bounds;
let axis = self.axis;
move |e: &MouseMoveEvent, phase, cx| {
move |e: &MouseMoveEvent, phase, window, cx| {
let dragged_handle = dragged_handle.borrow();
if phase.bubble() && *dragged_handle == Some(ix) {
Self::compute_resize(
@ -1223,6 +1238,7 @@ mod element {
child_bounds.origin,
bounds.size,
workspace.clone(),
window,
cx,
)
}
@ -1231,9 +1247,9 @@ mod element {
}
}
cx.on_mouse_event({
window.on_mouse_event({
let dragged_handle = layout.dragged_handle.clone();
move |_: &MouseUpEvent, phase, _cx| {
move |_: &MouseUpEvent, phase, _window, _cx| {
if phase.bubble() {
dragged_handle.replace(None);
}

View file

@ -2,13 +2,13 @@ use super::{SerializedAxis, SerializedWindowBounds};
use crate::{
item::ItemHandle, Member, Pane, PaneAxis, SerializableItemRegistry, Workspace, WorkspaceId,
};
use anyhow::{Context, Result};
use anyhow::{Context as _, Result};
use async_recursion::async_recursion;
use db::sqlez::{
bindable::{Bind, Column, StaticColumnCount},
statement::Statement,
};
use gpui::{AsyncWindowContext, Model, View, WeakView};
use gpui::{AsyncWindowContext, Entity, WeakEntity};
use itertools::Itertools as _;
use project::Project;
use remote::ssh_session::SshProjectId;
@ -353,11 +353,15 @@ impl SerializedPaneGroup {
#[async_recursion(?Send)]
pub(crate) async fn deserialize(
self,
project: &Model<Project>,
project: &Entity<Project>,
workspace_id: WorkspaceId,
workspace: WeakView<Workspace>,
workspace: WeakEntity<Workspace>,
cx: &mut AsyncWindowContext,
) -> Option<(Member, Option<View<Pane>>, Vec<Option<Box<dyn ItemHandle>>>)> {
) -> Option<(
Member,
Option<Entity<Pane>>,
Vec<Option<Box<dyn ItemHandle>>>,
)> {
match self {
SerializedPaneGroup::Group {
axis,
@ -394,7 +398,9 @@ impl SerializedPaneGroup {
}
SerializedPaneGroup::Pane(serialized_pane) => {
let pane = workspace
.update(cx, |workspace, cx| workspace.add_pane(cx).downgrade())
.update_in(cx, |workspace, window, cx| {
workspace.add_pane(window, cx).downgrade()
})
.log_err()?;
let active = serialized_pane.active;
let new_items = serialized_pane
@ -412,8 +418,8 @@ impl SerializedPaneGroup {
} else {
let pane = pane.upgrade()?;
workspace
.update(cx, |workspace, cx| {
workspace.force_remove_pane(&pane, &None, cx)
.update_in(cx, |workspace, window, cx| {
workspace.force_remove_pane(&pane, &None, window, cx)
})
.log_err()?;
None
@ -441,10 +447,10 @@ impl SerializedPane {
pub async fn deserialize_to(
&self,
project: &Model<Project>,
pane: &WeakView<Pane>,
project: &Entity<Project>,
pane: &WeakEntity<Pane>,
workspace_id: WorkspaceId,
workspace: WeakView<Workspace>,
workspace: WeakEntity<Workspace>,
cx: &mut AsyncWindowContext,
) -> Result<Vec<Option<Box<dyn ItemHandle>>>> {
let mut item_tasks = Vec::new();
@ -452,13 +458,14 @@ impl SerializedPane {
let mut preview_item_index = None;
for (index, item) in self.children.iter().enumerate() {
let project = project.clone();
item_tasks.push(pane.update(cx, |_, cx| {
item_tasks.push(pane.update_in(cx, |_, window, cx| {
SerializableItemRegistry::deserialize(
&item.kind,
project,
workspace.clone(),
workspace_id,
item.item_id,
window,
cx,
)
})?);
@ -476,15 +483,15 @@ impl SerializedPane {
items.push(item_handle.clone());
if let Some(item_handle) = item_handle {
pane.update(cx, |pane, cx| {
pane.add_item(item_handle.clone(), true, true, None, cx);
pane.update_in(cx, |pane, window, cx| {
pane.add_item(item_handle.clone(), true, true, None, window, cx);
})?;
}
}
if let Some(active_item_index) = active_item_index {
pane.update(cx, |pane, cx| {
pane.activate_item(active_item_index, false, false, cx);
pane.update_in(cx, |pane, window, cx| {
pane.activate_item(active_item_index, false, false, window, cx);
})?;
}

View file

@ -2,8 +2,8 @@ use std::{any::Any, sync::Arc};
use any_vec::AnyVec;
use gpui::{
AnyView, AnyWeakView, AppContext, EventEmitter, Subscription, Task, View, ViewContext,
WeakView, WindowContext,
AnyView, AnyWeakEntity, App, Context, Entity, EventEmitter, Subscription, Task, WeakEntity,
Window,
};
use project::search::SearchQuery;
@ -57,31 +57,66 @@ pub trait SearchableItem: Item + EventEmitter<SearchEvent> {
}
}
fn search_bar_visibility_changed(&mut self, _visible: bool, _cx: &mut ViewContext<Self>) {}
fn search_bar_visibility_changed(
&mut self,
_visible: bool,
_window: &mut Window,
_cx: &mut Context<Self>,
) {
}
fn has_filtered_search_ranges(&mut self) -> bool {
Self::supported_options().selection
}
fn toggle_filtered_search_ranges(&mut self, _enabled: bool, _cx: &mut ViewContext<Self>) {}
fn toggle_filtered_search_ranges(
&mut self,
_enabled: bool,
_window: &mut Window,
_cx: &mut Context<Self>,
) {
}
fn get_matches(&self, _: &mut WindowContext) -> Vec<Self::Match> {
fn get_matches(&self, _window: &mut Window, _: &mut App) -> Vec<Self::Match> {
Vec::new()
}
fn clear_matches(&mut self, cx: &mut ViewContext<Self>);
fn update_matches(&mut self, matches: &[Self::Match], cx: &mut ViewContext<Self>);
fn query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String;
fn activate_match(&mut self, index: usize, matches: &[Self::Match], cx: &mut ViewContext<Self>);
fn select_matches(&mut self, matches: &[Self::Match], cx: &mut ViewContext<Self>);
fn replace(&mut self, _: &Self::Match, _: &SearchQuery, _: &mut ViewContext<Self>);
fn clear_matches(&mut self, window: &mut Window, cx: &mut Context<Self>);
fn update_matches(
&mut self,
matches: &[Self::Match],
window: &mut Window,
cx: &mut Context<Self>,
);
fn query_suggestion(&mut self, window: &mut Window, cx: &mut Context<Self>) -> String;
fn activate_match(
&mut self,
index: usize,
matches: &[Self::Match],
window: &mut Window,
cx: &mut Context<Self>,
);
fn select_matches(
&mut self,
matches: &[Self::Match],
window: &mut Window,
cx: &mut Context<Self>,
);
fn replace(
&mut self,
_: &Self::Match,
_: &SearchQuery,
_window: &mut Window,
_: &mut Context<Self>,
);
fn replace_all(
&mut self,
matches: &mut dyn Iterator<Item = &Self::Match>,
query: &SearchQuery,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) {
for item in matches {
self.replace(item, query, cx);
self.replace(item, query, window, cx);
}
}
fn match_index_for_direction(
@ -90,7 +125,8 @@ pub trait SearchableItem: Item + EventEmitter<SearchEvent> {
current_index: usize,
direction: Direction,
count: usize,
_: &mut ViewContext<Self>,
_window: &mut Window,
_: &mut Context<Self>,
) -> usize {
match direction {
Direction::Prev => {
@ -107,12 +143,14 @@ pub trait SearchableItem: Item + EventEmitter<SearchEvent> {
fn find_matches(
&mut self,
query: Arc<SearchQuery>,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<Vec<Self::Match>>;
fn active_match_index(
&mut self,
matches: &[Self::Match],
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<usize>;
}
@ -122,25 +160,34 @@ pub trait SearchableItemHandle: ItemHandle {
fn supported_options(&self) -> SearchOptions;
fn subscribe_to_search_events(
&self,
cx: &mut WindowContext,
handler: Box<dyn Fn(&SearchEvent, &mut WindowContext) + Send>,
window: &mut Window,
cx: &mut App,
handler: Box<dyn Fn(&SearchEvent, &mut Window, &mut App) + Send>,
) -> Subscription;
fn clear_matches(&self, cx: &mut WindowContext);
fn update_matches(&self, matches: &AnyVec<dyn Send>, cx: &mut WindowContext);
fn query_suggestion(&self, cx: &mut WindowContext) -> String;
fn activate_match(&self, index: usize, matches: &AnyVec<dyn Send>, cx: &mut WindowContext);
fn select_matches(&self, matches: &AnyVec<dyn Send>, cx: &mut WindowContext);
fn clear_matches(&self, window: &mut Window, cx: &mut App);
fn update_matches(&self, matches: &AnyVec<dyn Send>, window: &mut Window, cx: &mut App);
fn query_suggestion(&self, window: &mut Window, cx: &mut App) -> String;
fn activate_match(
&self,
index: usize,
matches: &AnyVec<dyn Send>,
window: &mut Window,
cx: &mut App,
);
fn select_matches(&self, matches: &AnyVec<dyn Send>, window: &mut Window, cx: &mut App);
fn replace(
&self,
_: any_vec::element::ElementRef<'_, dyn Send>,
_: &SearchQuery,
_: &mut WindowContext,
_window: &mut Window,
_: &mut App,
);
fn replace_all(
&self,
matches: &mut dyn Iterator<Item = any_vec::element::ElementRef<'_, dyn Send>>,
query: &SearchQuery,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
);
fn match_index_for_direction(
&self,
@ -148,24 +195,27 @@ pub trait SearchableItemHandle: ItemHandle {
current_index: usize,
direction: Direction,
count: usize,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) -> usize;
fn find_matches(
&self,
query: Arc<SearchQuery>,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) -> Task<AnyVec<dyn Send>>;
fn active_match_index(
&self,
matches: &AnyVec<dyn Send>,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) -> Option<usize>;
fn search_bar_visibility_changed(&self, visible: bool, cx: &mut WindowContext);
fn search_bar_visibility_changed(&self, visible: bool, window: &mut Window, cx: &mut App);
fn toggle_filtered_search_ranges(&mut self, enabled: bool, cx: &mut WindowContext);
fn toggle_filtered_search_ranges(&mut self, enabled: bool, window: &mut Window, cx: &mut App);
}
impl<T: SearchableItem> SearchableItemHandle for View<T> {
impl<T: SearchableItem> SearchableItemHandle for Entity<T> {
fn downgrade(&self) -> Box<dyn WeakSearchableItemHandle> {
Box::new(self.downgrade())
}
@ -180,32 +230,45 @@ impl<T: SearchableItem> SearchableItemHandle for View<T> {
fn subscribe_to_search_events(
&self,
cx: &mut WindowContext,
handler: Box<dyn Fn(&SearchEvent, &mut WindowContext) + Send>,
window: &mut Window,
cx: &mut App,
handler: Box<dyn Fn(&SearchEvent, &mut Window, &mut App) + Send>,
) -> Subscription {
cx.subscribe(self, move |_, event: &SearchEvent, cx| handler(event, cx))
window.subscribe(self, cx, move |_, event: &SearchEvent, window, cx| {
handler(event, window, cx)
})
}
fn clear_matches(&self, cx: &mut WindowContext) {
self.update(cx, |this, cx| this.clear_matches(cx));
fn clear_matches(&self, window: &mut Window, cx: &mut App) {
self.update(cx, |this, cx| this.clear_matches(window, cx));
}
fn update_matches(&self, matches: &AnyVec<dyn Send>, cx: &mut WindowContext) {
let matches = matches.downcast_ref().unwrap();
self.update(cx, |this, cx| this.update_matches(matches.as_slice(), cx));
}
fn query_suggestion(&self, cx: &mut WindowContext) -> String {
self.update(cx, |this, cx| this.query_suggestion(cx))
}
fn activate_match(&self, index: usize, matches: &AnyVec<dyn Send>, cx: &mut WindowContext) {
fn update_matches(&self, matches: &AnyVec<dyn Send>, window: &mut Window, cx: &mut App) {
let matches = matches.downcast_ref().unwrap();
self.update(cx, |this, cx| {
this.activate_match(index, matches.as_slice(), cx)
this.update_matches(matches.as_slice(), window, cx)
});
}
fn query_suggestion(&self, window: &mut Window, cx: &mut App) -> String {
self.update(cx, |this, cx| this.query_suggestion(window, cx))
}
fn activate_match(
&self,
index: usize,
matches: &AnyVec<dyn Send>,
window: &mut Window,
cx: &mut App,
) {
let matches = matches.downcast_ref().unwrap();
self.update(cx, |this, cx| {
this.activate_match(index, matches.as_slice(), window, cx)
});
}
fn select_matches(&self, matches: &AnyVec<dyn Send>, cx: &mut WindowContext) {
fn select_matches(&self, matches: &AnyVec<dyn Send>, window: &mut Window, cx: &mut App) {
let matches = matches.downcast_ref().unwrap();
self.update(cx, |this, cx| this.select_matches(matches.as_slice(), cx));
self.update(cx, |this, cx| {
this.select_matches(matches.as_slice(), window, cx)
});
}
fn match_index_for_direction(
@ -214,20 +277,29 @@ impl<T: SearchableItem> SearchableItemHandle for View<T> {
current_index: usize,
direction: Direction,
count: usize,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) -> usize {
let matches = matches.downcast_ref().unwrap();
self.update(cx, |this, cx| {
this.match_index_for_direction(matches.as_slice(), current_index, direction, count, cx)
this.match_index_for_direction(
matches.as_slice(),
current_index,
direction,
count,
window,
cx,
)
})
}
fn find_matches(
&self,
query: Arc<SearchQuery>,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) -> Task<AnyVec<dyn Send>> {
let matches = self.update(cx, |this, cx| this.find_matches(query, cx));
cx.spawn(|_| async {
let matches = self.update(cx, |this, cx| this.find_matches(query, window, cx));
window.spawn(cx, |_| async {
let matches = matches.await;
let mut any_matches = AnyVec::with_capacity::<T::Match>(matches.len());
{
@ -242,11 +314,12 @@ impl<T: SearchableItem> SearchableItemHandle for View<T> {
fn active_match_index(
&self,
matches: &AnyVec<dyn Send>,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) -> Option<usize> {
let matches = matches.downcast_ref()?;
self.update(cx, |this, cx| {
this.active_match_index(matches.as_slice(), cx)
this.active_match_index(matches.as_slice(), window, cx)
})
}
@ -254,32 +327,39 @@ impl<T: SearchableItem> SearchableItemHandle for View<T> {
&self,
mat: any_vec::element::ElementRef<'_, dyn Send>,
query: &SearchQuery,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) {
let mat = mat.downcast_ref().unwrap();
self.update(cx, |this, cx| this.replace(mat, query, cx))
self.update(cx, |this, cx| this.replace(mat, query, window, cx))
}
fn replace_all(
&self,
matches: &mut dyn Iterator<Item = any_vec::element::ElementRef<'_, dyn Send>>,
query: &SearchQuery,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) {
self.update(cx, |this, cx| {
this.replace_all(&mut matches.map(|m| m.downcast_ref().unwrap()), query, cx);
this.replace_all(
&mut matches.map(|m| m.downcast_ref().unwrap()),
query,
window,
cx,
);
})
}
fn search_bar_visibility_changed(&self, visible: bool, cx: &mut WindowContext) {
fn search_bar_visibility_changed(&self, visible: bool, window: &mut Window, cx: &mut App) {
self.update(cx, |this, cx| {
this.search_bar_visibility_changed(visible, cx)
this.search_bar_visibility_changed(visible, window, cx)
});
}
fn toggle_filtered_search_ranges(&mut self, enabled: bool, cx: &mut WindowContext) {
fn toggle_filtered_search_ranges(&mut self, enabled: bool, window: &mut Window, cx: &mut App) {
self.update(cx, |this, cx| {
this.toggle_filtered_search_ranges(enabled, cx)
this.toggle_filtered_search_ranges(enabled, window, cx)
});
}
}
@ -305,17 +385,17 @@ impl PartialEq for Box<dyn SearchableItemHandle> {
impl Eq for Box<dyn SearchableItemHandle> {}
pub trait WeakSearchableItemHandle: WeakItemHandle {
fn upgrade(&self, cx: &AppContext) -> Option<Box<dyn SearchableItemHandle>>;
fn upgrade(&self, cx: &App) -> Option<Box<dyn SearchableItemHandle>>;
fn into_any(self) -> AnyWeakView;
fn into_any(self) -> AnyWeakEntity;
}
impl<T: SearchableItem> WeakSearchableItemHandle for WeakView<T> {
fn upgrade(&self, _cx: &AppContext) -> Option<Box<dyn SearchableItemHandle>> {
impl<T: SearchableItem> WeakSearchableItemHandle for WeakEntity<T> {
fn upgrade(&self, _cx: &App) -> Option<Box<dyn SearchableItemHandle>> {
Some(Box::new(self.upgrade()?))
}
fn into_any(self) -> AnyWeakView {
fn into_any(self) -> AnyWeakEntity {
self.into()
}
}

View file

@ -5,8 +5,8 @@ use crate::{
use call::{RemoteVideoTrack, RemoteVideoTrackView};
use client::{proto::PeerId, User};
use gpui::{
div, AppContext, EventEmitter, FocusHandle, FocusableView, InteractiveElement, ParentElement,
Render, SharedString, Styled, View, ViewContext, VisualContext, WindowContext,
div, AppContext, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement,
ParentElement, Render, SharedString, Styled,
};
use std::sync::Arc;
use ui::{prelude::*, Icon, IconName};
@ -19,7 +19,7 @@ pub struct SharedScreen {
pub peer_id: PeerId,
user: Arc<User>,
nav_history: Option<ItemNavHistory>,
view: View<RemoteVideoTrackView>,
view: Entity<RemoteVideoTrackView>,
focus: FocusHandle,
}
@ -28,9 +28,10 @@ impl SharedScreen {
track: RemoteVideoTrack,
peer_id: PeerId,
user: Arc<User>,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
let view = cx.new_view(|cx| RemoteVideoTrackView::new(track.clone(), cx));
let view = cx.new(|cx| RemoteVideoTrackView::new(track.clone(), window, cx));
cx.subscribe(&view, |_, _, ev, cx| match ev {
call::RemoteVideoTrackViewEvent::Close => cx.emit(Event::Close),
})
@ -47,13 +48,13 @@ impl SharedScreen {
impl EventEmitter<Event> for SharedScreen {}
impl FocusableView for SharedScreen {
fn focus_handle(&self, _: &AppContext) -> FocusHandle {
impl Focusable for SharedScreen {
fn focus_handle(&self, _: &App) -> FocusHandle {
self.focus.clone()
}
}
impl Render for SharedScreen {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
div()
.bg(cx.theme().colors().editor_background)
.track_focus(&self.focus)
@ -66,21 +67,21 @@ impl Render for SharedScreen {
impl Item for SharedScreen {
type Event = Event;
fn tab_tooltip_text(&self, _: &AppContext) -> Option<SharedString> {
fn tab_tooltip_text(&self, _: &App) -> Option<SharedString> {
Some(format!("{}'s screen", self.user.github_login).into())
}
fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
fn deactivated(&mut self, _window: &mut Window, cx: &mut Context<Self>) {
if let Some(nav_history) = self.nav_history.as_mut() {
nav_history.push::<()>(None, cx);
}
}
fn tab_icon(&self, _cx: &WindowContext) -> Option<Icon> {
fn tab_icon(&self, _window: &Window, _cx: &App) -> Option<Icon> {
Some(Icon::new(IconName::Screen))
}
fn tab_content_text(&self, _cx: &WindowContext) -> Option<SharedString> {
fn tab_content_text(&self, _window: &Window, _cx: &App) -> Option<SharedString> {
Some(format!("{}'s screen", self.user.github_login).into())
}
@ -88,17 +89,23 @@ impl Item for SharedScreen {
None
}
fn set_nav_history(&mut self, history: ItemNavHistory, _: &mut ViewContext<Self>) {
fn set_nav_history(
&mut self,
history: ItemNavHistory,
_window: &mut Window,
_cx: &mut Context<Self>,
) {
self.nav_history = Some(history);
}
fn clone_on_split(
&self,
_workspace_id: Option<WorkspaceId>,
cx: &mut ViewContext<Self>,
) -> Option<View<Self>> {
Some(cx.new_view(|cx| Self {
view: self.view.update(cx, |view, cx| view.clone(cx)),
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<Entity<Self>> {
Some(cx.new(|cx| Self {
view: self.view.update(cx, |view, cx| view.clone(window, cx)),
peer_id: self.peer_id,
user: self.user.clone(),
nav_history: Default::default(),

View file

@ -7,9 +7,8 @@ use call::participant::{Frame, RemoteVideoTrack};
use client::{proto::PeerId, User};
use futures::StreamExt;
use gpui::{
div, surface, AppContext, EventEmitter, FocusHandle, FocusableView, InteractiveElement,
ParentElement, Render, SharedString, Styled, Task, View, ViewContext, VisualContext,
WindowContext,
div, surface, App, Context, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement,
ParentElement, Render, SharedString, Styled, Task, Window,
};
use std::sync::{Arc, Weak};
use ui::{prelude::*, Icon, IconName};
@ -33,7 +32,8 @@ impl SharedScreen {
track: Arc<RemoteVideoTrack>,
peer_id: PeerId,
user: Arc<User>,
cx: &mut ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
cx.focus_handle();
let mut frames = track.frames();
@ -43,7 +43,7 @@ impl SharedScreen {
peer_id,
user,
nav_history: Default::default(),
_maintain_frame: cx.spawn(|this, mut cx| async move {
_maintain_frame: cx.spawn_in(window, |this, mut cx| async move {
while let Some(frame) = frames.next().await {
this.update(&mut cx, |this, cx| {
this.frame = Some(frame);
@ -60,13 +60,13 @@ impl SharedScreen {
impl EventEmitter<Event> for SharedScreen {}
impl FocusableView for SharedScreen {
fn focus_handle(&self, _: &AppContext) -> FocusHandle {
impl Focusable for SharedScreen {
fn focus_handle(&self, _: &App) -> FocusHandle {
self.focus.clone()
}
}
impl Render for SharedScreen {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
div()
.bg(cx.theme().colors().editor_background)
.track_focus(&self.focus)
@ -83,21 +83,21 @@ impl Render for SharedScreen {
impl Item for SharedScreen {
type Event = Event;
fn tab_tooltip_text(&self, _: &AppContext) -> Option<SharedString> {
fn tab_tooltip_text(&self, _: &App) -> Option<SharedString> {
Some(format!("{}'s screen", self.user.github_login).into())
}
fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
fn deactivated(&mut self, _: &mut Window, cx: &mut Context<Self>) {
if let Some(nav_history) = self.nav_history.as_mut() {
nav_history.push::<()>(None, cx);
}
}
fn tab_icon(&self, _cx: &WindowContext) -> Option<Icon> {
fn tab_icon(&self, _window: &Window, _cx: &App) -> Option<Icon> {
Some(Icon::new(IconName::Screen))
}
fn tab_content_text(&self, _cx: &WindowContext) -> Option<SharedString> {
fn tab_content_text(&self, _window: &Window, _cx: &App) -> Option<SharedString> {
Some(format!("{}'s screen", self.user.github_login).into())
}
@ -105,17 +105,23 @@ impl Item for SharedScreen {
None
}
fn set_nav_history(&mut self, history: ItemNavHistory, _: &mut ViewContext<Self>) {
fn set_nav_history(
&mut self,
history: ItemNavHistory,
_window: &mut Window,
_: &mut Context<Self>,
) {
self.nav_history = Some(history);
}
fn clone_on_split(
&self,
_workspace_id: Option<WorkspaceId>,
cx: &mut ViewContext<Self>,
) -> Option<View<Self>> {
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<Entity<Self>> {
let track = self.track.upgrade()?;
Some(cx.new_view(|cx| Self::new(track, self.peer_id, self.user.clone(), cx)))
Some(cx.new(|cx| Self::new(track, self.peer_id, self.user.clone(), window, cx)))
}
fn to_item_events(event: &Self::Event, mut f: impl FnMut(ItemEvent)) {

View file

@ -1,7 +1,7 @@
use crate::{ItemHandle, Pane};
use gpui::{
AnyView, Decorations, IntoElement, ParentElement, Render, Styled, Subscription, View,
ViewContext, WindowContext,
AnyView, App, Context, Decorations, Entity, IntoElement, ParentElement, Render, Styled,
Subscription, Window,
};
use std::any::TypeId;
use theme::CLIENT_SIDE_DECORATION_ROUNDING;
@ -12,7 +12,8 @@ pub trait StatusItemView: Render {
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>,
);
}
@ -21,7 +22,8 @@ trait StatusItemViewHandle: Send {
fn set_active_pane_item(
&self,
active_pane_item: Option<&dyn ItemHandle>,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
);
fn item_type(&self) -> TypeId;
}
@ -29,12 +31,12 @@ trait StatusItemViewHandle: Send {
pub struct StatusBar {
left_items: Vec<Box<dyn StatusItemViewHandle>>,
right_items: Vec<Box<dyn StatusItemViewHandle>>,
active_pane: View<Pane>,
active_pane: Entity<Pane>,
_observe_active_pane: Subscription,
}
impl Render for StatusBar {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
h_flex()
.w_full()
.justify_between()
@ -42,7 +44,7 @@ impl Render for StatusBar {
.py(DynamicSpacing::Base04.rems(cx))
.px(DynamicSpacing::Base08.rems(cx))
.bg(cx.theme().colors().status_bar_background)
.map(|el| match cx.window_decorations() {
.map(|el| match window.window_decorations() {
Decorations::Server => el,
Decorations::Client { tiling, .. } => el
.when(!(tiling.bottom || tiling.right), |el| {
@ -62,14 +64,14 @@ impl Render for StatusBar {
}
impl StatusBar {
fn render_left_tools(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
fn render_left_tools(&self, cx: &mut Context<Self>) -> impl IntoElement {
h_flex()
.gap(DynamicSpacing::Base04.rems(cx))
.overflow_x_hidden()
.children(self.left_items.iter().map(|item| item.to_any()))
}
fn render_right_tools(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
fn render_right_tools(&self, cx: &mut Context<Self>) -> impl IntoElement {
h_flex()
.gap(DynamicSpacing::Base04.rems(cx))
.children(self.right_items.iter().rev().map(|item| item.to_any()))
@ -77,30 +79,31 @@ impl StatusBar {
}
impl StatusBar {
pub fn new(active_pane: &View<Pane>, cx: &mut ViewContext<Self>) -> Self {
pub fn new(active_pane: &Entity<Pane>, window: &mut Window, cx: &mut Context<Self>) -> Self {
let mut this = Self {
left_items: Default::default(),
right_items: Default::default(),
active_pane: active_pane.clone(),
_observe_active_pane: cx
.observe(active_pane, |this, _, cx| this.update_active_pane_item(cx)),
_observe_active_pane: cx.observe_in(active_pane, window, |this, _, window, cx| {
this.update_active_pane_item(window, cx)
}),
};
this.update_active_pane_item(cx);
this.update_active_pane_item(window, cx);
this
}
pub fn add_left_item<T>(&mut self, item: View<T>, cx: &mut ViewContext<Self>)
pub fn add_left_item<T>(&mut self, item: Entity<T>, window: &mut Window, cx: &mut Context<Self>)
where
T: 'static + StatusItemView,
{
let active_pane_item = self.active_pane.read(cx).active_item();
item.set_active_pane_item(active_pane_item.as_deref(), cx);
item.set_active_pane_item(active_pane_item.as_deref(), window, cx);
self.left_items.push(Box::new(item));
cx.notify();
}
pub fn item_of_type<T: StatusItemView>(&self) -> Option<View<T>> {
pub fn item_of_type<T: StatusItemView>(&self) -> Option<Entity<T>> {
self.left_items
.iter()
.chain(self.right_items.iter())
@ -127,13 +130,14 @@ impl StatusBar {
pub fn insert_item_after<T>(
&mut self,
position: usize,
item: View<T>,
cx: &mut ViewContext<Self>,
item: Entity<T>,
window: &mut Window,
cx: &mut Context<Self>,
) where
T: 'static + StatusItemView,
{
let active_pane_item = self.active_pane.read(cx).active_item();
item.set_active_pane_item(active_pane_item.as_deref(), cx);
item.set_active_pane_item(active_pane_item.as_deref(), window, cx);
if position < self.left_items.len() {
self.left_items.insert(position + 1, Box::new(item))
@ -144,7 +148,7 @@ impl StatusBar {
cx.notify()
}
pub fn remove_item_at(&mut self, position: usize, cx: &mut ViewContext<Self>) {
pub fn remove_item_at(&mut self, position: usize, cx: &mut Context<Self>) {
if position < self.left_items.len() {
self.left_items.remove(position);
} else {
@ -153,33 +157,43 @@ impl StatusBar {
cx.notify();
}
pub fn add_right_item<T>(&mut self, item: View<T>, cx: &mut ViewContext<Self>)
where
pub fn add_right_item<T>(
&mut self,
item: Entity<T>,
window: &mut Window,
cx: &mut Context<Self>,
) where
T: 'static + StatusItemView,
{
let active_pane_item = self.active_pane.read(cx).active_item();
item.set_active_pane_item(active_pane_item.as_deref(), cx);
item.set_active_pane_item(active_pane_item.as_deref(), window, cx);
self.right_items.push(Box::new(item));
cx.notify();
}
pub fn set_active_pane(&mut self, active_pane: &View<Pane>, cx: &mut ViewContext<Self>) {
pub fn set_active_pane(
&mut self,
active_pane: &Entity<Pane>,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.active_pane = active_pane.clone();
self._observe_active_pane =
cx.observe(active_pane, |this, _, cx| this.update_active_pane_item(cx));
self.update_active_pane_item(cx);
self._observe_active_pane = cx.observe_in(active_pane, window, |this, _, window, cx| {
this.update_active_pane_item(window, cx)
});
self.update_active_pane_item(window, cx);
}
fn update_active_pane_item(&mut self, cx: &mut ViewContext<Self>) {
fn update_active_pane_item(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let active_pane_item = self.active_pane.read(cx).active_item();
for item in self.left_items.iter().chain(&self.right_items) {
item.set_active_pane_item(active_pane_item.as_deref(), cx);
item.set_active_pane_item(active_pane_item.as_deref(), window, cx);
}
}
}
impl<T: StatusItemView> StatusItemViewHandle for View<T> {
impl<T: StatusItemView> StatusItemViewHandle for Entity<T> {
fn to_any(&self) -> AnyView {
self.clone().into()
}
@ -187,10 +201,11 @@ impl<T: StatusItemView> StatusItemViewHandle for View<T> {
fn set_active_pane_item(
&self,
active_pane_item: Option<&dyn ItemHandle>,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) {
self.update(cx, |this, cx| {
this.set_active_pane_item(active_pane_item, cx)
this.set_active_pane_item(active_pane_item, window, cx)
});
}

View file

@ -1,7 +1,7 @@
use gpui::Context;
use project::TaskSourceKind;
use remote::ConnectionState;
use task::{ResolvedTask, TaskContext, TaskTemplate};
use ui::ViewContext;
use crate::Workspace;
@ -11,7 +11,7 @@ pub fn schedule_task(
task_to_resolve: &TaskTemplate,
task_cx: &TaskContext,
omit_history: bool,
cx: &mut ViewContext<Workspace>,
cx: &mut Context<Workspace>,
) {
match workspace.project.read(cx).ssh_connection_state(cx) {
None | Some(ConnectionState::Connected) => {}
@ -44,7 +44,7 @@ pub fn schedule_resolved_task(
task_source_kind: TaskSourceKind,
mut resolved_task: ResolvedTask,
omit_history: bool,
cx: &mut ViewContext<Workspace>,
cx: &mut Context<Workspace>,
) {
if let Some(spawn_in_terminal) = resolved_task.resolved.take() {
if !omit_history {

View file

@ -1,5 +1,5 @@
#![allow(unused, dead_code)]
use gpui::{actions, hsla, AnyElement, AppContext, EventEmitter, FocusHandle, FocusableView, Hsla};
use gpui::{actions, hsla, AnyElement, App, Entity, EventEmitter, FocusHandle, Focusable, Hsla};
use strum::IntoEnumIterator;
use theme::all_theme_colors;
use ui::{
@ -13,11 +13,11 @@ use crate::{Item, Workspace};
actions!(debug, [OpenThemePreview]);
pub fn init(cx: &mut AppContext) {
cx.observe_new_views(|workspace: &mut Workspace, _| {
workspace.register_action(|workspace, _: &OpenThemePreview, cx| {
let theme_preview = cx.new_view(ThemePreview::new);
workspace.add_item_to_active_pane(Box::new(theme_preview), None, true, cx)
pub fn init(cx: &mut App) {
cx.observe_new(|workspace: &mut Workspace, _, _| {
workspace.register_action(|workspace, _: &OpenThemePreview, window, cx| {
let theme_preview = cx.new(|cx| ThemePreview::new(window, cx));
workspace.add_item_to_active_pane(Box::new(theme_preview), None, true, window, cx)
});
})
.detach();
@ -46,7 +46,7 @@ struct ThemePreview {
}
impl ThemePreview {
pub fn new(cx: &mut ViewContext<Self>) -> Self {
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
Self {
current_page: ThemePreviewPage::Overview,
focus_handle: cx.focus_handle(),
@ -56,20 +56,25 @@ impl ThemePreview {
pub fn view(
&self,
page: ThemePreviewPage,
cx: &mut ViewContext<ThemePreview>,
window: &mut Window,
cx: &mut Context<ThemePreview>,
) -> impl IntoElement {
match page {
ThemePreviewPage::Overview => self.render_overview_page(cx).into_any_element(),
ThemePreviewPage::Typography => self.render_typography_page(cx).into_any_element(),
ThemePreviewPage::Components => self.render_components_page(cx).into_any_element(),
ThemePreviewPage::Overview => self.render_overview_page(window, cx).into_any_element(),
ThemePreviewPage::Typography => {
self.render_typography_page(window, cx).into_any_element()
}
ThemePreviewPage::Components => {
self.render_components_page(window, cx).into_any_element()
}
}
}
}
impl EventEmitter<()> for ThemePreview {}
impl FocusableView for ThemePreview {
fn focus_handle(&self, _: &AppContext) -> gpui::FocusHandle {
impl Focusable for ThemePreview {
fn focus_handle(&self, _: &App) -> gpui::FocusHandle {
self.focus_handle.clone()
}
}
@ -80,7 +85,7 @@ impl Item for ThemePreview {
fn to_item_events(_: &Self::Event, _: impl FnMut(crate::item::ItemEvent)) {}
fn tab_content_text(&self, cx: &WindowContext) -> Option<SharedString> {
fn tab_content_text(&self, window: &Window, cx: &App) -> Option<SharedString> {
let name = cx.theme().name.clone();
Some(format!("{} Preview", name).into())
}
@ -92,23 +97,29 @@ impl Item for ThemePreview {
fn clone_on_split(
&self,
_workspace_id: Option<crate::WorkspaceId>,
cx: &mut ViewContext<Self>,
) -> Option<gpui::View<Self>>
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<Entity<Self>>
where
Self: Sized,
{
Some(cx.new_view(Self::new))
Some(cx.new(|cx| Self::new(window, cx)))
}
}
const AVATAR_URL: &str = "https://avatars.githubusercontent.com/u/1714999?v=4";
impl ThemePreview {
fn preview_bg(cx: &WindowContext) -> Hsla {
fn preview_bg(window: &mut Window, cx: &mut App) -> Hsla {
cx.theme().colors().editor_background
}
fn render_text(&self, layer: ElevationIndex, cx: &ViewContext<Self>) -> impl IntoElement {
fn render_text(
&self,
layer: ElevationIndex,
window: &mut Window,
cx: &mut Context<Self>,
) -> impl IntoElement {
let bg = layer.bg(cx);
let label_with_contrast = |label: &str, fg: Hsla| {
@ -269,7 +280,12 @@ impl ThemePreview {
)
}
fn render_colors(&self, layer: ElevationIndex, cx: &ViewContext<Self>) -> impl IntoElement {
fn render_colors(
&self,
layer: ElevationIndex,
window: &mut Window,
cx: &mut Context<Self>,
) -> impl IntoElement {
let bg = layer.bg(cx);
let all_colors = all_theme_colors(cx);
@ -299,9 +315,15 @@ impl ThemePreview {
)
.size(ButtonSize::None)
.style(ButtonStyle::Transparent)
.tooltip(move |cx| {
.tooltip(move |window, cx| {
let name = name.clone();
Tooltip::with_meta(name, None, format!("{:?}", color), cx)
Tooltip::with_meta(
name,
None,
format!("{:?}", color),
window,
cx,
)
}),
)
})),
@ -311,7 +333,8 @@ impl ThemePreview {
fn render_theme_layer(
&self,
layer: ElevationIndex,
cx: &ViewContext<Self>,
window: &mut Window,
cx: &mut Context<Self>,
) -> impl IntoElement {
v_flex()
.p_4()
@ -319,11 +342,15 @@ impl ThemePreview {
.text_color(cx.theme().colors().text)
.gap_2()
.child(Headline::new(layer.clone().to_string()).size(HeadlineSize::Medium))
.child(self.render_text(layer, cx))
.child(self.render_colors(layer, cx))
.child(self.render_text(layer, window, cx))
.child(self.render_colors(layer, window, cx))
}
fn render_overview_page(&self, cx: &ViewContext<Self>) -> impl IntoElement {
fn render_overview_page(
&self,
window: &mut Window,
cx: &mut Context<Self>,
) -> impl IntoElement {
v_flex()
.id("theme-preview-overview")
.overflow_scroll()
@ -333,13 +360,17 @@ impl ThemePreview {
.child(Headline::new("Theme Preview").size(HeadlineSize::Large))
.child(div().w_full().text_color(cx.theme().colors().text_muted).child("This view lets you preview a range of UI elements across a theme. Use it for testing out changes to the theme."))
)
.child(self.render_theme_layer(ElevationIndex::Background, cx))
.child(self.render_theme_layer(ElevationIndex::Surface, cx))
.child(self.render_theme_layer(ElevationIndex::EditorSurface, cx))
.child(self.render_theme_layer(ElevationIndex::ElevatedSurface, cx))
.child(self.render_theme_layer(ElevationIndex::Background, window, cx))
.child(self.render_theme_layer(ElevationIndex::Surface, window, cx))
.child(self.render_theme_layer(ElevationIndex::EditorSurface, window, cx))
.child(self.render_theme_layer(ElevationIndex::ElevatedSurface, window, cx))
}
fn render_typography_page(&self, cx: &ViewContext<Self>) -> impl IntoElement {
fn render_typography_page(
&self,
window: &mut Window,
cx: &mut Context<Self>,
) -> impl IntoElement {
v_flex()
.id("theme-preview-typography")
.overflow_scroll()
@ -361,7 +392,7 @@ impl ThemePreview {
)
}
fn render_components_page(&self, cx: &mut WindowContext) -> impl IntoElement {
fn render_components_page(&self, window: &mut Window, cx: &mut App) -> impl IntoElement {
let layer = ElevationIndex::Surface;
v_flex()
@ -369,29 +400,29 @@ impl ThemePreview {
.overflow_scroll()
.size_full()
.gap_2()
.child(Button::render_component_previews(cx))
.child(Checkbox::render_component_previews(cx))
.child(CheckboxWithLabel::render_component_previews(cx))
.child(ContentGroup::render_component_previews(cx))
.child(DecoratedIcon::render_component_previews(cx))
.child(Facepile::render_component_previews(cx))
.child(Icon::render_component_previews(cx))
.child(IconDecoration::render_component_previews(cx))
.child(Indicator::render_component_previews(cx))
.child(Switch::render_component_previews(cx))
.child(Table::render_component_previews(cx))
.child(Button::render_component_previews(window, cx))
.child(Checkbox::render_component_previews(window, cx))
.child(CheckboxWithLabel::render_component_previews(window, cx))
.child(ContentGroup::render_component_previews(window, cx))
.child(DecoratedIcon::render_component_previews(window, cx))
.child(Facepile::render_component_previews(window, cx))
.child(Icon::render_component_previews(window, cx))
.child(IconDecoration::render_component_previews(window, cx))
.child(Indicator::render_component_previews(window, cx))
.child(Switch::render_component_previews(window, cx))
.child(Table::render_component_previews(window, cx))
}
fn render_page_nav(&self, cx: &ViewContext<Self>) -> impl IntoElement {
fn render_page_nav(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
h_flex()
.id("theme-preview-nav")
.items_center()
.gap_4()
.py_2()
.bg(Self::preview_bg(cx))
.bg(Self::preview_bg(window, cx))
.children(ThemePreviewPage::iter().map(|p| {
Button::new(ElementId::Name(p.name().into()), p.name())
.on_click(cx.listener(move |this, _, cx| {
.on_click(cx.listener(move |this, _, window, cx| {
this.current_page = p;
cx.notify();
}))
@ -402,7 +433,7 @@ impl ThemePreview {
}
impl Render for ThemePreview {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl ui::IntoElement {
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl ui::IntoElement {
v_flex()
.id("theme-preview")
.key_context("ThemePreview")
@ -412,8 +443,8 @@ impl Render for ThemePreview {
.max_h_full()
.track_focus(&self.focus_handle)
.px_2()
.bg(Self::preview_bg(cx))
.child(self.render_page_nav(cx))
.child(self.view(self.current_page, cx))
.bg(Self::preview_bg(window, cx))
.child(self.render_page_nav(window, cx))
.child(self.view(self.current_page, window, cx))
}
}

View file

@ -1,7 +1,7 @@
use crate::ItemHandle;
use gpui::{
AnyView, Entity, EntityId, EventEmitter, ParentElement as _, Render, Styled, View, ViewContext,
WindowContext,
AnyView, App, Context, Entity, EntityId, EventEmitter, ParentElement as _, Render, Styled,
Window,
};
use ui::prelude::*;
use ui::{h_flex, v_flex};
@ -14,10 +14,17 @@ pub trait ToolbarItemView: Render + EventEmitter<ToolbarItemEvent> {
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>,
) -> ToolbarItemLocation;
fn pane_focus_update(&mut self, _pane_focused: bool, _cx: &mut ViewContext<Self>) {}
fn pane_focus_update(
&mut self,
_pane_focused: bool,
_window: &mut Window,
_cx: &mut Context<Self>,
) {
}
}
trait ToolbarItemViewHandle: Send {
@ -26,9 +33,10 @@ trait ToolbarItemViewHandle: Send {
fn set_active_pane_item(
&self,
active_pane_item: Option<&dyn ItemHandle>,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) -> ToolbarItemLocation;
fn focus_changed(&mut self, pane_focused: bool, cx: &mut WindowContext);
fn focus_changed(&mut self, pane_focused: bool, window: &mut Window, cx: &mut App);
}
#[derive(Copy, Clone, Debug, PartialEq)]
@ -85,7 +93,7 @@ impl Toolbar {
}
impl Render for Toolbar {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
if !self.has_any_visible_items() {
return div();
}
@ -157,16 +165,16 @@ impl Toolbar {
}
}
pub fn set_can_navigate(&mut self, can_navigate: bool, cx: &mut ViewContext<Self>) {
pub fn set_can_navigate(&mut self, can_navigate: bool, cx: &mut Context<Self>) {
self.can_navigate = can_navigate;
cx.notify();
}
pub fn add_item<T>(&mut self, item: View<T>, cx: &mut ViewContext<Self>)
pub fn add_item<T>(&mut self, item: Entity<T>, window: &mut Window, cx: &mut Context<Self>)
where
T: 'static + ToolbarItemView,
{
let location = item.set_active_pane_item(self.active_item.as_deref(), cx);
let location = item.set_active_pane_item(self.active_item.as_deref(), window, cx);
cx.subscribe(&item, |this, item, event, cx| {
if let Some((_, current_location)) = this
.items
@ -188,7 +196,12 @@ impl Toolbar {
cx.notify();
}
pub fn set_active_item(&mut self, item: Option<&dyn ItemHandle>, cx: &mut ViewContext<Self>) {
pub fn set_active_item(
&mut self,
item: Option<&dyn ItemHandle>,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.active_item = item.map(|item| item.boxed_clone());
self.hidden = self
.active_item
@ -197,7 +210,7 @@ impl Toolbar {
.unwrap_or(false);
for (toolbar_item, current_location) in self.items.iter_mut() {
let new_location = toolbar_item.set_active_pane_item(item, cx);
let new_location = toolbar_item.set_active_pane_item(item, window, cx);
if new_location != *current_location {
*current_location = new_location;
cx.notify();
@ -205,13 +218,13 @@ impl Toolbar {
}
}
pub fn focus_changed(&mut self, focused: bool, cx: &mut ViewContext<Self>) {
pub fn focus_changed(&mut self, focused: bool, window: &mut Window, cx: &mut Context<Self>) {
for (toolbar_item, _) in self.items.iter_mut() {
toolbar_item.focus_changed(focused, cx);
toolbar_item.focus_changed(focused, window, cx);
}
}
pub fn item_of_type<T: ToolbarItemView>(&self) -> Option<View<T>> {
pub fn item_of_type<T: ToolbarItemView>(&self) -> Option<Entity<T>> {
self.items
.iter()
.find_map(|(item, _)| item.to_any().downcast().ok())
@ -222,7 +235,7 @@ impl Toolbar {
}
}
impl<T: ToolbarItemView> ToolbarItemViewHandle for View<T> {
impl<T: ToolbarItemView> ToolbarItemViewHandle for Entity<T> {
fn id(&self) -> EntityId {
self.entity_id()
}
@ -234,16 +247,17 @@ impl<T: ToolbarItemView> ToolbarItemViewHandle for View<T> {
fn set_active_pane_item(
&self,
active_pane_item: Option<&dyn ItemHandle>,
cx: &mut WindowContext,
window: &mut Window,
cx: &mut App,
) -> ToolbarItemLocation {
self.update(cx, |this, cx| {
this.set_active_pane_item(active_pane_item, cx)
this.set_active_pane_item(active_pane_item, window, cx)
})
}
fn focus_changed(&mut self, pane_focused: bool, cx: &mut WindowContext) {
fn focus_changed(&mut self, pane_focused: bool, window: &mut Window, cx: &mut App) {
self.update(cx, |this, cx| {
this.pane_focus_update(pane_focused, cx);
this.pane_focus_update(pane_focused, window, cx);
cx.notify();
});
}

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@ use std::num::NonZeroUsize;
use anyhow::Result;
use collections::HashMap;
use gpui::AppContext;
use gpui::App;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
@ -208,7 +208,7 @@ impl Settings for WorkspaceSettings {
type FileContent = WorkspaceSettingsContent;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
sources.json_merge()
}
}
@ -218,7 +218,7 @@ impl Settings for TabBarSettings {
type FileContent = TabBarSettingsContent;
fn load(sources: SettingsSources<Self::FileContent>, _: &mut AppContext) -> Result<Self> {
fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
sources.json_merge()
}
}