add MouseWatcher::set_display_region()
This commit is contained in:
parent
e390fbddaf
commit
a79af737d2
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 ©, 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ©, 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;
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ is_mouse_button(ButtonHandle button) {
|
|||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return button == _wheel_up || button == _wheel_down;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ¶m) {
|
|||
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 ¶m) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ¶m);
|
||||
void exit_region(MouseWatcherRegion *region, const MouseWatcherParameter ¶m);
|
||||
|
||||
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
|
||||
|
|
|
|||
Loading…
Reference in New Issue