549 lines
16 KiB
Text
549 lines
16 KiB
Text
|
/**
|
||
|
* PANDA 3D SOFTWARE
|
||
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||
|
*
|
||
|
* All use of this software is subject to the terms of the revised BSD
|
||
|
* license. You should have received a copy of this license along
|
||
|
* with this source code in a file named "LICENSE."
|
||
|
*
|
||
|
* @file mouseWatcher.I
|
||
|
* @author drose
|
||
|
* @date 2002-03-12
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Returns true if the mouse is anywhere within the window, false otherwise.
|
||
|
* Also see is_mouse_open().
|
||
|
*/
|
||
|
INLINE bool MouseWatcher::
|
||
|
has_mouse() const {
|
||
|
return _has_mouse;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the mouse is within the window and not over some particular
|
||
|
* MouseWatcherRegion that is marked to suppress mouse events; that is, that
|
||
|
* the mouse is in open space within the window.
|
||
|
*/
|
||
|
INLINE bool MouseWatcher::
|
||
|
is_mouse_open() const {
|
||
|
return _has_mouse && (_internal_suppress & MouseWatcherRegion::SF_mouse_position) == 0;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* It is only valid to call this if has_mouse() returns true. If so, this
|
||
|
* returns the current position of the mouse within the window.
|
||
|
*/
|
||
|
INLINE const LPoint2 &MouseWatcher::
|
||
|
get_mouse() const {
|
||
|
#ifndef NDEBUG
|
||
|
static LPoint2 bogus_mouse(0.0f, 0.0f);
|
||
|
nassertr(_has_mouse, bogus_mouse);
|
||
|
#endif
|
||
|
return _mouse;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* It is only valid to call this if has_mouse() returns true. If so, this
|
||
|
* returns the current X position of the mouse within the window.
|
||
|
*/
|
||
|
INLINE PN_stdfloat MouseWatcher::
|
||
|
get_mouse_x() const {
|
||
|
nassertr(_has_mouse, 0.0f);
|
||
|
return _mouse[0];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* It is only valid to call this if has_mouse() returns true. If so, this
|
||
|
* returns the current Y position of the mouse within the window.
|
||
|
*/
|
||
|
INLINE PN_stdfloat MouseWatcher::
|
||
|
get_mouse_y() const {
|
||
|
nassertr(_has_mouse, 0.0f);
|
||
|
return _mouse[1];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the frame of the MouseWatcher. See the next flavor of this method for
|
||
|
* a more verbose explanation.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
set_frame(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
|
||
|
set_frame(LVecBase4(left, right, bottom, top));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the frame of the MouseWatcher. This determines the coordinate space
|
||
|
* in which the MouseWatcherRegions should be expected to live. Normally,
|
||
|
* this is left at -1, 1, -1, 1, which is the default setting, and matches the
|
||
|
* mouse coordinate range.
|
||
|
*
|
||
|
* Whatever values you specify here indicate the shape of the full screen, and
|
||
|
* the MouseWatcherRegions will be given in coordinate space matching it. For
|
||
|
* instance, if you specify (0, 1, 0, 1), then a MouseWatcherRegion with the
|
||
|
* frame (0, 1, 0, .5) will cover the lower half of the screen.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
set_frame(const LVecBase4 &frame) {
|
||
|
_frame = frame;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the frame of the MouseWatcher. See set_frame().
|
||
|
*/
|
||
|
INLINE const LVecBase4 &MouseWatcher::
|
||
|
get_frame() const {
|
||
|
return _frame;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the mouse is over any rectangular region, false otherwise.
|
||
|
*/
|
||
|
INLINE bool MouseWatcher::
|
||
|
is_over_region() const {
|
||
|
return get_over_region() != nullptr;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the mouse is over any rectangular region, false otherwise.
|
||
|
*/
|
||
|
INLINE bool MouseWatcher::
|
||
|
is_over_region(PN_stdfloat x, PN_stdfloat y) const {
|
||
|
return get_over_region(x, y) != nullptr;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the mouse is over any rectangular region, false otherwise.
|
||
|
*/
|
||
|
INLINE bool MouseWatcher::
|
||
|
is_over_region(const LPoint2 &pos) const {
|
||
|
return get_over_region(pos) != nullptr;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the smallest region the mouse is currently over, or NULL if it is
|
||
|
* over no region.
|
||
|
*/
|
||
|
INLINE MouseWatcherRegion *MouseWatcher::
|
||
|
get_over_region() const {
|
||
|
return _preferred_region;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the smallest region the indicated point is over, or NULL if it is
|
||
|
* over no region.
|
||
|
*/
|
||
|
INLINE MouseWatcherRegion *MouseWatcher::
|
||
|
get_over_region(PN_stdfloat x, PN_stdfloat y) const {
|
||
|
return get_over_region(LPoint2(x, y));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the indicated button is currently being held down, false
|
||
|
* otherwise.
|
||
|
*/
|
||
|
INLINE bool MouseWatcher::
|
||
|
is_button_down(ButtonHandle button) const {
|
||
|
return _inactivity_state != IS_inactive && _current_buttons_down.get_bit(button.get_index());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the pattern string that indicates how the event names are generated
|
||
|
* when a button is depressed. This is a string that may contain any of the
|
||
|
* following:
|
||
|
*
|
||
|
* %r - the name of the region the mouse is over %b - the name of the button
|
||
|
* pressed.
|
||
|
*
|
||
|
* The event name will be based on the in_pattern string specified here, with
|
||
|
* all occurrences of the above strings replaced with the corresponding
|
||
|
* values.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
set_button_down_pattern(const std::string &pattern) {
|
||
|
_button_down_pattern = pattern;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the string that indicates how event names are generated when a
|
||
|
* button is depressed. See set_button_down_pattern().
|
||
|
*/
|
||
|
INLINE const std::string &MouseWatcher::
|
||
|
get_button_down_pattern() const {
|
||
|
return _button_down_pattern;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the pattern string that indicates how the event names are generated
|
||
|
* when a button is released. See set_button_down_pattern().
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
set_button_up_pattern(const std::string &pattern) {
|
||
|
_button_up_pattern = pattern;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the string that indicates how event names are generated when a
|
||
|
* button is released. See set_button_down_pattern().
|
||
|
*/
|
||
|
INLINE const std::string &MouseWatcher::
|
||
|
get_button_up_pattern() const {
|
||
|
return _button_up_pattern;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the pattern string that indicates how the event names are generated
|
||
|
* when a button is continuously held and generates keyrepeat "down" events.
|
||
|
* This is a string that may contain any of the following:
|
||
|
*
|
||
|
* %r - the name of the region the mouse is over %b - the name of the button
|
||
|
* pressed.
|
||
|
*
|
||
|
* The event name will be based on the in_pattern string specified here, with
|
||
|
* all occurrences of the above strings replaced with the corresponding
|
||
|
* values.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
set_button_repeat_pattern(const std::string &pattern) {
|
||
|
_button_repeat_pattern = pattern;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the string that indicates how event names are names are generated
|
||
|
* when a button is continuously held and generates keyrepeat "down" events.
|
||
|
* See set_button_repeat_pattern().
|
||
|
*/
|
||
|
INLINE const std::string &MouseWatcher::
|
||
|
get_button_repeat_pattern() const {
|
||
|
return _button_repeat_pattern;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the pattern string that indicates how the event names are generated
|
||
|
* when the mouse enters a region. This is different from within_pattern, in
|
||
|
* that a mouse is only "entered" in the topmost region at a given time, while
|
||
|
* it might be "within" multiple nested regions.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
set_enter_pattern(const std::string &pattern) {
|
||
|
_enter_pattern = pattern;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the string that indicates how event names are generated when the
|
||
|
* mouse enters a region. This is different from within_pattern, in that a
|
||
|
* mouse is only "entered" in the topmost region at a given time, while it
|
||
|
* might be "within" multiple nested regions.
|
||
|
*/
|
||
|
INLINE const std::string &MouseWatcher::
|
||
|
get_enter_pattern() const {
|
||
|
return _enter_pattern;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the pattern string that indicates how the event names are generated
|
||
|
* when the mouse leaves a region. This is different from without_pattern, in
|
||
|
* that a mouse is only "entered" in the topmost region at a given time, while
|
||
|
* it might be "within" multiple nested regions.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
set_leave_pattern(const std::string &pattern) {
|
||
|
_leave_pattern = pattern;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the string that indicates how event names are generated when the
|
||
|
* mouse leaves a region. This is different from without_pattern, in that a
|
||
|
* mouse is only "entered" in the topmost region at a given time, while it
|
||
|
* might be "within" multiple nested regions.
|
||
|
*/
|
||
|
INLINE const std::string &MouseWatcher::
|
||
|
get_leave_pattern() const {
|
||
|
return _leave_pattern;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the pattern string that indicates how the event names are generated
|
||
|
* when the mouse wanders over a region. This is different from
|
||
|
* enter_pattern, in that a mouse is only "entered" in the topmost region at a
|
||
|
* given time, while it might be "within" multiple nested regions.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
set_within_pattern(const std::string &pattern) {
|
||
|
_within_pattern = pattern;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the string that indicates how event names are generated when the
|
||
|
* mouse wanders over a region. This is different from enter_pattern, in that
|
||
|
* a mouse is only "entered" in the topmost region at a given time, while it
|
||
|
* might be "within" multiple nested regions.
|
||
|
*/
|
||
|
INLINE const std::string &MouseWatcher::
|
||
|
get_within_pattern() const {
|
||
|
return _within_pattern;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the pattern string that indicates how the event names are generated
|
||
|
* when the mouse wanders out of a region. This is different from
|
||
|
* leave_pattern, in that a mouse is only "entered" in the topmost region at a
|
||
|
* given time, while it might be "within" multiple nested regions.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
set_without_pattern(const std::string &pattern) {
|
||
|
_without_pattern = pattern;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the string that indicates how event names are generated when the
|
||
|
* mouse wanders out of a region. This is different from leave_pattern, in
|
||
|
* that a mouse is only "entered" in the topmost region at a given time, while
|
||
|
* it might be "within" multiple nested regions.
|
||
|
*/
|
||
|
INLINE const std::string &MouseWatcher::
|
||
|
get_without_pattern() const {
|
||
|
return _without_pattern;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the node that will be transformed each frame by the mouse's
|
||
|
* coordinates. It will also be hidden when the mouse goes outside the
|
||
|
* window. This can be used to implement a software mouse pointer for when a
|
||
|
* hardware (or system) mouse pointer is unavailable.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
set_geometry(PandaNode *node) {
|
||
|
_geometry = node;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if a software mouse pointer has been setup via set_geometry(),
|
||
|
* or false otherwise. See set_geometry().
|
||
|
*/
|
||
|
INLINE bool MouseWatcher::
|
||
|
has_geometry() const {
|
||
|
return !_geometry.is_null();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the node that has been set as the software mouse pointer, or NULL
|
||
|
* if no node has been set. See has_geometry() and set_geometry().
|
||
|
*/
|
||
|
INLINE PandaNode *MouseWatcher::
|
||
|
get_geometry() const {
|
||
|
return _geometry;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Stops the use of the software cursor set up via set_geometry().
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
clear_geometry() {
|
||
|
_geometry.clear();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* As an optimization for the C++ Gui, an extra handler can be registered with
|
||
|
* a mouseWatcher so that events can be dealt with much sooner.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
set_extra_handler(EventHandler *eh) {
|
||
|
_eh = eh;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* As an optimization for the C++ Gui, an extra handler can be registered with
|
||
|
* a mouseWatcher so that events can be dealt with much sooner.
|
||
|
*/
|
||
|
INLINE EventHandler *MouseWatcher::
|
||
|
get_extra_handler() const {
|
||
|
return _eh;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets the buttons that should be monitored as modifier buttons for
|
||
|
* generating events to the MouseWatcherRegions.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
set_modifier_buttons(const ModifierButtons &mods) {
|
||
|
_mods = mods;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the set of buttons that are being monitored as modifier buttons, as
|
||
|
* well as their current state.
|
||
|
*/
|
||
|
INLINE ModifierButtons MouseWatcher::
|
||
|
get_modifier_buttons() const {
|
||
|
return _mods;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Constrains the MouseWatcher to watching the mouse within a particular
|
||
|
* indicated region of the screen. DataNodes parented under the MouseWatcher
|
||
|
* will observe the mouse and keyboard events only when the mouse is within
|
||
|
* the indicated region, and the observed range will be from -1 .. 1 across
|
||
|
* the region.
|
||
|
*
|
||
|
* Do not delete the DisplayRegion while it is owned by the MouseWatcher.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
set_display_region(DisplayRegion *dr) {
|
||
|
_display_region = dr;
|
||
|
_button_down_display_region = nullptr;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Removes the display region constraint from the MouseWatcher, and restores
|
||
|
* it to the default behavior of watching the whole window.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
clear_display_region() {
|
||
|
_display_region = nullptr;
|
||
|
_button_down_display_region = nullptr;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the display region the MouseWatcher is constrained to by
|
||
|
* set_display_region(), or NULL if it is not constrained.
|
||
|
*/
|
||
|
INLINE DisplayRegion *MouseWatcher::
|
||
|
get_display_region() const {
|
||
|
return _display_region;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if the MouseWatcher has been constrained to a particular
|
||
|
* region of the screen via set_display_region(), or false otherwise. If this
|
||
|
* returns true, get_display_region() may be used to return the particular
|
||
|
* region.
|
||
|
*/
|
||
|
INLINE bool MouseWatcher::
|
||
|
has_display_region() const {
|
||
|
return (_display_region != nullptr);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets an inactivity timeout on the mouse activity. When this timeout (in
|
||
|
* seconds) is exceeded with no keyboard or mouse activity, all currently-held
|
||
|
* buttons are automatically released. This is intended to help protect
|
||
|
* against people who inadvertently (or intentionally) leave a keyboard key
|
||
|
* stuck down and then wander away from the keyboard.
|
||
|
*
|
||
|
* Also, when this timeout expires, the event specified by
|
||
|
* set_inactivity_timeout_event() will be generated.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
set_inactivity_timeout(double timeout) {
|
||
|
_has_inactivity_timeout = true;
|
||
|
_inactivity_timeout = timeout;
|
||
|
note_activity();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns true if an inactivity timeout has been set, false otherwise.
|
||
|
*/
|
||
|
INLINE bool MouseWatcher::
|
||
|
has_inactivity_timeout() const {
|
||
|
return _has_inactivity_timeout;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the inactivity timeout that has been set. It is an error to call
|
||
|
* this if has_inactivity_timeout() returns false.
|
||
|
*/
|
||
|
INLINE double MouseWatcher::
|
||
|
get_inactivity_timeout() const {
|
||
|
nassertr(_has_inactivity_timeout, 0.0);
|
||
|
return _inactivity_timeout;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Removes the inactivity timeout and restores the MouseWatcher to its default
|
||
|
* behavior of allowing a key to be held indefinitely.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
clear_inactivity_timeout() {
|
||
|
_has_inactivity_timeout = false;
|
||
|
_inactivity_timeout = 0.0;
|
||
|
note_activity();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Specifies the event string that will be generated when the inactivity
|
||
|
* timeout counter expires. See set_inactivity_timeout().
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
set_inactivity_timeout_event(const std::string &event) {
|
||
|
_inactivity_timeout_event = event;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the event string that will be generated when the inactivity timeout
|
||
|
* counter expires. See set_inactivity_timeout().
|
||
|
*/
|
||
|
INLINE const std::string &MouseWatcher::
|
||
|
get_inactivity_timeout_event() const {
|
||
|
return _inactivity_timeout_event;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Called internally to indicate the mouse pointer has moved within the
|
||
|
* indicated region's boundaries.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
within_region(MouseWatcherRegion *region, const MouseWatcherParameter ¶m) {
|
||
|
region->within_region(param);
|
||
|
throw_event_pattern(_within_pattern, region, ButtonHandle::none());
|
||
|
if (_enter_multiple) {
|
||
|
enter_region(region, param);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Called internally to indicate the mouse pointer has moved outside of the
|
||
|
* indicated region's boundaries.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
without_region(MouseWatcherRegion *region, const MouseWatcherParameter ¶m) {
|
||
|
if (_enter_multiple) {
|
||
|
exit_region(region, param);
|
||
|
}
|
||
|
region->without_region(param);
|
||
|
throw_event_pattern(_without_pattern, region, ButtonHandle::none());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Clears the mouse trail log. This does not prevent further accumulation of
|
||
|
* the log given future events.
|
||
|
*/
|
||
|
INLINE void MouseWatcher::
|
||
|
clear_trail_log() {
|
||
|
_trail_log->clear();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Obtain the mouse trail log. This is a PointerEventList. Does not make a
|
||
|
* copy, therefore, this PointerEventList will be updated each time
|
||
|
* process_events gets called.
|
||
|
*
|
||
|
* To use trail logging, you need to enable the generation of pointer events
|
||
|
* in the GraphicsWindowInputDevice and set the trail log duration in the
|
||
|
* MouseWatcher. Otherwise, the trail log will be empty.
|
||
|
*/
|
||
|
INLINE CPT(PointerEventList) MouseWatcher::
|
||
|
get_trail_log() const {
|
||
|
return _trail_log;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This counter indicates how many events were added to the trail log this
|
||
|
* frame. The trail log is updated once per frame, during the process_events
|
||
|
* operation.
|
||
|
*/
|
||
|
INLINE size_t MouseWatcher::
|
||
|
num_trail_recent() const {
|
||
|
return _num_trail_recent;
|
||
|
}
|