Added scrolling of widgets and sample
[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->m_children.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->m_children.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->m_parent;
283
284 if (m_menuBar->m_parent != 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->m_parent = 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 }
315
316 void wxMDIChildFrame::OnActivate( wxActivateEvent &WXUNUSED(event) )
317 {
318 }
319
320 //-----------------------------------------------------------------------------
321 // "size_allocate"
322 //-----------------------------------------------------------------------------
323
324 static void gtk_page_size_callback( GtkWidget *WXUNUSED(widget), GtkAllocation* alloc, wxWindow *win )
325 {
326 if (g_isIdle) wxapp_install_idle_handler();
327
328 if ((win->m_x == alloc->x) &&
329 (win->m_y == alloc->y) &&
330 (win->m_width == alloc->width) &&
331 (win->m_height == alloc->height) &&
332 (win->m_sizeSet))
333 {
334 return;
335 }
336
337 win->SetSize( alloc->x, alloc->y, alloc->width, alloc->height );
338 }
339
340 //-----------------------------------------------------------------------------
341 // InsertChild callback for wxMDIClientWindow
342 //-----------------------------------------------------------------------------
343
344 static void wxInsertChildInMDI( wxMDIClientWindow* parent, wxMDIChildFrame* child )
345 {
346 wxString s = child->m_title;
347 if (s.IsNull()) s = _("MDI child");
348
349 GtkWidget *label_widget = gtk_label_new( s.mbc_str() );
350 gtk_misc_set_alignment( GTK_MISC(label_widget), 0.0, 0.5 );
351
352 gtk_signal_connect( GTK_OBJECT(child->m_widget), "size_allocate",
353 GTK_SIGNAL_FUNC(gtk_page_size_callback), (gpointer)child );
354
355 GtkNotebook *notebook = GTK_NOTEBOOK(parent->m_widget);
356
357 gtk_notebook_append_page( notebook, child->m_widget, label_widget );
358
359 child->m_page = (GtkNotebookPage*) (g_list_last(notebook->children)->data);
360
361 wxMDIParentFrame *parent_frame = (wxMDIParentFrame*) parent->m_parent;
362 parent_frame->m_justInserted = TRUE;
363 }
364
365 //-----------------------------------------------------------------------------
366 // wxMDIClientWindow
367 //-----------------------------------------------------------------------------
368
369 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow,wxWindow)
370
371 wxMDIClientWindow::wxMDIClientWindow()
372 {
373 }
374
375 wxMDIClientWindow::wxMDIClientWindow( wxMDIParentFrame *parent, long style )
376 {
377 CreateClient( parent, style );
378 }
379
380 wxMDIClientWindow::~wxMDIClientWindow()
381 {
382 }
383
384 bool wxMDIClientWindow::CreateClient( wxMDIParentFrame *parent, long style )
385 {
386 m_needParent = TRUE;
387
388 m_insertCallback = (wxInsertChildFunction)wxInsertChildInMDI;
389
390 PreCreation( parent, -1, wxPoint(10,10), wxSize(100,100), style, "wxMDIClientWindow" );
391
392 m_widget = gtk_notebook_new();
393
394 gtk_notebook_set_scrollable( GTK_NOTEBOOK(m_widget), 1 );
395
396 m_parent->AddChild( this );
397
398 (m_parent->m_insertCallback)( m_parent, this );
399
400 PostCreation();
401
402 Show( TRUE );
403
404 return TRUE;
405 }
406
407
408