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:
Mouse was not inside the panel's bounds on the last frame.
Mouse is inside panel's bounds on the current frame.
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:
Mouse was inside the panel's bounds on the last frame.
Mouse was NOT inside the bounds of any childcontrols on the last frame.
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:
The article for OnCursorEntered says: "Called whenever the cursor entered the panels bounds"
The article for OnCursorExited says: "Called whenever the cursor left the panels bounds"
Diagram of the situation
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
Change OnCursorEntered and OnCursorExited to function in line with the exit/enter standard expected from major gui frameworks.
Add a flag to panels called UseLegacyCursorEvents that defaults to true. When true, the current behavior is used. When false, the superior behavior is used.
Or, if the requested mouse interaction changes have further reach than just affecting mouse enter/exit, the flag could be named something like IncludeChildrenInHitTest and default to false for the old behavior.
Duplicate the OnCursor... events into a new set like OnCursorEnteredEx that uses the fixed enter/exit behavior. Name pattern can be anything ofc, but I see Ex already used a lot in glua for superior versions of other methods.
The
OnCursorEntered
andOnCursorExited
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: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: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:
OnCursorEntered
says: "Called whenever the cursor entered the panels bounds"OnCursorExited
says: "Called whenever the cursor left the panels bounds"Diagram of the situation
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
OnCursorEntered
andOnCursorExited
to function in line with the exit/enter standard expected from major gui frameworks.UseLegacyCursorEvents
that defaults to true. When true, the current behavior is used. When false, the superior behavior is used.IncludeChildrenInHitTest
and default to false for the old behavior.OnCursor...
events into a new set likeOnCursorEnteredEx
that uses the fixed enter/exit behavior. Name pattern can be anything ofc, but I seeEx
already used a lot in glua for superior versions of other methods.