Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
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
35 Base-class and default implementation of event-handler for TGLViewer.
36 
37 This allows for complete disentanglement of GL-viewer from GUI
38 event handling. Further, alternative event-handlers can easily be
39 designed and set at run-time.
40 
41 The signals about object being selected or hovered above are
42 emitted via the TGLViewer itself.
43 
44 The following rootrc settings influence the behaviour:
45 ~~~ {.cpp}
46 OpenGL.EventHandler.ViewerCentricControls: 1
47 OpenGL.EventHandler.ArrowKeyFactor: -1.0
48 OpenGL.EventHandler.MouseDragFactor: -1.0
49 OpenGL.EventHandler.MouseWheelFactor: -1.0
50 ~~~
51 */
52 
53 ClassImp(TGLEventHandler);
54 
55 ////////////////////////////////////////////////////////////////////////////////
56 /// Constructor.
57 
58 TGLEventHandler::TGLEventHandler(TGWindow *w, TObject *obj) :
59  TGEventHandler ("TGLEventHandler", w, obj),
60  fGLViewer ((TGLViewer *)obj),
61  fMouseTimer (0),
62  fLastPos (-1, -1),
63  fLastMouseOverPos (-1, -1),
64  fLastMouseOverShape (0),
65  fTooltip (0),
66  fActiveButtonID (0),
67  fLastEventState (0),
68  fIgnoreButtonUp (kFALSE),
69  fInPointerGrab (kFALSE),
70  fMouseTimerRunning (kFALSE),
71  fTooltipShown (kFALSE),
72  fArcBall (kFALSE),
73  fTooltipPixelTolerance (3),
74  fSecSelType(TGLViewer::kOnRequest),
75  fDoInternalSelection(kTRUE),
76  fViewerCentricControls(kFALSE)
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 
90 TGLEventHandler::~TGLEventHandler()
91 {
92  delete fMouseTimer;
93  delete fTooltip;
94 }
95 
96 ////////////////////////////////////////////////////////////////////////////////
97 /// Acquire mouse grab.
98 
99 void TGLEventHandler::GrabMouse()
100 {
101  if (!fInPointerGrab)
102  {
103  gVirtualX->GrabPointer(fGLViewer->GetGLWidget()->GetId(),
104  kButtonPressMask | kButtonReleaseMask | kPointerMotionMask,
105  kNone, kNone, kTRUE, kFALSE);
106  fInPointerGrab = kTRUE;
107  }
108 }
109 
110 ////////////////////////////////////////////////////////////////////////////////
111 /// Release mouse grab.
112 
113 void TGLEventHandler::UnGrabMouse()
114 {
115  if (fInPointerGrab)
116  {
117  gVirtualX->GrabPointer(0, 0, 0, 0, kFALSE);
118  fInPointerGrab = kFALSE;
119  }
120 }
121 
122 ////////////////////////////////////////////////////////////////////////////////
123 /// Run selection (optionally with on secondary selection) and emit
124 /// corresponding Clicked() signals.
125 /// Protected method.
126 
127 void TGLEventHandler::SelectForClicked(Event_t *event)
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  {
144  case TGLSelectRecord::kEnteringSelection:
145  fGLViewer->Clicked(obj, event->fCode, event->fState);
146  break;
147  case TGLSelectRecord::kLeavingSelection:
148  fGLViewer->UnClicked(obj, event->fCode, event->fState);
149  break;
150  case TGLSelectRecord::kModifyingInternalSelection:
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 
169 void TGLEventHandler::SelectForMouseOver()
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  {
189  case TGLSelectRecord::kEnteringSelection:
190  fGLViewer->MouseOver(obj, fLastEventState);
191  break;
192  case TGLSelectRecord::kModifyingInternalSelection:
193  fGLViewer->ReMouseOver(obj, fLastEventState);
194  break;
195  case TGLSelectRecord::kLeavingSelection:
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;
209  fLastMouseOverPos = fLastPos;
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 
219 void TGLEventHandler::ExecuteEvent(Int_t event, Int_t px, Int_t py)
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 
351 Bool_t TGLEventHandler::HandleEvent(Event_t *event)
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  }
358  StartMouseTimer();
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  }
365  StopMouseTimer();
366  ClearMouseOver();
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 
376 Bool_t TGLEventHandler::HandleFocusChange(Event_t *event)
377 {
378  fGLViewer->MouseIdle(0, 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  }
384  StartMouseTimer();
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  }
392  StopMouseTimer();
393  ClearMouseOver();
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 
403 Bool_t TGLEventHandler::HandleCrossing(Event_t *event)
404 {
405  // Ignore grab and ungrab events.
406  if (event->fCode != 0) {
407  return kTRUE;
408  }
409 
410  fGLViewer->MouseIdle(0, 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  }
416  StartMouseTimer();
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  }
425  StopMouseTimer();
426  ClearMouseOver();
427  }
428 
429  return kTRUE;
430 }
431 
432 ////////////////////////////////////////////////////////////////////////////////
433 /// Handle mouse button 'event'.
434 
435 Bool_t TGLEventHandler::HandleButton(Event_t * event)
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 
456  Int_t zoom = TMath::Nint(fMouseWheelFactor * ControlValue(50));
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(0, 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  TGLVector3 v(event->fX, 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;
526  TGLUtil::PointToViewport(x, y);
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;
542  TGLUtil::PointToViewport(e.fX, e.fY);
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  {
558  fGLViewer->fDragAction = TGLViewer::kDragCameraRotate;
559  if (fMouseTimer)
560  {
561  fMouseTimer->TurnOff();
562  fMouseTimer->Reset();
563  }
564  break;
565  }
566  // MIDDLE mouse button
567  case kButton2:
568  {
569  fGLViewer->fDragAction = TGLViewer::kDragCameraTruck;
570  break;
571  }
572  // RIGHT mouse button
573  case kButton3:
574  {
575  fGLViewer->fDragAction = TGLViewer::kDragCameraDolly;
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  {
597  fIgnoreButtonUp = kFALSE;
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;
611  TGLUtil::PointToViewport(e.fX, e.fY);
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 &&
618  fGLViewer->fDragAction <= TGLViewer::kDragCameraDolly)
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  {
634  if (event->fState & kKeyShiftMask && fDoInternalSelection)
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 
671 Bool_t TGLEventHandler::HandleDoubleClick(Event_t *event)
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(0, 0, 0);
691  if (event->fCode == kButton1)
692  {
693  fGLViewer->DoubleClicked();
694  if (fGLViewer->GetSelected() == 0)
695  fGLViewer->SelectionChanged();
696  }
697  return kTRUE;
698 }
699 
700 ////////////////////////////////////////////////////////////////////////////////
701 /// Handle configure notify 'event' - a window resize/movement.
702 
703 Bool_t TGLEventHandler::HandleConfigureNotify(Event_t *event)
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;
716  TGLUtil::PointToViewport(x, y, w, h);
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 
726 Bool_t TGLEventHandler::HandleExpose(Event_t * event)
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 
745 Bool_t TGLEventHandler::HandleKey(Event_t *event)
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(0, 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;
780  TGLUtil::PointToViewport(e.fX, e.fY);
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:
809  fGLViewer->SetStyle(TGLRnrCtx::kWireFrame);
810  redraw = kTRUE;
811  break;
812  case kKey_T:
813  case kKey_t:
814  fGLViewer->SetStyle(TGLRnrCtx::kOutline);
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();
853  cam.SetExternalCenter(!cam.GetExternalCenter());
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 
889 Bool_t TGLEventHandler::HandleMotion(Event_t * event)
890 {
891  fGLViewer->MouseIdle(0, 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;
901  Short_t lod = TGLRnrCtx::kLODMed;
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 
910  if (fMouseTimerRunning) StopMouseTimer();
911 
912  if (fTooltipShown &&
913  ( TMath::Abs(event->fXRoot - fTooltipPos.fX) > fTooltipPixelTolerance ||
914  TMath::Abs(event->fYRoot - fTooltipPos.fY) > fTooltipPixelTolerance ))
915  {
916  RemoveTooltip();
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;
930  TGLUtil::PointToViewport(e.fX, e.fY);
931  processed = fGLViewer->fCurrentOvlElm->Handle(*fGLViewer->fRnrCtx, fGLViewer->fOvlSelRec, &e);
932  }
933  lod = TGLRnrCtx::kLODHigh;
934  if ( ! processed && ! fMouseTimerRunning)
935  StartMouseTimer();
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;
953  TGLUtil::PointToViewport(e.fX, e.fY);
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 
979 Bool_t TGLEventHandler::Rotate(Int_t xDelta, Int_t yDelta, Bool_t mod1, Bool_t mod2)
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 
989 Bool_t TGLEventHandler::HandleTimer(TTimer *t)
990 {
991  if (t != fMouseTimer) return kFALSE;
992 
993  fMouseTimerRunning = kFALSE;
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  {
1003  if (fLastMouseOverPos != fLastPos)
1004  {
1005  SelectForMouseOver();
1006  }
1007  }
1008  return kTRUE;
1009 }
1010 
1011 ////////////////////////////////////////////////////////////////////////////////
1012 /// Start mouse timer in single-shot mode.
1013 
1014 void TGLEventHandler::StartMouseTimer()
1015 {
1016  fMouseTimer->Start(-1, kTRUE);
1017  fMouseTimerRunning = kTRUE;
1018 }
1019 
1020 ////////////////////////////////////////////////////////////////////////////////
1021 /// Make sure mouse timers are not running.
1022 
1023 void TGLEventHandler::StopMouseTimer()
1024 {
1025  fMouseTimerRunning = kFALSE;
1026  fMouseTimer->Stop();
1027 }
1028 
1029 ////////////////////////////////////////////////////////////////////////////////
1030 /// Clear mouse-over state and emit mouse-over signals.
1031 /// Current overlay element is also told the mouse has left.
1032 
1033 void TGLEventHandler::ClearMouseOver()
1034 {
1035  fLastMouseOverPos.fX = fLastMouseOverPos.fY = -1;
1036  fLastMouseOverShape = 0;
1037  fGLViewer->MouseOver(fLastMouseOverShape);
1038  fGLViewer->MouseOver(fLastMouseOverShape, fLastEventState);
1039  fGLViewer->MouseOver((TObject*)0, fLastEventState);
1040 
1041  fGLViewer->ClearCurrentOvlElm();
1042 }
1043 
1044 ////////////////////////////////////////////////////////////////////////////////
1045 /// Handle window expose 'event' - show.
1046 
1047 void TGLEventHandler::Repaint()
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 
1062 void TGLEventHandler::PopupContextMenu(TGLPhysicalShape* pshp, Event_t * /*event*/,
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 
1089 void TGLEventHandler::TriggerTooltip(const char* text)
1090 {
1091  static UInt_t screenW = 0, screenH = 0;
1092  fTooltipPos = fLastGlobalPos;
1093  fTooltipShown = kTRUE;
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 
1116 void TGLEventHandler::RemoveTooltip()
1117 {
1118  fTooltip->Hide();
1119  fTooltipShown = kFALSE;
1120 }
1121 
1122 ////////////////////////////////////////////////////////////////////////////////
1123 /// Set delay of mouse-over probe (highlight).
1124 
1125 void TGLEventHandler::SetMouseOverSelectDelay(Int_t ms)
1126 {
1127  fMouseTimer->SetTime(ms);
1128 }
1129 
1130 ////////////////////////////////////////////////////////////////////////////////
1131 /// Set delay of tooltip timer.
1132 
1133 void TGLEventHandler::SetMouseOverTooltipDelay(Int_t ms)
1134 {
1135  fTooltip->SetDelay(ms);
1136 }