Merge remote-tracking branch 'origin/main' into perf-2

This commit is contained in:
Nathan Sobo 2023-12-14 16:56:36 -07:00
commit 02606d1fb9
34 changed files with 822 additions and 1270 deletions

19
Cargo.lock generated
View file

@ -182,7 +182,7 @@ dependencies = [
"alacritty_config", "alacritty_config",
"alacritty_config_derive", "alacritty_config_derive",
"base64 0.13.1", "base64 0.13.1",
"bitflags 2.4.0", "bitflags 2.4.1",
"home", "home",
"libc", "libc",
"log", "log",
@ -1025,9 +1025,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.4.0" version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -3280,6 +3280,7 @@ name = "feedback2"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bitflags 2.4.1",
"client2", "client2",
"db2", "db2",
"editor2", "editor2",
@ -4026,7 +4027,7 @@ dependencies = [
"async-task", "async-task",
"backtrace", "backtrace",
"bindgen 0.65.1", "bindgen 0.65.1",
"bitflags 2.4.0", "bitflags 2.4.1",
"block", "block",
"cbindgen", "cbindgen",
"cocoa", "cocoa",
@ -6195,7 +6196,7 @@ version = "0.10.57"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c"
dependencies = [ dependencies = [
"bitflags 2.4.0", "bitflags 2.4.1",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"foreign-types", "foreign-types",
"libc", "libc",
@ -7915,7 +7916,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2"
dependencies = [ dependencies = [
"bitflags 2.4.0", "bitflags 2.4.1",
"fallible-iterator", "fallible-iterator",
"fallible-streaming-iterator", "fallible-streaming-iterator",
"hashlink", "hashlink",
@ -8031,7 +8032,7 @@ version = "0.38.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f" checksum = "747c788e9ce8e92b12cd485c49ddf90723550b654b32508f979b71a7b1ecda4f"
dependencies = [ dependencies = [
"bitflags 2.4.0", "bitflags 2.4.1",
"errno 0.3.3", "errno 0.3.3",
"libc", "libc",
"linux-raw-sys 0.4.7", "linux-raw-sys 0.4.7",
@ -9134,7 +9135,7 @@ dependencies = [
"atoi", "atoi",
"base64 0.21.4", "base64 0.21.4",
"bigdecimal", "bigdecimal",
"bitflags 2.4.0", "bitflags 2.4.1",
"byteorder", "byteorder",
"bytes 1.5.0", "bytes 1.5.0",
"chrono", "chrono",
@ -9181,7 +9182,7 @@ dependencies = [
"atoi", "atoi",
"base64 0.21.4", "base64 0.21.4",
"bigdecimal", "bigdecimal",
"bitflags 2.4.0", "bitflags 2.4.1",
"byteorder", "byteorder",
"chrono", "chrono",
"crc", "crc",

View file

@ -2552,12 +2552,11 @@ impl CollabPanel {
.group("") .group("")
.flex() .flex()
.w_full() .w_full()
.on_drag({ .on_drag(channel.clone(), move |channel, cx| {
let channel = channel.clone(); cx.build_view(|cx| DraggedChannelView {
move |cx| { channel: channel.clone(),
let channel = channel.clone(); width,
cx.build_view(|cx| DraggedChannelView { channel, width }) })
}
}) })
.drag_over::<DraggedChannelView>(|style| { .drag_over::<DraggedChannelView>(|style| {
style.bg(cx.theme().colors().ghost_element_hover) style.bg(cx.theme().colors().ghost_element_hover)

View file

@ -9297,7 +9297,7 @@ impl Render for Editor {
let settings = ThemeSettings::get_global(cx); let settings = ThemeSettings::get_global(cx);
let text_style = match self.mode { let text_style = match self.mode {
EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle { EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
color: cx.theme().colors().text, color: cx.theme().colors().editor_foreground,
font_family: settings.ui_font.family.clone(), font_family: settings.ui_font.family.clone(),
font_features: settings.ui_font.features, font_features: settings.ui_font.features,
font_size: rems(0.875).into(), font_size: rems(0.875).into(),
@ -9310,7 +9310,7 @@ impl Render for Editor {
}, },
EditorMode::Full => TextStyle { EditorMode::Full => TextStyle {
color: cx.theme().colors().text, color: cx.theme().colors().editor_foreground,
font_family: settings.buffer_font.family.clone(), font_family: settings.buffer_font.family.clone(),
font_features: settings.buffer_font.features, font_features: settings.buffer_font.features,
font_size: settings.buffer_font_size(cx).into(), font_size: settings.buffer_font_size(cx).into(),

View file

@ -18,7 +18,6 @@ gpui = { package = "gpui2", path = "../gpui2" }
language = { package = "language2", path = "../language2" } language = { package = "language2", path = "../language2" }
menu = { package = "menu2", path = "../menu2" } menu = { package = "menu2", path = "../menu2" }
project = { package = "project2", path = "../project2" } project = { package = "project2", path = "../project2" }
regex.workspace = true
search = { package = "search2", path = "../search2" } search = { package = "search2", path = "../search2" }
settings = { package = "settings2", path = "../settings2" } settings = { package = "settings2", path = "../settings2" }
theme = { package = "theme2", path = "../theme2" } theme = { package = "theme2", path = "../theme2" }
@ -26,13 +25,16 @@ ui = { package = "ui2", path = "../ui2" }
util = { path = "../util" } util = { path = "../util" }
workspace = { package = "workspace2", path = "../workspace2"} workspace = { package = "workspace2", path = "../workspace2"}
bitflags = "2.4.1"
human_bytes = "0.4.1"
anyhow.workspace = true anyhow.workspace = true
futures.workspace = true futures.workspace = true
human_bytes = "0.4.1"
isahc.workspace = true isahc.workspace = true
lazy_static.workspace = true lazy_static.workspace = true
log.workspace = true log.workspace = true
postage.workspace = true postage.workspace = true
regex.workspace = true
serde.workspace = true serde.workspace = true
serde_derive.workspace = true serde_derive.workspace = true
smallvec.workspace = true smallvec.workspace = true

View file

@ -1,6 +1,7 @@
use std::{ops::RangeInclusive, sync::Arc, time::Duration}; use std::{ops::RangeInclusive, sync::Arc, time::Duration};
use anyhow::{anyhow, bail}; use anyhow::{anyhow, bail};
use bitflags::bitflags;
use client::{Client, ZED_SECRET_CLIENT_TOKEN, ZED_SERVER_URL}; use client::{Client, ZED_SECRET_CLIENT_TOKEN, ZED_SERVER_URL};
use db::kvp::KEY_VALUE_STORE; use db::kvp::KEY_VALUE_STORE;
use editor::{Editor, EditorEvent}; use editor::{Editor, EditorEvent};
@ -48,15 +49,17 @@ struct FeedbackRequestBody<'a> {
token: &'a str, token: &'a str,
} }
bitflags! {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
enum InvalidStateIssue { struct InvalidStateFlags: u8 {
EmailAddress, const EmailAddress = 0b00000001;
CharacterCount, const CharacterCount = 0b00000010;
}
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
enum CannotSubmitReason { enum CannotSubmitReason {
InvalidState { issues: Vec<InvalidStateIssue> }, InvalidState { flags: InvalidStateFlags },
AwaitingSubmission, AwaitingSubmission,
} }
@ -322,7 +325,7 @@ impl FeedbackModal {
return; return;
} }
let mut invalid_state_issues = Vec::new(); let mut invalid_state_flags = InvalidStateFlags::empty();
let valid_email_address = match self.email_address_editor.read(cx).text_option(cx) { let valid_email_address = match self.email_address_editor.read(cx).text_option(cx) {
Some(email_address) => Regex::new(EMAIL_REGEX).unwrap().is_match(&email_address), Some(email_address) => Regex::new(EMAIL_REGEX).unwrap().is_match(&email_address),
@ -330,37 +333,37 @@ impl FeedbackModal {
}; };
if !valid_email_address { if !valid_email_address {
invalid_state_issues.push(InvalidStateIssue::EmailAddress); invalid_state_flags |= InvalidStateFlags::EmailAddress;
} }
if !FEEDBACK_CHAR_LIMIT.contains(&self.character_count) { if !FEEDBACK_CHAR_LIMIT.contains(&self.character_count) {
invalid_state_issues.push(InvalidStateIssue::CharacterCount); invalid_state_flags |= InvalidStateFlags::CharacterCount;
} }
if invalid_state_issues.is_empty() { if invalid_state_flags.is_empty() {
self.submission_state = Some(SubmissionState::CanSubmit); self.submission_state = Some(SubmissionState::CanSubmit);
} else { } else {
self.submission_state = Some(SubmissionState::CannotSubmit { self.submission_state = Some(SubmissionState::CannotSubmit {
reason: CannotSubmitReason::InvalidState { reason: CannotSubmitReason::InvalidState {
issues: invalid_state_issues, flags: invalid_state_flags,
}, },
}); });
} }
} }
fn valid_email_address(&self) -> bool { fn valid_email_address(&self) -> bool {
!self.in_invalid_state(InvalidStateIssue::EmailAddress) !self.in_invalid_state(InvalidStateFlags::EmailAddress)
} }
fn valid_character_count(&self) -> bool { fn valid_character_count(&self) -> bool {
!self.in_invalid_state(InvalidStateIssue::CharacterCount) !self.in_invalid_state(InvalidStateFlags::CharacterCount)
} }
fn in_invalid_state(&self, a: InvalidStateIssue) -> bool { fn in_invalid_state(&self, flag: InvalidStateFlags) -> bool {
match self.submission_state { match self.submission_state {
Some(SubmissionState::CannotSubmit { Some(SubmissionState::CannotSubmit {
reason: CannotSubmitReason::InvalidState { ref issues }, reason: CannotSubmitReason::InvalidState { ref flags },
}) => issues.contains(&a), }) => flags.contains(flag),
_ => false, _ => false,
} }
} }

View file

@ -1139,8 +1139,10 @@ impl AppContext {
self.active_drag.is_some() self.active_drag.is_some()
} }
pub fn active_drag(&self) -> Option<AnyView> { pub fn active_drag<T: 'static>(&self) -> Option<&T> {
self.active_drag.as_ref().map(|drag| drag.view.clone()) self.active_drag
.as_ref()
.and_then(|drag| drag.value.downcast_ref())
} }
} }
@ -1296,6 +1298,7 @@ impl<G: 'static> DerefMut for GlobalLease<G> {
/// within the window or by dragging into the app from the underlying platform. /// within the window or by dragging into the app from the underlying platform.
pub struct AnyDrag { pub struct AnyDrag {
pub view: AnyView, pub view: AnyView,
pub value: Box<dyn Any>,
pub cursor_offset: Point<Pixels>, pub cursor_offset: Point<Pixels>,
} }

View file

@ -15,6 +15,7 @@ use std::{
cell::RefCell, cell::RefCell,
cmp::Ordering, cmp::Ordering,
fmt::Debug, fmt::Debug,
marker::PhantomData,
mem, mem,
rc::Rc, rc::Rc,
time::Duration, time::Duration,
@ -30,9 +31,18 @@ pub struct GroupStyle {
pub style: Box<StyleRefinement>, pub style: Box<StyleRefinement>,
} }
pub struct DragMoveEvent<W: Render> { pub struct DragMoveEvent<T> {
pub event: MouseMoveEvent, pub event: MouseMoveEvent,
pub drag: View<W>, drag: PhantomData<T>,
}
impl<T: 'static> DragMoveEvent<T> {
pub fn drag<'b>(&self, cx: &'b AppContext) -> &'b T {
cx.active_drag
.as_ref()
.and_then(|drag| drag.value.downcast_ref::<T>())
.expect("DragMoveEvent is only valid when the stored active drag is of the same type.")
}
} }
impl Interactivity { impl Interactivity {
@ -133,23 +143,26 @@ impl Interactivity {
})); }));
} }
pub fn on_drag_move<W>( pub fn on_drag_move<T>(
&mut self, &mut self,
listener: impl Fn(&DragMoveEvent<W>, &mut WindowContext) + 'static, listener: impl Fn(&DragMoveEvent<T>, &mut WindowContext) + 'static,
) where ) where
W: Render, T: 'static,
{ {
self.mouse_move_listeners self.mouse_move_listeners
.push(Box::new(move |event, bounds, phase, cx| { .push(Box::new(move |event, bounds, phase, cx| {
if phase == DispatchPhase::Capture if phase == DispatchPhase::Capture
&& bounds.drag_target_contains(&event.position, cx) && bounds.drag_target_contains(&event.position, cx)
{ {
if let Some(view) = cx.active_drag().and_then(|view| view.downcast::<W>().ok()) if cx
.active_drag
.as_ref()
.is_some_and(|drag| drag.value.type_id() == TypeId::of::<T>())
{ {
(listener)( (listener)(
&DragMoveEvent { &DragMoveEvent {
event: event.clone(), event: event.clone(),
drag: view, drag: PhantomData,
}, },
cx, cx,
); );
@ -252,14 +265,11 @@ impl Interactivity {
})); }));
} }
pub fn on_drop<W: 'static>( pub fn on_drop<T: 'static>(&mut self, listener: impl Fn(&T, &mut WindowContext) + 'static) {
&mut self,
listener: impl Fn(&View<W>, &mut WindowContext) + 'static,
) {
self.drop_listeners.push(( self.drop_listeners.push((
TypeId::of::<W>(), TypeId::of::<T>(),
Box::new(move |dragged_view, cx| { Box::new(move |dragged_value, cx| {
listener(&dragged_view.downcast().unwrap(), cx); listener(dragged_value.downcast_ref().unwrap(), cx);
}), }),
)); ));
} }
@ -272,19 +282,23 @@ impl Interactivity {
.push(Box::new(move |event, cx| listener(event, cx))); .push(Box::new(move |event, cx| listener(event, cx)));
} }
pub fn on_drag<W>(&mut self, constructor: impl Fn(&mut WindowContext) -> View<W> + 'static) pub fn on_drag<T, W>(
where &mut self,
value: T,
constructor: impl Fn(&T, &mut WindowContext) -> View<W> + 'static,
) where
Self: Sized, Self: Sized,
T: 'static,
W: 'static + Render, W: 'static + Render,
{ {
debug_assert!( debug_assert!(
self.drag_listener.is_none(), self.drag_listener.is_none(),
"calling on_drag more than once on the same element is not supported" "calling on_drag more than once on the same element is not supported"
); );
self.drag_listener = Some(Box::new(move |cursor_offset, cx| AnyDrag { self.drag_listener = Some((
view: constructor(cx).into(), Box::new(value),
cursor_offset, Box::new(move |value, cx| constructor(value.downcast_ref().unwrap(), cx).into()),
})); ));
} }
pub fn on_hover(&mut self, listener: impl Fn(&bool, &mut WindowContext) + 'static) pub fn on_hover(&mut self, listener: impl Fn(&bool, &mut WindowContext) + 'static)
@ -413,12 +427,12 @@ pub trait InteractiveElement: Sized {
self self
} }
fn on_drag_move<W>( fn on_drag_move<T>(
mut self, mut self,
listener: impl Fn(&DragMoveEvent<W>, &mut WindowContext) + 'static, listener: impl Fn(&DragMoveEvent<T>, &mut WindowContext) + 'static,
) -> Self ) -> Self
where where
W: Render, T: Render,
{ {
self.interactivity().on_drag_move(listener); self.interactivity().on_drag_move(listener);
self self
@ -485,14 +499,6 @@ pub trait InteractiveElement: Sized {
self self
} }
fn on_drop<W: 'static>(
mut self,
listener: impl Fn(&View<W>, &mut WindowContext) + 'static,
) -> Self {
self.interactivity().on_drop(listener);
self
}
fn drag_over<S: 'static>(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self { fn drag_over<S: 'static>(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self {
self.interactivity() self.interactivity()
.drag_over_styles .drag_over_styles
@ -514,6 +520,11 @@ pub trait InteractiveElement: Sized {
)); ));
self self
} }
fn on_drop<T: 'static>(mut self, listener: impl Fn(&T, &mut WindowContext) + 'static) -> Self {
self.interactivity().on_drop(listener);
self
}
} }
pub trait StatefulInteractiveElement: InteractiveElement { pub trait StatefulInteractiveElement: InteractiveElement {
@ -574,12 +585,17 @@ pub trait StatefulInteractiveElement: InteractiveElement {
self self
} }
fn on_drag<W>(mut self, constructor: impl Fn(&mut WindowContext) -> View<W> + 'static) -> Self fn on_drag<T, W>(
mut self,
value: T,
constructor: impl Fn(&T, &mut WindowContext) -> View<W> + 'static,
) -> Self
where where
Self: Sized, Self: Sized,
T: 'static,
W: 'static + Render, W: 'static + Render,
{ {
self.interactivity().on_drag(constructor); self.interactivity().on_drag(value, constructor);
self self
} }
@ -635,9 +651,9 @@ pub type ScrollWheelListener =
pub type ClickListener = Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>; pub type ClickListener = Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>;
pub type DragListener = Box<dyn Fn(Point<Pixels>, &mut WindowContext) -> AnyDrag + 'static>; pub type DragListener = Box<dyn Fn(&dyn Any, &mut WindowContext) -> AnyView + 'static>;
type DropListener = dyn Fn(AnyView, &mut WindowContext) + 'static; type DropListener = Box<dyn Fn(&dyn Any, &mut WindowContext) + 'static>;
pub type TooltipBuilder = Rc<dyn Fn(&mut WindowContext) -> AnyView + 'static>; pub type TooltipBuilder = Rc<dyn Fn(&mut WindowContext) -> AnyView + 'static>;
@ -834,9 +850,9 @@ pub struct Interactivity {
pub key_down_listeners: Vec<KeyDownListener>, pub key_down_listeners: Vec<KeyDownListener>,
pub key_up_listeners: Vec<KeyUpListener>, pub key_up_listeners: Vec<KeyUpListener>,
pub action_listeners: Vec<(TypeId, ActionListener)>, pub action_listeners: Vec<(TypeId, ActionListener)>,
pub drop_listeners: Vec<(TypeId, Box<DropListener>)>, pub drop_listeners: Vec<(TypeId, DropListener)>,
pub click_listeners: Vec<ClickListener>, pub click_listeners: Vec<ClickListener>,
pub drag_listener: Option<DragListener>, pub drag_listener: Option<(Box<dyn Any>, DragListener)>,
pub hover_listener: Option<Box<dyn Fn(&bool, &mut WindowContext)>>, pub hover_listener: Option<Box<dyn Fn(&bool, &mut WindowContext)>>,
pub tooltip_builder: Option<TooltipBuilder>, pub tooltip_builder: Option<TooltipBuilder>,
@ -1124,8 +1140,10 @@ impl Interactivity {
if phase == DispatchPhase::Bubble if phase == DispatchPhase::Bubble
&& interactive_bounds.drag_target_contains(&event.position, cx) && interactive_bounds.drag_target_contains(&event.position, cx)
{ {
if let Some(drag_state_type) = if let Some(drag_state_type) = cx
cx.active_drag.as_ref().map(|drag| drag.view.entity_type()) .active_drag
.as_ref()
.map(|drag| drag.value.as_ref().type_id())
{ {
for (drop_state_type, listener) in &drop_listeners { for (drop_state_type, listener) in &drop_listeners {
if *drop_state_type == drag_state_type { if *drop_state_type == drag_state_type {
@ -1134,7 +1152,7 @@ impl Interactivity {
.take() .take()
.expect("checked for type drag state type above"); .expect("checked for type drag state type above");
listener(drag.view.clone(), cx); listener(drag.value.as_ref(), cx);
cx.notify(); cx.notify();
cx.stop_propagation(); cx.stop_propagation();
} }
@ -1148,7 +1166,7 @@ impl Interactivity {
} }
let click_listeners = mem::take(&mut self.click_listeners); let click_listeners = mem::take(&mut self.click_listeners);
let drag_listener = mem::take(&mut self.drag_listener); let mut drag_listener = mem::take(&mut self.drag_listener);
if !click_listeners.is_empty() || drag_listener.is_some() { if !click_listeners.is_empty() || drag_listener.is_some() {
let pending_mouse_down = element_state let pending_mouse_down = element_state
@ -1157,7 +1175,7 @@ impl Interactivity {
.clone(); .clone();
let mouse_down = pending_mouse_down.borrow().clone(); let mouse_down = pending_mouse_down.borrow().clone();
if let Some(mouse_down) = mouse_down { if let Some(mouse_down) = mouse_down {
if let Some(drag_listener) = drag_listener { if drag_listener.is_some() {
let active_state = element_state let active_state = element_state
.clicked_state .clicked_state
.get_or_insert_with(Default::default) .get_or_insert_with(Default::default)
@ -1173,10 +1191,18 @@ impl Interactivity {
&& interactive_bounds.visibly_contains(&event.position, cx) && interactive_bounds.visibly_contains(&event.position, cx)
&& (event.position - mouse_down.position).magnitude() > DRAG_THRESHOLD && (event.position - mouse_down.position).magnitude() > DRAG_THRESHOLD
{ {
let (drag_value, drag_listener) = drag_listener
.take()
.expect("The notify below should invalidate this callback");
*active_state.borrow_mut() = ElementClickedState::default(); *active_state.borrow_mut() = ElementClickedState::default();
let cursor_offset = event.position - bounds.origin; let cursor_offset = event.position - bounds.origin;
let drag = drag_listener(cursor_offset, cx); let drag = (drag_listener)(drag_value.as_ref(), cx);
cx.active_drag = Some(drag); cx.active_drag = Some(AnyDrag {
view: drag,
value: drag_value,
cursor_offset,
});
cx.notify(); cx.notify();
cx.stop_propagation(); cx.stop_propagation();
} }
@ -1470,7 +1496,7 @@ impl Interactivity {
if let Some(drag) = cx.active_drag.take() { if let Some(drag) = cx.active_drag.take() {
for (state_type, group_drag_style) in &self.group_drag_over_styles { for (state_type, group_drag_style) in &self.group_drag_over_styles {
if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) { if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) {
if *state_type == drag.view.entity_type() if *state_type == drag.value.as_ref().type_id()
&& group_bounds.contains(&mouse_position) && group_bounds.contains(&mouse_position)
{ {
style.refine(&group_drag_style.style); style.refine(&group_drag_style.style);
@ -1479,7 +1505,7 @@ impl Interactivity {
} }
for (state_type, drag_over_style) in &self.drag_over_styles { for (state_type, drag_over_style) in &self.drag_over_styles {
if *state_type == drag.view.entity_type() if *state_type == drag.value.as_ref().type_id()
&& bounds && bounds
.intersect(&cx.content_mask().bounds) .intersect(&cx.content_mask().bounds)
.contains(&mouse_position) .contains(&mouse_position)

View file

@ -7,6 +7,7 @@ use crate::{
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use std::{ use std::{
any::TypeId, any::TypeId,
fmt,
hash::{Hash, Hasher}, hash::{Hash, Hasher},
}; };
@ -308,6 +309,20 @@ impl<V: 'static + Render> From<WeakView<V>> for AnyWeakView {
} }
} }
impl PartialEq for AnyWeakView {
fn eq(&self, other: &Self) -> bool {
self.model == other.model
}
}
impl std::fmt::Debug for AnyWeakView {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AnyWeakView")
.field("entity_id", &self.model.entity_id)
.finish_non_exhaustive()
}
}
impl<T, E> Render for T impl<T, E> Render for T
where where
T: 'static + FnMut(&mut WindowContext) -> E, T: 'static + FnMut(&mut WindowContext) -> E,

View file

@ -822,7 +822,7 @@ impl<'a> WindowContext<'a> {
/// a specific need to register a global listener. /// a specific need to register a global listener.
pub fn on_mouse_event<Event: 'static>( pub fn on_mouse_event<Event: 'static>(
&mut self, &mut self,
handler: impl Fn(&Event, DispatchPhase, &mut WindowContext) + 'static, mut handler: impl FnMut(&Event, DispatchPhase, &mut WindowContext) + 'static,
) { ) {
let order = self.window.next_frame.z_index_stack.clone(); let order = self.window.next_frame.z_index_stack.clone();
self.window self.window
@ -1400,6 +1400,7 @@ impl<'a> WindowContext<'a> {
self.window.mouse_position = position; self.window.mouse_position = position;
if self.active_drag.is_none() { if self.active_drag.is_none() {
self.active_drag = Some(AnyDrag { self.active_drag = Some(AnyDrag {
value: Box::new(files.clone()),
view: self.build_view(|_| files).into(), view: self.build_view(|_| files).into(),
cursor_offset: position, cursor_offset: position,
}); });

View file

@ -1377,33 +1377,28 @@ impl ProjectPanel {
}) })
.unwrap_or(theme.status().info); .unwrap_or(theme.status().info);
let file_name = details.filename.clone();
let icon = details.icon.clone();
let depth = details.depth;
div() div()
.id(entry_id.to_proto() as usize) .id(entry_id.to_proto() as usize)
.on_drag({ .on_drag(entry_id, move |entry_id, cx| {
let details = details.clone();
move |cx| {
let details = details.clone();
cx.build_view(|_| DraggedProjectEntryView { cx.build_view(|_| DraggedProjectEntryView {
details, details: details.clone(),
width, width,
entry_id, entry_id: *entry_id,
}) })
}
}) })
.drag_over::<DraggedProjectEntryView>(|style| { .drag_over::<ProjectEntryId>(|style| style.bg(cx.theme().colors().ghost_element_hover))
style.bg(cx.theme().colors().ghost_element_hover) .on_drop(cx.listener(move |this, dragged_id: &ProjectEntryId, cx| {
}) this.move_entry(*dragged_id, entry_id, kind.is_file(), cx);
.on_drop(cx.listener( }))
move |this, dragged_view: &View<DraggedProjectEntryView>, cx| {
this.move_entry(dragged_view.read(cx).entry_id, entry_id, kind.is_file(), cx);
},
))
.child( .child(
ListItem::new(entry_id.to_proto() as usize) ListItem::new(entry_id.to_proto() as usize)
.indent_level(details.depth) .indent_level(depth)
.indent_step_size(px(settings.indent_size)) .indent_step_size(px(settings.indent_size))
.selected(is_selected) .selected(is_selected)
.child(if let Some(icon) = &details.icon { .child(if let Some(icon) = &icon {
div().child(IconElement::from_path(icon.to_string())) div().child(IconElement::from_path(icon.to_string()))
} else { } else {
div() div()
@ -1414,7 +1409,7 @@ impl ProjectPanel {
} else { } else {
div() div()
.text_color(filename_text_color) .text_color(filename_text_color)
.child(Label::new(details.filename.clone())) .child(Label::new(file_name))
} }
.ml_1(), .ml_1(),
) )

View file

@ -1590,12 +1590,16 @@ impl Render for ProjectSearchBar {
); );
let replace_column = if search.replace_enabled { let replace_column = if search.replace_enabled {
h_stack() h_stack()
.p_1()
.flex_1() .flex_1()
.border_2() .h_full()
.gap_2()
.px_2()
.py_1()
.border_1()
.border_color(cx.theme().colors().border)
.rounded_lg() .rounded_lg()
.child(IconElement::new(Icon::Replace).size(ui::IconSize::Small)) .child(IconElement::new(Icon::Replace).size(ui::IconSize::Small))
.child(search.replacement_editor.clone()) .child(self.render_text_input(&search.replacement_editor, cx))
} else { } else {
// Fill out the space if we don't have a replacement editor. // Fill out the space if we don't have a replacement editor.
h_stack().flex_1() h_stack().flex_1()
@ -1658,10 +1662,10 @@ impl Render for ProjectSearchBar {
]); ]);
v_stack() v_stack()
.key_context(key_context) .key_context(key_context)
.flex_grow()
.p_1() .p_1()
.m_2() .m_2()
.gap_2() .gap_2()
.justify_between()
.on_action(cx.listener(|this, _: &ToggleFilters, cx| { .on_action(cx.listener(|this, _: &ToggleFilters, cx| {
this.toggle_filters(cx); this.toggle_filters(cx);
})) }))
@ -1713,10 +1717,59 @@ impl Render for ProjectSearchBar {
})) }))
}) })
}) })
.child(
h_stack()
.justify_between()
.child(query_column) .child(query_column)
.child(mode_column) .child(mode_column)
.child(replace_column) .child(replace_column)
.child(actions_column) .child(actions_column),
)
.when(search.filters_enabled, |this| {
this.child(
h_stack()
.flex_1()
.gap_2()
.justify_between()
.child(
h_stack()
.flex_1()
.h_full()
.px_2()
.py_1()
.border_1()
.border_color(cx.theme().colors().border)
.rounded_lg()
.child(self.render_text_input(&search.included_files_editor, cx))
.when(search.current_mode != SearchMode::Semantic, |this| {
this.child(
SearchOptions::INCLUDE_IGNORED.as_button(
search
.search_options
.contains(SearchOptions::INCLUDE_IGNORED),
cx.listener(|this, _, cx| {
this.toggle_search_option(
SearchOptions::INCLUDE_IGNORED,
cx,
);
}),
),
)
}),
)
.child(
h_stack()
.flex_1()
.h_full()
.px_2()
.py_1()
.border_1()
.border_color(cx.theme().colors().border)
.rounded_lg()
.child(self.render_text_input(&search.excluded_files_editor, cx)),
),
)
})
} }
} }
// impl Entity for ProjectSearchBar { // impl Entity for ProjectSearchBar {

View file

@ -695,7 +695,6 @@ impl TerminalElement {
move |external_paths, cx| { move |external_paths, cx| {
cx.focus(&focus); cx.focus(&focus);
let mut new_text = external_paths let mut new_text = external_paths
.read(cx)
.paths() .paths()
.iter() .iter()
.map(|path| format!(" {path:?}")) .map(|path| format!(" {path:?}"))

View file

@ -47,6 +47,7 @@ pub fn andromeda() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x3a3f4c77).into()), scrollbar_thumb_border: Some(rgba(0x3a3f4c77).into()),
scrollbar_track_background: Some(rgba(0x23262eff).into()), scrollbar_track_background: Some(rgba(0x23262eff).into()),
scrollbar_track_border: Some(rgba(0x1b1d23ff).into()), scrollbar_track_border: Some(rgba(0x1b1d23ff).into()),
editor_foreground: Some(rgba(0xd5ced9ff).into()),
editor_background: Some(rgba(0x23262eff).into()), editor_background: Some(rgba(0x23262eff).into()),
editor_gutter_background: Some(rgba(0x23262eff).into()), editor_gutter_background: Some(rgba(0x23262eff).into()),
editor_line_number: Some(rgba(0x746f77ff).into()), editor_line_number: Some(rgba(0x746f77ff).into()),
@ -261,6 +262,7 @@ pub fn andromeda() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x3a3f4c77).into()), scrollbar_thumb_border: Some(rgba(0x3a3f4c77).into()),
scrollbar_track_background: Some(rgba(0x262a33ff).into()), scrollbar_track_background: Some(rgba(0x262a33ff).into()),
scrollbar_track_border: Some(rgba(0x1b1d23ff).into()), scrollbar_track_border: Some(rgba(0x1b1d23ff).into()),
editor_foreground: Some(rgba(0xd5ced9ff).into()),
editor_background: Some(rgba(0x262a33ff).into()), editor_background: Some(rgba(0x262a33ff).into()),
editor_gutter_background: Some(rgba(0x262a33ff).into()), editor_gutter_background: Some(rgba(0x262a33ff).into()),
editor_line_number: Some(rgba(0x746f77ff).into()), editor_line_number: Some(rgba(0x746f77ff).into()),

View file

@ -46,6 +46,7 @@ pub fn ayu() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x8a919966).into()), scrollbar_thumb_border: Some(rgba(0x8a919966).into()),
scrollbar_track_background: Some(rgba(0xf8f9faff).into()), scrollbar_track_background: Some(rgba(0xf8f9faff).into()),
scrollbar_track_border: Some(rgba(0x6b7d8f1f).into()), scrollbar_track_border: Some(rgba(0x6b7d8f1f).into()),
editor_foreground: Some(rgba(0x5c6166ff).into()),
editor_background: Some(rgba(0xf8f9faff).into()), editor_background: Some(rgba(0xf8f9faff).into()),
editor_gutter_background: Some(rgba(0xf8f9faff).into()), editor_gutter_background: Some(rgba(0xf8f9faff).into()),
editor_line_number: Some(rgba(0x8a919966).into()), editor_line_number: Some(rgba(0x8a919966).into()),
@ -352,6 +353,7 @@ pub fn ayu() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x707a8c66).into()), scrollbar_thumb_border: Some(rgba(0x707a8c66).into()),
scrollbar_track_background: Some(rgba(0x1f2430ff).into()), scrollbar_track_background: Some(rgba(0x1f2430ff).into()),
scrollbar_track_border: Some(rgba(0x171b24ff).into()), scrollbar_track_border: Some(rgba(0x171b24ff).into()),
editor_foreground: Some(rgba(0xcccac2ff).into()),
editor_background: Some(rgba(0x1f2430ff).into()), editor_background: Some(rgba(0x1f2430ff).into()),
editor_gutter_background: Some(rgba(0x1f2430ff).into()), editor_gutter_background: Some(rgba(0x1f2430ff).into()),
editor_line_number: Some(rgba(0x8a919966).into()), editor_line_number: Some(rgba(0x8a919966).into()),
@ -658,6 +660,7 @@ pub fn ayu() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x565b6666).into()), scrollbar_thumb_border: Some(rgba(0x565b6666).into()),
scrollbar_track_background: Some(rgba(0x0b0e14ff).into()), scrollbar_track_background: Some(rgba(0x0b0e14ff).into()),
scrollbar_track_border: Some(rgba(0x1e232bff).into()), scrollbar_track_border: Some(rgba(0x1e232bff).into()),
editor_foreground: Some(rgba(0xbfbdb6ff).into()),
editor_background: Some(rgba(0x0b0e14ff).into()), editor_background: Some(rgba(0x0b0e14ff).into()),
editor_gutter_background: Some(rgba(0x0b0e14ff).into()), editor_gutter_background: Some(rgba(0x0b0e14ff).into()),
editor_line_number: Some(rgba(0x6c738099).into()), editor_line_number: Some(rgba(0x6c738099).into()),

View file

@ -43,6 +43,7 @@ pub fn dracula() -> UserThemeFamily {
tab_active_background: Some(rgba(0x282a36ff).into()), tab_active_background: Some(rgba(0x282a36ff).into()),
scrollbar_track_background: Some(rgba(0x282a36ff).into()), scrollbar_track_background: Some(rgba(0x282a36ff).into()),
scrollbar_track_border: Some(rgba(0x191a21ff).into()), scrollbar_track_border: Some(rgba(0x191a21ff).into()),
editor_foreground: Some(rgba(0xf8f8f2ff).into()),
editor_background: Some(rgba(0x282a36ff).into()), editor_background: Some(rgba(0x282a36ff).into()),
editor_gutter_background: Some(rgba(0x282a36ff).into()), editor_gutter_background: Some(rgba(0x282a36ff).into()),
editor_line_number: Some(rgba(0x6272a4ff).into()), editor_line_number: Some(rgba(0x6272a4ff).into()),

View file

@ -46,6 +46,7 @@ pub fn gruvbox() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x50494599).into()), scrollbar_thumb_border: Some(rgba(0x50494599).into()),
scrollbar_track_background: Some(rgba(0x1d2021ff).into()), scrollbar_track_background: Some(rgba(0x1d2021ff).into()),
scrollbar_track_border: Some(rgba(0x1d202100).into()), scrollbar_track_border: Some(rgba(0x1d202100).into()),
editor_foreground: Some(rgba(0xebdbb2ff).into()),
editor_background: Some(rgba(0x1d2021ff).into()), editor_background: Some(rgba(0x1d2021ff).into()),
editor_gutter_background: Some(rgba(0x1d2021ff).into()), editor_gutter_background: Some(rgba(0x1d2021ff).into()),
editor_line_number: Some(rgba(0x665c54ff).into()), editor_line_number: Some(rgba(0x665c54ff).into()),
@ -338,6 +339,7 @@ pub fn gruvbox() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x50494599).into()), scrollbar_thumb_border: Some(rgba(0x50494599).into()),
scrollbar_track_background: Some(rgba(0x282828ff).into()), scrollbar_track_background: Some(rgba(0x282828ff).into()),
scrollbar_track_border: Some(rgba(0x28282800).into()), scrollbar_track_border: Some(rgba(0x28282800).into()),
editor_foreground: Some(rgba(0xebdbb2ff).into()),
editor_background: Some(rgba(0x282828ff).into()), editor_background: Some(rgba(0x282828ff).into()),
editor_gutter_background: Some(rgba(0x282828ff).into()), editor_gutter_background: Some(rgba(0x282828ff).into()),
editor_line_number: Some(rgba(0x665c54ff).into()), editor_line_number: Some(rgba(0x665c54ff).into()),
@ -630,6 +632,7 @@ pub fn gruvbox() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x50494599).into()), scrollbar_thumb_border: Some(rgba(0x50494599).into()),
scrollbar_track_background: Some(rgba(0x32302fff).into()), scrollbar_track_background: Some(rgba(0x32302fff).into()),
scrollbar_track_border: Some(rgba(0x32302f00).into()), scrollbar_track_border: Some(rgba(0x32302f00).into()),
editor_foreground: Some(rgba(0xebdbb2ff).into()),
editor_background: Some(rgba(0x32302fff).into()), editor_background: Some(rgba(0x32302fff).into()),
editor_gutter_background: Some(rgba(0x32302fff).into()), editor_gutter_background: Some(rgba(0x32302fff).into()),
editor_line_number: Some(rgba(0x665c54ff).into()), editor_line_number: Some(rgba(0x665c54ff).into()),
@ -922,6 +925,7 @@ pub fn gruvbox() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0xd5c4a199).into()), scrollbar_thumb_border: Some(rgba(0xd5c4a199).into()),
scrollbar_track_background: Some(rgba(0xf9f5d7ff).into()), scrollbar_track_background: Some(rgba(0xf9f5d7ff).into()),
scrollbar_track_border: Some(rgba(0xf9f5d700).into()), scrollbar_track_border: Some(rgba(0xf9f5d700).into()),
editor_foreground: Some(rgba(0x3c3836ff).into()),
editor_background: Some(rgba(0xf9f5d7ff).into()), editor_background: Some(rgba(0xf9f5d7ff).into()),
editor_gutter_background: Some(rgba(0xf9f5d7ff).into()), editor_gutter_background: Some(rgba(0xf9f5d7ff).into()),
editor_line_number: Some(rgba(0xbdae93ff).into()), editor_line_number: Some(rgba(0xbdae93ff).into()),
@ -1214,6 +1218,7 @@ pub fn gruvbox() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0xd5c4a199).into()), scrollbar_thumb_border: Some(rgba(0xd5c4a199).into()),
scrollbar_track_background: Some(rgba(0xfbf1c7ff).into()), scrollbar_track_background: Some(rgba(0xfbf1c7ff).into()),
scrollbar_track_border: Some(rgba(0xfbf1c700).into()), scrollbar_track_border: Some(rgba(0xfbf1c700).into()),
editor_foreground: Some(rgba(0x3c3836ff).into()),
editor_background: Some(rgba(0xfbf1c7ff).into()), editor_background: Some(rgba(0xfbf1c7ff).into()),
editor_gutter_background: Some(rgba(0xfbf1c7ff).into()), editor_gutter_background: Some(rgba(0xfbf1c7ff).into()),
editor_line_number: Some(rgba(0xbdae93ff).into()), editor_line_number: Some(rgba(0xbdae93ff).into()),
@ -1506,6 +1511,7 @@ pub fn gruvbox() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0xd5c4a199).into()), scrollbar_thumb_border: Some(rgba(0xd5c4a199).into()),
scrollbar_track_background: Some(rgba(0xf2e5bcff).into()), scrollbar_track_background: Some(rgba(0xf2e5bcff).into()),
scrollbar_track_border: Some(rgba(0xf2e5bc00).into()), scrollbar_track_border: Some(rgba(0xf2e5bc00).into()),
editor_foreground: Some(rgba(0x3c3836ff).into()),
editor_background: Some(rgba(0xf2e5bcff).into()), editor_background: Some(rgba(0xf2e5bcff).into()),
editor_gutter_background: Some(rgba(0xf2e5bcff).into()), editor_gutter_background: Some(rgba(0xf2e5bcff).into()),
editor_line_number: Some(rgba(0xbdae93ff).into()), editor_line_number: Some(rgba(0xbdae93ff).into()),

