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