]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/mdi.cpp
misc fixes for wxDirDialog; new wxDD_CHANGE_DIR flag (patch 1478051)
[wxWidgets.git] / src / gtk / mdi.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/mdi.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #if wxUSE_MDI
14
15 #include "wx/mdi.h"
16
17 #ifndef WX_PRECOMP
18 #include "wx/intl.h"
19 #endif
20
21 #include "wx/notebook.h"
22 #include "wx/dialog.h"
23 #include "wx/menu.h"
24 #include "wx/gtk/private.h"
25
26 #include <glib.h>
27 #include <gdk/gdk.h>
28 #include <gtk/gtk.h>
29 #include "wx/gtk/win_gtk.h"
30
31 //-----------------------------------------------------------------------------
32 // constants
33 //-----------------------------------------------------------------------------
34
35 const int wxMENU_HEIGHT = 27;
36
37 //-----------------------------------------------------------------------------
38 // globals
39 //-----------------------------------------------------------------------------
40
41 extern wxList wxPendingDelete;
42
43 //-----------------------------------------------------------------------------
44 // "switch_page"
45 //-----------------------------------------------------------------------------
46
47 extern "C" {
48 static void
49 gtk_mdi_page_change_callback( GtkNotebook *WXUNUSED(widget),
50 GtkNotebookPage *page,
51 gint WXUNUSED(page_num),
52 wxMDIParentFrame *parent )
53 {
54 if (g_isIdle)
55 wxapp_install_idle_handler();
56
57 // send deactivate event to old child
58
59 wxMDIChildFrame *child = parent->GetActiveChild();
60 if (child)
61 {
62 wxActivateEvent event1( wxEVT_ACTIVATE, false, child->GetId() );
63 event1.SetEventObject( child);
64 child->GetEventHandler()->ProcessEvent( event1 );
65 }
66
67 // send activate event to new child
68
69 wxMDIClientWindow *client_window = parent->GetClientWindow();
70 if (!client_window)
71 return;
72
73 child = (wxMDIChildFrame*) NULL;
74
75 wxWindowList::compatibility_iterator node = client_window->GetChildren().GetFirst();
76 while ( node )
77 {
78 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
79
80 // child_frame can be NULL when this is called from dtor, probably
81 // because g_signal_connect (m_widget, "switch_page", (see below)
82 // isn't deleted early enough
83 if ( child_frame && child_frame->m_page == page )
84 {
85 child = child_frame;
86 break;
87 }
88 node = node->GetNext();
89 }
90
91 if (!child)
92 return;
93
94 wxActivateEvent event2( wxEVT_ACTIVATE, true, child->GetId() );
95 event2.SetEventObject( child);
96 child->GetEventHandler()->ProcessEvent( event2 );
97 }
98 }
99
100 //-----------------------------------------------------------------------------
101 // wxMDIParentFrame
102 //-----------------------------------------------------------------------------
103
104 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame,wxFrame)
105
106 void wxMDIParentFrame::Init()
107 {
108 m_justInserted = false;
109 m_clientWindow = (wxMDIClientWindow *) NULL;
110 }
111
112 wxMDIParentFrame::~wxMDIParentFrame()
113 {
114 }
115
116 bool wxMDIParentFrame::Create(wxWindow *parent,
117 wxWindowID id,
118 const wxString& title,
119 const wxPoint& pos,
120 const wxSize& size,
121 long style,
122 const wxString& name )
123 {
124 wxFrame::Create( parent, id, title, pos, size, style, name );
125
126 OnCreateClient();
127
128 return true;
129 }
130
131 void wxMDIParentFrame::GtkOnSize( int x, int y, int width, int height )
132 {
133 wxFrame::GtkOnSize( x, y, width, height );
134
135 wxMDIChildFrame *child_frame = GetActiveChild();
136 if (!child_frame) return;
137
138 wxMenuBar *menu_bar = child_frame->m_menuBar;
139 if (!menu_bar) return;
140 if (!menu_bar->m_widget) return;
141
142 menu_bar->m_x = 0;
143 menu_bar->m_y = 0;
144 menu_bar->m_width = m_width;
145 menu_bar->m_height = wxMENU_HEIGHT;
146 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
147 menu_bar->m_widget,
148 0, 0, m_width, wxMENU_HEIGHT );
149 }
150
151 void wxMDIParentFrame::OnInternalIdle()
152 {
153 /* if a an MDI child window has just been inserted
154 it has to be brought to the top in idle time. we
155 simply set the last notebook page active as new
156 pages can only be appended at the end */
157
158 if (m_justInserted)
159 {
160 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
161 gtk_notebook_set_current_page( notebook, g_list_length( notebook->children ) - 1 );
162
163 /* need to set the menubar of the child */
164 wxMDIChildFrame *active_child_frame = GetActiveChild();
165 if (active_child_frame != NULL)
166 {
167 wxMenuBar *menu_bar = active_child_frame->m_menuBar;
168 if (menu_bar)
169 {
170 menu_bar->m_width = m_width;
171 menu_bar->m_height = wxMENU_HEIGHT;
172 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
173 menu_bar->m_widget,
174 0, 0, m_width, wxMENU_HEIGHT );
175 menu_bar->SetInvokingWindow(active_child_frame);
176 }
177 }
178 m_justInserted = false;
179 return;
180 }
181
182 wxFrame::OnInternalIdle();
183
184 wxMDIChildFrame *active_child_frame = GetActiveChild();
185 bool visible_child_menu = false;
186
187 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
188 while (node)
189 {
190 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
191
192 if ( child_frame )
193 {
194 wxMenuBar *menu_bar = child_frame->m_menuBar;
195 if ( menu_bar )
196 {
197 if (child_frame == active_child_frame)
198 {
199 if (menu_bar->Show(true))
200 {
201 menu_bar->m_width = m_width;
202 menu_bar->m_height = wxMENU_HEIGHT;
203 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
204 menu_bar->m_widget,
205 0, 0, m_width, wxMENU_HEIGHT );
206 menu_bar->SetInvokingWindow( child_frame );
207 }
208 visible_child_menu = true;
209 }
210 else
211 {
212 if (menu_bar->Show(false))
213 {
214 menu_bar->UnsetInvokingWindow( child_frame );
215 }
216 }
217 }
218 }
219
220 node = node->GetNext();
221 }
222
223 /* show/hide parent menu bar as required */
224 if ((m_frameMenuBar) &&
225 (m_frameMenuBar->IsShown() == visible_child_menu))
226 {
227 if (visible_child_menu)
228 {
229 m_frameMenuBar->Show( false );
230 m_frameMenuBar->UnsetInvokingWindow( this );
231 }
232 else
233 {
234 m_frameMenuBar->Show( true );
235 m_frameMenuBar->SetInvokingWindow( this );
236
237 m_frameMenuBar->m_width = m_width;
238 m_frameMenuBar->m_height = wxMENU_HEIGHT;
239 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
240 m_frameMenuBar->m_widget,
241 0, 0, m_width, wxMENU_HEIGHT );
242 }
243 }
244 }
245
246 void wxMDIParentFrame::DoGetClientSize(int *width, int *height ) const
247 {
248 wxFrame::DoGetClientSize( width, height );
249 }
250
251 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
252 {
253 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
254
255 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
256 if (!notebook) return (wxMDIChildFrame*) NULL;
257
258 gint i = gtk_notebook_get_current_page( notebook );
259 if (i < 0) return (wxMDIChildFrame*) NULL;
260
261 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
262 if (!page) return (wxMDIChildFrame*) NULL;
263
264 wxWindowList::compatibility_iterator node = m_clientWindow->GetChildren().GetFirst();
265 while (node)
266 {
267 wxMDIChildFrame *child_frame = wxDynamicCast( node->GetData(), wxMDIChildFrame );
268
269 wxASSERT_MSG( child_frame, _T("child is not a wxMDIChildFrame") );
270
271 if (child_frame->m_page == page)
272 return child_frame;
273 node = node->GetNext();
274 }
275
276 return (wxMDIChildFrame*) NULL;
277 }
278
279 wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
280 {
281 return m_clientWindow;
282 }
283
284 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
285 {
286 m_clientWindow = new wxMDIClientWindow( this );
287 return m_clientWindow;
288 }
289
290 void wxMDIParentFrame::ActivateNext()
291 {
292 if (m_clientWindow)
293 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
294 }
295
296 void wxMDIParentFrame::ActivatePrevious()
297 {
298 if (m_clientWindow)
299 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
300 }
301
302 //-----------------------------------------------------------------------------
303 // wxMDIChildFrame
304 //-----------------------------------------------------------------------------
305
306 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
307
308 BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
309 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
310 EVT_MENU_HIGHLIGHT_ALL(wxMDIChildFrame::OnMenuHighlight)
311 END_EVENT_TABLE()
312
313 wxMDIChildFrame::wxMDIChildFrame()
314 {
315 m_menuBar = (wxMenuBar *) NULL;
316 m_page = (GtkNotebookPage *) NULL;
317 }
318
319 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
320 wxWindowID id, const wxString& title,
321 const wxPoint& WXUNUSED(pos), const wxSize& size,
322 long style, const wxString& name )
323 {
324 m_menuBar = (wxMenuBar *) NULL;
325 m_page = (GtkNotebookPage *) NULL;
326 Create( parent, id, title, wxDefaultPosition, size, style, name );
327 }
328
329 wxMDIChildFrame::~wxMDIChildFrame()
330 {
331 if (m_menuBar)
332 delete m_menuBar;
333 }
334
335 bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
336 wxWindowID id, const wxString& title,
337 const wxPoint& WXUNUSED(pos), const wxSize& size,
338 long style, const wxString& name )
339 {
340 m_title = title;
341
342 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
343 }
344
345 void wxMDIChildFrame::DoSetSize( int x, int y, int width, int height, int sizeFlags )
346 {
347 wxWindow::DoSetSize( x, y, width, height, sizeFlags );
348 }
349
350 void wxMDIChildFrame::DoSetClientSize(int width, int height)
351 {
352 wxWindow::DoSetClientSize( width, height );
353 }
354
355 void wxMDIChildFrame::DoGetClientSize( int *width, int *height ) const
356 {
357 wxWindow::DoGetClientSize( width, height );
358 }
359
360 void wxMDIChildFrame::AddChild( wxWindowBase *child )
361 {
362 wxWindow::AddChild(child);
363 }
364
365 void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
366 {
367 wxASSERT_MSG( m_menuBar == NULL, wxT("Only one menubar allowed") );
368
369 m_menuBar = menu_bar;
370
371 if (m_menuBar)
372 {
373 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
374
375 m_menuBar->SetParent( mdi_frame );
376
377 /* insert the invisible menu bar into the _parent_ mdi frame */
378 gtk_pizza_put( GTK_PIZZA(mdi_frame->m_mainWidget),
379 m_menuBar->m_widget,
380 0, 0, mdi_frame->m_width, wxMENU_HEIGHT );
381 }
382 }
383
384 wxMenuBar *wxMDIChildFrame::GetMenuBar() const
385 {
386 return m_menuBar;
387 }
388
389 void wxMDIChildFrame::Activate()
390 {
391 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
392 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
393 gint pageno = gtk_notebook_page_num( notebook, m_widget );
394 gtk_notebook_set_current_page( notebook, pageno );
395 }
396
397 void wxMDIChildFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
398 {
399 }
400
401 void wxMDIChildFrame::OnMenuHighlight( wxMenuEvent& event )
402 {
403 #if wxUSE_STATUSBAR
404 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
405 if ( !ShowMenuHelp(mdi_frame->GetStatusBar(), event.GetMenuId()) )
406 {
407 // we don't have any help text for this item, but may be the MDI frame
408 // does?
409 mdi_frame->OnMenuHighlight(event);
410 }
411 #endif // wxUSE_STATUSBAR
412 }
413
414 void wxMDIChildFrame::SetTitle( const wxString &title )
415 {
416 if ( title == m_title )
417 return;
418
419 m_title = title;
420
421 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
422 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
423 gtk_notebook_set_tab_label_text(notebook, m_widget, wxGTK_CONV( title ) );
424 }
425
426 //-----------------------------------------------------------------------------
427 // "size_allocate"
428 //-----------------------------------------------------------------------------
429
430 extern "C" {
431 static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
432 {
433 if (g_isIdle) wxapp_install_idle_handler();
434
435 if ((win->m_x == alloc->x) &&
436 (win->m_y == alloc->y) &&
437 (win->m_width == alloc->width) &&
438 (win->m_height == alloc->height) &&
439 (win->m_sizeSet))
440 {
441 return;
442 }
443
444 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
445 }
446 }
447
448 //-----------------------------------------------------------------------------
449 // InsertChild callback for wxMDIClientWindow
450 //-----------------------------------------------------------------------------
451
452 static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
453 {
454 wxString s = child->GetTitle();
455 if (s.IsNull()) s = _("MDI child");
456
457 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
458 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
459
460 g_signal_connect (child->m_widget, "size_allocate",
461 G_CALLBACK (gtk_page_size_callback), child);
462
463 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
464
465 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
466
467 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
468
469 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
470 parent_frame->m_justInserted = true;
471 }
472
473 //-----------------------------------------------------------------------------
474 // wxMDIClientWindow
475 //-----------------------------------------------------------------------------
476
477 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
478
479 wxMDIClientWindow::wxMDIClientWindow()
480 {
481 }
482
483 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
484 {
485 CreateClient( parent, style );
486 }
487
488 wxMDIClientWindow::~wxMDIClientWindow()
489 {
490
491 }
492
493 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
494 {
495 m_needParent = true;
496
497 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
498
499 if (!PreCreation( parent, wxDefaultPosition, wxDefaultSize ) ||
500 !CreateBase( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, style, wxDefaultValidator, wxT("wxMDIClientWindow") ))
501 {
502 wxFAIL_MSG( wxT("wxMDIClientWindow creation failed") );
503 return false;
504 }
505
506 m_widget = gtk_notebook_new();
507
508 g_signal_connect (m_widget, "switch_page",
509 G_CALLBACK (gtk_mdi_page_change_callback), parent);
510
511 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
512
513 m_parent->DoAddChild( this );
514
515 PostCreation();
516
517 Show( true );
518
519 return true;
520 }
521
522 #endif