View file

@ -46,6 +46,7 @@ pub fn night_owl() -> UserThemeFamily {
scrollbar_thumb_hover_background: Some(rgba(0x084d8180).into()), scrollbar_thumb_hover_background: Some(rgba(0x084d8180).into()),
scrollbar_thumb_border: Some(rgba(0x084d8180).into()), scrollbar_thumb_border: Some(rgba(0x084d8180).into()),
scrollbar_track_background: Some(rgba(0x011627ff).into()), scrollbar_track_background: Some(rgba(0x011627ff).into()),
editor_foreground: Some(rgba(0xd6deebff).into()),
editor_background: Some(rgba(0x011627ff).into()), editor_background: Some(rgba(0x011627ff).into()),
editor_gutter_background: Some(rgba(0x011627ff).into()), editor_gutter_background: Some(rgba(0x011627ff).into()),
editor_line_number: Some(rgba(0x4b6479ff).into()), editor_line_number: Some(rgba(0x4b6479ff).into()),
@ -305,6 +306,7 @@ pub fn night_owl() -> UserThemeFamily {
tab_inactive_background: Some(rgba(0xf0f0f0ff).into()), tab_inactive_background: Some(rgba(0xf0f0f0ff).into()),
tab_active_background: Some(rgba(0xf6f6f6ff).into()), tab_active_background: Some(rgba(0xf6f6f6ff).into()),
scrollbar_track_background: Some(rgba(0xfbfbfbff).into()), scrollbar_track_background: Some(rgba(0xfbfbfbff).into()),
editor_foreground: Some(rgba(0x403f53ff).into()),
editor_background: Some(rgba(0xfbfbfbff).into()), editor_background: Some(rgba(0xfbfbfbff).into()),
editor_gutter_background: Some(rgba(0xfbfbfbff).into()), editor_gutter_background: Some(rgba(0xfbfbfbff).into()),
editor_line_number: Some(rgba(0x90a7b2ff).into()), editor_line_number: Some(rgba(0x90a7b2ff).into()),

View file

@ -47,6 +47,7 @@ pub fn noctis() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x008ee633).into()), scrollbar_thumb_border: Some(rgba(0x008ee633).into()),
scrollbar_track_background: Some(rgba(0x07273bff).into()), scrollbar_track_background: Some(rgba(0x07273bff).into()),
scrollbar_track_border: Some(rgba(0x07273bff).into()), scrollbar_track_border: Some(rgba(0x07273bff).into()),
editor_foreground: Some(rgba(0xbecfdaff).into()),
editor_background: Some(rgba(0x07273bff).into()), editor_background: Some(rgba(0x07273bff).into()),
editor_gutter_background: Some(rgba(0x07273bff).into()), editor_gutter_background: Some(rgba(0x07273bff).into()),
editor_line_number: Some(rgba(0x4d6c80ff).into()), editor_line_number: Some(rgba(0x4d6c80ff).into()),
@ -324,6 +325,7 @@ pub fn noctis() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0xeb609133).into()), scrollbar_thumb_border: Some(rgba(0xeb609133).into()),
scrollbar_track_background: Some(rgba(0x322a2dff).into()), scrollbar_track_background: Some(rgba(0x322a2dff).into()),
scrollbar_track_border: Some(rgba(0x322a2dff).into()), scrollbar_track_border: Some(rgba(0x322a2dff).into()),
editor_foreground: Some(rgba(0xcbbec2ff).into()),
editor_background: Some(rgba(0x322a2dff).into()), editor_background: Some(rgba(0x322a2dff).into()),
editor_gutter_background: Some(rgba(0x322a2dff).into()), editor_gutter_background: Some(rgba(0x322a2dff).into()),
editor_line_number: Some(rgba(0x715b63ff).into()), editor_line_number: Some(rgba(0x715b63ff).into()),
@ -601,6 +603,7 @@ pub fn noctis() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x6a90955b).into()), scrollbar_thumb_border: Some(rgba(0x6a90955b).into()),
scrollbar_track_background: Some(rgba(0xf4f6f6ff).into()), scrollbar_track_background: Some(rgba(0xf4f6f6ff).into()),
scrollbar_track_border: Some(rgba(0xf4f6f6ff).into()), scrollbar_track_border: Some(rgba(0xf4f6f6ff).into()),
editor_foreground: Some(rgba(0x005661ff).into()),
editor_background: Some(rgba(0xf4f6f6ff).into()), editor_background: Some(rgba(0xf4f6f6ff).into()),
editor_gutter_background: Some(rgba(0xf4f6f6ff).into()), editor_gutter_background: Some(rgba(0xf4f6f6ff).into()),
editor_line_number: Some(rgba(0xa0abacff).into()), editor_line_number: Some(rgba(0xa0abacff).into()),
@ -878,6 +881,7 @@ pub fn noctis() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x6a90955b).into()), scrollbar_thumb_border: Some(rgba(0x6a90955b).into()),
scrollbar_track_background: Some(rgba(0xf2f1f8ff).into()), scrollbar_track_background: Some(rgba(0xf2f1f8ff).into()),
scrollbar_track_border: Some(rgba(0xf2f1f8ff).into()), scrollbar_track_border: Some(rgba(0xf2f1f8ff).into()),
editor_foreground: Some(rgba(0x0c006bff).into()),
editor_background: Some(rgba(0xf2f1f8ff).into()), editor_background: Some(rgba(0xf2f1f8ff).into()),
editor_gutter_background: Some(rgba(0xf2f1f8ff).into()), editor_gutter_background: Some(rgba(0xf2f1f8ff).into()),
editor_line_number: Some(rgba(0x9d9ab1ff).into()), editor_line_number: Some(rgba(0x9d9ab1ff).into()),
@ -1155,6 +1159,7 @@ pub fn noctis() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x6a90955b).into()), scrollbar_thumb_border: Some(rgba(0x6a90955b).into()),
scrollbar_track_background: Some(rgba(0xfef8ecff).into()), scrollbar_track_background: Some(rgba(0xfef8ecff).into()),
scrollbar_track_border: Some(rgba(0xfef8ecff).into()), scrollbar_track_border: Some(rgba(0xfef8ecff).into()),
editor_foreground: Some(rgba(0x005661ff).into()),
editor_background: Some(rgba(0xfef8ecff).into()), editor_background: Some(rgba(0xfef8ecff).into()),
editor_gutter_background: Some(rgba(0xfef8ecff).into()), editor_gutter_background: Some(rgba(0xfef8ecff).into()),
editor_line_number: Some(rgba(0xa0abacff).into()), editor_line_number: Some(rgba(0xa0abacff).into()),
@ -1432,6 +1437,7 @@ pub fn noctis() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x3f7fa633).into()), scrollbar_thumb_border: Some(rgba(0x3f7fa633).into()),
scrollbar_track_background: Some(rgba(0x1b2932ff).into()), scrollbar_track_background: Some(rgba(0x1b2932ff).into()),
scrollbar_track_border: Some(rgba(0x1b2932ff).into()), scrollbar_track_border: Some(rgba(0x1b2932ff).into()),
editor_foreground: Some(rgba(0xc5cdd3ff).into()),
editor_background: Some(rgba(0x1b2932ff).into()), editor_background: Some(rgba(0x1b2932ff).into()),
editor_gutter_background: Some(rgba(0x1b2932ff).into()), editor_gutter_background: Some(rgba(0x1b2932ff).into()),
editor_line_number: Some(rgba(0x5d6e79ff).into()), editor_line_number: Some(rgba(0x5d6e79ff).into()),
@ -1709,6 +1715,7 @@ pub fn noctis() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x6a90955b).into()), scrollbar_thumb_border: Some(rgba(0x6a90955b).into()),
scrollbar_track_background: Some(rgba(0x052529ff).into()), scrollbar_track_background: Some(rgba(0x052529ff).into()),
scrollbar_track_border: Some(rgba(0x052529ff).into()), scrollbar_track_border: Some(rgba(0x052529ff).into()),
editor_foreground: Some(rgba(0xb2cacdff).into()),
editor_background: Some(rgba(0x052529ff).into()), editor_background: Some(rgba(0x052529ff).into()),
editor_gutter_background: Some(rgba(0x052529ff).into()), editor_gutter_background: Some(rgba(0x052529ff).into()),
editor_line_number: Some(rgba(0x4e6b6eff).into()), editor_line_number: Some(rgba(0x4e6b6eff).into()),
@ -1986,6 +1993,7 @@ pub fn noctis() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x6a90955b).into()), scrollbar_thumb_border: Some(rgba(0x6a90955b).into()),
scrollbar_track_background: Some(rgba(0x031417ff).into()), scrollbar_track_background: Some(rgba(0x031417ff).into()),
scrollbar_track_border: Some(rgba(0x031417ff).into()), scrollbar_track_border: Some(rgba(0x031417ff).into()),
editor_foreground: Some(rgba(0xb2cacdff).into()),
editor_background: Some(rgba(0x031417ff).into()), editor_background: Some(rgba(0x031417ff).into()),
editor_gutter_background: Some(rgba(0x031417ff).into()), editor_gutter_background: Some(rgba(0x031417ff).into()),
editor_line_number: Some(rgba(0x4e6b6eff).into()), editor_line_number: Some(rgba(0x4e6b6eff).into()),
@ -2263,6 +2271,7 @@ pub fn noctis() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x6a90955b).into()), scrollbar_thumb_border: Some(rgba(0x6a90955b).into()),
scrollbar_track_background: Some(rgba(0x031417ff).into()), scrollbar_track_background: Some(rgba(0x031417ff).into()),
scrollbar_track_border: Some(rgba(0x031417ff).into()), scrollbar_track_border: Some(rgba(0x031417ff).into()),
editor_foreground: Some(rgba(0xb2cacdff).into()),
editor_background: Some(rgba(0x031417ff).into()), editor_background: Some(rgba(0x031417ff).into()),
editor_gutter_background: Some(rgba(0x031417ff).into()), editor_gutter_background: Some(rgba(0x031417ff).into()),
editor_line_number: Some(rgba(0x4e6b6eff).into()), editor_line_number: Some(rgba(0x4e6b6eff).into()),
@ -2540,6 +2549,7 @@ pub fn noctis() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x7060eb33).into()), scrollbar_thumb_border: Some(rgba(0x7060eb33).into()),
scrollbar_track_background: Some(rgba(0x292640ff).into()), scrollbar_track_background: Some(rgba(0x292640ff).into()),
scrollbar_track_border: Some(rgba(0x292640ff).into()), scrollbar_track_border: Some(rgba(0x292640ff).into()),
editor_foreground: Some(rgba(0xc5c2d6ff).into()),
editor_background: Some(rgba(0x292640ff).into()), editor_background: Some(rgba(0x292640ff).into()),
editor_gutter_background: Some(rgba(0x292640ff).into()), editor_gutter_background: Some(rgba(0x292640ff).into()),
editor_line_number: Some(rgba(0x5c5973ff).into()), editor_line_number: Some(rgba(0x5c5973ff).into()),
@ -2817,6 +2827,7 @@ pub fn noctis() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0xa660eb33).into()), scrollbar_thumb_border: Some(rgba(0xa660eb33).into()),
scrollbar_track_background: Some(rgba(0x30243dff).into()), scrollbar_track_background: Some(rgba(0x30243dff).into()),
scrollbar_track_border: Some(rgba(0x30243dff).into()), scrollbar_track_border: Some(rgba(0x30243dff).into()),
editor_foreground: Some(rgba(0xccbfd9ff).into()),
editor_background: Some(rgba(0x30243dff).into()), editor_background: Some(rgba(0x30243dff).into()),
editor_gutter_background: Some(rgba(0x30243dff).into()), editor_gutter_background: Some(rgba(0x30243dff).into()),
editor_line_number: Some(rgba(0x665973ff).into()), editor_line_number: Some(rgba(0x665973ff).into()),

