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