ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
G4UIWin32.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file G4UIWin32.cc
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 // Author: G.Barrand
27 // --------------------------------------------------------------------
28 
29 #ifdef G4UI_BUILD_WIN32_SESSION
30 
31 #include "G4UIWin32.hh"
32 
33 #include <string.h>
34 
35 #include <windows.h>
36 #include <windowsx.h>
37 #include <wingdi.h>
38 
39 #include "G4UImanager.hh"
40 #include "G4StateManager.hh"
41 #include "G4UIcommandTree.hh"
42 #include "G4UIcommandStatus.hh"
43 #include "G4Win32.hh"
44 
45 #define TEXT_MAX_LINES 300
46 
47 class TextBuffer
48 {
49 public:
50  TextBuffer();
51  ~TextBuffer();
52 
53  int GetNumberOfLines () { return linei;}
54  void SetHeightOfPage (int a_height) { heightOfPage = a_height; }
55  void SetEndOfPage (int a_value);
56  int GetEndOfPage () { return endOfPage; }
57 
58  void IncrementEndOfPage ();
59  void DecrementEndOfPage ();
60  void JumpDownEndOfPage ();
61  void JumpUpEndOfPage ();
62  G4bool AppendString (char* a_string);
63  void Draw (HDC a_hdc,RECT* a_rect);
64 
65 private:
66  G4String* lines;
67  int linen;
68  int linei;
69  int endOfPage,heightOfPage;
70  char spaces[256];
71 };
72 
73 TextBuffer::TextBuffer()
74  : linei(0),linen(TEXT_MAX_LINES),endOfPage(0),heightOfPage(12)
75 {
76  lines = new G4String[linen];
77  for(int count=0;count<256;count++) spaces[count] = ' ';
78 }
79 
80 TextBuffer::~TextBuffer()
81 {
82  delete [] lines;
83 }
84 
85 void TextBuffer::SetEndOfPage (int a_value)
86 {
87  if( (a_value<0) || (a_value>=linei)) {
88  endOfPage = linei-1;
89  } else {
90  endOfPage = a_value;
91  }
92 }
93 
94 void TextBuffer::IncrementEndOfPage ()
95 {
96  endOfPage++;
97  if(endOfPage>=linei) endOfPage = linei-1;
98 }
99 
100 void TextBuffer::DecrementEndOfPage ()
101 {
102  endOfPage--;
103  if(endOfPage<0) endOfPage = 0;
104 }
105 
106 void TextBuffer::JumpDownEndOfPage ()
107 {
108  endOfPage += heightOfPage;
109  if(endOfPage>=linei) endOfPage = linei-1;
110 }
111 
112 void TextBuffer::JumpUpEndOfPage ()
113 {
114  endOfPage -= heightOfPage;
115  if(endOfPage<0) endOfPage = 0;
116 }
117 
118 G4bool TextBuffer::AppendString (char* a_string)
119 {
120  G4bool value = false;
121  if( (a_string==NULL) || (a_string[0]=='\0') ) return value;
122  int length = strlen(a_string);
123  if(a_string[length-1]=='\n') {
124  lines[linei] += a_string;
125  lines[linei] = lines[linei].strip(G4String::trailing,'\n');
126  linei++;
127  value = true;
128  } else {
129  lines[linei] += a_string;
130  }
131  if(linei>=linen) {
132  for(int count=0;count<linen;count++) {
133  lines[count] = "";
134  }
135  linei = 0;
136  }
137  if(value==true) endOfPage = linei-1;
138  return value;
139 }
140 
141 void TextBuffer::Draw (HDC a_hdc,RECT* a_rect)
142 {
143  TEXTMETRIC tm;
144  GetTextMetrics (a_hdc,&tm);
145  short charWidth = (short)tm.tmAveCharWidth;
146  short charHeight = (short)(tm.tmHeight + tm.tmExternalLeading);
147  for(int row=0;row<heightOfPage;row++) {
148  int rowi = endOfPage - row;
149  short y = (short)(a_rect->bottom - charHeight * (row + 1));
150  if((rowi>=0)&&(rowi<linei)) {
151  TextOut (a_hdc,0,y,(char*)spaces,256); //Clear text background first.
152  const char* string = lines[rowi].data();
153  if(string!=NULL) {
154  TextOut (a_hdc,0,y,(char*)string,strlen((char*)string));
155  }
156  }
157  }
158 }
159 
160 /***************************************************************************/
161 static char mainClassName[] = "G4UIWin32";
162 static char textClassName[] = "G4UIWin32/Text";
163 static G4bool exitSession = true;
164 static G4bool exitPause = true;
165 static G4bool exitHelp = true;
166 static G4UIsession* tmpSession = NULL;
167 
168 static WNDPROC oldEditWindowProc;
169 static G4bool ConvertStringToInt(const char*,int&);
170 
171 static int actionIdentifier = 0;
172 
173 /***************************************************************************/
174 G4UIWin32::G4UIWin32 (
175 )
176 :mainWindow(NULL)
177 ,textWindow(NULL)
178 ,editWindow(NULL)
179 ,menuBar(NULL)
180 ,textBuffer(NULL)
181 ,textCols(80)
182 ,textRows(12)
183 ,fHelp(false)
184 ,fHelpChoice(0)
185 ,fHistoryPos(-1)
186 /***************************************************************************/
188 {
190  if(UI!=NULL) UI->SetSession(this);
191 
192  interactorManager = G4Win32::getInstance ();
193  static G4bool Done = FALSE;
194  if(Done==FALSE) {
195  WNDCLASS wc;
196  wc.style = CS_HREDRAW | CS_VREDRAW;
197  wc.lpfnWndProc = (WNDPROC)G4UIWin32::MainWindowProc;
198  wc.cbClsExtra = 0;
199  wc.cbWndExtra = 0;
200  wc.hInstance = ::GetModuleHandle(NULL);
201  wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
202  wc.hCursor = LoadCursor(NULL,IDC_ARROW);
203  wc.hbrBackground = GetStockBrush(WHITE_BRUSH);
204  wc.lpszMenuName = mainClassName;
205  wc.lpszClassName = mainClassName;
206  ::RegisterClass (&wc);
207 
208  wc.style = CS_HREDRAW | CS_VREDRAW;
209  wc.lpfnWndProc = (WNDPROC)G4UIWin32::TextWindowProc;
210  wc.cbClsExtra = 0;
211  wc.cbWndExtra = 0;
212  wc.hInstance = ::GetModuleHandle(NULL);
213  wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
214  wc.hCursor = LoadCursor(NULL,IDC_ARROW);
215  wc.hbrBackground = GetStockBrush(WHITE_BRUSH);
216  wc.lpszMenuName = textClassName;
217  wc.lpszClassName = textClassName;
218  ::RegisterClass (&wc);
219  Done = TRUE;
220  }
221 
222  menuBar = CreateMenu();
223  defaultMenu = CreatePopupMenu();
224  AppendMenu(menuBar,MF_POPUP,(UINT_PTR)defaultMenu,"Geant4");
225 
226  textBuffer = new TextBuffer();
227 
228  tmpSession = this;
229  mainWindow = ::CreateWindow(mainClassName,mainClassName,
230  WS_OVERLAPPEDWINDOW,
231  CW_USEDEFAULT,CW_USEDEFAULT,
232  0,0,
233  NULL,menuBar,
234  ::GetModuleHandle(NULL),
235  NULL);
236  tmpSession = NULL;
237  ::SetWindowLongPtr(mainWindow,GWLP_USERDATA,(LONG_PTR)this);
238 
239  ::SetForegroundWindow(mainWindow);
240  ::ShowWindow(mainWindow,SW_SHOWDEFAULT);
241  ::UpdateWindow(mainWindow);
242 
243  if(UI!=NULL) UI->SetCoutDestination(this);
244 }
245 /***************************************************************************/
246 G4UIWin32::~G4UIWin32 (
247 )
248 /***************************************************************************/
250 {
252  if(UI!=NULL) {
253  UI->SetSession(NULL);
254  UI->SetCoutDestination(NULL);
255  }
256  delete textBuffer;
257  if(textWindow!=NULL) ::SetWindowLongPtr(textWindow,GWLP_USERDATA,LONG(NULL));
258  if(mainWindow!=NULL) {
259  ::SetWindowLongPtr(mainWindow,GWLP_USERDATA,LONG(NULL));
260  ::DestroyWindow(mainWindow);
261  }
262 }
263 /***************************************************************************/
264 G4UIsession* G4UIWin32::SessionStart (
265 )
266 /***************************************************************************/
268 {
269  if(interactorManager==NULL) return this;
270  Prompt ("session");
271  exitSession = false;
272  interactorManager->DisableSecondaryLoop ();
273  void* event;
274  while((event = interactorManager->GetEvent())!=NULL) {
275  interactorManager->DispatchEvent(event);
276  if(exitSession==true) break;
277  }
278  interactorManager->EnableSecondaryLoop ();
279  return this;
280 }
281 /***************************************************************************/
282 void G4UIWin32::Prompt (
283  const G4String& a_prompt
284 )
285 /***************************************************************************/
287 {
288 }
289 /***************************************************************************/
290 void G4UIWin32::SessionTerminate (
291 )
292 /***************************************************************************/
294 {
295 }
296 /***************************************************************************/
297 void G4UIWin32::PauseSessionStart (
298  const G4String& a_state
299 )
300 /***************************************************************************/
302 {
303  if(a_state=="G4_pause> ") {
304  SecondaryLoop ("Pause, type continue to exit this state");
305  }
306 
307  if(a_state=="EndOfEvent") {
308  // Picking with feed back in event data Done here !!!
309  SecondaryLoop ("End of event, type continue to exit this state");
310  }
311 }
312 /***************************************************************************/
313 void G4UIWin32::SecondaryLoop (
314  const G4String& a_prompt
315 )
316 /***************************************************************************/
318 {
319  if(interactorManager==NULL) return;
320  Prompt(a_prompt);
321  exitPause = false;
322  void* event;
323  while((event = interactorManager->GetEvent())!=NULL) {
324  interactorManager->DispatchEvent(event);
325  if(exitPause==true) break;
326  }
327  Prompt("session");
328 }
329 /***************************************************************************/
330 G4int G4UIWin32::ReceiveG4cout (
331  const G4String& a_string
332 )
333 /***************************************************************************/
335 {
336  TextAppendString((char*)a_string.data());
337  return 0;
338 }
339 /***************************************************************************/
340 G4int G4UIWin32::ReceiveG4cerr (
341  const G4String& a_string
342 )
343 /***************************************************************************/
345 {
346  TextAppendString((char*)a_string.data());
347  return 0;
348 }
349 /***************************************************************************/
350 G4bool G4UIWin32::GetHelpChoice(
351  G4int& aInt
352 )
353 /***************************************************************************/
355 {
356  fHelp = true;
357  //
358  if(interactorManager==NULL) return false;
359  Prompt("Help");
360  exitHelp = false;
361  void* event;
362  while((event = interactorManager->GetEvent())!=NULL) {
363  interactorManager->DispatchEvent(event);
364  if(exitHelp==true) break;
365  }
366  Prompt("session");
367  //
368  if(fHelp==false) return false;
369  aInt = fHelpChoice;
370  fHelp = false;
371  return true;
372 }
373 /***************************************************************************/
374 void G4UIWin32::ExitHelp(
375 ) const
376 /***************************************************************************/
378 {
379 }
380 /***************************************************************************/
381 void G4UIWin32::AddMenu (
382  const char* a_name
383 ,const char* a_label
384 )
385 /***************************************************************************/
387 {
388  if(a_name==NULL) return;
389  if(defaultMenu!=NULL) {
390  DeleteMenu (menuBar,0,MF_BYPOSITION);
391  defaultMenu = NULL;
392  }
393  HMENU hMenu = CreatePopupMenu();
394  AppendMenu(menuBar,MF_POPUP,(UINT_PTR)hMenu,a_label);
395  AddInteractor(a_name,(G4Interactor)hMenu);
396  DrawMenuBar(mainWindow);
397 }
398 /***************************************************************************/
399 void G4UIWin32::AddButton (
400  const char* a_menu
401 ,const char* a_label
402 ,const char* a_command
403 )
404 /***************************************************************************/
406 {
407  if(a_menu==NULL) return;
408  if(a_label==NULL) return;
409  if(a_command==NULL) return;
410  HMENU hMenu = (HMENU)GetInteractor(a_menu);
411  actionIdentifier++;
412  commands[actionIdentifier] = a_command;
413  AppendMenu (hMenu,MF_STRING,actionIdentifier,a_label);
414 }
415 /***************************************************************************/
416 G4String G4UIWin32::GetCommand (
417  int a_id
418 )
419 /***************************************************************************/
421 {
422  return commands[a_id];
423 }
424 /***************************************************************************/
425 /***************************************************************************/
426 /***************************************************************************/
427 LRESULT CALLBACK G4UIWin32::MainWindowProc (
428  HWND a_window
429 ,UINT a_message
430 ,WPARAM a_wParam
431 ,LPARAM a_lParam
432 )
433 /***************************************************************************/
435 {
436  static short charWidth,charHeight;
437 
438  switch (a_message) {
439  case WM_CREATE:{
440  HDC hdc;
441  TEXTMETRIC tm;
442  RECT rect;
443  GetWindowRect (a_window,&rect);
444 
445  hdc = GetDC (a_window);
446  GetTextMetrics (hdc,&tm);
447  charWidth = (short)tm.tmAveCharWidth;
448  charHeight = (short)(tm.tmHeight + tm.tmExternalLeading);
449  ReleaseDC (a_window,hdc);
450 
451  G4UIWin32* This = (G4UIWin32*)tmpSession;
452  if(This!=NULL) {
453  This->textWindow = CreateWindow (textClassName,NULL,
454  WS_CHILD | WS_VISIBLE | WS_VSCROLL,
455  0,0,
456  This->textCols * charWidth,
457  This->textRows * charHeight,
458  a_window,NULL,
459  GetWindowInstance(a_window),
460  NULL);
461  ::SetWindowLongPtr (This->textWindow,GWLP_USERDATA,(LONG_PTR)This);
462 
463  This->editWindow = CreateWindow ("edit",NULL,
464  WS_CHILD | WS_VISIBLE | WS_BORDER,
465  0,This->textRows * charHeight,
466  This->textCols * charWidth,charHeight,
467  a_window,(HMENU)1,
468  GetWindowInstance(a_window),
469  NULL);
470  oldEditWindowProc = (WNDPROC)GetWindowLongPtr(This->editWindow,GWLP_WNDPROC);
471  SetWindowLongPtr (This->editWindow,GWLP_WNDPROC,(LONG_PTR)EditWindowProc);
472 
473  MoveWindow (a_window,
474  rect.left,rect.top,
475  2 * GetSystemMetrics(SM_CXFRAME) +
476  This->textCols * charWidth,
477  GetSystemMetrics(SM_CYCAPTION) +
478  2 * GetSystemMetrics(SM_CYFRAME) +
479  This->textRows * charHeight + charHeight,
480  TRUE);
481  }
482  }return 0;
483  case WM_SIZE:{
484  G4UIWin32* This = (G4UIWin32*)::GetWindowLongPtr(a_window,GWLP_USERDATA);
485  if(This!=NULL) {
486  // Client size :
487  int width = LOWORD(a_lParam);
488  int height = HIWORD(a_lParam);
489  int editHeight = /*2 * GetSystemMetrics(SM_CYBORDER) + */ charHeight;
490  MoveWindow (This->textWindow,
491  0,0,
492  width,height - editHeight,
493  FALSE);
494  MoveWindow (This->editWindow,
495  0,height - editHeight,
496  width,charHeight,
497  FALSE);
498  ((TextBuffer*)This->textBuffer)->SetHeightOfPage(height/charHeight);
499  }
500  }return 0;
501  case WM_SETFOCUS:{
502  G4UIWin32* This = (G4UIWin32*)::GetWindowLongPtr(a_window,GWLP_USERDATA);
503  if(This!=NULL) SetFocus (This->editWindow);
504  }return 0;
505  case WM_COMMAND:{
506  G4UIWin32* This = (G4UIWin32*)::GetWindowLongPtr(a_window,GWLP_USERDATA);
507  if(This!=NULL) {
508  if(This->fHelp==false) {
509  G4String command = This->GetCommand(a_wParam);
510  This->ApplyShellCommand (command,exitSession,exitPause);
511  }
512  }
513  }return 0;
514  case WM_DESTROY:
515  PostQuitMessage(0);
516  return 0;
517  }
518  return (DefWindowProc(a_window,a_message,a_wParam,a_lParam));
519 }
520 /***************************************************************************/
521 LRESULT CALLBACK G4UIWin32::TextWindowProc (
522  HWND a_window
523 ,UINT a_message
524 ,WPARAM a_wParam
525 ,LPARAM a_lParam
526 )
527 /***************************************************************************/
529 {
530  switch (a_message) {
531  case WM_PAINT:{
532  G4UIWin32* This = (G4UIWin32*)::GetWindowLongPtr(a_window,GWLP_USERDATA);
533  if(This!=NULL) {
534  TextBuffer* textBuffer = (TextBuffer*)This->textBuffer;
535  RECT rect;
536  GetClientRect (a_window,&rect);
537  PAINTSTRUCT ps;
538  HDC hdc = BeginPaint(a_window,&ps);
539  textBuffer->Draw(hdc,&rect);
540  EndPaint(a_window,&ps);
541  }
542  }return 0;
543  case WM_VSCROLL:{
544  G4UIWin32* This = (G4UIWin32*)::GetWindowLongPtr(a_window,GWLP_USERDATA);
545  if(This!=NULL) {
546  TextBuffer* textBuffer = (TextBuffer*)This->textBuffer;
547  int what = LOWORD(a_wParam);
548  switch(what) {
549  case SB_LINEUP:
550  textBuffer->DecrementEndOfPage();
551  break;
552  case SB_LINEDOWN:
553  textBuffer->IncrementEndOfPage();
554  break;
555  case SB_PAGEUP:
556  textBuffer->JumpUpEndOfPage();
557  break;
558  case SB_PAGEDOWN:
559  textBuffer->JumpDownEndOfPage();
560  break;
561  case SB_THUMBPOSITION:
562  case SB_THUMBTRACK:
563  textBuffer->SetEndOfPage(HIWORD(a_wParam));
564  break;
565  default:
566  return 0;
567  }
568  int eop = textBuffer->GetEndOfPage();
569  SetScrollPos(a_window,SB_VERT,eop,TRUE);
570  InvalidateRect(a_window,NULL,TRUE);
571  }}return 0;
572  case WM_DESTROY:
573  PostQuitMessage(0);
574  return 0;
575  }
576  return (DefWindowProc(a_window,a_message,a_wParam,a_lParam));
577 }
578 /***************************************************************************/
579 LRESULT CALLBACK G4UIWin32::EditWindowProc (
580  HWND a_window
581 ,UINT a_message
582 ,WPARAM a_wParam
583 ,LPARAM a_lParam
584 )
585 /***************************************************************************/
587 {
588  switch (a_message) {
589  case WM_KEYDOWN:
590  switch(a_wParam){
591  case VK_RETURN:{
592  G4UIWin32* This = (G4UIWin32*)::GetWindowLongPtr(
593  GetParent(a_window),GWLP_USERDATA);
594  char buffer[128];
595  GetWindowText (a_window,buffer,128);
596  G4String command (buffer);
597  //SetWindowText (a_window,"");
598  Edit_SetText(a_window,"");
599  Edit_SetSel(a_window,0,0);
600 
601  if(This!=NULL) {
602  if(This->fHelp==true) {
603  exitHelp = true;
604  This->fHelp = ConvertStringToInt(command.data(),This->fHelpChoice);
605  } else {
606  This->fHistory.push_back(command);
607  This->fHistoryPos = -1;
608  This->ApplyShellCommand (command,exitSession,exitPause);
609  }
610  }
611 
612  }break;
613  case VK_TAB:{
614  G4UIWin32* This = (G4UIWin32*)::GetWindowLongPtr(
615  GetParent(a_window),GWLP_USERDATA);
616  if( (This!=NULL) && (This->fHelp==true) ) break;
617  char buffer[128];
618  Edit_GetText(a_window,buffer,128);
619 
620  G4String command(buffer);
621 
622  if(This!=NULL) {
623  G4String cmd = This->Complete(command);
624  const char* d = cmd.data();
625  int l = strlen(d);
626  Edit_SetText(a_window,d);
627  Edit_SetSel(a_window,l,l);
628  }
629 
630  }break;
631  case VK_UP:{
632  G4UIWin32* This = (G4UIWin32*)::GetWindowLongPtr(
633  GetParent(a_window),GWLP_USERDATA);
634  if(This!=NULL) {
635  int pos = This->fHistoryPos== -1 ?
636  This->fHistory.size()-1 : This->fHistoryPos-1;
637  if((pos>=0)&&(pos<(int)This->fHistory.size())) {
638  G4String command = This->fHistory[pos];
639  const char* d = command.data();
640  int l = strlen(d);
641  Edit_SetText(a_window,d);
642  Edit_SetSel(a_window,l,l);
643  //
644  This->fHistoryPos = pos;
645  }
646  }
647  }return 0; //Do not jump into oldEditProc.
648  case VK_DOWN:{
649  G4UIWin32* This = (G4UIWin32*)::GetWindowLongPtr(
650  GetParent(a_window),GWLP_USERDATA);
651  if(This!=NULL) {
652  int pos = This->fHistoryPos + 1;
653  if((pos>=0)&&(pos<(int)This->fHistory.size())) {
654  G4String command = This->fHistory[pos];
655  const char* d = command.data();
656  int l = strlen(d);
657  Edit_SetText(a_window,d);
658  Edit_SetSel(a_window,l,l);
659  //
660  This->fHistoryPos = pos;
661  } else if(pos>=(int)This->fHistory.size()) {
662  Edit_SetText(a_window,"");
663  Edit_SetSel(a_window,0,0);
664  //
665  This->fHistoryPos = -1;
666  }
667  }
668  }return 0; //Do not jump into oldEditProc.
669  }
670  }
671  return CallWindowProc(oldEditWindowProc,
672  a_window,a_message,
673  a_wParam,a_lParam);
674 }
675 /***************************************************************************/
676 void G4UIWin32::TextAppendString (
677  char* a_string
678 )
679 /***************************************************************************/
681 {
682  if( (a_string==NULL) || (a_string[0]=='\0') ) return;
683  if(textWindow==NULL) return;
684  if(((TextBuffer*)textBuffer)->AppendString(a_string)==true) {
685  // The appending triggers and end of line, and then updates window :
686  RECT rect;
687  GetClientRect(textWindow,&rect);
688  InvalidateRect(textWindow,NULL,TRUE); //To erase background.
689  HDC hdc = GetDC(textWindow);
690  ((TextBuffer*)textBuffer)->Draw(hdc,&rect);
691  ReleaseDC (textWindow,hdc);
692  int linen = ((TextBuffer*)textBuffer)->GetNumberOfLines();
693  SetScrollRange(textWindow,SB_VERT,0,linen-1,TRUE);
694  SetScrollPos(textWindow,SB_VERT,linen-1,TRUE);
695  }
696 }
698 G4bool ConvertStringToInt(
699  const char* aString
700 ,int& aInt
701 )
704 {
705  aInt = 0;
706  if(aString==NULL) return false;
707  char* s;
708  long value = strtol(aString,&s,10);
709  if(s==aString) return false;
710  aInt = value;
711  return true;
712 }
713 
714 
715 #endif