00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "gui/widgets/event_handler.hpp"
00021
00022 #include "clipboard.hpp"
00023 #include "config.hpp"
00024 #include "gui/widgets/widget.hpp"
00025 #include "gui/widgets/window.hpp"
00026 #include "log.hpp"
00027 #include "serialization/parser.hpp"
00028 #include "tstring.hpp"
00029 #include "variable.hpp"
00030
00031 #define DBG_G_E LOG_STREAM_INDENT(debug, gui_event)
00032 #define LOG_G_E LOG_STREAM_INDENT(info, gui_event)
00033 #define WRN_G_E LOG_STREAM_INDENT(warn, gui_event)
00034 #define ERR_G_E LOG_STREAM_INDENT(err, gui_event)
00035
00036 namespace gui2{
00037
00038 static Uint32 hover_callback(Uint32 , void *param)
00039 {
00040 DBG_G_E << "Pushing hover event in queue.\n";
00041
00042 SDL_Event event;
00043 SDL_UserEvent data;
00044
00045 data.type = HOVER_EVENT;
00046 data.code = 0;
00047 data.data1 = param;
00048 data.data2 = 0;
00049
00050 event.type = HOVER_EVENT;
00051 event.user = data;
00052
00053 SDL_PushEvent(&event);
00054 return 0;
00055 }
00056
00057 static Uint32 popup_callback(Uint32 , void*)
00058 {
00059 DBG_G_E << "Pushing popup removal event in queue.\n";
00060
00061 SDL_Event event;
00062 SDL_UserEvent data;
00063
00064 data.type = HOVER_REMOVE_POPUP_EVENT;
00065 data.code = 0;
00066 data.data1 = 0;
00067 data.data2 = 0;
00068
00069 event.type = HOVER_REMOVE_POPUP_EVENT;
00070 event.user = data;
00071
00072 SDL_PushEvent(&event);
00073 return 0;
00074 }
00075
00076
00077
00078
00079 tevent_handler::tevent_handler() :
00080
00081 events::handler(false),
00082 event_context_(),
00083 mouse_x_(-1),
00084 mouse_y_(-1),
00085 left_("left",
00086 &tevent_executor::mouse_left_button_down,
00087 &tevent_executor::mouse_left_button_up,
00088 &tevent_executor::mouse_left_button_click,
00089 &tevent_executor::mouse_left_button_double_click,
00090 &tevent_executor::wants_mouse_left_double_click),
00091 middle_("middle",
00092 &tevent_executor::mouse_middle_button_down,
00093 &tevent_executor::mouse_middle_button_up,
00094 &tevent_executor::mouse_middle_button_click,
00095 &tevent_executor::mouse_middle_button_double_click,
00096 &tevent_executor::wants_mouse_middle_double_click),
00097 right_("right",
00098 &tevent_executor::mouse_right_button_down,
00099 &tevent_executor::mouse_right_button_up,
00100 &tevent_executor::mouse_right_button_click,
00101 &tevent_executor::mouse_right_button_double_click,
00102 &tevent_executor::wants_mouse_right_double_click),
00103 hover_pending_(false),
00104 hover_id_(0),
00105 hover_box_(),
00106 had_hover_(false),
00107 tooltip_(0),
00108 help_popup_(0),
00109 mouse_focus_(0),
00110 mouse_captured_(false),
00111 keyboard_focus_(0)
00112 {
00113 if(SDL_WasInit(SDL_INIT_TIMER) == 0) {
00114 if(SDL_InitSubSystem(SDL_INIT_TIMER) == -1) {
00115 assert(false);
00116 }
00117 }
00118
00119
00120 join();
00121 }
00122
00123 void tevent_handler::handle_event(const SDL_Event& event)
00124 {
00125
00126 twidget* mouse_over = 0;
00127 switch(event.type) {
00128 case SDL_MOUSEMOTION:
00129
00130 mouse_x_ = event.motion.x;
00131 mouse_y_ = event.motion.y;
00132 mouse_over =
00133 find_widget(get_window().client_position(tpoint(mouse_x_, mouse_y_)), true);
00134
00135 mouse_move(event, mouse_over);
00136
00137 break;
00138
00139 case SDL_MOUSEBUTTONDOWN:
00140
00141 mouse_x_ = event.button.x;
00142 mouse_y_ = event.button.y;
00143 mouse_over =
00144 find_widget(get_window().client_position(tpoint(mouse_x_, mouse_y_)), true);
00145
00146 switch(event.button.button) {
00147 case SDL_BUTTON_LEFT :
00148 DBG_G_E << "Event: Left button down.\n";
00149 mouse_button_down(event, mouse_over, left_);
00150 break;
00151 case SDL_BUTTON_MIDDLE :
00152 DBG_G_E << "Event: Middle button down.\n";
00153 mouse_button_down(event, mouse_over, middle_);
00154 break;
00155 case SDL_BUTTON_RIGHT :
00156 DBG_G_E << "Event: Right button down.\n";
00157 mouse_button_down(event, mouse_over, right_);
00158 break;
00159 default:
00160
00161 WRN_G_E << "Unhandled 'mouse button down' event for button "
00162 << static_cast<Uint32>(event.button.button) << ".\n";
00163 assert(false);
00164 break;
00165 }
00166 break;
00167
00168 case SDL_MOUSEBUTTONUP:
00169
00170 mouse_x_ = event.button.x;
00171 mouse_y_ = event.button.y;
00172 mouse_over =
00173 find_widget(get_window().client_position(tpoint(mouse_x_, mouse_y_)), true);
00174
00175 switch(event.button.button) {
00176
00177 case SDL_BUTTON_LEFT :
00178 DBG_G_E << "Event: Left button up.\n";
00179 mouse_button_up(event, mouse_over, left_);
00180 break;
00181 case SDL_BUTTON_MIDDLE :
00182 DBG_G_E << "Event: Middle button up.\n";
00183 mouse_button_up(event, mouse_over, middle_);
00184 break;
00185 case SDL_BUTTON_RIGHT :
00186 DBG_G_E << "Event: Right button up.\n";
00187 mouse_button_up(event, mouse_over, right_);
00188 break;
00189 default:
00190
00191 WRN_G_E << "Unhandled 'mouse button up' event for button "
00192 << static_cast<Uint32>(event.button.button) << ".\n";
00193 assert(false);
00194 break;
00195 }
00196 break;
00197
00198 case HOVER_EVENT:
00199 mouse_hover(event, 0);
00200 break;
00201
00202 case HOVER_REMOVE_POPUP_EVENT:
00203 remove_tooltip();
00204 remove_help_popup();
00205 break;
00206
00207 case SDL_KEYDOWN:
00208 key_down(event);
00209 break;
00210
00211 case SDL_VIDEORESIZE:
00212 get_window().window_resize(*this, event.resize.w, event.resize.h);
00213 break;
00214
00215 #if defined(_X11) && !defined(__APPLE__)
00216 case SDL_SYSWMEVENT: {
00217 DBG_G_E << "Event: System event.\n";
00218
00219 handle_system_event(event);
00220 break;
00221 }
00222 #endif
00223
00224 default:
00225
00226
00227 WRN_G_E << "Unhandled event " << static_cast<Uint32>(event.type) << ".\n";
00228 break;
00229 }
00230 }
00231
00232 void tevent_handler::mouse_capture(const bool capture)
00233 {
00234 assert(mouse_focus_);
00235 mouse_captured_ = capture;
00236 }
00237
00238 tpoint tevent_handler::get_mouse() const
00239 {
00240 return get_window().client_position(tpoint(mouse_x_, mouse_y_));
00241 }
00242
00243 void tevent_handler::show_tooltip(const t_string& tooltip, const unsigned timeout)
00244 {
00245 DBG_G_E << "Event: show tooltip.\n";
00246
00247 assert(!tooltip_);
00248
00249 if(help_popup_) {
00250 remove_help_popup();
00251 }
00252
00253 tooltip_ = mouse_focus_;
00254
00255 do_show_tooltip(get_window().client_position(tpoint(mouse_x_, mouse_y_)), tooltip);
00256
00257 if(timeout) {
00258 SDL_AddTimer(timeout, popup_callback, 0);
00259 }
00260 }
00261
00262 void tevent_handler::remove_tooltip()
00263 {
00264 if(!tooltip_) {
00265 return;
00266 }
00267
00268 tooltip_ = 0;
00269
00270 do_remove_tooltip();
00271 }
00272
00273 void tevent_handler::show_help_popup(const t_string& help_popup, const unsigned timeout)
00274 {
00275 DBG_G_E << "Event: show help popup.\n";
00276
00277 if(help_popup_) {
00278 DBG_G_E << "Help is already there, bailing out.\n";
00279 return;
00280 }
00281
00282 if(tooltip_) {
00283 remove_tooltip();
00284 }
00285
00286
00287 had_hover_ = true;
00288 hover_pending_ = false;
00289
00290 help_popup_ = mouse_focus_;
00291
00292 do_show_help_popup(get_window().client_position(tpoint(mouse_x_, mouse_y_)), help_popup);
00293
00294 if(timeout) {
00295 SDL_AddTimer(timeout, popup_callback, 0);
00296 }
00297 }
00298
00299 void tevent_handler::remove_help_popup()
00300 {
00301 if(!help_popup_) {
00302 return;
00303 }
00304
00305 help_popup_ = 0;
00306
00307 do_remove_help_popup();
00308 }
00309
00310 void tevent_handler::mouse_enter(const SDL_Event& , twidget* mouse_over)
00311 {
00312 DBG_G_E << "Event: remove tooltip.\n";
00313
00314 assert(mouse_over);
00315
00316 mouse_focus_ = mouse_over;
00317 mouse_over->mouse_enter(*this);
00318
00319 set_hover();
00320 }
00321
00322 void tevent_handler::mouse_hover(const SDL_Event& event, twidget* )
00323 {
00324 const unsigned hover_id = *static_cast<unsigned*>(event.user.data1);
00325 delete static_cast<unsigned*>(event.user.data1);
00326
00327 if(!hover_pending_ || hover_id != hover_id_) {
00328 return;
00329 }
00330
00331 assert(mouse_focus_);
00332
00333 mouse_focus_->mouse_hover(*this);
00334
00335 had_hover_ = true;
00336 }
00337
00338 void tevent_handler::mouse_move(const SDL_Event& event, twidget* mouse_over)
00339 {
00340
00341
00342 if(mouse_captured_) {
00343 mouse_focus_->mouse_move(*this);
00344 set_hover(true);
00345 } else {
00346 if(!mouse_focus_ && mouse_over) {
00347 mouse_enter(event, mouse_over);
00348 } else if (mouse_focus_ && !mouse_over) {
00349 mouse_leave(event, mouse_over);
00350 } else if(mouse_focus_ && mouse_focus_ == mouse_over) {
00351 mouse_over->mouse_move(*this);
00352 set_hover();
00353 } else if(mouse_focus_ && mouse_over) {
00354
00355 mouse_leave(event, mouse_over);
00356 mouse_enter(event, mouse_over);
00357 } else {
00358 assert(!mouse_focus_ && !mouse_over);
00359 }
00360 }
00361 }
00362
00363 void tevent_handler::mouse_leave(const SDL_Event& , twidget* )
00364 {
00365 assert(mouse_focus_);
00366
00367 had_hover_ = false;
00368 hover_pending_ =false;
00369
00370 remove_tooltip();
00371 remove_help_popup();
00372
00373 mouse_focus_->mouse_leave(*this);
00374 mouse_focus_ = 0;
00375 }
00376
00377 void tevent_handler::mouse_button_down(const SDL_Event& , twidget* mouse_over, tmouse_button& button)
00378 {
00379 if(button.is_down) {
00380 WRN_G_E << "In 'button down' for button '" << button.name
00381 << "' but the mouse button is already down, we missed an event.\n";
00382 return;
00383 }
00384 button.is_down = true;
00385 hover_pending_ = false;
00386
00387 if(mouse_captured_) {
00388 button.focus = mouse_focus_;
00389 (mouse_focus_->*button.down)(*this);
00390 } else {
00391 if(!mouse_over) {
00392 return;
00393 }
00394
00395 if(mouse_over != mouse_focus_) {
00396 WRN_G_E << "Mouse down event on non focussed widget "
00397 << "and mouse not captured, we missed events.\n";
00398 }
00399
00400 button.focus = mouse_over;
00401 (mouse_over->*button.down)(*this);
00402 }
00403 }
00404
00405 void tevent_handler::mouse_button_up(const SDL_Event& event, twidget* mouse_over, tmouse_button& button)
00406 {
00407 if(!button.is_down) {
00408 WRN_G_E << "In 'button up' for button '" << button.name
00409 << "' but the mouse button is already up, we missed an event.\n";
00410 return;
00411 }
00412
00413 button.is_down = false;
00414 if(button.focus) {
00415 (button.focus->*button.up)(*this);
00416 }
00417
00418 if(mouse_captured_) {
00419 if (!left_.is_down && !middle_.is_down && !right_.is_down) {
00420 mouse_captured_ = false;
00421 }
00422
00423 if(mouse_focus_ != mouse_over) {
00424 mouse_leave(event, mouse_over);
00425
00426 if(mouse_over) {
00427 mouse_enter(event, mouse_over);
00428 }
00429 } else {
00430 mouse_click(mouse_focus_, button);
00431 }
00432 } else if(button.focus && button.focus == mouse_over) {
00433 mouse_click(button.focus, button);
00434 }
00435
00436 button.focus = 0;
00437 set_hover();
00438 }
00439
00440 void tevent_handler::mouse_click(twidget* widget, tmouse_button& button)
00441 {
00442 if((widget->*button.wants_double_click)()) {
00443 Uint32 stamp = SDL_GetTicks();
00444 if(button.last_click_stamp + settings::double_click_time >= stamp) {
00445
00446 (widget->*button.double_click)(*this);
00447 button.last_click_stamp = 0;
00448
00449 } else {
00450
00451 (widget->*button.click)(*this);
00452 button.last_click_stamp = stamp;
00453 }
00454
00455 } else {
00456
00457 (widget->*button.click)(*this);
00458 }
00459 }
00460
00461 void tevent_handler::set_hover(const bool test_on_widget)
00462 {
00463
00464 if(had_hover_) {
00465 return;
00466 }
00467
00468
00469 if(!mouse_focus_ || !mouse_focus_->wants_mouse_hover()) {
00470 return;
00471 }
00472
00473
00474 if(hover_pending_ && point_in_rect(mouse_x_, mouse_y_, hover_box_)) {
00475 return;
00476 }
00477
00478
00479 if(left_.is_down || middle_.is_down || right_.is_down) {
00480 return;
00481 }
00482
00483 if(test_on_widget) {
00484
00485 }
00486
00487 static unsigned hover_id = 0;
00488
00489 hover_pending_ = true;
00490
00491
00492 hover_box_ = ::create_rect(mouse_x_ - 5, mouse_y_ - 5, 10, 10);
00493
00494 unsigned *hover = new unsigned;
00495 *hover = hover_id;
00496 hover_id_ = hover_id++;
00497
00498 SDL_AddTimer(settings::popup_show_delay, hover_callback, hover);
00499 }
00500
00501 void tevent_handler::key_down(const SDL_Event& event)
00502 {
00503
00504 if(mouse_focus_
00505 && event.key.keysym.sym == SDLK_F1) {
00506
00507 mouse_focus_->help_key(*this);
00508 return;
00509 }
00510
00511 bool handled = false;
00512 if(keyboard_focus_) {
00513 keyboard_focus_->key_press(*this, handled, event.key.keysym.sym, event.key.keysym.mod, event.key.keysym.unicode);
00514 }
00515
00516 if(!handled) {
00517 get_window().key_press(*this, handled, event.key.keysym.sym, event.key.keysym.mod, event.key.keysym.unicode);
00518 }
00519 }
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726 }
00727