Merge pull request #1762 from zed-industries/less-click-and-hover-invalidation
Reduce unnecessary view invalidations related to mouse events
This commit is contained in:
commit
3e23d1f48d
19 changed files with 136 additions and 60 deletions
|
@ -285,7 +285,7 @@ impl View for ActivityIndicator {
|
||||||
.workspace
|
.workspace
|
||||||
.status_bar
|
.status_bar
|
||||||
.lsp_status;
|
.lsp_status;
|
||||||
let style = if state.hovered && action.is_some() {
|
let style = if state.hovered() && action.is_some() {
|
||||||
theme.hover.as_ref().unwrap_or(&theme.default)
|
theme.hover.as_ref().unwrap_or(&theme.default)
|
||||||
} else {
|
} else {
|
||||||
&theme.default
|
&theme.default
|
||||||
|
|
|
@ -311,7 +311,7 @@ impl ChatPanel {
|
||||||
MouseEventHandler::<SignInPromptLabel>::new(0, cx, |mouse_state, _| {
|
MouseEventHandler::<SignInPromptLabel>::new(0, cx, |mouse_state, _| {
|
||||||
Label::new(
|
Label::new(
|
||||||
"Sign in to use chat".to_string(),
|
"Sign in to use chat".to_string(),
|
||||||
if mouse_state.hovered {
|
if mouse_state.hovered() {
|
||||||
theme.chat_panel.hovered_sign_in_prompt.clone()
|
theme.chat_panel.hovered_sign_in_prompt.clone()
|
||||||
} else {
|
} else {
|
||||||
theme.chat_panel.sign_in_prompt.clone()
|
theme.chat_panel.sign_in_prompt.clone()
|
||||||
|
|
|
@ -101,7 +101,7 @@ impl PickerDelegate for ContactFinder {
|
||||||
fn render_match(
|
fn render_match(
|
||||||
&self,
|
&self,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
mouse_state: MouseState,
|
mouse_state: &mut MouseState,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
cx: &gpui::AppContext,
|
cx: &gpui::AppContext,
|
||||||
) -> ElementBox {
|
) -> ElementBox {
|
||||||
|
|
|
@ -653,7 +653,11 @@ impl ContactList {
|
||||||
.constrained()
|
.constrained()
|
||||||
.with_height(theme.row_height)
|
.with_height(theme.row_height)
|
||||||
.contained()
|
.contained()
|
||||||
.with_style(*theme.contact_row.style_for(Default::default(), is_selected))
|
.with_style(
|
||||||
|
*theme
|
||||||
|
.contact_row
|
||||||
|
.style_for(&mut Default::default(), is_selected),
|
||||||
|
)
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -768,7 +772,9 @@ impl ContactList {
|
||||||
) -> ElementBox {
|
) -> ElementBox {
|
||||||
enum Header {}
|
enum Header {}
|
||||||
|
|
||||||
let header_style = theme.header_row.style_for(Default::default(), is_selected);
|
let header_style = theme
|
||||||
|
.header_row
|
||||||
|
.style_for(&mut Default::default(), is_selected);
|
||||||
let text = match section {
|
let text = match section {
|
||||||
Section::ActiveCall => "Collaborators",
|
Section::ActiveCall => "Collaborators",
|
||||||
Section::Requests => "Contact Requests",
|
Section::Requests => "Contact Requests",
|
||||||
|
@ -890,7 +896,11 @@ impl ContactList {
|
||||||
.constrained()
|
.constrained()
|
||||||
.with_height(theme.row_height)
|
.with_height(theme.row_height)
|
||||||
.contained()
|
.contained()
|
||||||
.with_style(*theme.contact_row.style_for(Default::default(), is_selected))
|
.with_style(
|
||||||
|
*theme
|
||||||
|
.contact_row
|
||||||
|
.style_for(&mut Default::default(), is_selected),
|
||||||
|
)
|
||||||
.boxed()
|
.boxed()
|
||||||
})
|
})
|
||||||
.on_click(MouseButton::Left, move |_, cx| {
|
.on_click(MouseButton::Left, move |_, cx| {
|
||||||
|
@ -1014,7 +1024,11 @@ impl ContactList {
|
||||||
row.constrained()
|
row.constrained()
|
||||||
.with_height(theme.row_height)
|
.with_height(theme.row_height)
|
||||||
.contained()
|
.contained()
|
||||||
.with_style(*theme.contact_row.style_for(Default::default(), is_selected))
|
.with_style(
|
||||||
|
*theme
|
||||||
|
.contact_row
|
||||||
|
.style_for(&mut Default::default(), is_selected),
|
||||||
|
)
|
||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -224,7 +224,7 @@ impl PickerDelegate for CommandPalette {
|
||||||
fn render_match(
|
fn render_match(
|
||||||
&self,
|
&self,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
mouse_state: MouseState,
|
mouse_state: &mut MouseState,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
cx: &gpui::AppContext,
|
cx: &gpui::AppContext,
|
||||||
) -> gpui::ElementBox {
|
) -> gpui::ElementBox {
|
||||||
|
|
|
@ -258,9 +258,10 @@ impl ContextMenu {
|
||||||
.with_children(self.items.iter().enumerate().map(|(ix, item)| {
|
.with_children(self.items.iter().enumerate().map(|(ix, item)| {
|
||||||
match item {
|
match item {
|
||||||
ContextMenuItem::Item { label, .. } => {
|
ContextMenuItem::Item { label, .. } => {
|
||||||
let style = style
|
let style = style.item.style_for(
|
||||||
.item
|
&mut Default::default(),
|
||||||
.style_for(Default::default(), Some(ix) == self.selected_index);
|
Some(ix) == self.selected_index,
|
||||||
|
);
|
||||||
|
|
||||||
Label::new(label.to_string(), style.label.clone())
|
Label::new(label.to_string(), style.label.clone())
|
||||||
.contained()
|
.contained()
|
||||||
|
@ -283,9 +284,10 @@ impl ContextMenu {
|
||||||
.with_children(self.items.iter().enumerate().map(|(ix, item)| {
|
.with_children(self.items.iter().enumerate().map(|(ix, item)| {
|
||||||
match item {
|
match item {
|
||||||
ContextMenuItem::Item { action, .. } => {
|
ContextMenuItem::Item { action, .. } => {
|
||||||
let style = style
|
let style = style.item.style_for(
|
||||||
.item
|
&mut Default::default(),
|
||||||
.style_for(Default::default(), Some(ix) == self.selected_index);
|
Some(ix) == self.selected_index,
|
||||||
|
);
|
||||||
KeystrokeLabel::new(
|
KeystrokeLabel::new(
|
||||||
action.boxed_clone(),
|
action.boxed_clone(),
|
||||||
style.keystroke.container,
|
style.keystroke.container,
|
||||||
|
|
|
@ -759,7 +759,7 @@ impl CompletionsMenu {
|
||||||
|state, _| {
|
|state, _| {
|
||||||
let item_style = if item_ix == selected_item {
|
let item_style = if item_ix == selected_item {
|
||||||
style.autocomplete.selected_item
|
style.autocomplete.selected_item
|
||||||
} else if state.hovered {
|
} else if state.hovered() {
|
||||||
style.autocomplete.hovered_item
|
style.autocomplete.hovered_item
|
||||||
} else {
|
} else {
|
||||||
style.autocomplete.item
|
style.autocomplete.item
|
||||||
|
@ -914,7 +914,7 @@ impl CodeActionsMenu {
|
||||||
MouseEventHandler::<ActionTag>::new(item_ix, cx, |state, _| {
|
MouseEventHandler::<ActionTag>::new(item_ix, cx, |state, _| {
|
||||||
let item_style = if item_ix == selected_item {
|
let item_style = if item_ix == selected_item {
|
||||||
style.autocomplete.selected_item
|
style.autocomplete.selected_item
|
||||||
} else if state.hovered {
|
} else if state.hovered() {
|
||||||
style.autocomplete.hovered_item
|
style.autocomplete.hovered_item
|
||||||
} else {
|
} else {
|
||||||
style.autocomplete.item
|
style.autocomplete.item
|
||||||
|
@ -5983,8 +5983,11 @@ impl Editor {
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
|
) -> Option<(fn(&Theme) -> Color, Vec<Range<Anchor>>)> {
|
||||||
|
let highlights = self.background_highlights.remove(&TypeId::of::<T>());
|
||||||
|
if highlights.is_some() {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
self.background_highlights.remove(&TypeId::of::<T>())
|
}
|
||||||
|
highlights
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "test-support")]
|
#[cfg(feature = "test-support")]
|
||||||
|
@ -6098,9 +6101,13 @@ impl Editor {
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
|
) -> Option<Arc<(HighlightStyle, Vec<Range<Anchor>>)>> {
|
||||||
|
let highlights = self
|
||||||
|
.display_map
|
||||||
|
.update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()));
|
||||||
|
if highlights.is_some() {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
self.display_map
|
}
|
||||||
.update(cx, |map, _| map.clear_text_highlights(TypeId::of::<T>()))
|
highlights
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_blink_epoch(&mut self) -> usize {
|
fn next_blink_epoch(&mut self) -> usize {
|
||||||
|
|
|
@ -251,7 +251,7 @@ impl PickerDelegate for FileFinder {
|
||||||
fn render_match(
|
fn render_match(
|
||||||
&self,
|
&self,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
mouse_state: MouseState,
|
mouse_state: &mut MouseState,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
cx: &AppContext,
|
cx: &AppContext,
|
||||||
) -> ElementBox {
|
) -> ElementBox {
|
||||||
|
|
|
@ -3774,10 +3774,32 @@ pub struct RenderContext<'a, T: View> {
|
||||||
pub refreshing: bool,
|
pub refreshing: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct MouseState {
|
pub struct MouseState {
|
||||||
pub hovered: bool,
|
hovered: bool,
|
||||||
pub clicked: Option<MouseButton>,
|
clicked: Option<MouseButton>,
|
||||||
|
accessed_hovered: bool,
|
||||||
|
accessed_clicked: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MouseState {
|
||||||
|
pub fn hovered(&mut self) -> bool {
|
||||||
|
self.accessed_hovered = true;
|
||||||
|
self.hovered
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clicked(&mut self) -> Option<MouseButton> {
|
||||||
|
self.accessed_clicked = true;
|
||||||
|
self.clicked
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn accessed_hovered(&self) -> bool {
|
||||||
|
self.accessed_hovered
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn accessed_clicked(&self) -> bool {
|
||||||
|
self.accessed_clicked
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, V: View> RenderContext<'a, V> {
|
impl<'a, V: View> RenderContext<'a, V> {
|
||||||
|
@ -3818,6 +3840,8 @@ impl<'a, V: View> RenderContext<'a, V> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
accessed_hovered: false,
|
||||||
|
accessed_clicked: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ pub struct MouseEventHandler<Tag: 'static> {
|
||||||
cursor_style: Option<CursorStyle>,
|
cursor_style: Option<CursorStyle>,
|
||||||
handlers: HandlerSet,
|
handlers: HandlerSet,
|
||||||
hoverable: bool,
|
hoverable: bool,
|
||||||
|
notify_on_hover: bool,
|
||||||
|
notify_on_click: bool,
|
||||||
padding: Padding,
|
padding: Padding,
|
||||||
_tag: PhantomData<Tag>,
|
_tag: PhantomData<Tag>,
|
||||||
}
|
}
|
||||||
|
@ -30,13 +32,19 @@ impl<Tag> MouseEventHandler<Tag> {
|
||||||
pub fn new<V, F>(region_id: usize, cx: &mut RenderContext<V>, render_child: F) -> Self
|
pub fn new<V, F>(region_id: usize, cx: &mut RenderContext<V>, render_child: F) -> Self
|
||||||
where
|
where
|
||||||
V: View,
|
V: View,
|
||||||
F: FnOnce(MouseState, &mut RenderContext<V>) -> ElementBox,
|
F: FnOnce(&mut MouseState, &mut RenderContext<V>) -> ElementBox,
|
||||||
{
|
{
|
||||||
|
let mut mouse_state = cx.mouse_state::<Tag>(region_id);
|
||||||
|
let child = render_child(&mut mouse_state, cx);
|
||||||
|
let notify_on_hover = mouse_state.accessed_hovered();
|
||||||
|
let notify_on_click = mouse_state.accessed_clicked();
|
||||||
Self {
|
Self {
|
||||||
child: render_child(cx.mouse_state::<Tag>(region_id), cx),
|
child,
|
||||||
region_id,
|
region_id,
|
||||||
cursor_style: None,
|
cursor_style: None,
|
||||||
handlers: Default::default(),
|
handlers: Default::default(),
|
||||||
|
notify_on_hover,
|
||||||
|
notify_on_click,
|
||||||
hoverable: true,
|
hoverable: true,
|
||||||
padding: Default::default(),
|
padding: Default::default(),
|
||||||
_tag: PhantomData,
|
_tag: PhantomData,
|
||||||
|
@ -185,7 +193,9 @@ impl<Tag> Element for MouseEventHandler<Tag> {
|
||||||
hit_bounds,
|
hit_bounds,
|
||||||
self.handlers.clone(),
|
self.handlers.clone(),
|
||||||
)
|
)
|
||||||
.with_hoverable(self.hoverable),
|
.with_hoverable(self.hoverable)
|
||||||
|
.with_notify_on_hover(self.notify_on_hover)
|
||||||
|
.with_notify_on_click(self.notify_on_click),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.child.paint(bounds.origin(), visible_bounds, cx);
|
self.child.paint(bounds.origin(), visible_bounds, cx);
|
||||||
|
|
|
@ -231,7 +231,7 @@ impl Presenter {
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Some(root_view_id) = cx.root_view_id(self.window_id) {
|
if let Some(root_view_id) = cx.root_view_id(self.window_id) {
|
||||||
let mut events_to_send = Vec::new();
|
let mut events_to_send = Vec::new();
|
||||||
let mut invalidated_views: HashSet<usize> = Default::default();
|
let mut notified_views: HashSet<usize> = Default::default();
|
||||||
|
|
||||||
// 1. Allocate the correct set of GPUI events generated from the platform events
|
// 1. Allocate the correct set of GPUI events generated from the platform events
|
||||||
// -> These are usually small: [Mouse Down] or [Mouse up, Click] or [Mouse Moved, Mouse Dragged?]
|
// -> These are usually small: [Mouse Down] or [Mouse up, Click] or [Mouse Moved, Mouse Dragged?]
|
||||||
|
@ -257,11 +257,6 @@ impl Presenter {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Clicked status is used when rendering views via the RenderContext.
|
|
||||||
// So when it changes, these views need to be rerendered
|
|
||||||
for clicked_region_id in self.clicked_region_ids.iter() {
|
|
||||||
invalidated_views.insert(clicked_region_id.view_id());
|
|
||||||
}
|
|
||||||
self.clicked_button = Some(e.button);
|
self.clicked_button = Some(e.button);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,17 +387,31 @@ impl Presenter {
|
||||||
//Ensure that hover entrance events aren't sent twice
|
//Ensure that hover entrance events aren't sent twice
|
||||||
if self.hovered_region_ids.insert(region.id()) {
|
if self.hovered_region_ids.insert(region.id()) {
|
||||||
valid_regions.push(region.clone());
|
valid_regions.push(region.clone());
|
||||||
invalidated_views.insert(region.id().view_id());
|
if region.notify_on_hover {
|
||||||
|
notified_views.insert(region.id().view_id());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Ensure that hover exit events aren't sent twice
|
// Ensure that hover exit events aren't sent twice
|
||||||
if self.hovered_region_ids.remove(®ion.id()) {
|
if self.hovered_region_ids.remove(®ion.id()) {
|
||||||
valid_regions.push(region.clone());
|
valid_regions.push(region.clone());
|
||||||
invalidated_views.insert(region.id().view_id());
|
if region.notify_on_hover {
|
||||||
|
notified_views.insert(region.id().view_id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
MouseRegionEvent::Down(_) | MouseRegionEvent::Up(_) => {
|
||||||
|
for (region, _) in self.mouse_regions.iter().rev() {
|
||||||
|
if region.bounds.contains_point(self.mouse_position) {
|
||||||
|
if region.notify_on_click {
|
||||||
|
notified_views.insert(region.id().view_id());
|
||||||
|
}
|
||||||
|
valid_regions.push(region.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
MouseRegionEvent::Click(e) => {
|
MouseRegionEvent::Click(e) => {
|
||||||
// Only raise click events if the released button is the same as the one stored
|
// Only raise click events if the released button is the same as the one stored
|
||||||
if self
|
if self
|
||||||
|
@ -413,11 +422,6 @@ impl Presenter {
|
||||||
// Clear clicked regions and clicked button
|
// Clear clicked regions and clicked button
|
||||||
let clicked_region_ids =
|
let clicked_region_ids =
|
||||||
std::mem::replace(&mut self.clicked_region_ids, Default::default());
|
std::mem::replace(&mut self.clicked_region_ids, Default::default());
|
||||||
// Clicked status is used when rendering views via the RenderContext.
|
|
||||||
// So when it changes, these views need to be rerendered
|
|
||||||
for clicked_region_id in clicked_region_ids.iter() {
|
|
||||||
invalidated_views.insert(clicked_region_id.view_id());
|
|
||||||
}
|
|
||||||
self.clicked_button = None;
|
self.clicked_button = None;
|
||||||
|
|
||||||
// Find regions which still overlap with the mouse since the last MouseDown happened
|
// Find regions which still overlap with the mouse since the last MouseDown happened
|
||||||
|
@ -459,7 +463,7 @@ impl Presenter {
|
||||||
//3. Fire region events
|
//3. Fire region events
|
||||||
let hovered_region_ids = self.hovered_region_ids.clone();
|
let hovered_region_ids = self.hovered_region_ids.clone();
|
||||||
for valid_region in valid_regions.into_iter() {
|
for valid_region in valid_regions.into_iter() {
|
||||||
let mut event_cx = self.build_event_context(&mut invalidated_views, cx);
|
let mut event_cx = self.build_event_context(&mut notified_views, cx);
|
||||||
|
|
||||||
region_event.set_region(valid_region.bounds);
|
region_event.set_region(valid_region.bounds);
|
||||||
if let MouseRegionEvent::Hover(e) = &mut region_event {
|
if let MouseRegionEvent::Hover(e) = &mut region_event {
|
||||||
|
@ -500,11 +504,11 @@ impl Presenter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !any_event_handled && !event_reused {
|
if !any_event_handled && !event_reused {
|
||||||
let mut event_cx = self.build_event_context(&mut invalidated_views, cx);
|
let mut event_cx = self.build_event_context(&mut notified_views, cx);
|
||||||
any_event_handled = event_cx.dispatch_event(root_view_id, &event);
|
any_event_handled = event_cx.dispatch_event(root_view_id, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
for view_id in invalidated_views {
|
for view_id in notified_views {
|
||||||
cx.notify_view(self.window_id, view_id);
|
cx.notify_view(self.window_id, view_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -516,7 +520,7 @@ impl Presenter {
|
||||||
|
|
||||||
pub fn build_event_context<'a>(
|
pub fn build_event_context<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
invalidated_views: &'a mut HashSet<usize>,
|
notified_views: &'a mut HashSet<usize>,
|
||||||
cx: &'a mut MutableAppContext,
|
cx: &'a mut MutableAppContext,
|
||||||
) -> EventContext<'a> {
|
) -> EventContext<'a> {
|
||||||
EventContext {
|
EventContext {
|
||||||
|
@ -524,7 +528,7 @@ impl Presenter {
|
||||||
font_cache: &self.font_cache,
|
font_cache: &self.font_cache,
|
||||||
text_layout_cache: &self.text_layout_cache,
|
text_layout_cache: &self.text_layout_cache,
|
||||||
view_stack: Default::default(),
|
view_stack: Default::default(),
|
||||||
invalidated_views,
|
notified_views,
|
||||||
notify_count: 0,
|
notify_count: 0,
|
||||||
handled: false,
|
handled: false,
|
||||||
window_id: self.window_id,
|
window_id: self.window_id,
|
||||||
|
@ -747,7 +751,7 @@ pub struct EventContext<'a> {
|
||||||
pub notify_count: usize,
|
pub notify_count: usize,
|
||||||
view_stack: Vec<usize>,
|
view_stack: Vec<usize>,
|
||||||
handled: bool,
|
handled: bool,
|
||||||
invalidated_views: &'a mut HashSet<usize>,
|
notified_views: &'a mut HashSet<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> EventContext<'a> {
|
impl<'a> EventContext<'a> {
|
||||||
|
@ -806,7 +810,7 @@ impl<'a> EventContext<'a> {
|
||||||
pub fn notify(&mut self) {
|
pub fn notify(&mut self) {
|
||||||
self.notify_count += 1;
|
self.notify_count += 1;
|
||||||
if let Some(view_id) = self.view_stack.last() {
|
if let Some(view_id) = self.view_stack.last() {
|
||||||
self.invalidated_views.insert(*view_id);
|
self.notified_views.insert(*view_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@ pub struct MouseRegion {
|
||||||
pub bounds: RectF,
|
pub bounds: RectF,
|
||||||
pub handlers: HandlerSet,
|
pub handlers: HandlerSet,
|
||||||
pub hoverable: bool,
|
pub hoverable: bool,
|
||||||
|
pub notify_on_hover: bool,
|
||||||
|
pub notify_on_click: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MouseRegion {
|
impl MouseRegion {
|
||||||
|
@ -52,6 +54,8 @@ impl MouseRegion {
|
||||||
bounds,
|
bounds,
|
||||||
handlers,
|
handlers,
|
||||||
hoverable: true,
|
hoverable: true,
|
||||||
|
notify_on_hover: false,
|
||||||
|
notify_on_click: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,6 +141,16 @@ impl MouseRegion {
|
||||||
self.hoverable = is_hoverable;
|
self.hoverable = is_hoverable;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_notify_on_hover(mut self, notify: bool) -> Self {
|
||||||
|
self.notify_on_hover = notify;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_notify_on_click(mut self, notify: bool) -> Self {
|
||||||
|
self.notify_on_click = notify;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||||
|
|
|
@ -113,7 +113,7 @@ impl View for Select {
|
||||||
Container::new((self.render_item)(
|
Container::new((self.render_item)(
|
||||||
self.selected_item_ix,
|
self.selected_item_ix,
|
||||||
ItemType::Header,
|
ItemType::Header,
|
||||||
mouse_state.hovered,
|
mouse_state.hovered(),
|
||||||
cx,
|
cx,
|
||||||
))
|
))
|
||||||
.with_style(style.header)
|
.with_style(style.header)
|
||||||
|
@ -145,7 +145,7 @@ impl View for Select {
|
||||||
} else {
|
} else {
|
||||||
ItemType::Unselected
|
ItemType::Unselected
|
||||||
},
|
},
|
||||||
mouse_state.hovered,
|
mouse_state.hovered(),
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -233,7 +233,7 @@ impl PickerDelegate for OutlineView {
|
||||||
fn render_match(
|
fn render_match(
|
||||||
&self,
|
&self,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
mouse_state: MouseState,
|
mouse_state: &mut MouseState,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
cx: &AppContext,
|
cx: &AppContext,
|
||||||
) -> ElementBox {
|
) -> ElementBox {
|
||||||
|
|
|
@ -33,7 +33,7 @@ pub trait PickerDelegate: View {
|
||||||
fn render_match(
|
fn render_match(
|
||||||
&self,
|
&self,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
state: MouseState,
|
state: &mut MouseState,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
cx: &AppContext,
|
cx: &AppContext,
|
||||||
) -> ElementBox;
|
) -> ElementBox;
|
||||||
|
|
|
@ -234,7 +234,7 @@ impl PickerDelegate for ProjectSymbolsView {
|
||||||
fn render_match(
|
fn render_match(
|
||||||
&self,
|
&self,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
mouse_state: MouseState,
|
mouse_state: &mut MouseState,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
cx: &AppContext,
|
cx: &AppContext,
|
||||||
) -> ElementBox {
|
) -> ElementBox {
|
||||||
|
|
|
@ -645,12 +645,12 @@ pub struct Interactive<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Interactive<T> {
|
impl<T> Interactive<T> {
|
||||||
pub fn style_for(&self, state: MouseState, active: bool) -> &T {
|
pub fn style_for(&self, state: &mut MouseState, active: bool) -> &T {
|
||||||
if active {
|
if active {
|
||||||
self.active.as_ref().unwrap_or(&self.default)
|
self.active.as_ref().unwrap_or(&self.default)
|
||||||
} else if state.clicked == Some(gpui::MouseButton::Left) && self.clicked.is_some() {
|
} else if state.clicked() == Some(gpui::MouseButton::Left) && self.clicked.is_some() {
|
||||||
self.clicked.as_ref().unwrap()
|
self.clicked.as_ref().unwrap()
|
||||||
} else if state.hovered {
|
} else if state.hovered() {
|
||||||
self.hover.as_ref().unwrap_or(&self.default)
|
self.hover.as_ref().unwrap_or(&self.default)
|
||||||
} else {
|
} else {
|
||||||
&self.default
|
&self.default
|
||||||
|
|
|
@ -230,7 +230,7 @@ impl PickerDelegate for ThemeSelector {
|
||||||
fn render_match(
|
fn render_match(
|
||||||
&self,
|
&self,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
mouse_state: MouseState,
|
mouse_state: &mut MouseState,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
cx: &AppContext,
|
cx: &AppContext,
|
||||||
) -> ElementBox {
|
) -> ElementBox {
|
||||||
|
|
|
@ -1088,7 +1088,7 @@ impl Pane {
|
||||||
move |mouse_state, cx| {
|
move |mouse_state, cx| {
|
||||||
let tab_style =
|
let tab_style =
|
||||||
theme.workspace.tab_bar.tab_style(pane_active, tab_active);
|
theme.workspace.tab_bar.tab_style(pane_active, tab_active);
|
||||||
let hovered = mouse_state.hovered;
|
let hovered = mouse_state.hovered();
|
||||||
Self::render_tab(
|
Self::render_tab(
|
||||||
&item,
|
&item,
|
||||||
pane,
|
pane,
|
||||||
|
@ -1161,7 +1161,8 @@ impl Pane {
|
||||||
.with_style(filler_style.container)
|
.with_style(filler_style.container)
|
||||||
.with_border(filler_style.container.border);
|
.with_border(filler_style.container.border);
|
||||||
|
|
||||||
if let Some(overlay) = Self::tab_overlay_color(mouse_state.hovered, &theme, cx)
|
if let Some(overlay) =
|
||||||
|
Self::tab_overlay_color(mouse_state.hovered(), &theme, cx)
|
||||||
{
|
{
|
||||||
filler = filler.with_overlay_color(overlay);
|
filler = filler.with_overlay_color(overlay);
|
||||||
}
|
}
|
||||||
|
@ -1283,7 +1284,7 @@ impl Pane {
|
||||||
enum TabCloseButton {}
|
enum TabCloseButton {}
|
||||||
let icon = Svg::new("icons/x_mark_thin_8.svg");
|
let icon = Svg::new("icons/x_mark_thin_8.svg");
|
||||||
MouseEventHandler::<TabCloseButton>::new(item_id, cx, |mouse_state, _| {
|
MouseEventHandler::<TabCloseButton>::new(item_id, cx, |mouse_state, _| {
|
||||||
if mouse_state.hovered {
|
if mouse_state.hovered() {
|
||||||
icon.with_color(tab_style.icon_close_active).boxed()
|
icon.with_color(tab_style.icon_close_active).boxed()
|
||||||
} else {
|
} else {
|
||||||
icon.with_color(tab_style.icon_close).boxed()
|
icon.with_color(tab_style.icon_close).boxed()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue