1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/mdig.cpp
3 // Purpose: Generic MDI (Multiple Document Interface) classes
4 // Author: Hans Van Leemputten
8 // Copyright: (c) Hans Van Leemputten
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
21 #pragma implementation "mdig.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
36 #include "wx/generic/mdig.h"
46 //-----------------------------------------------------------------------------
47 // wxGenericMDIParentFrame
48 //-----------------------------------------------------------------------------
50 IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIParentFrame
, wxFrame
)
52 BEGIN_EVENT_TABLE(wxGenericMDIParentFrame
, wxFrame
)
53 EVT_MENU (-1, wxGenericMDIParentFrame::DoHandleMenu
)
56 wxGenericMDIParentFrame::wxGenericMDIParentFrame()
61 wxGenericMDIParentFrame::wxGenericMDIParentFrame(wxWindow
*parent
,
63 const wxString
& title
,
71 (void)Create(parent
, id
, title
, pos
, size
, style
, name
);
74 wxGenericMDIParentFrame::~wxGenericMDIParentFrame()
76 // Make sure the client window is destructed before the menu bars are!
77 wxDELETE(m_pClientWindow
);
83 m_pMyMenuBar
= (wxMenuBar
*) NULL
;
86 RemoveWindowMenu(GetMenuBar());
91 m_pWindowMenu
= (wxMenu
*) NULL
;
96 bool wxGenericMDIParentFrame::Create(wxWindow
*parent
,
98 const wxString
& title
,
102 const wxString
& name
)
104 // this style can be used to prevent a window from having the standard MDI
106 if ( !(style
& wxFRAME_NO_WINDOW_MENU
) )
109 m_pWindowMenu
= new wxMenu
;
111 m_pWindowMenu
->Append(wxWINDOWCLOSE
, _T("Cl&ose"));
112 m_pWindowMenu
->Append(wxWINDOWCLOSEALL
, _T("Close Al&l"));
113 m_pWindowMenu
->AppendSeparator();
114 m_pWindowMenu
->Append(wxWINDOWNEXT
, _T("&Next"));
115 m_pWindowMenu
->Append(wxWINDOWPREV
, _T("&Previouse"));
116 #endif // wxUSE_MENUS
119 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
127 void wxGenericMDIParentFrame::SetWindowMenu(wxMenu
* pMenu
)
129 // Replace the window menu from the currently loaded menu bar.
130 wxMenuBar
*pMenuBar
= GetMenuBar();
134 RemoveWindowMenu(pMenuBar
);
136 wxDELETE(m_pWindowMenu
);
141 m_pWindowMenu
= pMenu
;
143 AddWindowMenu(pMenuBar
);
147 void wxGenericMDIParentFrame::SetMenuBar(wxMenuBar
*pMenuBar
)
149 // Remove the Window menu from the old menu bar
150 RemoveWindowMenu(GetMenuBar());
151 // Add the Window menu to the new menu bar.
152 AddWindowMenu(pMenuBar
);
154 wxFrame::SetMenuBar(pMenuBar
);
156 #endif // wxUSE_MENUS
158 void wxGenericMDIParentFrame::SetChildMenuBar(wxGenericMDIChildFrame
*pChild
)
161 if (pChild
== (wxGenericMDIChildFrame
*) NULL
)
163 // No Child, set Our menu bar back.
164 SetMenuBar(m_pMyMenuBar
);
166 // Make sure we know our menu bar is in use
167 m_pMyMenuBar
= (wxMenuBar
*) NULL
;
171 if (pChild
->GetMenuBar() == (wxMenuBar
*) NULL
)
174 // Do we need to save the current bar?
175 if (m_pMyMenuBar
== NULL
)
176 m_pMyMenuBar
= GetMenuBar();
178 SetMenuBar(pChild
->GetMenuBar());
180 #endif // wxUSE_MENUS
183 bool wxGenericMDIParentFrame::ProcessEvent(wxEvent
& event
)
186 * Redirect events to active child first.
189 // Stops the same event being processed repeatedly
190 static wxEventType inEvent
= wxEVT_NULL
;
191 if (inEvent
== event
.GetEventType())
194 inEvent
= event
.GetEventType();
196 // Let the active child (if any) process the event first.
198 if (m_pActiveChild
&& event
.IsKindOf(CLASSINFO(wxCommandEvent
))
200 /* This is sure to not give problems... */
201 && (event
.GetEventType() == wxEVT_COMMAND_MENU_SELECTED
||
202 event
.GetEventType() == wxEVT_UPDATE_UI
))
204 /* This was tested on wxMSW and worked... */
205 && event
.GetEventObject() != m_pClientWindow
206 && !(event
.GetEventType() == wxEVT_ACTIVATE
||
207 event
.GetEventType() == wxEVT_SET_FOCUS
||
208 event
.GetEventType() == wxEVT_KILL_FOCUS
||
209 event
.GetEventType() == wxEVT_CHILD_FOCUS
||
210 event
.GetEventType() == wxEVT_COMMAND_SET_FOCUS
||
211 event
.GetEventType() == wxEVT_COMMAND_KILL_FOCUS
))
214 res
= m_pActiveChild
->GetEventHandler()->ProcessEvent(event
);
217 // If the event was not handled this frame will handle it!
220 res
= GetEventHandler()->wxEvtHandler::ProcessEvent(event
);
223 inEvent
= wxEVT_NULL
;
228 wxGenericMDIChildFrame
*wxGenericMDIParentFrame::GetActiveChild() const
230 return m_pActiveChild
;
233 void wxGenericMDIParentFrame::SetActiveChild(wxGenericMDIChildFrame
* pChildFrame
)
235 m_pActiveChild
= pChildFrame
;
238 wxGenericMDIClientWindow
*wxGenericMDIParentFrame::GetClientWindow() const
240 return m_pClientWindow
;
243 wxGenericMDIClientWindow
*wxGenericMDIParentFrame::OnCreateClient()
245 #if wxUSE_GENERIC_MDI_AS_NATIVE
246 m_pClientWindow
= new wxMDIClientWindow( this );
248 m_pClientWindow
= new wxGenericMDIClientWindow( this );
250 return m_pClientWindow
;
253 void wxGenericMDIParentFrame::ActivateNext()
255 if (m_pClientWindow
&& m_pClientWindow
->GetSelection() != -1)
257 int active
= m_pClientWindow
->GetSelection() + 1;
258 if (active
>= m_pClientWindow
->GetPageCount())
261 m_pClientWindow
->SetSelection(active
);
265 void wxGenericMDIParentFrame::ActivatePrevious()
267 if (m_pClientWindow
&& m_pClientWindow
->GetSelection() != -1)
269 int active
= m_pClientWindow
->GetSelection() - 1;
271 active
= m_pClientWindow
->GetPageCount() - 1;
273 m_pClientWindow
->SetSelection(active
);
277 void wxGenericMDIParentFrame::Init()
279 m_pClientWindow
= (wxGenericMDIClientWindow
*) NULL
;
280 m_pActiveChild
= (wxGenericMDIChildFrame
*) NULL
;
282 m_pWindowMenu
= (wxMenu
*) NULL
;
283 m_pMyMenuBar
= (wxMenuBar
*) NULL
;
284 #endif // wxUSE_MENUS
288 void wxGenericMDIParentFrame::RemoveWindowMenu(wxMenuBar
*pMenuBar
)
290 if (pMenuBar
&& m_pWindowMenu
)
292 // Remove old window menu
293 int pos
= pMenuBar
->FindMenu(_T("&Window"));
294 if (pos
!= wxNOT_FOUND
)
296 wxASSERT(m_pWindowMenu
== pMenuBar
->GetMenu(pos
)); // DBG:: We're going to delete the wrong menu!!!
297 pMenuBar
->Remove(pos
);
302 void wxGenericMDIParentFrame::AddWindowMenu(wxMenuBar
*pMenuBar
)
304 if (pMenuBar
&& m_pWindowMenu
)
306 int pos
= pMenuBar
->FindMenu(_T("Help"));
307 if (pos
== wxNOT_FOUND
)
309 pMenuBar
->Append(m_pWindowMenu
, _T("&Window"));
313 pMenuBar
->Insert(pos
, m_pWindowMenu
, _T("&Window"));
318 void wxGenericMDIParentFrame::DoHandleMenu(wxCommandEvent
&event
)
320 switch (event
.GetId())
325 m_pActiveChild
->Close();
328 case wxWINDOWCLOSEALL
:
330 #if 0 // code is only needed if next #if is set to 0!
331 wxGenericMDIChildFrame
*pFirstActiveChild
= m_pActiveChild
;
333 while (m_pActiveChild
)
335 if (!m_pActiveChild
->Close())
337 return; // We failed...
341 #if 1 // What's best? Delayed deleting or immediate deleting?
342 delete m_pActiveChild
;
346 if (pFirstActiveChild
== m_pActiveChild
)
347 return; // We've called Close on all items, no need to continue.
363 #endif // wxUSE_MENUS
365 void wxGenericMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
367 wxFrame::DoGetClientSize( width
, height
);
371 //-----------------------------------------------------------------------------
372 // wxGenericMDIChildFrame
373 //-----------------------------------------------------------------------------
375 IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIChildFrame
, wxPanel
)
377 BEGIN_EVENT_TABLE(wxGenericMDIChildFrame
, wxPanel
)
378 EVT_MENU_HIGHLIGHT_ALL(wxGenericMDIChildFrame::OnMenuHighlight
)
379 EVT_ACTIVATE(wxGenericMDIChildFrame::OnActivate
)
381 EVT_CLOSE(wxGenericMDIChildFrame::OnCloseWindow
)
382 EVT_SIZE(wxGenericMDIChildFrame::OnSize
)
385 wxGenericMDIChildFrame::wxGenericMDIChildFrame()
390 wxGenericMDIChildFrame::wxGenericMDIChildFrame( wxGenericMDIParentFrame
*parent
,
391 wxWindowID id
, const wxString
& title
,
392 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
393 long style
, const wxString
& name
)
397 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
401 wxGenericMDIChildFrame::~wxGenericMDIChildFrame()
403 wxGenericMDIParentFrame
*pParentFrame
= GetMDIParentFrame();
405 if (pParentFrame
!= NULL
)
407 bool bActive
= FALSE
;
408 if (pParentFrame
->GetActiveChild() == this)
410 pParentFrame
->SetActiveChild((wxGenericMDIChildFrame
*) NULL
);
411 pParentFrame
->SetChildMenuBar((wxGenericMDIChildFrame
*) NULL
);
415 wxGenericMDIClientWindow
*pClientWindow
= pParentFrame
->GetClientWindow();
417 // Remove page if still there
419 for (pos
= 0; pos
< pClientWindow
->GetPageCount(); pos
++)
421 if (pClientWindow
->GetPage(pos
) == this)
423 if (pClientWindow
->RemovePage(pos
))
424 pClientWindow
->Refresh();
431 // Set the new selection to the a remaining page
432 if (pClientWindow
->GetPageCount() > pos
)
434 pClientWindow
->SetSelection(pos
);
438 if (pClientWindow
->GetPageCount() - 1 >= 0)
439 pClientWindow
->SetSelection(pClientWindow
->GetPageCount() - 1);
445 wxDELETE(m_pMenuBar
);
446 #endif // wxUSE_MENUS
449 bool wxGenericMDIChildFrame::Create( wxGenericMDIParentFrame
*parent
,
450 wxWindowID id
, const wxString
& title
,
451 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
452 long style
, const wxString
& name
)
454 wxGenericMDIClientWindow
* pClientWindow
= parent
->GetClientWindow();
456 wxASSERT_MSG((pClientWindow
!= (wxWindow
*) NULL
), "Missing MDI client window.");
458 wxPanel::Create(pClientWindow
, id
, wxDefaultPosition
, size
, style
, name
);
460 SetMDIParentFrame(parent
);
462 // This is the currently active child
463 parent
->SetActiveChild(this);
467 pClientWindow
->AddPage(this, title
, TRUE
);
468 ApplyMDIChildFrameRect(); // Ok confirme the size change!
469 pClientWindow
->Refresh();
475 void wxGenericMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
477 wxMenuBar
*pOldMenuBar
= m_pMenuBar
;
478 m_pMenuBar
= menu_bar
;
482 wxGenericMDIParentFrame
*pParentFrame
= GetMDIParentFrame();
484 if (pParentFrame
!= NULL
)
486 m_pMenuBar
->SetParent(pParentFrame
);
488 if (pParentFrame
->GetActiveChild() == this)
490 // Replace current menu bars
492 pParentFrame
->SetChildMenuBar((wxGenericMDIChildFrame
*) NULL
);
493 pParentFrame
->SetChildMenuBar((wxGenericMDIChildFrame
*) this);
499 wxMenuBar
*wxGenericMDIChildFrame::GetMenuBar() const
503 #endif // wxUSE_MENUS
505 void wxGenericMDIChildFrame::SetTitle(const wxString
& title
)
509 wxGenericMDIParentFrame
*pParentFrame
= GetMDIParentFrame();
511 if (pParentFrame
!= NULL
)
513 wxGenericMDIClientWindow
* pClientWindow
= pParentFrame
->GetClientWindow();
515 if (pClientWindow
!= NULL
)
518 for (pos
= 0; pos
< pClientWindow
->GetPageCount(); pos
++)
520 if (pClientWindow
->GetPage(pos
) == this)
522 pClientWindow
->SetPageText(pos
, m_Title
);
530 wxString
wxGenericMDIChildFrame::GetTitle()
535 void wxGenericMDIChildFrame::Activate()
537 wxGenericMDIParentFrame
*pParentFrame
= GetMDIParentFrame();
539 if (pParentFrame
!= NULL
)
541 wxGenericMDIClientWindow
* pClientWindow
= pParentFrame
->GetClientWindow();
543 if (pClientWindow
!= NULL
)
546 for (pos
= 0; pos
< pClientWindow
->GetPageCount(); pos
++)
548 if (pClientWindow
->GetPage(pos
) == this)
550 pClientWindow
->SetSelection(pos
);
558 void wxGenericMDIChildFrame::OnMenuHighlight(wxMenuEvent
& event
)
561 if ( m_pMDIParentFrame
)
563 // we don't have any help text for this item,
564 // but may be the MDI frame does?
565 m_pMDIParentFrame
->OnMenuHighlight(event
);
567 #endif // wxUSE_STATUSBAR
570 void wxGenericMDIChildFrame::OnActivate(wxActivateEvent
& event
)
575 /*** Copied from top level..! ***/
576 // default resizing behaviour - if only ONE subwindow, resize to fill the
578 void wxGenericMDIChildFrame::OnSize(wxSizeEvent
& WXUNUSED(event
))
580 // if we're using constraints or sizers - do use them
581 if ( GetAutoLayout() )
587 // do we have _exactly_ one child?
588 wxWindow
*child
= (wxWindow
*)NULL
;
589 for ( wxWindowList::Node
*node
= GetChildren().GetFirst();
591 node
= node
->GetNext() )
593 wxWindow
*win
= node
->GetData();
595 // exclude top level and managed windows (status bar isn't
596 // currently in the children list except under wxMac anyhow, but
597 // it makes no harm to test for it)
598 if ( !win
->IsTopLevel() /*&& !IsOneOfBars(win)*/ )
602 return; // it's our second subwindow - nothing to do
609 // do we have any children at all?
612 // exactly one child - set it's size to fill the whole frame
613 int clientW
, clientH
;
614 DoGetClientSize(&clientW
, &clientH
);
616 // for whatever reasons, wxGTK wants to have a small offset - it
617 // probably looks better with it?
619 static const int ofs
= 1;
621 static const int ofs
= 0;
624 child
->SetSize(ofs
, ofs
, clientW
- 2*ofs
, clientH
- 2*ofs
);
629 /*** Copied from top level..! ***/
630 // The default implementation for the close window event.
631 void wxGenericMDIChildFrame::OnCloseWindow(wxCloseEvent
& WXUNUSED(event
))
636 void wxGenericMDIChildFrame::SetMDIParentFrame(wxGenericMDIParentFrame
* parentFrame
)
638 m_pMDIParentFrame
= parentFrame
;
641 wxGenericMDIParentFrame
* wxGenericMDIChildFrame::GetMDIParentFrame() const
643 return m_pMDIParentFrame
;
646 void wxGenericMDIChildFrame::Init()
648 m_pMDIParentFrame
= (wxGenericMDIParentFrame
*) NULL
;
650 m_pMenuBar
= (wxMenuBar
*) NULL
;
651 #endif // wxUSE_MENUS
654 void wxGenericMDIChildFrame::DoMoveWindow(int x
, int y
, int width
, int height
)
656 m_MDIRect
= wxRect(x
, y
, width
, height
);
659 void wxGenericMDIChildFrame::ApplyMDIChildFrameRect()
661 wxPanel::DoMoveWindow(m_MDIRect
.x
, m_MDIRect
.y
, m_MDIRect
.width
, m_MDIRect
.height
);
664 //-----------------------------------------------------------------------------
665 // wxGenericMDIClientWindow
666 //-----------------------------------------------------------------------------
668 #define wxID_NOTEBOOK_CLIENT_AREA wxID_HIGHEST + 100
670 IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIClientWindow
, wxNotebook
)
672 BEGIN_EVENT_TABLE(wxGenericMDIClientWindow
, wxNotebook
)
673 EVT_NOTEBOOK_PAGE_CHANGED(wxID_NOTEBOOK_CLIENT_AREA
, wxGenericMDIClientWindow::OnPageChanged
)
674 EVT_SIZE(wxGenericMDIClientWindow::OnSize
)
678 wxGenericMDIClientWindow::wxGenericMDIClientWindow()
682 wxGenericMDIClientWindow::wxGenericMDIClientWindow( wxGenericMDIParentFrame
*parent
, long style
)
684 CreateClient( parent
, style
);
687 wxGenericMDIClientWindow::~wxGenericMDIClientWindow()
692 bool wxGenericMDIClientWindow::CreateClient( wxGenericMDIParentFrame
*parent
, long style
)
694 SetWindowStyleFlag(style
);
696 bool success
= wxNotebook::Create(parent
, wxID_NOTEBOOK_CLIENT_AREA
, wxPoint(0, 0), wxSize(100, 100), 0);
700 wxFont font(10, wxSWISS, wxNORMAL, wxNORMAL);
701 wxFont selFont(10, wxSWISS, wxNORMAL, wxBOLD);
702 GetTabView()->SetTabFont(font);
703 GetTabView()->SetSelectedTabFont(selFont);
704 GetTabView()->SetTabSize(120, 18);
705 GetTabView()->SetTabSelectionHeight(20);
713 int wxGenericMDIClientWindow::SetSelection(int nPage
)
715 int oldSelection
= wxNotebook::SetSelection(nPage
);
717 #if !defined(__WXMSW__) // No need to do this for wxMSW as wxNotebook::SetSelection()
718 // will already cause this to be done!
719 // Handle the page change.
720 PageChanged(oldSelection
, nPage
);
726 void wxGenericMDIClientWindow::PageChanged(int OldSelection
, int newSelection
)
728 // Don't do to much work, only when something realy should change!
729 if (OldSelection
== newSelection
)
731 // Again check if we realy need to do this...
732 if (newSelection
!= -1)
734 wxGenericMDIChildFrame
* child
= (wxGenericMDIChildFrame
*)GetPage(newSelection
);
736 if (child
->GetMDIParentFrame()->GetActiveChild() == child
)
740 // Notify old active child that it has been deactivated
741 if (OldSelection
!= -1)
743 wxGenericMDIChildFrame
* oldChild
= (wxGenericMDIChildFrame
*)GetPage(OldSelection
);
746 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, oldChild
->GetId());
747 event
.SetEventObject( oldChild
);
748 oldChild
->GetEventHandler()->ProcessEvent(event
);
752 // Notify new active child that it has been activated
753 if (newSelection
!= -1)
755 wxGenericMDIChildFrame
* activeChild
= (wxGenericMDIChildFrame
*)GetPage(newSelection
);
758 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, activeChild
->GetId());
759 event
.SetEventObject( activeChild
);
760 activeChild
->GetEventHandler()->ProcessEvent(event
);
762 if (activeChild
->GetMDIParentFrame())
764 activeChild
->GetMDIParentFrame()->SetActiveChild(activeChild
);
765 activeChild
->GetMDIParentFrame()->SetChildMenuBar(activeChild
);
771 void wxGenericMDIClientWindow::OnPageChanged(wxNotebookEvent
& event
)
773 PageChanged(event
.GetOldSelection(), event
.GetSelection());
778 void wxGenericMDIClientWindow::OnSize(wxSizeEvent
& event
)
780 wxNotebook::OnSize(event
);
783 for (pos
= 0; pos
< GetPageCount(); pos
++)
785 ((wxGenericMDIChildFrame
*)GetPage(pos
))->ApplyMDIChildFrameRect();
791 * Define normal wxMDI classes based on wxGenericMDI
794 #if wxUSE_GENERIC_MDI_AS_NATIVE
796 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxGenericMDIParentFrame
)
797 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxGenericMDIChildFrame
)
798 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxGenericMDIClientWindow
)