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 // 27 // 28 // L. Garnier 29 30 #include "G4UIQt.hh" 31 32 #include "G4MTcoutDestination.hh" 33 #include "G4Qt.hh" 34 #include "G4StateManager.hh" 35 #include "G4Types.hh" 36 #include "G4UIcommand.hh" 37 #include "G4UIcommandStatus.hh" 38 #include "G4UIcommandTree.hh" 39 #include "G4UImanager.hh" 40 #include "G4UIcommand.hh" 41 #include "G4UIparameter.hh" 42 #include "G4SceneTreeItem.hh" 43 #include "G4AttCheck.hh" 44 45 #include <qapplication.h> 46 #include <qdialog.h> 47 #include <qevent.h> 48 #include <qlabel.h> 49 #include <qlayout.h> 50 #include <qlineedit.h> 51 #include <qmenubar.h> 52 #include <qmessagebox.h> 53 #include <qpushbutton.h> 54 #include <qscrollbar.h> 55 #include <qsplitter.h> 56 #include <qtextbrowser.h> 57 #include <qtextedit.h> 58 #include <qwidget.h> 59 60 #include <cstring> 61 #include <qboxlayout.h> 62 #include <qbuttongroup.h> 63 #include <qcolordialog.h> 64 #include <qcombobox.h> 65 #include <qcompleter.h> 66 #include <qfiledialog.h> 67 #include <qgroupbox.h> 68 #include <qheaderview.h> 69 #include <qlistwidget.h> 70 #include <qmainwindow.h> 71 #include <qmenu.h> 72 #include <qpainter.h> 73 #include <qradiobutton.h> 74 #include <qscrollarea.h> 75 #include <qstandarditemmodel.h> 76 #include <qstringlist.h> 77 #include <qtabbar.h> 78 #include <qtablewidget.h> 79 #include <qtabwidget.h> 80 #include <qtextstream.h> 81 #include <qtoolbar.h> 82 #include <qtoolbox.h> 83 84 #include <QInputDialog> 85 86 #include <set> 87 #include <map> 88 #include <cstdlib> 89 90 #ifndef G4GMAKE 91 # include "moc_G4UIQt.cpp" 92 #endif 93 94 // Pourquoi Static et non variables de classe ? 95 static G4bool exitSession = true; 96 static G4bool exitPause = true; 97 98 /** Build a Qt window with a menubar, output area and promt area<br> 99 <pre> 100 +-----------------------+ 101 |exit menu| | 102 | | 103 | +-------------------+ | 104 | | | | 105 | | Output area | | 106 | | | | 107 | +-------------------+ | 108 | | clear | | 109 | +-------------------+ | 110 | | promt history | | 111 | +-------------------+ | 112 | +-------------------+ | 113 | |> promt area | | 114 | +-------------------+ | 115 +-----------------------+ 116 </pre> 117 */ 118 G4UIQt::G4UIQt(G4int argc, char** argv) 119 : fMainWindow(nullptr), 120 fCommandLabel(nullptr), 121 fCommandArea(nullptr), 122 fCoutTBTextArea(nullptr), 123 fUITabWidget(nullptr), 124 fCoutFilter(nullptr), 125 fCompleter(nullptr), 126 fDefaultIcons(true), 127 fHistoryTBTableList(nullptr), 128 fHelpTreeWidget(nullptr), 129 fHelpTBWidget(nullptr), 130 fHistoryTBWidget(nullptr), 131 fCoutDockWidget(nullptr), 132 fUIDockWidget(nullptr), 133 fSceneTreeWidget(nullptr), 134 fNewSceneTreeWidget(nullptr), 135 fNewSceneTreeItemTreeWidget(nullptr), 136 fViewerPropertiesWidget(nullptr), 137 fPickInfosWidget(nullptr), 138 fHelpLine(nullptr), 139 fViewerTabWidget(nullptr), 140 fCoutText("Output"), 141 fStartPage(nullptr), 142 fHelpVSplitter(nullptr), 143 fParameterHelpLabel(nullptr), 144 fParameterHelpTable(nullptr), 145 fToolbarApp(nullptr), 146 fToolbarUser(nullptr), 147 fStringSeparator("__$$$@%%###__"), 148 fLastOpenPath(""), 149 fSearchIcon(nullptr), 150 fClearIcon(nullptr), 151 fSaveIcon(nullptr), 152 fOpenIcon(nullptr), 153 fMoveIcon(nullptr), 154 fRotateIcon(nullptr), 155 fPickIcon(nullptr), 156 fZoomInIcon(nullptr), 157 fZoomOutIcon(nullptr), 158 fWireframeIcon(nullptr), 159 fSolidIcon(nullptr), 160 fHiddenLineRemovalIcon(nullptr), 161 fHiddenLineAndSurfaceRemovalIcon(nullptr), 162 fPerspectiveIcon(nullptr), 163 fOrthoIcon(nullptr), 164 fCommandIcon(nullptr), 165 fDirIcon(nullptr), 166 fRunIcon(nullptr), 167 fParamIcon(nullptr), 168 fPickTargetIcon(nullptr), 169 fExitIcon(nullptr) 170 #ifdef G4MULTITHREADED 171 , 172 fThreadsFilterComboBox(nullptr) 173 #endif 174 , 175 fDefaultViewerFirstPageHTMLText(""), 176 fViewerPropertiesDialog(nullptr), 177 fPickInfosDialog(nullptr), 178 fLastCompleteCommand(""), 179 fMoveSelected(false), 180 fRotateSelected(true), 181 fPickSelected(false), 182 fZoomInSelected(false), 183 fZoomOutSelected(false) 184 { 185 G4Qt* interactorManager = G4Qt::getInstance(argc, argv, (char*)"Qt"); 186 if ((QApplication*)interactorManager->GetMainInteractor() == nullptr) { 187 G4UImanager* UImanager = G4UImanager::GetUIpointer(); 188 G4int verbose = UImanager->GetVerboseLevel(); 189 190 if (verbose >= 2) { 191 G4cout << "G4UIQt : Unable to init Qt. Aborted" << G4endl; 192 } 193 } 194 195 G4UImanager* UI = G4UImanager::GetUIpointer(); 196 if (UI != nullptr) UI->SetSession(this); 197 if (UI != nullptr) UI->SetG4UIWindow(this); 198 199 // Check if already define in external app QMainWindow 200 G4bool found = false; 201 Q_FOREACH (QWidget* widget, QApplication::allWidgets()) { 202 if ((!found) && (widget->inherits("QMainWindow"))) { 203 found = true; 204 } 205 } 206 207 if (found) { 208 G4UImanager* UImanager = G4UImanager::GetUIpointer(); 209 G4int verbose = UImanager->GetVerboseLevel(); 210 211 if (verbose >= 2) { 212 G4cout << "G4UIQt : Found an external App with a QMainWindow already defined. Aborted" 213 << G4endl; 214 } 215 return; 216 } 217 CreateIcons(); 218 219 fMainWindow = new QMainWindow(); 220 fMainWindow->setAttribute(Qt::WA_DeleteOnClose); 221 222 fMainWindow->setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); 223 fMainWindow->setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); 224 fMainWindow->setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); 225 fMainWindow->setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea); 226 227 CreateViewerWidget(); 228 fMainWindow->addDockWidget(Qt::LeftDockWidgetArea, CreateUITabWidget()); 229 fMainWindow->addDockWidget(Qt::BottomDockWidgetArea, CreateCoutTBWidget()); 230 231 // Create the new scene tree stuff 232 fNewSceneTreeWidget = new QWidget; 233 fNewSceneTreeWidget->setStyleSheet ("padding: 0px "); 234 fNewSceneTreeWidget->setLayout(new QVBoxLayout); 235 fNewSceneTreeWidget->layout()->setContentsMargins(5,5,5,5); 236 fNewSceneTreeWidget->setWindowTitle("some name"/*QString(GetName().data())*/); 237 // Add it to the "old" fSceneTreeWidget 238 fSceneTreeWidget->layout()->addWidget(fNewSceneTreeWidget); 239 CreateNewSceneTreeWidget(); 240 241 // add defaults icons 242 SetDefaultIconsToolbar(); 243 244 if (UI != nullptr) UI->SetCoutDestination(this); // TO KEEP 245 246 #ifdef G4MULTITHREADED 247 // explicitly request that cout/cerr messages from threads are ALSO propagated to the master. 248 masterG4coutDestination = this; 249 #endif 250 251 fMainWindow->setWindowTitle(QFileInfo(QCoreApplication::applicationFilePath()).fileName()); 252 fMainWindow->move(QPoint(50, 50)); 253 254 // force the size at be correct at the beggining 255 // because the widget is not realized yet, the size of the main window is not up to date. But 256 // we need it in order to add some viewer inside 257 fMainWindow->resize(fUIDockWidget->width() + fCoutDockWidget->width() + 20, 258 fUIDockWidget->height() + fCoutDockWidget->height() + 20); 259 260 // set last focus on command line 261 fCommandArea->setFocus(Qt::TabFocusReason); 262 263 // Allow QTextCursor to be called by another thread : 264 // http://qt-project.org/doc/qt-4.8/qmetatype.html#qRegisterMetaType 265 qRegisterMetaType<QTextCursor>("QTextCursor"); 266 267 // add some tips 268 AddTabWidget(fStartPage, "Useful tips"); 269 270 // Set not visible until session start 271 fMainWindow->setVisible(false); 272 } 273 274 G4UIQt::~G4UIQt() 275 { 276 G4UImanager* UI = G4UImanager::GetUIpointer(); // TO KEEP 277 if (UI != nullptr) { // TO KEEP 278 UI->SetSession(nullptr); // TO KEEP 279 UI->SetG4UIWindow(nullptr); 280 UI->SetCoutDestination(nullptr); // TO KEEP 281 #ifdef G4MULTITHREADED 282 masterG4coutDestination = nullptr; // set to cout when UI is deleted 283 #endif 284 } 285 } 286 287 void G4UIQt::DefaultIcons(G4bool aVal) 288 { 289 fDefaultIcons = aVal; 290 291 if (! fMainWindow->isVisible()) { 292 return; 293 } 294 295 if (fToolbarApp != nullptr) { 296 if (aVal) { 297 fToolbarApp->setVisible(true); 298 } 299 else { 300 // Set not visible until session start 301 fToolbarApp->setVisible(false); 302 } 303 } 304 } 305 306 void G4UIQt::SetDefaultIconsToolbar() 307 { 308 if (fDefaultIcons) { 309 if (fToolbarApp == nullptr) { 310 fToolbarApp = new QToolBar(); 311 fToolbarApp->setIconSize(QSize(20, 20)); 312 fMainWindow->addToolBar(Qt::TopToolBarArea, fToolbarApp); 313 } 314 315 // Open/Save Icons 316 AddIcon("Open macro file", "open", "/control/execute"); 317 AddIcon("Save viewer state", "save", "/vis/viewer/save"); 318 319 // View parameters 320 fToolbarApp->addAction(QIcon(*fParamIcon), "Viewer properties", this, 321 [this]() { this->ViewerPropertiesIconCallback(0); }); 322 323 // Cursors style icons 324 AddIcon("Move", "move", ""); 325 AddIcon("Pick", "pick", ""); 326 AddIcon("Zoom out", "zoom_out", ""); 327 AddIcon("Zoom in", "zoom_in", ""); 328 AddIcon("Rotate", "rotate", ""); 329 330 // Surface Style icons 331 AddIcon("Hidden line removal", "hidden_line_removal", ""); 332 AddIcon("Hidden line and hidden surface removal", "hidden_line_and_surface_removal", ""); 333 AddIcon("Surfaces", "solid", ""); 334 AddIcon("Wireframe", "wireframe", ""); 335 336 // Perspective/Ortho icons 337 AddIcon("Perspective", "perspective", ""); 338 AddIcon("Orthographic", "ortho", ""); 339 AddIcon("Run beam on", "runBeamOn", "/run/beamOn 1"); 340 AddIcon("Exit Application", "exit", "exit"); 341 } 342 } 343 344 // clang-format off 345 void G4UIQt::CreateIcons() 346 { 347 const char * const save[]={ 348 "32 32 24 1", 349 " c None", 350 "+ c #000200", 351 "@ c #141E43", 352 "# c #000C56", 353 "$ c #494A47", 354 "% c #636662", 355 "& c #312F2A", 356 "* c #191B19", 357 "= c #002992", 358 "- c #003DFF", 359 "; c #041DA5", 360 "> c #A8A9A3", 361 ", c #FDFFFC", 362 "' c #DDE0DD", 363 ") c #818783", 364 "! c #C9CBC8", 365 "~ c #0116C3", 366 "{ c #C5C8FA", 367 "] c #6596FC", 368 "^ c #A0B4F9", 369 "/ c #0B2AFD", 370 "( c #799BE3", 371 "_ c #5F4826", 372 ": c #D5D8D5", 373 " ", 374 " ", 375 " +++++++++++++++++++++++++ ", 376 " +@##+$%%%%%%%%%%%%%%%&*$%&+ ", 377 " +=-;@>,,''',,,,,,,',,)&!,)+ ", 378 " +;-~@>,,,,,,,,,,,,,,,>$!,)+ ", 379 " +=-~@>,,,,,{]]]]]^,,,>*&$&+ ", 380 " +=-~@>,,,,,'{^{^^{,,,>*#=#+ ", 381 " +=-~@>,,,,,,,,,,,,,,,>@~/=+ ", 382 " +=-~@>,,,{{{''''{',,,>@~-=+ ", 383 " +=-~@>,,'^]]]]]]({,,,>@~-=+ ", 384 " +=-~@>,,,{{{{{{{{{,,,>@~-=+ ", 385 " +=-~@>,,,,,'{^{{^{,,,>@~-=+ ", 386 " +=-~@>,,,,,]]]]]]],,,>@~-=+ ", 387 " +=-~*>,,,,,,,,,,,,,,,>@~-=+ ", 388 " +=-~@>,,,,,,,,,,,,,,,>@~-=+ ", 389 " +=-/=$%%%%%%%%%%%%%%%$=/-=+ ", 390 " +=---;###############;---=+ ", 391 " +=---////////////////----=+ ", 392 " +=----------------///----=+ ", 393 " +=---=@##############@#--=+ ", 394 " +=---@+++++++++++*%))_+~-=+ ", 395 " +=---#+++++++++++&:,,>@~-=+ ", 396 " +=---#+++++++++++$',,>@~-=+ ", 397 " +=---#+++++++++++&!,,>@~-=+ ", 398 " +=/--#+++++++++++&',,>@~-=+ ", 399 " @;--#+++++++++++$',,>@~-=+ ", 400 " @;;@+++++++++++*)!>%@=;#+ ", 401 " @++++++++++++++*&**++@++ ", 402 " ", 403 " ", 404 " "} 405 ; 406 fSaveIcon = new QPixmap(save); 407 408 const char * const search[] = { 409 /* columns rows colors chars-per-pixel */ 410 "19 19 8 1", 411 " c #5C5C5C", 412 ". c #7D7D7D", 413 "X c #9B9B9B", 414 "o c #C3C3C3", 415 "O c None", 416 "+ c #000000", 417 "@ c #000000", 418 "# c None", 419 /* pixels */ 420 "OOOOOOOOOOOOOOOOOOO", 421 "OOOOOOOOOOOOOOOOOOO", 422 "OOOOOOOo. .oOOOOOO", 423 "OOOOOOX XOOOOO", 424 "OOOOOo XOOX oOOOO", 425 "OOOOO. XOOOOX .OOOO", 426 "OOOOO OOOOOO OOOO", 427 "OOOOO OOOOOO OOOO", 428 "OOOOO. XOOOOo .OOOO", 429 "OOOOOo oOOo oOOOO", 430 "OOOOOOX XOOOO", 431 "OOOOOOOo. . XOOO", 432 "OOOOOOOOOOOOO. XOO", 433 "OOOOOOOOOOOOOO. XOO", 434 "OOOOOOOOOOOOOOOoOOO", 435 "OOOOOOOOOOOOOOOOOOO", 436 "OOOOOOOOOOOOOOOOOOO", 437 "OOOOOOOOOOOOOOOOOOO", 438 "OOOOOOOOOOOOOOOOOOO" 439 }; 440 fSearchIcon = new QPixmap(search); 441 442 const char * const clear[] = { 443 /* columns rows colors chars-per-pixel */ 444 "20 20 8 1", 445 " c #020202", 446 ". c #202020", 447 "X c #2C2C2C", 448 "o c #797979", 449 "O c None", 450 "+ c #797979", 451 "@ c #797979", 452 "# c #797979", 453 /* pixels */ 454 "OOOOOOOOOOOOOOOOOOOO", 455 "OOOOOOOo oOOOOOOO", 456 "OOOOOXX XXOOOOO", 457 "OOOOOOOOOOOOOOOOOOOO", 458 "OOOOOOOOOOOOOOOOOOOO", 459 "OOOO XXXXXXXXXX OOOO", 460 "OOO XOOOOOOOOOO OOO", 461 "OOOOXOooOooOooO OOOO", 462 "OOOOXOooOooOooO OOOO", 463 "OOOOXOooOooOooO OOOO", 464 "OOOOXOooOooOooO OOOO", 465 "OOOOXOooOooOooO OOOO", 466 "OOOOXOooOooOooO OOOO", 467 "OOOOXOooOooOooO OOOO", 468 "OOOOXOooOooOooO OOOO", 469 "OOOOXOooOooOooO OOOO", 470 "OOOOXOooOooOooO OOOO", 471 "OOOOXOOOOOOOOOO OOOO", 472 "OOOOOooooooooooOOOOO", 473 "OOOOOO........OOOOOO" 474 }; 475 476 fClearIcon = new QPixmap(clear); 477 478 479 const char * const open[]={ 480 "32 32 33 1", 481 " c None", 482 "+ c #09091E", 483 "@ c #191B18", 484 "# c #5F615F", 485 "$ c #777977", 486 "% c #AEB1AF", 487 "& c #929491", 488 "* c #515250", 489 "= c #858784", 490 "- c #333533", 491 "; c #000100", 492 "> c #272926", 493 ", c #424341", 494 "' c #696C6A", 495 ") c #5F4927", 496 "! c #583D18", 497 "~ c #6E6A5B", 498 "{ c #47351D", 499 "] c #E0A554", 500 "^ c #FFD67B", 501 "/ c #EFB465", 502 "( c #FDBF6C", 503 "_ c #FFCD76", 504 ": c #806238", 505 "< c #362611", 506 "[ c #0B0D0A", 507 "} c #68471B", 508 "| c #523E22", 509 "1 c #B78A51", 510 "2 c #A17B44", 511 "3 c #D6A45E", 512 "4 c #C29354", 513 "5 c #A1A3A0", 514 " ", 515 " ", 516 " +@@@# ", 517 " $% +& * ", 518 " #= $ -; ", 519 " %>;+ ", 520 " ,;;+ ", 521 " &#$''#' >;;;+ ", 522 " =)!)!!!!~ *#$'' ", 523 " {]^/((_({- %%%%%%%%%%% ", 524 " {(^_^^^^:<{{{{{{{{{{{{{[& ", 525 " {/_/(((((/]]]]]]]]]]]/]!# ", 526 " {/^(((((_^^^^^^^^^^^^^^:# ", 527 " {/^(((_^^____________^^}$ ", 528 " {/^(((((/////////////((!# ", 529 " {/^/^_:<|||||||||||||||@@****1 ", 530 " {/^/^(<[)||||||||||||||))!!}<; ", 531 " {/^_(:|234444444444444444432)1 ", 532 " {/_^/<)34444444444444444443}, ", 533 " {/^(2{:41111111111111111142|5 ", 534 " {3^3<:31111111111111111143}- ", 535 " {/^2<:31111111111111111441|' ", 536 " {_/<:41111111111111111143}, ", 537 " {(4<:31111111111111111144!# ", 538 " )4))44111111111111111144}, ", 539 " )2<:31111111111111111144{# ", 540 " @|:14444444444444444444}* ", 541 " ;@434444444444444444434<# ", 542 " ;[))))))))))))))))))))!~ ", 543 " ++++++++++++++++++++++;% ", 544 " ", 545 " "} 546 ; 547 fOpenIcon = new QPixmap(open); 548 549 550 const char * const move[]={ 551 "32 32 16 1", 552 " c None", 553 ". c #F1F1F1", 554 "+ c #939393", 555 "@ c #282828", 556 "# c #787878", 557 "$ c #000000", 558 "% c #CCCCCC", 559 "& c #1A1A1A", 560 "* c #0D0D0D", 561 "= c #5D5D5D", 562 "- c #AEAEAE", 563 "; c #BBBBBB", 564 "> c #C9C9C9", 565 ", c #D6D6D6", 566 "' c #FFFFFF", 567 ") c #999999", 568 " ", 569 " ", 570 " ", 571 " ", 572 " .. ", 573 " ++ ", 574 " .@@. ", 575 " #$$# ", 576 " %&$$*% ", 577 " =$$$$= ", 578 " -**$$**- ", 579 " %;%&*>;% ", 580 " -% @& %- ", 581 " ,=*; @& ;*=, ", 582 " .#*$$> >$$*#. ", 583 " ')&$$$$*@@ @@*$$$$&)' ", 584 " ')&$$$$*@@ @@*$$$$&+' ", 585 " .#*$$> >$$*#. ", 586 " ,=*; @& ;*=, ", 587 " -% @& %- ", 588 " %;%&*>>% ", 589 " -**$$**- ", 590 " =$$$$= ", 591 " %&$$*% ", 592 " #$$# ", 593 " .@@. ", 594 " ++ ", 595 " .. ", 596 " ", 597 " ", 598 " ", 599 " "} 600 ; 601 fMoveIcon = new QPixmap(move); 602 603 const char * const rotate[]={ 604 "32 32 27 1", 605 " c None", 606 ". c #003333", 607 "+ c #000066", 608 "@ c #1A1A1A", 609 "# c #003399", 610 "$ c #3333CC", 611 "% c #000033", 612 "& c #353535", 613 "* c #434343", 614 "= c #336699", 615 "- c #3399FF", 616 "; c #003366", 617 "> c #5D5D5D", 618 ", c #282828", 619 "' c #3399CC", 620 ") c #333333", 621 "! c #3366CC", 622 "~ c #333399", 623 "{ c #505050", 624 "] c #666666", 625 "^ c #333366", 626 "/ c #0033CC", 627 "( c #3366FF", 628 "_ c #336666", 629 ": c #787878", 630 "< c #868686", 631 "[ c #6B6B6B", 632 " .++@ ", 633 " #$$%&* ", 634 " =--; *>, ", 635 " '-= )>& ", 636 " !-', ,>* ", 637 " !!=--= >* ", 638 " =------!!~@&)@ ", 639 " --------!*{{{*&, ", 640 " -------=){*{{{>>{) ", 641 " ,!-----= ){& ,&{{@", 642 " ,*>!----= &>& )@", 643 " ){>)~---= *]) @", 644 " @*>, --! ,&@ ", 645 " @{* '! ,-!=~^,@ ", 646 " @& == {/(----!^ ", 647 " _ ]:;(----' ", 648 " ==_ >{+(----~ ", 649 " !-!!======!!(((---! ", 650 " ='--------------! ", 651 " =!!!!'!!=; !-! ", 652 " &<* !~ ", 653 " @. *[* ; ", 654 " ;+)>* ", 655 " @@ ", 656 " ", 657 " ", 658 " ", 659 " ", 660 " ", 661 " ", 662 " ", 663 " "} 664 ; 665 fRotateIcon = new QPixmap(rotate); 666 667 const char * const pick[]={ 668 /* columns rows colors chars-per-pixel */ 669 "20 20 12 1 ", 670 " c #050804", 671 ". c #222321", 672 "X c #3B3C3A", 673 "o c #4C4E4B", 674 "O c #616360", 675 "+ c #747673", 676 "@ c #8A8C89", 677 "# c #9FA19E", 678 "$ c #BABCB9", 679 "% c #CED0CD", 680 "& c #E4E6E3", 681 "* c None", 682 /* pixels */ 683 "*********oo*********", 684 "*********oo*********", 685 "******$O. .O%******", 686 "****&o .O..O O*****", 687 "***&X @**oo**@ X****", 688 "***o $***oo***$ O***", 689 "**% @**********@ %**", 690 "**O.***********& +**", 691 "**.O*****@@*****o.**", 692 "oo .oo**@ #*&XX. oo", 693 "oo .oo**@ #*&oo. oO", 694 "**.O*****##*****oX**", 695 "**O ***********& +**", 696 "**% @****&&****+ &**", 697 "***O $***Xo***# +***", 698 "****X @&*Xo*&+ o****", 699 "*****O o..o +*****", 700 "******%+. X+&******", 701 "*********oo*********", 702 "*********oO*********" 703 }; 704 fPickIcon = new QPixmap(pick); 705 706 const char * const zoom_in[]={ 707 "32 32 11 1", 708 " c None", 709 ". c #C9CBC8", 710 "+ c #A8A9A3", 711 "@ c #818783", 712 "# c #D5D8D5", 713 "$ c #9BCCCC", 714 "% c #5FC7F4", 715 "& c #FDFFFC", 716 "* c #636662", 717 "= c #9599CE", 718 "- c #DDE0DD", 719 " ", 720 " ", 721 " ", 722 " ", 723 " ", 724 " .++@@++. ", 725 " +++..#.+++ ", 726 " .@+...++++#+@. ", 727 " @$.%%+&&&@%..@ ", 728 " ++.%%%+&&&*%%.++ ", 729 " .+#%%%%+&&&*%%.#+ ", 730 " ++..%%%+&&&*%%%.++ ", 731 " +#.+++++&&&*++++.+ ", 732 " @.+&&&&&&&&&&&&&+@ ", 733 " @#+&&&&&&&&&&&&&+@ ", 734 " @.+&&&&&&&&&&&&&+. ", 735 " +++@***+&&&****@+. ", 736 " ....++++&&&*++++.. ", 737 " ++.===+&&&*%=.++ ", 738 " @..==+&&&*=..@#& ", 739 " .@+#.+&&&@-+@@*@ ", 740 " +++.++++++ *+@* ", 741 " .+@@@++. @**+* ", 742 " .*@*+* ", 743 " .*@*+* ", 744 " +*@@* ", 745 " .**+ ", 746 " ", 747 " ", 748 " ", 749 " ", 750 " "} 751 ; 752 fZoomInIcon = new QPixmap(zoom_in); 753 754 const char * const zoom_out[]={ 755 "32 32 11 1", 756 " c None", 757 ". c #C9CBC8", 758 "+ c #A8A9A3", 759 "@ c #818783", 760 "# c #D5D8D5", 761 "$ c #5FC7F4", 762 "% c #9BCCCC", 763 "& c #FDFFFC", 764 "* c #636662", 765 "= c #9599CE", 766 "- c #DDE0DD", 767 " ", 768 " ", 769 " ", 770 " ", 771 " ", 772 " .++@@++. ", 773 " +++..#.+++ ", 774 " .@+..$$$$.#+@. ", 775 " @%.$$$$$$$$..@ ", 776 " ++.$$$$$$$$$$.++ ", 777 " .+#$$$$$$$$$$$.#+ ", 778 " ++..$$$$$$$$$$$.++ ", 779 " +#.+++++++++++++.+ ", 780 " @.+&&&&&&&&&&&&&+@ ", 781 " @#+&&&&&&&&&&&&&+@ ", 782 " @.+&&&&&&&&&&&&&+. ", 783 " +++@***********@+. ", 784 " ....++++++++++++.. ", 785 " ++.===$$$$$$=.++ ", 786 " @..===$$$$=..@#& ", 787 " .@+#.$$$..-+@@*@ ", 788 " +++#--.+++ *+@* ", 789 " .+@@@++. @**+* ", 790 " .*@*+* ", 791 " .*@*+* ", 792 " +*@@* ", 793 " .**+ ", 794 " ", 795 " ", 796 " ", 797 " ", 798 " "} 799 ; 800 fZoomOutIcon = new QPixmap(zoom_out); 801 802 const char * const wireframe[]={ 803 "32 32 24 1", 804 " c None", 805 "+ c #E4E4E4", 806 "@ c #D5D5D5", 807 "# c #E1E1E1", 808 "$ c #E7E7E7", 809 "% c #D8D8D8", 810 "& c #A7A7A7", 811 "* c #000000", 812 "= c #989898", 813 "- c #8A8A8A", 814 "; c #B5B5B5", 815 "> c #1B1B1B", 816 ", c #676767", 817 "' c #959595", 818 ") c #4A4A4A", 819 "! c #878787", 820 "~ c #D3D3D3", 821 "{ c #C4C4C4", 822 "] c #A4A4A4", 823 "^ c #5B5B5B", 824 "/ c #B3B3B3", 825 "( c #787878", 826 "_ c #C7C7C7", 827 ": c #585858", 828 " ", 829 " +@@# ", 830 " $%@@@@@&****=+ ", 831 " +&********&@-***; ", 832 " +@@@&**&@@@@@@$ @*-&>&+ ", 833 " +*****&+ %*@ ,**'# ", 834 " @***)!~ @*{&*****+ ", 835 " @*!]***&+ +-*^**'~!*@ ", 836 " @*~ +@&**&@@@@@@&****&+ ~*@ ", 837 " @*@ +&********&-*= @*@ ", 838 " @*@ $%@-*-@$ @*@ @*@ ", 839 " @*@ @*@ %*% @*@ ", 840 " @*@ %*% %*% @*@ ", 841 " @*@ %*% %*% @*@ ", 842 " @*@ %*% %*% @*@ ", 843 " @*@ %*% %*% @*@ ", 844 " @*@ %*% %*% @*@ ", 845 " @*@ @*@ %*% @*@ ", 846 " @*@ =*-+ @*@ @*@ ", 847 " @*@ $%@@&****&@-*-+ @*@ ", 848 " @*@ $@&*****&@@&******&~~!*@ ", 849 " @*{/***&@@%$ $@-*-&*****+ ", 850 " @*)*)(-~ @*@ ~)**] ", 851 " +*******&@@@@+ %*_+]**] ", 852 " +@@@@@&******&@%+_*^**]# ", 853 " $%@@@&****:**&+ ", 854 " +%@&**& ", 855 " ++ ", 856 " ", 857 " ", 858 " ", 859 " "} 860 ; 861 fWireframeIcon = new QPixmap(wireframe); 862 863 const char * const solid[]={ 864 "32 32 33 1", 865 " c None", 866 "+ c #C2DEDE", 867 "@ c #B5D7DF", 868 "# c #ACD6E6", 869 "$ c #60C0EC", 870 "% c #4EB7EE", 871 "& c #53B9ED", 872 "* c #82CEEA", 873 "= c #CFDDDA", 874 "- c #94C9E8", 875 "; c #0960FF", 876 "> c #0943FF", 877 ", c #0949FF", 878 "' c #3CB3F0", 879 ") c #71C7EB", 880 "! c #73CBE5", 881 "~ c #D3DDDB", 882 "{ c #C4DDDE", 883 "] c #B7D5DF", 884 "^ c #2DACF5", 885 "/ c #59C1ED", 886 "( c #5FC0ED", 887 "_ c #85CEE9", 888 ": c #096BFF", 889 "< c #2AACF6", 890 "[ c #5CBEEC", 891 "} c #7ACAE4", 892 "| c #73CAEB", 893 "1 c #71C8E5", 894 "2 c #D1DDDA", 895 "3 c #CBDDD9", 896 "4 c #67C1EB", 897 "5 c #80CDEA", 898 " ", 899 " ", 900 " +@@@@@@#$%&*= ", 901 " +-;>>>>>>>>>,')!~ ", 902 " {]@@-;>>>>>>>>>>>>^/(_= ", 903 " {:>>>>>>>>>>>>>>>>><//[)!= ", 904 " ]>>>>>>>>>>>>>>>>>><////[)} ", 905 " @>>>>>>>>>>>>>>>>>><//////| ", 906 " @>>>>>>>>>>>>>>>>>><//////| ", 907 " @>>>>>>>>>>>>>>>>>><//////| ", 908 " @>>>>>>>>>>>>>>>>>><//////| ", 909 " @>>>>>>>>>>>>>>>>>><//////| ", 910 " @>>>>>>>>>>>>>>>>>><//////| ", 911 " @>>>>>>>>>>>>>>>>>><//////| ", 912 " @>>>>>>>>>>>>>>>>>><//////| ", 913 " @>>>>>>>>>>>>>>>>>><//////| ", 914 " @>>>>>>>>>>>>>>>>>><//////| ", 915 " @>>>>>>>>>>>>>>>>>><//////| ", 916 " @>>>>>>>>>>>>>>>>>><//////| ", 917 " @>>>>>>>>>>>>>>>>>><//////| ", 918 " @>>>>>>>>>>>>>>>>>><//////| ", 919 " @>>>>>>>>>>>>>>>>>></////[1 ", 920 " @>>>>>>>>>>>>>>>>>><////[*2 ", 921 " {:>>>>>>>>>>>>>>>>><//[)12 ", 922 " +@@@@@-;>>>>>>>>>><[)13 ", 923 " {]@@@-;>>>,'*3 ", 924 " +@@#452 ", 925 " ", 926 " ", 927 " ", 928 " ", 929 " "} 930 ; 931 fSolidIcon = new QPixmap(solid); 932 933 const char * const hidden_line_removal[]={ 934 "32 32 15 1", 935 " c None", 936 "+ c #D5D5D5", 937 "@ c #C7C7C7", 938 "# c #9C9C9C", 939 "$ c #000000", 940 "% c #8E8E8E", 941 "& c #808080", 942 "* c #A9A9A9", 943 "= c #D8D8D8", 944 "- c #CACACA", 945 "; c #181818", 946 "> c #9F9F9F", 947 ", c #ACACAC", 948 "' c #B9B9B9", 949 ") c #555555", 950 " ", 951 " +@@+ ", 952 " +@@@@@@#$$$$%+ ", 953 " +#$$$$$$$$#@&$$$* ", 954 " =-@@#$$#@@@@@-= @$&#;>= ", 955 " =$$$$$#+ -$@ *$$%+ ", 956 " -$&@-= -$- #$$$= ", 957 " -$@ -$- +&$- ", 958 " @$@ @$@ @$@ ", 959 " @$@ @$@ @$@ ", 960 " @$@ @$@ @$@ ", 961 " @$@ @$@ @$@ ", 962 " @$@ @$@ @$@ ", 963 " @$@ @$@ @$@ ", 964 " @$@ @$@ @$@ ", 965 " @$@ @$@ @$@ ", 966 " @$@ @$@ @$@ ", 967 " @$@ @$@ @$@ ", 968 " @$@ @$@ @$@ ", 969 " @$@ @$@ @$@ ", 970 " @$@ @$@ @$@ ", 971 " @$@ @$@ #$= ", 972 " -$&@@@-= -$- =>;, ", 973 " =$$$$$$$#@@@-= -$'+#$$, ", 974 " =-@@@@#$$$$$$#@-+'$)$$#+ ", 975 " =-@@@#$$$$)$$#+ ", 976 " +@@#$$# ", 977 " ++ ", 978 " ", 979 " ", 980 " ", 981 " "} 982 ; 983 fHiddenLineRemovalIcon = new QPixmap(hidden_line_removal); 984 985 const char * const hidden_line_and_surface_removal[]={ 986 "32 32 40 1", 987 " c None", 988 "+ c #FFFFFF", 989 "@ c #89A2E9", 990 "# c #5378E3", 991 "$ c #A2B5ED", 992 "% c #5379E3", 993 "& c #5076E3", 994 "* c #3E69E4", 995 "= c #0C43F8", 996 "- c #043FFE", 997 "; c #CDD9ED", 998 "> c #BDCDE9", 999 ", c #FBFCFC", 1000 "' c #406AE4", 1001 ") c #0439FE", 1002 "! c #0137FF", 1003 "~ c #4F75E3", 1004 "{ c #9EB5E3", 1005 "] c #829FE0", 1006 "^ c #B6C6E7", 1007 "/ c #9DB4E3", 1008 "( c #7E9CE0", 1009 "_ c #B2C3E9", 1010 ": c #7E9AE0", 1011 "< c #86A2E1", 1012 "[ c #CAD6ED", 1013 "} c #5177E3", 1014 "| c #829CE0", 1015 "1 c #BCCCE9", 1016 "2 c #3A67E6", 1017 "3 c #0A43FA", 1018 "4 c #95ACE1", 1019 "5 c #BBCBE9", 1020 "6 c #A9BBE5", 1021 "7 c #96AFE1", 1022 "8 c #BDCBE9", 1023 "9 c #4067E4", 1024 "0 c #6485E5", 1025 "a c #E3EAF3", 1026 "b c #CAD6F3", 1027 " ", 1028 " ", 1029 " ++++ ", 1030 " ++++++++@#$+++ ", 1031 " ++@%####&*=-#+;>, ", 1032 " +++++@'=)))))))!)~+{]^++ ", 1033 " +$%&*=)!!!!!!!!!)~+/(]_+++ ", 1034 " +#-))!!!!!!!!!!!)~+/(::<[+ ", 1035 " +#)!!!!!!!!!!!!!!}+/::::{+ ", 1036 " +#)!!!!!!!!!!!!!!}+/::::{+ ", 1037 " +#)!!!!!!!!!!!!!!}+/::::{+ ", 1038 " +#)!!!!!!!!!!!!!!}+/::::{+ ", 1039 " +#)!!!!!!!!!!!!!!}+/::::{+ ", 1040 " +#)!!!!!!!!!!!!!!}+/::::{+ ", 1041 " +#)!!!!!!!!!!!!!!}+/::::{+ ", 1042 " +#)!!!!!!!!!!!!!!}+/::::{+ ", 1043 " +#)!!!!!!!!!!!!!!}+/::::{+ ", 1044 " +#)!!!!!!!!!!!!!!}+/::::{+ ", 1045 " +#)!!!!!!!!!!!!!!}+/::::{+ ", 1046 " +#)!!!!!!!!!!!!!!}+/::::{+ ", 1047 " +#)!!!!!!!!!!!!!!}+/::::{+ ", 1048 " +#)!!!!!!!!!!!!!!}+/:::|1+ ", 1049 " +$#}}~23!!!!!!!!)~+/(]45, ", 1050 " +++++++@#}}~23!!)~+678++ ", 1051 " ++++++@#~90+a++ ", 1052 " ++++b++ ", 1053 " ++ ", 1054 " ", 1055 " ", 1056 " ", 1057 " ", 1058 " "} 1059 ; 1060 fHiddenLineAndSurfaceRemovalIcon = new QPixmap(hidden_line_and_surface_removal); 1061 1062 const char * const perspective[]={ 1063 "32 32 3 1", 1064 " c None", 1065 ". c #D5D8D5", 1066 "+ c #000000", 1067 " ", 1068 " ", 1069 " ", 1070 " ", 1071 " ", 1072 " ................ ", 1073 " ....+++++++++++++++. ", 1074 " ...++++..+.........+++. ", 1075 " ..++..............++..+. ", 1076 " .+++++++++++++++++.. .+. ", 1077 " .+...............+. .+. ", 1078 " .+. .+. .+. .+. ", 1079 " .+. .+. .+. .+. ", 1080 " .+. .+. .+. .+. ", 1081 " .+. .+. .+. .+. ", 1082 " .+. .+. .+. .+. ", 1083 " .+. .+. .+. .+. ", 1084 " .+. .+. .+. .+. ", 1085 " .+. .+. .+. .+. ", 1086 " .+. .+......+....+. ", 1087 " .+. ..++++++.+.++++. ", 1088 " .+. .++.......+...+.. ", 1089 " .+. .++. .+..++. ", 1090 " .+. ..+.. .+..+. ", 1091 " .+..++. .+.+. ", 1092 " .+.++. .+++. ", 1093 " .+++.............++. ", 1094 " .+++++++++++++++++. ", 1095 " ................... ", 1096 " ", 1097 " ", 1098 " "} 1099 ; 1100 fPerspectiveIcon = new QPixmap(perspective); 1101 1102 const char * const ortho[]={ 1103 "32 32 3 1", 1104 " c None", 1105 ". c #D5D8D5", 1106 "@ c #000000", 1107 " ", 1108 " ", 1109 " ", 1110 " ................... ", 1111 " ..@@@@@@@@@@@@@@@@@. ", 1112 " ..@@@.............@@@. ", 1113 " ..@@.@. ..@..@. ", 1114 " ..@@ ..@. .@@...@. ", 1115 " ..@@..............@@.. .@. ", 1116 " .@@@@@@@@@@@@@@@@@.. .@. ", 1117 " .@...............@. .@. ", 1118 " .@. .@. .@. .@. ", 1119 " .@. .@. .@. .@. ", 1120 " .@. .@. .@. .@. ", 1121 " .@. .@. .@. .@. ", 1122 " .@. .@. .@. .@. ", 1123 " .@. .@. .@. .@. ", 1124 " .@. .@. .@. .@. ", 1125 " .@. .@. .@. .@. ", 1126 " .@. .@. .@. .@. ", 1127 " .@. .@. .@. .@. ", 1128 " .@. .@........@......@. ", 1129 " .@. .@@@@@@@@@.@.@@@@@@. ", 1130 " .@. .@@+........@....@@.. ", 1131 " .@...@. .@...@... ", 1132 " .@.@@. .@.@@ . ", 1133 " .@@@.............@@@.. ", 1134 " .@@@@@@@@@@@@@@@@@... ", 1135 " ................... ", 1136 " ", 1137 " ", 1138 " "} 1139 ; 1140 fOrthoIcon = new QPixmap(ortho); 1141 1142 const char * const commandIcon[]={ 1143 "20 20 25 1 ", 1144 " c #4ED17F", 1145 ". c #4FD280", 1146 "X c #50D381", 1147 "o c #5BD181", 1148 "O c #5DD382", 1149 "+ c #59D48A", 1150 "@ c #66D68C", 1151 "# c #6FD895", 1152 "$ c #85DEA4", 1153 "% c #8CE0AC", 1154 "& c #96E4B8", 1155 "* c #9EE3B8", 1156 "= c #A8E5BB", 1157 "- c #A7E8C4", 1158 "; c #B2EAC8", 1159 ": c #B9ECD1", 1160 "> c #C2EDD3", 1161 ", c #CBF1DF", 1162 "< c #D4F3E3", 1163 "1 c #DDF4E5", 1164 "2 c #DBF5EC", 1165 "3 c #E5F7F0", 1166 "4 c #EDFAFB", 1167 "5 c #F6FBFE", 1168 "6 c #FEFFFC", 1169 /* pixels */ 1170 "66666666666666666666", 1171 "66%++++++++++++++&56", 1172 "6$ o..o......o..o *6", 1173 "6+o...o*<441;@.o..+6", 1174 "6+..o@1553<354$..o+6", 1175 "6+..o<5<@ .*54#o.+6", 1176 "6+o.*52X :5-..@6", 1177 "6+..15% o$+o.+6", 1178 "6+.+55@ .o.+6", 1179 "6O.#54 .X.+6", 1180 "6O #54 .X.+6", 1181 "6O.+55@ .o.+6", 1182 "6+..25% @,*o.@6", 1183 "6+o.*52X :5>.o+6", 1184 "6+..O25<@ X=54#o.+6", 1185 "6+.o.@1553<354$...@6", 1186 "6+o..oo*<44<;@o..o+6", 1187 "6$ .o..o.....o..o *6", 1188 "66%+++++OOOO+++++*66", 1189 "66666666666666666666" 1190 }; 1191 fCommandIcon = new QPixmap(commandIcon); 1192 1193 const char * const dirIcon[]={ 1194 "20 20 25 1 ", 1195 " c #DF5959", 1196 ". c #DD5F5F", 1197 "X c #DE7370", 1198 "o c #E06360", 1199 "O c #E06467", 1200 "+ c #E06C6C", 1201 "@ c #E57979", 1202 "# c #E08886", 1203 "$ c #E18D91", 1204 "% c #E19D9B", 1205 "& c #E99B9D", 1206 "* c #E8A2A2", 1207 "= c #EEB2B0", 1208 "- c #EDBBBC", 1209 "; c #EDCBC7", 1210 ": c #E9CDD1", 1211 "> c #F1D5D6", 1212 ", c #F9DFE2", 1213 "< c #EFE8E7", 1214 "1 c #F3E3E4", 1215 "2 c #F8EEEC", 1216 "3 c #FCF6F4", 1217 "4 c #F6F3F9", 1218 "5 c #F2F8FC", 1219 "6 c #FEFFFD", 1220 /* pixels */ 1221 "66666666666666666666", 1222 "66$oOOOOOOOOOOOOo%66", 1223 "6# %6", 1224 "6o +,666663:+ o6", 1225 "6o =635533666$ o6", 1226 "6o -65:+ +165X o6", 1227 "6o >6<. 36; O6", 1228 "6o 26- &6>. o6", 1229 "6. o56* @63. o6", 1230 "6. X56& o66. o6", 1231 "6. X56& +63. o6", 1232 "6. o56* @62. o6", 1233 "6o 26- =61 O6", 1234 "6o >6<. o36: o6", 1235 "6o -65:+ @265X o6", 1236 "6o =635543665# O6", 1237 "6o +1666662;+ o6", 1238 "6# %6", 1239 "66$OOOoo....OOOOo%66", 1240 "66666666666666666666"} 1241 ; 1242 fDirIcon = new QPixmap(dirIcon); 1243 1244 1245 const char * const runIcon[]={ 1246 /* columns rows colors chars-per-pixel */ 1247 "20 20 33 1 ", 1248 " c #5CA323", 1249 ". c #5EA03F", 1250 "X c #6DB620", 1251 "o c #66AD3F", 1252 "O c #70B73C", 1253 "+ c #7CC13F", 1254 "@ c #569B41", 1255 "# c #61A14E", 1256 "$ c #70A95D", 1257 "% c #7EB55C", 1258 "& c #85B94E", 1259 "* c #90BE49", 1260 "= c #81B669", 1261 "- c #81B370", 1262 "; c #95CA46", 1263 ": c #A1CD40", 1264 "> c #AED045", 1265 ", c #B3D558", 1266 "< c #9BC87E", 1267 "1 c #AED668", 1268 "2 c #A2D075", 1269 "3 c #C2DC73", 1270 "4 c #A5C98F", 1271 "5 c #C1DC9F", 1272 "6 c #CAE18E", 1273 "7 c #CCE39A", 1274 "8 c #C4DCB6", 1275 "9 c #E3ECBA", 1276 "0 c #EEF3D3", 1277 "q c #F0F7DE", 1278 "w c #F8FAE9", 1279 "e c #FCFFFB", 1280 "r c None", 1281 /* pixels */ 1282 "rrrrrrrr%<<2rrrrrrrr", 1283 "rrrrr5=$$$$===rrrrrr", 1284 "rrrr<##$$$$$---&rrrr", 1285 "rrr=###$$$$-----%rrr", 1286 "rr=####$$$$------&rr", 1287 "r2@####7##$-------rr", 1288 "r.@####048$-------Or", 1289 "r.@####q4ee=----$@.r", 1290 " .@@###w4eee5%$#@@@X", 1291 " .@@@..w4eeeeqo..@@X", 1292 " .@..ooe<eeee7Oooo@X", 1293 " ..oooOe2eee6OOOooo ", 1294 "rOooOO+e2ew2+++++O+r", 1295 "r:oO+++e30,;;;;;++Or", 1296 "r :++;:9,>,,>>:;;1rr", 1297 "rr*1;:>,333333,>32rr", 1298 "rrr66,1367777637<rrr", 1299 "rrrr509799999905rrrr", 1300 "rrrrr=8wqwwww8-rrrrr", 1301 "rrrrrrrr4444rrrrrrrr" 1302 }; 1303 fRunIcon = new QPixmap(runIcon); 1304 1305 const char * const paramIcon[]={ 1306 /* columns rows colors chars-per-pixel */ 1307 "20 20 35 1 ", 1308 " c #2E2525", 1309 ". c #403737", 1310 "X c #423A3A", 1311 "o c #443C3C", 1312 "O c #473F3F", 1313 "+ c #4C4444", 1314 "@ c #4F4848", 1315 "# c #514949", 1316 "$ c #544D4D", 1317 "% c #595252", 1318 "& c #625B5B", 1319 "* c #696262", 1320 "= c #6D6666", 1321 "- c #716B6B", 1322 "; c #726C6C", 1323 ": c #767171", 1324 "> c #7E7878", 1325 ", c #8B8787", 1326 "< c #8C8787", 1327 "1 c #8D8888", 1328 "2 c #918D8D", 1329 "3 c #928E8E", 1330 "4 c #948F8F", 1331 "5 c #9C9898", 1332 "6 c #9D9999", 1333 "7 c #D5D4D4", 1334 "8 c #D8D6D6", 1335 "9 c #DDDBDB", 1336 "0 c #EFEFEF", 1337 "q c #F6F6F6", 1338 "w c None", 1339 "e c None", 1340 "r c None", 1341 "t c gray99", 1342 "y c None", 1343 /* pixels */ 1344 "wwwwwwww5 5wwwwwwww", 1345 "wwwwwwww, ,wwwwwwww", 1346 "www&;ww7+ +9ww=-www", 1347 "ww& O# OX *ww", 1348 "ww; >ww", 1349 "wwwO .%%X +www", 1350 "www# 3wwww3 Owww", 1351 "ww7 3wwwwww3 7ww", 1352 "5<+ .wwwwwww0. +<5", 1353 " %wwwwwwww$ ", 1354 " %wwwwwwww$ ", 1355 "5<+ .wwwwwww0X +<5", 1356 "ww9 4wwwwww1 9ww", 1357 "wwwO 30ww03 Owww", 1358 "wwwX X#$X @www", 1359 "ww= =ww", 1360 "ww- +O ++ :ww", 1361 "www*>ww7+ +7ww=:www", 1362 "wwwwwwww1 1wwwwwwww", 1363 "wwwwwwww5 5wwwwwwww" 1364 }; 1365 fParamIcon = new QPixmap(paramIcon); 1366 1367 const char * const exitIcon[]={ 1368 /* columns rows colors chars-per-pixel */ 1369 "23 28 55 1 ", 1370 " c None", 1371 ". c #350505", 1372 "X c #3A0505", 1373 "o c #3C0605", 1374 "O c #3D0605", 1375 "+ c #430606", 1376 "@ c #440606", 1377 "# c #470706", 1378 "$ c #500707", 1379 "% c #510807", 1380 "& c #520807", 1381 "* c #530807", 1382 "= c #550808", 1383 "- c #570808", 1384 "; c #5C0908", 1385 ": c #5D0908", 1386 "> c #5F0908", 1387 ", c #630A08", 1388 "< c #640A09", 1389 "1 c #6B0A09", 1390 "2 c #6C0A09", 1391 "3 c #720B0A", 1392 "4 c #760B0A", 1393 "5 c #770B0A", 1394 "6 c #7A0B0B", 1395 "7 c #7D0C0B", 1396 "8 c #7F0C0B", 1397 "9 c #840D0B", 1398 "0 c #850D0C", 1399 "q c #880D0C", 1400 "w c #8D0E0C", 1401 "e c #900E0C", 1402 "r c #940E0D", 1403 "t c #950E0D", 1404 "y c #9C0F0E", 1405 "u c #9E100E", 1406 "i c #AA100E", 1407 "p c #AC100F", 1408 "a c #AD100F", 1409 "s c #AE110F", 1410 "d c #B31110", 1411 "f c #B51210", 1412 "g c #B61210", 1413 "h c #B71210", 1414 "j c #B91210", 1415 "k c #C01311", 1416 "l c #C21311", 1417 "z c #C81311", 1418 "x c #C91312", 1419 "c c #CC1412", 1420 "v c #CE1412", 1421 "b c #D01412", 1422 "n c #D11412", 1423 "m c #D31412", 1424 "M c #D51513", 1425 /* pixels */ 1426 " ", 1427 " O= ", 1428 " :MMh ", 1429 " hMMM ", 1430 " jMMM ", 1431 " <x1 jMMM %xw ", 1432 " rMMM jMMM MMMk ", 1433 " rMMMM# jMMM MMMMx ", 1434 " OMMMMk jMMM 8MMMM9 ", 1435 " xMMMM jMMM pMMMM ", 1436 " MMMM jMMM xMMM8 ", 1437 "rMMM3 jMMM MMMM ", 1438 "MMMM hMMM MMMM ", 1439 "MMMM :MMh hMMM ", 1440 "MMMM O% 8MMM ", 1441 "MMMM pMMM ", 1442 "MMMM MMMM ", 1443 "wMMM3 MMMM ", 1444 ".MMMM xMMM9 ", 1445 " hMMMk wMMMM ", 1446 " MMMMMO hMMMM= ", 1447 " <MMMMMp: $rMMMMMp ", 1448 " yMMMMMMMMMMMMMMk ", 1449 " #MMMMMMMMMMMM3 ", 1450 " uMMMMMMMMk ", 1451 " #1wr3% ", 1452 " ", 1453 " " 1454 }; 1455 fExitIcon= new QPixmap(exitIcon); 1456 } 1457 // clang-format on 1458 1459 namespace { 1460 G4SceneTreeItem* ConvertToG4SceneTreeItem(QTreeWidgetItem* item) 1461 { 1462 auto qVariant = item->data(0, Qt::UserRole); 1463 std::istringstream iss(qVariant.toString().toStdString()); 1464 void* itemAddress; iss >> itemAddress; 1465 return static_cast<G4SceneTreeItem*>(itemAddress); 1466 } 1467 1468 QColor ConvertG4ColourToQColor(const G4Colour& g4Colour) 1469 { 1470 return QColor((int)(g4Colour.GetRed()*255), 1471 (int)(g4Colour.GetGreen()*255), 1472 (int)(g4Colour.GetBlue()*255), 1473 (int)(g4Colour.GetAlpha()*255)); 1474 } 1475 1476 G4Colour ConvertQColorToG4Colour(const QColor& qColor) 1477 { 1478 return G4Color(qColor.red()/255., 1479 qColor.green()/255., 1480 qColor.blue()/255., 1481 qColor.alpha()/255.); 1482 } 1483 } 1484 1485 void G4UIQt::CreateNewSceneTreeWidget() 1486 { 1487 auto vLayout = fNewSceneTreeWidget->layout(); 1488 // reduce margins 1489 vLayout->setContentsMargins(0,0,0,0); 1490 1491 fNewSceneTreeItemTreeWidget = new NewSceneTreeItemTreeWidget; 1492 fNewSceneTreeItemTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection); 1493 vLayout->addWidget(fNewSceneTreeItemTreeWidget); 1494 1495 // A click on the item is handled here. 1496 // A click on the check box makes the volume visible/invisible 1497 connect(fNewSceneTreeItemTreeWidget, &QTreeWidget::itemClicked, 1498 [&](QTreeWidgetItem* item){SceneTreeItemClicked(item);}); 1499 // A double click on either the colour icon or the name pops up a colour dialogue 1500 connect(fNewSceneTreeItemTreeWidget, &QTreeWidget::itemDoubleClicked, 1501 [&](QTreeWidgetItem* item){SceneTreeItemDoubleClicked(item);}); 1502 1503 // A click on the expansion triangle is handled here. 1504 connect(fNewSceneTreeItemTreeWidget, &QTreeWidget::itemExpanded, 1505 [&](QTreeWidgetItem* item){SceneTreeItemExpanded(item);}); 1506 connect(fNewSceneTreeItemTreeWidget, &QTreeWidget::itemCollapsed, 1507 [&](QTreeWidgetItem* item){SceneTreeItemCollapsed(item);}); 1508 } 1509 1510 void G4UIQt::UpdateSceneTree(const G4SceneTreeItem& root) 1511 { 1512 // G4debug << "\nG4UIQt::UpdateSceneTree: scene tree summary\n"; 1513 // root.DumpTree(G4debug); // Verbosity = 0 (one line per item) 1514 // G4debug << "\nG4UIQt::UpdateSceneTree: scene tree dump\n"; 1515 // root.DumpTree(G4debug,1); // Verbosity = 1 (higher levels available) 1516 1517 // Clear the existing GUI-side tree 1518 fNewSceneTreeItemTreeWidget->clear(); 1519 // (I think this deletes everything - the top level items and their children.) 1520 1521 // Build a new GUI-side tree 1522 fNewSceneTreeItemTreeWidget->setHeaderLabel (root.GetDescription().c_str()); 1523 for (const auto& model : root.GetChildren()) { 1524 1525 auto item = new QTreeWidgetItem(fNewSceneTreeItemTreeWidget); 1526 1527 // Add this GUI-side representation of the model as a child of the top widget 1528 fNewSceneTreeItemTreeWidget->insertTopLevelItem(0,item); 1529 1530 // Add text that appears in the scene tree 1531 item->setText(0, model.GetModelType().c_str()); 1532 1533 // Load with info from model 1534 // There may be a way to add data as a QVariant, or a list of QVariants, 1535 // but let's try adding a G4SceneTreeItem pointer as a hex string. (There 1536 // does not seem to be a way of adding a pointer directly.) 1537 std::ostringstream oss; oss << std::hex << &model; 1538 auto data = QVariant(oss.str().c_str()); 1539 item->setData(0, Qt::UserRole, data); 1540 1541 // Load a tooltip 1542 G4String toolTipMessage = model.GetModelDescription(); 1543 if (!model.GetFurtherInfo().empty()) { 1544 toolTipMessage += "\n " + model.GetFurtherInfo(); 1545 } 1546 item->setToolTip(0, toolTipMessage.c_str()); 1547 1548 // Set the check state 1549 item->setCheckState 1550 (0, model.GetVisAttributes().IsVisible()? Qt::Checked: Qt::Unchecked); 1551 1552 // Set the expand state 1553 item->setExpanded(model.IsExpanded()); 1554 1555 if (model.GetType() == G4SceneTreeItem::pvmodel) { 1556 BuildPVQTree(model,item); 1557 } 1558 } 1559 } 1560 1561 // Build Physical Volume tree of touchables 1562 void G4UIQt::BuildPVQTree(const G4SceneTreeItem& g4stItem, QTreeWidgetItem* qtwItem) 1563 { 1564 const auto& g4stChildren = g4stItem.GetChildren(); 1565 for (const auto& g4stChild: g4stChildren) { 1566 QStringList qStringList; 1567 qStringList.append(g4stChild.GetDescription().c_str()); 1568 auto newQTWItem = new QTreeWidgetItem(qStringList); 1569 1570 // Add a GUI-side representation of the touchable as a child 1571 qtwItem->addChild(newQTWItem); 1572 1573 // Load with info from g4stChild 1574 // There may be a way to add data as a QVariant, or a list of QVariants, 1575 // but let's try adding a G4SceneTreeItem pointer as a hex string. (There 1576 // does not seem to be a way of adding a pointer directly.) 1577 std::ostringstream oss; oss << std::hex << &g4stChild; 1578 auto data = QVariant(oss.str().c_str()); 1579 newQTWItem->setData(0, Qt::UserRole, data); 1580 1581 // Load a tooltip 1582 if (g4stChild.GetType() == G4SceneTreeItem::ghost) { 1583 auto& nameCopyNo = g4stChild.GetDescription(); 1584 auto name = nameCopyNo.substr(0,nameCopyNo.find(':')); 1585 oss.str(""); oss << nameCopyNo << 1586 ": Click to make visible and get more information." 1587 "\n This may not work if the volume is in the \"base path\". (Hover on" 1588 "\n the model to see base path.) If this is the case," 1589 "\n \"/vis/scene/add/volume " << name << "\" to bring into the displayed tree.)"; 1590 newQTWItem->setToolTip(0, oss.str().c_str()); 1591 } else { // A fully defined touchable 1592 oss.str(""); oss << g4stChild.GetPVPath() << 1593 "\nTo see properties, right-click/dump."; 1594 newQTWItem->setToolTip(0, oss.str().c_str()); 1595 } 1596 1597 // Set the check state 1598 newQTWItem->setCheckState 1599 (0, g4stChild.GetVisAttributes().IsVisible()? Qt::Checked: Qt::Unchecked); 1600 1601 // Set the expand state 1602 newQTWItem->setExpanded(g4stChild.IsExpanded()); 1603 1604 // Set colour icon 1605 QPixmap pixmap = QPixmap(QSize(16, 16)); 1606 pixmap.fill(ConvertG4ColourToQColor(g4stChild.GetVisAttributes().GetColour())); 1607 QPainter painter(&pixmap); 1608 painter.setPen(Qt::black); 1609 painter.drawRect(0,0,15,15); // Draw contour 1610 newQTWItem->setIcon(0,pixmap); 1611 1612 // Continue recursively 1613 BuildPVQTree(g4stChild,newQTWItem); 1614 } 1615 } 1616 1617 void G4UIQt::SceneTreeItemClicked(QTreeWidgetItem* item) 1618 { 1619 if (item == nullptr) return; 1620 auto sceneTreeItem = ConvertToG4SceneTreeItem(item); 1621 if (sceneTreeItem == nullptr) return; 1622 1623 auto uiMan = G4UImanager::GetUIpointer(); 1624 1625 // Respond according to type 1626 G4String argument = "false", inverse = "true"; 1627 auto newCheckState = item->checkState(0); 1628 auto oldCheckState 1629 = sceneTreeItem->GetVisAttributes().IsVisible()? Qt::Checked: Qt::Unchecked; 1630 switch (sceneTreeItem->GetType()) { 1631 case G4SceneTreeItem::unidentified: 1632 break; // Do nothing 1633 case G4SceneTreeItem::root: 1634 break; // Do nothing 1635 case G4SceneTreeItem::model: 1636 [[fallthrough]]; 1637 case G4SceneTreeItem::pvmodel: 1638 // Clicked - but has checkbox actually been clicked? 1639 if (newCheckState != oldCheckState) { 1640 if (newCheckState == Qt::Checked) argument = "true"; 1641 uiMan->ApplyCommand 1642 ("/vis/scene/activateModel \"" + sceneTreeItem->GetModelDescription() + "\" " + argument); 1643 } 1644 break; 1645 case G4SceneTreeItem::ghost: 1646 [[fallthrough]]; 1647 case G4SceneTreeItem::touchable: 1648 // Construct and apply touchable commands 1649 // Clicked - but has checkbox actually been clicked? 1650 if (newCheckState != oldCheckState) { 1651 if (newCheckState == Qt::Checked) { 1652 argument = "true"; inverse = "false"; 1653 } 1654 uiMan->ApplyCommand("/vis/set/touchable" + sceneTreeItem->GetPVPath()); 1655 uiMan->ApplyCommand("/vis/touchable/set/visibility " + argument); 1656 // If daughters, set daughtersInvisible too 1657 if (sceneTreeItem->GetChildren().size() > 0 ) { 1658 uiMan->ApplyCommand("/vis/touchable/set/daughtersInvisible " + inverse); 1659 } 1660 // If not cancelled and if daughters > 0 and if making invisible 1661 static G4bool wanted = true; 1662 if (wanted && sceneTreeItem->GetChildren().size() > 0 && argument == "false") { 1663 QMessageBox msgBox; 1664 msgBox.setText 1665 ("This action makes this volume and all descendants invisible." 1666 " To see descendants, right-click and select daughtersInvisible/false" 1667 " and check visibility of descendants individually."); 1668 msgBox.setInformativeText 1669 ("To suppress this message click \"Discard\" or \"Don't Save\""); 1670 msgBox.setStandardButtons(QMessageBox::Discard | QMessageBox::Ok); 1671 msgBox.setDefaultButton(QMessageBox::Ok); 1672 auto action = msgBox.exec(); 1673 if (action == QMessageBox::Discard) { 1674 wanted = false; 1675 } 1676 } 1677 } 1678 break; 1679 } 1680 } 1681 1682 void G4UIQt::SceneTreeItemDoubleClicked(QTreeWidgetItem* item) 1683 { 1684 if (item == nullptr) return; 1685 auto sceneTreeItem = ConvertToG4SceneTreeItem(item); 1686 if (sceneTreeItem == nullptr) return; 1687 if (sceneTreeItem->GetType() != G4SceneTreeItem::touchable) return; 1688 1689 auto oldQColor = ConvertG4ColourToQColor(sceneTreeItem->GetVisAttributes().GetColour()); 1690 auto newQColor = QColorDialog::getColor 1691 (oldQColor, fNewSceneTreeItemTreeWidget, "", QColorDialog::ShowAlphaChannel); 1692 if (!newQColor.isValid()) return; 1693 if (newQColor == oldQColor) return; 1694 1695 auto newColour = ConvertQColorToG4Colour(newQColor); 1696 std::ostringstream oss; oss << std::setprecision(2) 1697 << newColour.GetRed() << ' ' << newColour.GetGreen() 1698 << ' ' << newColour.GetBlue() << ' ' << newColour.GetAlpha(); 1699 auto uiMan = G4UImanager::GetUIpointer(); 1700 uiMan->ApplyCommand("/vis/set/touchable" + sceneTreeItem->GetPVPath()); 1701 uiMan->ApplyCommand("/vis/touchable/set/colour " + oss.str()); 1702 1703 // Normally the sceneTreeItem will be updated when the scene is processed after the above 1704 // commands, but if the user sets the opacity to zero, G4PhysicalVolumeModel does not 1705 // transmit it (this is because some users set the opacity to zero to make a volume 1706 // invisible - perhaps they should use the visibility flag, but hey-ho). 1707 // By design, the sceneTreeItem remains, so it can still be interacted with, but 1708 // the colour will not be updated, so we do it here. 1709 if (newColour.GetAlpha() == 0.) { 1710 sceneTreeItem->AccessVisAttributes().SetColour(newColour); 1711 } 1712 } 1713 1714 void G4UIQt::SceneTreeItemExpanded(QTreeWidgetItem* item) 1715 { 1716 if (item == nullptr) return; 1717 auto sceneTreeItem = ConvertToG4SceneTreeItem(item); 1718 if (sceneTreeItem == nullptr) return; 1719 1720 if (sceneTreeItem->GetType() == G4SceneTreeItem::ghost || 1721 sceneTreeItem->GetType() == G4SceneTreeItem::touchable) { 1722 sceneTreeItem->SetExpanded(true); 1723 } 1724 } 1725 1726 void G4UIQt::SceneTreeItemCollapsed(QTreeWidgetItem* item) 1727 { 1728 if (item == nullptr) return; 1729 auto sceneTreeItem = ConvertToG4SceneTreeItem(item); 1730 if (sceneTreeItem == nullptr) return; 1731 1732 if (sceneTreeItem->GetType() == G4SceneTreeItem::ghost || 1733 sceneTreeItem->GetType() == G4SceneTreeItem::touchable) { 1734 sceneTreeItem->SetExpanded(false); 1735 } 1736 } 1737 1738 void G4UIQt::NewSceneTreeItemTreeWidget::mousePressEvent(QMouseEvent* ev) 1739 { 1740 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) 1741 auto currentMousePressPosition = ev->globalPos(); 1742 #else 1743 auto currentMousePressPosition = ev->globalPosition().toPoint(); 1744 #endif 1745 1746 if (ev->button() == Qt::RightButton) { 1747 auto item = currentItem(); 1748 if (item) { 1749 auto sceneTreeItem = ConvertToG4SceneTreeItem(item); 1750 if (sceneTreeItem) { 1751 if (sceneTreeItem->GetType() == G4SceneTreeItem::touchable) { 1752 1753 // We wish to present actions (and menus) in alphabetical order. I have 1754 // not found the required insert methods so we make our own list (map) 1755 // and add actions and menus and then creating appropriate qActions. 1756 // Using std::map to get alphabetical order. To control the order use 1757 // std::list of pairs instead. 1758 enum CommandType {withoutParameter, withABool, withAnInteger, withADouble, withAString}; 1759 static std::map<G4String,CommandType> alphabetical; // Ensures alphabetical order 1760 static G4bool first = true; 1761 if (first) { 1762 first = false; 1763 // Rather than simply take all commands, select those that make sense 1764 // in this pop-up menu. 1765 // Select from /vis/touchable. These are actions without parameter or for 1766 // which it only makes sense to use their default omitable paramater. 1767 alphabetical["centreAndZoomInOn"] = withoutParameter; 1768 alphabetical["centreOn"] = withoutParameter; 1769 alphabetical["dump"] = withoutParameter; 1770 alphabetical["extentForField"] = withoutParameter; 1771 alphabetical["localAxes"] = withoutParameter; 1772 alphabetical["showExtent"] = withoutParameter; 1773 alphabetical["twinkle"] = withoutParameter; 1774 alphabetical["volumeForField"] = withoutParameter; 1775 // Commands from /vis/touchable/set 1776 // Actions with a Boolean paramater 1777 alphabetical["daughtersInvisible"] = withABool; 1778 alphabetical["forceAuxEdgeVisible"] = withABool; 1779 alphabetical["forceCloud"] = withABool; 1780 alphabetical["forceSolid"] = withABool; 1781 alphabetical["forceWireframe"] = withABool; 1782 alphabetical["visibility"] = withABool; 1783 // Actions with an integer 1784 alphabetical["lineSegmentsPerCircle"] = withAnInteger; 1785 alphabetical["numberOfCloudPoints"] = withAnInteger; 1786 // Actions with a double 1787 alphabetical["lineWidth"] = withADouble; 1788 // Actions with a string 1789 alphabetical["lineStyle"] = withAString; 1790 } 1791 1792 QMenu topMenu; // Local (temporary) object for this item 1793 std::vector<QAction*> actions; // Temporary container for action pointers 1794 std::vector<QMenu*> menus; // Temporary container for menu pointers 1795 1796 for (const auto& action : alphabetical) { 1797 const auto& af = action.first; // G4String name of action 1798 1799 if (action.second == withoutParameter) { 1800 1801 auto qAction = new QAction(af.c_str(), this); 1802 actions.push_back(qAction); // into temporary container 1803 topMenu.addAction(qAction); 1804 connect(qAction, &QAction::triggered, this, 1805 [this, &af, &sceneTreeItem]{ActWithoutParameter(af, sceneTreeItem);}); 1806 1807 } else if (action.second == withABool) { 1808 1809 auto menu = new QMenu(af.c_str()); 1810 menus.push_back(menu); // into temporary container 1811 topMenu.addMenu(menu); 1812 auto qActionTrue = new QAction("true", this); 1813 actions.push_back(qActionTrue); // into temporary container 1814 menu->addAction(qActionTrue); 1815 connect(qActionTrue, &QAction::triggered, this, 1816 [this, &af, &sceneTreeItem]{ActWithABool(af, sceneTreeItem, true);}); 1817 auto qActionFalse = new QAction("false", this); 1818 actions.push_back(qActionFalse); // into temporary container 1819 menu->addAction(qActionFalse); 1820 connect(qActionFalse, &QAction::triggered, this, 1821 [this, &af, &sceneTreeItem]{ActWithABool(af, sceneTreeItem, false);}); 1822 1823 } else if (action.second == withAnInteger) { 1824 1825 auto qAction = new QAction(af.c_str(), this); 1826 actions.push_back(qAction); // into temporary container 1827 topMenu.addAction(qAction); 1828 connect(qAction, &QAction::triggered, this, 1829 [this, &af, &sceneTreeItem]{ActWithAnInteger(af, sceneTreeItem);}); 1830 1831 } else if (action.second == withADouble) { 1832 1833 auto qAction = new QAction(af.c_str(), this); 1834 actions.push_back(qAction); // into temporary container 1835 topMenu.addAction(qAction); 1836 connect(qAction, &QAction::triggered, this, 1837 [this, &af, &sceneTreeItem]{ActWithADouble(af, sceneTreeItem);}); 1838 1839 } else if (action.second == withAString) { 1840 1841 auto qAction = new QAction(af.c_str(), this); 1842 actions.push_back(qAction); // into temporary container 1843 topMenu.addAction(qAction); 1844 connect(qAction, &QAction::triggered, this, 1845 [this, &af, &sceneTreeItem]{ActWithAString(af, sceneTreeItem);}); 1846 } 1847 } 1848 1849 topMenu.exec(currentMousePressPosition); 1850 1851 // Clean up 1852 for (auto action : actions) { 1853 // No need to disconnect. Qt say, "A signal-slot connection is removed 1854 // when either of the objects involved are destroyed." 1855 delete action; 1856 } 1857 for (auto menu : menus) { 1858 delete menu; 1859 } 1860 } 1861 } 1862 } 1863 } 1864 1865 // Pass event on up the widget tree for other actions 1866 QTreeWidget::mousePressEvent(ev); 1867 } 1868 1869 void G4UIQt::NewSceneTreeItemTreeWidget::ActWithoutParameter 1870 (const G4String& action, G4SceneTreeItem* sceneTreeItem) 1871 { 1872 // Special case: dump 1873 if (action == "dump") { 1874 static G4bool wanted = true; 1875 if (wanted) { 1876 QMessageBox msgBox; 1877 std::ostringstream oss; 1878 oss << G4AttCheck(sceneTreeItem->GetAttValues(), sceneTreeItem->GetAttDefs()); 1879 // Just the first 1000 characters, otherwise it spreads off screen 1880 msgBox.setText((oss.str().substr(0,1000)+"...").c_str()); 1881 msgBox.setInformativeText 1882 ("To suppress this message click \"Discard\" or \"Don't Save\"." 1883 "\nTo get a complete dump to session output click \"Ok\"," 1884 "\nElse click \"Close\"."); 1885 msgBox.setStandardButtons 1886 (QMessageBox::Discard | QMessageBox::Close | QMessageBox::Ok); 1887 msgBox.setDefaultButton(QMessageBox::Ok); 1888 auto result = msgBox.exec(); 1889 if (result == QMessageBox::Discard) { 1890 wanted = false; 1891 } else if (result == QMessageBox::Close) { 1892 return; 1893 } 1894 } 1895 } 1896 auto uiMan = G4UImanager::GetUIpointer(); 1897 uiMan->ApplyCommand("/vis/set/touchable" + sceneTreeItem->GetPVPath()); 1898 uiMan->ApplyCommand("/vis/touchable/" + action); 1899 } 1900 1901 void G4UIQt::NewSceneTreeItemTreeWidget::ActWithABool 1902 (const G4String& action, G4SceneTreeItem* sceneTreeItem, G4bool whatever) 1903 { 1904 auto uiMan = G4UImanager::GetUIpointer(); 1905 uiMan->ApplyCommand("/vis/set/touchable" + sceneTreeItem->GetPVPath()); 1906 G4String which = whatever? "true": "false"; 1907 uiMan->ApplyCommand("/vis/touchable/set/" + action + ' ' + which); 1908 } 1909 1910 void G4UIQt::NewSceneTreeItemTreeWidget::ActWithAnInteger 1911 (const G4String& action, G4SceneTreeItem* sceneTreeItem) 1912 { 1913 G4bool ok = true; 1914 auto newValue = QInputDialog::getInt(this, action.c_str(), action.c_str(), 1915 0, 0, 9999999, 1, &ok); 1916 if (ok) { 1917 auto uiMan = G4UImanager::GetUIpointer(); 1918 uiMan->ApplyCommand("/vis/set/touchable" + sceneTreeItem->GetPVPath()); 1919 uiMan->ApplyCommand("/vis/touchable/set/" + action + ' ' 1920 + G4UIcommand::ConvertToString(newValue)); 1921 } 1922 } 1923 1924 void G4UIQt::NewSceneTreeItemTreeWidget::ActWithADouble 1925 (const G4String& action, G4SceneTreeItem* sceneTreeItem) 1926 { 1927 G4bool ok = true; 1928 auto newValue = QInputDialog::getDouble(this, action.c_str(), action.c_str(), 1929 0, 0, 999, 1, &ok); 1930 if (ok) { 1931 auto uiMan = G4UImanager::GetUIpointer(); 1932 uiMan->ApplyCommand("/vis/set/touchable" + sceneTreeItem->GetPVPath()); 1933 uiMan->ApplyCommand("/vis/touchable/set/" + action + ' ' 1934 + G4UIcommand::ConvertToString(newValue)); 1935 } 1936 } 1937 1938 void G4UIQt::NewSceneTreeItemTreeWidget::ActWithAString 1939 (const G4String& action, G4SceneTreeItem* sceneTreeItem) 1940 { 1941 auto uiMan = G4UImanager::GetUIpointer(); 1942 auto command = uiMan->FindCommand("/vis/touchable/set/" + action); 1943 if (command) { 1944 QStringList qStringList; 1945 const auto& candidates = command->GetParameter(0)->GetParameterCandidates(); 1946 std::istringstream iss(candidates); 1947 G4String candidate; 1948 while (iss >> candidate) qStringList.append(candidate.c_str()); 1949 G4bool ok = true; 1950 auto chosenValue = QInputDialog::getItem(this, action.c_str(), action.c_str(), qStringList, 1951 0, false, &ok); 1952 if (ok) { 1953 uiMan->ApplyCommand("/vis/set/touchable" + sceneTreeItem->GetPVPath()); 1954 G4String g4ChosenValue = chosenValue.toStdString(); 1955 uiMan->ApplyCommand("/vis/touchable/set/" + action + ' ' + g4ChosenValue); 1956 } 1957 } 1958 } 1959 1960 1961 /** Create the History ToolBox Widget 1962 */ 1963 QWidget* G4UIQt::CreateHistoryTBWidget() 1964 { 1965 fHistoryTBWidget = new QWidget(); 1966 1967 auto layoutHistoryTB = new QVBoxLayout(); 1968 fHistoryTBTableList = new QListWidget(); 1969 fHistoryTBTableList->setSelectionMode(QAbstractItemView::SingleSelection); 1970 connect(fHistoryTBTableList, SIGNAL(itemSelectionChanged()), SLOT(CommandHistoryCallback())); 1971 1972 layoutHistoryTB->addWidget(fHistoryTBTableList); 1973 1974 fHistoryTBWidget->setLayout(layoutHistoryTB); 1975 return fHistoryTBWidget; 1976 } 1977 1978 /** Create the Help ToolBox Widget 1979 */ 1980 QWidget* G4UIQt::CreateHelpTBWidget() 1981 { 1982 fHelpTBWidget = new QWidget(); 1983 1984 auto helpWidget = new QWidget(); 1985 auto helpLayout = new QHBoxLayout(); 1986 auto vLayout = new QVBoxLayout(); 1987 fHelpVSplitter = new QSplitter(Qt::Vertical); 1988 fHelpLine = new QLineEdit(); 1989 helpLayout->addWidget(new QLabel("Search :")); 1990 helpLayout->addWidget(fHelpLine); 1991 connect(fHelpLine, SIGNAL(editingFinished()), this, SLOT(LookForHelpStringCallback())); 1992 1993 // Create Help tree 1994 FillHelpTree(); 1995 1996 fParameterHelpLabel = new QTextEdit(); 1997 fParameterHelpLabel->setReadOnly(true); 1998 fParameterHelpTable = new QTableWidget(); 1999 2000 // Set layouts 2001 2002 if (fHelpTreeWidget != nullptr) { 2003 fHelpVSplitter->addWidget(fHelpTreeWidget); 2004 fHelpVSplitter->setStretchFactor(0,4); 2005 } 2006 fHelpVSplitter->addWidget(fParameterHelpLabel); 2007 fHelpVSplitter->addWidget(fParameterHelpTable); 2008 2009 fParameterHelpLabel->setVisible(false); 2010 fParameterHelpTable->setVisible(false); 2011 QSizePolicy policy = QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); 2012 policy.setVerticalStretch(1); 2013 fParameterHelpLabel->setSizePolicy(policy); 2014 fParameterHelpTable->setSizePolicy(policy); 2015 2016 vLayout->addWidget(helpWidget); 2017 vLayout->addWidget(fHelpVSplitter, 1); 2018 vLayout->setContentsMargins(5, 5, 5, 5); 2019 2020 helpWidget->setLayout(helpLayout); 2021 fHelpTBWidget->setLayout(vLayout); 2022 2023 return fHelpTBWidget; 2024 } 2025 2026 /** Create the Cout ToolBox Widget 2027 */ 2028 G4UIDockWidget* G4UIQt::CreateCoutTBWidget() 2029 { 2030 auto coutTBWidget = new QWidget(); 2031 2032 auto layoutCoutTB = new QVBoxLayout(); 2033 2034 fCoutTBTextArea = new QTextEdit(); 2035 2036 fCoutFilter = new QLineEdit(); 2037 fCoutFilter->setToolTip("Filter output by..."); 2038 2039 fCoutFilter->addAction(*fSearchIcon, QLineEdit::TrailingPosition); 2040 fCoutFilter->setStyleSheet("border-radius:7px;"); 2041 2042 auto coutTBClearButton = new QPushButton(); 2043 coutTBClearButton->setIcon(*fClearIcon); 2044 coutTBClearButton->setToolTip("Clear console output"); 2045 coutTBClearButton->setStyleSheet("border-radius:7px;"); 2046 connect(coutTBClearButton, SIGNAL(clicked()), SLOT(ClearButtonCallback())); 2047 connect( 2048 fCoutFilter, SIGNAL(textEdited(const QString&)), SLOT(CoutFilterCallback(const QString&))); 2049 2050 auto coutTBSaveOutputButton = new QPushButton(); 2051 coutTBSaveOutputButton->setIcon(*fSaveIcon); 2052 coutTBSaveOutputButton->setToolTip("Save console output"); 2053 coutTBSaveOutputButton->setStyleSheet("border-radius:7px;"); 2054 connect(coutTBSaveOutputButton, SIGNAL(clicked()), SLOT(SaveOutputCallback())); 2055 2056 fCoutTBTextArea->setReadOnly(true); 2057 2058 auto coutButtonWidget = new QWidget(); 2059 auto layoutCoutTBButtons = new QHBoxLayout(); 2060 2061 #ifdef G4MULTITHREADED 2062 // add all candidates to widget 2063 fThreadsFilterComboBox = new QComboBox(); 2064 fThreadsFilterComboBox->setInsertPolicy(QComboBox::InsertAlphabetically); 2065 connect( 2066 fThreadsFilterComboBox, SIGNAL(activated(int)), this, SLOT(ThreadComboBoxCallback(int))); 2067 2068 UpdateCoutThreadFilter(); 2069 2070 fThreadsFilterComboBox->setToolTip("Thread selection in output"); 2071 layoutCoutTBButtons->addWidget(new QLabel(" Threads:")); 2072 layoutCoutTBButtons->addWidget(fThreadsFilterComboBox); 2073 #endif 2074 2075 layoutCoutTBButtons->addWidget(fCoutFilter); 2076 layoutCoutTBButtons->addWidget(coutTBClearButton); 2077 layoutCoutTBButtons->addWidget(coutTBSaveOutputButton); 2078 coutButtonWidget->setLayout(layoutCoutTBButtons); 2079 2080 // reduce margins 2081 layoutCoutTBButtons->setContentsMargins(3, 3, 3, 0); 2082 2083 layoutCoutTB->addWidget(coutButtonWidget); 2084 layoutCoutTB->addWidget(fCoutTBTextArea); 2085 2086 coutTBWidget->setLayout(layoutCoutTB); 2087 2088 fCoutTBTextArea->setMinimumSize(100, 100); 2089 2090 // Command line : 2091 auto commandLineWidget = new QWidget(); 2092 auto layoutCommandLine = new QHBoxLayout(); 2093 2094 // fill them 2095 2096 fCommandLabel = new QLabel(""); 2097 fCommandArea = new QLineEdit(); 2098 2099 // The QCompleter will be append at SessionStart() 2100 2101 fCommandArea->activateWindow(); 2102 2103 fCommandArea->setFocusPolicy(Qt::StrongFocus); 2104 fCommandArea->setFocus(Qt::TabFocusReason); 2105 fCommandArea->setToolTip("Apply command"); 2106 2107 layoutCommandLine->addWidget(fCommandLabel); 2108 layoutCommandLine->addWidget(fCommandArea); 2109 2110 // Connect signal 2111 connect(fCommandArea, SIGNAL(returnPressed()), SLOT(CommandEnteredCallback())); 2112 connect( 2113 fCommandArea, SIGNAL(textEdited(const QString&)), SLOT(CommandEditedCallback(const QString&))); 2114 2115 commandLineWidget->setLayout(layoutCommandLine); 2116 commandLineWidget->setMinimumSize(50, 50); 2117 2118 layoutCoutTB->addWidget(commandLineWidget); 2119 2120 fCoutDockWidget = new G4UIDockWidget("Output"); 2121 fCoutDockWidget->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea); 2122 2123 fCoutDockWidget->setWidget(coutTBWidget); 2124 return fCoutDockWidget; 2125 } 2126 2127 /** Create the VisParameters ToolBox Widget 2128 */ 2129 QWidget* G4UIQt::CreateVisParametersTBWidget() { return nullptr; } 2130 2131 /** Create the VisParameters ToolBox Widget 2132 */ 2133 G4UIDockWidget* G4UIQt::CreateUITabWidget() 2134 { 2135 fUITabWidget = new QTabWidget(); 2136 2137 // the left dock 2138 fUITabWidget->addTab(CreateSceneTreeWidget(), "Scene tree"); 2139 fUITabWidget->addTab(CreateHelpTBWidget(), "Help"); 2140 fUITabWidget->addTab(CreateHistoryTBWidget(), "History"); 2141 fUITabWidget->setCurrentWidget(fHelpTBWidget); 2142 2143 fUITabWidget->setTabToolTip(0, "Tree of scene items"); 2144 fUITabWidget->setTabToolTip(1, "Help widget"); 2145 fUITabWidget->setTabToolTip(2, "All commands history"); 2146 connect(fUITabWidget, SIGNAL(currentChanged(int)), SLOT(ToolBoxActivated(int))); 2147 2148 fUIDockWidget = new G4UIDockWidget(""); 2149 fUIDockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); 2150 2151 fUIDockWidget->setWidget(fUITabWidget); 2152 2153 return fUIDockWidget; 2154 } 2155 2156 QWidget* G4UIQt::CreateSceneTreeWidget() 2157 { 2158 fSceneTreeWidget = new QWidget(); 2159 auto layout = new QVBoxLayout(); 2160 fSceneTreeWidget->setLayout(layout); 2161 2162 fSceneTreeWidget->setVisible(false); 2163 2164 return fSceneTreeWidget; 2165 } 2166 2167 void G4UIQt::CreateViewerWidget() 2168 { 2169 // Set layouts 2170 2171 // clang-format off 2172 SetStartPage(std::string("<table width='100%'><tr><td width='30%'></td><td><div ")+ 2173 "style='color: rgb(140, 31, 31); font-size: xx-large; font-family: Garamond, serif; padding-bottom: 0px; font-weight: normal'>Geant4: "+ 2174 QApplication::applicationName ().toStdString()+ 2175 "</div></td><td width='40%'> <br/><i>http://cern.ch/geant4/</i></td></tr></table>"+ 2176 "<p> </p>"+ 2177 "<div style='background:#EEEEEE;'><b>Tooltips :</b><ul>"+ 2178 "<li><b>Start a new viewer :</b><br />"+ 2179 "<i>'/vis/open/...'<br />"+ 2180 "For example '/vis/open OGL'</i></li>"+ 2181 "<li><b>Execute a macro file :</b><br />"+ 2182 "<i>'/control/execute my_macro_file'</i></li>"+ 2183 "</ul></div>"+ 2184 2185 "<div style='background:#EEEEEE;'><b>Documentation :</b><ul>"+ 2186 "<li><b>Visualisation publication :</b><br />"+ 2187 "<i><a href='http://www.worldscientific.com/doi/abs/10.1142/S1793962313400011'>The Geant4 Visualization System - A Multi-Driver Graphics System</b><br />, Allison, J. et al., International Journal of Modeling, Simulation, and Scientific Computing, Vol. 4, Suppl. 1 (2013) 1340001</a>:<br/> http://www.worldscientific.com/doi/abs/10.1142/S1793962313400011</i></li>"+ 2188 "</ul></div>"+ 2189 2190 "<div style='background:#EEEEEE;'><b>Getting Help :</b><ul>"+ 2191 "<li><b>If problems arise, try <a href='https://cern.ch/geant4-forum'>browsing the user forum</a> to see whether or not your problem has already been encountered.<br /> If it hasn't, you can post it and Geant4 developers will do their best to find a solution. This is also a good place to<br /> discuss Geant4 topics in general.</b> https://cern.ch/geant4-forum"+ 2192 "<li><b>Get a look at <a href='http://cern.ch/geant4/support'>Geant4 User support pages</a>: <i>http://cern.ch/geant4/support</i></b></li>"+ 2193 "</ul></div>" 2194 ); 2195 // clang-format on 2196 2197 // fill right splitter 2198 if (fViewerTabWidget == nullptr) { 2199 #if QT_VERSION < 0x060000 2200 fViewerTabWidget = new G4QTabWidget(); 2201 #else 2202 fViewerTabWidget = new QTabWidget(); 2203 #endif 2204 fMainWindow->setCentralWidget(fViewerTabWidget); 2205 fViewerTabWidget->setTabsClosable(true); 2206 2207 fViewerTabWidget->setUsesScrollButtons(true); 2208 2209 connect(fViewerTabWidget, SIGNAL(tabCloseRequested(int)),this, SLOT(TabCloseCallback(int))); 2210 #if QT_VERSION < 0x060000 2211 connect(fViewerTabWidget, SIGNAL(currentChanged(int)), SLOT(UpdateTabWidget(int))); 2212 #else 2213 connect(fViewerTabWidget, SIGNAL(currentChanged(int)), this, SLOT(UpdateTabWidget(int))); 2214 #endif 2215 } 2216 2217 // set the QGLWidget size policy 2218 QSizePolicy policy = QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); 2219 policy.setVerticalStretch(4); 2220 fViewerTabWidget->setSizePolicy(policy); 2221 2222 fViewerTabWidget->setMinimumSize(40, 40); 2223 } 2224 2225 /** Get the ViewerComponents ToolBox Widget 2226 */ 2227 QWidget* G4UIQt::GetSceneTreeWidget() { return fSceneTreeWidget; } 2228 2229 /** Get the Viewer properties Widget 2230 */ 2231 QWidget* G4UIQt::GetViewerPropertiesWidget() 2232 { 2233 if (fViewerPropertiesDialog == nullptr) { 2234 CreateViewerPropertiesDialog(); 2235 } 2236 return fViewerPropertiesWidget; 2237 } 2238 2239 /** Get the Pick Widget 2240 */ 2241 QWidget* G4UIQt::GetPickInfosWidget() 2242 { 2243 if (fPickInfosDialog == nullptr) { 2244 CreatePickInfosDialog(); 2245 } 2246 return fPickInfosWidget; 2247 } 2248 2249 /** Add a new tab in the viewer 2250 */ 2251 G4bool G4UIQt::AddViewerTab(QWidget* aWidget, std::string title) 2252 { 2253 if (fViewerTabWidget == nullptr) { 2254 return false; 2255 } 2256 fViewerTabWidget->addTab(aWidget, title.c_str()); 2257 2258 return true; 2259 } 2260 2261 /** Add a new tab in the viewer 2262 */ 2263 G4bool G4UIQt::AddViewerTabFromFile(std::string fileName, std::string title) 2264 { 2265 if (fViewerTabWidget == nullptr) { 2266 return false; 2267 } 2268 2269 G4UImanager* UI = G4UImanager::GetUIpointer(); 2270 if (UI == nullptr) return false; 2271 std::ifstream file(UI->FindMacroPath(fileName.c_str()).data()); 2272 if (file) { 2273 std::string content((std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>())); 2274 2275 auto text = new QTextEdit(); 2276 text->setAcceptRichText(true); 2277 text->setContentsMargins(5, 5, 5, 5); 2278 text->setText(QString("<pre>") + content.c_str() + "</pre>"); 2279 text->setReadOnly(true); 2280 fViewerTabWidget->addTab(text, title.c_str()); 2281 } 2282 else { 2283 return false; 2284 } 2285 return true; 2286 } 2287 2288 /** Add a new tab widget. 2289 Create the tab if it was not done 2290 */ 2291 G4bool G4UIQt::AddTabWidget(QWidget* aWidget, QString name) 2292 { 2293 #if QT_VERSION < 0x060000 2294 if (fViewerTabWidget == nullptr) { 2295 CreateViewerWidget(); 2296 } 2297 #endif 2298 2299 if (aWidget == nullptr) { 2300 return false; 2301 } 2302 #if QT_VERSION < 0x060000 2303 // Has to be added before we put it into the fViewerTabWidget widget 2304 aWidget->setParent(fViewerTabWidget); // Will create in some cases widget outside 2305 // of UI for a really short moment 2306 2307 fViewerTabWidget->addTab(aWidget, name); 2308 2309 fViewerTabWidget->setCurrentIndex(fViewerTabWidget->count() - 1); 2310 2311 // Set visible 2312 fViewerTabWidget->setLastTabCreated(fViewerTabWidget->currentIndex()); 2313 #else 2314 //G.Barrand: disconnect temporarily the signal/slot on UpdateTabWidget(), else 2315 // if adding a viewer, the UpdateTabWidget/Apply("vis/viewer/select") will 2316 // issue an ERROR message since the viewer is not yet declared to the G4VisManager 2317 // at this moment (see the logic in G4VisManager::CreateViewer()). 2318 QObject::disconnect(fViewerTabWidget, SIGNAL(currentChanged(int)), this, SLOT(UpdateTabWidget(int))); 2319 fViewerTabWidget->addTab(aWidget, name); 2320 fViewerTabWidget->setCurrentIndex(fViewerTabWidget->count() - 1); 2321 QObject::connect(fViewerTabWidget, SIGNAL(currentChanged(int)), this, SLOT(UpdateTabWidget(int))); 2322 #endif 2323 2324 // Not the good solution, but ensure that the help tree is correctly build when launching a viewer 2325 // It should be done by a notification when adding a command, but that's nit done yet 2326 // (Geant4.10.1) 2327 FillHelpTree(); 2328 2329 return true; 2330 } 2331 2332 void G4UIQt::SetStartPage(const std::string& text) 2333 { 2334 if (! text.empty()) { 2335 fDefaultViewerFirstPageHTMLText = text; 2336 } 2337 if (fStartPage == nullptr) { 2338 fStartPage = new QTextBrowser(); 2339 fStartPage->setContentsMargins(5, 5, 5, 5); 2340 fStartPage->setReadOnly(true); 2341 } 2342 fStartPage->setOpenExternalLinks(true); 2343 fStartPage->setHtml(fDefaultViewerFirstPageHTMLText.c_str()); 2344 } 2345 2346 #if QT_VERSION < 0x060000 2347 void G4UIQt::UpdateTabWidget(int tabNumber) 2348 { 2349 if (fViewerTabWidget == nullptr) { 2350 fViewerTabWidget = new G4QTabWidget; 2351 } 2352 2353 fViewerTabWidget->setCurrentIndex(tabNumber); 2354 2355 // Send this signal to unblock graphic updates ! 2356 fViewerTabWidget->setTabSelected(false); 2357 2358 fViewerTabWidget->setVisible(true); 2359 2360 // This will send a paintEvent to OGL Viewers 2361 fViewerTabWidget->setTabSelected(true); 2362 } 2363 #else 2364 void G4UIQt::UpdateTabWidget(int) 2365 { 2366 //G.Barrand: have the Apply("vis/viewer/select") done here instead of 2367 // in a G4QTabWidget::paintEvent(). A signal/slot looks a more 2368 // adequate Qt mechanism to do that. 2369 if (fViewerTabWidget->currentWidget() != nullptr) { 2370 auto edit = dynamic_cast<QTextEdit*>(fViewerTabWidget->currentWidget()); 2371 if (edit == nullptr) { 2372 QString text = fViewerTabWidget->tabText(fViewerTabWidget->currentIndex()); 2373 QString paramSelect = QString("/vis/viewer/select ") + text; 2374 G4UImanager::GetUIpointer()->ApplyCommand(paramSelect.toStdString().c_str()); 2375 } 2376 } 2377 } 2378 #endif 2379 2380 /** Send resize event to all tabs 2381 */ 2382 void G4UIQt::ResizeTabWidget(QResizeEvent* e) 2383 { 2384 if (fViewerTabWidget != nullptr) { 2385 for (G4int a = 0; a < fViewerTabWidget->count(); a++) { 2386 fViewerTabWidget->widget(a)->resize(e->size()); 2387 } 2388 } 2389 } 2390 2391 /** Start the Qt main loop 2392 */ 2393 G4UIsession* G4UIQt::SessionStart() 2394 { 2395 G4Qt* interactorManager = G4Qt::getInstance(); 2396 Prompt("Session :"); 2397 exitSession = false; 2398 2399 QCoreApplication::sendPostedEvents(); 2400 2401 fMainWindow->setVisible(true); 2402 2403 if (fDefaultIcons) { 2404 fToolbarApp->setVisible(true); 2405 } 2406 else { 2407 // Set not visible until session start 2408 fToolbarApp->setVisible(false); 2409 } 2410 // Rebuild help tree (new command could be registered) 2411 FillHelpTree(); 2412 2413 // Rebuild command completion (new command could be registered) 2414 UpdateCommandCompleter(); 2415 2416 // Set event filters 2417 fHistoryTBTableList->installEventFilter(this); 2418 fCommandArea->installEventFilter(this); 2419 2420 // Focus on command line 2421 fCommandArea->setFocus(); 2422 2423 interactorManager->DisableSecondaryLoop(); // TO KEEP 2424 if ((QApplication*)interactorManager->GetMainInteractor() != nullptr) 2425 ((QApplication*)interactorManager->GetMainInteractor())->exec(); 2426 2427 interactorManager->EnableSecondaryLoop(); 2428 return this; 2429 } 2430 2431 /** Display the prompt in the prompt area 2432 @param aPrompt : string to display as the promt label 2433 */ 2434 void G4UIQt::Prompt(const G4String& aPrompt) 2435 { 2436 if (aPrompt == nullptr) return; 2437 2438 fCommandLabel->setText((char*)aPrompt.data()); 2439 } 2440 2441 void G4UIQt::SessionTerminate() 2442 { 2443 G4Qt* interactorManager = G4Qt::getInstance(); 2444 fMainWindow->close(); 2445 ((QApplication*)interactorManager->GetMainInteractor())->exit(); 2446 } 2447 2448 /** 2449 Called by intercoms/src/G4UImanager.cc<br> 2450 Called by visualization/management/src/G4VisCommands.cc with "EndOfEvent" argument<br> 2451 It have to pause the session command terminal.<br> 2452 Call SecondaryLoop to wait for exit event<br> 2453 @param aState 2454 @see : G4VisCommandReviewKeptEvents::SetNewValue 2455 */ 2456 void G4UIQt::PauseSessionStart(const G4String& aState) 2457 { 2458 if (aState == nullptr) return; 2459 2460 if (aState == "G4_pause> ") { // TO KEEP 2461 SecondaryLoop("Pause, type continue to exit this state"); // TO KEEP 2462 } // TO KEEP 2463 2464 if (aState == "EndOfEvent") { // TO KEEP 2465 // Picking with feed back in event data Done here !!! 2466 SecondaryLoop("End of event, type continue to exit this state"); // TO KEEP 2467 } // TO KEEP 2468 } 2469 2470 /** 2471 Begin the secondary loop 2472 @param a_prompt : label to display as the prompt label 2473 */ 2474 void G4UIQt::SecondaryLoop(const G4String& aPrompt) 2475 { 2476 if (aPrompt == nullptr) return; 2477 2478 G4Qt* interactorManager = G4Qt::getInstance(); // TO KEEP ? 2479 Prompt(aPrompt); // TO KEEP 2480 exitPause = false; // TO KEEP 2481 while (true) { 2482 ((QApplication*)interactorManager)->processEvents(QEventLoop::WaitForMoreEvents); 2483 if (exitPause) break; // TO KEEP 2484 } // TO KEEP 2485 Prompt("Session :"); // TO KEEP 2486 } 2487 2488 #ifdef G4MULTITHREADED 2489 # include "G4AutoLock.hh" 2490 # include "G4Threading.hh" 2491 namespace 2492 { 2493 G4Mutex ReceiveMutex = G4MUTEX_INITIALIZER; 2494 } // namespace 2495 #endif 2496 2497 /** 2498 Receive a debug log message from Geant4. We have to display it in the cout zone 2499 @param aString : label to add in the display area 2500 @return 0 2501 */ 2502 G4int G4UIQt::ReceiveG4debug(const G4String& aString) 2503 { 2504 if (aString.empty()) return 0; 2505 2506 #ifdef G4MULTITHREADED 2507 G4AutoLock al(&ReceiveMutex); 2508 #endif 2509 2510 // A workaround so that output is not lost after crash or G4Exception. 2511 // The "workaround" is to make sure all flushed output appears on 2512 // the terminal after a crash, because even flushed output can 2513 // get lost in the Qt UI system. 2514 // But...it seems workers write to std::cout/cerr anyway (is that a bug?), 2515 // so limit this to the master thread 2516 #ifdef G4MULTITHREADED 2517 if (G4Threading::IsMasterThread()) 2518 #endif 2519 std::cout << aString << std::flush; 2520 2521 G4String aStringWithStyle; 2522 // aString has a \n on the end (maybe it comes from G4endl or from the 2523 // Enter key on the command line) - ignore it. That’s why 2524 // i < aString.length() - 1 2525 // But other \n need to be translated to an HTML newline. 2526 // Similarly, spaces need to be translated to an HTML "non-breaking space". 2527 // Tabs (\t) are more tricky since the number of equivalent spaces depends 2528 // on how many characters precede it. Probably needs an HTML table. For now 2529 // we replace \t with four spaces. 2530 for (G4int i = 0; i < (G4int)aString.length() - 1; ++i) { 2531 if (aString[i] == '\n') { 2532 aStringWithStyle += "<br>"; 2533 } 2534 else if (aString[i] == ' ') { 2535 aStringWithStyle += " "; 2536 } 2537 else if (aString[i] == '\t') { 2538 aStringWithStyle += " "; 2539 } 2540 else if (aString[i] == '<') { 2541 aStringWithStyle += "<"; 2542 } 2543 else { 2544 aStringWithStyle += aString[i]; 2545 } 2546 } 2547 if (fOutputStyles["debug"].fixed) { 2548 aStringWithStyle = "<span style='font-family:courier;'>" + aStringWithStyle + "</span>"; 2549 } 2550 else { 2551 aStringWithStyle = "<span>" + aStringWithStyle + "</span>"; 2552 } 2553 2554 // Add to string 2555 G4UIOutputString txt = 2556 G4UIOutputString(QString((char*)aStringWithStyle.data()), GetThreadPrefix()); 2557 fG4OutputString.push_back(txt); 2558 2559 #ifdef G4MULTITHREADED 2560 QString result = FilterOutput(txt, fThreadsFilterComboBox->currentText(), fCoutFilter->text()); 2561 #else 2562 QString result = FilterOutput(txt, "", fCoutFilter->text()); 2563 #endif 2564 2565 if (result.isEmpty()) { 2566 return 0; 2567 } 2568 2569 if (fOutputStyles["debug"].highlight) { 2570 QPalette pal; 2571 result = QString("<span style='background:") + pal.link().color().name() + ";'> </span>" + 2572 "<span style='background: Pink;'> " + result + "</span>"; 2573 } 2574 result = QString("<font color=\"Green\">") + result + QString("</font>"); 2575 2576 fCoutTBTextArea->append(result); 2577 fCoutTBTextArea->ensureCursorVisible(); 2578 2579 #ifdef G4MULTITHREADED 2580 UpdateCoutThreadFilter(); 2581 #endif 2582 2583 return 0; 2584 } 2585 2586 /** 2587 Receive a cout from Geant4. We have to display it in the cout zone 2588 @param aString : label to add in the display area 2589 @return 0 2590 */ 2591 G4int G4UIQt::ReceiveG4cout(const G4String& aString) 2592 { 2593 if (aString.empty()) return 0; 2594 2595 // Try to be smart : 2596 // "*** This is just a warning message. ***" 2597 if (G4StrUtil::contains(aString, "*** This is just a warning message. ***")) { 2598 return ReceiveG4cerr(aString); 2599 } 2600 2601 #ifdef G4MULTITHREADED 2602 G4AutoLock al(&ReceiveMutex); 2603 #endif 2604 2605 // A workaround so that output is not lost after crash or G4Exception. 2606 // The "workaround" is to make sure all flushed output appears on 2607 // the terminal after a crash, because even flushed output can 2608 // get lost in the Qt UI system. 2609 // But...it seems workers write to std::cout/cerr anyway (is that a bug?), 2610 // so limit this to the master thread 2611 #ifdef G4MULTITHREADED 2612 if (G4Threading::IsMasterThread()) 2613 #endif 2614 std::cout << aString << std::flush; 2615 2616 G4String aStringWithStyle; 2617 // aString has a \n on the end (maybe it comes from G4endl or from the 2618 // Enter key on the command line) - ignore it. That’s why 2619 // i < aString.length() - 1 2620 // But other \n need to be translated to an HTML newline. 2621 // Similarly, spaces need to be translated to an HTML "non-breaking space". 2622 // Tabs (\t) are more tricky since the number of equivalent spaces depends 2623 // on how many characters precede it. Probably needs an HTML table. For now 2624 // we replace \t with four spaces. 2625 for (G4int i = 0; i < (G4int)aString.length() - 1; ++i) { 2626 if (aString[i] == '\n') { 2627 aStringWithStyle += "<br>"; 2628 } 2629 else if (aString[i] == ' ') { 2630 aStringWithStyle += " "; 2631 } 2632 else if (aString[i] == '\t') { 2633 aStringWithStyle += " "; 2634 } 2635 else if (aString[i] == '<') { 2636 aStringWithStyle += "<"; 2637 } 2638 else { 2639 aStringWithStyle += aString[i]; 2640 } 2641 } 2642 if (fOutputStyles["cout"].fixed) { 2643 aStringWithStyle = "<span style='font-family:courier;'>" + aStringWithStyle + "</span>"; 2644 } 2645 else { 2646 aStringWithStyle = "<span>" + aStringWithStyle + "</span>"; 2647 } 2648 2649 // Add to string 2650 G4UIOutputString txt = 2651 G4UIOutputString(QString((char*)aStringWithStyle.data()), GetThreadPrefix()); 2652 fG4OutputString.push_back(txt); 2653 2654 #ifdef G4MULTITHREADED 2655 QString result = FilterOutput(txt, fThreadsFilterComboBox->currentText(), fCoutFilter->text()); 2656 #else 2657 QString result = FilterOutput(txt, "", fCoutFilter->text()); 2658 #endif 2659 2660 if (result.isEmpty()) { 2661 return 0; 2662 } 2663 2664 G4UImanager* UI = G4UImanager::GetUIpointer(); 2665 if (fOutputStyles["cout"].highlight) { 2666 if (! UI->IsLastCommandOutputTreated()) { 2667 QPalette pal; 2668 result = QString("<span style='background:") + pal.link().color().name() + 2669 ";'> </span>" + "<span style='background:" + pal.highlight().color().name() + 2670 ";'> " + result + "</span>"; 2671 } 2672 } 2673 UI->SetLastCommandOutputTreated(); 2674 2675 fCoutTBTextArea->append(result); 2676 fCoutTBTextArea->ensureCursorVisible(); 2677 2678 #ifdef G4MULTITHREADED 2679 UpdateCoutThreadFilter(); 2680 #endif 2681 2682 // reset error stack 2683 fLastErrMessage = aString; 2684 return 0; 2685 } 2686 2687 /** 2688 Receive a cerr from Geant4. We have to display it in the cout zone 2689 @param aString : label to add in the display area 2690 @return 0 2691 */ 2692 G4int G4UIQt::ReceiveG4cerr(const G4String& aString) 2693 { 2694 if (aString.empty()) return 0; 2695 2696 #ifdef G4MULTITHREADED 2697 G4AutoLock al(&ReceiveMutex); 2698 #endif 2699 2700 // A workaround so that output is not lost after crash or G4Exception. 2701 // The "workaround" is to make sure all flushed output appears on 2702 // the terminal after a crash, because even flushed output can 2703 // get lost in the Qt UI system. 2704 // But...it seems workers write to std::cout/cerr anyway (is that a bug?), 2705 // so limit this to the master thread 2706 #ifdef G4MULTITHREADED 2707 if (G4Threading::IsMasterThread()) 2708 #endif 2709 std::cerr << aString << std::flush; 2710 2711 G4String aStringWithStyle; 2712 // aString has a \n on the end (maybe it comes from G4endl or from the 2713 // Enter key on the command line) - ignore it. That’s why 2714 // i < aString.length() - 1 2715 // But other \n need to be translated to an HTML newline. 2716 // Similarly, spaces need to be translated to an HTML "non-breaking space". 2717 // Tabs (\t) are more tricky since the number of equivalent spaces depends 2718 // on how many characters precede it. Probably needs an HTML table. For now 2719 // we replace \t with four spaces. 2720 for (G4int i = 0; i < (G4int)aString.length() - 1; ++i) { 2721 if (aString[i] == '\n') { 2722 aStringWithStyle += "<br>"; 2723 } 2724 else if (aString[i] == ' ') { 2725 aStringWithStyle += " "; 2726 } 2727 else if (aString[i] == '\t') { 2728 aStringWithStyle += " "; 2729 } 2730 else if (aString[i] == '<') { 2731 aStringWithStyle += "<"; 2732 } 2733 else { 2734 aStringWithStyle += aString[i]; 2735 } 2736 } 2737 if (fOutputStyles["cerr"].fixed) { 2738 aStringWithStyle = "<span style='font-family:courier;'>" + aStringWithStyle + "</span>"; 2739 } 2740 else { 2741 aStringWithStyle = "<span>" + aStringWithStyle + "</span>"; 2742 } 2743 2744 // Add to string 2745 2746 G4UIOutputString txt = 2747 G4UIOutputString(QString((char*)aStringWithStyle.data()).trimmed(), GetThreadPrefix(), "error"); 2748 fG4OutputString.push_back(txt); 2749 2750 #ifdef G4MULTITHREADED 2751 QString result = FilterOutput(txt, fThreadsFilterComboBox->currentText(), fCoutFilter->text()); 2752 #else 2753 QString result = FilterOutput(txt, "", fCoutFilter->text()); 2754 #endif 2755 if (result.isEmpty()) { 2756 return 0; 2757 } 2758 2759 // Suppress space, \n,\t,\r... 2760 if (QString(aString.data()).trimmed() != "") { 2761 if ((G4StateManager::GetStateManager()->GetCurrentState() == G4State_Abort) || 2762 (G4StateManager::GetStateManager()->GetCurrentState() == G4State_Quit)) 2763 { 2764 // In case of Abort or Quit, the useful error message should be in the last error message ! 2765 fLastErrMessage += "\n" + aString; 2766 QString criticalMessage = fLastErrMessage.data(); 2767 criticalMessage = criticalMessage.toHtmlEscaped(); 2768 QMessageBox::critical(fMainWindow, "Error", QString(fLastErrMessage)); 2769 } 2770 } 2771 fCoutTBTextArea->append(QString("<font color=\"Red\">") + result + QString("</font>")); 2772 fCoutTBTextArea->ensureCursorVisible(); 2773 2774 if (QString(aString.data()).trimmed() != "") { 2775 fLastErrMessage += aString; 2776 } 2777 #ifdef G4MULTITHREADED 2778 UpdateCoutThreadFilter(); 2779 #endif 2780 return 0; 2781 } 2782 2783 G4String G4UIQt::GetThreadPrefix() 2784 { 2785 G4String threadPrefix = ""; 2786 #ifdef G4MULTITHREADED 2787 G4UImanager* UI = G4UImanager::GetUIpointer(); 2788 if (UI == nullptr) return ""; 2789 if (UI->GetThreadCout() != nullptr) { 2790 threadPrefix = UI->GetThreadCout()->GetFullPrefixString().data(); 2791 if (UI->GetThreadCout()->GetPrefixString() == G4String("G4VIS")) { 2792 return "G4VIS"; 2793 } 2794 } 2795 #endif 2796 return threadPrefix; 2797 } 2798 2799 #ifdef G4MULTITHREADED 2800 void G4UIQt::UpdateCoutThreadFilter() 2801 { 2802 G4UImanager* UI = G4UImanager::GetUIpointer(); 2803 if (UI == nullptr) return; 2804 2805 // add "All" and "Master" 2806 if (fThreadsFilterComboBox->count() < 2) { 2807 if (fThreadsFilterComboBox->findText("All", Qt::MatchExactly) == -1) { 2808 fThreadsFilterComboBox->addItem("All"); 2809 } 2810 } 2811 if (fThreadsFilterComboBox->count() < 2) { 2812 if (fThreadsFilterComboBox->findText("Master", Qt::MatchExactly) == -1) { 2813 fThreadsFilterComboBox->addItem("Master"); 2814 } 2815 } 2816 // Add current Cout 2817 G4String prefix = GetThreadPrefix(); 2818 if (! prefix.empty()) { 2819 if (fThreadsFilterComboBox->findText(prefix.data(), Qt::MatchExactly) == -1) { 2820 fThreadsFilterComboBox->addItem(prefix.data()); 2821 } 2822 } 2823 } 2824 #endif 2825 2826 /** 2827 Add a new menu to the menu bar 2828 @param aName name of menu 2829 @param aLabel label to display 2830 */ 2831 void G4UIQt::AddMenu(const char* aName, const char* aLabel) 2832 { 2833 if (aName == nullptr) return; 2834 if (aLabel == nullptr) return; 2835 2836 auto fileMenu = new QMenu(aLabel); 2837 fMainWindow->menuBar()->addMenu(fileMenu); 2838 2839 AddInteractor(aName, (G4Interactor)fileMenu); 2840 } 2841 2842 /** 2843 Add a new button to a menu 2844 @param aMenu : parent menu 2845 @param aLabel : label to display 2846 @param aCommand : command to execute as a callback 2847 */ 2848 void G4UIQt::AddButton(const char* aMenu, const char* aLabel, const char* aCommand) 2849 { 2850 if (aMenu == nullptr) return; // TO KEEP 2851 if (aLabel == nullptr) return; // TO KEEP 2852 if (aCommand == nullptr) return; // TO KEEP 2853 2854 QMenu* parentTmp = (QMenu*)GetInteractor(aMenu); 2855 2856 if (parentTmp == nullptr) { 2857 G4UImanager* UImanager = G4UImanager::GetUIpointer(); 2858 G4int verbose = UImanager->GetVerboseLevel(); 2859 2860 if (verbose >= 2) { 2861 G4cout << "Menu name " << aMenu << " does not exist, please define it before using it." 2862 << G4endl; 2863 } 2864 return; 2865 } 2866 2867 // Find the command in the command tree 2868 G4UImanager* UI = G4UImanager::GetUIpointer(); 2869 if (UI == nullptr) return; 2870 G4UIcommandTree* treeTop = UI->GetTree(); 2871 2872 G4String cmd = aCommand; 2873 std::size_t cmdEndPos = cmd.find_first_of(" \t"); 2874 if (cmdEndPos != std::string::npos) { 2875 cmd.erase(cmdEndPos); 2876 } 2877 2878 if (treeTop->FindPath(cmd) == nullptr) { 2879 if (cmd != "ls" && cmd.substr(0, 3) != "ls " && cmd != "pwd" && cmd != "cd" && 2880 cmd.substr(0, 3) != "cd " && cmd != "help" && cmd.substr(0, 5) != "help " && 2881 cmd[0] != '?' && cmd != "hist" && cmd != "history" && cmd[0] != '!' && cmd != "exit" && 2882 cmd != "cont" && cmd != "continue") 2883 { 2884 G4UImanager* UImanager = G4UImanager::GetUIpointer(); 2885 G4int verbose = UImanager->GetVerboseLevel(); 2886 2887 if (verbose >= 2) { 2888 G4cout << "Warning: command '" << cmd 2889 << "' does not exist, please define it before using it." << G4endl; 2890 } 2891 } 2892 } 2893 2894 QString cmd_tmp = QString(aCommand); 2895 parentTmp->addAction(aLabel, this, [this, cmd_tmp]() { this->ButtonCallback(cmd_tmp); }); 2896 } 2897 2898 /** 2899 special case for the "open" icon. It will open a file selector and map the return file to the given 2900 command. 2901 */ 2902 void G4UIQt::AddIcon( 2903 const char* aLabel, const char* aIconFile, const char* aCommand, const char* aFileName) 2904 { 2905 if (aLabel == nullptr) return; // TO KEEP 2906 // special case, aCommand could be NULL if aIconFile is not user_icon 2907 if (aCommand == nullptr) { 2908 if (std::string(aIconFile) == "user_icon") { 2909 return; // TO KEEP 2910 } 2911 } 2912 QPixmap* pix; 2913 G4bool userToolBar = false; 2914 2915 if (! fDefaultIcons) { 2916 userToolBar = true; 2917 } 2918 if (std::string(aIconFile) == "user_icon") { 2919 // try to open a file 2920 G4UImanager* UImanager = G4UImanager::GetUIpointer(); 2921 pix = new QPixmap(UImanager->FindMacroPath(aFileName).data()); 2922 if (pix->isNull()) { 2923 G4int verbose = UImanager->GetVerboseLevel(); 2924 2925 if (verbose >= 2) { 2926 G4cout << "Warning: file '" << aFileName 2927 << "' is incorrect or does not exist, this command will not be build" << G4endl; 2928 } 2929 return; 2930 } 2931 } 2932 else if (std::string(aIconFile) == "open") { 2933 pix = fOpenIcon; 2934 } 2935 else if (std::string(aIconFile) == "save") { 2936 pix = fSaveIcon; 2937 } 2938 else if (std::string(aIconFile) == "move") { 2939 pix = fMoveIcon; 2940 } 2941 else if (std::string(aIconFile) == "rotate") { 2942 pix = fRotateIcon; 2943 } 2944 else if (std::string(aIconFile) == "pick") { 2945 pix = fPickIcon; 2946 } 2947 else if (std::string(aIconFile) == "zoom_in") { 2948 pix = fZoomInIcon; 2949 } 2950 else if (std::string(aIconFile) == "zoom_out") { 2951 pix = fZoomOutIcon; 2952 } 2953 else if (std::string(aIconFile) == "wireframe") { 2954 pix = fWireframeIcon; 2955 } 2956 else if (std::string(aIconFile) == "solid") { 2957 pix = fSolidIcon; 2958 } 2959 else if (std::string(aIconFile) == "hidden_line_removal") { 2960 pix = fHiddenLineRemovalIcon; 2961 } 2962 else if (std::string(aIconFile) == "hidden_line_and_surface_removal") { 2963 pix = fHiddenLineAndSurfaceRemovalIcon; 2964 } 2965 else if (std::string(aIconFile) == "perspective") { 2966 pix = fPerspectiveIcon; 2967 } 2968 else if (std::string(aIconFile) == "ortho") { 2969 pix = fOrthoIcon; 2970 } 2971 else if (std::string(aIconFile) == "runBeamOn") { 2972 pix = fRunIcon; 2973 } 2974 else if (std::string(aIconFile) == "exit") { 2975 pix = fExitIcon; 2976 } 2977 else { 2978 G4UImanager* UImanager = G4UImanager::GetUIpointer(); 2979 G4int verbose = UImanager->GetVerboseLevel(); 2980 2981 if (verbose >= 2) { 2982 G4cout << "Parameter" << aIconFile << " not defined" << G4endl; 2983 } 2984 return; 2985 } 2986 QToolBar* currentToolbar = nullptr; 2987 if (userToolBar) { 2988 if (fToolbarUser == nullptr) { 2989 fToolbarUser = new QToolBar(); 2990 fToolbarUser->setIconSize(QSize(20, 20)); 2991 fMainWindow->addToolBar(Qt::TopToolBarArea, fToolbarUser); 2992 } 2993 currentToolbar = fToolbarUser; 2994 } 2995 else { 2996 if (fToolbarApp == nullptr) { 2997 fToolbarApp = new QToolBar(); 2998 fToolbarApp->setIconSize(QSize(20, 20)); 2999 fMainWindow->addToolBar(Qt::TopToolBarArea, fToolbarApp); 3000 } 3001 currentToolbar = fToolbarApp; 3002 } 3003 3004 // Check if already present 3005 3006 QList<QAction*> list = currentToolbar->actions(); 3007 3008 for (auto i : list) { 3009 if (i->text() == QString(aLabel)) { 3010 G4UImanager* UI = G4UImanager::GetUIpointer(); 3011 if (UI == nullptr) return; 3012 G4int verbose = UI->GetVerboseLevel(); 3013 if (verbose >= 2) { 3014 G4cout << "Warning: A toolBar icon \"" << aLabel << "\" already exists with the same name!" 3015 << G4endl; 3016 } 3017 } 3018 } 3019 3020 // special cases :"open" 3021 if (std::string(aIconFile) == "open") { 3022 QString txt = aCommand + fStringSeparator + aLabel; 3023 currentToolbar->addAction( 3024 QIcon(*pix), aIconFile, this, [this, txt]() { this->OpenIconCallback(txt); }); 3025 3026 // special cases :"save" 3027 } 3028 else if (std::string(aIconFile) == "save") { 3029 QString txt = aCommand + fStringSeparator + aLabel; 3030 currentToolbar->addAction( 3031 QIcon(*pix), aIconFile, this, [this, txt]() { this->SaveIconCallback(txt); }); 3032 // special cases : cursor style 3033 } 3034 else if ((std::string(aIconFile) == "move") || (std::string(aIconFile) == "rotate") || 3035 (std::string(aIconFile) == "pick") || (std::string(aIconFile) == "zoom_out") || 3036 (std::string(aIconFile) == "zoom_in")) 3037 { 3038 QString txt = QString(aIconFile); 3039 QAction* action = currentToolbar->addAction( 3040 QIcon(*pix), aIconFile, this, [this, txt]() { this->ChangeCursorAction(txt); }); 3041 action->setCheckable(true); 3042 action->setChecked(true); 3043 action->setData(aIconFile); 3044 3045 if (std::string(aIconFile) == "move") { 3046 SetIconMoveSelected(); 3047 } 3048 if (std::string(aIconFile) == "rotate") { 3049 SetIconRotateSelected(); 3050 } 3051 if (std::string(aIconFile) == "pick") { 3052 SetIconPickSelected(); 3053 } 3054 if (std::string(aIconFile) == "zoom_in") { 3055 SetIconZoomInSelected(); 3056 } 3057 if (std::string(aIconFile) == "zoom_out") { 3058 SetIconZoomOutSelected(); 3059 } 3060 3061 // special case : surface style 3062 } 3063 else if ((std::string(aIconFile) == "hidden_line_removal") || 3064 (std::string(aIconFile) == "hidden_line_and_surface_removal") || 3065 (std::string(aIconFile) == "solid") || (std::string(aIconFile) == "wireframe")) 3066 { 3067 QString txt = QString(aIconFile); 3068 QAction* action = currentToolbar->addAction( 3069 QIcon(*pix), aIconFile, this, [this, txt]() { this->ChangeSurfaceStyle(txt); }); 3070 action->setCheckable(true); 3071 action->setChecked(true); 3072 action->setData(aIconFile); 3073 3074 if (std::string(aIconFile) == "hidden_line_removal") { 3075 SetIconHLRSelected(); 3076 } 3077 if (std::string(aIconFile) == "hidden_line_and_surface_removal") { 3078 SetIconHLHSRSelected(); 3079 } 3080 if (std::string(aIconFile) == "solid") { 3081 SetIconSolidSelected(); 3082 } 3083 if (std::string(aIconFile) == "wireframe") { 3084 SetIconWireframeSelected(); 3085 } 3086 3087 // special case : perspective/ortho 3088 } 3089 else if ((std::string(aIconFile) == "perspective") || (std::string(aIconFile) == "ortho")) { 3090 QString txt = QString(aIconFile); 3091 QAction* action = currentToolbar->addAction( 3092 QIcon(*pix), aIconFile, this, [this, txt]() { this->ChangePerspectiveOrtho(txt); }); 3093 action->setCheckable(true); 3094 action->setChecked(true); 3095 action->setData(aIconFile); 3096 3097 if (std::string(aIconFile) == "perspective") { 3098 SetIconPerspectiveSelected(); 3099 } 3100 if (std::string(aIconFile) == "ortho") { 3101 SetIconOrthoSelected(); 3102 } 3103 } 3104 else { 3105 // Find the command in the command tree 3106 G4UImanager* UI = G4UImanager::GetUIpointer(); 3107 if (UI == nullptr) return; 3108 G4UIcommandTree* treeTop = UI->GetTree(); 3109 if (aCommand != nullptr) { 3110 std::string str = aCommand; 3111 std::string::size_type pos = str.find(' '); 3112 if (pos != std::string::npos) { 3113 str = str.substr(0, pos).c_str(); 3114 } 3115 if (treeTop->FindPath(str.c_str()) == nullptr) { 3116 G4UImanager* UImanager = G4UImanager::GetUIpointer(); 3117 G4int verbose = UImanager->GetVerboseLevel(); 3118 3119 if (verbose >= 2) { 3120 G4cout << "Warning: command '" << aCommand 3121 << "' does not exist, please define it before using it." << G4endl; 3122 } 3123 } 3124 } 3125 QString txt = QString(aCommand); 3126 currentToolbar->addAction( 3127 QIcon(*pix), aCommand, this, [this, txt]() { this->ButtonCallback(txt); }); 3128 } 3129 } 3130 3131 void G4UIQt::SetOutputStyle(const char* destination, const char* style) 3132 { 3133 // Specify an output style 3134 // First argument destination ("cout" etc or "all") 3135 // Second argument is the required style - see guidance 3136 3137 SetStyleUtility(destination, style); 3138 } 3139 3140 void G4UIQt::NativeMenu(G4bool aVal) 3141 { 3142 if (fMainWindow->menuBar()->isNativeMenuBar() == aVal) return; // already in this state 3143 3144 // Menu become empty when goin from Qt to Native Bar 3145 fMainWindow->menuBar()->setNativeMenuBar(aVal); 3146 } 3147 3148 void G4UIQt::ClearMenu() { fMainWindow->menuBar()->clear(); } 3149 3150 void G4UIQt::ActivateCommand(G4String newCommand) 3151 { 3152 if (fHelpTreeWidget == nullptr) { 3153 return; 3154 } 3155 // Look for the choosen command "newCommand" 3156 std::size_t i = newCommand.find(' '); 3157 G4String targetCom = ""; 3158 if (i != std::string::npos) { 3159 G4String newValue = newCommand.substr(i + 1, newCommand.length() - (i + 1)); 3160 G4StrUtil::strip(newValue); 3161 targetCom = ModifyToFullPathCommand(newValue); 3162 } 3163 if (! targetCom.empty()) { 3164 OpenHelpTreeOnCommand(targetCom.data()); 3165 } 3166 3167 fUITabWidget->setCurrentWidget(fHelpTBWidget); 3168 } 3169 3170 /** 3171 Create the help tree widget 3172 @param parent : parent of tree widget 3173 @return the widget containing the tree or NULL if it could not have beeen created 3174 */ 3175 3176 void G4UIQt::InitHelpTreeAndVisParametersWidget() 3177 { 3178 if (fHelpTreeWidget == nullptr) { 3179 fHelpTreeWidget = new QTreeWidget(); 3180 } 3181 3182 // build widget 3183 fHelpTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection); 3184 QStringList labels; 3185 labels << QString("Command"); 3186 fHelpTreeWidget->setHeaderLabels(labels); 3187 3188 connect(fHelpTreeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(HelpTreeClicCallback())); 3189 connect(fHelpTreeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, 3190 SLOT(HelpTreeDoubleClicCallback())); 3191 } 3192 /** 3193 Create the help tree widget 3194 @param parent : parent of tree widget 3195 @return the widget containing the tree or NULL if it could not have beeen created 3196 */ 3197 3198 void G4UIQt::FillHelpTree() 3199 { 3200 if (fHelpTreeWidget == nullptr) { 3201 InitHelpTreeAndVisParametersWidget(); 3202 } 3203 3204 QString searchText = fHelpLine->text(); 3205 3206 if (searchText == "") { 3207 // clear old help tree 3208 // fHelpTreeWidget->clear(); 3209 } 3210 else { 3211 return; 3212 } 3213 3214 if (fParameterHelpLabel != nullptr) { 3215 fParameterHelpLabel->setText("Choose a command in the command tree"); 3216 fParameterHelpTable->setVisible(false); 3217 } 3218 3219 if (fHelpLine != nullptr) { 3220 fHelpLine->setText(""); 3221 } 3222 3223 G4UImanager* UI = G4UImanager::GetUIpointer(); 3224 if (UI == nullptr) return; 3225 G4UIcommandTree* treeTop = UI->GetTree(); 3226 3227 G4int treeSize = treeTop->GetTreeEntry(); 3228 QTreeWidgetItem* newItem = nullptr; 3229 QString commandText = ""; 3230 for (G4int a = 0; a < treeSize; ++a) { 3231 // Creating new item 3232 newItem = nullptr; 3233 3234 commandText = QString((char*)(treeTop->GetTree(a + 1)->GetPathName()).data()).trimmed(); 3235 3236 // if already exist, don't create it ! 3237 for (G4int b = 0; b < fHelpTreeWidget->topLevelItemCount(); ++b) { 3238 if (newItem == nullptr) newItem = FindTreeItem(fHelpTreeWidget->topLevelItem(b), commandText); 3239 } 3240 3241 if (newItem == nullptr) { 3242 newItem = new QTreeWidgetItem(); 3243 newItem->setText(0, GetShortCommandPath(commandText)); 3244 fHelpTreeWidget->addTopLevelItem(newItem); 3245 } 3246 3247 // look for childs 3248 CreateHelpTree(newItem, treeTop->GetTree(a + 1)); 3249 } 3250 } 3251 3252 /** Fill the Help Tree Widget 3253 @param aParent : parent item to fill 3254 @param aCommandTree : commandTree node associate with this part of the Tree 3255 */ 3256 void G4UIQt::CreateHelpTree(QTreeWidgetItem* aParent, G4UIcommandTree* aCommandTree) 3257 { 3258 if (aParent == nullptr) return; 3259 if (aCommandTree == nullptr) return; 3260 3261 // Creating new item 3262 QTreeWidgetItem* newItem; 3263 3264 QString commandText = ""; 3265 // Get the Sub directories 3266 for (G4int a = 0; a < aCommandTree->GetTreeEntry(); ++a) { 3267 commandText = QString((char*)(aCommandTree->GetTree(a + 1)->GetPathName()).data()).trimmed(); 3268 3269 // if already exist, don't create it ! 3270 newItem = FindTreeItem(aParent, commandText); 3271 if (newItem == nullptr) { 3272 newItem = new QTreeWidgetItem(); 3273 newItem->setText(0, GetShortCommandPath(commandText)); 3274 aParent->addChild(newItem); 3275 } 3276 CreateHelpTree(newItem, aCommandTree->GetTree(a + 1)); 3277 } 3278 3279 // Get the Commands 3280 3281 for (G4int a = 0; a < aCommandTree->GetCommandEntry(); ++a) { 3282 QStringList stringList; 3283 commandText = 3284 QString((char*)(aCommandTree->GetCommand(a + 1)->GetCommandPath()).data()).trimmed(); 3285 3286 // if already exist, don't create it ! 3287 newItem = FindTreeItem(aParent, commandText); 3288 if (newItem == nullptr) { 3289 newItem = new QTreeWidgetItem(); 3290 newItem->setText(0, GetShortCommandPath(commandText)); 3291 aParent->addChild(newItem); 3292 newItem->setExpanded(false); 3293 } 3294 } 3295 } 3296 3297 /** 3298 Add the following command to the corresponding groupbox 3299 If depthLevel is 1 : create ToolBox 3300 If depthLevel is 2 or more : create GroupBox 3301 */ 3302 G4bool G4UIQt::CreateVisCommandGroupAndToolBox( 3303 G4UIcommand* aCommand, QWidget* aParent, G4int aDepthLevel, G4bool isDialog) 3304 { 3305 QString commandText = 3306 QString((char*)(aCommand->GetCommandPath().data())).section("/", -aDepthLevel); 3307 3308 if (commandText == nullptr) { 3309 return false; 3310 } 3311 3312 // Look if groupBox is create 3313 // QGroupBox* gBoxCommandWidget; 3314 QWidget* newParentWidget = nullptr; 3315 G4bool found = false; 3316 QString commandSection = commandText.left(commandText.indexOf("/")); 3317 3318 if (aDepthLevel == 1) { 3319 auto currentParent = dynamic_cast<QToolBox*>(aParent); 3320 if (currentParent != nullptr) { 3321 // already exists ? 3322 for (G4int a = 0; a < currentParent->count(); ++a) { 3323 if (currentParent->itemText(a) == commandSection) { 3324 found = true; 3325 newParentWidget = currentParent->widget(a); 3326 } 3327 } 3328 } 3329 // Not found ? create it 3330 if (! found) { 3331 newParentWidget = new QGroupBox(); 3332 newParentWidget->setLayout(new QVBoxLayout()); 3333 if (currentParent != nullptr) { 3334 currentParent->addItem(newParentWidget, commandSection); 3335 } 3336 else { 3337 if (aParent->layout() == nullptr) { 3338 aParent->setLayout(new QVBoxLayout()); 3339 } 3340 aParent->layout()->addWidget(newParentWidget); 3341 } 3342 3343 if (commandText.indexOf("/") == -1) { 3344 // Guidance 3345 QString guidance; 3346 auto n_guidanceEntry = (G4int)aCommand->GetGuidanceEntries(); 3347 for (G4int i_thGuidance = 0; i_thGuidance < n_guidanceEntry; i_thGuidance++) { 3348 guidance += QString((char*)(aCommand->GetGuidanceLine(i_thGuidance)).data()) + "\n"; 3349 } 3350 newParentWidget->setToolTip(guidance); 3351 } 3352 3353 auto sc = dynamic_cast<QScrollArea*>(newParentWidget->parent()->parent()); 3354 if (sc != nullptr) { 3355 sc->ensureWidgetVisible(newParentWidget); 3356 } 3357 } 3358 } 3359 else { 3360 // try to know if this level is already there 3361 auto currentParent = dynamic_cast<QGroupBox*>(aParent); 3362 if (currentParent != nullptr) { 3363 // if depth==2, then we add a [more parameters inside] to the toolBoxItem parent 3364 // QGroupBox > QWidget > QScrollArea > QToolBox 3365 if (aDepthLevel == 2) { 3366 auto parentToolBox = dynamic_cast<QToolBox*>(currentParent->parent()->parent()->parent()); 3367 if (parentToolBox != nullptr) { 3368 // parentToolBox->setItemText(parentToolBox->indexOf(currentParent),"[more 3369 // parameters inside]"); 3370 } 3371 } 3372 for (G4int a = 0; a < aParent->layout()->count(); ++a) { 3373 auto gb = dynamic_cast<QGroupBox*>(aParent->layout()->itemAt(a)->widget()); 3374 if (gb != nullptr) { 3375 if (gb->title() == commandSection) { 3376 found = true; 3377 newParentWidget = gb; 3378 } 3379 } 3380 } 3381 } 3382 3383 // Not found ? create it 3384 if (! found) { 3385 newParentWidget = new QGroupBox(); 3386 newParentWidget->setLayout(new QVBoxLayout()); 3387 if (aParent->layout() == nullptr) { 3388 aParent->setLayout(new QVBoxLayout()); 3389 } 3390 aParent->layout()->addWidget(newParentWidget); 3391 3392 // set toolTip 3393 // Guidance 3394 QString guidance; 3395 auto n_guidanceEntry = (G4int)aCommand->GetGuidanceEntries(); 3396 for (G4int i_thGuidance = 0; i_thGuidance < n_guidanceEntry; i_thGuidance++) { 3397 guidance += QString((char*)(aCommand->GetGuidanceLine(i_thGuidance)).data()) + "\n"; 3398 } 3399 newParentWidget->setToolTip(guidance); 3400 } 3401 } 3402 3403 // fill command groupbox 3404 if (commandText.indexOf("/") == -1) { 3405 if (CreateCommandWidget(aCommand, newParentWidget, isDialog)) { 3406 return true; 3407 } 3408 } 3409 else { 3410 CreateVisCommandGroupAndToolBox(aCommand, newParentWidget, aDepthLevel - 1, isDialog); 3411 } 3412 3413 return true; 3414 } 3415 3416 /** Create a widget with the command parameters inside 3417 @param command: command line 3418 @parent : parent widget 3419 @isDialog : true if we want apply/cancel button and close at end, false if we want only apply 3420 */ 3421 G4bool G4UIQt::CreateCommandWidget(G4UIcommand* aCommand, QWidget* aParent, G4bool isDialog) 3422 { 3423 if (aCommand == nullptr) { 3424 return false; 3425 } 3426 3427 // parameters 3428 auto n_parameterEntry = (G4int)aCommand->GetParameterEntries(); 3429 if (n_parameterEntry > 0) { 3430 G4UIparameter* param; 3431 3432 // Re-implementation of G4UIparameter.cc 3433 auto paramWidget = new QWidget(); 3434 auto gridLayout = new QGridLayout(); 3435 paramWidget->setLayout(gridLayout); 3436 3437 // Special case for colour, try to display a color chooser if we found red/green/blue parameter 3438 unsigned int nbColorParameter = 0; 3439 G4bool isStillColorParameter = false; 3440 G4bool isColorDialogAdded = false; 3441 QLabel* redLabel = nullptr; 3442 QLabel* greenLabel = nullptr; 3443 QString redDefaultStr = ""; 3444 QString greenDefaultStr = ""; 3445 QString blueDefaultStr = ""; 3446 QWidget* redInput = nullptr; 3447 QWidget* greenInput = nullptr; 3448 3449 for (G4int i_thParameter = 0; i_thParameter < n_parameterEntry; i_thParameter++) { 3450 QString txt; 3451 param = aCommand->GetParameter(i_thParameter); 3452 auto label = new QLabel(QString((char*)(param->GetParameterName()).data())); 3453 3454 if ((label->text() == "red") || (label->text() == "red_or_string")) { 3455 nbColorParameter++; 3456 isStillColorParameter = true; 3457 } 3458 else if ((label->text() == "green") && isStillColorParameter) { 3459 nbColorParameter++; 3460 } 3461 else if ((label->text() == "blue") && isStillColorParameter) { 3462 nbColorParameter++; 3463 } 3464 else if (! isColorDialogAdded) { 3465 // not following red/green/blue parameters ? 3466 if (nbColorParameter == 1) { 3467 gridLayout->addWidget(redLabel, i_thParameter - 1, 0); 3468 gridLayout->addWidget(redInput, i_thParameter - 1, 1); 3469 } 3470 else if (nbColorParameter == 2) { 3471 gridLayout->addWidget(redLabel, i_thParameter - 2, 0); 3472 gridLayout->addWidget(redInput, i_thParameter - 2, 1); 3473 gridLayout->addWidget(greenLabel, i_thParameter - 1, 0); 3474 gridLayout->addWidget(greenInput, i_thParameter - 1, 1); 3475 } 3476 nbColorParameter = 0; 3477 } 3478 // Check parameter type, could be NULL if not found 3479 QWidget* input = nullptr; 3480 if ((QString(QChar(param->GetParameterType())) == "d") || 3481 (QString(QChar(param->GetParameterType())) == "i")) 3482 { 3483 input = new QLineEdit(); 3484 // set default value 3485 dynamic_cast<QLineEdit*>(input)->setText(QString((char*)(param->GetDefaultValue()).data())); 3486 3487 if (((label->text() == "red") || (label->text() == "red_or_string")) && 3488 isStillColorParameter) 3489 { 3490 redDefaultStr = QString((char*)(param->GetDefaultValue()).data()); 3491 } 3492 else if ((label->text() == "green") && isStillColorParameter) { 3493 greenDefaultStr = QString((char*)(param->GetDefaultValue()).data()); 3494 } 3495 else if ((label->text() == "blue") && isStillColorParameter) { 3496 blueDefaultStr = QString((char*)(param->GetDefaultValue()).data()); 3497 } 3498 } 3499 else if (QString(QChar(param->GetParameterType())) == "b") { 3500 input = new QWidget(); 3501 auto layout = new QHBoxLayout(); 3502 input->setLayout(layout); 3503 3504 auto buttons = new QButtonGroup(); 3505 auto radioOff = new QRadioButton("0"); 3506 auto radioOn = new QRadioButton("1"); 3507 buttons->addButton(radioOn); 3508 buttons->addButton(radioOff); 3509 layout->addWidget(radioOn); 3510 layout->addWidget(radioOff); 3511 3512 // set default value 3513 QString defaultValue = QString((char*)(param->GetDefaultValue()).data()); 3514 if (defaultValue == "0") { 3515 radioOff->setChecked(true); 3516 } 3517 else if (defaultValue == "1") { 3518 radioOn->setChecked(true); 3519 } 3520 } 3521 else if ((QString(QChar(param->GetParameterType())) == "s") && 3522 (! param->GetParameterCandidates().empty())) 3523 { 3524 input = new QComboBox(); 3525 QString candidates = QString((char*)(param->GetParameterCandidates()).data()); 3526 QStringList list = candidates.split(" "); 3527 3528 // add all candidates to widget 3529 QString defaultValue = QString((char*)(param->GetDefaultValue()).data()); 3530 for (int a = 0; a < list.size(); a++) { 3531 dynamic_cast<QComboBox*>(input)->addItem(list.at(a)); 3532 if (list.at(a) == defaultValue) { 3533 dynamic_cast<QComboBox*>(input)->setCurrentIndex(a); 3534 } 3535 } 3536 } 3537 else if ((QString(QChar(param->GetParameterType())) == "s")) { // string 3538 input = new QLineEdit(); 3539 // set default value 3540 dynamic_cast<QLineEdit*>(input)->setText(QString((char*)(param->GetDefaultValue()).data())); 3541 } 3542 else if ((QString(QChar(param->GetParameterType())) == "c")) { // on/off 3543 input = new QWidget(); 3544 auto layout = new QHBoxLayout(); 3545 input->setLayout(layout); 3546 3547 auto buttons = new QButtonGroup(); 3548 auto radioOff = new QRadioButton("off"); 3549 auto radioOn = new QRadioButton("on"); 3550 buttons->addButton(radioOn); 3551 buttons->addButton(radioOff); 3552 layout->addWidget(radioOn); 3553 layout->addWidget(radioOff); 3554 3555 // set default value 3556 QString defaultValue = QString((char*)(param->GetDefaultValue()).data()); 3557 if (defaultValue == "off") { 3558 radioOff->setChecked(true); 3559 } 3560 else if (defaultValue == "on") { 3561 radioOn->setChecked(true); 3562 } 3563 } 3564 else { 3565 input = new QLineEdit(); 3566 dynamic_cast<QLineEdit*>(input)->setText(QString((char*)(param->GetDefaultValue()).data())); 3567 } 3568 3569 txt += "\nParameter : " + QString((char*)(param->GetParameterName()).data()) + "\n"; 3570 if (! param->GetParameterGuidance().empty()) 3571 txt += QString((char*)(param->GetParameterGuidance()).data()) + "\n"; 3572 3573 txt += " Parameter type : " + QString(QChar(param->GetParameterType())) + "\n"; 3574 if (param->IsOmittable()) { 3575 txt += " Omittable : True\n"; 3576 } 3577 else { 3578 txt += " Omittable : False\n"; 3579 } 3580 if (param->GetCurrentAsDefault()) { 3581 txt += " Default value : taken from the current value\n"; 3582 } 3583 else if (! param->GetDefaultValue().empty()) { 3584 txt += " Default value : " + QString((char*)(param->GetDefaultValue()).data()) + "\n"; 3585 } 3586 if (! param->GetParameterRange().empty()) { 3587 txt += " Parameter range : " + QString((char*)(param->GetParameterRange()).data()) + "\n"; 3588 } 3589 if (! param->GetParameterCandidates().empty()) { 3590 txt += 3591 " Candidates : " + QString((char*)(param->GetParameterCandidates()).data()) + "\n"; 3592 } 3593 3594 if (isStillColorParameter && (nbColorParameter != 0)) { 3595 if ((label->text() == "red") || (label->text() == "red_or_string")) { 3596 redLabel = label; 3597 redInput = input; 3598 } 3599 else if (label->text() == "green") { 3600 greenLabel = label; 3601 greenInput = input; 3602 } 3603 else if (label->text() == "blue") { 3604 // we have all, then add a color chooser 3605 3606 // Create a pixmap with the default color 3607 QColor qc; 3608 if ((redDefaultStr != "") && (redDefaultStr != "") && (redDefaultStr != "")) { 3609 qc.setRgbF( 3610 redDefaultStr.toDouble(), greenDefaultStr.toDouble(), blueDefaultStr.toDouble()); 3611 } 3612 QPixmap pixmap = QPixmap(QSize(16, 16)); 3613 pixmap.fill(qc); 3614 QPainter painter(&pixmap); 3615 painter.setPen(Qt::black); 3616 painter.drawRect(0, 0, 15, 15); // Draw contour 3617 3618 input = new QPushButton("Change color"); 3619 dynamic_cast<QPushButton*>(input)->setIcon(pixmap); 3620 dynamic_cast<QPushButton*>(input)->setAccessibleName( 3621 redDefaultStr + " " + greenDefaultStr + " " + blueDefaultStr); 3622 label = new QLabel("Choose color"); 3623 3624 // less 1 because we have to add one to the row number 3625 nbColorParameter--; 3626 gridLayout->addWidget(label, i_thParameter - nbColorParameter, 0); 3627 input->setToolTip("Select the current color"); 3628 gridLayout->addWidget(input, i_thParameter - nbColorParameter, 1); 3629 3630 // Connect pushButton to ColorDialog in callback 3631 connect(dynamic_cast<QPushButton*>(input), &QPushButton::clicked, 3632 [this, input]() { this->ChangeColorCallback(input); }); 3633 isColorDialogAdded = true; 3634 isStillColorParameter = false; 3635 } 3636 } 3637 else { 3638 gridLayout->addWidget(label, i_thParameter - nbColorParameter, 0); 3639 input->setToolTip(txt); 3640 gridLayout->addWidget(input, i_thParameter - nbColorParameter, 1); 3641 } 3642 } 3643 // add command name in hidden value at last line position 0 3644 auto name = new QLabel(QString((char*)(aCommand->GetCommandPath().data()))); 3645 name->hide(); 3646 gridLayout->addWidget(name, n_parameterEntry - nbColorParameter, 0); 3647 3648 auto applyButton = new QPushButton("Apply"); 3649 if (! isDialog) { 3650 gridLayout->addWidget(applyButton, n_parameterEntry - nbColorParameter, 1); 3651 connect(applyButton, &QPushButton::clicked, 3652 [this, paramWidget]() { this->VisParameterCallback(paramWidget); }); 3653 } 3654 else { 3655 // Apply/Cancel buttons 3656 3657 applyButton->setAutoDefault(true); 3658 applyButton->setDefault(true); 3659 3660 auto cancelButton = new QPushButton(tr("&Cancel")); 3661 cancelButton->setAutoDefault(true); 3662 gridLayout->addWidget(cancelButton, n_parameterEntry - nbColorParameter, 1); 3663 gridLayout->addWidget(applyButton, n_parameterEntry - nbColorParameter, 0); 3664 3665 connect(applyButton, &QPushButton::clicked, 3666 [this, paramWidget]() { this->VisParameterCallback(paramWidget); }); 3667 3668 QWidget* parentCheck = aParent; 3669 QDialog* parentDialog = nullptr; 3670 G4bool found = false; 3671 while ((parentCheck->parentWidget()) != nullptr) { 3672 parentCheck = parentCheck->parentWidget(); 3673 parentDialog = dynamic_cast<QDialog*>(parentCheck); 3674 if (parentDialog != nullptr) { 3675 connect(applyButton, SIGNAL(clicked()), parentDialog, SLOT(accept())); 3676 connect(cancelButton, SIGNAL(clicked()), parentDialog, SLOT(reject())); 3677 found = true; 3678 } 3679 } 3680 if (! found) { 3681 return false; 3682 } 3683 } 3684 3685 if (aParent->layout() == nullptr) { 3686 aParent->setLayout(new QVBoxLayout()); 3687 } 3688 aParent->layout()->addWidget(paramWidget); 3689 } 3690 3691 return true; 3692 } 3693 3694 /** Find a treeItemWidget in the help tree 3695 @param aCommand item's String to look for 3696 @return item if found, NULL if not 3697 */ 3698 QTreeWidgetItem* G4UIQt::FindTreeItem(QTreeWidgetItem* aParent, const QString& aCommand) 3699 { 3700 if (aParent == nullptr) return nullptr; 3701 3702 // Suppress last "/" 3703 QString myCommand = aCommand; 3704 3705 if (myCommand.lastIndexOf("/") == (myCommand.size() - 1)) { 3706 myCommand = myCommand.left(myCommand.size() - 1); 3707 } 3708 3709 if (GetLongCommandPath(aParent) == myCommand) return aParent; 3710 3711 QTreeWidgetItem* tmp = nullptr; 3712 for (G4int a = 0; a < aParent->childCount(); ++a) { 3713 if (tmp == nullptr) tmp = FindTreeItem(aParent->child(a), myCommand); 3714 } 3715 return tmp; 3716 } 3717 3718 /** Build the command list parameters in a QString<br> 3719 Reimplement partialy the G4UIparameter.cc 3720 @param aCommand : command to list parameters 3721 @see G4UIparameter::List() 3722 @see G4UIcommand::List() 3723 @return the command list parameters, or "" if nothing 3724 */ 3725 QString G4UIQt::GetCommandList(const G4UIcommand* aCommand) 3726 { 3727 QString txt = ""; 3728 if (aCommand == nullptr) return txt; 3729 3730 G4String commandPath = aCommand->GetCommandPath(); 3731 G4String rangeString = aCommand->GetRange(); 3732 auto n_guidanceEntry = (G4int)aCommand->GetGuidanceEntries(); 3733 auto n_parameterEntry = (G4int)aCommand->GetParameterEntries(); 3734 3735 if ((commandPath.empty()) && (rangeString.empty()) && (n_guidanceEntry == 0) && 3736 (n_parameterEntry == 0)) 3737 { 3738 return txt; 3739 } 3740 3741 if ((commandPath.length() - 1) != '/') { 3742 txt += "Command " + QString((char*)(commandPath).data()) + "\n"; 3743 } 3744 txt += "Guidance :\n"; 3745 3746 for (G4int i_thGuidance = 0; i_thGuidance < n_guidanceEntry; i_thGuidance++) { 3747 txt += QString((char*)(aCommand->GetGuidanceLine(i_thGuidance)).data()) + "\n"; 3748 } 3749 if (! rangeString.empty()) { 3750 txt += " Range of parameters : " + QString((char*)(rangeString).data()) + "\n"; 3751 } 3752 if (n_parameterEntry > 0) { 3753 G4UIparameter* param; 3754 3755 // Re-implementation of G4UIparameter.cc 3756 3757 for (G4int i_thParameter = 0; i_thParameter < n_parameterEntry; i_thParameter++) { 3758 param = aCommand->GetParameter(i_thParameter); 3759 txt += "\nParameter : " + QString((char*)(param->GetParameterName()).data()) + "\n"; 3760 if (! param->GetParameterGuidance().empty()) 3761 txt += QString((char*)(param->GetParameterGuidance()).data()) + "\n"; 3762 txt += " Parameter type : " + QString(QChar(param->GetParameterType())) + "\n"; 3763 if (param->IsOmittable()) { 3764 txt += " Omittable : True\n"; 3765 } 3766 else { 3767 txt += " Omittable : False\n"; 3768 } 3769 if (param->GetCurrentAsDefault()) { 3770 txt += " Default value : taken from the current value\n"; 3771 } 3772 else if (! param->GetDefaultValue().empty()) { 3773 txt += " Default value : " + QString((char*)(param->GetDefaultValue()).data()) + "\n"; 3774 } 3775 if (! param->GetParameterRange().empty()) { 3776 txt += " Parameter range : " + QString((char*)(param->GetParameterRange()).data()) + "\n"; 3777 } 3778 if (! param->GetParameterCandidates().empty()) { 3779 txt += 3780 " Candidates : " + QString((char*)(param->GetParameterCandidates()).data()) + "\n"; 3781 } 3782 } 3783 } 3784 return txt; 3785 } 3786 3787 /** Build the command list parameters in a QString with HTML<br> 3788 Reimplement partialy the G4UIparameter.cc 3789 @param aCommand : command to list parameters 3790 @see G4UIparameter::List() 3791 @see G4UIcommand::List() 3792 @return the command list parameters, or "" if nothing 3793 */ 3794 void G4UIQt::updateHelpArea(const G4UIcommand* aCommand) 3795 { 3796 if (fParameterHelpLabel == nullptr) return; 3797 if (fParameterHelpTable == nullptr) return; 3798 3799 fParameterHelpLabel->setTextInteractionFlags(Qt::NoTextInteraction); 3800 QString txt; 3801 if (aCommand == nullptr) return; 3802 3803 G4String commandPath = aCommand->GetCommandPath(); 3804 G4String rangeString = aCommand->GetRange(); 3805 auto n_guidanceEntry = (G4int)aCommand->GetGuidanceEntries(); 3806 auto n_parameterEntry = (G4int)aCommand->GetParameterEntries(); 3807 3808 if ((commandPath.empty()) && (rangeString.empty()) && (n_guidanceEntry == 0) && 3809 (n_parameterEntry == 0)) 3810 { 3811 return; 3812 } 3813 3814 if ((commandPath.length() - 1) != '/') { 3815 txt += "<b>Command </b> " + QString((char*)(commandPath).data()) + "<br />"; 3816 } 3817 txt += "<b>Guidance :</b> "; 3818 QString tmpGuidance = ""; 3819 for (G4int i_thGuidance = 0; i_thGuidance < n_guidanceEntry; i_thGuidance++) { 3820 tmpGuidance = QString((char*)(aCommand->GetGuidanceLine(i_thGuidance)).data()); 3821 tmpGuidance = tmpGuidance.toHtmlEscaped(); 3822 tmpGuidance.replace("\n", "<br />"); 3823 txt += tmpGuidance + "<br />"; 3824 } 3825 if (! rangeString.empty()) { 3826 QString range = QString((char*)(rangeString).data()); 3827 range = range.toHtmlEscaped(); 3828 txt += "<b>Range of parameters : </b> " + range + "<br />"; 3829 } 3830 else { 3831 txt += "<br />"; 3832 } 3833 fParameterHelpLabel->setHtml(txt); 3834 3835 if (n_parameterEntry > 0) { 3836 G4UIparameter* param; 3837 3838 // Re-implementation of G4UIparameter.cc 3839 3840 fParameterHelpTable->clear(); 3841 fParameterHelpTable->setRowCount(n_parameterEntry); 3842 fParameterHelpTable->setColumnCount(8); 3843 fParameterHelpTable->setHorizontalHeaderLabels( 3844 QStringList() << tr("") << tr("Parameter") << tr("Guidance") << tr("Type") << tr("Ommitable") 3845 << tr("Default") << tr("Range") << tr("Candidate")); 3846 fParameterHelpTable->setColumnWidth(2, 60); 3847 3848 fParameterHelpTable->verticalHeader()->setVisible(false); 3849 fParameterHelpTable->setAlternatingRowColors(true); 3850 fParameterHelpTable->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); 3851 fParameterHelpTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch); 3852 fParameterHelpTable->setWordWrap(true); 3853 3854 QTableWidgetItem* t = fParameterHelpTable->horizontalHeaderItem(1); 3855 QFont fnt = t->font(); 3856 G4int size = fnt.pointSize(); 3857 fnt.setPointSize(size - 2); 3858 3859 for (G4int a = 0; a < n_parameterEntry; a++) { 3860 param = aCommand->GetParameter(a); 3861 fParameterHelpTable->setItem(a, 0, new QTableWidgetItem(QString::number(a + 1))); 3862 3863 fParameterHelpTable->setItem( 3864 a, 1, new QTableWidgetItem(QString((char*)(param->GetParameterName()).data()))); 3865 if (! param->GetParameterGuidance().empty()) { 3866 fParameterHelpTable->setItem( 3867 a, 2, new QTableWidgetItem(QString((char*)(param->GetParameterGuidance()).data()))); 3868 } 3869 fParameterHelpTable->setItem( 3870 a, 3, new QTableWidgetItem(QString(QChar(param->GetParameterType())))); 3871 3872 if (param->IsOmittable()) { 3873 fParameterHelpTable->setItem(a, 4, new QTableWidgetItem(QString("True"))); 3874 } 3875 else { 3876 fParameterHelpTable->setItem(a, 4, new QTableWidgetItem(QString("False"))); 3877 } 3878 if (param->GetCurrentAsDefault()) { 3879 fParameterHelpTable->setItem( 3880 a, 5, new QTableWidgetItem(QString("taken from the current value"))); 3881 } 3882 else if (! param->GetDefaultValue().empty()) { 3883 fParameterHelpTable->setItem( 3884 a, 5, new QTableWidgetItem(QString((char*)(param->GetDefaultValue()).data()))); 3885 } 3886 if (! param->GetParameterRange().empty()) { 3887 fParameterHelpTable->setItem( 3888 a, 6, new QTableWidgetItem(QString((char*)(param->GetParameterRange()).data()))); 3889 } 3890 if (! param->GetParameterCandidates().empty()) { 3891 fParameterHelpTable->setItem( 3892 a, 7, new QTableWidgetItem(QString((char*)(param->GetParameterCandidates()).data()))); 3893 } 3894 // tooltips 3895 for (G4int b = 0; b < 8; ++b) { 3896 QTableWidgetItem* tmp = fParameterHelpTable->item(a, b); 3897 if (tmp != nullptr) { 3898 tmp->setToolTip(tmp->text()); 3899 tmp->setFlags(Qt::NoItemFlags); 3900 } 3901 } 3902 fParameterHelpTable->resizeRowToContents(a); 3903 } 3904 for (G4int c = 0; c < 8; ++c) { 3905 if (c != 2) { 3906 fParameterHelpTable->resizeColumnToContents(c); 3907 } 3908 } 3909 fParameterHelpLabel->setVisible(true); 3910 fParameterHelpTable->setVisible(true); 3911 } 3912 } 3913 3914 /** 3915 Return true if this command takes almost a number (int, double, bool, 3916 string) as an input 3917 or a string with a candidate list 3918 */ 3919 G4bool G4UIQt::IsGUICommand(const G4UIcommand* aCommand) 3920 { 3921 if (aCommand == nullptr) return false; 3922 3923 auto n_parameterEntry = (G4int)aCommand->GetParameterEntries(); 3924 3925 if (n_parameterEntry > 0) { 3926 G4UIparameter* param; 3927 3928 // Re-implementation of G4UIparameter.cc 3929 3930 for (G4int i_thParameter = 0; i_thParameter < n_parameterEntry; i_thParameter++) { 3931 param = aCommand->GetParameter(i_thParameter); 3932 if (QString(QChar(param->GetParameterType())) == "d") { 3933 return true; 3934 } 3935 if (QString(QChar(param->GetParameterType())) == "b") { 3936 return true; 3937 } 3938 if (QString(QChar(param->GetParameterType())) == "i") { 3939 return true; 3940 } 3941 if (QString(QChar(param->GetParameterType())) == "s") { 3942 return true; 3943 } 3944 } 3945 } 3946 return false; 3947 } 3948 3949 /** Implement G4VBasicShell vurtual function 3950 */ 3951 G4bool G4UIQt::GetHelpChoice(G4int&) { return true; } 3952 3953 /** Event filter method. Every event from QtApplication goes here.<br/> 3954 We apply a filter only for the Up and Down Arrow press when the QLineEdit<br/> 3955 is active. If this filter match, Up arrow we give the previous command<br/> 3956 and Down arrow will give the next if exist.<br/> 3957 @param obj Emitter of the event 3958 @param event Kind of event 3959 */ 3960 G4bool G4UIQt::eventFilter( // Should stay with a minuscule eventFilter because of Qt 3961 QObject* aObj, QEvent* aEvent) 3962 { 3963 G4bool tabKeyPress = false; 3964 G4bool moveCommandCursor = false; 3965 if (aObj == nullptr) return false; 3966 if (aEvent == nullptr) return false; 3967 3968 if (aObj == fHistoryTBTableList) { 3969 if (aEvent->type() == QEvent::KeyPress) { 3970 fCommandArea->setFocus(); 3971 } 3972 } 3973 3974 if (aObj == fCompleter->popup()) { 3975 if (aEvent->type() == QEvent::KeyPress) { 3976 auto e = static_cast<QKeyEvent*>(aEvent); 3977 if (e->key() == (Qt::Key_Tab)) { 3978 tabKeyPress = true; 3979 } 3980 } 3981 else if (aEvent->type() == QEvent::Hide) { 3982 // Store this value 3983 QString c = fCommandArea->text(); 3984 fLastCompleteCommand = c.left(c.indexOf("<")); 3985 } 3986 } 3987 3988 if (aObj == fCommandArea) { 3989 if (aEvent->type() == QEvent::KeyPress) { 3990 auto e = static_cast<QKeyEvent*>(aEvent); 3991 if ((e->key() == (Qt::Key_Down)) || (e->key() == (Qt::Key_PageDown)) || 3992 (e->key() == (Qt::Key_Up)) || (e->key() == (Qt::Key_PageUp))) 3993 { 3994 G4int selection = fHistoryTBTableList->currentRow(); 3995 if (fHistoryTBTableList->count() != 0) { 3996 if (selection == -1) { 3997 selection = fHistoryTBTableList->count() - 1; 3998 } 3999 else { 4000 if (e->key() == (Qt::Key_Down)) { 4001 if (selection < (fHistoryTBTableList->count() - 1)) selection++; 4002 } 4003 else if (e->key() == (Qt::Key_PageDown)) { 4004 selection = fHistoryTBTableList->count() - 1; 4005 } 4006 else if (e->key() == (Qt::Key_Up)) { 4007 if (selection > 0) selection--; 4008 } 4009 else if (e->key() == (Qt::Key_PageUp)) { 4010 selection = 0; 4011 } 4012 } 4013 fHistoryTBTableList->clearSelection(); 4014 fHistoryTBTableList->item(selection)->setSelected(true); 4015 fHistoryTBTableList->setCurrentItem(fHistoryTBTableList->item(selection)); 4016 } 4017 moveCommandCursor = true; 4018 } 4019 else if (e->key() == (Qt::Key_Tab)) { 4020 tabKeyPress = true; 4021 } 4022 else if (((e->modifiers() == Qt::ControlModifier) || (e->modifiers() == Qt::MetaModifier)) && 4023 (e->key() == Qt::Key_A)) 4024 { 4025 fCommandArea->home(false); 4026 return true; 4027 } 4028 else if (((e->modifiers() == Qt::ControlModifier) || (e->modifiers() == Qt::MetaModifier)) && 4029 (e->key() == Qt::Key_E)) 4030 { 4031 fCommandArea->end(false); 4032 return true; 4033 } 4034 } 4035 else if (aEvent->type() == QEvent::Paint) { 4036 if (fLastCompleteCommand != "") { 4037 fCommandArea->setText(fLastCompleteCommand); 4038 fLastCompleteCommand = ""; 4039 } 4040 } 4041 } 4042 if (tabKeyPress) { 4043 G4String ss = Complete(fCommandArea->text().toStdString().c_str()); 4044 fCommandArea->setText((char*)(ss.data())); 4045 fCommandArea->setFocus(); 4046 // do not pass by parent, it will disable widget tab focus ! 4047 return true; 4048 // L.Garnier : MetaModifier is CTRL for MAC, but I don't want to put a MAC 4049 // specific #ifdef 4050 } 4051 4052 G4bool res = false; 4053 // change cursor position if needed 4054 if (moveCommandCursor) { 4055 fCommandArea->setCursorPosition((int)fCommandArea->text().length()); 4056 fCommandArea->setCursorPosition(4); 4057 } 4058 else { 4059 // pass the event on to the parent class 4060 res = QObject::eventFilter(aObj, aEvent); 4061 } 4062 return res; 4063 } 4064 4065 void G4UIQt::UpdateCommandCompleter() 4066 { 4067 if (fCommandArea == nullptr) return; 4068 4069 // remove previous one 4070 fCommandArea->setCompleter(nullptr); 4071 if (fCompleter != nullptr) { 4072 if (fCompleter->popup() != nullptr) { 4073 fCompleter->popup()->removeEventFilter(this); 4074 } 4075 } 4076 4077 QStandardItemModel* model = CreateCompleterModel("/"); 4078 fCompleter = new QCompleter(model); 4079 4080 // set all dir visibles in completion 4081 G4UImanager* UI = G4UImanager::GetUIpointer(); 4082 G4UIcommandTree* commandTreeTop = UI->GetTree(); 4083 G4UIcommandTree* aTree = commandTreeTop->FindCommandTree("/"); 4084 if (aTree != nullptr) { 4085 int Ndir = aTree->GetTreeEntry(); 4086 fCompleter->setMaxVisibleItems(Ndir); 4087 } 4088 fCommandArea->setCompleter(fCompleter); 4089 fCompleter->popup()->installEventFilter(this); 4090 } 4091 4092 QStandardItemModel* G4UIQt::CreateCompleterModel(const G4String& aCmd) 4093 { 4094 QList<QStandardItem*> dirModelList; 4095 QList<QStandardItem*> commandModelList; 4096 QList<QStandardItem*> subDirModelList; 4097 QList<QStandardItem*> subCommandModelList; 4098 4099 G4String strtmp; 4100 G4int nMatch = 0; 4101 4102 G4String pName = aCmd; 4103 G4String remainingPath = aCmd; 4104 G4String empty = ""; 4105 G4String matchingPath = empty; 4106 4107 // find the tree 4108 auto jpre = pName.rfind('/'); 4109 if (jpre != G4String::npos) pName.erase(jpre + 1); 4110 G4UImanager* UI = G4UImanager::GetUIpointer(); 4111 G4UIcommandTree* commandTreeTop = UI->GetTree(); 4112 G4UIcommandTree* aTree = commandTreeTop->FindCommandTree(pName); 4113 if (aTree != nullptr) { 4114 G4int Ndir = aTree->GetTreeEntry(); 4115 G4int Ncmd = aTree->GetCommandEntry(); 4116 4117 // directory ... 4118 for (G4int idir = 1; idir <= Ndir; ++idir) { 4119 G4String fpdir = aTree->GetTree(idir)->GetPathName(); 4120 // matching test 4121 if (fpdir.find(remainingPath, 0) == 0) { 4122 if (nMatch == 0) { 4123 matchingPath = fpdir; 4124 } 4125 else { 4126 matchingPath = aTree->GetFirstMatchedString(fpdir, matchingPath); 4127 } 4128 nMatch++; 4129 4130 // append to dir model list 4131 auto item1 = new QStandardItem(fpdir.data()); 4132 QIcon i = QIcon(*fDirIcon); 4133 item1->setData(1); // dir 4134 item1->setIcon(QIcon(*fDirIcon)); 4135 dirModelList.append(item1); 4136 4137 // Go recursively 4138 QStandardItemModel* subModel = CreateCompleterModel(fpdir.data()); 4139 for (G4int a = 0; a < subModel->rowCount(); ++a) { 4140 // copy item (an item could only be part of one model 4141 auto tempItem = new QStandardItem(subModel->item(a)->text()); 4142 tempItem->setIcon(subModel->item(a)->icon()); 4143 tempItem->setToolTip(subModel->item(a)->toolTip()); 4144 tempItem->setData(subModel->item(a)->data()); 4145 4146 // dir 4147 if (tempItem->data() == 1) { 4148 subModel->item(a); 4149 subDirModelList.append(tempItem); 4150 } 4151 // command 4152 else if (tempItem->data() == 0) { 4153 subCommandModelList.append(tempItem); 4154 } 4155 } 4156 } 4157 } 4158 4159 // command ... 4160 G4int n_parameterEntry; 4161 G4String rangeString; 4162 G4int n_guidanceEntry; 4163 G4UIcommand* command; 4164 G4UIparameter* param; 4165 std::string tooltip; 4166 G4String params; 4167 4168 for (G4int icmd = 1; icmd <= Ncmd; ++icmd) { 4169 tooltip = ""; 4170 params = " "; 4171 command = aTree->GetCommand(icmd); 4172 G4String longCommandName = aTree->GetPathName() + command->GetCommandName(); 4173 rangeString = command->GetRange(); 4174 n_guidanceEntry = (G4int)command->GetGuidanceEntries(); 4175 n_parameterEntry = (G4int)command->GetParameterEntries(); 4176 4177 // matching test 4178 if (longCommandName.find(remainingPath, 0) == 0) { 4179 if (nMatch == 0) { 4180 matchingPath = longCommandName + " "; 4181 } 4182 else { 4183 strtmp = longCommandName + " "; 4184 matchingPath = aTree->GetFirstMatchedString(matchingPath, strtmp); 4185 } 4186 4187 // guidance 4188 for (G4int i_thGuidance = 0; i_thGuidance < n_guidanceEntry; i_thGuidance++) { 4189 tooltip += std::string((command->GetGuidanceLine(i_thGuidance)).data()); 4190 if (i_thGuidance < n_guidanceEntry - 1) { 4191 tooltip += "\n"; 4192 } 4193 } 4194 4195 // parameters 4196 for (G4int a = 0; a < n_parameterEntry; a++) { 4197 param = command->GetParameter(a); 4198 if (param->IsOmittable()) { 4199 params += "[<" + param->GetParameterName() + ">] "; 4200 } 4201 else { 4202 params += "<" + param->GetParameterName() + "> "; 4203 } 4204 } 4205 nMatch++; 4206 4207 // Append to command model list 4208 auto item = new QStandardItem(G4String(longCommandName + params).data()); 4209 item->setData(0); // command 4210 item->setIcon(QIcon(*fCommandIcon)); 4211 item->setToolTip(tooltip.c_str()); 4212 4213 commandModelList.append(item); 4214 } 4215 } 4216 } 4217 4218 auto model = new QStandardItemModel(); 4219 // initialize the model 4220 model->setColumnCount(1); 4221 4222 // concat models 4223 for (auto a : dirModelList) { 4224 model->appendRow(a); 4225 } 4226 for (auto a : subDirModelList) { 4227 model->appendRow(a); 4228 } 4229 for (auto a : commandModelList) { 4230 model->appendRow(a); 4231 } 4232 for (auto a : subCommandModelList) { 4233 model->appendRow(a); 4234 } 4235 4236 return model; 4237 } 4238 4239 /***************************************************************************/ 4240 // 4241 // SLOTS DEFINITIONS 4242 // 4243 /***************************************************************************/ 4244 4245 /** Called when user give "help" command. 4246 */ 4247 void G4UIQt::ShowHelpCallback() { TerminalHelp(""); } 4248 4249 /** Called when user click on clear button. Clear the text Output area 4250 */ 4251 void G4UIQt::ClearButtonCallback() 4252 { 4253 fCoutTBTextArea->clear(); 4254 fG4OutputString.clear(); 4255 } 4256 4257 /** Called when user exit session 4258 */ 4259 void G4UIQt::ExitSession() { SessionTerminate(); } 4260 4261 void G4UIQt::ExitHelp() const {} 4262 4263 /** Callback call when "click on a menu entry.<br> 4264 Send the associated command to geant4 4265 */ 4266 void G4UIQt::CommandEnteredCallback() 4267 { 4268 // split by any new line character 4269 fCommandArea->setText(fCommandArea->text().trimmed()); 4270 #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) 4271 QStringList list = fCommandArea->text().split(QRegularExpression("[\r\n]"),QString::SkipEmptyParts); 4272 #else 4273 QStringList list = fCommandArea->text().split(QRegularExpression("[\r\n]"),Qt::SkipEmptyParts); 4274 #endif 4275 4276 // Apply for all commands 4277 for (G4int a = 0; a < list.size(); ++a) { 4278 QString txt(list[a].trimmed()); 4279 if (txt != "") { 4280 fHistoryTBTableList->addItem(txt); 4281 fHistoryTBTableList->clearSelection(); 4282 fHistoryTBTableList->setCurrentItem(nullptr); 4283 fCommandArea->setText(""); 4284 G4Qt* interactorManager = G4Qt::getInstance(); 4285 if (interactorManager != nullptr) { 4286 interactorManager->FlushAndWaitExecution(); 4287 } 4288 4289 G4String command = txt.toStdString().c_str(); 4290 if (command.substr(0, 4) != "help") { 4291 ApplyShellCommand(command, exitSession, exitPause); 4292 } 4293 else { 4294 ActivateCommand(command); 4295 } 4296 } 4297 } 4298 // set the focus to the command line 4299 fCommandArea->setFocus(); 4300 4301 // Rebuild help tree 4302 FillHelpTree(); 4303 4304 // Rebuild command completion 4305 UpdateCommandCompleter(); 4306 4307 if (exitSession) SessionTerminate(); 4308 } 4309 4310 /** Callback when the text in the line edit is changed. 4311 When a newline is inserted, trigger the Activate Command 4312 on this text end set unchanged the end of the line after the newline. 4313 */ 4314 void G4UIQt::CommandEditedCallback(const QString&) 4315 { 4316 #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) 4317 QStringList list = fCommandArea->text().split(QRegularExpression("[\r\n]"), QString::SkipEmptyParts); 4318 #else 4319 QStringList list = fCommandArea->text().split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts); 4320 #endif 4321 4322 if (list.size() > 1) { // trigger ActivateCommand 4323 for (G4int a = 0; a < list.size() - 1; ++a) { 4324 // set only the first part 4325 fCommandArea->setText(list[a]); 4326 // trigger callback 4327 CommandEnteredCallback(); 4328 } 4329 // reset unfinished command 4330 fCommandArea->setText(list[list.size() - 1]); 4331 } 4332 } 4333 4334 /** Callback when one of the scene/vis parameters has changed 4335 */ 4336 void G4UIQt::VisParameterCallback(QWidget* widget) 4337 { 4338 if (widget == nullptr) { 4339 return; 4340 } 4341 4342 // Look in all the Grid layout, but only column 1 (0 is the parameter name) 4343 auto grid = dynamic_cast<QGridLayout*>(widget->layout()); 4344 if (grid == nullptr) { 4345 return; 4346 } 4347 QString command; 4348 QWidget* name = grid->itemAtPosition(grid->rowCount() - 1, 0)->widget(); 4349 if (dynamic_cast<QLabel*>(name) == nullptr) { 4350 return; 4351 } 4352 command += (dynamic_cast<QLabel*>(name))->text() + " "; 4353 4354 for (G4int a = 0; a < grid->rowCount() - 1; ++a) { 4355 QWidget* widgetTmp = grid->itemAtPosition(a, 1)->widget(); 4356 4357 // 4 kind of widgets : QLineEdit / QComboBox / radioButtonsGroup / QPushButton (color chooser) 4358 if (widgetTmp != nullptr) { 4359 if (dynamic_cast<QLineEdit*>(widgetTmp) != nullptr) { 4360 command += (dynamic_cast<QLineEdit*>(widgetTmp))->text() + " "; 4361 } 4362 else if (dynamic_cast<QComboBox*>(widgetTmp) != nullptr) { 4363 command += (dynamic_cast<QComboBox*>(widgetTmp)) 4364 ->itemText((dynamic_cast<QComboBox*>(widgetTmp))->currentIndex()) + 4365 " "; 4366 4367 // Color chooser 4368 } 4369 else if (dynamic_cast<QPushButton*>(widgetTmp) != nullptr) { 4370 command += widgetTmp->accessibleName() + " "; 4371 4372 // Check for Button group 4373 } 4374 else if (dynamic_cast<QWidget*>(widgetTmp) != nullptr) { 4375 if (widgetTmp->layout()->count() > 0) { 4376 if (dynamic_cast<QRadioButton*>(widgetTmp->layout()->itemAt(0)->widget()) != nullptr) { 4377 QAbstractButton* checked = 4378 (dynamic_cast<QRadioButton*>(widgetTmp->layout()->itemAt(0)->widget())) 4379 ->group() 4380 ->checkedButton(); 4381 if (checked != nullptr) { 4382 command += (dynamic_cast<QRadioButton*>(widgetTmp->layout()->itemAt(0)->widget())) 4383 ->group() 4384 ->checkedButton() 4385 ->text() + 4386 " "; 4387 } 4388 } 4389 } 4390 } 4391 } 4392 } 4393 if (command != "") { 4394 G4UImanager* UI = G4UImanager::GetUIpointer(); 4395 if (UI != nullptr) { 4396 UI->ApplyCommand(command.toStdString().c_str()); 4397 } 4398 } 4399 } 4400 4401 /** Callback call when "enter" clicked on the command zone.<br> 4402 If command has no parameters :send the command to geant4 4403 Else, open a dialog for parameters input 4404 @param aCommand 4405 */ 4406 void G4UIQt::ButtonCallback(const QString& aCommand) 4407 { 4408 G4String ss = G4StrUtil::lstrip_copy(G4String(aCommand.toStdString().c_str())); 4409 4410 G4UImanager* UI = G4UImanager::GetUIpointer(); 4411 if (UI == nullptr) return; 4412 G4UIcommandTree* treeTop = UI->GetTree(); 4413 4414 G4UIcommand* command = treeTop->FindPath(ss); 4415 4416 if (command != nullptr) { 4417 // if is GUI, then open a dialog 4418 if (IsGUICommand(command)) { 4419 auto menuParameterDialog = new QDialog(); 4420 4421 if (CreateVisCommandGroupAndToolBox(command, menuParameterDialog, 1, true)) { 4422 menuParameterDialog->setWindowTitle(aCommand); 4423 menuParameterDialog->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); 4424 4425 // exec this dialog, apply the command automaticaly, and return 4426 menuParameterDialog->exec(); 4427 return; 4428 } 4429 delete menuParameterDialog; 4430 } 4431 } 4432 4433 ApplyShellCommand(ss, exitSession, exitPause); 4434 4435 // Rebuild help tree 4436 FillHelpTree(); 4437 4438 if (exitSession) SessionTerminate(); 4439 } 4440 4441 /** This callback is activated when user selected a item in the help tree 4442 */ 4443 void G4UIQt::HelpTreeClicCallback() 4444 { 4445 QTreeWidgetItem* item = nullptr; 4446 if (fHelpTreeWidget == nullptr) return; 4447 4448 QList<QTreeWidgetItem*> list = fHelpTreeWidget->selectedItems(); 4449 if (list.isEmpty()) return; 4450 item = list.first(); 4451 if (item == nullptr) return; 4452 4453 G4UImanager* UI = G4UImanager::GetUIpointer(); 4454 if (UI == nullptr) return; 4455 G4UIcommandTree* treeTop = UI->GetTree(); 4456 4457 std::string itemText = GetLongCommandPath(item).toStdString(); 4458 4459 // check if it is a command path 4460 if (item->childCount() > 0) { 4461 itemText += "/"; 4462 } 4463 G4UIcommand* command = treeTop->FindPath(itemText.c_str()); 4464 4465 if (command != nullptr) { 4466 updateHelpArea(command); 4467 } 4468 else { // this is a command 4469 G4UIcommandTree* path = treeTop->FindCommandTree(itemText.c_str()); 4470 if (path != nullptr) { 4471 // this is not a command, this is a sub directory 4472 // We display the Title 4473 fParameterHelpLabel->setVisible(true); 4474 fParameterHelpLabel->setText(path->GetTitle().data()); 4475 fParameterHelpTable->setVisible(false); 4476 } 4477 } 4478 } 4479 4480 /** This callback is activated when user double clic on a item in the help tree 4481 */ 4482 void G4UIQt::HelpTreeDoubleClicCallback() 4483 { 4484 HelpTreeClicCallback(); 4485 4486 QTreeWidgetItem* item = nullptr; 4487 if (fHelpTreeWidget == nullptr) return; 4488 4489 QList<QTreeWidgetItem*> list = fHelpTreeWidget->selectedItems(); 4490 if (list.isEmpty()) return; 4491 item = list.first(); 4492 if (item == nullptr) return; 4493 4494 fCommandArea->clear(); 4495 fCommandArea->setText(GetLongCommandPath(item)); 4496 } 4497 4498 /** Callback called when user select an old command in the command history<br> 4499 Give it to the command area. 4500 */ 4501 void G4UIQt::CommandHistoryCallback() 4502 { 4503 QListWidgetItem* item = nullptr; 4504 if (fHistoryTBTableList == nullptr) return; 4505 4506 QList<QListWidgetItem*> list = fHistoryTBTableList->selectedItems(); 4507 if (list.isEmpty()) return; 4508 item = list.first(); 4509 if (item == nullptr) return; 4510 fCommandArea->setText(item->text()); 4511 } 4512 4513 void G4UIQt::ThreadComboBoxCallback(int) { CoutFilterCallback(""); } 4514 4515 void G4UIQt::CoutFilterCallback(const QString&) 4516 { 4517 FilterAllOutputTextArea(); 4518 4519 fCoutTBTextArea->repaint(); 4520 fCoutTBTextArea->verticalScrollBar()->setSliderPosition( 4521 fCoutTBTextArea->verticalScrollBar()->maximum()); 4522 } 4523 4524 void G4UIQt::SaveOutputCallback() 4525 { 4526 QString fileName = QFileDialog::getSaveFileName( 4527 fMainWindow, "Save console output as...", fLastOpenPath, "Save output as..."); 4528 if (fileName != "") { 4529 QFile data(fileName); 4530 if (data.open(QFile::WriteOnly | QFile::Truncate)) { 4531 QTextStream out(&data); 4532 out << fCoutTBTextArea->toPlainText(); 4533 out.flush(); 4534 } 4535 data.close(); 4536 } 4537 } 4538 4539 QString G4UIQt::FilterOutput( 4540 const G4UIOutputString& output, const QString& currentThread, const QString& filter) 4541 { 4542 #ifdef G4MULTITHREADED 4543 if ((currentThread == "All") || (currentThread == output.fThread.data())) { 4544 #else 4545 if (currentThread == "") { 4546 #endif 4547 if (output.fText.contains(QRegularExpression(filter))) { 4548 return output.fText; 4549 } 4550 } 4551 return ""; 4552 } 4553 4554 void G4UIQt::FilterAllOutputTextArea() 4555 { 4556 QString currentThread = ""; 4557 #ifdef G4MULTITHREADED 4558 currentThread = fThreadsFilterComboBox->currentText(); 4559 if (currentThread == "Master") { 4560 currentThread = ""; 4561 } 4562 #endif 4563 QString filter = fCoutFilter->text(); 4564 G4String previousOutputStream = ""; 4565 4566 QString pref = ""; 4567 QString post = ""; 4568 4569 fCoutTBTextArea->clear(); 4570 4571 for (auto& out : fG4OutputString) { 4572 if (FilterOutput(out, currentThread, filter) != "") { 4573 // changing color ? 4574 if (out.fOutputStream != previousOutputStream) { 4575 previousOutputStream = out.fOutputStream; 4576 if (out.fOutputStream == "info") { 4577 pref = ""; 4578 post = ""; 4579 } 4580 else if (out.fOutputStream == "warning") { 4581 pref = "<font color=\"DarkYellow\">"; 4582 post = "</font>"; 4583 } 4584 else { 4585 pref = "<font color=\"Red\">"; 4586 post = "</font>"; 4587 } 4588 } 4589 fCoutTBTextArea->append(pref + out.fText + post); 4590 } 4591 } 4592 } 4593 4594 /** Callback called when user give a new string to look for<br> 4595 Display a list of matching commands descriptions. If no string is set, 4596 will display the complete help tree 4597 */ 4598 void G4UIQt::LookForHelpStringCallback() 4599 { 4600 fHelpLine->setText(fHelpLine->text().trimmed()); 4601 QString searchText = fHelpLine->text(); 4602 4603 fParameterHelpLabel->setText(""); 4604 fParameterHelpTable->setVisible(false); 4605 if (searchText == "") { 4606 // clear old help tree 4607 fHelpTreeWidget->clear(); 4608 4609 FillHelpTree(); 4610 4611 return; 4612 } 4613 OpenHelpTreeOnCommand(searchText); 4614 } 4615 4616 void G4UIQt::OpenHelpTreeOnCommand(const QString& searchText) 4617 { 4618 // the help tree 4619 G4UImanager* UI = G4UImanager::GetUIpointer(); 4620 if (UI == nullptr) return; 4621 G4UIcommandTree* treeTop = UI->GetTree(); 4622 4623 G4int treeSize = treeTop->GetTreeEntry(); 4624 4625 // clear old help tree 4626 fHelpTreeWidget->clear(); 4627 4628 // look for new items 4629 4630 int tmp = 0; 4631 4632 #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) 4633 // Before Qt5.15 4634 QMap<G4int, QString> commandResultMap; 4635 QMap<G4int, QString> commandChildResultMap; 4636 for (G4int a = 0; a < treeSize; ++a) { 4637 G4UIcommand* command = treeTop->FindPath(treeTop->GetTree(a + 1)->GetPathName().data()); 4638 tmp = GetCommandList(command).count(searchText, Qt::CaseInsensitive); 4639 if (tmp > 0) { 4640 commandResultMap.insertMulti( 4641 tmp, QString((char*)(treeTop->GetTree(a + 1)->GetPathName()).data())); 4642 } 4643 // look for childs 4644 commandChildResultMap = LookForHelpStringInChildTree(treeTop->GetTree(a + 1), searchText); 4645 // insert new childs 4646 if (! commandChildResultMap.empty()) { 4647 QMap<int, QString>::const_iterator i = commandChildResultMap.constBegin(); 4648 while (i != commandChildResultMap.constEnd()) { 4649 commandResultMap.insertMulti(i.key(), i.value()); 4650 i++; 4651 } 4652 commandChildResultMap.clear(); 4653 } 4654 } 4655 #else 4656 // Qt5.15 and beyond 4657 QMultiMap<G4int, QString> commandResultMap; 4658 QMultiMap<G4int, QString> commandChildResultMap; 4659 for (G4int a = 0; a < treeSize; ++a) { 4660 G4UIcommand* command = treeTop->FindPath(treeTop->GetTree(a + 1)->GetPathName().data()); 4661 tmp = (int)GetCommandList(command).count(searchText, Qt::CaseInsensitive); 4662 if (tmp > 0) { 4663 commandResultMap.insert(tmp, QString((char*)(treeTop->GetTree(a + 1)->GetPathName()).data())); 4664 } 4665 // look for childs 4666 commandChildResultMap = LookForHelpStringInChildTree(treeTop->GetTree(a + 1), searchText); 4667 // insert new childs 4668 if (! commandChildResultMap.empty()) { 4669 auto i = commandChildResultMap.constBegin(); 4670 while (i != commandChildResultMap.constEnd()) { 4671 commandResultMap.insert(i.key(), i.value()); 4672 ++i; 4673 } 4674 commandChildResultMap.clear(); 4675 } 4676 } 4677 #endif 4678 4679 // build new help tree 4680 fHelpTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection); 4681 fHelpTreeWidget->setColumnCount(2); 4682 QStringList labels; 4683 labels << QString("Command") << QString("Match"); 4684 fHelpTreeWidget->setHeaderLabels(labels); 4685 4686 if (commandResultMap.empty()) { 4687 fParameterHelpLabel->setText("No match found"); 4688 fParameterHelpTable->setVisible(false); 4689 return; 4690 } 4691 4692 auto i = commandResultMap.constEnd(); 4693 i--; 4694 // 10 maximum progress values 4695 G4float multValue = 10.0 / (G4float)(i.key()); 4696 QString progressChar = "|"; 4697 QString progressStr = "|"; 4698 4699 QTreeWidgetItem* newItem; 4700 G4bool end = false; 4701 while (! end) { 4702 if (i == commandResultMap.constBegin()) { 4703 end = true; 4704 } 4705 for (G4int a = 0; a < G4int(i.key() * multValue); ++a) { 4706 progressStr += progressChar; 4707 } 4708 newItem = new QTreeWidgetItem(); 4709 QString commandStr = i.value().trimmed(); 4710 4711 if (commandStr.indexOf("/") == 0) { 4712 commandStr = commandStr.right(commandStr.size() - 1); 4713 } 4714 4715 newItem->setText(0, commandStr); 4716 newItem->setText(1, progressStr); 4717 fHelpTreeWidget->addTopLevelItem(newItem); 4718 newItem->setForeground(1, QBrush(Qt::blue)); 4719 progressStr = "|"; 4720 i--; 4721 } 4722 fHelpTreeWidget->resizeColumnToContents(0); 4723 fHelpTreeWidget->sortItems(1, Qt::DescendingOrder); 4724 // fHelpTreeWidget->setColumnWidth(1,10);//resizeColumnToContents (1); 4725 } 4726 4727 #if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0)) 4728 // Before Qt5.15 4729 QMap<G4int, QString> G4UIQt::LookForHelpStringInChildTree( 4730 G4UIcommandTree* aCommandTree, const QString& text) 4731 { 4732 QMap<G4int, QString> commandResultMap; 4733 if (aCommandTree == NULL) return commandResultMap; 4734 // Get the Sub directories 4735 G4int tmp = 0; 4736 QMap<G4int, QString> commandChildResultMap; 4737 for (G4int a = 0; a < aCommandTree->GetTreeEntry(); ++a) { 4738 const G4UIcommand* command = aCommandTree->GetGuidance(); 4739 tmp = GetCommandList(command).count(text, Qt::CaseInsensitive); 4740 if (tmp > 0) { 4741 commandResultMap.insertMulti( 4742 tmp, QString((char*)(aCommandTree->GetTree(a + 1)->GetPathName()).data())); 4743 } 4744 // look for childs 4745 commandChildResultMap = LookForHelpStringInChildTree(aCommandTree->GetTree(a + 1), text); 4746 if (! commandChildResultMap.empty()) { 4747 // insert new childs 4748 QMap<G4int, QString>::const_iterator i = commandChildResultMap.constBegin(); 4749 while (i != commandChildResultMap.constEnd()) { 4750 commandResultMap.insertMulti(i.key(), i.value()); 4751 ++i; 4752 } 4753 commandChildResultMap.clear(); 4754 } 4755 } 4756 // Get the Commands 4757 for (G4int a = 0; a < aCommandTree->GetCommandEntry(); ++a) { 4758 const G4UIcommand* command = aCommandTree->GetCommand(a + 1); 4759 tmp = GetCommandList(command).count(text, Qt::CaseInsensitive); 4760 if (tmp > 0) { 4761 commandResultMap.insertMulti( 4762 tmp, QString((char*)(aCommandTree->GetCommand(a + 1)->GetCommandPath()).data())); 4763 } 4764 } 4765 return commandResultMap; 4766 } 4767 #else 4768 // Qt5.15 and beyond 4769 QMultiMap<G4int, QString> G4UIQt::LookForHelpStringInChildTree( 4770 G4UIcommandTree* aCommandTree, const QString& text) 4771 { 4772 QMultiMap<G4int, QString> commandResultMap; 4773 if (aCommandTree == nullptr) return commandResultMap; 4774 // Get the Sub directories 4775 G4int tmp = 0; 4776 QMultiMap<G4int, QString> commandChildResultMap; 4777 for (G4int a = 0; a < aCommandTree->GetTreeEntry(); ++a) { 4778 const G4UIcommand* command = aCommandTree->GetGuidance(); 4779 tmp = (int)GetCommandList(command).count(text, Qt::CaseInsensitive); 4780 if (tmp > 0) { 4781 commandResultMap.insert( 4782 tmp, QString((char*)(aCommandTree->GetTree(a + 1)->GetPathName()).data())); 4783 } 4784 // look for childs 4785 commandChildResultMap = LookForHelpStringInChildTree(aCommandTree->GetTree(a + 1), text); 4786 if (! commandChildResultMap.empty()) { 4787 // insert new childs 4788 auto i = commandChildResultMap.constBegin(); 4789 while (i != commandChildResultMap.constEnd()) { 4790 commandResultMap.insert(i.key(), i.value()); 4791 ++i; 4792 } 4793 commandChildResultMap.clear(); 4794 } 4795 } 4796 // Get the Commands 4797 for (G4int a = 0; a < aCommandTree->GetCommandEntry(); ++a) { 4798 const G4UIcommand* command = aCommandTree->GetCommand(a + 1); 4799 tmp = (int)GetCommandList(command).count(text, Qt::CaseInsensitive); 4800 if (tmp > 0) { 4801 commandResultMap.insert( 4802 tmp, QString((char*)(aCommandTree->GetCommand(a + 1)->GetCommandPath()).data())); 4803 } 4804 } 4805 return commandResultMap; 4806 } 4807 #endif 4808 4809 QString G4UIQt::GetShortCommandPath(QString& commandPath) 4810 { 4811 if (commandPath.indexOf("/") == 0) { 4812 commandPath = commandPath.right(commandPath.size() - 1); 4813 } 4814 4815 commandPath = commandPath.right(commandPath.size() - commandPath.lastIndexOf("/", -2) - 1); 4816 4817 if (commandPath.lastIndexOf("/") == (commandPath.size() - 1)) { 4818 commandPath = commandPath.left(commandPath.size() - 1); 4819 } 4820 4821 return commandPath; 4822 } 4823 4824 QString G4UIQt::GetLongCommandPath(QTreeWidgetItem* item) 4825 { 4826 if (item == nullptr) return ""; 4827 4828 // rebuild path: 4829 QString itemText = ""; 4830 itemText = item->text(0); 4831 4832 while (item->parent() != nullptr) { 4833 itemText = item->parent()->text(0) + "/" + itemText; 4834 item = item->parent(); 4835 } 4836 itemText = "/" + itemText; 4837 4838 return itemText; 4839 } 4840 4841 void G4UIQt::ChangeColorCallback(QWidget* widget) 4842 { 4843 if (widget == nullptr) { 4844 return; 4845 } 4846 4847 auto button = dynamic_cast<QPushButton*>(widget); 4848 if (button == nullptr) { 4849 return; 4850 } 4851 QString value = button->accessibleName(); 4852 4853 QColor old; 4854 old.setRgbF(value.section(" ", 0, 1).toDouble(), value.section(" ", 1, 2).toDouble(), 4855 value.section(" ", 2, 3).toDouble()); 4856 QColor color = 4857 QColorDialog::getColor(old, fUITabWidget, "Change color", QColorDialog::ShowAlphaChannel); 4858 4859 if (color.isValid()) { 4860 // rebuild the widget icon 4861 QPixmap pixmap = QPixmap(QSize(16, 16)); 4862 pixmap.fill(color); 4863 QPainter painter(&pixmap); 4864 painter.setPen(Qt::black); 4865 painter.drawRect(0, 0, 15, 15); // Draw contour 4866 4867 button->setAccessibleName(QString::number(color.redF()) + " " + 4868 QString::number(color.greenF()) + " " + 4869 QString::number(color.blueF()) + " "); 4870 button->setIcon(pixmap); 4871 } 4872 } 4873 4874 void G4UIQt::ChangeCursorAction(const QString& action) 4875 { 4876 // Theses actions should be in the app toolbar 4877 4878 fMoveSelected = true; 4879 fPickSelected = true; 4880 fRotateSelected = true; 4881 fZoomInSelected = true; 4882 fZoomOutSelected = true; 4883 4884 if (fToolbarApp == nullptr) return; 4885 QList<QAction*> list = fToolbarApp->actions(); 4886 for (auto i : list) { 4887 if (i->data().toString() == action) { 4888 i->setChecked(true); 4889 if (i->data().toString() == "pick") { 4890 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/picking true"); 4891 CreatePickInfosDialog(); 4892 4893 fPickInfosDialog->show(); 4894 fPickInfosDialog->raise(); 4895 fPickInfosDialog->activateWindow(); 4896 } 4897 } 4898 else if (i->data().toString() == "move") { 4899 fMoveSelected = false; 4900 i->setChecked(false); 4901 } 4902 else if (i->data().toString() == "pick") { 4903 fPickSelected = false; 4904 i->setChecked(false); 4905 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/picking false"); 4906 if (fPickInfosDialog != nullptr) { 4907 fPickInfosDialog->hide(); 4908 } 4909 } 4910 else if (i->data().toString() == "rotate") { 4911 fRotateSelected = false; 4912 i->setChecked(false); 4913 } 4914 else if (i->data().toString() == "zoom_in") { 4915 fZoomInSelected = false; 4916 i->setChecked(false); 4917 } 4918 else if (i->data().toString() == "zoom_out") { 4919 fZoomOutSelected = false; 4920 i->setChecked(false); 4921 } 4922 } 4923 // FIXME : Should connect this to Vis 4924 } 4925 4926 /* A little bit like "void G4OpenGLQtViewer::toggleDrawingAction(int aAction)" 4927 But for all viewers, not only Qt 4928 4929 FIXME : Should be a feedback when changing viewer ! 4930 4931 */ 4932 void G4UIQt::ChangeSurfaceStyle(const QString& action) 4933 { 4934 // Theses actions should be in the app toolbar 4935 4936 if (fToolbarApp == nullptr) return; 4937 QList<QAction*> list = fToolbarApp->actions(); 4938 for (auto i : list) { 4939 if (i->data().toString() == action) { 4940 i->setChecked(true); 4941 } 4942 else if (i->data().toString() == "hidden_line_removal") { 4943 i->setChecked(false); 4944 } 4945 else if (i->data().toString() == "hidden_line_and_surface_removal") { 4946 i->setChecked(false); 4947 } 4948 else if (i->data().toString() == "solid") { 4949 i->setChecked(false); 4950 } 4951 else if (i->data().toString() == "wireframe") { 4952 i->setChecked(false); 4953 } 4954 } 4955 // FIXME : Should connect this to Vis 4956 4957 if (action == "hidden_line_removal") { 4958 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/style w"); 4959 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/hiddenEdge 1"); 4960 } 4961 else if (action == "hidden_line_and_surface_removal") { 4962 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/style s"); 4963 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/hiddenEdge 1"); 4964 } 4965 else if (action == "solid") { 4966 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/style s"); 4967 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/hiddenEdge 0"); 4968 } 4969 else if (action == "wireframe") { 4970 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/style w"); 4971 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/hiddenEdge 0"); 4972 } 4973 } 4974 4975 void G4UIQt::OpenIconCallback(const QString& aParam) 4976 { 4977 QString aCommand = aParam.left(aParam.indexOf(fStringSeparator)); 4978 QString aLabel = aParam.mid(aParam.indexOf(fStringSeparator) + fStringSeparator.length()); 4979 4980 QString nomFich = QFileDialog::getOpenFileName(fMainWindow, aLabel, fLastOpenPath, 4981 "Macro files (*.mac);;Geant4 files( *.mac *.g4* *.in);;All (*.*)"); 4982 if (nomFich != "") { 4983 G4UImanager::GetUIpointer()->ApplyCommand( 4984 (QString(aCommand) + QString(" ") + nomFich).toStdString().c_str()); 4985 QDir dir; 4986 fLastOpenPath = dir.absoluteFilePath(nomFich); 4987 } 4988 } 4989 4990 void G4UIQt::SaveIconCallback(const QString& aParam) 4991 { 4992 QString aCommand = aParam.left(aParam.indexOf(fStringSeparator)); 4993 QString aLabel = aParam.mid(aParam.indexOf(fStringSeparator) + fStringSeparator.length()); 4994 4995 QString nomFich = 4996 QFileDialog::getSaveFileName(fMainWindow, aLabel, fLastOpenPath, "Macro files (*.mac)"); 4997 if (nomFich != "") { 4998 G4UImanager::GetUIpointer()->ApplyCommand( 4999 (QString(aCommand) + QString(" ") + nomFich).toStdString().c_str()); 5000 QDir dir; 5001 fLastOpenPath = dir.absoluteFilePath(nomFich); 5002 } 5003 } 5004 5005 void G4UIQt::CreateViewerPropertiesDialog() 5006 { 5007 if (fViewerPropertiesDialog != nullptr) { 5008 return; 5009 } 5010 fViewerPropertiesDialog = new QDialog(); 5011 5012 fViewerPropertiesDialog->setWindowTitle("Viewer properties"); 5013 fViewerPropertiesDialog->setSizePolicy( 5014 QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); 5015 5016 if (fViewerPropertiesWidget == nullptr) { 5017 fViewerPropertiesWidget = new QWidget(); 5018 auto layoutPropertiesWidget = new QVBoxLayout(); 5019 fViewerPropertiesWidget->setLayout(layoutPropertiesWidget); 5020 5021 CreateEmptyViewerPropertiesWidget(); 5022 } 5023 5024 auto layoutDialog = new QVBoxLayout(); 5025 5026 layoutDialog->addWidget(fViewerPropertiesWidget); 5027 layoutDialog->setContentsMargins(0, 0, 0, 0); 5028 fViewerPropertiesDialog->setLayout(layoutDialog); 5029 } 5030 5031 void G4UIQt::CreatePickInfosDialog() 5032 { 5033 if (fPickInfosDialog != nullptr) { 5034 return; 5035 } 5036 fPickInfosDialog = new QDialog(); 5037 5038 fPickInfosDialog->setWindowTitle("Pick infos"); 5039 fPickInfosDialog->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); 5040 5041 if (fPickInfosWidget == nullptr) { 5042 fPickInfosWidget = new QWidget(); 5043 auto layoutPickInfos = new QVBoxLayout(); 5044 fPickInfosWidget->setLayout(layoutPickInfos); 5045 5046 CreateEmptyPickInfosWidget(); 5047 } 5048 5049 auto layoutDialog = new QVBoxLayout(); 5050 5051 layoutDialog->addWidget(fPickInfosWidget); 5052 layoutDialog->setContentsMargins(0, 0, 0, 0); 5053 fPickInfosDialog->setLayout(layoutDialog); 5054 fPickInfosDialog->setWindowFlags(Qt::WindowStaysOnTopHint); 5055 } 5056 5057 void G4UIQt::CreateEmptyViewerPropertiesWidget() 5058 { 5059 if (fViewerPropertiesWidget == nullptr) return; 5060 if (fViewerPropertiesWidget->layout() == nullptr) return; 5061 QLayoutItem* wItem; 5062 if (fViewerPropertiesWidget->layout()->count() != 0) { 5063 while ((wItem = fViewerPropertiesWidget->layout()->takeAt(0)) != nullptr) { 5064 delete wItem->widget(); 5065 delete wItem; 5066 } 5067 } 5068 // Add empty one 5069 auto label = new QLabel("No viewer - Please open a viewer first"); 5070 fViewerPropertiesWidget->layout()->addWidget(label); 5071 fViewerPropertiesDialog->setWindowTitle("No viewer"); 5072 fViewerPropertiesDialog->setVisible(false); 5073 } 5074 5075 void G4UIQt::CreateEmptyPickInfosWidget() 5076 { 5077 QLayoutItem* wItem; 5078 if (fPickInfosWidget->layout()->count() != 0) { 5079 while ((wItem = fPickInfosWidget->layout()->takeAt(0)) != nullptr) { 5080 delete wItem->widget(); 5081 delete wItem; 5082 } 5083 } 5084 // Add empty one 5085 auto label = new QLabel("Click on the object you want to pick"); 5086 fPickInfosWidget->layout()->addWidget(label); 5087 fPickInfosDialog->setWindowTitle("Nothing to pick"); 5088 } 5089 5090 void G4UIQt::ViewerPropertiesIconCallback(int) 5091 { 5092 CreateViewerPropertiesDialog(); 5093 5094 fViewerPropertiesDialog->show(); 5095 fViewerPropertiesDialog->raise(); 5096 fViewerPropertiesDialog->activateWindow(); 5097 } 5098 5099 void G4UIQt::ChangePerspectiveOrtho(const QString& action) 5100 { 5101 // Theses actions should be in the app toolbar 5102 5103 if (fToolbarApp == nullptr) return; 5104 QList<QAction*> list = fToolbarApp->actions(); 5105 QString checked = ""; 5106 for (auto i : list) { 5107 if (i->data().toString() == action) { 5108 i->setChecked(true); 5109 checked = i->data().toString(); 5110 } 5111 else if (i->data().toString() == "perspective") { 5112 i->setChecked(false); 5113 } 5114 else if (i->data().toString() == "ortho") { 5115 i->setChecked(false); 5116 } 5117 } 5118 5119 if ((action == "ortho") && (checked == "ortho")) { 5120 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/projection o"); 5121 } 5122 else if ((action == "perspective") && (checked == "perspective")) { 5123 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/projection p"); 5124 } 5125 } 5126 5127 void G4UIQt::SetIconMoveSelected() 5128 { 5129 // Theses actions should be in the app toolbar 5130 fMoveSelected = true; 5131 fRotateSelected = false; 5132 fPickSelected = false; 5133 fZoomInSelected = false; 5134 fZoomOutSelected = false; 5135 5136 if (fToolbarApp == nullptr) return; 5137 QList<QAction*> list = fToolbarApp->actions(); 5138 for (auto i : list) { 5139 if (i->data().toString() == "move") { 5140 i->setChecked(true); 5141 } 5142 else if (i->data().toString() == "rotate") { 5143 i->setChecked(false); 5144 } 5145 else if (i->data().toString() == "pick") { 5146 i->setChecked(false); 5147 } 5148 else if (i->data().toString() == "zoom_in") { 5149 i->setChecked(false); 5150 } 5151 else if (i->data().toString() == "zoom_out") { 5152 i->setChecked(false); 5153 } 5154 } 5155 } 5156 5157 void G4UIQt::SetIconRotateSelected() 5158 { 5159 // Theses actions should be in the app toolbar 5160 fRotateSelected = true; 5161 fMoveSelected = false; 5162 fPickSelected = false; 5163 fZoomInSelected = false; 5164 fZoomOutSelected = false; 5165 5166 if (fToolbarApp == nullptr) return; 5167 QList<QAction*> list = fToolbarApp->actions(); 5168 for (auto i : list) { 5169 if (i->data().toString() == "rotate") { 5170 i->setChecked(true); 5171 } 5172 else if (i->data().toString() == "move") { 5173 i->setChecked(false); 5174 } 5175 else if (i->data().toString() == "pick") { 5176 i->setChecked(false); 5177 } 5178 else if (i->data().toString() == "zoom_in") { 5179 i->setChecked(false); 5180 } 5181 else if (i->data().toString() == "zoom_out") { 5182 i->setChecked(false); 5183 } 5184 } 5185 } 5186 5187 void G4UIQt::SetIconPickSelected() 5188 { 5189 // Theses actions should be in the app toolbar 5190 fPickSelected = true; 5191 fMoveSelected = false; 5192 fRotateSelected = false; 5193 fZoomInSelected = false; 5194 fZoomOutSelected = false; 5195 5196 QToolBar* bar = fToolbarApp; 5197 if (! fDefaultIcons) { 5198 bar = fToolbarUser; 5199 } 5200 if (bar == nullptr) return; 5201 5202 QList<QAction*> list = bar->actions(); 5203 for (auto i : list) { 5204 if (i->data().toString() == "pick") { 5205 i->setChecked(true); 5206 } 5207 else if (i->data().toString() == "move") { 5208 i->setChecked(false); 5209 } 5210 else if (i->data().toString() == "rotate") { 5211 i->setChecked(false); 5212 } 5213 else if (i->data().toString() == "zoom_in") { 5214 i->setChecked(false); 5215 } 5216 else if (i->data().toString() == "zoom_out") { 5217 i->setChecked(false); 5218 } 5219 } 5220 } 5221 5222 void G4UIQt::SetIconZoomInSelected() 5223 { 5224 // Theses actions should be in the app toolbar 5225 fZoomInSelected = true; 5226 fMoveSelected = false; 5227 fRotateSelected = false; 5228 fPickSelected = false; 5229 fZoomOutSelected = false; 5230 5231 QToolBar* bar = fToolbarApp; 5232 if (! fDefaultIcons) { 5233 bar = fToolbarUser; 5234 } 5235 if (bar == nullptr) return; 5236 5237 QList<QAction*> list = bar->actions(); 5238 for (auto i : list) { 5239 if (i->data().toString() == "zoom_in") { 5240 i->setChecked(true); 5241 } 5242 else if (i->data().toString() == "move") { 5243 i->setChecked(false); 5244 } 5245 else if (i->data().toString() == "rotate") { 5246 i->setChecked(false); 5247 } 5248 else if (i->data().toString() == "pick") { 5249 i->setChecked(false); 5250 } 5251 else if (i->data().toString() == "zoom_out") { 5252 i->setChecked(false); 5253 } 5254 } 5255 } 5256 5257 void G4UIQt::SetIconZoomOutSelected() 5258 { 5259 // Theses actions should be in the app toolbar 5260 fZoomOutSelected = true; 5261 fMoveSelected = false; 5262 fRotateSelected = false; 5263 fPickSelected = false; 5264 fZoomInSelected = false; 5265 5266 QToolBar* bar = fToolbarApp; 5267 if (! fDefaultIcons) { 5268 bar = fToolbarUser; 5269 } 5270 if (bar == nullptr) return; 5271 5272 QList<QAction*> list = bar->actions(); 5273 for (auto i : list) { 5274 if (i->data().toString() == "zoom_out") { 5275 i->setChecked(true); 5276 } 5277 else if (i->data().toString() == "move") { 5278 i->setChecked(false); 5279 } 5280 else if (i->data().toString() == "rotate") { 5281 i->setChecked(false); 5282 } 5283 else if (i->data().toString() == "pick") { 5284 i->setChecked(false); 5285 } 5286 else if (i->data().toString() == "zoom_in") { 5287 i->setChecked(false); 5288 } 5289 } 5290 } 5291 5292 void G4UIQt::SetIconSolidSelected() 5293 { 5294 // Theses actions should be in the app toolbar 5295 5296 QToolBar* bar = fToolbarApp; 5297 if (! fDefaultIcons) { 5298 bar = fToolbarUser; 5299 } 5300 if (bar == nullptr) return; 5301 5302 QList<QAction*> list = bar->actions(); 5303 for (auto i : list) { 5304 if (i->data().toString() == "solid") { 5305 i->setChecked(true); 5306 } 5307 else if (i->data().toString() == "hidden_line_removal") { 5308 i->setChecked(false); 5309 } 5310 else if (i->data().toString() == "hidden_line_and_surface_removal") { 5311 i->setChecked(false); 5312 } 5313 else if (i->data().toString() == "wireframe") { 5314 i->setChecked(false); 5315 } 5316 } 5317 } 5318 5319 void G4UIQt::SetIconWireframeSelected() 5320 { 5321 // Theses actions should be in the app toolbar 5322 5323 QToolBar* bar = fToolbarApp; 5324 if (! fDefaultIcons) { 5325 bar = fToolbarUser; 5326 } 5327 if (bar == nullptr) return; 5328 5329 QList<QAction*> list = bar->actions(); 5330 for (auto i : list) { 5331 if (i->data().toString() == "wireframe") { 5332 i->setChecked(true); 5333 } 5334 else if (i->data().toString() == "hidden_line_removal") { 5335 i->setChecked(false); 5336 } 5337 else if (i->data().toString() == "hidden_line_and_surface_removal") { 5338 i->setChecked(false); 5339 } 5340 else if (i->data().toString() == "solid") { 5341 i->setChecked(false); 5342 } 5343 } 5344 } 5345 5346 void G4UIQt::SetIconHLRSelected() 5347 { 5348 // Theses actions should be in the app toolbar 5349 5350 QToolBar* bar = fToolbarApp; 5351 if (! fDefaultIcons) { 5352 bar = fToolbarUser; 5353 } 5354 if (bar == nullptr) return; 5355 5356 QList<QAction*> list = bar->actions(); 5357 for (auto i : list) { 5358 if (i->data().toString() == "hidden_line_removal") { 5359 i->setChecked(true); 5360 } 5361 else if (i->data().toString() == "solid") { 5362 i->setChecked(false); 5363 } 5364 else if (i->data().toString() == "hidden_line_and_surface_removal") { 5365 i->setChecked(false); 5366 } 5367 else if (i->data().toString() == "wireframe") { 5368 i->setChecked(false); 5369 } 5370 } 5371 } 5372 5373 void G4UIQt::SetIconHLHSRSelected() 5374 { 5375 // Theses actions should be in the app toolbar 5376 5377 QToolBar* bar = fToolbarApp; 5378 if (! fDefaultIcons) { 5379 bar = fToolbarUser; 5380 } 5381 5382 if (bar == nullptr) return; 5383 5384 QList<QAction*> list = bar->actions(); 5385 for (auto i : list) { 5386 if (i->data().toString() == "hidden_line_and_surface_removal") { 5387 i->setChecked(true); 5388 } 5389 else if (i->data().toString() == "solid") { 5390 i->setChecked(false); 5391 } 5392 else if (i->data().toString() == "hidden_line_removal") { 5393 i->setChecked(false); 5394 } 5395 else if (i->data().toString() == "wireframe") { 5396 i->setChecked(false); 5397 } 5398 } 5399 } 5400 5401 void G4UIQt::SetIconPerspectiveSelected() 5402 { 5403 // Theses actions should be in the app toolbar 5404 5405 QToolBar* bar = fToolbarApp; 5406 if (! fDefaultIcons) { 5407 bar = fToolbarUser; 5408 } 5409 if (bar == nullptr) return; 5410 5411 QList<QAction*> list = bar->actions(); 5412 for (auto i : list) { 5413 if (i->data().toString() == "perspective") { 5414 i->setChecked(true); 5415 } 5416 else if (i->data().toString() == "ortho") { 5417 i->setChecked(false); 5418 } 5419 } 5420 } 5421 5422 void G4UIQt::SetIconOrthoSelected() 5423 { 5424 // Theses actions should be in the app toolbar 5425 5426 QToolBar* bar = fToolbarApp; 5427 if (! fDefaultIcons) { 5428 bar = fToolbarUser; 5429 } 5430 5431 if (bar == nullptr) return; 5432 5433 QList<QAction*> list = bar->actions(); 5434 for (auto i : list) { 5435 if (i->data().toString() == "ortho") { 5436 i->setChecked(true); 5437 } 5438 else if (i->data().toString() == "perspective") { 5439 i->setChecked(false); 5440 } 5441 } 5442 } 5443 5444 #if QT_VERSION < 0x060000 5445 G4QTabWidget::G4QTabWidget(QWidget* aParent, G4int sizeX, G4int sizeY) 5446 : QTabWidget(aParent), 5447 fTabSelected(false), 5448 fLastCreated(-1), 5449 fPreferedSizeX(sizeX + 6) // margin left+right 5450 , 5451 fPreferedSizeY(sizeY + 58) // tab label height + margin left+right 5452 { 5453 setMinimumSize(100, 100); 5454 QSizePolicy policy = QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); 5455 setSizePolicy(policy); 5456 } 5457 5458 G4QTabWidget::G4QTabWidget() 5459 : QTabWidget(), fTabSelected(false), fLastCreated(-1), fPreferedSizeX(0), fPreferedSizeY(0) 5460 {} 5461 #endif 5462 5463 G4UIOutputString::G4UIOutputString(const QString& text, const G4String& origine, const G4String& outputStream) 5464 : fText(text), fThread(origine) 5465 { 5466 if (! GetOutputList().contains(QString(" ") + outputStream + " ")) { 5467 fOutputStream = "info"; 5468 } 5469 else { 5470 fOutputStream = outputStream; 5471 } 5472 } 5473 5474 5475 void G4UIQt::TabCloseCallback(int a) 5476 { 5477 if (fViewerTabWidget == nullptr) return; 5478 5479 // get the address of the widget 5480 QWidget* temp = fViewerTabWidget->widget(a); 5481 5482 #if QT_VERSION < 0x060000 5483 // remove the tab 5484 fViewerTabWidget->removeTab(a); 5485 5486 // if last QWidget : Add empty string 5487 G4bool lastTab = true; 5488 for (G4int c = 0; c < fViewerTabWidget->count(); ++c) { 5489 if (fViewerTabWidget->tabText(c).contains("viewer")) { 5490 lastTab = false; 5491 } 5492 } 5493 5494 if (lastTab) { 5495 CreateEmptyViewerPropertiesWidget(); 5496 } 5497 // delete the widget 5498 delete temp; 5499 #else 5500 // remove the tab 5501 QObject::disconnect(fViewerTabWidget, SIGNAL(currentChanged(int)), this, SLOT(UpdateTabWidget(int))); 5502 fViewerTabWidget->removeTab(a); 5503 QObject::connect(fViewerTabWidget, SIGNAL(currentChanged(int)), this, SLOT(UpdateTabWidget(int))); 5504 5505 G4int lastViewerTabIndex = -1; 5506 for (G4int c = 0; c < fViewerTabWidget->count(); ++c) { 5507 if (fViewerTabWidget->tabText(c).contains("viewer")) { 5508 lastViewerTabIndex = c; 5509 } 5510 } 5511 5512 // delete the widget 5513 delete temp; 5514 5515 // if last QWidget : Add empty string 5516 if (lastViewerTabIndex==(-1)) { 5517 CreateEmptyViewerPropertiesWidget(); 5518 } else { 5519 UpdateTabWidget(lastViewerTabIndex); //have to do this after the widget deletion. 5520 } 5521 #endif 5522 } 5523 5524 void G4UIQt::ToolBoxActivated(int a) 5525 { 5526 if (fUITabWidget->widget(a) == fHelpTBWidget) { 5527 // Rebuild the help tree 5528 FillHelpTree(); 5529 } 5530 else if (fUITabWidget->widget(a) == fSceneTreeWidget) { 5531 fSceneTreeWidget->setVisible(true); 5532 } 5533 } 5534 5535 #if QT_VERSION < 0x060000 5536 void G4QTabWidget::paintEvent(QPaintEvent*) 5537 { 5538 if (currentWidget() != nullptr) { 5539 if (isTabSelected()) { 5540 // QCoreApplication::sendPostedEvents () ; 5541 5542 QString text = tabText(currentIndex()); 5543 5544 if (fLastCreated == -1) { 5545 auto edit = dynamic_cast<QTextEdit*>(currentWidget()); 5546 if (edit == nullptr) { 5547 QString paramSelect = QString("/vis/viewer/select ") + text; 5548 G4UImanager* UI = G4UImanager::GetUIpointer(); 5549 if (UI != nullptr) { 5550 UI->ApplyCommand(paramSelect.toStdString().c_str()); 5551 } 5552 } 5553 } 5554 else { 5555 fLastCreated = -1; 5556 } 5557 setTabSelected(false); 5558 } 5559 } 5560 } 5561 #endif 5562 5563 G4UIDockWidget::G4UIDockWidget(const QString& txt) : QDockWidget(txt) {} 5564 5565 void G4UIDockWidget::closeEvent(QCloseEvent* aEvent) 5566 { 5567 setFloating(false); 5568 5569 // prevent from closing 5570 aEvent->ignore(); 5571 // hide them instead 5572 hide(); 5573 } 5574