Panda3D
 All Classes Functions Variables Enumerations
mouseWatcherGroup.cxx
00001 // Filename: mouseWatcherGroup.cxx
00002 // Created by:  drose (02Jul01)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "mouseWatcherGroup.h"
00016 #include "lineSegs.h"
00017 #include "indent.h"
00018 #include "lightMutexHolder.h"
00019 
00020 TypeHandle MouseWatcherGroup::_type_handle;
00021 
00022 ////////////////////////////////////////////////////////////////////
00023 //     Function: MouseWatcherGroup::Constructor
00024 //       Access: Public
00025 //  Description: 
00026 ////////////////////////////////////////////////////////////////////
00027 MouseWatcherGroup::
00028 MouseWatcherGroup() :
00029   _lock("MouseWatcherGroup")
00030 {
00031   _sorted = true;
00032 #ifndef NDEBUG
00033   _show_regions = false;
00034   _color.set(0.4, 0.6f, 1.0f, 1.0f);
00035 #endif  // NDEBUG
00036 }
00037 
00038 ////////////////////////////////////////////////////////////////////
00039 //     Function: MouseWatcherGroup::Destructor
00040 //       Access: Public, Virtual
00041 //  Description: 
00042 ////////////////////////////////////////////////////////////////////
00043 MouseWatcherGroup::
00044 ~MouseWatcherGroup() {
00045 }
00046 
00047 ////////////////////////////////////////////////////////////////////
00048 //     Function: MouseWatcherGroup::add_region
00049 //       Access: Published
00050 //  Description: Adds the indicated region to the set of regions in
00051 //               the group.  It is an error to add the same region to
00052 //               the set more than once.
00053 ////////////////////////////////////////////////////////////////////
00054 void MouseWatcherGroup::
00055 add_region(MouseWatcherRegion *region) {
00056   PT(MouseWatcherRegion) pt = region;
00057 
00058   LightMutexHolder holder(_lock);
00059 
00060   // We will only bother to check for duplicates in the region list if
00061   // we are building a development Panda.  The overhead for doing this
00062   // may be too high if we have many regions.
00063 #ifdef _DEBUG
00064   // See if the region is in the set/vector already
00065   Regions::const_iterator ri = 
00066     find(_regions.begin(), _regions.end(), pt);
00067   nassertv(ri == _regions.end());
00068 #endif  // _DEBUG
00069 
00070 #ifndef NDEBUG
00071   // Also add it to the vizzes if we have them.
00072   if (_show_regions) {
00073     nassertv(_vizzes.size() == _regions.size());
00074     _vizzes.push_back(make_viz_region(pt));
00075   }
00076 #endif  // NDEBUG
00077 
00078   _regions.push_back(pt);
00079   _sorted = false;
00080 }
00081 
00082 ////////////////////////////////////////////////////////////////////
00083 //     Function: MouseWatcherGroup::has_region
00084 //       Access: Published
00085 //  Description: Returns true if the indicated region has already been
00086 //               added to the MouseWatcherGroup, false otherwise.
00087 ////////////////////////////////////////////////////////////////////
00088 bool MouseWatcherGroup::
00089 has_region(MouseWatcherRegion *region) const {
00090   LightMutexHolder holder(_lock);
00091 
00092   PT(MouseWatcherRegion) ptr = region;
00093 
00094   if (_sorted) {
00095     // If the vector is already sorted, we can do this the quick way.
00096     Regions::const_iterator ri = lower_bound(_regions.begin(), _regions.end(), ptr);
00097     return (ri != _regions.end() && (*ri) == ptr);
00098   }
00099 
00100   // If the vector isn't sorted, do a linear scan.
00101   Regions::const_iterator ri = find(_regions.begin(), _regions.end(), ptr);
00102   return (ri != _regions.end());
00103 }
00104 
00105 ////////////////////////////////////////////////////////////////////
00106 //     Function: MouseWatcherGroup::remove_region
00107 //       Access: Published
00108 //  Description: Removes the indicated region from the group.
00109 //               Returns true if it was successfully removed, or false
00110 //               if it wasn't there in the first place.
00111 ////////////////////////////////////////////////////////////////////
00112 bool MouseWatcherGroup::
00113 remove_region(MouseWatcherRegion *region) {
00114   LightMutexHolder holder(_lock);
00115   return do_remove_region(region);
00116 }
00117 
00118 ////////////////////////////////////////////////////////////////////
00119 //     Function: MouseWatcherGroup::find_region
00120 //       Access: Published
00121 //  Description: Returns a pointer to the first region found with the
00122 //               indicated name.  If multiple regions share the same
00123 //               name, the one that is returned is indeterminate.
00124 ////////////////////////////////////////////////////////////////////
00125 MouseWatcherRegion *MouseWatcherGroup::
00126 find_region(const string &name) const {
00127   LightMutexHolder holder(_lock);
00128 
00129   Regions::const_iterator ri;
00130   for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
00131     MouseWatcherRegion *region = (*ri);
00132     if (region->get_name() == name) {
00133       return region;
00134     }
00135   }
00136 
00137   return (MouseWatcherRegion *)NULL;
00138 }
00139 
00140 ////////////////////////////////////////////////////////////////////
00141 //     Function: MouseWatcherGroup::clear_regions
00142 //       Access: Published
00143 //  Description: Removes all the regions from the group.
00144 ////////////////////////////////////////////////////////////////////
00145 void MouseWatcherGroup::
00146 clear_regions() {
00147   LightMutexHolder holder(_lock);
00148 
00149   _regions.clear();
00150   _sorted = true;
00151 
00152 #ifndef NDEBUG
00153   if (_show_regions) {
00154     _show_regions_root.node()->remove_all_children();
00155     _vizzes.clear();
00156   }
00157 #endif  // NDEBUG
00158 }
00159 
00160 ////////////////////////////////////////////////////////////////////
00161 //     Function: MouseWatcherGroup::sort_regions
00162 //       Access: Published
00163 //  Description: Sorts all the regions in this group into pointer
00164 //               order.
00165 ////////////////////////////////////////////////////////////////////
00166 void MouseWatcherGroup::
00167 sort_regions() {
00168   LightMutexHolder holder(_lock);
00169   do_sort_regions();
00170 }
00171 
00172 ////////////////////////////////////////////////////////////////////
00173 //     Function: MouseWatcherGroup::is_sorted
00174 //       Access: Published
00175 //  Description: Returns true if the group has already been sorted,
00176 //               false otherwise.
00177 ////////////////////////////////////////////////////////////////////
00178 bool MouseWatcherGroup::
00179 is_sorted() const {
00180   LightMutexHolder holder(_lock);
00181 
00182   return _sorted;
00183 }
00184 
00185 ////////////////////////////////////////////////////////////////////
00186 //     Function: MouseWatcherGroup::get_num_regions
00187 //       Access: Published
00188 //  Description: Returns the number of regions in the group.
00189 ////////////////////////////////////////////////////////////////////
00190 int MouseWatcherGroup::
00191 get_num_regions() const {
00192   LightMutexHolder holder(_lock);
00193 
00194   return _regions.size();
00195 }
00196 
00197 ////////////////////////////////////////////////////////////////////
00198 //     Function: MouseWatcherGroup::get_region
00199 //       Access: Published
00200 //  Description: Returns the nth region of the group; returns NULL if
00201 //               there is no nth region.  Note that this is not
00202 //               thread-safe; another thread might have removed the
00203 //               nth region before you called this method.
00204 ////////////////////////////////////////////////////////////////////
00205 MouseWatcherRegion *MouseWatcherGroup::
00206 get_region(int n) const {
00207   LightMutexHolder holder(_lock);
00208   if (n >= 0 && n < (int)_regions.size()) {
00209     return _regions[n];
00210   }
00211   return NULL;
00212 }
00213 
00214 ////////////////////////////////////////////////////////////////////
00215 //     Function: MouseWatcherGroup::output
00216 //       Access: Published
00217 //  Description:
00218 ////////////////////////////////////////////////////////////////////
00219 void MouseWatcherGroup::
00220 output(ostream &out) const {
00221   out << "MouseWatcherGroup (" << _regions.size() << " regions)";
00222 }
00223 
00224 ////////////////////////////////////////////////////////////////////
00225 //     Function: MouseWatcherGroup::write
00226 //       Access: Published
00227 //  Description:
00228 ////////////////////////////////////////////////////////////////////
00229 void MouseWatcherGroup::
00230 write(ostream &out, int indent_level) const {
00231   LightMutexHolder holder(_lock);
00232 
00233   Regions::const_iterator ri;
00234   for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
00235     MouseWatcherRegion *region = (*ri);
00236     region->write(out, indent_level);
00237   }
00238 }
00239 
00240 #ifndef NDEBUG
00241 ////////////////////////////////////////////////////////////////////
00242 //     Function: MouseWatcherGroup::show_regions
00243 //       Access: Published
00244 //  Description: Enables the visualization of all of the regions
00245 //               handled by this MouseWatcherGroup.  The supplied
00246 //               NodePath should be the root of the 2-d scene graph
00247 //               for the window.
00248 ////////////////////////////////////////////////////////////////////
00249 void MouseWatcherGroup::
00250 show_regions(const NodePath &render2d, const string &bin_name, int draw_order) {
00251   LightMutexHolder holder(_lock);
00252   do_show_regions(render2d, bin_name, draw_order);
00253 }
00254 #endif  // NDEBUG
00255 
00256 #ifndef NDEBUG
00257 ////////////////////////////////////////////////////////////////////
00258 //     Function: MouseWatcherGroup::set_color
00259 //       Access: Published
00260 //  Description: Specifies the color used to draw the region
00261 //               rectangles for the regions visualized by
00262 //               show_regions().
00263 ////////////////////////////////////////////////////////////////////
00264 void MouseWatcherGroup::
00265 set_color(const LColor &color) {
00266   LightMutexHolder holder(_lock);
00267 
00268   _color = color;
00269   do_update_regions();
00270 }
00271 #endif  // NDEBUG
00272 
00273 #ifndef NDEBUG
00274 ////////////////////////////////////////////////////////////////////
00275 //     Function: MouseWatcherGroup::hide_regions
00276 //       Access: Published
00277 //  Description: Stops the visualization created by a previous call to
00278 //               show_regions().
00279 ////////////////////////////////////////////////////////////////////
00280 void MouseWatcherGroup::
00281 hide_regions() {
00282   LightMutexHolder holder(_lock);
00283   do_hide_regions();
00284 }
00285 #endif  // NDEBUG
00286 
00287 #ifndef NDEBUG
00288 ////////////////////////////////////////////////////////////////////
00289 //     Function: MouseWatcherGroup::update_regions
00290 //       Access: Published
00291 //  Description: Refreshes the visualization created by
00292 //               show_regions().
00293 ////////////////////////////////////////////////////////////////////
00294 void MouseWatcherGroup::
00295 update_regions() {
00296   LightMutexHolder holder(_lock);
00297   do_update_regions();
00298 }
00299 #endif  // NDEBUG
00300 
00301 
00302 ////////////////////////////////////////////////////////////////////
00303 //     Function: MouseWatcherGroup::do_sort_regions
00304 //       Access: Protected
00305 //  Description: Sorts all the regions in this group into pointer
00306 //               order.  Assumes the lock is already held.
00307 ////////////////////////////////////////////////////////////////////
00308 void MouseWatcherGroup::
00309 do_sort_regions() {
00310   if (!_sorted) {
00311     sort(_regions.begin(), _regions.end());
00312     _sorted = true;
00313   }
00314 }
00315 
00316 ////////////////////////////////////////////////////////////////////
00317 //     Function: MouseWatcherGroup::do_remove_region
00318 //       Access: Protected
00319 //  Description: The internal implementation of remove_region();
00320 //               assumes the lock is already held.
00321 ////////////////////////////////////////////////////////////////////
00322 bool MouseWatcherGroup::
00323 do_remove_region(MouseWatcherRegion *region) {
00324   // See if the region is in the vector.
00325   PT(MouseWatcherRegion) ptr = region;
00326   Regions::iterator ri;
00327 
00328   if (_sorted) {
00329     // Faster, binary search
00330     ri = lower_bound(_regions.begin(), _regions.end(), ptr);
00331   } else {
00332     // Unsorted, so use slower linear scan
00333     ri = find(_regions.begin(), _regions.end(), ptr);
00334   }
00335 
00336   if (ri != _regions.end() && (*ri) == ptr) {
00337     // Found it, now erase it
00338 #ifndef NDEBUG
00339     // Also remove it from the vizzes.
00340     if (_show_regions) {
00341       nassertr(_vizzes.size() == _regions.size(), false);
00342       size_t index = ri - _regions.begin();
00343       Vizzes::iterator vi = _vizzes.begin() + index;
00344       _show_regions_root.node()->remove_child(*vi);
00345       _vizzes.erase(vi);
00346     }
00347 #endif  // NDEBUG    
00348 
00349     _regions.erase(ri);
00350     return true;
00351   }
00352 
00353   // Did not find the region to erase
00354   return false;
00355 }
00356 
00357 #ifndef NDEBUG
00358 ////////////////////////////////////////////////////////////////////
00359 //     Function: MouseWatcherGroup::do_show_regions
00360 //       Access: Protected, Virtual
00361 //  Description: The protected implementation of show_regions().  This
00362 //               assumes the lock is already held.
00363 ////////////////////////////////////////////////////////////////////
00364 void MouseWatcherGroup::
00365 do_show_regions(const NodePath &render2d, const string &bin_name, 
00366                 int draw_order) {
00367   do_hide_regions();
00368   _show_regions = true;
00369   _show_regions_root = render2d.attach_new_node("show_regions");
00370   _show_regions_root.set_bin(bin_name, draw_order);
00371   do_update_regions();
00372 }
00373 #endif  // NDEBUG
00374 
00375 #ifndef NDEBUG
00376 ////////////////////////////////////////////////////////////////////
00377 //     Function: MouseWatcherGroup::do_hide_regions
00378 //       Access: Protected, Virtual
00379 //  Description: The protected implementation of hide_regions().  This
00380 //               assumes the lock is already held.
00381 ////////////////////////////////////////////////////////////////////
00382 void MouseWatcherGroup::
00383 do_hide_regions() {
00384   _show_regions_root.remove_node();
00385   _show_regions = false;
00386   _vizzes.clear();
00387 }
00388 #endif  // NDEBUG
00389 
00390 
00391 #ifndef NDEBUG
00392 ////////////////////////////////////////////////////////////////////
00393 //     Function: MouseWatcherGroup::do_update_regions
00394 //       Access: Protected
00395 //  Description: Internally regenerates the show_regions()
00396 //               visualization.  Assumes the lock is already held.
00397 ////////////////////////////////////////////////////////////////////
00398 void MouseWatcherGroup::
00399 do_update_regions() {
00400   nassertv(_lock.debug_is_locked());
00401 
00402   if (_show_regions) {
00403     _show_regions_root.node()->remove_all_children();
00404     _vizzes.clear();
00405     _vizzes.reserve(_regions.size());
00406     
00407     Regions::const_iterator ri;
00408     for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
00409       _vizzes.push_back(make_viz_region(*ri));
00410     }
00411   }
00412 }
00413 #endif  // NDEBUG
00414 
00415 
00416 #ifndef NDEBUG
00417 ////////////////////////////////////////////////////////////////////
00418 //     Function: MouseWatcherGroup::make_viz_region
00419 //       Access: Private
00420 //  Description: Creates a node to represent the indicated region, and
00421 //               attaches it to the _show_regions_root.  Does not add
00422 //               it to _vizzes.  Assumes the lock is already held.
00423 ////////////////////////////////////////////////////////////////////
00424 PandaNode *MouseWatcherGroup::
00425 make_viz_region(MouseWatcherRegion *region) {
00426   nassertr(_lock.debug_is_locked(), NULL);
00427 
00428   LineSegs ls("show_regions");
00429   ls.set_color(_color);
00430 
00431   const LVecBase4 &f = region->get_frame();
00432 
00433   ls.move_to(LVector3::rfu(f[0], 0.0f, f[2]));
00434   ls.draw_to(LVector3::rfu(f[1], 0.0f, f[2]));
00435   ls.draw_to(LVector3::rfu(f[1], 0.0f, f[3]));
00436   ls.draw_to(LVector3::rfu(f[0], 0.0f, f[3]));
00437   ls.draw_to(LVector3::rfu(f[0], 0.0f, f[2]));
00438 
00439   PT(PandaNode) node = ls.create();
00440   _show_regions_root.attach_new_node(node);
00441 
00442   return node;
00443 }
00444 #endif  // NDEBUG
 All Classes Functions Variables Enumerations