fix(clipboard): clipboard message (#4009)

* fix clipboard message

* fix clipboard message gitter

* style(fmt): rustfmt
This commit is contained in:
Aram Drevekenin 2025-02-20 17:14:43 +01:00 committed by GitHub
parent 9edad32ee1
commit f0680fdeb9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 241 additions and 90 deletions

View file

@ -24,6 +24,8 @@ struct State {
active_tab_idx: usize, active_tab_idx: usize,
mode_info: ModeInfo, mode_info: ModeInfo,
tab_line: Vec<LinePart>, tab_line: Vec<LinePart>,
text_copy_destination: Option<CopyDestination>,
display_system_clipboard_failure: bool,
} }
static ARROW_SEPARATOR: &str = ""; static ARROW_SEPARATOR: &str = "";
@ -37,6 +39,9 @@ impl ZellijPlugin for State {
EventType::TabUpdate, EventType::TabUpdate,
EventType::ModeUpdate, EventType::ModeUpdate,
EventType::Mouse, EventType::Mouse,
EventType::CopyToClipboard,
EventType::InputReceived,
EventType::SystemClipboardFailure,
]); ]);
} }
@ -77,6 +82,32 @@ impl ZellijPlugin for State {
}, },
_ => {}, _ => {},
}, },
Event::CopyToClipboard(copy_destination) => {
match self.text_copy_destination {
Some(text_copy_destination) => {
if text_copy_destination != copy_destination {
should_render = true;
}
},
None => {
should_render = true;
},
}
self.text_copy_destination = Some(copy_destination);
},
Event::SystemClipboardFailure => {
should_render = true;
self.display_system_clipboard_failure = true;
},
Event::InputReceived => {
if self.text_copy_destination.is_some()
|| self.display_system_clipboard_failure == true
{
should_render = true;
}
self.text_copy_destination = None;
self.display_system_clipboard_failure = false;
},
_ => { _ => {
eprintln!("Got unrecognized event: {:?}", event); eprintln!("Got unrecognized event: {:?}", event);
}, },
@ -85,60 +116,110 @@ impl ZellijPlugin for State {
} }
fn render(&mut self, _rows: usize, cols: usize) { fn render(&mut self, _rows: usize, cols: usize) {
if self.tabs.is_empty() { if let Some(copy_destination) = self.text_copy_destination {
return; let hint = text_copied_hint(copy_destination).part;
}
let mut all_tabs: Vec<LinePart> = vec![]; let background = self.mode_info.style.colors.text_unselected.background;
let mut active_tab_index = 0; match background {
let mut active_swap_layout_name = None; PaletteColor::Rgb((r, g, b)) => {
let mut is_swap_layout_dirty = false; print!("{}\u{1b}[48;2;{};{};{}m\u{1b}[0K", hint, r, g, b);
let mut is_alternate_tab = false; },
for t in &mut self.tabs { PaletteColor::EightBit(color) => {
let mut tabname = t.name.clone(); print!("{}\u{1b}[48;5;{}m\u{1b}[0K", hint, color);
if t.active && self.mode_info.mode == InputMode::RenameTab { },
if tabname.is_empty() {
tabname = String::from("Enter name...");
}
active_tab_index = t.position;
} else if t.active {
active_tab_index = t.position;
is_swap_layout_dirty = t.is_swap_layout_dirty;
active_swap_layout_name = t.active_swap_layout_name.clone();
} }
let tab = tab_style( } else if self.display_system_clipboard_failure {
tabname, let hint = system_clipboard_error().part;
t, let background = self.mode_info.style.colors.text_unselected.background;
is_alternate_tab, match background {
PaletteColor::Rgb((r, g, b)) => {
print!("{}\u{1b}[48;2;{};{};{}m\u{1b}[0K", hint, r, g, b);
},
PaletteColor::EightBit(color) => {
print!("{}\u{1b}[48;5;{}m\u{1b}[0K", hint, color);
},
}
} else {
if self.tabs.is_empty() {
return;
}
let mut all_tabs: Vec<LinePart> = vec![];
let mut active_tab_index = 0;
let mut active_swap_layout_name = None;
let mut is_swap_layout_dirty = false;
let mut is_alternate_tab = false;
for t in &mut self.tabs {
let mut tabname = t.name.clone();
if t.active && self.mode_info.mode == InputMode::RenameTab {
if tabname.is_empty() {
tabname = String::from("Enter name...");
}
active_tab_index = t.position;
} else if t.active {
active_tab_index = t.position;
is_swap_layout_dirty = t.is_swap_layout_dirty;
active_swap_layout_name = t.active_swap_layout_name.clone();
}
let tab = tab_style(
tabname,
t,
is_alternate_tab,
self.mode_info.style.colors,
self.mode_info.capabilities,
);
is_alternate_tab = !is_alternate_tab;
all_tabs.push(tab);
}
self.tab_line = tab_line(
self.mode_info.session_name.as_deref(),
all_tabs,
active_tab_index,
cols.saturating_sub(1),
self.mode_info.style.colors, self.mode_info.style.colors,
self.mode_info.capabilities, self.mode_info.capabilities,
self.mode_info.style.hide_session_name,
self.mode_info.mode,
&active_swap_layout_name,
is_swap_layout_dirty,
); );
is_alternate_tab = !is_alternate_tab; let output = self
all_tabs.push(tab); .tab_line
} .iter()
self.tab_line = tab_line( .fold(String::new(), |output, part| output + &part.part);
self.mode_info.session_name.as_deref(), let background = self.mode_info.style.colors.text_unselected.background;
all_tabs, match background {
active_tab_index, PaletteColor::Rgb((r, g, b)) => {
cols.saturating_sub(1), print!("{}\u{1b}[48;2;{};{};{}m\u{1b}[0K", output, r, g, b);
self.mode_info.style.colors, },
self.mode_info.capabilities, PaletteColor::EightBit(color) => {
self.mode_info.style.hide_session_name, print!("{}\u{1b}[48;5;{}m\u{1b}[0K", output, color);
self.mode_info.mode, },
&active_swap_layout_name, }
is_swap_layout_dirty,
);
let output = self
.tab_line
.iter()
.fold(String::new(), |output, part| output + &part.part);
let background = self.mode_info.style.colors.text_unselected.background;
match background {
PaletteColor::Rgb((r, g, b)) => {
print!("{}\u{1b}[48;2;{};{};{}m\u{1b}[0K", output, r, g, b);
},
PaletteColor::EightBit(color) => {
print!("{}\u{1b}[48;5;{}m\u{1b}[0K", output, color);
},
} }
} }
} }
pub fn text_copied_hint(copy_destination: CopyDestination) -> LinePart {
let hint = match copy_destination {
CopyDestination::Command => "Text piped to external command",
#[cfg(not(target_os = "macos"))]
CopyDestination::Primary => "Text copied to system primary selection",
#[cfg(target_os = "macos")] // primary selection does not exist on macos
CopyDestination::Primary => "Text copied to system clipboard",
CopyDestination::System => "Text copied to system clipboard",
};
LinePart {
part: serialize_text(&Text::new(&hint).color_range(2, ..).opaque()),
len: hint.len(),
tab_index: None,
}
}
pub fn system_clipboard_error() -> LinePart {
let hint = " Error using the system clipboard.";
LinePart {
part: serialize_text(&Text::new(&hint).color_range(2, ..).opaque()),
len: hint.len(),
tab_index: None,
}
}

