From ab140ee4c271c33be31aa3b8e60892aff40c80c7 Mon Sep 17 00:00:00 2001 From: Mikayla Date: Tue, 5 Dec 2023 12:07:17 -0800 Subject: [PATCH] Add event based drag API to GPUI, continue binding mouse handlers to terminal --- Cargo.lock | 1 + crates/gpui2/src/app.rs | 30 +- crates/gpui2/src/element.rs | 33 -- crates/gpui2/src/elements/div.rs | 73 +++- crates/gpui2/src/window.rs | 19 +- crates/terminal2/src/terminal2.rs | 9 +- crates/terminal_view2/Cargo.toml | 1 + crates/terminal_view2/src/terminal_element.rs | 352 ++++++++++-------- crates/terminal_view2/src/terminal_view.rs | 1 + 9 files changed, 295 insertions(+), 224 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 39683c9fc1..349ec8f175 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9478,6 +9478,7 @@ dependencies = [ "terminal2", "theme2", "thiserror", + "ui2", "util", "workspace2", ] diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index fec6f150f6..a639660c8d 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -185,7 +185,7 @@ pub struct AppContext { flushing_effects: bool, pending_updates: usize, pub(crate) actions: Rc, - pub(crate) active_drag: Option, + pub(crate) active_drag: Option, pub(crate) active_tooltip: Option, pub(crate) next_frame_callbacks: HashMap>, pub(crate) frame_consumers: HashMap>, @@ -1172,6 +1172,34 @@ pub struct AnyDrag { pub cursor_offset: Point, } +pub enum AnyDragState { + EventListener, + AnyDrag(AnyDrag), +} + +impl AnyDragState { + pub fn any_drag(&self) -> Option<&AnyDrag> { + match self { + AnyDragState::EventListener => None, + AnyDragState::AnyDrag(any_drag) => Some(any_drag), + } + } + + pub fn entity_id(&self) -> Option { + match self { + AnyDragState::EventListener => None, + AnyDragState::AnyDrag(any_drag) => Some(any_drag.view.entity_id()), + } + } + + pub fn entity_type(&self) -> Option { + match self { + AnyDragState::EventListener => None, + AnyDragState::AnyDrag(any_drag) => Some(any_drag.view.entity_type()), + } + } +} + #[derive(Clone)] pub(crate) struct AnyTooltip { pub view: AnyView, diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index 3c8f678b89..226a477012 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -370,39 +370,6 @@ impl DrawableElement { } } -// impl Element for DrawableElement { -// type State = ::State; - -// fn layout( -// &mut self, -// element_state: Option, -// cx: &mut WindowContext, -// ) -> (LayoutId, Self::State) { - -// } - -// fn paint( -// self, -// bounds: Bounds, -// element_state: &mut Self::State, -// cx: &mut WindowContext, -// ) { -// todo!() -// } -// } - -// impl RenderOnce for DrawableElement { -// type Element = Self; - -// fn element_id(&self) -> Option { -// self.element.as_ref()?.element_id() -// } - -// fn render_once(self) -> Self::Element { -// self -// } -// } - impl ElementObject for Option> where E: Element, diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index ce457fc693..e653710c0f 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -1,10 +1,10 @@ use crate::{ - point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, BorrowAppContext, - BorrowWindow, Bounds, ClickEvent, DispatchPhase, Element, ElementId, FocusEvent, FocusHandle, - IntoElement, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent, - MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, Render, ScrollWheelEvent, - SharedString, Size, StackingOrder, Style, StyleRefinement, Styled, Task, View, Visibility, - WindowContext, + point, px, Action, AnyDrag, AnyDragState, AnyElement, AnyTooltip, AnyView, AppContext, + BorrowAppContext, BorrowWindow, Bounds, ClickEvent, DispatchPhase, Element, ElementId, + FocusEvent, FocusHandle, IntoElement, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, + MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, + Render, ScrollWheelEvent, SharedString, Size, StackingOrder, Style, StyleRefinement, Styled, + Task, View, Visibility, WindowContext, }; use collections::HashMap; use refineable::Refineable; @@ -415,6 +415,19 @@ pub trait StatefulInteractiveElement: InteractiveElement { self } + fn on_drag_event( + mut self, + listener: impl Fn(&MouseMoveEvent, &mut WindowContext) + 'static, + ) -> Self + where + Self: Sized, + { + self.interactivity() + .drag_event_listeners + .push(Box::new(listener)); + self + } + fn on_hover(mut self, listener: impl Fn(&bool, &mut WindowContext) + 'static) -> Self where Self: Sized, @@ -559,6 +572,8 @@ pub type KeyDownListener = Box; +pub type DragEventListener = Box; + pub type ActionListener = Box; pub fn div() -> Div { @@ -746,6 +761,7 @@ pub struct Interactivity { pub action_listeners: SmallVec<[(TypeId, ActionListener); 8]>, pub drop_listeners: SmallVec<[(TypeId, Box); 2]>, pub click_listeners: SmallVec<[ClickListener; 2]>, + pub drag_event_listeners: SmallVec<[DragEventListener; 1]>, pub drag_listener: Option, pub hover_listener: Option>, pub tooltip_builder: Option, @@ -890,8 +906,11 @@ impl Interactivity { if phase == DispatchPhase::Bubble && interactive_bounds.visibly_contains(&event.position, &cx) { - if let Some(drag_state_type) = - cx.active_drag.as_ref().map(|drag| drag.view.entity_type()) + if let Some(drag_state_type) = cx + .active_drag + .as_ref() + .and_then(|drag| drag.any_drag()) + .map(|drag| drag.view.entity_type()) { for (drop_state_type, listener) in &drop_listeners { if *drop_state_type == drag_state_type { @@ -899,11 +918,14 @@ impl Interactivity { .active_drag .take() .expect("checked for type drag state type above"); + let drag = drag.any_drag().expect("checked for any drag above"); listener(drag.view.clone(), cx); cx.notify(); cx.stop_propagation(); } } + } else { + cx.active_drag = None; } } }); @@ -911,12 +933,16 @@ impl Interactivity { let click_listeners = mem::take(&mut self.click_listeners); let drag_listener = mem::take(&mut self.drag_listener); + let drag_event_listeners = mem::take(&mut self.drag_event_listeners); - if !click_listeners.is_empty() || drag_listener.is_some() { + if !click_listeners.is_empty() + || drag_listener.is_some() + || !drag_event_listeners.is_empty() + { let pending_mouse_down = element_state.pending_mouse_down.clone(); let mouse_down = pending_mouse_down.borrow().clone(); if let Some(mouse_down) = mouse_down { - if let Some(drag_listener) = drag_listener { + if !drag_event_listeners.is_empty() || drag_listener.is_some() { let active_state = element_state.clicked_state.clone(); let interactive_bounds = interactive_bounds.clone(); @@ -924,17 +950,29 @@ impl Interactivity { if cx.active_drag.is_some() { if phase == DispatchPhase::Capture { cx.notify(); + } else if interactive_bounds.visibly_contains(&event.position, cx) + && (event.position - mouse_down.position).magnitude() + > DRAG_THRESHOLD + { + for listener in &drag_event_listeners { + listener(event, cx); + } } } else if phase == DispatchPhase::Bubble && interactive_bounds.visibly_contains(&event.position, cx) && (event.position - mouse_down.position).magnitude() > DRAG_THRESHOLD { *active_state.borrow_mut() = ElementClickedState::default(); - let cursor_offset = event.position - bounds.origin; - let drag = drag_listener(cursor_offset, cx); - cx.active_drag = Some(drag); - cx.notify(); - cx.stop_propagation(); + if let Some(drag_listener) = &drag_listener { + let cursor_offset = event.position - bounds.origin; + let drag = drag_listener(cursor_offset, cx); + cx.active_drag = Some(AnyDragState::AnyDrag(drag)); + cx.notify(); + cx.stop_propagation(); + } + for listener in &drag_event_listeners { + listener(event, cx); + } } }); } @@ -1197,7 +1235,7 @@ impl Interactivity { if let Some(drag) = cx.active_drag.take() { 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() + if Some(*state_type) == drag.entity_type() && group_bounds.contains_point(&mouse_position) { style.refine(&group_drag_style.style); @@ -1206,7 +1244,7 @@ impl Interactivity { } for (state_type, drag_over_style) in &self.drag_over_styles { - if *state_type == drag.view.entity_type() + if Some(*state_type) == drag.entity_type() && bounds .intersect(&cx.content_mask().bounds) .contains_point(&mouse_position) @@ -1263,6 +1301,7 @@ impl Default for Interactivity { action_listeners: SmallVec::new(), drop_listeners: SmallVec::new(), click_listeners: SmallVec::new(), + drag_event_listeners: SmallVec::new(), drag_listener: None, hover_listener: None, tooltip_builder: None, diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 8eb14769bf..e83f3012a5 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -1159,12 +1159,15 @@ impl<'a> WindowContext<'a> { }); if let Some(active_drag) = self.app.active_drag.take() { - self.with_z_index(1, |cx| { - let offset = cx.mouse_position() - active_drag.cursor_offset; - let available_space = size(AvailableSpace::MinContent, AvailableSpace::MinContent); - active_drag.view.draw(offset, available_space, cx); - cx.active_drag = Some(active_drag); - }); + if let Some(active_drag) = active_drag.any_drag() { + self.with_z_index(1, |cx| { + let offset = cx.mouse_position() - active_drag.cursor_offset; + let available_space = + size(AvailableSpace::MinContent, AvailableSpace::MinContent); + active_drag.view.draw(offset, available_space, cx); + }); + } + self.active_drag = Some(active_drag); } else if let Some(active_tooltip) = self.app.active_tooltip.take() { self.with_z_index(1, |cx| { let available_space = size(AvailableSpace::MinContent, AvailableSpace::MinContent); @@ -1240,10 +1243,10 @@ impl<'a> WindowContext<'a> { FileDropEvent::Entered { position, files } => { self.window.mouse_position = position; if self.active_drag.is_none() { - self.active_drag = Some(AnyDrag { + self.active_drag = Some(crate::AnyDragState::AnyDrag(AnyDrag { view: self.build_view(|_| files).into(), cursor_offset: position, - }); + })); } InputEvent::MouseDown(MouseDownEvent { position, diff --git a/crates/terminal2/src/terminal2.rs b/crates/terminal2/src/terminal2.rs index 761bee26b2..197b912b1b 100644 --- a/crates/terminal2/src/terminal2.rs +++ b/crates/terminal2/src/terminal2.rs @@ -1104,7 +1104,12 @@ impl Terminal { } } - pub fn mouse_drag(&mut self, e: MouseMoveEvent, origin: Point, region: Bounds) { + pub fn mouse_drag( + &mut self, + e: &MouseMoveEvent, + origin: Point, + region: Bounds, + ) { let position = e.position - origin; self.last_mouse_position = Some(position); @@ -1130,7 +1135,7 @@ impl Terminal { } } - fn drag_line_delta(&mut self, e: MouseMoveEvent, region: Bounds) -> Option { + fn drag_line_delta(&mut self, e: &MouseMoveEvent, region: Bounds) -> Option { //TODO: Why do these need to be doubled? Probably the same problem that the IME has let top = region.origin.y + (self.last_content.size.line_height * 2.); let bottom = region.lower_left().y - (self.last_content.size.line_height * 2.); diff --git a/crates/terminal_view2/Cargo.toml b/crates/terminal_view2/Cargo.toml index 12e2c06504..9654bed7f5 100644 --- a/crates/terminal_view2/Cargo.toml +++ b/crates/terminal_view2/Cargo.toml @@ -21,6 +21,7 @@ workspace = { package = "workspace2", path = "../workspace2" } db = { package = "db2", path = "../db2" } procinfo = { git = "https://github.com/zed-industries/wezterm", rev = "5cd757e5f2eb039ed0c6bb6512223e69d5efc64d", default-features = false } terminal = { package = "terminal2", path = "../terminal2" } +ui = { package = "ui2", path = "../ui2" } smallvec.workspace = true smol.workspace = true mio-extras = "2.0.6" diff --git a/crates/terminal_view2/src/terminal_element.rs b/crates/terminal_view2/src/terminal_element.rs index 7b7c2a3041..96ffbb1ffb 100644 --- a/crates/terminal_view2/src/terminal_element.rs +++ b/crates/terminal_view2/src/terminal_element.rs @@ -1,9 +1,10 @@ use editor::{Cursor, HighlightedRange, HighlightedRangeLine}; use gpui::{ - black, point, px, red, relative, transparent_black, AnyElement, Bounds, Element, ElementId, - Font, FontStyle, FontWeight, HighlightStyle, Hsla, IntoElement, LayoutId, Pixels, Point, Rgba, - ShapedLine, Style, TextRun, TextStyle, TextSystem, UnderlineStyle, ViewContext, WeakModel, - WhiteSpace, WindowContext, + black, div, point, px, red, relative, transparent_black, AnyElement, AvailableSpace, Bounds, + Element, ElementId, FocusHandle, Font, FontStyle, FontWeight, HighlightStyle, Hsla, + InteractiveElement, InteractiveElementState, IntoElement, LayoutId, ModelContext, Pixels, + Point, Rgba, ShapedLine, Size, StatefulInteractiveElement, Styled, TextRun, TextStyle, + TextSystem, UnderlineStyle, WeakModel, WhiteSpace, WindowContext, }; use itertools::Itertools; use language::CursorShape; @@ -20,12 +21,11 @@ use terminal::{ IndexedCell, Terminal, TerminalContent, TerminalSize, }; use theme::{ActiveTheme, Theme, ThemeSettings}; +use ui::Tooltip; use std::mem; use std::{fmt::Debug, ops::RangeInclusive}; -use crate::TerminalView; - ///The information generated during layout that is necessary for painting pub struct LayoutState { cells: Vec, @@ -146,14 +146,25 @@ impl LayoutRect { ///We need to keep a reference to the view for mouse events, do we need it for any other terminal stuff, or can we move that to connection? pub struct TerminalElement { terminal: WeakModel, + focus: FocusHandle, focused: bool, cursor_visible: bool, can_navigate_to_selected_word: bool, + interactivity: gpui::Interactivity, } +impl InteractiveElement for TerminalElement { + fn interactivity(&mut self) -> &mut gpui::Interactivity { + &mut self.interactivity + } +} + +impl StatefulInteractiveElement for TerminalElement {} + impl TerminalElement { pub fn new( terminal: WeakModel, + focus: FocusHandle, focused: bool, cursor_visible: bool, can_navigate_to_selected_word: bool, @@ -161,8 +172,10 @@ impl TerminalElement { TerminalElement { terminal, focused, + focus, cursor_visible, can_navigate_to_selected_word, + interactivity: Default::default(), } } @@ -365,7 +378,6 @@ impl TerminalElement { //Setup layout information // todo!(Terminal tooltips) - // let link_style = settings.theme.editor.link_definition; // let tooltip_style = settings.theme.tooltip.clone(); let buffer_font_size = settings.buffer_font_size(cx); @@ -390,6 +402,20 @@ impl TerminalElement { let settings = ThemeSettings::get_global(cx); let theme = cx.theme().clone(); + + let link_style = HighlightStyle { + color: Some(gpui::blue()), + font_weight: None, + font_style: None, + background_color: None, + underline: Some(UnderlineStyle { + thickness: px(1.0), + color: Some(gpui::red()), + wavy: false, + }), + fade_out: None, + }; + let text_style = TextStyle { font_family, font_features, @@ -439,38 +465,19 @@ impl TerminalElement { let last_hovered_word = terminal_handle.update(cx, |terminal, cx| { terminal.set_size(dimensions); terminal.try_sync(cx); - // if self.can_navigate_to_selected_word && terminal.can_navigate_to_selected_word() { - // terminal.last_content.last_hovered_word.clone() - // } else { - None - // } + if self.can_navigate_to_selected_word && terminal.can_navigate_to_selected_word() { + terminal.last_content.last_hovered_word.clone() + } else { + None + } }); - // let hyperlink_tooltip = last_hovered_word.clone().map(|hovered_word| { - // let mut tooltip = Overlay::new( - // Empty::new() - // .contained() - // .constrained() - // .with_width(dimensions.width()) - // .with_height(dimensions.height()) - // .with_tooltip::( - // hovered_word.id, - // hovered_word.word, - // None, - // tooltip_style, - // cx, - // ), - // ) - // .with_position_mode(gpui::OverlayPositionMode::Local) - // .into_any(); - - // tooltip.layout( - // SizeConstraint::new(Point::zero(), cx.window_size()), - // view_state, - // cx, - // ); - // tooltip - // }); + let hyperlink_tooltip = last_hovered_word.clone().map(|hovered_word| { + div() + .size_full() + .id("terminal-element") + .tooltip(move |cx| Tooltip::text(hovered_word.word.clone(), cx)) + }); let TerminalContent { cells, @@ -498,10 +505,9 @@ impl TerminalElement { cells, &text_style, &cx.text_system(), - // todo!(Terminal tooltips) - last_hovered_word, - // .as_ref() - // .map(|last_hovered_word| (link_style, &last_hovered_word.word_match)), + last_hovered_word + .as_ref() + .map(|last_hovered_word| (link_style, &last_hovered_word.word_match)), cx, ); @@ -577,92 +583,95 @@ impl TerminalElement { } } - // todo!() - // fn generic_button_handler( - // connection: WeakModel, - // origin: Point, - // f: impl Fn(&mut Terminal, Point, E, &mut ModelContext), - // ) -> impl Fn(E, &mut TerminalView, &mut EventContext) { - // move |event, _: &mut TerminalView, cx| { - // cx.focus_parent(); - // if let Some(conn_handle) = connection.upgrade() { - // conn_handle.update(cx, |terminal, cx| { - // f(terminal, origin, event, cx); - - // cx.notify(); - // }) - // } - // } - // } - - fn attach_mouse_handlers( - &self, + fn generic_button_handler( + connection: WeakModel, + origin: Point, + focus_handle: FocusHandle, + f: impl Fn(&mut Terminal, Point, &E, &mut ModelContext), + ) -> impl Fn(&E, &mut WindowContext) { + move |event, cx| { + cx.focus(&focus_handle); + if let Some(conn_handle) = connection.upgrade() { + conn_handle.update(cx, |terminal, cx| { + f(terminal, origin, event, cx); + + cx.notify(); + }) + } + } + } + + fn paint_mouse_listeners( + self, origin: Point, - visible_bounds: Bounds, mode: TermMode, - cx: &mut ViewContext, - ) { - // todo!() - // let connection = self.terminal; + bounds: Bounds, + cx: &mut WindowContext, + ) -> Self { + let focus = self.focus.clone(); + let connection = self.terminal.clone(); - // let mut region = MouseRegion::new::(cx.view_id(), 0, visible_bounds); + self.on_mouse_down(gpui::MouseButton::Left, { + let connection = connection.clone(); + let focus = focus.clone(); + move |e, cx| { + cx.focus(&focus); + //todo!(context menu) + // v.context_menu.update(cx, |menu, _cx| menu.delay_cancel()); + if let Some(conn_handle) = connection.upgrade() { + conn_handle.update(cx, |terminal, cx| { + terminal.mouse_down(&e, origin); - // // Terminal Emulator controlled behavior: - // region = region - // // Start selections - // .on_down(MouseButton::Left, move |event, v: &mut TerminalView, cx| { - // let terminal_view = cx.handle(); - // cx.focus(&terminal_view); - // v.context_menu.update(cx, |menu, _cx| menu.delay_cancel()); - // if let Some(conn_handle) = connection.upgrade() { - // conn_handle.update(cx, |terminal, cx| { - // terminal.mouse_down(&event, origin); + cx.notify(); + }) + } + } + }) + .on_drag_event({ + let connection = connection.clone(); + let focus = focus.clone(); + move |e, cx| { + if focus.is_focused(cx) { + if let Some(conn_handle) = connection.upgrade() { + conn_handle.update(cx, |terminal, cx| { + terminal.mouse_drag(e, origin, bounds); + cx.notify(); + }) + } + } + } + }) + .on_mouse_up( + gpui::MouseButton::Left, + TerminalElement::generic_button_handler( + connection.clone(), + origin, + focus.clone(), + move |terminal, origin, e, cx| { + terminal.mouse_up(&e, origin, cx); + }, + ), + ) + .on_click({ + let connection = connection.clone(); + move |e, cx| { + if e.down.button == gpui::MouseButton::Right { + let mouse_mode = if let Some(conn_handle) = connection.upgrade() { + conn_handle.update(cx, |terminal, _cx| { + terminal.mouse_mode(e.down.modifiers.shift) + }) + } else { + // If we can't get the model handle, probably can't deploy the context menu + true + }; + if !mouse_mode { + //todo!(context menu) + // view.deploy_context_menu(e.position, cx); + } + } + } + }) - // cx.notify(); - // }) - // } - // }) - // // Update drag selections - // .on_drag(MouseButton::Left, move |event, _: &mut TerminalView, cx| { - // if event.end { - // return; - // } - - // if cx.is_self_focused() { - // if let Some(conn_handle) = connection.upgrade() { - // conn_handle.update(cx, |terminal, cx| { - // terminal.mouse_drag(event, origin); - // cx.notify(); - // }) - // } - // } - // }) - // // Copy on up behavior - // .on_up( - // MouseButton::Left, - // TerminalElement::generic_button_handler( - // connection, - // origin, - // move |terminal, origin, e, cx| { - // terminal.mouse_up(&e, origin, cx); - // }, - // ), - // ) - // // Context menu - // .on_click( - // MouseButton::Right, - // move |event, view: &mut TerminalView, cx| { - // let mouse_mode = if let Some(conn_handle) = connection.upgrade() { - // conn_handle.update(cx, |terminal, _cx| terminal.mouse_mode(event.shift)) - // } else { - // // If we can't get the model handle, probably can't deploy the context menu - // true - // }; - // if !mouse_mode { - // view.deploy_context_menu(event.position, cx); - // } - // }, - // ) // .on_move(move |event, _: &mut TerminalView, cx| { // if cx.is_self_focused() { // if let Some(conn_handle) = connection.upgrade() { @@ -733,71 +742,88 @@ impl TerminalElement { } impl Element for TerminalElement { - type State = (); + type State = InteractiveElementState; fn layout( &mut self, element_state: Option, cx: &mut WindowContext<'_>, ) -> (LayoutId, Self::State) { - let mut style = Style::default(); - style.size.width = relative(1.).into(); - style.size.height = relative(1.).into(); - let layout_id = cx.request_layout(&style, None); + let (layout_id, interactive_state) = + self.interactivity + .layout(element_state, cx, |mut style, cx| { + style.size.width = relative(1.).into(); + style.size.height = relative(1.).into(); + let layout_id = cx.request_layout(&style, None); - (layout_id, ()) + layout_id + }); + + (layout_id, interactive_state) } - fn paint(self, bounds: Bounds, _: &mut Self::State, cx: &mut WindowContext<'_>) { - let layout = self.compute_layout(bounds, cx); + fn paint(self, bounds: Bounds, state: &mut Self::State, cx: &mut WindowContext<'_>) { + let mut layout = self.compute_layout(bounds, cx); let theme = cx.theme(); + cx.paint_quad( bounds, Default::default(), - theme.colors().editor_background, + layout.background_color, Default::default(), Hsla::default(), ); let origin = bounds.origin + Point::new(layout.gutter, px(0.)); - for rect in &layout.rects { - rect.paint(origin, &layout, cx); - } + let this = self.paint_mouse_listeners(origin, layout.mode, bounds, cx); - cx.with_z_index(1, |cx| { - for (relative_highlighted_range, color) in layout.relative_highlighted_ranges.iter() { - if let Some((start_y, highlighted_range_lines)) = - to_highlighted_range_lines(relative_highlighted_range, &layout, origin) - { - let hr = HighlightedRange { - start_y, //Need to change this - line_height: layout.size.line_height, - lines: highlighted_range_lines, - color: color.clone(), - //Copied from editor. TODO: move to theme or something - corner_radius: 0.15 * layout.size.line_height, - }; - hr.paint(bounds, cx); + this.interactivity + .paint(bounds, bounds.size, state, cx, |_, _, cx| { + for rect in &layout.rects { + rect.paint(origin, &layout, cx); } - } - }); - cx.with_z_index(2, |cx| { - for cell in &layout.cells { - cell.paint(origin, &layout, bounds, cx); - } - }); + cx.with_z_index(1, |cx| { + for (relative_highlighted_range, color) in + layout.relative_highlighted_ranges.iter() + { + if let Some((start_y, highlighted_range_lines)) = + to_highlighted_range_lines(relative_highlighted_range, &layout, origin) + { + let hr = HighlightedRange { + start_y, //Need to change this + line_height: layout.size.line_height, + lines: highlighted_range_lines, + color: color.clone(), + //Copied from editor. TODO: move to theme or something + corner_radius: 0.15 * layout.size.line_height, + }; + hr.paint(bounds, cx); + } + } + }); - cx.with_z_index(3, |cx| { - if let Some(cursor) = &layout.cursor { - cursor.paint(origin, cx); - } - }); + cx.with_z_index(2, |cx| { + for cell in &layout.cells { + cell.paint(origin, &layout, bounds, cx); + } + }); - // if let Some(element) = &mut element_state.hyperlink_tooltip { - // element.paint(origin, visible_bounds, view_state, cx) - // } + if this.cursor_visible { + cx.with_z_index(3, |cx| { + if let Some(cursor) = &layout.cursor { + cursor.paint(origin, cx); + } + }); + } + + if let Some(element) = layout.hyperlink_tooltip.take() { + let width: AvailableSpace = bounds.size.width.into(); + let height: AvailableSpace = bounds.size.height.into(); + element.draw(origin, Size { width, height }, cx) + } + }); } // todo!() remove? diff --git a/crates/terminal_view2/src/terminal_view.rs b/crates/terminal_view2/src/terminal_view.rs index 63ed101f50..5b864f4a5e 100644 --- a/crates/terminal_view2/src/terminal_view.rs +++ b/crates/terminal_view2/src/terminal_view.rs @@ -555,6 +555,7 @@ impl Render for TerminalView { .on_action(cx.listener(TerminalView::select_all)) .child(TerminalElement::new( terminal_handle, + self.focus_handle.clone(), focused, self.should_show_cursor(focused, cx), self.can_navigate_to_selected_word,