New virtual key defines (NUMPAD_XXX).
[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 #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 if (child_frame->m_menuBar)
130 {
131 if (child_frame == active_child_frame)
132 {
133 gtk_widget_show( child_frame->m_menuBar->m_widget );
134 visible_child_menu = TRUE;
135 }
136 else
137 gtk_widget_hide( child_frame->m_menuBar->m_widget );
138 }
139 node = node->Next();
140 }
141
142 /* show/hide parent menu bar as required */
143 if (m_frameMenuBar) m_frameMenuBar->Show( !visible_child_menu );
144 }
145
146 void wxMDIParentFrame::GetClientSize(int *width, int *height ) const
147 {
148 wxFrame::GetClientSize( width, height );
149 }
150
151 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
152 {
153 if (!m_clientWindow) return (wxMDIChildFrame*) NULL;
154
155 GtkNotebook *notebook = GTK_NOTEBOOK(m_clientWindow->m_widget);
156 if (!notebook) return (wxMDIChildFrame*) NULL;
157
158 #if (GTK_MINOR_VERSION > 0)
159 gint i = gtk_notebook_get_current_page( notebook );
160 #else
161 gint i = gtk_notebook_current_page( notebook );
162 #endif
163 if (i < 0) return (wxMDIChildFrame*) NULL;
164
165 GtkNotebookPage* page = (GtkNotebookPage*) (g_list_nth(notebook->children,i)->data);
166 if (!page) return (wxMDIChildFrame*) NULL;
167
168 wxNode *node = m_clientWindow->GetChildren().First();
169 while (node)
170 {
171 wxMDIChildFrame *child_frame = (wxMDIChildFrame *)node->Data();
172 if (child_frame->m_page == page)
173 return child_frame;
174 node = node->Next();
175 }
176
177 return (wxMDIChildFrame*) NULL;
178 }
179
180 wxMDIClientWindow *wxMDIParentFrame::GetClientWindow() const
181 {
182 return m_clientWindow;
183 }
184
185 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
186 {
187 m_clientWindow = new wxMDIClientWindow( this );
188 return m_clientWindow;
189 }
190
191 void wxMDIParentFrame::ActivateNext()
192 {
193 if (m_clientWindow)
194 gtk_notebook_next_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
195 }
196
197 void wxMDIParentFrame::ActivatePrevious()
198 {
199 if (m_clientWindow)
200 gtk_notebook_prev_page( GTK_NOTEBOOK(m_clientWindow->m_widget) );
201 }
202
203 void wxMDIParentFrame::OnActivate( wxActivateEvent& WXUNUSED(event) )
204 {
205 }
206
207 void wxMDIParentFrame::OnSysColourChanged( wxSysColourChangedEvent& WXUNUSED(event) )
208 {
209 }
210
211 //-----------------------------------------------------------------------------
212 // wxMDIChildFrame
213 //-----------------------------------------------------------------------------
214
215 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame,wxFrame)
216
217 BEGIN_EVENT_TABLE(wxMDIChildFrame, wxFrame)
218 EVT_ACTIVATE(wxMDIChildFrame::OnActivate)
219 END_EVENT_TABLE()
220
221 wxMDIChildFrame::wxMDIChildFrame()
222 {
223 m_menuBar = (wxMenuBar *) NULL;
224 m_page = (GtkNotebookPage *) NULL;
225 }
226
227 wxMDIChildFrame::wxMDIChildFrame( wxMDIParentFrame *parent,
228 wxWindowID id, const wxString& title,
229 const wxPoint& WXUNUSED(pos), const wxSize& size,
230 long style, const wxString& name )
231 {
232 m_menuBar = (wxMenuBar *) NULL;
233 m_page = (GtkNotebookPage *) NULL;
234 Create( parent, id, title, wxDefaultPosition, size, style, name );
235 }
236
237 wxMDIChildFrame::~wxMDIChildFrame()
238 {
239 if (m_menuBar)
240 delete m_menuBar;
241 }
242
243 bool wxMDIChildFrame::Create( wxMDIParentFrame *parent,
244 wxWindowID id, const wxString& title,
245 const wxPoint& WXUNUSED(pos), const wxSize& size,
246 long style, const wxString& name )
247 {
248 m_title = title;
249
250 return wxWindow::Create( parent->GetClientWindow(), id, wxDefaultPosition, size, style, name );
251 }
252
253 void wxMDIChildFrame::GetClientSize( int *width, int *height ) const
254 {
255 wxWindow::GetClientSize( width, height );
256 }
257
258 void wxMDIChildFrame::AddChild( wxWindow *child )
259 {
260 wxWindow::AddChild( child );
261 }
262
263 static void SetInvokingWindow( wxMenu *menu, wxWindow *win )
264 {
265 menu->SetInvokingWindow( win );
266 wxNode *node = menu->GetItems().First();
267 while (node)
268 {
269 wxMenuItem *menuitem = (wxMenuItem*)node->Data();
270 if (menuitem->IsSubMenu())
271 SetInvokingWindow( menuitem->GetSubMenu(), win );
272 node = node->Next();
273 }
274 }
275
276 void wxMDIChildFrame::SetMenuBar( wxMenuBar *menu_bar )
277 {
278 m_menuBar = menu_bar;
279
280 if (m_menuBar)
281 {
282 wxMDIParentFrame *mdi_frame = (wxMDIParentFrame*)m_parent->GetParent();
283
284 if (m_menuBar->GetParent() != this)
285 {
286 wxNode *node = m_menuBar->GetMenus().First();
287 while (node)
288 {
289 wxMenu *menu = (wxMenu*)node->Data();
290 SetInvokingWindow( menu, this );
291 node = node->Next();
292 }
293
294 m_menuBar->SetParent( mdi_frame );
295 }
296
297 /* the menu bar of the child window is shown in idle time as needed */
298 gtk_widget_hide( m_menuBar->m_widget );
299
300 /* insert the invisible menu bar into the _parent_ mdi frame */
301 gtk_myfixed_put( GTK_MYFIXED(mdi_frame->m_mainWidget),
302 m_menuBar->m_widget,
303 0, 0, mdi_frame->m_width, wxMENU_HEIGHT );
304 }
305 }
306
307 wxMenuBar *wxMDIChildFrame::GetMenuBar() const
308 {
309 return m_menuBar;
310 }
311
312 void wxMDIChildFrame::Activate()
313 {
314 #if (GTK_MINOR_VERSION > 0)
315 wxMDIParentFrame* parent = (wxMDIParentFrame*) GetParent();
316 GtkNotebook* notebook = GTK_NOTEBOOK(parent->m_widget);
317 gint pageno = gtk_notebook_page_num( notebook, m_page->child );
318 gtk_notebook_set_page( notebook, pageno );
319 #else
320 // the only way I can see to do this under gtk+ 1.0.X would
321 // be to keep track of page numbers, start at first and
322 // do "next" enough times to get to this page number - messy
323 // - J. Russell Smyth
324 #endif
325 }
326
327 void wxMDIChildFrame::OnActivate( wxActivateEvent &WXUNUSED(event) )
328 {
329 }
330
331 //-----------------------------------------------------------------------------
332 // "size_allocate"
333 //-----------------------------------------------------------------------------
334
335 static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
336 {
337 if (g_isIdle) wxapp_install_idle_handler();
338
339 if ((win->m_x == alloc->x) &&
340 (win->m_y == alloc->y) &&
341 (win->m_width == alloc->width) &&
342 (win->m_height == alloc->height) &&
343 (win->m_sizeSet))
344 {
345 return;
346 }
347
348 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
349 }
350
351 //-----------------------------------------------------------------------------
352 // InsertChild callback for wxMDIClientWindow
353 //-----------------------------------------------------------------------------
354
355 static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
356 {
357 wxString s = child->m_title;
358 if (s.IsNull()) s = _("MDI child");
359
360 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
361 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
362
363 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
364 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
365
366 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
367
368 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
369
370 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
371
372 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->GetParent();
373 parent_frame->m_justInserted = TRUE;
374 }
375
376 //-----------------------------------------------------------------------------
377 // wxMDIClientWindow
378 //-----------------------------------------------------------------------------
379
380 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
381
382 wxMDIClientWindow::wxMDIClientWindow()
383 {
384 }
385
386 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
387 {
388 CreateClient( parent, style );
389 }
390
391 wxMDIClientWindow::~wxMDIClientWindow()
392 {
393 }
394
395 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
396 {
397 m_needParent = TRUE;
398
399 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
400
401 PreCreation( parent, -1, wxPoint(10,10), wxSize(100,100), style, "wxMDIClientWindow" );
402
403 m_widget = gtk_notebook_new();
404
405 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
406
407 m_parent->DoAddChild( this );
408
409 PostCreation();
410
411 Show( TRUE );
412
413 return TRUE;
414 }
415