View file

@ -329,7 +329,7 @@ impl State {
let active_tab = self.tabs.iter().find(|t| t.active); let active_tab = self.tabs.iter().find(|t| t.active);
if let Some(copy_destination) = self.text_copy_destination { if let Some(copy_destination) = self.text_copy_destination {
text_copied_hint(&self.mode_info.style.colors, copy_destination) text_copied_hint(copy_destination)
} else if self.display_system_clipboard_failure { } else if self.display_system_clipboard_failure {
system_clipboard_error(&self.mode_info.style.colors) system_clipboard_error(&self.mode_info.style.colors)
} else if let Some(active_tab) = active_tab { } else if let Some(active_tab) = active_tab {

View file

@ -24,7 +24,7 @@ pub fn one_line_ui(
clipboard_failure: bool, clipboard_failure: bool,
) -> LinePart { ) -> LinePart {
if let Some(text_copied_to_clipboard_destination) = text_copied_to_clipboard_destination { if let Some(text_copied_to_clipboard_destination) = text_copied_to_clipboard_destination {
return text_copied_hint(&help.style.colors, text_copied_to_clipboard_destination); return text_copied_hint(text_copied_to_clipboard_destination);
} }
if clipboard_failure { if clipboard_failure {
return system_clipboard_error(&help.style.colors); return system_clipboard_error(&help.style.colors);

View file

@ -348,8 +348,7 @@ pub fn keybinds(help: &ModeInfo, tip_name: &str, max_width: usize) -> LinePart {
best_effort_shortcut_list(help, tip_body.short, max_width) best_effort_shortcut_list(help, tip_body.short, max_width)
} }
pub fn text_copied_hint(palette: &Styling, copy_destination: CopyDestination) -> LinePart { pub fn text_copied_hint(copy_destination: CopyDestination) -> LinePart {
let green_color = palette_match!(palette.text_unselected.emphasis_2);
let hint = match copy_destination { let hint = match copy_destination {
CopyDestination::Command => "Text piped to external command", CopyDestination::Command => "Text piped to external command",
#[cfg(not(target_os = "macos"))] #[cfg(not(target_os = "macos"))]
@ -359,7 +358,7 @@ pub fn text_copied_hint(palette: &Styling, copy_destination: CopyDestination) ->
CopyDestination::System => "Text copied to system clipboard", CopyDestination::System => "Text copied to system clipboard",
}; };
LinePart { LinePart {
part: Style::new().fg(green_color).bold().paint(hint).to_string(), part: serialize_text(&Text::new(&hint).color_range(2, ..).opaque()),
len: hint.len(), len: hint.len(),
} }
} }

View file

@ -47,7 +47,9 @@ pub(crate) fn route_action(
let mut should_break = false; let mut should_break = false;
let err_context = || format!("failed to route action for client {client_id}"); let err_context = || format!("failed to route action for client {client_id}");
if !action.is_mouse_motion() { if !action.is_mouse_action() {
// mouse actions should only send InputReceived to plugins
// if they do not result in text being marked, this is handled in Tab
senders senders
.send_to_plugin(PluginInstruction::Update(vec![( .send_to_plugin(PluginInstruction::Update(vec![(
None, None,

View file

@ -3858,12 +3858,22 @@ pub(crate) fn screen_thread_main(
screen.unblock_input()?; screen.unblock_input()?;
}, },
ScreenInstruction::MouseEvent(event, client_id) => { ScreenInstruction::MouseEvent(event, client_id) => {
let state_changed = screen let mouse_effect = screen
.get_active_tab_mut(client_id) .get_active_tab_mut(client_id)
.and_then(|tab| tab.handle_mouse_event(&event, client_id))?; .and_then(|tab| tab.handle_mouse_event(&event, client_id))?;
if state_changed { if mouse_effect.state_changed {
screen.log_and_report_session_state()?; screen.log_and_report_session_state()?;
} }
if !mouse_effect.leave_clipboard_message {
let _ = screen
.bus
.senders
.send_to_plugin(PluginInstruction::Update(vec![(
None,
Some(client_id),
Event::InputReceived,
)]));
}
screen.render(None)?; screen.render(None)?;
}, },
ScreenInstruction::Copy(client_id) => { ScreenInstruction::Copy(client_id) => {

View file

@ -147,6 +147,33 @@ enum BufferedTabInstruction {
HoldPane(PaneId, Option<i32>, bool, RunCommand), // Option<i32> is the exit status, bool is is_first_run HoldPane(PaneId, Option<i32>, bool, RunCommand), // Option<i32> is the exit status, bool is is_first_run
} }
#[derive(Debug, Default, Copy, Clone)]
pub struct MouseEffect {
pub state_changed: bool,
pub leave_clipboard_message: bool,
}
impl MouseEffect {
pub fn state_changed() -> Self {
MouseEffect {
state_changed: true,
leave_clipboard_message: false,
}
}
pub fn leave_clipboard_message() -> Self {
MouseEffect {
state_changed: false,
leave_clipboard_message: true,
}
}
pub fn state_changed_and_leave_clipboard_message() -> Self {
MouseEffect {
state_changed: true,
leave_clipboard_message: true,
}
}
}
pub(crate) struct Tab { pub(crate) struct Tab {
pub index: usize, pub index: usize,
pub position: usize, pub position: usize,
@ -3225,7 +3252,7 @@ impl Tab {
point: &Position, point: &Position,
lines: usize, lines: usize,
client_id: ClientId, client_id: ClientId,
) -> Result<bool> { ) -> Result<MouseEffect> {
let err_context = || { let err_context = || {
format!("failed to handle scrollwheel up at position {point:?} for client {client_id}") format!("failed to handle scrollwheel up at position {point:?} for client {client_id}")
}; };
@ -3246,7 +3273,7 @@ impl Tab {
pane.scroll_up(lines, client_id); pane.scroll_up(lines, client_id);
} }
} }
Ok(false) Ok(MouseEffect::default())
} }
pub fn handle_scrollwheel_down( pub fn handle_scrollwheel_down(
@ -3254,7 +3281,7 @@ impl Tab {
point: &Position, point: &Position,
lines: usize, lines: usize,
client_id: ClientId, client_id: ClientId,
) -> Result<bool> { ) -> Result<MouseEffect> {
let err_context = || { let err_context = || {
format!( format!(
"failed to handle scrollwheel down at position {point:?} for client {client_id}" "failed to handle scrollwheel down at position {point:?} for client {client_id}"
@ -3283,7 +3310,7 @@ impl Tab {
} }
} }
} }
Ok(false) Ok(MouseEffect::default())
} }
fn get_pane_at( fn get_pane_at(
@ -3353,7 +3380,11 @@ impl Tab {
// returns true if the mouse event caused some sort of tab/pane state change that needs to be // returns true if the mouse event caused some sort of tab/pane state change that needs to be
// reported to plugins // reported to plugins
pub fn handle_mouse_event(&mut self, event: &MouseEvent, client_id: ClientId) -> Result<bool> { pub fn handle_mouse_event(
&mut self,
event: &MouseEvent,
client_id: ClientId,
) -> Result<MouseEffect> {
let err_context = let err_context =
|| format!("failed to handle mouse event {event:?} for client {client_id}"); || format!("failed to handle mouse event {event:?} for client {client_id}");
@ -3423,7 +3454,7 @@ impl Tab {
&mut self, &mut self,
event: &MouseEvent, event: &MouseEvent,
client_id: ClientId, client_id: ClientId,
) -> Result<bool> { ) -> Result<MouseEffect> {
let err_context = let err_context =
|| format!("failed to handle mouse event {event:?} for client {client_id}"); || format!("failed to handle mouse event {event:?} for client {client_id}");
let floating_panes_are_visible = self.floating_panes.panes_are_visible(); let floating_panes_are_visible = self.floating_panes.panes_are_visible();
@ -3436,7 +3467,7 @@ impl Tab {
let intercepted = pane_at_position.intercept_mouse_event_on_frame(&event, client_id); let intercepted = pane_at_position.intercept_mouse_event_on_frame(&event, client_id);
if intercepted { if intercepted {
self.set_force_render(); self.set_force_render();
return Ok(true); return Ok(MouseEffect::state_changed());
} else if floating_panes_are_visible { } else if floating_panes_are_visible {
// start moving if floating pane // start moving if floating pane
let search_selectable = false; let search_selectable = false;
@ -3446,7 +3477,7 @@ impl Tab {
{ {
self.swap_layouts.set_is_floating_damaged(); self.swap_layouts.set_is_floating_damaged();
self.set_force_render(); self.set_force_render();
return Ok(true); return Ok(MouseEffect::state_changed());
} }
} }
} else { } else {
@ -3466,19 +3497,26 @@ impl Tab {
} }
} else { } else {
// start selection for copy/paste // start selection for copy/paste
let mut leave_clipboard_message = false;
pane_at_position.start_selection(&relative_position, client_id); pane_at_position.start_selection(&relative_position, client_id);
if pane_at_position.get_selected_text().is_some() {
leave_clipboard_message = true;
}
if let PaneId::Terminal(_) = pane_at_position.pid() { if let PaneId::Terminal(_) = pane_at_position.pid() {
self.selecting_with_mouse_in_pane = Some(pane_at_position.pid()); self.selecting_with_mouse_in_pane = Some(pane_at_position.pid());
} }
if leave_clipboard_message {
return Ok(MouseEffect::leave_clipboard_message());
}
} }
} }
Ok(false) Ok(MouseEffect::default())
} }
fn handle_inactive_pane_left_mouse_press( fn handle_inactive_pane_left_mouse_press(
&mut self, &mut self,
event: &MouseEvent, event: &MouseEvent,
client_id: ClientId, client_id: ClientId,
) -> Result<bool> { ) -> Result<MouseEffect> {
let err_context = let err_context =
|| format!("failed to handle mouse event {event:?} for client {client_id}"); || format!("failed to handle mouse event {event:?} for client {client_id}");
if !self.floating_panes.panes_are_visible() { if !self.floating_panes.panes_are_visible() {
@ -3492,7 +3530,7 @@ impl Tab {
// focus it // focus it
self.show_floating_panes(); self.show_floating_panes();
self.floating_panes.focus_pane(pane_id, client_id); self.floating_panes.focus_pane(pane_id, client_id);
return Ok(true); return Ok(MouseEffect::state_changed());
} }
} }
let active_pane_id_before_click = self let active_pane_id_before_click = self
@ -3514,25 +3552,30 @@ impl Tab {
// we do this because this might be the beginning of the user dragging a pane // we do this because this might be the beginning of the user dragging a pane
// that was not focused // that was not focused
// TODO: rename move_pane_with_mouse to "start_moving_pane_with_mouse"? // TODO: rename move_pane_with_mouse to "start_moving_pane_with_mouse"?
return Ok(self let moved_pane_with_mouse = self
.floating_panes .floating_panes
.move_pane_with_mouse(event.position, search_selectable)); .move_pane_with_mouse(event.position, search_selectable);
if moved_pane_with_mouse {
return Ok(MouseEffect::state_changed());
} else {
return Ok(MouseEffect::default());
}
} }
let active_pane_id_after_click = self let active_pane_id_after_click = self
.get_active_pane_id(client_id) .get_active_pane_id(client_id)
.ok_or_else(|| anyhow!("Failed to find pane at position"))?; .ok_or_else(|| anyhow!("Failed to find pane at position"))?;
if active_pane_id_before_click != active_pane_id_after_click { if active_pane_id_before_click != active_pane_id_after_click {
// focus changed, need to report it // focus changed, need to report it
Ok(true) Ok(MouseEffect::state_changed())
} else { } else {
Ok(false) Ok(MouseEffect::default())
} }
} }
fn handle_left_mouse_motion( fn handle_left_mouse_motion(
&mut self, &mut self,
event: &MouseEvent, event: &MouseEvent,
client_id: ClientId, client_id: ClientId,
) -> Result<bool> { ) -> Result<MouseEffect> {
let err_context = let err_context =
|| format!("failed to handle mouse event {event:?} for client {client_id}"); || format!("failed to handle mouse event {event:?} for client {client_id}");
let pane_is_being_moved_with_mouse = self.floating_panes.pane_is_being_moved_with_mouse(); let pane_is_being_moved_with_mouse = self.floating_panes.pane_is_being_moved_with_mouse();
@ -3547,7 +3590,7 @@ impl Tab {
{ {
self.swap_layouts.set_is_floating_damaged(); self.swap_layouts.set_is_floating_damaged();
self.set_force_render(); self.set_force_render();
return Ok(true); return Ok(MouseEffect::state_changed());
} }
} else if let Some(pane_id_with_selection) = self.selecting_with_mouse_in_pane { } else if let Some(pane_id_with_selection) = self.selecting_with_mouse_in_pane {
if let Some(pane_with_selection) = self.get_pane_with_id_mut(pane_id_with_selection) { if let Some(pane_with_selection) = self.get_pane_with_id_mut(pane_id_with_selection) {
@ -3563,15 +3606,16 @@ impl Tab {
self.write_mouse_event_to_active_pane(event, client_id)?; self.write_mouse_event_to_active_pane(event, client_id)?;
} }
} }
Ok(false) Ok(MouseEffect::default())
} }
fn handle_left_mouse_release( fn handle_left_mouse_release(
&mut self, &mut self,
event: &MouseEvent, event: &MouseEvent,
client_id: ClientId, client_id: ClientId,
) -> Result<bool> { ) -> Result<MouseEffect> {
let err_context = let err_context =
|| format!("failed to handle mouse event {event:?} for client {client_id}"); || format!("failed to handle mouse event {event:?} for client {client_id}");
let mut leave_clipboard_message = false;
let floating_panes_are_visible = self.floating_panes.panes_are_visible(); let floating_panes_are_visible = self.floating_panes.panes_are_visible();
let copy_on_release = self.copy_on_select; let copy_on_release = self.copy_on_select;
@ -3606,6 +3650,7 @@ impl Tab {
let selected_text = pane_with_selection.get_selected_text(); let selected_text = pane_with_selection.get_selected_text();
if let Some(selected_text) = selected_text { if let Some(selected_text) = selected_text {
leave_clipboard_message = true;
self.write_selection_to_clipboard(&selected_text) self.write_selection_to_clipboard(&selected_text)
.with_context(err_context)?; .with_context(err_context)?;
} }
@ -3621,10 +3666,18 @@ impl Tab {
} else { } else {
self.write_mouse_event_to_active_pane(event, client_id)?; self.write_mouse_event_to_active_pane(event, client_id)?;
} }
Ok(false) if leave_clipboard_message {
Ok(MouseEffect::leave_clipboard_message())
} else {
Ok(MouseEffect::default())
}
} }
pub fn handle_right_click(&mut self, event: &MouseEvent, client_id: ClientId) -> Result<bool> { pub fn handle_right_click(
&mut self,
event: &MouseEvent,
client_id: ClientId,
) -> Result<MouseEffect> {
let err_context = || format!("failed to handle mouse right click for client {client_id}"); let err_context = || format!("failed to handle mouse right click for client {client_id}");
let absolute_position = event.position; let absolute_position = event.position;
@ -3655,10 +3708,14 @@ impl Tab {
} }
} }
}; };
Ok(false) Ok(MouseEffect::default())
} }
fn handle_middle_click(&mut self, event: &MouseEvent, client_id: ClientId) -> Result<bool> { fn handle_middle_click(
&mut self,
event: &MouseEvent,
client_id: ClientId,
) -> Result<MouseEffect> {
let err_context = || format!("failed to handle mouse middle click for client {client_id}"); let err_context = || format!("failed to handle mouse middle click for client {client_id}");
let absolute_position = event.position; let absolute_position = event.position;
@ -3687,10 +3744,14 @@ impl Tab {
} }
} }
}; };
Ok(false) Ok(MouseEffect::default())
} }
fn handle_mouse_no_click(&mut self, event: &MouseEvent, client_id: ClientId) -> Result<bool> { fn handle_mouse_no_click(
&mut self,
event: &MouseEvent,
client_id: ClientId,
) -> Result<MouseEffect> {
let err_context = || format!("failed to handle mouse no click for client {client_id}"); let err_context = || format!("failed to handle mouse no click for client {client_id}");
let absolute_position = event.position; let absolute_position = event.position;
@ -3719,7 +3780,7 @@ impl Tab {
} }
} }
}; };
Ok(false) Ok(MouseEffect::leave_clipboard_message())
} }
fn unselectable_pane_at_position(&mut self, point: &Position) -> Option<&mut Box<dyn Pane>> { fn unselectable_pane_at_position(&mut self, point: &Position) -> Option<&mut Box<dyn Pane>> {

View file

@ -10,7 +10,7 @@ use crate::data::{Direction, KeyWithModifier, PaneId, Resize};
use crate::data::{FloatingPaneCoordinates, InputMode}; use crate::data::{FloatingPaneCoordinates, InputMode};
use crate::home::{find_default_config_dir, get_layout_dir}; use crate::home::{find_default_config_dir, get_layout_dir};
use crate::input::config::{Config, ConfigError, KdlError}; use crate::input::config::{Config, ConfigError, KdlError};
use crate::input::mouse::{MouseEvent, MouseEventType}; use crate::input::mouse::MouseEvent;
use crate::input::options::OnForceClose; use crate::input::options::OnForceClose;
use miette::{NamedSource, Report}; use miette::{NamedSource, Report};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -800,11 +800,9 @@ impl Action {
_ => false, _ => false,
} }
} }
pub fn is_mouse_motion(&self) -> bool { pub fn is_mouse_action(&self) -> bool {
if let Action::MouseEvent(mouse_event) = self { if let Action::MouseEvent(_mouse_event) = self {
if let MouseEventType::Motion = mouse_event.event_type { return true;
return true;
}
} }
false false
} }