mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
* Fixed mouse grab issue * Fixed mouse grab regrssions. * Update Terminal.Gui/ViewBase/View.Mouse.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Terminal.Gui/ViewBase/View.Mouse.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Terminal.Gui/ViewBase/View.Mouse.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Terminal.Gui/ViewBase/View.Mouse.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Terminal.Gui/ViewBase/View.Mouse.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Terminal.Gui/ViewBase/View.Mouse.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * code cleanup * Update Terminal.Gui/ViewBase/View.Mouse.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Addressing pr feedback * updated mouse.md --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -126,12 +126,16 @@ Mouse events are processed through the following workflow using the [Cancellable
|
||||
|
||||
1. **Driver Level**: The driver captures platform-specific mouse events and converts them to `MouseEventArgs`
|
||||
2. **Application Level**: `IApplication.Mouse.RaiseMouseEvent` determines the target view and routes the event
|
||||
3. **View Level**: The target view processes the event through:
|
||||
- `OnMouseEvent` (virtual method that can be overridden)
|
||||
- `MouseEvent` event (for event subscribers)
|
||||
- Mouse bindings (if the event wasn't handled) which invoke commands
|
||||
- Command handlers (e.g., `OnSelecting` for `Command.Select`)
|
||||
- High-level events like `MouseEnter`, `MouseLeave`
|
||||
3. **View Level**: The target view processes the event through `View.NewMouseEvent()`:
|
||||
1. **Pre-condition validation** - Checks if view is enabled, visible, and wants the event type
|
||||
2. **Low-level MouseEvent** - Raises `OnMouseEvent()` and `MouseEvent` event
|
||||
3. **Mouse grab handling** - If `HighlightStates` or `WantContinuousButtonPressed` are set:
|
||||
- Automatically grabs mouse on button press
|
||||
- Handles press/release/click lifecycle
|
||||
- Sets focus if view is focusable
|
||||
- Updates `MouseState` (Pressed, PressedOutside)
|
||||
4. **Command invocation** - For click events, invokes commands via `MouseBindings` (default: `Command.Select` ? `Selecting` event)
|
||||
5. **Mouse wheel handling** - Raises `OnMouseWheel()` and `MouseWheel` event
|
||||
|
||||
### Handling Mouse Events Directly
|
||||
|
||||
@@ -228,15 +232,17 @@ public class MultiButtonView : View
|
||||
}
|
||||
```
|
||||
|
||||
## Mouse State
|
||||
## Mouse State and Mouse Grab
|
||||
|
||||
### Mouse State
|
||||
|
||||
The @Terminal.Gui.ViewBase.View.MouseState property provides an abstraction for the current state of the mouse, enabling views to do interesting things like change their appearance based on the mouse state.
|
||||
|
||||
Mouse states include:
|
||||
* **Normal** - Default state when mouse is not interacting with the view
|
||||
* **None** - No mouse interaction with the view
|
||||
* **In** - Mouse is positioned over the view (inside the viewport)
|
||||
* **Pressed** - Mouse button is pressed down while over the view
|
||||
* **PressedOutside** - Mouse was pressed inside but moved outside the view
|
||||
* **PressedOutside** - Mouse was pressed inside but moved outside the view (when not using `WantContinuousButtonPressed`)
|
||||
|
||||
It works in conjunction with the @Terminal.Gui.ViewBase.View.HighlightStates which is a list of mouse states that will cause a view to become highlighted.
|
||||
|
||||
@@ -253,6 +259,9 @@ view.MouseStateChanged += (sender, e) =>
|
||||
case MouseState.Pressed:
|
||||
// Change appearance when pressed
|
||||
break;
|
||||
case MouseState.PressedOutside:
|
||||
// Mouse was pressed inside but moved outside
|
||||
break;
|
||||
}
|
||||
};
|
||||
```
|
||||
@@ -264,6 +273,59 @@ Configure which states should cause highlighting:
|
||||
view.HighlightStates = MouseState.In | MouseState.Pressed;
|
||||
```
|
||||
|
||||
### Mouse Grab
|
||||
|
||||
Views with `HighlightStates` or `WantContinuousButtonPressed` enabled automatically **grab the mouse** when a button is pressed. This means:
|
||||
|
||||
1. **Automatic Grab**: The view receives all mouse events until the button is released, even if the mouse moves outside the view's `Viewport`
|
||||
2. **Focus Management**: If the view is focusable (`CanFocus = true`), it automatically receives focus on the first button press
|
||||
3. **State Tracking**: The view's `MouseState` is updated to reflect press/release/outside states
|
||||
4. **Automatic Ungrab**: The mouse is released when:
|
||||
- The button is released (via `WhenGrabbedHandleClicked()`)
|
||||
- The view is removed from its parent hierarchy (via `View.OnRemoved()`)
|
||||
- The application ends (via `App.End()`)
|
||||
|
||||
#### Continuous Button Press
|
||||
|
||||
When `WantContinuousButtonPressed` is set to `true`, the view receives repeated click events while the button is held down:
|
||||
|
||||
```cs
|
||||
view.WantContinuousButtonPressed = true;
|
||||
|
||||
view.Selecting += (s, e) =>
|
||||
{
|
||||
// This will be called repeatedly while the button is held down
|
||||
// Useful for scroll buttons, increment/decrement buttons, etc.
|
||||
DoRepeatAction();
|
||||
e.Handled = true;
|
||||
};
|
||||
```
|
||||
|
||||
**Note**: With `WantContinuousButtonPressed`, the `MouseState.PressedOutside` flag has no effect - the view continues to receive events and maintains the pressed state even when the mouse moves outside.
|
||||
|
||||
#### Mouse Grab Lifecycle
|
||||
|
||||
```
|
||||
Button Press (inside view)
|
||||
?
|
||||
Mouse Grabbed Automatically
|
||||
?? View receives focus (if CanFocus)
|
||||
?? MouseState |= MouseState.Pressed
|
||||
?? All mouse events route to this view
|
||||
|
||||
Mouse Move (while grabbed)
|
||||
?? Inside Viewport: MouseState remains Pressed
|
||||
?? Outside Viewport: MouseState |= MouseState.PressedOutside
|
||||
(unless WantContinuousButtonPressed is true)
|
||||
|
||||
Button Release
|
||||
?
|
||||
Mouse Ungrabbed Automatically
|
||||
?? MouseState &= ~MouseState.Pressed
|
||||
?? MouseState &= ~MouseState.PressedOutside
|
||||
?? Click event raised (if still in bounds)
|
||||
```
|
||||
|
||||
## Mouse Button and Movement Concepts
|
||||
|
||||
* **Down** - Indicates the user pushed a mouse button down.
|
||||
@@ -355,12 +417,25 @@ view.MouseEvent += (s, e) =>
|
||||
|
||||
* **Use Mouse Bindings and Commands** for simple mouse interactions - they integrate well with the Command system and work alongside keyboard bindings
|
||||
* **Use the `Selecting` event** to handle mouse clicks - it's raised by the default `Command.Select` binding for all mouse buttons
|
||||
* **Access mouse details via CommandContext** when you need position or flags in `Selecting` handlers
|
||||
* **Handle Mouse Events directly** for complex interactions like drag-and-drop or custom gestures
|
||||
* **Access mouse details via CommandContext** when you need position or flags in `Selecting` handlers:
|
||||
```cs
|
||||
view.Selecting += (s, e) =>
|
||||
{
|
||||
if (e.Context is CommandContext<MouseBinding> { Binding.MouseEventArgs: { } mouseArgs })
|
||||
{
|
||||
Point position = mouseArgs.Position;
|
||||
MouseFlags flags = mouseArgs.Flags;
|
||||
// Handle with position and flags
|
||||
}
|
||||
};
|
||||
```
|
||||
* **Handle Mouse Events directly** only for complex interactions like drag-and-drop or custom gestures (override `OnMouseEvent` or subscribe to `MouseEvent`)
|
||||
* **Use `HighlightStates`** to enable automatic mouse grab and visual feedback - views will automatically grab the mouse and update their appearance
|
||||
* **Use `WantContinuousButtonPressed`** for repeating actions (scroll buttons, increment/decrement) - the view will receive repeated events while the button is held
|
||||
* **Respect platform conventions** - use right-click for context menus, double-click for default actions
|
||||
* **Provide keyboard alternatives** - ensure all mouse functionality has keyboard equivalents
|
||||
* **Test with different terminals** - mouse support varies between terminal applications
|
||||
* **Use Mouse State** to provide visual feedback when users hover or interact with views
|
||||
* **Mouse grab is automatic** - you don't need to manually call `GrabMouse()`/`UngrabMouse()` when using `HighlightStates` or `WantContinuousButtonPressed`
|
||||
|
||||
## Limitations and Considerations
|
||||
|
||||
|
||||
Reference in New Issue
Block a user