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