View file

@ -46,6 +46,7 @@ pub fn nord() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x434c5e99).into()), scrollbar_thumb_border: Some(rgba(0x434c5e99).into()),
scrollbar_track_background: Some(rgba(0x2e3440ff).into()), scrollbar_track_background: Some(rgba(0x2e3440ff).into()),
scrollbar_track_border: Some(rgba(0x3b4252ff).into()), scrollbar_track_border: Some(rgba(0x3b4252ff).into()),
editor_foreground: Some(rgba(0xd8dee9ff).into()),
editor_background: Some(rgba(0x2e3440ff).into()), editor_background: Some(rgba(0x2e3440ff).into()),
editor_gutter_background: Some(rgba(0x2e3440ff).into()), editor_gutter_background: Some(rgba(0x2e3440ff).into()),
editor_line_number: Some(rgba(0x4c566aff).into()), editor_line_number: Some(rgba(0x4c566aff).into()),

View file

@ -46,6 +46,7 @@ pub fn palenight() -> UserThemeFamily {
scrollbar_thumb_hover_background: Some(rgba(0x694ca4cc).into()), scrollbar_thumb_hover_background: Some(rgba(0x694ca4cc).into()),
scrollbar_thumb_border: Some(rgba(0x694ca466).into()), scrollbar_thumb_border: Some(rgba(0x694ca466).into()),
scrollbar_track_background: Some(rgba(0x292d3eff).into()), scrollbar_track_background: Some(rgba(0x292d3eff).into()),
editor_foreground: Some(rgba(0xbfc7d5ff).into()),
editor_background: Some(rgba(0x292d3eff).into()), editor_background: Some(rgba(0x292d3eff).into()),
editor_gutter_background: Some(rgba(0x292d3eff).into()), editor_gutter_background: Some(rgba(0x292d3eff).into()),
editor_line_number: Some(rgba(0x4c5374ff).into()), editor_line_number: Some(rgba(0x4c5374ff).into()),
@ -331,6 +332,7 @@ pub fn palenight() -> UserThemeFamily {
scrollbar_thumb_hover_background: Some(rgba(0x694ca4cc).into()), scrollbar_thumb_hover_background: Some(rgba(0x694ca4cc).into()),
scrollbar_thumb_border: Some(rgba(0x694ca466).into()), scrollbar_thumb_border: Some(rgba(0x694ca466).into()),
scrollbar_track_background: Some(rgba(0x292d3eff).into()), scrollbar_track_background: Some(rgba(0x292d3eff).into()),
editor_foreground: Some(rgba(0xbfc7d5ff).into()),
editor_background: Some(rgba(0x292d3eff).into()), editor_background: Some(rgba(0x292d3eff).into()),
editor_gutter_background: Some(rgba(0x292d3eff).into()), editor_gutter_background: Some(rgba(0x292d3eff).into()),
editor_line_number: Some(rgba(0x4c5374ff).into()), editor_line_number: Some(rgba(0x4c5374ff).into()),
@ -616,6 +618,7 @@ pub fn palenight() -> UserThemeFamily {
scrollbar_thumb_hover_background: Some(rgba(0x694ca4cc).into()), scrollbar_thumb_hover_background: Some(rgba(0x694ca4cc).into()),
scrollbar_thumb_border: Some(rgba(0x694ca466).into()), scrollbar_thumb_border: Some(rgba(0x694ca466).into()),
scrollbar_track_background: Some(rgba(0x292d3eff).into()), scrollbar_track_background: Some(rgba(0x292d3eff).into()),
editor_foreground: Some(rgba(0xbfc7d5ff).into()),
editor_background: Some(rgba(0x292d3eff).into()), editor_background: Some(rgba(0x292d3eff).into()),
editor_gutter_background: Some(rgba(0x292d3eff).into()), editor_gutter_background: Some(rgba(0x292d3eff).into()),
editor_line_number: Some(rgba(0x4c5374ff).into()), editor_line_number: Some(rgba(0x4c5374ff).into()),

View file

@ -47,6 +47,7 @@ pub fn rose_pine() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x6e6a8633).into()), scrollbar_thumb_border: Some(rgba(0x6e6a8633).into()),
scrollbar_track_background: Some(rgba(0x191724ff).into()), scrollbar_track_background: Some(rgba(0x191724ff).into()),
scrollbar_track_border: Some(rgba(0x6e6a8666).into()), scrollbar_track_border: Some(rgba(0x6e6a8666).into()),
editor_foreground: Some(rgba(0xe0def4ff).into()),
editor_background: Some(rgba(0x191724ff).into()), editor_background: Some(rgba(0x191724ff).into()),
editor_gutter_background: Some(rgba(0x191724ff).into()), editor_gutter_background: Some(rgba(0x191724ff).into()),
editor_line_number: Some(rgba(0x908caaff).into()), editor_line_number: Some(rgba(0x908caaff).into()),
@ -306,6 +307,7 @@ pub fn rose_pine() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x817c9c26).into()), scrollbar_thumb_border: Some(rgba(0x817c9c26).into()),
scrollbar_track_background: Some(rgba(0x232136ff).into()), scrollbar_track_background: Some(rgba(0x232136ff).into()),
scrollbar_track_border: Some(rgba(0x817c9c4d).into()), scrollbar_track_border: Some(rgba(0x817c9c4d).into()),
editor_foreground: Some(rgba(0xe0def4ff).into()),
editor_background: Some(rgba(0x232136ff).into()), editor_background: Some(rgba(0x232136ff).into()),
editor_gutter_background: Some(rgba(0x232136ff).into()), editor_gutter_background: Some(rgba(0x232136ff).into()),
editor_line_number: Some(rgba(0x908caaff).into()), editor_line_number: Some(rgba(0x908caaff).into()),
@ -565,6 +567,7 @@ pub fn rose_pine() -> UserThemeFamily {
scrollbar_thumb_border: Some(rgba(0x6e6a8614).into()), scrollbar_thumb_border: Some(rgba(0x6e6a8614).into()),
scrollbar_track_background: Some(rgba(0xfaf4edff).into()), scrollbar_track_background: Some(rgba(0xfaf4edff).into()),
scrollbar_track_border: Some(rgba(0x6e6a8626).into()), scrollbar_track_border: Some(rgba(0x6e6a8626).into()),
editor_foreground: Some(rgba(0x575279ff).into()),
editor_background: Some(rgba(0xfaf4edff).into()), editor_background: Some(rgba(0xfaf4edff).into()),
editor_gutter_background: Some(rgba(0xfaf4edff).into()), editor_gutter_background: Some(rgba(0xfaf4edff).into()),
editor_line_number: Some(rgba(0x797593ff).into()), editor_line_number: Some(rgba(0x797593ff).into()),

View file

@ -42,6 +42,7 @@ pub fn solarized() -> UserThemeFamily {
tab_inactive_background: Some(rgba(0x004052ff).into()), tab_inactive_background: Some(rgba(0x004052ff).into()),
tab_active_background: Some(rgba(0x002b37ff).into()), tab_active_background: Some(rgba(0x002b37ff).into()),
scrollbar_track_background: Some(rgba(0x002b36ff).into()), scrollbar_track_background: Some(rgba(0x002b36ff).into()),
editor_foreground: Some(rgba(0xbbbbbbff).into()),
editor_background: Some(rgba(0x002b36ff).into()), editor_background: Some(rgba(0x002b36ff).into()),
editor_gutter_background: Some(rgba(0x002b36ff).into()), editor_gutter_background: Some(rgba(0x002b36ff).into()),
editor_line_number: Some(rgba(0x566c74ff).into()), editor_line_number: Some(rgba(0x566c74ff).into()),
@ -307,6 +308,7 @@ pub fn solarized() -> UserThemeFamily {
tab_inactive_background: Some(rgba(0xd3cbb7ff).into()), tab_inactive_background: Some(rgba(0xd3cbb7ff).into()),
tab_active_background: Some(rgba(0xfdf6e3ff).into()), tab_active_background: Some(rgba(0xfdf6e3ff).into()),
scrollbar_track_background: Some(rgba(0xfdf6e3ff).into()), scrollbar_track_background: Some(rgba(0xfdf6e3ff).into()),
editor_foreground: Some(rgba(0x333333ff).into()),
editor_background: Some(rgba(0xfdf6e3ff).into()), editor_background: Some(rgba(0xfdf6e3ff).into()),
editor_gutter_background: Some(rgba(0xfdf6e3ff).into()), editor_gutter_background: Some(rgba(0xfdf6e3ff).into()),
editor_line_number: Some(rgba(0x9ca8a6ff).into()), editor_line_number: Some(rgba(0x9ca8a6ff).into()),

View file

@ -201,6 +201,7 @@ impl<'a> Debug for ThemeColorsRefinementPrinter<'a> {
self.0.scrollbar_track_background, self.0.scrollbar_track_background,
), ),
("scrollbar_track_border", self.0.scrollbar_track_border), ("scrollbar_track_border", self.0.scrollbar_track_border),
("editor_foreground", self.0.editor_foreground),
("editor_background", self.0.editor_background), ("editor_background", self.0.editor_background),
("editor_gutter_background", self.0.editor_gutter_background), ("editor_gutter_background", self.0.editor_gutter_background),
( (

View file

@ -132,6 +132,11 @@ impl VsCodeThemeConverter {
.as_ref() .as_ref()
.traverse(|color| try_parse_color(&color))?; .traverse(|color| try_parse_color(&color))?;
let vscode_editor_foreground = vscode_colors
.editor_foreground
.as_ref()
.traverse(|color| try_parse_color(&color))?;
let vscode_editor_background = vscode_colors let vscode_editor_background = vscode_colors
.editor_background .editor_background
.as_ref() .as_ref()
@ -142,6 +147,16 @@ impl VsCodeThemeConverter {
.as_ref() .as_ref()
.traverse(|color| try_parse_color(&color))?; .traverse(|color| try_parse_color(&color))?;
let vscode_token_colors_foreground = self
.theme
.token_colors
.iter()
.find(|token_color| token_color.scope.is_none())
.and_then(|token_color| token_color.settings.foreground.as_ref())
.traverse(|color| try_parse_color(&color))
.ok()
.flatten();
Ok(ThemeColorsRefinement { Ok(ThemeColorsRefinement {
border: vscode_panel_border, border: vscode_panel_border,
border_variant: vscode_panel_border, border_variant: vscode_panel_border,
@ -197,16 +212,7 @@ impl VsCodeThemeConverter {
.foreground .foreground
.as_ref() .as_ref()
.traverse(|color| try_parse_color(&color))? .traverse(|color| try_parse_color(&color))?
.or_else(|| { .or(vscode_token_colors_foreground),
self.theme
.token_colors
.iter()
.find(|token_color| token_color.scope.is_none())
.and_then(|token_color| token_color.settings.foreground.as_ref())
.traverse(|color| try_parse_color(&color))
.ok()
.flatten()
}),
text_muted: vscode_colors text_muted: vscode_colors
.tab_inactive_foreground .tab_inactive_foreground
.as_ref() .as_ref()
@ -226,6 +232,7 @@ impl VsCodeThemeConverter {
.as_ref() .as_ref()
.traverse(|color| try_parse_color(&color))? .traverse(|color| try_parse_color(&color))?
.or(vscode_editor_background), .or(vscode_editor_background),
editor_foreground: vscode_editor_foreground.or(vscode_token_colors_foreground),
editor_background: vscode_editor_background, editor_background: vscode_editor_background,
editor_gutter_background: vscode_editor_background, editor_gutter_background: vscode_editor_background,
editor_line_number: vscode_colors editor_line_number: vscode_colors

View file

@ -41,7 +41,7 @@ pub trait Panel: FocusableView + EventEmitter<PanelEvent> {
} }
pub trait PanelHandle: Send + Sync { pub trait PanelHandle: Send + Sync {
fn entity_id(&self) -> EntityId; fn panel_id(&self) -> EntityId;
fn persistent_name(&self) -> &'static str; fn persistent_name(&self) -> &'static str;
fn position(&self, cx: &WindowContext) -> DockPosition; fn position(&self, cx: &WindowContext) -> DockPosition;
fn position_is_valid(&self, position: DockPosition, cx: &WindowContext) -> bool; fn position_is_valid(&self, position: DockPosition, cx: &WindowContext) -> bool;
@ -62,7 +62,7 @@ impl<T> PanelHandle for View<T>
where where
T: Panel, T: Panel,
{ {
fn entity_id(&self) -> EntityId { fn panel_id(&self) -> EntityId {
Entity::entity_id(self) Entity::entity_id(self)
} }
@ -135,7 +135,7 @@ pub struct Dock {
is_open: bool, is_open: bool,
active_panel_index: usize, active_panel_index: usize,
focus_handle: FocusHandle, focus_handle: FocusHandle,
focus_subscription: Subscription, _focus_subscription: Subscription,
} }
impl FocusableView for Dock { impl FocusableView for Dock {
@ -187,7 +187,6 @@ struct PanelEntry {
pub struct PanelButtons { pub struct PanelButtons {
dock: View<Dock>, dock: View<Dock>,
workspace: WeakView<Workspace>,
} }
impl Dock { impl Dock {
@ -204,7 +203,7 @@ impl Dock {
active_panel_index: 0, active_panel_index: 0,
is_open: false, is_open: false,
focus_handle, focus_handle,
focus_subscription, _focus_subscription: focus_subscription,
} }
} }
@ -261,7 +260,7 @@ impl Dock {
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, cx: &mut ViewContext<Self>) {
for entry in &mut self.panel_entries { for entry in &mut self.panel_entries {
if entry.panel.entity_id() == panel.entity_id() { if entry.panel.panel_id() == panel.entity_id() {
if zoomed != entry.panel.is_zoomed(cx) { if zoomed != entry.panel.is_zoomed(cx) {
entry.panel.set_zoomed(zoomed, cx); entry.panel.set_zoomed(zoomed, cx);
} }
@ -309,7 +308,7 @@ impl Dock {
let was_visible = this.is_open() let was_visible = this.is_open()
&& this.visible_panel().map_or(false, |active_panel| { && this.visible_panel().map_or(false, |active_panel| {
active_panel.entity_id() == Entity::entity_id(&panel) active_panel.panel_id() == Entity::entity_id(&panel)
}); });
this.remove_panel(&panel, cx); this.remove_panel(&panel, cx);
@ -351,7 +350,7 @@ impl Dock {
if let Some(ix) = this if let Some(ix) = this
.panel_entries .panel_entries
.iter() .iter()
.position(|entry| entry.panel.entity_id() == Entity::entity_id(&panel)) .position(|entry| entry.panel.panel_id() == Entity::entity_id(&panel))
{ {
this.set_open(true, cx); this.set_open(true, cx);
this.activate_panel(ix, cx); this.activate_panel(ix, cx);
@ -361,7 +360,7 @@ impl Dock {
PanelEvent::Close => { PanelEvent::Close => {
if this if this
.visible_panel() .visible_panel()
.map_or(false, |p| p.entity_id() == Entity::entity_id(&panel)) .map_or(false, |p| p.panel_id() == Entity::entity_id(&panel))
{ {
this.set_open(false, cx); this.set_open(false, cx);
} }
@ -389,7 +388,7 @@ impl Dock {
if let Some(panel_ix) = self if let Some(panel_ix) = self
.panel_entries .panel_entries
.iter() .iter()
.position(|entry| entry.panel.entity_id() == Entity::entity_id(panel)) .position(|entry| entry.panel.panel_id() == Entity::entity_id(panel))
{ {
if panel_ix == self.active_panel_index { if panel_ix == self.active_panel_index {
self.active_panel_index = 0; self.active_panel_index = 0;
@ -450,7 +449,7 @@ impl Dock {
pub fn panel_size(&self, panel: &dyn PanelHandle, cx: &WindowContext) -> Option<f32> { pub fn panel_size(&self, panel: &dyn PanelHandle, cx: &WindowContext) -> Option<f32> {
self.panel_entries self.panel_entries
.iter() .iter()
.find(|entry| entry.panel.entity_id() == panel.entity_id()) .find(|entry| entry.panel.panel_id() == panel.panel_id())
.map(|entry| entry.panel.size(cx)) .map(|entry| entry.panel.size(cx))
} }
@ -493,7 +492,9 @@ impl Render for Dock {
let handler = div() let handler = div()
.id("resize-handle") .id("resize-handle")
.bg(cx.theme().colors().border) .bg(cx.theme().colors().border)
.on_drag(move |cx| cx.build_view(|_| DraggedDock(position))) .on_drag(DraggedDock(position), |dock, cx| {
cx.build_view(|_| dock.clone())
})
.on_click(cx.listener(|v, e: &ClickEvent, cx| { .on_click(cx.listener(|v, e: &ClickEvent, cx| {
if e.down.button == MouseButton::Left && e.down.click_count == 2 { if e.down.button == MouseButton::Left && e.down.click_count == 2 {
v.resize_active_panel(None, cx) v.resize_active_panel(None, cx)
@ -547,166 +548,12 @@ impl Render for Dock {
} }
impl PanelButtons { impl PanelButtons {
pub fn new( pub fn new(dock: View<Dock>, cx: &mut ViewContext<Self>) -> Self {
dock: View<Dock>,
workspace: WeakView<Workspace>,
cx: &mut ViewContext<Self>,
) -> Self {
cx.observe(&dock, |_, _, cx| cx.notify()).detach(); cx.observe(&dock, |_, _, cx| cx.notify()).detach();
Self { dock, workspace } Self { dock }
} }
} }
// impl Render for PanelButtons {
// type Element = ();
// fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
// todo!("")
// }
// fn ui_name() -> &'static str {
// "PanelButtons"
// }
// fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
// let theme = &settings::get::<ThemeSettings>(cx).theme;
// let tooltip_style = theme.tooltip.clone();
// let theme = &theme.workspace.status_bar.panel_buttons;
// let button_style = theme.button.clone();
// let dock = self.dock.read(cx);
// let active_ix = dock.active_panel_index;
// let is_open = dock.is_open;
// let dock_position = dock.position;
// let group_style = match dock_position {
// DockPosition::Left => theme.group_left,
// DockPosition::Bottom => theme.group_bottom,
// DockPosition::Right => theme.group_right,
// };
// let menu_corner = match dock_position {
// DockPosition::Left => AnchorCorner::BottomLeft,
// DockPosition::Bottom | DockPosition::Right => AnchorCorner::BottomRight,
// };
// let panels = dock
// .panel_entries
// .iter()
// .map(|item| (item.panel.clone(), item.context_menu.clone()))
// .collect::<Vec<_>>();
// Flex::row()
// .with_children(panels.into_iter().enumerate().filter_map(
// |(panel_ix, (view, context_menu))| {
// let icon_path = view.icon_path(cx)?;
// let is_active = is_open && panel_ix == active_ix;
// let (tooltip, tooltip_action) = if is_active {
// (
// format!("Close {} dock", dock_position.to_label()),
// Some(match dock_position {
// DockPosition::Left => crate::ToggleLeftDock.boxed_clone(),
// DockPosition::Bottom => crate::ToggleBottomDock.boxed_clone(),
// DockPosition::Right => crate::ToggleRightDock.boxed_clone(),
// }),
// )
// } else {
// view.icon_tooltip(cx)
// };
// Some(
// Stack::new()
// .with_child(
// MouseEventHandler::new::<Self, _>(panel_ix, cx, |state, cx| {
// let style = button_style.in_state(is_active);
// let style = style.style_for(state);
// Flex::row()
// .with_child(
// Svg::new(icon_path)
// .with_color(style.icon_color)
// .constrained()
// .with_width(style.icon_size)
// .aligned(),
// )
// .with_children(if let Some(label) = view.icon_label(cx) {
// Some(
// Label::new(label, style.label.text.clone())
// .contained()
// .with_style(style.label.container)
// .aligned(),
// )
// } else {
// None
// })
// .constrained()
// .with_height(style.icon_size)
// .contained()
// .with_style(style.container)
// })
// .with_cursor_style(CursorStyle::PointingHand)
// .on_click(MouseButton::Left, {
// let tooltip_action =
// tooltip_action.as_ref().map(|action| action.boxed_clone());
// move |_, this, cx| {
// if let Some(tooltip_action) = &tooltip_action {
// let window = cx.window();
// let view_id = this.workspace.id();
// let tooltip_action = tooltip_action.boxed_clone();
// cx.spawn(|_, mut cx| async move {
// window.dispatch_action(
// view_id,
// &*tooltip_action,
// &mut cx,
// );
// })
// .detach();
// }
// }
// })
// .on_click(MouseButton::Right, {
// let view = view.clone();
// let menu = context_menu.clone();
// move |_, _, cx| {
// const POSITIONS: [DockPosition; 3] = [
// DockPosition::Left,
// DockPosition::Right,
// DockPosition::Bottom,
// ];
// menu.update(cx, |menu, cx| {
// let items = POSITIONS
// .into_iter()
// .filter(|position| {
// *position != dock_position
// && view.position_is_valid(*position, cx)
// })
// .map(|position| {
// let view = view.clone();
// ContextMenuItem::handler(
// format!("Dock {}", position.to_label()),
// move |cx| view.set_position(position, cx),
// )
// })
// .collect();
// menu.show(Default::default(), menu_corner, items, cx);
// })
// }
// })
// .with_tooltip::<Self>(
// panel_ix,
// tooltip,
// tooltip_action,
// tooltip_style.clone(),
// cx,
// ),
// )
// .with_child(ChildView::new(&context_menu, cx)),
// )
// },
// ))
// .contained()
// .with_style(group_style)
// .into_any()
// }
// }
// here be kittens
impl Render for PanelButtons { impl Render for PanelButtons {
type Element = Div; type Element = Div;

View file

@ -919,7 +919,7 @@ pub mod test {
impl EventEmitter<ItemEvent> for TestItem {} impl EventEmitter<ItemEvent> for TestItem {}
impl FocusableView for TestItem { impl FocusableView for TestItem {
fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle { fn focus_handle(&self, _: &AppContext) -> gpui::FocusHandle {
self.focus_handle.clone() self.focus_handle.clone()
} }
} }
@ -941,8 +941,8 @@ pub mod test {
fn tab_content( fn tab_content(
&self, &self,
detail: Option<usize>, detail: Option<usize>,
selected: bool, _selected: bool,
cx: &ui::prelude::WindowContext, _cx: &ui::prelude::WindowContext,
) -> AnyElement { ) -> AnyElement {
self.tab_detail.set(detail); self.tab_detail.set(detail);
gpui::div().into_any_element() gpui::div().into_any_element()

View file

@ -5,7 +5,7 @@ use gpui::{
use ui::{h_stack, v_stack}; use ui::{h_stack, v_stack};
pub trait ModalView: ManagedView { pub trait ModalView: ManagedView {
fn on_before_dismiss(&mut self, cx: &mut ViewContext<Self>) -> bool { fn on_before_dismiss(&mut self, _: &mut ViewContext<Self>) -> bool {
true true
} }
} }
@ -27,7 +27,7 @@ impl<V: ModalView> ModalViewHandle for View<V> {
pub struct ActiveModal { pub struct ActiveModal {
modal: Box<dyn ModalViewHandle>, modal: Box<dyn ModalViewHandle>,
subscription: Subscription, _subscription: Subscription,
previous_focus_handle: Option<FocusHandle>, previous_focus_handle: Option<FocusHandle>,
focus_handle: FocusHandle, focus_handle: FocusHandle,
} }
@ -63,7 +63,7 @@ impl ModalLayer {
{ {
self.active_modal = Some(ActiveModal { self.active_modal = Some(ActiveModal {
modal: Box::new(new_modal.clone()), modal: Box::new(new_modal.clone()),
subscription: cx.subscribe(&new_modal, |this, modal, _: &DismissEvent, cx| { _subscription: cx.subscribe(&new_modal, |this, _, _: &DismissEvent, cx| {
this.hide_modal(cx); this.hide_modal(cx);
}), }),
previous_focus_handle: cx.focused(), previous_focus_handle: cx.focused(),

View file

@ -104,12 +104,9 @@ impl Workspace {
}) })
{ {
let notification = build_notification(cx); let notification = build_notification(cx);
cx.subscribe( cx.subscribe(&notification, move |this, _, _: &DismissEvent, cx| {
&notification,
move |this, handle, event: &DismissEvent, cx| {
this.dismiss_notification_internal(type_id, id, cx); this.dismiss_notification_internal(type_id, id, cx);
}, })
)
.detach(); .detach();
self.notifications self.notifications
.push((type_id, id, Box::new(notification))); .push((type_id, id, Box::new(notification)));
@ -173,21 +170,15 @@ impl Workspace {
pub mod simple_message_notification { pub mod simple_message_notification {
use gpui::{ use gpui::{
div, AnyElement, AppContext, DismissEvent, Div, EventEmitter, InteractiveElement, div, DismissEvent, Div, EventEmitter, InteractiveElement, ParentElement, Render,
ParentElement, Render, SharedString, StatefulInteractiveElement, Styled, TextStyle, SharedString, StatefulInteractiveElement, Styled, ViewContext,
ViewContext,
}; };
use std::sync::Arc; use std::sync::Arc;
use ui::prelude::*; use ui::prelude::*;
use ui::{h_stack, v_stack, Button, Icon, IconElement, Label, StyledExt}; use ui::{h_stack, v_stack, Button, Icon, IconElement, Label, StyledExt};
enum NotificationMessage {
Text(SharedString),
Element(fn(TextStyle, &AppContext) -> AnyElement),
}
pub struct MessageNotification { pub struct MessageNotification {
message: NotificationMessage, message: SharedString,
on_click: Option<Arc<dyn Fn(&mut ViewContext<Self>)>>, on_click: Option<Arc<dyn Fn(&mut ViewContext<Self>)>>,
click_message: Option<SharedString>, click_message: Option<SharedString>,
} }
@ -200,23 +191,12 @@ pub mod simple_message_notification {
S: Into<SharedString>, S: Into<SharedString>,
{ {
Self { Self {
message: NotificationMessage::Text(message.into()), message: message.into(),
on_click: None, on_click: None,
click_message: None, click_message: None,
} }
} }
// not needed I think (only for the "new panel" toast, which is outdated now)
// pub fn new_element(
// message: fn(TextStyle, &AppContext) -> AnyElement,
// ) -> MessageNotification {
// Self {
// message: NotificationMessage::Element(message),
// on_click: None,
// click_message: None,
// }
// }
pub fn with_click_message<S>(mut self, message: S) -> Self pub fn with_click_message<S>(mut self, message: S) -> Self
where where
S: Into<SharedString>, S: Into<SharedString>,
@ -248,18 +228,13 @@ pub mod simple_message_notification {
.child( .child(
h_stack() h_stack()
.justify_between() .justify_between()
.child(div().max_w_80().child(match &self.message { .child(div().max_w_80().child(Label::new(self.message.clone())))
NotificationMessage::Text(text) => Label::new(text.clone()),
NotificationMessage::Element(element) => {
todo!()
}
}))
.child( .child(
div() div()
.id("cancel") .id("cancel")
.child(IconElement::new(Icon::Close)) .child(IconElement::new(Icon::Close))
.cursor_pointer() .cursor_pointer()
.on_click(cx.listener(|this, event, cx| this.dismiss(cx))), .on_click(cx.listener(|this, _, cx| this.dismiss(cx))),
), ),
) )
.children(self.click_message.iter().map(|message| { .children(self.click_message.iter().map(|message| {

View file

@ -7,7 +7,7 @@ use crate::{
use anyhow::Result; use anyhow::Result;
use collections::{HashMap, HashSet, VecDeque}; use collections::{HashMap, HashSet, VecDeque};
use gpui::{ use gpui::{
actions, impl_actions, overlay, prelude::*, Action, AnchorCorner, AnyWeakView, AppContext, actions, impl_actions, overlay, prelude::*, Action, AnchorCorner, AppContext,
AsyncWindowContext, DismissEvent, Div, EntityId, EventEmitter, FocusHandle, Focusable, AsyncWindowContext, DismissEvent, Div, EntityId, EventEmitter, FocusHandle, Focusable,
FocusableView, Model, MouseButton, NavigationDirection, Pixels, Point, PromptLevel, Render, FocusableView, Model, MouseButton, NavigationDirection, Pixels, Point, PromptLevel, Render,
ScrollHandle, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowContext, ScrollHandle, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
@ -164,11 +164,6 @@ impl fmt::Debug for Event {
} }
} }
struct FocusedView {
view: AnyWeakView,
focus_handle: FocusHandle,
}
pub struct Pane { pub struct Pane {
focus_handle: FocusHandle, focus_handle: FocusHandle,
items: Vec<Box<dyn ItemHandle>>, items: Vec<Box<dyn ItemHandle>>,
@ -187,7 +182,7 @@ pub struct Pane {
// can_drop: Rc<dyn Fn(&DragAndDrop<Workspace>, &WindowContext) -> bool>, // can_drop: Rc<dyn Fn(&DragAndDrop<Workspace>, &WindowContext) -> bool>,
can_split: bool, can_split: bool,
// render_tab_bar_buttons: Rc<dyn Fn(&mut Pane, &mut ViewContext<Pane>) -> AnyElement<Pane>>, // render_tab_bar_buttons: Rc<dyn Fn(&mut Pane, &mut ViewContext<Pane>) -> AnyElement<Pane>>,
subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
tab_bar_scroll_handle: ScrollHandle, tab_bar_scroll_handle: ScrollHandle,
} }
@ -231,6 +226,7 @@ pub struct NavigationEntry {
pub timestamp: usize, pub timestamp: usize,
} }
#[derive(Clone)]
struct DraggedTab { struct DraggedTab {
pub pane: View<Pane>, pub pane: View<Pane>,
pub ix: usize, pub ix: usize,
@ -431,14 +427,10 @@ impl Pane {
// }) // })
// .into_any() // .into_any()
// }), // }),
subscriptions, _subscriptions: subscriptions,
} }
} }
pub(crate) fn workspace(&self) -> &WeakView<Workspace> {
&self.workspace
}
pub fn has_focus(&self, cx: &WindowContext) -> bool { pub fn has_focus(&self, cx: &WindowContext) -> bool {
// todo!(); // inline this manually // todo!(); // inline this manually
self.focus_handle.contains_focused(cx) self.focus_handle.contains_focused(cx)
@ -1467,21 +1459,6 @@ impl Pane {
let label = item.tab_content(Some(detail), is_active, cx); let label = item.tab_content(Some(detail), is_active, cx);
let close_side = &ItemSettings::get_global(cx).close_position; let close_side = &ItemSettings::get_global(cx).close_position;
let (text_color, tab_bg, tab_hover_bg, tab_active_bg) = match ix == self.active_item_index {
false => (
cx.theme().colors().text_muted,
cx.theme().colors().tab_inactive_background,
cx.theme().colors().ghost_element_hover,
cx.theme().colors().ghost_element_active,
),
true => (
cx.theme().colors().text,
cx.theme().colors().tab_active_background,
cx.theme().colors().element_hover,
cx.theme().colors().element_active,
),
};
let indicator = maybe!({ let indicator = maybe!({
let indicator_color = match (item.has_conflict(cx), item.is_dirty(cx)) { let indicator_color = match (item.has_conflict(cx), item.is_dirty(cx)) {
(true, _) => Color::Warning, (true, _) => Color::Warning,
@ -1497,8 +1474,7 @@ impl Pane {
let is_last_item = ix == self.items.len() - 1; let is_last_item = ix == self.items.len() - 1;
let position_relative_to_active_item = ix.cmp(&self.active_item_index); let position_relative_to_active_item = ix.cmp(&self.active_item_index);
let tab = let tab = Tab::new(ix)
Tab::new(ix)
.position(if is_first_item { .position(if is_first_item {
TabPosition::First TabPosition::First
} else if is_last_item { } else if is_last_item {
@ -1511,27 +1487,27 @@ impl Pane {
ClosePosition::Right => ui::TabCloseSide::End, ClosePosition::Right => ui::TabCloseSide::End,
}) })
.selected(is_active) .selected(is_active)
.on_click(cx.listener(move |pane: &mut Self, event, cx| { .on_click(
pane.activate_item(ix, true, true, cx) cx.listener(move |pane: &mut Self, _, cx| pane.activate_item(ix, true, true, cx)),
})) )
.on_drag({ .on_drag(
let pane = cx.view().clone(); DraggedTab {
move |cx| { pane: cx.view().clone(),
cx.build_view(|cx| DraggedTab {
pane: pane.clone(),
detail, detail,
item_id, item_id,
is_active, is_active,
ix, ix,
}) },
} |tab, cx| cx.build_view(|_| tab.clone()),
})
.drag_over::<DraggedTab>(|tab| tab.bg(cx.theme().colors().tab_active_background))
.on_drop(
cx.listener(move |this, dragged_tab: &View<DraggedTab>, cx| {
this.handle_tab_drop(dragged_tab, ix, cx)
}),
) )
.drag_over::<DraggedTab>(|tab| tab.bg(cx.theme().colors().tab_active_background))
.drag_over::<ProjectEntryId>(|tab| tab.bg(gpui::red()))
.on_drop(cx.listener(move |this, dragged_tab: &DraggedTab, cx| {
this.handle_tab_drop(dragged_tab, ix, cx)
}))
.on_drop(cx.listener(move |this, entry_id: &ProjectEntryId, cx| {
this.handle_project_entry_drop(entry_id, cx)
}))
.when_some(item.tab_tooltip_text(cx), |tab, text| { .when_some(item.tab_tooltip_text(cx), |tab, text| {
tab.tooltip(move |cx| Tooltip::text(text.clone(), cx)) tab.tooltip(move |cx| Tooltip::text(text.clone(), cx))
}) })
@ -1616,12 +1592,12 @@ impl Pane {
IconButton::new("plus", Icon::Plus) IconButton::new("plus", Icon::Plus)
.icon_size(IconSize::Small) .icon_size(IconSize::Small)
.on_click(cx.listener(|this, _, cx| { .on_click(cx.listener(|this, _, cx| {
let menu = ContextMenu::build(cx, |menu, cx| { let menu = ContextMenu::build(cx, |menu, _| {
menu.action("New File", NewFile.boxed_clone()) menu.action("New File", NewFile.boxed_clone())
.action("New Terminal", NewCenterTerminal.boxed_clone()) .action("New Terminal", NewCenterTerminal.boxed_clone())
.action("New Search", NewSearch.boxed_clone()) .action("New Search", NewSearch.boxed_clone())
}); });
cx.subscribe(&menu, |this, _, event: &DismissEvent, cx| { cx.subscribe(&menu, |this, _, _: &DismissEvent, cx| {
this.focus(cx); this.focus(cx);
this.new_item_menu = None; this.new_item_menu = None;
}) })
@ -1640,13 +1616,13 @@ impl Pane {
IconButton::new("split", Icon::Split) IconButton::new("split", Icon::Split)
.icon_size(IconSize::Small) .icon_size(IconSize::Small)
.on_click(cx.listener(|this, _, cx| { .on_click(cx.listener(|this, _, cx| {
let menu = ContextMenu::build(cx, |menu, cx| { let menu = ContextMenu::build(cx, |menu, _| {
menu.action("Split Right", SplitRight.boxed_clone()) menu.action("Split Right", SplitRight.boxed_clone())
.action("Split Left", SplitLeft.boxed_clone()) .action("Split Left", SplitLeft.boxed_clone())
.action("Split Up", SplitUp.boxed_clone()) .action("Split Up", SplitUp.boxed_clone())
.action("Split Down", SplitDown.boxed_clone()) .action("Split Down", SplitDown.boxed_clone())
}); });
cx.subscribe(&menu, |this, _, event: &DismissEvent, cx| { cx.subscribe(&menu, |this, _, _: &DismissEvent, cx| {
this.focus(cx); this.focus(cx);
this.split_item_menu = None; this.split_item_menu = None;
}) })
@ -1677,11 +1653,13 @@ impl Pane {
.drag_over::<DraggedTab>(|bar| { .drag_over::<DraggedTab>(|bar| {
bar.bg(cx.theme().colors().tab_active_background) bar.bg(cx.theme().colors().tab_active_background)
}) })
.on_drop( .drag_over::<ProjectEntryId>(|bar| bar.bg(gpui::red()))
cx.listener(move |this, dragged_tab: &View<DraggedTab>, cx| { .on_drop(cx.listener(move |this, dragged_tab: &DraggedTab, cx| {
this.handle_tab_drop(dragged_tab, this.items.len(), cx) this.handle_tab_drop(dragged_tab, this.items.len(), cx)
}), }))
), .on_drop(cx.listener(move |this, entry_id: &ProjectEntryId, cx| {
this.handle_project_entry_drop(entry_id, cx)
})),
) )
} }
@ -1743,16 +1721,15 @@ impl Pane {
fn handle_tab_drop( fn handle_tab_drop(
&mut self, &mut self,
dragged_tab: &View<DraggedTab>, dragged_tab: &DraggedTab,
ix: usize, ix: usize,
cx: &mut ViewContext<'_, Pane>, cx: &mut ViewContext<'_, Pane>,
) { ) {
let dragged_tab = dragged_tab.read(cx);
let item_id = dragged_tab.item_id; let item_id = dragged_tab.item_id;
let from_pane = dragged_tab.pane.clone(); let from_pane = dragged_tab.pane.clone();
let to_pane = cx.view().clone(); let to_pane = cx.view().clone();
self.workspace self.workspace
.update(cx, |workspace, cx| { .update(cx, |_, cx| {
cx.defer(move |workspace, cx| { cx.defer(move |workspace, cx| {
workspace.move_item(from_pane, to_pane, item_id, ix, cx); workspace.move_item(from_pane, to_pane, item_id, ix, cx);
}); });
@ -1760,28 +1737,69 @@ impl Pane {
.log_err(); .log_err();
} }
fn handle_project_entry_drop(
&mut self,
project_entry_id: &ProjectEntryId,
cx: &mut ViewContext<'_, Pane>,
) {
let to_pane = cx.view().downgrade();
let project_entry_id = *project_entry_id;
self.workspace
.update(cx, |_, cx| {
cx.defer(move |workspace, cx| {
if let Some(path) = workspace
.project()
.read(cx)
.path_for_entry(project_entry_id, cx)
{
workspace
.open_path(path, Some(to_pane), true, cx)
.detach_and_log_err(cx);
}
});
})
.log_err();
}
fn handle_split_tab_drop( fn handle_split_tab_drop(
&mut self, &mut self,
dragged_tab: &View<DraggedTab>, dragged_tab: &DraggedTab,
split_direction: SplitDirection, split_direction: SplitDirection,
cx: &mut ViewContext<'_, Pane>, cx: &mut ViewContext<'_, Pane>,
) { ) {
let dragged_tab = dragged_tab.read(cx);
let item_id = dragged_tab.item_id; let item_id = dragged_tab.item_id;
let from_pane = dragged_tab.pane.clone(); let from_pane = dragged_tab.pane.clone();
let to_pane = cx.view().clone(); let to_pane = cx.view().clone();
self.workspace self.workspace
.update(cx, |workspace, cx| { .update(cx, |_, cx| {
cx.defer(move |workspace, cx| { cx.defer(move |workspace, cx| {
let item = from_pane let pane = workspace.split_pane(to_pane, split_direction, cx);
.read(cx) workspace.move_item(from_pane, pane, item_id, 0, cx);
.items() });
.find(|item| item.item_id() == item_id) })
.map(|item| item.boxed_clone()); .log_err();
if let Some(item) = item {
if let Some(item) = item.clone_on_split(workspace.database_id(), cx) {
workspace.split_item(split_direction, item, cx);
} }
fn handle_split_project_entry_drop(
&mut self,
project_entry_id: &ProjectEntryId,
split_direction: SplitDirection,
cx: &mut ViewContext<'_, Pane>,
) {
let project_entry_id = *project_entry_id;
let current_pane = cx.view().clone();
self.workspace
.update(cx, |_, cx| {
cx.defer(move |workspace, cx| {
if let Some(path) = workspace
.project()
.read(cx)
.path_for_entry(project_entry_id, cx)
{
let pane = workspace.split_pane(current_pane, split_direction, cx);
workspace
.open_path(path, Some(pane.downgrade()), true, cx)
.detach_and_log_err(cx);
} }
}); });
}) })
@ -1799,8 +1817,6 @@ impl Render for Pane {
type Element = Focusable<Div>; type Element = Focusable<Div>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let this = cx.view().downgrade();
v_stack() v_stack()
.key_context("Pane") .key_context("Pane")
.track_focus(&self.focus_handle) .track_focus(&self.focus_handle)
@ -1894,11 +1910,13 @@ impl Render for Pane {
.full() .full()
.z_index(1) .z_index(1)
.drag_over::<DraggedTab>(|style| style.bg(drag_target_color)) .drag_over::<DraggedTab>(|style| style.bg(drag_target_color))
.on_drop(cx.listener( .drag_over::<ProjectEntryId>(|style| style.bg(gpui::red()))
move |this, dragged_tab: &View<DraggedTab>, cx| { .on_drop(cx.listener(move |this, dragged_tab: &DraggedTab, cx| {
this.handle_tab_drop(dragged_tab, this.active_item_index(), cx) this.handle_tab_drop(dragged_tab, this.active_item_index(), cx)
}, }))
)), .on_drop(cx.listener(move |this, entry_id: &ProjectEntryId, cx| {
this.handle_project_entry_drop(entry_id, cx)
})),
) )
.children( .children(
[ [
@ -1915,9 +1933,15 @@ impl Render for Pane {
.invisible() .invisible()
.bg(drag_target_color) .bg(drag_target_color)
.drag_over::<DraggedTab>(|style| style.visible()) .drag_over::<DraggedTab>(|style| style.visible())
.on_drop(cx.listener( .drag_over::<ProjectEntryId>(|style| style.visible())
move |this, dragged_tab: &View<DraggedTab>, cx| { .on_drop(cx.listener(move |this, dragged_tab: &DraggedTab, cx| {
this.handle_split_tab_drop(dragged_tab, direction, cx) this.handle_split_tab_drop(dragged_tab, direction, cx)
}))
.on_drop(cx.listener(
move |this, entry_id: &ProjectEntryId, cx| {
this.handle_split_project_entry_drop(
entry_id, direction, cx,
)
}, },
)); ));
match direction { match direction {

View file

@ -16,7 +16,7 @@ const HANDLE_HITBOX_SIZE: f32 = 10.0; //todo!(change this back to 4)
const HORIZONTAL_MIN_SIZE: f32 = 80.; const HORIZONTAL_MIN_SIZE: f32 = 80.;
const VERTICAL_MIN_SIZE: f32 = 100.; const VERTICAL_MIN_SIZE: f32 = 100.;
#[derive(Clone, PartialEq)] #[derive(Clone)]
pub struct PaneGroup { pub struct PaneGroup {
pub(crate) root: Member, pub(crate) root: Member,
} }
@ -121,7 +121,7 @@ impl PaneGroup {
} }
} }
#[derive(Clone, PartialEq)] #[derive(Clone)]
pub(crate) enum Member { pub(crate) enum Member {
Axis(PaneAxis), Axis(PaneAxis),
Pane(View<Pane>), Pane(View<Pane>),
@ -426,12 +426,6 @@ pub(crate) struct PaneAxis {
pub bounding_boxes: Arc<Mutex<Vec<Option<Bounds<Pixels>>>>>, pub bounding_boxes: Arc<Mutex<Vec<Option<Bounds<Pixels>>>>>,
} }
impl PartialEq for PaneAxis {
fn eq(&self, other: &Self) -> bool {
todo!()
}
}
impl PaneAxis { impl PaneAxis {
pub fn new(axis: Axis, members: Vec<Member>) -> Self { pub fn new(axis: Axis, members: Vec<Member>) -> Self {
let flexes = Arc::new(Mutex::new(vec![1.; members.len()])); let flexes = Arc::new(Mutex::new(vec![1.; members.len()]));
@ -816,7 +810,7 @@ mod element {
proposed_current_pixel_change -= current_pixel_change; proposed_current_pixel_change -= current_pixel_change;
} }
// todo!(reserialize workspace) // todo!(schedule serialize)
// workspace.schedule_serialize(cx); // workspace.schedule_serialize(cx);
cx.notify(); cx.notify();
} }
@ -851,7 +845,7 @@ mod element {
cx.on_mouse_event({ cx.on_mouse_event({
let dragged_handle = dragged_handle.clone(); let dragged_handle = dragged_handle.clone();
move |e: &MouseDownEvent, phase, cx| { move |e: &MouseDownEvent, phase, _cx| {
if phase.bubble() && handle_bounds.contains(&e.position) { if phase.bubble() && handle_bounds.contains(&e.position) {
dragged_handle.replace(Some(ix)); dragged_handle.replace(Some(ix));
} }
@ -859,7 +853,7 @@ mod element {
}); });
cx.on_mouse_event(move |e: &MouseMoveEvent, phase, cx| { cx.on_mouse_event(move |e: &MouseMoveEvent, phase, cx| {
let dragged_handle = dragged_handle.borrow(); let dragged_handle = dragged_handle.borrow();
if *dragged_handle == Some(ix) { if phase.bubble() && *dragged_handle == Some(ix) {
Self::compute_resize(&flexes, e, ix, axis, axis_bounds, cx) Self::compute_resize(&flexes, e, ix, axis, axis_bounds, cx)
} }
}); });
@ -912,7 +906,7 @@ mod element {
let mut bounding_boxes = self.bounding_boxes.lock(); let mut bounding_boxes = self.bounding_boxes.lock();
bounding_boxes.clear(); bounding_boxes.clear();
for (ix, mut child) in self.children.iter_mut().enumerate() { for (ix, child) in self.children.iter_mut().enumerate() {
//todo!(active_pane_magnification) //todo!(active_pane_magnification)
// If usign active pane magnification, need to switch to using // If usign active pane magnification, need to switch to using
// 1 for all non-active panes, and then the magnification for the // 1 for all non-active panes, and then the magnification for the
@ -949,7 +943,7 @@ mod element {
cx.with_z_index(1, |cx| { cx.with_z_index(1, |cx| {
cx.on_mouse_event({ cx.on_mouse_event({
let state = state.clone(); let state = state.clone();
move |e: &MouseUpEvent, phase, cx| { move |_: &MouseUpEvent, phase, _cx| {
if phase.bubble() { if phase.bubble() {
state.replace(None); state.replace(None);
} }
@ -968,402 +962,4 @@ mod element {
fn flex_values_in_bounds(flexes: &[f32]) -> bool { fn flex_values_in_bounds(flexes: &[f32]) -> bool {
(flexes.iter().copied().sum::<f32>() - flexes.len() as f32).abs() < 0.001 (flexes.iter().copied().sum::<f32>() - flexes.len() as f32).abs() < 0.001
} }
// // use std::{cell::RefCell, iter::from_fn, ops::Range, rc::Rc};
// // use gpui::{
// // geometry::{
// // rect::Bounds<Pixels>,
// // vector::{vec2f, Vector2F},
// // },
// // json::{self, ToJson},
// // platform::{CursorStyle, MouseButton},
// // scene::MouseDrag,
// // AnyElement, Axis, CursorRegion, Element, EventContext, MouseRegion, Bounds<Pixels>Ext,
// // SizeConstraint, Vector2FExt, ViewContext,
// // };
// use crate::{
// pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE},
// Workspace, WorkspaceSettings,
// };
// pub struct PaneAxisElement {
// axis: Axis,
// basis: usize,
// active_pane_ix: Option<usize>,
// flexes: Rc<RefCell<Vec<f32>>>,
// children: Vec<AnyElement<Workspace>>,
// bounding_boxes: Rc<RefCell<Vec<Option<Bounds<Pixels>>>>>,
// }
// impl PaneAxisElement {
// pub fn new(
// axis: Axis,
// basis: usize,
// flexes: Rc<RefCell<Vec<f32>>>,
// bounding_boxes: Rc<RefCell<Vec<Option<Bounds<Pixels>>>>>,
// ) -> Self {
// Self {
// axis,
// basis,
// flexes,
// bounding_boxes,
// active_pane_ix: None,
// children: Default::default(),
// }
// }
// pub fn set_active_pane(&mut self, active_pane_ix: Option<usize>) {
// self.active_pane_ix = active_pane_ix;
// }
// fn layout_children(
// &mut self,
// active_pane_magnification: f32,
// constraint: SizeConstraint,
// remaining_space: &mut f32,
// remaining_flex: &mut f32,
// cross_axis_max: &mut f32,
// view: &mut Workspace,
// cx: &mut ViewContext<Workspace>,
// ) {
// let flexes = self.flexes.borrow();
// let cross_axis = self.axis.invert();
// for (ix, child) in self.children.iter_mut().enumerate() {
// let flex = if active_pane_magnification != 1. {
// if let Some(active_pane_ix) = self.active_pane_ix {
// if ix == active_pane_ix {
// active_pane_magnification
// } else {
// 1.
// }
// } else {
// 1.
// }
// } else {
// flexes[ix]
// };
// let child_size = if *remaining_flex == 0.0 {
// *remaining_space
// } else {
// let space_per_flex = *remaining_space / *remaining_flex;
// space_per_flex * flex
// };
// let child_constraint = match self.axis {
// Axis::Horizontal => SizeConstraint::new(
// vec2f(child_size, constraint.min.y()),
// vec2f(child_size, constraint.max.y()),
// ),
// Axis::Vertical => SizeConstraint::new(
// vec2f(constraint.min.x(), child_size),
// vec2f(constraint.max.x(), child_size),
// ),
// };
// let child_size = child.layout(child_constraint, view, cx);
// *remaining_space -= child_size.along(self.axis);
// *remaining_flex -= flex;
// *cross_axis_max = cross_axis_max.max(child_size.along(cross_axis));
// }
// }
// fn handle_resize(
// flexes: Rc<RefCell<Vec<f32>>>,
// axis: Axis,
// preceding_ix: usize,
// child_start: Vector2F,
// drag_bounds: Bounds<Pixels>,
// ) -> impl Fn(MouseDrag, &mut Workspace, &mut EventContext<Workspace>) {
// let size = move |ix, flexes: &[f32]| {
// drag_bounds.length_along(axis) * (flexes[ix] / flexes.len() as f32)
// };
// move |drag, workspace: &mut Workspace, cx| {
// if drag.end {
// // TODO: Clear cascading resize state
// return;
// }
// let min_size = match axis {
// Axis::Horizontal => HORIZONTAL_MIN_SIZE,
// Axis::Vertical => VERTICAL_MIN_SIZE,
// };
// let mut flexes = flexes.borrow_mut();
// // Don't allow resizing to less than the minimum size, if elements are already too small
// if min_size - 1. > size(preceding_ix, flexes.as_slice()) {
// return;
// }
// let mut proposed_current_pixel_change = (drag.position - child_start).along(axis)
// - size(preceding_ix, flexes.as_slice());
// let flex_changes = |pixel_dx, target_ix, next: isize, flexes: &[f32]| {
// let flex_change = pixel_dx / drag_bounds.length_along(axis);
// let current_target_flex = flexes[target_ix] + flex_change;
// let next_target_flex =
// flexes[(target_ix as isize + next) as usize] - flex_change;
// (current_target_flex, next_target_flex)
// };
// let mut successors = from_fn({
// let forward = proposed_current_pixel_change > 0.;
// let mut ix_offset = 0;
// let len = flexes.len();
// move || {
// let result = if forward {
// (preceding_ix + 1 + ix_offset < len).then(|| preceding_ix + ix_offset)
// } else {
// (preceding_ix as isize - ix_offset as isize >= 0)
// .then(|| preceding_ix - ix_offset)
// };
// ix_offset += 1;
// result
// }
// });
// while proposed_current_pixel_change.abs() > 0. {
// let Some(current_ix) = successors.next() else {
// break;
// };
// let next_target_size = f32::max(
// size(current_ix + 1, flexes.as_slice()) - proposed_current_pixel_change,
// min_size,
// );
// let current_target_size = f32::max(
// size(current_ix, flexes.as_slice())
// + size(current_ix + 1, flexes.as_slice())
// - next_target_size,
// min_size,
// );
// let current_pixel_change =
// current_target_size - size(current_ix, flexes.as_slice());
// let (current_target_flex, next_target_flex) =
// flex_changes(current_pixel_change, current_ix, 1, flexes.as_slice());
// flexes[current_ix] = current_target_flex;
// flexes[current_ix + 1] = next_target_flex;
// proposed_current_pixel_change -= current_pixel_change;
// }
// workspace.schedule_serialize(cx);
// cx.notify();
// }
// }
// }
// impl Extend<AnyElement<Workspace>> for PaneAxisElement {
// fn extend<T: IntoIterator<Item = AnyElement<Workspace>>>(&mut self, children: T) {
// self.children.extend(children);
// }
// }
// impl Element<Workspace> for PaneAxisElement {
// type LayoutState = f32;
// type PaintState = ();
// fn layout(
// &mut self,
// constraint: SizeConstraint,
// view: &mut Workspace,
// cx: &mut ViewContext<Workspace>,
// ) -> (Vector2F, Self::LayoutState) {
// debug_assert!(self.children.len() == self.flexes.borrow().len());
// let active_pane_magnification =
// settings::get::<WorkspaceSettings>(cx).active_pane_magnification;
// let mut remaining_flex = 0.;
// if active_pane_magnification != 1. {
// let active_pane_flex = self
// .active_pane_ix
// .map(|_| active_pane_magnification)
// .unwrap_or(1.);
// remaining_flex += self.children.len() as f32 - 1. + active_pane_flex;
// } else {
// for flex in self.flexes.borrow().iter() {
// remaining_flex += flex;
// }
// }
// let mut cross_axis_max: f32 = 0.0;
// let mut remaining_space = constraint.max_along(self.axis);
// if remaining_space.is_infinite() {
// panic!("flex contains flexible children but has an infinite constraint along the flex axis");
// }
// self.layout_children(
// active_pane_magnification,
// constraint,
// &mut remaining_space,
// &mut remaining_flex,
// &mut cross_axis_max,
// view,
// cx,
// );
// let mut size = match self.axis {
// Axis::Horizontal => vec2f(constraint.max.x() - remaining_space, cross_axis_max),
// Axis::Vertical => vec2f(cross_axis_max, constraint.max.y() - remaining_space),
// };
// if constraint.min.x().is_finite() {
// size.set_x(size.x().max(constraint.min.x()));
// }
// if constraint.min.y().is_finite() {
// size.set_y(size.y().max(constraint.min.y()));
// }
// if size.x() > constraint.max.x() {
// size.set_x(constraint.max.x());
// }
// if size.y() > constraint.max.y() {
// size.set_y(constraint.max.y());
// }
// (size, remaining_space)
// }
// fn paint(
// &mut self,
// bounds: Bounds<Pixels>,
// visible_bounds: Bounds<Pixels>,
// remaining_space: &mut Self::LayoutState,
// view: &mut Workspace,
// cx: &mut ViewContext<Workspace>,
// ) -> Self::PaintState {
// let can_resize = settings::get::<WorkspaceSettings>(cx).active_pane_magnification == 1.;
// let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
// let overflowing = *remaining_space < 0.;
// if overflowing {
// cx.scene().push_layer(Some(visible_bounds));
// }
// let mut child_origin = bounds.origin();
// let mut bounding_boxes = self.bounding_boxes.borrow_mut();
// bounding_boxes.clear();
// let mut children_iter = self.children.iter_mut().enumerate().peekable();
// while let Some((ix, child)) = children_iter.next() {
// let child_start = child_origin.clone();
// child.paint(child_origin, visible_bounds, view, cx);
// bounding_boxes.push(Some(Bounds<Pixels>::new(child_origin, child.size())));
// match self.axis {
// Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0),
// Axis::Vertical => child_origin += vec2f(0.0, child.size().y()),
// }
// if can_resize && children_iter.peek().is_some() {
// cx.scene().push_stacking_context(None, None);
// let handle_origin = match self.axis {
// Axis::Horizontal => child_origin - vec2f(HANDLE_HITBOX_SIZE / 2., 0.0),
// Axis::Vertical => child_origin - vec2f(0.0, HANDLE_HITBOX_SIZE / 2.),
// };
// let handle_bounds = match self.axis {
// Axis::Horizontal => Bounds<Pixels>::new(
// handle_origin,
// vec2f(HANDLE_HITBOX_SIZE, visible_bounds.height()),
// ),
// Axis::Vertical => Bounds<Pixels>::new(
// handle_origin,
// vec2f(visible_bounds.width(), HANDLE_HITBOX_SIZE),
// ),
// };
// let style = match self.axis {
// Axis::Horizontal => CursorStyle::ResizeLeftRight,
// Axis::Vertical => CursorStyle::ResizeUpDown,
// };
// cx.scene().push_cursor_region(CursorRegion {
// bounds: handle_bounds,
// style,
// });
// enum ResizeHandle {}
// let mut mouse_region = MouseRegion::new::<ResizeHandle>(
// cx.view_id(),
// self.basis + ix,
// handle_bounds,
// );
// mouse_region = mouse_region
// .on_drag(
// MouseButton::Left,
// Self::handle_resize(
// self.flexes.clone(),
// self.axis,
// ix,
// child_start,
// visible_bounds.clone(),
// ),
// )
// .on_click(MouseButton::Left, {
// let flexes = self.flexes.clone();
// move |e, v: &mut Workspace, cx| {
// if e.click_count >= 2 {
// let mut borrow = flexes.borrow_mut();
// *borrow = vec![1.; borrow.len()];
// v.schedule_serialize(cx);
// cx.notify();
// }
// }
// });
// cx.scene().push_mouse_region(mouse_region);
// cx.scene().pop_stacking_context();
// }
// }
// if overflowing {
// cx.scene().pop_layer();
// }
// }
// fn rect_for_text_range(
// &self,
// range_utf16: Range<usize>,
// _: Bounds<Pixels>,
// _: Bounds<Pixels>,
// _: &Self::LayoutState,
// _: &Self::PaintState,
// view: &Workspace,
// cx: &ViewContext<Workspace>,
// ) -> Option<Bounds<Pixels>> {
// self.children
// .iter()
// .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx))
// }
// fn debug(
// &self,
// bounds: Bounds<Pixels>,
// _: &Self::LayoutState,
// _: &Self::PaintState,
// view: &Workspace,
// cx: &ViewContext<Workspace>,
// ) -> json::Value {
// serde_json::json!({
// "type": "PaneAxis",
// "bounds": bounds.to_json(),
// "axis": self.axis.to_json(),
// "flexes": *self.flexes.borrow(),
// "children": self.children.iter().map(|child| child.debug(view, cx)).collect::<Vec<json::Value>>()
// })
// }
// }
} }

View file

@ -193,7 +193,7 @@ impl<T: SearchableItem> SearchableItemHandle for View<T> {
cx: &mut WindowContext, cx: &mut WindowContext,
) -> Task<Vec<Box<dyn Any + Send>>> { ) -> Task<Vec<Box<dyn Any + Send>>> {
let matches = self.update(cx, |this, cx| this.find_matches(query, cx)); let matches = self.update(cx, |this, cx| this.find_matches(query, cx));
cx.spawn(|cx| async { cx.spawn(|_| async {
let matches = matches.await; let matches = matches.await;
matches matches
.into_iter() .into_iter()
@ -253,7 +253,7 @@ pub trait WeakSearchableItemHandle: WeakItemHandle {
} }
impl<T: SearchableItem> WeakSearchableItemHandle for WeakView<T> { impl<T: SearchableItem> WeakSearchableItemHandle for WeakView<T> {
fn upgrade(&self, cx: &AppContext) -> Option<Box<dyn SearchableItemHandle>> { fn upgrade(&self, _cx: &AppContext) -> Option<Box<dyn SearchableItemHandle>> {
Some(Box::new(self.upgrade()?)) Some(Box::new(self.upgrade()?))
} }

View file

@ -51,14 +51,14 @@ impl Render for StatusBar {
} }
impl StatusBar { impl StatusBar {
fn render_left_tools(&self, cx: &mut ViewContext<Self>) -> impl IntoElement { fn render_left_tools(&self, _: &mut ViewContext<Self>) -> impl IntoElement {
h_stack() h_stack()
.items_center() .items_center()
.gap_2() .gap_2()
.children(self.left_items.iter().map(|item| item.to_any())) .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, _: &mut ViewContext<Self>) -> impl IntoElement {
h_stack() h_stack()
.items_center() .items_center()
.gap_2() .gap_2()

View file

@ -109,8 +109,22 @@ impl Render for Toolbar {
.child( .child(
h_stack() h_stack()
.justify_between() .justify_between()
.child(h_stack().children(self.left_items().map(|item| item.to_any()))) .when(self.left_items().count() > 0, |this| {
.child(h_stack().children(self.right_items().map(|item| item.to_any()))), this.child(
h_stack()
.flex_1()
.justify_start()
.children(self.left_items().map(|item| item.to_any())),
)
})
.when(self.right_items().count() > 0, |this| {
this.child(
h_stack()
.flex_1()
.justify_end()
.children(self.right_items().map(|item| item.to_any())),
)
}),
) )
.children(secondary_item) .children(secondary_item)
} }

View file

@ -1,15 +1,11 @@
#![allow(unused_variables, dead_code, unused_mut)]
// todo!() this is to make transition easier.
pub mod dock; pub mod dock;
pub mod item; pub mod item;
mod modal_layer;
pub mod notifications; pub mod notifications;
pub mod pane; pub mod pane;
pub mod pane_group; pub mod pane_group;
mod persistence; mod persistence;
pub mod searchable; pub mod searchable;
// todo!()
mod modal_layer;
pub mod shared_screen; pub mod shared_screen;
mod status_bar; mod status_bar;
mod toolbar; mod toolbar;
@ -236,14 +232,14 @@ pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
cx.on_action({ cx.on_action({
let app_state = Arc::downgrade(&app_state); let app_state = Arc::downgrade(&app_state);
move |_: &Open, cx: &mut AppContext| { move |_: &Open, cx: &mut AppContext| {
let mut paths = cx.prompt_for_paths(PathPromptOptions { let paths = cx.prompt_for_paths(PathPromptOptions {
files: true, files: true,
directories: true, directories: true,
multiple: true, multiple: true,
}); });
if let Some(app_state) = app_state.upgrade() { if let Some(app_state) = app_state.upgrade() {
cx.spawn(move |mut cx| async move { cx.spawn(move |cx| async move {
if let Some(paths) = paths.await.log_err().flatten() { if let Some(paths) = paths.await.log_err().flatten() {
cx.update(|cx| { cx.update(|cx| {
open_paths(&paths, &app_state, None, cx).detach_and_log_err(cx) open_paths(&paths, &app_state, None, cx).detach_and_log_err(cx)
@ -458,7 +454,7 @@ pub struct Workspace {
leader_updates_tx: mpsc::UnboundedSender<(PeerId, proto::UpdateFollowers)>, leader_updates_tx: mpsc::UnboundedSender<(PeerId, proto::UpdateFollowers)>,
database_id: WorkspaceId, database_id: WorkspaceId,
app_state: Arc<AppState>, app_state: Arc<AppState>,
subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
_apply_leader_updates: Task<Result<()>>, _apply_leader_updates: Task<Result<()>>,
_observe_current_user: Task<Result<()>>, _observe_current_user: Task<Result<()>>,
_schedule_serialize: Option<Task<()>>, _schedule_serialize: Option<Task<()>>,
@ -590,12 +586,9 @@ impl Workspace {
let left_dock = cx.build_view(|cx| Dock::new(DockPosition::Left, cx)); let left_dock = cx.build_view(|cx| Dock::new(DockPosition::Left, cx));
let bottom_dock = cx.build_view(|cx| Dock::new(DockPosition::Bottom, cx)); let bottom_dock = cx.build_view(|cx| Dock::new(DockPosition::Bottom, cx));
let right_dock = cx.build_view(|cx| Dock::new(DockPosition::Right, cx)); let right_dock = cx.build_view(|cx| Dock::new(DockPosition::Right, cx));
let left_dock_buttons = let left_dock_buttons = cx.build_view(|cx| PanelButtons::new(left_dock.clone(), cx));
cx.build_view(|cx| PanelButtons::new(left_dock.clone(), weak_handle.clone(), cx)); let bottom_dock_buttons = cx.build_view(|cx| PanelButtons::new(bottom_dock.clone(), cx));
let bottom_dock_buttons = let right_dock_buttons = cx.build_view(|cx| PanelButtons::new(right_dock.clone(), cx));
cx.build_view(|cx| PanelButtons::new(bottom_dock.clone(), weak_handle.clone(), cx));
let right_dock_buttons =
cx.build_view(|cx| PanelButtons::new(right_dock.clone(), weak_handle.clone(), cx));
let status_bar = cx.build_view(|cx| { let status_bar = cx.build_view(|cx| {
let mut status_bar = StatusBar::new(&center_pane.clone(), cx); let mut status_bar = StatusBar::new(&center_pane.clone(), cx);
status_bar.add_left_item(left_dock_buttons, cx); status_bar.add_left_item(left_dock_buttons, cx);
@ -604,8 +597,7 @@ impl Workspace {
status_bar status_bar
}); });
let workspace_handle = cx.view().downgrade(); let modal_layer = cx.build_view(|_| ModalLayer::new());
let modal_layer = cx.build_view(|cx| ModalLayer::new());
// todo!() // todo!()
// cx.update_default_global::<DragAndDrop<Workspace>, _, _>(|drag_and_drop, _| { // cx.update_default_global::<DragAndDrop<Workspace>, _, _>(|drag_and_drop, _| {
@ -703,7 +695,7 @@ impl Workspace {
_apply_leader_updates, _apply_leader_updates,
_schedule_serialize: None, _schedule_serialize: None,
leader_updates_tx, leader_updates_tx,
subscriptions, _subscriptions: subscriptions,
pane_history_timestamp, pane_history_timestamp,
workspace_actions: Default::default(), workspace_actions: Default::default(),
// This data will be incorrect, but it will be overwritten by the time it needs to be used. // This data will be incorrect, but it will be overwritten by the time it needs to be used.
@ -763,7 +755,7 @@ impl Workspace {
}; };
let window = if let Some(window) = requesting_window { let window = if let Some(window) = requesting_window {
cx.update_window(window.into(), |old_workspace, cx| { cx.update_window(window.into(), |_, cx| {
cx.replace_root_view(|cx| { cx.replace_root_view(|cx| {
Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx) Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx)
}); });
@ -1185,8 +1177,7 @@ impl Workspace {
} }
fn save_all(&mut self, action: &SaveAll, cx: &mut ViewContext<Self>) { fn save_all(&mut self, action: &SaveAll, cx: &mut ViewContext<Self>) {
let save_all = self self.save_all_internal(action.save_intent.unwrap_or(SaveIntent::SaveAll), cx)
.save_all_internal(action.save_intent.unwrap_or(SaveIntent::SaveAll), cx)
.detach_and_log_err(cx); .detach_and_log_err(cx);
} }
@ -1216,7 +1207,7 @@ impl Workspace {
cx.spawn(|workspace, mut cx| async move { cx.spawn(|workspace, mut cx| async move {
// Override save mode and display "Save all files" prompt // Override save mode and display "Save all files" prompt
if save_intent == SaveIntent::Close && dirty_items.len() > 1 { if save_intent == SaveIntent::Close && dirty_items.len() > 1 {
let mut answer = workspace.update(&mut cx, |_, cx| { let answer = workspace.update(&mut cx, |_, cx| {
let prompt = Pane::file_names_for_prompt( let prompt = Pane::file_names_for_prompt(
&mut dirty_items.iter().map(|(_, handle)| handle), &mut dirty_items.iter().map(|(_, handle)| handle),
dirty_items.len(), dirty_items.len(),
@ -1261,7 +1252,7 @@ impl Workspace {
} }
pub fn open(&mut self, _: &Open, cx: &mut ViewContext<Self>) { pub fn open(&mut self, _: &Open, cx: &mut ViewContext<Self>) {
let mut paths = cx.prompt_for_paths(PathPromptOptions { let paths = cx.prompt_for_paths(PathPromptOptions {
files: true, files: true,
directories: true, directories: true,
multiple: true, multiple: true,
@ -1390,7 +1381,7 @@ impl Workspace {
} }
fn add_folder_to_project(&mut self, _: &AddFolderToProject, cx: &mut ViewContext<Self>) { fn add_folder_to_project(&mut self, _: &AddFolderToProject, cx: &mut ViewContext<Self>) {
let mut paths = cx.prompt_for_paths(PathPromptOptions { let paths = cx.prompt_for_paths(PathPromptOptions {
files: false, files: false,
directories: true, directories: true,
multiple: true, multiple: true,
@ -1670,6 +1661,8 @@ impl Workspace {
None None
} }
// todo!("implement zoom")
#[allow(unused)]
fn zoom_out(&mut self, cx: &mut ViewContext<Self>) { fn zoom_out(&mut self, cx: &mut ViewContext<Self>) {
for pane in &self.panes { for pane in &self.panes {
pane.update(cx, |pane, cx| pane.set_zoomed(false, cx)); pane.update(cx, |pane, cx| pane.set_zoomed(false, cx));
@ -2043,20 +2036,20 @@ impl Workspace {
_ => bounding_box.center(), _ => bounding_box.center(),
}; };
let distance_to_next = 1.; //todo(pane dividers styling) let distance_to_next = 8.; //todo(pane dividers styling)
let target = match direction { let target = match direction {
SplitDirection::Left => { SplitDirection::Left => {
Point::new(bounding_box.origin.x - distance_to_next.into(), center.y) Point::new(bounding_box.left() - distance_to_next.into(), center.y)
} }
SplitDirection::Right => { SplitDirection::Right => {
Point::new(bounding_box.right() + distance_to_next.into(), center.y) Point::new(bounding_box.right() + distance_to_next.into(), center.y)
} }
SplitDirection::Up => { SplitDirection::Up => {
Point::new(center.x, bounding_box.origin.y - distance_to_next.into()) Point::new(center.x, bounding_box.top() - distance_to_next.into())
} }
SplitDirection::Down => { SplitDirection::Down => {
Point::new(center.x, bounding_box.top() + distance_to_next.into()) Point::new(center.x, bounding_box.bottom() + distance_to_next.into())
} }
}; };
self.center.pane_at_pixel_position(target) self.center.pane_at_pixel_position(target)
@ -2574,7 +2567,7 @@ impl Workspace {
// } // }
// } // }
fn render_notifications(&self, cx: &ViewContext<Self>) -> Option<Div> { fn render_notifications(&self, _cx: &ViewContext<Self>) -> Option<Div> {
if self.notifications.is_empty() { if self.notifications.is_empty() {
None None
} else { } else {
@ -3005,6 +2998,7 @@ impl Workspace {
cx.notify(); cx.notify();
} }
#[allow(unused)]
fn schedule_serialize(&mut self, cx: &mut ViewContext<Self>) { fn schedule_serialize(&mut self, cx: &mut ViewContext<Self>) {
self._schedule_serialize = Some(cx.spawn(|this, mut cx| async move { self._schedule_serialize = Some(cx.spawn(|this, mut cx| async move {
cx.background_executor() cx.background_executor()
@ -3143,12 +3137,7 @@ impl Workspace {
cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
) -> Task<Result<Vec<Option<Box<dyn ItemHandle>>>>> { ) -> Task<Result<Vec<Option<Box<dyn ItemHandle>>>>> {
cx.spawn(|workspace, mut cx| async move { cx.spawn(|workspace, mut cx| async move {
let (project, old_center_pane) = workspace.update(&mut cx, |workspace, _| { let project = workspace.update(&mut cx, |workspace, _| workspace.project().clone())?;
(
workspace.project().clone(),
workspace.last_active_center_pane.clone(),
)
})?;
let mut center_group = None; let mut center_group = None;
let mut center_items = None; let mut center_items = None;
@ -3293,7 +3282,7 @@ impl Workspace {
.on_action(cx.listener(|workspace, action: &SwapPaneInDirection, cx| { .on_action(cx.listener(|workspace, action: &SwapPaneInDirection, cx| {
workspace.swap_pane_in_direction(action.0, cx) workspace.swap_pane_in_direction(action.0, cx)
})) }))
.on_action(cx.listener(|this, e: &ToggleLeftDock, cx| { .on_action(cx.listener(|this, _: &ToggleLeftDock, cx| {
this.toggle_dock(DockPosition::Left, cx); this.toggle_dock(DockPosition::Left, cx);
})) }))
.on_action( .on_action(
@ -3313,42 +3302,12 @@ impl Workspace {
) )
.on_action(cx.listener(Workspace::open)) .on_action(cx.listener(Workspace::open))
.on_action(cx.listener(Workspace::close_window)) .on_action(cx.listener(Workspace::close_window))
.on_action(cx.listener(Workspace::activate_pane_at_index))
// cx.add_action(Workspace::activate_pane_at_index); .on_action(
// cx.add_action(|workspace: &mut Workspace, _: &ReopenClosedItem, cx| { cx.listener(|workspace: &mut Workspace, _: &ReopenClosedItem, cx| {
// workspace.reopen_closed_item(cx).detach(); workspace.reopen_closed_item(cx).detach();
// }); }),
// cx.add_action(|workspace: &mut Workspace, _: &GoBack, cx| { )
// workspace
// .go_back(workspace.active_pane().downgrade(), cx)
// .detach();
// });
// cx.add_action(|workspace: &mut Workspace, _: &GoForward, cx| {
// workspace
// .go_forward(workspace.active_pane().downgrade(), cx)
// .detach();
// });
// cx.add_action(|_: &mut Workspace, _: &install_cli::Install, cx| {
// cx.spawn(|workspace, mut cx| async move {
// let err = install_cli::install_cli(&cx)
// .await
// .context("Failed to create CLI symlink");
// workspace.update(&mut cx, |workspace, cx| {
// if matches!(err, Err(_)) {
// err.notify_err(workspace, cx);
// } else {
// workspace.show_notification(1, cx, |cx| {
// cx.build_view(|_| {
// MessageNotification::new("Successfully installed the `zed` binary")
// })
// });
// }
// })
// })
// .detach();
// });
} }
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
@ -3418,7 +3377,7 @@ impl Workspace {
self self
} }
fn add_workspace_actions_listeners(&self, mut div: Div, cx: &mut ViewContext<Self>) -> Div { fn add_workspace_actions_listeners(&self, div: Div, cx: &mut ViewContext<Self>) -> Div {
let mut div = div let mut div = div
.on_action(cx.listener(Self::close_inactive_items_and_panes)) .on_action(cx.listener(Self::close_inactive_items_and_panes))
.on_action(cx.listener(Self::close_all_items_and_panes)) .on_action(cx.listener(Self::close_all_items_and_panes))
@ -3578,9 +3537,7 @@ impl FocusableView for Workspace {
} }
} }
struct WorkspaceBounds(Bounds<Pixels>); #[derive(Clone, Render)]
#[derive(Render)]
struct DraggedDock(DockPosition); struct DraggedDock(DockPosition);
impl Render for Workspace { impl Render for Workspace {
@ -3628,7 +3585,7 @@ impl Render for Workspace {
.border_b() .border_b()
.border_color(cx.theme().colors().border) .border_color(cx.theme().colors().border)
.child( .child(
canvas(cx.listener(|workspace, bounds, cx| { canvas(cx.listener(|workspace, bounds, _| {
workspace.bounds = *bounds; workspace.bounds = *bounds;
})) }))
.absolute() .absolute()
@ -3636,7 +3593,7 @@ impl Render for Workspace {
) )
.on_drag_move( .on_drag_move(
cx.listener(|workspace, e: &DragMoveEvent<DraggedDock>, cx| { cx.listener(|workspace, e: &DragMoveEvent<DraggedDock>, cx| {
match e.drag.read(cx).0 { match e.drag(cx).0 {
DockPosition::Left => { DockPosition::Left => {
let size = workspace.bounds.left() + e.event.position.x; let size = workspace.bounds.left() + e.event.position.x;
workspace.left_dock.update(cx, |left_dock, cx| { workspace.left_dock.update(cx, |left_dock, cx| {
@ -4056,7 +4013,7 @@ async fn join_channel_internal(
active_call: &Model<ActiveCall>, active_call: &Model<ActiveCall>,
cx: &mut AsyncAppContext, cx: &mut AsyncAppContext,
) -> Result<bool> { ) -> Result<bool> {
let (should_prompt, open_room) = active_call.read_with(cx, |active_call, cx| { let (should_prompt, open_room) = active_call.update(cx, |active_call, cx| {
let Some(room) = active_call.room().map(|room| room.read(cx)) else { let Some(room) = active_call.room().map(|room| room.read(cx)) else {
return (false, None); return (false, None);
}; };
@ -4421,7 +4378,7 @@ pub fn restart(_: &Restart, cx: &mut AppContext) {
} }
cx.spawn(|mut cx| async move { cx.spawn(|mut cx| async move {
if let Some(mut prompt) = prompt { if let Some(prompt) = prompt {
let answer = prompt.await?; let answer = prompt.await?;
if answer != 0 { if answer != 0 {
return Ok(()); return Ok(());
@ -4460,6 +4417,8 @@ fn parse_pixel_size_env_var(value: &str) -> Option<Size<GlobalPixels>> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::{cell::RefCell, rc::Rc};
use super::*; use super::*;
use crate::item::{ use crate::item::{
test::{TestItem, TestProjectItem}, test::{TestItem, TestProjectItem},
@ -4470,7 +4429,6 @@ mod tests {
use project::{Project, ProjectEntryId}; use project::{Project, ProjectEntryId};
use serde_json::json; use serde_json::json;
use settings::SettingsStore; use settings::SettingsStore;
use std::{cell::RefCell, rc::Rc};
#[gpui::test] #[gpui::test]
async fn test_tab_disambiguation(cx: &mut TestAppContext) { async fn test_tab_disambiguation(cx: &mut TestAppContext) {
@ -4544,7 +4502,7 @@ mod tests {
let project = Project::test(fs, ["root1".as_ref()], cx).await; let project = Project::test(fs, ["root1".as_ref()], cx).await;
let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx)); let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone()); let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone());
let worktree_id = project.read_with(cx, |project, cx| { let worktree_id = project.update(cx, |project, cx| {
project.worktrees().next().unwrap().read(cx).id() project.worktrees().next().unwrap().read(cx).id()
}); });
@ -4557,7 +4515,7 @@ mod tests {
// Add an item to an empty pane // Add an item to an empty pane
workspace.update(cx, |workspace, cx| workspace.add_item(Box::new(item1), cx)); workspace.update(cx, |workspace, cx| workspace.add_item(Box::new(item1), cx));
project.read_with(cx, |project, cx| { project.update(cx, |project, cx| {
assert_eq!( assert_eq!(
project.active_entry(), project.active_entry(),
project project
@ -4570,7 +4528,7 @@ mod tests {
// Add a second item to a non-empty pane // Add a second item to a non-empty pane
workspace.update(cx, |workspace, cx| workspace.add_item(Box::new(item2), cx)); workspace.update(cx, |workspace, cx| workspace.add_item(Box::new(item2), cx));
assert_eq!(cx.window_title().as_deref(), Some("two.txt — root1")); assert_eq!(cx.window_title().as_deref(), Some("two.txt — root1"));
project.read_with(cx, |project, cx| { project.update(cx, |project, cx| {
assert_eq!( assert_eq!(
project.active_entry(), project.active_entry(),
project project
@ -4586,7 +4544,7 @@ mod tests {
.await .await
.unwrap(); .unwrap();
assert_eq!(cx.window_title().as_deref(), Some("one.txt — root1")); assert_eq!(cx.window_title().as_deref(), Some("one.txt — root1"));
project.read_with(cx, |project, cx| { project.update(cx, |project, cx| {
assert_eq!( assert_eq!(
project.active_entry(), project.active_entry(),
project project
@ -4970,14 +4928,14 @@ mod tests {
item.is_dirty = true; item.is_dirty = true;
cx.blur(); cx.blur();
}); });
cx.executor().run_until_parked(); cx.run_until_parked();
item.update(cx, |item, _| assert_eq!(item.save_count, 5)); item.update(cx, |item, _| assert_eq!(item.save_count, 5));
// Ensure autosave is prevented for deleted files also when closing the buffer. // Ensure autosave is prevented for deleted files also when closing the buffer.
let _close_items = pane.update(cx, |pane, cx| { let _close_items = pane.update(cx, |pane, cx| {
pane.close_items(cx, SaveIntent::Close, move |id| id == item_id) pane.close_items(cx, SaveIntent::Close, move |id| id == item_id)
}); });
cx.executor().run_until_parked(); cx.run_until_parked();
assert!(cx.has_pending_prompt()); assert!(cx.has_pending_prompt());
item.update(cx, |item, _| assert_eq!(item.save_count, 5)); item.update(cx, |item, _| assert_eq!(item.save_count, 5));
} }
@ -5042,11 +5000,10 @@ mod tests {
// let fs = FakeFs::new(cx.executor()); // let fs = FakeFs::new(cx.executor());
// let project = Project::test(fs, [], cx).await; // let project = Project::test(fs, [], cx).await;
// let window = cx.add_window(|cx| Workspace::test_new(project, cx)); // let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project, cx));
// let workspace = window.root(cx);
// let panel = workspace.update(cx, |workspace, cx| { // let panel = workspace.update(cx, |workspace, cx| {
// let panel = cx.build_view(|_| TestPanel::new(DockPosition::Right)); // let panel = cx.build_view(|cx| TestPanel::new(DockPosition::Right, cx));
// workspace.add_panel(panel.clone(), cx); // workspace.add_panel(panel.clone(), cx);
// workspace // workspace
@ -5058,7 +5015,7 @@ mod tests {
// let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone()); // let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone());
// pane.update(cx, |pane, cx| { // pane.update(cx, |pane, cx| {
// let item = cx.build_view(|_| TestItem::new(cx)); // let item = cx.build_view(|cx| TestItem::new(cx));
// pane.add_item(Box::new(item), true, true, None, cx); // pane.add_item(Box::new(item), true, true, None, cx);
// }); // });
@ -5070,7 +5027,7 @@ mod tests {
// workspace.update(cx, |workspace, cx| { // workspace.update(cx, |workspace, cx| {
// assert!(workspace.right_dock().read(cx).is_open()); // assert!(workspace.right_dock().read(cx).is_open());
// assert!(!panel.is_zoomed(cx)); // assert!(!panel.is_zoomed(cx));
// assert!(panel.has_focus(cx)); // assert!(panel.read(cx).focus_handle(cx).contains_focused(cx));
// }); // });
// // Transfer focus from panel to center // // Transfer focus from panel to center
@ -5081,7 +5038,7 @@ mod tests {
// workspace.update(cx, |workspace, cx| { // workspace.update(cx, |workspace, cx| {
// assert!(workspace.right_dock().read(cx).is_open()); // assert!(workspace.right_dock().read(cx).is_open());
// assert!(!panel.is_zoomed(cx)); // assert!(!panel.is_zoomed(cx));
// assert!(!panel.has_focus(cx)); // assert!(!panel.read(cx).focus_handle(cx).contains_focused(cx));
// }); // });
// // Close the dock // // Close the dock
@ -5092,7 +5049,7 @@ mod tests {
// workspace.update(cx, |workspace, cx| { // workspace.update(cx, |workspace, cx| {
// assert!(!workspace.right_dock().read(cx).is_open()); // assert!(!workspace.right_dock().read(cx).is_open());
// assert!(!panel.is_zoomed(cx)); // assert!(!panel.is_zoomed(cx));
// assert!(!panel.has_focus(cx)); // assert!(!panel.read(cx).focus_handle(cx).contains_focused(cx));
// }); // });
// // Open the dock // // Open the dock
@ -5103,7 +5060,7 @@ mod tests {
// workspace.update(cx, |workspace, cx| { // workspace.update(cx, |workspace, cx| {
// assert!(workspace.right_dock().read(cx).is_open()); // assert!(workspace.right_dock().read(cx).is_open());
// assert!(!panel.is_zoomed(cx)); // assert!(!panel.is_zoomed(cx));
// assert!(panel.has_focus(cx)); // assert!(panel.read(cx).focus_handle(cx).contains_focused(cx));
// }); // });
// // Focus and zoom panel // // Focus and zoom panel
@ -5115,7 +5072,7 @@ mod tests {
// workspace.update(cx, |workspace, cx| { // workspace.update(cx, |workspace, cx| {
// assert!(workspace.right_dock().read(cx).is_open()); // assert!(workspace.right_dock().read(cx).is_open());
// assert!(panel.is_zoomed(cx)); // assert!(panel.is_zoomed(cx));
// assert!(panel.has_focus(cx)); // assert!(panel.read(cx).focus_handle(cx).contains_focused(cx));
// }); // });
// // Transfer focus to the center closes the dock // // Transfer focus to the center closes the dock
@ -5126,7 +5083,7 @@ mod tests {
// workspace.update(cx, |workspace, cx| { // workspace.update(cx, |workspace, cx| {
// assert!(!workspace.right_dock().read(cx).is_open()); // assert!(!workspace.right_dock().read(cx).is_open());
// assert!(panel.is_zoomed(cx)); // assert!(panel.is_zoomed(cx));
// assert!(!panel.has_focus(cx)); // assert!(!panel.read(cx).focus_handle(cx).contains_focused(cx));
// }); // });
// // Transferring focus back to the panel keeps it zoomed // // Transferring focus back to the panel keeps it zoomed
@ -5137,7 +5094,7 @@ mod tests {
// workspace.update(cx, |workspace, cx| { // workspace.update(cx, |workspace, cx| {
// assert!(workspace.right_dock().read(cx).is_open()); // assert!(workspace.right_dock().read(cx).is_open());
// assert!(panel.is_zoomed(cx)); // assert!(panel.is_zoomed(cx));
// assert!(panel.has_focus(cx)); // assert!(panel.read(cx).focus_handle(cx).contains_focused(cx));
// }); // });
// // Close the dock while it is zoomed // // Close the dock while it is zoomed
@ -5149,7 +5106,7 @@ mod tests {
// assert!(!workspace.right_dock().read(cx).is_open()); // assert!(!workspace.right_dock().read(cx).is_open());
// assert!(panel.is_zoomed(cx)); // assert!(panel.is_zoomed(cx));
// assert!(workspace.zoomed.is_none()); // assert!(workspace.zoomed.is_none());
// assert!(!panel.has_focus(cx)); // assert!(!panel.read(cx).focus_handle(cx).contains_focused(cx));
// }); // });
// // Opening the dock, when it's zoomed, retains focus // // Opening the dock, when it's zoomed, retains focus
@ -5161,7 +5118,7 @@ mod tests {
// assert!(workspace.right_dock().read(cx).is_open()); // assert!(workspace.right_dock().read(cx).is_open());
// assert!(panel.is_zoomed(cx)); // assert!(panel.is_zoomed(cx));
// assert!(workspace.zoomed.is_some()); // assert!(workspace.zoomed.is_some());
// assert!(panel.has_focus(cx)); // assert!(panel.read(cx).focus_handle(cx).contains_focused(cx));
// }); // });
// // Unzoom and close the panel, zoom the active pane. // // Unzoom and close the panel, zoom the active pane.
@ -5178,7 +5135,7 @@ mod tests {
// workspace.update(cx, |workspace, cx| { // workspace.update(cx, |workspace, cx| {
// let pane = pane.read(cx); // let pane = pane.read(cx);
// assert!(!pane.is_zoomed()); // assert!(!pane.is_zoomed());
// assert!(!pane.has_focus()); // assert!(!pane.focus_handle(cx).is_focused(cx));
// assert!(workspace.right_dock().read(cx).is_open()); // assert!(workspace.right_dock().read(cx).is_open());
// assert!(workspace.zoomed.is_none()); // assert!(workspace.zoomed.is_none());
// }); // });
@ -5190,17 +5147,16 @@ mod tests {
// let fs = FakeFs::new(cx.executor()); // let fs = FakeFs::new(cx.executor());
// let project = Project::test(fs, [], cx).await; // let project = Project::test(fs, [], cx).await;
// let window = cx.add_window(|cx| Workspace::test_new(project, cx)); // let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project, cx));
// let workspace = window.root(cx);
// let (panel_1, panel_2) = workspace.update(cx, |workspace, cx| { // let (panel_1, panel_2) = workspace.update(cx, |workspace, cx| {
// // Add panel_1 on the left, panel_2 on the right. // // Add panel_1 on the left, panel_2 on the right.
// let panel_1 = cx.build_view(|_| TestPanel::new(DockPosition::Left)); // let panel_1 = cx.build_view(|cx| TestPanel::new(DockPosition::Left, cx));
// workspace.add_panel(panel_1.clone(), cx); // workspace.add_panel(panel_1.clone(), cx);
// workspace // workspace
// .left_dock() // .left_dock()
// .update(cx, |left_dock, cx| left_dock.set_open(true, cx)); // .update(cx, |left_dock, cx| left_dock.set_open(true, cx));
// let panel_2 = cx.build_view(|_| TestPanel::new(DockPosition::Right)); // let panel_2 = cx.build_view(|cx| TestPanel::new(DockPosition::Right, cx));
// workspace.add_panel(panel_2.clone(), cx); // workspace.add_panel(panel_2.clone(), cx);
// workspace // workspace
// .right_dock() // .right_dock()
@ -5208,8 +5164,8 @@ mod tests {
// let left_dock = workspace.left_dock(); // let left_dock = workspace.left_dock();
// assert_eq!( // assert_eq!(
// left_dock.read(cx).visible_panel().unwrap().id(), // left_dock.read(cx).visible_panel().unwrap().panel_id(),
// panel_1.id() // panel_1.panel_id()
// ); // );
// assert_eq!( // assert_eq!(
// left_dock.read(cx).active_panel_size(cx).unwrap(), // left_dock.read(cx).active_panel_size(cx).unwrap(),
@ -5225,8 +5181,8 @@ mod tests {
// .read(cx) // .read(cx)
// .visible_panel() // .visible_panel()
// .unwrap() // .unwrap()
// .id(), // .panel_id(),
// panel_2.id() // panel_2.panel_id(),
// ); // );
// (panel_1, panel_2) // (panel_1, panel_2)
@ -5244,8 +5200,8 @@ mod tests {
// assert!(workspace.left_dock().read(cx).visible_panel().is_none()); // assert!(workspace.left_dock().read(cx).visible_panel().is_none());
// let right_dock = workspace.right_dock(); // let right_dock = workspace.right_dock();
// assert_eq!( // assert_eq!(
// right_dock.read(cx).visible_panel().unwrap().id(), // right_dock.read(cx).visible_panel().unwrap().panel_id(),
// panel_1.id() // panel_1.panel_id()
// ); // );
// assert_eq!(right_dock.read(cx).active_panel_size(cx).unwrap(), 1337.); // assert_eq!(right_dock.read(cx).active_panel_size(cx).unwrap(), 1337.);
@ -5264,8 +5220,8 @@ mod tests {
// .read(cx) // .read(cx)
// .visible_panel() // .visible_panel()
// .unwrap() // .unwrap()
// .id(), // .panel_id(),
// panel_1.id() // panel_1.panel_id(),
// ); // );
// }); // });
@ -5279,8 +5235,8 @@ mod tests {
// let left_dock = workspace.left_dock(); // let left_dock = workspace.left_dock();
// assert!(left_dock.read(cx).is_open()); // assert!(left_dock.read(cx).is_open());
// assert_eq!( // assert_eq!(
// left_dock.read(cx).visible_panel().unwrap().id(), // left_dock.read(cx).visible_panel().unwrap().panel_id(),
// panel_1.id() // panel_1.panel_id()
// ); // );
// assert_eq!(left_dock.read(cx).active_panel_size(cx).unwrap(), 1337.); // assert_eq!(left_dock.read(cx).active_panel_size(cx).unwrap(), 1337.);
// // And right the dock should be closed as it no longer has any panels. // // And right the dock should be closed as it no longer has any panels.
@ -5306,52 +5262,53 @@ mod tests {
// }); // });
// // Emit activated event on panel 1 // // Emit activated event on panel 1
// panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::Activated)); // panel_1.update(cx, |_, cx| cx.emit(PanelEvent::Activate));
// // Now the left dock is open and panel_1 is active and focused. // // Now the left dock is open and panel_1 is active and focused.
// workspace.update(cx, |workspace, cx| { // workspace.update(cx, |workspace, cx| {
// let left_dock = workspace.left_dock(); // let left_dock = workspace.left_dock();
// assert!(left_dock.read(cx).is_open()); // assert!(left_dock.read(cx).is_open());
// assert_eq!( // assert_eq!(
// left_dock.read(cx).visible_panel().unwrap().id(), // left_dock.read(cx).visible_panel().unwrap().panel_id(),
// panel_1.id() // panel_1.panel_id(),
// ); // );
// assert!(panel_1.is_focused(cx)); // assert!(panel_1.focus_handle(cx).is_focused(cx));
// }); // });
// // Emit closed event on panel 2, which is not active // // Emit closed event on panel 2, which is not active
// panel_2.update(cx, |_, cx| cx.emit(TestPanelEvent::Closed)); // panel_2.update(cx, |_, cx| cx.emit(PanelEvent::Close));
// // Wo don't close the left dock, because panel_2 wasn't the active panel // // Wo don't close the left dock, because panel_2 wasn't the active panel
// workspace.update(cx, |workspace, cx| { // workspace.update(cx, |workspace, cx| {
// let left_dock = workspace.left_dock(); // let left_dock = workspace.left_dock();
// assert!(left_dock.read(cx).is_open()); // assert!(left_dock.read(cx).is_open());
// assert_eq!( // assert_eq!(
// left_dock.read(cx).visible_panel().unwrap().id(), // left_dock.read(cx).visible_panel().unwrap().panel_id(),
// panel_1.id() // panel_1.panel_id(),
// ); // );
// }); // });
// // Emitting a ZoomIn event shows the panel as zoomed. // // Emitting a ZoomIn event shows the panel as zoomed.
// panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::ZoomIn)); // panel_1.update(cx, |_, cx| cx.emit(PanelEvent::ZoomIn));
// workspace.update(cx, |workspace, _| { // workspace.update(cx, |workspace, _| {
// assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any())); // assert_eq!(workspace.zoomed, Some(panel_1.to_any().downgrade()));
// assert_eq!(workspace.zoomed_position, Some(DockPosition::Left)); // assert_eq!(workspace.zoomed_position, Some(DockPosition::Left));
// }); // });
// // Move panel to another dock while it is zoomed // // Move panel to another dock while it is zoomed
// panel_1.update(cx, |panel, cx| panel.set_position(DockPosition::Right, cx)); // panel_1.update(cx, |panel, cx| panel.set_position(DockPosition::Right, cx));
// workspace.update(cx, |workspace, _| { // workspace.update(cx, |workspace, _| {
// assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any())); // assert_eq!(workspace.zoomed, Some(panel_1.to_any().downgrade()));
// assert_eq!(workspace.zoomed_position, Some(DockPosition::Right)); // assert_eq!(workspace.zoomed_position, Some(DockPosition::Right));
// }); // });
// // If focus is transferred to another view that's not a panel or another pane, we still show // // If focus is transferred to another view that's not a panel or another pane, we still show
// // the panel as zoomed. // // the panel as zoomed.
// let focus_receiver = cx.build_view(|_| EmptyView); // let other_focus_handle = cx.update(|cx| cx.focus_handle());
// focus_receiver.update(cx, |_, cx| cx.focus_self()); // cx.update(|cx| cx.focus(&other_focus_handle));
// workspace.update(cx, |workspace, _| { // workspace.update(cx, |workspace, _| {
// assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any())); // assert_eq!(workspace.zoomed, Some(panel_1.to_any().downgrade()));
// assert_eq!(workspace.zoomed_position, Some(DockPosition::Right)); // assert_eq!(workspace.zoomed_position, Some(DockPosition::Right));
// }); // });
@ -5364,7 +5321,7 @@ mod tests {
// // If focus is transferred again to another view that's not a panel or a pane, we won't // // If focus is transferred again to another view that's not a panel or a pane, we won't
// // show the panel as zoomed because it wasn't zoomed before. // // show the panel as zoomed because it wasn't zoomed before.
// focus_receiver.update(cx, |_, cx| cx.focus_self()); // cx.update(|cx| cx.focus(&other_focus_handle));
// workspace.update(cx, |workspace, _| { // workspace.update(cx, |workspace, _| {
// assert_eq!(workspace.zoomed, None); // assert_eq!(workspace.zoomed, None);
// assert_eq!(workspace.zoomed_position, None); // assert_eq!(workspace.zoomed_position, None);
@ -5373,19 +5330,19 @@ mod tests {
// // When focus is transferred back to the panel, it is zoomed again. // // When focus is transferred back to the panel, it is zoomed again.
// panel_1.update(cx, |_, cx| cx.focus_self()); // panel_1.update(cx, |_, cx| cx.focus_self());
// workspace.update(cx, |workspace, _| { // workspace.update(cx, |workspace, _| {
// assert_eq!(workspace.zoomed, Some(panel_1.downgrade().into_any())); // assert_eq!(workspace.zoomed, Some(panel_1.to_any().downgrade()));
// assert_eq!(workspace.zoomed_position, Some(DockPosition::Right)); // assert_eq!(workspace.zoomed_position, Some(DockPosition::Right));
// }); // });
// // Emitting a ZoomOut event unzooms the panel. // // Emitting a ZoomOut event unzooms the panel.
// panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::ZoomOut)); // panel_1.update(cx, |_, cx| cx.emit(PanelEvent::ZoomOut));
// workspace.update(cx, |workspace, _| { // workspace.update(cx, |workspace, _| {
// assert_eq!(workspace.zoomed, None); // assert_eq!(workspace.zoomed, None);
// assert_eq!(workspace.zoomed_position, None); // assert_eq!(workspace.zoomed_position, None);
// }); // });
// // Emit closed event on panel 1, which is active // // Emit closed event on panel 1, which is active
// panel_1.update(cx, |_, cx| cx.emit(TestPanelEvent::Closed)); // panel_1.update(cx, |_, cx| cx.emit(PanelEvent::Close));
// // Now the left dock is closed, because panel_1 was the active panel // // Now the left dock is closed, because panel_1 was the active panel
// workspace.update(cx, |workspace, cx| { // workspace.update(cx, |workspace, cx| {