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