Geant4 11.4.0
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4OpenGLQtViewer.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26// G4OpenGLQtViewer : Class to provide Qt specific
27// functionality for OpenGL in GEANT4
28//
29// 27/06/2003 : G.Barrand : implementation (at last !).
30// 30/06/2014 : M.Kelsey : Change QPixmap objects to pointers
31
36#include "G4Text.hh"
37#include "G4UnitsTable.hh"
39#include "G4Threading.hh"
40#include "G4SystemOfUnits.hh"
41
42#include "G4OpenGLQtViewer.hh"
46#include "G4Qt.hh"
47#include "G4UIQt.hh"
48#include "G4UImanager.hh"
49#include "G4UIcommandTree.hh"
50
52
53#include <typeinfo>
54#include <mutex>
55
56#include <qlayout.h>
57#include <qlabel.h>
58#include <qdialog.h>
59#include <qpushbutton.h>
60#include <qprocess.h>
61#include <qmenu.h>
62#include <qimagewriter.h>
63
64#include <qtextedit.h>
65#include <qtreewidget.h>
66#include <qapplication.h>
67#include <qmessagebox.h>
68#include <qfiledialog.h>
69#include <qdatetime.h>
70#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
71 #include <qelapsedtimer.h>
72#endif
73#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))
74 #include "qdesktopwidget.h"
75#endif
76#include <qpainter.h>
77#include <qdialog.h>
78#include <qcolordialog.h>
79#include <qevent.h> //include <qcontextmenuevent.h>
80#include <qobject.h>
81#include <qgroupbox.h>
82#include <qcombobox.h>
83#include <qlineedit.h>
84#include <qscreen.h>
85#include <qmainwindow.h>
86#include <qtablewidget.h>
87#include <qheaderview.h>
88#include <qscrollarea.h>
89#include <qsplitter.h>
90#include <qcheckbox.h>
91#include <qcursor.h>
92#include <qthread.h>
93
94#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
95#include <QGLContext>
96#else
97#include <QOpenGLContext>
98#endif
99
100#ifndef G4GMAKE
101#include "moc_G4OpenGLQtViewer.cpp"
102#endif
103
104//////////////////////////////////////////////////////////////////////////////
106 G4QGLWidgetType* glWidget
107 ,const QString& name
108)
109//////////////////////////////////////////////////////////////////////////////
110//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
111{
112
113 if(fGLWidget) return; //Done.
114
115 fGLWidget = glWidget ;
116
117#if QT_VERSION < 0x060000
118 ResizeWindow(fVP.GetWindowSizeHintX(),fVP.GetWindowSizeHintY());
119#else
120 ResizeWindow(glWidget->devicePixelRatio()*fVP.GetWindowSizeHintX(),glWidget->devicePixelRatio()*fVP.GetWindowSizeHintY());
121#endif
122
123 // FIXME L.Garnier 9/11/09 Has to be check !!!
124 // Qt UI with Qt Vis
125 // Qt UI with X Vis
126 // X UI with Qt Vis
127 // X UI with X Vis
128 // Ne marche pas avec un UIBatch !! (ecran blanc)
129
130 // return false if G4UIQt was not launch
131
133 if (UI == NULL) return;
134
135 if (! static_cast<G4UIQt*> (UI->GetG4UIWindow())) {
136 // NO UI, should be batch mode
137 fBatchMode = true;
138 return;
139 }
140 fUiQt = static_cast<G4UIQt*> (UI->GetG4UIWindow());
141
142 bool isTabbedView = false;
143 if ( fUiQt) {
144 if (!fBatchMode) {
145 G4Qt* interactorManager = G4Qt::getInstance ();
146 if (!interactorManager->IsExternalApp()) {
147 // INIT size
148 fWinSize_x = fVP.GetWindowSizeHintX();
149 fWinSize_y = fVP.GetWindowSizeHintY();
150
151 isTabbedView = fUiQt->AddTabWidget((QWidget*)fGLWidget,name);
152 QObject::connect(fUiQt->GetViewerTabWidget(),
153 SIGNAL(currentChanged(int)),
154 this,
155 SLOT(currentTabActivated(int)));
156
157#if QT_VERSION < 0x060000
158#else
159 createViewerPropertiesWidget();
160#endif
161
162 }
163 createSceneTreeWidget();
164 // activate them
165 }
166 }
167
168 if (!isTabbedView) { // we have to do a dialog
169
170 QWidget *glDialogWidget = getParentWidget();
171 if (glDialogWidget == NULL) {
172 return;
173 }
174 glWidget->setParent(glDialogWidget);
175 QHBoxLayout *mainLayout = new QHBoxLayout();
176
177 mainLayout->setContentsMargins(0,0,0,0);
178 mainLayout->setSpacing(0);
179 mainLayout->addWidget(fGLWidget);
180 if (fGLWidget->inherits("QMainWindow")) {
181 fGLWidget->setWindowTitle( name);
182 }
183 glDialogWidget->setLayout(mainLayout);
184
185
186 //useful for MACOSX, we have to compt the menuBar height
187#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
188 G4int offset = QGuiApplication::primaryScreen()->availableGeometry().height()
189 - QGuiApplication::screenAt(QPoint(20,20))->availableGeometry().height();
190#else
191 G4int offset = QApplication::desktop()->height()
192 - QApplication::desktop()->availableGeometry().height();
193#endif
194
195 G4int YPos= fVP.GetWindowAbsoluteLocationHintY(QGuiApplication::primaryScreen()->availableGeometry().height());
196 if (fVP.GetWindowAbsoluteLocationHintY(QGuiApplication::primaryScreen()->availableGeometry().height())< offset) {
197 YPos = offset;
198 }
199 glDialogWidget->resize(getWinWidth(), getWinHeight());
200 glDialogWidget->move(fVP.GetWindowAbsoluteLocationHintX(QGuiApplication::primaryScreen()->availableGeometry().width()),YPos);
201 glDialogWidget->show();
202 }
203
204 if(!fGLWidget) return;
205
206 if (!fContextMenu)
207 createPopupMenu();
208
209}
210
211
212//////////////////////////////////////////////////////////////////////////////
215)
216 :G4VViewer (scene, -1)
217 ,G4OpenGLViewer (scene)
218 ,fUiQt(NULL)
219 ,fGLWidget(NULL)
221 ,fMouseOnSceneTree(false)
222 ,fContextMenu(0)
223 ,fLastPickPoint(-1,-1)
224 ,fDeltaDepth(0.01)
225 ,fDeltaZoom(0.05)
226 ,fHoldKeyEvent(false)
227 ,fHoldMoveEvent(false)
228 ,fHoldRotateEvent(false)
229 ,fAutoMove(false)
230 ,fEncoderPath("")
231 ,fTempFolderPath("")
232 ,fMovieTempFolderPath("")
233 ,fSaveFileName("")
234 ,fParameterFileName("ppmtompeg_encode_parameter_file.par")
235 ,fMovieParametersDialog(NULL)
236 ,fRecordingStep(WAIT)
237 ,fProcess(NULL)
238 ,fNbMaxFramesPerSec(100)
239 ,fNbMaxAnglePerSec(360)
240 ,fLaunchSpinDelay(100)
241 ,fUISceneTreeWidget(NULL)
242 ,fUIViewerPropertiesWidget(NULL)
243 ,fUIPickInfosWidget(NULL)
244 ,fNoKeyPress(true)
245 ,fAltKeyPress(false)
246 ,fControlKeyPress(false)
247 ,fShiftKeyPress(false)
248 ,fBatchMode(false)
249 ,fCheckSceneTreeComponentSignalLock(false)
250 ,fViewerPropertiesTableWidgetIsInit(false)
251 ,fSceneTreeComponentTreeWidget(NULL)
252 ,fSceneTreeWidget(NULL)
253 ,fPVRootNodeCreate(false)
254 ,fFilterOutput(NULL)
255 ,fNbRotation(0)
256 ,fTimeRotation(0)
257 ,fTouchableVolumes("Touchables")
258 ,fShortcutsDialog(NULL)
259 ,fViewerPropertiesTableWidget(NULL)
260 ,fPickInfosWidget(NULL)
261 ,fPickInfosScrollArea(NULL)
262 ,fTreeWidgetInfosIgnoredCommands(0)
263 ,fSceneTreeDepthSlider(NULL)
264 ,fSceneTreeDepth(1)
265 ,fModelShortNameItem(NULL)
266 ,fMaxPOindexInserted(-1)
267 ,fTreeIconOpen(NULL)
268 ,fTreeIconClosed(NULL)
269 ,fLastExportSliderValue(80)
270 ,fLastHighlightColor(G4Color(0,0,0,0))
271 ,fLastHighlightName(0)
272 ,fIsDeleting(false)
273{
274 // launch Qt if not
275 if (QCoreApplication::instance () == NULL) {
276 fBatchMode = true;
277 }
279
280 fLastPos3 = QPoint(-1,-1);
281 fLastPos2 = QPoint(-1,-1);
282 fLastPos1 = QPoint(-1,-1);
283
284 initMovieParameters();
285
286#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
287 fLastEventTime = new QTime();
288#else
289 fLastEventTime = new QElapsedTimer();
290#endif
291 // Set default path and format
292 fFileSavePath = QDir::currentPath();
293
294 // add available export format
295 QList<QByteArray> formats = QImageWriter::supportedImageFormats ();
296 for (int i = 0; i < formats.size(); ++i) {
297 addExportImageFormat(formats.at(i).data());
298 }
299
300 const char * const icon1[]={
301 /* columns rows colors chars-per-pixel */
302 "20 20 34 1",
303 " c None",
304 ". c #7C7C7C7C7C7C",
305 "X c #7D7D7D7D7D7D",
306 "o c #828282828282",
307 "O c #838383838383",
308 "+ c #848484848484",
309 "@ c #858585858585",
310 "# c #878787878787",
311 "$ c #888888888888",
312 "% c #8B8B8B8B8B8B",
313 "& c #8C8C8C8C8C8C",
314 "* c #8F8F8F8F8F8F",
315 "= c #909090909090",
316 "- c #919191919191",
317 "; c #999999999999",
318 ": c #9D9D9D9D9D9D",
319 "> c #A2A2A2A2A2A2",
320 ", c #A3A3A3A3A3A3",
321 "< c #A5A5A5A5A5A5",
322 "1 c #A6A6A6A6A6A6",
323 "2 c #B3B3B3B3B3B3",
324 "3 c #B6B6B6B6B6B6",
325 "4 c #C2C2C2C2C2C2",
326 "5 c #C6C6C6C6C6C6",
327 "6 c #CACACACACACA",
328 "7 c #CFCFCFCFCFCF",
329 "8 c #D0D0D0D0D0D0",
330 "9 c #D4D4D4D4D4D4",
331 "0 c #D7D7D7D7D7D7",
332 "q c #DEDEDEDEDEDE",
333 "w c #E0E0E0E0E0E0",
334 "e c #E7E7E7E7E7E7",
335 "r c #F4F4F4F4F4F4",
336 "t c #F7F7F7F7F7F7",
337 " ",
338 " ",
339 " ",
340 " ",
341 " ",
342 " ",
343 " =========> ",
344 " 7&X+++Oo<e ",
345 " 2o+@@+-8 ",
346 " w;.#@+3 ",
347 " 4$o@:q ",
348 " r1X%5 ",
349 " 9*,t ",
350 " 60 ",
351 " ",
352 " ",
353 " ",
354 " ",
355 " ",
356 " "
357 };
358 const char * const icon2[]={
359 "20 20 68 1",
360 " c None",
361 ". c #5F5F10102323",
362 "X c #40405F5F1010",
363 "o c #696963632E2E",
364 "O c #101019194C4C",
365 "+ c #101023237070",
366 "@ c #70702D2D6363",
367 "# c #73732D2D6464",
368 "$ c #79792E2E6767",
369 "% c #19194C4C5353",
370 "& c #2D2D63636161",
371 "* c #2E2E61617070",
372 "= c #6F6F6E6E4343",
373 "- c #707065655F5F",
374 "; c #727279795454",
375 ": c #535341417070",
376 "> c #797954547979",
377 ", c #434361617474",
378 "< c #414170707070",
379 "1 c #686869696363",
380 "2 c #6C6C69696363",
381 "3 c #656567676F6F",
382 "4 c #69696F6F6E6E",
383 "5 c #747465656767",
384 "6 c #757562626C6C",
385 "7 c #70706C6C6969",
386 "8 c #616174746565",
387 "9 c #656573736969",
388 "0 c #616174746969",
389 "q c #707075756262",
390 "w c #797970706565",
391 "e c #636361617474",
392 "r c #67676F6F7272",
393 "t c #727261617070",
394 "y c #616170707070",
395 "u c #6F6F72727979",
396 "i c #67676E6ED1D1",
397 "p c #808080808080",
398 "a c #828282828282",
399 "s c #838383838383",
400 "d c #848484848484",
401 "f c #858585858585",
402 "g c #868686868686",
403 "h c #888888888888",
404 "j c #8A8A8A8A8A8A",
405 "k c #8D8D8D8D8D8D",
406 "l c #8F8F8F8F8F8F",
407 "z c #909090909090",
408 "x c #949494949494",
409 "c c #9C9C9C9C9C9C",
410 "v c #9F9F9F9F9F9F",
411 "b c #A2A2A2A2A2A2",
412 "n c #AEAEAEAEAEAE",
413 "m c #B7B7B7B7B7B7",
414 "M c #C7C7C7C7C7C7",
415 "N c #C9C9C9C9C9C9",
416 "B c #D1D1D1D1D1D1",
417 "V c #D4D4D4D4D4D4",
418 "C c #D9D9D9D9D9D9",
419 "Z c #E0E0E0E0E0E0",
420 "A c #E2E2E2E2E2E2",
421 "S c #EEEEEEEEEEEE",
422 "D c #F0F0F0F0F0F0",
423 "F c #F5F5F5F5F5F5",
424 "G c #F6F6F6F6F6F6",
425 "H c #F9F9F9F9F9F9",
426 "J c #FCFCFCFCFCFC",
427 "K c #FDFDFDFDFDFD",
428 " ",
429 " ",
430 " ",
431 " ",
432 " ",
433 " bC ",
434 " zjnD ",
435 " ldjjMK ",
436 " zdhdjcA ",
437 " zddhdddVK ",
438 " zghdalBH ",
439 " zghamSK ",
440 " lubZH ",
441 " xMF ",
442 " G ",
443 " ",
444 " ",
445 " ",
446 " ",
447 " ",
448
449 };
450
451 const char * const search[] = {
452 /* columns rows colors chars-per-pixel */
453 "19 19 8 1",
454 " c #5C5C5C",
455 ". c #7D7D7D",
456 "X c #9B9B9B",
457 "o c #C3C3C3",
458 "O c None",
459 "+ c #000000",
460 "@ c #000000",
461 "# c None",
462 /* pixels */
463 "OOOOOOOOOOOOOOOOOOO",
464 "OOOOOOOOOOOOOOOOOOO",
465 "OOOOOOOo. .oOOOOOO",
466 "OOOOOOX XOOOOO",
467 "OOOOOo XOOX oOOOO",
468 "OOOOO. XOOOOX .OOOO",
469 "OOOOO OOOOOO OOOO",
470 "OOOOO OOOOOO OOOO",
471 "OOOOO. XOOOOo .OOOO",
472 "OOOOOo oOOo oOOOO",
473 "OOOOOOX XOOOO",
474 "OOOOOOOo. . XOOO",
475 "OOOOOOOOOOOOO. XOO",
476 "OOOOOOOOOOOOOO. XOO",
477 "OOOOOOOOOOOOOOOoOOO",
478 "OOOOOOOOOOOOOOOOOOO",
479 "OOOOOOOOOOOOOOOOOOO",
480 "OOOOOOOOOOOOOOOOOOO",
481 "OOOOOOOOOOOOOOOOOOO"
482 };
483
484 fSearchIcon = new QPixmap(search);
485 fTreeIconOpen = new QPixmap(icon1);
486 fTreeIconClosed = new QPixmap(icon2);
487
488}
489
490//////////////////////////////////////////////////////////////////////////////
492)
493//////////////////////////////////////////////////////////////////////////////
494//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
495{
496 fIsDeleting = true;
497
498 // remove scene tree from layout
499 // Delete all the existing buttons in the layout
500 QLayoutItem *wItem;
501 if (fSceneTreeWidget != NULL) {
502 if (fSceneTreeWidget->layout() != NULL) {
503 while ((wItem = fSceneTreeWidget->layout()->takeAt(0)) != 0) {
504 delete wItem->widget();
505 delete wItem;
506 }
507 }
508 }
509
510 // Delete the open/close icons
511 delete fTreeIconOpen;
512 delete fTreeIconClosed;
513
514#if QT_VERSION < 0x060000
515 G4cout <<removeTempFolder().toStdString().c_str() <<G4endl; //G.Barrand: with Qt6, it crashes at exit if the viewer is in a detached dialog window.
516#endif
517
518}
519
521#if QT_VERSION < 0x060000
522 return true;
523#else
524 if(!fGLWidget) return false;
525 auto* qGLW = dynamic_cast<G4QGLWidgetType*>(fGLWidget);
526 if (!qGLW) return false;
527 return qGLW->isValid();
528#endif
529}
530
531//
532// Create a popup menu for the widget. This menu is activated by right-mouse click
533//
534void G4OpenGLQtViewer::createPopupMenu() {
535
536 fContextMenu = new QMenu("All");
537
538 QMenu *mMouseAction = fContextMenu->addMenu("&Mouse actions");
539 fMouseRotateAction = mMouseAction->addAction("Rotate", this, [this](){ this->toggleMouseAction(1); });
540 fMouseMoveAction = mMouseAction->addAction("Move", this, [this](){ this->toggleMouseAction(2); });
541 fMousePickAction = mMouseAction->addAction("Pick", this, [this](){ this->toggleMouseAction(3); });
542 fMouseZoomOutAction = mMouseAction->addAction("Zoom out", this, [this](){ this->toggleMouseAction(4); });
543 fMouseZoomInAction = mMouseAction->addAction("Zoom in", this, [this](){ this->toggleMouseAction(5); });
544 QAction *shortcutsAction = mMouseAction->addAction("Show shortcuts");
545
546 fMouseRotateAction->setCheckable(true);
547 fMouseMoveAction->setCheckable(true);
548 fMousePickAction->setCheckable(true);
549 fMouseZoomOutAction->setCheckable(true);
550 fMouseZoomInAction->setCheckable(true);
551 shortcutsAction->setCheckable(false);
552
553 QObject::connect(shortcutsAction,
554 SIGNAL(triggered(bool)),
555 this,
556 SLOT(showShortcuts()));
557
558 // === Style Menu ===
559 QMenu *mStyle = fContextMenu->addMenu("&Style");
560
561 QMenu *mProjection = mStyle->addMenu("&Projection");
562
563 // no more radioAction, not realy useful and could be confusing to use context menu and icon at the same time
564 fProjectionOrtho = mProjection->addAction("Orthographic", this, [this](){ this->toggleProjection(true); });
565 fProjectionPerspective = mProjection->addAction("Perspective", this, [this](){ this->toggleProjection(false); });
566 // === Drawing Menu ===
567 QMenu *mDrawing = mStyle->addMenu("&Drawing");
568 fDrawingWireframe = mDrawing->addAction("Wireframe", this, [this](){ this->toggleSurfaceAction(1); });
569 fDrawingLineRemoval = mDrawing->addAction("Hidden line removal", this, [this](){ this->toggleSurfaceAction(2); });
570 fDrawingSurfaceRemoval = mDrawing->addAction("Hidden Surface removal", this, [this](){ this->toggleSurfaceAction(3); });
571 fDrawingLineSurfaceRemoval = mDrawing->addAction("Hidden line and surface removal", this, [this](){ this->toggleSurfaceAction(4); });
572
573 fDrawingWireframe->setCheckable(true);
574 fDrawingLineRemoval->setCheckable(true);
575 fDrawingSurfaceRemoval->setCheckable(true);
576 fDrawingLineSurfaceRemoval->setCheckable(true);
577
578 // Background Color
579
580 QAction *backgroundColorChooser ;
581 // === Action Menu ===
582 backgroundColorChooser = mStyle->addAction("Background color");
583 QObject ::connect(backgroundColorChooser,
584 SIGNAL(triggered()),
585 this,
586 SLOT(actionChangeBackgroundColor()));
587
588 // Text Color
589
590 QAction *textColorChooser ;
591 // === Action Menu ===
592 textColorChooser = mStyle->addAction("Text color");
593 QObject ::connect(textColorChooser,
594 SIGNAL(triggered()),
595 this,
596 SLOT(actionChangeTextColor()));
597
598 // Default Color
599
600 QAction *defaultColorChooser ;
601 // === Action Menu ===
602 defaultColorChooser = mStyle->addAction("Default color");
603 QObject ::connect(defaultColorChooser,
604 SIGNAL(triggered()),
605 this,
606 SLOT(actionChangeDefaultColor()));
607
608
609 // === Action Menu ===
610 QMenu *mActions = fContextMenu->addMenu("&Actions");
611 QAction *createEPS = mActions->addAction("Save as ...");
612 QObject ::connect(createEPS,
613 SIGNAL(triggered()),
614 this,
615 SLOT(actionSaveImage()));
616
617 // === Action Menu ===
618 QAction *movieParameters = mActions->addAction("Save as movie...");
619 QObject ::connect(movieParameters,
620 SIGNAL(triggered()),
621 this,
622 SLOT(actionMovieParameters()));
623
624
625
626
627 // === Special Menu ===
628 QMenu *mSpecial = fContextMenu->addMenu("S&pecial");
629 QMenu *mTransparency = mSpecial->addMenu("Transparency");
630 QAction *transparencyOn = mTransparency->addAction("On");
631 QAction *transparencyOff = mTransparency->addAction("Off");
632
633 if (transparency_enabled == false) {
634 createRadioAction(transparencyOn,transparencyOff,SLOT(toggleTransparency(bool)),2);
635 } else if (transparency_enabled == true) {
636 createRadioAction(transparencyOn,transparencyOff,SLOT(toggleTransparency(bool)),1);
637 } else {
638 mSpecial->clear();
639 }
640
641
642 QMenu *mAntialiasing = mSpecial->addMenu("Antialiasing");
643 QAction *antialiasingOn = mAntialiasing->addAction("On");
644 QAction *antialiasingOff = mAntialiasing->addAction("Off");
645
646 if (antialiasing_enabled == false) {
647 createRadioAction(antialiasingOn,antialiasingOff,SLOT(toggleAntialiasing(bool)),2);
648 } else if (antialiasing_enabled == true) {
649 createRadioAction(antialiasingOn,antialiasingOff,SLOT(toggleAntialiasing(bool)),1);
650 } else {
651 mAntialiasing->clear();
652 }
653
654 QMenu *mHaloing = mSpecial->addMenu("Haloing");
655 QAction *haloingOn = mHaloing->addAction("On");
656 QAction *haloingOff = mHaloing->addAction("Off");
657 if (haloing_enabled == false) {
658 createRadioAction(haloingOn,haloingOff,SLOT(toggleHaloing(bool)),2);
659 } else if (haloing_enabled == true) {
660 createRadioAction(haloingOn,haloingOff,SLOT(toggleHaloing(bool)),1);
661 } else {
662 mHaloing->clear();
663 }
664
665 QMenu *mAux = mSpecial->addMenu("Auxiliary edges");
666 QAction *auxOn = mAux->addAction("On");
667 QAction *auxOff = mAux->addAction("Off");
668 if (!fVP.IsAuxEdgeVisible()) {
669 createRadioAction(auxOn,auxOff,SLOT(toggleAux(bool)),2);
670 } else {
671 createRadioAction(auxOn,auxOff,SLOT(toggleAux(bool)),1);
672 }
673
674
675 QMenu *mHiddenMarkers = mSpecial->addMenu("Hidden markers");
676 QAction *hiddenMarkersOn = mHiddenMarkers->addAction("On");
677 QAction *hiddenMarkersOff = mHiddenMarkers->addAction("Off");
678 if (fVP.IsMarkerNotHidden()) {
679 createRadioAction(hiddenMarkersOn,hiddenMarkersOff,SLOT(toggleHiddenMarkers(bool)),2);
680 } else {
681 createRadioAction(hiddenMarkersOn,hiddenMarkersOff,SLOT(toggleHiddenMarkers(bool)),1);
682 }
683
684
685
686 QMenu *mFullScreen = mSpecial->addMenu("&Full screen");
687 fFullScreenOn = mFullScreen->addAction("On");
688 fFullScreenOff = mFullScreen->addAction("Off");
689 createRadioAction(fFullScreenOn,fFullScreenOff,SLOT(toggleFullScreen(bool)),2);
690
691 // INIT All
693}
694
696{
697 if (!fGLWidget) {
698 G4cerr << "Visualization window not defined, please choose one before" << G4endl;
699 } else {
700
701 if (!fContextMenu)
702 createPopupMenu();
703
704 // launch menu
705 if ( fContextMenu ) {
707 fContextMenu->exec( e->globalPos() );
708 // delete fContextMenu;
709 }
710 }
711 e->accept();
712}
713
714
715/**
716 Create a radio button menu. The two menu will be connected. When click on one,
717 eatch state will be invert and callback method will be called.
718 @param action1 first action to connect
719 @param action2 second action to connect
720 @param method callback method
721 @param nCheck: 1 : first action will be set true. 2 : second action will be set true
722*/
723void G4OpenGLQtViewer::createRadioAction(QAction *action1,QAction *action2, const std::string& method,unsigned int nCheck) {
724
725 action1->setCheckable(true);
726 action2->setCheckable(true);
727
728 if (nCheck ==1)
729 action1->setChecked (true);
730 else
731 action2->setChecked (true);
732
733 QObject ::connect(action1, SIGNAL(triggered(bool)),action2, SLOT(toggle()));
734 QObject ::connect(action2, SIGNAL(triggered(bool)),action1, SLOT(toggle()));
735
736 QObject ::connect(action1, SIGNAL(toggled(bool)),this, method.c_str());
737
738}
739
740
741
742/**
743 Show shortcuts for this mouse action
744*/
745void G4OpenGLQtViewer::showShortcuts() {
746 G4String text;
747
748 text = "========= Mouse Shortcuts =========\n";
749 if (fUiQt != NULL) {
750 if (fUiQt->IsIconRotateSelected()) { // rotate
751 text += "Click and move mouse to rotate volume \n";
752 text += "ALT + Click and move mouse to rotate volume (Toggle View/Theta-Phi Direction) \n";
753 text += "CTRL + Click and move mouse to zoom in/out \n";
754 text += "SHIFT + Click and move mouse to change camera point of view \n";
755 } else if (fUiQt->IsIconMoveSelected()) { //move
756 text += "Move camera point of view with mouse \n";
757 } else if (fUiQt->IsIconPickSelected()) { //pick
758 text += "Click and pick \n";
759 }
760 } else {
761 text += "Click and move mouse to rotate volume \n";
762 text += "ALT + Click and move mouse to rotate volume (Toggle View/Theta-Phi Direction) \n";
763 text += "CTRL + Click and zoom mouse to zoom in/out \n";
764 text += "SHIFT + Click and zoommove camera point of view \n";
765 }
766 text += "========= Move Shortcuts ========= \n";
767 text += "Press left/right arrows to move volume left/right \n";
768 text += "Press up/down arrows to move volume up/down \n";
769 text += "Press '+'/'-' to move volume toward/forward \n";
770 text += "\n";
771 text += "========= Rotation (Theta/Phi) Shortcuts ========= \n";
772 text += "Press SHIFT + left/right arrows to rotate volume left/right \n";
773 text += "Press SHIFT + up/down arrows to rotate volume up/down \n";
774 text += "\n";
775 text += "========= Rotation (View Direction) Shortcuts ========= \n";
776 text += "Press ALT + left/right to rotate volume around vertical direction \n";
777 text += "Press ALT + up/down to rotate volume around horizontal direction \n";
778 text += "\n";
779 text += "========= Zoom View ========= \n";
780 text += "Press CTRL + '+'/'-' to zoom into volume \n";
781 text += "\n";
782 text += "========= Misc ========= \n";
783 text += "Press ALT +/- to slow/speed rotation/move \n";
784 text += "Press H to reset view \n";
785 text += "Press Esc to exit FullScreen \n";
786 text += "\n";
787 text += "========= Video ========= \n";
788 text += "In video mode : \n";
789 text += " Press SPACE to Start/Pause video recording \n";
790 text += " Press RETURN to Stop video recording \n";
791 text += "\n";
792
793 G4cout << text;
794
795 if ( fShortcutsDialog == NULL) {
796 fShortcutsDialog = new QDialog();
797 fShortcutsDialogInfos = new QTextEdit() ;
798 QVBoxLayout *mainLayout = new QVBoxLayout;
799 mainLayout->addWidget(fShortcutsDialogInfos);
800 fShortcutsDialog->setLayout(mainLayout);
801 fShortcutsDialog->setWindowTitle(tr("Shortcuts"));
802 }
803
804 fShortcutsDialogInfos->setPlainText(text.data());
805 fShortcutsDialog->show();
806}
807
808
809
810/**
811 Slot activated when mouse action is toggle
812 @param aAction : 1 rotate, 2 move, 3 pick, 4 zoom out, 5 zoom in
813 @see G4OpenGLStoredQtViewer::DrawView
814 @see G4XXXStoredViewer::CompareForKernelVisit
815*/
816void G4OpenGLQtViewer::toggleMouseAction(int aAction) {
817
818 if (aAction == 1) {
819 fUiQt->SetIconRotateSelected();
820 } else if (aAction == 2) {
821 fUiQt->SetIconMoveSelected();
822 } else if (aAction == 3) {
823 togglePicking();
824 } else if (aAction == 4) {
825 fUiQt->SetIconZoomOutSelected();
826 } else if (aAction == 5) {
827 fUiQt->SetIconZoomInSelected();
828 }
829
832}
833
834
835/**
836 Slot activated when drawing menu is toggle
837 Warning : When G4OpenGLStoredQtViewer::DrawView() method call,
838 KernelVisitDecision () will be call and will set the fNeedKernelVisit
839 to 1. See G4XXXStoredViewer::CompareForKernelVisit for explanations.
840 It will cause a redraw of the view
841 @param aAction : 1 wireframe, 2 line removal, 3 surface removal, 4 line & surface removal
842 @see G4OpenGLStoredQtViewer::DrawView
843 @see G4XXXStoredViewer::CompareForKernelVisit
844*/
845void G4OpenGLQtViewer::toggleSurfaceAction(int aAction) {
846
848
849 if (aAction ==1) {
851
852 } else if (aAction ==2) {
853 d_style = G4ViewParameters::hlr;
854
855 } else if (aAction ==3) {
856 d_style = G4ViewParameters::hsr;
857
858 } else if (aAction ==4) {
859 d_style = G4ViewParameters::hlhsr;
860 }
861 fVP.SetDrawingStyle(d_style);
862
865}
866
867
868/**
869 SLOT Activate by a click on the projection menu
870 Warning : When G4OpenGLStoredQtViewer::DrawView() method call,
871 KernelVisitDecision () will be call and will set the fNeedKernelVisit
872 to 1. See G4XXXStoredViewer::CompareForKernelVisit for explanations.
873 It will cause a redraw of the view
874 @param check : 1 orthographic, 2 perspective
875 @see G4OpenGLStoredQtViewer::DrawView
876 @see G4XXXStoredViewer::CompareForKernelVisit
877*/
878void G4OpenGLQtViewer::toggleProjection(bool check) {
879
880 if (check) {
881 fVP.SetOrthogonalProjection ();
882 } else {
883 fVP.SetPerspectiveProjection();
884 }
887}
888
889
890/**
891 SLOT Activate by a click on the transparency menu
892 @param check : 1 , 0
893*/
894void G4OpenGLQtViewer::toggleTransparency(bool check) {
895
896 if (check) {
898 } else {
899 transparency_enabled = false;
900 }
901 SetNeedKernelVisit (true);
904}
905
906/**
907 SLOT Activate by a click on the antialiasing menu
908 @param check : 1 , 0
909*/
910void G4OpenGLQtViewer::toggleAntialiasing(bool check) {
911
912 if (!check) {
913 antialiasing_enabled = false;
914 glDisable (GL_LINE_SMOOTH);
915 glDisable (GL_POLYGON_SMOOTH);
916 } else {
918 glEnable (GL_LINE_SMOOTH);
919 glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
920 glEnable (GL_POLYGON_SMOOTH);
921 glHint (GL_POLYGON_SMOOTH_HINT, GL_NICEST);
922 }
923
926}
927
928/**
929 SLOT Activate by a click on the haloing menu
930 @param check : 1 , 0
931*/
932//FIXME : I SEE NOTHING...
933void G4OpenGLQtViewer::toggleHaloing(bool check) {
934 if (check) {
935 haloing_enabled = false;
936 } else {
937 haloing_enabled = true;
938 }
939
942
943}
944
945/**
946 SLOT Activate by a click on the auxiliaire edges menu
947 @param check : 1 , 0
948*/
949void G4OpenGLQtViewer::toggleAux(bool check) {
950 if (check) {
951 fVP.SetAuxEdgeVisible(true);
952 } else {
953 fVP.SetAuxEdgeVisible(false);
954 }
955 SetNeedKernelVisit (true);
958}
959
960
961void G4OpenGLQtViewer::togglePicking() {
962
963 if (fUiQt) {
964 fUiQt->TogglePickSelection();
965 }
966
967 G4UImanager* UI = G4UImanager::GetUIpointer();
968 if(UI != NULL) {
969 if (!fVP.IsPicking()) {
970 UI->ApplyCommand(std::string("/vis/viewer/set/picking true"));
971 } else {
972 UI->ApplyCommand(std::string("/vis/viewer/set/picking false"));
973 }
974 }
975
976}
977
978
979/**
980 SLOT Activate by a click on the hidden marker menu
981 @param check : 1 , 0
982*/
983void G4OpenGLQtViewer::toggleHiddenMarkers(bool check) {
984 if (check) {
985 fVP.SetMarkerHidden();
986 } else {
987 fVP.SetMarkerNotHidden();
988 }
989 // SetNeedKernelVisit (true);
992}
993
994/**
995 SLOT Activate by a click on the full screen menu
996*/
997void G4OpenGLQtViewer::toggleFullScreen(bool check) {
998 if (check != fGLWidget->isFullScreen()) { //toggle
999 fGLWidget->setWindowState(fGLWidget->windowState() ^ Qt::WindowFullScreen);
1000 }
1001}
1002
1003
1005 if (fMovieTempFolderPath == "") {
1006 return;
1007 }
1008 auto qGLW = dynamic_cast<G4QGLWidgetType*> (fGLWidget) ;
1009 if (! qGLW) {
1010 return;
1011 }
1012 QString fileName ="Test"+QString::number(fRecordFrameNumber)+".ppm";
1013 QString filePath =fMovieTempFolderPath+fileName;
1014
1015 QImage image;
1016#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
1017 image = qGLW->grabFrameBuffer();
1018#else
1019 image = qGLW->grabFramebuffer();
1020#endif
1021 bool res = false;
1022
1023 res = image.save(filePath,0);
1024 if (res == false) {
1026 setRecordingInfos("Can't save tmp file "+filePath);
1027 return;
1028 }
1029
1030 setRecordingInfos("File "+fileName+" saved");
1032}
1033
1034
1035
1036void G4OpenGLQtViewer::actionSaveImage() {
1037 QString filters;
1038 for (unsigned int i = 0; i < fExportImageFormatVector.size(); ++i) {
1039 filters += QString("*.") + fExportImageFormatVector.at(i).c_str() + ";;";
1040 }
1041
1042 QString* selectedFormat = new QString(fDefaultExportImageFormat.c_str());
1043 QString qFilename;
1044 qFilename = QFileDialog::getSaveFileName ( fGLWidget,
1045 tr("Save as ..."),
1046 fFileSavePath,
1047 filters,
1048 selectedFormat );
1049
1050
1051 std::string name = qFilename.toStdString().c_str();
1052
1053 // bmp jpg jpeg png ppm xbm xpm
1054 if (name.empty()) {
1055 return;
1056 }
1057
1058 fFileSavePath = QFileInfo(qFilename).path();
1059
1060 std::string format = selectedFormat->toLower().toStdString().c_str();
1061
1062 // set the format to current
1063 fExportImageFormat = format.substr(format.find_last_of(".") + 1);
1064
1065 std::string filename = name;
1066 std::string extension = "";
1067 if (name.find_last_of(".") != std::string::npos) {
1068 filename = name.substr(0,name.find_last_of(".") + 1);
1069 extension = name.substr(name.find_last_of(".") + 1);
1070 } else {
1071 extension = fExportImageFormat;
1072 }
1073
1074 filename+= "."+ extension;
1075
1076 if (!setExportFilename(filename.c_str(),0)) {
1077 return;
1078 }
1079
1080 G4OpenGLQtExportDialog* exportDialog= new G4OpenGLQtExportDialog(fGLWidget,format.c_str(),fGLWidget->height(),fGLWidget->width());
1081 if( exportDialog->exec()) {
1082
1083 if ((exportDialog->getWidth() !=fGLWidget->width()) ||
1084 (exportDialog->getHeight() !=fGLWidget->height())) {
1085 setExportSize(exportDialog->getWidth(),exportDialog->getHeight());
1086
1087 }
1088 if (fExportImageFormat == "eps") {
1089 fVectoredPs = exportDialog->getVectorEPS();
1090 } else if (fExportImageFormat == "ps") {
1091 fVectoredPs = true;
1092 }
1093 fLastExportSliderValue = exportDialog->getSliderValue();
1094
1095 if (exportImage(filename)) {
1096 // set the default format to current
1098 }
1099 } else { // cancel selected
1100 return;
1101 }
1102
1103}
1104
1105
1106void G4OpenGLQtViewer::actionChangeBackgroundColor() {
1107
1108 // //I need to revisit the kernel if the background colour changes and
1109 // //hidden line removal is enabled, because hlr drawing utilises the
1110 // //background colour in its drawing...
1111 // // (Note added by JA 13/9/2005) Background now handled in view
1112 // // parameters. A kernel visit is triggered on change of background.
1113 const QColor color =
1114 QColorDialog::getColor(Qt::black,
1115 fGLWidget,
1116 " Get background color and transparency",
1117 QColorDialog::ShowAlphaChannel);
1118 if (color.isValid()) {
1119 G4Colour colour(((G4double)color.red())/255,
1120 ((G4double)color.green())/255,
1121 ((G4double)color.blue())/255,
1122 ((G4double)color.alpha())/255);
1123 fVP.SetBackgroundColour(colour);
1124
1126 updateQWidget();
1127 }
1128}
1129
1130void G4OpenGLQtViewer::actionChangeTextColor() {
1131 const QColor& color =
1132 QColorDialog::getColor(Qt::yellow,
1133 fGLWidget,
1134 " Get text color and transparency",
1135 QColorDialog::ShowAlphaChannel);
1136 if (color.isValid()) {
1137 G4Colour colour(((G4double)color.red())/255,
1138 ((G4double)color.green())/255,
1139 ((G4double)color.blue())/255,
1140 ((G4double)color.alpha())/255);
1141
1142 fVP.SetDefaultTextColour(colour);
1143
1145 updateQWidget();
1146 }
1147}
1148
1149void G4OpenGLQtViewer::actionChangeDefaultColor() {
1150 const QColor& color =
1151 QColorDialog::getColor(Qt::white,
1152 fGLWidget,
1153 " Get default color and transparency",
1154 QColorDialog::ShowAlphaChannel);
1155 if (color.isValid()) {
1156 G4Colour colour(((G4double)color.red())/255,
1157 ((G4double)color.green())/255,
1158 ((G4double)color.blue())/255,
1159 ((G4double)color.alpha())/255);
1160
1161 fVP.SetDefaultColour(colour);
1162
1164 updateQWidget();
1165 }
1166}
1167
1168
1169void G4OpenGLQtViewer::actionMovieParameters() {
1170 showMovieParametersDialog();
1171}
1172
1173
1174void G4OpenGLQtViewer::showMovieParametersDialog() {
1175 if (!fMovieParametersDialog) {
1176 fMovieParametersDialog= new G4OpenGLQtMovieDialog(this,fGLWidget);
1178 fMovieParametersDialog->checkEncoderSwParameters();
1179 fMovieParametersDialog->checkSaveFileNameParameters();
1180 fMovieParametersDialog->checkTempFolderParameters();
1181 if (getEncoderPath() == "") {
1182 setRecordingInfos("ppmtompeg is needed to encode in video format. It is available here: http://netpbm.sourceforge.net ");
1183 }
1184 }
1185 fMovieParametersDialog->show();
1186}
1187
1188
1189
1191{
1192 /* From Apple doc:
1193 CGLFlushDrawable : Copies the back buffer of a double-buffered context to the front buffer.
1194 If the backing store attribute is set to false, the buffers can be exchanged rather than copied
1195 */
1196 glFlush ();
1197
1198 // L. Garnier 10/2009 : Not necessary and cause problems on mac OS X 10.6
1199 // fGLWidget->swapBuffers ();
1200}
1201
1202/**
1203 Save the current mouse press point
1204 @param p mouse click point
1205*/
1207{
1208 if (evnt->button() == Qt::RightButton) {
1209 return;
1210 }
1211 if ((evnt->button() & Qt::LeftButton) && (! (evnt->modifiers() & Qt::ControlModifier ))){
1212 fGLWidget->setMouseTracking(true);
1213 fAutoMove = false; // stop automove
1214 fLastPos1 = evnt->pos();
1215 fLastPos2 = fLastPos1;
1216 fLastPos3 = fLastPos2;
1217 fLastEventTime->start();
1218 if (fUiQt != NULL) {
1219
1220 if (fUiQt->IsIconZoomInSelected()) { // zoomIn
1221 // Move click point to center of OGL
1222
1223 float deltaX = ((float)getWinWidth()/2-evnt->pos().x());
1224 float deltaY = ((float)getWinHeight()/2-evnt->pos().y());
1225
1226 G4double coefTrans = 0;
1227 coefTrans = ((G4double)GetSceneNearWidth())/((G4double)getWinWidth());
1228 if (getWinHeight() <getWinWidth()) {
1229 coefTrans = ((G4double)GetSceneNearWidth())/((G4double)getWinHeight());
1230 }
1231 fVP.IncrementPan(-deltaX*coefTrans,deltaY*coefTrans,0);
1232 fVP.SetZoomFactor(1.5 * fVP.GetZoomFactor());
1233
1234 updateQWidget();
1235
1236 } else if (fUiQt->IsIconZoomOutSelected()) { // zoomOut
1237 // Move click point to center of OGL
1238 moveScene(((float)getWinWidth()/2-evnt->pos().x()),((float)getWinHeight()/2-evnt->pos().y()),0,true);
1239
1240 fVP.SetZoomFactor(0.75 * fVP.GetZoomFactor());
1241 updateQWidget();
1242
1243 } else if (fUiQt->IsIconRotateSelected() ) {
1244
1245 if (fShiftKeyPress) { // move
1246 fGLWidget->setCursor(QCursor(Qt::SizeAllCursor));
1247
1248 } else { // rotate
1249 fGLWidget->setCursor(QCursor(Qt::ClosedHandCursor));
1250 }
1251 } else if (fUiQt->IsIconMoveSelected()) {
1252 fGLWidget->setCursor(QCursor(Qt::SizeAllCursor));
1253 } else if (fUiQt->IsIconPickSelected()) {
1254 fGLWidget->setCursor(QCursor(Qt::PointingHandCursor));
1255 }
1256 }
1257 }
1258}
1259
1260/**
1261 */
1263{
1264#if QT_VERSION < 0x060000
1265#else
1266 {auto* qGLW = dynamic_cast<G4QGLWidgetType*> (fGLWidget) ;
1267 if (qGLW) qGLW->makeCurrent();}
1268 ResizeGLView();
1269#endif
1270 GLint viewport[4];
1271 glGetIntegerv(GL_VIEWPORT, viewport);
1272
1273 // factorX == factorY
1274 double factorX = ((double)viewport[2]/fGLWidget->width());
1275 double factorY = ((double)viewport[3]/fGLWidget->height());
1276 fSpinningDelay = (int)fLastEventTime->elapsed();
1277 QPoint delta = (fLastPos3-fLastPos1)*factorX;
1278
1279 // reset cursor state
1280 fGLWidget->setCursor(QCursor(Qt::ArrowCursor));
1281
1282 if (fVP.IsPicking()){ // pick
1283 if ((delta.x() != 0) || (delta.y() != 0) || (evnt->button() & Qt::RightButton)) {
1284 return;
1285 }
1286 updatePickInfosWidget(evnt->pos().x()*factorX,evnt->pos().y()*factorY);
1287
1288 } else if (fSpinningDelay < fLaunchSpinDelay ) {
1289 if ((delta.x() == 0) && (delta.y() == 0)) {
1290 return;
1291 }
1292
1293 fAutoMove = true;
1294#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
1295 QTime lastMoveTime;
1296#else
1297 QElapsedTimer lastMoveTime;
1298#endif
1299 lastMoveTime.start();
1300 // try to addapt speed move/rotate looking to drawing speed
1301 float correctionFactor = 5;
1302 while (fAutoMove) {
1303 if ( lastMoveTime.elapsed() >= (int)(1000/fNbMaxFramesPerSec)) {
1304 float lTime = 1000.0f/lastMoveTime.elapsed();
1305 if (((((float)delta.x())/correctionFactor)*lTime > fNbMaxAnglePerSec) ||
1306 ((((float)delta.x())/correctionFactor)*lTime < -fNbMaxAnglePerSec) ) {
1307 correctionFactor = (float)delta.x()*(lTime/fNbMaxAnglePerSec);
1308 if (delta.x() <0 ) {
1309 correctionFactor = -correctionFactor;
1310 }
1311 }
1312 if (((((float)delta.y())/correctionFactor)*lTime > fNbMaxAnglePerSec) ||
1313 ((((float)delta.y())/correctionFactor)*lTime < -fNbMaxAnglePerSec) ) {
1314 correctionFactor = (float)delta.y()*(lTime/fNbMaxAnglePerSec);
1315 if (delta.y() <0 ) {
1316 correctionFactor = -correctionFactor;
1317 }
1318 }
1319
1320 // Check Qt Versions for META Keys
1321
1322 // Click and move mouse to rotate volume
1323 // ALT + Click and move mouse to rotate volume (View Direction)
1324 // SHIFT + Click and move camera point of view
1325 // CTRL + Click and zoom mouse to zoom in/out
1326
1327 lastMoveTime.start();
1328
1329 bool rotate = false;
1330 bool move = false;
1331
1332 if (fUiQt != NULL) {
1333 if (fUiQt->IsIconRotateSelected()) { // rotate
1334 rotate = true;
1335 } else if (fUiQt->IsIconMoveSelected()) { // move
1336 move = true;
1337 }
1338 } else {
1339 rotate = true;
1340 }
1341 // prevent from closing widget when rotating (cause a crash)
1342 if (fIsDeleting) {
1343 return;
1344 }
1345
1346 if (rotate) { // rotate
1347 if (fNoKeyPress) {
1348 rotateQtScene(((float)delta.x())/correctionFactor,((float)delta.y())/correctionFactor);
1349 } else if (fAltKeyPress) {
1350 rotateQtSceneToggle(((float)delta.x())/correctionFactor,((float)delta.y())/correctionFactor);
1351 }
1352
1353 } else if (move) { // move
1354 moveScene(-((float)delta.x())/correctionFactor,-((float)delta.y())/correctionFactor,0,true);
1355 }
1356 }
1357 ((QApplication*)G4Qt::getInstance ())->processEvents();
1358 }
1359 }
1360 fGLWidget->setMouseTracking(false);
1361
1362}
1363
1364
1366{
1367 fGLWidget->setMouseTracking(true);
1368}
1369
1370
1371/**
1372 @param pos_x mouse x position
1373 @param pos_y mouse y position
1374 @param mButtons mouse button active
1375 @param mAutoMove true: apply this move till another evnt came, false :one time move
1376*/
1377
1379{
1380
1381 Qt::MouseButtons mButtons = evnt->buttons();
1382
1383 updateKeyModifierState(evnt->modifiers());
1384
1385 if (fAutoMove) {
1386 return;
1387 }
1388
1389 fLastPos3 = fLastPos2;
1390 fLastPos2 = fLastPos1;
1391
1392#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
1393 fLastPos1 = QPoint(evnt->x(), evnt->y());
1394#else
1395 fLastPos1 = QPoint(evnt->position().x(), evnt->position().y());
1396#endif
1397
1398 int deltaX = fLastPos2.x()-fLastPos1.x();
1399 int deltaY = fLastPos2.y()-fLastPos1.y();
1400
1401 bool move = false;
1402 if (fUiQt != NULL) {
1403 if (fUiQt->IsIconMoveSelected()) { // move
1404 move = true;
1405 }
1406 }
1407 if (!move) { // rotate, pick, zoom...
1408 if (mButtons & Qt::LeftButton) {
1409 if (fNoKeyPress) {
1410 rotateQtScene(((float)deltaX),((float)deltaY));
1411 } else if (fAltKeyPress) {
1412 rotateQtSceneToggle(((float)deltaX),((float)deltaY));
1413 } else if (fShiftKeyPress) {
1414 moveScene(-(float)deltaX, -(float)deltaY, 0, true);
1415 } else if (fControlKeyPress) {
1416 fVP.SetZoomFactor(fVP.GetZoomFactor()*(1+((float)deltaY)));
1417 }
1418 }
1419 } else if (move) { // move
1420 if (mButtons & Qt::LeftButton) {
1421 moveScene(-(float)deltaX,-(float)deltaY,0,true);
1422 }
1423 }
1424
1425 fLastEventTime->start();
1426}
1427
1428
1429/**
1430 Move the scene of dx, dy, dz values.
1431 @param dx delta mouse x position
1432 @param dy delta mouse y position
1433 @param mouseMove : true if event comes from a mouse move, false if event comes from key action
1434*/
1435
1436void G4OpenGLQtViewer::moveScene(float dx,float dy, float dz,bool mouseMove)
1437{
1438 if (fHoldMoveEvent)
1439 return;
1440 fHoldMoveEvent = true;
1441
1442 G4double coefTrans = 0;
1443 GLdouble coefDepth = 0;
1444 if(mouseMove) {
1445 if (fVP.GetFieldHalfAngle() == 0.0) {
1446 // Orthographic projection
1447 coefTrans = ((G4double)GetSceneNearWidth()) / ((G4double)getWinWidth());
1448 if (getWinHeight() < getWinWidth()) {
1449 coefTrans = ((G4double)GetSceneNearWidth()) / ((G4double)getWinHeight());
1450 }
1451 } else {
1452 // Perspective projection
1453 G4double radius = fSceneHandler.GetScene()->GetExtent().GetExtentRadius();
1454 if (radius <= 0.) radius = 1.;
1455 const G4double cameraDistance = fVP.GetCameraDistance(radius);
1456 coefTrans = cameraDistance * std::tan(fVP.GetFieldHalfAngle()) / ((G4double)getWinWidth());
1457 if (getWinHeight() < getWinWidth()) {
1458 coefTrans = cameraDistance * std::tan(fVP.GetFieldHalfAngle()) / ((G4double)getWinHeight());
1459 }
1460 }
1461 } else {
1462 coefTrans = GetSceneNearWidth()*fPan_sens;
1463 coefDepth = getSceneDepth()*fDeltaDepth;
1464 }
1465 fVP.IncrementPan(-dx*coefTrans,dy*coefTrans,dz*coefDepth);
1466
1467 updateQWidget();
1468 if (fAutoMove)
1469 ((QApplication*)G4Qt::getInstance ())->processEvents();
1470
1471 fHoldMoveEvent = false;
1472}
1473
1474
1475/**
1476 @param dx delta mouse x position
1477 @param dy delta mouse y position
1478*/
1479
1480void G4OpenGLQtViewer::rotateQtScene(float dx, float dy)
1481{
1482 if (fHoldRotateEvent)
1483 return;
1484 fHoldRotateEvent = true;
1485
1486 rotateScene(dx,dy);
1487
1488 updateQWidget();
1489
1490 fHoldRotateEvent = false;
1491}
1492
1493/**
1494 @param dx delta mouse x position
1495 @param dy delta mouse y position
1496*/
1497
1499{
1500 if (fHoldRotateEvent)
1501 return;
1502 fHoldRotateEvent = true;
1503
1504 rotateSceneToggle(dx,dy);
1505
1506 updateQWidget();
1507
1508 fHoldRotateEvent = false;
1509}
1510
1511
1512G4bool G4OpenGLQtViewer::GetWindowSize(unsigned int& a_w, unsigned int& a_h)
1513{
1514 a_w = fWinSize_x / fGLWidget->devicePixelRatio();
1515 a_h = fWinSize_y / fGLWidget->devicePixelRatio();
1516 return true;
1517}
1518
1519G4bool G4OpenGLQtViewer::GetRenderAreaSize(unsigned int& a_w, unsigned int& a_h)
1520{
1521 a_w = fWinSize_x;
1522 a_h = fWinSize_y;
1523 return true;
1524}
1525
1526
1527/** This is the benning of a rescale function. It does nothing for the moment
1528 @param aWidth : new width
1529 @param aHeight : new height
1530*/
1531void G4OpenGLQtViewer::rescaleImage(
1532 int /* aWidth */
1533,int /* aHeight */
1534){
1535 // GLfloat* feedback_buffer;
1536 // GLint returned;
1537 // FILE* file;
1538
1539 // feedback_buffer = new GLfloat[size];
1540 // glFeedbackBuffer (size, GL_3D_COLOR, feedback_buffer);
1541 // glRenderMode (GL_FEEDBACK);
1542
1543 // DrawView();
1544 // returned = glRenderMode (GL_RENDER);
1545
1546}
1547
1548
1549
1550
1551void G4OpenGLQtViewer::G4wheelEvent (QWheelEvent * evnt)
1552{
1553#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
1554 double delta = evnt->delta();
1555#else
1556 double delta = evnt->angleDelta().y();
1557#endif
1558
1559 ZoomFromMouseWheel(delta, evnt->modifiers() & Qt::ShiftModifier, evnt->position().x(), evnt->position().y());
1560
1561 updateQWidget();
1562}
1563
1564
1566{
1567 if (fHoldKeyEvent)
1568 return;
1569
1570 fHoldKeyEvent = true;
1571
1572
1573 // with no modifiers
1574 updateKeyModifierState(evnt->modifiers());
1575 if ((fNoKeyPress) || (evnt->modifiers() == Qt::KeypadModifier )) {
1576 if (evnt->key() == Qt::Key_Down) { // go down
1577 moveScene(0,1,0,false);
1578 }
1579 else if (evnt->key() == Qt::Key_Up) { // go up
1580 moveScene(0,-1,0,false);
1581 }
1582 if (evnt->key() == Qt::Key_Left) { // go left
1583 moveScene(-1,0,0,false);
1584 }
1585 else if (evnt->key() == Qt::Key_Right) { // go right
1586 moveScene(1,0,0,false);
1587 }
1588 if (evnt->key() == Qt::Key_Minus) { // go backward
1589 moveScene(0,0,1,false);
1590 }
1591 else if (evnt->key() == Qt::Key_Plus) { // go forward
1592 moveScene(0,0,-1,false);
1593 }
1594 // escaped from full screen
1595 if (evnt->key() == Qt::Key_Escape) {
1596 toggleFullScreen(false);
1597 }
1598 }
1599 // several case here : If return is pressed, in every case -> display the movie parameters dialog
1600 // If one parameter is wrong -> put it in red (only save filenam could be wrong..)
1601 // If encoder not found-> does nothing.Only display a message in status box
1602 // If all ok-> generate parameter file
1603 // If ok -> put encoder button enabled
1604
1605 if ((evnt->key() == Qt::Key_Return) || (evnt->key() == Qt::Key_Enter)){ // end of video
1606 stopVideo();
1607 }
1608 if (evnt->key() == Qt::Key_Space){ // start/pause of video
1610 }
1611
1612 // H : Return Home view
1613 if (evnt->key() == Qt::Key_H){ // go Home
1614 ResetView();
1615
1616 updateQWidget();
1617 }
1618
1619 // Shift Modifier
1620 if (fShiftKeyPress) {
1621 fGLWidget->setCursor(QCursor(Qt::SizeAllCursor));
1622
1623 if (evnt->key() == Qt::Key_Down) { // rotate phi
1625 }
1626 else if (evnt->key() == Qt::Key_Up) { // rotate phi
1628 }
1629 if (evnt->key() == Qt::Key_Left) { // rotate theta
1631 }
1632 else if (evnt->key() == Qt::Key_Right) { // rotate theta
1634 }
1635 if (evnt->key() == Qt::Key_Plus) { // go forward ("Plus" imply
1636 // "Shift" on Mac French keyboard
1637 moveScene(0,0,-1,false);
1638 }
1639
1640 // Alt Modifier
1641 }
1642 if ((fAltKeyPress)) {
1643 fGLWidget->setCursor(QCursor(Qt::ClosedHandCursor));
1644
1645 if (evnt->key() == Qt::Key_Down) { // rotate phi
1647 }
1648 else if (evnt->key() == Qt::Key_Up) { // rotate phi
1650 }
1651 if (evnt->key() == Qt::Key_Left) { // rotate theta
1653 }
1654 else if (evnt->key() == Qt::Key_Right) { // rotate theta
1656 }
1657
1658 // Rotatio +/-
1659 if (evnt->key() == Qt::Key_Plus) {
1660 fRot_sens = fRot_sens/0.7;
1661 G4cout << "Auto-rotation set to : " << fRot_sens << G4endl;
1662 }
1663 else if (evnt->key() == Qt::Key_Minus) {
1664 fRot_sens = fRot_sens*0.7;
1665 G4cout << "Auto-rotation set to : " << fRot_sens << G4endl;
1666 }
1667
1668 // Control Modifier OR Command on MAC
1669 }
1670 if ((fControlKeyPress)) {
1671 if (evnt->key() == Qt::Key_Plus) {
1672 fVP.SetZoomFactor(fVP.GetZoomFactor()*(1+fDeltaZoom));
1673 updateQWidget();
1674 }
1675 else if (evnt->key() == Qt::Key_Minus) {
1676 fVP.SetZoomFactor(fVP.GetZoomFactor()*(1-fDeltaZoom));
1677 updateQWidget();
1678 }
1679 }
1680
1681 fHoldKeyEvent = false;
1682}
1683
1684
1686{
1687 fGLWidget->setCursor(QCursor(Qt::ArrowCursor));
1688}
1689
1690
1691void G4OpenGLQtViewer::updateKeyModifierState(const Qt::KeyboardModifiers& modifier) {
1692 // Check Qt Versions for META Keys
1693
1694 fNoKeyPress = true;
1695 fAltKeyPress = false;
1696 fShiftKeyPress = false;
1697 fControlKeyPress = false;
1698
1699 if (modifier & Qt::AltModifier ) {
1700 fAltKeyPress = true;
1701 fNoKeyPress = false;
1702 }
1703 if (modifier & Qt::ShiftModifier ) {
1704 fShiftKeyPress = true;
1705 fNoKeyPress = false;
1706 }
1707 if (modifier & Qt::ControlModifier ) {
1708 fControlKeyPress = true;
1709 fNoKeyPress = false;
1710 }
1711}
1712
1713
1714/** Stop the video. Check all parameters and enable encoder button if all is ok.
1715 */
1717
1718 // if encoder parameter is wrong, display parameters dialog and return
1719 if (!fMovieParametersDialog) {
1720 showMovieParametersDialog();
1721 }
1722 setRecordingStatus(STOP);
1723
1724 if (fRecordFrameNumber >0) {
1725 // check parameters if they were modified (Re APPLY them...)
1726 if (!(fMovieParametersDialog->checkEncoderSwParameters())) {
1727 setRecordingStatus(BAD_ENCODER);
1728 } else if (!(fMovieParametersDialog->checkSaveFileNameParameters())) {
1729 setRecordingStatus(BAD_OUTPUT);
1730 }
1731 } else {
1733 setRecordingInfos("No frame to encode.");
1734 }
1735}
1736
1737/** Stop the video. Check all parameters and enable encoder button if all is ok.
1738 */
1740
1741 // if encoder parameter is wrong, display parameters dialog and return
1742 if (!fMovieParametersDialog) {
1743 showMovieParametersDialog();
1744 }
1745
1746 fMovieParametersDialog->checkEncoderSwParameters();
1747 fMovieParametersDialog->checkSaveFileNameParameters();
1748
1749 if (fRecordingStep == STOP) {
1750 setRecordingStatus(SAVE);
1752 encodeVideo();
1753 }
1754}
1755
1756
1757/** Start/Pause the video..
1758 */
1760
1761 // first time, if temp parameter is wrong, display parameters dialog and return
1762
1763 if ( fRecordingStep == WAIT) {
1764 if ( fRecordFrameNumber == 0) {
1765 if (getTempFolderPath() == "") { // BAD_OUTPUT
1766 showMovieParametersDialog();
1767 setRecordingInfos("You should specified the temp folder in order to make movie");
1768 return;
1769 } else {
1770 // remove temp folder if it was create
1771 QString tmp = removeTempFolder();
1772 if (tmp !="") {
1773 setRecordingInfos(tmp);
1774 return;
1775 }
1776 tmp = createTempFolder();
1777 if (tmp != "") {
1778 setRecordingInfos("Can't create temp folder."+tmp);
1779 return;
1780 }
1781 }
1782 }
1783 }
1784 if (fRecordingStep == WAIT) {
1785 setRecordingStatus(START);
1786 } else if (fRecordingStep == START) {
1787 setRecordingStatus(PAUSE);
1788 } else if (fRecordingStep == PAUSE) {
1789 setRecordingStatus(CONTINUE);
1790 } else if (fRecordingStep == CONTINUE) {
1791 setRecordingStatus(PAUSE);
1792 }
1793}
1794
1795void G4OpenGLQtViewer::setRecordingStatus(RECORDING_STEP step) {
1796
1797 fRecordingStep = step;
1799}
1800
1801
1803
1804 QString txtStatus = "";
1805 if (fRecordingStep == WAIT) {
1806 txtStatus = "Waiting to start...";
1807 fRecordFrameNumber = 0; // reset the frame number
1808 } else if (fRecordingStep == START) {
1809 txtStatus = "Start Recording...";
1810 } else if (fRecordingStep == PAUSE) {
1811 txtStatus = "Pause Recording...";
1812 } else if (fRecordingStep == CONTINUE) {
1813 txtStatus = "Continue Recording...";
1814 } else if (fRecordingStep == STOP) {
1815 txtStatus = "Stop Recording...";
1816 } else if (fRecordingStep == READY_TO_ENCODE) {
1817 txtStatus = "Ready to Encode...";
1818 } else if (fRecordingStep == ENCODING) {
1819 txtStatus = "Encoding...";
1820 } else if (fRecordingStep == FAILED) {
1821 txtStatus = "Failed to encode...";
1822 } else if ((fRecordingStep == BAD_ENCODER)
1823 || (fRecordingStep == BAD_OUTPUT)
1824 || (fRecordingStep == BAD_TMP)) {
1825 txtStatus = "Correct above errors first";
1826 } else if (fRecordingStep == SUCCESS) {
1827 txtStatus = "File encoded successfully";
1828 } else {
1829 }
1830
1831 if (fMovieParametersDialog) {
1832 fMovieParametersDialog->setRecordingStatus(txtStatus);
1833 } else {
1834 G4cout << txtStatus.toStdString().c_str() << G4endl;
1835 }
1836 setRecordingInfos("");
1837}
1838
1839
1840void G4OpenGLQtViewer::setRecordingInfos(const QString& txt) {
1841 if (fMovieParametersDialog) {
1842 fMovieParametersDialog->setRecordingInfos(txt);
1843 } else {
1844 G4cout << txt.toStdString().c_str() << G4endl;
1845 }
1846}
1847
1848/** Init the movie parameters. Temp dir and encoder path
1849 */
1850void G4OpenGLQtViewer::initMovieParameters() {
1851 //init encoder
1852
1853 //look for encoderPath
1854 fProcess = new QProcess();
1855
1856 QObject ::connect(fProcess,SIGNAL(finished ( int)),
1857 this,SLOT(processLookForFinished()));
1858 fProcess->setProcessChannelMode(QProcess::MergedChannels);
1859#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
1860 fProcess->start ("which ppmtompeg");
1861#else
1862 fProcess->start ("which ppmtompeg", QStringList());
1863#endif
1864}
1865
1866/** @return encoder path or "" if it does not exist
1867 */
1869 return fEncoderPath;
1870}
1871
1872
1873/**
1874 * set the new encoder path
1875 * @return "" if correct. The error otherwise
1876 */
1878 if (path == "") {
1879 return "ppmtompeg is needed to encode in video format. It is available here: http://netpbm.sourceforge.net ";
1880 }
1881
1882 path = QDir::cleanPath(path);
1883 QFileInfo *f = new QFileInfo(path);
1884 if (!f->exists()) {
1885 return "File does not exist";
1886 } else if (f->isDir()) {
1887 return "This is a directory";
1888 } else if (!f->isExecutable()) {
1889 return "File exist but is not executable";
1890 } else if (!f->isFile()) {
1891 return "This is not a file";
1892 }
1893 fEncoderPath = path;
1894
1895 if (fRecordingStep == BAD_ENCODER) {
1896 setRecordingStatus(STOP);
1897 }
1898 return "";
1899}
1900
1901
1903 if ((fRecordingStep == START) || (fRecordingStep == CONTINUE)) {
1904 return true;
1905 }
1906 return false;
1907}
1908
1910 if (fRecordingStep == PAUSE) {
1911 return true;
1912 }
1913 return false;
1914}
1915
1917 if (fRecordingStep == ENCODING) {
1918 return true;
1919 }
1920 return false;
1921}
1922
1924 if (fRecordingStep == WAIT) {
1925 return true;
1926 }
1927 return false;
1928}
1929
1931 if (fRecordingStep == STOP) {
1932 return true;
1933 }
1934 return false;
1935}
1936
1938 if (fRecordingStep == FAILED) {
1939 return true;
1940 }
1941 return false;
1942}
1943
1945 if (fRecordingStep == SUCCESS) {
1946 return true;
1947 }
1948 return false;
1949}
1950
1952 if (fRecordingStep == BAD_ENCODER) {
1953 return true;
1954 }
1955 return false;
1956}
1958 if (fRecordingStep == BAD_TMP) {
1959 return true;
1960 }
1961 return false;
1962}
1964 if (fRecordingStep == BAD_OUTPUT) {
1965 return true;
1966 }
1967 return false;
1968}
1969
1971 fRecordingStep = BAD_ENCODER;
1973}
1975 fRecordingStep = BAD_TMP;
1977}
1979 fRecordingStep = BAD_OUTPUT;
1981}
1982
1984 fRecordingStep = WAIT;
1986}
1987
1988
1990 if (fRecordingStep == READY_TO_ENCODE) {
1991 return true;
1992 }
1993 return false;
1994}
1995
1997 setRecordingStatus(WAIT);
1998}
1999
2000/**
2001 * set the temp folder path
2002 * @return "" if correct. The error otherwise
2003 */
2005
2006 if (path == "") {
2007 return "Path does not exist";
2008 }
2009 path = QDir::cleanPath(path);
2010 QFileInfo *d = new QFileInfo(path);
2011 if (!d->exists()) {
2012 return "Path does not exist";
2013 } else if (!d->isDir()) {
2014 return "This is not a directory";
2015 } else if (!d->isReadable()) {
2016 return path +" is read protected";
2017 } else if (!d->isWritable()) {
2018 return path +" is write protected";
2019 }
2020
2021 if (fRecordingStep == BAD_TMP) {
2022 setRecordingStatus(WAIT);
2023 }
2024 fTempFolderPath = path;
2025 return "";
2026}
2027
2028/** @return the temp folder path or "" if it does not exist
2029 */
2031 return fTempFolderPath;
2032}
2033
2034/**
2035 * set the save file name path
2036 * @return "" if correct. The error otherwise
2037 */
2039
2040 if (path == "") {
2041 return "Path does not exist";
2042 }
2043
2044 QFileInfo *file = new QFileInfo(path);
2045 QDir dir = file->dir();
2046 path = QDir::cleanPath(path);
2047 if (file->exists()) {
2048 return "File already exist, please choose a new one";
2049 } else if (!dir.exists()) {
2050 return "Dir does not exist";
2051 } else if (!dir.isReadable()) {
2052 return path +" is read protected";
2053 }
2054
2055 if (fRecordingStep == BAD_OUTPUT) {
2056 setRecordingStatus(STOP);
2057 }
2058 fSaveFileName = path;
2059 return "";
2060}
2061
2062/** @return the save file path
2063 */
2065 return fSaveFileName ;
2066}
2067
2068/** Create a Qt_temp folder in the temp folder given
2069 * The temp folder will be like this /tmp/QtMovie_12-02-2008_12_12_58/
2070 * @return "" if success. Error message if not.
2071 */
2072QString G4OpenGLQtViewer::createTempFolder() {
2073 fMovieTempFolderPath = "";
2074 //check
2075 QString tmp = setTempFolderPath(fTempFolderPath);
2076 if (tmp != "") {
2077 return tmp;
2078 }
2079 QString sep = QString(QDir::separator());
2080 QString path = sep+"QtMovie_"+QDateTime::currentDateTime ().toString("dd-MM-yyyy_hh-mm-ss")+sep;
2081 QDir *d = new QDir(QDir::cleanPath(fTempFolderPath));
2082 // check if it is already present
2083 if (d->exists(path)) {
2084 return "Folder "+path+" already exists.Please remove it first";
2085 }
2086 if (d->mkdir(fTempFolderPath+path)) {
2087 fMovieTempFolderPath = fTempFolderPath+path;
2088 return "";
2089 }
2090 return "Can't create "+fTempFolderPath+path;
2091}
2092
2093/** Remove the Qt_temp folder in the temp folder
2094 */
2095QString G4OpenGLQtViewer::removeTempFolder() {
2096 // remove files in Qt_temp folder
2097 if (fMovieTempFolderPath == "") {
2098 return "";
2099 }
2100 QDir *d = new QDir(QDir::cleanPath(fMovieTempFolderPath));
2101 if (!d->exists()) {
2102 return ""; // already remove
2103 }
2104
2105 d->setFilter( QDir::Files );
2106 QStringList subDirList = d->entryList();
2107 int res = true;
2108 QString error = "";
2109 for (QStringList::ConstIterator it = subDirList.begin() ;(it != subDirList.end()) ; it++) {
2110 const QString currentFile = *it;
2111 if (!d->remove(currentFile)) {
2112 res = false;
2113 QString file = fMovieTempFolderPath+currentFile;
2114 error +="Removing file failed : "+file;
2115 } else {
2116 }
2117 }
2118 if (res) {
2119 if (d->rmdir(fMovieTempFolderPath)) {
2120 fMovieTempFolderPath = "";
2121 return "";
2122 } else {
2123 return "Dir "+fMovieTempFolderPath+" should be empty, but could not remove it";
2124 }
2125
2126 }
2127 return "Could not remove "+fMovieTempFolderPath+" because of the following errors :"+error;
2128}
2129
2130/**
2131 Export image. Try to get the format according to the file extention.
2132 If not present, the last one choosen by /vis/ogl/set/exportFormat
2133 If not, will take the default format : eps
2134 Best format actually available is pdf (vectored and allow transparency)
2135 If name is not set, it will take the default name value given by /vis/ogl/set/printFilename
2136 */
2137bool G4OpenGLQtViewer::exportImage(std::string name, int width, int height) {
2138
2139 auto* qGLW = dynamic_cast<G4QGLWidgetType*> (fGLWidget) ;
2140 if (! qGLW) {
2141 return false;
2142 }
2143 // If there is already an extention
2144 bool increaseFileNumber = true;
2145 // if
2146 if (name.size() != name.substr(name.find_last_of(".") + 1).size()) {
2147 increaseFileNumber = false;
2148 }
2149 if (! setExportFilename(name,increaseFileNumber)) {
2150 return false;
2151 }
2152 if ((width !=-1) && (height != -1)) {
2153 setExportSize(width, height);
2154 }
2155 // first, try to do it with generic function
2156 if (G4OpenGLViewer::exportImage(name, width, height)) {
2157 return true;
2158
2159 // Then try Qt saving functions
2160 } else {
2161 QImage image;
2162#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
2163 image = qGLW->grabFrameBuffer();
2164#else
2165 image = qGLW->grabFramebuffer();
2166#endif
2167
2168 bool res = image.save(QString(getRealPrintFilename().c_str()),0,fLastExportSliderValue);
2169
2170 if (!res) {
2171 G4cerr << "Error saving file... " << getRealPrintFilename().c_str() << G4endl;
2172 return false;
2173 } else {
2174 G4cout << "File " << getRealPrintFilename().c_str() << " size: " << fGLWidget->width() << "x" << fGLWidget->height() << " has been saved " << G4endl;
2176 }
2177 }
2178 return true;
2179}
2180
2182
2183 // save the parameter file
2184 FILE* fp;
2185 fp = fopen (QString(fMovieTempFolderPath+fParameterFileName).toStdString().c_str(), "w");
2186
2187 if (fp == NULL) {
2188 setRecordingInfos("Generation of parameter file failed");
2189 return false;
2190 }
2191
2192 fprintf (fp,"# Pattern affects speed, quality and compression. See the User's Guide\n");
2193 fprintf (fp,"# for more info.\n");
2194 fprintf (fp,"\n");
2195 fprintf (fp,"PATTERN I\n");
2196 fprintf (fp,"OUTPUT %s\n",getSaveFileName().toStdString().c_str());
2197 fprintf (fp,"\n");
2198 fprintf (fp,"# You must specify the type of the input files. The choices are:\n");
2199 fprintf (fp,"# YUV, PPM, JMOVIE, Y, JPEG, PNM\n");
2200 fprintf (fp,"# (must be upper case)\n");
2201 fprintf (fp,"#\n");
2202 fprintf (fp,"BASE_FILE_FORMAT PPM\n");
2203 fprintf (fp,"\n");
2204 fprintf (fp,"\n");
2205 fprintf (fp,"# If you are using YUV, there are different supported file formats.\n");
2206 fprintf (fp,"# EYUV or UCB are the same as previous versions of this encoder.\n");
2207 fprintf (fp,"# (All the Y's, then U's then V's, in 4:2:0 subsampling.)\n");
2208 fprintf (fp,"# Other formats, such as Abekas, Phillips, or a general format are\n");
2209 fprintf (fp,"# permissible, the general format is a string of Y's, U's, and V's\n");
2210 fprintf (fp,"# to specify the file order.\n");
2211 fprintf (fp,"\n");
2212 fprintf (fp,"INPUT_FORMAT UCB\n");
2213 fprintf (fp,"\n");
2214 fprintf (fp,"# the conversion statement\n");
2215 fprintf (fp,"#\n");
2216 fprintf (fp,"# Each occurrence of '*' will be replaced by the input file\n");
2217 fprintf (fp,"#\n");
2218 fprintf (fp,"# e.g., if you have a bunch of GIF files, then this might be:\n");
2219 fprintf (fp,"# INPUT_CONVERT giftoppm *\n");
2220 fprintf (fp,"#\n");
2221 fprintf (fp,"# e.g., if you have a bunch of files like a.Y a.U a.V, etc., then:\n");
2222 fprintf (fp,"# INPUT_CONVERT cat *.Y *.U *.V\n");
2223 fprintf (fp,"#\n");
2224 fprintf (fp,"# e.g., if you are grabbing from laser disc you might have something like\n");
2225 fprintf (fp,"# INPUT_CONVERT goto frame *; grabppm\n");
2226 fprintf (fp,"# 'INPUT_CONVERT *' means the files are already in the base file format\n");
2227 fprintf (fp,"#\n");
2228 fprintf (fp,"INPUT_CONVERT * \n");
2229 fprintf (fp,"\n");
2230 fprintf (fp,"# number of frames in a GOP.\n");
2231 fprintf (fp,"#\n");
2232 fprintf (fp,"# since each GOP must have at least one I-frame, the encoder will find the\n");
2233 fprintf (fp,"# the first I-frame after GOP_SIZE frames to start the next GOP\n");
2234 fprintf (fp,"#\n");
2235 fprintf (fp,"# later, will add more flexible GOP signalling\n");
2236 fprintf (fp,"#\n");
2237 fprintf (fp,"GOP_SIZE 1\n");
2238 fprintf (fp,"\n");
2239 fprintf (fp,"# number of slices in a frame\n");
2240 fprintf (fp,"#\n");
2241 fprintf (fp,"# 1 is a good number. another possibility is the number of macroblock rows\n");
2242 fprintf (fp,"# (which is the height divided by 16)\n");
2243 fprintf (fp,"#\n");
2244 fprintf (fp,"SLICES_PER_FRAME 1\n");
2245 fprintf (fp,"PIXEL HALF");
2246 fprintf (fp,"\n");
2247 fprintf (fp,"# directory to get all input files from (makes this file easier to read)\n");
2248 fprintf (fp,"INPUT_DIR %s\n",fMovieTempFolderPath.toStdString().c_str());
2249 fprintf (fp,"\n");
2250 fprintf (fp,"# There are a bunch of ways to specify the input files.\n");
2251 fprintf (fp,"# from a simple one-per-line listing, to the following \n");
2252 fprintf (fp,"# way of numbering them. See the manual for more information.\n");
2253 fprintf (fp,"INPUT\n");
2254 fprintf (fp,"# '*' is replaced by the numbers 01, 02, 03, 04\n");
2255 fprintf (fp,"# if I instead do [01-11], it would be 01, 02, ..., 09, 10, 11\n");
2256 fprintf (fp,"# if I instead do [1-11], it would be 1, 2, 3, ..., 9, 10, 11\n");
2257 fprintf (fp,"# if I instead do [1-11+3], it would be 1, 4, 7, 10\n");
2258 fprintf (fp,"# the program assumes none of your input files has a name ending in ']'\n");
2259 fprintf (fp,"# if you do, too bad!!!\n");
2260 fprintf (fp,"#\n");
2261 fprintf (fp,"#\n");
2262 fprintf (fp,"Test*.ppm [0-%d]\n",fRecordFrameNumber-1);
2263 fprintf (fp,"# can have more files here if you want...there is no limit on the number\n");
2264 fprintf (fp,"# of files\n");
2265 fprintf (fp,"END_INPUT\n");
2266 fprintf (fp,"\n");
2267 fprintf (fp,"\n");
2268 fprintf (fp,"\n");
2269 fprintf (fp,"# Many of the remaining options have to do with the motion search and qscale\n");
2270 fprintf (fp,"\n");
2271 fprintf (fp,"# FULL or HALF -- must be upper case\n");
2272 fprintf (fp,"# Should be FULL for computer generated images\n");
2273 fprintf (fp,"PIXEL FULL\n");
2274 fprintf (fp,"\n");
2275 fprintf (fp,"# means +/- this many pixels for both P and B frame searches\n");
2276 fprintf (fp,"# specify two numbers if you wish to serc different ranges in the two.\n");
2277 fprintf (fp,"RANGE 10\n");
2278 fprintf (fp,"\n");
2279 fprintf (fp,"# The two search algorithm parameters below mostly affect speed,\n");
2280 fprintf (fp,"# with some affect on compression and almost none on quality.\n");
2281 fprintf (fp,"\n");
2282 fprintf (fp,"# this must be one of {EXHAUSTIVE, SUBSAMPLE, LOGARITHMIC}\n");
2283 fprintf (fp,"PSEARCH_ALG LOGARITHMIC\n");
2284 fprintf (fp,"\n");
2285 fprintf (fp,"# this must be one of {SIMPLE, CROSS2, EXHAUSTIVE}\n");
2286 fprintf (fp,"#\n");
2287 fprintf (fp,"# note that EXHAUSTIVE is really, really, really slow\n");
2288 fprintf (fp,"#\n");
2289 fprintf (fp,"BSEARCH_ALG SIMPLE\n");
2290 fprintf (fp,"\n");
2291 fprintf (fp,"#\n");
2292 fprintf (fp,"# these specify the q-scale for I, P, and B frames\n");
2293 fprintf (fp,"# (values must be between 1 and 31)\n");
2294 fprintf (fp,"# These are the Qscale values for the entire frame in variable bit-rate\n");
2295 fprintf (fp,"# mode, and starting points (but not important) for constant bit rate\n");
2296 fprintf (fp,"#\n");
2297 fprintf (fp,"\n");
2298 fprintf (fp,"# Qscale (Quantization scale) affects quality and compression,\n");
2299 fprintf (fp,"# but has very little effect on speed.\n");
2300 fprintf (fp,"\n");
2301 fprintf (fp,"IQSCALE 4\n");
2302 fprintf (fp,"PQSCALE 5\n");
2303 fprintf (fp,"BQSCALE 12\n");
2304 fprintf (fp,"\n");
2305 fprintf (fp,"# this must be ORIGINAL or DECODED\n");
2306 fprintf (fp,"REFERENCE_FRAME ORIGINAL\n");
2307 fprintf (fp,"\n");
2308 fprintf (fp,"# for parallel parameters see parallel.param in the examples subdirectory\n");
2309 fprintf (fp,"\n");
2310 fprintf (fp,"# if you want constant bit-rate mode, specify it as follows (number is bits/sec):\n");
2311 fprintf (fp,"#BIT_RATE 1000000\n");
2312 fprintf (fp,"\n");
2313 fprintf (fp,"# To specify the buffer size (327680 is default, measused in bits, for 16bit words)\n");
2314 fprintf (fp,"BUFFER_SIZE 327680\n");
2315 fprintf (fp,"\n");
2316 fprintf (fp,"# The frame rate is the number of frames/second (legal values:\n");
2317 fprintf (fp,"# 23.976, 24, 25, 29.97, 30, 50 ,59.94, 60\n");
2318 fprintf (fp,"FRAME_RATE 30\n");
2319 fprintf (fp,"\n");
2320 fprintf (fp,"# There are many more options, see the users manual for examples....\n");
2321 fprintf (fp,"# ASPECT_RATIO, USER_DATA, GAMMA, IQTABLE, etc.\n");
2322 fprintf (fp,"\n");
2323 fprintf (fp,"\n");
2324 fclose (fp);
2325
2326 setRecordingInfos("Parameter file "+fParameterFileName+" generated in "+fMovieTempFolderPath);
2327 setRecordingStatus(READY_TO_ENCODE);
2328 return true;
2329}
2330
2332{
2333 if ((getEncoderPath() != "") && (getSaveFileName() != "")) {
2334 setRecordingStatus(ENCODING);
2335
2336 fProcess = new QProcess();
2337 QObject ::connect(fProcess,SIGNAL(finished ( int,QProcess::ExitStatus)),
2338 this,SLOT(processEncodeFinished()));
2339 QObject ::connect(fProcess,SIGNAL(readyReadStandardOutput ()),
2340 this,SLOT(processEncodeStdout()));
2341#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))
2342 fProcess->setReadChannelMode(QProcess::MergedChannels);
2343#else
2344 fProcess->setProcessChannelMode(QProcess::MergedChannels);
2345#endif
2346 fProcess->start (fEncoderPath, QStringList(fMovieTempFolderPath+fParameterFileName));
2347 }
2348}
2349
2350
2351// FIXME : does not work on Qt3
2352void G4OpenGLQtViewer::processEncodeStdout()
2353{
2354 QString tmp = fProcess->readAllStandardOutput ().data();
2355 auto start = tmp.lastIndexOf("ESTIMATED TIME");
2356 tmp = tmp.mid(start,tmp.indexOf("\n",start)-start);
2357 setRecordingInfos(tmp);
2358}
2359
2360
2361void G4OpenGLQtViewer::processEncodeFinished()
2362{
2363
2364 QString txt = "";
2365 txt = getProcessErrorMsg();
2366 if (txt == "") {
2367 setRecordingStatus(SUCCESS);
2368 } else {
2369 setRecordingStatus(FAILED);
2370 }
2371 // setRecordingInfos(txt+removeTempFolder());
2372}
2373
2374
2375void G4OpenGLQtViewer::processLookForFinished()
2376{
2377
2378 QString txt = getProcessErrorMsg();
2379 if (txt != "") {
2380 fEncoderPath = "";
2381 } else {
2382 fEncoderPath = QString(fProcess->readAllStandardOutput ().data()).trimmed();
2383 // if not found, return "not found"
2384 if (fEncoderPath.contains(" ")) {
2385 fEncoderPath = "";
2386 } else if (!fEncoderPath.contains("ppmtompeg")) {
2387 fEncoderPath = "";
2388 }
2389 setEncoderPath(fEncoderPath);
2390 }
2391 // init temp folder
2392 setTempFolderPath(QDir::temp ().absolutePath ());
2393}
2394
2395
2396QString G4OpenGLQtViewer::getProcessErrorMsg()
2397{
2398 QString txt = "";
2399 if (fProcess->exitCode() != 0) {
2400 switch (fProcess->error()) {
2401 case QProcess::FailedToStart:
2402 txt = "The process failed to start. Either the invoked program is missing, or you may have insufficient permissions to invoke the program.\n";
2403 break;
2404 case QProcess::Crashed:
2405 txt = "The process crashed some time after starting successfully.\n";
2406 break;
2407 case QProcess::Timedout:
2408 txt = "The last waitFor...() function timed out. The state of QProcess is unchanged, and you can try calling waitFor...() again.\n";
2409 break;
2410 case QProcess::WriteError:
2411 txt = "An error occurred when attempting to write to the process. For example, the process may not be running, or it may have closed its input channel.\n";
2412 break;
2413 case QProcess::ReadError:
2414 txt = "An error occurred when attempting to read from the process. For example, the process may not be running.\n";
2415 break;
2416 case QProcess::UnknownError:
2417 txt = "An unknown error occurred. This is the default return value of error().\n";
2418 break;
2419 }
2420 }
2421 return txt;
2422}
2423
2424
2425
2426
2427QWidget *G4OpenGLQtViewer::getParentWidget()
2428{
2429 // launch Qt if not
2430 G4Qt* interactorManager = G4Qt::getInstance ();
2431
2432 bool found = false;
2433 QDialog* dialog = NULL;
2434 // create window
2435 if (((QApplication*)interactorManager->GetMainInteractor())) {
2436 // look for the main window
2437 QWidgetList wl = QApplication::allWidgets();
2438 QWidget *widget = NULL;
2439 for (int i=0; i < wl.size(); i++) {
2440 widget = wl.at(i);
2441 if ((found== false) && (widget->inherits("QMainWindow"))) {
2442 dialog = new QDialog(widget,Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint);
2443 found = true;
2444 }
2445 }
2446
2447 if (found==false) {
2448 dialog = new QDialog();
2449 }
2450 } else {
2451 dialog= new QDialog();
2452 }
2453 if (found) {
2454 return dialog;
2455 } else {
2456 return NULL;
2457 }
2458}
2459
2460
2461void G4OpenGLQtViewer::createSceneTreeWidget() {
2462 fUISceneTreeWidget = fUiQt->GetSceneTreeWidget();
2463
2464 if (!fUISceneTreeWidget) {
2465 return;
2466 }
2467
2468 // do not remove previous widgets, hide them!
2469 QLayoutItem * wItem;
2470 bool found = false;
2471 if (fUISceneTreeWidget->layout()->count() ) {
2472 for(int idx = 0; idx < fUISceneTreeWidget->layout()->count(); idx++){
2473 wItem = fUISceneTreeWidget->layout()->itemAt(idx);
2474 if (fSceneTreeWidget) {
2475 if(dynamic_cast<QWidget *>(wItem->widget())) {
2476 if (wItem->widget()->windowTitle() == fSceneTreeWidget->windowTitle()) {
2477 wItem->widget()->show();
2478 found = true;
2479 } else {
2480 wItem->widget()->hide();
2481 }
2482 }
2483 } else {
2484// wItem->widget()->hide();
2485 }
2486 }
2487 }
2488
2489 if (!found) {
2490 // initialize scene tree / viewer properties / picking
2491 fSceneTreeWidget = new QWidget();
2492 QVBoxLayout* layoutSceneTree = new QVBoxLayout();
2493 fSceneTreeWidget->setStyleSheet ("padding: 0px ");
2494
2495 fSceneTreeWidget->setLayout(layoutSceneTree);
2496 fSceneTreeWidget->layout()->setContentsMargins(5,5,5,5);
2497 fSceneTreeWidget->setWindowTitle(QString(GetName().data()));
2498
2499 if (fUISceneTreeWidget != NULL) {
2500// fUISceneTreeWidget->layout()->addWidget(fSceneTreeWidget);
2501 }
2502
2503 // not available for Immediate mode
2504 if (dynamic_cast<G4OpenGLStoredQtViewer*> (this)) {
2505 createSceneTreeComponent();
2506 }
2507 }
2508}
2509
2510
2511void G4OpenGLQtViewer::createSceneTreeComponent(){
2512
2513 QLayout* vLayout = fSceneTreeWidget->layout();
2514
2515 // Search line
2516 QWidget* coutButtonWidget = new QWidget();
2517 QHBoxLayout* layoutCoutTBButtons = new QHBoxLayout();
2518
2519 fFilterOutput = new QLineEdit();
2520 fFilterOutput->setToolTip("Filter output by...");
2521 fFilterOutput->setStyleSheet ("padding: 0px ");
2522
2523 QPixmap* searchIcon = fUiQt->getSearchIcon();
2524 fFilterOutput->addAction(*searchIcon,QLineEdit::TrailingPosition);
2525 fFilterOutput->setStyleSheet ("border-radius:7px;");
2526 layoutCoutTBButtons->addWidget(fFilterOutput);
2527
2528 coutButtonWidget->setLayout(layoutCoutTBButtons);
2529 vLayout->addWidget(coutButtonWidget);
2530
2531 // reduce margins
2532 vLayout->setContentsMargins(0,0,0,0);
2533
2534
2535 fSceneTreeComponentTreeWidget = new QTreeWidget();
2536 fSceneTreeComponentTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
2537 fSceneTreeComponentTreeWidget->setHeaderLabel ("Scene tree : "+QString(GetName().data()));
2538 fSceneTreeComponentTreeWidget->setColumnHidden (1,true); // copy number
2539 fSceneTreeComponentTreeWidget->setColumnHidden (2,true); // PO index
2540 fSceneTreeComponentTreeWidget->setColumnHidden (3,true); // Informations
2541 // data(0) : POindex
2542 // data(1) : copy number
2543 // data(2) : g4color
2544
2545 vLayout->addWidget(fSceneTreeComponentTreeWidget);
2546
2547 connect(fSceneTreeComponentTreeWidget,SIGNAL(itemChanged(QTreeWidgetItem*, int)),SLOT(sceneTreeComponentItemChanged(QTreeWidgetItem*, int)));
2548 connect(fSceneTreeComponentTreeWidget,SIGNAL(itemSelectionChanged ()),SLOT(sceneTreeComponentSelected()));
2549 connect(fSceneTreeComponentTreeWidget,SIGNAL(itemDoubleClicked ( QTreeWidgetItem*, int)),SLOT(changeColorAndTransparency( QTreeWidgetItem*, int)));
2550
2551
2552 // Depth slider
2553 QWidget *helpWidget = new QWidget();
2554 QHBoxLayout *helpLayout = new QHBoxLayout();
2555
2556 QWidget* depthWidget = new QWidget();
2557 QWidget *showBox = new QWidget(depthWidget);
2558 QHBoxLayout *showBoxLayout = new QHBoxLayout();
2559
2560 // reduce margins
2561 showBoxLayout->setContentsMargins(5,5,5,5);
2562
2563 QLabel *zero = new QLabel();
2564 zero->setText("Show all");
2565 QLabel *one = new QLabel();
2566 one->setText("Hide all");
2567 fSceneTreeDepthSlider = new QSlider ( Qt::Horizontal);
2568 fSceneTreeDepthSlider->setMaximum (1000);
2569 fSceneTreeDepthSlider->setMinimum (0);
2570 fSceneTreeDepthSlider->setTickPosition(QSlider::TicksAbove);
2571 // set a minimum size
2572 fSceneTreeDepthSlider->setMinimumWidth (40);
2573
2574 showBoxLayout->addWidget(zero);
2575 showBoxLayout->addWidget(fSceneTreeDepthSlider);
2576 showBoxLayout->addWidget(one);
2577
2578 showBox->setLayout(showBoxLayout);
2579
2580 helpLayout->addWidget(showBox);
2581 helpWidget->setLayout(helpLayout);
2582 helpLayout->setContentsMargins(0,0,0,0);
2583
2584 vLayout->addWidget(helpWidget);
2585
2586 connect( fSceneTreeDepthSlider, SIGNAL( valueChanged(int) ), this, SLOT( changeDepthInSceneTree(int) ) );
2587 connect( fFilterOutput, SIGNAL( textEdited ( const QString &) ), this, SLOT(changeSearchSelection()));
2588 fTreeItemModels.clear();
2589
2590 fPVRootNodeCreate = false;
2591
2592 fMaxPOindexInserted = -1;
2593
2594
2595}
2596
2597
2598void G4OpenGLQtViewer::createViewerPropertiesWidget() {
2599
2600 // Get the pointer to the Viewer Properties widget
2601 fUIViewerPropertiesWidget = fUiQt->GetViewerPropertiesWidget();
2602
2603 if (!fUIViewerPropertiesWidget) {
2604 return;
2605 }
2606
2607 // remove previous widgets
2608 QLayoutItem * wItem;
2609 if (fUIViewerPropertiesWidget->layout()->count()) {
2610 while ((wItem = fUIViewerPropertiesWidget->layout()->takeAt(0)) != 0) {
2611 delete wItem->widget();
2612 delete wItem;
2613 }
2614 }
2615
2616 // add properties
2617 QGroupBox *groupBox = new QGroupBox();
2618 groupBox->setTitle(GetName().data());
2619 QVBoxLayout *vbox = new QVBoxLayout;
2620
2621 // add properties content
2622 fViewerPropertiesTableWidget = new QTableWidget();
2623
2624 QSizePolicy vPolicy = fViewerPropertiesTableWidget->sizePolicy();
2625 vPolicy.setVerticalStretch(4);
2626
2627 vbox->addWidget(fViewerPropertiesTableWidget);
2628 groupBox->setLayout(vbox);
2629 fUIViewerPropertiesWidget->layout()->addWidget(groupBox);
2630
2631 connect(fViewerPropertiesTableWidget, SIGNAL(itemChanged(QTableWidgetItem*)),this, SLOT(tableWidgetViewerSetItemChanged(QTableWidgetItem *)));
2632
2634
2635 QDialog* dial = static_cast<QDialog*> (fUIViewerPropertiesWidget->parent());
2636 if (dial) {
2637 // change name
2638 dial->setWindowTitle(QString("Viewer properties - ")+GetName());
2639 }
2640}
2641
2642
2643void G4OpenGLQtViewer::createPickInfosWidget(){
2644
2645 // Get the pointer to the Pick infos widget
2646 fUIPickInfosWidget = fUiQt->GetPickInfosWidget();
2647
2648 if (!fUIPickInfosWidget) {
2649 return;
2650 }
2651
2652 // remove previous widgets
2653 QLayoutItem * wItem;
2654 if (fUIPickInfosWidget->layout()->count()) {
2655 while ((wItem = fUIPickInfosWidget->layout()->takeAt(0)) != 0) {
2656 delete wItem->widget();
2657 delete wItem;
2658 }
2659 }
2660
2661 QGroupBox *groupBox = new QGroupBox("");
2662 QVBoxLayout *vbox = new QVBoxLayout;
2663
2664 // add picking infos
2665 QWidget *pickingInfoWidget = new QWidget();
2666 QHBoxLayout *pickingInfoLayout = new QHBoxLayout();
2667
2668 pickingInfoWidget->setStyleSheet ("padding-left: 0px; border:0px;");
2669 pickingInfoWidget->setLayout(pickingInfoLayout);
2670
2671 vbox->addWidget(pickingInfoWidget);
2672 // add picking content
2673
2674 fPickInfosScrollArea = new QScrollArea();
2675 fPickInfosScrollArea->setWidgetResizable(true);
2676
2677
2678 fPickInfosWidget = new QWidget();
2679 fPickInfosWidget->setStyleSheet ("padding: 0px ");
2680
2681 QVBoxLayout* vLayout = new QVBoxLayout();
2682 fPickInfosWidget->setLayout (vLayout);
2683 fPickInfosScrollArea->setWidget(fPickInfosWidget);
2684
2685 QSizePolicy vPolicy = fPickInfosWidget->sizePolicy();
2686 vPolicy.setVerticalStretch(4);
2687 vbox->addWidget(fPickInfosScrollArea);
2688 pickingInfoLayout->setContentsMargins(0,0,0,0);
2689 vLayout->setContentsMargins(0,0,0,0);
2690 vbox->setContentsMargins(1,1,1,1);
2691
2692 groupBox->setLayout(vbox);
2693 fUIPickInfosWidget->layout()->addWidget(groupBox);
2694
2695 updatePickInfosWidget(fLastPickPoint.x(),fLastPickPoint.y());
2696}
2697
2698
2699// set the component to check/unchecked, also go into its child
2700// and set the same status to all his childs
2701void G4OpenGLQtViewer::setCheckComponent(QTreeWidgetItem* item,bool check)
2702{
2703 if (item) {
2704
2705 const PVPath& fullPath = fTreeItemModels[item->data(0,Qt::UserRole).toInt()];
2706 // If a physical volume
2707 if (fullPath.size() > 0) {
2708 fMouseOnSceneTree = true;
2709 }
2710 }
2711
2712 if (item != NULL) {
2713 if (check) {
2714 item->setCheckState(0,Qt::Checked);
2715 } else {
2716 item->setCheckState(0,Qt::Unchecked);
2717 }
2718 updatePositivePoIndexSceneTreeWidgetQuickMap(item->data(0,Qt::UserRole).toInt(),item);
2719 int nChildCount = item->childCount();
2720 for (int i = 0; i < nChildCount; i++) {
2721 setCheckComponent(item->child(i),check);
2722 }
2723 }
2724}
2725
2726#if QT_VERSION < 0x060000
2727#else
2728//G.Barrand : from stackoverflow "How to render text with QOpenGLWidget":
2729static void transform_point(GLdouble out[4], const GLdouble model[16], const GLdouble in[4])
2730{
2731#define M(row,col) model[col*4+row]
2732 out[0] =
2733 M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];
2734 out[1] =
2735 M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];
2736 out[2] =
2737 M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];
2738 out[3] =
2739 M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];
2740#undef M
2741}
2742inline GLint project_point(GLdouble objx, GLdouble objy, GLdouble objz,
2743 const GLdouble model[16], const GLdouble proj[16],
2744 const GLint viewport[4],
2745 GLdouble * winx, GLdouble * winy, GLdouble * winz)
2746{
2747 GLdouble in[4], out[4];
2748
2749 in[0] = objx;
2750 in[1] = objy;
2751 in[2] = objz;
2752 in[3] = 1.0;
2753 transform_point(out, model, in);
2754 transform_point(in, proj, out);
2755
2756 if (in[3] == 0.0)
2757 return GL_FALSE;
2758
2759 in[0] /= in[3];
2760 in[1] /= in[3];
2761 in[2] /= in[3];
2762
2763 *winx = viewport[0] + (1 + in[0]) * viewport[2] / 2;
2764 *winy = viewport[1] + (1 + in[1]) * viewport[3] / 2;
2765
2766 *winz = (1 + in[2]) / 2;
2767 return GL_TRUE;
2768}
2769static void render_text(QOpenGLWidget& widget,
2770 double world_x, double world_y, double world_z,
2771 double offset_x, double offset_y,
2772 const QFont& font,
2773 const QColor& color,
2774 const char* text)
2775{
2776 GLdouble model[4][4];
2777 glGetDoublev(GL_MODELVIEW_MATRIX, &model[0][0]);
2778 GLdouble proj[4][4];
2779 glGetDoublev(GL_PROJECTION_MATRIX, &proj[0][0]);
2780 GLint view[4];
2781 glGetIntegerv(GL_VIEWPORT, &view[0]);
2782
2783 GLdouble textPosX = 0, textPosY = 0, textPosZ = 0;
2784 project_point(world_x, world_y, world_z,
2785 &model[0][0], &proj[0][0], &view[0],
2786 &textPosX, &textPosY, &textPosZ);
2787
2788 textPosX /= GLdouble(widget.devicePixelRatio());
2789 textPosY /= GLdouble(widget.devicePixelRatio());
2790
2791 textPosY = GLdouble(widget.height()) - textPosY; // y is inverted
2792
2793 textPosX += offset_x;
2794 textPosY += offset_y;
2795
2796 GLboolean GL_BLEND_enabled = glIsEnabled(GL_BLEND);
2797
2798 QPainter painter(&widget);
2799 painter.setPen(color);
2800 painter.setFont(font);
2801 painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
2802 painter.drawText(textPosX, textPosY, text);
2803 painter.end();
2804
2805 if(GL_BLEND_enabled==GL_TRUE) {
2806 ::glEnable(GL_BLEND);
2807 ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2808 }
2809}
2810#endif
2811
2813{
2814 auto* qGLW = dynamic_cast<G4QGLWidgetType*> (fGLWidget) ;
2815 if (! qGLW) {
2816 return;
2817 }
2818 if (isGl2psWriting()) {
2819
2821
2822 } else {
2823
2824 if (!fGLWidget) return;
2825
2826 if (!G4Threading::IsMasterThread()) return;
2827
2829 G4double size = fSceneHandler.GetMarkerSize(g4text,sizeType);
2830
2831 QFont font = QFont();
2832 font.setPointSizeF(size);
2833
2834 const G4Colour& c = fSceneHandler.GetTextColour(g4text);
2835
2836 G4Point3D position = g4text.GetPosition();
2837
2838 const G4String& textString = g4text.GetText();
2839 const char* textCString = textString.c_str();
2840
2841 // Calculate move for centre and right adjustment
2842 QFontMetrics f(font);
2843 G4double span = f.boundingRect(textCString).width();
2844
2845 G4double xmove = 0.;
2846 G4double ymove = 0.;
2847
2848 switch (g4text.GetLayout()) {
2849 case G4Text::left: break;
2850 case G4Text::centre: xmove -= span / 2.; break;
2851 case G4Text::right: xmove -= span;
2852 }
2853
2854 //Add offsets
2855 xmove += g4text.GetXOffset();
2856 ymove += g4text.GetYOffset();
2857
2858#if QT_VERSION < 0x060000
2859 glColor4d(c.GetRed(),c.GetGreen(),c.GetBlue(),c.GetAlpha());
2860 glRasterPos3d(position.x(),position.y(),position.z());
2861 // xmove, ymove in pixels - or are they?
2862#ifdef __APPLE__
2863 const G4double fudgeFactor = 2.;
2864#else
2865 const G4double fudgeFactor = 1.;
2866#endif
2867 xmove *= fudgeFactor;
2868 ymove *= fudgeFactor;
2869 qGLW->renderText
2870 ((position.x()+(2*xmove)/getWinWidth()),
2871 (position.y()+(2*ymove)/getWinHeight()),
2872 position.z(),
2873 textCString,
2874 font);
2875#else
2876 QColor color((int)(c.GetRed()*255),
2877 (int)(c.GetGreen()*255),
2878 (int)(c.GetBlue()*255),
2879 (int)(c.GetAlpha()*255));
2880 render_text(*qGLW,
2881 position.x(),position.y(),position.z(),
2882 xmove,ymove,
2883 font,color,textCString);
2884#endif
2885 }
2886}
2887
2888
2891 fDeltaDepth = 0.01;
2892 fDeltaZoom = 0.05;
2893}
2894
2895
2896
2897
2898void G4OpenGLQtViewer::addPVSceneTreeElement(const G4String& model, G4PhysicalVolumeModel* pPVModel, int currentPOIndex) {
2899
2900 const QString& modelShortName = getModelShortName(model);
2901
2902 if (modelShortName == "") {
2903 return ;
2904 }
2905 // try to init it
2906 if (fSceneTreeComponentTreeWidget == NULL) {
2907 createSceneTreeComponent();
2908 }
2909
2910 // if no UI
2911 if (fSceneTreeComponentTreeWidget == NULL) {
2912 return;
2913 }
2914
2915 fSceneTreeComponentTreeWidget->blockSignals(true);
2916
2917 // Create the "volume" node if not
2918 // if (fSceneTreeComponentTreeWidget->topLevelItemCount () == 0) {
2919 if (!fPVRootNodeCreate) {
2920 const G4Colour& color = fSceneHandler.GetColour();
2921
2922 fModelShortNameItem = createTreeWidgetItem(pPVModel->GetFullPVPath(),
2923 modelShortName,
2924 0, // currentPVCopyNb
2925 -1, // currentPVPOIndex
2926 "",
2927 Qt::Checked,
2928 NULL,
2929 color);
2930 fPVRootNodeCreate = true;
2931 }
2932
2933 bool added = parseAndInsertInSceneTree(fModelShortNameItem,pPVModel,0,modelShortName,0,currentPOIndex);
2934 if (!added) {
2935 }
2936
2937 fSceneTreeComponentTreeWidget->blockSignals(false);
2938
2939}
2940
2941
2942/**
2943 if treeNode is NULL, then add this treeNode to the TreeWidget
2944 @return the inserted item
2945*/
2946QTreeWidgetItem* G4OpenGLQtViewer::createTreeWidgetItem(
2947 const PVPath& fullPath
2948 ,const QString& name
2949 ,int copyNb
2950 ,int POIndex
2951 ,const QString& logicalName
2952 ,Qt::CheckState state
2953 ,QTreeWidgetItem * parentTreeNode
2954 ,const G4Colour& color
2955) {
2956
2957 // Set depth
2958 if (fullPath.size() > fSceneTreeDepth) {
2959 fSceneTreeDepth = (unsigned int)fullPath.size();
2960 // Change slider value
2961 if (fSceneTreeDepthSlider) {
2962 fSceneTreeDepthSlider->setTickInterval(1000/(fSceneTreeDepth+1));
2963 }
2964 }
2965 QTreeWidgetItem * newItem = NULL;
2966 if (parentTreeNode == NULL) {
2967 newItem = new QTreeWidgetItem();
2968 fSceneTreeComponentTreeWidget->addTopLevelItem(newItem);
2969 } else {
2970 newItem = new QTreeWidgetItem(parentTreeNode);
2971 fSceneTreeComponentTreeWidget->addTopLevelItem(parentTreeNode);
2972 }
2973
2974
2975 newItem->setText(0,name);
2976 newItem->setData(1,Qt::UserRole,copyNb);
2977 newItem->setText(2,QString::number(POIndex));
2978 newItem->setData(0, Qt::UserRole, POIndex);
2979 newItem->setText(3,logicalName);
2980 newItem->setFlags(newItem->flags()|Qt::ItemIsUserCheckable);
2981 newItem->setCheckState(0,state);
2982 newItem->setExpanded(true);
2983 updatePositivePoIndexSceneTreeWidgetQuickMap(POIndex,newItem);
2984
2985 changeQColorForTreeWidgetItem(newItem,QColor((int)(color.GetRed()*255),
2986 (int)(color.GetGreen()*255),
2987 (int)(color.GetBlue()*255),
2988 (int)(color.GetAlpha()*255)));
2989
2990 // If invisible
2991 if ((state == Qt::Unchecked) && (POIndex == -1)) {
2992 newItem->setForeground (0, QBrush( Qt::gray) );
2993
2994 // Set a tootip
2995 newItem->setToolTip (0,QString(
2996 "This node exists in the geometry but has not been\n")+
2997 "drawn, perhaps because it has been set invisible. It \n"+
2998 "cannot be made visible with a click on the button.\n"+
2999 "To see it, change the visibility, for example, with \n"+
3000 "/vis/geometry/set/visibility " + logicalName + " 0 true\n"+
3001 "and rebuild the view with /vis/viewer/rebuild.\n"+
3002 "Click here will only show/hide all child components");
3003 } else {
3004 // Set a tootip
3005 newItem->setToolTip (0,QString("double-click to change the color"));
3006 }
3007
3008 // special case: if alpha=0, it is a totally transparent objet,
3009 // then, do not redraw it
3010 if (color.GetAlpha() == 0) {
3011 state = Qt::Unchecked;
3012 newItem->setCheckState(0,state);
3013 updatePositivePoIndexSceneTreeWidgetQuickMap(POIndex,newItem);
3014 }
3015
3016 fTreeItemModels.insert(std::pair <int, PVPath > (POIndex,fullPath) );
3017
3018 // Check last status of this item and change if necessary
3019 // open/close/hidden/visible/selected
3020 changeOpenCloseVisibleHiddenSelectedColorSceneTreeElement(newItem);
3021 return newItem;
3022}
3023
3024
3025//
3026// Recursive function.
3027// Try to insert the given item :
3028// - If not present and last item of the path: insert it and mark it CHECK
3029// - If not present and NOT last item of the path: insert it and mark it UNCHECKED
3030// - If already present and name/PO/Transformation identical, then it is a transparent
3031// object : Change the PO number and transparency
3032// - If already present and PO different, then it is an unvisible item : Have to
3033// set it visible
3034// - else : Create a new element
3035// @return true if inserted, false if already present
3036//
3037bool G4OpenGLQtViewer::parseAndInsertInSceneTree(
3038 QTreeWidgetItem * parentItem
3039 ,G4PhysicalVolumeModel* pPVModel
3040 ,unsigned int fullPathIndex
3041 ,const QString& parentRoot
3042 ,unsigned int currentIndexInTreeSceneHandler
3043 ,int currentPVPOIndex
3044) {
3045
3046 if (parentItem == NULL) {
3047 return false;
3048 }
3049
3050 const PVPath& fullPath = pPVModel->GetFullPVPath();
3051
3052 std::ostringstream oss;
3053 oss << fullPath.at(fullPathIndex).GetCopyNo();
3054 std::string currentPVName = G4String(fullPath.at(fullPathIndex).GetPhysicalVolume()->GetName()+" ["+oss.str()+"]").data();
3055
3056 int currentPVCopyNb = fullPath.at(fullPathIndex).GetCopyNo();
3057
3058 const G4Colour& color = fSceneHandler.GetColour();
3059
3060 // look in all children in order to get if their is already a
3061 // child corresponding:
3062 // - if so, go into this child
3063 // - if not : create it as invisible
3064
3065 // Realy quick check if the POindex is already there
3066 QTreeWidgetItem* subItem = NULL;
3067 QList<QTreeWidgetItem *> parentItemList;
3068
3069
3070 // first of all, very quick check if it was not the same as last one
3071
3072 // Check only if it is a transparent object
3073 // If it is the last item and it is not transparent -> nothing to look for,
3074 // simply add it.
3075 if ((currentIndexInTreeSceneHandler == (fullPath.size()-1)) && ((color.GetAlpha() == 1.))) {
3076 } else {
3077 QString lookForString = QString(currentPVName.c_str());
3078 for (int i = 0;i < parentItem->childCount(); i++ ) {
3079 if (parentItem->child(i)->text(0) == lookForString) {
3080 parentItemList.push_back(parentItem->child(i));
3081 }
3082 }
3083 }
3084
3085 for (int i = 0; i < parentItemList.size(); ++i) {
3086 const std::string& parentItemName = parentItemList.at(i)->text(0).toStdString();
3087 int parentItemCopyNb = parentItemList.at(i)->data(1,Qt::UserRole).toInt();
3088 int parentItemPOIndex = parentItemList.at(i)->data(0,Qt::UserRole).toInt();
3089
3090 // if already inside
3091 // -> return true
3092 // special case, do not have to deal with hierarchy except for PhysicalVolume
3093
3094
3095 /* Physical Volume AND copy number equal AND name equal */
3096 if (((parentRoot == fTouchableVolumes) && (currentPVCopyNb == parentItemCopyNb)
3097 && (currentPVName == parentItemName)) ||
3098 /* NOT a Physical Volume AND copy number equal */
3099 ((parentRoot != fTouchableVolumes) && (currentPVCopyNb == parentItemCopyNb)
3100 /*AND name equal AND PO index equal*/
3101 && (currentPVName == parentItemName) && (currentPVPOIndex == parentItemPOIndex) )) {
3102
3103 // then check for the Transform3D
3104 bool sameTransform = true;
3105 if (parentItemPOIndex >= 0) {
3106 const PVPath& fullPathTmp = fTreeItemModels[parentItemPOIndex];
3107 if (fullPathTmp.size() > 0) {
3108 if (fullPathTmp.at(fullPathTmp.size()-1).GetTransform () == pPVModel->GetTransformation ()) {
3109 sameTransform = true;
3110 } else {
3111 sameTransform = false;
3112 }
3113 }
3114 }
3115
3116 // Same transformation, then try to change the PO index
3117 if (sameTransform == true) {
3118 // already exist in the tree, is it a transparent object ?
3119 // If so, then have to change the PO index ONLY if it is the last
3120 // and then change the state ONLY if POIndex has change
3121 // If not, then go deaper
3122
3123 // last element
3124 if (currentIndexInTreeSceneHandler == (fullPath.size()-1)) {
3125
3126 parentItemList.at(i)->setText(2,QString::number(currentPVPOIndex));
3127 parentItemList.at(i)->setData(0, Qt::UserRole,currentPVPOIndex);
3128
3129 fTreeItemModels.insert(std::pair <int, PVPath >(currentPVPOIndex,fullPath) );
3130
3131 // Then remove tooltip and special font
3132 QFont f = QFont();
3133 parentItemList.at(i)->setFont (0,f);
3134
3135 // set foreground
3136 parentItemList.at(i)->setForeground (0,QBrush());
3137
3138 // Set a tootip
3139 parentItemList.at(i)->setToolTip (0,"");
3140
3141 changeQColorForTreeWidgetItem(parentItemList.at(i),QColor((int)(color.GetRed()*255),
3142 (int)(color.GetGreen()*255),
3143 (int)(color.GetBlue()*255),
3144 (int)(color.GetAlpha()*255)));
3145
3146 // set check only if there is something to display
3147 if (color.GetAlpha() > 0) {
3148 parentItemList.at(i)->setCheckState(0,Qt::Checked);
3149 updatePositivePoIndexSceneTreeWidgetQuickMap(currentPVPOIndex,parentItemList.at(i));
3150 }
3151 return false;
3152 } else {
3153 subItem = parentItemList.at(i);
3154 }
3155
3156 // Exists but not the end of path, then forget get it
3157 } else if (currentIndexInTreeSceneHandler < (fullPath.size()-1)) {
3158 subItem = parentItemList.at(i);
3159 }
3160 }
3161
3162 } // end for
3163
3164 // if it the last, then add it and set it checked
3165 if (currentIndexInTreeSceneHandler == (fullPath.size()-1)) {
3166 /* subItem =*/ createTreeWidgetItem(fullPath,
3167 QString(currentPVName.c_str()),
3168 currentPVCopyNb,
3169 currentPVPOIndex,
3170 QString(fullPath.at(fullPathIndex).GetPhysicalVolume()->GetLogicalVolume()->GetName().data()),
3171 Qt::Checked,
3172 parentItem,
3173 color);
3174
3175 if (currentPVPOIndex > fMaxPOindexInserted) {
3176 fMaxPOindexInserted = currentPVPOIndex;
3177 }
3178
3179 } else {
3180
3181 // if no child found, then this child is create and marked as invisible, then go inside
3182 if (subItem == NULL) {
3183
3184 if (currentIndexInTreeSceneHandler < (fullPath.size()-1)) {
3185 subItem = createTreeWidgetItem(fullPath,
3186 QString(currentPVName.c_str()),
3187 currentPVCopyNb,
3188 -1,
3189 QString(fullPath.at(fullPathIndex).GetPhysicalVolume()->GetLogicalVolume()->GetName().data()),
3190 Qt::Unchecked,
3191 parentItem,
3192 color);
3193 }
3194 }
3195
3196 return parseAndInsertInSceneTree(subItem,pPVModel,fullPathIndex+1,parentRoot,currentIndexInTreeSceneHandler+1,currentPVPOIndex);
3197 }
3198 return true;
3199}
3200
3201
3202void G4OpenGLQtViewer::changeOpenCloseVisibleHiddenSelectedColorSceneTreeElement(
3203 QTreeWidgetItem* subItem
3204)
3205{
3206 // Check if object with the same POIndex is the same in old tree
3207 QTreeWidgetItem* oldItem = NULL;
3208
3209 QTreeWidgetItem* foundItem = getOldTreeWidgetItem(subItem->data(0,Qt::UserRole).toInt());
3210
3211 if (foundItem != NULL) {
3212 if (isSameSceneTreeElement(foundItem,subItem)) {
3213 oldItem = foundItem;
3214 }
3215 }
3216 if (foundItem == NULL) { // PO should have change, parse all
3217
3218 // POindex > 0
3219 std::map <int, QTreeWidgetItem*>::const_iterator i;
3220 i = fOldPositivePoIndexSceneTreeWidgetQuickMap.cbegin();
3221 while (i != fOldPositivePoIndexSceneTreeWidgetQuickMap.cend()) {
3222 if (isSameSceneTreeElement(i->second,subItem)) {
3223 oldItem = i->second;
3224 i = fOldPositivePoIndexSceneTreeWidgetQuickMap.cend();
3225 } else {
3226 ++i;
3227 }
3228 }
3229 // POindex == 0 ?
3230 if (oldItem == NULL) {
3231 std::size_t a = 0;
3232 while (a < fOldNullPoIndexSceneTreeWidgetQuickVector.size()) {
3233 if (isSameSceneTreeElement(fOldNullPoIndexSceneTreeWidgetQuickVector[a],subItem)) {
3234 oldItem = fOldNullPoIndexSceneTreeWidgetQuickVector[a];
3235 a = fOldNullPoIndexSceneTreeWidgetQuickVector.size();
3236 } else {
3237 ++a;
3238 }
3239 }
3240 }
3241 }
3242
3243 // if found : retore old state
3244 if (oldItem != NULL) {
3245 subItem->setFlags(oldItem->flags()); // flags
3246 subItem->setCheckState(0,oldItem->checkState(0)); // check state
3247 subItem->setSelected(oldItem->isSelected()); // selected
3248 subItem->setExpanded(oldItem->isExpanded ()); // expand
3249
3250 // change color
3251 // when we call this function, the color in the item is the one of vis Attr
3252
3253 std::map <int, QTreeWidgetItem* >::iterator it;
3254
3255 // getOldPO
3256 int oldPOIndex = oldItem->data(0,Qt::UserRole).toInt();
3257 it = fOldPositivePoIndexSceneTreeWidgetQuickMap.find(oldPOIndex);
3258 QColor color;
3259
3260 // get old Vis Attr Color
3261 std::map <int, QColor >::iterator itVis;
3262 itVis = fOldVisAttrColorMap.find(oldPOIndex);
3263
3264 QColor oldVisAttrColor;
3265 const QColor& newVisAttrColor = subItem->data(2,Qt::UserRole).value<QColor>();
3266
3267 bool visAttrChange = false;
3268 // if old vis attr color found
3269 if (itVis != fOldVisAttrColorMap.end()) {
3270 oldVisAttrColor = itVis->second;
3271 if (oldVisAttrColor != newVisAttrColor) {
3272 visAttrChange = true;
3273 }
3274 } else {
3275 visAttrChange = true;
3276 }
3277
3278 if (visAttrChange) {
3279 fOldVisAttrColorMap.insert(std::pair <int, QColor > (subItem->data(0,Qt::UserRole).toInt(),newVisAttrColor) );
3280
3281 } else { // if no changes, get old PO value
3282 // if old PO found
3283 if (it != fOldPositivePoIndexSceneTreeWidgetQuickMap.end()) {
3284 color = (it->second)->data(2,Qt::UserRole).value<QColor>();
3285 } else {
3286 color = oldItem->data(2,Qt::UserRole).value<QColor>();
3287 }
3288 changeQColorForTreeWidgetItem(subItem,color);
3289 }
3290 }
3291
3292 return;
3293}
3294
3295
3296
3297// Check if both items are identical.
3298// For that, check name, copy number, transformation
3299// special case for "non Touchables", do not check the PO index, check only the name
3300bool G4OpenGLQtViewer::isSameSceneTreeElement(
3301 QTreeWidgetItem* parentOldItem
3302 ,QTreeWidgetItem* parentNewItem
3303) {
3304
3305 int newPO = -1;
3306 int oldPO = -1;
3307
3308 int newCpNumber = -1;
3309 int oldCpNumber = -1;
3310
3311 bool firstWhile = true;
3312
3313 while ((parentOldItem != NULL) && (parentNewItem != NULL)) {
3314
3315 // check transform, optimize getting data(..,..) that consume lot of time
3316 if (!firstWhile) {
3317 oldPO = parentOldItem->data(0,Qt::UserRole).toInt();
3318 newPO = parentNewItem->data(0,Qt::UserRole).toInt();
3319 }
3320 firstWhile = false;
3321
3322 if ((oldPO >= 0) &&
3323 (newPO >= 0)) {
3324 const PVPath& oldFullPath = fOldTreeItemModels[oldPO];
3325 const PVPath& newFullPath = fTreeItemModels[newPO];
3326 if ((oldFullPath.size() > 0) &&
3327 (newFullPath.size() > 0)) {
3328 if (oldFullPath.size() != newFullPath.size()) {
3329 return false;
3330 }
3331 if (oldFullPath.at(oldFullPath.size()-1).GetTransform () == newFullPath.at(newFullPath.size()-1).GetTransform ()) {
3332 newCpNumber = newFullPath.at(newFullPath.size()-1).GetCopyNo();
3333 oldCpNumber = oldFullPath.at(oldFullPath.size()-1).GetCopyNo();
3334 // ok
3335 } else {
3336 return false;
3337 }
3338 }
3339 }
3340
3341 // Check copy Number
3342 if (oldCpNumber == -1) {
3343 oldCpNumber = parentOldItem->data(1,Qt::UserRole).toInt();
3344 }
3345 if (newCpNumber == -1) {
3346 newCpNumber = parentNewItem->data(1,Qt::UserRole).toInt();
3347 }
3348 if ((oldCpNumber != newCpNumber) ||
3349 // Check name
3350 (parentOldItem->text(0) != parentNewItem->text(0)) ) {
3351 // try to optimize
3352 return false;
3353 } else if ((parentOldItem->text(0) != parentNewItem->text(0)) || // Logical Name
3354 (parentOldItem->text(3) != parentNewItem->text(3))) { // Check logical name
3355 return false;
3356 } else {
3357 parentOldItem = parentOldItem->parent();
3358 parentNewItem = parentNewItem->parent();
3359 }
3360 } // end while
3361
3362 return true;
3363}
3364
3365
3367 const G4String& model
3368 ,int currentPOIndex
3369 ,const std::string& modelDescription
3370 ,const G4Visible& visible
3371) {
3372
3373 QString modelShortName = getModelShortName(model);
3374 G4Colour color;
3375
3376 // Special case for text
3377 try {
3378 const G4Text& g4Text = dynamic_cast<const G4Text&>(visible);
3379 color = fSceneHandler.GetTextColour(g4Text);
3380 }
3381 catch (const std::bad_cast&) {
3382 color = fSceneHandler.GetColour();
3383 }
3384
3385 // Special case for marker
3386 try {
3387 const G4VMarker& g4Marker = dynamic_cast<const G4VMarker&>(visible);
3388 if (g4Marker.GetInfo() != "") {
3389 modelShortName = g4Marker.GetInfo();
3390 }
3391 }
3392 catch (const std::bad_cast&) {}
3393
3394 if (modelShortName == "") {
3395 return ;
3396 }
3397 // try to init it
3398 if (fSceneTreeComponentTreeWidget == NULL) {
3399 createSceneTreeComponent();
3400 }
3401
3402 // if no UI
3403 if (fSceneTreeComponentTreeWidget == NULL) {
3404 return;
3405 }
3406
3407 fSceneTreeComponentTreeWidget->blockSignals(true);
3408
3409 // Create the "Model" node if not
3410
3411 QList<QTreeWidgetItem *> resItem;
3412 resItem = fSceneTreeComponentTreeWidget->findItems (modelShortName, Qt::MatchExactly, 0 );
3413 QTreeWidgetItem * currentItem = NULL;
3414 const PVPath tmpFullPath;
3415
3416 if (resItem.empty()) {
3417 currentItem = createTreeWidgetItem(tmpFullPath,
3418 modelShortName,
3419 0, // currentPVCopyNb
3420 -1, // currentPVPOIndex
3421 "",
3422 Qt::Checked,
3423 NULL,
3424 color);
3425 } else {
3426 currentItem = resItem.first();
3427 }
3428
3429 // Is this volume already in the tree AND PO is not the same?
3430 const QList<QTreeWidgetItem *>&
3431 resItems = fSceneTreeComponentTreeWidget->findItems (QString(modelDescription.c_str()), Qt::MatchFixedString| Qt::MatchCaseSensitive|Qt::MatchRecursive, 0 );
3432
3433 bool alreadyPresent = false;
3434 for (int i = 0; i < resItems.size(); ++i) {
3435 if (currentPOIndex == resItems.at(i)->data(0,Qt::UserRole).toInt()) {
3436 alreadyPresent = true;
3437 }
3438 }
3439 if (!alreadyPresent) {
3440 createTreeWidgetItem(tmpFullPath,
3441 modelShortName,
3442 0, // currentPVCopyNb
3443 currentPOIndex,
3444 "",
3445 Qt::Checked,
3446 currentItem,
3447 color);
3448 }
3449 fSceneTreeComponentTreeWidget->blockSignals(false);
3450
3451}
3452
3453
3454/**
3455 Get the short name for a given label
3456*/
3457QString G4OpenGLQtViewer::getModelShortName(const G4String& model) {
3458
3459 QString modelShortName = model.data();
3460 if (modelShortName.mid(0,modelShortName.indexOf(" ")) == "G4PhysicalVolumeModel") {
3461 modelShortName = fTouchableVolumes;
3462 } else {
3463 if (modelShortName.mid(0,2) == "G4") {
3464 modelShortName = modelShortName.mid(2);
3465 }
3466 if (modelShortName.indexOf("Model") != -1) {
3467 modelShortName = modelShortName.mid(0,modelShortName.indexOf("Model"));
3468 }
3469 }
3470 return modelShortName;
3471}
3472
3473
3474
3476
3477 // If no scene tree (Immediate viewer)
3478 if (fSceneTreeComponentTreeWidget == NULL) {
3479 return false;
3480 }
3481
3482 // should be the next one
3483 // Prevent to get out the std::map
3484 if (fLastSceneTreeWidgetAskForIterator != fLastSceneTreeWidgetAskForIteratorEnd) {
3485 fLastSceneTreeWidgetAskForIterator++;
3486 }
3487 QTreeWidgetItem* item = getTreeWidgetItem(POindex);
3488
3489 if (item != NULL) {
3490 if ( item->checkState(0) == Qt::Checked) {
3491 return true;
3492 }
3493 }
3494 return false;
3495}
3496
3497
3498bool G4OpenGLQtViewer::parseAndCheckVisibility(QTreeWidgetItem * treeNode,int POindex){
3499 bool isFound = false;
3500 for (int i = 0; i < treeNode->childCount() ; ++i) {
3501
3502 if (treeNode->child(i)->data(0,Qt::UserRole).toInt() == POindex) {
3503 if (treeNode->child(i)->checkState(0) == Qt::Checked) {
3504 return true;
3505 }
3506 }
3507 isFound = parseAndCheckVisibility(treeNode->child(i),POindex);
3508 if (isFound) {
3509 return true;
3510 }
3511 } // end for
3512 return false;
3513}
3514
3515
3516std::string G4OpenGLQtViewer::parseSceneTreeAndSaveState(){
3517 std::string commandLine = "";
3518 for (int b=0;b<fSceneTreeComponentTreeWidget->topLevelItemCount();b++) {
3519 commandLine += parseSceneTreeElementAndSaveState(fSceneTreeComponentTreeWidget->topLevelItem(b),1)+"\n";
3520 }
3521 if (commandLine != "") {
3522 commandLine = std::string("# Disable auto refresh and quieten vis messages whilst scene and\n") +
3523 "# trajectories are established:\n" +
3524 "/vis/viewer/set/autoRefresh false\n" +
3525 "/vis/verbose errors" +
3526 commandLine +
3527 "# Re-establish auto refreshing and verbosity:\n" +
3528 "/vis/viewer/set/autoRefresh true\n" +
3529 "/vis/verbose confirmations\n";
3530 }
3531 return commandLine;
3532}
3533
3534
3535std::string G4OpenGLQtViewer::parseSceneTreeElementAndSaveState(QTreeWidgetItem* item, unsigned int level){
3536 // parse current item
3537 std::string str( level, ' ' );
3538 std::string commandLine = "\n#"+ str + "PV Name: " + item->text(0).toStdString();
3539
3540 if (item->text(3) != "") {
3541 commandLine += " LV Name: "+item->text(3).toStdString()+"\n";
3542 // save check state
3543 commandLine += "/vis/geometry/set/visibility " + item->text(3).toStdString() + " ! "; // let default value for depth
3544 if (item->checkState(0) == Qt::Checked) {
3545 commandLine += "1";
3546 }
3547 if (item->checkState(0) == Qt::Unchecked) {
3548 commandLine += "0";
3549 }
3550 commandLine +="\n";
3551
3552 // save color
3553 const QColor& c = item->data(2,Qt::UserRole).value<QColor>();
3554 std::stringstream red;
3555 red << ((double)c.red())/255;
3556 std::stringstream green;
3557 green << (double)c.green()/255;
3558 std::stringstream blue;
3559 blue << ((double)c.blue())/255;
3560 std::stringstream alpha;
3561 alpha << ((double)c.alpha())/255;
3562
3563 commandLine += "/vis/geometry/set/colour " + item->text(3).toStdString() + " ! " + red.str() + " " + green.str() + " " + blue.str() + " " + alpha.str()+"\n";
3564
3565 } else {
3566 commandLine += "\n";
3567 }
3568
3569 // parse childs
3570 for (int b=0;b< item->childCount();b++) {
3571 commandLine += parseSceneTreeElementAndSaveState(item->child(b),level+1);
3572 }
3573
3574 return commandLine;
3575}
3576
3577
3578void G4OpenGLQtViewer::sceneTreeComponentItemChanged(QTreeWidgetItem* item, int) {
3579
3580 if (fCheckSceneTreeComponentSignalLock == false) {
3581 fCheckSceneTreeComponentSignalLock = true;
3582 G4bool checked = false;
3583 if (item->checkState(0) == Qt::Checked) {
3584 checked = true;
3585 }
3586 setCheckComponent(item,checked);
3587 updateQWidget();
3588
3589 fCheckSceneTreeComponentSignalLock = false;
3590 }
3591}
3592
3593
3594void G4OpenGLQtViewer::sceneTreeComponentSelected() {
3595}
3596
3597void G4OpenGLQtViewer::changeDepthInSceneTree (int val){
3598
3599 // If no scene tree (Immediate viewer)
3600 if (fSceneTreeComponentTreeWidget == NULL) {
3601 return;
3602 }
3603
3604 // max depth : fSceneTreeDepth
3605 // val is between 0 and 1
3606 // 0 .1 .2 .3 .4 .5 .6 .7 .8 .9 1
3607 // 1 1.4 2
3608 // 1 2 3 4
3609
3610 // Get the depth :
3611 double depth = 1 + ((double)val)/1000 * ((double)fSceneTreeDepth+1);
3612
3613 // lock update on scene tree items
3614 fCheckSceneTreeComponentSignalLock = true;
3615
3616 // Disable redraw each time !
3617 G4bool currentAutoRefresh = fVP.IsAutoRefresh();
3618 fVP.SetAutoRefresh(false);
3619
3620 for (int b=0;b<fSceneTreeComponentTreeWidget->topLevelItemCount();b++) {
3621 changeDepthOnSceneTreeItem(depth,1.,fSceneTreeComponentTreeWidget->topLevelItem(b));
3622 }
3623
3624 // Enable redraw !
3625 fVP.SetAutoRefresh(currentAutoRefresh);
3626 updateQWidget();
3627
3628 // unlock update on scene tree items
3629 fCheckSceneTreeComponentSignalLock = false;
3630
3631}
3632
3633
3634void G4OpenGLQtViewer::changeColorAndTransparency(QTreeWidgetItem* item,int) {
3635
3636 if (item == NULL) {
3637 return;
3638 }
3639 const QColor& old = QColor(item->data(2,Qt::UserRole).value<QColor>());
3640
3641 const QColor& color = QColorDialog::getColor(old,
3642 fSceneTreeComponentTreeWidget,
3643 " Get color and transparency",
3644 QColorDialog::ShowAlphaChannel);
3645
3646 if (color.isValid()) {
3647
3648 changeColorAndTransparency(item->data(0,Qt::UserRole).toInt(),
3649 G4Colour (((G4double)color.red())/255,
3650 ((G4double)color.green())/255,
3651 ((G4double)color.blue())/255,
3652 ((G4double)color.alpha())/255));
3653
3654 // set scene tree parameters
3655 changeQColorForTreeWidgetItem(item,color);
3656 }
3657}
3658
3659
3660void G4OpenGLQtViewer::changeColorAndTransparency(GLuint index, G4Color /*color*/) {
3661
3662 // change vis attributes to set new colour
3663 G4int iPO = index;
3664 if (iPO >= 0 && fTreeItemModels.find(iPO) != fTreeItemModels.end()) {
3665 const PVPath& fullPath = fTreeItemModels[iPO];
3666 // If a physical volume
3667 if (fullPath.size()) {
3668 fMouseOnSceneTree = true;
3669 }
3670 }
3671}
3672
3673
3675 // FIXME 09/2014 : Could be optimize by searching in a tab instead of item->data
3676 QTreeWidgetItem* item = getTreeWidgetItem(poIndex);
3677
3678 if (item != NULL) {
3679
3680 const QColor& color = item->data(2,Qt::UserRole).value<QColor>();
3681 G4Colour g4c(((G4double)color.red())/255,
3682 ((G4double)color.green())/255,
3683 ((G4double)color.blue())/255,
3684 ((G4double)color.alpha())/255);
3685
3686 return g4c;
3687 }
3688 return G4Colour();
3689}
3690
3691
3692const std::vector<G4ModelingParameters::VisAttributesModifier>*
3694{
3695 static std::vector<G4ModelingParameters::VisAttributesModifier>
3696 privateVisAttributesModifiers;
3697
3698 privateVisAttributesModifiers.clear();
3699
3700// I don't think we need this. (JA Sep 2016).
3701// // For each modified touchable...
3702// std::map<int,PVPath>::const_iterator i;
3703// for (i = fTreeItemModels.begin();
3704// i != fTreeItemModels.end();
3705// ++i) {
3706//
3707// // How do I know if it's been modified or not?
3708//
3709// int iPO = i->first;
3710// const PVPath& fullPath = i->second;
3711//
3712// // If a physical volume
3713// if (fullPath.size()) {
3714//
3715// // const G4bool& visibilityChanged = ???
3716// // const G4bool& visibility = ???
3717// // const G4bool& colourChanged = ???
3718// // const QColor& colour = ???
3719// // G4Colour g4colour(((G4double)colour.red())/255,
3720// // ((G4double)colour.green())/255,
3721// // ((G4double)colour.blue())/255,
3722// // ((G4double)colour.alpha())/255);
3723// // Next 4 lines are for testing, to be replaced by the above...
3724// G4bool visibilityChanged = true;
3725// G4bool visibility = true;
3726// G4bool colourChanged = true;
3727// G4Colour g4colour(G4Colour::Red());
3728//
3729// // Instantiate a working copy of a G4VisAttributes object...
3730// G4VisAttributes workingVisAtts;
3731// // ...and use it to create vis attribute modifiers...
3732// if (visibilityChanged) {
3733// workingVisAtts.SetVisibility(visibility);
3734// privateVisAttributesModifiers.push_back
3735// (G4ModelingParameters::VisAttributesModifier
3736// (workingVisAtts,
3737// G4ModelingParameters::VASVisibility,
3738// fullPath));
3739// }
3740// if (colourChanged) {
3741// workingVisAtts.SetColour(g4colour);
3742// privateVisAttributesModifiers.push_back
3743// (G4ModelingParameters::VisAttributesModifier
3744// (workingVisAtts,
3745// G4ModelingParameters::VASColour,
3746// fullPath));
3747// }
3748// }
3749// }
3750
3751 return &privateVisAttributesModifiers;
3752}
3753
3754
3755void G4OpenGLQtViewer::changeSearchSelection()
3756{
3757 const QString& searchText = fFilterOutput->text();
3758 if (fSceneTreeComponentTreeWidget == NULL) {
3759 return;
3760 }
3761
3762 // unselect all
3763 for (int a=0; a<fSceneTreeComponentTreeWidget->topLevelItemCount(); a++) {
3764 fSceneTreeComponentTreeWidget->topLevelItem(a)->setExpanded(false);
3765 fSceneTreeComponentTreeWidget->topLevelItem(a)->setSelected(false);
3766 clearSceneTreeSelection(fSceneTreeComponentTreeWidget->topLevelItem(a));
3767 }
3768
3769 QList<QTreeWidgetItem *> itemList = fSceneTreeComponentTreeWidget->findItems (searchText,Qt::MatchContains | Qt::MatchRecursive,0);
3770
3771 for (int i = 0; i < itemList.size(); ++i) {
3772 QTreeWidgetItem* expandParentItem = itemList.at(i);
3773 while (expandParentItem->parent() != NULL) {
3774 expandParentItem->parent()->setExpanded(true);
3775 expandParentItem = expandParentItem->parent();
3776 }
3777 itemList.at(i)->setSelected(true);
3778 }
3779
3780}
3781
3782
3783void G4OpenGLQtViewer::clearSceneTreeSelection(QTreeWidgetItem* item) {
3784 for (int a=0; a<item->childCount(); a++) {
3785 item->child(a)->setSelected(false);
3786 item->child(a)->setExpanded(false);
3787 clearSceneTreeSelection(item->child(a));
3788 }
3789
3790}
3791
3792
3793bool G4OpenGLQtViewer::isPVVolume(QTreeWidgetItem* item) {
3794 QTreeWidgetItem* sParent = item;
3795 while (sParent->parent() != NULL) {
3796 sParent = sParent->parent();
3797 }
3798 if (sParent->text(0) != fTouchableVolumes) {
3799 return false;
3800 }
3801 // item is the "Touchable" node
3802 if (item->text(0) == fTouchableVolumes) {
3803 return false;
3804 }
3805 return true;
3806}
3807
3808
3809void G4OpenGLQtViewer::changeDepthOnSceneTreeItem(
3810 double lookForDepth
3811 ,double currentDepth
3812 ,QTreeWidgetItem* item
3813) {
3814 double transparencyLevel = 0.;
3815
3816 // look for a 2.2 depth and we are at level 3
3817 // -> Set all theses items to Opaque
3818 // ONLY if it is a PV volume !
3819 if (isPVVolume(item)) {
3820 if ((lookForDepth-currentDepth) < 0) {
3821 item->setCheckState(0,Qt::Checked);
3822 updatePositivePoIndexSceneTreeWidgetQuickMap(item->data(0,Qt::UserRole).toInt(),item);
3823 transparencyLevel = 1;
3824 } else if ((lookForDepth-currentDepth) > 1 ){
3825 item->setCheckState(0,Qt::Unchecked);
3826 updatePositivePoIndexSceneTreeWidgetQuickMap(item->data(0,Qt::UserRole).toInt(),item);
3827 transparencyLevel = 0;
3828 } else {
3829 item->setCheckState(0,Qt::Checked);
3830 updatePositivePoIndexSceneTreeWidgetQuickMap(item->data(0,Qt::UserRole).toInt(),item);
3831 transparencyLevel = 1-(lookForDepth-currentDepth);
3832 }
3833 }
3834
3835 if (item->data(0,Qt::UserRole).toInt() >= 0) {
3836 const G4Colour& color = getColorForPoIndex(item->data(0,Qt::UserRole).toInt());
3837
3838 // We are less depper (ex:tree depth:2) than lookForDepth (ex:3.1)
3839 // -> Have to hide this level ONLY if it was not hidden before
3840
3841 // Not on a top level item case
3842 // Do not set if it was already set
3843
3844 // Should add them all the time in case of an older command has change transparency
3845 // before. Should be checked in changeDepthInSceneTree for duplicated commands
3846 // Do not change transparency if not visible by humain (and avoid precision value
3847 // problems..)
3848 if (((color.GetAlpha()-transparencyLevel) > 0.000001) ||
3849 ((color.GetAlpha()-transparencyLevel) < -0.000001)) {
3850 if ((item->text(3) != "")) {
3851 // FIXME : Should not test this here because of transparent
3852 // volume that will came after and with a different alpha level
3853 // Good thing to do is to check and suppress doubles in changeDepthInSceneTree
3854 // and then check if last (transparents volumes) has to change alpha
3855
3856 changeQColorForTreeWidgetItem(item,QColor((int)(color.GetRed()*255),
3857 (int)(color.GetGreen()*255),
3858 (int)(color.GetBlue()*255),
3859 (int)(transparencyLevel*255)));
3860 }
3861 }
3862 }
3863
3864 for (int b=0;b< item->childCount();b++) {
3865 changeDepthOnSceneTreeItem(lookForDepth,currentDepth+1,item->child(b));
3866 }
3867}
3868
3869
3871 // be careful about calling this twice
3872
3873 if (fSceneTreeComponentTreeWidget) {
3874
3875 if (fSceneTreeComponentTreeWidget->topLevelItemCount () > 0) {
3876
3877 fPVRootNodeCreate = false;
3878
3879 // reset all old
3880 fOldPositivePoIndexSceneTreeWidgetQuickMap.clear();
3881 fOldNullPoIndexSceneTreeWidgetQuickVector.clear();
3882 fOldTreeItemModels.clear();
3883
3884 // Clone everything
3885 for (int b =0; b <fSceneTreeComponentTreeWidget->topLevelItemCount();b++) {
3886 // All tree widgets are in :
3887 // then we could get the old POindex and get
3888 // .visible/Hidden
3889 // .Check/Uncheck
3890 // .selected
3891 // .colour status from std::map
3892
3893 // clone top level items
3894 int poIndex = fSceneTreeComponentTreeWidget->topLevelItem(b)->data(0,Qt::UserRole).toInt();
3895 if (poIndex != -1) {
3896 fOldPositivePoIndexSceneTreeWidgetQuickMap.insert(std::pair <int, QTreeWidgetItem*> (poIndex,cloneWidgetItem(fSceneTreeComponentTreeWidget->topLevelItem(b))));
3897 } else {
3898 fOldNullPoIndexSceneTreeWidgetQuickVector.push_back(cloneWidgetItem(fSceneTreeComponentTreeWidget->topLevelItem(b)));
3899 }
3900
3901 // clone leaves
3902 cloneSceneTree(fSceneTreeComponentTreeWidget->topLevelItem(b));
3903 }
3904 // delete all elements
3905
3906 fOldTreeItemModels.insert(fTreeItemModels.begin(), fTreeItemModels.end());
3907
3908 // all is copy, then clear scene tree
3909 int tmp2 = fSceneTreeComponentTreeWidget->topLevelItemCount();
3910 while (tmp2 > 0) {
3911 delete fSceneTreeComponentTreeWidget->takeTopLevelItem (0);
3912 tmp2 = fSceneTreeComponentTreeWidget->topLevelItemCount();
3913 }
3914 fPositivePoIndexSceneTreeWidgetQuickMap.clear();
3915
3916 // put correct value in paramaters
3917 fOldLastSceneTreeWidgetAskForIterator = fOldPositivePoIndexSceneTreeWidgetQuickMap.begin();
3918 fOldLastSceneTreeWidgetAskForIteratorEnd = fOldPositivePoIndexSceneTreeWidgetQuickMap.end();
3919 fSceneTreeDepth = 1;
3920 fModelShortNameItem = NULL;
3921 fMaxPOindexInserted = -1;
3922
3923 }
3924 }
3925}
3926
3927
3928/**
3929 Clone :
3930 - Open/close
3931 - Visible/hidden
3932 - Selected
3933*/
3934QTreeWidgetItem * G4OpenGLQtViewer::cloneWidgetItem(QTreeWidgetItem* item) {
3935
3936 QTreeWidgetItem* cloneItem = new QTreeWidgetItem();
3937
3938 // Clone what is create createTreeWidgetItem step
3939
3940 cloneItem->setText(0,item->text(0));
3941 cloneItem->setData(1,Qt::UserRole,item->data(1,Qt::UserRole).toInt());
3942 cloneItem->setText(2,item->text(2));
3943 cloneItem->setData(0, Qt::UserRole,item->data(0,Qt::UserRole).toInt());
3944 cloneItem->setText(3,item->text(3));
3945 cloneItem->setFlags(item->flags());
3946 cloneItem->setToolTip(0,item->toolTip(0));
3947 cloneItem->setCheckState(0,item->checkState(0));
3948 cloneItem->setSelected(item->isSelected());
3949 cloneItem->setExpanded(item->isExpanded ());
3950
3951 cloneItem->setData(2,Qt::UserRole,item->data(2,Qt::UserRole).value<QColor>());
3952
3953 return cloneItem;
3954}
3955
3956
3957/**
3958 Clone the current tree in order to get a snapshot of old version
3959*/
3960void G4OpenGLQtViewer::cloneSceneTree(
3961 QTreeWidgetItem* rootItem
3962) {
3963
3964 for (int b=0;b< rootItem->childCount();b++) {
3965
3966 QTreeWidgetItem *child = rootItem->child(b);
3967
3968 // clone top level items
3969 int poIndex = child->data(0,Qt::UserRole).toInt();
3970 if (poIndex != -1) {
3971 fOldPositivePoIndexSceneTreeWidgetQuickMap.insert(std::pair <int, QTreeWidgetItem*> (poIndex,cloneWidgetItem(child)));
3972 } else {
3973 fOldNullPoIndexSceneTreeWidgetQuickVector.push_back(cloneWidgetItem(child));
3974 }
3975 cloneSceneTree(child);
3976 }
3977}
3978
3979
3980/**
3981 Update the quick scene tree visibility map (used by parseAndCheckVisibility)
3982*/
3983 void G4OpenGLQtViewer::updatePositivePoIndexSceneTreeWidgetQuickMap(int POindex,QTreeWidgetItem* item) {
3984
3985 // Check state
3986 std::map <int, QTreeWidgetItem*>::iterator i;
3987 i = fPositivePoIndexSceneTreeWidgetQuickMap.find(POindex);
3988
3989 if (i == fPositivePoIndexSceneTreeWidgetQuickMap.end()) {
3990 fPositivePoIndexSceneTreeWidgetQuickMap.insert(std::pair <int, QTreeWidgetItem*> (POindex,item) );
3991 fLastSceneTreeWidgetAskForIterator = fPositivePoIndexSceneTreeWidgetQuickMap.end();
3992 fLastSceneTreeWidgetAskForIteratorEnd = fPositivePoIndexSceneTreeWidgetQuickMap.end();
3993 } else {
3994 i->second = item;
3995 }
3996 }
3997
3998
3999
4000void G4OpenGLQtViewer::changeQColorForTreeWidgetItem(QTreeWidgetItem* item,const QColor& qc) {
4001
4002 int POIndex = item->data(0,Qt::UserRole).toInt();
4003 updatePositivePoIndexSceneTreeWidgetQuickMap(POIndex,item );
4004
4005 QPixmap pixmap = QPixmap(QSize(16, 16));
4006 if (item->data(0,Qt::UserRole).toInt() != -1) {
4007 pixmap.fill (qc);
4008 } else {
4009 pixmap.fill (QColor(255,255,255,255));
4010 }
4011 QPainter painter(&pixmap);
4012 painter.setPen(Qt::black);
4013 painter.drawRect(0,0,15,15); // Draw contour
4014
4015 item->setIcon(0,pixmap);
4016 item->setData(2,Qt::UserRole,qc);
4017}
4018
4019
4020
4021/**
4022 @return the corresponding item if existing.
4023 Look into fPositivePoIndexSceneTreeWidgetQuickMap
4024 */
4025QTreeWidgetItem* G4OpenGLQtViewer::getTreeWidgetItem(int POindex){
4026
4027 // -1 is not a visible item
4028 if (POindex == -1) {
4029 return NULL;
4030 }
4031
4032 if (fPositivePoIndexSceneTreeWidgetQuickMap.size() == 0){
4033 return NULL;
4034 }
4035
4036 if (fLastSceneTreeWidgetAskForIterator != fLastSceneTreeWidgetAskForIteratorEnd) {
4037 if (POindex == fLastSceneTreeWidgetAskForIterator->first) {
4038 if (fLastSceneTreeWidgetAskForIterator->second != NULL) {
4039 return fLastSceneTreeWidgetAskForIterator->second;
4040 }
4041 }
4042 }
4043
4044 // if not, use the "find" algorithm
4045 fLastSceneTreeWidgetAskForIterator = fPositivePoIndexSceneTreeWidgetQuickMap.find(POindex);
4046 fLastSceneTreeWidgetAskForIteratorEnd = fPositivePoIndexSceneTreeWidgetQuickMap.end();
4047
4048 if (fLastSceneTreeWidgetAskForIterator != fPositivePoIndexSceneTreeWidgetQuickMap.end()) {
4049 return fLastSceneTreeWidgetAskForIterator->second;
4050 }
4051 return NULL;
4052}
4053
4054/**
4055 @return the corresponding item if existing in the old tree
4056 Look into fOldPositivePoIndexSceneTreeWidgetQuickMap
4057 */
4058QTreeWidgetItem* G4OpenGLQtViewer::getOldTreeWidgetItem(int POindex){
4059
4060
4061 // -1 is not a visible item
4062 if (POindex == -1) {
4063 return NULL;
4064 }
4065
4066 if (fOldPositivePoIndexSceneTreeWidgetQuickMap.size() == 0){
4067 return NULL;
4068 }
4069
4070 // Should be call only once by item addition
4071 // Prevent to get out the std::map
4072 if (fOldLastSceneTreeWidgetAskForIterator != fOldLastSceneTreeWidgetAskForIteratorEnd) {
4073 fOldLastSceneTreeWidgetAskForIterator++;
4074 }
4075
4076 if (fOldLastSceneTreeWidgetAskForIterator != fOldPositivePoIndexSceneTreeWidgetQuickMap.end()) {
4077 if (POindex == fOldLastSceneTreeWidgetAskForIterator->first) {
4078 if (fOldLastSceneTreeWidgetAskForIterator->second != NULL) {
4079 return fOldLastSceneTreeWidgetAskForIterator->second;
4080 }
4081 }
4082 }
4083
4084 // if not, use the "find" algorithm
4085 fOldLastSceneTreeWidgetAskForIterator = fOldPositivePoIndexSceneTreeWidgetQuickMap.find(POindex);
4086 fOldLastSceneTreeWidgetAskForIteratorEnd = fOldPositivePoIndexSceneTreeWidgetQuickMap.end();
4087
4088 if (fOldLastSceneTreeWidgetAskForIterator != fOldPositivePoIndexSceneTreeWidgetQuickMap.end()) {
4089 return fOldLastSceneTreeWidgetAskForIterator->second;
4090 }
4091 return NULL;
4092}
4093
4094
4095
4096/**
4097 Should replace actual tree by the one in this class
4098 and update tree
4099*/
4101 // no UI
4102 if (fUISceneTreeWidget == NULL) {
4103 return;
4104 }
4105 if (fSceneTreeComponentTreeWidget == NULL) {
4106 return;
4107 }
4108
4109 // sort tree items
4110 fSceneTreeComponentTreeWidget->sortItems (0, Qt::AscendingOrder );
4111
4112 return;
4113}
4114
4115
4116/**
4117 Update the toolbar Icons/Mouse context menu
4118 - Change ortho/perspective
4119 - Change surface style
4120 - Change cursor style
4121 */
4123 if (fBatchMode) {
4124 return;
4125 }
4126
4128 d_style = fVP.GetDrawingStyle();
4129
4130 // Surface style
4131 if (d_style == G4ViewParameters::wireframe) {
4132 if (fUiQt) fUiQt->SetIconWireframeSelected();
4133 if (fContextMenu) {
4134 fDrawingWireframe->setChecked(true);
4135 fDrawingLineRemoval->setChecked(false);
4136 fDrawingSurfaceRemoval->setChecked(false);
4137 fDrawingLineSurfaceRemoval->setChecked(false);
4138 }
4139 } else if (d_style == G4ViewParameters::hlr) {
4140 if (fUiQt) fUiQt->SetIconHLRSelected();
4141 if (fContextMenu) {
4142 fDrawingLineRemoval->setChecked(true);
4143 fDrawingWireframe->setChecked(false);
4144 fDrawingSurfaceRemoval->setChecked(false);
4145 fDrawingLineSurfaceRemoval->setChecked(false);
4146 }
4147 } else if (d_style == G4ViewParameters::hsr) {
4148 if (fUiQt) fUiQt->SetIconSolidSelected();
4149 if (fContextMenu) {
4150 fDrawingSurfaceRemoval->setChecked(true);
4151 fDrawingWireframe->setChecked(false);
4152 fDrawingLineRemoval->setChecked(false);
4153 fDrawingLineSurfaceRemoval->setChecked(false);
4154 }
4155 } else if (d_style == G4ViewParameters::hlhsr) {
4156 if (fUiQt) fUiQt->SetIconHLHSRSelected();
4157 if (fContextMenu) {
4158 fDrawingLineSurfaceRemoval->setChecked(true);
4159 fDrawingWireframe->setChecked(false);
4160 fDrawingLineRemoval->setChecked(false);
4161 fDrawingSurfaceRemoval->setChecked(false);
4162 fDrawingLineSurfaceRemoval->setChecked(false);
4163 }
4164 }
4165
4166
4167 // projection style
4168 G4double d_proj = fVP.GetFieldHalfAngle () ;
4169 if (d_proj == 0.) { // ortho
4170 if (fUiQt) fUiQt->SetIconOrthoSelected();
4171 if (fContextMenu) {
4172 fProjectionOrtho->setChecked(true);
4173 fProjectionPerspective->setChecked(false);
4174 }
4175 } else {
4176 if (fUiQt) fUiQt->SetIconPerspectiveSelected();
4177 if (fContextMenu) {
4178 fProjectionPerspective->setChecked(true);
4179 fProjectionOrtho->setChecked(false);
4180 }
4181 }
4182
4183
4184 // mouse style : They are controlled by UI !
4185 if (fUiQt && fContextMenu) {
4186 if (fUiQt->IsIconPickSelected()) {
4187 fMousePickAction->setChecked(true);
4188 } else {
4189 fMousePickAction->setChecked(false);
4190 }
4191 if (fUiQt->IsIconZoomOutSelected()) {
4192 fMouseZoomOutAction->setChecked(true);
4193 fMouseZoomInAction->setChecked(false);
4194 fMouseRotateAction->setChecked(false);
4195 fMouseMoveAction->setChecked(false);
4196 } else if (fUiQt->IsIconZoomInSelected()) {
4197 fMouseZoomInAction->setChecked(true);
4198 fMouseZoomOutAction->setChecked(false);
4199 fMouseRotateAction->setChecked(false);
4200 fMouseMoveAction->setChecked(false);
4201 } else if (fUiQt->IsIconRotateSelected()) {
4202 fMouseRotateAction->setChecked(true);
4203 fMouseZoomOutAction->setChecked(false);
4204 fMouseZoomInAction->setChecked(false);
4205 fMouseMoveAction->setChecked(false);
4206 } else if (fUiQt->IsIconMoveSelected()) {
4207 fMouseMoveAction->setChecked(true);
4208 fMouseZoomOutAction->setChecked(false);
4209 fMouseZoomInAction->setChecked(false);
4210 fMouseRotateAction->setChecked(false);
4211 }
4212 }
4213}
4214
4215
4216/**
4217 Update the scene tree widget
4218 */
4220 // Ensure case where closing a UI tab close the widget
4221 if (!fSceneTreeWidget) {
4222 createSceneTreeWidget();
4223 }
4224}
4225
4226
4227 /**
4228 Update the viewer properties component widget
4229 Clear it only if the number of command is less than the previous table widget row count
4230 */
4232
4233 if (!isCurrentWidget()) {
4234 return;
4235 }
4236
4237 // Ensure case where closing a UI tab close the widget
4238 if (!fViewerPropertiesTableWidget) {
4239 createViewerPropertiesWidget();
4240 }
4241 int treeWidgetInfosIgnoredCommands = 0;
4243 G4UIcommandTree * commandTreeTop = UI->GetTree();
4244 G4UIcommandTree* path = commandTreeTop->FindCommandTree("/vis/viewer/set/");
4245
4246 if (!path) {
4247 return;
4248 }
4249
4250 // clear old table
4251 if ((path->GetCommandEntry()-fTreeWidgetInfosIgnoredCommands) != fViewerPropertiesTableWidget->rowCount()) {
4252 fViewerPropertiesTableWidget->clear();
4253 }
4254
4255 fViewerPropertiesTableWidget->blockSignals(true);
4256 // TODO : Could be optimized by comparing current command to old commands. That should not change so much
4257
4258 fViewerPropertiesTableWidget->setColumnCount (2);
4259 fViewerPropertiesTableWidget->setRowCount (path->GetCommandEntry()-fTreeWidgetInfosIgnoredCommands);
4260 fViewerPropertiesTableWidget->setHorizontalHeaderLabels(QStringList() << tr("Property")
4261 << tr("Value"));
4262 fViewerPropertiesTableWidget->verticalHeader()->setVisible(false);
4263 fViewerPropertiesTableWidget->setAlternatingRowColors (true);
4264
4265 // For the moment, we do only command that have a "set" command in UI
4266
4267 for (int a=0;a<path->GetCommandEntry();a++) {
4268 G4UIcommand* commandTmp = path->GetCommand(a+1);
4269
4270 // get current parameters
4271 QString params = "";
4272
4273 if(commandTmp->GetCommandName() == "autoRefresh") {
4274 if (fVP.IsAutoRefresh()) {
4275 params = "True";
4276 } else {
4277 params = "False";
4278 }
4279 } else if(commandTmp->GetCommandName() == "auxiliaryEdge") {
4280 if (fVP.IsAuxEdgeVisible()) {
4281 params = "True";
4282 } else {
4283 params = "False";
4284 }
4285 } else if(commandTmp->GetCommandName() == "background") {
4286 params = QString().number(fVP.GetBackgroundColour().GetRed()) + " "+
4287 QString().number(fVP.GetBackgroundColour().GetGreen()) + " "+
4288 QString().number(fVP.GetBackgroundColour().GetBlue()) + " "+
4289 QString().number(fVP.GetBackgroundColour().GetAlpha());
4290
4291 } else if(commandTmp->GetCommandName() == "culling") {
4292 params = QString().number(fVP. IsCulling ());
4293 } else if(commandTmp->GetCommandName() == "cutawayMode") {
4294 if (fVP.GetCutawayMode() == G4ViewParameters::cutawayUnion) {
4295 params = "union";
4296 } else {
4297 params = "intersection";
4298 }
4299
4300 } else if(commandTmp->GetCommandName() == "defaultColour") {
4301 params = QString().number(fVP.GetDefaultVisAttributes()->GetColor().GetRed()) + " "+
4302 QString().number(fVP.GetDefaultVisAttributes()->GetColor().GetGreen()) + " "+
4303 QString().number(fVP.GetDefaultVisAttributes()->GetColor().GetBlue()) + " "+
4304 QString().number(fVP.GetDefaultVisAttributes()->GetColor().GetAlpha());
4305
4306 } else if(commandTmp->GetCommandName() == "defaultTextColour") {
4307 params = QString().number(fVP.GetDefaultTextVisAttributes()->GetColor().GetRed()) + " "+
4308 QString().number(fVP.GetDefaultTextVisAttributes()->GetColor().GetGreen()) + " "+
4309 QString().number(fVP.GetDefaultTextVisAttributes()->GetColor().GetBlue()) + " "+
4310 QString().number(fVP.GetDefaultTextVisAttributes()->GetColor().GetAlpha());
4311
4312 } else if(commandTmp->GetCommandName() == "edge") {
4313 G4ViewParameters::DrawingStyle existingStyle = fVP.GetDrawingStyle();
4314 params = "False";
4315 if (existingStyle == G4ViewParameters::hsr) {
4316 params = "True";
4317 }
4318
4319 } else if(commandTmp->GetCommandName() == "explodeFactor") {
4320 params = QString().number(fVP.GetExplodeFactor()) + " " + QString(G4String(G4BestUnit(fVP.GetExplodeFactor(),"Length")).data());
4321
4322 } else if(commandTmp->GetCommandName() == "globalLineWidthScale") {
4323 params = QString().number(fVP.GetGlobalLineWidthScale());
4324
4325 } else if(commandTmp->GetCommandName() == "globalMarkerScale") {
4326 params = QString().number(fVP.GetGlobalMarkerScale());
4327
4328 } else if(commandTmp->GetCommandName() == "hiddenEdge") {
4329 G4ViewParameters::DrawingStyle style = fVP.GetDrawingStyle();
4330 if ((style == G4ViewParameters::hlr) ||
4331 (style == G4ViewParameters::hlhsr)) {
4332 params = "True";
4333 } else {
4334 params = "False";
4335 }
4336
4337 } else if(commandTmp->GetCommandName() == "hiddenMarker") {
4338 if (fVP.IsMarkerNotHidden()) {
4339 params = "False";
4340 } else {
4341 params = "True";
4342 }
4343
4344 } else if(commandTmp->GetCommandName() == "lightsMove") {
4345 if (fVP.GetLightsMoveWithCamera()) {
4346 params = "camera";
4347 } else {
4348 params = "object";
4349 }
4350 } else if(commandTmp->GetCommandName() == "lightsThetaPhi") {
4351 G4Vector3D direction = fVP.GetLightpointDirection();
4352 // degree
4353 params = QString().number(direction.theta()/CLHEP::degree)+ " "+ QString().number(direction.phi()/CLHEP::degree)+" deg";
4354 if (commandTmp->GetParameterEntries() == 3) {
4355 if (commandTmp->GetParameter(2)->GetDefaultValue() != "deg") {
4356 params = QString().number(direction.theta())+ " "+ QString().number(direction.phi())+" "+commandTmp->GetParameter(2)->GetDefaultValue().data();
4357 }
4358 }
4359 } else if(commandTmp->GetCommandName() == "lightsVector") {
4360 params = QString().number(fVP.GetLightpointDirection().x()) + " "+
4361 QString().number(fVP.GetLightpointDirection().y()) + " "+
4362 QString().number(fVP.GetLightpointDirection().z());
4363
4364 } else if(commandTmp->GetCommandName() == "lineSegmentsPerCircle") {
4365 params = QString().number(fVP.GetNoOfSides());
4366
4367 } else if(commandTmp->GetCommandName() == "picking") {
4368 if (fVP.IsPicking()) {
4369 params = "True";
4370 } else {
4371 params = "False";
4372 }
4373
4374 } else if(commandTmp->GetCommandName() == "projection") {
4375 if (fVP.GetFieldHalfAngle() == 0.) {
4376 params = "orthogonal";
4377 } else {
4378 params = QString("perspective ") + QString().number(fVP.GetFieldHalfAngle()/CLHEP::degree) + " deg";
4379 }
4380
4381 } else if(commandTmp->GetCommandName() == "rotationStyle") {
4382 if (fVP.GetRotationStyle() == G4ViewParameters::constrainUpDirection) {
4383 params = "constrainUpDirection";
4384 } else {
4385 params = "freeRotation";
4386 }
4387
4388 } else if(commandTmp->GetCommandName() == "sectionPlane") {
4389 if (fVP.IsSection()) {
4390 params = QString("on ") +
4391 G4String(G4BestUnit(fVP.GetSectionPlane().point(),"Length")).data()+
4392 QString().number(fVP.GetSectionPlane().normal().x())
4393 + " " + QString().number(fVP.GetSectionPlane().normal().y())
4394 + " " + QString().number(fVP.GetSectionPlane().normal().z());
4395 } else {
4396 params = "off";
4397 }
4398
4399 } else if(commandTmp->GetCommandName() == "style") {
4400 if (fVP.GetDrawingStyle() == G4ViewParameters::wireframe || fVP.GetDrawingStyle() == G4ViewParameters::hlr) {
4401 params = "wireframe";
4402 } else {
4403 params = "surface";
4404 }
4405
4406
4407 } else if(commandTmp->GetCommandName() == "targetPoint") {
4408 G4Point3D point = fVP.GetCurrentTargetPoint();
4409 if (fSceneHandler.GetScene()) {
4410 G4String b = G4BestUnit(fSceneHandler.GetScene()->GetStandardTargetPoint() + fVP.GetCurrentTargetPoint(),"Length");
4411 params = b.data();
4412 }
4413 } else if(commandTmp->GetCommandName() == "upThetaPhi") {
4414 G4Vector3D up = fVP.GetUpVector();
4415 // degree
4416 params = QString().number(up.theta()/CLHEP::degree)+ " "+ QString().number(up.phi()/CLHEP::degree)+" deg";
4417 if (commandTmp->GetParameterEntries() == 3) {
4418 if (commandTmp->GetParameter(2)->GetDefaultValue() != "deg") {
4419 params = QString().number(up.theta())+ " "+ QString().number(up.phi())+" "+commandTmp->GetParameter(2)->GetDefaultValue().data();
4420 }
4421 }
4422 } else if(commandTmp->GetCommandName() == "upVector") {
4423 G4Vector3D up = fVP.GetUpVector();
4424 params = QString().number(up.x())+ " "+ QString().number(up.y())+" "+QString().number(up.z())+ " ";
4425
4426 } else if(commandTmp->GetCommandName() == "viewpointThetaPhi") {
4427 G4Vector3D direction = fVP.GetViewpointDirection();
4428 // degree
4429 params = QString().number(direction.theta()/CLHEP::degree)+ " "+ QString().number(direction.phi()/CLHEP::degree)+" deg";
4430 if (commandTmp->GetParameterEntries() == 3) {
4431 if (commandTmp->GetParameter(2)->GetDefaultValue() != "deg") {
4432 params = QString().number(direction.theta())+ " "+ QString().number(direction.phi())+" "+commandTmp->GetParameter(2)->GetDefaultValue().data();
4433 }
4434 }
4435 } else if(commandTmp->GetCommandName() == "viewpointVector") {
4436 G4Vector3D direction = fVP.GetViewpointDirection();
4437 params = QString().number(direction.x())+ " "+ QString().number(direction.y())+" "+QString().number(direction.z());
4438 } else {
4439 // No help
4440 }
4441
4442 /* DO NOT DISPLAY COMMANDS WITHOUT ANY PARAMETERS SET
4443 if (params == "") {
4444 // TODO : display default parameters // should not be editable ?
4445
4446 for( G4int i_thParameter=0; i_thParameter<commandTmp->GetParameterEntries(); i_thParameter++ ) {
4447 commandParam = commandTmp->GetParameter(i_thParameter);
4448
4449 if (QString(QChar(commandParam->GetParameterType())) == "b") {
4450 if (commandParam->GetDefaultValue().data()) {
4451 params += "True";
4452 } else {
4453 params += "False";
4454 }
4455 } else {
4456 params += QString((char*)(commandParam->GetDefaultValue()).data());
4457 }
4458 if (i_thParameter<commandTmp->GetParameterEntries()-1) {
4459 params += " ";
4460 }
4461 }
4462 }
4463 */
4464
4465 if (params != "") {
4466
4467 QTableWidgetItem *nameItem;
4468 QTableWidgetItem *paramItem;
4469
4470 // already present ?
4471 QList<QTableWidgetItem *> list = fViewerPropertiesTableWidget->findItems (commandTmp->GetCommandName().data(),Qt::MatchExactly);
4472 if (list.size() == 1) {
4473 nameItem = list.first();
4474 paramItem = fViewerPropertiesTableWidget->item(nameItem->row(),1);
4475
4476 } else {
4477 nameItem = new QTableWidgetItem();
4478 paramItem = new QTableWidgetItem();
4479 fViewerPropertiesTableWidget->setItem(a-treeWidgetInfosIgnoredCommands, 0, nameItem);
4480 fViewerPropertiesTableWidget->setItem(a-treeWidgetInfosIgnoredCommands, 1, paramItem);
4481
4482 // Set Guidance
4483 QString guidance;
4484 G4int n_guidanceEntry = (G4int)commandTmp->GetGuidanceEntries();
4485 for( G4int i_thGuidance=0; i_thGuidance < n_guidanceEntry; i_thGuidance++ ) {
4486 guidance += QString((char*)(commandTmp->GetGuidanceLine(i_thGuidance)).data()) + "\n";
4487 }
4488
4489 nameItem->setToolTip(guidance);
4490 paramItem->setToolTip(GetCommandParameterList(commandTmp));
4491
4492 fViewerPropertiesTableWidget->setRowHeight(a-treeWidgetInfosIgnoredCommands,15);
4493 }
4494
4495 // set current name and parameters
4496 nameItem->setText(commandTmp->GetCommandName().data());
4497 paramItem->setText(params);
4498
4499 nameItem->setFlags(Qt::NoItemFlags);
4500 nameItem->setForeground(QBrush());
4501
4502 } else {
4503 treeWidgetInfosIgnoredCommands++;
4504 }
4505 }
4506 // remove empty content row
4507 for (int i=0; i<treeWidgetInfosIgnoredCommands; i++) {
4508 fViewerPropertiesTableWidget->removeRow (fViewerPropertiesTableWidget->rowCount() - 1);
4509 }
4510
4511 // The resize should done only at creation
4512 if (!fViewerPropertiesTableWidgetIsInit) {
4513 fViewerPropertiesTableWidgetIsInit = true;
4514
4515 fViewerPropertiesTableWidget->resizeColumnsToContents();
4516
4517 int x = fViewerPropertiesTableWidget->horizontalHeader()->length();
4518 int y = fViewerPropertiesTableWidget->verticalHeader()->length()+ fViewerPropertiesTableWidget->horizontalHeader()->sizeHint().height() + 2;
4519
4520 // fViewerPropertiesTableWidget->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
4521 // fViewerPropertiesTableWidget->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
4522
4523 // resize to fit content
4524 QDialog* dial = static_cast<QDialog*> (fUIViewerPropertiesWidget->parent());
4525 if (dial) {
4526 dial->resize(x+56,y+46); // more or less (margins) ...
4527 }
4528 }
4529 fViewerPropertiesTableWidget->blockSignals(false);
4530
4531 fTreeWidgetInfosIgnoredCommands = treeWidgetInfosIgnoredCommands;
4532}
4533
4534
4535/**
4536 Update the pick infos component widget
4537 */
4539 fLastPickPoint = QPoint(aX,aY);
4540
4541 if (!isCurrentWidget()) {
4542 return;
4543 }
4544 // Ensure case where closing a UI tab close the widget
4545 if (!fPickInfosWidget) {
4546 createPickInfosWidget();
4547 }
4548
4549#if QT_VERSION < 0x060000
4550#else
4551 {auto* qGLW = dynamic_cast<G4QGLWidgetType*> (fGLWidget) ;
4552 if (qGLW) qGLW->makeCurrent();}
4553 ResizeGLView();
4554#endif
4555 const std::vector < G4OpenGLViewerPickMap* > & pickMapVector = GetPickDetails(aX,aY);
4556
4557 // remove all previous widgets
4558 if (fPickInfosWidget) {
4559 QLayoutItem * wItem;
4560 if (fPickInfosWidget->layout()->count()) {
4561 while ((wItem = fPickInfosWidget->layout()->takeAt(0)) != 0) {
4562 delete wItem->widget();
4563 delete wItem;
4564 }
4565 }
4566 } else {
4567 // Ensure case where closing a UI tab close the widget
4568 if (!fPickInfosWidget) {
4569 createPickInfosWidget();
4570 }
4571 }
4572
4573 // parse all pick results
4574 G4int nPickedObjectsWithAttributes = 0;
4575 for (unsigned int a=0; a< pickMapVector.size(); a++) {
4576 const auto& pickMap = pickMapVector[a];
4577 // Add a box inside the pick viewer box
4578 std::ostringstream label;
4579 std::ostringstream content;
4580 std::string txt = pickMap->getAttributes()[0].data();
4581 if (pickMapVector[a]->getAttributes().size()) {
4582 ++nPickedObjectsWithAttributes;
4583
4584 std::size_t pos1 = txt.find(':');
4585 std::string storeKey = txt.substr(0,pos1);
4586
4587 if (storeKey == "G4PhysicalVolumeModel") {
4588
4589 label << "Volume:";
4590 std::size_t pos2 = txt.find(':',pos1+1);
4591 std::size_t pos3 = txt.find('\n',pos2+1);
4592 label << txt.substr(pos2+1,pos3-pos2-1);
4593
4594 } else if (storeKey == "G4TrajectoriesModel") {
4595
4596 label << "Trajectory:";
4597 std::size_t pos2 = txt.find(':',pos1+1);
4598 std::size_t pos3 = txt.find('\n',pos2+1);
4599 label << " Run:" << txt.substr(pos2+1,pos3-pos2-1);
4600 std::size_t pos4 = txt.find(':',pos3+1);
4601 std::size_t pos5 = txt.find('\n',pos4+1);
4602 label << ", Event:" << txt.substr(pos4+1,pos5-pos4-1);
4603
4604 } else {
4605
4606 label << "Hit number:" << a << ", PickName: " << pickMap->getPickName();
4607
4608 }
4609
4610 // Accumulate all content with the same pickname
4611 content << pickMap->print().data();
4612 G4int thisPickName = pickMap->getPickName();
4613 while (++a < pickMapVector.size()) {
4614 const auto& a_pickMap = pickMapVector[a];
4615 if (a_pickMap->getPickName() == thisPickName) {
4616 content << a_pickMap->print().data();
4617 } else {
4618 a--;
4619 break;
4620 }
4621 }
4622
4623 QPushButton* pickCoutButton = new QPushButton(label.str().c_str());
4624 pickCoutButton->setStyleSheet ("text-align: left; padding: 1px; border: 0px;");
4625 pickCoutButton->setIcon(*fTreeIconClosed);
4626 fPickInfosWidget->layout()->addWidget(pickCoutButton);
4627
4628 QStringList newStr;
4629
4630 // Add to stringList
4631 newStr = QStringList(QString(content.str().c_str()).trimmed());
4632
4633 QTextEdit* ed = new QTextEdit();
4634 ed->setReadOnly(true);
4635 fPickInfosWidget->layout()->addWidget(ed);
4636 ed->setVisible((false));
4637 ed->append(newStr.join(""));
4638
4639 int tmp = fPickInfosWidget->layout()->count()-1;
4640 connect(pickCoutButton, &QPushButton::clicked , [this, tmp](){ this->toggleSceneTreeComponentPickingCout(tmp);});
4641
4642 }
4643 }
4644
4645 // add a label to push everything up!
4646 QLabel * pushUp = new QLabel("");
4647 QSizePolicy vPolicy = QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Minimum);
4648 vPolicy.setVerticalStretch(10);
4649 pushUp->setSizePolicy(vPolicy);
4650 fPickInfosWidget->layout()->addWidget(pushUp);
4651
4652 // highlight the first one :
4653
4654 // first un-highlight the last selected
4655 changeColorAndTransparency(fLastHighlightName,fLastHighlightColor);
4656
4657 if (pickMapVector.size() > 0 ) {
4658 // get the new one
4659 fLastHighlightName = pickMapVector[0]->getPickName();
4660 fLastHighlightColor = getColorForPoIndex(fLastHighlightName);
4661 // set the new one
4662 changeColorAndTransparency(fLastHighlightName,G4Color(1,1,1,1));
4663
4664 updateQWidget();
4665 }
4666 QDialog* dial = static_cast<QDialog*> (fUIPickInfosWidget->parent());
4667 if (dial) {
4668 // change name
4669 std::ostringstream oss;
4670 if (nPickedObjectsWithAttributes == 0) {
4671 oss << "No object";
4672 } else if (nPickedObjectsWithAttributes == 1) {
4673 oss << "1 object";
4674 } else {
4675 oss << nPickedObjectsWithAttributes << " objects";
4676 }
4677 oss << " selected - " << GetName();
4678 dial->setWindowTitle(oss.str().c_str());
4679 }
4680 // set picking cout visible
4681 fPickInfosScrollArea->setVisible(true);
4682 dial->show();
4683}
4684
4685
4686void G4OpenGLQtViewer::toggleSceneTreeComponentPickingCout(int pickItem) {
4687
4688 QWidget* w;
4689 // close other items, it could take too much space
4690
4691 for (int a=0; a<fPickInfosWidget->layout()->count(); a++) {
4692 w = fPickInfosWidget->layout()->itemAt(a)->widget();
4693 QTextEdit* ed = dynamic_cast<QTextEdit*>(w);
4694 QPushButton* button;
4695 if (ed) {
4696 if (a == pickItem) {
4697 w->setVisible(!w->isVisible());
4698 } else {
4699 w->setVisible(false);
4700 }
4701 if (a >= 1) {
4702 button = dynamic_cast<QPushButton*>(fPickInfosWidget->layout()->itemAt(a-1)->widget());
4703 if (button) {
4704 if (button->isVisible()) {
4705 button->setIcon(*fTreeIconOpen);
4706 } else {
4707 button->setIcon(*fTreeIconClosed);
4708 }
4709 }
4710 }
4711 }
4712 }
4713}
4714
4715
4716void G4OpenGLQtViewer::currentTabActivated(int currentTab) {
4717 if (fUiQt->GetViewerTabWidget()->tabText(currentTab) == GetName().data()) {
4718 createViewerPropertiesWidget();
4719 }
4720}
4721
4722
4723void G4OpenGLQtViewer::tableWidgetViewerSetItemChanged(QTableWidgetItem * item) {
4724 G4UImanager* UI = G4UImanager::GetUIpointer();
4725 if(UI != NULL) {
4726 QTableWidgetItem* previous = fViewerPropertiesTableWidget->item(fViewerPropertiesTableWidget->row(item),0);
4727 if (previous) {
4728 fViewerPropertiesTableWidget->blockSignals(true);
4729 UI->ApplyCommand((std::string("/vis/viewer/set/")
4730 + previous->text().toStdString()
4731 + " "
4732 + item->text().toStdString()).c_str());
4733 fViewerPropertiesTableWidget->blockSignals(false);
4734 }
4735 }
4736}
4737
4739 G4Qt* interactorManager = G4Qt::getInstance ();
4740 if (!interactorManager->IsExternalApp()) {
4741
4742 // Prevent from repainting a hidden tab (the current tab name has to be the one of th GL viewer)
4743 if ( GetName() != fUiQt->GetViewerTabWidget()->tabText(fUiQt->GetViewerTabWidget()->currentIndex()).toStdString().c_str()) {
4744 return false;
4745 }
4746 }
4747 return true;
4748}
4749
4750/** Build the parameter list parameters in a QString<br>
4751 Reimplement partialy the G4UIparameter.cc
4752 @param aCommand : command to list parameters
4753 @see G4UIparameter::List()
4754 @see G4UIcommand::List()
4755 @return the command list parameters, or "" if nothing
4756 */
4757QString G4OpenGLQtViewer::GetCommandParameterList (
4758 const G4UIcommand *aCommand
4759 )
4760{
4761 G4int n_parameterEntry = (G4int)aCommand->GetParameterEntries();
4762 QString txt;
4763
4764 if( n_parameterEntry > 0 ) {
4765 G4UIparameter *param;
4766
4767 // Re-implementation of G4UIparameter.cc
4768
4769 for( G4int i_thParameter=0; i_thParameter<n_parameterEntry; i_thParameter++ ) {
4770 param = aCommand->GetParameter(i_thParameter);
4771 txt += "\nParameter : " + QString((char*)(param->GetParameterName()).data()) + "\n";
4772 if( ! param->GetParameterGuidance().empty() )
4773 txt += QString((char*)(param->GetParameterGuidance()).data())+ "\n" ;
4774 txt += " Parameter type : " + QString(QChar(param->GetParameterType())) + "\n";
4775 if(param->IsOmittable()){
4776 txt += " Omittable : True\n";
4777 } else {
4778 txt += " Omittable : False\n";
4779 }
4780 if( param->GetCurrentAsDefault() ) {
4781 txt += " Default value : taken from the current value\n";
4782 } else if( ! param->GetDefaultValue().empty() ) {
4783 txt += " Default value : " + QString((char*)(param->GetDefaultValue()).data())+ "\n";
4784 }
4785 if( ! param->GetParameterRange().empty() ) {
4786 txt += " Parameter range : " + QString((char*)(param->GetParameterRange()).data())+ "\n";
4787 }
4788 if( ! param->GetParameterCandidates().empty() ) {
4789 txt += " Candidates : " + QString((char*)(param->GetParameterCandidates()).data())+ "\n";
4790 }
4791 }
4792 }
4793 return txt;
4794}
4795
4796#ifdef G4MULTITHREADED
4797
4798namespace {
4799 G4Mutex visSubThreadMutex = G4MUTEX_INITIALIZER;
4800 G4Condition waitForVisSubThreadInitialized = G4CONDITION_INITIALIZER;
4801 G4bool visSubThreadEstablished = false;
4802 G4bool qObjectsSwitched = false;
4803 G4QGLWidgetType* qGLWidget = nullptr;
4804}
4805
4807{
4808 // Called by Main Thread !
4809
4810 // Initialise and check qGLWidget - no need to check in subsequent functions
4811 qGLWidget = dynamic_cast<G4QGLWidgetType*>(fGLWidget);
4812 if (qGLWidget == nullptr) return;
4813
4814 // Done with master thread
4815 qGLWidget->doneCurrent();
4816
4817 // Set current QThread for the way back
4818 fQGLContextMainThread = QThread::currentThread();
4819}
4820
4822{
4823 // Still on master thread but vis thread has been launched
4824
4825 if (qGLWidget == nullptr) return;
4826
4827 // Wait until SwitchToVisSubThread has found vis sub-thread QThread
4828 {
4829 G4AutoLock lock(&visSubThreadMutex);
4830 G4CONDITIONWAITLAMBDA(&waitForVisSubThreadInitialized, &lock, []{return visSubThreadEstablished;})
4831 }
4832
4833 // Move stuff to sub-thread
4834 if(qGLWidget->context()) qGLWidget->context()->moveToThread(fQGLContextVisSubThread);
4835
4836 // Inform sub-thread
4837 G4AutoLock lock(&visSubThreadMutex);
4838 qObjectsSwitched = true;
4839 lock.unlock();
4840 G4CONDITIONBROADCAST(&waitForVisSubThreadInitialized);
4841}
4842
4844{
4845 // Called by VisSub Thread !
4846
4847 if (qGLWidget == nullptr) return;
4848
4849 // Set the current QThread to its static variable
4850 fQGLContextVisSubThread = QThread::currentThread();
4851
4852 // Let MovingToVisSubThread know we have the QThread
4853 {
4854 G4AutoLock lock(&visSubThreadMutex);
4855 visSubThreadEstablished = true;
4856 G4CONDITIONBROADCAST(&waitForVisSubThreadInitialized);
4857 }
4858
4859 // Wait until MovingToVisSubThread has moved stuff
4860 {
4861 G4AutoLock lock(&visSubThreadMutex);
4862 G4CONDITIONWAITLAMBDA(&waitForVisSubThreadInitialized, &lock, []{return qObjectsSwitched;})
4863 }
4864
4865 // make context current
4866 qGLWidget->makeCurrent();
4867}
4868
4870{
4871 // Called by vis sub thread
4872
4873 if (qGLWidget == nullptr) return;
4874
4875 // finish with this vis sub thread context
4876 qGLWidget->doneCurrent();
4877
4878 // and move stuff back to the main thread
4879 if(qGLWidget->context()) qGLWidget->context()->moveToThread(fQGLContextMainThread);
4880}
4881
4883{
4884 // Called by master Thread !
4885
4886 if (qGLWidget == nullptr) return;
4887
4888 qGLWidget->makeCurrent();
4889
4890 visSubThreadEstablished = false;
4891 qObjectsSwitched = false;
4892}
4893
4894#endif
4895
4896
4897/*
4898
4899void MultiLayer::exportToSVG(const QString& fname)
4900{
4901QPicture picture;
4902QPainter p(&picture);
4903for (int i=0;i<(int)graphsList->count();i++)
4904{
4905Graph *gr=(Graph *)graphsList->at(i);
4906Plot *myPlot= (Plot *)gr->plotWidget();
4907
4908QPoint pos=gr->pos();
4909
4910int width=int(myPlot->frameGeometry().width());
4911int height=int(myPlot->frameGeometry().height());
4912
4913myPlot->print(&p, QRect(pos,QSize(width,height)));
4914}
4915
4916p.end();
4917picture.save(fname, "svg");
4918}
4919*/
G4TemplateAutoLock< G4Mutex > G4AutoLock
G4Colour G4Color
Definition G4Color.hh:41
G4ThreadLocal T * G4GeomSplitter< T >::offset
QOpenGLWidget G4QGLWidgetType
#define M(row, col)
HepGeom::Point3D< G4double > G4Point3D
Definition G4Point3D.hh:34
#define G4BestUnit(a, b)
#define G4CONDITION_INITIALIZER
#define G4MUTEX_INITIALIZER
#define G4CONDITIONWAITLAMBDA(cond, mutex, lambda)
G4int G4Condition
#define G4CONDITIONBROADCAST(cond)
std::mutex G4Mutex
double G4double
Definition G4Types.hh:83
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
HepGeom::Vector3D< G4double > G4Vector3D
Definition G4Vector3D.hh:34
G4GLOB_DLL std::ostream G4cerr
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
G4double GetBlue() const
Definition G4Colour.hh:172
G4double GetAlpha() const
Definition G4Colour.hh:173
G4double GetRed() const
Definition G4Colour.hh:170
G4double GetGreen() const
Definition G4Colour.hh:171
void G4MouseReleaseEvent(QMouseEvent *evnt)
virtual G4bool ReadyToDraw()
void rotateQtSceneToggle(float, float)
void G4MouseMoveEvent(QMouseEvent *event)
void G4keyPressEvent(QKeyEvent *event)
void updateViewerPropertiesTableWidget()
void addNonPVSceneTreeElement(const G4String &model, int currentPVPOIndex, const std::string &modelDescription, const G4Visible &visible)
void G4MousePressEvent(QMouseEvent *event)
void G4wheelEvent(QWheelEvent *event)
G4OpenGLQtViewer(G4OpenGLSceneHandler &scene)
bool isTouchableVisible(int POindex)
void moveScene(float, float, float, bool)
void G4manageContextMenuEvent(QContextMenuEvent *e)
G4bool GetWindowSize(unsigned int &a_w, unsigned int &a_h)
void rotateQtScene(float, float)
bool exportImage(std::string name="", int width=-1, int height=-1)
void updateToolbarAndMouseContextMenu()
void updateKeyModifierState(const Qt::KeyboardModifiers &)
void G4keyReleaseEvent(QKeyEvent *event)
virtual void CreateMainWindow(G4QGLWidgetType *, const QString &)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
G4Colour getColorForPoIndex(int poIndex)
void updatePickInfosWidget(int, int)
virtual ~G4OpenGLQtViewer()
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!//
void DrawText(const G4Text &)
QString setEncoderPath(QString path)
G4bool GetRenderAreaSize(unsigned int &a_w, unsigned int &a_h)
virtual void updateQWidget()=0
QString setSaveFileName(QString path)
void addPVSceneTreeElement(const G4String &model, G4PhysicalVolumeModel *pPVModel, int currentPVPOIndex)
const std::vector< G4ModelingParameters::VisAttributesModifier > * GetPrivateVisAttributesModifiers() const
QString setTempFolderPath(QString path)
unsigned int fWinSize_y
std::vector< std::string > fExportImageFormatVector
friend class G4OpenGLSceneHandler
void rotateSceneToggle(G4double dx, G4double dy)
virtual void ResetView()
unsigned int getWinHeight() const
std::string fExportImageFormat
void ResizeWindow(unsigned int, unsigned int)
unsigned int getWinWidth() const
std::string fDefaultExportImageFormat
bool setExportFilename(G4String name, G4bool inc=true)
G4OpenGLViewer(G4OpenGLSceneHandler &scene)
void addExportImageFormat(std::string format)
G4bool antialiasing_enabled
virtual void DrawText(const G4Text &)
void setExportSize(G4int, G4int)
void rotateScene(G4double dx, G4double dy)
GLdouble getSceneDepth()
G4bool transparency_enabled
virtual bool exportImage(std::string name="", int width=-1, int height=-1)
G4bool isGl2psWriting()
unsigned int fWinSize_x
std::string getRealPrintFilename()
G4double GetSceneNearWidth()
const std::vector< G4OpenGLViewerPickMap * > & GetPickDetails(GLdouble x, GLdouble y)
const G4Transform3D & GetTransformation() const
const std::vector< G4PhysicalVolumeNodeID > & GetFullPVPath() const
Definition G4Qt.hh:50
static G4Qt * getInstance()
Definition G4Qt.cc:61
bool IsExternalApp()
Definition G4Qt.cc:210
Layout GetLayout() const
G4double GetYOffset() const
G4double GetXOffset() const
G4String GetText() const
@ centre
Definition G4Text.hh:76
@ right
Definition G4Text.hh:76
@ left
Definition G4Text.hh:76
G4int GetCommandEntry() const
G4UIcommand * GetCommand(G4int i)
G4UIcommandTree * FindCommandTree(const char *commandPath)
std::size_t GetParameterEntries() const
const G4String & GetGuidanceLine(G4int i) const
G4UIparameter * GetParameter(G4int i) const
std::size_t GetGuidanceEntries() const
const G4String & GetCommandName() const
G4UIcommandTree * GetTree() const
G4int ApplyCommand(const char *aCommand)
G4UIsession * GetG4UIWindow() const
static G4UImanager * GetUIpointer()
const G4String & GetParameterCandidates() const
const G4String & GetParameterGuidance() const
G4bool IsOmittable() const
const G4String & GetParameterRange() const
G4bool GetCurrentAsDefault() const
char GetParameterType() const
const G4String & GetParameterName() const
const G4String & GetDefaultValue() const
G4Point3D GetPosition() const
const G4String & GetName() const
virtual void DoneWithMasterThread()
Definition G4VViewer.hh:124
G4VSceneHandler & fSceneHandler
Definition G4VViewer.hh:268
void SetNeedKernelVisit(G4bool need)
virtual void SwitchToMasterThread()
Definition G4VViewer.hh:139
virtual void SwitchToVisSubThread()
Definition G4VViewer.hh:130
G4ViewParameters fVP
Definition G4VViewer.hh:272
G4VViewer(G4VSceneHandler &, G4int id, const G4String &name="")
Definition G4VViewer.cc:49
void ZoomFromMouseWheel(G4double delta, G4bool shift=false, G4double xPos=0, G4double yPos=0)
Definition G4VViewer.cc:144
virtual void MovingToVisSubThread()
Definition G4VViewer.hh:127
virtual void DoneWithVisSubThread()
Definition G4VViewer.hh:133
virtual const G4String & GetInfo() const
const char * name(G4int ptype)
G4bool IsMasterThread()