16 #include "pgMouseWatcherParameter.h"
17 #include "pgCullTraverser.h"
18 #include "config_pgui.h"
19 #include "boundingVolume.h"
20 #include "pandaNode.h"
21 #include "sceneGraphReducer.h"
22 #include "throw_event.h"
23 #include "string_utils.h"
25 #include "cullTraverser.h"
26 #include "cullTraverserData.h"
27 #include "cullBinManager.h"
28 #include "clipPlaneAttrib.h"
29 #include "scissorAttrib.h"
31 #include "boundingSphere.h"
32 #include "boundingBox.h"
33 #include "config_mathutil.h"
36 #include "audioSound.h"
51 return (v1[0] * v2[1] - v1[1] * v2[0]) > 0;
60 PGItem(
const string &name) :
68 _frame.set(0, 0, 0, 0);
82 _notify->remove_item(
this);
86 nassertv(_region->_item ==
this);
87 _region->_item = (
PGItem *)NULL;
90 if (_focus_item ==
this) {
91 _focus_item = (
PGItem *)NULL;
101 PGItem(
const PGItem ©) :
103 _has_frame(copy._has_frame),
108 , _sounds(copy._sounds)
117 _region->set_name(copy._region->get_name());
120 size_t num_state_defs = copy._state_defs.size();
121 _state_defs.reserve(num_state_defs);
122 for (
size_t i = 0; i < num_state_defs; ++i) {
126 StateDef &old_sd = (StateDef &)(copy._state_defs[i]);
127 old_sd._frame.remove_node();
128 old_sd._frame_stale =
true;
131 new_sd._root = old_sd._root.copy_to(
NodePath());
132 new_sd._frame_style = old_sd._frame_style;
134 _state_defs.push_back(new_sd);
160 transform_changed() {
162 PandaNode::transform_changed();
176 draw_mask_changed() {
178 PandaNode::draw_mask_changed();
220 if (trav->
is_exact_type(PGCullTraverser::get_class_type())) {
222 DCAST_INTO_R(pg_trav, trav,
true);
224 CPT(TransformState) net_transform = data.get_net_transform(trav);
225 const
LMatrix4 &transform = net_transform->get_mat();
230 int bin_index = data._state->get_bin_index();
234 CullBinManager::BinType bin_type = bin_manager->get_bin_type(bin_index);
238 sort = data._state->get_draw_order();
240 }
else if (bin_type == CullBinManager::BT_unsorted) {
243 sort = pg_trav->_sort_index;
244 pg_trav->_sort_index++;
253 int bin_sort = bin_manager->
get_bin_sort(data._state->get_bin_index());
261 sort = (bin_sort << 16) | ((sort + 0x8000) & 0xffff);
264 DCAST(
ClipPlaneAttrib, data._state->get_attrib(ClipPlaneAttrib::get_class_slot())),
265 DCAST(
ScissorAttrib, data._state->get_attrib(ScissorAttrib::get_class_slot())))) {
276 trav->traverse(next_data);
294 is_renderable()
const {
308 int &internal_vertices,
310 Thread *current_thread)
const {
312 int num_vertices = 0;
322 if (btype == BoundingVolume::BT_sphere) {
335 for (
int i = 0; i < (int)_state_defs.size(); i++) {
339 child_volumes.push_back(node->get_bounds(current_thread));
345 const BoundingVolume **child_end = child_begin + child_volumes.size();
347 bound->around(child_begin, child_end);
349 internal_bounds = bound;
350 internal_vertices = num_vertices;
365 StateDefs::iterator di;
366 for (di = _state_defs.begin(); di != _state_defs.end(); ++di) {
371 child->r_prepare_scene(gsg, child_state, transformer, current_thread);
375 PandaNode::r_prepare_scene(gsg, node_state, transformer, current_thread);
389 LPoint3 ll(_frame[0], 0.0f, _frame[2]);
390 LPoint3 ur(_frame[1], 0.0f, _frame[3]);
393 _frame.set(ll[0], ur[0], ll[2], ur[2]);
396 StateDefs::iterator di;
397 for (di = _state_defs.begin(); di != _state_defs.end(); ++di) {
407 if ((*di)._frame_style.xform(mat)) {
408 (*di)._frame_stale =
true;
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]));
470 for (
int i = 0; i < num_on_planes; ++i) {
472 LPlane plane = DCAST(
PlaneNode, plane_path.
node())->get_plane();
473 plane.xform(plane_path.get_net_transform()->
get_mat());
478 clip_frame(points, plane);
481 if (points.empty()) {
486 ClipPoints::iterator pi;
488 frame.set((*pi)[0], (*pi)[0], (*pi)[1], (*pi)[1]);
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]);
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])));
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]) {
519 _region->set_frame(frame);
521 _region->set_sort(sort);
522 _region->set_active(
true);
543 if (pgui_cat.is_debug()) {
545 << *
this <<
"::enter_region(" << param <<
")\n";
570 if (pgui_cat.is_debug()) {
572 << *
this <<
"::exit_region(" << param <<
")\n";
600 if (pgui_cat.is_debug()) {
602 << *
this <<
"::within_region(" << param <<
")\n";
625 if (pgui_cat.is_debug()) {
627 << *
this <<
"::without_region(" << param <<
")\n";
649 if (pgui_cat.is_debug()) {
651 << *
this <<
"::focus_in()\n";
672 if (pgui_cat.is_debug()) {
674 << *
this <<
"::focus_out()\n";
696 if (pgui_cat.is_debug()) {
698 << *
this <<
"::press(" << param <<
", " << background <<
")\n";
728 if (pgui_cat.is_debug()) {
730 << *
this <<
"::release(" << param <<
", " << background <<
")\n";
754 if (pgui_cat.is_debug()) {
756 << *
this <<
"::keystroke(" << param <<
", " << background <<
")\n";
780 if (pgui_cat.is_debug()) {
782 << *
this <<
"::candidate(" << param <<
", " << background <<
")\n";
802 if (pgui_cat.is_debug()) {
804 << *
this <<
"::move(" << param <<
")\n";
820 BackgroundFocus::const_iterator fi;
821 for (fi = _background_focus.begin(); fi != _background_focus.end(); ++fi) {
824 item->
press(param,
true);
837 BackgroundFocus::const_iterator fi;
838 for (fi = _background_focus.begin(); fi != _background_focus.end(); ++fi) {
854 BackgroundFocus::const_iterator fi;
855 for (fi = _background_focus.begin(); fi != _background_focus.end(); ++fi) {
871 BackgroundFocus::const_iterator fi;
872 for (fi = _background_focus.begin(); fi != _background_focus.end(); ++fi) {
926 if (_focus_item !=
this) {
927 if (_focus_item != (
PGItem *)NULL) {
939 if (_focus_item ==
this) {
941 _focus_item = (
PGItem *)NULL;
949 _region->set_keyboard(focus);
967 _flags |= F_background_focus;
968 bool inserted = _background_focus.insert(
this).second;
973 _flags &= ~F_background_focus;
974 size_t num_erased = _background_focus.erase(
this);
975 nassertv(num_erased == 1);
994 return _state_defs.size();
1007 if (state < 0 || state >= (
int)_state_defs.size()) {
1010 return (!_state_defs[state]._root.is_empty());
1023 if (state < 0 || state >= (
int)_state_defs.size()) {
1027 _state_defs[state]._root =
NodePath();
1028 _state_defs[state]._frame =
NodePath();
1029 _state_defs[state]._frame_stale =
true;
1046 slot_state_def(state);
1048 if (_state_defs[state]._root.is_empty()) {
1050 _state_defs[state]._root =
NodePath(
"state_" + format_string(state));
1051 _state_defs[state]._frame_stale =
true;
1054 if (_state_defs[state]._frame_stale) {
1055 update_frame(state);
1058 return _state_defs[state]._root;
1089 if (state < 0 || state >= (
int)_state_defs.size()) {
1092 return _state_defs[state]._frame_style;
1109 _state_defs[state]._frame_style = style;
1110 _state_defs[state]._frame_stale =
true;
1123 set_sound(
const string &event,
AudioSound *sound) {
1125 _sounds[event] = sound;
1135 clear_sound(
const string &event) {
1137 _sounds.erase(event);
1147 get_sound(
const string &event)
const {
1149 Sounds::const_iterator si = _sounds.find(event);
1150 if (si != _sounds.end()) {
1151 return (*si).second;
1163 has_sound(
const string &event)
const {
1165 return (_sounds.count(event) != 0);
1167 #endif // HAVE_AUDIO
1178 if (_text_node == (
TextNode *)NULL) {
1179 _text_node =
new TextNode(
"pguiText");
1180 _text_node->set_text_color(0.0f, 0.0f, 0.0f, 1.0f);
1184 _text_node->set_align(TextNode::A_left);
1196 play_sound(
const string &event) {
1199 Sounds::const_iterator si = _sounds.find(event);
1200 if (si != _sounds.end()) {
1204 #endif // HAVE_AUDIO
1226 LVecBase4 oframe = get_relative_frame(obscurer);
1230 LVecBase4 right(max(frame[0], oframe[1]), frame[1], frame[2], frame[3]);
1231 LVecBase4 left(frame[0], min(frame[1], oframe[0]), frame[2], frame[3]);
1232 LVecBase4 above(frame[0], frame[1], max(frame[2], oframe[3]), frame[3]);
1233 LVecBase4 below(frame[0], frame[1], frame[2], min(frame[3], oframe[2]));
1237 PN_stdfloat largest_area = compute_area(*largest);
1238 compare_largest(largest, largest_area, &left);
1239 compare_largest(largest, largest_area, &above);
1240 compare_largest(largest, largest_area, &below);
1254 get_relative_frame(
PGItem *item)
const {
1267 LPoint3 ll(orig_frame[0], 0.0f, orig_frame[2]);
1268 LPoint3 lr(orig_frame[1], 0.0f, orig_frame[2]);
1269 LPoint3 ul(orig_frame[0], 0.0f, orig_frame[3]);
1270 LPoint3 ur(orig_frame[1], 0.0f, orig_frame[3]);
1271 ll = ll * transform;
1272 lr = lr * transform;
1273 ul = ul * transform;
1274 ur = ur * transform;
1276 return LVecBase4(min(min(ll[0], lr[0]), min(ul[0], ur[0])),
1277 max(max(ll[0], lr[0]), max(ul[0], ur[0])),
1278 min(min(ll[2], lr[2]), min(ul[2], ur[2])),
1279 max(max(ll[2], lr[2]), max(ul[2], ur[2])));
1289 mouse_to_local(
const LPoint2 &mouse_point)
const {
1293 CPT(TransformState) inv_transform =
NodePath().get_transform(this_np);
1294 return inv_transform->get_mat().xform_point(
LVector3::rfu(mouse_point[0], 0, mouse_point[1]));
1304 mark_frames_stale();
1317 slot_state_def(
int state) {
1318 while (state >= (
int)_state_defs.size()) {
1319 _state_defs.push_back(StateDef());
1330 update_frame(
int state) {
1332 if (state >= 0 && state < (
int)_state_defs.size()) {
1333 _state_defs[state]._frame.remove_node();
1339 _state_defs[state]._frame_stale =
false;
1344 _state_defs[state]._frame =
1345 _state_defs[state]._frame_style.generate_into(root, _frame);
1357 mark_frames_stale() {
1358 StateDefs::iterator di;
1359 for (di = _state_defs.begin(); di != _state_defs.end(); ++di) {
1361 (*di)._frame.remove_node();
1362 (*di)._frame_stale =
true;
1379 clip_frame(ClipPoints &source_points,
const LPlane &plane)
const {
1380 if (source_points.empty()) {
1399 LPoint2 from2d(from3d[0], from3d[2]);
1400 LVector2 delta2d(delta3d[0], delta3d[2]);
1402 PN_stdfloat a = -delta2d[1];
1403 PN_stdfloat b = delta2d[0];
1404 PN_stdfloat c = from2d[0] * delta2d[1] - from2d[1] * delta2d[0];
1413 ClipPoints new_points;
1414 new_points.reserve(source_points.size() + 1);
1416 LPoint2 last_point(source_points.back());
1417 bool last_is_in = is_right(last_point - from2d, delta2d);
1418 bool all_in = last_is_in;
1419 ClipPoints::const_iterator pi;
1420 for (pi = source_points.begin(); pi != source_points.end(); ++pi) {
1422 bool this_is_in = is_right(this_point - from2d, delta2d);
1426 bool crossed_over = (this_is_in != last_is_in);
1430 LVector2 d = this_point - last_point;
1431 PN_stdfloat denom = (a * d[0] + b * d[1]);
1433 PN_stdfloat t = -(a * last_point[0] + b * last_point[1] + c) / denom;
1434 LPoint2 p = last_point + t * d;
1436 new_points.push_back(p);
1437 last_is_in = this_is_in;
1443 new_points.push_back(this_point);
1448 last_point = this_point;
1451 source_points.swap(new_points);
ButtonHandle get_button() const
Returns the mouse or keyboard button associated with this event.
const LVecBase4 & get_frame() const
Returns the bounding rectangle of the item.
A basic node of the scene graph or data graph.
This specialization on MouseWatcherParameter allows us to tag on additional elements to events for th...
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
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...
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...
virtual void xform(const LMatrix4 &mat)
Transforms the contents of this node by the indicated matrix, if it means anything to do so...
bool get_background_focus() const
Returns whether background_focus is currently enabled.
This is the base class for all the various kinds of gui widget objects.
An optional parameter associated with an event.
NodePath & get_state_def(int state)
Returns the Node that is the root of the subgraph that will be drawn when the PGItem is in the indica...
static void background_release(const MouseWatcherParameter ¶m)
Calls release() on all the PGItems with background focus.
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...
virtual void without_region(const MouseWatcherParameter ¶m)
This is a callback hook function, called whenever the mouse moves completely outside the boundaries o...
This defines a bounding sphere, consisting of a center and a radius.
const TransformState * get_transform(Thread *current_thread=Thread::get_current_thread()) const
Returns the complete transform object set on this node.
static const LPoint3f & zero()
Returns a zero-length point.
An interface for simplifying ("flattening") scene graphs by eliminating unneeded nodes and collapsing...
int get_num_state_defs() const
Returns one more than the highest-numbered state def that was ever assigned to the PGItem...
int get_nested_vertices(Thread *current_thread=Thread::get_current_thread()) const
Returns the total number of vertices that will be rendered by this node and all of its descendents...
This collects together the pieces of data that are accumulated for each node while walking the scene ...
virtual void enter_region(const MouseWatcherParameter ¶m)
This is a callback hook function, called whenever the mouse enters the region.
PandaNode * node() const
Returns the referenced node of the path.
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
virtual void focus_out()
This is a callback hook function, called whenever the widget loses the keyboard focus.
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
This functions similarly to a LightAttrib.
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
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...
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...
void set_transform(const TransformState *transform, Thread *current_thread=Thread::get_current_thread())
Changes the complete transform object on this node.
bool has_frame() const
Returns true if the item has a bounding rectangle; see set_frame().
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...
This is our own Panda specialization on the default STL vector.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
BoundingVolume::BoundsType get_bounds_type() const
Returns the bounding volume type set with set_bounds_type().
PGItemNotify * get_notify() const
Returns the object which will be notified when the PGItem changes, if any.
string get_exit_event() const
Returns the event name that will be thrown when the item is active and the mouse exits its frame...
NodePath find_path_to(PandaNode *node) const
Searches for the indicated node below this node and returns the shortest NodePath that connects them...
void mark_internal_bounds_stale(Thread *current_thread=Thread::get_current_thread())
Should be called by a derived class to mark the internal bounding volume stale, so that compute_inter...
virtual void focus_in()
This is a callback hook function, called whenever the widget gets the keyboard focus.
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...
virtual void set_focus(bool focus)
Sets whether the PGItem currently has keyboard focus.
int get_state() const
Returns the "state" of this particular PGItem.
bool has_notify() const
Returns true if there is an object configured to be notified when the PGItem changes, false otherwise.
This is a 4-by-4 transform matrix.
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...
This is a specialization of CullTraverser for use within the pgui system.
static void background_press(const MouseWatcherParameter ¶m)
Calls press() on all the PGItems with background focus.
bool activate_region(const LMatrix4 &transform, int sort, const ClipPlaneAttrib *cpa, const ScissorAttrib *sa)
Applies the indicated scene graph transform and order as determined by the traversal from PGTop...
virtual void release(const MouseWatcherParameter ¶m, bool background)
This is a callback hook function, called whenever a mouse or keyboard button previously depressed wit...
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...
bool get_active() const
Returns whether the PGItem is currently active for mouse events.
This is a specialization on MouseWatcherRegion, to add a bit more fields that are relevant to the PG ...
bool invert_from(const LMatrix4f &other)
Computes the inverse of the other matrix, and stores the result in this matrix.
static TextNode * get_text_node()
Returns the TextNode object that will be used by all PGItems to generate default labels given a strin...
NodePath get_on_plane(int n) const
Returns the nth plane enabled by the attribute, sorted in render order.
string get_enter_event() const
Returns the event name that will be thrown when the item is active and the mouse enters its frame...
virtual void within_region(const MouseWatcherParameter ¶m)
This is a callback hook function, called whenever the mouse moves within the boundaries of the region...
static LVector3f right(CoordinateSystem cs=CS_default)
Returns the right vector for the given coordinate system.
int get_num_on_planes() const
Returns the number of planes that are enabled by the attribute.
Similar to MutexHolder, but for a light reentrant mutex.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
const DrawMask & get_camera_mask() const
Returns the visibility mask from the camera viewing the scene.
string get_focus_out_event() const
Returns the event name that will be thrown when the item loses the keyboard focus.
This is the base class for all three-component vectors and points.
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...
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
This is a two-component vector offset.
virtual void move(const MouseWatcherParameter ¶m)
This is a callback hook function, called whenever a mouse is moved while within the region...
string get_focus_in_event() const
Returns the event name that will be thrown when the item gets the keyboard focus. ...
A thread; that is, a lightweight process.
static LPoint3f rfu(float right, float fwd, float up, CoordinateSystem cs=CS_default)
Returns a point described by right, forward, up displacements from the origin, wherever that maps to ...
void set_background_focus(bool focus)
Sets the background_focus flag for this item.
bool is_keyrepeat() const
Returns true if the button-down even was generated due to keyrepeat, or false if it was an original b...
The primary interface to this module.
bool is_empty() const
Returns true if the NodePath contains no nodes.
void clear_state_def(int state)
Resets the NodePath assigned to the indicated state to its initial default, with only a frame represe...
virtual void candidate(const MouseWatcherParameter ¶m, bool background)
This is a callback hook function, called whenever the user highlights an option in the IME window...
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_...
virtual void keystroke(const MouseWatcherParameter ¶m, bool background)
This is a callback hook function, called whenever the user presses a key.
void add_region(MouseWatcherRegion *region)
Adds the indicated region to the set of regions in the group.
This restricts rendering to within a rectangular region of the scene, without otherwise affecting the...
PGMouseWatcherRegion * get_region() const
Returns the MouseWatcherRegion associated with this item.
Objects that inherit from this class can receive specialized messages when PGItems change in certain ...
This is a two-component point in space.
TypeHandle is the identifier used to differentiate C++ class types.
This is sent along as a parameter to most events generated for a region to indicate the mouse and but...
This is a global object that maintains the collection of named CullBins in the world.
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...
const LVecBase4 & get_frame() const
Returns the left, right, bottom, top coordinates of the scissor frame.
virtual void exit_region(const MouseWatcherParameter ¶m)
This is a callback hook function, called whenever the mouse exits the region.
const LMatrix4 & get_mat() const
Returns the transform matrix that has been applied to the referenced node, or the identity matrix if ...
bool is_this_node_hidden(const DrawMask &camera_mask) const
Returns true if this particular node is hidden, even though we might be traversing past this node to ...
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 ...
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
bool get_focus() const
Returns whether the PGItem currently has focus for keyboard events.
static LVector3f up(CoordinateSystem cs=CS_default)
Returns the up vector for the given coordinate system.
This object performs a depth-first traversal of the scene graph, with optional view-frustum culling...
virtual void set_active(bool active)
Sets whether the PGItem is active for mouse watching.
A node that contains a plane.
static void background_candidate(const MouseWatcherParameter ¶m)
Calls candidate() on all the PGItems with background focus.
string get_without_event() const
Returns the event name that will be thrown when the item is active and the mouse moves completely out...
virtual void press(const MouseWatcherParameter ¶m, bool background)
This is a callback hook function, called whenever a mouse or keyboard button is depressed while the m...
static void background_keystroke(const MouseWatcherParameter ¶m)
Calls keystroke() on all the PGItems with background focus.
bool is_overall_hidden() const
Returns true if the node has been hidden to all cameras by clearing its overall bit.