add MouseWatcher::set_display_region()

This commit is contained in:
David Rose 2004-03-05 20:10:19 +00:00
parent e390fbddaf
commit a79af737d2
9 changed files with 439 additions and 103 deletions

View File

@ -26,6 +26,8 @@
#include "graphicsPipeSelection.h"
#include "nodePathCollection.h"
#include "textNode.h"
#include "mouseAndKeyboard.h"
#include "mouseRecorder.h"
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::Constructor
@ -157,6 +159,59 @@ get_default_pipe() {
return _default_pipe;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::get_mouse
// Access: Public
// Description: Returns a NodePath to the MouseAndKeyboard associated
// with the indicated GraphicsWindow object. If there's
// not yet a mouse associated with the window, creates
// one.
//
// This allows multiple WindowFramework objects that
// represent different display regions of the same
// GraphicsWindow to share the same mouse.
////////////////////////////////////////////////////////////////////
NodePath PandaFramework::
get_mouse(GraphicsWindow *window) {
Mouses::iterator mi = _mouses.find(window);
if (mi != _mouses.end()) {
return (*mi).second;
}
NodePath mouse;
NodePath data_root = get_data_root();
MouseAndKeyboard *mouse_node = new MouseAndKeyboard(window, 0, "mouse");
mouse = data_root.attach_new_node(mouse_node);
RecorderController *recorder = get_recorder();
if (recorder != (RecorderController *)NULL) {
// If we're in recording or playback mode, associate a recorder.
MouseRecorder *mouse_recorder = new MouseRecorder("mouse");
mouse = mouse.attach_new_node(mouse_recorder);
recorder->add_recorder("mouse", mouse_recorder);
}
_mouses[window] = mouse;
return mouse;
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::remove_mouse
// Access: Public
// Description: Removes the mouse that may have been created by an
// earlier call to get_mouse().
////////////////////////////////////////////////////////////////////
void PandaFramework::
remove_mouse(const GraphicsWindow *window) {
Mouses::iterator mi = _mouses.find(window);
if (mi != _mouses.end()) {
(*mi).second.remove_node();
_mouses.erase(mi);
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::define_key
// Access: Public
@ -276,9 +331,9 @@ open_window(const WindowProperties &props, GraphicsPipe *pipe,
////////////////////////////////////////////////////////////////////
// Function: PandaFramework::find_window
// Access: Public
// Description: Returns the index of the WindowFramework object that
// references the indicated GraphicsWindow pointer, or
// -1 if none do.
// Description: Returns the index of the first WindowFramework object
// found that references the indicated GraphicsWindow
// pointer, or -1 if none do.
////////////////////////////////////////////////////////////////////
int PandaFramework::
find_window(const GraphicsWindow *win) const {
@ -351,7 +406,13 @@ close_all_windows() {
wf->close_window();
}
Mouses::iterator mi;
for (mi = _mouses.begin(); mi != _mouses.end(); ++mi) {
(*mi).second.remove_node();
}
_windows.clear();
_mouses.clear();
}
////////////////////////////////////////////////////////////////////
@ -758,9 +819,21 @@ event_esc(CPT_Event event, void *data) {
WindowFramework *wf;
DCAST_INTO_V(wf, param.get_ptr());
PT(GraphicsWindow) win = wf->get_graphics_window();
PandaFramework *self = (PandaFramework *)data;
self->close_window(wf);
// Also close any other WindowFrameworks on the same window.
int window_index = self->find_window(win);
while (window_index != -1) {
self->close_window(window_index);
window_index = self->find_window(win);
}
// Free up the mouse for that window.
self->remove_mouse(win);
// If we closed the last window, shut down.
if (self->_windows.empty()) {
self->_exit_flag = true;
@ -1221,10 +1294,20 @@ event_window_event(CPT_Event event, void *data) {
if (window_index == -1) {
framework_cat.debug()
<< "Ignoring message from unknown window.\n";
} else {
if (!win->get_properties().get_open()) {
int window_index = self->find_window(win);
while (window_index != -1) {
self->close_window(window_index);
window_index = self->find_window(win);
}
// Free up the mouse for that window.
self->remove_mouse(win);
// If the last window was closed, exit the application.
if (self->all_windows_closed() && !self->_exit_flag) {
if (self->_windows.empty() && !self->_exit_flag) {
framework_cat.info()
<< "Last window was closed by user.\n";
self->_exit_flag = true;

View File

@ -51,6 +51,8 @@ public:
INLINE GraphicsEngine *get_graphics_engine();
INLINE const NodePath &get_data_root() const;
INLINE EventHandler &get_event_handler();
NodePath get_mouse(GraphicsWindow *window);
void remove_mouse(const GraphicsWindow *window);
void define_key(const string &event_name,
const string &description,
@ -155,6 +157,9 @@ private:
typedef pvector< PT(WindowFramework) > Windows;
Windows _windows;
typedef pmap< const GraphicsWindow *, NodePath > Mouses;
Mouses _mouses;
NodePath _models;
// For counting frame rate.
@ -187,6 +192,8 @@ private:
double _screenshot_clear_time;
PT(RecorderController) _recorder;
friend class WindowFramework;
};
#include "pandaFramework.I"

View File

@ -18,8 +18,7 @@
#include "windowFramework.h"
#include "pandaFramework.h"
#include "mouseAndKeyboard.h"
#include "mouseRecorder.h"
#include "displayRegion.h"
#include "buttonThrower.h"
#include "transform2sg.h"
#include "dSearchPath.h"
@ -77,6 +76,34 @@ WindowFramework(PandaFramework *panda_framework) :
_background_type = BT_default;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::Copy Constructor
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
WindowFramework::
WindowFramework(const WindowFramework &copy, DisplayRegion *display_region) :
_panda_framework(copy._panda_framework),
_window(copy._window),
_display_region_3d(display_region)
{
_alight = (AmbientLight *)NULL;
_dlight = (DirectionalLight *)NULL;
_got_keyboard = false;
_got_trackball = false;
_got_lights = false;
_wireframe_enabled = false;
_texture_enabled = true;
_two_sided_enabled = false;
_one_sided_reverse_enabled = false;
_lighting_enabled = false;
_background_type = BT_default;
set_background_type(copy._background_type);
// Set up a 3-d camera for the window by default.
make_camera();
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::Destructor
// Access: Public, Virtual
@ -120,6 +147,21 @@ open_window(const WindowProperties &props, GraphicsEngine *engine,
_window = engine->make_window(ptgsg, name, 0);
if (_window != (GraphicsWindow *)NULL) {
_window->request_properties(props);
// Get the first channel on the window. This will be the only
// channel on non-SGI hardware.
PT(GraphicsChannel) channel = _window->get_channel(0);
// Make a layer on the channel to hold our display region.
PT(GraphicsLayer) layer = channel->make_layer();
// And create a display region that covers the entire window.
_display_region_3d = layer->make_display_region();
// Make sure the DisplayRegion does the clearing, not the window,
// so we can have multiple DisplayRegions of different colors.
_window->set_clear_color_active(false);
_window->set_clear_depth_active(false);
set_background_type(_background_type);
// Set up a 3-d camera for the window by default.
@ -228,8 +270,11 @@ get_render_2d() {
// Make a layer on the channel to hold our display region.
PT(GraphicsLayer) layer = channel->make_layer(10);
// And create a display region that covers the entire window.
PT(DisplayRegion) dr = layer->make_display_region();
// And create a display region that matches the size of the 3-d
// display region.
float l, r, b, t;
_display_region_3d->get_dimensions(l, r, b, t);
_display_region_2d = layer->make_display_region(l, r, b, t);
// Finally, we need a camera to associate with the display region.
PT(Camera) camera = new Camera("camera2d");
@ -247,7 +292,7 @@ get_render_2d() {
camera->set_lens(lens);
camera->set_scene(_render_2d);
dr->set_camera(camera_np);
_display_region_2d->set_camera(camera_np);
}
return _render_2d;
@ -294,19 +339,16 @@ get_aspect_2d() {
const NodePath &WindowFramework::
get_mouse() {
if (_mouse.is_empty()) {
nassertr(_window->get_num_input_devices() > 0, _mouse);
NodePath data_root = _panda_framework->get_data_root();
MouseAndKeyboard *mouse_node =
new MouseAndKeyboard(_window, 0, "mouse");
_mouse = data_root.attach_new_node(mouse_node);
NodePath mouse = _panda_framework->get_mouse(_window);
RecorderController *recorder = _panda_framework->get_recorder();
if (recorder != (RecorderController *)NULL) {
// If we're in recording or playback mode, associate a recorder.
MouseRecorder *mouse_recorder = new MouseRecorder("mouse");
_mouse = _mouse.attach_new_node(mouse_recorder);
recorder->add_recorder("mouse", mouse_recorder);
}
// Create a MouseWatcher to filter the mouse input. We do this
// mainly so we can constrain the mouse input to our particular
// display region, if we have one. This means the node we return
// from get_mouse() is actually a MouseWatcher, but since it
// presents the same interface as a Mouse, no one should mind.
PT(MouseWatcher) mw = new MouseWatcher("watcher");
mw->set_display_region(_display_region_3d);
_mouse = mouse.attach_new_node(mw);
}
return _mouse;
}
@ -326,6 +368,8 @@ enable_keyboard() {
if (_window->get_num_input_devices() > 0) {
NodePath mouse = get_mouse();
// Create a button thrower to listen for our keyboard events and
// associate this WindowFramework pointer with each one.
PT(ButtonThrower) bt = new ButtonThrower("kb-events");
bt->add_parameter(EventParameter(this));
ModifierButtons mods;
@ -479,8 +523,6 @@ bool WindowFramework::
load_models(const NodePath &parent, const pvector<Filename> &files) {
bool all_ok = true;
NodePath render = get_render();
pvector<Filename>::const_iterator fi;
for (fi = files.begin(); fi != files.end(); ++fi) {
const Filename &filename = (*fi);
@ -610,6 +652,59 @@ loop_animations() {
_anim_controls.loop_all(true);
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::split_window
// Access: Public
// Description: Divides the window into two display regions, each of
// which gets its own trackball and keyboard events.
// The new window pointer is returned.
//
// There is not an interface for recombining divided
// windows.
////////////////////////////////////////////////////////////////////
WindowFramework *WindowFramework::
split_window(SplitType split_type) {
DisplayRegion *new_region = NULL;
if (split_type == ST_default) {
// Choose either horizontal or vertical according to the largest
// dimension.
if (_display_region_3d->get_pixel_width() >
_display_region_3d->get_pixel_height()) {
split_type = ST_horizontal;
} else {
split_type = ST_vertical;
}
}
float left, right, bottom, top;
_display_region_3d->get_dimensions(left, right, bottom, top);
new_region = _display_region_3d->get_layer()->make_display_region();
if (split_type == ST_vertical) {
_display_region_3d->set_dimensions(left, right, bottom, (top + bottom) / 2.0f);
if (_display_region_2d != (DisplayRegion *)NULL) {
_display_region_2d->set_dimensions(left, right, bottom, (top + bottom) / 2.0f);
}
new_region->set_dimensions(left, right, (top + bottom) / 2.0f, top);
} else {
_display_region_3d->set_dimensions(left, (left + right) / 2.0f, bottom, top);
if (_display_region_2d != (DisplayRegion *)NULL) {
_display_region_2d->set_dimensions(left, (left + right) / 2.0f, bottom, top);
}
new_region->set_dimensions((left + right) / 2.0f, right, bottom, top);
}
PT(WindowFramework) wf = new WindowFramework(*this, new_region);
_panda_framework->_windows.push_back(wf);
return wf;
}
////////////////////////////////////////////////////////////////////
// Function: WindowFramework::set_wireframe
// Access: Public
@ -756,38 +851,40 @@ void WindowFramework::
set_background_type(WindowFramework::BackgroundType type) {
_background_type = type;
if (_window != (GraphicsWindow *)NULL) {
switch (_background_type) {
case BT_other:
break;
case BT_default:
_window->set_clear_color_active(true);
_window->set_clear_depth_active(true);
_window->set_clear_color(Colorf(win_background_r, win_background_g,
win_background_b, 1.0f));
_window->set_clear_depth(1.0f);
break;
case BT_gray:
_window->set_clear_color_active(true);
_window->set_clear_depth_active(true);
_window->set_clear_color(Colorf(0.3f, 0.3f, 0.3f, 1.0f));
_window->set_clear_depth(1.0f);
break;
case BT_black:
_window->set_clear_color_active(true);
_window->set_clear_depth_active(true);
_window->set_clear_color(Colorf(0.0f, 0.0f, 0.0f, 1.0f));
_window->set_clear_depth(1.0f);
if (_display_region_3d == (DisplayRegion *)NULL) {
return;
}
switch (_background_type) {
case BT_other:
break;
case BT_default:
_display_region_3d->set_clear_color_active(true);
_display_region_3d->set_clear_depth_active(true);
_display_region_3d->set_clear_color(Colorf(win_background_r, win_background_g,
win_background_b, 1.0f));
_display_region_3d->set_clear_depth(1.0f);
break;
case BT_gray:
_display_region_3d->set_clear_color_active(true);
_display_region_3d->set_clear_depth_active(true);
_display_region_3d->set_clear_color(Colorf(0.3f, 0.3f, 0.3f, 1.0f));
_display_region_3d->set_clear_depth(1.0f);
break;
case BT_black:
_display_region_3d->set_clear_color_active(true);
_display_region_3d->set_clear_depth_active(true);
_display_region_3d->set_clear_color(Colorf(0.0f, 0.0f, 0.0f, 1.0f));
_display_region_3d->set_clear_depth(1.0f);
break;
case BT_none:
_window->set_clear_color_active(false);
_window->set_clear_depth_active(false);
break;
}
case BT_none:
_display_region_3d->set_clear_color_active(false);
_display_region_3d->set_clear_depth_active(false);
break;
}
}
@ -798,16 +895,6 @@ set_background_type(WindowFramework::BackgroundType type) {
////////////////////////////////////////////////////////////////////
PT(Camera) WindowFramework::
make_camera() {
// Get the first channel on the window. This will be the only
// channel on non-SGI hardware.
PT(GraphicsChannel) channel = _window->get_channel(0);
// Make a layer on the channel to hold our display region.
PT(GraphicsLayer) layer = channel->make_layer();
// And create a display region that covers the entire window.
PT(DisplayRegion) dr = layer->make_display_region();
// Finally, we need a camera to associate with the display region.
PT(Camera) camera = new Camera("camera");
NodePath camera_np = get_camera_group().attach_new_node(camera);
@ -833,7 +920,7 @@ make_camera() {
camera->set_lens(lens);
camera->set_scene(get_render());
dr->set_camera(camera_np);
_display_region_3d->set_camera(camera_np);
return camera;
}

View File

@ -37,6 +37,7 @@ class AmbientLight;
class DirectionalLight;
class GraphicsEngine;
class GraphicsPipe;
class DisplayRegion;
////////////////////////////////////////////////////////////////////
// Class : WindowFramework
@ -46,6 +47,8 @@ class GraphicsPipe;
class EXPCL_FRAMEWORK WindowFramework : public TypedWritableReferenceCount {
protected:
WindowFramework(PandaFramework *panda_framework);
WindowFramework(const WindowFramework &copy, DisplayRegion *display_region);
public:
virtual ~WindowFramework();
@ -58,6 +61,7 @@ protected:
public:
INLINE PandaFramework *get_panda_framework() const;
INLINE GraphicsWindow *get_graphics_window() const;
INLINE DisplayRegion *get_display_region() const;
const NodePath &get_camera_group();
INLINE int get_num_cameras() const;
@ -88,6 +92,13 @@ public:
BT_none
};
enum SplitType {
ST_default,
ST_horizontal,
ST_vertical,
};
WindowFramework *split_window(SplitType split_type = ST_default);
void set_wireframe(bool enable);
void set_texture(bool enable);
void set_two_sided(bool enable);
@ -112,6 +123,8 @@ private:
private:
PandaFramework *_panda_framework;
PT(GraphicsWindow) _window;
PT(DisplayRegion) _display_region_2d;
PT(DisplayRegion) _display_region_3d;
NodePath _camera_group;
typedef pvector< PT(Camera) > Cameras;

View File

@ -111,7 +111,7 @@ is_mouse_button(ButtonHandle button) {
}
}
return false;
return button == _wheel_up || button == _wheel_down;
}
////////////////////////////////////////////////////////////////////

View File

@ -52,6 +52,22 @@ event_W(CPT_Event, void *) {
}
}
void
event_2(CPT_Event event, void *) {
// 2: split the window into two display regions.
EventParameter param = event->get_parameter(0);
WindowFramework *wf;
DCAST_INTO_V(wf, param.get_ptr());
WindowFramework *split = wf->split_window();
if (split != (WindowFramework *)NULL) {
split->enable_keyboard();
split->setup_trackball();
framework.get_models().instance_to(split->get_render());
}
}
void
usage() {
cerr <<
@ -162,6 +178,7 @@ main(int argc, char *argv[]) {
framework.enable_default_keys();
framework.define_key("shift-w", "open a new window", event_W, NULL);
framework.define_key("2", "split the window", event_2, NULL);
framework.main_loop();
framework.report_frame_rate(nout);
}

View File

@ -406,6 +406,63 @@ get_modifier_buttons() const {
return _mods;
}
////////////////////////////////////////////////////////////////////
// Function: MouseWatcher::set_display_region
// Access: Published
// Description: 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;
}
////////////////////////////////////////////////////////////////////
// Function: MouseWatcher::clear_display_region
// Access: Published
// Description: 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 = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: MouseWatcher::get_display_region
// Access: Published
// Description: 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;
}
////////////////////////////////////////////////////////////////////
// Function: MouseWatcher::has_display_region
// Access: Published
// Description: 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 != (DisplayRegion *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: MouseWatcher::within_region
// Access: Protected

View File

@ -27,6 +27,7 @@
#include "eventParameter.h"
#include "dataNodeTransmit.h"
#include "transformState.h"
#include "displayRegion.h"
#include "dcast.h"
#include <algorithm>
@ -59,7 +60,8 @@ MouseWatcher(const string &name) :
_preferred_region = (MouseWatcherRegion *)NULL;
_preferred_button_down_region = (MouseWatcherRegion *)NULL;
_button_down = false;
_eh = (EventHandler*)0L;
_eh = (EventHandler *)NULL;
_display_region = (DisplayRegion *)NULL;
// When this flag is true, the mouse pointer is allowed to be
// "entered" into multiple regions simultaneously; when false, it
@ -707,8 +709,8 @@ keystroke(int keycode) {
// Keystrokes go to all those regions that want keyboard events,
// regardless of which is the "preferred" region (that is, without
// respect to the mouse position). However, we do set the outside
// flag according to whether the given region is preferred region or
// not.
// flag according to whether the given region is the preferred
// region or not.
Regions::const_iterator ri;
for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
@ -832,6 +834,52 @@ exit_region(MouseWatcherRegion *region, const MouseWatcherParameter &param) {
throw_event_pattern(_leave_pattern, region, ButtonHandle::none());
}
////////////////////////////////////////////////////////////////////
// Function: MouseWatcher::set_no_mouse
// Access: Protected
// Description: Called from do_transmit_data() to indicate the mouse
// is not within the window.
////////////////////////////////////////////////////////////////////
void MouseWatcher::
set_no_mouse() {
if (_has_mouse) {
// Hide the mouse pointer.
if (!_geometry.is_null()) {
_geometry->set_draw_mask(DrawMask::all_off());
}
}
_has_mouse = false;
clear_current_regions();
}
////////////////////////////////////////////////////////////////////
// Function: MouseWatcher::set_mouse
// Access: Protected
// Description: Called from do_transmit_data() to indicate the mouse
// is within the window, and to specify its current
// position.
////////////////////////////////////////////////////////////////////
void MouseWatcher::
set_mouse(const LVecBase2f &xy, const LVecBase2f &pixel_xy) {
if (!_geometry.is_null()) {
// Transform the mouse pointer.
_geometry->set_transform(TransformState::make_pos(LVecBase3f(xy[0], 0, xy[1])));
if (!_has_mouse) {
// Show the mouse pointer.
_geometry->set_draw_mask(DrawMask::all_on());
}
}
_has_mouse = true;
_mouse = xy;
_mouse_pixel = pixel_xy;
VRegions regions;
get_over_regions(regions, _mouse);
set_current_regions(regions);
}
////////////////////////////////////////////////////////////////////
// Function: MouseWatcher::do_transmit_data
// Access: Protected, Virtual
@ -847,43 +895,58 @@ exit_region(MouseWatcherRegion *region, const MouseWatcherParameter &param) {
////////////////////////////////////////////////////////////////////
void MouseWatcher::
do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
// Initially, we do not suppress any events to objects below us in
// the data graph.
_suppress_flags = 0;
if (!input.has_data(_xy_input)) {
// No mouse in the window.
if (_has_mouse) {
// Hide the mouse pointer.
if (!_geometry.is_null()) {
_geometry->set_draw_mask(DrawMask::all_off());
}
}
_has_mouse = false;
clear_current_regions();
set_no_mouse();
} else {
// The mouse is within the window. Get the current mouse position.
const EventStoreVec2 *xy;
const EventStoreVec2 *xy, *pixel_xy;
DCAST_INTO_V(xy, input.get_data(_xy_input).get_ptr());
const LVecBase2f &p = xy->get_value();
_mouse.set(p[0], p[1]);
if (!_geometry.is_null()) {
// Transform the mouse pointer.
_geometry->set_transform(TransformState::make_pos(LVecBase3f(p[0], 0, p[1])));
if (!_has_mouse) {
// Show the mouse pointer.
_geometry->set_draw_mask(DrawMask::all_on());
DCAST_INTO_V(pixel_xy, input.get_data(_pixel_xy_input).get_ptr());
const LVecBase2f &f = xy->get_value();
const LVecBase2f &p = pixel_xy->get_value();
if (_display_region != (DisplayRegion *)NULL) {
// If we've got a display region, constrain the mouse to it.
int xo, yo, width, height;
_display_region->get_region_pixels_i(xo, yo, width, height);
if (p[0] < xo || p[0] >= xo + width ||
p[1] < yo || p[1] >= yo + height) {
// The mouse is outside the display region, even though it's
// within the window. This is considered not having a mouse.
set_no_mouse();
// This also means we should suppress button events below us.
_suppress_flags = MouseWatcherRegion::SF_any_button;
} else {
// The mouse is within the display region; rescale it.
float left, right, bottom, top;
_display_region->get_dimensions(left, right, bottom, top);
LVecBase2f new_f((f[0] - left) / (right - left),
(f[1] - bottom) / (top - bottom));
LVecBase2f new_p(p[0] - xo, p[1] - xo);
set_mouse(new_f, new_p);
}
} else {
// No display region; respect the whole window.
set_mouse(f, p);
}
_has_mouse = true;
VRegions regions;
get_over_regions(regions, _mouse);
set_current_regions(regions);
}
_suppress_flags = 0;
// If the mouse is over a particular region, or still considered
// owned by a region because of a recent button-down event, that
// region determines whether we suppress events below us.
if (_preferred_region != (MouseWatcherRegion *)NULL) {
_suppress_flags = _preferred_region->get_suppress_flags();
}
@ -920,15 +983,15 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
if (_has_mouse &&
(_suppress_flags & MouseWatcherRegion::SF_mouse_position) == 0) {
// Transmit the mouse position.
output.set_data(_xy_output, input.get_data(_xy_input));
output.set_data(_pixel_xy_output, input.get_data(_pixel_xy_input));
_xy->set_value(_mouse);
output.set_data(_xy_output, EventParameter(_xy));
_pixel_xy->set_value(_mouse_pixel);
output.set_data(_pixel_xy_output, EventParameter(_pixel_xy));
}
int suppress_buttons = (_suppress_flags & MouseWatcherRegion::SF_any_button);
if (suppress_buttons == MouseWatcherRegion::SF_any_button) {
// Suppress all buttons.
} else if (suppress_buttons != 0) {
if (suppress_buttons != 0) {
// Suppress some buttons.
_button_events->clear();
@ -947,7 +1010,7 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
suppress = ((suppress_buttons & MouseWatcherRegion::SF_other_button) != 0);
}
if (!suppress) {
if (!suppress || be._type == ButtonEvent::T_up) {
// Don't suppress this button event; pass it through.
_button_events->add_event(be);
}
@ -963,4 +1026,3 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
output.set_data(_button_events_output, input.get_data(_button_events_input));
}
}

View File

@ -34,6 +34,7 @@
#include "pvector.h"
class MouseWatcherParameter;
class DisplayRegion;
////////////////////////////////////////////////////////////////////
// Class : MouseWatcher
@ -103,6 +104,11 @@ PUBLISHED:
INLINE void set_modifier_buttons(const ModifierButtons &mods);
INLINE ModifierButtons get_modifier_buttons() const;
INLINE void set_display_region(DisplayRegion *dr);
INLINE void clear_display_region();
INLINE DisplayRegion *get_display_region() const;
INLINE bool has_display_region() const;
public:
virtual void output(ostream &out) const;
virtual void write(ostream &out, int indent_level = 0) const;
@ -141,6 +147,9 @@ protected:
void enter_region(MouseWatcherRegion *region, const MouseWatcherParameter &param);
void exit_region(MouseWatcherRegion *region, const MouseWatcherParameter &param);
void set_no_mouse();
void set_mouse(const LVecBase2f &xy, const LVecBase2f &pixel_xy);
// This wants to be a set, but because you cannot export sets across
// dlls in windows, we will make it a vector instead
typedef pvector< PT(MouseWatcherGroup) > Groups;
@ -149,6 +158,7 @@ protected:
bool _has_mouse;
int _suppress_flags;
LPoint2f _mouse;
LPoint2f _mouse_pixel;
VRegions _current_regions;
PT(MouseWatcherRegion) _preferred_region;
@ -168,8 +178,8 @@ protected:
PT(PandaNode) _geometry;
EventHandler *_eh;
ModifierButtons _mods;
DisplayRegion *_display_region;
protected:
// Inherited from DataNode