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