1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 /*=========================================================================
19  *
20  *  Portions of this file are subject to the VTK Toolkit Version 3 copyright.
21  *
22  *  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
23  *
24  *  For complete copyright, license and disclaimer of warranty information
25  *  please refer to the NOTICE file at the top of the ITK source tree.
26  *
27  *=========================================================================*/
28 #include "itkWin32OutputWindow.h"
29 
30 namespace itk
31 {
32 /** */
33 HWND Win32OutputWindow:: m_OutputWindow = 0;
34 
35 Win32OutputWindow
~Win32OutputWindow()36 ::~Win32OutputWindow()
37 {
38   if ( Win32OutputWindow::m_OutputWindow )
39     {
40     DestroyWindow(Win32OutputWindow::m_OutputWindow);
41     Win32OutputWindow::m_OutputWindow = nullptr;
42     }
43 }
44 
45 /** */
46 LRESULT APIENTRY
47 Win32OutputWindow
WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)48 ::WndProc(HWND hWnd, UINT message,
49           WPARAM wParam,
50           LPARAM lParam)
51 {
52   switch ( message )
53     {
54     case WM_SIZE:
55       {
56       /** width of client area  */
57       int w = LOWORD(lParam);
58 
59       /** height of client area */
60       int h = HIWORD(lParam);
61 
62       MoveWindow(Win32OutputWindow::m_OutputWindow,
63                  0, 0, w, h, true);
64       }
65       break;
66     case WM_DESTROY:
67       Win32OutputWindow::m_OutputWindow = nullptr;
68       Object::GlobalWarningDisplayOff();
69       break;
70     case WM_CLOSE:
71       if ( Win32OutputWindow::m_OutputWindow )
72         {
73         DestroyWindow(Win32OutputWindow::m_OutputWindow);
74         Win32OutputWindow::m_OutputWindow = nullptr;
75         }
76       break;
77     case WM_CREATE:
78       break;
79     }
80   return DefWindowProc(hWnd, message, wParam, lParam);
81 }
82 
83 /** Display text in the window, and translate the \n to \r\n. */
84 void
85 Win32OutputWindow
DisplayText(const char * text)86 ::DisplayText(const char *text)
87 {
88   if ( !text )
89     {
90     return;
91     }
92 
93   if ( this->GetPromptUser() )
94     {
95     this->PromptText(text);
96     return;
97     }
98 
99   /** Create a buffer big enough to hold the entire text */
100   char *buffer = new char[strlen(text) + 1];
101 
102   /** Start at the beginning */
103   const char *NewLinePos = text;
104   while ( NewLinePos )
105     {
106     /** Find the next new line in text */
107     NewLinePos = strchr(text, '\n');
108     /** if no new line is found then just add the text */
109     if ( NewLinePos == 0 )
110       {
111       Win32OutputWindow::AddText(text);
112       }
113     /** if a new line is found copy it to the buffer
114      *  and add the buffer with a control new line */
115     else
116       {
117       int len = NewLinePos - text;
118       strncpy(buffer, text, len);
119       buffer[len] = 0;
120       text = NewLinePos + 1;
121       Win32OutputWindow::AddText(buffer);
122       Win32OutputWindow::AddText("\r\n");
123       }
124     }
125   delete[] buffer;
126 }
127 
128 /** Add some text to the EDIT control. */
129 void
130 Win32OutputWindow
AddText(const char * text)131 ::AddText(const char *text)
132 {
133   if ( !Initialize()  || ( strlen(text) == 0 ) )
134     {
135     return;
136     }
137 
138   /** move to the end of the text area */
139   SendMessage(Win32OutputWindow::m_OutputWindow, EM_SETSEL,
140               (WPARAM)-1, (LPARAM)-1);
141 
142   /** Append the text to the control */
143   SendMessage(Win32OutputWindow::m_OutputWindow, EM_REPLACESEL,
144               0, (LPARAM)text);
145 }
146 
147 /** initialize the output window with an EDIT control and
148  *  a container window. */
149 int
150 Win32OutputWindow
Initialize()151 ::Initialize()
152 {
153   /** check to see if it is already initialized */
154   if ( Win32OutputWindow::m_OutputWindow )
155     {
156     return 1;
157     }
158   /** Initialized the output window */
159 
160   WNDCLASS wndClass;
161   /** has the class been registered ? */
162   if ( !GetClassInfo(GetModuleHandle(nullptr), "OutputWindow", &wndClass) )
163     {
164     wndClass.style = CS_HREDRAW | CS_VREDRAW;
165     wndClass.lpfnWndProc = Win32OutputWindow::WndProc;
166     wndClass.cbClsExtra = 0;
167     wndClass.hInstance = GetModuleHandle(nullptr);
168     wndClass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
169     wndClass.hCursor = LoadCursor(nullptr, IDC_ARROW);
170     wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
171     wndClass.lpszMenuName = nullptr;
172     wndClass.lpszClassName = "OutputWindow";
173     /** doesn't use these extra 4 bytes, but app writers may want them,
174      *  so we provide them. */
175     wndClass.cbWndExtra = 4;
176     RegisterClass(&wndClass);
177     }
178 
179   /** create parent container window */
180   HWND win = CreateWindow(
181     "OutputWindow", "OutputWindow",
182     WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
183     0, 0, 1024, 768,
184     nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
185 
186   /** Now create child window with text display box */
187   CREATESTRUCT lpParam;
188   lpParam.hInstance = GetModuleHandle(nullptr);
189   lpParam.hMenu = nullptr;
190   lpParam.hwndParent = win;
191   lpParam.cx = 1024;
192   lpParam.cy = 768;
193   lpParam.x = 0;
194   lpParam.y = 0;
195   lpParam.style = ES_MULTILINE | ES_READONLY | WS_CHILD
196                   | ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_VISIBLE | WS_MAXIMIZE
197                   | WS_VSCROLL | WS_HSCROLL;
198 
199   lpParam.lpszName = "Output Control";
200   lpParam.lpszClass = "EDIT";  // use the RICHEDIT control widget
201   lpParam.dwExStyle = 0;
202 
203   /**Create the EDIT window as a child of win */
204   Win32OutputWindow::m_OutputWindow = CreateWindow(
205     lpParam.lpszClass,  // pointer to registered class name
206     "",                 // pointer to window name
207     lpParam.style,      // window style
208     lpParam.x,          // horizontal position of window
209     lpParam.y,          // vertical position of window
210     lpParam.cx,         // window width
211     lpParam.cy,         // window height
212     lpParam.hwndParent, // handle to parent or owner window
213     nullptr,               // handle to menu or child-window identifier
214     lpParam.hInstance,  // handle to application instance
215     &lpParam            // pointer to window-creation data
216     );
217   constexpr int maxsize = 5242880;
218 
219   SendMessage(Win32OutputWindow::m_OutputWindow,
220               EM_LIMITTEXT, maxsize, 0L);
221 
222   /** show the top level container window */
223   ShowWindow(win, SW_SHOW);
224   return 1;
225 }
226 
227 /** Prompt some text */
228 void
229 Win32OutputWindow
PromptText(const char * text)230 ::PromptText(const char *text)
231 {
232   std::ostringstream msg;
233 
234   msg << text << "\nPress Cancel to suppress any further messages.";
235   if ( MessageBox(nullptr, msg.str().c_str(), "Error",
236                   MB_ICONERROR | MB_OKCANCEL) == IDCANCEL )
237     {
238     Object::GlobalWarningDisplayOff();
239     }
240 }
241 } // end namespace itk
242