mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-28 20:01:33 +00:00
Context menu, Dragon Drop, for collab panel (#3441)
Release Notes: - N/A
This commit is contained in:
commit
fb377aed73
11 changed files with 490 additions and 478 deletions
File diff suppressed because it is too large
Load diff
|
@ -824,7 +824,6 @@ impl Interactivity {
|
|||
.and_then(|group_hover| GroupBounds::get(&group_hover.group, cx));
|
||||
|
||||
if let Some(group_bounds) = hover_group_bounds {
|
||||
// todo!() needs cx.was_top_layer
|
||||
let hovered = group_bounds.contains_point(&cx.mouse_position());
|
||||
cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
|
@ -836,13 +835,13 @@ impl Interactivity {
|
|||
}
|
||||
|
||||
if self.hover_style.is_some()
|
||||
|| (cx.active_drag.is_some() && !self.drag_over_styles.is_empty())
|
||||
|| cx.active_drag.is_some() && !self.drag_over_styles.is_empty()
|
||||
{
|
||||
let interactive_bounds = interactive_bounds.clone();
|
||||
let hovered = interactive_bounds.visibly_contains(&cx.mouse_position(), cx);
|
||||
let bounds = bounds.intersect(&cx.content_mask().bounds);
|
||||
let hovered = bounds.contains_point(&cx.mouse_position());
|
||||
cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
if interactive_bounds.visibly_contains(&event.position, cx) != hovered {
|
||||
if bounds.contains_point(&event.position) != hovered {
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
@ -1143,7 +1142,9 @@ impl Interactivity {
|
|||
let mouse_position = cx.mouse_position();
|
||||
if let Some(group_hover) = self.group_hover_style.as_ref() {
|
||||
if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
|
||||
if group_bounds.contains_point(&mouse_position) {
|
||||
if group_bounds.contains_point(&mouse_position)
|
||||
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
|
||||
{
|
||||
style.refine(&group_hover.style);
|
||||
}
|
||||
}
|
||||
|
@ -1162,7 +1163,6 @@ impl Interactivity {
|
|||
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 *state_type == drag.view.entity_type()
|
||||
// todo!() needs to handle cx.content_mask() and cx.is_top()
|
||||
&& group_bounds.contains_point(&mouse_position)
|
||||
{
|
||||
style.refine(&group_drag_style.style);
|
||||
|
@ -1175,7 +1175,6 @@ impl Interactivity {
|
|||
&& bounds
|
||||
.intersect(&cx.content_mask().bounds)
|
||||
.contains_point(&mouse_position)
|
||||
&& cx.was_top_layer(&mouse_position, cx.stacking_order())
|
||||
{
|
||||
style.refine(drag_over_style);
|
||||
}
|
||||
|
|
|
@ -740,7 +740,7 @@ impl<T> Copy for Corners<T> where T: Copy + Clone + Default + Debug {}
|
|||
Deserialize,
|
||||
)]
|
||||
#[repr(transparent)]
|
||||
pub struct Pixels(pub(crate) f32);
|
||||
pub struct Pixels(pub f32);
|
||||
|
||||
impl std::ops::Div for Pixels {
|
||||
type Output = f32;
|
||||
|
|
|
@ -1480,7 +1480,7 @@ impl Render for ProjectPanel {
|
|||
.children(self.context_menu.as_ref().map(|(menu, position, _)| {
|
||||
overlay()
|
||||
.position(*position)
|
||||
.anchor(gpui::AnchorCorner::BottomLeft)
|
||||
.anchor(gpui::AnchorCorner::TopLeft)
|
||||
.child(menu.clone())
|
||||
}))
|
||||
} else {
|
||||
|
|
|
@ -3,29 +3,22 @@ use std::rc::Rc;
|
|||
use gpui::ClickEvent;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{Color, Icon, IconButton, IconSize, ToggleState, Toggleable};
|
||||
use crate::{Color, Icon, IconButton, IconSize};
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct Disclosure {
|
||||
state: ToggleState,
|
||||
is_open: bool,
|
||||
on_toggle: Option<Rc<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
|
||||
}
|
||||
|
||||
impl Disclosure {
|
||||
pub fn new(state: ToggleState) -> Self {
|
||||
pub fn new(is_open: bool) -> Self {
|
||||
Self {
|
||||
state,
|
||||
is_open,
|
||||
on_toggle: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_toggleable(toggleable: Toggleable) -> Option<Self> {
|
||||
match toggleable {
|
||||
Toggleable::Toggleable(state) => Some(Self::new(state)),
|
||||
Toggleable::NotToggleable => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_toggle(
|
||||
mut self,
|
||||
handler: impl Into<Option<Rc<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>>,
|
||||
|
@ -41,9 +34,10 @@ impl RenderOnce for Disclosure {
|
|||
fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
|
||||
IconButton::new(
|
||||
"toggle",
|
||||
match self.state {
|
||||
ToggleState::Toggled => Icon::ChevronDown,
|
||||
ToggleState::NotToggled => Icon::ChevronRight,
|
||||
if self.is_open {
|
||||
Icon::ChevronDown
|
||||
} else {
|
||||
Icon::ChevronRight
|
||||
},
|
||||
)
|
||||
.color(Color::Muted)
|
||||
|
|
|
@ -7,7 +7,7 @@ use gpui::{AnyElement, Div};
|
|||
use smallvec::SmallVec;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{v_stack, Label, ToggleState, Toggleable};
|
||||
use crate::{v_stack, Label};
|
||||
|
||||
pub use list_header::*;
|
||||
pub use list_item::*;
|
||||
|
@ -20,7 +20,7 @@ pub struct List {
|
|||
/// Defaults to "No items"
|
||||
empty_message: SharedString,
|
||||
header: Option<ListHeader>,
|
||||
toggle: Toggleable,
|
||||
toggle: Option<bool>,
|
||||
children: SmallVec<[AnyElement; 2]>,
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ impl List {
|
|||
Self {
|
||||
empty_message: "No items".into(),
|
||||
header: None,
|
||||
toggle: Toggleable::NotToggleable,
|
||||
toggle: None,
|
||||
children: SmallVec::new(),
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ impl List {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn toggle(mut self, toggle: Toggleable) -> Self {
|
||||
pub fn toggle(mut self, toggle: Option<bool>) -> Self {
|
||||
self.toggle = toggle;
|
||||
self
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ impl RenderOnce for List {
|
|||
.children(self.header.map(|header| header))
|
||||
.map(|this| match (self.children.is_empty(), self.toggle) {
|
||||
(false, _) => this.children(self.children),
|
||||
(true, Toggleable::Toggleable(ToggleState::NotToggled)) => this,
|
||||
(true, Some(false)) => this,
|
||||
(true, _) => this.child(Label::new(self.empty_message.clone()).color(Color::Muted)),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::rc::Rc;
|
|||
use gpui::{ClickEvent, Div};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{h_stack, Disclosure, Icon, IconButton, IconElement, IconSize, Label, Toggleable};
|
||||
use crate::{h_stack, Disclosure, Icon, IconButton, IconElement, IconSize, Label};
|
||||
|
||||
pub enum ListHeaderMeta {
|
||||
Tools(Vec<IconButton>),
|
||||
|
@ -17,7 +17,7 @@ pub struct ListHeader {
|
|||
label: SharedString,
|
||||
left_icon: Option<Icon>,
|
||||
meta: Option<ListHeaderMeta>,
|
||||
toggle: Toggleable,
|
||||
toggle: Option<bool>,
|
||||
on_toggle: Option<Rc<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
|
||||
inset: bool,
|
||||
selected: bool,
|
||||
|
@ -30,13 +30,13 @@ impl ListHeader {
|
|||
left_icon: None,
|
||||
meta: None,
|
||||
inset: false,
|
||||
toggle: Toggleable::NotToggleable,
|
||||
toggle: None,
|
||||
on_toggle: None,
|
||||
selected: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle(mut self, toggle: Toggleable) -> Self {
|
||||
pub fn toggle(mut self, toggle: Option<bool>) -> Self {
|
||||
self.toggle = toggle;
|
||||
self
|
||||
}
|
||||
|
@ -114,8 +114,8 @@ impl RenderOnce for ListHeader {
|
|||
.child(Label::new(self.label.clone()).color(Color::Muted)),
|
||||
)
|
||||
.children(
|
||||
Disclosure::from_toggleable(self.toggle)
|
||||
.map(|disclosure| disclosure.on_toggle(self.on_toggle)),
|
||||
self.toggle
|
||||
.map(|is_open| Disclosure::new(is_open).on_toggle(self.on_toggle)),
|
||||
),
|
||||
)
|
||||
.child(meta),
|
||||
|
|
|
@ -6,7 +6,7 @@ use gpui::{
|
|||
use smallvec::SmallVec;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{Avatar, Disclosure, GraphicSlot, Icon, IconElement, IconSize, Toggleable};
|
||||
use crate::{Avatar, Disclosure, GraphicSlot, Icon, IconElement, IconSize};
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct ListItem {
|
||||
|
@ -17,7 +17,7 @@ pub struct ListItem {
|
|||
indent_level: usize,
|
||||
indent_step_size: Pixels,
|
||||
left_slot: Option<GraphicSlot>,
|
||||
toggle: Toggleable,
|
||||
toggle: Option<bool>,
|
||||
inset: bool,
|
||||
on_click: Option<Rc<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
|
||||
on_toggle: Option<Rc<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
|
||||
|
@ -33,7 +33,7 @@ impl ListItem {
|
|||
indent_level: 0,
|
||||
indent_step_size: px(12.),
|
||||
left_slot: None,
|
||||
toggle: Toggleable::NotToggleable,
|
||||
toggle: None,
|
||||
inset: false,
|
||||
on_click: None,
|
||||
on_secondary_mouse_down: None,
|
||||
|
@ -70,7 +70,7 @@ impl ListItem {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn toggle(mut self, toggle: Toggleable) -> Self {
|
||||
pub fn toggle(mut self, toggle: Option<bool>) -> Self {
|
||||
self.toggle = toggle;
|
||||
self
|
||||
}
|
||||
|
@ -151,8 +151,8 @@ impl RenderOnce for ListItem {
|
|||
.items_center()
|
||||
.relative()
|
||||
.children(
|
||||
Disclosure::from_toggleable(self.toggle)
|
||||
.map(|disclosure| disclosure.on_toggle(self.on_toggle)),
|
||||
self.toggle
|
||||
.map(|is_open| Disclosure::new(is_open).on_toggle(self.on_toggle)),
|
||||
)
|
||||
.map(|this| match self.left_slot {
|
||||
Some(GraphicSlot::Icon(i)) => this.child(
|
||||
|
|
|
@ -2,7 +2,7 @@ use gpui::{Div, Render};
|
|||
use story::Story;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{Disclosure, ToggleState};
|
||||
use crate::Disclosure;
|
||||
|
||||
pub struct DisclosureStory;
|
||||
|
||||
|
@ -13,8 +13,8 @@ impl Render for DisclosureStory {
|
|||
Story::container()
|
||||
.child(Story::title_for::<Disclosure>())
|
||||
.child(Story::label("Toggled"))
|
||||
.child(Disclosure::new(ToggleState::Toggled))
|
||||
.child(Disclosure::new(true))
|
||||
.child(Story::label("Not Toggled"))
|
||||
.child(Disclosure::new(ToggleState::NotToggled))
|
||||
.child(Disclosure::new(false))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
/// Whether an element is able to be toggled.
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
||||
pub enum Toggleable {
|
||||
Toggleable(ToggleState),
|
||||
NotToggleable,
|
||||
}
|
||||
|
||||
/// The current state of a [`Toggleable`] element.
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
|
||||
pub enum ToggleState {
|
||||
Toggled,
|
||||
NotToggled,
|
||||
}
|
||||
|
||||
impl ToggleState {
|
||||
/// Returns whether an entry is toggled.
|
||||
pub fn is_toggled(&self) -> bool {
|
||||
match self {
|
||||
ToggleState::Toggled => true,
|
||||
ToggleState::NotToggled => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for ToggleState {
|
||||
fn from(toggled: bool) -> Self {
|
||||
match toggled {
|
||||
true => Self::Toggled,
|
||||
false => Self::NotToggled,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ToggleState> for bool {
|
||||
fn from(value: ToggleState) -> Self {
|
||||
value.is_toggled()
|
||||
}
|
||||
}
|
|
@ -21,7 +21,6 @@ mod selectable;
|
|||
mod slot;
|
||||
mod styled_ext;
|
||||
mod styles;
|
||||
mod toggleable;
|
||||
pub mod utils;
|
||||
|
||||
pub use clickable::*;
|
||||
|
@ -33,4 +32,3 @@ pub use selectable::*;
|
|||
pub use slot::*;
|
||||
pub use styled_ext::*;
|
||||
pub use styles::*;
|
||||
pub use toggleable::*;
|
||||
|
|
Loading…
Reference in a new issue