don't generate non-MSVC makefiles for MSVC-only samples
[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 // (4) Unicode builds may produce the linker error "unresolved external symbol _WinMain@16".
54 // MFC requires you to manually add the Unicode entry point to the linker settings,
55 // Entry point symbol -> wWinMainCRTStartup
56
57 #include "stdafx.h"
58
59 // For compilers that support precompilation, includes "wx/wx.h".
60 #include "wx/wxprec.h"
61
62 #ifdef __BORLANDC__
63 #pragma hdrstop
64 #endif
65
66 #ifndef WX_PRECOMP
67 #include "wx/wx.h"
68 #endif
69
70 #include "wx/evtloop.h"
71
72 #include "resource.h"
73
74 #include "mfctest.h"
75
76 /////////////////////////////////////////////////////////////////////////////
77
78 // theApp:
79 // Just creating this application object runs the whole application.
80 //
81 CTheApp theApp;
82
83 // wxWidgets elements
84
85 // Define a new application type
86 class MyApp: public wxApp
87 {
88 public:
89 virtual bool OnInit();
90
91 // we need to override this as the default behaviour only works when we're
92 // running wxWidgets main loop, not MFC one
93 virtual void ExitMainLoop();
94
95 wxFrame *CreateFrame();
96 };
97
98 class MyCanvas: public wxScrolledWindow
99 {
100 public:
101 MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size);
102 void OnPaint(wxPaintEvent& event);
103 void OnMouseEvent(wxMouseEvent& event);
104 DECLARE_EVENT_TABLE()
105 };
106
107 class MyChild: public wxFrame
108 {
109 public:
110 MyChild(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size, const long style);
111 virtual ~MyChild();
112
113 void OnQuit(wxCommandEvent& event);
114 void OnNew(wxCommandEvent& event);
115 void OnActivate(wxActivateEvent& event);
116
117 MyCanvas *canvas;
118
119 DECLARE_EVENT_TABLE()
120 };
121
122 // ID for the menu quit command
123 #define HELLO_QUIT 1
124 #define HELLO_NEW 2
125
126 DECLARE_APP(MyApp)
127
128 // notice use of IMPLEMENT_APP_NO_MAIN() instead of the usual IMPLEMENT_APP!
129 IMPLEMENT_APP_NO_MAIN(MyApp)
130
131 CMainWindow::CMainWindow()
132 {
133 LoadAccelTable( _T("MainAccelTable") );
134 Create( NULL, _T("Hello Foundation Application"),
135 WS_OVERLAPPEDWINDOW, rectDefault, NULL, _T("MainMenu") );
136 }
137
138 void CMainWindow::OnPaint()
139 {
140 CString s = _T("Hello, Windows!");
141 CPaintDC dc( this );
142 CRect rect;
143
144 GetClientRect( rect );
145 dc.SetTextAlign( TA_BASELINE | TA_CENTER );
146 dc.SetTextColor( ::GetSysColor( COLOR_WINDOWTEXT ) );
147 dc.SetBkMode(TRANSPARENT);
148 dc.TextOut( ( rect.right / 2 ), ( rect.bottom / 2 ),
149 s, s.GetLength() );
150 }
151
152 void CMainWindow::OnAbout()
153 {
154 CDialog about( _T("AboutBox"), this );
155 about.DoModal();
156 }
157
158 void CMainWindow::OnTest()
159 {
160 wxMessageBox(_T("This is a wxWidgets message box.\nWe're about to create a new wxWidgets frame."), _T("wxWidgets"), wxOK);
161 wxGetApp().CreateFrame();
162 }
163
164 // CMainWindow message map:
165 // Associate messages with member functions.
166 //
167 // It is implied that the ON_WM_PAINT macro expects a member function
168 // "void OnPaint()".
169 //
170 // It is implied that members connected with the ON_COMMAND macro
171 // receive no arguments and are void of return type, e.g., "void OnAbout()".
172 //
173 BEGIN_MESSAGE_MAP( CMainWindow, CFrameWnd )
174 //{{AFX_MSG_MAP( CMainWindow )
175 ON_WM_PAINT()
176 ON_COMMAND( IDM_ABOUT, OnAbout )
177 ON_COMMAND( IDM_TEST, OnTest )
178 //}}AFX_MSG_MAP
179 END_MESSAGE_MAP()
180
181 BOOL CTheApp::InitInstance()
182 {
183 if ( !CWinApp::InitInstance() )
184 return FALSE;
185
186 // TODO: cmd line parsing
187 WXDLLIMPEXP_BASE void wxSetInstance(HINSTANCE hInst);
188 wxSetInstance(m_hInstance);
189 wxApp::m_nCmdShow = m_nCmdShow;
190 int argc = 0;
191 wxChar **argv = NULL;
192 wxEntryStart(argc, argv);
193 if ( !wxTheApp || !wxTheApp->CallOnInit() )
194 return FALSE;
195
196 #if START_WITH_MFC_WINDOW
197 // Demonstrate creation of an initial MFC main window.
198 m_pMainWnd = new CMainWindow();
199 m_pMainWnd->ShowWindow( m_nCmdShow );
200 m_pMainWnd->UpdateWindow();
201 #else
202 // Demonstrate creation of an initial wxWidgets main window.
203 // Wrap wxWidgets window in a dummy MFC window and
204 // make the main window.
205 if (wxTheApp && wxTheApp->GetTopWindow())
206 {
207 m_pMainWnd = new CDummyWindow((HWND) wxTheApp->GetTopWindow()->GetHWND());
208 }
209 #endif
210
211 return TRUE;
212 }
213
214 int CTheApp::ExitInstance()
215 {
216 #if !START_WITH_MFC_WINDOW
217 delete m_pMainWnd;
218 #endif
219
220 if ( wxTheApp )
221 wxTheApp->OnExit();
222 wxEntryCleanup();
223
224 return CWinApp::ExitInstance();
225 }
226
227 // Override this to provide wxWidgets message loop compatibility
228 BOOL CTheApp::PreTranslateMessage(MSG *msg)
229 {
230 wxEventLoop * const
231 evtLoop = static_cast<wxEventLoop *>(wxEventLoop::GetActive());
232 if ( evtLoop && evtLoop->PreProcessMessage(msg) )
233 return TRUE;
234
235 return CWinApp::PreTranslateMessage(msg);
236 }
237
238 BOOL CTheApp::OnIdle(LONG WXUNUSED(lCount))
239 {
240 return wxTheApp && wxTheApp->ProcessIdle();
241 }
242
243 /*********************************************************************
244 * wxWidgets elements
245 ********************************************************************/
246
247 bool MyApp::OnInit()
248 {
249 if ( !wxApp::OnInit() )
250 return false;
251
252 #if !START_WITH_MFC_WINDOW
253 // as we're not inside wxWidgets main loop, the default logic doesn't work
254 // in our case and we need to do this explicitly
255 SetExitOnFrameDelete(true);
256
257 (void) CreateFrame();
258 #endif
259
260 return true;
261 }
262
263 void MyApp::ExitMainLoop()
264 {
265 // instead of existing wxWidgets main loop, terminate the MFC one
266 ::PostQuitMessage(0);
267 }
268
269 wxFrame *MyApp::CreateFrame()
270 {
271 MyChild *subframe = new MyChild(NULL, _T("Canvas Frame"), wxPoint(10, 10), wxSize(300, 300),
272 wxDEFAULT_FRAME_STYLE);
273
274 subframe->SetTitle(_T("wxWidgets canvas frame"));
275
276 // Give it a status line
277 subframe->CreateStatusBar();
278
279 // Make a menubar
280 wxMenu *file_menu = new wxMenu;
281
282 file_menu->Append(HELLO_NEW, _T("&New MFC Window"));
283 file_menu->Append(HELLO_QUIT, _T("&Close"));
284
285 wxMenuBar *menu_bar = new wxMenuBar;
286
287 menu_bar->Append(file_menu, _T("&File"));
288
289 // Associate the menu bar with the frame
290 subframe->SetMenuBar(menu_bar);
291
292 int width, height;
293 subframe->GetClientSize(&width, &height);
294
295 MyCanvas *canvas = new MyCanvas(subframe, wxPoint(0, 0), wxSize(width, height));
296 canvas->SetCursor(wxCursor(wxCURSOR_PENCIL));
297 subframe->canvas = canvas;
298 subframe->Show(true);
299
300 // Return the main frame window
301 return subframe;
302 }
303
304 BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
305 EVT_PAINT(MyCanvas::OnPaint)
306 EVT_MOUSE_EVENTS(MyCanvas::OnMouseEvent)
307 END_EVENT_TABLE()
308
309 // Define a constructor for my canvas
310 MyCanvas::MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size)
311 : wxScrolledWindow(parent, -1, pos, size)
312 {
313 }
314
315 // Define the repainting behaviour
316 void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
317 {
318 wxPaintDC dc(this);
319
320 dc.SetFont(* wxSWISS_FONT);
321 dc.SetPen(* wxGREEN_PEN);
322 dc.DrawLine(0, 0, 200, 200);
323 dc.DrawLine(200, 0, 0, 200);
324
325 dc.SetBrush(* wxCYAN_BRUSH);
326 dc.SetPen(* wxRED_PEN);
327 dc.DrawRectangle(100, 100, 100, 50);
328 dc.DrawRoundedRectangle(150, 150, 100, 50, 20);
329
330 dc.DrawEllipse(250, 250, 100, 50);
331 dc.DrawLine(50, 230, 200, 230);
332 dc.DrawText(_T("This is a test string"), 50, 230);
333 }
334
335 // This implements a tiny doodling program! Drag the mouse using
336 // the left button.
337 void MyCanvas::OnMouseEvent(wxMouseEvent& event)
338 {
339 static long s_xpos = -1;
340 static long s_ypos = -1;
341
342 wxClientDC dc(this);
343 dc.SetPen(* wxBLACK_PEN);
344 wxPoint pos = event.GetPosition();
345 if (s_xpos > -1 && s_ypos > -1 && event.Dragging())
346 {
347 dc.DrawLine(s_xpos, s_ypos, pos.x, pos.y);
348 }
349
350 s_xpos = pos.x;
351 s_ypos = pos.y;
352 }
353
354 BEGIN_EVENT_TABLE(MyChild, wxFrame)
355 EVT_MENU(HELLO_QUIT, MyChild::OnQuit)
356 EVT_MENU(HELLO_NEW, MyChild::OnNew)
357 EVT_ACTIVATE(MyChild::OnActivate)
358 END_EVENT_TABLE()
359
360 MyChild::MyChild(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size, const long style)
361 : wxFrame(frame, -1, title, pos, size, style)
362 {
363 canvas = NULL;
364 }
365
366 MyChild::~MyChild()
367 {
368 if ( IsLastBeforeExit() )
369 PostQuitMessage(0);
370 }
371
372 void MyChild::OnQuit(wxCommandEvent& WXUNUSED(event))
373 {
374 Close(true);
375 }
376
377 void MyChild::OnNew(wxCommandEvent& WXUNUSED(event))
378 {
379 CMainWindow *mainWin = new CMainWindow();
380 mainWin->ShowWindow( TRUE );
381 mainWin->UpdateWindow();
382 }
383
384 void MyChild::OnActivate(wxActivateEvent& event)
385 {
386 if (event.GetActive() && canvas)
387 canvas->SetFocus();
388 }
389
390 // Dummy MFC window for specifying a valid main window to MFC, using
391 // a wxWidgets HWND.
392 CDummyWindow::CDummyWindow(HWND hWnd)
393 {
394 Attach(hWnd);
395 }
396
397 // Don't let the CWnd destructor delete the HWND
398 CDummyWindow::~CDummyWindow()
399 {
400 Detach();
401 }
402