From f99422e9e916202c36a62534236d2288aae435c7 Mon Sep 17 00:00:00 2001 From: David Elliott Date: Thu, 13 Nov 2003 16:03:08 +0000 Subject: [PATCH] Added implementation of MDI using top level windows git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@24546 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/cocoa/mdi.h | 163 ++++++++++++++++++++ src/cocoa/mdi.mm | 335 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 498 insertions(+) create mode 100644 include/wx/cocoa/mdi.h create mode 100644 src/cocoa/mdi.mm diff --git a/include/wx/cocoa/mdi.h b/include/wx/cocoa/mdi.h new file mode 100644 index 0000000000..e2e3b6e772 --- /dev/null +++ b/include/wx/cocoa/mdi.h @@ -0,0 +1,163 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/cocoa/mdi.h +// Purpose: wxMDIParentFrame, wxMDIChildFrame, wxMDIClientWindow +// Author: David Elliott +// Modified by: +// Created: 2003/09/08 +// RCS-ID: $Id$ +// Copyright: (c) 2003 David Elliott +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef __WX_COCOA_MDI_H__ +#define __WX_COCOA_MDI_H__ + +#include "wx/frame.h" + +DECLARE_WXCOCOA_OBJC_CLASS(wxMDIParentFrameObserver); + +class WXDLLEXPORT wxMDIChildFrame; +class WXDLLEXPORT wxMDIClientWindow; + +WX_DECLARE_LIST(wxMDIChildFrame, wxCocoaMDIChildFrameList); + +// ======================================================================== +// wxMDIParentFrame +// ======================================================================== +class WXDLLEXPORT wxMDIParentFrame: public wxFrame +{ + friend class WXDLLEXPORT wxMDIChildFrame; + DECLARE_EVENT_TABLE() + DECLARE_DYNAMIC_CLASS(wxMDIParentFrame) +// ------------------------------------------------------------------------ +// initialization +// ------------------------------------------------------------------------ +public: + wxMDIParentFrame() { Init(); } + wxMDIParentFrame(wxWindow *parent, + wxWindowID winid, + const wxString& title, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_FRAME_STYLE, + const wxString& name = wxFrameNameStr) + { + Init(); + Create(parent, winid, title, pos, size, style, name); + } + + virtual ~wxMDIParentFrame(); + + bool Create(wxWindow *parent, + wxWindowID winid, + const wxString& title, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_FRAME_STYLE, + const wxString& name = wxFrameNameStr); +protected: + void Init(); +// ------------------------------------------------------------------------ +// Cocoa specifics +// ------------------------------------------------------------------------ +public: + void WindowDidBecomeMain(NSNotification *notification); +protected: + virtual void CocoaDelegate_windowDidBecomeKey(void); + virtual void CocoaDelegate_windowDidResignKey(void); + virtual bool Cocoa_canBecomeMainWindow(bool &canBecome); + virtual wxMenuBar* GetAppMenuBar(wxCocoaNSWindow *win); + + void AddMDIChild(wxMDIChildFrame *child); + void RemoveMDIChild(wxMDIChildFrame *child); + + wxMDIParentFrameObserver *m_observer; +// ------------------------------------------------------------------------ +// Implementation +// ------------------------------------------------------------------------ +public: + wxMDIChildFrame *GetActiveChild() const; + void SetActiveChild(wxMDIChildFrame *child); + + wxMDIClientWindow *GetClientWindow() const; + virtual wxMDIClientWindow *OnCreateClient(); + + virtual void Cascade() {} + virtual void Tile() {} + virtual void ArrangeIcons() {} + virtual void ActivateNext(); + virtual void ActivatePrevious(); +protected: + wxMDIClientWindow *m_clientWindow; + wxMDIChildFrame *m_currentChild; + wxCocoaMDIChildFrameList m_mdiChildren; +}; + +// ======================================================================== +// wxMDIChildFrame +// ======================================================================== +class WXDLLEXPORT wxMDIChildFrame: public wxFrame +{ + friend class WXDLLEXPORT wxMDIParentFrame; + DECLARE_EVENT_TABLE() + DECLARE_DYNAMIC_CLASS(wxMDIChildFrame) +// ------------------------------------------------------------------------ +// initialization +// ------------------------------------------------------------------------ +public: + wxMDIChildFrame() { Init(); } + wxMDIChildFrame(wxMDIParentFrame *parent, + wxWindowID winid, + const wxString& title, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_FRAME_STYLE, + const wxString& name = wxFrameNameStr) + { + Init(); + Create(parent, winid, title, pos, size, style, name); + } + + virtual ~wxMDIChildFrame(); + + bool Create(wxMDIParentFrame *parent, + wxWindowID winid, + const wxString& title, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_FRAME_STYLE, + const wxString& name = wxFrameNameStr); +protected: + void Init(); +// ------------------------------------------------------------------------ +// Cocoa specifics +// ------------------------------------------------------------------------ +public: +protected: + virtual void CocoaDelegate_windowDidBecomeKey(void); + virtual void CocoaDelegate_windowDidBecomeMain(void); + virtual void CocoaDelegate_windowDidResignKey(void); +// ------------------------------------------------------------------------ +// Implementation +// ------------------------------------------------------------------------ +public: + virtual void Activate(); + virtual bool Destroy(); +protected: + wxMDIParentFrame *m_mdiParent; +}; + +// ======================================================================== +// wxMDIClientWindow +// ======================================================================== +class wxMDIClientWindow: public wxWindow +{ + DECLARE_DYNAMIC_CLASS(wxMDIClientWindow) +public: + wxMDIClientWindow(); + wxMDIClientWindow( wxMDIParentFrame *parent, long style = 0 ); + ~wxMDIClientWindow(); + virtual bool CreateClient( wxMDIParentFrame *parent, long style = 0 ); +}; + +#endif // __WX_COCOA_MDI_H__ diff --git a/src/cocoa/mdi.mm b/src/cocoa/mdi.mm new file mode 100644 index 0000000000..1d069d58b0 --- /dev/null +++ b/src/cocoa/mdi.mm @@ -0,0 +1,335 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: cocoa/mdi.mm +// Purpose: wxMDIParentFrame, wxMDIChildFrame, wxMDIClientWindow +// Author: David Elliott +// Modified by: +// Created: 2003/09/08 +// RCS-ID: $Id$ +// Copyright: (c) 2003 David Elliott +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/mdi.h" +#endif // WX_PRECOMP + +// #include "wx/cocoa/autorelease.h" +#include "wx/cocoa/mbarman.h" + +#import +#import +// #import +// #import + +#include +WX_DEFINE_LIST(wxCocoaMDIChildFrameList); + +WX_DECLARE_HASH_MAP(int, wxMDIChildFrame*, wxIntegerHash, wxIntegerEqual, wxIntMDIChildFrameHashMap); + +// ============================================================================ +// wxMDIParentFrameObserver +// ============================================================================ +@interface wxMDIParentFrameObserver : NSObject +{ + wxMDIParentFrame *m_mdiParent; +} + +- (id)init; +- (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent; +- (void)windowDidBecomeMain: (NSNotification *)notification; +@end // interface wxMDIParentFrameObserver : NSObject + +@implementation wxMDIParentFrameObserver : NSObject +- (id)init +{ + wxFAIL_MSG("[wxMDIParentFrameObserver -init] should never be called!"); + m_mdiParent = NULL; + return self; +} + +- (id)initWithWxMDIParentFrame: (wxMDIParentFrame *)mdiParent +{ + wxASSERT(mdiParent); + m_mdiParent = mdiParent; + return [super init]; +} + +- (void)windowDidBecomeMain: (NSNotification *)notification +{ + wxASSERT(m_mdiParent); + m_mdiParent->WindowDidBecomeMain(notification); +} + +@end // implementation wxMDIParentFrameObserver : NSObject + +// ======================================================================== +// wxMDIParentFrame +// ======================================================================== +IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame) +BEGIN_EVENT_TABLE(wxMDIParentFrame,wxFrame) +END_EVENT_TABLE() + +void wxMDIParentFrame::Init() +{ + m_clientWindow = NULL; + m_currentChild = NULL; + m_observer = [[wxMDIParentFrameObserver alloc] + initWithWxMDIParentFrame:this]; + [[NSNotificationCenter defaultCenter] addObserver:m_observer + selector:@selector(windowDidBecomeMain:) + name:NSWindowDidBecomeMainNotification object:nil]; +} + +bool wxMDIParentFrame::Create(wxWindow *parent, + wxWindowID winid, const wxString& title, + const wxPoint& pos, const wxSize& size, + long style, const wxString& name) +{ + bool success = wxFrame::Create(parent,winid,title,pos,size,style,name); + if(success) + OnCreateClient(); + return success; +} + +wxMDIParentFrame::~wxMDIParentFrame() +{ + for(wxCocoaMDIChildFrameList::compatibility_iterator node = + m_mdiChildren.GetFirst(); node; node = m_mdiChildren.GetFirst()) + { + wxMDIChildFrame *child = node->GetData(); + // Delete it NOW + delete child; + wxASSERT_MSG(!m_mdiChildren.Find(child), + wxT("MDI child didn't remove itself using RemoveMDIChild()")); + } + [m_observer release]; +} + +void wxMDIParentFrame::AddMDIChild(wxMDIChildFrame *child) +{ + m_mdiChildren.Append(child); +} + +void wxMDIParentFrame::RemoveMDIChild(wxMDIChildFrame *child) +{ + m_mdiChildren.DeleteObject(child); + if(child==m_currentChild) + SetActiveChild(NULL); +} + +wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const +{ + return m_currentChild; +} + +void wxMDIParentFrame::SetActiveChild(wxMDIChildFrame *child) +{ + m_currentChild = child; + wxMenuBarManager::GetInstance()->UpdateMenuBar(); +} + +wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const +{ + return m_clientWindow; +} + +wxMDIClientWindow *wxMDIParentFrame::OnCreateClient() +{ + m_clientWindow = new wxMDIClientWindow( this ); + return m_clientWindow; +} + +void wxMDIParentFrame::ActivateNext() +{ +} + +void wxMDIParentFrame::ActivatePrevious() +{ +} + +wxMenuBar *wxMDIParentFrame::GetAppMenuBar(wxCocoaNSWindow *win) +{ + if(m_currentChild && (win==this)) + return m_currentChild->GetAppMenuBar(win); + return wxFrame::GetAppMenuBar(win); +} + +void wxMDIParentFrame::CocoaDelegate_windowDidBecomeKey(void) +{ + wxLogDebug("wxMDIParentFrame=%p::CocoaDelegate_windowDidBecomeKey",this); + if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_currentChild) + { + sm_cocoaDeactivateWindow = NULL; + } + #if 0 + else if(sm_cocoaDeactivateWindow == this) + { + sm_cocoaDeactivateWindow = NULL; + } + #endif + else + { + if(m_currentChild) + { + NSWindow *nswin = m_currentChild->GetNSWindow(); + if(![nswin isMainWindow]) + [nswin makeMainWindow]; + } + wxFrame::CocoaDelegate_windowDidBecomeKey(); + } +} + +void wxMDIParentFrame::CocoaDelegate_windowDidResignKey(void) +{ + wxLogDebug("wxMDIParentFrame=%p::CocoaDelegate_windowDidResignKey",this); + if(m_closed) + wxFrame::CocoaDelegate_windowDidResignKey(); + else + sm_cocoaDeactivateWindow = this; +} + +// We should not become the main window as we aren't a document window +// MDI "Children" should be the main window +bool wxMDIParentFrame::Cocoa_canBecomeMainWindow(bool &canBecome) +{ + canBecome = m_mdiChildren.IsEmpty(); return true; +} + +void wxMDIParentFrame::WindowDidBecomeMain(NSNotification *notification) +{ + // If we aren't the key window, we don't care + if(![m_cocoaNSWindow isKeyWindow]) + return; + wxCocoaNSWindow *win = wxCocoaNSWindow::GetFromCocoa([notification object]); + // If we are key and becoming main, that's great + if(win==this) + return; + // If one of our children is becoming main, also great + for(wxCocoaMDIChildFrameList::compatibility_iterator node = + m_mdiChildren.GetFirst(); node; node = node->GetNext()) + { + wxMDIChildFrame *child = node->GetData(); + if(win==child) + return; + } + // Some other window is becoming main, but we are key + // Make the new main window the key window + [[notification object] makeKeyWindow]; + if(!m_currentChild) + { + wxIntMDIChildFrameHashMap hashmap; + for(wxCocoaMDIChildFrameList::compatibility_iterator node = + m_mdiChildren.GetFirst(); node; node = node->GetNext()) + { + wxMDIChildFrame *child = node->GetData(); + hashmap.insert(wxIntMDIChildFrameHashMap::value_type([child->m_cocoaNSWindow windowNumber],child)); + } + if(!hashmap.empty()) + { + int windowCount = 0; + NSCountWindows(&windowCount); + wxASSERT(windowCount>0); + int *windowList = new int[windowCount]; + NSWindowList(windowCount, windowList); + wxIntMDIChildFrameHashMap::iterator iter = hashmap.end(); + for(int i=0; isecond; + } + } +} + +// ======================================================================== +// wxMDIChildFrame +// ======================================================================== +IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame) +BEGIN_EVENT_TABLE(wxMDIChildFrame,wxFrame) +END_EVENT_TABLE() + +void wxMDIChildFrame::Init() +{ + m_mdiParent = NULL; +} + +bool wxMDIChildFrame::Create(wxMDIParentFrame *parent, + wxWindowID winid, const wxString& title, + const wxPoint& pos, const wxSize& size, + long style, const wxString& name) +{ + bool success = wxFrame::Create(parent,winid,title,pos,size,style,name); + if(success) + { + m_mdiParent = parent; + parent->AddMDIChild(this); + } + return success; +} + +wxMDIChildFrame::~wxMDIChildFrame() +{ + // Just in case Destroy() wasn't called + m_mdiParent->RemoveMDIChild(this); +} + +void wxMDIChildFrame::Activate() +{ +} + +void wxMDIChildFrame::CocoaDelegate_windowDidBecomeKey(void) +{ + wxLogDebug("wxMDIChildFrame=%p::CocoaDelegate_windowDidBecomeKey",this); + if(sm_cocoaDeactivateWindow && sm_cocoaDeactivateWindow==m_mdiParent) + { + sm_cocoaDeactivateWindow = NULL; + if(m_mdiParent->GetActiveChild() != this) + sm_cocoaDeactivateWindow = m_mdiParent->GetActiveChild(); + } + m_mdiParent->SetActiveChild(this); + wxFrame::CocoaDelegate_windowDidBecomeKey(); +} + +void wxMDIChildFrame::CocoaDelegate_windowDidBecomeMain(void) +{ + m_mdiParent->SetActiveChild(this); + wxFrame::CocoaDelegate_windowDidBecomeMain(); +} + +void wxMDIChildFrame::CocoaDelegate_windowDidResignKey(void) +{ + wxLogDebug("wxMDIChildFrame=%p::CocoaDelegate_windowDidResignKey",this); + sm_cocoaDeactivateWindow = this; +} + +bool wxMDIChildFrame::Destroy() +{ + // It's good to do this here before we are really closed + m_mdiParent->RemoveMDIChild(this); + return wxFrame::Destroy(); +} + +// ======================================================================== +// wxMDIClientWindow +// ======================================================================== +IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow) + +wxMDIClientWindow::wxMDIClientWindow() +{ +} + +wxMDIClientWindow::wxMDIClientWindow(wxMDIParentFrame *parent, long style) +: wxWindow(parent, -1) +{ +} + +wxMDIClientWindow::~wxMDIClientWindow() +{ +} + +bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style) +{ + return false; +} +