test ShowFullScreen() to verify that restoring menu works correctly
[wxWidgets.git] / samples / mdi / mdi.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: mdi.cpp
3 // Purpose: MDI sample
4 // Author: Julian Smart
5 // Modified by: 2008-10-31 Vadim Zeitlin: big clean up
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1997 Julian Smart
9 // (c) 2008 Vadim Zeitlin
10 // Licence: wxWindows license
11 /////////////////////////////////////////////////////////////////////////////
12
13 // ===========================================================================
14 // declarations
15 // ===========================================================================
16
17 // ---------------------------------------------------------------------------
18 // headers
19 // ---------------------------------------------------------------------------
20
21 // For compilers that support precompilation, includes "wx/wx.h".
22 #include "wx/wxprec.h"
23
24 #ifdef __BORLANDC__
25 #pragma hdrstop
26 #endif
27
28 #ifndef WX_PRECOMP
29 #include "wx/wx.h"
30 #include "wx/mdi.h"
31 #endif
32
33 #include "wx/toolbar.h"
34
35 #if !defined(__WXMSW__)
36 #include "../sample.xpm"
37 #include "chart.xpm"
38 #endif
39
40 #include "bitmaps/new.xpm"
41 #include "bitmaps/open.xpm"
42 #include "bitmaps/save.xpm"
43 #include "bitmaps/copy.xpm"
44 #include "bitmaps/cut.xpm"
45 #include "bitmaps/paste.xpm"
46 #include "bitmaps/print.xpm"
47 #include "bitmaps/help.xpm"
48
49 // replace this 0 with 1 to build the sample using the generic MDI classes (you
50 // may also need to add src/generic/mdig.cpp to the build)
51 #if 0
52 #include "wx/generic/mdig.h"
53 #define wxMDIParentFrame wxGenericMDIParentFrame
54 #define wxMDIChildFrame wxGenericMDIChildFrame
55 #define wxMDIClientWindow wxGenericMDIClientWindow
56 #endif
57
58 #include "mdi.h"
59
60 IMPLEMENT_APP(MyApp)
61
62 // ---------------------------------------------------------------------------
63 // event tables
64 // ---------------------------------------------------------------------------
65
66 BEGIN_EVENT_TABLE(MyFrame, wxMDIParentFrame)
67 EVT_MENU(wxID_ABOUT, MyFrame::OnAbout)
68 EVT_MENU(wxID_NEW, MyFrame::OnNewWindow)
69 EVT_MENU(MDI_FULLSCREEN, MyFrame::OnFullScreen)
70 EVT_MENU(wxID_EXIT, MyFrame::OnQuit)
71
72 EVT_CLOSE(MyFrame::OnClose)
73 END_EVENT_TABLE()
74
75 // Note that wxID_NEW and wxID_ABOUT commands get passed
76 // to the parent window for processing, so no need to
77 // duplicate event handlers here.
78 BEGIN_EVENT_TABLE(MyChild, wxMDIChildFrame)
79 EVT_MENU(wxID_CLOSE, MyChild::OnClose)
80 EVT_MENU(MDI_REFRESH, MyChild::OnRefresh)
81 EVT_MENU(MDI_CHANGE_TITLE, MyChild::OnChangeTitle)
82 EVT_MENU(MDI_CHANGE_POSITION, MyChild::OnChangePosition)
83 EVT_MENU(MDI_CHANGE_SIZE, MyChild::OnChangeSize)
84
85 #if wxUSE_CLIPBOARD
86 EVT_MENU(wxID_PASTE, MyChild::OnPaste)
87 EVT_UPDATE_UI(wxID_PASTE, MyChild::OnUpdatePaste)
88 #endif // wxUSE_CLIPBOARD
89
90 EVT_SIZE(MyChild::OnSize)
91 EVT_MOVE(MyChild::OnMove)
92
93 EVT_CLOSE(MyChild::OnCloseWindow)
94 END_EVENT_TABLE()
95
96 BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
97 EVT_MOUSE_EVENTS(MyCanvas::OnEvent)
98 END_EVENT_TABLE()
99
100 // ===========================================================================
101 // implementation
102 // ===========================================================================
103
104 // ---------------------------------------------------------------------------
105 // MyApp
106 // ---------------------------------------------------------------------------
107
108 // Initialise this in OnInit, not statically
109 bool MyApp::OnInit()
110 {
111 if ( !wxApp::OnInit() )
112 return false;
113
114 // Create the main frame window
115
116 MyFrame *frame = new MyFrame;
117
118 frame->Show(true);
119
120 return true;
121 }
122
123 // ---------------------------------------------------------------------------
124 // MyFrame
125 // ---------------------------------------------------------------------------
126
127 // Define my frame constructor
128 MyFrame::MyFrame()
129 : wxMDIParentFrame(NULL, wxID_ANY, "wxWidgets MDI Sample",
130 wxDefaultPosition, wxSize(500, 400))
131 {
132 SetIcon(wxICON(sample));
133
134 // Make a menubar
135 #if wxUSE_MENUS
136 wxMenu *file_menu = new wxMenu;
137
138 file_menu->Append(wxID_NEW, "&New window\tCtrl-N", "Create a new child window");
139 file_menu->AppendCheckItem(MDI_FULLSCREEN, "Show &fullscreen\tCtrl-F");
140 file_menu->Append(wxID_EXIT, "&Exit\tAlt-X", "Quit the program");
141
142 wxMenu *help_menu = new wxMenu;
143 help_menu->Append(wxID_ABOUT, "&About\tF1");
144
145 wxMenuBar *menu_bar = new wxMenuBar;
146
147 menu_bar->Append(file_menu, "&File");
148 menu_bar->Append(help_menu, "&Help");
149
150 // Associate the menu bar with the frame
151 SetMenuBar(menu_bar);
152
153 #if 0
154 // Experimental: change the window menu
155 wxMenu* windowMenu = new wxMenu;
156 windowMenu->Append(5000, "My menu item!");
157 frame->SetWindowMenu(windowMenu);
158 #endif
159 #endif // wxUSE_MENUS
160
161 #if wxUSE_STATUSBAR
162 CreateStatusBar();
163 #endif // wxUSE_STATUSBAR
164
165
166 m_textWindow = new wxTextCtrl(this, wxID_ANY, "A help window",
167 wxDefaultPosition, wxDefaultSize,
168 wxTE_MULTILINE | wxSUNKEN_BORDER);
169
170 #if wxUSE_TOOLBAR
171 CreateToolBar(wxNO_BORDER | wxTB_FLAT | wxTB_HORIZONTAL);
172 InitToolBar(GetToolBar());
173 #endif // wxUSE_TOOLBAR
174
175 #if wxUSE_ACCEL
176 // Accelerators
177 wxAcceleratorEntry entries[3];
178 entries[0].Set(wxACCEL_CTRL, (int) 'N', wxID_NEW);
179 entries[1].Set(wxACCEL_CTRL, (int) 'X', wxID_EXIT);
180 entries[2].Set(wxACCEL_CTRL, (int) 'A', wxID_ABOUT);
181 wxAcceleratorTable accel(3, entries);
182 SetAcceleratorTable(accel);
183 #endif // wxUSE_ACCEL
184
185 // connect it only now, after creating m_textWindow
186 Connect(wxEVT_SIZE, wxSizeEventHandler(MyFrame::OnSize));
187 }
188
189 MyFrame::~MyFrame()
190 {
191 // and disconnect it to prevent accessing already deleted m_textWindow in
192 // the size event handler if it's called during destruction
193 Disconnect(wxEVT_SIZE, wxSizeEventHandler(MyFrame::OnSize));
194 }
195
196 void MyFrame::OnClose(wxCloseEvent& event)
197 {
198 unsigned numChildren = MyChild::GetChildrenCount();
199 if ( event.CanVeto() && (numChildren > 0) )
200 {
201 wxString msg;
202 msg.Printf("%d windows still open, close anyhow?", numChildren);
203 if ( wxMessageBox(msg, "Please confirm",
204 wxICON_QUESTION | wxYES_NO) != wxYES )
205 {
206 event.Veto();
207
208 return;
209 }
210 }
211
212 event.Skip();
213 }
214
215 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
216 {
217 Close();
218 }
219
220 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
221 {
222 (void)wxMessageBox("wxWidgets 2.0 MDI Demo\n"
223 "Author: Julian Smart (c) 1997\n"
224 "Usage: mdi.exe", "About MDI Demo");
225 }
226
227 void MyFrame::OnNewWindow(wxCommandEvent& WXUNUSED(event) )
228 {
229 // create and show another child frame
230 MyChild *subframe = new MyChild(this);
231 subframe->Show(true);
232 }
233
234 void MyFrame::OnFullScreen(wxCommandEvent& event)
235 {
236 ShowFullScreen(event.IsChecked());
237 }
238
239 void MyFrame::OnSize(wxSizeEvent& event)
240 {
241 int w, h;
242 GetClientSize(&w, &h);
243
244 m_textWindow->SetSize(0, 0, 200, h);
245 GetClientWindow()->SetSize(200, 0, w - 200, h);
246
247 // FIXME: On wxX11, we need the MDI frame to process this
248 // event, but on other platforms this should not
249 // be done.
250 #ifdef __WXUNIVERSAL__
251 event.Skip();
252 #else
253 wxUnusedVar(event);
254 #endif
255 }
256
257 #if wxUSE_TOOLBAR
258 void MyFrame::InitToolBar(wxToolBar* toolBar)
259 {
260 wxBitmap bitmaps[8];
261
262 bitmaps[0] = wxBitmap( new_xpm );
263 bitmaps[1] = wxBitmap( open_xpm );
264 bitmaps[2] = wxBitmap( save_xpm );
265 bitmaps[3] = wxBitmap( copy_xpm );
266 bitmaps[4] = wxBitmap( cut_xpm );
267 bitmaps[5] = wxBitmap( paste_xpm );
268 bitmaps[6] = wxBitmap( print_xpm );
269 bitmaps[7] = wxBitmap( help_xpm );
270
271 toolBar->AddTool(wxID_NEW, "New", bitmaps[0], "New file");
272 toolBar->AddTool(1, "Open", bitmaps[1], "Open file");
273 toolBar->AddTool(2, "Save", bitmaps[2], "Save file");
274 toolBar->AddSeparator();
275 toolBar->AddTool(3, "Copy", bitmaps[3], "Copy");
276 toolBar->AddTool(4, "Cut", bitmaps[4], "Cut");
277 toolBar->AddTool(5, "Paste", bitmaps[5], "Paste");
278 toolBar->AddSeparator();
279 toolBar->AddTool(6, "Print", bitmaps[6], "Print");
280 toolBar->AddSeparator();
281 toolBar->AddTool(wxID_ABOUT, "About", bitmaps[7], "Help");
282
283 toolBar->Realize();
284 }
285 #endif // wxUSE_TOOLBAR
286
287 // ---------------------------------------------------------------------------
288 // MyCanvas
289 // ---------------------------------------------------------------------------
290
291 // Define a constructor for my canvas
292 MyCanvas::MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size)
293 : wxScrolledWindow(parent, wxID_ANY, pos, size,
294 wxSUNKEN_BORDER |
295 wxNO_FULL_REPAINT_ON_RESIZE |
296 wxVSCROLL | wxHSCROLL)
297 {
298 SetBackgroundColour(wxColour("WHITE"));
299 SetCursor(wxCursor(wxCURSOR_PENCIL));
300
301 SetScrollbars(20, 20, 50, 50);
302
303 m_dirty = false;
304 }
305
306 // Define the repainting behaviour
307 void MyCanvas::OnDraw(wxDC& dc)
308 {
309 if ( !m_text.empty() )
310 dc.DrawText(m_text, 10, 10);
311
312 dc.SetFont(*wxSWISS_FONT);
313 dc.SetPen(*wxGREEN_PEN);
314 dc.DrawLine(0, 0, 200, 200);
315 dc.DrawLine(200, 0, 0, 200);
316
317 dc.SetBrush(*wxCYAN_BRUSH);
318 dc.SetPen(*wxRED_PEN);
319 dc.DrawRectangle(100, 100, 100, 50);
320 dc.DrawRoundedRectangle(150, 150, 100, 50, 20);
321
322 dc.DrawEllipse(250, 250, 100, 50);
323 #if wxUSE_SPLINES
324 dc.DrawSpline(50, 200, 50, 100, 200, 10);
325 #endif // wxUSE_SPLINES
326 dc.DrawLine(50, 230, 200, 230);
327 dc.DrawText("This is a test string", 50, 230);
328
329 wxPoint points[3];
330 points[0].x = 200; points[0].y = 300;
331 points[1].x = 100; points[1].y = 400;
332 points[2].x = 300; points[2].y = 400;
333
334 dc.DrawPolygon(3, points);
335 }
336
337 // This implements a tiny doodling program! Drag the mouse using the left
338 // button.
339 void MyCanvas::OnEvent(wxMouseEvent& event)
340 {
341 wxClientDC dc(this);
342 PrepareDC(dc);
343
344 wxPoint pt(event.GetLogicalPosition(dc));
345
346 static long xpos = -1;
347 static long ypos = -1;
348
349 if (xpos > -1 && ypos > -1 && event.Dragging())
350 {
351 dc.SetPen(*wxBLACK_PEN);
352 dc.DrawLine(xpos, ypos, pt.x, pt.y);
353
354 m_dirty = true;
355 }
356
357 xpos = pt.x;
358 ypos = pt.y;
359 }
360
361 // ---------------------------------------------------------------------------
362 // MyChild
363 // ---------------------------------------------------------------------------
364
365 unsigned MyChild::ms_numChildren = 0;
366
367 MyChild::MyChild(wxMDIParentFrame *parent)
368 : wxMDIChildFrame
369 (
370 parent,
371 wxID_ANY,
372 wxString::Format("Child %u", ++ms_numChildren)
373 )
374 {
375 m_canvas = new MyCanvas(this, wxPoint(0, 0), GetClientSize());
376
377 SetIcon(wxICON(chart));
378
379 const bool canBeResized = !IsAlwaysMaximized();
380
381 // create our menubar: it will be shown instead of the main frame one when
382 // we're active
383 #if wxUSE_MENUS
384 // Make a menubar
385 wxMenu *file_menu = new wxMenu;
386
387 file_menu->Append(wxID_NEW, "&New window\tCtrl-N");
388 file_menu->Append(wxID_CLOSE, "&Close child\tCtrl-W", "Close this window");
389 file_menu->AppendCheckItem(MDI_FULLSCREEN, "Show &fullscreen\tCtrl-F");
390 file_menu->Append(wxID_EXIT, "&Exit\tAlt-X", "Quit the program");
391
392 wxMenu *option_menu = new wxMenu;
393
394 option_menu->Append(MDI_REFRESH, "&Refresh picture");
395 option_menu->Append(MDI_CHANGE_TITLE, "Change &title...\tCtrl-T");
396 if ( canBeResized )
397 {
398 option_menu->AppendSeparator();
399 option_menu->Append(MDI_CHANGE_POSITION, "Move frame\tCtrl-M");
400 option_menu->Append(MDI_CHANGE_SIZE, "Resize frame\tCtrl-S");
401 }
402 #if wxUSE_CLIPBOARD
403 option_menu->AppendSeparator();
404 option_menu->Append(wxID_PASTE, "Copy text from clipboard\tCtrl-V");
405 #endif // wxUSE_CLIPBOARD
406
407 wxMenu *help_menu = new wxMenu;
408 help_menu->Append(wxID_ABOUT, "&About");
409
410 wxMenuBar *menu_bar = new wxMenuBar;
411
412 menu_bar->Append(file_menu, "&File");
413 menu_bar->Append(option_menu, "&Child");
414 menu_bar->Append(help_menu, "&Help");
415
416 // Associate the menu bar with the frame
417 SetMenuBar(menu_bar);
418 #endif // wxUSE_MENUS
419
420 // this should work for MDI frames as well as for normal ones, provided
421 // they can be resized at all
422 if ( canBeResized )
423 SetSizeHints(100, 100);
424 }
425
426 MyChild::~MyChild()
427 {
428 ms_numChildren--;
429 }
430
431 void MyChild::OnClose(wxCommandEvent& WXUNUSED(event))
432 {
433 Close(true);
434 }
435
436 void MyChild::OnRefresh(wxCommandEvent& WXUNUSED(event))
437 {
438 if ( m_canvas )
439 m_canvas->Refresh();
440 }
441
442 void MyChild::OnChangePosition(wxCommandEvent& WXUNUSED(event))
443 {
444 Move(10, 10);
445 }
446
447 void MyChild::OnChangeSize(wxCommandEvent& WXUNUSED(event))
448 {
449 SetClientSize(100, 100);
450 }
451
452 void MyChild::OnChangeTitle(wxCommandEvent& WXUNUSED(event))
453 {
454 #if wxUSE_TEXTDLG
455 static wxString s_title = "Canvas Frame";
456
457 wxString title = wxGetTextFromUser("Enter the new title for MDI child",
458 "MDI sample question",
459 s_title,
460 GetParent()->GetParent());
461 if ( !title )
462 return;
463
464 s_title = title;
465 SetTitle(s_title);
466 #endif // wxUSE_TEXTDLG
467 }
468
469 void MyChild::OnActivate(wxActivateEvent& event)
470 {
471 if ( event.GetActive() && m_canvas )
472 m_canvas->SetFocus();
473 }
474
475 void MyChild::OnMove(wxMoveEvent& event)
476 {
477 // VZ: here everything is totally wrong under MSW, the positions are
478 // different and both wrong (pos2 is off by 2 pixels for me which seems
479 // to be the width of the MDI canvas border)
480 wxPoint pos1 = event.GetPosition(),
481 pos2 = GetPosition();
482 wxLogStatus("position from event: (%d, %d), from frame (%d, %d)",
483 pos1.x, pos1.y, pos2.x, pos2.y);
484
485 event.Skip();
486 }
487
488 void MyChild::OnSize(wxSizeEvent& event)
489 {
490 // VZ: under MSW the size event carries the client size (quite
491 // unexpectedly) *except* for the very first one which has the full
492 // size... what should it really be? TODO: check under wxGTK
493 wxSize size1 = event.GetSize(),
494 size2 = GetSize(),
495 size3 = GetClientSize();
496 wxLogStatus("size from event: %dx%d, from frame %dx%d, client %dx%d",
497 size1.x, size1.y, size2.x, size2.y, size3.x, size3.y);
498
499 event.Skip();
500 }
501
502 void MyChild::OnCloseWindow(wxCloseEvent& event)
503 {
504 if ( m_canvas && m_canvas->IsDirty() )
505 {
506 if ( wxMessageBox("Really close?", "Please confirm",
507 wxICON_QUESTION | wxYES_NO) != wxYES )
508 {
509 event.Veto();
510
511 return;
512 }
513 }
514
515 event.Skip();
516 }
517
518 #if wxUSE_CLIPBOARD
519
520 #include "wx/clipbrd.h"
521
522 void MyChild::OnPaste(wxCommandEvent& WXUNUSED(event))
523 {
524 wxClipboardLocker lock;
525 wxTextDataObject data;
526 m_canvas->SetText(wxTheClipboard->GetData(data)
527 ? data.GetText()
528 : wxString("No text on clipboard"));
529 }
530
531 void MyChild::OnUpdatePaste(wxUpdateUIEvent& event)
532 {
533 wxClipboardLocker lock;
534 event.Enable( wxTheClipboard->IsSupported(wxDF_TEXT) );
535 }
536
537 #endif // wxUSE_CLIPBOARD