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