Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TGLSAViewer.cxx
Go to the documentation of this file.
1 // @(#)root/gl:$Id$
2 // Author: Timur Pocheptsov / Richard Maunder
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2004, 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 <memory>
13 
14 #include "TRootHelpDialog.h"
15 #include "TPluginManager.h"
16 #include "TApplication.h"
17 #include "TGClient.h"
18 #include "TGCanvas.h"
19 #include "HelpText.h"
20 #include "GuiTypes.h"
21 #include "TG3DLine.h"
22 #include "TSystem.h"
23 #include "TGFrame.h"
24 #include "TGLabel.h"
25 #include "TGMenu.h"
26 #include "TGButton.h"
27 #include "TGSplitter.h"
28 #include "TColor.h"
29 
30 #include "TVirtualPad.h"
31 #include "TGedEditor.h"
32 #include "TRootEmbeddedCanvas.h"
33 #include "TString.h"
34 #include "TGFileDialog.h"
35 
36 #include "TGLOutput.h"
37 #include "TGLFormat.h"
38 
39 #include "TGLLogicalShape.h"
40 #include "TGLPhysicalShape.h"
41 #include "TGLPShapeObj.h"
42 #include "TGLClip.h"
43 #include "TROOT.h"
44 
45 #ifdef WIN32
46 #include "TWin32SplashThread.h"
47 #endif
48 
49 #include "TGLPhysicalShape.h"
50 #include "TGLWidget.h"
51 #include "TGLSAViewer.h"
52 #include "TGLSAFrame.h"
53 #include "TGLOutput.h"
54 #include "TGLEventHandler.h"
55 
56 
57 const char * TGLSAViewer::fgHelpText1 = "\
58 DIRECT SCENE INTERACTIONS\n\n\
59  Press:\n\
60  \tw --- wireframe mode\n\
61  \te --- switch between dark / light color-set\n\
62  \tr --- filled polygons mode\n\
63  \tt --- outline mode\n\
64  \tj --- ZOOM in\n\
65  \tk --- ZOOM out\n\
66  \ta --- switch on/off arc-ball camera rotation control\n\
67  \tArrow Keys --- PAN (TRUCK) across scene\n\
68  \tHome --- reset current camera\n\
69  \tCtrl-Home --- switch external/automatic camera center\n\
70 \n\
71  LEFT mouse button -- ROTATE (ORBIT) the scene by holding the mouse button and moving\n\
72  the mouse (perspective camera, needs to be enabled in menu for orthographic cameras).\n\
73  By default, the scene will be rotated about its center. To select arbitrary center\n\
74  bring up the viewer-editor (e.g., shift-click into empty background) and use\n\
75  'Camera center' controls in the 'Guides' tab.\n\
76 \n\
77  MIDDLE mouse button or arrow keys -- PAN (TRUCK) the camera.\n\
78 \n\
79  RIGHT mouse button action depends on camera type:\n\
80  orthographic -- zoom,\n\
81  perspective -- move camera forwards / backwards\n\
82 \n\
83  By pressing Ctrl and Shift keys the mouse precision can be changed:\n\
84  Shift -- 10 times less precise\n\
85  Ctrl -- 10 times more precise\n\
86  Ctrl Shift -- 100 times more precise\n\
87 \n\
88  Mouse wheel action depends on camera type:\n\
89  orthographic -- zoom,\n\
90  perspective -- change field-of-view (focal length)\n\
91 \n\
92  To invert direction of mouse and key actions from scene-centric\n\
93  to viewer-centric, set in your .rootrc file:\n\
94  OpenGL.EventHandler.ViewerCentricControls: 1\n\
95 \n\
96  Double click will show GUI editor of the viewer (if assigned).\n\
97 \n\
98  RESET the camera via the button in viewer-editor or Home key.\n\
99 \n\
100  SELECT a shape with Shift+Left mouse button click.\n\
101 \n\
102  SELECT the viewer with Shift+Left mouse button click on a free space.\n\
103 \n\
104  MOVE a selected shape using Shift+Mid mouse drag.\n\
105 \n\
106  Invoke the CONTEXT menu with Shift+Right mouse click.\n\n"
107  "Secondary selection and direct render object interaction is initiated\n\
108  by Alt+Left mouse click (Mod1, actually). Only few classes support this option.\n\
109  When 'Alt' is taken by window manager, try Alt-Ctrl-Left.\n\
110 \n\
111 CAMERA\n\
112 \n\
113  The \"Camera\" menu is used to select the different projections from \n\
114  the 3D world onto the 2D viewport. There are three perspective cameras:\n\
115 \n\
116  \tPerspective (Floor XOZ)\n\
117  \tPerspective (Floor YOZ)\n\
118  \tPerspective (Floor XOY)\n\
119 \n\
120  In each case the floor plane (defined by two axes) is kept level.\n\
121 \n\
122  There are also four orthographic cameras:\n\
123 \n\
124  \tOrthographic (XOY)\n\
125  \tOrthographic (XOZ)\n\
126  \tOrthographic (ZOY)\n\
127  \tOrthographic (ZOX)\n\
128 \n\
129  In each case the first axis is placed horizontal, the second vertical e.g.\n\
130  XOY means X horizontal, Y vertical.\n\n";
131 
132 const char * TGLSAViewer::fgHelpText2 = "\
133 SHAPES COLOR AND MATERIAL\n\
134 \n\
135  The selected shape's color can be modified in the Shapes-Color tabs.\n\
136  Shape's color is specified by the percentage of red, green, blue light\n\
137  it reflects. A surface can reflect DIFFUSE, AMBIENT and SPECULAR light.\n\
138  A surface can also emit light. The EMISSIVE parameter allows to define it.\n\
139  The surface SHININESS can also be modified.\n\
140 \n\
141 SHAPES GEOMETRY\n\
142 \n\
143  The selected shape's location and geometry can be modified in the Shapes-Geom\n\
144  tabs by entering desired values in respective number entry controls.\n\
145 \n\
146 SCENE CLIPPING\n\
147 \n\
148  In the Scene-Clipping tabs select a 'Clip Type': None, Plane, Box\n\
149 \n\
150  For 'Plane' and 'Box' the lower pane shows the relevant parameters:\n\
151 \n\
152 \tPlane: Equation coefficients of form aX + bY + cZ + d = 0\n\
153 \tBox: Center X/Y/Z and Length X/Y/Z\n\n"
154  "For Box checking the 'Show / Edit' checkbox shows the clip box (in light blue)\n\
155  in viewer. It also attaches the current manipulator to the box - enabling\n\
156  direct editing in viewer.\n\
157 \n\
158 MANIPULATORS\n\
159 \n\
160  A widget attached to the selected object - allowing direct manipulation\n\
161  of the object with respect to its local axes.\n\
162 \n\
163  There are three modes, toggled with keys while manipulator is active, that is,\n\
164  mouse pointer is above it (switches color to yellow):\n\
165  \tMode\t\tWidget Component Style\t\tKey\n\
166  \t----\t\t----------------------\t\t---\n\
167  \tTranslation\tLocal axes with arrows\t\tv\n\
168  \tScale\t\tLocal axes with boxes\t\tx\n\
169  \tRotate\t\tLocal axes rings\t\tc\n\
170 \n\
171  Each widget has three axis components - red (X), green (Y) and blue (Z).\n\
172  The component turns yellow, indicating an active state, when the mouse is moved\n\
173  over it. Left click and drag on the active component to adjust the objects\n\
174  translation, scale or rotation.\n\
175  Some objects do not support all manipulations (e.g. clipping planes cannot be \n\
176  scaled). If a manipulation is not permitted the component it drawn in grey and \n\
177  cannot be selected/dragged.\n";
178 
179 
180 /** \class TGLSAViewer
181 \ingroup opengl
182 The top level standalone GL-viewer - created via plugin manager.
183 */
184 
185 ClassImp(TGLSAViewer);
186 
187 Long_t TGLSAViewer::fgMenuHidingTimeout = 400;
188 
189 const Int_t TGLSAViewer::fgInitX = 0;
190 const Int_t TGLSAViewer::fgInitY = 0;
191 const Int_t TGLSAViewer::fgInitW = 780;
192 const Int_t TGLSAViewer::fgInitH = 670;
193 
194 // A lot of raw pointers/naked new-expressions - good way to discredit C++ (or C++ programmer
195 // ROOT has system to cleanup - I'll try to use it
196 
197 const char *gGLSaveAsTypes[] = {"Encapsulated PostScript", "*.eps",
198  "PDF", "*.pdf",
199  "GIF", "*.gif",
200  "Animated GIF", "*.gif+",
201  "JPEG", "*.jpg",
202  "PNG", "*.png",
203  0, 0};
204 
205 ////////////////////////////////////////////////////////////////////////////////
206 /// Construct a standalone viewer, bound to supplied 'pad'.
207 
208 TGLSAViewer::TGLSAViewer(TVirtualPad *pad, TGLFormat* format) :
209  TGLViewer(pad, fgInitX, fgInitY, fgInitW, fgInitH),
210  fFrame(0),
211  fFormat(format),
212  fFileMenu(0),
213  fFileSaveMenu(0),
214  fCameraMenu(0),
215  fHelpMenu(0),
216  fLeftVerticalFrame(0),
217  fRightVerticalFrame(0),
218  fDirName("."),
219  fTypeIdx(0),
220  fOverwrite(kFALSE),
221  fMenuBar(0),
222  fMenuBut(0),
223  fHideMenuBar(kFALSE),
224  fMenuHidingTimer(0),
225  fMenuHidingShowMenu(kTRUE),
226  fDeleteMenuBar(kFALSE)
227 {
228  fFrame = new TGLSAFrame(*this);
229 
230  CreateMenus();
231  CreateFrames();
232 
233  fFrame->SetWindowName("ROOT's GL viewer");
234  fFrame->SetClassHints("GLViewer", "GLViewer");
235  fFrame->SetMWMHints(kMWMDecorAll, kMWMFuncAll, kMWMInputModeless);
236  fFrame->MapSubwindows();
237  fFrame->HideFrame(fMenuBut);
238 
239  fFrame->Resize(fFrame->GetDefaultSize());
240  fFrame->MoveResize(fgInitX, fgInitY, fgInitW, fgInitH);
241  fFrame->SetWMPosition(fgInitX, fgInitY);
242 
243  // set recursive cleanup, but exclude fGedEditor
244  // destructor of fGedEditor has own way of handling child nodes
245  TObject* fe = fLeftVerticalFrame->GetList()->First();
246  fLeftVerticalFrame->GetList()->Remove(fe);
247  fFrame->SetCleanup(kDeepCleanup);
248  fLeftVerticalFrame->GetList()->AddFirst(fe);
249 
250  Show();
251 }
252 
253 ////////////////////////////////////////////////////////////////////////////////
254 /// Construct an embedded standalone viewer, bound to supplied 'pad'.
255 /// If format is passed, it gets adopted by the viewer as it might
256 /// need to be reused several times when recreating the GL-widget.
257 ///
258 /// Modified version of the previous constructor for embedding the
259 /// viewer into another frame (parent).
260 
261 TGLSAViewer::TGLSAViewer(const TGWindow *parent, TVirtualPad *pad, TGedEditor *ged,
262  TGLFormat* format) :
263  TGLViewer(pad, fgInitX, fgInitY, fgInitW, fgInitH),
264  fFrame(0),
265  fFormat(format),
266  fFileMenu(0),
267  fCameraMenu(0),
268  fHelpMenu(0),
269  fLeftVerticalFrame(0),
270  fRightVerticalFrame(0),
271  fTypeIdx(0),
272  fMenuBar(0),
273  fMenuBut(0),
274  fHideMenuBar(kFALSE),
275  fMenuHidingTimer(0),
276  fMenuHidingShowMenu(kTRUE),
277  fDeleteMenuBar(kFALSE)
278 {
279  fGedEditor = ged;
280  fFrame = new TGLSAFrame(parent, *this);
281 
282  CreateMenus();
283  CreateFrames();
284 
285  fFrame->MapSubwindows();
286  fFrame->HideFrame(fMenuBut);
287  fFrame->Resize(fFrame->GetDefaultSize());
288  fFrame->Resize(fgInitW, fgInitH);
289 
290  // set recursive cleanup, but exclude fGedEditor
291  // destructor of fGedEditor has own way of handling child nodes
292  if (fLeftVerticalFrame)
293  {
294  TObject* fe = fLeftVerticalFrame->GetList()->First();
295  fLeftVerticalFrame->GetList()->Remove(fe);
296  fFrame->SetCleanup(kDeepCleanup);
297  fLeftVerticalFrame->GetList()->AddFirst(fe);
298  }
299 
300  Show();
301 }
302 
303 ////////////////////////////////////////////////////////////////////////////////
304 /// Destroy standalone viewer object.
305 
306 TGLSAViewer::~TGLSAViewer()
307 {
308  fGedEditor->DisconnectFromCanvas();
309 
310  DisableMenuBarHiding();
311 
312  delete fHelpMenu;
313  delete fCameraMenu;
314  delete fFileSaveMenu;
315  delete fFileMenu;
316  if(fDeleteMenuBar) {
317  delete fMenuBar;
318  }
319  delete fFormat;
320  delete fFrame;
321  fGLWidget = 0;
322 }
323 
324 ////////////////////////////////////////////////////////////////////////////////
325 /// Return the main-frame.
326 
327 TGCompositeFrame* TGLSAViewer::GetFrame() const
328 {
329  return fFrame;
330 }
331 
332 ////////////////////////////////////////////////////////////////////////////////
333 /// Create a GLwidget, it is an error if it is already created.
334 /// This is needed for frame-swapping on mac.
335 
336 void TGLSAViewer::CreateGLWidget()
337 {
338  if (fGLWidget) {
339  Error("CreateGLWidget", "Widget already exists.");
340  return;
341  }
342 
343  if (fFormat == 0)
344  fFormat = new TGLFormat;
345 
346  fGLWidget = TGLWidget::Create(*fFormat, fRightVerticalFrame, kTRUE, kTRUE, 0, 10, 10);
347  fGLWidget->SetEventHandler(fEventHandler);
348 
349  fRightVerticalFrame->AddFrame(fGLWidget, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
350  fFrame->Layout();
351 
352  fGLWidget->MapWindow();
353 }
354 
355 ////////////////////////////////////////////////////////////////////////////////
356 /// Destroy the GLwidget, it is an error if it does not exist.
357 /// This is needed for frame-swapping on mac.
358 
359 void TGLSAViewer::DestroyGLWidget()
360 {
361  if (fGLWidget == 0) {
362  Error("DestroyGLWidget", "Widget does not exist.");
363  return;
364  }
365 
366  fGLWidget->UnmapWindow();
367  fGLWidget->SetEventHandler(0);
368 
369  fRightVerticalFrame->RemoveFrame(fGLWidget);
370  fGLWidget->DeleteWindow();
371  fGLWidget = 0;
372 }
373 
374 ////////////////////////////////////////////////////////////////////////////////
375 ///File/Camera/Help menus.
376 
377 void TGLSAViewer::CreateMenus()
378 {
379  fFileMenu = new TGPopupMenu(fFrame->GetClient()->GetDefaultRoot());
380  fFileMenu->AddEntry("&Hide Menus", kGLHideMenus);
381  fFileMenu->AddEntry("&Edit Object", kGLEditObject);
382  fFileMenu->AddSeparator();
383  fFileMenu->AddEntry("&Close Viewer", kGLCloseViewer);
384  fFileMenu->AddSeparator();
385  fFileSaveMenu = new TGPopupMenu(fFrame->GetClient()->GetDefaultRoot());
386  fFileSaveMenu->AddEntry("viewer.&eps", kGLSaveEPS);
387  fFileSaveMenu->AddEntry("viewer.&pdf", kGLSavePDF);
388  fFileSaveMenu->AddEntry("viewer.&gif", kGLSaveGIF);
389  fFileSaveMenu->AddEntry("viewer.g&if+", kGLSaveAnimGIF);
390  fFileSaveMenu->AddEntry("viewer.&jpg", kGLSaveJPG);
391  fFileSaveMenu->AddEntry("viewer.p&ng", kGLSavePNG);
392  fFileMenu->AddPopup("&Save", fFileSaveMenu);
393  fFileMenu->AddEntry("Save &As...", kGLSaveAS);
394  fFileMenu->AddSeparator();
395  fFileMenu->AddEntry("&Quit ROOT", kGLQuitROOT);
396  fFileMenu->Associate(fFrame);
397 
398  fCameraMenu = new TGPopupMenu(fFrame->GetClient()->GetDefaultRoot());
399  fCameraMenu->AddEntry("Perspective (Floor XOZ)", kGLPerspXOZ);
400  fCameraMenu->AddEntry("Perspective (Floor YOZ)", kGLPerspYOZ);
401  fCameraMenu->AddEntry("Perspective (Floor XOY)", kGLPerspXOY);
402  fCameraMenu->AddEntry("Orthographic (XOY)", kGLXOY);
403  fCameraMenu->AddEntry("Orthographic (XOZ)", kGLXOZ);
404  fCameraMenu->AddEntry("Orthographic (ZOY)", kGLZOY);
405  fCameraMenu->AddEntry("Orthographic (ZOX)", kGLZOX);
406  fCameraMenu->AddEntry("Orthographic (XnOY)", kGLXnOY);
407  fCameraMenu->AddEntry("Orthographic (XnOZ)", kGLXnOZ);
408  fCameraMenu->AddEntry("Orthographic (ZnOY)", kGLZnOY);
409  fCameraMenu->AddEntry("Orthographic (ZnOX)", kGLZnOX);
410  fCameraMenu->AddSeparator();
411  fCameraMenu->AddEntry("Ortho allow rotate", kGLOrthoRotate);
412  fCameraMenu->AddEntry("Ortho allow dolly", kGLOrthoDolly);
413  fCameraMenu->Associate(fFrame);
414 
415  fHelpMenu = new TGPopupMenu(fFrame->GetClient()->GetDefaultRoot());
416  fHelpMenu->AddEntry("Help on GL Viewer...", kGLHelpViewer);
417  fHelpMenu->AddSeparator();
418  fHelpMenu->AddEntry("&About ROOT...", kGLHelpAbout);
419  fHelpMenu->Associate(fFrame);
420 
421  // Create menubar
422  fMenuBar = new TGMenuBar(fFrame);
423  fMenuBar->AddPopup("&File", fFileMenu, new TGLayoutHints(kLHintsTop | kLHintsLeft, 0, 4, 0, 0));
424  fMenuBar->AddPopup("&Camera", fCameraMenu, new TGLayoutHints(kLHintsTop | kLHintsLeft, 0, 4, 0, 0));
425  fMenuBar->AddPopup("&Help", fHelpMenu, new TGLayoutHints(kLHintsTop | kLHintsRight));
426  fFrame->AddFrame(fMenuBar, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX, 0, 0, 1, 1));
427  gVirtualX->SelectInput(fMenuBar->GetId(),
428  kKeyPressMask | kExposureMask | kPointerMotionMask
429  | kStructureNotifyMask | kFocusChangeMask
430  | kEnterWindowMask | kLeaveWindowMask);
431 
432  fMenuBut = new TGButton(fFrame);
433  fMenuBut->ChangeOptions(kRaisedFrame | kFixedHeight);
434  fMenuBut->Resize(20, 4);
435  fMenuBut->SetBackgroundColor(0x80A0C0);
436  fFrame->AddFrame(fMenuBut, new TGLayoutHints(kLHintsNormal | kLHintsExpandX, 0, 0, 1, 1));
437 }
438 
439 ////////////////////////////////////////////////////////////////////////////////
440 /// Internal frames creation.
441 
442 void TGLSAViewer::CreateFrames()
443 {
444  TGCompositeFrame* compositeFrame = fFrame;
445  if (fGedEditor == 0)
446  {
447  compositeFrame = new TGCompositeFrame(fFrame, 100, 100, kHorizontalFrame | kRaisedFrame);
448  fFrame->AddFrame(compositeFrame, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY));
449 
450  fLeftVerticalFrame = new TGVerticalFrame(compositeFrame, 195, 10, kFixedWidth);
451  compositeFrame->AddFrame(fLeftVerticalFrame, new TGLayoutHints(kLHintsLeft | kLHintsExpandY, 2, 2, 2, 2));
452 
453  const TGWindow* cw = fFrame->GetClient()->GetRoot();
454  fFrame->GetClient()->SetRoot(fLeftVerticalFrame);
455 
456  fGedEditor = new TGedEditor();
457  fGedEditor->GetTGCanvas()->ChangeOptions(0);
458  fLeftVerticalFrame->RemoveFrame(fGedEditor);
459  fLeftVerticalFrame->AddFrame(fGedEditor, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandX | kLHintsExpandY, 0, 0, 2, 2));
460  fLeftVerticalFrame->GetClient()->SetRoot((TGWindow*)cw);
461  fLeftVerticalFrame->MapSubwindows();
462 
463  TGVSplitter *splitter = new TGVSplitter(compositeFrame);
464  splitter->SetFrame(fLeftVerticalFrame, kTRUE);
465  compositeFrame->AddFrame(splitter, new TGLayoutHints(kLHintsLeft | kLHintsExpandY, 0,1,2,2) );
466  }
467 
468  // SunkenFrame introduces 1-pixel offset - in TGFrame.cxx:163
469  //
470  // TGVerticalFrame *rightVerticalFrame = new TGVerticalFrame(compositeFrame, 10, 10, kSunkenFrame);
471  // compositeFrame->AddFrame(rightVerticalFrame, new TGLayoutHints(kLHintsRight | kLHintsExpandX | kLHintsExpandY,0,2,2,2));
472  fRightVerticalFrame = new TGVerticalFrame(compositeFrame, 10, 10);
473  compositeFrame->AddFrame(fRightVerticalFrame, new TGLayoutHints(kLHintsRight | kLHintsExpandX | kLHintsExpandY));
474 
475  fEventHandler = new TGLEventHandler(0, this);
476  CreateGLWidget();
477 }
478 
479 ////////////////////////////////////////////////////////////////////////////////
480 /// Update GUI components for embedded viewer selection change.
481 /// Override from TGLViewer.
482 
483 void TGLSAViewer::SelectionChanged()
484 {
485  TGLPhysicalShape *selected = const_cast<TGLPhysicalShape*>(GetSelected());
486 
487  if (selected) {
488  fPShapeWrap->fPShape = selected;
489  if (fFileMenu->IsEntryChecked(kGLEditObject))
490  fGedEditor->SetModel(fPad, selected->GetLogical()->GetExternal(), kButton1Down);
491  else
492  fGedEditor->SetModel(fPad, fPShapeWrap, kButton1Down);
493  } else {
494  fPShapeWrap->fPShape = 0;
495  fGedEditor->SetModel(fPad, this, kButton1Down);
496  }
497 }
498 
499 ////////////////////////////////////////////////////////////////////////////////
500 /// Show the viewer
501 
502 void TGLSAViewer::Show()
503 {
504  fFrame->MapRaised();
505  fGedEditor->SetModel(fPad, this, kButton1Down);
506  RequestDraw();
507 }
508 
509 ////////////////////////////////////////////////////////////////////////////////
510 /// Close the viewer - destructed.
511 
512 void TGLSAViewer::Close()
513 {
514  // Commit suicide when contained GUI is closed.
515  delete this;
516 }
517 
518 ////////////////////////////////////////////////////////////////////////////////
519 /// Delete the menu bar.
520 
521 void TGLSAViewer::DeleteMenuBar()
522 {
523  fDeleteMenuBar=kTRUE;
524 }
525 
526 ////////////////////////////////////////////////////////////////////////////////
527 /// Deactivate menu entries for closing the GL window and exiting ROOT.
528 
529 void TGLSAViewer::DisableCloseMenuEntries()
530 {
531  fFileMenu->DeleteEntry(kGLCloseViewer);
532  fFileMenu->DeleteEntry(kGLQuitROOT);
533 }
534 
535 ////////////////////////////////////////////////////////////////////////////////
536 /// Enable hiding of menu bar.
537 
538 void TGLSAViewer::EnableMenuBarHiding()
539 {
540  if (fHideMenuBar)
541  return;
542 
543  fHideMenuBar = kTRUE;
544 
545  fMenuBar->Connect("ProcessedEvent(Event_t*)", "TGLSAViewer", this, "HandleMenuBarHiding(Event_t*)");
546  fMenuBut->Connect("ProcessedEvent(Event_t*)", "TGLSAViewer", this, "HandleMenuBarHiding(Event_t*)");
547 
548  fFrame->HideFrame(fMenuBar);
549  fFrame->ShowFrame(fMenuBut);
550  fFrame->Layout();
551 
552  fMenuHidingTimer = new TTimer;
553  fMenuHidingTimer->Connect("Timeout()", "TGLSAViewer", this, "MenuHidingTimeout()");
554 
555  fFileMenu->CheckEntry(kGLHideMenus);
556 }
557 
558 ////////////////////////////////////////////////////////////////////////////////
559 /// Disable hiding of menu bar.
560 
561 void TGLSAViewer::DisableMenuBarHiding()
562 {
563  if (!fHideMenuBar)
564  return;
565 
566  fHideMenuBar = kFALSE;
567 
568  fMenuBar->Disconnect("ProcessedEvent(Event_t*)", this, "HandleMenuBarHiding(Event_t*)");
569  fMenuBut->Disconnect("ProcessedEvent(Event_t*)", this, "HandleMenuBarHiding(Event_t*)");
570 
571  fFrame->ShowFrame(fMenuBar);
572  fFrame->HideFrame(fMenuBut);
573  fFrame->Layout();
574 
575  fMenuHidingTimer->TurnOff();
576  delete fMenuHidingTimer;
577  fMenuHidingTimer = 0;
578 
579  fFileMenu->UnCheckEntry(kGLHideMenus);
580 }
581 
582 ////////////////////////////////////////////////////////////////////////////////
583 /// Maybe switch menu-bar / menu-button.
584 
585 void TGLSAViewer::HandleMenuBarHiding(Event_t* ev)
586 {
587  TGFrame *f = (TGFrame*) gTQSender;
588 
589  if (f == fMenuBut)
590  {
591  if (ev->fType == kEnterNotify)
592  ResetMenuHidingTimer(kTRUE);
593  else
594  fMenuHidingTimer->TurnOff();
595  }
596  else if (f == fMenuBar)
597  {
598  if (ev->fType == kLeaveNotify &&
599  (ev->fX < 0 || ev->fX >= (Int_t) f->GetWidth() ||
600  ev->fY < 0 || ev->fY >= (Int_t) f->GetHeight()))
601  {
602  if (fMenuBar->GetCurrent() == 0)
603  ResetMenuHidingTimer(kFALSE);
604  else
605  fMenuBar->GetCurrent()->Connect("ProcessedEvent(Event_t*)", "TGLSAViewer", this, "HandleMenuBarHiding(Event_t*)");
606  }
607  else
608  {
609  fMenuHidingTimer->TurnOff();
610  }
611  }
612  else
613  {
614  f->Disconnect("ProcessedEvent(Event_t*)", this);
615  ResetMenuHidingTimer(kFALSE);
616  }
617 }
618 
619 ////////////////////////////////////////////////////////////////////////////////
620 /// Reset the timer for menu-bar hiding.
621 
622 void TGLSAViewer::ResetMenuHidingTimer(Bool_t show_menu)
623 {
624  // This happens, mysteriously.
625  if (fMenuHidingTimer == 0)
626  return;
627 
628  fMenuHidingTimer->TurnOff();
629 
630  fMenuHidingShowMenu = show_menu;
631 
632  fMenuHidingTimer->SetTime(fgMenuHidingTimeout);
633  fMenuHidingTimer->Reset();
634  fMenuHidingTimer->TurnOn();
635 }
636 
637 ////////////////////////////////////////////////////////////////////////////////
638 /// Action for menu-hiding timeout.
639 
640 void TGLSAViewer::MenuHidingTimeout()
641 {
642  fMenuHidingTimer->TurnOff();
643  if (fMenuHidingShowMenu) {
644  fFrame->HideFrame(fMenuBut);
645  fFrame->ShowFrame(fMenuBar);
646  } else {
647  fFrame->HideFrame(fMenuBar);
648  fFrame->ShowFrame(fMenuBut);
649  }
650  fFrame->Layout();
651 }
652 
653 ////////////////////////////////////////////////////////////////////////////////
654 /// Set global timeout for menu-hiding in mili-seconds.
655 /// Static function.
656 
657 void TGLSAViewer::SetMenuHidingTimeout(Long_t timeout)
658 {
659  fgMenuHidingTimeout = timeout;
660 }
661 
662 ////////////////////////////////////////////////////////////////////////////////
663 /// Process GUI message capture by the main GUI frame (TGLSAFrame).
664 
665 Bool_t TGLSAViewer::ProcessFrameMessage(Long_t msg, Long_t parm1, Long_t)
666 {
667  switch (GET_MSG(msg)) {
668  case kC_COMMAND:
669  switch (GET_SUBMSG(msg)) {
670  case kCM_BUTTON:
671  case kCM_MENU:
672  switch (parm1) {
673  case kGLHelpAbout: {
674 #ifdef R__UNIX
675  TString rootx = TROOT::GetBinDir() + "/root -a &";
676  gSystem->Exec(rootx);
677 #else
678 #ifdef WIN32
679  new TWin32SplashThread(kTRUE);
680 #else
681  char str[32];
682  snprintf(str,32, "About ROOT %s...", gROOT->GetVersion());
683  hd = new TRootHelpDialog(this, str, 600, 400);
684  hd->SetText(gHelpAbout);
685  hd->Popup();
686 #endif
687 #endif
688  break;
689  }
690  case kGLHelpViewer: {
691  TRootHelpDialog * hd = new TRootHelpDialog(fFrame, "Help on GL Viewer...", 660, 400);
692  hd->AddText(fgHelpText1);
693  hd->AddText(fgHelpText2);
694  hd->Popup();
695  break;
696  }
697  case kGLPerspYOZ:
698  SetCurrentCamera(TGLViewer::kCameraPerspYOZ);
699  break;
700  case kGLPerspXOZ:
701  SetCurrentCamera(TGLViewer::kCameraPerspXOZ);
702  break;
703  case kGLPerspXOY:
704  SetCurrentCamera(TGLViewer::kCameraPerspXOY);
705  break;
706  case kGLXOY:
707  SetCurrentCamera(TGLViewer::kCameraOrthoXOY);
708  break;
709  case kGLXOZ:
710  SetCurrentCamera(TGLViewer::kCameraOrthoXOZ);
711  break;
712  case kGLZOY:
713  SetCurrentCamera(TGLViewer::kCameraOrthoZOY);
714  break;
715  case kGLZOX:
716  SetCurrentCamera(TGLViewer::kCameraOrthoZOX);
717  break;
718  case kGLXnOY:
719  SetCurrentCamera(TGLViewer::kCameraOrthoXnOY);
720  break;
721  case kGLXnOZ:
722  SetCurrentCamera(TGLViewer::kCameraOrthoXnOZ);
723  break;
724  case kGLZnOY:
725  SetCurrentCamera(TGLViewer::kCameraOrthoZnOY);
726  break;
727  case kGLZnOX:
728  SetCurrentCamera(TGLViewer::kCameraOrthoZnOX);
729  break;
730  case kGLOrthoRotate:
731  ToggleOrthoRotate();
732  break;
733  case kGLOrthoDolly:
734  ToggleOrthoDolly();
735  break;
736  case kGLSaveEPS:
737  SavePicture("viewer.eps");
738  break;
739  case kGLSavePDF:
740  SavePicture("viewer.pdf");
741  break;
742  case kGLSaveGIF:
743  SavePicture("viewer.gif");
744  break;
745  case kGLSaveAnimGIF:
746  SavePicture("viewer.gif+");
747  break;
748  case kGLSaveJPG:
749  SavePicture("viewer.jpg");
750  break;
751  case kGLSavePNG:
752  SavePicture("viewer.png");
753  break;
754  case kGLSaveAS:
755  {
756  TGFileInfo fi;
757  fi.fFileTypes = gGLSaveAsTypes;
758  fi.fIniDir = StrDup(fDirName);
759  fi.fFileTypeIdx = fTypeIdx;
760  fi.fOverwrite = fOverwrite;
761  new TGFileDialog(gClient->GetDefaultRoot(), fFrame, kFDSave, &fi);
762  if (!fi.fFilename) return kTRUE;
763  TString ft(fi.fFileTypes[fi.fFileTypeIdx+1]);
764  fDirName = fi.fIniDir;
765  fTypeIdx = fi.fFileTypeIdx;
766  fOverwrite = fi.fOverwrite;
767 
768  TString file = fi.fFilename;
769  Bool_t match = kFALSE;
770  const char** fin = gGLSaveAsTypes; ++fin;
771  while (*fin != 0)
772  {
773  if (file.EndsWith(*fin + 1))
774  {
775  match = kTRUE;
776  break;
777  }
778  fin += 2;
779  }
780  if ( ! match)
781  {
782  file += ft(ft.Index("."), ft.Length());
783  }
784  SavePicture(file);
785  }
786  break;
787  case kGLHideMenus:
788  if (fHideMenuBar)
789  DisableMenuBarHiding();
790  else
791  EnableMenuBarHiding();
792  break;
793  case kGLEditObject:
794  ToggleEditObject();
795  break;
796  case kGLCloseViewer:
797  // Exit needs to be delayed to avoid bad drawable X ids - GUI
798  // will all be changed in future anyway
799  TTimer::SingleShot(50, "TGLSAFrame", fFrame, "SendCloseMessage()");
800  break;
801  case kGLQuitROOT:
802  if (!gApplication->ReturnFromRun())
803  delete this;
804  gApplication->Terminate(0);
805  break;
806  default:
807  break;
808  }
809  default:
810  break;
811  }
812  default:
813  break;
814  }
815 
816  return kTRUE;
817 }
818 
819 ////////////////////////////////////////////////////////////////////////////////
820 /// Toggle state of the 'Edit Object' menu entry.
821 
822 void TGLSAViewer::ToggleEditObject()
823 {
824  if (fFileMenu->IsEntryChecked(kGLEditObject))
825  fFileMenu->UnCheckEntry(kGLEditObject);
826  else
827  fFileMenu->CheckEntry(kGLEditObject);
828  SelectionChanged();
829 }
830 
831 ////////////////////////////////////////////////////////////////////////////////
832 /// Toggle state of the 'Ortho allow rotate' menu entry.
833 
834 void TGLSAViewer::ToggleOrthoRotate()
835 {
836  if (fCameraMenu->IsEntryChecked(kGLOrthoRotate))
837  fCameraMenu->UnCheckEntry(kGLOrthoRotate);
838  else
839  fCameraMenu->CheckEntry(kGLOrthoRotate);
840  Bool_t state = fCameraMenu->IsEntryChecked(kGLOrthoRotate);
841  fOrthoXOYCamera.SetEnableRotate(state);
842  fOrthoXOZCamera.SetEnableRotate(state);
843  fOrthoZOYCamera.SetEnableRotate(state);
844  fOrthoXnOYCamera.SetEnableRotate(state);
845  fOrthoXnOZCamera.SetEnableRotate(state);
846  fOrthoZnOYCamera.SetEnableRotate(state);
847 }
848 
849 ////////////////////////////////////////////////////////////////////////////////
850 /// Toggle state of the 'Ortho allow dolly' menu entry.
851 
852 void TGLSAViewer::ToggleOrthoDolly()
853 {
854  if (fCameraMenu->IsEntryChecked(kGLOrthoDolly))
855  fCameraMenu->UnCheckEntry(kGLOrthoDolly);
856  else
857  fCameraMenu->CheckEntry(kGLOrthoDolly);
858  Bool_t state = ! fCameraMenu->IsEntryChecked(kGLOrthoDolly);
859  fOrthoXOYCamera.SetDollyToZoom(state);
860  fOrthoXOZCamera.SetDollyToZoom(state);
861  fOrthoZOYCamera.SetDollyToZoom(state);
862 }