Rewrote MDI system
[wxWidgets.git] / src / gtk1 / mdi.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: mdi.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation "mdi.h"
12 #endif
13
14 #include "wx/mdi.h"
15 #include "wx/dialog.h"
16 #include "wx/menu.h"
17 #include <wx/intl.h>
18
19 #include "glib.h"
20 #include "gdk/gdk.h"
21 #include "gtk/gtk.h"
22 #include "wx/gtk/win_gtk.h"
23
24 //-----------------------------------------------------------------------------
25 // constants
26 //-----------------------------------------------------------------------------
27
28 const int wxMENU_HEIGHT = 27;
29
30 //-----------------------------------------------------------------------------
31 // globals
32 //-----------------------------------------------------------------------------
33
34 extern wxList wxPendingDelete;
35
36 //-----------------------------------------------------------------------------
37 // wxMDIParentFrame
38 //-----------------------------------------------------------------------------
39
40 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
41
42 BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
43 END_EVENT_TABLE()
44
45 wxMDIParentFrame::wxMDIParentFrame()
46 {
47 m_justInserted = FALSE;
48 m_clientWindow = (wxMDIClientWindow *) NULL;
49 }
50
51 wxMDIParentFrame::wxMDIParentFrame( wxWindow *parent,
52 wxWindowID id, const wxString& title,
53 const wxPoint& pos, const wxSize& size,
54 long style, const wxString& name )
55 {
56 m_justInserted = FALSE;
57 m_clientWindow = (wxMDIClientWindow *) NULL;
58 Create( parent, id, title, pos, size, style, name );
59 }
60
61 wxMDIParentFrame::~wxMDIParentFrame()
62 {
63 }
64
65 bool wxMDIParentFrame::Create( wxWindow *parent,
66 wxWindowID id, const wxString& title,
67 const wxPoint& pos, const wxSize& size,
68 long style, const wxString& name )
69 {
70 wxFrame::Create( parent, id, title, pos, size, style, name );
71
72 OnCreateClient();
73
74 return TRUE;
75 }
76
77 void wxMDIParentFrame::GtkOnSize( int x, int y, int width, int height )
78 {
79 wxFrame::GtkOnSize( x, y, width, height );
80
81 wxMDIChildFrame *child_frame = GetActiveChild();
82 if (!child_frame) return;
83
84 wxMenuBar *menu_bar = child_frame->m_menuBar;
85 if (!menu_bar) return;
86 if (!menu_bar->m_widget) return;
87
88 menu_bar->m_x = 0;
89 menu_bar->m_y = 0;
90 menu_bar->m_width = m_width;
91 menu_bar->m_height = wxMENU_HEIGHT;
92 gtk_myfixed_move( GTK_MYFIXED(m_mainWidget), menu_bar->m_widget, 0, 0 );
93 gtk_widget_set_usize( menu_bar->m_widget, m_width, wxMENU_HEIGHT );
94 }
95
96 void wxMDIParentFrame::OnInternalIdle()
97 {
98 /* if a an MDI child window has just been inserted
99 it has to be brought to the top in idle time. we
100 simply set the last notebook page active as new
101 pages can only be appended at the end */
102
103 if (m_justInserted)
104 {
105 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
106 gtk_notebook_set_page( notebook, g_list_length( notebook->children ) - 1 );
107
108 m_justInserted = FALSE;
109 return;
110 }
111
112 wxFrame::OnInternalIdle();
113
114 wxMDIChildFrame *active_child_frame = GetActiveChild();
115
116 wxNode *node = m_clientWindow->m_children.First();
117 while (node)
118 {
119 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
120 if (child_frame->m_menuBar)
121 {
122 if (child_frame == active_child_frame)
123 gtk_widget_show( child_frame->m_menuBar->m_widget );
124 else
125 gtk_widget_hide( child_frame->m_menuBar->m_widget );
126 }
127 node = node->Next();
128 }
129
130 /* show/hide parent menu bar as required */
131 if (m_frameMenuBar) m_frameMenuBar->Show( (active_child_frame == NULL) );
132 }
133
134 void wxMDIParentFrame::GetClientSize(int *width, int *height ) const
135 {
136 wxFrame::GetClientSize( width, height );
137 }
138
139 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
140 {
141 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
142
143 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
144 if (!notebook) return (wxMDIChildFrame*) NULL;
145
146 gint i = gtk_notebook_get_current_page( notebook );
147 if (i < 0) return (wxMDIChildFrame*) NULL;
148
149 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
150 if (!page) return (wxMDIChildFrame*) NULL;
151
152 wxNode *node = m_clientWindow->m_children.First();
153 while (node)
154 {
155 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
156 if (child_frame->m_page == page)
157 return child_frame;
158 node = node->Next();
159 }
160
161 return (wxMDIChildFrame*) NULL;
162 }
163
164 wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
165 {
166 return m_clientWindow;
167 }
168
169 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
170 {
171 m_clientWindow = new wxMDIClientWindow( this );
172 return m_clientWindow;
173 }
174
175 void wxMDIParentFrame::ActivateNext()
176 {
177 if (m_clientWindow)
178 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
179 }
180
181 void wxMDIParentFrame::ActivatePrevious()
182 {
183 if (m_clientWindow)
184 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
185 }
186
187 void wxMDIParentFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
188 {
189 }
190
191 void wxMDIParentFrame::OnSysColourChanged( wxSysColourChangedEvent& WXUNUSED(event) )
192 {
193 }
194
195 //-----------------------------------------------------------------------------
196 // wxMDIChildFrame
197 //-----------------------------------------------------------------------------
198
199 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
200
201 BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
202 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
203 END_EVENT_TABLE()
204
205 wxMDIChildFrame::wxMDIChildFrame()
206 {
207 m_menuBar = (wxMenuBar *) NULL;
208 m_page = (GtkNotebookPage *) NULL;
209 }
210
211 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
212 wxWindowID id, const wxString& title,
213 const wxPoint& WXUNUSED(pos), const wxSize& size,
214 long style, const wxString& name )
215 {
216 m_menuBar = (wxMenuBar *) NULL;
217 m_page = (GtkNotebookPage *) NULL;
218 Create( parent, id, title, wxDefaultPosition, size, style, name );
219 }
220
221 wxMDIChildFrame::~wxMDIChildFrame()
222 {
223 if (m_menuBar)
224 delete m_menuBar;
225 }
226
227 bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
228 wxWindowID id, const wxString& title,
229 const wxPoint& WXUNUSED(pos), const wxSize& size,
230 long style, const wxString& name )
231 {
232 m_title = title;
233
234 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
235 }
236
237 void wxMDIChildFrame::GetClientSize( int *width, int *height ) const
238 {
239 wxWindow::GetClientSize( width, height );
240 }
241
242 void wxMDIChildFrame::AddChild( wxWindow *child )
243 {
244 wxWindow::AddChild( child );
245 }
246
247 static void SetInvokingWindow( wxMenu *menu, wxWindow *win )
248 {
249 menu->SetInvokingWindow( win );
250 wxNode *node = menu->GetItems().First();
251 while (node)
252 {
253 wxMenuItem *menuitem = (wxMenuItem*)node->Data();
254 if (menuitem->IsSubMenu())
255 SetInvokingWindow( menuitem->GetSubMenu(), win );
256 node = node->Next();
257 }
258 }
259
260 void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
261 {
262 m_menuBar = menu_bar;
263
264 if (m_menuBar)
265 {
266 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->m_parent;
267
268 if (m_menuBar->m_parent != this)
269 {
270 wxNode *node = m_menuBar->GetMenus().First();
271 while (node)
272 {
273 wxMenu *menu = (wxMenu*)node->Data();
274 SetInvokingWindow( menu, this );
275 node = node->Next();
276 }
277
278 m_menuBar->m_parent = mdi_frame;
279 }
280
281 /* the menu bar of the child window is shown in idle time as needed */
282 gtk_widget_hide( m_menuBar->m_widget );
283
284 /* insert the invisible menu bar into the _parent_ mdi frame */
285 gtk_myfixed_put( GTK_MYFIXED(mdi_frame->m_mainWidget), m_menuBar->m_widget, 0, 0 );
286 gtk_widget_set_usize( menu_bar->m_widget, mdi_frame->m_width, wxMENU_HEIGHT );
287 }
288 }
289
290 wxMenuBar *wxMDIChildFrame::GetMenuBar() const
291 {
292 return m_menuBar;
293 }
294
295 void wxMDIChildFrame::Activate()
296 {
297 }
298
299 void wxMDIChildFrame::OnActivate( wxActivateEvent &WXUNUSED(event) )
300 {
301 }
302
303 //-----------------------------------------------------------------------------
304 // "size_allocate"
305 //-----------------------------------------------------------------------------
306
307 static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
308 {
309 if ((win->m_x == alloc->x) &&
310 (win->m_y == alloc->y) &&
311 (win->m_width == alloc->width) &&
312 (win->m_height == alloc->height) &&
313 (win->m_sizeSet))
314 {
315 return;
316 }
317
318 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
319 }
320
321 //-----------------------------------------------------------------------------
322 // InsertChild callback for wxMDIClientWindow
323 //-----------------------------------------------------------------------------
324
325 static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
326 {
327 wxString s = child->m_title;
328 if (s.IsNull()) s = _("MDI child");
329
330 GtkWidget *label_widget = gtk_label_new( s );
331 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
332
333 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
334 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
335
336 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
337
338 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
339
340 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
341
342 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->m_parent;
343 parent_frame->m_justInserted = TRUE;
344 }
345
346 //-----------------------------------------------------------------------------
347 // wxMDIClientWindow
348 //-----------------------------------------------------------------------------
349
350 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
351
352 wxMDIClientWindow::wxMDIClientWindow()
353 {
354 }
355
356 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
357 {
358 CreateClient( parent, style );
359 }
360
361 wxMDIClientWindow::~wxMDIClientWindow()
362 {
363 }
364
365 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
366 {
367 m_needParent = TRUE;
368
369 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
370
371 PreCreation( parent, -1, wxPoint(10,10), wxSize(100,100), style, "wxMDIClientWindow" );
372
373 m_widget = gtk_notebook_new();
374
375 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
376
377 m_parent->AddChild( this );
378
379 (m_parent->m_insertCallback)( m_parent, this );
380
381 PostCreation();
382
383 Show( TRUE );
384
385 return TRUE;
386 }
387
388
389