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