Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/interfaces/implementation/src/G4UIWin32.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 // Original author: G.Barrand, 1998
 27 // Rewrite: O.Pena-Rodriguez, March 2021
 28 // --------------------------------------------------------------------
 29 
 30 #include "G4UIWin32.hh"
 31 
 32 #include "G4MTcoutDestination.hh"
 33 #include "G4StateManager.hh"
 34 #include "G4UIcommand.hh"
 35 #include "G4UIcommandTree.hh"
 36 #include "G4UImanager.hh"
 37 #include "G4Win32.hh"
 38 
 39 #include <commctrl.h>
 40 #include <windows.h>
 41 #include <wingdi.h>
 42 
 43 #include <cstring>
 44 #include <utility>
 45 
 46 /***************************************************************************/
 47 static char mainClassName[] = "G4UIWin32";
 48 static G4bool exitSession = true;
 49 static G4bool exitPause = true;
 50 static G4bool exitHelp = true;
 51 static G4UIsession* tmpSession = nullptr;
 52 
 53 // Original wndproc for the Combo Editor
 54 static WNDPROC origComboEditorWindowProc;
 55 
 56 static G4bool ConvertStringToInt(const char*, G4int&);
 57 
 58 static G4int actionIdentifier = 0;
 59 
 60 /****************************************************************************************************/
 61 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
 62 G4UIWin32::G4UIWin32()
 63   : fHWndMainWindow(nullptr),
 64     fHWndEditor(nullptr),
 65     fHWndToolBar(nullptr),
 66     fHWndComboBox(nullptr),
 67     fHWndComboEditor(nullptr),
 68     fHWndHelpTree(nullptr),
 69     fHWndStatus(nullptr),
 70     menuBar(nullptr),
 71     fHelp(false),
 72     fHelpChoice(0),
 73     fHistoryPos(-1)
 74 {
 75   G4UImanager* UI = G4UImanager::GetUIpointer();
 76   if (UI != nullptr) {
 77     UI->SetSession(this);
 78     UI->SetG4UIWindow(this);
 79   }
 80 
 81   // Ensure that the common control DLL is loaded
 82   INITCOMMONCONTROLSEX commCtrls;
 83   commCtrls.dwSize = sizeof(INITCOMMONCONTROLSEX);
 84   commCtrls.dwICC = ICC_BAR_CLASSES | ICC_LISTVIEW_CLASSES;
 85   // this loads list-view and toolbar classes.
 86   InitCommonControlsEx(&commCtrls);
 87 
 88   interactorManager = G4Win32::getInstance();
 89 
 90   static G4bool Done = false;
 91   if (! Done) {
 92     WNDCLASS wc;
 93     wc.style = 0;
 94     wc.lpfnWndProc = (WNDPROC)G4UIWin32::MainWindowProc;
 95     wc.cbClsExtra = 0;
 96     wc.cbWndExtra = 0;
 97     wc.hInstance = ::GetModuleHandle(nullptr);
 98     wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
 99     wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
100     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
101     wc.lpszMenuName = (PTSTR)mainClassName;
102     wc.lpszClassName = (PTSTR)mainClassName;
103 
104     if (! RegisterClass(&wc)) {
105       MessageBoxA(nullptr, "G4UIWin32: Win32 window registration failed!", "Error!",
106         MB_ICONEXCLAMATION | MB_OK);
107       G4cout << "G4UIWin32: Win32 window registration failed!" << G4endl;
108       return;
109     }
110 
111     Done = true;
112   }
113 
114   menuBar = CreateMenu();
115 
116   // Add some initial options to the menu
117   HMENU hMenu = CreatePopupMenu();
118   AppendMenuA(menuBar, MF_POPUP, (UINT_PTR)hMenu, "&Geant4");
119   AddInteractor("Geant4", (G4Interactor)hMenu);
120 
121   AppendMenuA(hMenu, MF_STRING, ID_OPEN_MACRO, "&Open macro...");
122   AppendMenuA(hMenu, MF_STRING, ID_SAVE_VIEWER_STATE, "&Save viewer state...");
123   AppendMenuA(hMenu, MF_SEPARATOR, -1, "");
124   AppendMenuA(hMenu, MF_STRING, ID_RUN_BEAMON, "&Beam On");
125   AppendMenuA(hMenu, MF_SEPARATOR, -1, "");
126   AppendMenuA(hMenu, MF_STRING, ID_EXIT_APP, "E&xit");
127 
128   hMenu = CreatePopupMenu();
129   AppendMenuA(menuBar, MF_POPUP, (UINT_PTR)hMenu, "&View");
130   AddInteractor("View", (G4Interactor)hMenu);
131 
132   AppendMenuA(hMenu, MF_STRING, ID_VIEW_SOLID, "S&olid");
133   AppendMenuA(hMenu, MF_STRING, ID_VIEW_WIREFRAME, "&Wireframe");
134   AppendMenuA(hMenu, MF_SEPARATOR, -1, "");
135   AppendMenuA(hMenu, MF_STRING, ID_PROJ_ORTHOGRAPHIC, "&Orthographic");
136   AppendMenuA(hMenu, MF_STRING, ID_PROJ_PERSPECTIVE, "P&erspective");
137   AppendMenuA(hMenu, MF_SEPARATOR, -1, "");
138   AppendMenuA(hMenu, MF_STRING, ID_ORIENTATION_XY, "&X-Y Plane");
139   AppendMenuA(hMenu, MF_STRING, ID_ORIENTATION_XZ, "X-&Z Plane");
140   AppendMenuA(hMenu, MF_STRING, ID_ORIENTATION_YZ, "&Y-Z Plane");
141   AppendMenuA(hMenu, MF_STRING, ID_ORIENTATION_OBLIQUE, "&Oblique");
142 
143   hMenu = CreatePopupMenu();
144   AppendMenuA(menuBar, MF_POPUP, (UINT_PTR)hMenu, "&Zoom");
145   AddInteractor("Zoom", (G4Interactor)hMenu);
146 
147   AppendMenuA(hMenu, MF_STRING, ID_ZOOM_IN, "Zoom &In");
148   AppendMenuA(hMenu, MF_STRING, ID_ZOOM_OUT, "Zoom &Out");
149 
150   tmpSession = this;
151   char winName[] = "Geant4";
152   fHWndMainWindow = ::CreateWindowEx(WS_EX_CLIENTEDGE, (PTSTR)mainClassName, (PTSTR)winName,
153     WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
154     CW_USEDEFAULT, nullptr, menuBar, ::GetModuleHandle(nullptr), nullptr);
155 
156   if (fHWndMainWindow == nullptr) {
157     MessageBoxA(nullptr, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
158     return;
159   }
160   tmpSession = nullptr;
161   ::SetWindowLongPtr(fHWndMainWindow, GWLP_USERDATA, (LONG_PTR)this);
162 
163   ::SetForegroundWindow(fHWndMainWindow);
164   ::ShowWindow(fHWndMainWindow, SW_SHOWDEFAULT);
165   ::UpdateWindow(fHWndMainWindow);
166 
167   if (UI != nullptr) UI->SetCoutDestination(this);
168 
169   // TODO: Manage multithreaded output
170   // #ifdef G4MULTITHREADED
171   // explicitly request that cout/cerr messages from threads are ALSO propagated to the master.
172   // masterG4coutDestination = this;
173   // #endif
174 }
175 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
176 /****************************************************************************************************/
177 
178 /****************************************************************************************************/
179 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
180 G4UIWin32::~G4UIWin32()
181 {
182   G4UImanager* UI = G4UImanager::GetUIpointer();
183   if (UI != nullptr) {
184     UI->SetSession(nullptr);
185     UI->SetG4UIWindow(nullptr);
186     UI->SetCoutDestination(nullptr);
187   }
188 
189   // TODO: Manage multithreaded output
190   // #ifdef G4MULTITHREADED
191   // masterG4coutDestination = 0; // set to cout when UI is deleted
192   // #endif
193 
194   if (fHWndStatus != nullptr) ::SetWindowLongPtr(fHWndStatus, GWLP_USERDATA, LONG(NULL));
195   if (fHWndHelpTree != nullptr) ::SetWindowLongPtr(fHWndHelpTree, GWLP_USERDATA, LONG(NULL));
196   if (fHWndComboBox != nullptr) ::SetWindowLongPtr(fHWndComboBox, GWLP_USERDATA, LONG(NULL));
197   if (fHWndToolBar != nullptr) ::SetWindowLongPtr(fHWndToolBar, GWLP_USERDATA, LONG(NULL));
198   if (fHWndEditor != nullptr) ::SetWindowLongPtr(fHWndEditor, GWLP_USERDATA, LONG(NULL));
199   if (fHWndMainWindow != nullptr) {
200     ::SetWindowLongPtr(fHWndMainWindow, GWLP_USERDATA, LONG(NULL));
201     ::DestroyWindow(fHWndMainWindow);
202   }
203 }
204 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
205 /****************************************************************************************************/
206 
207 /****************************************************************************************************/
208 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
209 G4UIsession* G4UIWin32::SessionStart()
210 {
211   if (interactorManager != nullptr) {
212     Prompt("session");
213     exitSession = false;
214 
215     // TODO: Ensure that the list of commands is updated
216     // Load commands into Help Tree View
217     InitHelpTreeItems();
218 
219     interactorManager->DisableSecondaryLoop();
220     void* event;
221     while ((event = interactorManager->GetEvent()) != nullptr) {
222       interactorManager->DispatchEvent(event);
223       if (exitSession) break;
224     }
225     interactorManager->EnableSecondaryLoop();
226     return this;
227   }
228   else
229     return this;
230 }
231 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
232 /****************************************************************************************************/
233 
234 /****************************************************************************************************/
235 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
236 void G4UIWin32::Prompt(const G4String& a_prompt) {}
237 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
238 /****************************************************************************************************/
239 
240 /****************************************************************************************************/
241 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
242 void G4UIWin32::SessionTerminate() {}
243 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
244 /****************************************************************************************************/
245 
246 /****************************************************************************************************/
247 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
248 void G4UIWin32::PauseSessionStart(const G4String& a_state)
249 {
250   if (a_state == "G4_pause> ") {
251     SecondaryLoop("Pause, type continue to exit this state");
252   }
253 
254   if (a_state == "EndOfEvent") {
255     // Picking with feed back in event data Done here !!!
256     SecondaryLoop("End of event, type continue to exit this state");
257   }
258 }
259 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
260 /****************************************************************************************************/
261 
262 /****************************************************************************************************/
263 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
264 void G4UIWin32::SecondaryLoop(const G4String& a_prompt)
265 {
266   if (interactorManager != nullptr) {
267     Prompt(a_prompt);
268     exitPause = false;
269     void* event;
270     while ((event = interactorManager->GetEvent()) != nullptr) {
271       interactorManager->DispatchEvent(event);
272       if (exitPause) break;
273     }
274     Prompt("session");
275   }
276 }
277 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
278 /****************************************************************************************************/
279 
280 /****************************************************************************************************/
281 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
282 G4int G4UIWin32::ReceiveG4debug(const G4String& a_string)
283 {
284   // Geant4 uses UNIX's style for new lines (\n)
285   // we must convert them to Windows' style (\r\n)
286   G4String str = ConvertNewLines(a_string);
287 
288   AddText((LPSTR)str.data());
289 
290   return 0;
291 }
292 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
293 /****************************************************************************************************/
294 
295 /****************************************************************************************************/
296 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
297 G4int G4UIWin32::ReceiveG4cout(const G4String& a_string)
298 {
299   // Geant4 uses UNIX's style for new lines (\n)
300   // we must convert them to Windows' style (\r\n)
301   G4String str = ConvertNewLines(a_string);
302 
303   AddText((LPSTR)str.data());
304 
305   return 0;
306 }
307 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
308 /****************************************************************************************************/
309 
310 /****************************************************************************************************/
311 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
312 G4int G4UIWin32::ReceiveG4cerr(const G4String& a_string)
313 {
314   // Geant4 uses UNIX's style for new lines (\n)
315   // we must convert them to Windows' style (\r\n)
316   G4String str = ConvertNewLines(a_string);
317 
318   AddText((LPSTR)str.data());
319 
320   return 0;
321 }
322 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
323 /****************************************************************************************************/
324 
325 /****************************************************************************************************/
326 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
327 G4bool G4UIWin32::GetHelpChoice(G4int& aInt)
328 {
329   fHelp = true;
330 
331   if (interactorManager != nullptr) {
332     Prompt("Help");
333     exitHelp = false;
334     void* event;
335     while ((event = interactorManager->GetEvent()) != nullptr) {
336       interactorManager->DispatchEvent(event);
337       if (exitHelp) break;
338     }
339     Prompt("session");
340     //
341     if (! fHelp) return false;
342     aInt = fHelpChoice;
343     fHelp = false;
344     return true;
345   }
346   else
347     return false;
348 }
349 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
350 /****************************************************************************************************/
351 
352 /****************************************************************************************************/
353 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
354 void G4UIWin32::ExitHelp() const {}
355 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
356 /****************************************************************************************************/
357 
358 /****************************************************************************************************/
359 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
360 void G4UIWin32::AddMenu(const char* a_name, const char* a_label)
361 {
362   if (a_name != nullptr) {
363     HMENU hMenu = CreatePopupMenu();
364     AppendMenuA(menuBar, MF_POPUP, (UINT_PTR)hMenu, a_label);
365     AddInteractor(a_name, (G4Interactor)hMenu);
366     DrawMenuBar(fHWndMainWindow);
367   }
368 }
369 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
370 /****************************************************************************************************/
371 
372 /****************************************************************************************************/
373 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
374 void G4UIWin32::AddButton(const char* a_menu, const char* a_label, const char* a_command)
375 {
376   if ((a_menu != nullptr) && (a_label != nullptr) && (a_command != nullptr)) {
377     HMENU hMenu = (HMENU)GetInteractor(a_menu);
378     actionIdentifier++;
379     commands[actionIdentifier] = a_command;
380     AppendMenuA(hMenu, MF_STRING, actionIdentifier, a_label);
381   }
382 }
383 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
384 /****************************************************************************************************/
385 
386 /****************************************************************************************************/
387 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
388 G4String G4UIWin32::GetCommand(G4int a_id) { return commands[a_id]; }
389 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
390 /****************************************************************************************************/
391 
392 /****************************************************************************************************/
393 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
394 LRESULT CALLBACK G4UIWin32::MainWindowProc(
395   HWND aWindow, UINT aMessage, WPARAM wParam, LPARAM lParam)
396 {
397   switch (aMessage) {
398     case WM_CREATE: {
399       auto* This = (G4UIWin32*)tmpSession;
400       if (This != nullptr) {
401         if (! This->CreateComponents(aWindow)) {
402           MessageBoxA(aWindow, "Could not create components.", "Error", MB_OK | MB_ICONERROR);
403           return false;
404         }
405       }
406     }
407       return 0;
408 
409     case WM_SIZE: {
410       auto* This = (G4UIWin32*)::GetWindowLongPtr(aWindow, GWLP_USERDATA);
411       if (This != nullptr) {
412         if (! This->ResizeComponents(aWindow)) {
413           MessageBoxA(aWindow, "Could not resize components.", "Error", MB_OK | MB_ICONERROR);
414           return false;
415         }
416       }
417     }
418       return 0;
419 
420     case WM_CLOSE:
421       DestroyWindow(aWindow);
422       return 0;
423 
424     case WM_DESTROY:
425       PostQuitMessage(0);
426       return 0;
427 
428     case WM_SETFOCUS: {
429       auto* This = (G4UIWin32*)::GetWindowLongPtr(aWindow, GWLP_USERDATA);
430       if (This != nullptr) SetFocus(This->fHWndComboBox);
431     }
432       return 0;
433 
434     case WM_NOTIFY: {
435       auto* This = (G4UIWin32*)::GetWindowLongPtr(aWindow, GWLP_USERDATA);
436       if (This != nullptr) {
437         switch (((LPNMHDR)lParam)->code) {
438           // Tooltip for Toolbar
439           case TTN_NEEDTEXT: {
440             auto lpttt = (LPTOOLTIPTEXT)lParam;
441             lpttt->hinst = nullptr;
442             UINT idButton = lpttt->hdr.idFrom;
443             lpttt->lpszText = (PTSTR)This->GetToolTips(idButton).c_str();
444           } break;
445 
446           // Tooltip for TreeView
447           case TVN_GETINFOTIP: {
448             auto pTip = (LPNMTVGETINFOTIP)lParam;
449             pTip->pszText = (PTSTR)This->GetHelpTreeToolTips(pTip->hItem).c_str();
450           } break;
451 
452           // Double click for TreeView
453           case NM_DBLCLK: {
454             auto lpnmh = (LPNMHDR)lParam;
455             auto item = TreeView_GetSelection(lpnmh->hwndFrom);
456             This->HelpTreeDoubleClick(item);
457           } break;
458         }
459       }
460     }
461       return 0;
462 
463     case WM_COMMAND: {
464       auto* This = (G4UIWin32*)::GetWindowLongPtr(aWindow, GWLP_USERDATA);
465       if (This != nullptr)
466         if (! This->ProcessDefaultCommands(LOWORD(wParam)))
467           // If the command was not processed, do it now
468           switch (LOWORD(wParam)) {
469             case IDC_MAIN_EDIT: {
470               // We have to release some space when the buffer is full
471               if (HIWORD(wParam) == EN_ERRSPACE || HIWORD(wParam) == EN_MAXTEXT) {
472                 G4int bufferSize =
473                   SendMessage(This->fHWndEditor, EM_GETLIMITTEXT, (WPARAM)0, (LPARAM)0);
474 
475                 // Select the first third of the text
476                 SendMessage(This->fHWndEditor, EM_SETSEL, (WPARAM)0, (LPARAM)bufferSize / 3);
477                 // Delete it
478                 SendMessage(This->fHWndEditor, EM_REPLACESEL, (WPARAM)0, (LPARAM) "");
479                 // Scroll to the bottom
480                 SendMessage(This->fHWndEditor, WM_VSCROLL, SB_BOTTOM, NULL);
481               }
482             } break;
483             default:
484               if (! This->fHelp) {
485                 G4String command = This->GetCommand(wParam);
486                 This->ApplyShellCommand(command, exitSession, exitPause);
487               }
488           }
489     }
490       return 0;
491     default:
492       //  For all the other cases, call the default window procedure.
493       return DefWindowProc(aWindow, aMessage, wParam, lParam);
494   }
495 }
496 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
497 /****************************************************************************************************/
498 
499 /****************************************************************************************************/
500 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
501 LRESULT CALLBACK G4UIWin32::ComboEditorWindowProc(
502   HWND aWindow, UINT aMessage, WPARAM wParam, LPARAM lParam)
503 {
504   // We need to go two steps up: Editor -> ComboBox -> Window
505   HWND parent = GetParent(GetParent(aWindow));
506   auto* This = (G4UIWin32*)::GetWindowLongPtr(parent, GWLP_USERDATA);
507 
508   switch (aMessage) {
509     case WM_KEYDOWN:
510       switch (wParam) {
511         case VK_TAB: {
512           if (This != nullptr) {
513             if (This->fHelp) break;
514 
515             This->ProcessTabKey();
516           }
517         }
518           return 0;  // Do not jump into origComboEditorWindowProc.
519 
520         case VK_ESCAPE: {
521           if (This != nullptr) This->ProcessEscKey();
522         }
523           return 0;  // Do not jump into origComboEditorWindowProc.
524 
525         case VK_RETURN: {
526           if (This != nullptr) This->ProcessEnterKey();
527         }
528           return 0;  // Do not jump into origComboEditorWindowProc.
529 
530         case VK_UP: {
531           if (This != nullptr) This->ProcessUpKey();
532         }
533           return 0;  // Do not jump into origComboEditorWindowProc.
534 
535         case VK_DOWN: {
536           if (This != nullptr) This->ProcessDownKey();
537         }
538           return 0;  // Do not jump into origComboEditorWindowProc.
539       }
540       break;
541 
542     case WM_KEYUP:
543     case WM_CHAR:
544       switch (wParam) {
545         case VK_TAB:
546         case VK_ESCAPE:
547         case VK_RETURN:
548         case VK_UP:
549         case VK_DOWN:
550           return 0;  // Do not jump into origComboEditorWindowProc.
551       }
552   }
553 
554   //  Call the original window procedure for default processing.
555   return CallWindowProc(origComboEditorWindowProc, aWindow, aMessage, wParam, lParam);
556 }
557 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
558 /****************************************************************************************************/
559 
560 /****************************************************************************************************/
561 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
562 G4bool G4UIWin32::CreateComponents(HWND aWindow)
563 {
564   HFONT hfDefault;
565   TBBUTTON tbb[NUM_BUTTONS];
566   TBADDBITMAP tbab;
567   RECT rcClient;  // dimensions of client area
568 
569   G4int statwidths[] = {100, -1};
570 
571   // Create Edit Control
572   char winName[] = "EDIT";
573   char winParam[] = "";
574   fHWndEditor = CreateWindowEx(WS_EX_CLIENTEDGE, (PTSTR)winName, (PTSTR)winParam,
575     WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL | ES_MULTILINE | ES_AUTOVSCROLL |
576       ES_AUTOHSCROLL | ES_READONLY,
577     0, 0, 100, 100, aWindow, (HMENU)IDC_MAIN_EDIT, GetModuleHandle(nullptr), nullptr);
578   if (fHWndEditor == nullptr)
579     MessageBoxA(aWindow, "Could not create edit box.", "Error", MB_OK | MB_ICONERROR);
580 
581   // Set editor font
582   // hfDefault = (HFONT) GetStockObject(DEFAULT_GUI_FONT);
583   hfDefault = CreateFontA(-10, -8, 0, 0, 0, false, 0, 0, OEM_CHARSET, OUT_RASTER_PRECIS,
584     CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH, "System");
585   SendMessage(fHWndEditor, WM_SETFONT, (WPARAM)hfDefault, MAKELPARAM(false, 0));
586 
587   // Set editor's buffer size (the default value is too small)
588   SendMessage(fHWndEditor, EM_SETLIMITTEXT, (WPARAM)500000, (LPARAM)0);
589 
590   // Create Toolbar
591   fHWndToolBar = CreateWindowEx(0, TOOLBARCLASSNAME, nullptr,
592     WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS, 0, 0, 0, 0, aWindow,
593     (HMENU)IDC_MAIN_TOOL, GetModuleHandle(nullptr), nullptr);
594   if (fHWndToolBar == nullptr)
595     MessageBoxA(aWindow, "Could not create tool bar.", "Error", MB_OK | MB_ICONERROR);
596 
597   // Required for backward compatibility.
598   SendMessage(fHWndToolBar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), (LPARAM)0);
599 
600   // Load standard images
601   tbab.hInst = HINST_COMMCTRL;
602   tbab.nID = IDB_STD_SMALL_COLOR;
603   SendMessage(fHWndToolBar, TB_ADDBITMAP, (WPARAM)0, (LPARAM)&tbab);
604 
605   // Load history images
606   tbab.hInst = HINST_COMMCTRL;
607   tbab.nID = IDB_HIST_SMALL_COLOR;
608   SendMessage(fHWndToolBar, TB_ADDBITMAP, (WPARAM)0, (LPARAM)&tbab);
609 
610   G4int btnBMP[NUM_BUTTONS] = {STD_FILEOPEN, STD_FILESAVE, -1, STD_FIND, STD_FIND, -1,
611     15 + HIST_FORWARD, -1, STD_HELP, -1, STD_FILENEW, STD_FILESAVE};
612   G4int btnSTL[NUM_BUTTONS] = {TBSTYLE_BUTTON, TBSTYLE_BUTTON, TBSTYLE_SEP, TBSTYLE_BUTTON,
613     TBSTYLE_BUTTON, TBSTYLE_SEP, TBSTYLE_BUTTON, TBSTYLE_SEP, TBSTYLE_BUTTON, TBSTYLE_SEP,
614     TBSTYLE_BUTTON, TBSTYLE_BUTTON};
615   G4int btnCMD[NUM_BUTTONS] = {ID_OPEN_MACRO, ID_SAVE_VIEWER_STATE, -1, ID_ZOOM_IN, ID_ZOOM_OUT, -1,
616     ID_RUN_BEAMON, -1, ID_HELP_ABOUT, -1, ID_LOG_CLEAN, ID_LOG_SAVE};
617   ZeroMemory(tbb, sizeof(tbb));
618   for (G4int i = 0; i < NUM_BUTTONS; i++) {
619     tbb[i].iBitmap = btnBMP[i];
620     tbb[i].fsState = TBSTATE_ENABLED;
621     tbb[i].fsStyle = btnSTL[i];
622     tbb[i].idCommand = btnCMD[i];
623   }
624 
625   SendMessage(fHWndToolBar, TB_ADDBUTTONS, sizeof(tbb) / sizeof(TBBUTTON), (LPARAM)&tbb);
626 
627   // Create the Combobox
628   fHWndComboBox = CreateWindowEx(0, WC_COMBOBOX, TEXT(""),
629     CBS_DROPDOWN | CBS_HASSTRINGS | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE, 150, 0, 200, 200,
630     aWindow, (HMENU)IDC_MAIN_COMBO, GetModuleHandle(nullptr), nullptr);
631 
632   // Display an initial item in the selection field
633   SendMessage(fHWndComboBox, CB_SETCURSEL, (WPARAM)2, (LPARAM)0);
634 
635   // Get aWindow of edit control in combobox created earlier.
636   fHWndComboEditor = FindWindowEx(fHWndComboBox, nullptr, WC_EDIT, nullptr);
637 
638   //  Change the window procedure for the edit windows to the subclass procedure.
639   origComboEditorWindowProc =
640     (WNDPROC)SetWindowLongPtr(fHWndComboEditor, GWLP_WNDPROC, (LONG_PTR)ComboEditorWindowProc);
641 
642   // Create TreeView
643 
644   // Get the dimensions of the parent window's client area, and create
645   // the tree-view control.
646   GetClientRect(aWindow, &rcClient);
647   fHWndHelpTree = CreateWindowEx(0, WC_TREEVIEW, TEXT("Tree View"),
648     WS_VISIBLE | WS_CHILD | WS_BORDER | TVS_INFOTIP | TVS_HASBUTTONS | TVS_HASLINES |
649       TVS_LINESATROOT,
650     0, 0, rcClient.right, rcClient.bottom, aWindow, (HMENU)IDC_MAIN_TREE_VIEW,
651     GetModuleHandle(nullptr), nullptr);
652 
653   // Initialize the Help Tree View.
654   /*    if (!InitHelpTreeItems()) {
655           DestroyWindow(fHWndHelpTree);
656           return false;
657       }*/
658 
659   // Create Status bar
660   fHWndStatus = CreateWindowEx(0, STATUSCLASSNAME, nullptr, WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
661     100, 100, 200, 200, aWindow, (HMENU)IDC_MAIN_STATUS, GetModuleHandle(nullptr), nullptr);
662 
663   SendMessage(fHWndStatus, SB_SETPARTS, sizeof(statwidths) / sizeof(int), (LPARAM)statwidths);
664   // SendMessage(fHWndStatus, SB_SETTEXT, 0, (LPARAM) "Hi there :)");
665 
666   return true;
667 }
668 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
669 /****************************************************************************************************/
670 
671 /****************************************************************************************************/
672 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
673 G4bool G4UIWin32::ResizeComponents(HWND aWindow)
674 {
675   RECT rcTool;
676   G4int iToolHeight, iToolWidth;
677 
678   RECT rcStatus;
679   G4int iStatusHeight;
680 
681   RECT rcComboBox;
682   G4int iComboBoxHeight;
683 
684   G4int iTreeViewHeight, iTreeViewWidth;
685   G4int iEditHeight, iEditWidth;
686 
687   RECT rcClient;
688 
689   // Size toolbar and get height and width
690   SendMessage(fHWndToolBar, TB_AUTOSIZE, 0, 0);
691 
692   GetWindowRect(fHWndToolBar, &rcTool);
693   iToolHeight = rcTool.bottom - rcTool.top;
694   iToolWidth = rcTool.right - rcTool.left;
695 
696   // Size status bar and get height
697   SendMessage(fHWndStatus, WM_SIZE, 0, 0);
698 
699   GetWindowRect(fHWndStatus, &rcStatus);
700   iStatusHeight = rcStatus.bottom - rcStatus.top;
701 
702   // Size status the Combo Box and get height
703   SendMessage(fHWndComboBox, WM_SIZE, 0, 0);
704 
705   GetWindowRect(fHWndComboBox, &rcComboBox);
706   iComboBoxHeight = rcComboBox.bottom - rcComboBox.top;
707 
708   // Calculate remaining height and size edit
709   GetClientRect(aWindow, &rcClient);
710 
711   iTreeViewHeight = rcClient.bottom - iToolHeight - iStatusHeight;
712   iTreeViewWidth = iToolWidth / 4;
713 
714   iEditHeight = rcClient.bottom - iToolHeight - iComboBoxHeight - iStatusHeight;
715   iEditWidth = iToolWidth - iTreeViewWidth;
716 
717   // TreeView location and size
718   SetWindowPos(
719     fHWndHelpTree, nullptr, 0, iToolHeight, iTreeViewWidth, iTreeViewHeight, SWP_NOZORDER);
720 
721   // Editor location and size
722   SetWindowPos(
723     fHWndEditor, nullptr, iTreeViewWidth, iToolHeight, iEditWidth, iEditHeight, SWP_NOZORDER);
724 
725   // ComboBox location and size
726   SetWindowPos(
727     fHWndComboBox, nullptr, iTreeViewWidth, iToolHeight + iEditHeight, iEditWidth, 200, 0);
728 
729   return true;
730 }
731 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
732 /****************************************************************************************************/
733 
734 /****************************************************************************************************/
735 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
736 void G4UIWin32::ProcessTabKey()
737 {
738   char buffer[256];
739 
740   // Only process the command it the user has written something
741   if (SendMessage(fHWndComboBox, WM_GETTEXT, (WPARAM)sizeof(buffer), (LPARAM)buffer) != 0) {
742     G4String command(buffer);
743 
744     SetFocus(fHWndComboBox);
745 
746     G4String cmd = Complete(command);
747     const char* d = cmd.data();
748     G4int l = strlen(d);
749     Edit_SetText(fHWndComboEditor, (PTSTR)d);
750     Edit_SetSel(fHWndComboEditor, l, l);
751   }
752   else {
753     if (GetFocus() == fHWndComboEditor)
754       SetFocus(fHWndHelpTree);
755     else
756       SetFocus(fHWndComboBox);
757   }
758 }
759 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
760 /****************************************************************************************************/
761 
762 /****************************************************************************************************/
763 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
764 void G4UIWin32::ProcessEscKey()
765 {
766   // Clear the current selection.
767   SendMessage(fHWndComboBox, CB_SETCURSEL, (WPARAM)(-1), (LPARAM)0);
768   // Set the focus to the Combo Box.
769   SetFocus(fHWndComboBox);
770 }
771 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
772 /****************************************************************************************************/
773 
774 /****************************************************************************************************/
775 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
776 void G4UIWin32::ProcessEnterKey()
777 {
778   char buffer[256];
779   DWORD dwIndex, numItems;
780 
781   // Only process the command it the user has written something
782   if (SendMessage(fHWndComboBox, WM_GETTEXT, (WPARAM)sizeof(buffer), (LPARAM)buffer) != 0) {
783     SetFocus(fHWndComboBox);
784 
785     // Read command
786     G4String command(buffer);
787 
788     // Now clear the current selection.
789     SendMessage(fHWndComboBox, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0);
790 
791     if (fHelp) {
792       exitHelp = true;
793       fHelp = ConvertStringToInt(command.data(), fHelpChoice);
794     }
795     else {
796       fHistory.push_back(command);
797       fHistoryPos = -1;
798       ApplyShellCommand(command, exitSession, exitPause);
799 
800       // Now update the history in the ComboBox
801 
802       // Check if this command exists in the ComboBox
803       dwIndex = SendMessage(fHWndComboBox, CB_FINDSTRINGEXACT, (WPARAM)(-1), (LPARAM)buffer);
804 
805       //  Add the string, if necessary
806       if (dwIndex == CB_ERR)
807         dwIndex = SendMessage(fHWndComboBox, CB_INSERTSTRING, (WPARAM)0, (LPARAM)buffer);
808       // If the string exists, move it to the first position
809       if (dwIndex != CB_ERR) {
810         SendMessage(fHWndComboBox, CB_DELETESTRING, (WPARAM)dwIndex, (LPARAM)0);
811         dwIndex = SendMessage(fHWndComboBox, CB_INSERTSTRING, (WPARAM)0, (LPARAM)buffer);
812       }
813 
814       numItems = SendMessage(fHWndComboBox, CB_GETCOUNT, (WPARAM)0, (LPARAM)0);
815       while (numItems > MAX_HISTORY_ITEMS) {
816         SendMessage(fHWndComboBox, CB_DELETESTRING, (WPARAM)(numItems - 1), (LPARAM)0);
817         numItems = SendMessage(fHWndComboBox, CB_GETCOUNT, (WPARAM)0, (LPARAM)0);
818       }
819     }
820   }
821 }
822 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
823 /****************************************************************************************************/
824 
825 /****************************************************************************************************/
826 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
827 void G4UIWin32::ProcessUpKey()
828 {
829   G4int pos = fHistoryPos == -1 ? fHistory.size() - 1 : fHistoryPos - 1;
830   if ((pos >= 0) && (pos < (G4int)fHistory.size())) {
831     G4String command = fHistory[pos];
832     const char* d = command.data();
833     G4int l = strlen(d);
834     Edit_SetText(fHWndComboEditor, (PTSTR)d);
835     Edit_SetSel(fHWndComboEditor, l, l);
836 
837     fHistoryPos = pos;
838   }
839 }
840 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
841 /****************************************************************************************************/
842 
843 /****************************************************************************************************/
844 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
845 void G4UIWin32::ProcessDownKey()
846 {
847   G4int pos = fHistoryPos + 1;
848   if ((pos >= 0) && (pos < (G4int)fHistory.size())) {
849     G4String command = fHistory[pos];
850     const char* d = command.data();
851     G4int l = strlen(d);
852     Edit_SetText(fHWndComboEditor, (PTSTR)d);
853     Edit_SetSel(fHWndComboEditor, l, l);
854 
855     fHistoryPos = pos;
856   }
857   else if (pos >= (G4int)fHistory.size()) {
858   char eName[] = "";
859     Edit_SetText(fHWndComboEditor, (PTSTR)eName);
860     Edit_SetSel(fHWndComboEditor, 0, 0);
861 
862     fHistoryPos = -1;
863   }
864 }
865 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
866 /****************************************************************************************************/
867 
868 /****************************************************************************************************/
869 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
870 G4bool G4UIWin32::ProcessDefaultCommands(G4int idCommand)
871 {
872   switch (idCommand) {
873     case ID_EXIT_APP:
874       PostMessage(fHWndMainWindow, WM_CLOSE, 0, 0);
875       return true;
876     case ID_OPEN_MACRO:
877       DoOpenMacro(fHWndMainWindow);
878       return true;
879     case ID_SAVE_VIEWER_STATE:
880       DoSaveViewer(fHWndMainWindow);
881       return true;
882     case ID_RUN_BEAMON:
883       if (! fHelp) {
884         G4String command = "/run/beamOn 1";
885         ApplyShellCommand(command, exitSession, exitPause);
886       }
887       return true;
888     case ID_RUN_CMD:
889       return true;
890     case ID_VIEW_SOLID:
891       if (! fHelp) {
892         G4String command = "/vis/viewer/set/style s";
893         ApplyShellCommand(command, exitSession, exitPause);
894       }
895       return true;
896     case ID_VIEW_WIREFRAME:
897       if (! fHelp) {
898         G4String command = "/vis/viewer/set/style w";
899         ApplyShellCommand(command, exitSession, exitPause);
900       }
901       return true;
902     case ID_PROJ_ORTHOGRAPHIC:
903       if (! fHelp) {
904         G4String command = "/vis/viewer/set/projection o";
905         ApplyShellCommand(command, exitSession, exitPause);
906       }
907       return true;
908     case ID_PROJ_PERSPECTIVE:
909       if (! fHelp) {
910         G4String command = "/vis/viewer/set/projection p";
911         ApplyShellCommand(command, exitSession, exitPause);
912       }
913       return true;
914     case ID_ZOOM_IN:
915       if (! fHelp) {
916         G4String command = "/vis/viewer/zoom 1.2";
917         ApplyShellCommand(command, exitSession, exitPause);
918       }
919       return true;
920     case ID_ZOOM_OUT:
921       if (! fHelp) {
922         G4String command = "/vis/viewer/zoom 0.8";
923         ApplyShellCommand(command, exitSession, exitPause);
924       }
925       return true;
926     case ID_ORIENTATION_XY:
927       if (! fHelp) {
928         G4String command = "/vis/viewer/set/viewpointThetaPhi 0. 0.";
929         ApplyShellCommand(command, exitSession, exitPause);
930       }
931       return true;
932     case ID_ORIENTATION_XZ:
933       if (! fHelp) {
934         G4String command = "/vis/viewer/set/viewpointThetaPhi 90. 0.";
935         ApplyShellCommand(command, exitSession, exitPause);
936       }
937       return true;
938     case ID_ORIENTATION_YZ:
939       if (! fHelp) {
940         G4String command = "/vis/viewer/set/viewpointThetaPhi 0. 90.";
941         ApplyShellCommand(command, exitSession, exitPause);
942       }
943       return true;
944     case ID_ORIENTATION_OBLIQUE:
945       if (! fHelp) {
946         G4String command = "/vis/viewer/set/viewpointThetaPhi 45. -45.";
947         ApplyShellCommand(command, exitSession, exitPause);
948       }
949       return true;
950     case ID_HELP_ABOUT:
951       return true;
952     case ID_LOG_CLEAN:
953     {
954       char eName[] = "";
955         SetDlgItemText(fHWndMainWindow, IDC_MAIN_EDIT, (PTSTR)eName);
956     }
957       return true;
958     case ID_LOG_SAVE:
959       DoSaveLog(fHWndMainWindow);
960       return true;
961     default:
962       return false;
963   }
964 }
965 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
966 /****************************************************************************************************/
967 
968 /****************************************************************************************************/
969 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
970 G4String G4UIWin32::GetToolTips(G4int idButton)
971 {
972   switch (idButton) {
973     case ID_OPEN_MACRO:
974       return "Open and execute macro file";
975 
976     case ID_SAVE_VIEWER_STATE:
977       return "Save viewer state";
978 
979     case ID_ZOOM_IN:
980       return "Zoom in";
981 
982     case ID_ZOOM_OUT:
983       return "Zoom out";
984 
985     case ID_RUN_BEAMON:
986       return "Beam on (one particle)";
987 
988     case ID_HELP_ABOUT:
989       return "About G4UIWin32";
990 
991     case ID_LOG_CLEAN:
992       return "Clean log";
993 
994     case ID_LOG_SAVE:
995       return "Save log";
996 
997     default:
998       return "";
999   }
1000 }
1001 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1002 /****************************************************************************************************/
1003 
1004 /****************************************************************************************************/
1005 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1006 G4String G4UIWin32::GetHelpTreeToolTips(HTREEITEM item)
1007 {
1008   // Tooltips for the help tree
1009   G4UImanager* UI = G4UImanager::GetUIpointer();
1010   if (UI == nullptr) return "";
1011   G4UIcommandTree* treeTop = UI->GetTree();
1012 
1013   G4String itemText = GetItemPath(item);
1014 
1015   // Check if it is a command path
1016   if (TreeView_GetChild(fHWndHelpTree, item) != nullptr) itemText += "/";
1017 
1018   G4UIcommand* command = treeTop->FindPath(itemText.c_str());
1019 
1020   if (command) {
1021     // This is a command, return the first line of help
1022     return command->GetGuidanceLine(0).data();
1023   }
1024   else {
1025     // This is not a command, but a sub directory, return the title
1026     G4UIcommandTree* path = treeTop->FindCommandTree(itemText.c_str());
1027     if (path) return path->GetTitle().data();
1028   }
1029 
1030   return "";
1031 }
1032 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1033 /****************************************************************************************************/
1034 
1035 /****************************************************************************************************/
1036 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1037 G4String G4UIWin32::ConvertNewLines(const G4String& a_string)
1038 {
1039   // Geant4 uses UNIX's style for new lines (\n)
1040   // we must convert them to Windows' style (\r\n)
1041   G4String str = a_string;
1042   std::size_t index = str.find("\n", 0);
1043   while (index < str.length()) {
1044     str.replace(index, 1, "\r\n");
1045     // Advance index forward so the next iteration doesn't pick it up as well.
1046     index = str.find("\n", index + 2);
1047   }
1048   return str;
1049 }
1050 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1051 /****************************************************************************************************/
1052 
1053 /****************************************************************************************************/
1054 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1055 void G4UIWin32::HelpTreeDoubleClick(HTREEITEM item)
1056 {
1057   const char* item_path = GetItemPath(item);
1058   G4int l = strlen(item_path);
1059   Edit_SetText(fHWndComboEditor, (PTSTR)item_path);
1060   Edit_SetSel(fHWndComboEditor, l, l);
1061 
1062   SetFocus(fHWndComboEditor);
1063 }
1064 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1065 /****************************************************************************************************/
1066 
1067 /****************************************************************************************************/
1068 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1069 G4bool G4UIWin32::SaveLogFile(LPCTSTR fileName)
1070 {
1071   HANDLE hFile;
1072   G4bool bSuccess = false;
1073 
1074   hFile =
1075     CreateFile(fileName, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
1076   if (hFile != INVALID_HANDLE_VALUE) {
1077     DWORD dwTextLength;
1078 
1079     dwTextLength = GetWindowTextLength(fHWndEditor);
1080     // No need to bother if there's no text.
1081     if (dwTextLength > 0) {
1082       LPSTR text;
1083       DWORD dwBufferSize = dwTextLength + 1;
1084 
1085       text = (LPSTR)GlobalAlloc(GPTR, dwBufferSize);
1086       if (text != nullptr) {
1087         if (GetWindowTextA(fHWndEditor, text, dwBufferSize)) {
1088           DWORD dwWritten;
1089 
1090           if (WriteFile(hFile, text, dwTextLength, &dwWritten, nullptr)) bSuccess = true;
1091         }
1092         GlobalFree(text);
1093       }
1094     }
1095     CloseHandle(hFile);
1096   }
1097   return bSuccess;
1098 }
1099 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1100 /****************************************************************************************************/
1101 
1102 /****************************************************************************************************/
1103 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1104 void G4UIWin32::AddText(LPSTR text)
1105 {
1106   if ((fHWndEditor != nullptr) && (text != nullptr) && (text[0] != '\0')) {
1107     // Get current text length
1108     G4int ndx = GetWindowTextLength(fHWndEditor);
1109 
1110     // Select the end of the text
1111     SendMessage(fHWndEditor, EM_SETSEL, (WPARAM)ndx, (LPARAM)ndx);
1112     // Add the new text
1113     SendMessage(fHWndEditor, EM_REPLACESEL, (WPARAM)0, (LPARAM)text);
1114     // Scroll to the bottom
1115     SendMessage(fHWndEditor, WM_VSCROLL, SB_BOTTOM, NULL);
1116   }
1117 }
1118 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1119 /****************************************************************************************************/
1120 
1121 /****************************************************************************************************/
1122 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1123 void G4UIWin32::DoOpenMacro(HWND aWindow)
1124 {
1125   OPENFILENAME ofn;
1126   char szFileName[MAX_PATH] = "";
1127 
1128   ZeroMemory(&ofn, sizeof(ofn));
1129 
1130   ofn.lStructSize = sizeof(ofn);
1131   ofn.hwndOwner = aWindow;
1132   char fName[] = "Macro Files (*.mac)\0*.mac\0All Files (*.*)\0*.*\0";
1133   ofn.lpstrFilter = (PTSTR)fName;
1134   ofn.lpstrFile = (PTSTR)szFileName;
1135   ofn.nMaxFile = MAX_PATH;
1136   ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
1137   char dName[] = "mac";
1138   ofn.lpstrDefExt = (PTSTR)dName;
1139 
1140   if (GetOpenFileName(&ofn)) {
1141     G4String command = "/control/execute " + G4String(szFileName);
1142     ApplyShellCommand(command, exitSession, exitPause);
1143 
1144     SendDlgItemMessage(aWindow, IDC_MAIN_STATUS, SB_SETTEXT, 0, (LPARAM) "Opened macro...");
1145     SendDlgItemMessage(aWindow, IDC_MAIN_STATUS, SB_SETTEXT, 1, (LPARAM)szFileName);
1146   }
1147 }
1148 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1149 /****************************************************************************************************/
1150 
1151 /****************************************************************************************************/
1152 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1153 void G4UIWin32::DoSaveViewer(HWND aWindow)
1154 {
1155   OPENFILENAME ofn;
1156   char szFileName[MAX_PATH] = "";
1157 
1158   ZeroMemory(&ofn, sizeof(ofn));
1159 
1160   ofn.lStructSize = sizeof(ofn);
1161   ofn.hwndOwner = aWindow;
1162   char fName[] = "Macro Files (*.mac)\0*.mac\0All Files (*.*)\0*.*\0";
1163   ofn.lpstrFilter = (PTSTR)fName;
1164   ofn.lpstrFile = (PTSTR)szFileName;
1165   ofn.nMaxFile = MAX_PATH;
1166   char dName[] = "mac";
1167   ofn.lpstrDefExt = (PTSTR)dName;
1168   ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
1169 
1170   if (GetSaveFileName(&ofn)) {
1171     G4String command = "/vis/viewer/save " + G4String(szFileName);
1172     ApplyShellCommand(command, exitSession, exitPause);
1173 
1174     SendDlgItemMessage(aWindow, IDC_MAIN_STATUS, SB_SETTEXT, 0, (LPARAM) "State saved...");
1175     SendDlgItemMessage(aWindow, IDC_MAIN_STATUS, SB_SETTEXT, 1, (LPARAM)szFileName);
1176   }
1177 }
1178 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1179 /****************************************************************************************************/
1180 
1181 /****************************************************************************************************/
1182 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1183 void G4UIWin32::DoSaveLog(HWND aWindow)
1184 {
1185   OPENFILENAME ofn;
1186   char szFileName[MAX_PATH] = "";
1187 
1188   ZeroMemory(&ofn, sizeof(ofn));
1189 
1190   ofn.lStructSize = sizeof(ofn);
1191   ofn.hwndOwner = aWindow;
1192   char fName[] = "Log Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0";
1193   ofn.lpstrFilter = (PTSTR)fName;
1194   ofn.lpstrFile = (PTSTR)szFileName;
1195   ofn.nMaxFile = MAX_PATH;
1196   char dName[] = "txt";
1197   ofn.lpstrDefExt = (PTSTR)dName;
1198   ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
1199 
1200   if (GetSaveFileName(&ofn)) {
1201     if (SaveLogFile((PTSTR)szFileName)) {
1202       SendDlgItemMessage(aWindow, IDC_MAIN_STATUS, SB_SETTEXT, 0, (LPARAM) "Saved log file...");
1203       SendDlgItemMessage(aWindow, IDC_MAIN_STATUS, SB_SETTEXT, 1, (LPARAM)szFileName);
1204     }
1205   }
1206 }
1207 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1208 /****************************************************************************************************/
1209 
1210 /****************************************************************************************************/
1211 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1212 G4bool G4UIWin32::InitHelpTreeItems()
1213 {
1214   HTREEITEM newItem;
1215 
1216   G4UImanager* UI = G4UImanager::GetUIpointer();
1217   if (UI == nullptr) return false;
1218   G4UIcommandTree* treeTop = UI->GetTree();
1219 
1220   G4int treeSize = treeTop->GetTreeEntry();
1221   G4String commandText;
1222   for (G4int a = 0; a < treeSize; a++) {
1223     // Creating new item
1224     commandText = treeTop->GetTree(a + 1)->GetPathName().data();
1225 
1226     // Add the item to the tree-view control.
1227     newItem = AddItemToHelpTree((PTSTR)GetShortCommandPath(commandText).c_str());
1228 
1229     if (newItem == nullptr) return false;
1230 
1231     // Look for children
1232     CreateHelpTree(newItem, treeTop->GetTree(a + 1));
1233   }
1234 
1235   return true;
1236 }
1237 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1238 /****************************************************************************************************/
1239 
1240 /****************************************************************************************************/
1241 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1242 void G4UIWin32::CreateHelpTree(HTREEITEM aParent, G4UIcommandTree* aCommandTree)
1243 {
1244   if ((aParent != nullptr) && (aCommandTree != nullptr)) {
1245     // Creating new item
1246     HTREEITEM newItem;
1247 
1248     G4String commandText;
1249     // Get the Sub directories
1250     for (G4int a = 0; a < aCommandTree->GetTreeEntry(); a++) {
1251       commandText = aCommandTree->GetTree(a + 1)->GetPathName().data();
1252 
1253       // Add the item to the tree-view control.
1254       newItem =
1255         AddItemToHelpTree((PTSTR)GetShortCommandPath(commandText).c_str(), aParent);
1256 
1257       // Look for children
1258       CreateHelpTree(newItem, aCommandTree->GetTree(a + 1));
1259     }
1260 
1261     // Get the Commands
1262     for (G4int a = 0; a < aCommandTree->GetCommandEntry(); a++) {
1263       commandText = aCommandTree->GetCommand(a + 1)->GetCommandPath().data();
1264 
1265       // Add the item to the tree-view control.
1266       AddItemToHelpTree((PTSTR)GetShortCommandPath(commandText).c_str(), aParent);
1267     }
1268   }
1269 }
1270 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1271 /****************************************************************************************************/
1272 
1273 /****************************************************************************************************/
1274 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1275 HTREEITEM G4UIWin32::AddItemToHelpTree(LPTSTR lpszItem, HTREEITEM aParent)
1276 {
1277   TVITEM tvi;
1278   TVINSERTSTRUCT tvins;
1279   static auto hPrev = (HTREEITEM)TVI_FIRST;
1280 
1281   tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
1282 
1283   // Set the text of the item.
1284   tvi.pszText = lpszItem;
1285   tvi.cchTextMax = sizeof(tvi.pszText) / sizeof(tvi.pszText[0]);
1286 
1287   // Save the heading level in the item's application-defined
1288   // data area.
1289   tvi.lParam = (LPARAM)aParent;
1290   tvins.item = tvi;
1291   tvins.hInsertAfter = hPrev;
1292   // Set the parent item.
1293   tvins.hParent = aParent;
1294 
1295   // Add the item to the tree-view control.
1296   hPrev = (HTREEITEM)SendMessage(
1297     fHWndHelpTree, TVM_INSERTITEM, (WPARAM)0, (LPARAM)(LPTVINSERTSTRUCT)&tvins);
1298 
1299   if (hPrev == nullptr)
1300     return nullptr;
1301   else
1302     return hPrev;
1303 }
1304 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1305 /****************************************************************************************************/
1306 
1307 /****************************************************************************************************/
1308 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1309 G4String G4UIWin32::GetShortCommandPath(const G4String& commandPath)
1310 {
1311   G4String str = commandPath;
1312 
1313   if (str.find_last_of("/") == (str.size() - 1)) str = str.erase(str.size() - 1, 1);
1314 
1315   str = str.erase(0, str.find_last_of("/") + 1);
1316 
1317   return str;
1318 }
1319 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1320 /****************************************************************************************************/
1321 
1322 /****************************************************************************************************/
1323 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1324 LPSTR G4UIWin32::GetItemPath(HTREEITEM item)
1325 {
1326   // Get the text for the item.
1327   TVITEM tvitem;
1328   tvitem.mask = TVIF_TEXT;
1329   tvitem.hItem = item;
1330   TCHAR infoTipBuf[1024];
1331   tvitem.pszText = infoTipBuf;
1332   tvitem.cchTextMax = sizeof(infoTipBuf) / sizeof(TCHAR);
1333 
1334   std::string str = "";
1335   while  (item != nullptr) {
1336     TreeView_GetItem(fHWndHelpTree, &tvitem);
1337     str = "/" + std::string((PSTR)tvitem.pszText) + str;
1338 
1339     item = TreeView_GetParent(fHWndHelpTree, item);
1340     tvitem.hItem = item;
1341   }
1342 
1343   auto* result = new TCHAR[str.size() + 1];
1344   result[str.size()] = 0;
1345   std::copy(str.begin(), str.end(), result);
1346 
1347   return (LPSTR)result;
1348 }
1349 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1350 /****************************************************************************************************/
1351 
1352 /****************************************************************************************************/
1353 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1354 G4bool ConvertStringToInt(const char* aString, G4int& aInt)
1355 {
1356   aInt = 0;
1357   if (aString == nullptr) return false;
1358   char* s;
1359   G4long value = strtol(aString, &s, 10);
1360   if (s == aString) return false;
1361   aInt = value;
1362   return true;
1363 }
1364 /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
1365 /****************************************************************************************************/
1366