Facepunch / garrysmod-requests

Feature requests for Garry's Mod
85 stars 24 forks source link

Fix Panel's OnCursorEntered and OnCursorExited events #1724

Open TiberiumFusion opened 4 years ago

TiberiumFusion commented 4 years ago

The OnCursorEntered and OnCursorExited are often unusable without repetitive code for handling these events on child controls and manually raising events on the parent control. This boilerplate equals code mess and possible slowdown in guis with many controls.

Summary

Gmod exclusively uses the binary change of "is over immediate hit test/is not over immediate hit test" to determine when exit/enter are fired. The action of the cursor crossing the boundary of a control is never considered. As soon as the cursor leaves one panel and enters another, even if it is a child panel, the parent panel no longer thinks the mouse is above it. This methology is inferior to modern gui standards and is difficult to work with, especially when creating any form of gui that isn't deadass plain/simple.

Specifics

Currently, OnCursorEntered only fires under these conditions:

  1. Mouse was not inside the panel's bounds on the last frame.
  2. Mouse is inside panel's bounds on the current frame.
  3. Mouse is NOT inside the bounds of any child control. Condition 3 is strange behavior that does not exist in normal gui frameworks. Mouse enter should fire as long as the mouse has moved into the panel's bounds, regardless of final cursor location above any possible child controls.

These three conditions simplify down to: "OnCursorEntered only fires when the mouse enters the immediate hit test area of the panel, whereupon all child controls are considered voids in the parent's immediate hit test area."

Currently, OnCursorExited only fires under these conditions:

  1. Mouse was inside the panel's bounds on the last frame.
  2. Mouse was NOT inside the bounds of any childcontrols on the last frame.
  3. Mouse is either outside of the panel's bounds or inside the bounds of a child control on the current frame. Conditions 2+3 are strange behavior that does not exist in normal gui frameworks. Mouse exit should fire only when the mouse leaves the control's bounds, not when it enters any other control, even a child control.

These three conditions simplify down to: "OnCursorExitied only fires when the mouse exits the immediate hit test area of the panel, whereupon all child controls are considered voids in the parent's immediate hit test area."

Misleading wiki information

Additionally, the wiki falsely describes the the current behavior:

Diagram of the situation

Bad gmod ui events diagram fix

Impact

Gmod's current behavior requires the programmer to manually fit all of their panels with a check using IsChildHovered() to determine if any mouse enter/exit events on the child should propogate to the parent control. An additional field for keeping track of mouse state per control is also needed, as well as handling for lazy panel dimension changes that have yet to reevaluate their layout. All of this requires the child to be aware of the parent and adds unnecessary mess to interface code. Some advanced control types (like canvas-style controls with out-of-bounds drawing enabled) will require the programmer to create even more complex checks to work around the issues of the current system.

If the proposed changes to mouse interaction are made, it will be much simpler, faster, and reliable to create guis that react to the location of the cursor in order to provide a superior experience.

Solution ideas

TiberiumFusion commented 1 year ago

Zzzzzzzz ‑ facepunch, probably