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