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  */
47 add_region(PT(MouseWatcherRegion) region) {
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  */
76 has_region(MouseWatcherRegion *region) const {
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  */
124 clear_regions() {
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  */
224 hide_regions() {
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  */
237 update_regions() {
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
bool debug_is_locked() const
Returns true if the current thread has locked the LightMutex, false otherwise.
Similar to MutexHolder, but for a light mutex.
Encapsulates creation of a series of connected or disconnected line segments or points,...
Definition: lineSegs.h:33
This represents a collection of MouseWatcherRegions that may be managed as a group.
bool remove_region(MouseWatcherRegion *region)
Removes the indicated region from the group.
get_num_regions
Returns the number of regions in the group.
void clear_regions()
Removes all the regions from the group.
void add_region(PT(MouseWatcherRegion) region)
Adds the indicated region to the set of regions in the group.
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.
MouseWatcherRegion * find_region(const std::string &name) const
Returns a pointer to the first region found with the indicated name.
get_region
Returns the nth region of the group; returns NULL if there is no nth region.
void set_color(const LColor &color)
Specifies the color used to draw the region rectangles for the regions visualized by show_regions().
void update_regions()
Refreshes the visualization created by show_regions().
void hide_regions()
Stops the visualization created by a previous call to show_regions().
bool has_region(MouseWatcherRegion *region) const
Returns true if the indicated region has already been added to the MouseWatcherBase,...
This is the class that defines a rectangular region on the screen for the MouseWatcher.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
Definition: nodePath.cxx:628
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
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:600
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:2868
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
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
void remove_child(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth child from the node.
Definition: pandaNode.cxx:564
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
void push_back(const value_type_0 &key)
Adds the new element to the end of the vector without regard for proper sorting.
size_type_0 size() const
Returns the number of elements in the ordered vector.
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
void clear()
Removes all elements from the ordered vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.