include <wx/...> => include "wx/..."
[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 *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 BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
104 END_EVENT_TABLE()
105
106 wxMDIParentFrame::wxMDIParentFrame()
107 {
108 m_justInserted = FALSE;
109 m_clientWindow = (wxMDIClientWindow *) NULL;
110 }
111
112 wxMDIParentFrame::wxMDIParentFrame( wxWindow *parent,
113 wxWindowID id, const wxString& title,
114 const wxPoint& pos, const wxSize& size,
115 long style, const wxString& name )
116 {
117 m_justInserted = FALSE;
118 m_clientWindow = (wxMDIClientWindow *) NULL;
119 Create( parent, id, title, pos, size, style, name );
120 }
121
122 wxMDIParentFrame::~wxMDIParentFrame()
123 {
124 }
125
126 bool wxMDIParentFrame::Create( wxWindow *parent,
127 wxWindowID id, const wxString& title,
128 const wxPoint& pos, const wxSize& size,
129 long style, const wxString& name )
130 {
131 wxFrame::Create( parent, id, title, pos, size, style, name );
132
133 OnCreateClient();
134
135 return TRUE;
136 }
137
138 void wxMDIParentFrame::GtkOnSize( int x, int y, int width, int height )
139 {
140 wxFrame::GtkOnSize( x, y, width, height );
141
142 wxMDIChildFrame *child_frame = GetActiveChild();
143 if (!child_frame) return;
144
145 wxMenuBar *menu_bar = child_frame->m_menuBar;
146 if (!menu_bar) return;
147 if (!menu_bar->m_widget) return;
148
149 menu_bar->m_x = 0;
150 menu_bar->m_y = 0;
151 menu_bar->m_width = m_width;
152 menu_bar->m_height = wxMENU_HEIGHT;
153 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
154 menu_bar->m_widget,
155 0, 0, m_width, wxMENU_HEIGHT );
156 }
157
158 void wxMDIParentFrame::OnInternalIdle()
159 {
160 /* if a an MDI child window has just been inserted
161 it has to be brought to the top in idle time. we
162 simply set the last notebook page active as new
163 pages can only be appended at the end */
164
165 if (m_justInserted)
166 {
167 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
168 gtk_notebook_set_page( notebook, g_list_length( notebook->children ) - 1 );
169
170 m_justInserted = FALSE;
171 return;
172 }
173
174 wxFrame::OnInternalIdle();
175
176 wxMDIChildFrame *active_child_frame = GetActiveChild();
177 bool visible_child_menu = FALSE;
178
179 wxNode *node = m_clientWindow->GetChildren().First();
180 while (node)
181 {
182 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
183 wxMenuBar *menu_bar = child_frame->m_menuBar;
184 if (child_frame->m_menuBar)
185 {
186 if (child_frame == active_child_frame)
187 {
188 if (menu_bar->Show(TRUE))
189 {
190 menu_bar->m_width = m_width;
191 menu_bar->m_height = wxMENU_HEIGHT;
192 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
193 menu_bar->m_widget,
194 0, 0, m_width, wxMENU_HEIGHT );
195 menu_bar->SetInvokingWindow( child_frame );
196 }
197 visible_child_menu = TRUE;
198 }
199 else
200 {
201 if (menu_bar->Show(FALSE))
202 {
203 menu_bar->UnsetInvokingWindow( child_frame );
204 }
205 }
206 }
207 node = node->Next();
208 }
209
210 /* show/hide parent menu bar as required */
211 if ((m_frameMenuBar) &&
212 (m_frameMenuBar->IsShown() == visible_child_menu))
213 {
214 if (visible_child_menu)
215 {
216 m_frameMenuBar->Show( FALSE );
217 m_frameMenuBar->UnsetInvokingWindow( this );
218 }
219 else
220 {
221 m_frameMenuBar->Show( TRUE );
222 m_frameMenuBar->SetInvokingWindow( this );
223
224 m_frameMenuBar->m_width = m_width;
225 m_frameMenuBar->m_height = wxMENU_HEIGHT;
226 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
227 m_frameMenuBar->m_widget,
228 0, 0, m_width, wxMENU_HEIGHT );
229 }
230 }
231 }
232
233 void wxMDIParentFrame::GetClientSize(int *width, int *height ) const
234 {
235 wxFrame::GetClientSize( width, height );
236 }
237
238 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
239 {
240 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
241
242 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
243 if (!notebook) return (wxMDIChildFrame*) NULL;
244
245 #if (GTK_MINOR_VERSION > 0)
246 gint i = gtk_notebook_get_current_page( notebook );
247 #else
248 gint i = gtk_notebook_current_page( notebook );
249 #endif
250 if (i < 0) return (wxMDIChildFrame*) NULL;
251
252 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
253 if (!page) return (wxMDIChildFrame*) NULL;
254
255 wxNode *node = m_clientWindow->GetChildren().First();
256 while (node)
257 {
258 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
259 if (child_frame->m_page == page)
260 return child_frame;
261 node = node->Next();
262 }
263
264 return (wxMDIChildFrame*) NULL;
265 }
266
267 wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
268 {
269 return m_clientWindow;
270 }
271
272 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
273 {
274 m_clientWindow = new wxMDIClientWindow( this );
275 return m_clientWindow;
276 }
277
278 void wxMDIParentFrame::ActivateNext()
279 {
280 if (m_clientWindow)
281 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
282 }
283
284 void wxMDIParentFrame::ActivatePrevious()
285 {
286 if (m_clientWindow)
287 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
288 }
289
290 void wxMDIParentFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
291 {
292 }
293
294 void wxMDIParentFrame::OnSysColourChanged( wxSysColourChangedEvent& WXUNUSED(event) )
295 {
296 }
297
298 //-----------------------------------------------------------------------------
299 // wxMDIChildFrame
300 //-----------------------------------------------------------------------------
301
302 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
303
304 BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
305 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
306 END_EVENT_TABLE()
307
308 wxMDIChildFrame::wxMDIChildFrame()
309 {
310 m_menuBar = (wxMenuBar *) NULL;
311 m_page = (GtkNotebookPage *) NULL;
312 }
313
314 wxMDIChildFrame::wxMDIChildFrame( 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_menuBar = (wxMenuBar *) NULL;
320 m_page = (GtkNotebookPage *) NULL;
321 Create( parent, id, title, wxDefaultPosition, size, style, name );
322 }
323
324 wxMDIChildFrame::~wxMDIChildFrame()
325 {
326 if (m_menuBar)
327 delete m_menuBar;
328 }
329
330 bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
331 wxWindowID id, const wxString& title,
332 const wxPoint& WXUNUSED(pos), const wxSize& size,
333 long style, const wxString& name )
334 {
335 m_title = title;
336
337 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
338 }
339
340 void wxMDIChildFrame::GetClientSize( int *width, int *height ) const
341 {
342 wxWindow::GetClientSize( width, height );
343 }
344
345 void wxMDIChildFrame::AddChild( wxWindowBase *child )
346 {
347 wxWindow::AddChild(child);
348 }
349
350 void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
351 {
352 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
353
354 m_menuBar = menu_bar;
355
356 if (m_menuBar)
357 {
358 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
359
360 m_menuBar->SetParent( mdi_frame );
361
362 /* insert the invisible menu bar into the _parent_ mdi frame */
363 gtk_pizza_put( GTK_PIZZA(mdi_frame->m_mainWidget),
364 m_menuBar->m_widget,
365 0, 0, mdi_frame->m_width, wxMENU_HEIGHT );
366 }
367 }
368
369 wxMenuBar *wxMDIChildFrame::GetMenuBar() const
370 {
371 return m_menuBar;
372 }
373
374 void wxMDIChildFrame::Activate()
375 {
376 #if (GTK_MINOR_VERSION > 0)
377 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
378 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
379 gint pageno = gtk_notebook_page_num( notebook, m_page->child );
380 gtk_notebook_set_page( notebook, pageno );
381 #else
382 // the only way I can see to do this under gtk+ 1.0.X would
383 // be to keep track of page numbers, start at first and
384 // do "next" enough times to get to this page number - messy
385 // - J. Russell Smyth
386 #endif
387 }
388
389 void wxMDIChildFrame::OnActivate( wxActivateEvent &WXUNUSED(event) )
390 {
391 }
392
393 //-----------------------------------------------------------------------------
394 // "size_allocate"
395 //-----------------------------------------------------------------------------
396
397 static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
398 {
399 if (g_isIdle) wxapp_install_idle_handler();
400
401 if ((win->m_x == alloc->x) &&
402 (win->m_y == alloc->y) &&
403 (win->m_width == alloc->width) &&
404 (win->m_height == alloc->height) &&
405 (win->m_sizeSet))
406 {
407 return;
408 }
409
410 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
411 }
412
413 //-----------------------------------------------------------------------------
414 // InsertChild callback for wxMDIClientWindow
415 //-----------------------------------------------------------------------------
416
417 static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
418 {
419 wxString s = child->m_title;
420 if (s.IsNull()) s = _("MDI child");
421
422 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
423 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
424
425 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
426 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
427
428 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
429
430 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
431
432 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
433
434 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
435 parent_frame->m_justInserted = TRUE;
436 }
437
438 //-----------------------------------------------------------------------------
439 // wxMDIClientWindow
440 //-----------------------------------------------------------------------------
441
442 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
443
444 wxMDIClientWindow::wxMDIClientWindow()
445 {
446 }
447
448 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
449 {
450 CreateClient( parent, style );
451 }
452
453 wxMDIClientWindow::~wxMDIClientWindow()
454 {
455 }
456
457 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
458 {
459 m_needParent = TRUE;
460
461 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
462
463 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
464 !CreateBase( parent, -1, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
465 {
466 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
467 return FALSE;
468 }
469
470 m_widget = gtk_notebook_new();
471
472 gtk_signal_connect( GTK_OBJECT(m_widget), "switch_page",
473 GTK_SIGNAL_FUNC(gtk_mdi_page_change_callback), (gpointer)parent );
474
475 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
476
477 m_parent->DoAddChild( this );
478
479 PostCreation();
480
481 Show( TRUE );
482
483 return TRUE;
484 }
485
486 #endif