Added wxEVT_COMMAND_DIRCTRL_CHANGED for wxDirCtrl selection changes.
[wxWidgets.git] / samples / mfc / mfctest.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: mfctest.cpp
3 // Purpose: Sample to demonstrate mixing MFC and wxWidgets code
4 // Author: Julian Smart
5 // Id: $Id$
6 // Copyright: (c) Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // This sample pops up an initial wxWidgets frame, with a menu item
11 // that allows a new MFC window to be created. Note that CDummyWindow
12 // is a class that allows a wxWidgets window to be seen as a CWnd
13 // for the purposes of specifying a valid main window to the
14 // MFC initialisation.
15 //
16 // You can easily modify this code so that an MFC window pops up
17 // initially as the main frame, and allows wxWidgets frames to be
18 // created subsequently.
19 //
20 // (1) Make MyApp::OnInit not create a main window.
21 // (2) Make MFC's InitInstance create a main window, and remove
22 // creation of CDummyWindow.
23 //
24 // This can be accomplished by setting START_WITH_MFC_WINDOW to 1 below.
25
26 #define START_WITH_MFC_WINDOW 0
27
28 //
29 // IMPORTANT NOTES:
30 //
31 // (1) You may need to set wxUSE_MFC to 1 in include/wx/msw/setup.h but
32 // normally this shouldn't be needed any longer, i.e. it works without
33 // it for me (VZ)
34 //
35 // (2) You should link with MFC DLL, not static libraries: or, to use static
36 // run-time libraries, use this command for both building wxWidgets and
37 // the sample:
38 //
39 // nmake -f makefile.vc BUILD=debug SHARED=0 DEBUG_RUNTIME_LIBS=0 RUNTIME_LIBS=static all
40 //
41 // Unless the run-time library settings match for wxWidgets and MFC, you
42 // will get link errors for symbols such as __mbctype, __argc, and __argv
43 //
44 // (3) If you see bogus memory leaks within the MSVC IDE on exit, in this
45 // sample or in your own project, you must be using __WXDEBUG__ +
46 // WXUSINGDLL + _AFXDLL
47 // Unfortunately this confuses the MSVC/MFC leak detector. To do away with
48 // these bogus memory leaks, add this to the list of link objects, make it
49 // first: mfc[version][u]d.lib
50 // - [version] -> 42 or 70 or 80 etc
51 // - u if using Unicode
52
53 // Disable deprecation warnings from headers included from stdafx.h for VC8+
54 #ifndef _CRT_SECURE_NO_WARNINGS
55 #define _CRT_SECURE_NO_WARNINGS
56 #endif
57
58 // Also define WINVER to avoid warnings about it being undefined from the
59 // platform SDK headers (usually this is not necessary because it is done by wx
60 // headers but here we include the system ones before them)
61 #ifndef WINVER
62 #define WINVER 0x0600
63 #endif
64
65 #include "stdafx.h"
66
67 // For compilers that support precompilation, includes "wx/wx.h".
68 #include "wx/wxprec.h"
69
70 #ifdef __BORLANDC__
71 #pragma hdrstop
72 #endif
73
74 #ifndef WX_PRECOMP
75 #include "wx/wx.h"
76 #endif
77
78 #include "wx/evtloop.h"
79
80 #include "resource.h"
81
82 #include "mfctest.h"
83
84 /////////////////////////////////////////////////////////////////////////////
85
86 // theApp:
87 // Just creating this application object runs the whole application.
88 //
89 CTheApp theApp;
90
91 // wxWidgets elements
92
93 // Define a new application type
94 class MyApp: public wxApp
95 {
96 public:
97 virtual bool OnInit();
98
99 // we need to override this as the default behaviour only works when we're
100 // running wxWidgets main loop, not MFC one
101 virtual void ExitMainLoop();
102
103 wxFrame *CreateFrame();
104 };
105
106 class MyCanvas: public wxScrolledWindow
107 {
108 public:
109 MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size);
110 void OnPaint(wxPaintEvent& event);
111 void OnMouseEvent(wxMouseEvent& event);
112 DECLARE_EVENT_TABLE()
113 };
114
115 class MyChild: public wxFrame
116 {
117 public:
118 MyChild(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size, const long style);
119 virtual ~MyChild();
120
121 void OnQuit(wxCommandEvent& event);
122 void OnNew(wxCommandEvent& event);
123 void OnActivate(wxActivateEvent& event);
124
125 MyCanvas *canvas;
126
127 DECLARE_EVENT_TABLE()
128 };
129
130 // ID for the menu quit command
131 #define HELLO_QUIT 1
132 #define HELLO_NEW 2
133
134 DECLARE_APP(MyApp)
135
136 // notice use of IMPLEMENT_APP_NO_MAIN() instead of the usual IMPLEMENT_APP!
137 IMPLEMENT_APP_NO_MAIN(MyApp)
138
139 #ifdef _UNICODE
140 // In Unicode build MFC normally requires to manually change the entry point to
141 // wWinMainCRTStartup() but to avoid having to modify the project options to do
142 // it we provide an adapter for it.
143 extern "C" int wWinMainCRTStartup();
144
145 int WINAPI WinMain(HINSTANCE, HINSTANCE, char *, int)
146 {
147 wWinMainCRTStartup();
148 }
149 #endif // _UNICODE
150
151 CMainWindow::CMainWindow()
152 {
153 LoadAccelTable( wxT("MainAccelTable") );
154 Create( NULL, wxT("Hello Foundation Application"),
155 WS_OVERLAPPEDWINDOW, rectDefault, NULL, wxT("MainMenu") );
156 }
157
158 void CMainWindow::OnPaint()
159 {
160 CString s = wxT("Hello, Windows!");
161 CPaintDC dc( this );
162 CRect rect;
163
164 GetClientRect( rect );
165 dc.SetTextAlign( TA_BASELINE | TA_CENTER );
166 dc.SetTextColor( ::GetSysColor( COLOR_WINDOWTEXT ) );
167 dc.SetBkMode(TRANSPARENT);
168 dc.TextOut( ( rect.right / 2 ), ( rect.bottom / 2 ),
169 s, s.GetLength() );
170 }
171
172 void CMainWindow::OnAbout()
173 {
174 CDialog about( wxT("AboutBox"), this );
175 about.DoModal();
176 }
177
178 void CMainWindow::OnTest()
179 {
180 wxMessageBox(wxT("This is a wxWidgets message box.\nWe're about to create a new wxWidgets frame."), wxT("wxWidgets"), wxOK);
181 wxGetApp().CreateFrame();
182 }
183
184 // CMainWindow message map:
185 // Associate messages with member functions.
186 //
187 // It is implied that the ON_WM_PAINT macro expects a member function
188 // "void OnPaint()".
189 //
190 // It is implied that members connected with the ON_COMMAND macro
191 // receive no arguments and are void of return type, e.g., "void OnAbout()".
192 //
193 BEGIN_MESSAGE_MAP( CMainWindow, CFrameWnd )
194 //{{AFX_MSG_MAP( CMainWindow )
195 ON_WM_PAINT()
196 ON_COMMAND( IDM_ABOUT, OnAbout )
197 ON_COMMAND( IDM_TEST, OnTest )
198 //}}AFX_MSG_MAP
199 END_MESSAGE_MAP()
200
201 BOOL CTheApp::InitInstance()
202 {
203 if ( !CWinApp::InitInstance() )
204 return FALSE;
205
206 // TODO: cmd line parsing
207 WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
208 wxSetInstance(m_hInstance);
209 wxApp::m_nCmdShow = m_nCmdShow;
210 int argc = 0;
211 wxChar **argv = NULL;
212 wxEntryStart(argc, argv);
213 if ( !wxTheApp || !wxTheApp->CallOnInit() )
214 return FALSE;
215
216 #if START_WITH_MFC_WINDOW
217 // Demonstrate creation of an initial MFC main window.
218 m_pMainWnd = new CMainWindow();
219 m_pMainWnd->ShowWindow( m_nCmdShow );
220 m_pMainWnd->UpdateWindow();
221 #else
222 // Demonstrate creation of an initial wxWidgets main window.
223 // Wrap wxWidgets window in a dummy MFC window and
224 // make the main window.
225 if (wxTheApp && wxTheApp->GetTopWindow())
226 {
227 m_pMainWnd = new CDummyWindow((HWND) wxTheApp->GetTopWindow()->GetHWND());
228 }
229 #endif
230
231 return TRUE;
232 }
233
234 int CTheApp::ExitInstance()
235 {
236 #if !START_WITH_MFC_WINDOW
237 delete m_pMainWnd;
238 #endif
239
240 if ( wxTheApp )
241 wxTheApp->OnExit();
242 wxEntryCleanup();
243
244 return CWinApp::ExitInstance();
245 }
246
247 // Override this to provide wxWidgets message loop compatibility
248 BOOL CTheApp::PreTranslateMessage(MSG *msg)
249 {
250 wxEventLoop * const
251 evtLoop = static_cast<wxEventLoop *>(wxEventLoop::GetActive());
252 if ( evtLoop && evtLoop->PreProcessMessage(msg) )
253 return TRUE;
254
255 return CWinApp::PreTranslateMessage(msg);
256 }
257
258 BOOL CTheApp::OnIdle(LONG WXUNUSED(lCount))
259 {
260 return wxTheApp && wxTheApp->ProcessIdle();
261 }
262
263 /*********************************************************************
264 * wxWidgets elements
265 ********************************************************************/
266
267 bool MyApp::OnInit()
268 {
269 if ( !wxApp::OnInit() )
270 return false;
271
272 #if !START_WITH_MFC_WINDOW
273 // as we're not inside wxWidgets main loop, the default logic doesn't work
274 // in our case and we need to do this explicitly
275 SetExitOnFrameDelete(true);
276
277 (void) CreateFrame();
278 #endif
279
280 return true;
281 }
282
283 void MyApp::ExitMainLoop()
284 {
285 // instead of existing wxWidgets main loop, terminate the MFC one
286 ::PostQuitMessage(0);
287 }
288
289 wxFrame *MyApp::CreateFrame()
290 {
291 MyChild *subframe = new MyChild(NULL, wxT("Canvas Frame"), wxPoint(10, 10), wxSize(300, 300),
292 wxDEFAULT_FRAME_STYLE);
293
294 subframe->SetTitle(wxT("wxWidgets canvas frame"));
295
296 // Give it a status line
297 subframe->CreateStatusBar();
298
299 // Make a menubar
300 wxMenu *file_menu = new wxMenu;
301
302 file_menu->Append(HELLO_NEW, wxT("&New MFC Window"));
303 file_menu->Append(HELLO_QUIT, wxT("&Close"));
304
305 wxMenuBar *menu_bar = new wxMenuBar;
306
307 menu_bar->Append(file_menu, wxT("&File"));
308
309 // Associate the menu bar with the frame
310 subframe->SetMenuBar(menu_bar);
311
312 int width, height;
313 subframe->GetClientSize(&width, &height);
314
315 MyCanvas *canvas = new MyCanvas(subframe, wxPoint(0, 0), wxSize(width, height));
316 canvas->SetCursor(wxCursor(wxCURSOR_PENCIL));
317 subframe->canvas = canvas;
318 subframe->Show(true);
319
320 // Return the main frame window
321 return subframe;
322 }
323
324 BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
325 EVT_PAINT(MyCanvas::OnPaint)
326 EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent)
327 END_EVENT_TABLE()
328
329 // Define a constructor for my canvas
330 MyCanvas::MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size)
331 : wxScrolledWindow(parent, -1, pos, size)
332 {
333 }
334
335 // Define the repainting behaviour
336 void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
337 {
338 wxPaintDC dc(this);
339
340 dc.SetFont(* wxSWISS_FONT);
341 dc.SetPen(* wxGREEN_PEN);
342 dc.DrawLine(0, 0, 200, 200);
343 dc.DrawLine(200, 0, 0, 200);
344
345 dc.SetBrush(* wxCYAN_BRUSH);
346 dc.SetPen(* wxRED_PEN);
347 dc.DrawRectangle(100, 100, 100, 50);
348 dc.DrawRoundedRectangle(150, 150, 100, 50, 20);
349
350 dc.DrawEllipse(250, 250, 100, 50);
351 dc.DrawLine(50, 230, 200, 230);
352 dc.DrawText(wxT("This is a test string"), 50, 230);
353 }
354
355 // This implements a tiny doodling program! Drag the mouse using
356 // the left button.
357 void MyCanvas::OnMouseEvent(wxMouseEvent& event)
358 {
359 static long s_xpos = -1;
360 static long s_ypos = -1;
361
362 wxClientDC dc(this);
363 dc.SetPen(* wxBLACK_PEN);
364 wxPoint pos = event.GetPosition();
365 if (s_xpos > -1 && s_ypos > -1 && event.Dragging())
366 {
367 dc.DrawLine(s_xpos, s_ypos, pos.x, pos.y);
368 }
369
370 s_xpos = pos.x;
371 s_ypos = pos.y;
372 }
373
374 BEGIN_EVENT_TABLE(MyChild, wxFrame)
375 EVT_MENU(HELLO_QUIT, MyChild::OnQuit)
376 EVT_MENU(HELLO_NEW, MyChild::OnNew)
377 EVT_ACTIVATE(MyChild::OnActivate)
378 END_EVENT_TABLE()
379
380 MyChild::MyChild(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size, const long style)
381 : wxFrame(frame, -1, title, pos, size, style)
382 {
383 canvas = NULL;
384 }
385
386 MyChild::~MyChild()
387 {
388 if ( IsLastBeforeExit() )
389 PostQuitMessage(0);
390 }
391
392 void MyChild::OnQuit(wxCommandEvent& WXUNUSED(event))
393 {
394 Close(true);
395 }
396
397 void MyChild::OnNew(wxCommandEvent& WXUNUSED(event))
398 {
399 CMainWindow *mainWin = new CMainWindow();
400 mainWin->ShowWindow( TRUE );
401 mainWin->UpdateWindow();
402 }
403
404 void MyChild::OnActivate(wxActivateEvent& event)
405 {
406 if (event.GetActive() && canvas)
407 canvas->SetFocus();
408 }
409
410 // Dummy MFC window for specifying a valid main window to MFC, using
411 // a wxWidgets HWND.
412 CDummyWindow::CDummyWindow(HWND hWnd)
413 {
414 Attach(hWnd);
415 }
416
417 // Don't let the CWnd destructor delete the HWND
418 CDummyWindow::~CDummyWindow()
419 {
420 Detach();
421 }
422