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 #ifndef NDEBUG
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  LightMutexHolder holder(_lock);
197  do_show_regions(render2d, bin_name, draw_order);
198 }
199 #endif // NDEBUG
200 
201 #ifndef NDEBUG
202 /**
203  * Specifies the color used to draw the region rectangles for the regions
204  * visualized by show_regions().
205  */
207 set_color(const LColor &color) {
208  LightMutexHolder holder(_lock);
209 
210  _color = color;
211  do_update_regions();
212 }
213 #endif // NDEBUG
214 
215 #ifndef NDEBUG
216 /**
217  * Stops the visualization created by a previous call to show_regions().
218  */
221  LightMutexHolder holder(_lock);
222  do_hide_regions();
223 }
224 #endif // NDEBUG
225 
226 #ifndef NDEBUG
227 /**
228  * Refreshes the visualization created by show_regions().
229  */
232  LightMutexHolder holder(_lock);
233  do_update_regions();
234 }
235 #endif // NDEBUG
236 
237 
238 /**
239  * Sorts all the regions in this group into pointer order. Assumes the lock
240  * is already held.
241  */
242 void MouseWatcherBase::
243 do_sort_regions() {
244  if (!_sorted) {
245  _regions.sort_unique();
246  _sorted = true;
247  }
248 }
249 
250 /**
251  * The internal implementation of remove_region(); assumes the lock is already
252  * held.
253  */
254 bool MouseWatcherBase::
255 do_remove_region(MouseWatcherRegion *region) {
256  // See if the region is in the vector.
257  PT(MouseWatcherRegion) ptr = region;
258  Regions::iterator ri;
259 
260  if (_sorted) {
261  // Faster, binary search
262  ri = lower_bound(_regions.begin(), _regions.end(), ptr);
263  } else {
264  // Unsorted, so use slower linear scan
265  ri = find(_regions.begin(), _regions.end(), ptr);
266  }
267 
268  if (ri != _regions.end() && (*ri) == ptr) {
269  // Found it, now erase it
270 #ifndef NDEBUG
271  // Also remove it from the vizzes.
272  if (_show_regions) {
273  nassertr(_vizzes.size() == _regions.size(), false);
274  size_t index = ri - _regions.begin();
275  Vizzes::iterator vi = _vizzes.begin() + index;
276  _show_regions_root.node()->remove_child(*vi);
277  _vizzes.erase(vi);
278  }
279 #endif // NDEBUG
280 
281  _regions.erase(ri);
282  return true;
283  }
284 
285  // Did not find the region to erase
286  return false;
287 }
288 
289 #ifndef NDEBUG
290 /**
291  * The protected implementation of show_regions(). This assumes the lock is
292  * already held.
293  */
294 void MouseWatcherBase::
295 do_show_regions(const NodePath &render2d, const std::string &bin_name,
296  int draw_order) {
297  do_hide_regions();
298  _show_regions = true;
299  _show_regions_root = render2d.attach_new_node("show_regions");
300  _show_regions_root.set_bin(bin_name, draw_order);
301  do_update_regions();
302 }
303 #endif // NDEBUG
304 
305 #ifndef NDEBUG
306 /**
307  * The protected implementation of hide_regions(). This assumes the lock is
308  * already held.
309  */
310 void MouseWatcherBase::
311 do_hide_regions() {
312  _show_regions_root.remove_node();
313  _show_regions = false;
314  _vizzes.clear();
315 }
316 #endif // NDEBUG
317 
318 #ifndef NDEBUG
319 /**
320  * Internally regenerates the show_regions() visualization. Assumes the lock
321  * is already held.
322  */
323 void MouseWatcherBase::
324 do_update_regions() {
325  nassertv(_lock.debug_is_locked());
326 
327  if (_show_regions) {
328  // Make sure we have no duplicates.
329  do_sort_regions();
330 
331  _show_regions_root.node()->remove_all_children();
332  _vizzes.clear();
333  _vizzes.reserve(_regions.size());
334 
335  for (MouseWatcherRegion *region : _regions) {
336  _vizzes.push_back(make_viz_region(region));
337  }
338  }
339 }
340 #endif // NDEBUG
341 
342 
343 #ifndef NDEBUG
344 /**
345  * Creates a node to represent the indicated region, and attaches it to the
346  * _show_regions_root. Does not add it to _vizzes. Assumes the lock is
347  * already held.
348  */
349 PandaNode *MouseWatcherBase::
350 make_viz_region(MouseWatcherRegion *region) {
351  nassertr(_lock.debug_is_locked(), nullptr);
352 
353  LineSegs ls("show_regions");
354  ls.set_color(_color);
355 
356  const LVecBase4 &f = region->get_frame();
357 
358  ls.move_to(LVector3::rfu(f[0], 0.0f, f[2]));
359  ls.draw_to(LVector3::rfu(f[1], 0.0f, f[2]));
360  ls.draw_to(LVector3::rfu(f[1], 0.0f, f[3]));
361  ls.draw_to(LVector3::rfu(f[0], 0.0f, f[3]));
362  ls.draw_to(LVector3::rfu(f[0], 0.0f, f[2]));
363 
364  PT(PandaNode) node = ls.create();
365  _show_regions_root.attach_new_node(node);
366 
367  return node;
368 }
369 #endif // NDEBUG
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
void remove_child(int child_index, Thread *current_thread=Thread::get_current_thread())
Removes the nth child from the node.
Definition: pandaNode.cxx:570
bool debug_is_locked() const
Returns true if the current thread has locked the LightMutex, false otherwise.
size_type_0 size() const
Returns the number of elements in the ordered vector.
void clear()
Removes all elements from the ordered vector.
bool remove_region(MouseWatcherRegion *region)
Removes the indicated region from the group.
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
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void add_region(PT(MouseWatcherRegion) region)
Adds the indicated region to the set of regions in the group.
get_region
Returns the nth region of the group; returns NULL if there is no nth region.
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
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.
bool has_region(MouseWatcherRegion *region) const
Returns true if the indicated region has already been added to the MouseWatcherBase,...
void clear_regions()
Removes all the regions from the group.
void hide_regions()
Stops the visualization created by a previous call to show_regions().
Encapsulates creation of a series of connected or disconnected line segments or points,...
Definition: lineSegs.h:33
void update_regions()
Refreshes the visualization created by show_regions().
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
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:836
Similar to MutexHolder, but for a light mutex.
This is the class that defines a rectangular region on the screen for the MouseWatcher.
void set_color(const LColor &color)
Specifies the color used to draw the region rectangles for the regions visualized by show_regions().
This represents a collection of MouseWatcherRegions that may be managed as a group.
void push_back(const value_type_0 &key)
Adds the new element to the end of the vector without regard for proper sorting.
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
void remove_node(Thread *current_thread=Thread::get_current_thread())
Disconnects the referenced node from the scene graph.
Definition: nodePath.cxx:591
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:161
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
MouseWatcherRegion * find_region(const std::string &name) const
Returns a pointer to the first region found with the indicated name.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.