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