wxaui/tabmdi size fix for gtk
[wxWidgets.git] / src / aui / tabmdi.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/tabmdi.cpp
3 // Purpose: Generic MDI (Multiple Document Interface) classes
4 // Author: Hans Van Leemputten
5 // Modified by: Benjamin I. Williams / Kirix Corporation
6 // Created: 29/07/2002
7 // RCS-ID: $Id$
8 // Copyright: (c) Hans Van Leemputten
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_MDI
28
29 #include "wx/aui/tabmdi.h"
30
31 #ifndef WX_PRECOMP
32 #include "wx/panel.h"
33 #include "wx/menu.h"
34 #include "wx/intl.h"
35 #include "wx/log.h"
36 #include "wx/settings.h"
37 #endif //WX_PRECOMP
38
39 #include "wx/stockitem.h"
40
41 enum MDI_MENU_ID
42 {
43 wxWINDOWCLOSE = 4001,
44 wxWINDOWCLOSEALL,
45 wxWINDOWNEXT,
46 wxWINDOWPREV
47 };
48
49 //-----------------------------------------------------------------------------
50 // wxTabMDIParentFrame
51 //-----------------------------------------------------------------------------
52
53 IMPLEMENT_DYNAMIC_CLASS(wxTabMDIParentFrame, wxFrame)
54
55 BEGIN_EVENT_TABLE(wxTabMDIParentFrame, wxFrame)
56 #if wxUSE_MENUS
57 EVT_MENU (wxID_ANY, wxTabMDIParentFrame::DoHandleMenu)
58 #endif
59 END_EVENT_TABLE()
60
61 wxTabMDIParentFrame::wxTabMDIParentFrame()
62 {
63 Init();
64 }
65
66 wxTabMDIParentFrame::wxTabMDIParentFrame(wxWindow *parent,
67 wxWindowID id,
68 const wxString& title,
69 const wxPoint& pos,
70 const wxSize& size,
71 long style,
72 const wxString& name)
73 {
74 Init();
75 (void)Create(parent, id, title, pos, size, style, name);
76 }
77
78 wxTabMDIParentFrame::~wxTabMDIParentFrame()
79 {
80 // Make sure the client window is destructed before the menu bars are!
81 wxDELETE(m_pClientWindow);
82
83 #if wxUSE_MENUS
84 RemoveWindowMenu(GetMenuBar());
85 delete m_pWindowMenu;
86 #endif // wxUSE_MENUS
87 }
88
89 bool wxTabMDIParentFrame::Create(wxWindow *parent,
90 wxWindowID id,
91 const wxString& title,
92 const wxPoint& pos,
93 const wxSize& size,
94 long style,
95 const wxString& name)
96 {
97 #if wxUSE_MENUS
98 // this style can be used to prevent a window from having the standard MDI
99 // "Window" menu
100 if (!(style & wxFRAME_NO_WINDOW_MENU))
101 {
102 m_pWindowMenu = new wxMenu;
103 m_pWindowMenu->Append(wxWINDOWCLOSE, _("Cl&ose"));
104 m_pWindowMenu->Append(wxWINDOWCLOSEALL, _("Close All"));
105 m_pWindowMenu->AppendSeparator();
106 m_pWindowMenu->Append(wxWINDOWNEXT, _("&Next"));
107 m_pWindowMenu->Append(wxWINDOWPREV, _("&Previous"));
108 }
109 #endif // wxUSE_MENUS
110
111 wxFrame::Create(parent, id, title, pos, size, style, name);
112 OnCreateClient();
113 return true;
114 }
115
116 #if wxUSE_MENUS
117 void wxTabMDIParentFrame::SetWindowMenu(wxMenu* pMenu)
118 {
119 // Replace the window menu from the currently loaded menu bar.
120 wxMenuBar *pMenuBar = GetMenuBar();
121
122 if (m_pWindowMenu)
123 {
124 RemoveWindowMenu(pMenuBar);
125 wxDELETE(m_pWindowMenu);
126 }
127
128 if (pMenu)
129 {
130 m_pWindowMenu = pMenu;
131 AddWindowMenu(pMenuBar);
132 }
133 }
134
135 void wxTabMDIParentFrame::SetMenuBar(wxMenuBar* pMenuBar)
136 {
137 // Remove the Window menu from the old menu bar
138 RemoveWindowMenu(GetMenuBar());
139
140 // Add the Window menu to the new menu bar.
141 AddWindowMenu(pMenuBar);
142
143 wxFrame::SetMenuBar(pMenuBar);
144 m_pMyMenuBar = GetMenuBar();
145 }
146 #endif // wxUSE_MENUS
147
148 void wxTabMDIParentFrame::SetChildMenuBar(wxTabMDIChildFrame* pChild)
149 {
150 #if wxUSE_MENUS
151 if (!pChild)
152 {
153 // No Child, set Our menu bar back.
154 SetMenuBar(m_pMyMenuBar);
155
156 // Make sure we know our menu bar is in use
157 //m_pMyMenuBar = NULL;
158 }
159 else
160 {
161 if (pChild->GetMenuBar() == NULL)
162 return;
163
164 // Do we need to save the current bar?
165 if (m_pMyMenuBar == NULL)
166 m_pMyMenuBar = GetMenuBar();
167
168 SetMenuBar(pChild->GetMenuBar());
169 }
170 #endif // wxUSE_MENUS
171 }
172
173 bool wxTabMDIParentFrame::ProcessEvent(wxEvent& event)
174 {
175 // Stops the same event being processed repeatedly
176 static wxEventType inEvent = wxEVT_NULL;
177 if (inEvent == event.GetEventType())
178 return false;
179
180 inEvent = event.GetEventType();
181
182 // Let the active child (if any) process the event first.
183 bool res = false;
184 if (m_pActiveChild &&
185 event.IsCommandEvent() &&
186 event.GetEventObject() != m_pClientWindow &&
187 !(event.GetEventType() == wxEVT_ACTIVATE ||
188 event.GetEventType() == wxEVT_SET_FOCUS ||
189 event.GetEventType() == wxEVT_KILL_FOCUS ||
190 event.GetEventType() == wxEVT_CHILD_FOCUS ||
191 event.GetEventType() == wxEVT_COMMAND_SET_FOCUS ||
192 event.GetEventType() == wxEVT_COMMAND_KILL_FOCUS )
193 )
194 {
195 res = m_pActiveChild->GetEventHandler()->ProcessEvent(event);
196 }
197
198 // If the event was not handled this frame will handle it!
199 if (!res)
200 {
201 //res = GetEventHandler()->ProcessEvent(event);
202 res = wxEvtHandler::ProcessEvent(event);
203 }
204
205 inEvent = wxEVT_NULL;
206
207 return res;
208 }
209
210 wxTabMDIChildFrame *wxTabMDIParentFrame::GetActiveChild() const
211 {
212 return m_pActiveChild;
213 }
214
215 void wxTabMDIParentFrame::SetActiveChild(wxTabMDIChildFrame* pChildFrame)
216 {
217 m_pActiveChild = pChildFrame;
218 }
219
220 wxTabMDIClientWindow *wxTabMDIParentFrame::GetClientWindow() const
221 {
222 return m_pClientWindow;
223 }
224
225 wxTabMDIClientWindow *wxTabMDIParentFrame::OnCreateClient()
226 {
227 m_pClientWindow = new wxTabMDIClientWindow( this );
228 return m_pClientWindow;
229 }
230
231 void wxTabMDIParentFrame::ActivateNext()
232 {
233 if (m_pClientWindow && m_pClientWindow->GetSelection() != wxNOT_FOUND)
234 {
235 size_t active = m_pClientWindow->GetSelection() + 1;
236 if (active >= m_pClientWindow->GetPageCount())
237 active = 0;
238
239 m_pClientWindow->SetSelection(active);
240 }
241 }
242
243 void wxTabMDIParentFrame::ActivatePrevious()
244 {
245 if (m_pClientWindow && m_pClientWindow->GetSelection() != wxNOT_FOUND)
246 {
247 int active = m_pClientWindow->GetSelection() - 1;
248 if (active < 0)
249 active = m_pClientWindow->GetPageCount() - 1;
250
251 m_pClientWindow->SetSelection(active);
252 }
253 }
254
255 void wxTabMDIParentFrame::Init()
256 {
257 m_pClientWindow = NULL;
258 m_pActiveChild = NULL;
259 #if wxUSE_MENUS
260 m_pWindowMenu = NULL;
261 m_pMyMenuBar = NULL;
262 #endif // wxUSE_MENUS
263 }
264
265 #if wxUSE_MENUS
266 void wxTabMDIParentFrame::RemoveWindowMenu(wxMenuBar* pMenuBar)
267 {
268 if (pMenuBar && m_pWindowMenu)
269 {
270 // Remove old window menu
271 int pos = pMenuBar->FindMenu(_("&Window"));
272 if (pos != wxNOT_FOUND)
273 {
274 // DBG:: We're going to delete the wrong menu!!!
275 wxASSERT(m_pWindowMenu == pMenuBar->GetMenu(pos));
276 pMenuBar->Remove(pos);
277 }
278 }
279 }
280
281 void wxTabMDIParentFrame::AddWindowMenu(wxMenuBar *pMenuBar)
282 {
283 if (pMenuBar && m_pWindowMenu)
284 {
285 int pos = pMenuBar->FindMenu(wxGetStockLabel(wxID_HELP,false));
286 if (pos == wxNOT_FOUND)
287 pMenuBar->Append(m_pWindowMenu, _("&Window"));
288 else
289 pMenuBar->Insert(pos, m_pWindowMenu, _("&Window"));
290 }
291 }
292
293 void wxTabMDIParentFrame::DoHandleMenu(wxCommandEvent& event)
294 {
295 switch (event.GetId())
296 {
297 case wxWINDOWCLOSE:
298 if (m_pActiveChild)
299 m_pActiveChild->Close();
300 break;
301 case wxWINDOWCLOSEALL:
302 while (m_pActiveChild)
303 {
304 if (!m_pActiveChild->Close())
305 {
306 return; // failure
307 }
308 else
309 {
310 delete m_pActiveChild;
311 m_pActiveChild = NULL;
312 }
313 }
314 break;
315 case wxWINDOWNEXT:
316 ActivateNext();
317 break;
318 case wxWINDOWPREV:
319 ActivatePrevious();
320 break;
321 default:
322 event.Skip();
323 }
324 }
325 #endif // wxUSE_MENUS
326
327 void wxTabMDIParentFrame::DoGetClientSize(int* width, int* height) const
328 {
329 wxFrame::DoGetClientSize(width, height);
330 }
331
332 //-----------------------------------------------------------------------------
333 // wxTabMDIChildFrame
334 //-----------------------------------------------------------------------------
335
336 IMPLEMENT_DYNAMIC_CLASS(wxTabMDIChildFrame, wxPanel)
337
338 BEGIN_EVENT_TABLE(wxTabMDIChildFrame, wxPanel)
339 EVT_MENU_HIGHLIGHT_ALL(wxTabMDIChildFrame::OnMenuHighlight)
340 EVT_ACTIVATE(wxTabMDIChildFrame::OnActivate)
341 EVT_CLOSE(wxTabMDIChildFrame::OnCloseWindow)
342 END_EVENT_TABLE()
343
344 wxTabMDIChildFrame::wxTabMDIChildFrame()
345 {
346 Init();
347 }
348
349 wxTabMDIChildFrame::wxTabMDIChildFrame(wxTabMDIParentFrame *parent,
350 wxWindowID id,
351 const wxString& title,
352 const wxPoint& WXUNUSED(pos),
353 const wxSize& size,
354 long style,
355 const wxString& name)
356 {
357 Init();
358 Create(parent, id, title, wxDefaultPosition, size, style, name);
359 }
360
361 wxTabMDIChildFrame::~wxTabMDIChildFrame()
362 {
363 #if wxUSE_MENUS
364 wxDELETE(m_pMenuBar);
365 #endif // wxUSE_MENUS
366 }
367
368 bool wxTabMDIChildFrame::Create(wxTabMDIParentFrame* parent,
369 wxWindowID id,
370 const wxString& title,
371 const wxPoint& WXUNUSED(pos),
372 const wxSize& size,
373 long style,
374 const wxString& name)
375 {
376 wxTabMDIClientWindow* pClientWindow = parent->GetClientWindow();
377 wxASSERT_MSG((pClientWindow != (wxWindow*) NULL), wxT("Missing MDI client window."));
378
379 wxPanel::Create(pClientWindow, id, wxDefaultPosition, size, style|wxNO_BORDER, name);
380
381 SetMDIParentFrame(parent);
382
383 // this is the currently active child
384 parent->SetActiveChild(this);
385
386 m_title = title;
387
388 pClientWindow->AddPage(this, title, true);
389 pClientWindow->Refresh();
390
391 return true;
392 }
393
394 bool wxTabMDIChildFrame::Destroy()
395 {
396 wxTabMDIParentFrame* pParentFrame = GetMDIParentFrame();
397 wxASSERT_MSG(pParentFrame, wxT("Missing MDI Parent Frame"));
398
399 wxTabMDIClientWindow* pClientWindow = pParentFrame->GetClientWindow();
400 wxASSERT_MSG(pClientWindow, wxT("Missing MDI Client Window"));
401
402 bool bActive = false;
403 if (pParentFrame->GetActiveChild() == this)
404 {
405 pParentFrame->SetActiveChild(NULL);
406 pParentFrame->SetChildMenuBar(NULL);
407 bActive = true;
408 }
409
410 size_t pos, page_count = pClientWindow->GetPageCount();
411 for (pos = 0; pos < page_count; pos++)
412 {
413 if (pClientWindow->GetPage(pos) == this)
414 return pClientWindow->DeletePage(pos);
415 }
416
417 return false;
418 }
419
420 #if wxUSE_MENUS
421 void wxTabMDIChildFrame::SetMenuBar(wxMenuBar *menu_bar)
422 {
423 wxMenuBar *pOldMenuBar = m_pMenuBar;
424 m_pMenuBar = menu_bar;
425
426 if (m_pMenuBar)
427 {
428 wxTabMDIParentFrame* pParentFrame = GetMDIParentFrame();
429 wxASSERT_MSG(pParentFrame, wxT("Missing MDI Parent Frame"));
430
431 m_pMenuBar->SetParent(pParentFrame);
432 if (pParentFrame->GetActiveChild() == this)
433 {
434 // replace current menu bars
435 if (pOldMenuBar)
436 pParentFrame->SetChildMenuBar(NULL);
437 pParentFrame->SetChildMenuBar(this);
438 }
439 }
440 }
441
442 wxMenuBar *wxTabMDIChildFrame::GetMenuBar() const
443 {
444 return m_pMenuBar;
445 }
446 #endif // wxUSE_MENUS
447
448 void wxTabMDIChildFrame::SetTitle(const wxString& title)
449 {
450 m_title = title;
451
452 wxTabMDIParentFrame* pParentFrame = GetMDIParentFrame();
453 wxASSERT_MSG(pParentFrame, wxT("Missing MDI Parent Frame"));
454
455 wxTabMDIClientWindow* pClientWindow = pParentFrame->GetClientWindow();
456 if (pClientWindow != NULL)
457 {
458 size_t pos;
459 for (pos = 0; pos < pClientWindow->GetPageCount(); pos++)
460 {
461 if (pClientWindow->GetPage(pos) == this)
462 {
463 pClientWindow->SetPageText(pos, m_title);
464 break;
465 }
466 }
467 }
468 }
469
470 wxString wxTabMDIChildFrame::GetTitle() const
471 {
472 return m_title;
473 }
474
475 void wxTabMDIChildFrame::Activate()
476 {
477 wxTabMDIParentFrame* pParentFrame = GetMDIParentFrame();
478 wxASSERT_MSG(pParentFrame, wxT("Missing MDI Parent Frame"));
479
480 wxTabMDIClientWindow* pClientWindow = pParentFrame->GetClientWindow();
481
482 if (pClientWindow != NULL)
483 {
484 size_t pos;
485 for (pos = 0; pos < pClientWindow->GetPageCount(); pos++)
486 {
487 if (pClientWindow->GetPage(pos) == this)
488 {
489 pClientWindow->SetSelection(pos);
490 break;
491 }
492 }
493 }
494 }
495
496 void wxTabMDIChildFrame::OnMenuHighlight(wxMenuEvent& event)
497 {
498 #if wxUSE_STATUSBAR
499 if (m_pMDIParentFrame)
500 {
501 // we don't have any help text for this item,
502 // but may be the MDI frame does?
503 m_pMDIParentFrame->OnMenuHighlight(event);
504 }
505 #else
506 wxUnusedVar(event);
507 #endif // wxUSE_STATUSBAR
508 }
509
510 void wxTabMDIChildFrame::OnActivate(wxActivateEvent& WXUNUSED(event))
511 {
512 // do nothing
513 }
514
515 void wxTabMDIChildFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
516 {
517 Destroy();
518 }
519
520 void wxTabMDIChildFrame::SetMDIParentFrame(wxTabMDIParentFrame* parentFrame)
521 {
522 m_pMDIParentFrame = parentFrame;
523 }
524
525 wxTabMDIParentFrame* wxTabMDIChildFrame::GetMDIParentFrame() const
526 {
527 return m_pMDIParentFrame;
528 }
529
530 void wxTabMDIChildFrame::Init()
531 {
532 m_pMDIParentFrame = NULL;
533 #if wxUSE_MENUS
534 m_pMenuBar = NULL;
535 #endif // wxUSE_MENUS
536 }
537
538 bool wxTabMDIChildFrame::Show(bool WXUNUSED(show))
539 {
540 // do nothing
541 return true;
542 }
543
544 void wxTabMDIChildFrame::DoShow(bool show)
545 {
546 wxWindow::Show(show);
547 }
548
549 void wxTabMDIChildFrame::DoSetSize(int x, int y, int width, int height, int sizeFlags)
550 {
551 m_mdi_newrect = wxRect(x, y, width, height);
552 #ifdef __WXGTK__
553 wxPanel::DoSetSize(x,y,width, height, sizeFlags);
554 #endif
555 }
556
557 void wxTabMDIChildFrame::DoMoveWindow(int x, int y, int width, int height)
558 {
559 m_mdi_newrect = wxRect(x, y, width, height);
560 }
561
562 void wxTabMDIChildFrame::ApplyMDIChildFrameRect()
563 {
564 if (m_mdi_currect != m_mdi_newrect)
565 {
566 wxPanel::DoMoveWindow(m_mdi_newrect.x, m_mdi_newrect.y,
567 m_mdi_newrect.width, m_mdi_newrect.height);
568 m_mdi_currect = m_mdi_newrect;
569 }
570 }
571
572
573 //-----------------------------------------------------------------------------
574 // wxTabMDIClientWindow
575 //-----------------------------------------------------------------------------
576
577 IMPLEMENT_DYNAMIC_CLASS(wxTabMDIClientWindow, wxAuiMultiNotebook)
578
579 BEGIN_EVENT_TABLE(wxTabMDIClientWindow, wxAuiMultiNotebook)
580 EVT_AUINOTEBOOK_PAGE_CHANGED(wxID_ANY, wxTabMDIClientWindow::OnPageChanged)
581 EVT_SIZE(wxTabMDIClientWindow::OnSize)
582 END_EVENT_TABLE()
583
584 wxTabMDIClientWindow::wxTabMDIClientWindow()
585 {
586 }
587
588 wxTabMDIClientWindow::wxTabMDIClientWindow(wxTabMDIParentFrame* parent, long style)
589 {
590 CreateClient(parent, style);
591 }
592
593 wxTabMDIClientWindow::~wxTabMDIClientWindow()
594 {
595 DestroyChildren();
596 }
597
598 bool wxTabMDIClientWindow::CreateClient(wxTabMDIParentFrame* parent, long style)
599 {
600 SetWindowStyleFlag(style);
601
602 if (!wxAuiMultiNotebook::Create(parent,
603 wxID_ANY,
604 wxPoint(0,0),
605 wxSize(100, 100),
606 wxNO_BORDER))
607 {
608 return false;
609 }
610
611 wxColour bkcolour = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE);
612 SetBackgroundColour(bkcolour);
613
614 m_mgr.GetArtProvider()->SetColour(wxAUI_ART_BACKGROUND_COLOUR, bkcolour);
615
616 return true;
617 }
618
619 int wxTabMDIClientWindow::SetSelection(size_t nPage)
620 {
621 return wxAuiMultiNotebook::SetSelection(nPage);
622 }
623
624 void wxTabMDIClientWindow::PageChanged(int old_selection, int new_selection)
625 {
626 // don't do anything if the page doesn't actually change
627 if (old_selection == new_selection)
628 return;
629
630 // don't do anything if the new page is already active
631 if (new_selection != -1)
632 {
633 wxTabMDIChildFrame* child = (wxTabMDIChildFrame*)GetPage(new_selection);
634 if (child->GetMDIParentFrame()->GetActiveChild() == child)
635 return;
636 }
637
638 // notify old active child that it has been deactivated
639 if (old_selection != -1)
640 {
641 wxTabMDIChildFrame* old_child = (wxTabMDIChildFrame*)GetPage(old_selection);
642 wxASSERT_MSG(old_child, wxT("wxTabMDIClientWindow::PageChanged - null page pointer"));
643
644 wxActivateEvent event(wxEVT_ACTIVATE, false, old_child->GetId());
645 event.SetEventObject(old_child);
646 old_child->GetEventHandler()->ProcessEvent(event);
647 }
648
649 // notify new active child that it has been activated
650 if (new_selection != -1)
651 {
652 wxTabMDIChildFrame* active_child = (wxTabMDIChildFrame*)GetPage(new_selection);
653 wxASSERT_MSG(active_child, wxT("wxTabMDIClientWindow::PageChanged - null page pointer"));
654
655 wxActivateEvent event(wxEVT_ACTIVATE, true, active_child->GetId());
656 event.SetEventObject(active_child);
657 active_child->GetEventHandler()->ProcessEvent(event);
658
659 if (active_child->GetMDIParentFrame())
660 {
661 active_child->GetMDIParentFrame()->SetActiveChild(active_child);
662 active_child->GetMDIParentFrame()->SetChildMenuBar(active_child);
663 }
664 }
665 }
666
667 void wxTabMDIClientWindow::OnPageChanged(wxAuiNotebookEvent& evt)
668 {
669 PageChanged(evt.GetOldSelection(), evt.GetSelection());
670 evt.Skip();
671 }
672
673 void wxTabMDIClientWindow::OnSize(wxSizeEvent& evt)
674 {
675 wxAuiMultiNotebook::OnSize(evt);
676
677 for (size_t pos = 0; pos < GetPageCount(); pos++)
678 ((wxTabMDIChildFrame *)GetPage(pos))->ApplyMDIChildFrameRect();
679 }
680
681 #endif // wxUSE_MDI