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