Geant4 11.2.2
Toolkit for the simulation of the passage of particles through matter
Loading...
Searching...
No Matches
G4UIQt.cc
Go to the documentation of this file.
1//
2// ********************************************************************
3// * License and Disclaimer *
4// * *
5// * The Geant4 software is copyright of the Copyright Holders of *
6// * the Geant4 Collaboration. It is provided under the terms and *
7// * conditions of the Geant4 Software License, included in the file *
8// * LICENSE and available at http://cern.ch/geant4/license . These *
9// * include a list of copyright holders. *
10// * *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work make any representation or warranty, express or implied, *
14// * regarding this software system or assume any liability for its *
15// * use. Please see the license in the file LICENSE and URL above *
16// * for the full disclaimer and the limitation of liability. *
17// * *
18// * This code implementation is the result of the scientific and *
19// * technical work of the GEANT4 collaboration. *
20// * By using, copying, modifying or distributing the software (or *
21// * any work based on the software) you agree to acknowledge its *
22// * use in resulting scientific publications, and indicate your *
23// * acceptance of all terms of the Geant4 Software license. *
24// ********************************************************************
25//
26//
27//
28// L. Garnier
29
30#include "G4UIQt.hh"
31
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 ?
95static G4bool exitSession = true;
96static 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*/
118G4UIQt::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) {
188 G4int verbose = UImanager->GetVerboseLevel();
189
190 if (verbose >= 2) {
191 G4cout << "G4UIQt : Unable to init Qt. Aborted" << G4endl;
192 }
193 }
194
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) {
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.
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
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
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
306void 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
345void 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.@####[email protected]",
1290 " .@@###w4eee5%$#@@@X",
1291 " .@@@..w4eeeeqo..@@X",
1292 " [email protected]<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
1459namespace {
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
1485void 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
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 item->setToolTip(0, model.GetModelDescription().c_str());
1543
1544 // Set the check state
1545 item->setCheckState
1546 (0, model.GetVisAttributes().IsVisible()? Qt::Checked: Qt::Unchecked);
1547
1548 // Set the expand state
1549 item->setExpanded(model.IsExpanded());
1550
1551 if (model.GetType() == G4SceneTreeItem::pvmodel) {
1552 BuildPVQTree(model,item);
1553 }
1554 }
1555}
1556
1557// Build Physical Volume tree of touchables
1558void G4UIQt::BuildPVQTree(const G4SceneTreeItem& g4stItem, QTreeWidgetItem* qtwItem)
1559{
1560 const auto& g4stChildren = g4stItem.GetChildren();
1561 for (const auto& g4stChild: g4stChildren) {
1562 QStringList qStringList;
1563 qStringList.append(g4stChild.GetDescription().c_str());
1564 auto newQTWItem = new QTreeWidgetItem(qStringList);
1565
1566 // Add a GUI-side representation of the touchable as a child
1567 qtwItem->addChild(newQTWItem);
1568
1569 // Load with info from g4stChild
1570 // There may be a way to add data as a QVariant, or a list of QVariants,
1571 // but let's try adding a G4SceneTreeItem pointer as a hex string. (There
1572 // does not seem to be a way of adding a pointer directly.)
1573 std::ostringstream oss; oss << std::hex << &g4stChild;
1574 auto data = QVariant(oss.str().c_str());
1575 newQTWItem->setData(0, Qt::UserRole, data);
1576
1577 // Load a tooltip
1578 if (g4stChild.GetType() == G4SceneTreeItem::ghost) {
1579 auto& nameCopyNo = g4stChild.GetDescription();
1580 auto name = nameCopyNo.substr(0,nameCopyNo.find(':'));
1581 oss.str(""); oss << nameCopyNo <<
1582 ": Click to make visible and get more information."
1583 "\n This may not work if the volume is in the \"base path\". (Hover on"
1584 "\n the model to see base path.) If this is the case,"
1585 "\n \"/vis/scene/add/volume " << name << "\" to bring into the displayed tree.)";
1586 newQTWItem->setToolTip(0, oss.str().c_str());
1587 } else { // A fully defined touchable
1588 oss.str(""); oss << g4stChild.GetPVPath() <<
1589 "\nTo see properties, right-click/dump.";
1590 newQTWItem->setToolTip(0, oss.str().c_str());
1591 }
1592
1593 // Set the check state
1594 newQTWItem->setCheckState
1595 (0, g4stChild.GetVisAttributes().IsVisible()? Qt::Checked: Qt::Unchecked);
1596
1597 // Set the expand state
1598 newQTWItem->setExpanded(g4stChild.IsExpanded());
1599
1600 // Set colour icon
1601 QPixmap pixmap = QPixmap(QSize(16, 16));
1602 pixmap.fill(ConvertG4ColourToQColor(g4stChild.GetVisAttributes().GetColour()));
1603 QPainter painter(&pixmap);
1604 painter.setPen(Qt::black);
1605 painter.drawRect(0,0,15,15); // Draw contour
1606 newQTWItem->setIcon(0,pixmap);
1607
1608 // Continue recursively
1609 BuildPVQTree(g4stChild,newQTWItem);
1610 }
1611}
1612
1613void G4UIQt::SceneTreeItemClicked(QTreeWidgetItem* item)
1614{
1615 if (item == nullptr) return;
1616 auto sceneTreeItem = ConvertToG4SceneTreeItem(item);
1617 if (sceneTreeItem == nullptr) return;
1618
1619 auto uiMan = G4UImanager::GetUIpointer();
1620
1621 // Respond according to type
1622 G4String argument = "false", inverse = "true";
1623 auto newCheckState = item->checkState(0);
1624 auto oldCheckState
1625 = sceneTreeItem->GetVisAttributes().IsVisible()? Qt::Checked: Qt::Unchecked;
1626 switch (sceneTreeItem->GetType()) {
1628 break; // Do nothing
1630 break; // Do nothing
1632 // Clicked - but has checkbox actually been clicked?
1633 if (newCheckState != oldCheckState) {
1634 if (newCheckState == Qt::Checked) argument = "true";
1635 G4String modelName, text;
1636 std::istringstream iss(sceneTreeItem->GetModelDescription());
1637 iss >> modelName >> text;
1638 if (modelName.find("Text") != std::string::npos) {
1639 // Text model: special case, use text to identify
1640 uiMan->ApplyCommand("/vis/scene/activateModel " + text + ' ' + argument);
1641 } else {
1642 uiMan->ApplyCommand("/vis/scene/activateModel " + modelName + ' ' + argument);
1643 }
1644 }
1645 break;
1647 // Clicked - but has checkbox actually been clicked?
1648 if (newCheckState != oldCheckState) {
1649 if (newCheckState == Qt::Checked) argument = "true";
1650 G4String modelName, pvName;
1651 std::istringstream iss(sceneTreeItem->GetModelDescription());
1652 iss >> modelName >> pvName;
1653 uiMan->ApplyCommand("/vis/scene/activateModel " + pvName + ' ' + argument);
1654 }
1655 break;
1657 [[fallthrough]];
1659 // Construct and apply touchable commands
1660 // Clicked - but has checkbox actually been clicked?
1661 if (newCheckState != oldCheckState) {
1662 if (newCheckState == Qt::Checked) {
1663 argument = "true"; inverse = "false";
1664 }
1665 uiMan->ApplyCommand("/vis/set/touchable" + sceneTreeItem->GetPVPath());
1666 uiMan->ApplyCommand("/vis/touchable/set/visibility " + argument);
1667 // If daughters, set daughtersInvisible too
1668 if (sceneTreeItem->GetChildren().size() > 0 ) {
1669 uiMan->ApplyCommand("/vis/touchable/set/daughtersInvisible " + inverse);
1670 }
1671 // If not cancelled and if daughters > 0 and if making invisible
1672 static G4bool wanted = true;
1673 if (wanted && sceneTreeItem->GetChildren().size() > 0 && argument == "false") {
1674 QMessageBox msgBox;
1675 msgBox.setText
1676 ("This action makes this volume and all descendants invisible."
1677 " To see descendants, right-click and select daughtersInvisible/false"
1678 " and check visibility of descendants individually.");
1679 msgBox.setInformativeText
1680 ("To suppress this message click \"Discard\" or \"Don't Save\"");
1681 msgBox.setStandardButtons(QMessageBox::Discard | QMessageBox::Ok);
1682 msgBox.setDefaultButton(QMessageBox::Ok);
1683 auto action = msgBox.exec();
1684 if (action == QMessageBox::Discard) {
1685 wanted = false;
1686 }
1687 }
1688 }
1689 break;
1690 }
1691}
1692
1693void G4UIQt::SceneTreeItemDoubleClicked(QTreeWidgetItem* item)
1694{
1695 if (item == nullptr) return;
1696 auto sceneTreeItem = ConvertToG4SceneTreeItem(item);
1697 if (sceneTreeItem == nullptr) return;
1698 if (sceneTreeItem->GetType() != G4SceneTreeItem::touchable) return;
1699
1700 auto oldQColor = ConvertG4ColourToQColor(sceneTreeItem->GetVisAttributes().GetColour());
1701 auto newQColor = QColorDialog::getColor(oldQColor, fNewSceneTreeItemTreeWidget, "", QColorDialog::ShowAlphaChannel);
1702 if (!newQColor.isValid()) return;
1703 if (newQColor == oldQColor) return;
1704
1705 auto newColour = ConvertQColorToG4Colour(newQColor);
1706 std::ostringstream oss; oss << std::setprecision(2)
1707 << newColour.GetRed() << ' ' << newColour.GetGreen()
1708 << ' ' << newColour.GetBlue() << ' ' << newColour.GetAlpha();
1709 auto uiMan = G4UImanager::GetUIpointer();
1710 uiMan->ApplyCommand("/vis/set/touchable" + sceneTreeItem->GetPVPath());
1711 uiMan->ApplyCommand("/vis/touchable/set/colour " + oss.str());
1712}
1713
1714void 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
1726void 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
1738void 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
1869void 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
1901void 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
1910void 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, 999, 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
1924void 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
1938void 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 */
1963QWidget* 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 */
1980QWidget* 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 */
2028G4UIDockWidget* 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 */
2129QWidget* G4UIQt::CreateVisParametersTBWidget() { return nullptr; }
2130
2131/** Create the VisParameters ToolBox Widget
2132 */
2133G4UIDockWidget* 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
2156QWidget* 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
2167void 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%'>&nbsp;<br/><i>http://cern.ch/geant4/</i></td></tr></table>"+
2176 "<p>&nbsp;</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 fViewerTabWidget = new G4QTabWidget();
2200 fMainWindow->setCentralWidget(fViewerTabWidget);
2201 fViewerTabWidget->setTabsClosable(true);
2202
2203 fViewerTabWidget->setUsesScrollButtons(true);
2204
2205 connect(fViewerTabWidget, SIGNAL(tabCloseRequested(int)),this, SLOT(TabCloseCallback(int)));
2206 connect(fViewerTabWidget, SIGNAL(currentChanged(int)), SLOT(UpdateTabWidget(int)));
2207 }
2208
2209 // set the QGLWidget size policy
2210 QSizePolicy policy = QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
2211 policy.setVerticalStretch(4);
2212 fViewerTabWidget->setSizePolicy(policy);
2213
2214 fViewerTabWidget->setMinimumSize(40, 40);
2215}
2216
2217/** Get the ViewerComponents ToolBox Widget
2218 */
2219QWidget* G4UIQt::GetSceneTreeWidget() { return fSceneTreeWidget; }
2220
2221/** Get the Viewer properties Widget
2222 */
2224{
2225 if (fViewerPropertiesDialog == nullptr) {
2226 CreateViewerPropertiesDialog();
2227 }
2228 return fViewerPropertiesWidget;
2229}
2230
2231/** Get the Pick Widget
2232 */
2234{
2235 if (fPickInfosDialog == nullptr) {
2236 CreatePickInfosDialog();
2237 }
2238 return fPickInfosWidget;
2239}
2240
2241/** Add a new tab in the viewer
2242 */
2243G4bool G4UIQt::AddViewerTab(QWidget* aWidget, std::string title)
2244{
2245 if (fViewerTabWidget == nullptr) {
2246 return false;
2247 }
2248 fViewerTabWidget->addTab(aWidget, title.c_str());
2249
2250 return true;
2251}
2252
2253/** Add a new tab in the viewer
2254 */
2255G4bool G4UIQt::AddViewerTabFromFile(std::string fileName, std::string title)
2256{
2257 if (fViewerTabWidget == nullptr) {
2258 return false;
2259 }
2260
2262 if (UI == nullptr) return false;
2263 std::ifstream file(UI->FindMacroPath(fileName.c_str()).data());
2264 if (file) {
2265 std::string content((std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>()));
2266
2267 auto text = new QTextEdit();
2268 text->setAcceptRichText(true);
2269 text->setContentsMargins(5, 5, 5, 5);
2270 text->setText(QString("<pre>") + content.c_str() + "</pre>");
2271 text->setReadOnly(true);
2272 fViewerTabWidget->addTab(text, title.c_str());
2273 }
2274 else {
2275 return false;
2276 }
2277 return true;
2278}
2279
2280/** Add a new tab widget.
2281 Create the tab if it was not done
2282*/
2283G4bool G4UIQt::AddTabWidget(QWidget* aWidget, QString name)
2284{
2285 if (fViewerTabWidget == nullptr) {
2286 CreateViewerWidget();
2287 }
2288
2289 if (aWidget == nullptr) {
2290 return false;
2291 }
2292 // Has to be added before we put it into the fViewerTabWidget widget
2293 aWidget->setParent(fViewerTabWidget); // Will create in some cases widget outside
2294 // of UI for a really short moment
2295
2296 fViewerTabWidget->addTab(aWidget, name);
2297
2298 fViewerTabWidget->setCurrentIndex(fViewerTabWidget->count() - 1);
2299
2300 // Set visible
2301 fViewerTabWidget->setLastTabCreated(fViewerTabWidget->currentIndex());
2302
2303 // Not the good solution, but ensure that the help tree is correctly build when launching a viewer
2304 // It should be done by a notification when adding a command, but that's nit done yet
2305 // (Geant4.10.1)
2306 FillHelpTree();
2307
2308 return true;
2309}
2310
2311void G4UIQt::SetStartPage(const std::string& text)
2312{
2313 if (! text.empty()) {
2314 fDefaultViewerFirstPageHTMLText = text;
2315 }
2316 if (fStartPage == nullptr) {
2317 fStartPage = new QTextBrowser();
2318 fStartPage->setContentsMargins(5, 5, 5, 5);
2319 fStartPage->setReadOnly(true);
2320 }
2321 fStartPage->setOpenExternalLinks(true);
2322 fStartPage->setHtml(fDefaultViewerFirstPageHTMLText.c_str());
2323}
2324
2325void G4UIQt::UpdateTabWidget(int tabNumber)
2326{
2327 if (fViewerTabWidget == nullptr) {
2328 fViewerTabWidget = new G4QTabWidget;
2329 }
2330
2331 fViewerTabWidget->setCurrentIndex(tabNumber);
2332
2333 // Send this signal to unblock graphic updates !
2334 fViewerTabWidget->setTabSelected(false);
2335
2336 fViewerTabWidget->setVisible(true);
2337
2338 // This will send a paintEvent to OGL Viewers
2339 fViewerTabWidget->setTabSelected(true);
2340}
2341
2342/** Send resize event to all tabs
2343 */
2344void G4UIQt::ResizeTabWidget(QResizeEvent* e)
2345{
2346 if (fViewerTabWidget != nullptr) {
2347 for (G4int a = 0; a < fViewerTabWidget->count(); a++) {
2348 fViewerTabWidget->widget(a)->resize(e->size());
2349 }
2350 }
2351}
2352
2353/** Start the Qt main loop
2354 */
2356{
2357 G4Qt* interactorManager = G4Qt::getInstance();
2358 Prompt("Session :");
2359 exitSession = false;
2360
2361 QCoreApplication::sendPostedEvents();
2362
2363 fMainWindow->setVisible(true);
2364
2365 if (fDefaultIcons) {
2366 fToolbarApp->setVisible(true);
2367 }
2368 else {
2369 // Set not visible until session start
2370 fToolbarApp->setVisible(false);
2371 }
2372 // Rebuild help tree (new command could be registered)
2373 FillHelpTree();
2374
2375 // Rebuild command completion (new command could be registered)
2376 UpdateCommandCompleter();
2377
2378 // Set event filters
2379 fHistoryTBTableList->installEventFilter(this);
2380 fCommandArea->installEventFilter(this);
2381
2382 // Focus on command line
2383 fCommandArea->setFocus();
2384
2385 interactorManager->DisableSecondaryLoop(); // TO KEEP
2386 if ((QApplication*)interactorManager->GetMainInteractor() != nullptr)
2387 ((QApplication*)interactorManager->GetMainInteractor())->exec();
2388
2389 interactorManager->EnableSecondaryLoop();
2390 return this;
2391}
2392
2393/** Display the prompt in the prompt area
2394 @param aPrompt : string to display as the promt label
2395*/
2397{
2398 if (aPrompt == nullptr) return;
2399
2400 fCommandLabel->setText((char*)aPrompt.data());
2401}
2402
2404{
2405 G4Qt* interactorManager = G4Qt::getInstance();
2406 fMainWindow->close();
2407 ((QApplication*)interactorManager->GetMainInteractor())->exit();
2408}
2409
2410/**
2411 Called by intercoms/src/G4UImanager.cc<br>
2412 Called by visualization/management/src/G4VisCommands.cc with "EndOfEvent" argument<br>
2413 It have to pause the session command terminal.<br>
2414 Call SecondaryLoop to wait for exit event<br>
2415 @param aState
2416 @see : G4VisCommandReviewKeptEvents::SetNewValue
2417*/
2419{
2420 if (aState == nullptr) return;
2421
2422 if (aState == "G4_pause> ") { // TO KEEP
2423 SecondaryLoop("Pause, type continue to exit this state"); // TO KEEP
2424 } // TO KEEP
2425
2426 if (aState == "EndOfEvent") { // TO KEEP
2427 // Picking with feed back in event data Done here !!!
2428 SecondaryLoop("End of event, type continue to exit this state"); // TO KEEP
2429 } // TO KEEP
2430}
2431
2432/**
2433 Begin the secondary loop
2434 @param a_prompt : label to display as the prompt label
2435 */
2436void G4UIQt::SecondaryLoop(G4String aPrompt)
2437{
2438 if (aPrompt == nullptr) return;
2439
2440 G4Qt* interactorManager = G4Qt::getInstance(); // TO KEEP ?
2441 Prompt(aPrompt); // TO KEEP
2442 exitPause = false; // TO KEEP
2443 while (true) {
2444 ((QApplication*)interactorManager)->processEvents(QEventLoop::WaitForMoreEvents);
2445 if (exitPause) break; // TO KEEP
2446 } // TO KEEP
2447 Prompt("Session :"); // TO KEEP
2448}
2449
2450#ifdef G4MULTITHREADED
2451# include "G4AutoLock.hh"
2452# include "G4Threading.hh"
2453namespace
2454{
2455 G4Mutex ReceiveMutex = G4MUTEX_INITIALIZER;
2456} // namespace
2457#endif
2458
2459/**
2460 Receive a debug log message from Geant4. We have to display it in the cout zone
2461 @param aString : label to add in the display area
2462 @return 0
2463*/
2465{
2466 if (aString.empty()) return 0;
2467
2468#ifdef G4MULTITHREADED
2469 G4AutoLock al(&ReceiveMutex);
2470#endif
2471
2472 // A workaround so that output is not lost after crash or G4Exception.
2473 // The "workaround" is to make sure all flushed output appears on
2474 // the terminal after a crash, because even flushed output can
2475 // get lost in the Qt UI system.
2476 // But...it seems workers write to std::cout/cerr anyway (is that a bug?),
2477 // so limit this to the master thread
2478#ifdef G4MULTITHREADED
2480#endif
2481 std::cout << aString << std::flush;
2482
2483 G4String aStringWithStyle;
2484 // aString has a \n on the end (maybe it comes from G4endl or from the
2485 // Enter key on the command line) - ignore it. That’s why
2486 // i < aString.length() - 1
2487 // But other \n need to be translated to an HTML newline.
2488 // Similarly, spaces need to be translated to an HTML "non-breaking space".
2489 // Tabs (\t) are more tricky since the number of equivalent spaces depends
2490 // on how many characters precede it. Probably needs an HTML table. For now
2491 // we replace \t with four spaces.
2492 for (G4int i = 0; i < (G4int)aString.length() - 1; ++i) {
2493 if (aString[i] == '\n') {
2494 aStringWithStyle += "<br>";
2495 }
2496 else if (aString[i] == ' ') {
2497 aStringWithStyle += "&nbsp;";
2498 }
2499 else if (aString[i] == '\t') {
2500 aStringWithStyle += "&nbsp;&nbsp;&nbsp;&nbsp;";
2501 }
2502 else if (aString[i] == '<') {
2503 aStringWithStyle += "&lt;";
2504 }
2505 else {
2506 aStringWithStyle += aString[i];
2507 }
2508 }
2509 if (fOutputStyles["debug"].fixed) {
2510 aStringWithStyle = "<span style='font-family:courier;'>" + aStringWithStyle + "</span>";
2511 }
2512 else {
2513 aStringWithStyle = "<span>" + aStringWithStyle + "</span>";
2514 }
2515
2516 // Add to string
2517 G4UIOutputString txt =
2518 G4UIOutputString(QString((char*)aStringWithStyle.data()), GetThreadPrefix());
2519 fG4OutputString.push_back(txt);
2520
2521#ifdef G4MULTITHREADED
2522 QString result = FilterOutput(txt, fThreadsFilterComboBox->currentText(), fCoutFilter->text());
2523#else
2524 QString result = FilterOutput(txt, "", fCoutFilter->text());
2525#endif
2526
2527 if (result.isEmpty()) {
2528 return 0;
2529 }
2530
2531 if (fOutputStyles["debug"].highlight) {
2532 QPalette pal;
2533 result = QString("<span style='background:") + pal.link().color().name() + ";'>&nbsp;</span>" +
2534 "<span style='background: Pink;'> " + result + "</span>";
2535 }
2536 result = QString("<font color=\"Green\">") + result + QString("</font>");
2537
2538 fCoutTBTextArea->append(result);
2539 fCoutTBTextArea->ensureCursorVisible();
2540
2541#ifdef G4MULTITHREADED
2542 UpdateCoutThreadFilter();
2543#endif
2544
2545 return 0;
2546}
2547
2548/**
2549 Receive a cout from Geant4. We have to display it in the cout zone
2550 @param aString : label to add in the display area
2551 @return 0
2552*/
2554{
2555 if (aString.empty()) return 0;
2556
2557 // Try to be smart :
2558 // "*** This is just a warning message. ***"
2559 if (G4StrUtil::contains(aString, "*** This is just a warning message. ***")) {
2560 return ReceiveG4cerr(aString);
2561 }
2562
2563#ifdef G4MULTITHREADED
2564 G4AutoLock al(&ReceiveMutex);
2565#endif
2566
2567 // A workaround so that output is not lost after crash or G4Exception.
2568 // The "workaround" is to make sure all flushed output appears on
2569 // the terminal after a crash, because even flushed output can
2570 // get lost in the Qt UI system.
2571 // But...it seems workers write to std::cout/cerr anyway (is that a bug?),
2572 // so limit this to the master thread
2573#ifdef G4MULTITHREADED
2575#endif
2576 std::cout << aString << std::flush;
2577
2578 G4String aStringWithStyle;
2579 // aString has a \n on the end (maybe it comes from G4endl or from the
2580 // Enter key on the command line) - ignore it. That’s why
2581 // i < aString.length() - 1
2582 // But other \n need to be translated to an HTML newline.
2583 // Similarly, spaces need to be translated to an HTML "non-breaking space".
2584 // Tabs (\t) are more tricky since the number of equivalent spaces depends
2585 // on how many characters precede it. Probably needs an HTML table. For now
2586 // we replace \t with four spaces.
2587 for (G4int i = 0; i < (G4int)aString.length() - 1; ++i) {
2588 if (aString[i] == '\n') {
2589 aStringWithStyle += "<br>";
2590 }
2591 else if (aString[i] == ' ') {
2592 aStringWithStyle += "&nbsp;";
2593 }
2594 else if (aString[i] == '\t') {
2595 aStringWithStyle += "&nbsp;&nbsp;&nbsp;&nbsp;";
2596 }
2597 else if (aString[i] == '<') {
2598 aStringWithStyle += "&lt;";
2599 }
2600 else {
2601 aStringWithStyle += aString[i];
2602 }
2603 }
2604 if (fOutputStyles["cout"].fixed) {
2605 aStringWithStyle = "<span style='font-family:courier;'>" + aStringWithStyle + "</span>";
2606 }
2607 else {
2608 aStringWithStyle = "<span>" + aStringWithStyle + "</span>";
2609 }
2610
2611 // Add to string
2612 G4UIOutputString txt =
2613 G4UIOutputString(QString((char*)aStringWithStyle.data()), GetThreadPrefix());
2614 fG4OutputString.push_back(txt);
2615
2616#ifdef G4MULTITHREADED
2617 QString result = FilterOutput(txt, fThreadsFilterComboBox->currentText(), fCoutFilter->text());
2618#else
2619 QString result = FilterOutput(txt, "", fCoutFilter->text());
2620#endif
2621
2622 if (result.isEmpty()) {
2623 return 0;
2624 }
2625
2627 if (fOutputStyles["cout"].highlight) {
2628 if (! UI->IsLastCommandOutputTreated()) {
2629 QPalette pal;
2630 result = QString("<span style='background:") + pal.link().color().name() +
2631 ";'>&nbsp;</span>" + "<span style='background:" + pal.highlight().color().name() +
2632 ";'> " + result + "</span>";
2633 }
2634 }
2636
2637 fCoutTBTextArea->append(result);
2638 fCoutTBTextArea->ensureCursorVisible();
2639
2640#ifdef G4MULTITHREADED
2641 UpdateCoutThreadFilter();
2642#endif
2643
2644 // reset error stack
2645 fLastErrMessage = aString;
2646 return 0;
2647}
2648
2649/**
2650 Receive a cerr from Geant4. We have to display it in the cout zone
2651 @param aString : label to add in the display area
2652 @return 0
2653*/
2655{
2656 if (aString.empty()) return 0;
2657
2658#ifdef G4MULTITHREADED
2659 G4AutoLock al(&ReceiveMutex);
2660#endif
2661
2662 // A workaround so that output is not lost after crash or G4Exception.
2663 // The "workaround" is to make sure all flushed output appears on
2664 // the terminal after a crash, because even flushed output can
2665 // get lost in the Qt UI system.
2666 // But...it seems workers write to std::cout/cerr anyway (is that a bug?),
2667 // so limit this to the master thread
2668#ifdef G4MULTITHREADED
2670#endif
2671 std::cerr << aString << std::flush;
2672
2673 G4String aStringWithStyle;
2674 // aString has a \n on the end (maybe it comes from G4endl or from the
2675 // Enter key on the command line) - ignore it. That’s why
2676 // i < aString.length() - 1
2677 // But other \n need to be translated to an HTML newline.
2678 // Similarly, spaces need to be translated to an HTML "non-breaking space".
2679 // Tabs (\t) are more tricky since the number of equivalent spaces depends
2680 // on how many characters precede it. Probably needs an HTML table. For now
2681 // we replace \t with four spaces.
2682 for (G4int i = 0; i < (G4int)aString.length() - 1; ++i) {
2683 if (aString[i] == '\n') {
2684 aStringWithStyle += "<br>";
2685 }
2686 else if (aString[i] == ' ') {
2687 aStringWithStyle += "&nbsp;";
2688 }
2689 else if (aString[i] == '\t') {
2690 aStringWithStyle += "&nbsp;&nbsp;&nbsp;&nbsp;";
2691 }
2692 else if (aString[i] == '<') {
2693 aStringWithStyle += "&lt;";
2694 }
2695 else {
2696 aStringWithStyle += aString[i];
2697 }
2698 }
2699 if (fOutputStyles["cerr"].fixed) {
2700 aStringWithStyle = "<span style='font-family:courier;'>" + aStringWithStyle + "</span>";
2701 }
2702 else {
2703 aStringWithStyle = "<span>" + aStringWithStyle + "</span>";
2704 }
2705
2706 // Add to string
2707
2708 G4UIOutputString txt =
2709 G4UIOutputString(QString((char*)aStringWithStyle.data()).trimmed(), GetThreadPrefix(), "error");
2710 fG4OutputString.push_back(txt);
2711
2712#ifdef G4MULTITHREADED
2713 QString result = FilterOutput(txt, fThreadsFilterComboBox->currentText(), fCoutFilter->text());
2714#else
2715 QString result = FilterOutput(txt, "", fCoutFilter->text());
2716#endif
2717 if (result.isEmpty()) {
2718 return 0;
2719 }
2720
2721 // Suppress space, \n,\t,\r...
2722 if (QString(aString.data()).trimmed() != "") {
2723 if ((G4StateManager::GetStateManager()->GetCurrentState() == G4State_Abort) ||
2724 (G4StateManager::GetStateManager()->GetCurrentState() == G4State_Quit))
2725 {
2726 // In case of Abort or Quit, the useful error message should be in the last error message !
2727 fLastErrMessage += "\n" + aString;
2728 QString criticalMessage = fLastErrMessage.data();
2729 criticalMessage = criticalMessage.toHtmlEscaped();
2730 QMessageBox::critical(fMainWindow, "Error", QString(fLastErrMessage));
2731 }
2732 }
2733 fCoutTBTextArea->append(QString("<font color=\"Red\">") + result + QString("</font>"));
2734 fCoutTBTextArea->ensureCursorVisible();
2735
2736 if (QString(aString.data()).trimmed() != "") {
2737 fLastErrMessage += aString;
2738 }
2739#ifdef G4MULTITHREADED
2740 UpdateCoutThreadFilter();
2741#endif
2742 return 0;
2743}
2744
2745G4String G4UIQt::GetThreadPrefix()
2746{
2747 G4String threadPrefix = "";
2748#ifdef G4MULTITHREADED
2750 if (UI == nullptr) return "";
2751 if (UI->GetThreadCout() != nullptr) {
2752 threadPrefix = UI->GetThreadCout()->GetFullPrefixString().data();
2753 if (UI->GetThreadCout()->GetPrefixString() == G4String("G4VIS")) {
2754 return "G4VIS";
2755 }
2756 }
2757#endif
2758 return threadPrefix;
2759}
2760
2761#ifdef G4MULTITHREADED
2762void G4UIQt::UpdateCoutThreadFilter()
2763{
2765 if (UI == nullptr) return;
2766
2767 // add "All" and "Master"
2768 if (fThreadsFilterComboBox->count() < 2) {
2769 if (fThreadsFilterComboBox->findText("All", Qt::MatchExactly) == -1) {
2770 fThreadsFilterComboBox->addItem("All");
2771 }
2772 }
2773 if (fThreadsFilterComboBox->count() < 2) {
2774 if (fThreadsFilterComboBox->findText("Master", Qt::MatchExactly) == -1) {
2775 fThreadsFilterComboBox->addItem("Master");
2776 }
2777 }
2778 // Add current Cout
2779 G4String prefix = GetThreadPrefix();
2780 if (! prefix.empty()) {
2781 if (fThreadsFilterComboBox->findText(prefix.data(), Qt::MatchExactly) == -1) {
2782 fThreadsFilterComboBox->addItem(prefix.data());
2783 }
2784 }
2785}
2786#endif
2787
2788/**
2789 Add a new menu to the menu bar
2790 @param aName name of menu
2791 @param aLabel label to display
2792 */
2793void G4UIQt::AddMenu(const char* aName, const char* aLabel)
2794{
2795 if (aName == nullptr) return;
2796 if (aLabel == nullptr) return;
2797
2798 auto fileMenu = new QMenu(aLabel);
2799 fMainWindow->menuBar()->addMenu(fileMenu);
2800
2801 AddInteractor(aName, (G4Interactor)fileMenu);
2802}
2803
2804/**
2805 Add a new button to a menu
2806 @param aMenu : parent menu
2807 @param aLabel : label to display
2808 @param aCommand : command to execute as a callback
2809 */
2810void G4UIQt::AddButton(const char* aMenu, const char* aLabel, const char* aCommand)
2811{
2812 if (aMenu == nullptr) return; // TO KEEP
2813 if (aLabel == nullptr) return; // TO KEEP
2814 if (aCommand == nullptr) return; // TO KEEP
2815
2816 QMenu* parentTmp = (QMenu*)GetInteractor(aMenu);
2817
2818 if (parentTmp == nullptr) {
2820 G4int verbose = UImanager->GetVerboseLevel();
2821
2822 if (verbose >= 2) {
2823 G4cout << "Menu name " << aMenu << " does not exist, please define it before using it."
2824 << G4endl;
2825 }
2826 return;
2827 }
2828
2829 // Find the command in the command tree
2831 if (UI == nullptr) return;
2832 G4UIcommandTree* treeTop = UI->GetTree();
2833
2834 G4String cmd = aCommand;
2835 std::size_t cmdEndPos = cmd.find_first_of(" \t");
2836 if (cmdEndPos != std::string::npos) {
2837 cmd.erase(cmdEndPos);
2838 }
2839
2840 if (treeTop->FindPath(cmd) == nullptr) {
2841 if (cmd != "ls" && cmd.substr(0, 3) != "ls " && cmd != "pwd" && cmd != "cd" &&
2842 cmd.substr(0, 3) != "cd " && cmd != "help" && cmd.substr(0, 5) != "help " &&
2843 cmd[0] != '?' && cmd != "hist" && cmd != "history" && cmd[0] != '!' && cmd != "exit" &&
2844 cmd != "cont" && cmd != "continue")
2845 {
2847 G4int verbose = UImanager->GetVerboseLevel();
2848
2849 if (verbose >= 2) {
2850 G4cout << "Warning: command '" << cmd
2851 << "' does not exist, please define it before using it." << G4endl;
2852 }
2853 }
2854 }
2855
2856 QString cmd_tmp = QString(aCommand);
2857 parentTmp->addAction(aLabel, this, [this, cmd_tmp]() { this->ButtonCallback(cmd_tmp); });
2858}
2859
2860/**
2861 special case for the "open" icon. It will open a file selector and map the return file to the given
2862 command.
2863*/
2865 const char* aLabel, const char* aIconFile, const char* aCommand, const char* aFileName)
2866{
2867 if (aLabel == nullptr) return; // TO KEEP
2868 // special case, aCommand could be NULL if aIconFile is not user_icon
2869 if (aCommand == nullptr) {
2870 if (std::string(aIconFile) == "user_icon") {
2871 return; // TO KEEP
2872 }
2873 }
2874 QPixmap* pix;
2875 G4bool userToolBar = false;
2876
2877 if (! fDefaultIcons) {
2878 userToolBar = true;
2879 }
2880 if (std::string(aIconFile) == "user_icon") {
2881 // try to open a file
2883 pix = new QPixmap(UImanager->FindMacroPath(aFileName).data());
2884 if (pix->isNull()) {
2885 G4int verbose = UImanager->GetVerboseLevel();
2886
2887 if (verbose >= 2) {
2888 G4cout << "Warning: file '" << aFileName
2889 << "' is incorrect or does not exist, this command will not be build" << G4endl;
2890 }
2891 return;
2892 }
2893 }
2894 else if (std::string(aIconFile) == "open") {
2895 pix = fOpenIcon;
2896 }
2897 else if (std::string(aIconFile) == "save") {
2898 pix = fSaveIcon;
2899 }
2900 else if (std::string(aIconFile) == "move") {
2901 pix = fMoveIcon;
2902 }
2903 else if (std::string(aIconFile) == "rotate") {
2904 pix = fRotateIcon;
2905 }
2906 else if (std::string(aIconFile) == "pick") {
2907 pix = fPickIcon;
2908 }
2909 else if (std::string(aIconFile) == "zoom_in") {
2910 pix = fZoomInIcon;
2911 }
2912 else if (std::string(aIconFile) == "zoom_out") {
2913 pix = fZoomOutIcon;
2914 }
2915 else if (std::string(aIconFile) == "wireframe") {
2916 pix = fWireframeIcon;
2917 }
2918 else if (std::string(aIconFile) == "solid") {
2919 pix = fSolidIcon;
2920 }
2921 else if (std::string(aIconFile) == "hidden_line_removal") {
2922 pix = fHiddenLineRemovalIcon;
2923 }
2924 else if (std::string(aIconFile) == "hidden_line_and_surface_removal") {
2925 pix = fHiddenLineAndSurfaceRemovalIcon;
2926 }
2927 else if (std::string(aIconFile) == "perspective") {
2928 pix = fPerspectiveIcon;
2929 }
2930 else if (std::string(aIconFile) == "ortho") {
2931 pix = fOrthoIcon;
2932 }
2933 else if (std::string(aIconFile) == "runBeamOn") {
2934 pix = fRunIcon;
2935 }
2936 else if (std::string(aIconFile) == "exit") {
2937 pix = fExitIcon;
2938 }
2939 else {
2941 G4int verbose = UImanager->GetVerboseLevel();
2942
2943 if (verbose >= 2) {
2944 G4cout << "Parameter" << aIconFile << " not defined" << G4endl;
2945 }
2946 return;
2947 }
2948 QToolBar* currentToolbar = nullptr;
2949 if (userToolBar) {
2950 if (fToolbarUser == nullptr) {
2951 fToolbarUser = new QToolBar();
2952 fToolbarUser->setIconSize(QSize(20, 20));
2953 fMainWindow->addToolBar(Qt::TopToolBarArea, fToolbarUser);
2954 }
2955 currentToolbar = fToolbarUser;
2956 }
2957 else {
2958 if (fToolbarApp == nullptr) {
2959 fToolbarApp = new QToolBar();
2960 fToolbarApp->setIconSize(QSize(20, 20));
2961 fMainWindow->addToolBar(Qt::TopToolBarArea, fToolbarApp);
2962 }
2963 currentToolbar = fToolbarApp;
2964 }
2965
2966 // Check if already present
2967
2968 QList<QAction*> list = currentToolbar->actions();
2969
2970 for (auto i : list) {
2971 if (i->text() == QString(aLabel)) {
2973 if (UI == nullptr) return;
2974 G4int verbose = UI->GetVerboseLevel();
2975 if (verbose >= 2) {
2976 G4cout << "Warning: A toolBar icon \"" << aLabel << "\" already exists with the same name!"
2977 << G4endl;
2978 }
2979 }
2980 }
2981
2982 // special cases :"open"
2983 if (std::string(aIconFile) == "open") {
2984 QString txt = aCommand + fStringSeparator + aLabel;
2985 currentToolbar->addAction(
2986 QIcon(*pix), aIconFile, this, [this, txt]() { this->OpenIconCallback(txt); });
2987
2988 // special cases :"save"
2989 }
2990 else if (std::string(aIconFile) == "save") {
2991 QString txt = aCommand + fStringSeparator + aLabel;
2992 currentToolbar->addAction(
2993 QIcon(*pix), aIconFile, this, [this, txt]() { this->SaveIconCallback(txt); });
2994 // special cases : cursor style
2995 }
2996 else if ((std::string(aIconFile) == "move") || (std::string(aIconFile) == "rotate") ||
2997 (std::string(aIconFile) == "pick") || (std::string(aIconFile) == "zoom_out") ||
2998 (std::string(aIconFile) == "zoom_in"))
2999 {
3000 QString txt = QString(aIconFile);
3001 QAction* action = currentToolbar->addAction(
3002 QIcon(*pix), aIconFile, this, [this, txt]() { this->ChangeCursorAction(txt); });
3003 action->setCheckable(true);
3004 action->setChecked(true);
3005 action->setData(aIconFile);
3006
3007 if (std::string(aIconFile) == "move") {
3009 }
3010 if (std::string(aIconFile) == "rotate") {
3012 }
3013 if (std::string(aIconFile) == "pick") {
3015 }
3016 if (std::string(aIconFile) == "zoom_in") {
3018 }
3019 if (std::string(aIconFile) == "zoom_out") {
3021 }
3022
3023 // special case : surface style
3024 }
3025 else if ((std::string(aIconFile) == "hidden_line_removal") ||
3026 (std::string(aIconFile) == "hidden_line_and_surface_removal") ||
3027 (std::string(aIconFile) == "solid") || (std::string(aIconFile) == "wireframe"))
3028 {
3029 QString txt = QString(aIconFile);
3030 QAction* action = currentToolbar->addAction(
3031 QIcon(*pix), aIconFile, this, [this, txt]() { this->ChangeSurfaceStyle(txt); });
3032 action->setCheckable(true);
3033 action->setChecked(true);
3034 action->setData(aIconFile);
3035
3036 if (std::string(aIconFile) == "hidden_line_removal") {
3038 }
3039 if (std::string(aIconFile) == "hidden_line_and_surface_removal") {
3041 }
3042 if (std::string(aIconFile) == "solid") {
3044 }
3045 if (std::string(aIconFile) == "wireframe") {
3047 }
3048
3049 // special case : perspective/ortho
3050 }
3051 else if ((std::string(aIconFile) == "perspective") || (std::string(aIconFile) == "ortho")) {
3052 QString txt = QString(aIconFile);
3053 QAction* action = currentToolbar->addAction(
3054 QIcon(*pix), aIconFile, this, [this, txt]() { this->ChangePerspectiveOrtho(txt); });
3055 action->setCheckable(true);
3056 action->setChecked(true);
3057 action->setData(aIconFile);
3058
3059 if (std::string(aIconFile) == "perspective") {
3061 }
3062 if (std::string(aIconFile) == "ortho") {
3064 }
3065 }
3066 else {
3067 // Find the command in the command tree
3069 if (UI == nullptr) return;
3070 G4UIcommandTree* treeTop = UI->GetTree();
3071 if (aCommand != nullptr) {
3072 std::string str = aCommand;
3073 std::string::size_type pos = str.find(' ');
3074 if (pos != std::string::npos) {
3075 str = str.substr(0, pos).c_str();
3076 }
3077 if (treeTop->FindPath(str.c_str()) == nullptr) {
3079 G4int verbose = UImanager->GetVerboseLevel();
3080
3081 if (verbose >= 2) {
3082 G4cout << "Warning: command '" << aCommand
3083 << "' does not exist, please define it before using it." << G4endl;
3084 }
3085 }
3086 }
3087 QString txt = QString(aCommand);
3088 currentToolbar->addAction(
3089 QIcon(*pix), aCommand, this, [this, txt]() { this->ButtonCallback(txt); });
3090 }
3091}
3092
3093void G4UIQt::SetOutputStyle(const char* destination, const char* style)
3094{
3095 // Specify an output style
3096 // First argument destination ("cout" etc or "all")
3097 // Second argument is the required style - see guidance
3098
3099 SetStyleUtility(destination, style);
3100}
3101
3103{
3104 if (fMainWindow->menuBar()->isNativeMenuBar() == aVal) return; // already in this state
3105
3106 // Menu become empty when goin from Qt to Native Bar
3107 fMainWindow->menuBar()->setNativeMenuBar(aVal);
3108}
3109
3110void G4UIQt::ClearMenu() { fMainWindow->menuBar()->clear(); }
3111
3112void G4UIQt::ActivateCommand(G4String newCommand)
3113{
3114 if (fHelpTreeWidget == nullptr) {
3115 return;
3116 }
3117 // Look for the choosen command "newCommand"
3118 std::size_t i = newCommand.find(' ');
3119 G4String targetCom = "";
3120 if (i != std::string::npos) {
3121 G4String newValue = newCommand.substr(i + 1, newCommand.length() - (i + 1));
3122 G4StrUtil::strip(newValue);
3123 targetCom = ModifyToFullPathCommand(newValue);
3124 }
3125 if (! targetCom.empty()) {
3126 OpenHelpTreeOnCommand(targetCom.data());
3127 }
3128
3129 fUITabWidget->setCurrentWidget(fHelpTBWidget);
3130}
3131
3132/**
3133 Create the help tree widget
3134 @param parent : parent of tree widget
3135 @return the widget containing the tree or NULL if it could not have beeen created
3136 */
3137
3138void G4UIQt::InitHelpTreeAndVisParametersWidget()
3139{
3140 if (fHelpTreeWidget == nullptr) {
3141 fHelpTreeWidget = new QTreeWidget();
3142 }
3143
3144 // build widget
3145 fHelpTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
3146 QStringList labels;
3147 labels << QString("Command");
3148 fHelpTreeWidget->setHeaderLabels(labels);
3149
3150 connect(fHelpTreeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(HelpTreeClicCallback()));
3151 connect(fHelpTreeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this,
3152 SLOT(HelpTreeDoubleClicCallback()));
3153}
3154/**
3155 Create the help tree widget
3156 @param parent : parent of tree widget
3157 @return the widget containing the tree or NULL if it could not have beeen created
3158 */
3159
3160void G4UIQt::FillHelpTree()
3161{
3162 if (fHelpTreeWidget == nullptr) {
3163 InitHelpTreeAndVisParametersWidget();
3164 }
3165
3166 QString searchText = fHelpLine->text();
3167
3168 if (searchText == "") {
3169 // clear old help tree
3170 // fHelpTreeWidget->clear();
3171 }
3172 else {
3173 return;
3174 }
3175
3176 if (fParameterHelpLabel != nullptr) {
3177 fParameterHelpLabel->setText("Choose a command in the command tree");
3178 fParameterHelpTable->setVisible(false);
3179 }
3180
3181 if (fHelpLine != nullptr) {
3182 fHelpLine->setText("");
3183 }
3184
3186 if (UI == nullptr) return;
3187 G4UIcommandTree* treeTop = UI->GetTree();
3188
3189 G4int treeSize = treeTop->GetTreeEntry();
3190 QTreeWidgetItem* newItem = nullptr;
3191 QString commandText = "";
3192 for (G4int a = 0; a < treeSize; ++a) {
3193 // Creating new item
3194 newItem = nullptr;
3195
3196 commandText = QString((char*)(treeTop->GetTree(a + 1)->GetPathName()).data()).trimmed();
3197
3198 // if already exist, don't create it !
3199 for (G4int b = 0; b < fHelpTreeWidget->topLevelItemCount(); ++b) {
3200 if (newItem == nullptr) newItem = FindTreeItem(fHelpTreeWidget->topLevelItem(b), commandText);
3201 }
3202
3203 if (newItem == nullptr) {
3204 newItem = new QTreeWidgetItem();
3205 newItem->setText(0, GetShortCommandPath(commandText));
3206 fHelpTreeWidget->addTopLevelItem(newItem);
3207 }
3208
3209 // look for childs
3210 CreateHelpTree(newItem, treeTop->GetTree(a + 1));
3211 }
3212}
3213
3214/** Fill the Help Tree Widget
3215 @param aParent : parent item to fill
3216 @param aCommandTree : commandTree node associate with this part of the Tree
3217*/
3218void G4UIQt::CreateHelpTree(QTreeWidgetItem* aParent, G4UIcommandTree* aCommandTree)
3219{
3220 if (aParent == nullptr) return;
3221 if (aCommandTree == nullptr) return;
3222
3223 // Creating new item
3224 QTreeWidgetItem* newItem;
3225
3226 QString commandText = "";
3227 // Get the Sub directories
3228 for (G4int a = 0; a < aCommandTree->GetTreeEntry(); ++a) {
3229 commandText = QString((char*)(aCommandTree->GetTree(a + 1)->GetPathName()).data()).trimmed();
3230
3231 // if already exist, don't create it !
3232 newItem = FindTreeItem(aParent, commandText);
3233 if (newItem == nullptr) {
3234 newItem = new QTreeWidgetItem();
3235 newItem->setText(0, GetShortCommandPath(commandText));
3236 aParent->addChild(newItem);
3237 }
3238 CreateHelpTree(newItem, aCommandTree->GetTree(a + 1));
3239 }
3240
3241 // Get the Commands
3242
3243 for (G4int a = 0; a < aCommandTree->GetCommandEntry(); ++a) {
3244 QStringList stringList;
3245 commandText =
3246 QString((char*)(aCommandTree->GetCommand(a + 1)->GetCommandPath()).data()).trimmed();
3247
3248 // if already exist, don't create it !
3249 newItem = FindTreeItem(aParent, commandText);
3250 if (newItem == nullptr) {
3251 newItem = new QTreeWidgetItem();
3252 newItem->setText(0, GetShortCommandPath(commandText));
3253 aParent->addChild(newItem);
3254 newItem->setExpanded(false);
3255 }
3256 }
3257}
3258
3259/**
3260 Add the following command to the corresponding groupbox
3261 If depthLevel is 1 : create ToolBox
3262 If depthLevel is 2 or more : create GroupBox
3263*/
3264G4bool G4UIQt::CreateVisCommandGroupAndToolBox(
3265 G4UIcommand* aCommand, QWidget* aParent, G4int aDepthLevel, G4bool isDialog)
3266{
3267 QString commandText =
3268 QString((char*)(aCommand->GetCommandPath().data())).section("/", -aDepthLevel);
3269
3270 if (commandText == nullptr) {
3271 return false;
3272 }
3273
3274 // Look if groupBox is create
3275 // QGroupBox* gBoxCommandWidget;
3276 QWidget* newParentWidget = nullptr;
3277 G4bool found = false;
3278 QString commandSection = commandText.left(commandText.indexOf("/"));
3279
3280 if (aDepthLevel == 1) {
3281 auto currentParent = dynamic_cast<QToolBox*>(aParent);
3282 if (currentParent != nullptr) {
3283 // already exists ?
3284 for (G4int a = 0; a < currentParent->count(); ++a) {
3285 if (currentParent->itemText(a) == commandSection) {
3286 found = true;
3287 newParentWidget = currentParent->widget(a);
3288 }
3289 }
3290 }
3291 // Not found ? create it
3292 if (! found) {
3293 newParentWidget = new QGroupBox();
3294 newParentWidget->setLayout(new QVBoxLayout());
3295 if (currentParent != nullptr) {
3296 currentParent->addItem(newParentWidget, commandSection);
3297 }
3298 else {
3299 if (aParent->layout() == nullptr) {
3300 aParent->setLayout(new QVBoxLayout());
3301 }
3302 aParent->layout()->addWidget(newParentWidget);
3303 }
3304
3305 if (commandText.indexOf("/") == -1) {
3306 // Guidance
3307 QString guidance;
3308 auto n_guidanceEntry = (G4int)aCommand->GetGuidanceEntries();
3309 for (G4int i_thGuidance = 0; i_thGuidance < n_guidanceEntry; i_thGuidance++) {
3310 guidance += QString((char*)(aCommand->GetGuidanceLine(i_thGuidance)).data()) + "\n";
3311 }
3312 newParentWidget->setToolTip(guidance);
3313 }
3314
3315 auto sc = dynamic_cast<QScrollArea*>(newParentWidget->parent()->parent());
3316 if (sc != nullptr) {
3317 sc->ensureWidgetVisible(newParentWidget);
3318 }
3319 }
3320 }
3321 else {
3322 // try to know if this level is already there
3323 auto currentParent = dynamic_cast<QGroupBox*>(aParent);
3324 if (currentParent != nullptr) {
3325 // if depth==2, then we add a [more parameters inside] to the toolBoxItem parent
3326 // QGroupBox > QWidget > QScrollArea > QToolBox
3327 if (aDepthLevel == 2) {
3328 auto parentToolBox = dynamic_cast<QToolBox*>(currentParent->parent()->parent()->parent());
3329 if (parentToolBox != nullptr) {
3330 // parentToolBox->setItemText(parentToolBox->indexOf(currentParent),"[more
3331 // parameters inside]");
3332 }
3333 }
3334 for (G4int a = 0; a < aParent->layout()->count(); ++a) {
3335 auto gb = dynamic_cast<QGroupBox*>(aParent->layout()->itemAt(a)->widget());
3336 if (gb != nullptr) {
3337 if (gb->title() == commandSection) {
3338 found = true;
3339 newParentWidget = gb;
3340 }
3341 }
3342 }
3343 }
3344
3345 // Not found ? create it
3346 if (! found) {
3347 newParentWidget = new QGroupBox();
3348 newParentWidget->setLayout(new QVBoxLayout());
3349 if (aParent->layout() == nullptr) {
3350 aParent->setLayout(new QVBoxLayout());
3351 }
3352 aParent->layout()->addWidget(newParentWidget);
3353
3354 // set toolTip
3355 // Guidance
3356 QString guidance;
3357 auto n_guidanceEntry = (G4int)aCommand->GetGuidanceEntries();
3358 for (G4int i_thGuidance = 0; i_thGuidance < n_guidanceEntry; i_thGuidance++) {
3359 guidance += QString((char*)(aCommand->GetGuidanceLine(i_thGuidance)).data()) + "\n";
3360 }
3361 newParentWidget->setToolTip(guidance);
3362 }
3363 }
3364
3365 // fill command groupbox
3366 if (commandText.indexOf("/") == -1) {
3367 if (CreateCommandWidget(aCommand, newParentWidget, isDialog)) {
3368 return true;
3369 }
3370 }
3371 else {
3372 CreateVisCommandGroupAndToolBox(aCommand, newParentWidget, aDepthLevel - 1, isDialog);
3373 }
3374
3375 return true;
3376}
3377
3378/** Create a widget with the command parameters inside
3379 @param command: command line
3380 @parent : parent widget
3381 @isDialog : true if we want apply/cancel button and close at end, false if we want only apply
3382*/
3383G4bool G4UIQt::CreateCommandWidget(G4UIcommand* aCommand, QWidget* aParent, G4bool isDialog)
3384{
3385 if (aCommand == nullptr) {
3386 return false;
3387 }
3388
3389 // parameters
3390 auto n_parameterEntry = (G4int)aCommand->GetParameterEntries();
3391 if (n_parameterEntry > 0) {
3392 G4UIparameter* param;
3393
3394 // Re-implementation of G4UIparameter.cc
3395 auto paramWidget = new QWidget();
3396 auto gridLayout = new QGridLayout();
3397 paramWidget->setLayout(gridLayout);
3398
3399 // Special case for colour, try to display a color chooser if we found red/green/blue parameter
3400 unsigned int nbColorParameter = 0;
3401 G4bool isStillColorParameter = false;
3402 G4bool isColorDialogAdded = false;
3403 QLabel* redLabel = nullptr;
3404 QLabel* greenLabel = nullptr;
3405 QString redDefaultStr = "";
3406 QString greenDefaultStr = "";
3407 QString blueDefaultStr = "";
3408 QWidget* redInput = nullptr;
3409 QWidget* greenInput = nullptr;
3410
3411 for (G4int i_thParameter = 0; i_thParameter < n_parameterEntry; i_thParameter++) {
3412 QString txt;
3413 param = aCommand->GetParameter(i_thParameter);
3414 auto label = new QLabel(QString((char*)(param->GetParameterName()).data()));
3415
3416 if ((label->text() == "red") || (label->text() == "red_or_string")) {
3417 nbColorParameter++;
3418 isStillColorParameter = true;
3419 }
3420 else if ((label->text() == "green") && isStillColorParameter) {
3421 nbColorParameter++;
3422 }
3423 else if ((label->text() == "blue") && isStillColorParameter) {
3424 nbColorParameter++;
3425 }
3426 else if (! isColorDialogAdded) {
3427 // not following red/green/blue parameters ?
3428 if (nbColorParameter == 1) {
3429 gridLayout->addWidget(redLabel, i_thParameter - 1, 0);
3430 gridLayout->addWidget(redInput, i_thParameter - 1, 1);
3431 }
3432 else if (nbColorParameter == 2) {
3433 gridLayout->addWidget(redLabel, i_thParameter - 2, 0);
3434 gridLayout->addWidget(redInput, i_thParameter - 2, 1);
3435 gridLayout->addWidget(greenLabel, i_thParameter - 1, 0);
3436 gridLayout->addWidget(greenInput, i_thParameter - 1, 1);
3437 }
3438 nbColorParameter = 0;
3439 }
3440 // Check parameter type, could be NULL if not found
3441 QWidget* input = nullptr;
3442 if ((QString(QChar(param->GetParameterType())) == "d") ||
3443 (QString(QChar(param->GetParameterType())) == "i"))
3444 {
3445 input = new QLineEdit();
3446 // set default value
3447 dynamic_cast<QLineEdit*>(input)->setText(QString((char*)(param->GetDefaultValue()).data()));
3448
3449 if (((label->text() == "red") || (label->text() == "red_or_string")) &&
3450 isStillColorParameter)
3451 {
3452 redDefaultStr = QString((char*)(param->GetDefaultValue()).data());
3453 }
3454 else if ((label->text() == "green") && isStillColorParameter) {
3455 greenDefaultStr = QString((char*)(param->GetDefaultValue()).data());
3456 }
3457 else if ((label->text() == "blue") && isStillColorParameter) {
3458 blueDefaultStr = QString((char*)(param->GetDefaultValue()).data());
3459 }
3460 }
3461 else if (QString(QChar(param->GetParameterType())) == "b") {
3462 input = new QWidget();
3463 auto layout = new QHBoxLayout();
3464 input->setLayout(layout);
3465
3466 auto buttons = new QButtonGroup();
3467 auto radioOff = new QRadioButton("0");
3468 auto radioOn = new QRadioButton("1");
3469 buttons->addButton(radioOn);
3470 buttons->addButton(radioOff);
3471 layout->addWidget(radioOn);
3472 layout->addWidget(radioOff);
3473
3474 // set default value
3475 QString defaultValue = QString((char*)(param->GetDefaultValue()).data());
3476 if (defaultValue == "0") {
3477 radioOff->setChecked(true);
3478 }
3479 else if (defaultValue == "1") {
3480 radioOn->setChecked(true);
3481 }
3482 }
3483 else if ((QString(QChar(param->GetParameterType())) == "s") &&
3484 (! param->GetParameterCandidates().empty()))
3485 {
3486 input = new QComboBox();
3487 QString candidates = QString((char*)(param->GetParameterCandidates()).data());
3488 QStringList list = candidates.split(" ");
3489
3490 // add all candidates to widget
3491 QString defaultValue = QString((char*)(param->GetDefaultValue()).data());
3492 for (int a = 0; a < list.size(); a++) {
3493 dynamic_cast<QComboBox*>(input)->addItem(list.at(a));
3494 if (list.at(a) == defaultValue) {
3495 dynamic_cast<QComboBox*>(input)->setCurrentIndex(a);
3496 }
3497 }
3498 }
3499 else if ((QString(QChar(param->GetParameterType())) == "s")) { // string
3500 input = new QLineEdit();
3501 // set default value
3502 dynamic_cast<QLineEdit*>(input)->setText(QString((char*)(param->GetDefaultValue()).data()));
3503 }
3504 else if ((QString(QChar(param->GetParameterType())) == "c")) { // on/off
3505 input = new QWidget();
3506 auto layout = new QHBoxLayout();
3507 input->setLayout(layout);
3508
3509 auto buttons = new QButtonGroup();
3510 auto radioOff = new QRadioButton("off");
3511 auto radioOn = new QRadioButton("on");
3512 buttons->addButton(radioOn);
3513 buttons->addButton(radioOff);
3514 layout->addWidget(radioOn);
3515 layout->addWidget(radioOff);
3516
3517 // set default value
3518 QString defaultValue = QString((char*)(param->GetDefaultValue()).data());
3519 if (defaultValue == "off") {
3520 radioOff->setChecked(true);
3521 }
3522 else if (defaultValue == "on") {
3523 radioOn->setChecked(true);
3524 }
3525 }
3526 else {
3527 input = new QLineEdit();
3528 dynamic_cast<QLineEdit*>(input)->setText(QString((char*)(param->GetDefaultValue()).data()));
3529 }
3530
3531 txt += "\nParameter : " + QString((char*)(param->GetParameterName()).data()) + "\n";
3532 if (! param->GetParameterGuidance().empty())
3533 txt += QString((char*)(param->GetParameterGuidance()).data()) + "\n";
3534
3535 txt += " Parameter type : " + QString(QChar(param->GetParameterType())) + "\n";
3536 if (param->IsOmittable()) {
3537 txt += " Omittable : True\n";
3538 }
3539 else {
3540 txt += " Omittable : False\n";
3541 }
3542 if (param->GetCurrentAsDefault()) {
3543 txt += " Default value : taken from the current value\n";
3544 }
3545 else if (! param->GetDefaultValue().empty()) {
3546 txt += " Default value : " + QString((char*)(param->GetDefaultValue()).data()) + "\n";
3547 }
3548 if (! param->GetParameterRange().empty()) {
3549 txt += " Parameter range : " + QString((char*)(param->GetParameterRange()).data()) + "\n";
3550 }
3551 if (! param->GetParameterCandidates().empty()) {
3552 txt +=
3553 " Candidates : " + QString((char*)(param->GetParameterCandidates()).data()) + "\n";
3554 }
3555
3556 if (isStillColorParameter && (nbColorParameter != 0)) {
3557 if ((label->text() == "red") || (label->text() == "red_or_string")) {
3558 redLabel = label;
3559 redInput = input;
3560 }
3561 else if (label->text() == "green") {
3562 greenLabel = label;
3563 greenInput = input;
3564 }
3565 else if (label->text() == "blue") {
3566 // we have all, then add a color chooser
3567
3568 // Create a pixmap with the default color
3569 QColor qc;
3570 if ((redDefaultStr != "") && (redDefaultStr != "") && (redDefaultStr != "")) {
3571 qc.setRgbF(
3572 redDefaultStr.toDouble(), greenDefaultStr.toDouble(), blueDefaultStr.toDouble());
3573 }
3574 QPixmap pixmap = QPixmap(QSize(16, 16));
3575 pixmap.fill(qc);
3576 QPainter painter(&pixmap);
3577 painter.setPen(Qt::black);
3578 painter.drawRect(0, 0, 15, 15); // Draw contour
3579
3580 input = new QPushButton("Change color");
3581 dynamic_cast<QPushButton*>(input)->setIcon(pixmap);
3582 dynamic_cast<QPushButton*>(input)->setAccessibleName(
3583 redDefaultStr + " " + greenDefaultStr + " " + blueDefaultStr);
3584 label = new QLabel("Choose color");
3585
3586 // less 1 because we have to add one to the row number
3587 nbColorParameter--;
3588 gridLayout->addWidget(label, i_thParameter - nbColorParameter, 0);
3589 input->setToolTip("Select the current color");
3590 gridLayout->addWidget(input, i_thParameter - nbColorParameter, 1);
3591
3592 // Connect pushButton to ColorDialog in callback
3593 connect(dynamic_cast<QPushButton*>(input), &QPushButton::clicked,
3594 [this, input]() { this->ChangeColorCallback(input); });
3595 isColorDialogAdded = true;
3596 isStillColorParameter = false;
3597 }
3598 }
3599 else {
3600 gridLayout->addWidget(label, i_thParameter - nbColorParameter, 0);
3601 input->setToolTip(txt);
3602 gridLayout->addWidget(input, i_thParameter - nbColorParameter, 1);
3603 }
3604 }
3605 // add command name in hidden value at last line position 0
3606 auto name = new QLabel(QString((char*)(aCommand->GetCommandPath().data())));
3607 name->hide();
3608 gridLayout->addWidget(name, n_parameterEntry - nbColorParameter, 0);
3609
3610 auto applyButton = new QPushButton("Apply");
3611 if (! isDialog) {
3612 gridLayout->addWidget(applyButton, n_parameterEntry - nbColorParameter, 1);
3613 connect(applyButton, &QPushButton::clicked,
3614 [this, paramWidget]() { this->VisParameterCallback(paramWidget); });
3615 }
3616 else {
3617 // Apply/Cancel buttons
3618
3619 applyButton->setAutoDefault(true);
3620 applyButton->setDefault(true);
3621
3622 auto cancelButton = new QPushButton(tr("&Cancel"));
3623 cancelButton->setAutoDefault(true);
3624 gridLayout->addWidget(cancelButton, n_parameterEntry - nbColorParameter, 1);
3625 gridLayout->addWidget(applyButton, n_parameterEntry - nbColorParameter, 0);
3626
3627 connect(applyButton, &QPushButton::clicked,
3628 [this, paramWidget]() { this->VisParameterCallback(paramWidget); });
3629
3630 QWidget* parentCheck = aParent;
3631 QDialog* parentDialog = nullptr;
3632 G4bool found = false;
3633 while ((parentCheck->parentWidget()) != nullptr) {
3634 parentCheck = parentCheck->parentWidget();
3635 parentDialog = dynamic_cast<QDialog*>(parentCheck);
3636 if (parentDialog != nullptr) {
3637 connect(applyButton, SIGNAL(clicked()), parentDialog, SLOT(accept()));
3638 connect(cancelButton, SIGNAL(clicked()), parentDialog, SLOT(reject()));
3639 found = true;
3640 }
3641 }
3642 if (! found) {
3643 return false;
3644 }
3645 }
3646
3647 if (aParent->layout() == nullptr) {
3648 aParent->setLayout(new QVBoxLayout());
3649 }
3650 aParent->layout()->addWidget(paramWidget);
3651 }
3652
3653 return true;
3654}
3655
3656/** Find a treeItemWidget in the help tree
3657 @param aCommand item's String to look for
3658 @return item if found, NULL if not
3659*/
3660QTreeWidgetItem* G4UIQt::FindTreeItem(QTreeWidgetItem* aParent, const QString& aCommand)
3661{
3662 if (aParent == nullptr) return nullptr;
3663
3664 // Suppress last "/"
3665 QString myCommand = aCommand;
3666
3667 if (myCommand.lastIndexOf("/") == (myCommand.size() - 1)) {
3668 myCommand = myCommand.left(myCommand.size() - 1);
3669 }
3670
3671 if (GetLongCommandPath(aParent) == myCommand) return aParent;
3672
3673 QTreeWidgetItem* tmp = nullptr;
3674 for (G4int a = 0; a < aParent->childCount(); ++a) {
3675 if (tmp == nullptr) tmp = FindTreeItem(aParent->child(a), myCommand);
3676 }
3677 return tmp;
3678}
3679
3680/** Build the command list parameters in a QString<br>
3681 Reimplement partialy the G4UIparameter.cc
3682 @param aCommand : command to list parameters
3683 @see G4UIparameter::List()
3684 @see G4UIcommand::List()
3685 @return the command list parameters, or "" if nothing
3686 */
3687QString G4UIQt::GetCommandList(const G4UIcommand* aCommand)
3688{
3689 QString txt = "";
3690 if (aCommand == nullptr) return txt;
3691
3692 G4String commandPath = aCommand->GetCommandPath();
3693 G4String rangeString = aCommand->GetRange();
3694 auto n_guidanceEntry = (G4int)aCommand->GetGuidanceEntries();
3695 auto n_parameterEntry = (G4int)aCommand->GetParameterEntries();
3696
3697 if ((commandPath.empty()) && (rangeString.empty()) && (n_guidanceEntry == 0) &&
3698 (n_parameterEntry == 0))
3699 {
3700 return txt;
3701 }
3702
3703 if ((commandPath.length() - 1) != '/') {
3704 txt += "Command " + QString((char*)(commandPath).data()) + "\n";
3705 }
3706 txt += "Guidance :\n";
3707
3708 for (G4int i_thGuidance = 0; i_thGuidance < n_guidanceEntry; i_thGuidance++) {
3709 txt += QString((char*)(aCommand->GetGuidanceLine(i_thGuidance)).data()) + "\n";
3710 }
3711 if (! rangeString.empty()) {
3712 txt += " Range of parameters : " + QString((char*)(rangeString).data()) + "\n";
3713 }
3714 if (n_parameterEntry > 0) {
3715 G4UIparameter* param;
3716
3717 // Re-implementation of G4UIparameter.cc
3718
3719 for (G4int i_thParameter = 0; i_thParameter < n_parameterEntry; i_thParameter++) {
3720 param = aCommand->GetParameter(i_thParameter);
3721 txt += "\nParameter : " + QString((char*)(param->GetParameterName()).data()) + "\n";
3722 if (! param->GetParameterGuidance().empty())
3723 txt += QString((char*)(param->GetParameterGuidance()).data()) + "\n";
3724 txt += " Parameter type : " + QString(QChar(param->GetParameterType())) + "\n";
3725 if (param->IsOmittable()) {
3726 txt += " Omittable : True\n";
3727 }
3728 else {
3729 txt += " Omittable : False\n";
3730 }
3731 if (param->GetCurrentAsDefault()) {
3732 txt += " Default value : taken from the current value\n";
3733 }
3734 else if (! param->GetDefaultValue().empty()) {
3735 txt += " Default value : " + QString((char*)(param->GetDefaultValue()).data()) + "\n";
3736 }
3737 if (! param->GetParameterRange().empty()) {
3738 txt += " Parameter range : " + QString((char*)(param->GetParameterRange()).data()) + "\n";
3739 }
3740 if (! param->GetParameterCandidates().empty()) {
3741 txt +=
3742 " Candidates : " + QString((char*)(param->GetParameterCandidates()).data()) + "\n";
3743 }
3744 }
3745 }
3746 return txt;
3747}
3748
3749/** Build the command list parameters in a QString with HTML<br>
3750 Reimplement partialy the G4UIparameter.cc
3751 @param aCommand : command to list parameters
3752 @see G4UIparameter::List()
3753 @see G4UIcommand::List()
3754 @return the command list parameters, or "" if nothing
3755*/
3756void G4UIQt::updateHelpArea(const G4UIcommand* aCommand)
3757{
3758 if (fParameterHelpLabel == nullptr) return;
3759 if (fParameterHelpTable == nullptr) return;
3760
3761 fParameterHelpLabel->setTextInteractionFlags(Qt::NoTextInteraction);
3762 QString txt;
3763 if (aCommand == nullptr) return;
3764
3765 G4String commandPath = aCommand->GetCommandPath();
3766 G4String rangeString = aCommand->GetRange();
3767 auto n_guidanceEntry = (G4int)aCommand->GetGuidanceEntries();
3768 auto n_parameterEntry = (G4int)aCommand->GetParameterEntries();
3769
3770 if ((commandPath.empty()) && (rangeString.empty()) && (n_guidanceEntry == 0) &&
3771 (n_parameterEntry == 0))
3772 {
3773 return;
3774 }
3775
3776 if ((commandPath.length() - 1) != '/') {
3777 txt += "<b>Command </b> " + QString((char*)(commandPath).data()) + "<br />";
3778 }
3779 txt += "<b>Guidance :</b> ";
3780 QString tmpGuidance = "";
3781 for (G4int i_thGuidance = 0; i_thGuidance < n_guidanceEntry; i_thGuidance++) {
3782 tmpGuidance = QString((char*)(aCommand->GetGuidanceLine(i_thGuidance)).data());
3783 tmpGuidance = tmpGuidance.toHtmlEscaped();
3784 tmpGuidance.replace("\n", "<br />");
3785 txt += tmpGuidance + "<br />";
3786 }
3787 if (! rangeString.empty()) {
3788 QString range = QString((char*)(rangeString).data());
3789 range = range.toHtmlEscaped();
3790 txt += "<b>Range of parameters : </b> " + range + "<br />";
3791 }
3792 else {
3793 txt += "<br />";
3794 }
3795 fParameterHelpLabel->setHtml(txt);
3796
3797 if (n_parameterEntry > 0) {
3798 G4UIparameter* param;
3799
3800 // Re-implementation of G4UIparameter.cc
3801
3802 fParameterHelpTable->clear();
3803 fParameterHelpTable->setRowCount(n_parameterEntry);
3804 fParameterHelpTable->setColumnCount(8);
3805 fParameterHelpTable->setHorizontalHeaderLabels(
3806 QStringList() << tr("") << tr("Parameter") << tr("Guidance") << tr("Type") << tr("Ommitable")
3807 << tr("Default") << tr("Range") << tr("Candidate"));
3808 fParameterHelpTable->setColumnWidth(2, 60);
3809
3810 fParameterHelpTable->verticalHeader()->setVisible(false);
3811 fParameterHelpTable->setAlternatingRowColors(true);
3812 fParameterHelpTable->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
3813 fParameterHelpTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
3814 fParameterHelpTable->setWordWrap(true);
3815
3816 QTableWidgetItem* t = fParameterHelpTable->horizontalHeaderItem(1);
3817 QFont fnt = t->font();
3818 G4int size = fnt.pointSize();
3819 fnt.setPointSize(size - 2);
3820
3821 for (G4int a = 0; a < n_parameterEntry; a++) {
3822 param = aCommand->GetParameter(a);
3823 fParameterHelpTable->setItem(a, 0, new QTableWidgetItem(QString::number(a + 1)));
3824
3825 fParameterHelpTable->setItem(
3826 a, 1, new QTableWidgetItem(QString((char*)(param->GetParameterName()).data())));
3827 if (! param->GetParameterGuidance().empty()) {
3828 fParameterHelpTable->setItem(
3829 a, 2, new QTableWidgetItem(QString((char*)(param->GetParameterGuidance()).data())));
3830 }
3831 fParameterHelpTable->setItem(
3832 a, 3, new QTableWidgetItem(QString(QChar(param->GetParameterType()))));
3833
3834 if (param->IsOmittable()) {
3835 fParameterHelpTable->setItem(a, 4, new QTableWidgetItem(QString("True")));
3836 }
3837 else {
3838 fParameterHelpTable->setItem(a, 4, new QTableWidgetItem(QString("False")));
3839 }
3840 if (param->GetCurrentAsDefault()) {
3841 fParameterHelpTable->setItem(
3842 a, 5, new QTableWidgetItem(QString("taken from the current value")));
3843 }
3844 else if (! param->GetDefaultValue().empty()) {
3845 fParameterHelpTable->setItem(
3846 a, 5, new QTableWidgetItem(QString((char*)(param->GetDefaultValue()).data())));
3847 }
3848 if (! param->GetParameterRange().empty()) {
3849 fParameterHelpTable->setItem(
3850 a, 6, new QTableWidgetItem(QString((char*)(param->GetParameterRange()).data())));
3851 }
3852 if (! param->GetParameterCandidates().empty()) {
3853 fParameterHelpTable->setItem(
3854 a, 7, new QTableWidgetItem(QString((char*)(param->GetParameterCandidates()).data())));
3855 }
3856 // tooltips
3857 for (G4int b = 0; b < 8; ++b) {
3858 QTableWidgetItem* tmp = fParameterHelpTable->item(a, b);
3859 if (tmp != nullptr) {
3860 tmp->setToolTip(tmp->text());
3861 tmp->setFlags(Qt::NoItemFlags);
3862 }
3863 }
3864 fParameterHelpTable->resizeRowToContents(a);
3865 }
3866 for (G4int c = 0; c < 8; ++c) {
3867 if (c != 2) {
3868 fParameterHelpTable->resizeColumnToContents(c);
3869 }
3870 }
3871 fParameterHelpLabel->setVisible(true);
3872 fParameterHelpTable->setVisible(true);
3873 }
3874}
3875
3876/**
3877 Return true if this command takes almost a number (int, double, bool,
3878 string) as an input
3879 or a string with a candidate list
3880 */
3881G4bool G4UIQt::IsGUICommand(const G4UIcommand* aCommand)
3882{
3883 if (aCommand == nullptr) return false;
3884
3885 auto n_parameterEntry = (G4int)aCommand->GetParameterEntries();
3886
3887 if (n_parameterEntry > 0) {
3888 G4UIparameter* param;
3889
3890 // Re-implementation of G4UIparameter.cc
3891
3892 for (G4int i_thParameter = 0; i_thParameter < n_parameterEntry; i_thParameter++) {
3893 param = aCommand->GetParameter(i_thParameter);
3894 if (QString(QChar(param->GetParameterType())) == "d") {
3895 return true;
3896 }
3897 if (QString(QChar(param->GetParameterType())) == "b") {
3898 return true;
3899 }
3900 if (QString(QChar(param->GetParameterType())) == "i") {
3901 return true;
3902 }
3903 if (QString(QChar(param->GetParameterType())) == "s") {
3904 return true;
3905 }
3906 }
3907 }
3908 return false;
3909}
3910
3911/** Implement G4VBasicShell vurtual function
3912 */
3913G4bool G4UIQt::GetHelpChoice(G4int&) { return true; }
3914
3915/** Event filter method. Every event from QtApplication goes here.<br/>
3916 We apply a filter only for the Up and Down Arrow press when the QLineEdit<br/>
3917 is active. If this filter match, Up arrow we give the previous command<br/>
3918 and Down arrow will give the next if exist.<br/>
3919 @param obj Emitter of the event
3920 @param event Kind of event
3921*/
3922G4bool G4UIQt::eventFilter( // Should stay with a minuscule eventFilter because of Qt
3923 QObject* aObj, QEvent* aEvent)
3924{
3925 G4bool tabKeyPress = false;
3926 G4bool moveCommandCursor = false;
3927 if (aObj == nullptr) return false;
3928 if (aEvent == nullptr) return false;
3929
3930 if (aObj == fHistoryTBTableList) {
3931 if (aEvent->type() == QEvent::KeyPress) {
3932 fCommandArea->setFocus();
3933 }
3934 }
3935
3936 if (aObj == fCompleter->popup()) {
3937 if (aEvent->type() == QEvent::KeyPress) {
3938 auto e = static_cast<QKeyEvent*>(aEvent);
3939 if (e->key() == (Qt::Key_Tab)) {
3940 tabKeyPress = true;
3941 }
3942 }
3943 else if (aEvent->type() == QEvent::Hide) {
3944 // Store this value
3945 QString c = fCommandArea->text();
3946 fLastCompleteCommand = c.left(c.indexOf("<"));
3947 }
3948 }
3949
3950 if (aObj == fCommandArea) {
3951 if (aEvent->type() == QEvent::KeyPress) {
3952 auto e = static_cast<QKeyEvent*>(aEvent);
3953 if ((e->key() == (Qt::Key_Down)) || (e->key() == (Qt::Key_PageDown)) ||
3954 (e->key() == (Qt::Key_Up)) || (e->key() == (Qt::Key_PageUp)))
3955 {
3956 G4int selection = fHistoryTBTableList->currentRow();
3957 if (fHistoryTBTableList->count() != 0) {
3958 if (selection == -1) {
3959 selection = fHistoryTBTableList->count() - 1;
3960 }
3961 else {
3962 if (e->key() == (Qt::Key_Down)) {
3963 if (selection < (fHistoryTBTableList->count() - 1)) selection++;
3964 }
3965 else if (e->key() == (Qt::Key_PageDown)) {
3966 selection = fHistoryTBTableList->count() - 1;
3967 }
3968 else if (e->key() == (Qt::Key_Up)) {
3969 if (selection > 0) selection--;
3970 }
3971 else if (e->key() == (Qt::Key_PageUp)) {
3972 selection = 0;
3973 }
3974 }
3975 fHistoryTBTableList->clearSelection();
3976 fHistoryTBTableList->item(selection)->setSelected(true);
3977 fHistoryTBTableList->setCurrentItem(fHistoryTBTableList->item(selection));
3978 }
3979 moveCommandCursor = true;
3980 }
3981 else if (e->key() == (Qt::Key_Tab)) {
3982 tabKeyPress = true;
3983 }
3984 else if (((e->modifiers() == Qt::ControlModifier) || (e->modifiers() == Qt::MetaModifier)) &&
3985 (e->key() == Qt::Key_A))
3986 {
3987 fCommandArea->home(false);
3988 return true;
3989 }
3990 else if (((e->modifiers() == Qt::ControlModifier) || (e->modifiers() == Qt::MetaModifier)) &&
3991 (e->key() == Qt::Key_E))
3992 {
3993 fCommandArea->end(false);
3994 return true;
3995 }
3996 }
3997 else if (aEvent->type() == QEvent::Paint) {
3998 if (fLastCompleteCommand != "") {
3999 fCommandArea->setText(fLastCompleteCommand);
4000 fLastCompleteCommand = "";
4001 }
4002 }
4003 }
4004 if (tabKeyPress) {
4005 G4String ss = Complete(fCommandArea->text().toStdString().c_str());
4006 fCommandArea->setText((char*)(ss.data()));
4007 fCommandArea->setFocus();
4008 // do not pass by parent, it will disable widget tab focus !
4009 return true;
4010 // L.Garnier : MetaModifier is CTRL for MAC, but I don't want to put a MAC
4011 // specific #ifdef
4012 }
4013
4014 G4bool res = false;
4015 // change cursor position if needed
4016 if (moveCommandCursor) {
4017 fCommandArea->setCursorPosition((int)fCommandArea->text().length());
4018 fCommandArea->setCursorPosition(4);
4019 }
4020 else {
4021 // pass the event on to the parent class
4022 res = QObject::eventFilter(aObj, aEvent);
4023 }
4024 return res;
4025}
4026
4027void G4UIQt::UpdateCommandCompleter()
4028{
4029 if (fCommandArea == nullptr) return;
4030
4031 // remove previous one
4032 fCommandArea->setCompleter(nullptr);
4033 if (fCompleter != nullptr) {
4034 if (fCompleter->popup() != nullptr) {
4035 fCompleter->popup()->removeEventFilter(this);
4036 }
4037 }
4038
4039 QStandardItemModel* model = CreateCompleterModel("/");
4040 fCompleter = new QCompleter(model);
4041
4042 // set all dir visibles in completion
4044 G4UIcommandTree* commandTreeTop = UI->GetTree();
4045 G4UIcommandTree* aTree = commandTreeTop->FindCommandTree("/");
4046 if (aTree != nullptr) {
4047 int Ndir = aTree->GetTreeEntry();
4048 fCompleter->setMaxVisibleItems(Ndir);
4049 }
4050 fCommandArea->setCompleter(fCompleter);
4051 fCompleter->popup()->installEventFilter(this);
4052}
4053
4054QStandardItemModel* G4UIQt::CreateCompleterModel(G4String aCmd)
4055{
4056 QList<QStandardItem*> dirModelList;
4057 QList<QStandardItem*> commandModelList;
4058 QList<QStandardItem*> subDirModelList;
4059 QList<QStandardItem*> subCommandModelList;
4060
4061 G4String strtmp;
4062 G4int nMatch = 0;
4063
4064 G4String pName = aCmd;
4065 G4String remainingPath = aCmd;
4066 G4String empty = "";
4067 G4String matchingPath = empty;
4068
4069 // find the tree
4070 auto jpre = pName.rfind('/');
4071 if (jpre != G4String::npos) pName.erase(jpre + 1);
4073 G4UIcommandTree* commandTreeTop = UI->GetTree();
4074 G4UIcommandTree* aTree = commandTreeTop->FindCommandTree(pName);
4075 if (aTree != nullptr) {
4076 G4int Ndir = aTree->GetTreeEntry();
4077 G4int Ncmd = aTree->GetCommandEntry();
4078
4079 // directory ...
4080 for (G4int idir = 1; idir <= Ndir; ++idir) {
4081 G4String fpdir = aTree->GetTree(idir)->GetPathName();
4082 // matching test
4083 if (fpdir.find(remainingPath, 0) == 0) {
4084 if (nMatch == 0) {
4085 matchingPath = fpdir;
4086 }
4087 else {
4088 matchingPath = aTree->GetFirstMatchedString(fpdir, matchingPath);
4089 }
4090 nMatch++;
4091
4092 // append to dir model list
4093 auto item1 = new QStandardItem(fpdir.data());
4094 QIcon i = QIcon(*fDirIcon);
4095 item1->setData(1); // dir
4096 item1->setIcon(QIcon(*fDirIcon));
4097 dirModelList.append(item1);
4098
4099 // Go recursively
4100 QStandardItemModel* subModel = CreateCompleterModel(fpdir.data());
4101 for (G4int a = 0; a < subModel->rowCount(); ++a) {
4102 // copy item (an item could only be part of one model
4103 auto tempItem = new QStandardItem(subModel->item(a)->text());
4104 tempItem->setIcon(subModel->item(a)->icon());
4105 tempItem->setToolTip(subModel->item(a)->toolTip());
4106 tempItem->setData(subModel->item(a)->data());
4107
4108 // dir
4109 if (tempItem->data() == 1) {
4110 subModel->item(a);
4111 subDirModelList.append(tempItem);
4112 }
4113 // command
4114 else if (tempItem->data() == 0) {
4115 subCommandModelList.append(tempItem);
4116 }
4117 }
4118 }
4119 }
4120
4121 // command ...
4122 G4int n_parameterEntry;
4123 G4String rangeString;
4124 G4int n_guidanceEntry;
4125 G4UIcommand* command;
4126 G4UIparameter* param;
4127 std::string tooltip;
4128 G4String params;
4129
4130 for (G4int icmd = 1; icmd <= Ncmd; ++icmd) {
4131 tooltip = "";
4132 params = " ";
4133 command = aTree->GetCommand(icmd);
4134 G4String longCommandName = aTree->GetPathName() + command->GetCommandName();
4135 rangeString = command->GetRange();
4136 n_guidanceEntry = (G4int)command->GetGuidanceEntries();
4137 n_parameterEntry = (G4int)command->GetParameterEntries();
4138
4139 // matching test
4140 if (longCommandName.find(remainingPath, 0) == 0) {
4141 if (nMatch == 0) {
4142 matchingPath = longCommandName + " ";
4143 }
4144 else {
4145 strtmp = longCommandName + " ";
4146 matchingPath = aTree->GetFirstMatchedString(matchingPath, strtmp);
4147 }
4148
4149 // guidance
4150 for (G4int i_thGuidance = 0; i_thGuidance < n_guidanceEntry; i_thGuidance++) {
4151 tooltip += std::string((command->GetGuidanceLine(i_thGuidance)).data());
4152 if (i_thGuidance < n_guidanceEntry - 1) {
4153 tooltip += "\n";
4154 }
4155 }
4156
4157 // parameters
4158 for (G4int a = 0; a < n_parameterEntry; a++) {
4159 param = command->GetParameter(a);
4160 if (param->IsOmittable()) {
4161 params += "[<" + param->GetParameterName() + ">] ";
4162 }
4163 else {
4164 params += "<" + param->GetParameterName() + "> ";
4165 }
4166 }
4167 nMatch++;
4168
4169 // Append to command model list
4170 auto item = new QStandardItem(G4String(longCommandName + params).data());
4171 item->setData(0); // command
4172 item->setIcon(QIcon(*fCommandIcon));
4173 item->setToolTip(tooltip.c_str());
4174
4175 commandModelList.append(item);
4176 }
4177 }
4178 }
4179
4180 auto model = new QStandardItemModel();
4181 // initialize the model
4182 model->setColumnCount(1);
4183
4184 // concat models
4185 for (auto a : dirModelList) {
4186 model->appendRow(a);
4187 }
4188 for (auto a : subDirModelList) {
4189 model->appendRow(a);
4190 }
4191 for (auto a : commandModelList) {
4192 model->appendRow(a);
4193 }
4194 for (auto a : subCommandModelList) {
4195 model->appendRow(a);
4196 }
4197
4198 return model;
4199}
4200
4201/***************************************************************************/
4202//
4203// SLOTS DEFINITIONS
4204//
4205/***************************************************************************/
4206
4207/** Called when user give "help" command.
4208 */
4209void G4UIQt::ShowHelpCallback() { TerminalHelp(""); }
4210
4211/** Called when user click on clear button. Clear the text Output area
4212 */
4213void G4UIQt::ClearButtonCallback()
4214{
4215 fCoutTBTextArea->clear();
4216 fG4OutputString.clear();
4217}
4218
4219/** Called when user exit session
4220 */
4221void G4UIQt::ExitSession() { SessionTerminate(); }
4222
4223void G4UIQt::ExitHelp() const {}
4224
4225/** Callback call when "click on a menu entry.<br>
4226 Send the associated command to geant4
4227*/
4228void G4UIQt::CommandEnteredCallback()
4229{
4230 // split by any new line character
4231 fCommandArea->setText(fCommandArea->text().trimmed());
4232#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
4233 QStringList list = fCommandArea->text().split(QRegularExpression("[\r\n]"),QString::SkipEmptyParts);
4234#else
4235 QStringList list = fCommandArea->text().split(QRegularExpression("[\r\n]"),Qt::SkipEmptyParts);
4236#endif
4237
4238 // Apply for all commands
4239 for (G4int a = 0; a < list.size(); ++a) {
4240 QString txt(list[a].trimmed());
4241 if (txt != "") {
4242 fHistoryTBTableList->addItem(txt);
4243 fHistoryTBTableList->clearSelection();
4244 fHistoryTBTableList->setCurrentItem(nullptr);
4245 fCommandArea->setText("");
4246 G4Qt* interactorManager = G4Qt::getInstance();
4247 if (interactorManager != nullptr) {
4248 interactorManager->FlushAndWaitExecution();
4249 }
4250
4251 G4String command = txt.toStdString().c_str();
4252 if (command.substr(0, 4) != "help") {
4253 ApplyShellCommand(command, exitSession, exitPause);
4254 }
4255 else {
4256 ActivateCommand(command);
4257 }
4258 }
4259 }
4260 // set the focus to the command line
4261 fCommandArea->setFocus();
4262
4263 // Rebuild help tree
4264 FillHelpTree();
4265
4266 // Rebuild command completion
4267 UpdateCommandCompleter();
4268
4269 if (exitSession) SessionTerminate();
4270}
4271
4272/** Callback when the text in the line edit is changed.
4273 When a newline is inserted, trigger the Activate Command
4274 on this text end set unchanged the end of the line after the newline.
4275 */
4276void G4UIQt::CommandEditedCallback(const QString&)
4277{
4278#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
4279 QStringList list = fCommandArea->text().split(QRegularExpression("[\r\n]"), QString::SkipEmptyParts);
4280#else
4281 QStringList list = fCommandArea->text().split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts);
4282#endif
4283
4284 if (list.size() > 1) { // trigger ActivateCommand
4285 for (G4int a = 0; a < list.size() - 1; ++a) {
4286 // set only the first part
4287 fCommandArea->setText(list[a]);
4288 // trigger callback
4289 CommandEnteredCallback();
4290 }
4291 // reset unfinished command
4292 fCommandArea->setText(list[list.size() - 1]);
4293 }
4294}
4295
4296/** Callback when one of the scene/vis parameters has changed
4297 */
4298void G4UIQt::VisParameterCallback(QWidget* widget)
4299{
4300 if (widget == nullptr) {
4301 return;
4302 }
4303
4304 // Look in all the Grid layout, but only column 1 (0 is the parameter name)
4305 auto grid = dynamic_cast<QGridLayout*>(widget->layout());
4306 if (grid == nullptr) {
4307 return;
4308 }
4309 QString command;
4310 QWidget* name = grid->itemAtPosition(grid->rowCount() - 1, 0)->widget();
4311 if (dynamic_cast<QLabel*>(name) == nullptr) {
4312 return;
4313 }
4314 command += (dynamic_cast<QLabel*>(name))->text() + " ";
4315
4316 for (G4int a = 0; a < grid->rowCount() - 1; ++a) {
4317 QWidget* widgetTmp = grid->itemAtPosition(a, 1)->widget();
4318
4319 // 4 kind of widgets : QLineEdit / QComboBox / radioButtonsGroup / QPushButton (color chooser)
4320 if (widgetTmp != nullptr) {
4321 if (dynamic_cast<QLineEdit*>(widgetTmp) != nullptr) {
4322 command += (dynamic_cast<QLineEdit*>(widgetTmp))->text() + " ";
4323 }
4324 else if (dynamic_cast<QComboBox*>(widgetTmp) != nullptr) {
4325 command += (dynamic_cast<QComboBox*>(widgetTmp))
4326 ->itemText((dynamic_cast<QComboBox*>(widgetTmp))->currentIndex()) +
4327 " ";
4328
4329 // Color chooser
4330 }
4331 else if (dynamic_cast<QPushButton*>(widgetTmp) != nullptr) {
4332 command += widgetTmp->accessibleName() + " ";
4333
4334 // Check for Button group
4335 }
4336 else if (dynamic_cast<QWidget*>(widgetTmp) != nullptr) {
4337 if (widgetTmp->layout()->count() > 0) {
4338 if (dynamic_cast<QRadioButton*>(widgetTmp->layout()->itemAt(0)->widget()) != nullptr) {
4339 QAbstractButton* checked =
4340 (dynamic_cast<QRadioButton*>(widgetTmp->layout()->itemAt(0)->widget()))
4341 ->group()
4342 ->checkedButton();
4343 if (checked != nullptr) {
4344 command += (dynamic_cast<QRadioButton*>(widgetTmp->layout()->itemAt(0)->widget()))
4345 ->group()
4346 ->checkedButton()
4347 ->text() +
4348 " ";
4349 }
4350 }
4351 }
4352 }
4353 }
4354 }
4355 if (command != "") {
4357 if (UI != nullptr) {
4358 UI->ApplyCommand(command.toStdString().c_str());
4359 }
4360 }
4361}
4362
4363/** Callback call when "enter" clicked on the command zone.<br>
4364 If command has no parameters :send the command to geant4
4365 Else, open a dialog for parameters input
4366 @param aCommand
4367*/
4368void G4UIQt::ButtonCallback(const QString& aCommand)
4369{
4370 G4String ss = G4StrUtil::lstrip_copy(G4String(aCommand.toStdString().c_str()));
4371
4373 if (UI == nullptr) return;
4374 G4UIcommandTree* treeTop = UI->GetTree();
4375
4376 G4UIcommand* command = treeTop->FindPath(ss);
4377
4378 if (command != nullptr) {
4379 // if is GUI, then open a dialog
4380 if (IsGUICommand(command)) {
4381 auto menuParameterDialog = new QDialog();
4382
4383 if (CreateVisCommandGroupAndToolBox(command, menuParameterDialog, 1, true)) {
4384 menuParameterDialog->setWindowTitle(aCommand);
4385 menuParameterDialog->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
4386
4387 // exec this dialog, apply the command automaticaly, and return
4388 menuParameterDialog->exec();
4389 return;
4390 }
4391 delete menuParameterDialog;
4392 }
4393 }
4394
4395 ApplyShellCommand(ss, exitSession, exitPause);
4396
4397 // Rebuild help tree
4398 FillHelpTree();
4399
4400 if (exitSession) SessionTerminate();
4401}
4402
4403/** This callback is activated when user selected a item in the help tree
4404 */
4405void G4UIQt::HelpTreeClicCallback()
4406{
4407 QTreeWidgetItem* item = nullptr;
4408 if (fHelpTreeWidget == nullptr) return;
4409
4410 QList<QTreeWidgetItem*> list = fHelpTreeWidget->selectedItems();
4411 if (list.isEmpty()) return;
4412 item = list.first();
4413 if (item == nullptr) return;
4414
4416 if (UI == nullptr) return;
4417 G4UIcommandTree* treeTop = UI->GetTree();
4418
4419 std::string itemText = GetLongCommandPath(item).toStdString();
4420
4421 // check if it is a command path
4422 if (item->childCount() > 0) {
4423 itemText += "/";
4424 }
4425 G4UIcommand* command = treeTop->FindPath(itemText.c_str());
4426
4427 if (command != nullptr) {
4428 updateHelpArea(command);
4429 }
4430 else { // this is a command
4431 G4UIcommandTree* path = treeTop->FindCommandTree(itemText.c_str());
4432 if (path != nullptr) {
4433 // this is not a command, this is a sub directory
4434 // We display the Title
4435 fParameterHelpLabel->setVisible(true);
4436 fParameterHelpLabel->setText(path->GetTitle().data());
4437 fParameterHelpTable->setVisible(false);
4438 }
4439 }
4440}
4441
4442/** This callback is activated when user double clic on a item in the help tree
4443 */
4444void G4UIQt::HelpTreeDoubleClicCallback()
4445{
4446 HelpTreeClicCallback();
4447
4448 QTreeWidgetItem* item = nullptr;
4449 if (fHelpTreeWidget == nullptr) return;
4450
4451 QList<QTreeWidgetItem*> list = fHelpTreeWidget->selectedItems();
4452 if (list.isEmpty()) return;
4453 item = list.first();
4454 if (item == nullptr) return;
4455
4456 fCommandArea->clear();
4457 fCommandArea->setText(GetLongCommandPath(item));
4458}
4459
4460/** Callback called when user select an old command in the command history<br>
4461 Give it to the command area.
4462*/
4463void G4UIQt::CommandHistoryCallback()
4464{
4465 QListWidgetItem* item = nullptr;
4466 if (fHistoryTBTableList == nullptr) return;
4467
4468 QList<QListWidgetItem*> list = fHistoryTBTableList->selectedItems();
4469 if (list.isEmpty()) return;
4470 item = list.first();
4471 if (item == nullptr) return;
4472 fCommandArea->setText(item->text());
4473}
4474
4475void G4UIQt::ThreadComboBoxCallback(int) { CoutFilterCallback(""); }
4476
4477void G4UIQt::CoutFilterCallback(const QString&)
4478{
4479 FilterAllOutputTextArea();
4480
4481 fCoutTBTextArea->repaint();
4482 fCoutTBTextArea->verticalScrollBar()->setSliderPosition(
4483 fCoutTBTextArea->verticalScrollBar()->maximum());
4484}
4485
4486void G4UIQt::SaveOutputCallback()
4487{
4488 QString fileName = QFileDialog::getSaveFileName(
4489 fMainWindow, "Save console output as...", fLastOpenPath, "Save output as...");
4490 if (fileName != "") {
4491 QFile data(fileName);
4492 if (data.open(QFile::WriteOnly | QFile::Truncate)) {
4493 QTextStream out(&data);
4494 out << fCoutTBTextArea->toPlainText();
4495 out.flush();
4496 }
4497 data.close();
4498 }
4499}
4500
4501QString G4UIQt::FilterOutput(
4502 const G4UIOutputString& output, const QString& currentThread, const QString& filter)
4503{
4504#ifdef G4MULTITHREADED
4505 if ((currentThread == "All") || (currentThread == output.fThread)) {
4506#else
4507 if (currentThread == "") {
4508#endif
4509 if (output.fText.contains(QRegularExpression(filter))) {
4510 return output.fText;
4511 }
4512 }
4513 return "";
4514}
4515
4516void G4UIQt::FilterAllOutputTextArea()
4517{
4518 QString currentThread = "";
4519#ifdef G4MULTITHREADED
4520 currentThread = fThreadsFilterComboBox->currentText();
4521 if (currentThread == "Master") {
4522 currentThread = "";
4523 }
4524#endif
4525 QString filter = fCoutFilter->text();
4526 G4String previousOutputStream = "";
4527
4528 QString pref = "";
4529 QString post = "";
4530
4531 fCoutTBTextArea->clear();
4532
4533 for (auto& out : fG4OutputString) {
4534 if (FilterOutput(out, currentThread, filter) != "") {
4535 // changing color ?
4536 if (out.fOutputStream != previousOutputStream) {
4537 previousOutputStream = out.fOutputStream;
4538 if (out.fOutputStream == "info") {
4539 pref = "";
4540 post = "";
4541 }
4542 else if (out.fOutputStream == "warning") {
4543 pref = "<font color=\"DarkYellow\">";
4544 post = "</font>";
4545 }
4546 else {
4547 pref = "<font color=\"Red\">";
4548 post = "</font>";
4549 }
4550 }
4551 fCoutTBTextArea->append(pref + out.fText + post);
4552 }
4553 }
4554}
4555
4556/** Callback called when user give a new string to look for<br>
4557 Display a list of matching commands descriptions. If no string is set,
4558 will display the complete help tree
4559*/
4560void G4UIQt::LookForHelpStringCallback()
4561{
4562 fHelpLine->setText(fHelpLine->text().trimmed());
4563 QString searchText = fHelpLine->text();
4564
4565 fParameterHelpLabel->setText("");
4566 fParameterHelpTable->setVisible(false);
4567 if (searchText == "") {
4568 // clear old help tree
4569 fHelpTreeWidget->clear();
4570
4571 FillHelpTree();
4572
4573 return;
4574 }
4575 OpenHelpTreeOnCommand(searchText);
4576}
4577
4578void G4UIQt::OpenHelpTreeOnCommand(const QString& searchText)
4579{
4580 // the help tree
4582 if (UI == nullptr) return;
4583 G4UIcommandTree* treeTop = UI->GetTree();
4584
4585 G4int treeSize = treeTop->GetTreeEntry();
4586
4587 // clear old help tree
4588 fHelpTreeWidget->clear();
4589
4590 // look for new items
4591
4592 int tmp = 0;
4593
4594#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
4595 // Before Qt5.15
4596 QMap<G4int, QString> commandResultMap;
4597 QMap<G4int, QString> commandChildResultMap;
4598 for (G4int a = 0; a < treeSize; ++a) {
4599 G4UIcommand* command = treeTop->FindPath(treeTop->GetTree(a + 1)->GetPathName().data());
4600 tmp = GetCommandList(command).count(searchText, Qt::CaseInsensitive);
4601 if (tmp > 0) {
4602 commandResultMap.insertMulti(
4603 tmp, QString((char*)(treeTop->GetTree(a + 1)->GetPathName()).data()));
4604 }
4605 // look for childs
4606 commandChildResultMap = LookForHelpStringInChildTree(treeTop->GetTree(a + 1), searchText);
4607 // insert new childs
4608 if (! commandChildResultMap.empty()) {
4609 QMap<int, QString>::const_iterator i = commandChildResultMap.constBegin();
4610 while (i != commandChildResultMap.constEnd()) {
4611 commandResultMap.insertMulti(i.key(), i.value());
4612 i++;
4613 }
4614 commandChildResultMap.clear();
4615 }
4616 }
4617#else
4618 // Qt5.15 and beyond
4619 QMultiMap<G4int, QString> commandResultMap;
4620 QMultiMap<G4int, QString> commandChildResultMap;
4621 for (G4int a = 0; a < treeSize; ++a) {
4622 G4UIcommand* command = treeTop->FindPath(treeTop->GetTree(a + 1)->GetPathName().data());
4623 tmp = (int)GetCommandList(command).count(searchText, Qt::CaseInsensitive);
4624 if (tmp > 0) {
4625 commandResultMap.insert(tmp, QString((char*)(treeTop->GetTree(a + 1)->GetPathName()).data()));
4626 }
4627 // look for childs
4628 commandChildResultMap = LookForHelpStringInChildTree(treeTop->GetTree(a + 1), searchText);
4629 // insert new childs
4630 if (! commandChildResultMap.empty()) {
4631 auto i = commandChildResultMap.constBegin();
4632 while (i != commandChildResultMap.constEnd()) {
4633 commandResultMap.insert(i.key(), i.value());
4634 ++i;
4635 }
4636 commandChildResultMap.clear();
4637 }
4638 }
4639#endif
4640
4641 // build new help tree
4642 fHelpTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection);
4643 fHelpTreeWidget->setColumnCount(2);
4644 QStringList labels;
4645 labels << QString("Command") << QString("Match");
4646 fHelpTreeWidget->setHeaderLabels(labels);
4647
4648 if (commandResultMap.empty()) {
4649 fParameterHelpLabel->setText("No match found");
4650 fParameterHelpTable->setVisible(false);
4651 return;
4652 }
4653
4654 auto i = commandResultMap.constEnd();
4655 i--;
4656 // 10 maximum progress values
4657 G4float multValue = 10.0 / (G4float)(i.key());
4658 QString progressChar = "|";
4659 QString progressStr = "|";
4660
4661 QTreeWidgetItem* newItem;
4662 G4bool end = false;
4663 while (! end) {
4664 if (i == commandResultMap.constBegin()) {
4665 end = true;
4666 }
4667 for (G4int a = 0; a < G4int(i.key() * multValue); ++a) {
4668 progressStr += progressChar;
4669 }
4670 newItem = new QTreeWidgetItem();
4671 QString commandStr = i.value().trimmed();
4672
4673 if (commandStr.indexOf("/") == 0) {
4674 commandStr = commandStr.right(commandStr.size() - 1);
4675 }
4676
4677 newItem->setText(0, commandStr);
4678 newItem->setText(1, progressStr);
4679 fHelpTreeWidget->addTopLevelItem(newItem);
4680 newItem->setForeground(1, QBrush(Qt::blue));
4681 progressStr = "|";
4682 i--;
4683 }
4684 fHelpTreeWidget->resizeColumnToContents(0);
4685 fHelpTreeWidget->sortItems(1, Qt::DescendingOrder);
4686 // fHelpTreeWidget->setColumnWidth(1,10);//resizeColumnToContents (1);
4687}
4688
4689#if (QT_VERSION < QT_VERSION_CHECK(5, 15, 0))
4690// Before Qt5.15
4691QMap<G4int, QString> G4UIQt::LookForHelpStringInChildTree(
4692 G4UIcommandTree* aCommandTree, const QString& text)
4693{
4694 QMap<G4int, QString> commandResultMap;
4695 if (aCommandTree == NULL) return commandResultMap;
4696 // Get the Sub directories
4697 G4int tmp = 0;
4698 QMap<G4int, QString> commandChildResultMap;
4699 for (G4int a = 0; a < aCommandTree->GetTreeEntry(); ++a) {
4700 const G4UIcommand* command = aCommandTree->GetGuidance();
4701 tmp = GetCommandList(command).count(text, Qt::CaseInsensitive);
4702 if (tmp > 0) {
4703 commandResultMap.insertMulti(
4704 tmp, QString((char*)(aCommandTree->GetTree(a + 1)->GetPathName()).data()));
4705 }
4706 // look for childs
4707 commandChildResultMap = LookForHelpStringInChildTree(aCommandTree->GetTree(a + 1), text);
4708 if (! commandChildResultMap.empty()) {
4709 // insert new childs
4710 QMap<G4int, QString>::const_iterator i = commandChildResultMap.constBegin();
4711 while (i != commandChildResultMap.constEnd()) {
4712 commandResultMap.insertMulti(i.key(), i.value());
4713 ++i;
4714 }
4715 commandChildResultMap.clear();
4716 }
4717 }
4718 // Get the Commands
4719 for (G4int a = 0; a < aCommandTree->GetCommandEntry(); ++a) {
4720 const G4UIcommand* command = aCommandTree->GetCommand(a + 1);
4721 tmp = GetCommandList(command).count(text, Qt::CaseInsensitive);
4722 if (tmp > 0) {
4723 commandResultMap.insertMulti(
4724 tmp, QString((char*)(aCommandTree->GetCommand(a + 1)->GetCommandPath()).data()));
4725 }
4726 }
4727 return commandResultMap;
4728}
4729#else
4730// Qt5.15 and beyond
4731QMultiMap<G4int, QString> G4UIQt::LookForHelpStringInChildTree(
4732 G4UIcommandTree* aCommandTree, const QString& text)
4733{
4734 QMultiMap<G4int, QString> commandResultMap;
4735 if (aCommandTree == nullptr) return commandResultMap;
4736 // Get the Sub directories
4737 G4int tmp = 0;
4738 QMultiMap<G4int, QString> commandChildResultMap;
4739 for (G4int a = 0; a < aCommandTree->GetTreeEntry(); ++a) {
4740 const G4UIcommand* command = aCommandTree->GetGuidance();
4741 tmp = (int)GetCommandList(command).count(text, Qt::CaseInsensitive);
4742 if (tmp > 0) {
4743 commandResultMap.insert(
4744 tmp, QString((char*)(aCommandTree->GetTree(a + 1)->GetPathName()).data()));
4745 }
4746 // look for childs
4747 commandChildResultMap = LookForHelpStringInChildTree(aCommandTree->GetTree(a + 1), text);
4748 if (! commandChildResultMap.empty()) {
4749 // insert new childs
4750 auto i = commandChildResultMap.constBegin();
4751 while (i != commandChildResultMap.constEnd()) {
4752 commandResultMap.insert(i.key(), i.value());
4753 ++i;
4754 }
4755 commandChildResultMap.clear();
4756 }
4757 }
4758 // Get the Commands
4759 for (G4int a = 0; a < aCommandTree->GetCommandEntry(); ++a) {
4760 const G4UIcommand* command = aCommandTree->GetCommand(a + 1);
4761 tmp = (int)GetCommandList(command).count(text, Qt::CaseInsensitive);
4762 if (tmp > 0) {
4763 commandResultMap.insert(
4764 tmp, QString((char*)(aCommandTree->GetCommand(a + 1)->GetCommandPath()).data()));
4765 }
4766 }
4767 return commandResultMap;
4768}
4769#endif
4770
4771QString G4UIQt::GetShortCommandPath(QString commandPath)
4772{
4773 if (commandPath.indexOf("/") == 0) {
4774 commandPath = commandPath.right(commandPath.size() - 1);
4775 }
4776
4777 commandPath = commandPath.right(commandPath.size() - commandPath.lastIndexOf("/", -2) - 1);
4778
4779 if (commandPath.lastIndexOf("/") == (commandPath.size() - 1)) {
4780 commandPath = commandPath.left(commandPath.size() - 1);
4781 }
4782
4783 return commandPath;
4784}
4785
4786QString G4UIQt::GetLongCommandPath(QTreeWidgetItem* item)
4787{
4788 if (item == nullptr) return "";
4789
4790 // rebuild path:
4791 QString itemText = "";
4792 itemText = item->text(0);
4793
4794 while (item->parent() != nullptr) {
4795 itemText = item->parent()->text(0) + "/" + itemText;
4796 item = item->parent();
4797 }
4798 itemText = "/" + itemText;
4799
4800 return itemText;
4801}
4802
4803void G4UIQt::ChangeColorCallback(QWidget* widget)
4804{
4805 if (widget == nullptr) {
4806 return;
4807 }
4808
4809 auto button = dynamic_cast<QPushButton*>(widget);
4810 if (button == nullptr) {
4811 return;
4812 }
4813 QString value = button->accessibleName();
4814
4815 QColor old;
4816 old.setRgbF(value.section(" ", 0, 1).toDouble(), value.section(" ", 1, 2).toDouble(),
4817 value.section(" ", 2, 3).toDouble());
4818 QColor color =
4819 QColorDialog::getColor(old, fUITabWidget, "Change color", QColorDialog::ShowAlphaChannel);
4820
4821 if (color.isValid()) {
4822 // rebuild the widget icon
4823 QPixmap pixmap = QPixmap(QSize(16, 16));
4824 pixmap.fill(color);
4825 QPainter painter(&pixmap);
4826 painter.setPen(Qt::black);
4827 painter.drawRect(0, 0, 15, 15); // Draw contour
4828
4829 button->setAccessibleName(QString::number(color.redF()) + " " +
4830 QString::number(color.greenF()) + " " +
4831 QString::number(color.blueF()) + " ");
4832 button->setIcon(pixmap);
4833 }
4834}
4835
4836void G4UIQt::ChangeCursorAction(const QString& action)
4837{
4838 // Theses actions should be in the app toolbar
4839
4840 fMoveSelected = true;
4841 fPickSelected = true;
4842 fRotateSelected = true;
4843 fZoomInSelected = true;
4844 fZoomOutSelected = true;
4845
4846 if (fToolbarApp == nullptr) return;
4847 QList<QAction*> list = fToolbarApp->actions();
4848 for (auto i : list) {
4849 if (i->data().toString() == action) {
4850 i->setChecked(true);
4851 if (i->data().toString() == "pick") {
4852 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/picking true");
4853 CreatePickInfosDialog();
4854
4855 fPickInfosDialog->show();
4856 fPickInfosDialog->raise();
4857 fPickInfosDialog->activateWindow();
4858 }
4859 }
4860 else if (i->data().toString() == "move") {
4861 fMoveSelected = false;
4862 i->setChecked(false);
4863 }
4864 else if (i->data().toString() == "pick") {
4865 fPickSelected = false;
4866 i->setChecked(false);
4867 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/picking false");
4868 if (fPickInfosDialog != nullptr) {
4869 fPickInfosDialog->hide();
4870 }
4871 }
4872 else if (i->data().toString() == "rotate") {
4873 fRotateSelected = false;
4874 i->setChecked(false);
4875 }
4876 else if (i->data().toString() == "zoom_in") {
4877 fZoomInSelected = false;
4878 i->setChecked(false);
4879 }
4880 else if (i->data().toString() == "zoom_out") {
4881 fZoomOutSelected = false;
4882 i->setChecked(false);
4883 }
4884 }
4885 // FIXME : Should connect this to Vis
4886}
4887
4888/* A little bit like "void G4OpenGLQtViewer::toggleDrawingAction(int aAction)"
4889 But for all viewers, not only Qt
4890
4891FIXME : Should be a feedback when changing viewer !
4892
4893 */
4894void G4UIQt::ChangeSurfaceStyle(const QString& action)
4895{
4896 // Theses actions should be in the app toolbar
4897
4898 if (fToolbarApp == nullptr) return;
4899 QList<QAction*> list = fToolbarApp->actions();
4900 for (auto i : list) {
4901 if (i->data().toString() == action) {
4902 i->setChecked(true);
4903 }
4904 else if (i->data().toString() == "hidden_line_removal") {
4905 i->setChecked(false);
4906 }
4907 else if (i->data().toString() == "hidden_line_and_surface_removal") {
4908 i->setChecked(false);
4909 }
4910 else if (i->data().toString() == "solid") {
4911 i->setChecked(false);
4912 }
4913 else if (i->data().toString() == "wireframe") {
4914 i->setChecked(false);
4915 }
4916 }
4917 // FIXME : Should connect this to Vis
4918
4919 if (action == "hidden_line_removal") {
4920 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/style w");
4921 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/hiddenEdge 1");
4922 }
4923 else if (action == "hidden_line_and_surface_removal") {
4924 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/style s");
4925 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/hiddenEdge 1");
4926 }
4927 else if (action == "solid") {
4928 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/style s");
4929 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/hiddenEdge 0");
4930 }
4931 else if (action == "wireframe") {
4932 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/style w");
4933 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/hiddenEdge 0");
4934 }
4935}
4936
4937void G4UIQt::OpenIconCallback(const QString& aParam)
4938{
4939 QString aCommand = aParam.left(aParam.indexOf(fStringSeparator));
4940 QString aLabel = aParam.mid(aParam.indexOf(fStringSeparator) + fStringSeparator.length());
4941
4942 QString nomFich = QFileDialog::getOpenFileName(fMainWindow, aLabel, fLastOpenPath,
4943 "Macro files (*.mac);;Geant4 files( *.mac *.g4* *.in);;All (*.*)");
4944 if (nomFich != "") {
4946 (QString(aCommand) + QString(" ") + nomFich).toStdString().c_str());
4947 QDir dir;
4948 fLastOpenPath = dir.absoluteFilePath(nomFich);
4949 }
4950}
4951
4952void G4UIQt::SaveIconCallback(const QString& aParam)
4953{
4954 QString aCommand = aParam.left(aParam.indexOf(fStringSeparator));
4955 QString aLabel = aParam.mid(aParam.indexOf(fStringSeparator) + fStringSeparator.length());
4956
4957 QString nomFich =
4958 QFileDialog::getSaveFileName(fMainWindow, aLabel, fLastOpenPath, "Macro files (*.mac)");
4959 if (nomFich != "") {
4961 (QString(aCommand) + QString(" ") + nomFich).toStdString().c_str());
4962 QDir dir;
4963 fLastOpenPath = dir.absoluteFilePath(nomFich);
4964 }
4965}
4966
4967void G4UIQt::CreateViewerPropertiesDialog()
4968{
4969 if (fViewerPropertiesDialog != nullptr) {
4970 return;
4971 }
4972 fViewerPropertiesDialog = new QDialog();
4973
4974 fViewerPropertiesDialog->setWindowTitle("Viewer properties");
4975 fViewerPropertiesDialog->setSizePolicy(
4976 QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
4977
4978 if (fViewerPropertiesWidget == nullptr) {
4979 fViewerPropertiesWidget = new QWidget();
4980 auto layoutPropertiesWidget = new QVBoxLayout();
4981 fViewerPropertiesWidget->setLayout(layoutPropertiesWidget);
4982
4983 CreateEmptyViewerPropertiesWidget();
4984 }
4985
4986 auto layoutDialog = new QVBoxLayout();
4987
4988 layoutDialog->addWidget(fViewerPropertiesWidget);
4989 layoutDialog->setContentsMargins(0, 0, 0, 0);
4990 fViewerPropertiesDialog->setLayout(layoutDialog);
4991}
4992
4993void G4UIQt::CreatePickInfosDialog()
4994{
4995 if (fPickInfosDialog != nullptr) {
4996 return;
4997 }
4998 fPickInfosDialog = new QDialog();
4999
5000 fPickInfosDialog->setWindowTitle("Pick infos");
5001 fPickInfosDialog->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
5002
5003 if (fPickInfosWidget == nullptr) {
5004 fPickInfosWidget = new QWidget();
5005 auto layoutPickInfos = new QVBoxLayout();
5006 fPickInfosWidget->setLayout(layoutPickInfos);
5007
5008 CreateEmptyPickInfosWidget();
5009 }
5010
5011 auto layoutDialog = new QVBoxLayout();
5012
5013 layoutDialog->addWidget(fPickInfosWidget);
5014 layoutDialog->setContentsMargins(0, 0, 0, 0);
5015 fPickInfosDialog->setLayout(layoutDialog);
5016 fPickInfosDialog->setWindowFlags(Qt::WindowStaysOnTopHint);
5017}
5018
5019void G4UIQt::CreateEmptyViewerPropertiesWidget()
5020{
5021 if (fViewerPropertiesWidget == nullptr) return;
5022 if (fViewerPropertiesWidget->layout() == nullptr) return;
5023 QLayoutItem* wItem;
5024 if (fViewerPropertiesWidget->layout()->count() != 0) {
5025 while ((wItem = fViewerPropertiesWidget->layout()->takeAt(0)) != nullptr) {
5026 delete wItem->widget();
5027 delete wItem;
5028 }
5029 }
5030 // Add empty one
5031 auto label = new QLabel("No viewer - Please open a viewer first");
5032 fViewerPropertiesWidget->layout()->addWidget(label);
5033 fViewerPropertiesDialog->setWindowTitle("No viewer");
5034 fViewerPropertiesDialog->setVisible(false);
5035}
5036
5037void G4UIQt::CreateEmptyPickInfosWidget()
5038{
5039 QLayoutItem* wItem;
5040 if (fPickInfosWidget->layout()->count() != 0) {
5041 while ((wItem = fPickInfosWidget->layout()->takeAt(0)) != nullptr) {
5042 delete wItem->widget();
5043 delete wItem;
5044 }
5045 }
5046 // Add empty one
5047 auto label = new QLabel("Click on the object you want to pick");
5048 fPickInfosWidget->layout()->addWidget(label);
5049 fPickInfosDialog->setWindowTitle("Nothing to pick");
5050}
5051
5052void G4UIQt::ViewerPropertiesIconCallback(int)
5053{
5054 CreateViewerPropertiesDialog();
5055
5056 fViewerPropertiesDialog->show();
5057 fViewerPropertiesDialog->raise();
5058 fViewerPropertiesDialog->activateWindow();
5059}
5060
5061void G4UIQt::ChangePerspectiveOrtho(const QString& action)
5062{
5063 // Theses actions should be in the app toolbar
5064
5065 if (fToolbarApp == nullptr) return;
5066 QList<QAction*> list = fToolbarApp->actions();
5067 QString checked = "";
5068 for (auto i : list) {
5069 if (i->data().toString() == action) {
5070 i->setChecked(true);
5071 checked = i->data().toString();
5072 }
5073 else if (i->data().toString() == "perspective") {
5074 i->setChecked(false);
5075 }
5076 else if (i->data().toString() == "ortho") {
5077 i->setChecked(false);
5078 }
5079 }
5080
5081 if ((action == "ortho") && (checked == "ortho")) {
5082 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/projection o");
5083 }
5084 else if ((action == "perspective") && (checked == "perspective")) {
5085 G4UImanager::GetUIpointer()->ApplyCommand("/vis/viewer/set/projection p");
5086 }
5087}
5088
5090{
5091 // Theses actions should be in the app toolbar
5092 fMoveSelected = true;
5093 fRotateSelected = false;
5094 fPickSelected = false;
5095 fZoomInSelected = false;
5096 fZoomOutSelected = false;
5097
5098 if (fToolbarApp == nullptr) return;
5099 QList<QAction*> list = fToolbarApp->actions();
5100 for (auto i : list) {
5101 if (i->data().toString() == "move") {
5102 i->setChecked(true);
5103 }
5104 else if (i->data().toString() == "rotate") {
5105 i->setChecked(false);
5106 }
5107 else if (i->data().toString() == "pick") {
5108 i->setChecked(false);
5109 }
5110 else if (i->data().toString() == "zoom_in") {
5111 i->setChecked(false);
5112 }
5113 else if (i->data().toString() == "zoom_out") {
5114 i->setChecked(false);
5115 }
5116 }
5117}
5118
5120{
5121 // Theses actions should be in the app toolbar
5122 fRotateSelected = true;
5123 fMoveSelected = false;
5124 fPickSelected = false;
5125 fZoomInSelected = false;
5126 fZoomOutSelected = false;
5127
5128 if (fToolbarApp == nullptr) return;
5129 QList<QAction*> list = fToolbarApp->actions();
5130 for (auto i : list) {
5131 if (i->data().toString() == "rotate") {
5132 i->setChecked(true);
5133 }
5134 else if (i->data().toString() == "move") {
5135 i->setChecked(false);
5136 }
5137 else if (i->data().toString() == "pick") {
5138 i->setChecked(false);
5139 }
5140 else if (i->data().toString() == "zoom_in") {
5141 i->setChecked(false);
5142 }
5143 else if (i->data().toString() == "zoom_out") {
5144 i->setChecked(false);
5145 }
5146 }
5147}
5148
5150{
5151 // Theses actions should be in the app toolbar
5152 fPickSelected = true;
5153 fMoveSelected = false;
5154 fRotateSelected = false;
5155 fZoomInSelected = false;
5156 fZoomOutSelected = false;
5157
5158 QToolBar* bar = fToolbarApp;
5159 if (! fDefaultIcons) {
5160 bar = fToolbarUser;
5161 }
5162 if (bar == nullptr) return;
5163
5164 QList<QAction*> list = bar->actions();
5165 for (auto i : list) {
5166 if (i->data().toString() == "pick") {
5167 i->setChecked(true);
5168 }
5169 else if (i->data().toString() == "move") {
5170 i->setChecked(false);
5171 }
5172 else if (i->data().toString() == "rotate") {
5173 i->setChecked(false);
5174 }
5175 else if (i->data().toString() == "zoom_in") {
5176 i->setChecked(false);
5177 }
5178 else if (i->data().toString() == "zoom_out") {
5179 i->setChecked(false);
5180 }
5181 }
5182}
5183
5185{
5186 // Theses actions should be in the app toolbar
5187 fZoomInSelected = true;
5188 fMoveSelected = false;
5189 fRotateSelected = false;
5190 fPickSelected = false;
5191 fZoomOutSelected = false;
5192
5193 QToolBar* bar = fToolbarApp;
5194 if (! fDefaultIcons) {
5195 bar = fToolbarUser;
5196 }
5197 if (bar == nullptr) return;
5198
5199 QList<QAction*> list = bar->actions();
5200 for (auto i : list) {
5201 if (i->data().toString() == "zoom_in") {
5202 i->setChecked(true);
5203 }
5204 else if (i->data().toString() == "move") {
5205 i->setChecked(false);
5206 }
5207 else if (i->data().toString() == "rotate") {
5208 i->setChecked(false);
5209 }
5210 else if (i->data().toString() == "pick") {
5211 i->setChecked(false);
5212 }
5213 else if (i->data().toString() == "zoom_out") {
5214 i->setChecked(false);
5215 }
5216 }
5217}
5218
5220{
5221 // Theses actions should be in the app toolbar
5222 fZoomOutSelected = true;
5223 fMoveSelected = false;
5224 fRotateSelected = false;
5225 fPickSelected = false;
5226 fZoomInSelected = false;
5227
5228 QToolBar* bar = fToolbarApp;
5229 if (! fDefaultIcons) {
5230 bar = fToolbarUser;
5231 }
5232 if (bar == nullptr) return;
5233
5234 QList<QAction*> list = bar->actions();
5235 for (auto i : list) {
5236 if (i->data().toString() == "zoom_out") {
5237 i->setChecked(true);
5238 }
5239 else if (i->data().toString() == "move") {
5240 i->setChecked(false);
5241 }
5242 else if (i->data().toString() == "rotate") {
5243 i->setChecked(false);
5244 }
5245 else if (i->data().toString() == "pick") {
5246 i->setChecked(false);
5247 }
5248 else if (i->data().toString() == "zoom_in") {
5249 i->setChecked(false);
5250 }
5251 }
5252}
5253
5255{
5256 // Theses actions should be in the app toolbar
5257
5258 QToolBar* bar = fToolbarApp;
5259 if (! fDefaultIcons) {
5260 bar = fToolbarUser;
5261 }
5262 if (bar == nullptr) return;
5263
5264 QList<QAction*> list = bar->actions();
5265 for (auto i : list) {
5266 if (i->data().toString() == "solid") {
5267 i->setChecked(true);
5268 }
5269 else if (i->data().toString() == "hidden_line_removal") {
5270 i->setChecked(false);
5271 }
5272 else if (i->data().toString() == "hidden_line_and_surface_removal") {
5273 i->setChecked(false);
5274 }
5275 else if (i->data().toString() == "wireframe") {
5276 i->setChecked(false);
5277 }
5278 }
5279}
5280
5282{
5283 // Theses actions should be in the app toolbar
5284
5285 QToolBar* bar = fToolbarApp;
5286 if (! fDefaultIcons) {
5287 bar = fToolbarUser;
5288 }
5289 if (bar == nullptr) return;
5290
5291 QList<QAction*> list = bar->actions();
5292 for (auto i : list) {
5293 if (i->data().toString() == "wireframe") {
5294 i->setChecked(true);
5295 }
5296 else if (i->data().toString() == "hidden_line_removal") {
5297 i->setChecked(false);
5298 }
5299 else if (i->data().toString() == "hidden_line_and_surface_removal") {
5300 i->setChecked(false);
5301 }
5302 else if (i->data().toString() == "solid") {
5303 i->setChecked(false);
5304 }
5305 }
5306}
5307
5309{
5310 // Theses actions should be in the app toolbar
5311
5312 QToolBar* bar = fToolbarApp;
5313 if (! fDefaultIcons) {
5314 bar = fToolbarUser;
5315 }
5316 if (bar == nullptr) return;
5317
5318 QList<QAction*> list = bar->actions();
5319 for (auto i : list) {
5320 if (i->data().toString() == "hidden_line_removal") {
5321 i->setChecked(true);
5322 }
5323 else if (i->data().toString() == "solid") {
5324 i->setChecked(false);
5325 }
5326 else if (i->data().toString() == "hidden_line_and_surface_removal") {
5327 i->setChecked(false);
5328 }
5329 else if (i->data().toString() == "wireframe") {
5330 i->setChecked(false);
5331 }
5332 }
5333}
5334
5336{
5337 // Theses actions should be in the app toolbar
5338
5339 QToolBar* bar = fToolbarApp;
5340 if (! fDefaultIcons) {
5341 bar = fToolbarUser;
5342 }
5343
5344 if (bar == nullptr) return;
5345
5346 QList<QAction*> list = bar->actions();
5347 for (auto i : list) {
5348 if (i->data().toString() == "hidden_line_and_surface_removal") {
5349 i->setChecked(true);
5350 }
5351 else if (i->data().toString() == "solid") {
5352 i->setChecked(false);
5353 }
5354 else if (i->data().toString() == "hidden_line_removal") {
5355 i->setChecked(false);
5356 }
5357 else if (i->data().toString() == "wireframe") {
5358 i->setChecked(false);
5359 }
5360 }
5361}
5362
5364{
5365 // Theses actions should be in the app toolbar
5366
5367 QToolBar* bar = fToolbarApp;
5368 if (! fDefaultIcons) {
5369 bar = fToolbarUser;
5370 }
5371 if (bar == nullptr) return;
5372
5373 QList<QAction*> list = bar->actions();
5374 for (auto i : list) {
5375 if (i->data().toString() == "perspective") {
5376 i->setChecked(true);
5377 }
5378 else if (i->data().toString() == "ortho") {
5379 i->setChecked(false);
5380 }
5381 }
5382}
5383
5385{
5386 // Theses actions should be in the app toolbar
5387
5388 QToolBar* bar = fToolbarApp;
5389 if (! fDefaultIcons) {
5390 bar = fToolbarUser;
5391 }
5392
5393 if (bar == nullptr) return;
5394
5395 QList<QAction*> list = bar->actions();
5396 for (auto i : list) {
5397 if (i->data().toString() == "ortho") {
5398 i->setChecked(true);
5399 }
5400 else if (i->data().toString() == "perspective") {
5401 i->setChecked(false);
5402 }
5403 }
5404}
5405
5406G4QTabWidget::G4QTabWidget(QWidget* aParent, G4int sizeX, G4int sizeY)
5407 : QTabWidget(aParent),
5408 fTabSelected(false),
5409 fLastCreated(-1),
5410 fPreferedSizeX(sizeX + 6) // margin left+right
5411 ,
5412 fPreferedSizeY(sizeY + 58) // tab label height + margin left+right
5413{
5414 setMinimumSize(100, 100);
5415 QSizePolicy policy = QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
5416 setSizePolicy(policy);
5417}
5418
5420 : QTabWidget(), fTabSelected(false), fLastCreated(-1), fPreferedSizeX(0), fPreferedSizeY(0)
5421{}
5422
5423G4UIOutputString::G4UIOutputString(QString text, G4String origine, G4String outputStream)
5424 : fText(text), fThread(origine)
5425{
5426 if (! GetOutputList().contains(QString(" ") + outputStream + " ")) {
5427 fOutputStream = "info";
5428 }
5429 else {
5430 fOutputStream = outputStream;
5431 }
5432}
5433
5434
5435void G4UIQt::TabCloseCallback(int a)
5436{
5437 if (fViewerTabWidget == nullptr) return;
5438
5439 // get the address of the widget
5440 QWidget* temp = fViewerTabWidget->widget(a);
5441 // remove the tab
5442 fViewerTabWidget->removeTab(a);
5443
5444 // if last QWidget : Add empty string
5445 G4bool lastTab = true;
5446 for (G4int c = 0; c < fViewerTabWidget->count(); ++c) {
5447 if (fViewerTabWidget->tabText(c).contains("viewer")) {
5448 lastTab = false;
5449 }
5450 }
5451
5452 if (lastTab) {
5453 CreateEmptyViewerPropertiesWidget();
5454 }
5455 // delete the widget
5456 delete temp;
5457}
5458
5459void G4UIQt::ToolBoxActivated(int a)
5460{
5461 if (fUITabWidget->widget(a) == fHelpTBWidget) {
5462 // Rebuild the help tree
5463 FillHelpTree();
5464 }
5465 else if (fUITabWidget->widget(a) == fSceneTreeWidget) {
5466 fSceneTreeWidget->setVisible(true);
5467 }
5468}
5469
5471{
5472 if (currentWidget() != nullptr) {
5473 if (isTabSelected()) {
5474 // QCoreApplication::sendPostedEvents () ;
5475
5476 QString text = tabText(currentIndex());
5477
5478 if (fLastCreated == -1) {
5479 auto edit = dynamic_cast<QTextEdit*>(currentWidget());
5480 if (edit == nullptr) {
5481 QString paramSelect = QString("/vis/viewer/select ") + text;
5483 if (UI != nullptr) {
5484 UI->ApplyCommand(paramSelect.toStdString().c_str());
5485 }
5486 }
5487 }
5488 else {
5489 fLastCreated = -1;
5490 }
5491 setTabSelected(false);
5492 }
5493 }
5494}
5495
5496G4UIDockWidget::G4UIDockWidget(QString txt) : QDockWidget(txt) {}
5497
5498void G4UIDockWidget::closeEvent(QCloseEvent* aEvent)
5499{
5500 setFloating(false);
5501
5502 // prevent from closing
5503 aEvent->ignore();
5504 // hide them instead
5505 hide();
5506}
@ G4State_Quit
@ G4State_Abort
G4Colour G4Color
Definition G4Color.hh:41
#define G4MUTEX_INITIALIZER
std::mutex G4Mutex
float G4float
Definition G4Types.hh:84
bool G4bool
Definition G4Types.hh:86
int G4int
Definition G4Types.hh:85
void * G4Interactor
#define G4endl
Definition G4ios.hh:67
G4GLOB_DLL std::ostream G4cout
G4double GetBlue() const
Definition G4Colour.hh:154
G4double GetAlpha() const
Definition G4Colour.hh:155
G4double GetRed() const
Definition G4Colour.hh:152
G4double GetGreen() const
Definition G4Colour.hh:153
G4String GetFullPrefixString() const
G4String GetPrefixString() const
void setLastTabCreated(G4int a)
Definition G4UIQt.hh:89
void paintEvent(QPaintEvent *event) override
Definition G4UIQt.cc:5470
void setTabSelected(G4bool a)
Definition G4UIQt.hh:88
G4int fLastCreated
Definition G4UIQt.hh:92
bool isTabSelected()
Definition G4UIQt.hh:90
Definition G4Qt.hh:50
static G4Qt * getInstance()
Definition G4Qt.cc:51
void FlushAndWaitExecution() override
Definition G4Qt.cc:174
const G4String & GetDescription() const
const std::list< G4SceneTreeItem > & GetChildren() const
const G4String & GetPVPath() const
const std::map< G4String, G4AttDef > * GetAttDefs() const
std::vector< G4AttValue > * GetAttValues() const
static G4StateManager * GetStateManager()
void closeEvent(QCloseEvent *) override
Definition G4UIQt.cc:5498
G4UIDockWidget(QString txt)
Definition G4UIQt.cc:5496
G4String fOutputStream
Definition G4UIQt.hh:110
QString fText
Definition G4UIQt.hh:108
G4String fThread
Definition G4UIQt.hh:109
G4UIOutputString(QString text, G4String thread="", G4String outputstream="info")
Definition G4UIQt.cc:5423
QString GetOutputList()
Definition G4UIQt.hh:107
void SetIconPickSelected()
Definition G4UIQt.cc:5149
G4bool AddTabWidget(QWidget *, QString)
Definition G4UIQt.cc:2283
QWidget * GetViewerPropertiesWidget()
Definition G4UIQt.cc:2223
void SetIconOrthoSelected()
Definition G4UIQt.cc:5384
void UpdateSceneTree(const G4SceneTreeItem &) override
Definition G4UIQt.cc:1510
G4UIsession * SessionStart() override
Definition G4UIQt.cc:2355
void SetStartPage(const std::string &)
Definition G4UIQt.cc:2311
G4bool AddViewerTabFromFile(std::string fileName, std::string title)
Definition G4UIQt.cc:2255
~G4UIQt() override
Definition G4UIQt.cc:274
G4int ReceiveG4cout(const G4String &) override
Definition G4UIQt.cc:2553
void SetIconZoomInSelected()
Definition G4UIQt.cc:5184
void PauseSessionStart(const G4String &) override
Definition G4UIQt.cc:2418
void AddMenu(const char *, const char *) override
Definition G4UIQt.cc:2793
QWidget * GetSceneTreeWidget()
Definition G4UIQt.cc:2219
G4int ReceiveG4cerr(const G4String &) override
Definition G4UIQt.cc:2654
void AddButton(const char *, const char *, const char *) override
Definition G4UIQt.cc:2810
void SetOutputStyle(const char *destination, const char *style) override
Definition G4UIQt.cc:3093
void SetIconZoomOutSelected()
Definition G4UIQt.cc:5219
void SetIconHLRSelected()
Definition G4UIQt.cc:5308
void ClearMenu() override
Definition G4UIQt.cc:3110
void SetIconPerspectiveSelected()
Definition G4UIQt.cc:5363
void NativeMenu(G4bool aVal) override
Definition G4UIQt.cc:3102
QWidget * GetPickInfosWidget()
Definition G4UIQt.cc:2233
void DefaultIcons(G4bool aVal) override
Definition G4UIQt.cc:287
void SetIconSolidSelected()
Definition G4UIQt.cc:5254
G4int ReceiveG4debug(const G4String &) override
Definition G4UIQt.cc:2464
void SetIconRotateSelected()
Definition G4UIQt.cc:5119
void SessionTerminate()
Definition G4UIQt.cc:2403
void Prompt(G4String)
Definition G4UIQt.cc:2396
void SetIconWireframeSelected()
Definition G4UIQt.cc:5281
void SetIconMoveSelected()
Definition G4UIQt.cc:5089
G4bool AddViewerTab(QWidget *w, std::string title)
Definition G4UIQt.cc:2243
G4UIQt(G4int, char **)
Definition G4UIQt.cc:118
void AddIcon(const char *userLabel, const char *iconFile, const char *command, const char *file_name="") override
Definition G4UIQt.cc:2864
void SetIconHLHSRSelected()
Definition G4UIQt.cc:5335
G4int GetCommandEntry() const
const G4UIcommand * GetGuidance() const
G4UIcommand * GetCommand(G4int i)
const G4String & GetPathName() const
G4int GetTreeEntry() const
G4UIcommandTree * GetTree(G4int i)
G4UIcommandTree * FindCommandTree(const char *commandPath)
const G4String GetTitle() const
G4String GetFirstMatchedString(const G4String &, const G4String &) const
G4UIcommand * FindPath(const char *commandPath) const
std::size_t GetParameterEntries() const
const G4String & GetGuidanceLine(G4int i) const
G4UIparameter * GetParameter(G4int i) const
static G4String ConvertToString(G4bool boolVal)
const G4String & GetCommandPath() const
std::size_t GetGuidanceEntries() const
const G4String & GetCommandName() const
const G4String & GetRange() const
void SetCoutDestination(G4UIsession *const value)
G4UIcommandTree * GetTree() const
G4int ApplyCommand(const char *aCommand)
bool IsLastCommandOutputTreated()
G4int GetVerboseLevel() const
G4String FindMacroPath(const G4String &fname) const
static G4UImanager * GetUIpointer()
G4MTcoutDestination * GetThreadCout()
void SetSession(G4UIsession *const value)
void SetG4UIWindow(G4UIsession *const value)
void SetLastCommandOutputTreated()
const G4String & GetParameterCandidates() const
const G4String & GetParameterGuidance() const
G4bool IsOmittable() const
const G4String & GetParameterRange() const
G4bool GetCurrentAsDefault() const
char GetParameterType() const
const G4String & GetParameterName() const
const G4String & GetDefaultValue() const
G4String ModifyToFullPathCommand(const char *aCommandLine) const
G4String Complete(const G4String &)
void TerminalHelp(const G4String &)
void ApplyShellCommand(const G4String &, G4bool &, G4bool &)
void SetStyleUtility(const G4String &destination, const G4String &style)
std::map< G4String, OutputStyle > fOutputStyles
void AddInteractor(G4String, G4Interactor)
G4Interactor GetInteractor(G4String)
static G4MTGLOB_DLL G4coutDestination * masterG4coutDestination
const char * name(G4int ptype)
G4bool IsMasterThread()