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