1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: MDI classes
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
18 #include "wx/settings.h"
21 #include "wx/mac/private.h"
22 #include "wx/mac/uma.h"
24 extern wxWindowList wxModelessWindows
;
26 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxFrame
)
27 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxFrame
)
28 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxWindow
)
30 BEGIN_EVENT_TABLE(wxMDIParentFrame
, wxFrame
)
31 EVT_ACTIVATE(wxMDIParentFrame::OnActivate
)
32 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged
)
35 BEGIN_EVENT_TABLE(wxMDIClientWindow
, wxWindow
)
36 EVT_SCROLL(wxMDIClientWindow::OnScroll
)
39 static const wxChar
*TRACE_MDI
= _T("mdi");
41 static const int IDM_WINDOWTILE
= 4001;
42 static const int IDM_WINDOWTILEHOR
= 4001;
43 static const int IDM_WINDOWCASCADE
= 4002;
44 static const int IDM_WINDOWICONS
= 4003;
45 static const int IDM_WINDOWNEXT
= 4004;
46 static const int IDM_WINDOWTILEVERT
= 4005;
47 static const int IDM_WINDOWPREV
= 4006;
49 // This range gives a maximum of 500 MDI children. Should be enough :-)
50 static const int wxFIRST_MDI_CHILD
= 4100;
51 static const int wxLAST_MDI_CHILD
= 4600;
53 // Status border dimensions
54 static const int wxTHICK_LINE_BORDER
= 3;
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 void wxMDIParentFrame::Init()
62 m_clientWindow
= NULL
;
63 m_currentChild
= NULL
;
64 m_windowMenu
= (wxMenu
*) NULL
;
65 m_parentFrameActive
= true;
66 m_shouldBeShown
= false;
69 bool wxMDIParentFrame::Create(wxWindow
*parent
,
71 const wxString
& title
,
77 // this style can be used to prevent a window from having the standard MDI
79 if ( style
& wxFRAME_NO_WINDOW_MENU
)
81 m_windowMenu
= (wxMenu
*)NULL
;
82 style
-= wxFRAME_NO_WINDOW_MENU
;
84 else // normal case: we have the window menu, so construct it
86 m_windowMenu
= new wxMenu
;
88 m_windowMenu
->Append(IDM_WINDOWCASCADE
, wxT("&Cascade"));
89 m_windowMenu
->Append(IDM_WINDOWTILEHOR
, wxT("Tile &Horizontally"));
90 m_windowMenu
->Append(IDM_WINDOWTILEVERT
, wxT("Tile &Vertically"));
91 m_windowMenu
->AppendSeparator();
92 m_windowMenu
->Append(IDM_WINDOWICONS
, wxT("&Arrange Icons"));
93 m_windowMenu
->Append(IDM_WINDOWNEXT
, wxT("&Next"));
96 wxFrame::Create( parent
, id
, title
, pos
, size
, style
, name
) ;
97 m_parentFrameActive
= true;
104 wxMDIParentFrame::~wxMDIParentFrame()
107 // already deleted by DestroyChildren()
108 m_clientWindow
= NULL
;
114 void wxMDIParentFrame::SetMenuBar(wxMenuBar
*menu_bar
)
116 wxFrame::SetMenuBar( menu_bar
) ;
119 void wxMDIParentFrame::GetRectForTopLevelChildren(int *x
, int *y
, int *w
, int *h
)
128 void wxMDIParentFrame::AddChild(wxWindowBase
*child
)
130 if ( !m_currentChild
)
132 m_currentChild
= wxDynamicCast(child
, wxMDIChildFrame
);
134 if ( m_currentChild
&& IsShown() && !ShouldBeVisible() )
136 // we shouldn't remain visible any more
137 wxFrame::Show(false);
138 m_shouldBeShown
= true;
142 wxFrame::AddChild(child
);
145 void wxMDIParentFrame::RemoveChild(wxWindowBase
*child
)
147 if ( child
== m_currentChild
)
149 // the current child isn't active any more, try to find another one
150 m_currentChild
= NULL
;
152 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
154 node
= node
->GetNext() )
157 childCur
= wxDynamicCast(node
->GetData(), wxMDIChildFrame
);
158 if ( childCur
!= child
)
160 m_currentChild
= childCur
;
166 wxFrame::RemoveChild(child
);
168 // if there are no more children left we need to show the frame if we
169 // hadn't shown it before because there were active children and it was
170 // useless (note that we have to do it after fully removing the child, i.e.
171 // after calling the base class RemoveChild() as otherwise we risk to touch
172 // pointer to the child being deleted)
173 if ( !m_currentChild
&& m_shouldBeShown
&& !IsShown() )
175 // we have to show it, but at least move it out of sight and make it of
176 // smallest possible size (unfortunately (0, 0) doesn't work so that it
177 // doesn't appear in expose
178 SetSize(-10000, -10000, 1, 1);
183 void wxMDIParentFrame::MacActivate(long timestamp
, bool activating
)
185 wxLogTrace(TRACE_MDI
, wxT("MDI PARENT=%p MacActivate(0x%08lx,%s)"),this,timestamp
,activating
?wxT("ACTIV"):wxT("deact"));
188 if(s_macDeactivateWindow
&& s_macDeactivateWindow
->GetParent()==this)
190 wxLogTrace(TRACE_MDI
, wxT("child had been scheduled for deactivation, rehighlighting"));
191 UMAHighlightAndActivateWindow((WindowRef
)s_macDeactivateWindow
->MacGetWindowRef(), true);
192 wxLogTrace(TRACE_MDI
, wxT("done highliting child"));
193 s_macDeactivateWindow
= NULL
;
195 else if(s_macDeactivateWindow
== this)
197 wxLogTrace(TRACE_MDI
, wxT("Avoided deactivation/activation of this=%p"), this);
198 s_macDeactivateWindow
= NULL
;
200 else // window to deactivate is NULL or is not us or one of our kids
202 // activate kid instead
204 m_currentChild
->MacActivate(timestamp
,activating
);
206 wxFrame::MacActivate(timestamp
,activating
);
211 // We were scheduled for deactivation, and now we do it.
212 if(s_macDeactivateWindow
==this)
214 s_macDeactivateWindow
= NULL
;
216 m_currentChild
->MacActivate(timestamp
,activating
);
217 wxFrame::MacActivate(timestamp
,activating
);
219 else // schedule ourselves for deactivation
221 if(s_macDeactivateWindow
)
222 wxLogTrace(TRACE_MDI
, wxT("window=%p SHOULD have been deactivated, oh well!"),s_macDeactivateWindow
);
223 wxLogTrace(TRACE_MDI
, wxT("Scheduling delayed MDI Parent deactivation"));
224 s_macDeactivateWindow
= this;
229 void wxMDIParentFrame::OnActivate(wxActivateEvent
& event
)
234 // Returns the active MDI child window
235 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
237 return m_currentChild
;
240 // Create the client window class (don't Create the window,
241 // just return a new class)
242 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
244 m_clientWindow
= new wxMDIClientWindow( this );
245 return m_clientWindow
;
248 // Responds to colour changes, and passes event on to children.
249 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
253 // Propagate the event to the non-top-level children
254 wxFrame::OnSysColourChanged(event
);
258 void wxMDIParentFrame::Cascade()
263 void wxMDIParentFrame::Tile(wxOrientation
WXUNUSED(orient
))
268 void wxMDIParentFrame::ArrangeIcons()
273 void wxMDIParentFrame::ActivateNext()
278 void wxMDIParentFrame::ActivatePrevious()
283 bool wxMDIParentFrame::ShouldBeVisible() const
285 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
287 node
= node
->GetNext() )
289 wxWindow
*win
= node
->GetData();
292 && !wxDynamicCast(win
, wxMDIChildFrame
)
294 && win
!= GetStatusBar()
295 #endif // wxUSE_STATUSBAR
296 && win
!= GetClientWindow() )
298 // if we have a non-MDI child, do remain visible so that it could
307 bool wxMDIParentFrame::Show( bool show
)
309 m_shouldBeShown
= false;
311 // don't really show the MDI frame unless it has any children other than
312 // MDI children as it is pretty useless in this case
316 if ( !ShouldBeVisible() && m_currentChild
)
318 // don't make the window visible now but remember that we should
320 m_shouldBeShown
= true;
325 return wxFrame::Show(show
);
328 // ----------------------------------------------------------------------------
330 // ----------------------------------------------------------------------------
332 wxMDIChildFrame::wxMDIChildFrame()
336 void wxMDIChildFrame::Init()
340 bool wxMDIChildFrame::Create(wxMDIParentFrame
*parent
,
342 const wxString
& title
,
346 const wxString
& name
)
353 m_windowId
= (int)NewControlId();
355 if (parent
) parent
->AddChild(this);
357 MacCreateRealWindow( title
, pos
, size
, MacRemoveBordersFromStyle(style
) , name
) ;
359 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE
));
361 wxModelessWindows
.Append(this);
365 wxMDIChildFrame::~wxMDIChildFrame()
370 void wxMDIChildFrame::SetMenuBar(wxMenuBar
*menu_bar
)
372 return wxFrame::SetMenuBar( menu_bar
) ;
375 void wxMDIChildFrame::MacActivate(long timestamp
, bool activating
)
377 wxLogTrace(TRACE_MDI
, wxT("MDI child=%p MacActivate(0x%08lx,%s)"),this,timestamp
,activating
?wxT("ACTIV"):wxT("deact"));
378 wxMDIParentFrame
*mdiparent
= wxDynamicCast(m_parent
, wxMDIParentFrame
);
382 if(s_macDeactivateWindow
== m_parent
)
384 wxLogTrace(TRACE_MDI
, wxT("parent had been scheduled for deactivation, rehighlighting"));
385 UMAHighlightAndActivateWindow((WindowRef
)s_macDeactivateWindow
->MacGetWindowRef(), true);
386 wxLogTrace(TRACE_MDI
, wxT("done highliting parent"));
387 s_macDeactivateWindow
= NULL
;
389 else if((mdiparent
->m_currentChild
==this) || !s_macDeactivateWindow
)
390 mdiparent
->wxFrame::MacActivate(timestamp
,activating
);
392 if(mdiparent
->m_currentChild
&& mdiparent
->m_currentChild
!=this)
393 mdiparent
->m_currentChild
->wxFrame::MacActivate(timestamp
,false);
394 mdiparent
->m_currentChild
= this;
396 if(s_macDeactivateWindow
==this)
398 wxLogTrace(TRACE_MDI
, wxT("Avoided deactivation/activation of this=%p"),this);
399 s_macDeactivateWindow
=NULL
;
402 wxFrame::MacActivate(timestamp
, activating
);
406 // We were scheduled for deactivation, and now we do it.
407 if(s_macDeactivateWindow
==this)
409 s_macDeactivateWindow
= NULL
;
410 wxFrame::MacActivate(timestamp
,activating
);
411 if(mdiparent
->m_currentChild
==this)
412 mdiparent
->wxFrame::MacActivate(timestamp
,activating
);
414 else // schedule ourselves for deactivation
416 if(s_macDeactivateWindow
)
417 wxLogTrace(TRACE_MDI
, wxT("window=%p SHOULD have been deactivated, oh well!"),s_macDeactivateWindow
);
418 wxLogTrace(TRACE_MDI
, wxT("Scheduling delayed deactivation"));
419 s_macDeactivateWindow
= this;
425 void wxMDIChildFrame::Maximize()
427 wxFrame::Maximize() ;
430 void wxMDIChildFrame::Restore()
435 void wxMDIChildFrame::Activate()
439 //-----------------------------------------------------------------------------
441 //-----------------------------------------------------------------------------
443 wxMDIClientWindow::wxMDIClientWindow()
447 wxMDIClientWindow::~wxMDIClientWindow()
452 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame
*parent
, long style
)
454 if ( !wxWindow::Create(parent
, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, style
))
457 wxModelessWindows
.Append(this);
461 // Get size *available for subwindows* i.e. excluding menu bar.
462 void wxMDIClientWindow::DoGetClientSize(int *x
, int *y
) const
464 wxDisplaySize( x
, y
) ;
467 // Explicitly call default scroll behaviour
468 void wxMDIClientWindow::OnScroll(wxScrollEvent
& event
)