1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: MDI classes
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
20 #include "wx/settings.h"
21 #include "wx/statusbr.h"
24 #include "wx/mac/private.h"
25 #include "wx/mac/uma.h"
27 extern wxWindowList wxModelessWindows
;
29 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxFrame
)
30 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxFrame
)
31 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxWindow
)
33 BEGIN_EVENT_TABLE(wxMDIParentFrame
, wxFrame
)
34 EVT_ACTIVATE(wxMDIParentFrame::OnActivate
)
35 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged
)
38 BEGIN_EVENT_TABLE(wxMDIClientWindow
, wxWindow
)
39 EVT_SCROLL(wxMDIClientWindow::OnScroll
)
42 static const wxChar
*TRACE_MDI
= _T("mdi");
44 static const int IDM_WINDOWTILE
= 4001;
45 static const int IDM_WINDOWTILEHOR
= 4001;
46 static const int IDM_WINDOWCASCADE
= 4002;
47 static const int IDM_WINDOWICONS
= 4003;
48 static const int IDM_WINDOWNEXT
= 4004;
49 static const int IDM_WINDOWTILEVERT
= 4005;
50 static const int IDM_WINDOWPREV
= 4006;
52 // This range gives a maximum of 500 MDI children. Should be enough :-)
53 static const int wxFIRST_MDI_CHILD
= 4100;
54 static const int wxLAST_MDI_CHILD
= 4600;
56 // Status border dimensions
57 static const int wxTHICK_LINE_BORDER
= 3;
59 // ----------------------------------------------------------------------------
61 // ----------------------------------------------------------------------------
63 void wxMDIParentFrame::Init()
65 m_clientWindow
= NULL
;
66 m_currentChild
= NULL
;
67 m_windowMenu
= (wxMenu
*) NULL
;
68 m_parentFrameActive
= true;
69 m_shouldBeShown
= false;
72 bool wxMDIParentFrame::Create(wxWindow
*parent
,
74 const wxString
& title
,
80 // this style can be used to prevent a window from having the standard MDI
82 if ( style
& wxFRAME_NO_WINDOW_MENU
)
84 m_windowMenu
= (wxMenu
*)NULL
;
85 style
-= wxFRAME_NO_WINDOW_MENU
;
87 else // normal case: we have the window menu, so construct it
89 m_windowMenu
= new wxMenu
;
91 m_windowMenu
->Append(IDM_WINDOWCASCADE
, wxT("&Cascade"));
92 m_windowMenu
->Append(IDM_WINDOWTILEHOR
, wxT("Tile &Horizontally"));
93 m_windowMenu
->Append(IDM_WINDOWTILEVERT
, wxT("Tile &Vertically"));
94 m_windowMenu
->AppendSeparator();
95 m_windowMenu
->Append(IDM_WINDOWICONS
, wxT("&Arrange Icons"));
96 m_windowMenu
->Append(IDM_WINDOWNEXT
, wxT("&Next"));
99 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
) ;
100 m_parentFrameActive
= true;
107 wxMDIParentFrame::~wxMDIParentFrame()
111 // already deleted by DestroyChildren()
112 m_clientWindow
= NULL
;
117 void wxMDIParentFrame::SetMenuBar(wxMenuBar
*menu_bar
)
119 wxFrame::SetMenuBar( menu_bar
) ;
122 void wxMDIParentFrame::GetRectForTopLevelChildren(int *x
, int *y
, int *w
, int *h
)
132 void wxMDIParentFrame::AddChild(wxWindowBase
*child
)
134 if ( !m_currentChild
)
136 m_currentChild
= wxDynamicCast(child
, wxMDIChildFrame
);
138 if ( m_currentChild
&& IsShown() && !ShouldBeVisible() )
140 // we shouldn't remain visible any more
141 wxFrame::Show(false);
142 m_shouldBeShown
= true;
146 wxFrame::AddChild(child
);
149 void wxMDIParentFrame::RemoveChild(wxWindowBase
*child
)
151 if ( child
== m_currentChild
)
153 // the current child isn't active any more, try to find another one
154 m_currentChild
= NULL
;
156 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
158 node
= node
->GetNext() )
161 childCur
= wxDynamicCast(node
->GetData(), wxMDIChildFrame
);
162 if ( childCur
!= child
)
164 m_currentChild
= childCur
;
170 wxFrame::RemoveChild(child
);
172 // if there are no more children left we need to show the frame if we
173 // hadn't shown it before because there were active children and it was
174 // useless (note that we have to do it after fully removing the child, i.e.
175 // after calling the base class RemoveChild() as otherwise we risk to touch
176 // pointer to the child being deleted)
177 if ( !m_currentChild
&& m_shouldBeShown
&& !IsShown() )
179 // we have to show it, but at least move it out of sight and make it of
180 // smallest possible size (unfortunately (0, 0) doesn't work so that it
181 // doesn't appear in expose
182 SetSize(-10000, -10000, 1, 1);
187 void wxMDIParentFrame::MacActivate(long timestamp
, bool activating
)
189 wxLogTrace(TRACE_MDI
, wxT("MDI PARENT=%p MacActivate(0x%08lx,%s)"), this, timestamp
, activating
? wxT("ACTIV") : wxT("deact"));
193 if (s_macDeactivateWindow
&& s_macDeactivateWindow
->GetParent() == this)
195 wxLogTrace(TRACE_MDI
, wxT("child had been scheduled for deactivation, rehighlighting"));
197 UMAHighlightAndActivateWindow((WindowRef
)s_macDeactivateWindow
->MacGetWindowRef(), true);
199 wxLogTrace(TRACE_MDI
, wxT("finished highliting child"));
201 s_macDeactivateWindow
= NULL
;
203 else if (s_macDeactivateWindow
== this)
205 wxLogTrace(TRACE_MDI
, wxT("Avoided deactivation/activation of this=%p"), this);
207 s_macDeactivateWindow
= NULL
;
209 else // window to deactivate is NULL or is not us or one of our kids
211 // activate kid instead
213 m_currentChild
->MacActivate(timestamp
, activating
);
215 wxFrame::MacActivate(timestamp
, activating
);
220 // We were scheduled for deactivation, and now we do it.
221 if (s_macDeactivateWindow
== this)
223 s_macDeactivateWindow
= NULL
;
225 m_currentChild
->MacActivate(timestamp
, activating
);
226 wxFrame::MacActivate(timestamp
, activating
);
228 else // schedule ourselves for deactivation
230 if (s_macDeactivateWindow
)
231 wxLogTrace(TRACE_MDI
, wxT("window=%p SHOULD have been deactivated, oh well!"), s_macDeactivateWindow
);
232 wxLogTrace(TRACE_MDI
, wxT("Scheduling delayed MDI Parent deactivation"));
234 s_macDeactivateWindow
= this;
239 void wxMDIParentFrame::OnActivate(wxActivateEvent
& event
)
244 // Returns the active MDI child window
245 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
247 return m_currentChild
;
250 // Create the client window class (don't Create the window,
251 // just return a new class)
252 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
254 m_clientWindow
= new wxMDIClientWindow( this );
256 return m_clientWindow
;
259 // Responds to colour changes, and passes event on to children.
260 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
264 // Propagate the event to the non-top-level children
265 wxFrame::OnSysColourChanged(event
);
269 void wxMDIParentFrame::Cascade()
274 void wxMDIParentFrame::Tile(wxOrientation
WXUNUSED(orient
))
279 void wxMDIParentFrame::ArrangeIcons()
284 void wxMDIParentFrame::ActivateNext()
289 void wxMDIParentFrame::ActivatePrevious()
294 bool wxMDIParentFrame::ShouldBeVisible() const
296 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
298 node
= node
->GetNext() )
300 wxWindow
*win
= node
->GetData();
303 && !wxDynamicCast(win
, wxMDIChildFrame
)
305 && win
!= (wxWindow
*) GetStatusBar()
307 && win
!= GetClientWindow() )
309 // if we have a non-MDI child, do remain visible so that it could
318 bool wxMDIParentFrame::Show( bool show
)
320 m_shouldBeShown
= false;
322 // don't really show the MDI frame unless it has any children other than
323 // MDI children as it is pretty useless in this case
327 if ( !ShouldBeVisible() && m_currentChild
)
329 // don't make the window visible now but remember that we should
331 m_shouldBeShown
= true;
337 return wxFrame::Show(show
);
340 // ----------------------------------------------------------------------------
342 // ----------------------------------------------------------------------------
344 wxMDIChildFrame::wxMDIChildFrame()
348 void wxMDIChildFrame::Init()
352 bool wxMDIChildFrame::Create(wxMDIParentFrame
*parent
,
354 const wxString
& title
,
358 const wxString
& name
)
365 m_windowId
= (int)NewControlId();
368 parent
->AddChild(this);
370 MacCreateRealWindow( title
, pos
, size
, MacRemoveBordersFromStyle(style
) , name
) ;
372 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE
));
374 wxModelessWindows
.Append(this);
379 wxMDIChildFrame::~wxMDIChildFrame()
384 void wxMDIChildFrame::SetMenuBar(wxMenuBar
*menu_bar
)
386 return wxFrame::SetMenuBar( menu_bar
) ;
389 void wxMDIChildFrame::MacActivate(long timestamp
, bool activating
)
391 wxLogTrace(TRACE_MDI
, wxT("MDI child=%p MacActivate(0x%08lx,%s)"),this, timestamp
, activating
? wxT("ACTIV") : wxT("deact"));
393 wxMDIParentFrame
*mdiparent
= wxDynamicCast(m_parent
, wxMDIParentFrame
);
398 if (s_macDeactivateWindow
== m_parent
)
400 wxLogTrace(TRACE_MDI
, wxT("parent had been scheduled for deactivation, rehighlighting"));
402 UMAHighlightAndActivateWindow((WindowRef
)s_macDeactivateWindow
->MacGetWindowRef(), true);
404 wxLogTrace(TRACE_MDI
, wxT("finished highliting parent"));
406 s_macDeactivateWindow
= NULL
;
408 else if ((mdiparent
->m_currentChild
== this) || !s_macDeactivateWindow
)
409 mdiparent
->wxFrame::MacActivate(timestamp
, activating
);
411 if (mdiparent
->m_currentChild
&& mdiparent
->m_currentChild
!= this)
412 mdiparent
->m_currentChild
->wxFrame::MacActivate(timestamp
, false);
413 mdiparent
->m_currentChild
= this;
415 if (s_macDeactivateWindow
== this)
417 wxLogTrace(TRACE_MDI
, wxT("Avoided deactivation/activation of this=%p"), this);
419 s_macDeactivateWindow
= NULL
;
422 wxFrame::MacActivate(timestamp
, activating
);
426 // We were scheduled for deactivation, and now we do it.
427 if (s_macDeactivateWindow
== this)
429 s_macDeactivateWindow
= NULL
;
430 wxFrame::MacActivate(timestamp
, activating
);
431 if (mdiparent
->m_currentChild
== this)
432 mdiparent
->wxFrame::MacActivate(timestamp
, activating
);
434 else // schedule ourselves for deactivation
436 if (s_macDeactivateWindow
)
437 wxLogTrace(TRACE_MDI
, wxT("window=%p SHOULD have been deactivated, oh well!"), s_macDeactivateWindow
);
438 wxLogTrace(TRACE_MDI
, wxT("Scheduling delayed deactivation"));
440 s_macDeactivateWindow
= this;
446 void wxMDIChildFrame::Maximize()
448 wxFrame::Maximize() ;
451 void wxMDIChildFrame::Restore()
456 void wxMDIChildFrame::Activate()
460 //-----------------------------------------------------------------------------
462 //-----------------------------------------------------------------------------
464 wxMDIClientWindow::wxMDIClientWindow()
468 wxMDIClientWindow::~wxMDIClientWindow()
473 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame
*parent
, long style
)
475 if ( !wxWindow::Create(parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
) )
478 wxModelessWindows
.Append(this);
483 // Get size *available for subwindows* i.e. excluding menu bar.
484 void wxMDIClientWindow::DoGetClientSize(int *x
, int *y
) const
486 wxDisplaySize( x
, y
) ;
489 // Explicitly call default scroll behaviour
490 void wxMDIClientWindow::OnScroll(wxScrollEvent
& event
)