Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
TGLEventHandler.cxx
Go to the documentation of this file.
1// @(#)root/gl:$Id$
2// Author: Bertrand Bellenot 29/01/2008
3
4/*************************************************************************
5 * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include "TGLEventHandler.h"
13#include "TGEventHandler.h"
14#include "TGLViewer.h"
15#include "TGLWidget.h"
16#include "TGWindow.h"
17#include "TPoint.h"
18#include "TVirtualPad.h" // Remove when pad removed - use signal
19#include "TVirtualX.h"
20#include "TGClient.h"
21#include "TVirtualGL.h"
22#include "TGLOverlay.h"
23#include "TGLLogicalShape.h"
24#include "TGLPhysicalShape.h"
25#include "TContextMenu.h"
26#include "TGToolTip.h"
27#include "KeySymbols.h"
28#include "TGLAnnotation.h"
29#include "TEnv.h"
30#include "TMath.h"
31#include "RConfigure.h"
32
33/** \class TGLEventHandler
34\ingroup opengl
35Base-class and default implementation of event-handler for TGLViewer.
36
37This allows for complete disentanglement of GL-viewer from GUI
38event handling. Further, alternative event-handlers can easily be
39designed and set at run-time.
40
41The signals about object being selected or hovered above are
42emitted via the TGLViewer itself.
43
44The following rootrc settings influence the behaviour:
45~~~ {.cpp}
46OpenGL.EventHandler.ViewerCentricControls: 1
47OpenGL.EventHandler.ArrowKeyFactor: -1.0
48OpenGL.EventHandler.MouseDragFactor: -1.0
49OpenGL.EventHandler.MouseWheelFactor: -1.0
50~~~
51*/
52
53
54////////////////////////////////////////////////////////////////////////////////
55/// Constructor.
56
58 TGEventHandler ("TGLEventHandler", w, obj),
59 fGLViewer ((TGLViewer *)obj),
60 fMouseTimer (nullptr),
61 fLastPos (-1, -1),
62 fLastMouseOverPos (-1, -1),
63 fLastMouseOverShape (nullptr),
64 fTooltip (nullptr),
73 fSecSelType(TGLViewer::kOnRequest),
76{
77 fMouseTimer = new TTimer(this, 80);
78 fTooltip = new TGToolTip(0, 0, "", 650);
79 fTooltip->Hide();
80 fViewerCentricControls = gEnv->GetValue("OpenGL.EventHandler.ViewerCentricControls", 0) != 0;
81 fArrowKeyFactor = gEnv->GetValue("OpenGL.EventHandler.ArrowKeyFactor", 1.0);
82 fMouseDragFactor = gEnv->GetValue("OpenGL.EventHandler.MouseDragFactor", 1.0);
83 fMouseWheelFactor = gEnv->GetValue("OpenGL.EventHandler.MouseWheelFactor", 1.0);
84}
85
86////////////////////////////////////////////////////////////////////////////////
87/// Destructor.
88
94
95////////////////////////////////////////////////////////////////////////////////
96/// Acquire mouse grab.
97
99{
100 if (!fInPointerGrab)
101 {
102 gVirtualX->GrabPointer(fGLViewer->GetGLWidget()->GetId(),
106 }
107}
108
109////////////////////////////////////////////////////////////////////////////////
110/// Release mouse grab.
111
113{
114 if (fInPointerGrab)
115 {
116 gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);
118 }
119}
120
121////////////////////////////////////////////////////////////////////////////////
122/// Run selection (optionally with on secondary selection) and emit
123/// corresponding Clicked() signals.
124/// Protected method.
125
127{
128 fGLViewer->RequestSelect(fLastPos.fX, fLastPos.fY);
129
130 TGLLogicalShape *lshp = fGLViewer->fSelRec.GetLogShape();
131 TObject *obj = fGLViewer->fSelRec.GetObject();
132
133 // secondary selection
134 if (lshp && (event->fState & kKeyMod1Mask || (fSecSelType == TGLViewer::kOnRequest && lshp->AlwaysSecondarySelect())))
135 {
136 fGLViewer->RequestSecondarySelect(fLastPos.fX, fLastPos.fY);
137 fGLViewer->fSecSelRec.SetMultiple(event->fState & kKeyControlMask);
138
139 lshp->ProcessSelection(*fGLViewer->fRnrCtx, fGLViewer->fSecSelRec);
140
141 switch (fGLViewer->fSecSelRec.GetSecSelResult())
142 {
144 fGLViewer->Clicked(obj, event->fCode, event->fState);
145 break;
147 fGLViewer->UnClicked(obj, event->fCode, event->fState);
148 break;
150 fGLViewer->ReClicked(obj, event->fCode, event->fState);
151 break;
152 default:
153 break;
154 }
155 }
156 else
157 {
158 fGLViewer->Clicked(obj);
159 fGLViewer->Clicked(obj, event->fCode, event->fState);
160 }
161}
162
163////////////////////////////////////////////////////////////////////////////////
164/// Run selection (optionally with on secondary selection) and emit
165/// corresponding MouseOver() signals.
166/// Protected method.
167
169{
170 fGLViewer->RequestSelect(fLastPos.fX, fLastPos.fY);
171
172 TGLPhysicalShape *pshp = fGLViewer->fSelRec.GetPhysShape();
173 TGLLogicalShape *lshp = fGLViewer->fSelRec.GetLogShape();
174 TObject *obj = fGLViewer->fSelRec.GetObject();
175
176 if (lshp && (fSecSelType == TGLViewer::kOnRequest && lshp->AlwaysSecondarySelect()))
177 {
178 fGLViewer->RequestSecondarySelect(fLastPos.fX, fLastPos.fY);
179 fGLViewer->fSecSelRec.SetMultiple(kFALSE);
180 fGLViewer->fSecSelRec.SetHighlight(kTRUE);
181
182 lshp->ProcessSelection(*fGLViewer->fRnrCtx, fGLViewer->fSecSelRec);
183
184 fGLViewer->fSecSelRec.SetHighlight(kFALSE);
185
186 switch (fGLViewer->fSecSelRec.GetSecSelResult())
187 {
189 fGLViewer->MouseOver(obj, fLastEventState);
190 break;
192 fGLViewer->ReMouseOver(obj, fLastEventState);
193 break;
195 fGLViewer->UnMouseOver(obj, fLastEventState);
196 break;
197 default:
198 break;
199 }
200 }
201 else if (fLastMouseOverShape != pshp)
202 {
203 fGLViewer->MouseOver(pshp);
204 fGLViewer->MouseOver(pshp, fLastEventState);
205 fGLViewer->MouseOver(obj, fLastEventState);
206 }
207 fLastMouseOverShape = pshp;
209}
210
211//==============================================================================
212
213////////////////////////////////////////////////////////////////////////////////
214/// Process event of type 'event' - one of EEventType types,
215/// occurring at window location px, py
216/// This is provided for use when embedding GL viewer into pad
217
219{
220 /*enum EEventType {
221 kNoEvent = 0,
222 kButton1Down = 1, kButton2Down = 2, kButton3Down = 3, kKeyDown = 4,
223 kButton1Up = 11, kButton2Up = 12, kButton3Up = 13, kKeyUp = 14,
224 kButton1Motion = 21, kButton2Motion = 22, kButton3Motion = 23, kKeyPress = 24,
225 kButton1Locate = 41, kButton2Locate = 42, kButton3Locate = 43,
226 kMouseMotion = 51, kMouseEnter = 52, kMouseLeave = 53,
227 kButton1Double = 61, kButton2Double = 62, kButton3Double = 63
228
229 enum EGEventType {
230 kGKeyPress, kKeyRelease, kButtonPress, kButtonRelease,
231 kMotionNotify, kEnterNotify, kLeaveNotify, kFocusIn, kFocusOut,
232 kExpose, kConfigureNotify, kMapNotify, kUnmapNotify, kDestroyNotify,
233 kClientMessage, kSelectionClear, kSelectionRequest, kSelectionNotify,
234 kColormapNotify, kButtonDoubleClick, kOtherEvent*/
235
236 // Map our event EEventType (base/inc/Buttons.h) back to Event_t (base/inc/GuiTypes.h)
237 // structure, and call appropriate HandleXyzz() function
238 Event_t eventSt = { kOtherEvent, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
239 kFALSE, 0, 0, {0, 0, 0, 0, 0} };
240 eventSt.fX = px;
241 eventSt.fY = py;
242 eventSt.fState = 0;
243 eventSt.fXRoot = eventSt.fYRoot = 0;
244
245 if (event != kKeyPress) {
246 eventSt.fY -= Int_t((1 - gPad->GetHNDC() - gPad->GetYlowNDC()) * gPad->GetWh());
247 eventSt.fX -= Int_t(gPad->GetXlowNDC() * gPad->GetWw());
248 eventSt.fXRoot = eventSt.fX;
249 eventSt.fYRoot = eventSt.fY;
250 }
251
252 switch (event) {
253 case kMouseMotion:
254 eventSt.fCode = kMouseMotion;
255 eventSt.fType = kMotionNotify;
256 HandleMotion(&eventSt);
257 break;
258 case kButton1Down:
259 case kButton1Up:
260 {
261 eventSt.fCode = kButton1;
262 eventSt.fType = event == kButton1Down ? kButtonPress:kButtonRelease;
263 HandleButton(&eventSt);
264 }
265 break;
266 case kButton2Down:
267 case kButton2Up:
268 {
269 eventSt.fCode = kButton2;
270 eventSt.fType = event == kButton2Down ? kButtonPress:kButtonRelease;
271 HandleButton(&eventSt);
272 }
273 break;
274 case kButton3Down:
275 {
276 eventSt.fState = kKeyShiftMask;
277 eventSt.fCode = kButton1;
278 eventSt.fType = kButtonPress;
279 HandleButton(&eventSt);
280 }
281 break;
282 case kButton3Up:
283 {
284 eventSt.fCode = kButton3;
285 eventSt.fType = kButtonRelease;//event == kButton3Down ? kButtonPress:kButtonRelease;
286 HandleButton(&eventSt);
287 }
288 break;
289 case kButton1Double:
290 case kButton2Double:
291 case kButton3Double:
292 {
293 eventSt.fCode = event == kButton1Double ? kButton1 : event == kButton2Double ? kButton2 : kButton3;
294 eventSt.fType = kButtonDoubleClick;
295 HandleDoubleClick(&eventSt);
296 }
297 break;
298 case kButton1Motion:
299 case kButton2Motion:
300 case kButton3Motion:
301 {
302
303 eventSt.fCode = event == kButton1Motion ? kButton1 : event == kButton2Motion ? kButton2 : kButton3;
304 eventSt.fType = kMotionNotify;
305 HandleMotion(&eventSt);
306 }
307 break;
308 case kKeyPress: // We only care about full key 'presses' not individual down/up
309 {
310 eventSt.fType = kGKeyPress;
311 eventSt.fCode = py; // px contains key code - need modifiers from somewhere
312 HandleKey(&eventSt);
313 }
314 break;
315 case 6://trick :)
316 if (fGLViewer->CurrentCamera().Zoom(+50, kFALSE, kFALSE)) { //TODO : val static const somewhere
317 if (fGLViewer->fGLDevice != -1) {
318 gGLManager->MarkForDirectCopy(fGLViewer->fGLDevice, kTRUE);
319 gVirtualX->SetDrawMode(TVirtualX::kCopy);
320 }
321 fGLViewer->RequestDraw();
322 }
323 break;
324 case 5://trick :)
325 if (fGLViewer->CurrentCamera().Zoom(-50, kFALSE, kFALSE)) { //TODO : val static const somewhere
326 if (fGLViewer->fGLDevice != -1) {
327 gGLManager->MarkForDirectCopy(fGLViewer->fGLDevice, kTRUE);
328 gVirtualX->SetDrawMode(TVirtualX::kCopy);
329 }
330 fGLViewer->RequestDraw();
331 }
332 break;
333 case 7://trick :)
334 eventSt.fState = kKeyShiftMask;
335 eventSt.fCode = kButton1;
336 eventSt.fType = kButtonPress;
337 HandleButton(&eventSt);
338 break;
339 default:
340 {
341 // Error("TGLEventHandler::ExecuteEvent", "invalid event type");
342 }
343 }
344}
345
346////////////////////////////////////////////////////////////////////////////////
347/// Handle generic Event_t type 'event' - provided to catch focus changes
348/// and terminate any interaction in viewer.
349
351{
352 if (event->fType == kFocusIn) {
353 if (fGLViewer->fDragAction != TGLViewer::kDragNone) {
354 Error("TGLEventHandler::HandleEvent", "active drag-action at focus-in.");
355 fGLViewer->fDragAction = TGLViewer::kDragNone;
356 }
358 }
359 if (event->fType == kFocusOut) {
360 if (fGLViewer->fDragAction != TGLViewer::kDragNone) {
361 Warning("TGLEventHandler::HandleEvent", "drag-action active at focus-out.");
362 fGLViewer->fDragAction = TGLViewer::kDragNone;
363 }
366 }
367
368 return kTRUE;
369}
370
371////////////////////////////////////////////////////////////////////////////////
372/// Handle generic Event_t type 'event' - provided to catch focus changes
373/// and terminate any interaction in viewer.
374
376{
377 fGLViewer->MouseIdle(nullptr, 0, 0);
378 if (event->fType == kFocusIn) {
379 if (fGLViewer->fDragAction != TGLViewer::kDragNone) {
380 Error("TGLEventHandler::HandleFocusChange", "active drag-action at focus-in.");
381 fGLViewer->fDragAction = TGLViewer::kDragNone;
382 }
384 fGLViewer->Activated();
385 }
386 if (event->fType == kFocusOut) {
387 if (fGLViewer->fDragAction != TGLViewer::kDragNone) {
388 Warning("TGLEventHandler::HandleFocusChange", "drag-action active at focus-out.");
389 fGLViewer->fDragAction = TGLViewer::kDragNone;
390 }
393 }
394
395 return kTRUE;
396}
397
398////////////////////////////////////////////////////////////////////////////////
399/// Handle generic Event_t type 'event' - provided to catch focus changes
400/// and terminate any interaction in viewer.
401
403{
404 // Ignore grab and ungrab events.
405 if (event->fCode != 0) {
406 return kTRUE;
407 }
408
409 fGLViewer->MouseIdle(nullptr, 0, 0);
410 if (event->fType == kEnterNotify) {
411 if (fGLViewer->fDragAction != TGLViewer::kDragNone) {
412 Error("TGLEventHandler::HandleCrossing", "active drag-action at enter-notify.");
413 fGLViewer->fDragAction = TGLViewer::kDragNone;
414 }
416 // Maybe, maybe not...
417 fGLViewer->Activated();
418 }
419 if (event->fType == kLeaveNotify) {
420 if (fGLViewer->fDragAction != TGLViewer::kDragNone) {
421 Warning("TGLEventHandler::HandleCrossing", "drag-action active at leave-notify.");
422 fGLViewer->fDragAction = TGLViewer::kDragNone;
423 }
426 }
427
428 return kTRUE;
429}
430
431////////////////////////////////////////////////////////////////////////////////
432/// Handle mouse button 'event'.
433
435{
436 if (fGLViewer->IsLocked()) {
437 if (gDebug>2) {
438 Info("TGLEventHandler::HandleButton", "ignored - viewer is %s",
439 fGLViewer->LockName(fGLViewer->CurrentLock()));
440 }
441 return kFALSE;
442 }
443
444 // Handle mouse-wheel events first.
445 if (event->fCode > kButton3)
446 {
447 // On Win32 only button release events come for mouse wheel.
448 // Note: Modifiers (ctrl/shift) disabled as fState doesn't seem to
449 // have correct modifier flags with mouse wheel under Windows.
450
451 if (event->fType == kButtonRelease)
452 {
453 Bool_t redraw = kFALSE;
454
456 switch(event->fCode)
457 {
458 case kButton5: // Zoom out (dolly or adjust camera FOV).
459 redraw = fGLViewer->CurrentCamera().Zoom(zoom, kFALSE, kFALSE);
460 break;
461
462 case kButton4: // Zoom in (dolly or adjust camera FOV).
463 redraw = fGLViewer->CurrentCamera().Zoom(-zoom, kFALSE, kFALSE);
464 break;
465
466 case kButton6:
467 case kButton7: // Ignore for now.
468 break;
469 }
470
471 if (redraw)
472 fGLViewer->fRedrawTimer->RequestDraw(10, TGLRnrCtx::kLODMed);
473 }
474 return kTRUE;
475 }
476
477 // Now we know we have Button 1 -> 3.
478 // Allow a single action/button down/up pairing - block others
479 if (fActiveButtonID && event->fCode != fActiveButtonID)
480 {
481 return kTRUE;
482 }
483 else
484 {
485 fActiveButtonID = event->fCode;
486 }
487
488#if defined(R__HAS_COCOA)
489 // On osx/cocoa use cmd modifier for mouse-2 and cmd-alt for mouse-3.
490 if (event->fCode == kButton1 && event->fState & kKeyMod2Mask)
491 {
492 event->fCode = event->fState & kKeyMod1Mask ? kButton3 : kButton2;
493 }
494#endif
495
496 // Button DOWN
497 if (event->fType == kButtonPress)
498 {
499 GrabMouse();
500
501 fGLViewer->MouseIdle(nullptr, 0, 0);
502
503 fButtonPushPos.fX = event->fX;
504 fButtonPushPos.fY = event->fY;
505
506 if (fGLViewer->GetPushAction() != TGLViewer::kPushStd)
507 {
508 fGLViewer->RequestSelect(event->fX, event->fY);
509 if (fGLViewer->fSelRec.GetN() > 0)
510 {
511 auto scaling = TGLUtil::GetScreenScalingFactor();
512 TGLVector3 v(scaling * event->fX, scaling * event->fY, 0.5*fGLViewer->fSelRec.GetMinZ());
513 fGLViewer->CurrentCamera().WindowToViewport(v);
514 v = fGLViewer->CurrentCamera().ViewportToWorld(v);
515 if (fGLViewer->GetPushAction() == TGLViewer::kPushCamCenter)
516 {
517 fGLViewer->CurrentCamera().SetExternalCenter(kTRUE);
518 fGLViewer->CurrentCamera().SetCenterVec(v.X(), v.Y(), v.Z());
519 }
520 else
521 {
522 TGLSelectRecord& rec = fGLViewer->GetSelRec();
523 TObject* obj = rec.GetObject();
524 TGLRect& vp = fGLViewer->CurrentCamera().RefViewport();
525 Int_t x = event->fX, y = event->fY;
527 new TGLAnnotation(fGLViewer, obj->GetTitle(),
528 x * 1.0f/vp.Width(),
529 1 - y * 1.0f/vp.Height(), v);
530 }
531
532 fGLViewer->RequestDraw();
533 }
534 return kTRUE;
535 }
536
537 Bool_t handled = kFALSE;
538
539 if (fGLViewer->fDragAction == TGLViewer::kDragNone && fGLViewer->fCurrentOvlElm)
540 {
541 Event_t e = *event;
543 if (fGLViewer->fCurrentOvlElm->Handle(*fGLViewer->fRnrCtx, fGLViewer->fOvlSelRec, &e))
544 {
545 handled = kTRUE;
546 fGLViewer->fDragAction = TGLViewer::kDragOverlay;
547 fGLViewer->RequestDraw();
548 }
549 }
550
551 if ( ! handled)
552 {
553 switch (event->fCode)
554 {
555 // LEFT mouse button
556 case kButton1:
557 {
559 if (fMouseTimer)
560 {
561 fMouseTimer->TurnOff();
562 fMouseTimer->Reset();
563 }
564 break;
565 }
566 // MIDDLE mouse button
567 case kButton2:
568 {
570 break;
571 }
572 // RIGHT mouse button
573 case kButton3:
574 {
576 break;
577 }
578 }
579 }
580 }
581 // Button UP
582 else if (event->fType == kButtonRelease)
583 {
584 fActiveButtonID = 0;
585
586 if (fInPointerGrab)
587 {
588 UnGrabMouse();
589 }
590 else
591 {
592 Warning("TGLEventHandler::HandleButton", "Unexpected button-release.");
593 }
594
595 if (fIgnoreButtonUp)
596 {
598 return kTRUE;
599 }
600
601 if (fGLViewer->GetPushAction() != TGLViewer::kPushStd)
602 {
603 // This should be 'tool' dependant.
604 fGLViewer->fPushAction = TGLViewer::kPushStd;
605 fGLViewer->RefreshPadEditor(fGLViewer);
606 return kTRUE;
607 }
608 else if (fGLViewer->fDragAction == TGLViewer::kDragOverlay && fGLViewer->fCurrentOvlElm)
609 {
610 Event_t e = *event;
612 fGLViewer->fCurrentOvlElm->Handle(*fGLViewer->fRnrCtx, fGLViewer->fOvlSelRec, &e);
613 fGLViewer->OverlayDragFinished();
614 if (fGLViewer->RequestOverlaySelect(event->fX, event->fY))
615 fGLViewer->RequestDraw();
616 }
617 else if (fGLViewer->fDragAction >= TGLViewer::kDragCameraRotate &&
619 {
620 fGLViewer->RequestDraw(TGLRnrCtx::kLODHigh);
621 }
622
623 fGLViewer->fDragAction = TGLViewer::kDragNone;
624
625 if (fGLViewer->fGLDevice != -1)
626 {
627 gGLManager->MarkForDirectCopy(fGLViewer->fGLDevice, kFALSE);
628 }
629
630 if (event->fX == fButtonPushPos.fX && event->fY == fButtonPushPos.fY)
631 {
632 if (event->fCode == kButton1)
633 {
635 {
636 if (fGLViewer->RequestSelect(event->fX, event->fY))
637 {
638 fGLViewer->ApplySelection();
639 }
640 }
641 else
642 {
643 SelectForClicked(event);
644 }
645 }
646 else if (event->fCode == kButton3)
647 {
648 Int_t x, y;
649 Window_t childdum;
650 gVirtualX->TranslateCoordinates(fGLViewer->fGLWidget->GetId(), gClient->GetDefaultRoot()->GetId(),
651 event->fX, event->fY, x, y, childdum);
652
653 fGLViewer->RequestSelect(event->fX, event->fY);
654
655 PopupContextMenu(fGLViewer->fSelRec.GetPhysShape(), event, x, y);
656 }
657 }
658
659 if (event->fCode == kButton1 && fMouseTimer)
660 {
661 fMouseTimer->TurnOn();
662 }
663 }
664
665 return kTRUE;
666}
667
668////////////////////////////////////////////////////////////////////////////////
669/// Handle mouse double click 'event'.
670
672{
673 if (fGLViewer->IsLocked()) {
674 if (gDebug>3) {
675 Info("TGLEventHandler::HandleDoubleClick", "ignored - viewer is %s",
676 fGLViewer->LockName(fGLViewer->CurrentLock()));
677 }
678 return kFALSE;
679 }
680
681 if (event->fCode > 3)
682 return kTRUE;
683
684 if (fActiveButtonID)
685 return kTRUE;
686
687 fActiveButtonID = event->fCode;
688 GrabMouse();
689
690 fGLViewer->MouseIdle(nullptr, 0, 0);
691 if (event->fCode == kButton1)
692 {
693 fGLViewer->DoubleClicked();
694 if (fGLViewer->GetSelected() == nullptr)
695 fGLViewer->SelectionChanged();
696 }
697 return kTRUE;
698}
699
700////////////////////////////////////////////////////////////////////////////////
701/// Handle configure notify 'event' - a window resize/movement.
702
704{
705 if (fGLViewer->IsLocked())
706 {
707 if (gDebug > 0) {
708 Info("TGLEventHandler::HandleConfigureNotify", "ignored - viewer is %s",
709 fGLViewer->LockName(fGLViewer->CurrentLock()));
710 }
711 return kFALSE;
712 }
713 if (event)
714 {
715 Int_t x = event->fX, y = event->fY, w = event->fWidth, h = event->fHeight;
717 fGLViewer->SetViewport(x, y, w, h);
718 fGLViewer->fRedrawTimer->RequestDraw(10, TGLRnrCtx::kLODMed);
719 }
720 return kTRUE;
721}
722
723////////////////////////////////////////////////////////////////////////////////
724/// Handle window expose 'event' - show.
725
727{
728 if (event->fCount != 0) return kTRUE;
729
730 if (fGLViewer->IsLocked()) {
731 if (gDebug > 0) {
732 Info("TGLViewer::HandleExpose", "ignored - viewer is %s",
733 fGLViewer->LockName(fGLViewer->CurrentLock()));
734 }
735 return kFALSE;
736 }
737
738 fGLViewer->fRedrawTimer->RequestDraw(20, TGLRnrCtx::kLODHigh);
739 return kTRUE;
740}
741
742////////////////////////////////////////////////////////////////////////////////
743/// Handle keyboard 'event'.
744
746{
747 // We only handle key-press events.
748 if (event->fType == kKeyRelease)
749 return kTRUE;
750
751 if (fTooltipShown)
752 fTooltip->Hide();
753
754 fLastEventState = event->fState;
755
756 fGLViewer->MouseIdle(nullptr, 0, 0);
757 if (fGLViewer->IsLocked()) {
758 if (gDebug>3) {
759 Info("TGLEventHandler::HandleKey", "ignored - viewer is %s",
760 fGLViewer->LockName(fGLViewer->CurrentLock()));
761 }
762 return kFALSE;
763 }
764
765 char tmp[10] = {0};
766 UInt_t keysym = 0;
767
768 if (fGLViewer->fGLDevice == -1)
769 gVirtualX->LookupString(event, tmp, sizeof(tmp), keysym);
770 else
771 keysym = event->fCode;
772 fGLViewer->fRnrCtx->SetEventKeySym(keysym);
773
774 Bool_t handled = kFALSE;
775 Bool_t redraw = kFALSE;
776
777 if (fGLViewer->fCurrentOvlElm)
778 {
779 Event_t e = *event;
781 if (fGLViewer->fCurrentOvlElm->Handle(*fGLViewer->fRnrCtx, fGLViewer->fOvlSelRec, &e))
782 {
783 handled = kTRUE;
784 redraw = kTRUE;
785 }
786 }
787
788 if ( ! handled)
789 {
790 const Bool_t mod1 = event->fState & kKeyControlMask;
791 const Bool_t mod2 = event->fState & kKeyShiftMask;
792
793 const Int_t shift = TMath::Nint(fArrowKeyFactor * ControlValue(10));
794
795 switch (keysym)
796 {
797 case kKey_R:
798 case kKey_r:
799 fGLViewer->SetStyle(TGLRnrCtx::kFill);
800 redraw = kTRUE;
801 break;
802 case kKey_E:
803 case kKey_e:
804 fGLViewer->SwitchColorSet();
805 redraw = kTRUE;
806 break;
807 case kKey_W:
808 case kKey_w:
810 redraw = kTRUE;
811 break;
812 case kKey_T:
813 case kKey_t:
815 redraw = kTRUE;
816 break;
817
818 case kKey_F1:
819 fGLViewer->RequestSelect(fLastPos.fX, fLastPos.fY);
820 fGLViewer->MouseIdle(fGLViewer->fSelRec.GetPhysShape(), (UInt_t)fLastPos.fX, (UInt_t)fLastPos.fY);
821 break;
822
823 // Camera
824 case kKey_A:
825 case kKey_a:
826 fArcBall = ! fArcBall;
827 break;
828 case kKey_Plus:
829 case kKey_J:
830 case kKey_j:
831 redraw = fGLViewer->CurrentCamera().Dolly(shift, mod1, mod2);
832 break;
833 case kKey_Minus:
834 case kKey_K:
835 case kKey_k:
836 redraw = fGLViewer->CurrentCamera().Dolly(-shift, mod1, mod2);
837 break;
838 case kKey_Up:
839 redraw = fGLViewer->CurrentCamera().Truck(0, shift, mod1, mod2);
840 break;
841 case kKey_Down:
842 redraw = fGLViewer->CurrentCamera().Truck(0, -shift, mod1, mod2);
843 break;
844 case kKey_Left:
845 redraw = fGLViewer->CurrentCamera().Truck(-shift, 0, mod1, mod2);
846 break;
847 case kKey_Right:
848 redraw = fGLViewer->CurrentCamera().Truck(shift, 0, mod1, mod2);
849 break;
850 case kKey_Home:
851 if (mod1) {
852 TGLCamera &cam = fGLViewer->CurrentCamera();
854 fGLViewer->RefreshPadEditor(fGLViewer);
855 } else {
856 fGLViewer->ResetCurrentCamera();
857 }
858 redraw = kTRUE;
859 break;
860
861 // Toggle debugging mode
862 case kKey_d:
863 fGLViewer->fDebugMode = !fGLViewer->fDebugMode;
864 redraw = kTRUE;
865 Info("OpenGL viewer debug mode : ", fGLViewer->fDebugMode ? "ON" : "OFF");
866 break;
867 // Forced rebuild for debugging mode
868 case kKey_D:
869 if (fGLViewer->fDebugMode) {
870 Info("OpenGL viewer FORCED rebuild", " ");
871 fGLViewer->UpdateScene();
872 }
873 default:;
874 } // switch
875 }
876
877 if (redraw) {
878 if (fGLViewer->fGLDevice != -1)
879 gGLManager->MarkForDirectCopy(fGLViewer->fGLDevice, kTRUE);
880 fGLViewer->RequestDraw();
881 }
882
883 return kTRUE;
884}
885
886////////////////////////////////////////////////////////////////////////////////
887/// Handle mouse motion 'event'.
888
890{
891 fGLViewer->MouseIdle(nullptr, 0, 0);
892 if (fGLViewer->IsLocked()) {
893 if (gDebug>3) {
894 Info("TGLEventHandler::HandleMotion", "ignored - viewer is %s",
895 fGLViewer->LockName(fGLViewer->CurrentLock()));
896 }
897 return kFALSE;
898 }
899
900 Bool_t processed = kFALSE, changed = kFALSE;
902
903 // Camera interface requires GL coords - Y inverted
904 Int_t xDelta = TMath::Nint(fMouseDragFactor * ControlValue(event->fX - fLastPos.fX));
905 Int_t yDelta = TMath::Nint(fMouseDragFactor * ControlValue(event->fY - fLastPos.fY));
906 Bool_t mod1 = event->fState & kKeyControlMask;
907 Bool_t mod2 = event->fState & kKeyShiftMask;
908 TGLUtil::PointToViewport(xDelta, yDelta);
909
911
912 if (fTooltipShown &&
915 {
917 }
918
919 if (fGLViewer->fDragAction == TGLViewer::kDragNone)
920 {
921 if (fGLViewer->fRedrawTimer->IsPending()) {
922 if (gDebug > 2)
923 Info("TGLEventHandler::HandleMotion", "Redraw pending, ignoring.");
924 return kTRUE;
925 }
926 changed = fGLViewer->RequestOverlaySelect(event->fX, event->fY);
927 if (fGLViewer->fCurrentOvlElm)
928 {
929 Event_t e = *event;
931 processed = fGLViewer->fCurrentOvlElm->Handle(*fGLViewer->fRnrCtx, fGLViewer->fOvlSelRec, &e);
932 }
934 if ( ! processed && ! fMouseTimerRunning)
936 }
937 else if (fGLViewer->fDragAction == TGLViewer::kDragCameraRotate)
938 {
939 processed = Rotate(xDelta, yDelta, mod1, mod2);
940 }
941 else if (fGLViewer->fDragAction == TGLViewer::kDragCameraTruck)
942 {
943 processed = fGLViewer->CurrentCamera().Truck(xDelta, -yDelta, mod1, mod2);
944 }
945 else if (fGLViewer->fDragAction == TGLViewer::kDragCameraDolly)
946 {
947 processed = fGLViewer->CurrentCamera().Dolly(yDelta - xDelta, mod1, mod2);
948 }
949 else if (fGLViewer->fDragAction == TGLViewer::kDragOverlay)
950 {
951 if (fGLViewer->fCurrentOvlElm) {
952 Event_t e = *event;
954 processed = fGLViewer->fCurrentOvlElm->Handle(*fGLViewer->fRnrCtx, fGLViewer->fOvlSelRec, &e);
955 }
956 }
957
958 fLastPos.fX = event->fX;
959 fLastPos.fY = event->fY;
960
961 fLastGlobalPos.fX = event->fXRoot;
962 fLastGlobalPos.fY = event->fYRoot;
963
964 if (processed || changed) {
965 if (fGLViewer->fGLDevice != -1) {
966 gGLManager->MarkForDirectCopy(fGLViewer->fGLDevice, kTRUE);
967 gVirtualX->SetDrawMode(TVirtualX::kCopy);
968 }
969
970 fGLViewer->RequestDraw(lod);
971 }
972
973 return processed;
974}
975
976////////////////////////////////////////////////////////////////////////////////
977/// Method to handle action TGLViewer::kDragCameraRotate.
978
980{
981 TGLCamera &cam = fGLViewer->CurrentCamera();
982 if (fArcBall) return cam.RotateArcBall(xDelta, -yDelta, mod1, mod2);
983 else return cam.Rotate (xDelta, -yDelta, mod1, mod2);
984}
985
986////////////////////////////////////////////////////////////////////////////////
987/// If mouse delay timer times out emit signal.
988
990{
991 if (t != fMouseTimer) return kFALSE;
992
994
995 if (fGLViewer->fRedrawTimer->IsPending()) {
996 if (gDebug > 2)
997 Info("TGLEventHandler::HandleTimer", "Redraw pending, ignoring.");
998 return kTRUE;
999 }
1000
1001 if (fGLViewer->fDragAction == TGLViewer::kDragNone)
1002 {
1004 {
1006 }
1007 }
1008 return kTRUE;
1009}
1010
1011////////////////////////////////////////////////////////////////////////////////
1012/// Start mouse timer in single-shot mode.
1013
1019
1020////////////////////////////////////////////////////////////////////////////////
1021/// Make sure mouse timers are not running.
1022
1028
1029////////////////////////////////////////////////////////////////////////////////
1030/// Clear mouse-over state and emit mouse-over signals.
1031/// Current overlay element is also told the mouse has left.
1032
1034{
1036 fLastMouseOverShape = nullptr;
1037 fGLViewer->MouseOver(fLastMouseOverShape);
1039 fGLViewer->MouseOver((TObject*)nullptr, fLastEventState);
1040
1041 fGLViewer->ClearCurrentOvlElm();
1042}
1043
1044////////////////////////////////////////////////////////////////////////////////
1045/// Handle window expose 'event' - show.
1046
1048{
1049 if (fGLViewer->IsLocked()) {
1050 if (gDebug > 0) {
1051 Info("TGLViewer::HandleExpose", "ignored - viewer is %s",
1052 fGLViewer->LockName(fGLViewer->CurrentLock()));
1053 }
1054 return;
1055 }
1056 fGLViewer->fRedrawTimer->RequestDraw(20, TGLRnrCtx::kLODHigh);
1057}
1058
1059////////////////////////////////////////////////////////////////////////////////
1060/// Popup context menu.
1061
1063 Int_t gx, Int_t gy)
1064{
1065 if (!fGLViewer->fContextMenu)
1066 {
1067 fGLViewer->fContextMenu = new TContextMenu("glcm", "GL Viewer Context Menu");
1068 }
1069
1070 if (pshp)
1071 {
1072 fActiveButtonID = 0;
1073 UnGrabMouse();
1074
1075 pshp->InvokeContextMenu(*fGLViewer->fContextMenu, gx, gy);
1076 }
1077
1078 // This is dangerous ... should have special menu, probably even
1079 // tool / context specific.
1080 // else
1081 // {
1082 // fGLViewer->fContextMenu->Popup(x, y, fGLViewer);
1083 // }
1084}
1085
1086////////////////////////////////////////////////////////////////////////////////
1087/// Trigger display of tooltip.
1088
1090{
1091 static UInt_t screenW = 0, screenH = 0;
1094 fTooltip->SetText(text);
1095 Int_t x = fTooltipPos.fX + 16, y = fTooltipPos.fY + 16;
1096 if (screenW == 0 || screenH == 0) {
1097 screenW = gClient->GetDisplayWidth();
1098 screenH = gClient->GetDisplayHeight();
1099 }
1100 if (x + 5 + fTooltip->GetWidth() > screenW) {
1101 x = screenW - fTooltip->GetWidth() - 5;
1102 if (y + 5 + fTooltip->GetHeight() > screenH) {
1103 y -= (25 + fTooltip->GetHeight());
1104 }
1105 }
1106 if (y + 5 + fTooltip->GetHeight() > screenH) {
1107 y = screenH - fTooltip->GetHeight() - 10;
1108 }
1109 fTooltip->SetPosition(x, y);
1110 fTooltip->Reset();
1111}
1112
1113////////////////////////////////////////////////////////////////////////////////
1114/// Hide the tooltip.
1115
1117{
1118 fTooltip->Hide();
1120}
1121
1122////////////////////////////////////////////////////////////////////////////////
1123/// Set delay of mouse-over probe (highlight).
1124
1126{
1127 fMouseTimer->SetTime(ms);
1128}
1129
1130////////////////////////////////////////////////////////////////////////////////
1131/// Set delay of tooltip timer.
1132
1134{
1135 fTooltip->SetDelay(ms);
1136}
@ kMouseMotion
Definition Buttons.h:23
@ kButton3Up
Definition Buttons.h:19
@ kButton2Motion
Definition Buttons.h:20
@ kButton3Motion
Definition Buttons.h:20
@ kButton3Down
Definition Buttons.h:17
@ kButton2Down
Definition Buttons.h:17
@ kKeyPress
Definition Buttons.h:20
@ kButton2Double
Definition Buttons.h:24
@ kButton1Double
Definition Buttons.h:24
@ kButton3Double
Definition Buttons.h:24
@ kButton1Motion
Definition Buttons.h:20
@ kButton1Up
Definition Buttons.h:19
@ kButton2Up
Definition Buttons.h:19
@ kButton1Down
Definition Buttons.h:17
@ kGKeyPress
Definition GuiTypes.h:61
@ kButtonRelease
Definition GuiTypes.h:61
@ kButtonPress
Definition GuiTypes.h:61
@ kButtonDoubleClick
Definition GuiTypes.h:65
@ kFocusOut
Definition GuiTypes.h:62
@ kMotionNotify
Definition GuiTypes.h:62
@ kFocusIn
Definition GuiTypes.h:62
@ kEnterNotify
Definition GuiTypes.h:62
@ kOtherEvent
Definition GuiTypes.h:65
@ kKeyRelease
Definition GuiTypes.h:61
@ kLeaveNotify
Definition GuiTypes.h:62
const Mask_t kButtonPressMask
Definition GuiTypes.h:162
const Mask_t kKeyMod1Mask
typically the Alt key
Definition GuiTypes.h:199
const Mask_t kPointerMotionMask
Definition GuiTypes.h:164
const Mask_t kKeyShiftMask
Definition GuiTypes.h:196
const Handle_t kNone
Definition GuiTypes.h:89
const Mask_t kKeyControlMask
Definition GuiTypes.h:198
const Mask_t kKeyMod2Mask
typically mod on numeric keys
Definition GuiTypes.h:200
const Mask_t kButtonReleaseMask
Definition GuiTypes.h:163
@ kButton4
Definition GuiTypes.h:216
@ kButton7
Definition GuiTypes.h:216
@ kButton2
Definition GuiTypes.h:215
@ kButton5
Definition GuiTypes.h:216
@ kButton3
Definition GuiTypes.h:215
@ kButton1
Definition GuiTypes.h:215
@ kButton6
Definition GuiTypes.h:216
Handle_t Window_t
Window handle.
Definition GuiTypes.h:29
@ kKey_Right
Definition KeySymbols.h:42
@ kKey_J
Definition KeySymbols.h:135
@ kKey_W
Definition KeySymbols.h:148
@ kKey_Down
Definition KeySymbols.h:43
@ kKey_F1
Definition KeySymbols.h:57
@ kKey_Up
Definition KeySymbols.h:41
@ kKey_r
Definition KeySymbols.h:175
@ kKey_j
Definition KeySymbols.h:167
@ kKey_A
Definition KeySymbols.h:126
@ kKey_Left
Definition KeySymbols.h:40
@ kKey_E
Definition KeySymbols.h:130
@ kKey_T
Definition KeySymbols.h:145
@ kKey_D
Definition KeySymbols.h:129
@ kKey_Home
Definition KeySymbols.h:38
@ kKey_e
Definition KeySymbols.h:162
@ kKey_w
Definition KeySymbols.h:180
@ kKey_k
Definition KeySymbols.h:168
@ kKey_Plus
Definition KeySymbols.h:104
@ kKey_t
Definition KeySymbols.h:177
@ kKey_R
Definition KeySymbols.h:143
@ kKey_a
Definition KeySymbols.h:158
@ kKey_Minus
Definition KeySymbols.h:106
@ kKey_d
Definition KeySymbols.h:161
@ kKey_K
Definition KeySymbols.h:136
#define h(i)
Definition RSha256.hxx:106
#define e(i)
Definition RSha256.hxx:103
int Int_t
Signed integer 4 bytes (int).
Definition RtypesCore.h:59
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int).
Definition RtypesCore.h:60
bool Bool_t
Boolean (0=false, 1=true) (bool).
Definition RtypesCore.h:77
short Short_t
Signed Short integer 2 bytes (short).
Definition RtypesCore.h:53
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
externTEnv * gEnv
Definition TEnv.h:170
#define gClient
Definition TGClient.h:157
Int_t gDebug
Definition TROOT.cxx:777
#define gGLManager
Definition TVirtualGL.h:159
#define gPad
#define gVirtualX
Definition TVirtualX.h:375
This class provides an interface to context sensitive popup menus.
TGEventHandler(const TGEventHandler &)=delete
GL-overlay annotation.
Abstract base camera class - concrete classes for orthographic and perspective cameras derive from it...
Definition TGLCamera.h:44
virtual Bool_t Rotate(Int_t xDelta, Int_t yDelta, Bool_t mod1, Bool_t mod2)
Rotate the camera round view volume center established in Setup().
Bool_t GetExternalCenter()
Definition TGLCamera.h:153
void SetExternalCenter(Bool_t x)
Set camera center diffrent than scene center, if enable is kTRUE.
virtual Bool_t RotateArcBall(Int_t xDelta, Int_t yDelta, Bool_t mod1, Bool_t mod2)
Rotate the camera round view volume center established in Setup().
Bool_t HandleDoubleClick(Event_t *event) override
Handle mouse double click 'event'.
virtual void GrabMouse()
Acquire mouse grab.
void SetMouseOverSelectDelay(Int_t ms)
Set delay of mouse-over probe (highlight).
TGLEventHandler(TGWindow *w, TObject *obj)
Constructor.
virtual void SelectForClicked(Event_t *event)
Run selection (optionally with on secondary selection) and emit corresponding Clicked() signals.
TGLViewer * fGLViewer
TGLPhysicalShape * fLastMouseOverShape
virtual void UnGrabMouse()
Release mouse grab.
virtual Bool_t HandleExpose(Event_t *event)
Handle window expose 'event' - show.
virtual void StartMouseTimer()
Start mouse timer in single-shot mode.
virtual void TriggerTooltip(const char *text)
Trigger display of tooltip.
virtual void StopMouseTimer()
Make sure mouse timers are not running.
Bool_t HandleTimer(TTimer *t) override
If mouse delay timer times out emit signal.
virtual void PopupContextMenu(TGLPhysicalShape *pshp, Event_t *event, Int_t gx, Int_t gy)
Popup context menu.
Bool_t HandleFocusChange(Event_t *event) override
Handle generic Event_t type 'event' - provided to catch focus changes and terminate any interaction i...
Bool_t HandleButton(Event_t *event) override
Handle mouse button 'event'.
virtual Bool_t Rotate(Int_t xDelta, Int_t yDelta, Bool_t mod1, Bool_t mod2)
Method to handle action TGLViewer::kDragCameraRotate.
void ExecuteEvent(Int_t event, Int_t px, Int_t py) override
Process event of type 'event' - one of EEventType types, occurring at window location px,...
~TGLEventHandler() override
Destructor.
Bool_t HandleKey(Event_t *event) override
Handle keyboard 'event'.
Bool_t HandleConfigureNotify(Event_t *event) override
Handle configure notify 'event' - a window resize/movement.
Float_t fMouseWheelFactor
Bool_t fViewerCentricControls
Bool_t HandleMotion(Event_t *event) override
Handle mouse motion 'event'.
Bool_t HandleEvent(Event_t *event) override
Handle generic Event_t type 'event' - provided to catch focus changes and terminate any interaction i...
void SetMouseOverTooltipDelay(Int_t ms)
Set delay of tooltip timer.
Bool_t fDoInternalSelection
virtual void ClearMouseOver()
Clear mouse-over state and emit mouse-over signals.
TGToolTip * fTooltip
virtual void SelectForMouseOver()
Run selection (optionally with on secondary selection) and emit corresponding MouseOver() signals.
Bool_t HandleCrossing(Event_t *event) override
Handle generic Event_t type 'event' - provided to catch focus changes and terminate any interaction i...
virtual void RemoveTooltip()
Hide the tooltip.
Int_t ControlValue(Int_t v)
void Repaint() override
Handle window expose 'event' - show.
Abstract logical shape - a GL 'drawable' - base for all shapes - faceset sphere etc.
virtual void ProcessSelection(TGLRnrCtx &rnrCtx, TGLSelectRecord &rec)
Virtual method called-back after a secondary selection hit is recorded (see TGLViewer::HandleButton()...
virtual Bool_t AlwaysSecondarySelect() const
Concrete physical shape - a GL drawable.
void InvokeContextMenu(TContextMenu &menu, UInt_t x, UInt_t y) const
Request creation of context menu on shape, attached to 'menu' at screen position 'x' 'y'.
Viewport (pixel base) 2D rectangle class.
Definition TGLUtil.h:422
Int_t Height() const
Definition TGLUtil.h:452
Int_t Width() const
Definition TGLUtil.h:450
Standard selection record including information about containing scene and details ob out selected ob...
TObject * GetObject() const
static Float_t GetScreenScalingFactor()
Returns scaling factor between screen points and GL viewport pixels.
Definition TGLUtil.cxx:1843
static void PointToViewport(Int_t &x, Int_t &y)
Convert from point/screen coordinates to GL viewport coordinates.
Definition TGLUtil.cxx:1814
3 component (x/y/z) vector class.
Definition TGLUtil.h:248
Base GL viewer object - used by both standalone and embedded (in pad) GL.
Definition TGLViewer.h:55
@ kPushCamCenter
Definition TGLViewer.h:126
@ kDragCameraTruck
Definition TGLViewer.h:128
@ kDragCameraRotate
Definition TGLViewer.h:128
@ kDragCameraDolly
Definition TGLViewer.h:128
A tooltip can be a one or multiple lines help text that is displayed in a window when the mouse curso...
Definition TGToolTip.h:24
ROOT GUI Window base class.
Definition TGWindow.h:23
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1084
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1098
virtual const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:507
TObject()
TObject constructor.
Definition TObject.h:259
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1072
Handles synchronous and a-synchronous timer events.
Definition TTimer.h:51
TText * text
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
Int_t Nint(T x)
Round to nearest integer. Rounds half integers to the nearest even integer.
Definition TMath.h:704
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:122
Event structure.
Definition GuiTypes.h:175
EGEventType fType
of event (see EGEventType)
Definition GuiTypes.h:176
Int_t fY
pointer x, y coordinates in event window
Definition GuiTypes.h:179
Int_t fXRoot
Definition GuiTypes.h:180
Int_t fCount
if non-zero, at least this many more exposes
Definition GuiTypes.h:184
UInt_t fState
key or button mask
Definition GuiTypes.h:182
Int_t fYRoot
coordinates relative to root
Definition GuiTypes.h:180
Int_t fX
Definition GuiTypes.h:179
UInt_t fCode
key or button code
Definition GuiTypes.h:181