Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/tform/mouseWatcher.cxx

Go to the documentation of this file.
00001 // Filename: mouseWatcher.cxx
00002 // Created by:  drose (12Mar02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "mouseWatcher.h"
00020 #include "config_tform.h"
00021 #include "mouseWatcherParameter.h"
00022 #include "mouseAndKeyboard.h"
00023 #include "mouseData.h"
00024 #include "buttonEventList.h"
00025 #include "mouseButton.h"
00026 #include "throw_event.h"
00027 #include "eventParameter.h"
00028 #include "dataNodeTransmit.h"
00029 #include "transformState.h"
00030 #include "dcast.h"
00031 
00032 #include <algorithm>
00033 
00034 TypeHandle MouseWatcher::_type_handle;
00035 
00036 ////////////////////////////////////////////////////////////////////
00037 //     Function: MouseWatcher::Constructor
00038 //       Access: Published
00039 //  Description:
00040 ////////////////////////////////////////////////////////////////////
00041 MouseWatcher::
00042 MouseWatcher(const string &name) : 
00043   DataNode(name) 
00044 {
00045   _pixel_xy_input = define_input("pixel_xy", EventStoreVec2::get_class_type());
00046   _xy_input = define_input("xy", EventStoreVec2::get_class_type());
00047   _button_events_input = define_input("button_events", ButtonEventList::get_class_type());
00048 
00049   _pixel_xy_output = define_output("pixel_xy", EventStoreVec2::get_class_type());
00050   _xy_output = define_output("xy", EventStoreVec2::get_class_type());
00051   _button_events_output = define_output("button_events", ButtonEventList::get_class_type());
00052 
00053   _pixel_xy = new EventStoreVec2(LPoint2f(0.0f, 0.0f));
00054   _xy = new EventStoreVec2(LPoint2f(0.0f, 0.0f));
00055   _button_events = new ButtonEventList;
00056 
00057   _has_mouse = false;
00058   _suppress_flags = 0;
00059   _preferred_region = (MouseWatcherRegion *)NULL;
00060   _preferred_button_down_region = (MouseWatcherRegion *)NULL;
00061   _button_down = false;
00062   _eh = (EventHandler*)0L;
00063 
00064   // When this flag is true, the mouse pointer is allowed to be
00065   // "entered" into multiple regions simultaneously; when false, it
00066   // will only be "within" multiple regions, but "entered" into the
00067   // topmost of those.
00068   _enter_multiple = false;
00069 
00070   // When this flag is true, moving the pointer into a region is
00071   // enough to click it.  The click is simulated with mouse button
00072   // one.
00073   _implicit_click = false;
00074 }
00075 
00076 ////////////////////////////////////////////////////////////////////
00077 //     Function: MouseWatcher::Destructor
00078 //       Access: Published
00079 //  Description:
00080 ////////////////////////////////////////////////////////////////////
00081 MouseWatcher::
00082 ~MouseWatcher() {
00083 }
00084 
00085 ////////////////////////////////////////////////////////////////////
00086 //     Function: MouseWatcher::remove_region
00087 //       Access: Published
00088 //  Description: Removes the indicated region from the group.
00089 //               Returns true if it was successfully removed, or false
00090 //               if it wasn't there in the first place.
00091 ////////////////////////////////////////////////////////////////////
00092 bool MouseWatcher::
00093 remove_region(MouseWatcherRegion *region) {
00094   remove_region_from(_current_regions, region);
00095   if (region == _preferred_region) {
00096     _preferred_region = (MouseWatcherRegion *)NULL;
00097   }
00098   if (region == _preferred_button_down_region) {
00099     _preferred_button_down_region = (MouseWatcherRegion *)NULL;
00100   }
00101 
00102   return MouseWatcherGroup::remove_region(region);
00103 }
00104 
00105 ////////////////////////////////////////////////////////////////////
00106 //     Function: MouseWatcher::get_over_region
00107 //       Access: Published
00108 //  Description: Returns the preferred region the mouse is over.  In
00109 //               the case of overlapping regions, the region with the
00110 //               largest sort order is preferred; if two regions have
00111 //               the same sort order, then the smaller region is
00112 //               preferred.
00113 ////////////////////////////////////////////////////////////////////
00114 MouseWatcherRegion *MouseWatcher::
00115 get_over_region(const LPoint2f &pos) const {
00116   VRegions regions;
00117   get_over_regions(regions, pos);
00118   return get_preferred_region(regions);
00119 }
00120 
00121 
00122 ////////////////////////////////////////////////////////////////////
00123 //     Function: MouseWatcher::output
00124 //       Access: Public, Virtual
00125 //  Description:
00126 ////////////////////////////////////////////////////////////////////
00127 void MouseWatcher::
00128 output(ostream &out) const {
00129   DataNode::output(out);
00130 
00131   int count = _regions.size();
00132   Groups::const_iterator gi;
00133   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00134     MouseWatcherGroup *group = (*gi);
00135     count += group->_regions.size();
00136   }
00137 
00138   out << " (" << count << " regions)";
00139 }
00140 
00141 ////////////////////////////////////////////////////////////////////
00142 //     Function: MouseWatcher::write
00143 //       Access: Public, Virtual
00144 //  Description:
00145 ////////////////////////////////////////////////////////////////////
00146 void MouseWatcher::
00147 write(ostream &out, int indent_level) const {
00148   indent(out, indent_level)
00149     << "MouseWatcher " << get_name() << ":\n";
00150   Regions::const_iterator ri;
00151   for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
00152     MouseWatcherRegion *region = (*ri);
00153     region->write(out, indent_level + 2);
00154   }
00155 
00156   if (!_groups.empty()) {
00157     Groups::const_iterator gi;
00158     for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00159       MouseWatcherGroup *group = (*gi);
00160       indent(out, indent_level + 2)
00161         << "Subgroup:\n";
00162       for (ri = group->_regions.begin(); ri != group->_regions.end(); ++ri) {
00163         MouseWatcherRegion *region = (*ri);
00164         region->write(out, indent_level + 4);
00165       }
00166     }
00167   }
00168 }
00169 
00170 ////////////////////////////////////////////////////////////////////
00171 //     Function: MouseWatcher::add_group
00172 //       Access: Public
00173 //  Description: Adds the indicated group of regions to the set of
00174 //               regions the MouseWatcher will monitor each frame.
00175 //
00176 //               Since the MouseWatcher itself inherits from
00177 //               MouseWatcherGroup, this operation is normally not
00178 //               necessary--you can simply add the Regions you care
00179 //               about one at a time.  Adding a complete group is
00180 //               useful when you may want to explicitly remove the
00181 //               regions as a group later.
00182 //
00183 //               Returns true if the group was successfully added, or
00184 //               false if it was already on the list.
00185 ////////////////////////////////////////////////////////////////////
00186 bool MouseWatcher::
00187 add_group(MouseWatcherGroup *group) {
00188   // return _groups.insert(group).second;
00189 
00190   // See if the group is in the set/vector already
00191   PT(MouseWatcherGroup) pt = group;
00192   Groups::const_iterator gi = 
00193     find(_groups.begin(), _groups.end(), pt);
00194   if (gi != _groups.end()) {
00195     // Already in the set, return false
00196     return false;
00197   }
00198 
00199   // Not in the set, add it and return true
00200   _groups.push_back(pt);
00201   return true;
00202 }
00203 
00204 ////////////////////////////////////////////////////////////////////
00205 //     Function: MouseWatcher::remove_group
00206 //       Access: Public
00207 //  Description: Removes the indicated group from the set of extra
00208 //               groups associated with the MouseWatcher.  Returns
00209 //               true if successful, or false if the group was already
00210 //               removed or was never added via add_group().
00211 ////////////////////////////////////////////////////////////////////
00212 bool MouseWatcher::
00213 remove_group(MouseWatcherGroup *group) {
00214   remove_regions_from(_current_regions, group);
00215   if (group->has_region(_preferred_region)) {
00216     _preferred_region = (MouseWatcherRegion *)NULL;
00217   }
00218   if (group->has_region(_preferred_button_down_region)) {
00219     _preferred_button_down_region = (MouseWatcherRegion *)NULL;
00220   }
00221 
00222   // See if the group is in the set/vector
00223   PT(MouseWatcherGroup) pt = group;
00224   Groups::iterator gi = 
00225     find(_groups.begin(), _groups.end(), pt);
00226   if (gi != _groups.end()) {
00227     // Found it, now erase it
00228     _groups.erase(gi);
00229     return true;
00230   }
00231 
00232   // Did not find the group to erase
00233   return false;
00234 }
00235 
00236 ////////////////////////////////////////////////////////////////////
00237 //     Function: MouseWatcher::get_over_regions
00238 //       Access: Protected
00239 //  Description: Fills up the "regions" list with the set of regions
00240 //               that the indicated point is over, sorted in order by
00241 //               pointer.
00242 ////////////////////////////////////////////////////////////////////
00243 void MouseWatcher::
00244 get_over_regions(MouseWatcher::VRegions &regions, const LPoint2f &pos) const {
00245   // Ensure the vector is empty before we begin.
00246   regions.clear();
00247 
00248   Regions::const_iterator ri;
00249   for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
00250     MouseWatcherRegion *region = (*ri);
00251     const LVecBase4f &frame = region->get_frame();
00252 
00253     if (region->get_active() &&
00254         pos[0] >= frame[0] && pos[0] <= frame[1] &&
00255         pos[1] >= frame[2] && pos[1] <= frame[3]) {
00256 
00257       regions.push_back(region);
00258     }
00259   }
00260 
00261   // Also check all of our sub-groups.
00262   Groups::const_iterator gi;
00263   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00264     MouseWatcherGroup *group = (*gi);
00265     for (ri = group->_regions.begin(); ri != group->_regions.end(); ++ri) {
00266       MouseWatcherRegion *region = (*ri);
00267       const LVecBase4f &frame = region->get_frame();
00268       
00269       if (region->get_active() &&
00270           pos[0] >= frame[0] && pos[0] <= frame[1] &&
00271           pos[1] >= frame[2] && pos[1] <= frame[3]) {
00272         
00273         regions.push_back(region);
00274       }
00275     }
00276   }
00277 
00278   // Now sort the regions by pointer.  By convention, the Regions
00279   // vectors are always kept in order by pointer, so we can do easy
00280   // linear comparison and intersection operations.
00281   sort(regions.begin(), regions.end());
00282 }
00283 
00284 ////////////////////////////////////////////////////////////////////
00285 //     Function: MouseWatcher::get_preferred_region
00286 //       Access: Protected, Static
00287 //  Description: Returns the innermost region of all the regions
00288 //               indicated in the given vector (usually, the regions
00289 //               the mouse is over).  This is the "preferred" region
00290 //               that gets some special treatment.
00291 ////////////////////////////////////////////////////////////////////
00292 MouseWatcherRegion *MouseWatcher::
00293 get_preferred_region(const MouseWatcher::VRegions &regions) {
00294   if (regions.empty()) {
00295     return (MouseWatcherRegion *)NULL;
00296   }
00297 
00298   VRegions::const_iterator ri;
00299   ri = regions.begin();
00300   MouseWatcherRegion *preferred = *ri;
00301   ++ri;
00302   while (ri != regions.end()) {
00303     MouseWatcherRegion *region = *ri;
00304 
00305     if (*region < *preferred) {
00306       preferred = region;
00307     }
00308     ++ri;
00309   }
00310 
00311   return preferred;
00312 }
00313 
00314 ////////////////////////////////////////////////////////////////////
00315 //     Function: MouseWatcher::set_current_regions
00316 //       Access: Protected
00317 //  Description: Changes the "current" regions--the one we consider the
00318 //               mouse to be over--to the indicated list, and throws
00319 //               whatever events are appropriate because of that.
00320 //
00321 //               The list passed in is destroyed.
00322 ////////////////////////////////////////////////////////////////////
00323 void MouseWatcher::
00324 set_current_regions(MouseWatcher::VRegions &regions) {
00325   // Set up a parameter for passing through any change events.
00326   MouseWatcherParameter param;
00327   param.set_modifier_buttons(_mods);
00328   param.set_mouse(_mouse);
00329 
00330   // Now do a standard sorted comparison between the two vectors.
00331   VRegions::const_iterator new_ri = regions.begin();
00332   VRegions::const_iterator old_ri = _current_regions.begin();
00333 
00334   // Queue up all the new regions so we can send the within patterns
00335   // all at once, after all of the without patterns have been thrown.
00336   vector<MouseWatcherRegion *> new_regions;
00337 
00338   bool any_changes = false;
00339   while (new_ri != regions.end() && old_ri != _current_regions.end()) {
00340     if ((*new_ri) < (*old_ri)) {
00341       // Here's a new region that we didn't have last frame.
00342       MouseWatcherRegion *new_region = (*new_ri);
00343       new_regions.push_back(new_region);
00344       any_changes = true;
00345       ++new_ri;
00346 
00347     } else if ((*old_ri) < (*new_ri)) {
00348       // Here's a region we don't have any more.
00349       MouseWatcherRegion *old_region = (*old_ri);
00350       without_region(old_region, param);
00351       any_changes = true;
00352       ++old_ri;
00353 
00354     } else {
00355       // Here's a region that hasn't changed.
00356       ++new_ri;
00357       ++old_ri;
00358     }
00359   }
00360 
00361   while (new_ri != regions.end()) {
00362     // Here's a new region that we didn't have last frame.
00363     MouseWatcherRegion *new_region = (*new_ri);
00364     new_regions.push_back(new_region);
00365     any_changes = true;
00366     ++new_ri;
00367   }
00368 
00369   while (old_ri != _current_regions.end()) {
00370     // Here's a region we don't have any more.
00371     MouseWatcherRegion *old_region = (*old_ri);
00372     without_region(old_region, param);
00373     any_changes = true;
00374     ++old_ri;
00375   }
00376 
00377   if (any_changes) {
00378     // Now that we've compared the two vectors, simply swap them to set
00379     // the new vector.
00380     _current_regions.swap(regions);
00381 
00382     // And don't forget to throw all of the new regions' "within" events.
00383     vector<MouseWatcherRegion *>::const_iterator ri;
00384     for (ri = new_regions.begin(); ri != new_regions.end(); ++ri) {
00385       MouseWatcherRegion *new_region = (*ri);
00386       within_region(new_region, param);
00387     }
00388   }
00389 
00390   if (!_enter_multiple) {
00391     // Determine which is the "preferred region", if any.  This is the
00392     // topmost region that the mouse cursor is over, and the one that
00393     // we are considered "entered" into.
00394     MouseWatcherRegion *new_preferred_region = 
00395       get_preferred_region(_current_regions);
00396     
00397     if (_button_down && new_preferred_region != _preferred_button_down_region) {
00398       // If the button's being held down, we're only allowed to select
00399       // the preferred button down region.
00400       new_preferred_region = (MouseWatcherRegion *)NULL;
00401     }
00402 
00403     if (new_preferred_region != _preferred_region) {
00404       if (_preferred_region != (MouseWatcherRegion *)NULL) {
00405         exit_region(_preferred_region, param);
00406       }
00407       _preferred_region = new_preferred_region;
00408       if (_preferred_region != (MouseWatcherRegion *)NULL) {
00409         enter_region(_preferred_region, param);
00410       }
00411     }
00412   }
00413 }
00414 
00415 ////////////////////////////////////////////////////////////////////
00416 //     Function: MouseWatcher::clear_current_regions
00417 //       Access: Protected
00418 //  Description: Empties the set of current regions.
00419 ////////////////////////////////////////////////////////////////////
00420 void MouseWatcher::
00421 clear_current_regions() {
00422   if (!_current_regions.empty()) {
00423     // Set up a parameter for passing through any change events.
00424     MouseWatcherParameter param;
00425     param.set_modifier_buttons(_mods);
00426     param.set_mouse(_mouse);
00427     
00428     VRegions::const_iterator old_ri = _current_regions.begin();
00429     
00430     while (old_ri != _current_regions.end()) {
00431       // Here's a region we don't have any more.
00432       MouseWatcherRegion *old_region = (*old_ri);
00433       old_region->exit(param);
00434       throw_event_pattern(_leave_pattern, old_region, ButtonHandle::none());
00435       ++old_ri;
00436     }
00437     
00438     _current_regions.clear();
00439 
00440     if (_preferred_region != (MouseWatcherRegion *)NULL) {
00441       _preferred_region->exit(param);
00442       throw_event_pattern(_leave_pattern, _preferred_region, ButtonHandle::none());
00443       _preferred_region = (MouseWatcherRegion *)NULL;
00444     }
00445   }
00446 }
00447 
00448 ////////////////////////////////////////////////////////////////////
00449 //     Function: MouseWatcher::intersect_regions
00450 //       Access: Protected, Static
00451 //  Description: Sets result to be the intersection of the list of
00452 //               regions in regions_a and regions_b.  It is assumed
00453 //               that both vectors are already sorted in pointer
00454 //               order.
00455 ////////////////////////////////////////////////////////////////////
00456 void MouseWatcher::
00457 intersect_regions(MouseWatcher::VRegions &result,
00458                   const MouseWatcher::VRegions &regions_a,
00459                   const MouseWatcher::VRegions &regions_b) {
00460   // Get a temporary vector for storing the result in.  We don't use
00461   // result directly, because it might be the same vector as one of a
00462   // or b.
00463   VRegions temp;
00464 
00465   // Now do a standard sorted intersection between the two vectors.
00466   VRegions::const_iterator a_ri = regions_a.begin();
00467   VRegions::const_iterator b_ri = regions_b.begin();
00468 
00469   while (a_ri != regions_a.end() && b_ri != regions_b.end()) {
00470     if ((*a_ri) < (*b_ri)) {
00471       // Here's a region in a, not in b.
00472       ++a_ri;
00473 
00474     } else if ((*b_ri) < (*a_ri)) {
00475       // Here's a region in b, not in a.
00476       ++b_ri;
00477 
00478     } else {
00479       // Here's a region in both vectors.
00480       temp.push_back(*a_ri);
00481       ++a_ri;
00482       ++b_ri;
00483     }
00484   }
00485 
00486   // Now store the result!
00487   result.swap(temp);
00488 }
00489 
00490 ////////////////////////////////////////////////////////////////////
00491 //     Function: MouseWatcher::remove_region_from
00492 //       Access: Protected, Static
00493 //  Description: Removes the indicated region from the given vector.
00494 //               Assumes the vector is sorted in pointer order.
00495 ////////////////////////////////////////////////////////////////////
00496 void MouseWatcher::
00497 remove_region_from(MouseWatcher::VRegions &regions,
00498                    MouseWatcherRegion *region) {
00499   PT(MouseWatcherRegion) ptr = region;
00500   VRegions::iterator ri = lower_bound(regions.begin(), regions.end(), ptr);
00501   if (ri != regions.end() && (*ri) == ptr) {
00502     // The region is in the vector.  Remove it.
00503     regions.erase(ri);
00504   }
00505 }
00506 
00507 ////////////////////////////////////////////////////////////////////
00508 //     Function: MouseWatcher::remove_regions_from
00509 //       Access: Protected, Static
00510 //  Description: Removes all the regions in the indicated group from
00511 //               the given vector.  Assumes the vector is sorted in
00512 //               pointer order.
00513 ////////////////////////////////////////////////////////////////////
00514 void MouseWatcher::
00515 remove_regions_from(MouseWatcher::VRegions &regions,
00516                     MouseWatcherGroup *group) {
00517   // Since the group stores a set of regions, which are also sorted in
00518   // pointer order, we can just do an intersection operation here.
00519   VRegions temp;
00520 
00521   VRegions::const_iterator a_ri = regions.begin();
00522   MouseWatcherGroup::Regions::const_iterator b_ri = group->_regions.begin();
00523 
00524   while (a_ri != regions.end() && b_ri != group->_regions.end()) {
00525     if ((*a_ri) < (*b_ri)) {
00526       // Here's a region in the group, not in regions.
00527       ++a_ri;
00528 
00529     } else if ((*b_ri) < (*a_ri)) {
00530       // Here's a region in regions, not in the group.
00531       temp.push_back(*b_ri);
00532       ++b_ri;
00533 
00534     } else {
00535       // Here's a region in the group and in regions.
00536       ++a_ri;
00537       ++b_ri;
00538     }
00539   }
00540 
00541   // Now store the result!
00542   regions.swap(temp);
00543 }
00544 
00545 ////////////////////////////////////////////////////////////////////
00546 //     Function: MouseWatcher::throw_event_for
00547 //       Access: Protected
00548 //  Description: Throws an event associated with the indicated region,
00549 //               using the given pattern.
00550 ////////////////////////////////////////////////////////////////////
00551 void MouseWatcher::
00552 throw_event_pattern(const string &pattern, const MouseWatcherRegion *region,
00553                     const ButtonHandle &button) {
00554   if (pattern.empty()) {
00555     return;
00556   }
00557 #ifndef NDEBUG
00558   if (region != (MouseWatcherRegion *)NULL) {
00559     region->test_ref_count_integrity();
00560   }
00561 #endif
00562 
00563   string button_name;
00564   if (button != ButtonHandle::none()) {
00565     if (!_mods.has_button(button)) {
00566       // We only prepend modifier names for buttons which are not
00567       // themselves modifiers.
00568       button_name = _mods.get_prefix();
00569     }
00570     button_name += button.get_name();
00571   }
00572 
00573   string event;
00574   for (size_t p = 0; p < pattern.size(); ++p) {
00575     if (pattern[p] == '%') {
00576       string cmd = pattern.substr(p + 1, 1);
00577       p++;
00578       if (cmd == "r") {
00579         if (region != (MouseWatcherRegion *)NULL) {
00580           event += button_name;
00581         }
00582 
00583       } else if (cmd == "b") {
00584         event += button.get_name();
00585 
00586       } else {
00587         tform_cat.error()
00588           << "Invalid symbol in event_pattern: %" << cmd << "\n";
00589       }
00590     } else {
00591       event += pattern[p];
00592     }
00593   }
00594 
00595   if (!event.empty()) {
00596     throw_event(event, EventParameter(region), EventParameter(button_name));
00597     if (_eh != (EventHandler*)0L)
00598       throw_event_directly(*_eh, event, EventParameter(region),
00599                            EventParameter(button_name));
00600   }
00601 }
00602 
00603 ////////////////////////////////////////////////////////////////////
00604 //     Function: MouseWatcher::press
00605 //       Access: Protected
00606 //  Description: Records the indicated mouse or keyboard button as
00607 //               being depressed.
00608 ////////////////////////////////////////////////////////////////////
00609 void MouseWatcher::
00610 press(ButtonHandle button) {
00611   MouseWatcherParameter param;
00612   param.set_button(button);
00613   param.set_modifier_buttons(_mods);
00614   param.set_mouse(_mouse);
00615 
00616   if (MouseButton::is_mouse_button(button)) {
00617     // Mouse buttons are inextricably linked to the mouse position.
00618     
00619     if (!_button_down) {
00620       _preferred_button_down_region = _preferred_region;
00621     }
00622     _button_down = true;
00623 
00624     if (_preferred_button_down_region != (MouseWatcherRegion *)NULL) {
00625       _preferred_button_down_region->press(param);
00626       throw_event_pattern(_button_down_pattern,
00627                           _preferred_button_down_region, button);
00628     }
00629     
00630   } else {
00631     // It's a keyboard button; therefore, send the event to every
00632     // region that wants keyboard buttons, regardless of the mouse
00633     // position.
00634     if (_preferred_region != (MouseWatcherRegion *)NULL) {
00635       // Our current region, the one under the mouse, always get
00636       // all the keyboard events, even if it doesn't set its
00637       // keyboard flag.
00638       _preferred_region->press(param);
00639     }
00640 
00641     if ((_suppress_flags & MouseWatcherRegion::SF_other_button) == 0) {
00642       // All the other regions only get the keyboard events if they
00643       // set their global keyboard flag, *and* the current region does
00644       // not suppress keyboard buttons.
00645       param.set_outside(true);
00646       global_keyboard_press(param);
00647     }
00648   }
00649 }
00650 
00651 ////////////////////////////////////////////////////////////////////
00652 //     Function: MouseWatcher::release
00653 //       Access: Protected
00654 //  Description: Records the indicated mouse or keyboard button as
00655 //               being released.
00656 ////////////////////////////////////////////////////////////////////
00657 void MouseWatcher::
00658 release(ButtonHandle button) {
00659   MouseWatcherParameter param;
00660   param.set_button(button);
00661   param.set_modifier_buttons(_mods);
00662   param.set_mouse(_mouse);
00663 
00664   if (MouseButton::is_mouse_button(button)) {
00665     // Button up.  Send the up event associated with the region(s) we
00666     // were over when the button went down.
00667     
00668     // There is some danger of losing button-up events here.  If
00669     // more than one button goes down together, we won't detect
00670     // both of the button-up events properly.
00671     if (_preferred_button_down_region != (MouseWatcherRegion *)NULL) {
00672       param.set_outside(_preferred_button_down_region != _preferred_region);
00673       _preferred_button_down_region->release(param);
00674       throw_event_pattern(_button_up_pattern,
00675                           _preferred_button_down_region, button);
00676     }
00677 
00678     _button_down = false;
00679     _preferred_button_down_region = (MouseWatcherRegion *)NULL;
00680     
00681   } else {
00682     // It's a keyboard button; therefore, send the event to every
00683     // region that wants keyboard buttons, regardless of the mouse
00684     // position.
00685     if (_preferred_region != (MouseWatcherRegion *)NULL) {
00686       _preferred_region->release(param);
00687     }
00688     
00689     param.set_outside(true);
00690     global_keyboard_release(param);
00691   }
00692 }
00693 
00694 ////////////////////////////////////////////////////////////////////
00695 //     Function: MouseWatcher::keystroke
00696 //       Access: Protected
00697 //  Description: Records that the indicated keystroke has been
00698 //               generated.
00699 ////////////////////////////////////////////////////////////////////
00700 void MouseWatcher::
00701 keystroke(int keycode) {
00702   MouseWatcherParameter param;
00703   param.set_keycode(keycode);
00704   param.set_modifier_buttons(_mods);
00705   param.set_mouse(_mouse);
00706 
00707   // Keystrokes go to all those regions that want keyboard events,
00708   // regardless of which is the "preferred" region (that is, without
00709   // respect to the mouse position).  However, we do set the outside
00710   // flag according to whether the given region is preferred region or
00711   // not.
00712 
00713   Regions::const_iterator ri;
00714   for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
00715     MouseWatcherRegion *region = (*ri);
00716 
00717     if (region->get_keyboard()) {
00718       param.set_outside(region != _preferred_region);
00719       region->keystroke(param);
00720     }
00721   }
00722 
00723   // Also check all of our sub-groups.
00724   Groups::const_iterator gi;
00725   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00726     MouseWatcherGroup *group = (*gi);
00727     for (ri = group->_regions.begin(); ri != group->_regions.end(); ++ri) {
00728       MouseWatcherRegion *region = (*ri);
00729 
00730       if (region->get_keyboard()) {
00731         param.set_outside(region != _preferred_region);
00732         region->keystroke(param);
00733       }
00734     }
00735   }
00736 }
00737 
00738 ////////////////////////////////////////////////////////////////////
00739 //     Function: MouseWatcher::global_keyboard_press
00740 //       Access: Protected
00741 //  Description: Calls press() on all regions that are interested in
00742 //               receiving global keyboard events, except for the
00743 //               current region (which already received this one).
00744 ////////////////////////////////////////////////////////////////////
00745 void MouseWatcher::
00746 global_keyboard_press(const MouseWatcherParameter &param) {
00747   Regions::const_iterator ri;
00748   for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
00749     MouseWatcherRegion *region = (*ri);
00750 
00751     if (region != _preferred_region && region->get_keyboard()) {
00752       region->press(param);
00753     }
00754   }
00755 
00756   // Also check all of our sub-groups.
00757   Groups::const_iterator gi;
00758   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00759     MouseWatcherGroup *group = (*gi);
00760     for (ri = group->_regions.begin(); ri != group->_regions.end(); ++ri) {
00761       MouseWatcherRegion *region = (*ri);
00762 
00763       if (region != _preferred_region && region->get_keyboard()) {
00764         region->press(param);
00765       }
00766     }
00767   }
00768 }
00769 ////////////////////////////////////////////////////////////////////
00770 //     Function: MouseWatcher::global_keyboard_release
00771 //       Access: Protected
00772 //  Description: Calls release() on all regions that are interested in
00773 //               receiving global keyboard events, except for the
00774 //               current region (which already received this one).
00775 ////////////////////////////////////////////////////////////////////
00776 void MouseWatcher::
00777 global_keyboard_release(const MouseWatcherParameter &param) {
00778   Regions::const_iterator ri;
00779   for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
00780     MouseWatcherRegion *region = (*ri);
00781 
00782     if (region != _preferred_region && region->get_keyboard()) {
00783       region->release(param);
00784     }
00785   }
00786 
00787   // Also check all of our sub-groups.
00788   Groups::const_iterator gi;
00789   for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00790     MouseWatcherGroup *group = (*gi);
00791     for (ri = group->_regions.begin(); ri != group->_regions.end(); ++ri) {
00792       MouseWatcherRegion *region = (*ri);
00793 
00794       if (region != _preferred_region && region->get_keyboard()) {
00795         region->release(param);
00796       }
00797     }
00798   }
00799 }
00800 
00801 ////////////////////////////////////////////////////////////////////
00802 //     Function: MouseWatcher::enter_region
00803 //       Access: Protected
00804 //  Description: Called internally to indicate the mouse pointer is no
00805 //               longer favoring the indicated region.
00806 ////////////////////////////////////////////////////////////////////
00807 void MouseWatcher::
00808 enter_region(MouseWatcherRegion *region, const MouseWatcherParameter &param) {
00809   region->enter(param);
00810   throw_event_pattern(_enter_pattern, region, ButtonHandle::none());
00811   if (_implicit_click) {
00812     MouseWatcherParameter param1(param);
00813     param1.set_button(MouseButton::one());
00814     region->press(param1);
00815   }
00816 }
00817 
00818 ////////////////////////////////////////////////////////////////////
00819 //     Function: MouseWatcher::exit_region
00820 //       Access: Protected
00821 //  Description: Called internally to indicate the mouse pointer is no
00822 //               longer favoring the indicated region.
00823 ////////////////////////////////////////////////////////////////////
00824 void MouseWatcher::
00825 exit_region(MouseWatcherRegion *region, const MouseWatcherParameter &param) {
00826   if (_implicit_click) {
00827     MouseWatcherParameter param1(param);
00828     param1.set_button(MouseButton::one());
00829     region->release(param1);
00830   }
00831   region->exit(param);
00832   throw_event_pattern(_leave_pattern, region, ButtonHandle::none());
00833 }
00834 
00835 ////////////////////////////////////////////////////////////////////
00836 //     Function: MouseWatcher::do_transmit_data
00837 //       Access: Protected, Virtual
00838 //  Description: The virtual implementation of transmit_data().  This
00839 //               function receives an array of input parameters and
00840 //               should generate an array of output parameters.  The
00841 //               input parameters may be accessed with the index
00842 //               numbers returned by the define_input() calls that
00843 //               were made earlier (presumably in the constructor);
00844 //               likewise, the output parameters should be set with
00845 //               the index numbers returned by the define_output()
00846 //               calls.
00847 ////////////////////////////////////////////////////////////////////
00848 void MouseWatcher::
00849 do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &output) {
00850   if (!input.has_data(_xy_input)) {
00851     // No mouse in the window.
00852 
00853     if (_has_mouse) {
00854       // Hide the mouse pointer.
00855       if (!_geometry.is_null()) {
00856         _geometry->set_draw_mask(DrawMask::all_off());
00857       }
00858     }
00859 
00860     _has_mouse = false;
00861     clear_current_regions();
00862 
00863   } else {
00864     // The mouse is within the window.  Get the current mouse position.
00865     const EventStoreVec2 *xy;
00866     DCAST_INTO_V(xy, input.get_data(_xy_input).get_ptr());
00867     const LVecBase2f &p = xy->get_value();
00868     _mouse.set(p[0], p[1]);
00869     
00870     if (!_geometry.is_null()) {
00871       // Transform the mouse pointer.
00872       _geometry->set_transform(TransformState::make_pos(LVecBase3f(p[0], 0, p[1])));
00873       if (!_has_mouse) {
00874         // Show the mouse pointer.
00875         _geometry->set_draw_mask(DrawMask::all_on());
00876       }
00877     }
00878 
00879     _has_mouse = true;
00880 
00881     VRegions regions;
00882     get_over_regions(regions, _mouse);
00883     set_current_regions(regions);
00884   }
00885 
00886   _suppress_flags = 0;
00887   if (_preferred_region != (MouseWatcherRegion *)NULL) {
00888     _suppress_flags = _preferred_region->get_suppress_flags();
00889   }
00890 
00891   // Look for button events.
00892   if (input.has_data(_button_events_input)) {
00893     const ButtonEventList *button_events;
00894     DCAST_INTO_V(button_events, input.get_data(_button_events_input).get_ptr());
00895     int num_events = button_events->get_num_events();
00896     for (int i = 0; i < num_events; i++) {
00897       const ButtonEvent &be = button_events->get_event(i);
00898       _mods.add_event(be);
00899 
00900       switch (be._type) {
00901       case ButtonEvent::T_down:
00902         press(be._button);
00903         break;
00904 
00905       case ButtonEvent::T_up:
00906         release(be._button);
00907         break;
00908 
00909       case ButtonEvent::T_keystroke:
00910         keystroke(be._keycode);
00911         break;
00912 
00913       case ButtonEvent::T_resume_down:
00914         // Ignore this, since the button wasn't pressed just now.
00915         break;
00916       }
00917     }
00918   }
00919 
00920   if (_has_mouse &&
00921       (_suppress_flags & MouseWatcherRegion::SF_mouse_position) == 0) {
00922     // Transmit the mouse position.
00923     output.set_data(_xy_output, input.get_data(_xy_input));
00924     output.set_data(_pixel_xy_output, input.get_data(_pixel_xy_input));
00925   }
00926 
00927   int suppress_buttons = (_suppress_flags & MouseWatcherRegion::SF_any_button);
00928   if (suppress_buttons == MouseWatcherRegion::SF_any_button) {
00929     // Suppress all buttons.
00930 
00931   } else if (suppress_buttons != 0) {
00932     // Suppress some buttons.
00933     _button_events->clear();
00934 
00935     if (input.has_data(_button_events_input)) {
00936       const ButtonEventList *button_events;
00937       DCAST_INTO_V(button_events, input.get_data(_button_events_input).get_ptr());
00938       int num_events = button_events->get_num_events();
00939       for (int i = 0; i < num_events; i++) {
00940         const ButtonEvent &be = button_events->get_event(i);
00941         bool suppress = true;
00942         
00943         if (be._type != ButtonEvent::T_keystroke && 
00944             MouseButton::is_mouse_button(be._button)) {
00945           suppress = ((suppress_buttons & MouseWatcherRegion::SF_mouse_button) != 0);
00946         } else {
00947           suppress = ((suppress_buttons & MouseWatcherRegion::SF_other_button) != 0);
00948         }
00949 
00950         if (!suppress) {
00951           // Don't suppress this button event; pass it through.
00952           _button_events->add_event(be);
00953         }
00954       }
00955     }
00956 
00957     if (_button_events->get_num_events() != 0) {
00958       output.set_data(_button_events_output, EventParameter(_button_events));
00959     }
00960 
00961   } else {
00962     // Transmit all buttons.
00963     output.set_data(_button_events_output, input.get_data(_button_events_input));
00964   }
00965 }
00966 

Generated on Fri May 2 00:44:27 2003 for Panda by doxygen1.3