1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        wx/mdi.h
3 // Purpose:     wxMDI base header
4 // Author:      Julian Smart (original)
5 //              Vadim Zeitlin (base MDI classes refactoring)
6 // Copyright:   (c) 1998 Julian Smart
7 //              (c) 2008 Vadim Zeitlin
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 #ifndef _WX_MDI_H_BASE_
12 #define _WX_MDI_H_BASE_
13 
14 #include "wx/defs.h"
15 
16 #if wxUSE_MDI
17 
18 #include "wx/frame.h"
19 #include "wx/menu.h"
20 
21 // forward declarations
22 class WXDLLIMPEXP_FWD_CORE wxMDIParentFrame;
23 class WXDLLIMPEXP_FWD_CORE wxMDIChildFrame;
24 class WXDLLIMPEXP_FWD_CORE wxMDIClientWindowBase;
25 class WXDLLIMPEXP_FWD_CORE wxMDIClientWindow;
26 
27 // ----------------------------------------------------------------------------
28 // wxMDIParentFrameBase: base class for parent frame for MDI children
29 // ----------------------------------------------------------------------------
30 
31 class WXDLLIMPEXP_CORE wxMDIParentFrameBase : public wxFrame
32 {
33 public:
wxMDIParentFrameBase()34     wxMDIParentFrameBase()
35     {
36         m_clientWindow = NULL;
37         m_currentChild = NULL;
38 #if wxUSE_MENUS
39         m_windowMenu = NULL;
40 #endif // wxUSE_MENUS
41     }
42 
43     /*
44         Derived classes should provide ctor and Create() with the following
45         declaration:
46 
47     bool Create(wxWindow *parent,
48                 wxWindowID winid,
49                 const wxString& title,
50                 const wxPoint& pos = wxDefaultPosition,
51                 const wxSize& size = wxDefaultSize,
52                 long style = wxDEFAULT_FRAME_STYLE | wxVSCROLL | wxHSCROLL,
53                 const wxString& name = wxFrameNameStr);
54      */
55 
56 #if wxUSE_MENUS
~wxMDIParentFrameBase()57     virtual ~wxMDIParentFrameBase()
58     {
59         delete m_windowMenu;
60     }
61 #endif // wxUSE_MENUS
62 
63     // accessors
64     // ---------
65 
66     // Get or change the active MDI child window
GetActiveChild()67     virtual wxMDIChildFrame *GetActiveChild() const
68         { return m_currentChild; }
SetActiveChild(wxMDIChildFrame * child)69     virtual void SetActiveChild(wxMDIChildFrame *child)
70         { m_currentChild = child; }
71 
72 
73     // Get the client window
GetClientWindow()74     wxMDIClientWindowBase *GetClientWindow() const { return m_clientWindow; }
75 
76 
77     // MDI windows menu functions
78     // --------------------------
79 
80 #if wxUSE_MENUS
81     // return the pointer to the current window menu or NULL if we don't have
82     // because of wxFRAME_NO_WINDOW_MENU style
GetWindowMenu()83     wxMenu* GetWindowMenu() const { return m_windowMenu; }
84 
85     // use the given menu instead of the default window menu
86     //
87     // menu can be NULL to disable the window menu completely
SetWindowMenu(wxMenu * menu)88     virtual void SetWindowMenu(wxMenu *menu)
89     {
90         if ( menu != m_windowMenu )
91         {
92             delete m_windowMenu;
93             m_windowMenu = menu;
94         }
95     }
96 #endif // wxUSE_MENUS
97 
98 
99     // standard MDI window management functions
100     // ----------------------------------------
101 
Cascade()102     virtual void Cascade() { }
103     virtual void Tile(wxOrientation WXUNUSED(orient) = wxHORIZONTAL) { }
ArrangeIcons()104     virtual void ArrangeIcons() { }
105     virtual void ActivateNext() = 0;
106     virtual void ActivatePrevious() = 0;
107 
108     /*
109         Derived classes must provide the following function:
110 
111     static bool IsTDI();
112     */
113 
114     // Create the client window class (don't Create() the window here, just
115     // return a new object of a wxMDIClientWindow-derived class)
116     //
117     // Notice that if you override this method you should use the default
118     // constructor and Create() and not the constructor creating the window
119     // when creating the frame or your overridden version is not going to be
120     // called (as the call to a virtual function from ctor will be dispatched
121     // to this class version)
122     virtual wxMDIClientWindow *OnCreateClient();
123 
124 protected:
125     // Override to pass menu/toolbar events to the active child first.
126     virtual bool TryBefore(wxEvent& event);
127 
128 
129     // This is wxMDIClientWindow for all the native implementations but not for
130     // the generic MDI version which has its own wxGenericMDIClientWindow and
131     // so we store it as just a base class pointer because we don't need its
132     // exact type anyhow
133     wxMDIClientWindowBase *m_clientWindow;
134     wxMDIChildFrame *m_currentChild;
135 
136 #if wxUSE_MENUS
137     // the current window menu or NULL if we are not using it
138     wxMenu *m_windowMenu;
139 #endif // wxUSE_MENUS
140 };
141 
142 // ----------------------------------------------------------------------------
143 // wxMDIChildFrameBase: child frame managed by wxMDIParentFrame
144 // ----------------------------------------------------------------------------
145 
146 class WXDLLIMPEXP_CORE wxMDIChildFrameBase : public wxFrame
147 {
148 public:
wxMDIChildFrameBase()149     wxMDIChildFrameBase() { m_mdiParent = NULL; }
150 
151     /*
152         Derived classes should provide Create() with the following signature:
153 
154     bool Create(wxMDIParentFrame *parent,
155                 wxWindowID id,
156                 const wxString& title,
157                 const wxPoint& pos = wxDefaultPosition,
158                 const wxSize& size = wxDefaultSize,
159                 long style = wxDEFAULT_FRAME_STYLE,
160                 const wxString& name = wxFrameNameStr);
161 
162         And setting m_mdiParent to parent parameter.
163      */
164 
165     // MDI children specific methods
166     virtual void Activate() = 0;
167 
168     // Return the MDI parent frame: notice that it may not be the same as
169     // GetParent() (our parent may be the client window or even its subwindow
170     // in some implementations)
GetMDIParent()171     wxMDIParentFrame *GetMDIParent() const { return m_mdiParent; }
172 
173     // Synonym for GetMDIParent(), was used in some other ports
GetMDIParentFrame()174     wxMDIParentFrame *GetMDIParentFrame() const { return GetMDIParent(); }
175 
176 
177     // in most ports MDI children frames are not really top-level, the only
178     // exception are the Mac ports in which MDI children are just normal top
179     // level windows too
IsTopLevel()180     virtual bool IsTopLevel() const { return false; }
181 
182     // In all ports keyboard navigation must stop at MDI child frame level and
183     // can't cross its boundary. Indicate this by overriding this function to
184     // return true.
IsTopNavigationDomain()185     virtual bool IsTopNavigationDomain() const { return true; }
186 
187     // Raising any frame is supposed to show it but wxFrame Raise()
188     // implementation doesn't work for MDI child frames in most forms so
189     // forward this to Activate() which serves the same purpose by default.
Raise()190     virtual void Raise() { Activate(); }
191 
192 protected:
193     wxMDIParentFrame *m_mdiParent;
194 };
195 
196 // ----------------------------------------------------------------------------
197 // wxTDIChildFrame: child frame used by TDI implementations
198 // ----------------------------------------------------------------------------
199 
200 class WXDLLIMPEXP_CORE wxTDIChildFrame : public wxMDIChildFrameBase
201 {
202 public:
203     // override wxFrame methods for this non top-level window
204 
205 #if wxUSE_STATUSBAR
206     // no status bars
207     //
208     // TODO: MDI children should have their own status bars, why not?
WXUNUSED(number)209     virtual wxStatusBar* CreateStatusBar(int WXUNUSED(number) = 1,
210                                          long WXUNUSED(style) = 1,
211                                          wxWindowID WXUNUSED(id) = 1,
212                                          const wxString& WXUNUSED(name)
213                                             = wxEmptyString)
214       { return NULL; }
215 
GetStatusBar()216     virtual wxStatusBar *GetStatusBar() const
217         { return NULL; }
218     virtual void SetStatusText(const wxString &WXUNUSED(text),
219                                int WXUNUSED(number)=0)
220         { }
SetStatusWidths(int WXUNUSED (n),const int WXUNUSED (widths)[])221     virtual void SetStatusWidths(int WXUNUSED(n),
222                                  const int WXUNUSED(widths)[])
223         { }
224 #endif // wxUSE_STATUSBAR
225 
226 #if wxUSE_TOOLBAR
227     // no toolbar
228     //
229     // TODO: again, it should be possible to have tool bars
CreateToolBar(long WXUNUSED (style),wxWindowID WXUNUSED (id),const wxString & WXUNUSED (name))230     virtual wxToolBar *CreateToolBar(long WXUNUSED(style),
231                                      wxWindowID WXUNUSED(id),
232                                      const wxString& WXUNUSED(name))
233         { return NULL; }
GetToolBar()234     virtual wxToolBar *GetToolBar() const { return NULL; }
235 #endif // wxUSE_TOOLBAR
236 
237     // no icon
SetIcons(const wxIconBundle & WXUNUSED (icons))238     virtual void SetIcons(const wxIconBundle& WXUNUSED(icons)) { }
239 
240     // title is used as the tab label
GetTitle()241     virtual wxString GetTitle() const { return m_title; }
242     virtual void SetTitle(const wxString& title) = 0;
243 
244     // no maximize etc
WXUNUSED(maximize)245     virtual void Maximize(bool WXUNUSED(maximize) = true) { }
IsMaximized()246     virtual bool IsMaximized() const { return true; }
IsAlwaysMaximized()247     virtual bool IsAlwaysMaximized() const { return true; }
WXUNUSED(iconize)248     virtual void Iconize(bool WXUNUSED(iconize) = true) { }
IsIconized()249     virtual bool IsIconized() const { return false; }
Restore()250     virtual void Restore() { }
251 
ShowFullScreen(bool WXUNUSED (show),long WXUNUSED (style))252     virtual bool ShowFullScreen(bool WXUNUSED(show),
253                                 long WXUNUSED(style)) { return false; }
IsFullScreen()254     virtual bool IsFullScreen() const { return false; }
255 
256 
257     // we need to override these functions to ensure that a child window is
258     // created even though we derive from wxFrame -- basically we make it
259     // behave as just a wxWindow by short-circuiting wxTLW changes to the base
260     // class behaviour
261 
AddChild(wxWindowBase * child)262     virtual void AddChild(wxWindowBase *child) { wxWindow::AddChild(child); }
263 
Destroy()264     virtual bool Destroy() { return wxWindow::Destroy(); }
265 
266     // extra platform-specific hacks
267 #ifdef __WXMSW__
268     virtual WXDWORD MSWGetStyle(long flags, WXDWORD *exstyle = NULL) const
269     {
270         return wxWindow::MSWGetStyle(flags, exstyle);
271     }
272 
MSWGetParent()273     virtual WXHWND MSWGetParent() const
274     {
275         return wxWindow::MSWGetParent();
276     }
277 
MSWWindowProc(WXUINT message,WXWPARAM wParam,WXLPARAM lParam)278     WXLRESULT MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
279     {
280         return wxWindow::MSWWindowProc(message, wParam, lParam);
281     }
282 #endif // __WXMSW__
283 
284 protected:
DoGetSize(int * width,int * height)285     virtual void DoGetSize(int *width, int *height) const
286     {
287         wxWindow::DoGetSize(width, height);
288     }
289 
DoSetSize(int x,int y,int width,int height,int sizeFlags)290     virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags)
291     {
292         wxWindow::DoSetSize(x, y, width, height, sizeFlags);
293     }
294 
DoGetClientSize(int * width,int * height)295     virtual void DoGetClientSize(int *width, int *height) const
296     {
297         wxWindow::DoGetClientSize(width, height);
298     }
299 
DoSetClientSize(int width,int height)300     virtual void DoSetClientSize(int width, int height)
301     {
302         wxWindow::DoSetClientSize(width, height);
303     }
304 
DoMoveWindow(int x,int y,int width,int height)305     virtual void DoMoveWindow(int x, int y, int width, int height)
306     {
307         wxWindow::DoMoveWindow(x, y, width, height);
308     }
309 
310     // no size hints
DoSetSizeHints(int WXUNUSED (minW),int WXUNUSED (minH),int WXUNUSED (maxW),int WXUNUSED (maxH),int WXUNUSED (incW),int WXUNUSED (incH))311     virtual void DoSetSizeHints(int WXUNUSED(minW), int WXUNUSED(minH),
312                                 int WXUNUSED(maxW), int WXUNUSED(maxH),
313                                 int WXUNUSED(incW), int WXUNUSED(incH)) { }
314 
315     wxString m_title;
316 };
317 
318 // ----------------------------------------------------------------------------
319 // wxMDIClientWindowBase: child of parent frame, parent of children frames
320 // ----------------------------------------------------------------------------
321 
322 class WXDLLIMPEXP_CORE wxMDIClientWindowBase : public wxWindow
323 {
324 public:
325     /*
326         The derived class must provide the default ctor only (CreateClient()
327         will be called later).
328     */
329 
330     // Can be overridden in the derived classes but the base class version must
331     // be usually called first to really create the client window.
332     virtual bool CreateClient(wxMDIParentFrame *parent,
333                               long style = wxVSCROLL | wxHSCROLL) = 0;
334 };
335 
336 // ----------------------------------------------------------------------------
337 // Include the port-specific implementation of the base classes defined above
338 // ----------------------------------------------------------------------------
339 
340 // wxUSE_GENERIC_MDI_AS_NATIVE may be predefined to force the generic MDI
341 // implementation use even on the platforms which usually don't use it
342 //
343 // notice that generic MDI can still be used without this, but you would need
344 // to explicitly use wxGenericMDIXXX classes in your code (and currently also
345 // add src/generic/mdig.cpp to your build as it's not compiled in if generic
346 // MDI is not used by default -- but this may change later...)
347 #ifndef wxUSE_GENERIC_MDI_AS_NATIVE
348     // wxUniv always uses the generic MDI implementation and so do the ports
349     // without native version (although wxCocoa seems to have one -- but it's
350     // probably not functional?)
351     #if defined(__WXCOCOA__) || \
352         defined(__WXMOTIF__) || \
353         defined(__WXPM__) || \
354         defined(__WXUNIVERSAL__)
355         #define wxUSE_GENERIC_MDI_AS_NATIVE   1
356     #else
357         #define wxUSE_GENERIC_MDI_AS_NATIVE   0
358     #endif
359 #endif // wxUSE_GENERIC_MDI_AS_NATIVE
360 
361 #if wxUSE_GENERIC_MDI_AS_NATIVE
362     #include "wx/generic/mdig.h"
363 #elif defined(__WXMSW__)
364     #include "wx/msw/mdi.h"
365 #elif defined(__WXGTK20__)
366     #include "wx/gtk/mdi.h"
367 #elif defined(__WXGTK__)
368     #include "wx/gtk1/mdi.h"
369 #elif defined(__WXMAC__)
370     #include "wx/osx/mdi.h"
371 #elif defined(__WXCOCOA__)
372     #include "wx/cocoa/mdi.h"
373 #endif
374 
OnCreateClient()375 inline wxMDIClientWindow *wxMDIParentFrameBase::OnCreateClient()
376 {
377     return new wxMDIClientWindow;
378 }
379 
TryBefore(wxEvent & event)380 inline bool wxMDIParentFrameBase::TryBefore(wxEvent& event)
381 {
382     // Menu (and toolbar) events should be sent to the active child frame
383     // first, if any.
384     if ( event.GetEventType() == wxEVT_MENU ||
385             event.GetEventType() == wxEVT_UPDATE_UI )
386     {
387         wxMDIChildFrame * const child = GetActiveChild();
388         if ( child )
389         {
390             // However avoid sending the event back to the child if it's
391             // currently being propagated to us from it.
392             wxWindow* const
393                 from = static_cast<wxWindow*>(event.GetPropagatedFrom());
394             if ( !from || !from->IsDescendant(child) )
395             {
396                 if ( child->ProcessWindowEventLocally(event) )
397                     return true;
398             }
399         }
400     }
401 
402     return wxFrame::TryBefore(event);
403 }
404 
405 #endif // wxUSE_MDI
406 
407 #endif // _WX_MDI_H_BASE_
408