00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "mouseWatcher.h"
00016 #include "config_tform.h"
00017 #include "dataGraphTraverser.h"
00018 #include "mouseWatcherParameter.h"
00019 #include "mouseAndKeyboard.h"
00020 #include "mouseData.h"
00021 #include "buttonEventList.h"
00022 #include "mouseButton.h"
00023 #include "throw_event.h"
00024 #include "eventParameter.h"
00025 #include "dataNodeTransmit.h"
00026 #include "transformState.h"
00027 #include "displayRegion.h"
00028 #include "stereoDisplayRegion.h"
00029 #include "geomVertexWriter.h"
00030 #include "geomLinestrips.h"
00031 #include "geomPoints.h"
00032 #include "dcast.h"
00033 #include "indent.h"
00034 #include "lightMutexHolder.h"
00035 #include "nearly_zero.h"
00036
00037 #include <algorithm>
00038
00039 TypeHandle MouseWatcher::_type_handle;
00040
00041
00042
00043
00044
00045
00046 MouseWatcher::
00047 MouseWatcher(const string &name) :
00048 DataNode(name)
00049 {
00050 _pixel_xy_input = define_input("pixel_xy", EventStoreVec2::get_class_type());
00051 _pixel_size_input = define_input("pixel_size", EventStoreVec2::get_class_type());
00052 _xy_input = define_input("xy", EventStoreVec2::get_class_type());
00053 _button_events_input = define_input("button_events", ButtonEventList::get_class_type());
00054 _pointer_events_input = define_input("pointer_events", PointerEventList::get_class_type());
00055
00056 _pixel_xy_output = define_output("pixel_xy", EventStoreVec2::get_class_type());
00057 _pixel_size_output = define_output("pixel_size", EventStoreVec2::get_class_type());
00058 _xy_output = define_output("xy", EventStoreVec2::get_class_type());
00059 _button_events_output = define_output("button_events", ButtonEventList::get_class_type());
00060
00061 _pixel_xy = new EventStoreVec2(LPoint2(0.0f, 0.0f));
00062 _xy = new EventStoreVec2(LPoint2(0.0f, 0.0f));
00063 _pixel_size = new EventStoreVec2(LPoint2(0.0f, 0.0f));
00064 _button_events = new ButtonEventList;
00065
00066 _has_mouse = false;
00067 _internal_suppress = 0;
00068 _preferred_region = (MouseWatcherRegion *)NULL;
00069 _preferred_button_down_region = (MouseWatcherRegion *)NULL;
00070 _button_down = false;
00071 _eh = (EventHandler *)NULL;
00072 _display_region = (DisplayRegion *)NULL;
00073 _button_down_display_region = (DisplayRegion *)NULL;
00074
00075 _frame.set(-1.0f, 1.0f, -1.0f, 1.0f);
00076
00077 _inactivity_timeout = inactivity_timeout;
00078 _has_inactivity_timeout = !IS_NEARLY_ZERO(_inactivity_timeout);
00079
00080 _num_trail_recent = 0;
00081 _trail_log_duration = 0.0;
00082 _trail_log = new PointerEventList();
00083
00084 _inactivity_timeout_event = "inactivity_timeout";
00085 _last_activity = 0.0;
00086 _inactivity_state = IS_active;
00087
00088
00089
00090
00091
00092 _enter_multiple = false;
00093
00094
00095
00096
00097 _implicit_click = false;
00098 }
00099
00100
00101
00102
00103
00104
00105 MouseWatcher::
00106 ~MouseWatcher() {
00107 }
00108
00109
00110
00111
00112
00113
00114
00115
00116 bool MouseWatcher::
00117 remove_region(MouseWatcherRegion *region) {
00118 LightMutexHolder holder(_lock);
00119
00120 remove_region_from(_current_regions, region);
00121 if (region == _preferred_region) {
00122 if (_preferred_region != (MouseWatcherRegion *)NULL) {
00123 exit_region(_preferred_region, MouseWatcherParameter());
00124 }
00125 _preferred_region = (MouseWatcherRegion *)NULL;
00126 }
00127 if (region == _preferred_button_down_region) {
00128 _preferred_button_down_region = (MouseWatcherRegion *)NULL;
00129 }
00130
00131 return MouseWatcherGroup::do_remove_region(region);
00132 }
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 MouseWatcherRegion *MouseWatcher::
00144 get_over_region(const LPoint2 &pos) const {
00145 LightMutexHolder holder(_lock);
00146
00147 Regions regions;
00148 get_over_regions(regions, pos);
00149 return get_preferred_region(regions);
00150 }
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168 bool MouseWatcher::
00169 add_group(MouseWatcherGroup *group) {
00170 LightMutexHolder holder(_lock);
00171
00172
00173 PT(MouseWatcherGroup) pt = group;
00174 Groups::const_iterator gi =
00175 find(_groups.begin(), _groups.end(), pt);
00176 if (gi != _groups.end()) {
00177
00178 return false;
00179 }
00180
00181 #ifndef NDEBUG
00182 if (!_show_regions_render2d.is_empty()) {
00183 group->show_regions(_show_regions_render2d, _show_regions_bin_name,
00184 _show_regions_draw_order);
00185 }
00186 #endif // NDEBUG
00187
00188
00189 _groups.push_back(pt);
00190 return true;
00191 }
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 bool MouseWatcher::
00202 remove_group(MouseWatcherGroup *group) {
00203 LightMutexHolder holder(_lock);
00204 LightMutexHolder holder2(group->_lock);
00205
00206 group->do_sort_regions();
00207
00208 Regions only_a, only_b, both;
00209 intersect_regions(only_a, only_b, both,
00210 _current_regions, group->_regions);
00211 set_current_regions(only_a);
00212
00213 if (has_region_in(both, _preferred_region)) {
00214 if (_preferred_region != (MouseWatcherRegion *)NULL) {
00215 exit_region(_preferred_region, MouseWatcherParameter());
00216 }
00217 _preferred_region = (MouseWatcherRegion *)NULL;
00218 }
00219 if (has_region_in(both, _preferred_button_down_region)) {
00220 _preferred_button_down_region = (MouseWatcherRegion *)NULL;
00221 }
00222
00223 #ifndef NDEBUG
00224 if (!_show_regions_render2d.is_empty()) {
00225 group->do_hide_regions();
00226 }
00227 #endif // NDEBUG
00228
00229
00230 PT(MouseWatcherGroup) pt = group;
00231 Groups::iterator gi =
00232 find(_groups.begin(), _groups.end(), pt);
00233 if (gi != _groups.end()) {
00234
00235 _groups.erase(gi);
00236 return true;
00237 }
00238
00239
00240 return false;
00241 }
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255 bool MouseWatcher::
00256 replace_group(MouseWatcherGroup *old_group, MouseWatcherGroup *new_group) {
00257 if (old_group == new_group) {
00258
00259 return true;
00260 }
00261
00262 LightMutexHolder holder(_lock);
00263
00264 LightMutexHolder holder2(old_group->_lock);
00265 LightMutexHolder holder3(new_group->_lock);
00266
00267 old_group->do_sort_regions();
00268 new_group->do_sort_regions();
00269
00270 #ifndef NDEBUG
00271 if (!_show_regions_render2d.is_empty()) {
00272 old_group->do_hide_regions();
00273 new_group->do_show_regions(_show_regions_render2d, _show_regions_bin_name,
00274 _show_regions_draw_order);
00275 }
00276 #endif // NDEBUG
00277
00278
00279 Regions remove, add, keep;
00280 intersect_regions(remove, add, keep,
00281 old_group->_regions, new_group->_regions);
00282
00283 Regions new_current_regions;
00284 bool any_new_current_regions = false;
00285
00286
00287 if (!remove.empty()) {
00288 Regions only_a, only_b, both;
00289 intersect_regions(only_a, only_b, both,
00290 _current_regions, remove);
00291 new_current_regions.swap(only_a);
00292 any_new_current_regions = true;
00293
00294 if (has_region_in(both, _preferred_region)) {
00295 if (_preferred_region != (MouseWatcherRegion *)NULL) {
00296 exit_region(_preferred_region, MouseWatcherParameter());
00297 }
00298 _preferred_region = (MouseWatcherRegion *)NULL;
00299 }
00300 if (has_region_in(both, _preferred_button_down_region)) {
00301 _preferred_button_down_region = (MouseWatcherRegion *)NULL;
00302 }
00303 }
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324 if (any_new_current_regions) {
00325 set_current_regions(new_current_regions);
00326 }
00327
00328
00329 PT(MouseWatcherGroup) pt = new_group;
00330 Groups::iterator gi =
00331 find(_groups.begin(), _groups.end(), pt);
00332 if (gi == _groups.end()) {
00333 _groups.push_back(new_group);
00334 }
00335
00336 #ifndef NDEBUG
00337 if (!_show_regions_render2d.is_empty()) {
00338 new_group->do_update_regions();
00339 }
00340 #endif // NDEBUG
00341
00342
00343 pt = old_group;
00344 gi = find(_groups.begin(), _groups.end(), pt);
00345 if (gi != _groups.end()) {
00346
00347 _groups.erase(gi);
00348 return true;
00349 }
00350
00351
00352 return false;
00353 }
00354
00355
00356
00357
00358
00359
00360
00361 int MouseWatcher::
00362 get_num_groups() const {
00363 LightMutexHolder holder(_lock);
00364 return _groups.size();
00365 }
00366
00367
00368
00369
00370
00371
00372
00373 MouseWatcherGroup *MouseWatcher::
00374 get_group(int n) const {
00375 LightMutexHolder holder(_lock);
00376 nassertr(n >= 0 && n < (int)_groups.size(), NULL);
00377 return _groups[n];
00378 }
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388 void MouseWatcher::
00389 set_trail_log_duration(double duration) {
00390 if (duration < 0.0) {
00391 duration = 0.0;
00392 }
00393 _trail_log_duration = duration;
00394 discard_excess_trail_log();
00395 }
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408 void MouseWatcher::
00409 discard_excess_trail_log() {
00410 if (_trail_log_duration == 0.0) {
00411 _trail_log->clear();
00412 } else {
00413 if (_trail_log->get_num_events() > 2) {
00414 double old = ClockObject::get_global_clock()->get_frame_time() - _trail_log_duration;
00415 while ((_trail_log->get_num_events() > 2)&&
00416 (_trail_log->get_time(0) <= old)&&
00417 (_trail_log->get_time(1) <= old)) {
00418 _trail_log->pop_front();
00419 }
00420 }
00421 }
00422 }
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441 PT(GeomNode) MouseWatcher::
00442 get_trail_node() {
00443 if (_trail_node == 0) {
00444 _trail_node = new GeomNode("Mouse Trail Node");
00445 update_trail_node();
00446 }
00447 return _trail_node;
00448 }
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459 void MouseWatcher::
00460 clear_trail_node() {
00461 _trail_node = 0;
00462 }
00463
00464
00465
00466
00467
00468
00469 void MouseWatcher::
00470 update_trail_node() {
00471 if (_trail_node == 0) {
00472 return;
00473 }
00474 _trail_node->remove_all_geoms();
00475
00476 if (_trail_log->get_num_events() < 2) {
00477 return;
00478 }
00479
00480 PT(GeomVertexData) data = new GeomVertexData
00481 ("mouseTrailSegs", GeomVertexFormat::get_v3(), Geom::UH_static);
00482
00483 GeomVertexWriter vertex(data, InternalName::get_vertex());
00484
00485 PT(GeomLinestrips) lines = new GeomLinestrips(Geom::UH_static);
00486
00487 double xscale = 2.0 / _pixel_size->get_value().get_x();
00488 double yscale = 2.0 / _pixel_size->get_value().get_y();
00489
00490 for (int i=0; i<(int)_trail_log->get_num_events(); i++) {
00491 double x = (_trail_log->get_xpos(i) * xscale) - 1.0;
00492 double y = (_trail_log->get_ypos(i) * yscale) - 1.0;
00493 vertex.add_data3(LVecBase3(x,0.0,-y));
00494 lines->add_vertex(i);
00495 }
00496 lines->close_primitive();
00497
00498 PT(Geom) l_geom = new Geom(data);
00499 l_geom->add_primitive(lines);
00500 _trail_node->add_geom(l_geom);
00501 }
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518 void MouseWatcher::
00519 note_activity() {
00520 _last_activity = ClockObject::get_global_clock()->get_frame_time();
00521 switch (_inactivity_state) {
00522 case IS_active:
00523 break;
00524
00525 case IS_inactive:
00526 _inactivity_state = IS_inactive_to_active;
00527 break;
00528
00529 case IS_active_to_inactive:
00530 _inactivity_state = IS_active;
00531 break;
00532
00533 case IS_inactive_to_active:
00534 break;
00535 }
00536 }
00537
00538
00539
00540
00541
00542
00543
00544 void MouseWatcher::
00545 output(ostream &out) const {
00546 LightMutexHolder holder(_lock);
00547 DataNode::output(out);
00548
00549 int count = _regions.size();
00550 Groups::const_iterator gi;
00551 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00552 MouseWatcherGroup *group = (*gi);
00553 count += group->_regions.size();
00554 }
00555
00556 out << " (" << count << " regions)";
00557 }
00558
00559
00560
00561
00562
00563
00564 void MouseWatcher::
00565 write(ostream &out, int indent_level) const {
00566 indent(out, indent_level)
00567 << "MouseWatcher " << get_name() << ":\n";
00568 MouseWatcherGroup::write(out, indent_level + 2);
00569
00570 LightMutexHolder holder(_lock);
00571 if (!_groups.empty()) {
00572 Groups::const_iterator gi;
00573 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00574 MouseWatcherGroup *group = (*gi);
00575 indent(out, indent_level + 2)
00576 << "Subgroup:\n";
00577 group->write(out, indent_level + 4);
00578 }
00579 }
00580 }
00581
00582
00583
00584
00585
00586
00587
00588
00589 void MouseWatcher::
00590 get_over_regions(MouseWatcher::Regions ®ions, const LPoint2 &pos) const {
00591 nassertv(_lock.debug_is_locked());
00592
00593
00594 PN_stdfloat mx = (pos[0] + 1.0f) * 0.5f * (_frame[1] - _frame[0]) + _frame[0];
00595 PN_stdfloat my = (pos[1] + 1.0f) * 0.5f * (_frame[3] - _frame[2]) + _frame[2];
00596
00597
00598
00599
00600
00601 regions.clear();
00602
00603 Regions::const_iterator ri;
00604 for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
00605 MouseWatcherRegion *region = (*ri);
00606 const LVecBase4 &frame = region->get_frame();
00607
00608 if (region->get_active() &&
00609 mx >= frame[0] && mx <= frame[1] &&
00610 my >= frame[2] && my <= frame[3]) {
00611
00612 regions.push_back(region);
00613 }
00614 }
00615
00616
00617 Groups::const_iterator gi;
00618 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00619 MouseWatcherGroup *group = (*gi);
00620 for (ri = group->_regions.begin(); ri != group->_regions.end(); ++ri) {
00621 MouseWatcherRegion *region = (*ri);
00622 const LVecBase4 &frame = region->get_frame();
00623
00624 if (region->get_active() &&
00625 mx >= frame[0] && mx <= frame[1] &&
00626 my >= frame[2] && my <= frame[3]) {
00627
00628 regions.push_back(region);
00629 }
00630 }
00631 }
00632
00633
00634
00635
00636 sort(regions.begin(), regions.end());
00637 }
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648 MouseWatcherRegion *MouseWatcher::
00649 get_preferred_region(const MouseWatcher::Regions ®ions) {
00650 if (regions.empty()) {
00651 return (MouseWatcherRegion *)NULL;
00652 }
00653
00654 Regions::const_iterator ri;
00655 ri = regions.begin();
00656 MouseWatcherRegion *preferred = *ri;
00657 ++ri;
00658 while (ri != regions.end()) {
00659 MouseWatcherRegion *region = *ri;
00660
00661 if (*region < *preferred) {
00662 preferred = region;
00663 }
00664 ++ri;
00665 }
00666
00667 return preferred;
00668 }
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680 void MouseWatcher::
00681 set_current_regions(MouseWatcher::Regions ®ions) {
00682 nassertv(_lock.debug_is_locked());
00683
00684
00685 MouseWatcherParameter param;
00686 param.set_modifier_buttons(_mods);
00687 param.set_mouse(_mouse);
00688
00689
00690 Regions::const_iterator new_ri = regions.begin();
00691 Regions::const_iterator old_ri = _current_regions.begin();
00692
00693
00694
00695 vector<MouseWatcherRegion *> new_regions;
00696
00697 bool any_changes = false;
00698 while (new_ri != regions.end() && old_ri != _current_regions.end()) {
00699 if ((*new_ri) < (*old_ri)) {
00700
00701 MouseWatcherRegion *new_region = (*new_ri);
00702 new_regions.push_back(new_region);
00703 any_changes = true;
00704 ++new_ri;
00705
00706 } else if ((*old_ri) < (*new_ri)) {
00707
00708 MouseWatcherRegion *old_region = (*old_ri);
00709 without_region(old_region, param);
00710 any_changes = true;
00711 ++old_ri;
00712
00713 } else {
00714
00715 ++new_ri;
00716 ++old_ri;
00717 }
00718 }
00719
00720 while (new_ri != regions.end()) {
00721
00722 MouseWatcherRegion *new_region = (*new_ri);
00723 new_regions.push_back(new_region);
00724 any_changes = true;
00725 ++new_ri;
00726 }
00727
00728 while (old_ri != _current_regions.end()) {
00729
00730 MouseWatcherRegion *old_region = (*old_ri);
00731 without_region(old_region, param);
00732 any_changes = true;
00733 ++old_ri;
00734 }
00735
00736 if (any_changes) {
00737
00738
00739 _current_regions.swap(regions);
00740
00741
00742 vector<MouseWatcherRegion *>::const_iterator ri;
00743 for (ri = new_regions.begin(); ri != new_regions.end(); ++ri) {
00744 MouseWatcherRegion *new_region = (*ri);
00745 within_region(new_region, param);
00746 }
00747 }
00748
00749 if (!_enter_multiple) {
00750
00751
00752
00753 MouseWatcherRegion *new_preferred_region =
00754 get_preferred_region(_current_regions);
00755
00756 if (_button_down && new_preferred_region != _preferred_button_down_region) {
00757
00758
00759 new_preferred_region = (MouseWatcherRegion *)NULL;
00760 }
00761
00762 if (new_preferred_region != _preferred_region) {
00763 if (_preferred_region != (MouseWatcherRegion *)NULL) {
00764 exit_region(_preferred_region, param);
00765 }
00766 _preferred_region = new_preferred_region;
00767 if (_preferred_region != (MouseWatcherRegion *)NULL) {
00768 enter_region(_preferred_region, param);
00769 }
00770 }
00771 }
00772 }
00773
00774
00775
00776
00777
00778
00779
00780 void MouseWatcher::
00781 clear_current_regions() {
00782 nassertv(_lock.debug_is_locked());
00783
00784 if (!_current_regions.empty()) {
00785
00786 MouseWatcherParameter param;
00787 param.set_modifier_buttons(_mods);
00788 param.set_mouse(_mouse);
00789
00790 Regions::const_iterator old_ri = _current_regions.begin();
00791
00792 while (old_ri != _current_regions.end()) {
00793
00794 MouseWatcherRegion *old_region = (*old_ri);
00795 old_region->exit_region(param);
00796 throw_event_pattern(_leave_pattern, old_region, ButtonHandle::none());
00797 ++old_ri;
00798 }
00799
00800 _current_regions.clear();
00801
00802 if (_preferred_region != (MouseWatcherRegion *)NULL) {
00803 _preferred_region->exit_region(param);
00804 throw_event_pattern(_leave_pattern, _preferred_region, ButtonHandle::none());
00805 _preferred_region = (MouseWatcherRegion *)NULL;
00806 }
00807 }
00808 }
00809
00810 #ifndef NDEBUG
00811
00812
00813
00814
00815
00816
00817 void MouseWatcher::
00818 do_show_regions(const NodePath &render2d, const string &bin_name,
00819 int draw_order) {
00820 MouseWatcherGroup::do_show_regions(render2d, bin_name, draw_order);
00821 _show_regions_render2d = render2d;
00822 _show_regions_bin_name = bin_name;
00823 _show_regions_draw_order = draw_order;
00824
00825 Groups::const_iterator gi;
00826 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00827 MouseWatcherGroup *group = (*gi);
00828 group->show_regions(render2d, bin_name, draw_order);
00829 }
00830 }
00831 #endif // NDEBUG
00832
00833 #ifndef NDEBUG
00834
00835
00836
00837
00838
00839
00840 void MouseWatcher::
00841 do_hide_regions() {
00842 MouseWatcherGroup::do_hide_regions();
00843 _show_regions_render2d = NodePath();
00844 _show_regions_bin_name = string();
00845 _show_regions_draw_order = 0;
00846
00847 Groups::const_iterator gi;
00848 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
00849 MouseWatcherGroup *group = (*gi);
00850 group->hide_regions();
00851 }
00852 }
00853 #endif // NDEBUG
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869 void MouseWatcher::
00870 intersect_regions(MouseWatcher::Regions &only_a,
00871 MouseWatcher::Regions &only_b,
00872 MouseWatcher::Regions &both,
00873 const MouseWatcher::Regions ®ions_a,
00874 const MouseWatcher::Regions ®ions_b) {
00875
00876 Regions::const_iterator a_ri = regions_a.begin();
00877 Regions::const_iterator b_ri = regions_b.begin();
00878
00879 while (a_ri != regions_a.end() && b_ri != regions_b.end()) {
00880 if ((*a_ri) < (*b_ri)) {
00881
00882 only_a.push_back(*a_ri);
00883 ++a_ri;
00884
00885 } else if ((*b_ri) < (*a_ri)) {
00886
00887 only_b.push_back(*b_ri);
00888 ++b_ri;
00889
00890 } else {
00891
00892 both.push_back(*a_ri);
00893 ++a_ri;
00894 ++b_ri;
00895 }
00896 }
00897 }
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907 bool MouseWatcher::
00908 remove_region_from(MouseWatcher::Regions ®ions,
00909 MouseWatcherRegion *region) {
00910 PT(MouseWatcherRegion) ptr = region;
00911 Regions::iterator ri = lower_bound(regions.begin(), regions.end(), ptr);
00912 if (ri != regions.end() && (*ri) == ptr) {
00913
00914 regions.erase(ri);
00915 return true;
00916 }
00917
00918 return false;
00919 }
00920
00921
00922
00923
00924
00925
00926
00927 bool MouseWatcher::
00928 has_region_in(const MouseWatcher::Regions ®ions,
00929 MouseWatcherRegion *region) {
00930 PT(MouseWatcherRegion) ptr = region;
00931 Regions::const_iterator ri = lower_bound(regions.begin(), regions.end(), ptr);
00932 return (ri != regions.end() && (*ri) == ptr);
00933 }
00934
00935
00936
00937
00938
00939
00940
00941 void MouseWatcher::
00942 throw_event_pattern(const string &pattern, const MouseWatcherRegion *region,
00943 const ButtonHandle &button) {
00944 if (pattern.empty()) {
00945 return;
00946 }
00947 #ifndef NDEBUG
00948 if (region != (MouseWatcherRegion *)NULL) {
00949 region->test_ref_count_integrity();
00950 }
00951 #endif
00952
00953 string button_name;
00954 if (button != ButtonHandle::none()) {
00955 if (!_mods.has_button(button)) {
00956
00957
00958 button_name = _mods.get_prefix();
00959 }
00960 button_name += button.get_name();
00961 }
00962
00963 string event;
00964 for (size_t p = 0; p < pattern.size(); ++p) {
00965 if (pattern[p] == '%') {
00966 string cmd = pattern.substr(p + 1, 1);
00967 p++;
00968 if (cmd == "r") {
00969 if (region != (MouseWatcherRegion *)NULL) {
00970 event += region->get_name();
00971 }
00972
00973 } else if (cmd == "b") {
00974 event += button.get_name();
00975
00976 } else {
00977 tform_cat.error()
00978 << "Invalid symbol in event_pattern: %" << cmd << "\n";
00979 }
00980 } else {
00981 event += pattern[p];
00982 }
00983 }
00984
00985 if (!event.empty()) {
00986 throw_event(event, EventParameter(region), EventParameter(button_name));
00987 if (_eh != (EventHandler*)0L)
00988 throw_event_directly(*_eh, event, EventParameter(region),
00989 EventParameter(button_name));
00990 }
00991 }
00992
00993
00994
00995
00996
00997
00998
00999 void MouseWatcher::
01000 move() {
01001 nassertv(_lock.debug_is_locked());
01002
01003 MouseWatcherParameter param;
01004 param.set_modifier_buttons(_mods);
01005 param.set_mouse(_mouse);
01006
01007 if (_preferred_button_down_region != (MouseWatcherRegion *)NULL) {
01008 _preferred_button_down_region->move(param);
01009 }
01010 }
01011
01012
01013
01014
01015
01016
01017
01018 void MouseWatcher::
01019 press(ButtonHandle button, bool keyrepeat) {
01020 nassertv(_lock.debug_is_locked());
01021
01022 MouseWatcherParameter param;
01023 param.set_button(button);
01024 param.set_keyrepeat(keyrepeat);
01025 param.set_modifier_buttons(_mods);
01026 param.set_mouse(_mouse);
01027
01028 if (MouseButton::is_mouse_button(button)) {
01029
01030
01031 if (!_button_down) {
01032 _preferred_button_down_region = _preferred_region;
01033 }
01034 _button_down = true;
01035
01036 if (_preferred_button_down_region != (MouseWatcherRegion *)NULL) {
01037 _preferred_button_down_region->press(param);
01038 if (keyrepeat) {
01039 throw_event_pattern(_button_repeat_pattern,
01040 _preferred_button_down_region, button);
01041 } else {
01042 throw_event_pattern(_button_down_pattern,
01043 _preferred_button_down_region, button);
01044 }
01045 }
01046
01047 } else {
01048
01049
01050
01051 if (_preferred_region != (MouseWatcherRegion *)NULL) {
01052
01053
01054
01055 _preferred_region->press(param);
01056 consider_keyboard_suppress(_preferred_region);
01057 }
01058
01059 if ((_internal_suppress & MouseWatcherRegion::SF_other_button) == 0) {
01060
01061
01062
01063 param.set_outside(true);
01064 global_keyboard_press(param);
01065 }
01066 }
01067 }
01068
01069
01070
01071
01072
01073
01074
01075 void MouseWatcher::
01076 release(ButtonHandle button) {
01077 nassertv(_lock.debug_is_locked());
01078
01079 MouseWatcherParameter param;
01080 param.set_button(button);
01081 param.set_modifier_buttons(_mods);
01082 param.set_mouse(_mouse);
01083
01084 if (MouseButton::is_mouse_button(button)) {
01085
01086
01087
01088
01089
01090
01091 if (_preferred_button_down_region != (MouseWatcherRegion *)NULL) {
01092 param.set_outside(_preferred_button_down_region != _preferred_region);
01093 _preferred_button_down_region->release(param);
01094 throw_event_pattern(_button_up_pattern,
01095 _preferred_button_down_region, button);
01096 }
01097
01098 _button_down = false;
01099 _preferred_button_down_region = (MouseWatcherRegion *)NULL;
01100
01101 } else {
01102
01103
01104
01105 if (_preferred_region != (MouseWatcherRegion *)NULL) {
01106 _preferred_region->release(param);
01107 }
01108
01109 param.set_outside(true);
01110 global_keyboard_release(param);
01111 }
01112 }
01113
01114
01115
01116
01117
01118
01119
01120 void MouseWatcher::
01121 keystroke(int keycode) {
01122 nassertv(_lock.debug_is_locked());
01123
01124 MouseWatcherParameter param;
01125 param.set_keycode(keycode);
01126 param.set_modifier_buttons(_mods);
01127 param.set_mouse(_mouse);
01128
01129
01130
01131
01132
01133
01134
01135 Regions::const_iterator ri;
01136 for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
01137 MouseWatcherRegion *region = (*ri);
01138
01139 if (region->get_keyboard()) {
01140 param.set_outside(region != _preferred_region);
01141 region->keystroke(param);
01142 consider_keyboard_suppress(region);
01143 }
01144 }
01145
01146
01147 Groups::const_iterator gi;
01148 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
01149 MouseWatcherGroup *group = (*gi);
01150 for (ri = group->_regions.begin(); ri != group->_regions.end(); ++ri) {
01151 MouseWatcherRegion *region = (*ri);
01152
01153 if (region->get_keyboard()) {
01154 param.set_outside(region != _preferred_region);
01155 region->keystroke(param);
01156 consider_keyboard_suppress(region);
01157 }
01158 }
01159 }
01160 }
01161
01162
01163
01164
01165
01166
01167
01168 void MouseWatcher::
01169 candidate(const wstring &candidate_string, size_t highlight_start,
01170 size_t highlight_end, size_t cursor_pos) {
01171 nassertv(_lock.debug_is_locked());
01172
01173 MouseWatcherParameter param;
01174 param.set_candidate(candidate_string, highlight_start, highlight_end, cursor_pos);
01175 param.set_modifier_buttons(_mods);
01176 param.set_mouse(_mouse);
01177
01178
01179
01180
01181 Regions::const_iterator ri;
01182 for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
01183 MouseWatcherRegion *region = (*ri);
01184
01185 if (region->get_keyboard()) {
01186 param.set_outside(region != _preferred_region);
01187 region->candidate(param);
01188 }
01189 }
01190
01191
01192 Groups::const_iterator gi;
01193 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
01194 MouseWatcherGroup *group = (*gi);
01195 for (ri = group->_regions.begin(); ri != group->_regions.end(); ++ri) {
01196 MouseWatcherRegion *region = (*ri);
01197
01198 if (region->get_keyboard()) {
01199 param.set_outside(region != _preferred_region);
01200 region->candidate(param);
01201 }
01202 }
01203 }
01204 }
01205
01206
01207
01208
01209
01210
01211
01212
01213 void MouseWatcher::
01214 global_keyboard_press(const MouseWatcherParameter ¶m) {
01215 nassertv(_lock.debug_is_locked());
01216
01217 Regions::const_iterator ri;
01218 for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
01219 MouseWatcherRegion *region = (*ri);
01220
01221 if (region != _preferred_region && region->get_keyboard()) {
01222 region->press(param);
01223 consider_keyboard_suppress(region);
01224 }
01225 }
01226
01227
01228 Groups::const_iterator gi;
01229 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
01230 MouseWatcherGroup *group = (*gi);
01231 for (ri = group->_regions.begin(); ri != group->_regions.end(); ++ri) {
01232 MouseWatcherRegion *region = (*ri);
01233
01234 if (region != _preferred_region && region->get_keyboard()) {
01235 region->press(param);
01236 consider_keyboard_suppress(region);
01237 }
01238 }
01239 }
01240 }
01241
01242
01243
01244
01245
01246
01247
01248 void MouseWatcher::
01249 global_keyboard_release(const MouseWatcherParameter ¶m) {
01250 nassertv(_lock.debug_is_locked());
01251
01252 Regions::const_iterator ri;
01253 for (ri = _regions.begin(); ri != _regions.end(); ++ri) {
01254 MouseWatcherRegion *region = (*ri);
01255
01256 if (region != _preferred_region && region->get_keyboard()) {
01257 region->release(param);
01258 }
01259 }
01260
01261
01262 Groups::const_iterator gi;
01263 for (gi = _groups.begin(); gi != _groups.end(); ++gi) {
01264 MouseWatcherGroup *group = (*gi);
01265 for (ri = group->_regions.begin(); ri != group->_regions.end(); ++ri) {
01266 MouseWatcherRegion *region = (*ri);
01267
01268 if (region != _preferred_region && region->get_keyboard()) {
01269 region->release(param);
01270 }
01271 }
01272 }
01273 }
01274
01275
01276
01277
01278
01279
01280
01281 void MouseWatcher::
01282 enter_region(MouseWatcherRegion *region, const MouseWatcherParameter ¶m) {
01283 nassertv(_lock.debug_is_locked());
01284
01285 region->enter_region(param);
01286 throw_event_pattern(_enter_pattern, region, ButtonHandle::none());
01287 if (_implicit_click) {
01288 MouseWatcherParameter param1(param);
01289 param1.set_button(MouseButton::one());
01290 region->press(param1);
01291 }
01292 }
01293
01294
01295
01296
01297
01298
01299
01300 void MouseWatcher::
01301 exit_region(MouseWatcherRegion *region, const MouseWatcherParameter ¶m) {
01302 nassertv(_lock.debug_is_locked());
01303
01304 if (_implicit_click) {
01305 MouseWatcherParameter param1(param);
01306 param1.set_button(MouseButton::one());
01307 region->release(param1);
01308 }
01309 region->exit_region(param);
01310 throw_event_pattern(_leave_pattern, region, ButtonHandle::none());
01311 }
01312
01313
01314
01315
01316
01317
01318
01319 void MouseWatcher::
01320 set_no_mouse() {
01321 nassertv(_lock.debug_is_locked());
01322
01323 if (_has_mouse) {
01324
01325 if (!_geometry.is_null()) {
01326 _geometry->set_overall_hidden(true);
01327 }
01328 }
01329
01330 _has_mouse = false;
01331 clear_current_regions();
01332 }
01333
01334
01335
01336
01337
01338
01339
01340
01341 void MouseWatcher::
01342 set_mouse(const LVecBase2 &xy, const LVecBase2 &pixel_xy) {
01343 nassertv(_lock.debug_is_locked());
01344
01345 if (!_geometry.is_null()) {
01346
01347 _geometry->set_transform(TransformState::make_pos(LVecBase3(xy[0], 0, xy[1])));
01348 if (!_has_mouse) {
01349
01350 _geometry->set_overall_hidden(false);
01351 }
01352 }
01353
01354 _has_mouse = true;
01355 _mouse = xy;
01356 _mouse_pixel = pixel_xy;
01357
01358 Regions regions;
01359 get_over_regions(regions, _mouse);
01360 set_current_regions(regions);
01361 }
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375 void MouseWatcher::
01376 consider_keyboard_suppress(const MouseWatcherRegion *region) {
01377 if ((region->get_suppress_flags() & MouseWatcherRegion::SF_other_button) != 0) {
01378 _external_suppress |= MouseWatcherRegion::SF_other_button;
01379 }
01380 }
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395 void MouseWatcher::
01396 do_transmit_data(DataGraphTraverser *trav, const DataNodeTransmit &input,
01397 DataNodeTransmit &output) {
01398 Thread *current_thread = trav->get_current_thread();
01399 LightMutexHolder holder(_lock);
01400
01401 bool activity = false;
01402
01403
01404
01405 _internal_suppress = 0;
01406 _external_suppress = 0;
01407
01408
01409 EventStoreVec2 *pixel_size;
01410 DCAST_INTO_V(pixel_size, input.get_data(_pixel_size_input).get_ptr());
01411 output.set_data(_pixel_size_output, pixel_size);
01412 _pixel_size = pixel_size;
01413
01414 if (input.has_data(_xy_input)) {
01415
01416 const EventStoreVec2 *xy, *pixel_xy;
01417 DCAST_INTO_V(xy, input.get_data(_xy_input).get_ptr());
01418 DCAST_INTO_V(pixel_xy, input.get_data(_pixel_xy_input).get_ptr());
01419
01420 LVecBase2 f = xy->get_value();
01421 LVecBase2 p = pixel_xy->get_value();
01422
01423
01424 const LVecBase2 &last_f = _xy->get_value();
01425 if (f != last_f) {
01426 activity = true;
01427 move();
01428 }
01429
01430 if (_display_region != (DisplayRegion *)NULL) {
01431
01432 if (constrain_display_region(_display_region, f, p, current_thread)) {
01433 set_mouse(f, p);
01434
01435 } else {
01436
01437
01438 set_no_mouse();
01439
01440
01441 _internal_suppress |= MouseWatcherRegion::SF_mouse_button;
01442 }
01443
01444 } else {
01445
01446 set_mouse(f, p);
01447 }
01448 }
01449
01450
01451 _num_trail_recent = 0;
01452 if (input.has_data(_pointer_events_input) && (_trail_log_duration > 0.0)) {
01453 const PointerEventList *this_pointer_events;
01454 DCAST_INTO_V(this_pointer_events, input.get_data(_pointer_events_input).get_ptr());
01455 _num_trail_recent = this_pointer_events->get_num_events();
01456 for (int i = 0; i < _num_trail_recent; i++) {
01457 bool in_win = this_pointer_events->get_in_window(i);
01458 int xpos = this_pointer_events->get_xpos(i);
01459 int ypos = this_pointer_events->get_ypos(i);
01460 int sequence = this_pointer_events->get_sequence(i);
01461 double time = this_pointer_events->get_time(i);
01462 _trail_log->add_event(in_win, xpos, ypos, sequence, time);
01463 }
01464 }
01465 if (_trail_log->get_num_events() > 0) {
01466 discard_excess_trail_log();
01467 update_trail_node();
01468 }
01469 if (_num_trail_recent > _trail_log->get_num_events()) {
01470 _num_trail_recent = _trail_log->get_num_events();
01471 }
01472
01473
01474
01475
01476 if (_preferred_region != (MouseWatcherRegion *)NULL) {
01477 _internal_suppress |= _preferred_region->get_suppress_flags();
01478 }
01479
01480 ButtonEventList new_button_events;
01481
01482
01483 if (input.has_data(_button_events_input)) {
01484 const ButtonEventList *this_button_events;
01485 DCAST_INTO_V(this_button_events, input.get_data(_button_events_input).get_ptr());
01486 int num_events = this_button_events->get_num_events();
01487 for (int i = 0; i < num_events; i++) {
01488 const ButtonEvent &be = this_button_events->get_event(i);
01489 be.update_mods(_mods);
01490
01491 switch (be._type) {
01492 case ButtonEvent::T_down:
01493 if (!_current_buttons_down.get_bit(be._button.get_index())) {
01494
01495
01496 activity = true;
01497 _current_buttons_down.set_bit(be._button.get_index());
01498 press(be._button, false);
01499 new_button_events.add_event(be);
01500 break;
01501 }
01502
01503
01504
01505 case ButtonEvent::T_repeat:
01506 _current_buttons_down.set_bit(be._button.get_index());
01507 press(be._button, true);
01508 new_button_events.add_event(ButtonEvent(be._button, ButtonEvent::T_repeat,
01509 be._time));
01510 break;
01511
01512 case ButtonEvent::T_up:
01513 activity = true;
01514 _current_buttons_down.clear_bit(be._button.get_index());
01515 release(be._button);
01516 new_button_events.add_event(be);
01517 break;
01518
01519 case ButtonEvent::T_keystroke:
01520
01521
01522 keystroke(be._keycode);
01523 new_button_events.add_event(be);
01524 break;
01525
01526 case ButtonEvent::T_candidate:
01527 activity = true;
01528 candidate(be._candidate_string, be._highlight_start, be._highlight_end, be._cursor_pos);
01529 new_button_events.add_event(be);
01530 break;
01531
01532 case ButtonEvent::T_resume_down:
01533
01534
01535
01536 new_button_events.add_event(be);
01537 break;
01538
01539 case ButtonEvent::T_move:
01540
01541 break;
01542 }
01543 }
01544 }
01545
01546 if (!input.has_data(_xy_input)) {
01547
01548
01549
01550
01551 set_no_mouse();
01552 }
01553
01554
01555 if (_has_inactivity_timeout) {
01556 if (activity) {
01557 note_activity();
01558
01559 } else {
01560 double now = ClockObject::get_global_clock()->get_frame_time();
01561 double elapsed = now - _last_activity;
01562
01563
01564 if (elapsed > _inactivity_timeout) {
01565 switch (_inactivity_state) {
01566 case IS_active:
01567 _inactivity_state = IS_active_to_inactive;
01568 break;
01569
01570 case IS_inactive:
01571 break;
01572
01573 case IS_active_to_inactive:
01574 break;
01575
01576 case IS_inactive_to_active:
01577 _inactivity_state = IS_inactive;
01578 break;
01579 }
01580 }
01581 }
01582 }
01583
01584 switch (_inactivity_state) {
01585 case IS_active:
01586 case IS_inactive:
01587 break;
01588
01589 case IS_active_to_inactive:
01590
01591 if (tform_cat.is_debug()) {
01592 tform_cat.info()
01593 << "MouseWatcher detected " << _inactivity_timeout
01594 << " seconds of inactivity; releasing held buttons.\n";
01595 }
01596 {
01597 for (int i = 0; i < _current_buttons_down.get_num_bits(); ++i) {
01598 if (_current_buttons_down.get_bit(i)) {
01599 release(ButtonHandle(i));
01600 new_button_events.add_event(ButtonEvent(ButtonHandle(i), ButtonEvent::T_up));
01601 }
01602 }
01603 }
01604 _inactivity_state = IS_inactive;
01605 throw_event(_inactivity_timeout_event);
01606 break;
01607
01608 case IS_inactive_to_active:
01609
01610 {
01611 for (int i = 0; i < _current_buttons_down.get_num_bits(); ++i) {
01612 if (_current_buttons_down.get_bit(i)) {
01613 press(ButtonHandle(i), false);
01614 new_button_events.add_event(ButtonEvent(ButtonHandle(i), ButtonEvent::T_down));
01615 }
01616 }
01617 }
01618 _inactivity_state = IS_active;
01619 break;
01620 }
01621
01622 if (_has_mouse &&
01623 (_internal_suppress & MouseWatcherRegion::SF_mouse_position) == 0) {
01624
01625 _xy->set_value(_mouse);
01626 output.set_data(_xy_output, EventParameter(_xy));
01627 _pixel_xy->set_value(_mouse_pixel);
01628 output.set_data(_pixel_xy_output, EventParameter(_pixel_xy));
01629 }
01630
01631
01632 int suppress_buttons = ((_internal_suppress | _external_suppress) & MouseWatcherRegion::SF_any_button);
01633
01634 _button_events->clear();
01635
01636 int num_events = new_button_events.get_num_events();
01637 for (int i = 0; i < num_events; i++) {
01638 const ButtonEvent &be = new_button_events.get_event(i);
01639 bool suppress = true;
01640
01641 if (be._type != ButtonEvent::T_keystroke &&
01642 MouseButton::is_mouse_button(be._button)) {
01643 suppress = ((suppress_buttons & MouseWatcherRegion::SF_mouse_button) != 0);
01644 } else {
01645 suppress = ((suppress_buttons & MouseWatcherRegion::SF_other_button) != 0);
01646 }
01647
01648 if (!suppress || be._type == ButtonEvent::T_up) {
01649
01650 _button_events->add_event(be);
01651 }
01652 }
01653
01654 if (_button_events->get_num_events() != 0) {
01655 output.set_data(_button_events_output, EventParameter(_button_events));
01656 }
01657 }
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669 bool MouseWatcher::
01670 constrain_display_region(DisplayRegion *display_region,
01671 LVecBase2 &f, LVecBase2 &p,
01672 Thread *current_thread) {
01673 if (!_button_down) {
01674 _button_down_display_region = NULL;
01675 }
01676 if (_button_down_display_region != NULL) {
01677
01678
01679
01680 display_region = _button_down_display_region;
01681
01682 } else {
01683
01684
01685
01686 if (display_region->is_stereo()) {
01687 StereoDisplayRegion *stereo_display_region;
01688 DCAST_INTO_R(stereo_display_region, display_region, false);
01689 return constrain_display_region(stereo_display_region->get_left_eye(), f, p, current_thread) ||
01690 constrain_display_region(stereo_display_region->get_right_eye(), f, p, current_thread);
01691 }
01692 }
01693
01694 DisplayRegionPipelineReader dr_reader(display_region, current_thread);
01695 PN_stdfloat left, right, bottom, top;
01696 dr_reader.get_dimensions(left, right, bottom, top);
01697
01698
01699 PN_stdfloat x = (f[0] + 1.0f) / 2.0f;
01700 PN_stdfloat y = (f[1] + 1.0f) / 2.0f;
01701
01702 if (_button_down_display_region == NULL &&
01703 (x < left || x >= right || y < bottom || y >= top)) {
01704
01705 return false;
01706 }
01707
01708
01709 if (_button_down) {
01710 _button_down_display_region = display_region;
01711 }
01712
01713
01714 PN_stdfloat xp = (x - left) / (right - left);
01715
01716 PN_stdfloat xpp = (xp * 2.0f) - 1.0f;
01717
01718 PN_stdfloat yp = (y - bottom) / (top - bottom);
01719 PN_stdfloat ypp = (yp * 2.0f) - 1.0f;
01720
01721 int xo, yo, w, h;
01722 dr_reader.get_region_pixels_i(xo, yo, w, h);
01723
01724 f.set(xpp, ypp);
01725 p.set(p[0] - xo, p[1] - yo);
01726 return true;
01727 }