]> git.saurik.com Git - wxWidgets.git/blob - src/aui/tabmdi.cpp
Fix redraw problems with hint rectangle when there is no transparency
[wxWidgets.git] / src / aui / tabmdi.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/mdig.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/settings.h"
30 #include "wx/aui/tabmdi.h"
31
32 #ifndef WX_PRECOMP
33 #include "wx/panel.h"
34 #include "wx/menu.h"
35 #include "wx/intl.h"
36 #include "wx/log.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() != -1)
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() != -1)
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 /*
421 wxTabMDIParentFrame* pParentFrame = GetMDIParentFrame();
422 wxASSERT_MSG(pParentFrame, wxT("Missing MDI Parent Frame"));
423
424 bool bActive = false;
425 if (pParentFrame->GetActiveChild() == this)
426 {
427 pParentFrame->SetActiveChild(NULL);
428 pParentFrame->SetChildMenuBar(NULL);
429 bActive = true;
430 }
431
432 wxTabMDIClientWindow* pClientWindow = pParentFrame->GetClientWindow();
433
434 // remove page if it is still there
435 size_t pos;
436 for (pos = 0; pos < pClientWindow->GetPageCount(); pos++)
437 {
438 if (pClientWindow->GetPage(pos) == this)
439 {
440 if (pClientWindow->RemovePage(pos))
441 pClientWindow->Refresh();
442 break;
443 }
444 }
445
446 if (bActive)
447 {
448 // Set the new selection to the a remaining page
449 if (pos < pClientWindow->GetPageCount())
450 {
451 pClientWindow->SetSelection(pos);
452 }
453 else
454 {
455 if (pClientWindow->GetPageCount() >= 1)
456 pClientWindow->SetSelection(pClientWindow->GetPageCount() - 1);
457 }
458 }
459
460 // delete the child frame with pending delete, as is
461 // customary with frame windows
462 if (!wxPendingDelete.Member(this))
463 wxPendingDelete.Append(this);
464
465 return true;
466 */
467
468
469 #if wxUSE_MENUS
470 void wxTabMDIChildFrame::SetMenuBar(wxMenuBar *menu_bar)
471 {
472 wxMenuBar *pOldMenuBar = m_pMenuBar;
473 m_pMenuBar = menu_bar;
474
475 if (m_pMenuBar)
476 {
477 wxTabMDIParentFrame* pParentFrame = GetMDIParentFrame();
478 wxASSERT_MSG(pParentFrame, wxT("Missing MDI Parent Frame"));
479
480 m_pMenuBar->SetParent(pParentFrame);
481 if (pParentFrame->GetActiveChild() == this)
482 {
483 // replace current menu bars
484 if (pOldMenuBar)
485 pParentFrame->SetChildMenuBar(NULL);
486 pParentFrame->SetChildMenuBar(this);
487 }
488 }
489 }
490
491 wxMenuBar *wxTabMDIChildFrame::GetMenuBar() const
492 {
493 return m_pMenuBar;
494 }
495 #endif // wxUSE_MENUS
496
497 void wxTabMDIChildFrame::SetTitle(const wxString& title)
498 {
499 m_title = title;
500
501 wxTabMDIParentFrame* pParentFrame = GetMDIParentFrame();
502 wxASSERT_MSG(pParentFrame, wxT("Missing MDI Parent Frame"));
503
504 wxTabMDIClientWindow* pClientWindow = pParentFrame->GetClientWindow();
505 if (pClientWindow != NULL)
506 {
507 size_t pos;
508 for (pos = 0; pos < pClientWindow->GetPageCount(); pos++)
509 {
510 if (pClientWindow->GetPage(pos) == this)
511 {
512 pClientWindow->SetPageText(pos, m_title);
513 break;
514 }
515 }
516 }
517 }
518
519 wxString wxTabMDIChildFrame::GetTitle() const
520 {
521 return m_title;
522 }
523
524 void wxTabMDIChildFrame::Activate()
525 {
526 wxTabMDIParentFrame* pParentFrame = GetMDIParentFrame();
527 wxASSERT_MSG(pParentFrame, wxT("Missing MDI Parent Frame"));
528
529 wxTabMDIClientWindow* pClientWindow = pParentFrame->GetClientWindow();
530
531 if (pClientWindow != NULL)
532 {
533 size_t pos;
534 for (pos = 0; pos < pClientWindow->GetPageCount(); pos++)
535 {
536 if (pClientWindow->GetPage(pos) == this)
537 {
538 pClientWindow->SetSelection(pos);
539 break;
540 }
541 }
542 }
543 }
544
545 void wxTabMDIChildFrame::OnMenuHighlight(wxMenuEvent& event)
546 {
547 #if wxUSE_STATUSBAR
548 if (m_pMDIParentFrame)
549 {
550 // we don't have any help text for this item,
551 // but may be the MDI frame does?
552 m_pMDIParentFrame->OnMenuHighlight(event);
553 }
554 #else
555 wxUnusedVar(event);
556 #endif // wxUSE_STATUSBAR
557 }
558
559 void wxTabMDIChildFrame::OnActivate(wxActivateEvent& WXUNUSED(event))
560 {
561 // do nothing
562 }
563
564 void wxTabMDIChildFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
565 {
566 Destroy();
567 }
568
569 void wxTabMDIChildFrame::SetMDIParentFrame(wxTabMDIParentFrame* parentFrame)
570 {
571 m_pMDIParentFrame = parentFrame;
572 }
573
574 wxTabMDIParentFrame* wxTabMDIChildFrame::GetMDIParentFrame() const
575 {
576 return m_pMDIParentFrame;
577 }
578
579 void wxTabMDIChildFrame::Init()
580 {
581 m_pMDIParentFrame = NULL;
582 #if wxUSE_MENUS
583 m_pMenuBar = NULL;
584 #endif // wxUSE_MENUS
585 }
586
587 bool wxTabMDIChildFrame::Show(bool WXUNUSED(show))
588 {
589 // do nothing
590 return true;
591 }
592
593 void wxTabMDIChildFrame::DoShow(bool show)
594 {
595 wxWindow::Show(show);
596 }
597
598 void wxTabMDIChildFrame::DoSetSize(int x, int y, int width, int height, int WXUNUSED(sizeFlags))
599 {
600 m_mdi_newrect = wxRect(x, y, width, height);
601 }
602
603 void wxTabMDIChildFrame::DoMoveWindow(int x, int y, int width, int height)
604 {
605 m_mdi_newrect = wxRect(x, y, width, height);
606 }
607
608 void wxTabMDIChildFrame::ApplyMDIChildFrameRect()
609 {
610 if (m_mdi_currect != m_mdi_newrect)
611 {
612 wxPanel::DoMoveWindow(m_mdi_newrect.x, m_mdi_newrect.y,
613 m_mdi_newrect.width, m_mdi_newrect.height);
614 m_mdi_currect = m_mdi_newrect;
615 }
616 }
617
618
619 //-----------------------------------------------------------------------------
620 // wxTabMDIClientWindow
621 //-----------------------------------------------------------------------------
622
623 IMPLEMENT_DYNAMIC_CLASS(wxTabMDIClientWindow, wxAuiMultiNotebook)
624
625 BEGIN_EVENT_TABLE(wxTabMDIClientWindow, wxAuiMultiNotebook)
626 EVT_AUINOTEBOOK_PAGE_CHANGED(-1, wxTabMDIClientWindow::OnPageChanged)
627 EVT_SIZE(wxTabMDIClientWindow::OnSize)
628 END_EVENT_TABLE()
629
630 wxTabMDIClientWindow::wxTabMDIClientWindow()
631 {
632 }
633
634 wxTabMDIClientWindow::wxTabMDIClientWindow(wxTabMDIParentFrame* parent, long style)
635 {
636 CreateClient(parent, style);
637 }
638
639 wxTabMDIClientWindow::~wxTabMDIClientWindow()
640 {
641 DestroyChildren();
642 }
643
644 bool wxTabMDIClientWindow::CreateClient(wxTabMDIParentFrame* parent, long style)
645 {
646 SetWindowStyleFlag(style);
647
648 if (!wxAuiMultiNotebook::Create(parent,
649 -1,
650 wxPoint(0,0),
651 wxSize(100, 100),
652 wxNO_BORDER))
653 {
654 return false;
655 }
656
657 wxColour bkcolour = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE);
658 SetBackgroundColour(bkcolour);
659
660 m_mgr.GetArtProvider()->SetColour(wxAUI_ART_BACKGROUND_COLOUR, bkcolour);
661
662 return true;
663 }
664
665 int wxTabMDIClientWindow::SetSelection(size_t nPage)
666 {
667 return wxAuiMultiNotebook::SetSelection(nPage);
668 }
669
670 void wxTabMDIClientWindow::PageChanged(int old_selection, int new_selection)
671 {
672 // don't do anything if the page doesn't actually change
673 if (old_selection == new_selection)
674 return;
675
676 // don't do anything if the new page is already active
677 if (new_selection != -1)
678 {
679 wxTabMDIChildFrame* child = (wxTabMDIChildFrame*)GetPage(new_selection);
680 if (child->GetMDIParentFrame()->GetActiveChild() == child)
681 return;
682 }
683
684 // notify old active child that it has been deactivated
685 if (old_selection != -1)
686 {
687 wxTabMDIChildFrame* old_child = (wxTabMDIChildFrame*)GetPage(old_selection);
688 wxASSERT_MSG(old_child, wxT("wxTabMDIClientWindow::PageChanged - null page pointer"));
689
690 wxActivateEvent event(wxEVT_ACTIVATE, false, old_child->GetId());
691 event.SetEventObject(old_child);
692 old_child->GetEventHandler()->ProcessEvent(event);
693 }
694
695 // notify new active child that it has been activated
696 if (new_selection != -1)
697 {
698 wxTabMDIChildFrame* active_child = (wxTabMDIChildFrame*)GetPage(new_selection);
699 wxASSERT_MSG(active_child, wxT("wxTabMDIClientWindow::PageChanged - null page pointer"));
700
701 wxActivateEvent event(wxEVT_ACTIVATE, true, active_child->GetId());
702 event.SetEventObject(active_child);
703 active_child->GetEventHandler()->ProcessEvent(event);
704
705 if (active_child->GetMDIParentFrame())
706 {
707 active_child->GetMDIParentFrame()->SetActiveChild(active_child);
708 active_child->GetMDIParentFrame()->SetChildMenuBar(active_child);
709 }
710 }
711 }
712
713 void wxTabMDIClientWindow::OnPageChanged(wxAuiNotebookEvent& evt)
714 {
715 PageChanged(evt.GetOldSelection(), evt.GetSelection());
716 evt.Skip();
717 }
718
719 void wxTabMDIClientWindow::OnSize(wxSizeEvent& evt)
720 {
721 wxAuiMultiNotebook::OnSize(evt);
722
723 for (size_t pos = 0; pos < GetPageCount(); pos++)
724 ((wxTabMDIChildFrame *)GetPage(pos))->ApplyMDIChildFrameRect();
725 }
726
727 #endif // wxUSE_MDI