removed unused wxWindowGTK::m_isFrame
[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 #if (GTK_MINOR_VERSION > 0)
241 gint i = gtk_notebook_get_current_page( notebook );
242 #else
243 gint i = gtk_notebook_current_page( notebook );
244 #endif
245 if (i < 0) return (wxMDIChildFrame*) NULL;
246
247 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
248 if (!page) return (wxMDIChildFrame*) NULL;
249
250 wxNode *node = m_clientWindow->GetChildren().First();
251 while (node)
252 {
253 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
254 if (child_frame->m_page == page)
255 return child_frame;
256 node = node->Next();
257 }
258
259 return (wxMDIChildFrame*) NULL;
260 }
261
262 wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
263 {
264 return m_clientWindow;
265 }
266
267 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
268 {
269 m_clientWindow = new wxMDIClientWindow( this );
270 return m_clientWindow;
271 }
272
273 void wxMDIParentFrame::ActivateNext()
274 {
275 if (m_clientWindow)
276 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
277 }
278
279 void wxMDIParentFrame::ActivatePrevious()
280 {
281 if (m_clientWindow)
282 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
283 }
284
285 //-----------------------------------------------------------------------------
286 // wxMDIChildFrame
287 //-----------------------------------------------------------------------------
288
289 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
290
291 BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
292 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
293 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
294 END_EVENT_TABLE()
295
296 wxMDIChildFrame::wxMDIChildFrame()
297 {
298 m_menuBar = (wxMenuBar *) NULL;
299 m_page = (GtkNotebookPage *) NULL;
300 }
301
302 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
303 wxWindowID id, const wxString& title,
304 const wxPoint& WXUNUSED(pos), const wxSize& size,
305 long style, const wxString& name )
306 {
307 m_menuBar = (wxMenuBar *) NULL;
308 m_page = (GtkNotebookPage *) NULL;
309 Create( parent, id, title, wxDefaultPosition, size, style, name );
310 }
311
312 wxMDIChildFrame::~wxMDIChildFrame()
313 {
314 if (m_menuBar)
315 delete m_menuBar;
316 }
317
318 bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
319 wxWindowID id, const wxString& title,
320 const wxPoint& WXUNUSED(pos), const wxSize& size,
321 long style, const wxString& name )
322 {
323 m_title = title;
324
325 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
326 }
327
328 void wxMDIChildFrame::DoGetClientSize( int *width, int *height ) const
329 {
330 wxWindow::DoGetClientSize( width, height );
331 }
332
333 void wxMDIChildFrame::AddChild( wxWindowBase *child )
334 {
335 wxWindow::AddChild(child);
336 }
337
338 void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
339 {
340 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
341
342 m_menuBar = menu_bar;
343
344 if (m_menuBar)
345 {
346 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
347
348 m_menuBar->SetParent( mdi_frame );
349
350 /* insert the invisible menu bar into the _parent_ mdi frame */
351 gtk_pizza_put( GTK_PIZZA(mdi_frame->m_mainWidget),
352 m_menuBar->m_widget,
353 0, 0, mdi_frame->m_width, wxMENU_HEIGHT );
354 }
355 }
356
357 wxMenuBar *wxMDIChildFrame::GetMenuBar() const
358 {
359 return m_menuBar;
360 }
361
362 void wxMDIChildFrame::Activate()
363 {
364 #if defined(__WXGTK20__) || (GTK_MINOR_VERSION > 0)
365 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
366 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
367 gint pageno = gtk_notebook_page_num( notebook, m_widget );
368 gtk_notebook_set_page( notebook, pageno );
369 #else // GTK+ 1.0
370 // the only way I can see to do this under gtk+ 1.0.X would
371 // be to keep track of page numbers, start at first and
372 // do "next" enough times to get to this page number - messy
373 // - J. Russell Smyth
374 #endif
375 }
376
377 void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
378 {
379 }
380
381 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
382 {
383 #if wxUSE_STATUSBAR
384 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
385 if ( !ShowMenuHelp(mdi_frame->GetStatusBar(), event.GetMenuId()) )
386 {
387 // we don't have any help text for this item, but may be the MDI frame
388 // does?
389 mdi_frame->OnMenuHighlight(event);
390 }
391 #endif // wxUSE_STATUSBAR
392 }
393
394 void wxMDIChildFrame::SetTitle( const wxString &title )
395 {
396 if ( title == m_title )
397 return;
398
399 m_title = title;
400
401 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
402 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
403 gtk_notebook_set_tab_label_text(notebook, m_widget, title.mbc_str());
404 }
405
406 //-----------------------------------------------------------------------------
407 // "size_allocate"
408 //-----------------------------------------------------------------------------
409
410 static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
411 {
412 if (g_isIdle) wxapp_install_idle_handler();
413
414 if ((win->m_x == alloc->x) &&
415 (win->m_y == alloc->y) &&
416 (win->m_width == alloc->width) &&
417 (win->m_height == alloc->height) &&
418 (win->m_sizeSet))
419 {
420 return;
421 }
422
423 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
424 }
425
426 //-----------------------------------------------------------------------------
427 // InsertChild callback for wxMDIClientWindow
428 //-----------------------------------------------------------------------------
429
430 static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
431 {
432 wxString s = child->m_title;
433 if (s.IsNull()) s = _("MDI child");
434
435 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
436 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
437
438 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
439 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
440
441 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
442
443 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
444
445 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
446
447 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
448 parent_frame->m_justInserted = TRUE;
449 }
450
451 //-----------------------------------------------------------------------------
452 // wxMDIClientWindow
453 //-----------------------------------------------------------------------------
454
455 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
456
457 wxMDIClientWindow::wxMDIClientWindow()
458 {
459 }
460
461 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
462 {
463 CreateClient( parent, style );
464 }
465
466 wxMDIClientWindow::~wxMDIClientWindow()
467 {
468 }
469
470 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
471 {
472 m_needParent = TRUE;
473
474 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
475
476 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
477 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
478 {
479 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
480 return FALSE;
481 }
482
483 m_widget = gtk_notebook_new();
484
485 gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page",
486 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback), (gpointer)parent );
487
488 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
489
490 m_parent->DoAddChild( this );
491
492 PostCreation();
493
494 Show( TRUE );
495
496 return TRUE;
497 }
498
499 #endif