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