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"
37 #include "wx/generic/mdig.h"
47 //-----------------------------------------------------------------------------
48 // wxGenericMDIParentFrame
49 //-----------------------------------------------------------------------------
51 IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIParentFrame
, wxFrame
)
53 BEGIN_EVENT_TABLE(wxGenericMDIParentFrame
, wxFrame
)
54 EVT_MENU (-1, wxGenericMDIParentFrame::DoHandleMenu
)
57 wxGenericMDIParentFrame::wxGenericMDIParentFrame()
62 wxGenericMDIParentFrame::wxGenericMDIParentFrame(wxWindow
*parent
,
64 const wxString
& title
,
72 (void)Create(parent
, id
, title
, pos
, size
, style
, name
);
75 wxGenericMDIParentFrame::~wxGenericMDIParentFrame()
77 // Make sure the client window is destructed before the menu bars are!
78 wxDELETE(m_pClientWindow
);
84 m_pMyMenuBar
= (wxMenuBar
*) NULL
;
87 RemoveWindowMenu(GetMenuBar());
92 m_pWindowMenu
= (wxMenu
*) NULL
;
97 bool wxGenericMDIParentFrame::Create(wxWindow
*parent
,
99 const wxString
& title
,
103 const wxString
& name
)
105 // this style can be used to prevent a window from having the standard MDI
107 if ( !(style
& wxFRAME_NO_WINDOW_MENU
) )
110 m_pWindowMenu
= new wxMenu
;
112 m_pWindowMenu
->Append(wxWINDOWCLOSE
, _("Cl&ose"));
113 m_pWindowMenu
->Append(wxWINDOWCLOSEALL
, _("Close All"));
114 m_pWindowMenu
->AppendSeparator();
115 m_pWindowMenu
->Append(wxWINDOWNEXT
, _("&Next"));
116 m_pWindowMenu
->Append(wxWINDOWPREV
, _("&Previous"));
117 #endif // wxUSE_MENUS
120 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
);
128 void wxGenericMDIParentFrame::SetWindowMenu(wxMenu
* pMenu
)
130 // Replace the window menu from the currently loaded menu bar.
131 wxMenuBar
*pMenuBar
= GetMenuBar();
135 RemoveWindowMenu(pMenuBar
);
137 wxDELETE(m_pWindowMenu
);
142 m_pWindowMenu
= pMenu
;
144 AddWindowMenu(pMenuBar
);
148 void wxGenericMDIParentFrame::SetMenuBar(wxMenuBar
*pMenuBar
)
150 // Remove the Window menu from the old menu bar
151 RemoveWindowMenu(GetMenuBar());
152 // Add the Window menu to the new menu bar.
153 AddWindowMenu(pMenuBar
);
155 wxFrame::SetMenuBar(pMenuBar
);
157 #endif // wxUSE_MENUS
159 void wxGenericMDIParentFrame::SetChildMenuBar(wxGenericMDIChildFrame
*pChild
)
162 if (pChild
== (wxGenericMDIChildFrame
*) NULL
)
164 // No Child, set Our menu bar back.
165 SetMenuBar(m_pMyMenuBar
);
167 // Make sure we know our menu bar is in use
168 m_pMyMenuBar
= (wxMenuBar
*) NULL
;
172 if (pChild
->GetMenuBar() == (wxMenuBar
*) NULL
)
175 // Do we need to save the current bar?
176 if (m_pMyMenuBar
== NULL
)
177 m_pMyMenuBar
= GetMenuBar();
179 SetMenuBar(pChild
->GetMenuBar());
181 #endif // wxUSE_MENUS
184 bool wxGenericMDIParentFrame::ProcessEvent(wxEvent
& event
)
187 * Redirect events to active child first.
190 // Stops the same event being processed repeatedly
191 static wxEventType inEvent
= wxEVT_NULL
;
192 if (inEvent
== event
.GetEventType())
195 inEvent
= event
.GetEventType();
197 // Let the active child (if any) process the event first.
199 if (m_pActiveChild
&& event
.IsKindOf(CLASSINFO(wxCommandEvent
))
201 /* This is sure to not give problems... */
202 && (event
.GetEventType() == wxEVT_COMMAND_MENU_SELECTED
||
203 event
.GetEventType() == wxEVT_UPDATE_UI
)
205 /* This was tested on wxMSW and worked... */
206 && event
.GetEventObject() != m_pClientWindow
207 && !(event
.GetEventType() == wxEVT_ACTIVATE
||
208 event
.GetEventType() == wxEVT_SET_FOCUS
||
209 event
.GetEventType() == wxEVT_KILL_FOCUS
||
210 event
.GetEventType() == wxEVT_CHILD_FOCUS
||
211 event
.GetEventType() == wxEVT_COMMAND_SET_FOCUS
||
212 event
.GetEventType() == wxEVT_COMMAND_KILL_FOCUS
)
216 res
= m_pActiveChild
->GetEventHandler()->ProcessEvent(event
);
219 // If the event was not handled this frame will handle it!
222 res
= GetEventHandler()->wxEvtHandler::ProcessEvent(event
);
225 inEvent
= wxEVT_NULL
;
230 wxGenericMDIChildFrame
*wxGenericMDIParentFrame::GetActiveChild() const
232 return m_pActiveChild
;
235 void wxGenericMDIParentFrame::SetActiveChild(wxGenericMDIChildFrame
* pChildFrame
)
237 m_pActiveChild
= pChildFrame
;
240 wxGenericMDIClientWindow
*wxGenericMDIParentFrame::GetClientWindow() const
242 return m_pClientWindow
;
245 wxGenericMDIClientWindow
*wxGenericMDIParentFrame::OnCreateClient()
247 #if wxUSE_GENERIC_MDI_AS_NATIVE
248 m_pClientWindow
= new wxMDIClientWindow( this );
250 m_pClientWindow
= new wxGenericMDIClientWindow( this );
252 return m_pClientWindow
;
255 void wxGenericMDIParentFrame::ActivateNext()
257 if (m_pClientWindow
&& m_pClientWindow
->GetSelection() != -1)
259 int active
= m_pClientWindow
->GetSelection() + 1;
260 if (active
>= m_pClientWindow
->GetPageCount())
263 m_pClientWindow
->SetSelection(active
);
267 void wxGenericMDIParentFrame::ActivatePrevious()
269 if (m_pClientWindow
&& m_pClientWindow
->GetSelection() != -1)
271 int active
= m_pClientWindow
->GetSelection() - 1;
273 active
= m_pClientWindow
->GetPageCount() - 1;
275 m_pClientWindow
->SetSelection(active
);
279 void wxGenericMDIParentFrame::Init()
281 m_pClientWindow
= (wxGenericMDIClientWindow
*) NULL
;
282 m_pActiveChild
= (wxGenericMDIChildFrame
*) NULL
;
284 m_pWindowMenu
= (wxMenu
*) NULL
;
285 m_pMyMenuBar
= (wxMenuBar
*) NULL
;
286 #endif // wxUSE_MENUS
290 void wxGenericMDIParentFrame::RemoveWindowMenu(wxMenuBar
*pMenuBar
)
292 if (pMenuBar
&& m_pWindowMenu
)
294 // Remove old window menu
295 int pos
= pMenuBar
->FindMenu(_("&Window"));
296 if (pos
!= wxNOT_FOUND
)
298 wxASSERT(m_pWindowMenu
== pMenuBar
->GetMenu(pos
)); // DBG:: We're going to delete the wrong menu!!!
299 pMenuBar
->Remove(pos
);
304 void wxGenericMDIParentFrame::AddWindowMenu(wxMenuBar
*pMenuBar
)
306 if (pMenuBar
&& m_pWindowMenu
)
308 int pos
= pMenuBar
->FindMenu(_("Help"));
309 if (pos
== wxNOT_FOUND
)
311 pMenuBar
->Append(m_pWindowMenu
, _("&Window"));
315 pMenuBar
->Insert(pos
, m_pWindowMenu
, _("&Window"));
320 void wxGenericMDIParentFrame::DoHandleMenu(wxCommandEvent
&event
)
322 switch (event
.GetId())
327 m_pActiveChild
->Close();
330 case wxWINDOWCLOSEALL
:
332 #if 0 // code is only needed if next #if is set to 0!
333 wxGenericMDIChildFrame
*pFirstActiveChild
= m_pActiveChild
;
335 while (m_pActiveChild
)
337 if (!m_pActiveChild
->Close())
339 return; // We failed...
343 #if 1 // What's best? Delayed deleting or immediate deleting?
344 delete m_pActiveChild
;
348 if (pFirstActiveChild
== m_pActiveChild
)
349 return; // We've called Close on all items, no need to continue.
365 #endif // wxUSE_MENUS
367 void wxGenericMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
369 wxFrame::DoGetClientSize( width
, height
);
373 //-----------------------------------------------------------------------------
374 // wxGenericMDIChildFrame
375 //-----------------------------------------------------------------------------
377 IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIChildFrame
, wxPanel
)
379 BEGIN_EVENT_TABLE(wxGenericMDIChildFrame
, wxPanel
)
380 EVT_MENU_HIGHLIGHT_ALL(wxGenericMDIChildFrame::OnMenuHighlight
)
381 EVT_ACTIVATE(wxGenericMDIChildFrame::OnActivate
)
383 EVT_CLOSE(wxGenericMDIChildFrame::OnCloseWindow
)
384 EVT_SIZE(wxGenericMDIChildFrame::OnSize
)
387 wxGenericMDIChildFrame::wxGenericMDIChildFrame()
392 wxGenericMDIChildFrame::wxGenericMDIChildFrame( wxGenericMDIParentFrame
*parent
,
393 wxWindowID id
, const wxString
& title
,
394 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
395 long style
, const wxString
& name
)
399 Create( parent
, id
, title
, wxDefaultPosition
, size
, style
, name
);
403 wxGenericMDIChildFrame::~wxGenericMDIChildFrame()
405 wxGenericMDIParentFrame
*pParentFrame
= GetMDIParentFrame();
407 if (pParentFrame
!= NULL
)
409 bool bActive
= FALSE
;
410 if (pParentFrame
->GetActiveChild() == this)
412 pParentFrame
->SetActiveChild((wxGenericMDIChildFrame
*) NULL
);
413 pParentFrame
->SetChildMenuBar((wxGenericMDIChildFrame
*) NULL
);
417 wxGenericMDIClientWindow
*pClientWindow
= pParentFrame
->GetClientWindow();
419 // Remove page if still there
421 for (pos
= 0; pos
< pClientWindow
->GetPageCount(); pos
++)
423 if (pClientWindow
->GetPage(pos
) == this)
425 if (pClientWindow
->RemovePage(pos
))
426 pClientWindow
->Refresh();
433 // Set the new selection to the a remaining page
434 if (pClientWindow
->GetPageCount() > pos
)
436 pClientWindow
->SetSelection(pos
);
440 if (pClientWindow
->GetPageCount() - 1 >= 0)
441 pClientWindow
->SetSelection(pClientWindow
->GetPageCount() - 1);
447 wxDELETE(m_pMenuBar
);
448 #endif // wxUSE_MENUS
451 bool wxGenericMDIChildFrame::Create( wxGenericMDIParentFrame
*parent
,
452 wxWindowID id
, const wxString
& title
,
453 const wxPoint
& WXUNUSED(pos
), const wxSize
& size
,
454 long style
, const wxString
& name
)
456 wxGenericMDIClientWindow
* pClientWindow
= parent
->GetClientWindow();
458 wxASSERT_MSG((pClientWindow
!= (wxWindow
*) NULL
), wxT("Missing MDI client window.") );
460 wxPanel::Create(pClientWindow
, id
, wxDefaultPosition
, size
, style
, name
);
462 SetMDIParentFrame(parent
);
464 // This is the currently active child
465 parent
->SetActiveChild(this);
469 pClientWindow
->AddPage(this, title
, TRUE
);
470 ApplyMDIChildFrameRect(); // Ok confirme the size change!
471 pClientWindow
->Refresh();
477 void wxGenericMDIChildFrame::SetMenuBar( wxMenuBar
*menu_bar
)
479 wxMenuBar
*pOldMenuBar
= m_pMenuBar
;
480 m_pMenuBar
= menu_bar
;
484 wxGenericMDIParentFrame
*pParentFrame
= GetMDIParentFrame();
486 if (pParentFrame
!= NULL
)
488 m_pMenuBar
->SetParent(pParentFrame
);
490 if (pParentFrame
->GetActiveChild() == this)
492 // Replace current menu bars
494 pParentFrame
->SetChildMenuBar((wxGenericMDIChildFrame
*) NULL
);
495 pParentFrame
->SetChildMenuBar((wxGenericMDIChildFrame
*) this);
501 wxMenuBar
*wxGenericMDIChildFrame::GetMenuBar() const
505 #endif // wxUSE_MENUS
507 void wxGenericMDIChildFrame::SetTitle(const wxString
& title
)
511 wxGenericMDIParentFrame
*pParentFrame
= GetMDIParentFrame();
513 if (pParentFrame
!= NULL
)
515 wxGenericMDIClientWindow
* pClientWindow
= pParentFrame
->GetClientWindow();
517 if (pClientWindow
!= NULL
)
520 for (pos
= 0; pos
< pClientWindow
->GetPageCount(); pos
++)
522 if (pClientWindow
->GetPage(pos
) == this)
524 pClientWindow
->SetPageText(pos
, m_Title
);
532 wxString
wxGenericMDIChildFrame::GetTitle() const
537 void wxGenericMDIChildFrame::Activate()
539 wxGenericMDIParentFrame
*pParentFrame
= GetMDIParentFrame();
541 if (pParentFrame
!= NULL
)
543 wxGenericMDIClientWindow
* pClientWindow
= pParentFrame
->GetClientWindow();
545 if (pClientWindow
!= NULL
)
548 for (pos
= 0; pos
< pClientWindow
->GetPageCount(); pos
++)
550 if (pClientWindow
->GetPage(pos
) == this)
552 pClientWindow
->SetSelection(pos
);
560 void wxGenericMDIChildFrame::OnMenuHighlight(wxMenuEvent
& event
)
563 if ( m_pMDIParentFrame
)
565 // we don't have any help text for this item,
566 // but may be the MDI frame does?
567 m_pMDIParentFrame
->OnMenuHighlight(event
);
569 #endif // wxUSE_STATUSBAR
572 void wxGenericMDIChildFrame::OnActivate(wxActivateEvent
& event
)
577 /*** Copied from top level..! ***/
578 // default resizing behaviour - if only ONE subwindow, resize to fill the
580 void wxGenericMDIChildFrame::OnSize(wxSizeEvent
& WXUNUSED(event
))
582 // if we're using constraints or sizers - do use them
583 if ( GetAutoLayout() )
589 // do we have _exactly_ one child?
590 wxWindow
*child
= (wxWindow
*)NULL
;
591 for ( wxWindowList::Node
*node
= GetChildren().GetFirst();
593 node
= node
->GetNext() )
595 wxWindow
*win
= node
->GetData();
597 // exclude top level and managed windows (status bar isn't
598 // currently in the children list except under wxMac anyhow, but
599 // it makes no harm to test for it)
600 if ( !win
->IsTopLevel() /*&& !IsOneOfBars(win)*/ )
604 return; // it's our second subwindow - nothing to do
611 // do we have any children at all?
614 // exactly one child - set it's size to fill the whole frame
615 int clientW
, clientH
;
616 DoGetClientSize(&clientW
, &clientH
);
618 // for whatever reasons, wxGTK wants to have a small offset - it
619 // probably looks better with it?
621 static const int ofs
= 1;
623 static const int ofs
= 0;
626 child
->SetSize(ofs
, ofs
, clientW
- 2*ofs
, clientH
- 2*ofs
);
631 /*** Copied from top level..! ***/
632 // The default implementation for the close window event.
633 void wxGenericMDIChildFrame::OnCloseWindow(wxCloseEvent
& WXUNUSED(event
))
638 void wxGenericMDIChildFrame::SetMDIParentFrame(wxGenericMDIParentFrame
* parentFrame
)
640 m_pMDIParentFrame
= parentFrame
;
643 wxGenericMDIParentFrame
* wxGenericMDIChildFrame::GetMDIParentFrame() const
645 return m_pMDIParentFrame
;
648 void wxGenericMDIChildFrame::Init()
650 m_pMDIParentFrame
= (wxGenericMDIParentFrame
*) NULL
;
652 m_pMenuBar
= (wxMenuBar
*) NULL
;
653 #endif // wxUSE_MENUS
656 void wxGenericMDIChildFrame::DoMoveWindow(int x
, int y
, int width
, int height
)
658 m_MDIRect
= wxRect(x
, y
, width
, height
);
661 void wxGenericMDIChildFrame::ApplyMDIChildFrameRect()
663 wxPanel::DoMoveWindow(m_MDIRect
.x
, m_MDIRect
.y
, m_MDIRect
.width
, m_MDIRect
.height
);
666 //-----------------------------------------------------------------------------
667 // wxGenericMDIClientWindow
668 //-----------------------------------------------------------------------------
670 #define wxID_NOTEBOOK_CLIENT_AREA wxID_HIGHEST + 100
672 IMPLEMENT_DYNAMIC_CLASS(wxGenericMDIClientWindow
, wxNotebook
)
674 BEGIN_EVENT_TABLE(wxGenericMDIClientWindow
, wxNotebook
)
675 EVT_NOTEBOOK_PAGE_CHANGED(wxID_NOTEBOOK_CLIENT_AREA
, wxGenericMDIClientWindow::OnPageChanged
)
676 EVT_SIZE(wxGenericMDIClientWindow::OnSize
)
680 wxGenericMDIClientWindow::wxGenericMDIClientWindow()
684 wxGenericMDIClientWindow::wxGenericMDIClientWindow( wxGenericMDIParentFrame
*parent
, long style
)
686 CreateClient( parent
, style
);
689 wxGenericMDIClientWindow::~wxGenericMDIClientWindow()
694 bool wxGenericMDIClientWindow::CreateClient( wxGenericMDIParentFrame
*parent
, long style
)
696 SetWindowStyleFlag(style
);
698 bool success
= wxNotebook::Create(parent
, wxID_NOTEBOOK_CLIENT_AREA
, wxPoint(0, 0), wxSize(100, 100), 0);
702 wxFont font(10, wxSWISS, wxNORMAL, wxNORMAL);
703 wxFont selFont(10, wxSWISS, wxNORMAL, wxBOLD);
704 GetTabView()->SetTabFont(font);
705 GetTabView()->SetSelectedTabFont(selFont);
706 GetTabView()->SetTabSize(120, 18);
707 GetTabView()->SetTabSelectionHeight(20);
715 int wxGenericMDIClientWindow::SetSelection(int nPage
)
717 int oldSelection
= wxNotebook::SetSelection(nPage
);
719 #if !defined(__WXMSW__) // No need to do this for wxMSW as wxNotebook::SetSelection()
720 // will already cause this to be done!
721 // Handle the page change.
722 PageChanged(oldSelection
, nPage
);
728 void wxGenericMDIClientWindow::PageChanged(int OldSelection
, int newSelection
)
730 // Don't do to much work, only when something realy should change!
731 if (OldSelection
== newSelection
)
733 // Again check if we realy need to do this...
734 if (newSelection
!= -1)
736 wxGenericMDIChildFrame
* child
= (wxGenericMDIChildFrame
*)GetPage(newSelection
);
738 if (child
->GetMDIParentFrame()->GetActiveChild() == child
)
742 // Notify old active child that it has been deactivated
743 if (OldSelection
!= -1)
745 wxGenericMDIChildFrame
* oldChild
= (wxGenericMDIChildFrame
*)GetPage(OldSelection
);
748 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, oldChild
->GetId());
749 event
.SetEventObject( oldChild
);
750 oldChild
->GetEventHandler()->ProcessEvent(event
);
754 // Notify new active child that it has been activated
755 if (newSelection
!= -1)
757 wxGenericMDIChildFrame
* activeChild
= (wxGenericMDIChildFrame
*)GetPage(newSelection
);
760 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, activeChild
->GetId());
761 event
.SetEventObject( activeChild
);
762 activeChild
->GetEventHandler()->ProcessEvent(event
);
764 if (activeChild
->GetMDIParentFrame())
766 activeChild
->GetMDIParentFrame()->SetActiveChild(activeChild
);
767 activeChild
->GetMDIParentFrame()->SetChildMenuBar(activeChild
);
773 void wxGenericMDIClientWindow::OnPageChanged(wxNotebookEvent
& event
)
775 PageChanged(event
.GetOldSelection(), event
.GetSelection());
780 void wxGenericMDIClientWindow::OnSize(wxSizeEvent
& event
)
782 wxNotebook::OnSize(event
);
785 for (pos
= 0; pos
< GetPageCount(); pos
++)
787 ((wxGenericMDIChildFrame
*)GetPage(pos
))->ApplyMDIChildFrameRect();
793 * Define normal wxMDI classes based on wxGenericMDI
796 #if wxUSE_GENERIC_MDI_AS_NATIVE
798 wxMDIChildFrame
* wxMDIParentFrame::GetActiveChild() const
800 wxGenericMDIChildFrame
*pGFrame
= wxGenericMDIParentFrame::GetActiveChild();
801 wxMDIChildFrame
*pFrame
= wxDynamicCast(pGFrame
, wxMDIChildFrame
);
803 wxASSERT_MSG(!(pFrame
== NULL
&& pGFrame
!= NULL
), wxT("Active frame is class not derived from wxMDIChildFrame!"));
808 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxGenericMDIParentFrame
)
809 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxGenericMDIChildFrame
)
810 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxGenericMDIClientWindow
)