Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/interfaces/implementation/src/G4UIQt.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

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