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