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