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