1///////////////////////////////////////////////////////////////////////////// 2// Name: src/mac/carbon/mdi.cpp 3// Purpose: MDI classes 4// Author: Stefan Csomor 5// Modified by: 6// Created: 1998-01-01 7// RCS-ID: $Id: mdi.cpp 53039 2008-04-06 09:31:01Z CE $ 8// Copyright: (c) Stefan Csomor 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12#include "wx/wxprec.h" 13 14#if wxUSE_MDI 15 16#include "wx/mdi.h" 17 18#ifndef WX_PRECOMP 19 #include "wx/log.h" 20 #include "wx/menu.h" 21 #include "wx/settings.h" 22 #include "wx/statusbr.h" 23#endif 24 25#include "wx/mac/private.h" 26#include "wx/mac/uma.h" 27 28extern wxWindowList wxModelessWindows; 29 30IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxFrame) 31IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxFrame) 32IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxWindow) 33 34BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame) 35 EVT_ACTIVATE(wxMDIParentFrame::OnActivate) 36 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged) 37END_EVENT_TABLE() 38 39BEGIN_EVENT_TABLE(wxMDIClientWindow, wxWindow) 40 EVT_SCROLL(wxMDIClientWindow::OnScroll) 41END_EVENT_TABLE() 42 43static const wxChar *TRACE_MDI = _T("mdi"); 44 45static const int IDM_WINDOWTILEHOR = 4001; 46static const int IDM_WINDOWCASCADE = 4002; 47static const int IDM_WINDOWICONS = 4003; 48static const int IDM_WINDOWNEXT = 4004; 49static const int IDM_WINDOWTILEVERT = 4005; 50 51// ---------------------------------------------------------------------------- 52// Parent frame 53// ---------------------------------------------------------------------------- 54 55void wxMDIParentFrame::Init() 56{ 57 m_clientWindow = NULL; 58 m_currentChild = NULL; 59 m_windowMenu = (wxMenu*) NULL; 60 m_parentFrameActive = true; 61 m_shouldBeShown = false; 62} 63 64bool wxMDIParentFrame::Create(wxWindow *parent, 65 wxWindowID id, 66 const wxString& title, 67 const wxPoint& pos, 68 const wxSize& size, 69 long style, 70 const wxString& name) 71{ 72 // this style can be used to prevent a window from having the standard MDI 73 // "Window" menu 74 if ( style & wxFRAME_NO_WINDOW_MENU ) 75 { 76 m_windowMenu = (wxMenu *)NULL; 77 style -= wxFRAME_NO_WINDOW_MENU ; 78 } 79 else // normal case: we have the window menu, so construct it 80 { 81 m_windowMenu = new wxMenu; 82 83 m_windowMenu->Append(IDM_WINDOWCASCADE, wxT("&Cascade")); 84 m_windowMenu->Append(IDM_WINDOWTILEHOR, wxT("Tile &Horizontally")); 85 m_windowMenu->Append(IDM_WINDOWTILEVERT, wxT("Tile &Vertically")); 86 m_windowMenu->AppendSeparator(); 87 m_windowMenu->Append(IDM_WINDOWICONS, wxT("&Arrange Icons")); 88 m_windowMenu->Append(IDM_WINDOWNEXT, wxT("&Next")); 89 } 90 91 wxFrame::Create( parent , id , title , pos , size , style , name ) ; 92 m_parentFrameActive = true; 93 94 OnCreateClient(); 95 96 return true; 97} 98 99wxMDIParentFrame::~wxMDIParentFrame() 100{ 101 DestroyChildren(); 102 103 // already deleted by DestroyChildren() 104 m_clientWindow = NULL ; 105 106 delete m_windowMenu; 107} 108 109void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar) 110{ 111 wxFrame::SetMenuBar( menu_bar ) ; 112} 113 114void wxMDIParentFrame::GetRectForTopLevelChildren(int *x, int *y, int *w, int *h) 115{ 116 if (x) 117 *x = 0; 118 if (y) 119 *y = 0; 120 121 wxDisplaySize(w, h); 122} 123 124void wxMDIParentFrame::AddChild(wxWindowBase *child) 125{ 126 // moved this to front, so that we don't run into unset m_parent problems later 127 wxFrame::AddChild(child); 128 129 if ( !m_currentChild ) 130 { 131 m_currentChild = wxDynamicCast(child, wxMDIChildFrame); 132 133 if ( m_currentChild && IsShown() && !ShouldBeVisible() ) 134 { 135 // we shouldn't remain visible any more 136 wxFrame::Show(false); 137 m_shouldBeShown = true; 138 } 139 } 140} 141 142void wxMDIParentFrame::RemoveChild(wxWindowBase *child) 143{ 144 if ( child == m_currentChild ) 145 { 146 // the current child isn't active any more, try to find another one 147 m_currentChild = NULL; 148 149 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); 150 node; 151 node = node->GetNext() ) 152 { 153 wxMDIChildFrame * 154 childCur = wxDynamicCast(node->GetData(), wxMDIChildFrame); 155 if ( childCur != child ) 156 { 157 m_currentChild = childCur; 158 break; 159 } 160 } 161 } 162 163 wxFrame::RemoveChild(child); 164 165 // if there are no more children left we need to show the frame if we 166 // hadn't shown it before because there were active children and it was 167 // useless (note that we have to do it after fully removing the child, i.e. 168 // after calling the base class RemoveChild() as otherwise we risk to touch 169 // pointer to the child being deleted) 170 if ( !m_currentChild && m_shouldBeShown && !IsShown() ) 171 { 172 // we have to show it, but at least move it out of sight and make it of 173 // smallest possible size (unfortunately (0, 0) doesn't work so that it 174 // doesn't appear in expose 175 SetSize(-10000, -10000, 1, 1); 176 Show(); 177 } 178} 179 180void wxMDIParentFrame::MacActivate(long timestamp, bool activating) 181{ 182 wxLogTrace(TRACE_MDI, wxT("MDI PARENT=%p MacActivate(0x%08lx,%s)"), this, timestamp, activating ? wxT("ACTIV") : wxT("deact")); 183 184 if (activating) 185 { 186 if (s_macDeactivateWindow && s_macDeactivateWindow->GetParent() == this) 187 { 188 wxLogTrace(TRACE_MDI, wxT("child had been scheduled for deactivation, rehighlighting")); 189 190 UMAHighlightAndActivateWindow((WindowRef)s_macDeactivateWindow->MacGetWindowRef(), true); 191 192 wxLogTrace(TRACE_MDI, wxT("finished highliting child")); 193 194 s_macDeactivateWindow = NULL; 195 } 196 else if (s_macDeactivateWindow == this) 197 { 198 wxLogTrace(TRACE_MDI, wxT("Avoided deactivation/activation of this=%p"), this); 199 200 s_macDeactivateWindow = NULL; 201 } 202 else // window to deactivate is NULL or is not us or one of our kids 203 { 204 // activate kid instead 205 if (m_currentChild) 206 m_currentChild->MacActivate(timestamp, activating); 207 else 208 wxFrame::MacActivate(timestamp, activating); 209 } 210 } 211 else 212 { 213 // We were scheduled for deactivation, and now we do it. 214 if (s_macDeactivateWindow == this) 215 { 216 s_macDeactivateWindow = NULL; 217 if (m_currentChild) 218 m_currentChild->MacActivate(timestamp, activating); 219 wxFrame::MacActivate(timestamp, activating); 220 } 221 else // schedule ourselves for deactivation 222 { 223 if (s_macDeactivateWindow) 224 wxLogTrace(TRACE_MDI, wxT("window=%p SHOULD have been deactivated, oh well!"), s_macDeactivateWindow); 225 wxLogTrace(TRACE_MDI, wxT("Scheduling delayed MDI Parent deactivation")); 226 227 s_macDeactivateWindow = this; 228 } 229 } 230} 231 232void wxMDIParentFrame::OnActivate(wxActivateEvent& event) 233{ 234 event.Skip(); 235} 236 237// Returns the active MDI child window 238wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const 239{ 240 return m_currentChild ; 241} 242 243// Create the client window class (don't Create the window, 244// just return a new class) 245wxMDIClientWindow *wxMDIParentFrame::OnCreateClient() 246{ 247 m_clientWindow = new wxMDIClientWindow( this ); 248 249 return m_clientWindow; 250} 251 252// Responds to colour changes, and passes event on to children. 253void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent& event) 254{ 255 // TODO 256 257 // Propagate the event to the non-top-level children 258 wxFrame::OnSysColourChanged(event); 259} 260 261// MDI operations 262void wxMDIParentFrame::Cascade() 263{ 264 // TODO 265} 266 267void wxMDIParentFrame::Tile(wxOrientation WXUNUSED(orient)) 268{ 269 // TODO 270} 271 272void wxMDIParentFrame::ArrangeIcons() 273{ 274 // TODO 275} 276 277void wxMDIParentFrame::ActivateNext() 278{ 279 // TODO 280} 281 282void wxMDIParentFrame::ActivatePrevious() 283{ 284 // TODO 285} 286 287bool wxMDIParentFrame::ShouldBeVisible() const 288{ 289 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); 290 node; 291 node = node->GetNext() ) 292 { 293 wxWindow *win = node->GetData(); 294 295 if ( win->IsShown() 296 && !wxDynamicCast(win, wxMDIChildFrame) 297#if wxUSE_STATUSBAR 298 && win != (wxWindow*) GetStatusBar() 299#endif 300 && win != GetClientWindow() ) 301 { 302 // if we have a non-MDI child, do remain visible so that it could 303 // be used 304 return true; 305 } 306 } 307 308 return false; 309} 310 311bool wxMDIParentFrame::Show( bool show ) 312{ 313 m_shouldBeShown = false; 314 315 // don't really show the MDI frame unless it has any children other than 316 // MDI children as it is pretty useless in this case 317 318 if ( show ) 319 { 320 if ( !ShouldBeVisible() && m_currentChild ) 321 { 322 // don't make the window visible now but remember that we should 323 // have had done it 324 m_shouldBeShown = true; 325 326 return false; 327 } 328 } 329 330 return wxFrame::Show(show); 331} 332 333// ---------------------------------------------------------------------------- 334// Child frame 335// ---------------------------------------------------------------------------- 336 337wxMDIChildFrame::wxMDIChildFrame() 338{ 339 Init() ; 340} 341void wxMDIChildFrame::Init() 342{ 343} 344 345bool wxMDIChildFrame::Create(wxMDIParentFrame *parent, 346 wxWindowID id, 347 const wxString& title, 348 const wxPoint& pos, 349 const wxSize& size, 350 long style, 351 const wxString& name) 352{ 353 SetName(name); 354 355 if ( id == wxID_ANY ) 356 m_windowId = (int)NewControlId(); 357 else 358 m_windowId = id; 359 360 if (parent) 361 parent->AddChild(this); 362 363 MacCreateRealWindow( title, pos , size , MacRemoveBordersFromStyle(style) , name ) ; 364 365 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE)); 366 367 wxModelessWindows.Append(this); 368 369 return true; 370} 371 372wxMDIChildFrame::~wxMDIChildFrame() 373{ 374 DestroyChildren(); 375} 376 377void wxMDIChildFrame::SetMenuBar(wxMenuBar *menu_bar) 378{ 379 return wxFrame::SetMenuBar( menu_bar ) ; 380} 381 382void wxMDIChildFrame::MacActivate(long timestamp, bool activating) 383{ 384 wxLogTrace(TRACE_MDI, wxT("MDI child=%p MacActivate(0x%08lx,%s)"),this, timestamp, activating ? wxT("ACTIV") : wxT("deact")); 385 386 wxMDIParentFrame *mdiparent = wxDynamicCast(m_parent, wxMDIParentFrame); 387 wxASSERT(mdiparent); 388 389 if (activating) 390 { 391 if (s_macDeactivateWindow == m_parent) 392 { 393 wxLogTrace(TRACE_MDI, wxT("parent had been scheduled for deactivation, rehighlighting")); 394 395 UMAHighlightAndActivateWindow((WindowRef)s_macDeactivateWindow->MacGetWindowRef(), true); 396 397 wxLogTrace(TRACE_MDI, wxT("finished highliting parent")); 398 399 s_macDeactivateWindow = NULL; 400 } 401 else if ((mdiparent->m_currentChild == this) || !s_macDeactivateWindow) 402 mdiparent->wxFrame::MacActivate(timestamp, activating); 403 404 if (mdiparent->m_currentChild && mdiparent->m_currentChild != this) 405 mdiparent->m_currentChild->wxFrame::MacActivate(timestamp, false); 406 mdiparent->m_currentChild = this; 407 408 if (s_macDeactivateWindow == this) 409 { 410 wxLogTrace(TRACE_MDI, wxT("Avoided deactivation/activation of this=%p"), this); 411 412 s_macDeactivateWindow = NULL; 413 } 414 else 415 wxFrame::MacActivate(timestamp, activating); 416 } 417 else 418 { 419 // We were scheduled for deactivation, and now we do it. 420 if (s_macDeactivateWindow == this) 421 { 422 s_macDeactivateWindow = NULL; 423 wxFrame::MacActivate(timestamp, activating); 424 if (mdiparent->m_currentChild == this) 425 mdiparent->wxFrame::MacActivate(timestamp, activating); 426 } 427 else // schedule ourselves for deactivation 428 { 429 if (s_macDeactivateWindow) 430 wxLogTrace(TRACE_MDI, wxT("window=%p SHOULD have been deactivated, oh well!"), s_macDeactivateWindow); 431 wxLogTrace(TRACE_MDI, wxT("Scheduling delayed deactivation")); 432 433 s_macDeactivateWindow = this; 434 } 435 } 436} 437 438// MDI operations 439void wxMDIChildFrame::Maximize() 440{ 441 wxFrame::Maximize() ; 442} 443 444void wxMDIChildFrame::Restore() 445{ 446 wxFrame::Restore() ; 447} 448 449void wxMDIChildFrame::Activate() 450{ 451 Raise(); 452} 453 454//----------------------------------------------------------------------------- 455// wxMDIClientWindow 456//----------------------------------------------------------------------------- 457 458wxMDIClientWindow::wxMDIClientWindow() 459{ 460} 461 462wxMDIClientWindow::~wxMDIClientWindow() 463{ 464 DestroyChildren(); 465} 466 467bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style) 468{ 469 if ( !wxWindow::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style) ) 470 return false; 471 472 wxModelessWindows.Append(this); 473 474 return true; 475} 476 477// Get size *available for subwindows* i.e. excluding menu bar. 478void wxMDIClientWindow::DoGetClientSize(int *x, int *y) const 479{ 480 wxDisplaySize( x , y ) ; 481} 482 483// Explicitly call default scroll behaviour 484void wxMDIClientWindow::OnScroll(wxScrollEvent& event) 485{ 486} 487 488#endif // wxUSE_MDI 489