Overrode wxMDIChildFrame's DoSetSize to not misplace
[wxWidgets.git] / src / gtk / 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
16 #if wxUSE_MDI_ARCHITECTURE
17
18 #include "wx/dialog.h"
19 #include "wx/menu.h"
20 #include "wx/intl.h"
21
22 #include <glib.h>
23 #include <gdk/gdk.h>
24 #include <gtk/gtk.h>
25 #include "wx/gtk/win_gtk.h"
26
27 //-----------------------------------------------------------------------------
28 // constants
29 //-----------------------------------------------------------------------------
30
31 const int wxMENU_HEIGHT = 27;
32
33 //-----------------------------------------------------------------------------
34 // idle system
35 //-----------------------------------------------------------------------------
36
37 extern void wxapp_install_idle_handler();
38 extern bool g_isIdle;
39
40 //-----------------------------------------------------------------------------
41 // globals
42 //-----------------------------------------------------------------------------
43
44 extern wxList wxPendingDelete;
45
46 //-----------------------------------------------------------------------------
47 // "switch_page"
48 //-----------------------------------------------------------------------------
49
50 static void
51 gtk_mdi_page_change_callback( GtkNotebook *WXUNUSED(widget),
52 GtkNotebookPage *page,
53 gint WXUNUSED(page_num),
54 wxMDIParentFrame *parent )
55 {
56 if (g_isIdle)
57 wxapp_install_idle_handler();
58
59 // send deactivate event to old child
60
61 wxMDIChildFrame *child = parent->GetActiveChild();
62 if (child)
63 {
64 wxActivateEvent event1( wxEVT_ACTIVATE, FALSE, child->GetId() );
65 event1.SetEventObject( child);
66 child->GetEventHandler()->ProcessEvent( event1 );
67 }
68
69 // send activate event to new child
70
71 wxMDIClientWindow *client_window = parent->GetClientWindow();
72 if (!client_window)
73 return;
74
75 child = (wxMDIChildFrame*) NULL;
76
77 wxNode *node = client_window->GetChildren().First();
78 while (node)
79 {
80 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
81 if (child_frame->m_page == page)
82 {
83 child = child_frame;
84 break;
85 }
86 node = node->Next();
87 }
88
89 if (!child)
90 return;
91
92 wxActivateEvent event2( wxEVT_ACTIVATE, TRUE, child->GetId() );
93 event2.SetEventObject( child);
94 child->GetEventHandler()->ProcessEvent( event2 );
95 }
96
97 //-----------------------------------------------------------------------------
98 // wxMDIParentFrame
99 //-----------------------------------------------------------------------------
100
101 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
102
103 void wxMDIParentFrame::Init()
104 {
105 m_justInserted = FALSE;
106 m_clientWindow = (wxMDIClientWindow *) NULL;
107 }
108
109 wxMDIParentFrame::~wxMDIParentFrame()
110 {
111 }
112
113 bool wxMDIParentFrame::Create(wxWindow *parent,
114 wxWindowID id,
115 const wxString& title,
116 const wxPoint& pos,
117 const wxSize& size,
118 long style,
119 const wxString& name )
120 {
121 wxFrame::Create( parent, id, title, pos, size, style, name );
122
123 OnCreateClient();
124
125 return TRUE;
126 }
127
128 void wxMDIParentFrame::GtkOnSize( int x, int y, int width, int height )
129 {
130 wxFrame::GtkOnSize( x, y, width, height );
131
132 wxMDIChildFrame *child_frame = GetActiveChild();
133 if (!child_frame) return;
134
135 wxMenuBar *menu_bar = child_frame->m_menuBar;
136 if (!menu_bar) return;
137 if (!menu_bar->m_widget) return;
138
139 menu_bar->m_x = 0;
140 menu_bar->m_y = 0;
141 menu_bar->m_width = m_width;
142 menu_bar->m_height = wxMENU_HEIGHT;
143 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
144 menu_bar->m_widget,
145 0, 0, m_width, wxMENU_HEIGHT );
146 }
147
148 void wxMDIParentFrame::OnInternalIdle()
149 {
150 /* if a an MDI child window has just been inserted
151 it has to be brought to the top in idle time. we
152 simply set the last notebook page active as new
153 pages can only be appended at the end */
154
155 if (m_justInserted)
156 {
157 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
158 gtk_notebook_set_page( notebook, g_list_length( notebook->children ) - 1 );
159
160 m_justInserted = FALSE;
161 return;
162 }
163
164 wxFrame::OnInternalIdle();
165
166 wxMDIChildFrame *active_child_frame = GetActiveChild();
167 bool visible_child_menu = FALSE;
168
169 wxNode *node = m_clientWindow->GetChildren().First();
170 while (node)
171 {
172 wxObject *child = node->Data();
173 wxMDIChildFrame *child_frame = wxDynamicCast(child, wxMDIChildFrame);
174 if ( child_frame )
175 {
176 wxMenuBar *menu_bar = child_frame->m_menuBar;
177 if ( menu_bar )
178 {
179 if (child_frame == active_child_frame)
180 {
181 if (menu_bar->Show(TRUE))
182 {
183 menu_bar->m_width = m_width;
184 menu_bar->m_height = wxMENU_HEIGHT;
185 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
186 menu_bar->m_widget,
187 0, 0, m_width, wxMENU_HEIGHT );
188 menu_bar->SetInvokingWindow( child_frame );
189 }
190 visible_child_menu = TRUE;
191 }
192 else
193 {
194 if (menu_bar->Show(FALSE))
195 {
196 menu_bar->UnsetInvokingWindow( child_frame );
197 }
198 }
199 }
200 }
201
202 node = node->Next();
203 }
204
205 /* show/hide parent menu bar as required */
206 if ((m_frameMenuBar) &&
207 (m_frameMenuBar->IsShown() == visible_child_menu))
208 {
209 if (visible_child_menu)
210 {
211 m_frameMenuBar->Show( FALSE );
212 m_frameMenuBar->UnsetInvokingWindow( this );
213 }
214 else
215 {
216 m_frameMenuBar->Show( TRUE );
217 m_frameMenuBar->SetInvokingWindow( this );
218
219 m_frameMenuBar->m_width = m_width;
220 m_frameMenuBar->m_height = wxMENU_HEIGHT;
221 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
222 m_frameMenuBar->m_widget,
223 0, 0, m_width, wxMENU_HEIGHT );
224 }
225 }
226 }
227
228 void wxMDIParentFrame::DoGetClientSize(int *width, int *height ) const
229 {
230 wxFrame::DoGetClientSize( width, height );
231 }
232
233 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
234 {
235 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
236
237 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
238 if (!notebook) return (wxMDIChildFrame*) NULL;
239
240 gint i = gtk_notebook_get_current_page( notebook );
241 if (i < 0) return (wxMDIChildFrame*) NULL;
242
243 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
244 if (!page) return (wxMDIChildFrame*) NULL;
245
246 wxNode *node = m_clientWindow->GetChildren().First();
247 while (node)
248 {
249 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
250 if (child_frame->m_page == page)
251 return child_frame;
252 node = node->Next();
253 }
254
255 return (wxMDIChildFrame*) NULL;
256 }
257
258 wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
259 {
260 return m_clientWindow;
261 }
262
263 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
264 {
265 m_clientWindow = new wxMDIClientWindow( this );
266 return m_clientWindow;
267 }
268
269 void wxMDIParentFrame::ActivateNext()
270 {
271 if (m_clientWindow)
272 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
273 }
274
275 void wxMDIParentFrame::ActivatePrevious()
276 {
277 if (m_clientWindow)
278 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
279 }
280
281 //-----------------------------------------------------------------------------
282 // wxMDIChildFrame
283 //-----------------------------------------------------------------------------
284
285 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
286
287 BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
288 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
289 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
290 END_EVENT_TABLE()
291
292 wxMDIChildFrame::wxMDIChildFrame()
293 {
294 m_menuBar = (wxMenuBar *) NULL;
295 m_page = (GtkNotebookPage *) NULL;
296 }
297
298 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
299 wxWindowID id, const wxString& title,
300 const wxPoint& WXUNUSED(pos), const wxSize& size,
301 long style, const wxString& name )
302 {
303 m_menuBar = (wxMenuBar *) NULL;
304 m_page = (GtkNotebookPage *) NULL;
305 Create( parent, id, title, wxDefaultPosition, size, style, name );
306 }
307
308 wxMDIChildFrame::~wxMDIChildFrame()
309 {
310 if (m_menuBar)
311 delete m_menuBar;
312 }
313
314 bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
315 wxWindowID id, const wxString& title,
316 const wxPoint& WXUNUSED(pos), const wxSize& size,
317 long style, const wxString& name )
318 {
319 m_title = title;
320
321 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
322 }
323
324 void wxMDIChildFrame::DoSetSize( int x, int y, int width, int height, int sizeFlags )
325 {
326 wxWindow::DoSetSize( x, y, width, height, sizeFlags );
327 }
328
329 void wxMDIChildFrame::DoSetClientSize(int width, int height)
330 {
331 wxWindow::DoSetClientSize( width, height );
332 }
333
334 void wxMDIChildFrame::DoGetClientSize( int *width, int *height ) const
335 {
336 wxWindow::DoGetClientSize( width, height );
337 }
338
339 void wxMDIChildFrame::AddChild( wxWindowBase *child )
340 {
341 wxWindow::AddChild(child);
342 }
343
344 void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
345 {
346 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
347
348 m_menuBar = menu_bar;
349
350 if (m_menuBar)
351 {
352 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
353
354 m_menuBar->SetParent( mdi_frame );
355
356 /* insert the invisible menu bar into the _parent_ mdi frame */
357 gtk_pizza_put( GTK_PIZZA(mdi_frame->m_mainWidget),
358 m_menuBar->m_widget,
359 0, 0, mdi_frame->m_width, wxMENU_HEIGHT );
360 }
361 }
362
363 wxMenuBar *wxMDIChildFrame::GetMenuBar() const
364 {
365 return m_menuBar;
366 }
367
368 void wxMDIChildFrame::Activate()
369 {
370 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
371 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
372 gint pageno = gtk_notebook_page_num( notebook, m_widget );
373 gtk_notebook_set_page( notebook, pageno );
374 }
375
376 void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
377 {
378 }
379
380 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
381 {
382 #if wxUSE_STATUSBAR
383 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
384 if ( !ShowMenuHelp(mdi_frame->GetStatusBar(), event.GetMenuId()) )
385 {
386 // we don't have any help text for this item, but may be the MDI frame
387 // does?
388 mdi_frame->OnMenuHighlight(event);
389 }
390 #endif // wxUSE_STATUSBAR
391 }
392
393 void wxMDIChildFrame::SetTitle( const wxString &title )
394 {
395 if ( title == m_title )
396 return;
397
398 m_title = title;
399
400 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
401 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
402 gtk_notebook_set_tab_label_text(notebook, m_widget, title.mbc_str());
403 }
404
405 //-----------------------------------------------------------------------------
406 // "size_allocate"
407 //-----------------------------------------------------------------------------
408
409 static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
410 {
411 if (g_isIdle) wxapp_install_idle_handler();
412
413 if ((win->m_x == alloc->x) &&
414 (win->m_y == alloc->y) &&
415 (win->m_width == alloc->width) &&
416 (win->m_height == alloc->height) &&
417 (win->m_sizeSet))
418 {
419 return;
420 }
421
422 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
423 }
424
425 //-----------------------------------------------------------------------------
426 // InsertChild callback for wxMDIClientWindow
427 //-----------------------------------------------------------------------------
428
429 static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
430 {
431 wxString s = child->m_title;
432 if (s.IsNull()) s = _("MDI child");
433
434 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
435 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
436
437 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
438 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
439
440 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
441
442 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
443
444 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
445
446 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
447 parent_frame->m_justInserted = TRUE;
448 }
449
450 //-----------------------------------------------------------------------------
451 // wxMDIClientWindow
452 //-----------------------------------------------------------------------------
453
454 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
455
456 wxMDIClientWindow::wxMDIClientWindow()
457 {
458 }
459
460 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
461 {
462 CreateClient( parent, style );
463 }
464
465 wxMDIClientWindow::~wxMDIClientWindow()
466 {
467 }
468
469 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
470 {
471 m_needParent = TRUE;
472
473 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
474
475 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
476 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
477 {
478 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
479 return FALSE;
480 }
481
482 m_widget = gtk_notebook_new();
483
484 gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page",
485 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback), (gpointer)parent );
486
487 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
488
489 m_parent->DoAddChild( this );
490
491 PostCreation();
492
493 Show( TRUE );
494
495 return TRUE;
496 }
497
498 #endif