Panda3D

pgItem.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 pgItem.cxx
10 * @author drose
11 * @date 2002-03-13
12 */
13
14 #include "pgItem.h"
15 #include "pgMouseWatcherParameter.h"
16 #include "pgCullTraverser.h"
17 #include "config_pgui.h"
18 #include "boundingVolume.h"
19 #include "pandaNode.h"
20 #include "sceneGraphReducer.h"
21 #include "throw_event.h"
22 #include "string_utils.h"
23 #include "nodePath.h"
24 #include "cullTraverser.h"
25 #include "cullTraverserData.h"
26 #include "cullBinManager.h"
27 #include "clipPlaneAttrib.h"
28 #include "scissorAttrib.h"
29 #include "dcast.h"
30 #include "boundingSphere.h"
31 #include "boundingBox.h"
32 #include "config_mathutil.h"
33 #include "pipeline.h"
34
35 #ifdef HAVE_AUDIO
36 #include "audioSound.h"
37 #endif
38
39 using std::string;
40
41 TypeHandle PGItem::_type_handle;
42 PT(TextNode) PGItem::_text_node;
43 PGItem *PGItem::_focus_item = nullptr;
44 PGItem::BackgroundFocus PGItem::_background_focus;
45
46
47 /**
48 * Returns true if the 2-d v1 is to the right of v2.
49 */
50 INLINE bool
51 is_right(const LVector2 &v1, const LVector2 &v2) {
52 return (v1[0] * v2[1] - v1[1] * v2[0]) > 0;
53 }
54
55 /**
56 *
57 */
58 PGItem::
59 PGItem(const string &name) :
60 PandaNode(name),
61 _lock(name),
62 _notify(nullptr),
63 _has_frame(false),
64 _frame(0, 0, 0, 0),
65 _region(new PGMouseWatcherRegion(this)),
66 _state(0),
67 _flags(0)
68 {
69 set_cull_callback();
70 }
71
72 /**
73 *
74 */
75 PGItem::
76 ~PGItem() {
77 if (_notify != nullptr) {
78 _notify->remove_item(this);
79 _notify = nullptr;
80 }
81
82 nassertv(_region->_item == this);
83 _region->_item = nullptr;
84
85 set_background_focus(false);
86 if (_focus_item == this) {
87 _focus_item = nullptr;
88 }
89 }
90
91 /**
92 *
93 */
94 PGItem::
95 PGItem(const PGItem &copy) :
96 PandaNode(copy),
97 _notify(nullptr),
98 _has_frame(copy._has_frame),
99 _frame(copy._frame),
100 _state(copy._state),
101 _flags(copy._flags),
102 _region(new PGMouseWatcherRegion(this))
103 #ifdef HAVE_AUDIO
104 , _sounds(copy._sounds)
105 #endif
106 {
107 // We give our region the same name as the region for the PGItem we're
108 // copying--so that this PGItem will generate the same event names when the
109 // user interacts with it.
110 _region->set_name(copy._region->get_name());
111
112 // Make a deep copy of all of the original PGItem's StateDefs.
113 size_t num_state_defs = copy._state_defs.size();
114 _state_defs.reserve(num_state_defs);
115 for (size_t i = 0; i < num_state_defs; ++i) {
116 // We cheat and cast away the const, because the frame is just a cache.
117 // But we have to get the frame out of the source before we can safely
118 // copy it.
119 StateDef &old_sd = (StateDef &)(copy._state_defs[i]);
120 old_sd._frame.remove_node();
121 old_sd._frame_stale = true;
122
123 StateDef new_sd;
124 new_sd._root = old_sd._root.copy_to(NodePath());
125 new_sd._frame_style = old_sd._frame_style;
126
127 _state_defs.push_back(new_sd);
128
129 #ifdef THREADED_PIPELINE
130 if (Pipeline::get_render_pipeline()->get_num_stages() > 1) {
131 ((PGItem &)copy).update_frame((int)i);
132 update_frame((int)i);
133 }
134 #endif
135 }
136 }
137
138 /**
139 * Returns a newly-allocated Node that is a shallow copy of this one. It will
140 * be a different Node pointer, but its internal data may or may not be shared
141 * with that of the original Node.
142 */
143 PandaNode *PGItem::
144 make_copy() const {
145 LightReMutexHolder holder(_lock);
146 return new PGItem(*this);
147 }
148
149 /**
150 * Called after the node's transform has been changed for any reason, this
151 * just provides a hook so derived classes can do something special in this
152 * case.
153 */
154 void PGItem::
155 transform_changed() {
156 LightReMutexHolder holder(_lock);
157 PandaNode::transform_changed();
158 if (_notify != nullptr) {
159 _notify->item_transform_changed(this);
160 }
161 }
162
163 /**
164 * Called after the node's draw_mask has been changed for any reason, this
165 * just provides a hook so derived classes can do something special in this
166 * case.
167 */
168 void PGItem::
169 draw_mask_changed() {
170 LightReMutexHolder holder(_lock);
171 PandaNode::draw_mask_changed();
172 if (_notify != nullptr) {
173 _notify->item_draw_mask_changed(this);
174 }
175 }
176
177 /**
178 * This function will be called during the cull traversal to perform any
179 * additional operations that should be performed at cull time. This may
180 * include additional manipulation of render state or additional
181 * visible/invisible decisions, or any other arbitrary operation.
182 *
183 * Note that this function will *not* be called unless set_cull_callback() is
184 * called in the constructor of the derived class. It is necessary to call
185 * set_cull_callback() to indicated that we require cull_callback() to be
186 * called.
187 *
188 * By the time this function is called, the node has already passed the
189 * bounding-volume test for the viewing frustum, and the node's transform and
190 * state have already been applied to the indicated CullTraverserData object.
191 *
192 * The return value is true if this node should be visible, or false if it
193 * should be culled.
194 */
195 bool PGItem::
196 cull_callback(CullTraverser *trav, CullTraverserData &data) {
197 // We try not to hold the lock for longer than necessary.
198 PT(PandaNode) state_def_root;
199 bool has_frame;
200 PGMouseWatcherRegion *region;
201 {
202 LightReMutexHolder holder(_lock);
203 has_frame = _has_frame && ((_flags & F_active) != 0);
204 region = _region;
205
206 int state = _state;
207 if (state >= 0 && (size_t)state < _state_defs.size()) {
208 StateDef &state_def = _state_defs[state];
209 if (!state_def._root.is_empty()) {
210 if (Thread::get_current_pipeline_stage() == 0) {
211 if (state_def._frame_stale) {
212 update_frame(state);
213 }
214 }
215
216 state_def_root = state_def._root.node();
217 }
218 }
219 }
220
221 if (has_frame && !data.is_this_node_hidden(trav->get_camera_mask())) {
222 // The item has a frame, so we want to generate a region for it and update
223 // the MouseWatcher.
224
225 // We can only do this if our traverser is a PGCullTraverser (which will
226 // be the case if this node was parented somewhere under a PGTop node).
227 if (trav->is_exact_type(PGCullTraverser::get_class_type())) {
228 PGCullTraverser *pg_trav;
229 DCAST_INTO_R(pg_trav, trav, true);
230
231 const LMatrix4 &transform = data.get_net_transform(trav)->get_mat();
232
233 // Consider the cull bin this object is in. Since the binning affects
234 // the render order, we want bins that render later to get higher sort
235 // values.
236 int bin_index = data._state->get_bin_index();
237 int sort;
238
239 CullBinManager *bin_manager = CullBinManager::get_global_ptr();
240 CullBinManager::BinType bin_type = bin_manager->get_bin_type(bin_index);
241 if (bin_type == CullBinManager::BT_fixed) {
242 // If the bin is a "fixed" type bin, our local sort is based on the
243 // fixed order.
244 sort = data._state->get_draw_order();
245
246 } else if (bin_type == CullBinManager::BT_unsorted) {
247 // If the bin is an "unsorted" type bin, we base the local sort on the
248 // scene graph order.
249 sort = pg_trav->_sort_index;
250 pg_trav->_sort_index++;
251
252 } else {
253 // Otherwise, the local sort is irrelevant.
254 sort = 0;
255 }
256
257 // Now what order does this bin sort relative to the other bins? This
258 // becomes the high-order part of the final sort count.
259 int bin_sort = bin_manager->get_bin_sort(data._state->get_bin_index());
260
261 // Combine the two sorts into a single int. This assumes we only need
262 // 16 bits for each sort number, possibly an erroneous assumption. We
263 // should really provide two separate sort values, both ints, in the
264 // MouseWatcherRegion; but in the interest of expediency we work within
265 // the existing interface which only provides one.
266 sort = (bin_sort << 16) | ((sort + 0x8000) & 0xffff);
267
268 const ClipPlaneAttrib *clip = nullptr;
269 const ScissorAttrib *scissor = nullptr;
270 data._state->get_attrib(clip);
271 data._state->get_attrib(scissor);
272 if (activate_region(transform, sort, clip, scissor)) {
273 pg_trav->_top->add_region(region);
274 }
275 }
276 }
277
278 if (state_def_root != nullptr) {
279 // This item has a current state definition that we should use to render
280 // the item.
281 CullTraverserData next_data(data, state_def_root);
282 trav->traverse(next_data);
283 }
284
285 // Now continue to render everything else below this node.
286 return true;
287 }
288
289 /**
290 * Returns true if there is some value to visiting this particular node during
291 * the cull traversal for any camera, false otherwise. This will be used to
292 * optimize the result of get_net_draw_show_mask(), so that any subtrees that
293 * contain only nodes for which is_renderable() is false need not be visited.
294 */
295 bool PGItem::
296 is_renderable() const {
297 return true;
298 }
299
300 /**
301 * Called when needed to recompute the node's _internal_bound object. Nodes
302 * that contain anything of substance should redefine this to do the right
303 * thing.
304 */
305 void PGItem::
306 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
307 int &internal_vertices,
308 int pipeline_stage,
309 Thread *current_thread) const {
310 LightReMutexHolder holder(_lock, current_thread);
311 int num_vertices = 0;
312
313 // First, get ourselves a fresh, empty bounding volume.
314 PT(BoundingVolume) bound;
315
316 BoundingVolume::BoundsType btype = get_bounds_type();
317 if (btype == BoundingVolume::BT_default) {
318 btype = bounds_type;
319 }
320
321 if (btype == BoundingVolume::BT_sphere) {
322 bound = new BoundingSphere;
323 } else {
324 bound = new BoundingBox;
325 }
326
327 // Now actually compute the bounding volume by putting it around all of our
328 // states' bounding volumes.
329 pvector<const BoundingVolume *> child_volumes;
330
331 // We walk through the list of state defs indirectly, calling
332 // get_state_def() on each one, to ensure that the frames are updated
333 // correctly before we measure their bounding volumes.
334 for (int i = 0; i < (int)_state_defs.size(); i++) {
335 NodePath &root = ((PGItem *)this)->do_get_state_def(i);
336 if (!root.is_empty()) {
337 PandaNode *node = root.node();
338 child_volumes.push_back(node->get_bounds(current_thread));
339 num_vertices += node->get_nested_vertices(current_thread);
340 }
341 }
342
343 const BoundingVolume **child_begin = &child_volumes[0];
344 const BoundingVolume **child_end = child_begin + child_volumes.size();
345
346 bound->around(child_begin, child_end);
347
348 internal_bounds = bound;
349 internal_vertices = num_vertices;
350 }
351
352 /**
353 * The recursive implementation of prepare_scene(). Don't call this directly;
354 * call PandaNode::prepare_scene() or NodePath::prepare_scene() instead.
355 */
356 void PGItem::
357 r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state,
358 GeomTransformer &transformer, Thread *current_thread) {
359 LightReMutexHolder holder(_lock);
360 for (StateDef &def : _state_defs) {
361 NodePath &root = def._root;
362 if (!root.is_empty()) {
363 PandaNode *child = root.node();
364 CPT(RenderState) child_state = node_state->compose(child->get_state());
365 child->r_prepare_scene(gsg, child_state, transformer, current_thread);
366 }
367 }
368
369 PandaNode::r_prepare_scene(gsg, node_state, transformer, current_thread);
370 }
371
372 /**
373 * Transforms the contents of this node by the indicated matrix, if it means
374 * anything to do so. For most kinds of nodes, this does nothing.
375 */
376 void PGItem::
377 xform(const LMatrix4 &mat) {
378 LightReMutexHolder holder(_lock);
379 // Transform the frame.
380 LPoint3 ll(_frame[0], 0.0f, _frame[2]);
381 LPoint3 ur(_frame[1], 0.0f, _frame[3]);
382 ll = ll * mat;
383 ur = ur * mat;
384 _frame.set(ll[0], ur[0], ll[2], ur[2]);
385
386 // Transform the individual states and their frame styles.
387 for (size_t state = 0; state < _state_defs.size(); ++state) {
388 StateDef &def = _state_defs[state];
389 NodePath &root = def._root;
390 // Apply the matrix to the previous transform.
391 root.set_transform(root.get_transform()->compose(TransformState::make_mat(mat)));
392
393 // Now flatten the transform into the subgraph.
394 SceneGraphReducer gr;
395 gr.apply_attribs(root.node());
396
397 // Transform the frame style too.
398 if (def._frame_style.xform(mat)) {
399 #ifdef THREADED_PIPELINE
400 if (Pipeline::get_render_pipeline()->get_num_stages() > 1) {
401 update_frame((int)state);
402 }
403 else
404 #endif
405 {
406 def._frame_stale = true;
407 }
408 }
409 }
410 mark_internal_bounds_stale();
411 }
412
413 /**
414 * Applies the indicated scene graph transform and order as determined by the
415 * traversal from PGTop.
416 *
417 * The return value is true if the region is valid, or false if it is empty or
418 * completely clipped.
419 */
420 bool PGItem::
421 activate_region(const LMatrix4 &transform, int sort,
422 const ClipPlaneAttrib *cpa,
423 const ScissorAttrib *sa) {
424 using std::min;
425 using std::max;
426
427 LightReMutexHolder holder(_lock);
428 // Transform all four vertices, and get the new bounding box. This way the
429 // region works (mostly) even if has been rotated.
430 LPoint3 ll = LPoint3::rfu(_frame[0], 0.0f, _frame[2]) * transform;
431 LPoint3 lr = LPoint3::rfu(_frame[1], 0.0f, _frame[2]) * transform;
432 LPoint3 ul = LPoint3::rfu(_frame[0], 0.0f, _frame[3]) * transform;
433 LPoint3 ur = LPoint3::rfu(_frame[1], 0.0f, _frame[3]) * transform;
434 LVector3 up = LVector3::up();
435 int up_axis;
436 if (up[1]) {
437 up_axis = 1;
438 }
439 else if (up[2]) {
440 up_axis = 2;
441 }
442 else {
443 up_axis = 0;
444 }
445 LVector3 right = LVector3::right();
446 int right_axis;
447 if (right[0]) {
448 right_axis = 0;
449 }
450 else if (right[2]) {
451 right_axis = 2;
452 }
453 else {
454 right_axis = 1;
455 }
456
457 LVecBase4 frame;
458 if (cpa != nullptr && cpa->get_num_on_planes() != 0) {
459 // Apply the clip plane(s) andor scissor region now that we are here in
460 // world space.
461
462 ClipPoints points;
463 points.reserve(4);
464 points.push_back(LPoint2(ll[right_axis], ll[up_axis]));
465 points.push_back(LPoint2(lr[right_axis], lr[up_axis]));
466 points.push_back(LPoint2(ur[right_axis], ur[up_axis]));
467 points.push_back(LPoint2(ul[right_axis], ul[up_axis]));
468
469 int num_on_planes = cpa->get_num_on_planes();
470 for (int i = 0; i < num_on_planes; ++i) {
471 NodePath plane_path = cpa->get_on_plane(i);
472 LPlane plane = DCAST(PlaneNode, plane_path.node())->get_plane();
473 plane.xform(plane_path.get_net_transform()->get_mat());
474
475 // We ignore the forward axis, assuming the frame is still in the right-
476 // up plane after being transformed. Not sure if we really need to
477 // support general 3-D transforms on 2-D objects.
478 clip_frame(points, plane);
479 }
480
481 if (points.empty()) {
482 // Turns out it's completely clipped after all.
483 return false;
484 }
485
486 ClipPoints::iterator pi;
487 pi = points.begin();
488 frame.set((*pi)[0], (*pi)[0], (*pi)[1], (*pi)[1]);
489 ++pi;
490 while (pi != points.end()) {
491 frame[0] = min(frame[0], (*pi)[0]);
492 frame[1] = max(frame[1], (*pi)[0]);
493 frame[2] = min(frame[2], (*pi)[1]);
494 frame[3] = max(frame[3], (*pi)[1]);
495 ++pi;
496 }
497 } else {
498 // Since there are no clip planes involved, just set the frame.
499 frame.set(min(min(ll[right_axis], lr[right_axis]), min(ul[right_axis], ur[right_axis])),
500 max(max(ll[right_axis], lr[right_axis]), max(ul[right_axis], ur[right_axis])),
501 min(min(ll[up_axis], lr[up_axis]), min(ul[up_axis], ur[up_axis])),
502 max(max(ll[up_axis], lr[up_axis]), max(ul[up_axis], ur[up_axis])));
503 }
504
505 if (sa != nullptr) {
506 // Also restrict it to within the scissor region.
507 const LVecBase4 &sf = sa->get_frame();
508 // Expand sf from 0..1 to -1..1.
509 frame.set(max(frame[0], sf[0] * 2.0f - 1.0f),
510 min(frame[1], sf[1] * 2.0f - 1.0f),
511 max(frame[2], sf[2] * 2.0f - 1.0f),
512 min(frame[3], sf[3] * 2.0f - 1.0f));
513 if (frame[1] <= frame[0] || frame[3] <= frame[2]) {
514 // Completely outside the scissor region.
515 return false;
516 }
517 }
518
519 _region->set_frame(frame);
520
521 _region->set_sort(sort);
522 _region->set_active(true);
523
524 // calculate the inverse of this transform, which is needed to go back to
525 // the frame space.
526 _frame_inv_xform.invert_from(transform);
527
528 return true;
529 }
530
531 /**
532 * This is a callback hook function, called whenever the mouse enters the
533 * region. The mouse is only considered to be "entered" in one region at a
534 * time; in the case of nested regions, it exits the outer region before
535 * entering the inner one.
536 */
537 void PGItem::
538 enter_region(const MouseWatcherParameter &param) {
539 LightReMutexHolder holder(_lock);
540 if (pgui_cat.is_debug()) {
541 pgui_cat.debug()
542 << *this << "::enter_region(" << param << ")\n";
543 }
544
545 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
546 string event = get_enter_event();
547 play_sound(event);
548 throw_event(event, EventParameter(ep));
549
550 if (_notify != nullptr) {
551 _notify->item_enter(this, param);
552 }
553 }
554
555 /**
556 * This is a callback hook function, called whenever the mouse exits the
557 * region. The mouse is only considered to be "entered" in one region at a
558 * time; in the case of nested regions, it exits the outer region before
559 * entering the inner one.
560 */
561 void PGItem::
562 exit_region(const MouseWatcherParameter &param) {
563 LightReMutexHolder holder(_lock);
564 if (pgui_cat.is_debug()) {
565 pgui_cat.debug()
566 << *this << "::exit_region(" << param << ")\n";
567 }
568
569 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
570 string event = get_exit_event();
571 play_sound(event);
572 throw_event(event, EventParameter(ep));
573
574 if (_notify != nullptr) {
575 _notify->item_exit(this, param);
576 }
577
578 // pgui_cat.info() << get_name() << "::exit()" << endl;
579 }
580
581 /**
582 * This is a callback hook function, called whenever the mouse moves within
583 * the boundaries of the region, even if it is also within the boundaries of a
584 * nested region. This is different from "enter", which is only called
585 * whenever the mouse is within only that region.
586 */
587 void PGItem::
588 within_region(const MouseWatcherParameter &param) {
589 LightReMutexHolder holder(_lock);
590 if (pgui_cat.is_debug()) {
591 pgui_cat.debug()
592 << *this << "::within_region(" << param << ")\n";
593 }
594
595 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
596 string event = get_within_event();
597 play_sound(event);
598 throw_event(event, EventParameter(ep));
599
600 if (_notify != nullptr) {
601 _notify->item_within(this, param);
602 }
603 }
604
605 /**
606 * This is a callback hook function, called whenever the mouse moves
607 * completely outside the boundaries of the region. See within().
608 */
609 void PGItem::
610 without_region(const MouseWatcherParameter &param) {
611 LightReMutexHolder holder(_lock);
612 if (pgui_cat.is_debug()) {
613 pgui_cat.debug()
614 << *this << "::without_region(" << param << ")\n";
615 }
616
617 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
618 string event = get_without_event();
619 play_sound(event);
620 throw_event(event, EventParameter(ep));
621
622 if (_notify != nullptr) {
623 _notify->item_without(this, param);
624 }
625 }
626
627 /**
628 * This is a callback hook function, called whenever the widget gets the
629 * keyboard focus.
630 */
631 void PGItem::
632 focus_in() {
633 LightReMutexHolder holder(_lock);
634 if (pgui_cat.is_debug()) {
635 pgui_cat.debug()
636 << *this << "::focus_in()\n";
637 }
638
639 string event = get_focus_in_event();
640 play_sound(event);
641 throw_event(event);
642
643 if (_notify != nullptr) {
644 _notify->item_focus_in(this);
645 }
646 }
647
648 /**
649 * This is a callback hook function, called whenever the widget loses the
650 * keyboard focus.
651 */
652 void PGItem::
653 focus_out() {
654 LightReMutexHolder holder(_lock);
655 if (pgui_cat.is_debug()) {
656 pgui_cat.debug()
657 << *this << "::focus_out()\n";
658 }
659
660 string event = get_focus_out_event();
661 play_sound(event);
662 throw_event(event);
663
664 if (_notify != nullptr) {
665 _notify->item_focus_out(this);
666 }
667 }
668
669 /**
670 * This is a callback hook function, called whenever a mouse or keyboard
671 * button is depressed while the mouse is within the region.
672 */
673 void PGItem::
674 press(const MouseWatcherParameter &param, bool background) {
675 LightReMutexHolder holder(_lock);
676 if (pgui_cat.is_debug()) {
677 pgui_cat.debug()
678 << *this << "::press(" << param << ", " << background << ")\n";
679 }
680
681 if (!background) {
682 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
683 string event;
684 if (param.is_keyrepeat()) {
685 event = get_repeat_event(param.get_button());
686 } else {
687 event = get_press_event(param.get_button());
688 }
689 play_sound(event);
690 throw_event(event, EventParameter(ep));
691 }
692
693 if (_notify != nullptr) {
694 _notify->item_press(this, param);
695 }
696 }
697
698 /**
699 * This is a callback hook function, called whenever a mouse or keyboard
700 * button previously depressed with press() is released.
701 */
702 void PGItem::
703 release(const MouseWatcherParameter &param, bool background) {
704 LightReMutexHolder holder(_lock);
705 if (pgui_cat.is_debug()) {
706 pgui_cat.debug()
707 << *this << "::release(" << param << ", " << background << ")\n";
708 }
709
710 if (!background) {
711 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
712 string event = get_release_event(param.get_button());
713 play_sound(event);
714 throw_event(event, EventParameter(ep));
715 }
716
717 if (_notify != nullptr) {
718 _notify->item_release(this, param);
719 }
720 }
721
722 /**
723 * This is a callback hook function, called whenever the user presses a key.
724 */
725 void PGItem::
726 keystroke(const MouseWatcherParameter &param, bool background) {
727 LightReMutexHolder holder(_lock);
728 if (pgui_cat.is_debug()) {
729 pgui_cat.debug()
730 << *this << "::keystroke(" << param << ", " << background << ")\n";
731 }
732
733 if (!background) {
734 PGMouseWatcherParameter *ep = new PGMouseWatcherParameter(param);
735 string event = get_keystroke_event();
736 play_sound(event);
737 throw_event(event, EventParameter(ep));
738
739 if (has_notify()) {
740 get_notify()->item_keystroke(this, param);
741 }
742 }
743 }
744
745 /**
746 * This is a callback hook function, called whenever the user highlights an
747 * option in the IME window.
748 */
749 void PGItem::
750 candidate(const MouseWatcherParameter &param, bool background) {
751 LightReMutexHolder holder(_lock);
752 if (pgui_cat.is_debug()) {
753 pgui_cat.debug()
754 << *this << "::candidate(" << param << ", " << background << ")\n";
755 }
756
757 // We don't throw sound events for candidate selections for now.
758 if (!background) {
759 if (has_notify()) {
760 get_notify()->item_candidate(this, param);
761 }
762 }
763 }
764
765 /**
766 * This is a callback hook function, called whenever a mouse is moved while
767 * within the region.
768 */
769 void PGItem::
770 move(const MouseWatcherParameter &param) {
771 LightReMutexHolder holder(_lock);
772 if (pgui_cat.is_debug()) {
773 pgui_cat.debug()
774 << *this << "::move(" << param << ")\n";
775 }
776
777 if (_notify != nullptr) {
778 _notify->item_move(this, param);
779 }
780 }
781
782 /**
783 * Calls press() on all the PGItems with background focus.
784 */
785 void PGItem::
786 background_press(const MouseWatcherParameter &param) {
787 for (PGItem *item : _background_focus) {
788 if (!item->get_focus()) {
789 item->press(param, true);
790 }
791 }
792 }
793
794 /**
795 * Calls release() on all the PGItems with background focus.
796 */
797 void PGItem::
798 background_release(const MouseWatcherParameter &param) {
799 for (PGItem *item : _background_focus) {
800 if (!item->get_focus()) {
801 item->release(param, true);
802 }
803 }
804 }
805
806 /**
807 * Calls keystroke() on all the PGItems with background focus.
808 */
809 void PGItem::
810 background_keystroke(const MouseWatcherParameter &param) {
811 for (PGItem *item : _background_focus) {
812 if (!item->get_focus()) {
813 item->keystroke(param, true);
814 }
815 }
816 }
817
818 /**
819 * Calls candidate() on all the PGItems with background focus.
820 */
821 void PGItem::
822 background_candidate(const MouseWatcherParameter &param) {
823 for (PGItem *item : _background_focus) {
824 if (!item->get_focus()) {
825 item->candidate(param, true);
826 }
827 }
828 }
829
830 /**
831 * Sets whether the PGItem is active for mouse watching. This is not
832 * necessarily related to the active/inactive appearance of the item, which is
833 * controlled by set_state(), but it does affect whether it responds to mouse
834 * events.
835 */
836 void PGItem::
837 set_active(bool active) {
838 LightReMutexHolder holder(_lock);
839 if (active) {
840 _flags |= F_active;
841 } else {
842 _flags &= ~F_active;
843 // Deactivating the item automatically defocuses it too.
844 if (get_focus()) {
845 set_focus(false);
846 }
847 }
848 }
849
850 /**
851 * Sets whether the PGItem currently has keyboard focus. This simply means
852 * that the item may respond to keyboard events as well as to mouse events;
853 * precisely what this means is up to the individual item.
854 *
855 * Only one PGItem in the world is allowed to have focus at any given time.
856 * Setting the focus on any other item automatically disables the focus from
857 * the previous item.
858 */
859 void PGItem::
860 set_focus(bool focus) {
861 LightReMutexHolder holder(_lock);
862 if (focus) {
863 if (!get_active()) {
864 // Cannot set focus on an inactive item.
865 return;
866 }
867
868 // Set the keyboard focus to this item.
869 if (_focus_item != this) {
870 if (_focus_item != nullptr) {
871 // Clear the focus from whatever item currently has it.
872 _focus_item->set_focus(false);
873 }
874 _focus_item = this;
875 }
876 if (!get_focus()) {
877 focus_in();
878 _flags |= F_focus;
879 }
880
881 } else {
882 if (_focus_item == this) {
883 // Remove this item from the focus.
884 _focus_item = nullptr;
885 }
886
887 if (get_focus()) {
888 focus_out();
889 _flags &= ~F_focus;
890 }
891 }
892 _region->set_keyboard(focus);
893 }
894
895 /**
896 * Sets the background_focus flag for this item. When background_focus is
897 * enabled, the item will receive keypress events even if it is not in focus;
898 * in fact, even if it is not onscreen. Unlike normal focus, many items may
899 * have background_focus simultaneously.
900 */
901 void PGItem::
902 set_background_focus(bool focus) {
903 LightReMutexHolder holder(_lock);
904 if (focus != get_background_focus()) {
905 if (focus) {
906 // Activate background focus.
907 _flags |= F_background_focus;
908 bool inserted = _background_focus.insert(this).second;
909 nassertv(inserted);
910
911 } else {
912 // Deactivate background focus.
913 _flags &= ~F_background_focus;
914 size_t num_erased = _background_focus.erase(this);
915 nassertv(num_erased == 1);
916 }
917 }
918 }
919
920 /**
921 * Returns one more than the highest-numbered state def that was ever assigned
922 * to the PGItem. The complete set of state defs assigned may then be
923 * retrieved by indexing from 0 to (get_num_state_defs() - 1).
924 *
925 * This is only an upper limit on the actual number of state defs, since there
926 * may be holes in the list.
927 */
928 int PGItem::
929 get_num_state_defs() const {
930 LightReMutexHolder holder(_lock);
931 return _state_defs.size();
932 }
933
934 /**
935 * Returns true if get_state_def() has ever been called for the indicated
936 * state (thus defining a render subgraph for this state index), false
937 * otherwise.
938 */
939 bool PGItem::
940 has_state_def(int state) const {
941 LightReMutexHolder holder(_lock);
942 if (state < 0 || state >= (int)_state_defs.size()) {
943 return false;
944 }
945 return (!_state_defs[state]._root.is_empty());
946 }
947
948 /**
949 * Resets the NodePath assigned to the indicated state to its initial default,
950 * with only a frame representation if appropriate.
951 */
952 void PGItem::
953 clear_state_def(int state) {
954 LightReMutexHolder holder(_lock);
955 if (state < 0 || state >= (int)_state_defs.size()) {
956 return;
957 }
958
959 _state_defs[state]._root = NodePath();
960 _state_defs[state]._frame = NodePath();
961 _state_defs[state]._frame_stale = true;
962
963 mark_internal_bounds_stale();
964
965 #ifdef THREADED_PIPELINE
966 if (Pipeline::get_render_pipeline()->get_num_stages() > 1) {
967 update_frame(state);
968 }
969 #endif
970 }
971
972 /**
973 * Parents an instance of the bottom node of the indicated NodePath to the
974 * indicated state index.
975 */
976 NodePath PGItem::
977 instance_to_state_def(int state, const NodePath &path) {
978 LightReMutexHolder holder(_lock);
979 if (path.is_empty()) {
980 // If the source is empty, quietly do nothing.
981 return NodePath();
982 }
983
984 mark_internal_bounds_stale();
985
986 return path.instance_to(do_get_state_def(state));
987 }
988
989 /**
990 * Returns the kind of frame that will be drawn behind the item when it is in
991 * the indicated state.
992 */
993 PGFrameStyle PGItem::
994 get_frame_style(int state) {
995 LightReMutexHolder holder(_lock);
996 if (state < 0 || state >= (int)_state_defs.size()) {
997 return PGFrameStyle();
998 }
999 return _state_defs[state]._frame_style;
1000 }
1001
1002 /**
1003 * Changes the kind of frame that will be drawn behind the item when it is in
1004 * the indicated state.
1005 */
1006 void PGItem::
1007 set_frame_style(int state, const PGFrameStyle &style) {
1008 LightReMutexHolder holder(_lock);
1009
1010 slot_state_def(state);
1011
1012 if (_state_defs[state]._root.is_empty()) {
1013 // Create a new node.
1014 _state_defs[state]._root = NodePath("state_" + format_string(state));
1015 }
1016
1017 _state_defs[state]._frame_style = style;
1018 _state_defs[state]._frame_stale = true;
1019
1020 mark_internal_bounds_stale();
1021
1022 #ifdef THREADED_PIPELINE
1023 if (Pipeline::get_render_pipeline()->get_num_stages() > 1) {
1024 update_frame(state);
1025 }
1026 #endif
1027 }
1028
1029 #ifdef HAVE_AUDIO
1030 /**
1031 * Sets the sound that will be played whenever the indicated event occurs.
1032 */
1033 void PGItem::
1034 set_sound(const string &event, AudioSound *sound) {
1035 LightReMutexHolder holder(_lock);
1036 _sounds[event] = sound;
1037 }
1038
1039 /**
1040 * Removes the sound associated with the indicated event.
1041 */
1042 void PGItem::
1043 clear_sound(const string &event) {
1044 LightReMutexHolder holder(_lock);
1045 _sounds.erase(event);
1046 }
1047
1048 /**
1049 * Returns the sound associated with the indicated event, or NULL if there is
1050 * no associated sound.
1051 */
1052 AudioSound *PGItem::
1053 get_sound(const string &event) const {
1054 LightReMutexHolder holder(_lock);
1055 Sounds::const_iterator si = _sounds.find(event);
1056 if (si != _sounds.end()) {
1057 return (*si).second;
1058 }
1059 return nullptr;
1060 }
1061
1062 /**
1063 * Returns true if there is a sound associated with the indicated event, or
1064 * false otherwise.
1065 */
1066 bool PGItem::
1067 has_sound(const string &event) const {
1068 LightReMutexHolder holder(_lock);
1069 return (_sounds.count(event) != 0);
1070 }
1071 #endif // HAVE_AUDIO
1072
1073 /**
1074 * Returns the TextNode object that will be used by all PGItems to generate
1075 * default labels given a string. This can be loaded with the default font,
1076 * etc.
1077 */
1078 TextNode *PGItem::
1079 get_text_node() {
1080 if (_text_node == nullptr) {
1081 _text_node = new TextNode("pguiText");
1082 _text_node->set_text_color(0.0f, 0.0f, 0.0f, 1.0f);
1083
1084 // The default TextNode is aligned to the left, for the convenience of
1085 // PGEntry.
1086 _text_node->set_align(TextNode::A_left);
1087 }
1088 return _text_node;
1089 }
1090
1091 /**
1092 * Plays the sound associated with the indicated event, if there is one.
1093 */
1094 void PGItem::
1095 play_sound(const string &event) {
1096 #ifdef HAVE_AUDIO
1097 LightReMutexHolder holder(_lock);
1098 Sounds::const_iterator si = _sounds.find(event);
1099 if (si != _sounds.end()) {
1100 AudioSound *sound = (*si).second;
1101 sound->play();
1102 }
1103 #endif // HAVE_AUDIO
1104 }
1105
1106 /**
1107 * The frame parameter is an in/out parameter. This function adjusts frame so
1108 * that it represents the largest part of the rectangular region passed in,
1109 * that does not overlap with the rectangular region of the indicated
1110 * obscurer. If the obscurer is NULL, or is a hidden node, it is not
1111 * considered and the frame is left unchanged.
1112 *
1113 * This is used by slider bars and scroll frames, which have to automatically
1114 * figure out how much space they have to work with after allowing space for
1115 * scroll bars and buttons.
1116 */
1117 void PGItem::
1118 reduce_region(LVecBase4 &frame, PGItem *obscurer) const {
1119 using std::min;
1120 using std::max;
1121
1122 if (obscurer != nullptr && !obscurer->is_overall_hidden()) {
1123 LVecBase4 oframe = get_relative_frame(obscurer);
1124
1125 // Determine the four rectangular regions on the four sides of the
1126 // obscuring region.
1127 LVecBase4 right(max(frame[0], oframe[1]), frame[1], frame[2], frame[3]);
1128 LVecBase4 left(frame[0], min(frame[1], oframe[0]), frame[2], frame[3]);
1129 LVecBase4 above(frame[0], frame[1], max(frame[2], oframe[3]), frame[3]);
1130 LVecBase4 below(frame[0], frame[1], frame[2], min(frame[3], oframe[2]));
1131
1132 // Now choose the largest of those four.
1133 const LVecBase4 *largest = &right;
1134 PN_stdfloat largest_area = compute_area(*largest);
1135 compare_largest(largest, largest_area, &left);
1136 compare_largest(largest, largest_area, &above);
1137 compare_largest(largest, largest_area, &below);
1138
1139 frame = *largest;
1140 }
1141 }
1142
1143 /**
1144 * Returns the LVecBase4 frame of the indicated item, converted into this
1145 * item's coordinate space. Presumably, item is a child of this node.
1146 */
1147 LVecBase4 PGItem::
1148 get_relative_frame(PGItem *item) const {
1149 using std::min;
1150 using std::max;
1151
1152 NodePath this_np = NodePath::any_path((PGItem *)this);
1153 NodePath item_np = this_np.find_path_to(item);
1154 if (item_np.is_empty()) {
1155 item_np = NodePath::any_path(item);
1156 }
1157 const LVecBase4 &orig_frame = item->get_frame();
1158 LMatrix4 transform = item_np.get_mat(this_np);
1159
1160 // Transform the item's frame into the PGScrollFrame's coordinate space.
1161 // Transform all four vertices, and get the new bounding box. This way the
1162 // region works (mostly) even if has been rotated.
1163 LPoint3 ll(orig_frame[0], 0.0f, orig_frame[2]);
1164 LPoint3 lr(orig_frame[1], 0.0f, orig_frame[2]);
1165 LPoint3 ul(orig_frame[0], 0.0f, orig_frame[3]);
1166 LPoint3 ur(orig_frame[1], 0.0f, orig_frame[3]);
1167 ll = ll * transform;
1168 lr = lr * transform;
1169 ul = ul * transform;
1170 ur = ur * transform;
1171
1172 return LVecBase4(min(min(ll[0], lr[0]), min(ul[0], ur[0])),
1173 max(max(ll[0], lr[0]), max(ul[0], ur[0])),
1174 min(min(ll[2], lr[2]), min(ul[2], ur[2])),
1175 max(max(ll[2], lr[2]), max(ul[2], ur[2])));
1176 }
1177
1178 /**
1179 * Converts from the 2-d mouse coordinates into the coordinate space of the
1180 * item.
1181 */
1182 LPoint3 PGItem::
1183 mouse_to_local(const LPoint2 &mouse_point) const {
1184 // This is ambiguous if the PGItem has multiple instances. Why would you do
1185 // that, anyway?
1186 NodePath this_np((PGItem *)this);
1187 CPT(TransformState) inv_transform = NodePath().get_transform(this_np);
1188 return inv_transform->get_mat().xform_point(LVector3::rfu(mouse_point[0], 0, mouse_point[1]));
1189 }
1190
1191 /**
1192 * Called when the user changes the frame size. Assumes the lock is held.
1193 */
1194 void PGItem::
1195 frame_changed() {
1196 mark_frames_stale();
1197 if (_notify != nullptr) {
1198 _notify->item_frame_changed(this);
1199 }
1200 }
1201
1202 /**
1203 * Returns the Node that is the root of the subgraph that will be drawn when
1204 * the PGItem is in the indicated state. The first time this is called for a
1205 * particular state index, it may create the Node.
1206 *
1207 * Assumes the lock is already held.
1208 */
1209 NodePath &PGItem::
1210 do_get_state_def(int state) {
1211 slot_state_def(state);
1212
1213 if (_state_defs[state]._root.is_empty()) {
1214 // Create a new node.
1215 _state_defs[state]._root = NodePath("state_" + format_string(state));
1216 _state_defs[state]._frame_stale = true;
1217 }
1218
1219 if (_state_defs[state]._frame_stale) {
1220 update_frame(state);
1221 }
1222
1223 return _state_defs[state]._root;
1224 }
1225
1226 /**
1227 * Ensures there is a slot in the array for the given state definition.
1228 * Assumes the lock is already held.
1229 */
1230 void PGItem::
1231 slot_state_def(int state) {
1232 while (state >= (int)_state_defs.size()) {
1233 _state_defs.push_back(StateDef());
1234 }
1235 }
1236
1237 /**
1238 * Generates a new instance of the frame geometry for the indicated state.
1239 * Assumes the lock is already held.
1240 */
1241 void PGItem::
1242 update_frame(int state) {
1243 // First, remove the old frame geometry, if any.
1244 if (state >= 0 && state < (int)_state_defs.size()) {
1245 _state_defs[state]._frame.remove_node();
1246 }
1247
1248 // We must turn off the stale flag first, before we call get_state_def(), to
1249 // prevent get_state_def() from being a recursive call.
1250 _state_defs[state]._frame_stale = false;
1251
1252 // Now create new frame geometry.
1253 if (has_frame()) {
1254 NodePath &root = do_get_state_def(state);
1255 _state_defs[state]._frame =
1256 _state_defs[state]._frame_style.generate_into(root, _frame);
1257 }
1258 }
1259
1260 /**
1261 * Marks all the frames in all states stale, so that they will be regenerated
1262 * the next time each state is requested. Assumes the lock is already held.
1263 */
1264 void PGItem::
1265 mark_frames_stale() {
1266 #ifdef THREADED_PIPELINE
1267 // If we are using the threaded pipeline, we must update the frame geometry
1268 // immediately on the App thread, since this class isn't pipeline-cycled.
1269 if (Pipeline::get_render_pipeline()->get_num_stages() > 1) {
1270 for (int state = 0; state < (int)_state_defs.size(); ++state) {
1271 update_frame(state);
1272 }
1273 }
1274 else
1275 #endif
1276 {
1277 for (StateDef &def : _state_defs) {
1278 // Remove the old frame, if any.
1279 def._frame.remove_node();
1280 def._frame_stale = true;
1281 }
1282 }
1283 mark_internal_bounds_stale();
1284 }
1285
1286 /**
1287 * Clips the four corners of the item's frame by the indicated clipping plane,
1288 * and modifies the points to reflect the new set of clipped points.
1289 *
1290 * The return value is true if the set of points is unmodified (all points are
1291 * behind the clip plane), or false otherwise.
1292 */
1293 bool PGItem::
1294 clip_frame(ClipPoints &source_points, const LPlane &plane) const {
1295 if (source_points.empty()) {
1296 return true;
1297 }
1298
1299 LPoint3 from3d;
1300 LVector3 delta3d;
1301 if (!plane.intersects_plane(from3d, delta3d, LPlane(LVector3(0, 1, 0), LPoint3::zero()))) {
1302 // The clipping plane is parallel to the polygon. The polygon is either
1303 // all in or all out.
1304 if (plane.dist_to_plane(LPoint3::zero()) < 0.0) {
1305 // A point within the polygon is behind the clipping plane: the polygon
1306 // is all in.
1307 return true;
1308 }
1309 return false;
1310 }
1311
1312 // Project the line of intersection into the X-Z plane. Now we have a 2-d
1313 // clipping line.
1314 LPoint2 from2d(from3d[0], from3d[2]);
1315 LVector2 delta2d(delta3d[0], delta3d[2]);
1316
1317 PN_stdfloat a = -delta2d[1];
1318 PN_stdfloat b = delta2d[0];
1319 PN_stdfloat c = from2d[0] * delta2d[1] - from2d[1] * delta2d[0];
1320
1321 // Now walk through the points. Any point on the left of our line gets
1322 // removed, and the line segment clipped at the point of intersection.
1323
1324 // We might increase the number of vertices by as many as 1, if the plane
1325 // clips off exactly one corner. (We might also decrease the number of
1326 // vertices, or keep them the same number.)
1327 ClipPoints new_points;
1328 new_points.reserve(source_points.size() + 1);
1329
1330 LPoint2 last_point(source_points.back());
1331 bool last_is_in = is_right(last_point - from2d, delta2d);
1332 bool all_in = last_is_in;
1333
1334 for (LPoint2 this_point : source_points) {
1335 bool this_is_in = is_right(this_point - from2d, delta2d);
1336
1337 // There appears to be a compiler bug in gcc 4.0: we need to extract this
1338 // comparison outside of the if statement.
1339 bool crossed_over = (this_is_in != last_is_in);
1340 if (crossed_over) {
1341 // We have just crossed over the clipping line. Find the point of
1342 // intersection.
1343 LVector2 d = this_point - last_point;
1344 PN_stdfloat denom = (a * d[0] + b * d[1]);
1345 if (denom != 0.0) {
1346 PN_stdfloat t = -(a * last_point[0] + b * last_point[1] + c) / denom;
1347 LPoint2 p = last_point + t * d;
1348
1349 new_points.push_back(p);
1350 last_is_in = this_is_in;
1351 }
1352 }
1353
1354 if (this_is_in) {
1355 // We are behind the clipping line. Keep the point.
1356 new_points.push_back(this_point);
1357 } else {
1358 all_in = false;
1359 }
1360
1361 last_point = this_point;
1362 }
1363
1364 source_points.swap(new_points);
1365 return all_in;
1366 }
audioSound.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
boundingBox.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
boundingSphere.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
boundingVolume.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
AudioSound
Definition: audioSound.h:25
BoundingBox
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
Definition: boundingBox.h:29
BoundingSphere
This defines a bounding sphere, consisting of a center and a radius.
Definition: boundingSphere.h:25
BoundingVolume
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
Definition: boundingVolume.h:41
ClipPlaneAttrib
This functions similarly to a LightAttrib.
Definition: clipPlaneAttrib.h:31
ClipPlaneAttrib::get_on_plane
get_on_plane
Returns the nth plane enabled by the attribute, sorted in render order.
Definition: clipPlaneAttrib.h:74
ClipPlaneAttrib::get_num_on_planes
get_num_on_planes
Returns the number of planes that are enabled by the attribute.
Definition: clipPlaneAttrib.h:74
CullBinManager
This is a global object that maintains the collection of named CullBins in the world.
Definition: cullBinManager.h:34
CullBinManager::get_bin_type
BinType get_bin_type(int bin_index) const
Returns the type of the bin with the indicated bin_index (where bin_index was retrieved by get_bin() ...
Definition: cullBinManager.I:78
CullBinManager::get_global_ptr
static CullBinManager * get_global_ptr()
Returns the pointer to the global CullBinManager object.
Definition: cullBinManager.I:281
CullBinManager::get_bin_sort
int get_bin_sort(int bin_index) const
Returns the sort order of the bin with the indicated bin_index (where bin_index was retrieved by get_...
Definition: cullBinManager.I:129
CullTraverserData
This collects together the pieces of data that are accumulated for each node while walking the scene ...
Definition: cullTraverserData.h:40
CullTraverser
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling,...
Definition: cullTraverser.h:45
CullTraverser::get_camera_mask
const DrawMask & get_camera_mask() const
Returns the visibility mask from the camera viewing the scene.
Definition: cullTraverser.I:112
CullTraverser::traverse
void traverse(const NodePath &root)
Begins the traversal from the indicated node.
Definition: cullTraverser.cxx:106
EventParameter
An optional parameter associated with an event.
Definition: eventParameter.h:35
GeomTransformer
An object specifically designed to transform the vertices of a Geom without disturbing indexing or af...
Definition: geomTransformer.h:42
GraphicsStateGuardianBase
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Definition: graphicsStateGuardianBase.h:110
LightReMutexHolder
Similar to MutexHolder, but for a light reentrant mutex.
Definition: lightReMutexHolder.h:25
MouseWatcherParameter
This is sent along as a parameter to most events generated for a region to indicate the mouse and but...
Definition: mouseWatcherParameter.h:28
MouseWatcherParameter::get_button
ButtonHandle get_button() const
Returns the mouse or keyboard button associated with this event.
Definition: mouseWatcherParameter.I:148
MouseWatcherParameter::is_keyrepeat
bool is_keyrepeat() const
Returns true if the button-down even was generated due to keyrepeat, or false if it was an original b...
Definition: mouseWatcherParameter.I:157
NodePath
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
NodePath::any_path
static NodePath any_path(PandaNode *node, Thread *current_thread=Thread::get_current_thread())
Returns a new NodePath that represents any arbitrary path from the root to the indicated node.
Definition: nodePath.I:62
NodePath::find_path_to
NodePath find_path_to(PandaNode *node) const
Searches for the indicated node below this node and returns the shortest NodePath that connects them.
Definition: nodePath.cxx:332
NodePath::is_empty
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188
NodePath::get_mat
const LMatrix4 & get_mat() const
Returns the transform matrix that has been applied to the referenced node, or the identity matrix if ...
Definition: nodePath.I:776
NodePath::node
PandaNode * node() const
Returns the referenced node of the path.
Definition: nodePath.I:227
NodePath::get_transform
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
Definition: nodePath.cxx:791
NodePath::instance_to
NodePath instance_to(const NodePath &other, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Adds the referenced node of the NodePath as a child of the referenced node of the indicated other Nod...
Definition: nodePath.cxx:471
NodePath::set_transform
void set_transform(const TransformState *transform, Thread *current_thread=Thread::get_current_thread())
Changes the complete transform object on this node.
Definition: nodePath.I:565
PGCullTraverser
This is a specialization of CullTraverser for use within the pgui system.
Definition: pgCullTraverser.h:28
PGFrameStyle
Definition: pgFrameStyle.h:29
PGItem
This is the base class for all the various kinds of gui widget objects.
Definition: pgItem.h:53
PGItem::background_release
static void background_release(const MouseWatcherParameter &param)
Calls release() on all the PGItems with background focus.
Definition: pgItem.cxx:798
PGItem::get_frame
const LVecBase4 & get_frame() const
Returns the bounding rectangle of the item.
Definition: pgItem.I:106
PGItem::press
virtual void press(const MouseWatcherParameter &param, bool background)
This is a callback hook function, called whenever a mouse or keyboard button is depressed while the m...
Definition: pgItem.cxx:674
PGItem::get_active
bool get_active() const
Returns whether the PGItem is currently active for mouse events.
Definition: pgItem.I:160
PGItem::set_frame_style
void set_frame_style(int state, const PGFrameStyle &style)
Changes the kind of frame that will be drawn behind the item when it is in the indicated state.
Definition: pgItem.cxx:1007
PGItem::background_candidate
static void background_candidate(const MouseWatcherParameter &param)
Calls candidate() on all the PGItems with background focus.
Definition: pgItem.cxx:822
PGItem::get_keystroke_event
std::string get_keystroke_event() const
Returns the event name that will be thrown when the item is active and any key is pressed by the user...
Definition: pgItem.I:446
PGItem::get_without_event
std::string get_without_event() const
Returns the event name that will be thrown when the item is active and the mouse moves completely out...
Definition: pgItem.I:383
PGItem::get_focus_out_event
std::string get_focus_out_event() const
Returns the event name that will be thrown when the item loses the keyboard focus.
Definition: pgItem.I:403
PGItem::get_notify
PGItemNotify * get_notify() const
Returns the object which will be notified when the PGItem changes, if any.
Definition: pgItem.I:69
PGItem::clear_state_def
void clear_state_def(int state)
Resets the NodePath assigned to the indicated state to its initial default, with only a frame represe...
Definition: pgItem.cxx:953
PGItem::get_exit_event
std::string get_exit_event() const
Returns the event name that will be thrown when the item is active and the mouse exits its frame,...
Definition: pgItem.I:359
PGItem::get_text_node
static TextNode * get_text_node()
Returns the TextNode object that will be used by all PGItems to generate default labels given a strin...
Definition: pgItem.cxx:1079
PGItem::has_state_def
bool has_state_def(int state) const
Returns true if get_state_def() has ever been called for the indicated state (thus defining a render ...
Definition: pgItem.cxx:940
PGItem::get_focus
bool get_focus() const
Returns whether the PGItem currently has focus for keyboard events.
Definition: pgItem.I:170
PGItem::get_background_focus
bool get_background_focus() const
Returns whether background_focus is currently enabled.
Definition: pgItem.I:180
PGItem::get_num_state_defs
get_num_state_defs
Returns one more than the highest-numbered state def that was ever assigned to the PGItem.
Definition: pgItem.h:135
PGItem::release
virtual void release(const MouseWatcherParameter &param, bool background)
This is a callback hook function, called whenever a mouse or keyboard button previously depressed wit...
Definition: pgItem.cxx:703
PGItem::get_frame_style
PGFrameStyle get_frame_style(int state)
Returns the kind of frame that will be drawn behind the item when it is in the indicated state.
Definition: pgItem.cxx:994
PGItem::instance_to_state_def
NodePath instance_to_state_def(int state, const NodePath &path)
Parents an instance of the bottom node of the indicated NodePath to the indicated state index.
Definition: pgItem.cxx:977
PGItem::set_background_focus
void set_background_focus(bool focus)
Sets the background_focus flag for this item.
Definition: pgItem.cxx:902
PGItem::without_region
virtual void without_region(const MouseWatcherParameter &param)
This is a callback hook function, called whenever the mouse moves completely outside the boundaries o...
Definition: pgItem.cxx:610
PGItem::get_press_event
std::string get_press_event(const ButtonHandle &button) const
Returns the event name that will be thrown when the item is active and the indicated mouse or keyboar...
Definition: pgItem.I:414
PGItem::get_within_event
std::string get_within_event() const
Returns the event name that will be thrown when the item is active and the mouse moves within the bou...
Definition: pgItem.I:371
PGItem::keystroke
virtual void keystroke(const MouseWatcherParameter &param, bool background)
This is a callback hook function, called whenever the user presses a key.
Definition: pgItem.cxx:726
PGItem::exit_region
virtual void exit_region(const MouseWatcherParameter &param)
This is a callback hook function, called whenever the mouse exits the region.
Definition: pgItem.cxx:562
PGItem::background_press
static void background_press(const MouseWatcherParameter &param)
Calls press() on all the PGItems with background focus.
Definition: pgItem.cxx:786
PGItem::set_focus
virtual void set_focus(bool focus)
Sets whether the PGItem currently has keyboard focus.
Definition: pgItem.cxx:860
PGItem::get_repeat_event
std::string get_repeat_event(const ButtonHandle &button) const
Returns the event name that will be thrown when the item is active and the indicated mouse or keyboar...
Definition: pgItem.I:425
PGItem::focus_in
virtual void focus_in()
This is a callback hook function, called whenever the widget gets the keyboard focus.
Definition: pgItem.cxx:632
PGItem::has_notify
bool has_notify() const
Returns true if there is an object configured to be notified when the PGItem changes,...
Definition: pgItem.I:59
PGItem::focus_out
virtual void focus_out()
This is a callback hook function, called whenever the widget loses the keyboard focus.
Definition: pgItem.cxx:653
PGItem::move
virtual void move(const MouseWatcherParameter &param)
This is a callback hook function, called whenever a mouse is moved while within the region.
Definition: pgItem.cxx:770
PGItem::has_frame
bool has_frame() const
Returns true if the item has a bounding rectangle; see set_frame().
Definition: pgItem.I:116
PGItem::within_region
virtual void within_region(const MouseWatcherParameter &param)
This is a callback hook function, called whenever the mouse moves within the boundaries of the region...
Definition: pgItem.cxx:588
PGItem::get_release_event
std::string get_release_event(const ButtonHandle &button) const
Returns the event name that will be thrown when the item is active and the indicated mouse or keyboar...
Definition: pgItem.I:436
PGItem::candidate
virtual void candidate(const MouseWatcherParameter &param, bool background)
This is a callback hook function, called whenever the user highlights an option in the IME window.
Definition: pgItem.cxx:750
PGItem::background_keystroke
static void background_keystroke(const MouseWatcherParameter &param)
Calls keystroke() on all the PGItems with background focus.
Definition: pgItem.cxx:810
PGItem::get_enter_event
std::string get_enter_event() const
Returns the event name that will be thrown when the item is active and the mouse enters its frame,...
Definition: pgItem.I:349
PGItem::get_focus_in_event
std::string get_focus_in_event() const
Returns the event name that will be thrown when the item gets the keyboard focus.
Definition: pgItem.I:393
PGItem::enter_region
virtual void enter_region(const MouseWatcherParameter &param)
This is a callback hook function, called whenever the mouse enters the region.
Definition: pgItem.cxx:538
PGItem::set_active
virtual void set_active(bool active)
Sets whether the PGItem is active for mouse watching.
Definition: pgItem.cxx:837
PGMouseWatcherParameter
This specialization on MouseWatcherParameter allows us to tag on additional elements to events for th...
Definition: pgMouseWatcherParameter.h:27
PGMouseWatcherRegion
This is a specialization on MouseWatcherRegion, to add a bit more fields that are relevant to the PG ...
Definition: pgMouseWatcherRegion.h:28
PGTop::add_region
void add_region(MouseWatcherRegion *region)
Adds the indicated region to the set of regions in the group.
Definition: pgTop.I:76
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
PandaNode::is_overall_hidden
is_overall_hidden
Returns true if the node has been hidden to all cameras by clearing its overall bit.
Definition: pandaNode.h:248
PandaNode::r_prepare_scene
virtual void r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state, GeomTransformer &transformer, Thread *current_thread)
The recursive implementation of prepare_scene().
Definition: pandaNode.cxx:2436
PandaNode::get_bounds_type
get_bounds_type
Returns the bounding volume type set with set_bounds_type().
Definition: pandaNode.h:293
Pipeline::get_num_stages
int get_num_stages() const
Returns the number of stages required for the pipeline.
Definition: pipeline.I:37
Pipeline::get_render_pipeline
static Pipeline * get_render_pipeline()
Returns a pointer to the global render pipeline.
Definition: pipeline.I:18
PlaneNode
A node that contains a plane.
Definition: planeNode.h:36
RenderState
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
SceneGraphReducer
An interface for simplifying ("flattening") scene graphs by eliminating unneeded nodes and collapsing...
Definition: sceneGraphReducer.h:39
SceneGraphReducer::apply_attribs
void apply_attribs(PandaNode *node, int attrib_types=~(TT_clip_plane|TT_cull_face|TT_apply_texture_color))
Walks the scene graph, accumulating attribs of the indicated types, applying them to the vertices,...
Definition: sceneGraphReducer.I:78
ScissorAttrib
This restricts rendering to within a rectangular region of the scene, without otherwise affecting the...
Definition: scissorAttrib.h:36
ScissorAttrib::get_frame
get_frame
Returns the left, right, bottom, top coordinates of the scissor frame.
Definition: scissorAttrib.h:51
TextNode
The primary interface to this module.
Definition: textNode.h:48
Thread
A thread; that is, a lightweight process.
Definition: thread.h:46
Thread::get_current_pipeline_stage
get_current_pipeline_stage
Returns the integer pipeline stage associated with the current thread.
Definition: thread.h:110
TransformState
Indicates a coordinate-system transform on vertices.
Definition: transformState.h:54
TransformState::get_mat
get_mat
Returns the matrix that describes the transform.
Definition: transformState.h:156
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
TypedObject::is_exact_type
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition: typedObject.I:38
pset< PGItem * >
pvector
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
clipPlaneAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_mathutil.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
config_pgui.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
cullBinManager.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
cullTraverserData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
cullTraverser.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
dcast.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
nodePath.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pandaNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pgCullTraverser.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
is_right
bool is_right(const LVector2 &v1, const LVector2 &v2)
Returns true if the 2-d v1 is to the right of v2.
Definition: pgItem.cxx:51
pgItem.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pgMouseWatcherParameter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pipeline.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
sceneGraphReducer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
scissorAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
string_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
throw_event.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.