Belle II Software  release-05-01-25
SplitGLView.cc
1 #include <display/SplitGLView.h>
2 #include <display/EveGeometry.h>
3 #include <display/InfoWidget.h>
4 #include <framework/logging/Logger.h>
5 
6 #include "TEveScene.h"
7 #include "TEveManager.h"
8 #include "TEveBrowser.h"
9 #include "TEveProjectionAxes.h"
10 #include "TEveViewer.h"
11 #include "TEveWindowManager.h"
12 #include "TGMenu.h"
13 #include "TGStatusBar.h"
14 #include "TGTab.h"
15 #include "TGLPhysicalShape.h"
16 #include "TGLLogicalShape.h"
17 #include "TGLWidget.h"
18 
19 #include "TString.h"
20 
21 using namespace Belle2;
22 
23 namespace {
25  bool toggleMenuEntry(TGPopupMenu* menu, int entryid)
26  {
27  if (menu->IsEntryChecked(entryid))
28  menu->UnCheckEntry(entryid);
29  else
30  menu->CheckEntry(entryid);
31  return menu->IsEntryChecked(entryid);
32  }
33 }
34 
36  m_activeViewer(-1),
37  m_infoWidget(nullptr)
38 {
39  const char* projectionName[3] = { "3D", "Rho/Z", "R/Phi" };
40  TGLViewer::ECameraType cameraType[3] = { TGLViewer::kCameraPerspXOZ, TGLViewer::kCameraOrthoXOY, TGLViewer::kCameraOrthoXOY };
41 
42  TEveWindowSlot* slot = TEveWindow::CreateWindowMainFrame();
43  TEveWindowPack* pack = slot->MakePack();
44  pack->SetVertical();
45  pack->SetShowTitleBar(kFALSE);
46 
47  TEveWindowSlot* viewerslots[3];
48  auto pack1 = pack->NewSlot()->MakePack();
49  pack1->SetHorizontal();
50  pack1->SetShowTitleBar(kFALSE);
51  viewerslots[0] = pack1->NewSlotWithWeight(0.7);
52  TEveWindowSlot* infoslot = pack1->NewSlotWithWeight(0.3);
53 
54  auto pack2 = pack->NewSlot()->MakePack();
55  pack2->SetHorizontal();
56  pack2->SetShowTitleBar(kFALSE);
57  viewerslots[1] = pack2->NewSlot();
58  viewerslots[2] = pack2->NewSlot();
59 
60 
61  //0: 3d, 1: rhoz, 2: rphi
62  for (int iFrame = 0; iFrame < 3; iFrame++) {
63  TEveViewer* viewer = new TEveViewer(TString::Format("%s viewer", projectionName[iFrame]));
64  m_glViewer[iFrame] = viewer->SpawnGLEmbeddedViewer();
65  viewerslots[iFrame]->ReplaceWindow(viewer);
66  viewerslots[iFrame] = nullptr; // invalid after ReplaceWindow()
67 
68  viewer->SetShowTitleBar(kFALSE); //might want to show these?
69  m_window[iFrame] = viewer;
70 
71  m_glViewer[iFrame]->SetCurrentCamera(cameraType[iFrame]);
72  //create projection managers
73  TEveProjectionManager* projectionMgr = 0;
74  if (iFrame == 1) {
75  m_rhozManager = new TEveProjectionManager(TEveProjection::kPT_RhoZ);
76  projectionMgr = m_rhozManager;
77  m_glViewer[iFrame]->CurrentCamera().Zoom(+300, false, false);
78  } else if (iFrame == 2) {
79  m_rphiManager = new TEveProjectionManager(TEveProjection::kPT_RPhi);
80  projectionMgr = m_rphiManager;
81  m_glViewer[iFrame]->CurrentCamera().Zoom(-50, false, false);
82  }
83 
84  // connect signals we are interested in
85  m_glViewer[iFrame]->Connect("MouseOver(TGLPhysicalShape*)", "Belle2::SplitGLView", this, "onMouseOver(TGLPhysicalShape*)");
86  m_glViewer[iFrame]->Connect("Clicked(TObject*)", "Belle2::SplitGLView", this, "onClicked(TObject*)");
87  if (iFrame == 0) {
88  viewer->AddScene(gEve->GetGlobalScene());
89  viewer->AddScene(gEve->GetEventScene());
90  }
91  TEveScene* s = 0;
92  if (projectionMgr) {
93  s = gEve->SpawnNewScene(TString::Format("%s projection", projectionName[iFrame]));
94  viewer->AddScene(s);
95  }
96 
97  gEve->GetViewers()->AddElement(viewer);
98  if (projectionMgr) {
99  s->AddElement(projectionMgr);
100  gEve->AddToListTree(projectionMgr, kTRUE);
101  TEveProjectionAxes* axes = new TEveProjectionAxes(projectionMgr);
102  projectionMgr->AddElement(axes);
103  }
104  }
105 
106  m_infoWidget = new InfoWidget(gClient->GetRoot());
107 
108  TEveWindowFrame* eveFrame = new TEveWindowFrame(m_infoWidget, "DataStore Info");
109  infoslot->ReplaceWindow(eveFrame);
110  eveFrame->SetShowTitleBar(kFALSE);
111  infoslot = nullptr; // invalid after ReplaceWindow()
112 
113 
114  // create the "camera" popup menu
115  m_cameraMenu = new TGPopupMenu(gClient->GetDefaultRoot());
116  m_cameraMenu->AddEntry("Perspective (Floor X/Z)", kGLPerspXOZ);
117  m_cameraMenu->AddEntry("Perspective (Floor Y/Z)", kGLPerspYOZ);
118  m_cameraMenu->AddEntry("Perspective (Floor X/Y)", kGLPerspXOY);
119  m_cameraMenu->AddEntry("Orthographic (X/Y)", kGLXOY);
120  m_cameraMenu->AddEntry("Orthographic (X/Z)", kGLXOZ);
121  m_cameraMenu->AddEntry("Orthographic (Z/Y)", kGLZOY);
122  m_cameraMenu->AddSeparator();
123  m_cameraMenu->AddEntry("Orthographic: Allow Rotating", kGLOrthoRotate);
124  m_cameraMenu->AddEntry("Orthographic: Right Click to Dolly", kGLOrthoDolly);
125  m_cameraMenu->AddSeparator();
126  m_cameraMenu->AddEntry("Perspective: Enable Stereographic 3D (Requires Hardware or stereowrap)", kGLStereo);
127 
128  m_sceneMenu = new TGPopupMenu(gClient->GetDefaultRoot());
129  m_sceneMenu->AddEntry("&Update Current", kSceneUpdate);
130  m_sceneMenu->AddEntry("Update &All", kSceneUpdateAll);
131  m_sceneMenu->AddSeparator();
132  m_sceneMenu->AddEntry("&Show Scale for Projections", kShowScale);
133  m_sceneMenu->CheckEntry(kShowScale);
134  m_sceneMenu->AddSeparator();
135  m_sceneMenu->AddEntry("Save &Geometry Extract", kSaveGeometryExtract);
136 
137  TGMenuBar* menuBar = gEve->GetBrowser()->GetMenuBar();
138  menuBar->AddPopup("&Camera", m_cameraMenu, new TGLayoutHints(kLHintsTop | kLHintsLeft, 0, 4, 0, 0));
139  menuBar->AddPopup("&Scene", m_sceneMenu, new TGLayoutHints(kLHintsTop | kLHintsLeft, 0, 4, 0, 0));
140 
141  // connect menu signals to our menu handler slot
142  m_cameraMenu->Connect("Activated(Int_t)", "Belle2::SplitGLView", this, "handleMenu(Int_t)");
143  m_sceneMenu->Connect("Activated(Int_t)", "Belle2::SplitGLView", this, "handleMenu(Int_t)");
144 
145  // use status bar from the browser
146  m_statusBar = gEve->GetBrowser()->GetStatusBar();
147 
148  //needs to come after menu
150 
151  gEve->GetListTree()->Connect("Clicked(TGListTreeItem*, Int_t, Int_t, Int_t)",
152  "Belle2::SplitGLView", this, "itemClicked(TGListTreeItem*, Int_t, Int_t, Int_t)");
153 }
154 
156 {
157  // Clean up main frame...
158  for (int i = 0; i < 3; i++) {
159  delete m_glViewer[i];
160  }
161  delete m_cameraMenu;
162  delete m_sceneMenu;
163  delete m_infoWidget;
164 }
165 
166 void SplitGLView::updateCamera(int cameraAction)
167 {
168  TGLEmbeddedViewer* viewer = getActiveGLViewer();
169  if (!viewer)
170  return;
171 
172  TGLViewer::ECameraType cameraType;
173  switch (cameraAction) {
174  case kGLPerspYOZ:
175  cameraType = TGLViewer::kCameraPerspYOZ;
176  break;
177  case kGLPerspXOZ:
178  cameraType = TGLViewer::kCameraPerspXOZ;
179  break;
180  case kGLPerspXOY:
181  cameraType = TGLViewer::kCameraPerspXOY;
182  break;
183  case kGLXOY:
184  cameraType = TGLViewer::kCameraOrthoXOY;
185  break;
186  case kGLXOZ:
187  cameraType = TGLViewer::kCameraOrthoXOZ;
188  break;
189  case kGLZOY:
190  cameraType = TGLViewer::kCameraOrthoZOY;
191  break;
192  default:
193  B2ERROR("unknown camera action " << cameraAction);
194  return;
195  }
196  viewer->SetCurrentCamera(cameraType);
197 }
198 
199 void SplitGLView::handleMenu(Int_t menuCommand)
200 {
201  // Handle menu items.
202 
203  switch (menuCommand) {
204  case kGLPerspYOZ:
205  case kGLPerspXOZ:
206  case kGLPerspXOY:
207  case kGLXOY:
208  case kGLXOZ:
209  case kGLZOY:
210  updateCamera(menuCommand);
211  break;
212  case kGLOrthoRotate:
214  break;
215  case kGLOrthoDolly:
217  break;
218 
219  case kGLStereo:
220  toggleStereo();
221  break;
222 
223  case kSceneUpdate:
224  if (getActiveGLViewer())
225  getActiveGLViewer()->UpdateScene();
226  break;
227 
228  case kSceneUpdateAll:
229  for (int i = 0; i < 3; i++)
230  m_glViewer[i]->UpdateScene();
231  break;
232 
233  case kShowScale:
234  toggleShowScale();
235  break;
236 
237  case kSaveGeometryExtract:
239  break;
240 
241  default:
242  break;
243  }
244 }
245 
246 void SplitGLView::onClicked(TObject* obj)
247 {
248  // Handle click events in GL viewer
249 
250  if (obj) {
251  m_statusBar->SetText(Form("User clicked on: \"%s\"", obj->GetName()), 1);
252 
253  TEveElement* elem = dynamic_cast<TEveElement*>(obj);
254  if (TEveProjected* projected = dynamic_cast<TEveProjected*>(obj)) {
255  elem = dynamic_cast<TEveElement*>(projected->GetProjectable());
256  }
257  if (!elem)
258  return;
259 
260  TGListTreeItem* eventItem = gEve->GetListTree()->FindItemByPathname("Event");
261  TGListTreeItem* item = gEve->GetListTree()->FindItemByObj(eventItem, elem);
262  if (item) {
263  //focus Eve tab
264  gEve->GetBrowser()->GetTabLeft()->SetTab("Eve");
265 
266  //open all parent nodes
267  TGListTreeItem* parent = item;
268  while ((parent = parent->GetParent()) != nullptr)
269  gEve->GetListTree()->OpenItem(parent);
270 
271  //scroll to clicked item
272  gEve->GetListTree()->AdjustPosition(item);
273  }
274  } else {
275  m_statusBar->SetText("", 1);
276  }
277 
278 
279  // change the active GL viewer to the one who emitted the signal
280  TGLEmbeddedViewer* sender = dynamic_cast<TGLEmbeddedViewer*>(static_cast<TQObject*>(gTQSender));
281 
282  if (!sender) {
283  B2WARNING("onClicked() signal not from a TGLEmbeddedViewer?");
284  return;
285  }
286  setActiveViewer(sender);
287 }
288 
289 TGLEmbeddedViewer* SplitGLView::getActiveGLViewer()
290 {
291  const TEveWindow* currentWindow = gEve->GetWindowManager()->GetCurrentWindow();
292  if (m_activeViewer < 0 or m_window[m_activeViewer] != currentWindow) {
293  //check if some other viewer was selected
294  for (int i = 0; i < 3; i++) {
295  if (m_window[i] == currentWindow) {
296  m_activeViewer = i;
297  }
298  }
299  }
300  if (m_activeViewer < 0)
301  return NULL;
302 
303  return m_glViewer[m_activeViewer];
304 }
305 
306 void SplitGLView::setActiveViewer(TGLEmbeddedViewer* v)
307 {
308  bool found = false;
309  for (int i = 0; i < 3; i++) {
310  if (m_glViewer[i] == v) {
311  m_activeViewer = i;
312  found = true;
313  }
314  }
315  if (!found) {
316  B2WARNING("setActiveViewer(): viewer not found!");
317  m_activeViewer = -1;
318  }
319  if (m_activeViewer >= 0) {
320  //activate corresponding window
321  m_window[m_activeViewer]->MakeCurrent();
322 
323  // update menu entries to match active viewer's options
324  if (getActiveGLViewer()->GetOrthoXOYCamera()->GetDollyToZoom() &&
325  getActiveGLViewer()->GetOrthoXOZCamera()->GetDollyToZoom() &&
326  getActiveGLViewer()->GetOrthoZOYCamera()->GetDollyToZoom())
327  m_cameraMenu->UnCheckEntry(kGLOrthoDolly);
328  else
329  m_cameraMenu->CheckEntry(kGLOrthoDolly);
330 
331  if (getActiveGLViewer()->GetOrthoXOYCamera()->GetEnableRotate() &&
332  getActiveGLViewer()->GetOrthoXOZCamera()->GetEnableRotate() &&
333  getActiveGLViewer()->GetOrthoZOYCamera()->GetEnableRotate())
334  m_cameraMenu->CheckEntry(kGLOrthoRotate);
335  else
336  m_cameraMenu->UnCheckEntry(kGLOrthoRotate);
337 
338  if (getActiveGLViewer()->GetStereo())
339  m_cameraMenu->CheckEntry(kGLStereo);
340  else
341  m_cameraMenu->UnCheckEntry(kGLStereo);
342  }
343 }
344 
345 
346 void SplitGLView::onMouseOver(TGLPhysicalShape* shape)
347 {
348  // Slot used to handle "onMouseOver" signal coming from any GL viewer.
349  // We receive a pointer on the physical shape in which the mouse cursor is.
350 
351  // display informations on the physical shape in the status bar
352  if (shape && shape->GetLogical() && shape->GetLogical()->GetExternal())
353  m_statusBar->SetText(Form("Mouse Over: \"%s\"",
354  shape->GetLogical()->GetExternal()->GetName()), 0);
355  else
356  m_statusBar->SetText("", 0);
357 }
358 
359 
361 {
362  Bool_t state = toggleMenuEntry(m_cameraMenu, kGLOrthoRotate);
363  if (getActiveGLViewer()) {
364  getActiveGLViewer()->GetOrthoXOYCamera()->SetEnableRotate(state);
365  getActiveGLViewer()->GetOrthoXOZCamera()->SetEnableRotate(state);
366  getActiveGLViewer()->GetOrthoZOYCamera()->SetEnableRotate(state);
367  }
368 }
369 
371 {
372  Bool_t state = !toggleMenuEntry(m_cameraMenu, kGLOrthoDolly);
373  if (getActiveGLViewer()) {
374  getActiveGLViewer()->GetOrthoXOYCamera()->SetDollyToZoom(state);
375  getActiveGLViewer()->GetOrthoXOZCamera()->SetDollyToZoom(state);
376  getActiveGLViewer()->GetOrthoZOYCamera()->SetDollyToZoom(state);
377  }
378 }
379 
381 {
382  if (!getActiveGLViewer())
383  return;
384 
385  getActiveGLViewer()->SetStereo(toggleMenuEntry(m_cameraMenu, kGLStereo));
386 }
387 
389 {
390  bool state = toggleMenuEntry(m_sceneMenu, kShowScale);
391 
392  std::vector<TEveProjectionManager*> projections = {m_rhozManager, m_rphiManager};
393  for (auto mgr : projections) {
394  TEveElement::List_ci end_it = mgr->EndChildren();
395  for (TEveElement::List_i it = mgr->BeginChildren(); it != end_it; ++it) {
396  TEveProjectionAxes* a = dynamic_cast<TEveProjectionAxes*>(*it);
397  if (a) {
398  a->SetRnrSelf(state);
399  }
400  }
401  }
402  gEve->Redraw3D(false); //do not reset camera when redrawing
403 }
404 
405 void SplitGLView::itemClicked(TGListTreeItem* item, Int_t, Int_t, Int_t)
406 {
407  // Item has been clicked, based on mouse button do:
408 
409  static const TEveException eh("SplitGLView::itemClicked ");
410  TEveElement* re = static_cast<TEveElement*>(item->GetUserData());
411  if (re == 0) return;
412  TObject* obj = re->GetObject(eh);
413  if (obj->InheritsFrom("TEveViewer")) {
414  TGLViewer* v = static_cast<TEveViewer*>(obj)->GetGLViewer();
415  //v->Activated();
416  if (v->InheritsFrom("TGLEmbeddedViewer")) {
417  TGLEmbeddedViewer* ev = (TGLEmbeddedViewer*)v;
418  gVirtualX->SetInputFocus(ev->GetGLWidget()->GetId());
419  }
420  }
421 }
Belle2::SplitGLView::m_cameraMenu
TGPopupMenu * m_cameraMenu
'Camera' popup menu
Definition: SplitGLView.h:77
Belle2::SplitGLView::m_sceneMenu
TGPopupMenu * m_sceneMenu
'Scene' popup menu
Definition: SplitGLView.h:78
Belle2::SplitGLView::toggleShowScale
void toggleShowScale()
Toggle visibility of axes for projections.
Definition: SplitGLView.cc:388
Belle2::SplitGLView::handleMenu
void handleMenu(Int_t menuCommand)
menu item handler
Definition: SplitGLView.cc:199
Belle2::SplitGLView::SplitGLView
SplitGLView()
constructor.
Definition: SplitGLView.cc:35
Belle2::SplitGLView::m_rhozManager
TEveProjectionManager * m_rhozManager
Rho-Z projection.
Definition: SplitGLView.h:75
Belle2::EveGeometry::saveExtract
void saveExtract()
Save a geometry extract from the current state of the TGeo geometry.
Definition: EveGeometry.cc:194
Belle2::InfoWidget
text-based info viewer showing DataStore contents.
Definition: InfoWidget.h:20
Belle2::SplitGLView::~SplitGLView
virtual ~SplitGLView()
destructor.
Definition: SplitGLView.cc:155
Belle2::SplitGLView::m_infoWidget
InfoWidget * m_infoWidget
text-based info viewer.
Definition: SplitGLView.h:82
Belle2::SplitGLView::onMouseOver
void onMouseOver(TGLPhysicalShape *shape)
show name of shape in status bar.
Definition: SplitGLView.cc:346
Belle2::SplitGLView::m_statusBar
TGStatusBar * m_statusBar
status bar
Definition: SplitGLView.h:79
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::SplitGLView::itemClicked
void itemClicked(TGListTreeItem *item, Int_t btn, Int_t x, Int_t y=43)
handler for clicks inside GL viewer.
Definition: SplitGLView.cc:405
Belle2::SplitGLView::m_rphiManager
TEveProjectionManager * m_rphiManager
R-Phi projection.
Definition: SplitGLView.h:74
Belle2::SplitGLView::toggleStereo
void toggleStereo()
Toggle stereo viewing for perspective viewer.
Definition: SplitGLView.cc:380
Belle2::SplitGLView::onClicked
void onClicked(TObject *obj)
make current viewer active & show name of obj in status bar.
Definition: SplitGLView.cc:246
Belle2::SplitGLView::getActiveGLViewer
TGLEmbeddedViewer * getActiveGLViewer()
return TGLEmbeddedViewer that is active right now.
Definition: SplitGLView.cc:289
Belle2::SplitGLView::updateCamera
void updateCamera(int cameraAction)
change camera type, given one of EMenuCommands.
Definition: SplitGLView.cc:166
Belle2::SplitGLView::toggleOrthoDolly
void toggleOrthoDolly()
Toggle state of the 'Ortho allow dolly' menu entry.
Definition: SplitGLView.cc:370
Belle2::SplitGLView::toggleOrthoRotate
void toggleOrthoRotate()
toggle wether the active viewer may be rotated (not that useful for projections).
Definition: SplitGLView.cc:360
Belle2::SplitGLView::m_window
TEveWindow * m_window[3]
corresponding windows
Definition: SplitGLView.h:72
Belle2::SplitGLView::m_glViewer
TGLEmbeddedViewer * m_glViewer[3]
GL viewers.
Definition: SplitGLView.h:71
Belle2::SplitGLView::setActiveViewer
void setActiveViewer(TGLEmbeddedViewer *v)
set m_activeViewer and update UI accordingly.
Definition: SplitGLView.cc:306
Belle2::SplitGLView::m_activeViewer
int m_activeViewer
selected viewer/window, or -1.
Definition: SplitGLView.h:73