namespace Terminal.Gui; public partial class View { /// /// Gets or sets whether the will highlight the view visually when the mouse button is pressed/released. /// public bool HighlightOnPress { get; set; } /// Gets or sets a value indicating whether this want continuous button pressed event. public virtual bool WantContinuousButtonPressed { get; set; } /// Gets or sets a value indicating whether this wants mouse position reports. /// if want mouse position reports; otherwise, . public virtual bool WantMousePositionReports { get; set; } /// Event fired when a mouse event occurs. /// /// /// The coordinates are relative to . /// /// public event EventHandler MouseEvent; /// Event fired when a mouse click occurs. /// /// /// Fired when the mouse is either clicked or double-clicked. Check /// to see which button was clicked. /// /// /// The coordinates are relative to . /// /// public event EventHandler MouseClick; /// Event fired when the mouse moves into the View's . public event EventHandler MouseEnter; /// Event fired when the mouse leaves the View's . public event EventHandler MouseLeave; // TODO: OnMouseEnter should not be public virtual, but protected. /// /// Called when the mouse enters the View's . The view will now receive mouse events until the mouse leaves /// the view. At which time, will be called. /// /// /// The coordinates are relative to . /// /// /// , if the event was handled, otherwise. protected internal virtual bool OnMouseEnter (MouseEvent mouseEvent) { if (!Enabled) { return true; } if (!CanBeVisible (this)) { return false; } var args = new MouseEventEventArgs (mouseEvent); MouseEnter?.Invoke (this, args); return args.Handled; } // TODO: OnMouseLeave should not be public virtual, but protected. /// /// Called when the mouse has moved out of the View's . The view will no longer receive mouse events (until the /// mouse moves within the view again and is called). /// /// /// The coordinates are relative to . /// /// /// , if the event was handled, otherwise. protected internal virtual bool OnMouseLeave (MouseEvent mouseEvent) { if (!Enabled) { return true; } if (!CanBeVisible (this)) { return false; } var args = new MouseEventEventArgs (mouseEvent); MouseLeave?.Invoke (this, args); return args.Handled; } [CanBeNull] private ColorScheme _savedColorScheme; // TODO: OnMouseEvent should not be public virtual, but protected. /// Called when a mouse event occurs within the view's . /// /// /// The coordinates are relative to . /// /// /// /// , if the event was handled, otherwise. protected internal virtual bool OnMouseEvent (MouseEvent mouseEvent) { if (!Enabled) { // A disabled view should not eat mouse events return false; } if (!CanBeVisible (this)) { return false; } var args = new MouseEventEventArgs (mouseEvent); // Default behavior is to invoke Accept (via HotKey) on clicked. if ((!WantContinuousButtonPressed && Application.MouseGrabView != this && mouseEvent.Flags.HasFlag (MouseFlags.Button1Clicked)) || mouseEvent.Flags.HasFlag (MouseFlags.Button2Clicked) || mouseEvent.Flags.HasFlag (MouseFlags.Button3Clicked) || mouseEvent.Flags.HasFlag (MouseFlags.Button4Clicked)) { return OnMouseClick (args); } if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed)) { // If WantContinuousButtonPressed is true, and this is not the first pressed event, // invoke Accept (via HotKey) if (WantContinuousButtonPressed && Application.MouseGrabView == this) { return OnMouseClick (args); } // The first time we get pressed event, grab the mouse and invert the colors if (Application.MouseGrabView != this) { Application.GrabMouse (this); _savedColorScheme = ColorScheme; if (HighlightOnPress && ColorScheme is { }) { if (CanFocus) { // TODO: Make the inverted color configurable var cs = new ColorScheme (ColorScheme) { Focus = new Attribute (ColorScheme.Normal.Foreground, ColorScheme.Focus.Background) }; ColorScheme = cs; } else { var cs = new ColorScheme (ColorScheme) { Normal = new Attribute (ColorScheme.Focus.Background, ColorScheme.Normal.Foreground) }; ColorScheme = cs; } } if (CanFocus){ // Set the focus, but don't invoke Accept SetFocus (); } } } if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Released)) { // When the mouse is released, if WantContinuousButtonPressed is set, invoke Accept one last time. if (WantContinuousButtonPressed) { OnMouseClick (args); } if (Application.MouseGrabView == this) { Application.UngrabMouse (); if (HighlightOnPress && _savedColorScheme is { }) { ColorScheme = _savedColorScheme; _savedColorScheme = null; } } } //// Clicked support for all buttons and single and double click //if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Clicked) // || mouseEvent.Flags.HasFlag (MouseFlags.Button2Clicked) // || mouseEvent.Flags.HasFlag (MouseFlags.Button3Clicked) // || mouseEvent.Flags.HasFlag (MouseFlags.Button4Clicked)) //{ // OnMouseClick (args); //} //if (mouseEvent.Flags.HasFlag (MouseFlags.Button1DoubleClicked) // || mouseEvent.Flags.HasFlag (MouseFlags.Button2DoubleClicked) // || mouseEvent.Flags.HasFlag (MouseFlags.Button3DoubleClicked) // || mouseEvent.Flags.HasFlag (MouseFlags.Button4DoubleClicked)) //{ // OnMouseClick (args); //} if (args.Handled != true) { MouseEvent?.Invoke (this, args); } return args.Handled == true; } /// Invokes the MouseClick event. /// /// /// Called when the mouse is either clicked or double-clicked. Check /// to see which button was clicked. /// /// protected bool OnMouseClick (MouseEventEventArgs args) { if (!Enabled) { // QUESTION: Is this right? Should a disabled view eat mouse clicks? args.Handled = true; return true; } MouseClick?.Invoke (this, args); if (args.Handled) { return true; } if (!HasFocus && CanFocus) { args.Handled = true; SetFocus (); } return args.Handled; } }