Panda3D
mouseWatcherBase.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file mouseWatcherBase.cxx
10  * @author rdb
11  * @date 2014-01-13
12  */
13 
14 #include "mouseWatcherBase.h"
15 #include "lineSegs.h"
16 #include "indent.h"
17 #include "lightMutexHolder.h"
18 
19 TypeHandle MouseWatcherBase::_type_handle;
20 
21 /**
22  *
23  */
24 MouseWatcherBase::
25 MouseWatcherBase() :
26  _lock("MouseWatcherBase")
27 {
28  _sorted = true;
29 #ifndef NDEBUG
30  _show_regions = false;
31  _color.set(0.4, 0.6f, 1.0f, 1.0f);
32 #endif // NDEBUG
33 }
34 
35 /**
36  *
37  */
38 MouseWatcherBase::
39 ~MouseWatcherBase() {
40 }
41 
42 /**
43  * Adds the indicated region to the set of regions in the group. It is no
44  * longer an error to call this for the same region more than once.
45  */
48  LightMutexHolder holder(_lock);
49 
50 #ifndef NDEBUG
51  // Also add it to the vizzes if we have them.
52  if (UNLIKELY(_show_regions)) {
53  // We need to check whether it is already in the set, so that we don't
54  // create a duplicate viz.
55  Regions::const_iterator ri =
56  std::find(_regions.begin(), _regions.end(), region);
57 
58  if (ri == _regions.end()) {
59  nassertv(_vizzes.size() == _regions.size());
60  _vizzes.push_back(make_viz_region(region));
61  } else {
62  return;
63  }
64  }
65 #endif // NDEBUG
66 
67  _regions.push_back(std::move(region));
68  _sorted = false;
69 }
70 
71 /**
72  * Returns true if the indicated region has already been added to the
73  * MouseWatcherBase, false otherwise.
74  */
77  LightMutexHolder holder(_lock);
78 
79  PT(MouseWatcherRegion) ptr = region;
80 
81  if (_sorted) {
82  // If the vector is already sorted, we can do this the quick way.
83  Regions::const_iterator ri = lower_bound(_regions.begin(), _regions.end(), ptr);
84  return (ri != _regions.end() && (*ri) == ptr);
85  }
86 
87  // If the vector isn't sorted, do a linear scan.
88  Regions::const_iterator ri = find(_regions.begin(), _regions.end(), ptr);
89  return (ri != _regions.end());
90 }
91 
92 /**
93  * Removes the indicated region from the group. Returns true if it was
94  * successfully removed, or false if it wasn't there in the first place.
95  */
98  LightMutexHolder holder(_lock);
99  return do_remove_region(region);
100 }
101 
102 /**
103  * Returns a pointer to the first region found with the indicated name. If
104  * multiple regions share the same name, the one that is returned is
105  * indeterminate.
106  */
108 find_region(const std::string &name) const {
109  LightMutexHolder holder(_lock);
110 
111  for (MouseWatcherRegion *region : _regions) {
112  if (region->get_name() == name) {
113  return region;
114  }
115  }
116 
117  return nullptr;
118 }
119 
120 /**
121  * Removes all the regions from the group.
122  */
125  LightMutexHolder holder(_lock);
126 
127  _regions.clear();
128  _sorted = true;
129 
130 #ifndef NDEBUG
131  if (_show_regions) {
132  _show_regions_root.node()->remove_all_children();
133  _vizzes.clear();
134  }
135 #endif // NDEBUG
136 }
137 
138 /**
139  * Returns the number of regions in the group.
140  */
141 size_t MouseWatcherBase::
142 get_num_regions() const {
143  LightMutexHolder holder(_lock);
144  if (!_sorted) {
145  // Remove potential duplicates to get an accurate count.
146  ((MouseWatcherBase *)this)->do_sort_regions();
147  }
148  return _regions.size();
149 }
150 
151 /**
152  * Returns the nth region of the group; returns NULL if there is no nth
153  * region. Note that this is not thread-safe; another thread might have
154  * removed the nth region before you called this method.
155  */
157 get_region(size_t n) const {
158  LightMutexHolder holder(_lock);
159  if (!_sorted) {
160  ((MouseWatcherBase *)this)->do_sort_regions();
161  }
162  if (n < _regions.size()) {
163  return _regions[n];
164  }
165  return nullptr;
166 }
167 
168 /**
169  *
170  */
171 void MouseWatcherBase::
172 output(std::ostream &out) const {
173  out << "MouseWatcherGroup (" << _regions.size() << " regions)";
174 }
175 
176 /**
177  *
178  */
179 void MouseWatcherBase::
180 write(std::ostream &out, int indent_level) const {
181  LightMutexHolder holder(_lock);
182 
183  for (MouseWatcherRegion *region : _regions) {
184  region->write(out, indent_level);
185  }
186 }
187 
188 #if !defined(NDEBUG) || !defined(CPPPARSER)
189 /**
190  * Enables the visualization of all of the regions handled by this
191  * MouseWatcherBase. The supplied NodePath should be the root of the 2-d
192  * scene graph for the window.
193  */
195 show_regions(const NodePath &render2d, const std::string &bin_name, int draw_order) {
196 #ifndef NDEBUG
197  LightMutexHolder holder(_lock);
198  do_show_regions(render2d, bin_name, draw_order);
199 #endif
200 }
201 #endif // NDEBUG
202 
203 #if !defined(NDEBUG) || !defined(CPPPARSER)
204 /**
205  * Specifies the color used to draw the region rectangles for the regions
206  * visualized by show_regions().
207  */
209 set_color(const LColor &color) {
210 #ifndef NDEBUG
211  LightMutexHolder holder(_lock);
212 
213  _color = color;
214  do_update_regions();
215 #endif
216 }
217 #endif // NDEBUG
218 
219 #if !defined(NDEBUG) || !defined(CPPPARSER)
220 /**
221  * Stops the visualization created by a previous call to show_regions().
222  */
225 #ifndef NDEBUG
226  LightMutexHolder holder(_lock);
227  do_hide_regions();
228 #endif
229 }
230 #endif // NDEBUG
231 
232 #if !defined(NDEBUG) || !defined(CPPPARSER)
233 /**
234  * Refreshes the visualization created by show_regions().
235  */
238 #ifndef NDEBUG
239  LightMutexHolder holder(_lock);
240  do_update_regions();
241 #endif
242 }
243 #endif // NDEBUG
244 
245 
246 /**
247  * Sorts all the regions in this group into pointer order. Assumes the lock
248  * is already held.
249  */
250 void MouseWatcherBase::
251 do_sort_regions() {
252  if (!_sorted) {
253  _regions.sort_unique();
254  _sorted = true;
255  }
256 }
257 
258 /**
259  * The internal implementation of remove_region(); assumes the lock is already
260  * held.
261  */
262 bool MouseWatcherBase::
263 do_remove_region(MouseWatcherRegion *region) {
264  // See if the region is in the vector.
265  PT(MouseWatcherRegion) ptr = region;
266  Regions::iterator ri;
267 
268  if (_sorted) {
269  // Faster, binary search
270  ri = lower_bound(_regions.begin(), _regions.end(), ptr);
271  } else {
272  // Unsorted, so use slower linear scan
273  ri = find(_regions.begin(), _regions.end(), ptr);
274  }
275 
276  if (ri != _regions.end() && (*ri) == ptr) {
277  // Found it, now erase it
278 #ifndef NDEBUG
279  // Also remove it from the vizzes.
280  if (_show_regions) {
281  nassertr(_vizzes.size() == _regions.size(), false);
282  size_t index = ri - _regions.begin();
283  Vizzes::iterator vi = _vizzes.begin() + index;
284  _show_regions_root.node()->remove_child(*vi);
285  _vizzes.erase(vi);
286  }
287 #endif // NDEBUG
288 
289  _regions.erase(ri);
290  return true;
291  }
292 
293  // Did not find the region to erase
294  return false;
295 }
296 
297 #ifndef NDEBUG
298 /**
299  * The protected implementation of show_regions(). This assumes the lock is
300  * already held.
301  */
302 void MouseWatcherBase::
303 do_show_regions(const NodePath &render2d, const std::string &bin_name,
304  int draw_order) {
305  do_hide_regions();
306  _show_regions = true;
307  _show_regions_root = render2d.attach_new_node("show_regions");
308  _show_regions_root.set_bin(bin_name, draw_order);
309  do_update_regions();
310 }
311 #endif // NDEBUG
312 
313 #ifndef NDEBUG
314 /**
315  * The protected implementation of hide_regions(). This assumes the lock is
316  * already held.
317  */
318 void MouseWatcherBase::
319 do_hide_regions() {
320  _show_regions_root.remove_node();
321  _show_regions = false;
322  _vizzes.clear();
323 }
324 #endif // NDEBUG
325 
326 #ifndef NDEBUG
327 /**
328  * Internally regenerates the show_regions() visualization. Assumes the lock
329  * is already held.
330  */
331 void MouseWatcherBase::
332 do_update_regions() {
333  nassertv(_lock.debug_is_locked());
334 
335  if (_show_regions) {
336  // Make sure we have no duplicates.
337  do_sort_regions();
338 
339  _show_regions_root.node()->remove_all_children();
340  _vizzes.clear();
341  _vizzes.reserve(_regions.size());
342 
343  for (MouseWatcherRegion *region : _regions) {
344  _vizzes.push_back(make_viz_region(region));
345  }
346  }
347 }
348 #endif // NDEBUG
349 
350 
351 #ifndef NDEBUG
352 /**
353  * Creates a node to represent the indicated region, and attaches it to the
354  * _show_regions_root. Does not add it to _vizzes. Assumes the lock is
355  * already held.
356  */
357 PandaNode *MouseWatcherBase::
358 make_viz_region(MouseWatcherRegion *region) {
359  nassertr(_lock.debug_is_locked(), nullptr);
360 
361  LineSegs ls("show_regions");
362  ls.set_color(_color);
363 
364  const LVecBase4 &f = region->get_frame();
365 
366  ls.move_to(LVector3::rfu(f[0], 0.0f, f[2]));
367  ls.draw_to(LVector3::rfu(f[1], 0.0f, f[2]));
368  ls.draw_to(LVector3::rfu(f[1], 0.0f, f[3]));
369  ls.draw_to(LVector3::rfu(f[0], 0.0f, f[3]));
370  ls.draw_to(LVector3::rfu(f[0], 0.0f, f[2]));
371 
372  PT(PandaNode) node = ls.create();
373  _show_regions_root.attach_new_node(node);
374 
375  return node;
376 }
377 #endif // NDEBUG
PandaNode::remove_all_children
void remove_all_children(Thread *current_thread=Thread::get_current_thread())
Removes all the children from the node at once, including stashed children.
Definition: pandaNode.cxx:830
ordered_vector::size
size_type_0 size() const
Returns the number of elements in the ordered vector.
Definition: ordered_vector.I:221
LightMutexHolder
Similar to MutexHolder, but for a light mutex.
Definition: lightMutexHolder.h:25
MouseWatcherBase::get_region
get_region
Returns the nth region of the group; returns NULL if there is no nth region.
Definition: mouseWatcherBase.h:50
LineSegs
Encapsulates creation of a series of connected or disconnected line segments or points,...
Definition: lineSegs.h:33
MouseWatcherBase::show_regions
void show_regions(const NodePath &render2d, const std::string &bin_name, int draw_order)
Enables the visualization of all of the regions handled by this MouseWatcherBase.
Definition: mouseWatcherBase.cxx:195
NodePath::set_bin
void set_bin(const std::string &bin_name, int draw_order, int priority=0)
Assigns the geometry at this level and below to the named rendering bin.
Definition: nodePath.cxx:2801
MouseWatcherBase
This represents a collection of MouseWatcherRegions that may be managed as a group.
Definition: mouseWatcherBase.h:32
MouseWatcherBase::find_region
MouseWatcherRegion * find_region(const std::string &name) const
Returns a pointer to the first region found with the indicated name.
Definition: mouseWatcherBase.cxx:108
MouseWatcherBase::has_region
bool has_region(MouseWatcherRegion *region) const
Returns true if the indicated region has already been added to the MouseWatcherBase,...
Definition: mouseWatcherBase.cxx:76
MouseWatcherBase::clear_regions
void clear_regions()
Removes all the regions from the group.
Definition: mouseWatcherBase.cxx:124
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
MouseWatcherBase::remove_region
bool remove_region(MouseWatcherRegion *region)
Removes the indicated region from the group.
Definition: mouseWatcherBase.cxx:97
lightMutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ordered_vector::push_back
void push_back(const value_type_0 &key)
Adds the new element to the end of the vector without regard for proper sorting.
Definition: ordered_vector.I:614
PandaNode::remove_child
void remove_child(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth child from the node.
Definition: pandaNode.cxx:564
LightMutexDirect::debug_is_locked
bool debug_is_locked() const
Returns true if the current thread has locked the LightMutex, false otherwise.
Definition: lightMutexDirect.I:81
MouseWatcherBase::get_num_regions
get_num_regions
Returns the number of regions in the group.
Definition: mouseWatcherBase.h:50
MouseWatcherBase::set_color
void set_color(const LColor &color)
Specifies the color used to draw the region rectangles for the regions visualized by show_regions().
Definition: mouseWatcherBase.cxx:209
MouseWatcherBase::add_region
void add_region(PT(MouseWatcherRegion) region)
Adds the indicated region to the set of regions in the group.
Definition: mouseWatcherBase.cxx:47
ordered_vector::end
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
Definition: ordered_vector.I:50
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
MouseWatcherRegion
This is the class that defines a rectangular region on the screen for the MouseWatcher.
Definition: mouseWatcherRegion.h:31
MouseWatcherBase::update_regions
void update_regions()
Refreshes the visualization created by show_regions().
Definition: mouseWatcherBase.cxx:237
lineSegs.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
MouseWatcherBase::hide_regions
void hide_regions()
Stops the visualization created by a previous call to show_regions().
Definition: mouseWatcherBase.cxx:224
NodePath::attach_new_node
NodePath attach_new_node(PandaNode *node, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Attaches a new node, with or without existing parents, to the scene graph below the referenced node o...
Definition: nodePath.cxx:563
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
mouseWatcherBase.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
NodePath::node
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
ordered_vector::begin
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
Definition: ordered_vector.I:41
NodePath::remove_node
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
Definition: nodePath.cxx:591
ordered_vector::clear
void clear()
Removes all elements from the ordered vector.
Definition: ordered_vector.I:412