simplify toolbar and statusbar create/set code
[wxWidgets.git] / src / gtk / frame.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/frame.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 #include "wx/frame.h"
14
15 #ifndef WX_PRECOMP
16 #include "wx/menu.h"
17 #include "wx/toolbar.h"
18 #include "wx/statusbr.h"
19 #endif // WX_PRECOMP
20
21 #include <gtk/gtk.h>
22 #include "wx/gtk/win_gtk.h"
23
24 // ----------------------------------------------------------------------------
25 // constants
26 // ----------------------------------------------------------------------------
27
28 static const int wxSTATUS_HEIGHT = 25;
29 static const int wxPLACE_HOLDER = 0;
30
31 // ----------------------------------------------------------------------------
32 // event tables
33 // ----------------------------------------------------------------------------
34
35 IMPLEMENT_DYNAMIC_CLASS(wxFrame, wxTopLevelWindow)
36
37 // ============================================================================
38 // implementation
39 // ============================================================================
40
41 // ----------------------------------------------------------------------------
42 // GTK callbacks
43 // ----------------------------------------------------------------------------
44
45 #if wxUSE_MENUS_NATIVE
46
47 //-----------------------------------------------------------------------------
48 // "child_attached" of menu bar
49 //-----------------------------------------------------------------------------
50
51 extern "C" {
52 static void gtk_menu_attached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
53 {
54 if (!win->m_hasVMT) return;
55
56 win->m_menuBarDetached = false;
57 win->GtkUpdateSize();
58 }
59 }
60
61 //-----------------------------------------------------------------------------
62 // "child_detached" of menu bar
63 //-----------------------------------------------------------------------------
64
65 extern "C" {
66 static void gtk_menu_detached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
67 {
68 if (!win->m_hasVMT) return;
69
70 // Raise the client area area
71 gdk_window_raise( win->m_wxwindow->window );
72
73 win->m_menuBarDetached = true;
74 win->GtkUpdateSize();
75 }
76 }
77
78 #endif // wxUSE_MENUS_NATIVE
79
80 #if wxUSE_TOOLBAR
81 //-----------------------------------------------------------------------------
82 // "child_attached" of tool bar
83 //-----------------------------------------------------------------------------
84
85 extern "C" {
86 static void gtk_toolbar_attached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
87 {
88 if (!win->m_hasVMT) return;
89
90 win->m_toolBarDetached = false;
91 win->GtkUpdateSize();
92 }
93 }
94
95 //-----------------------------------------------------------------------------
96 // "child_detached" of tool bar
97 //-----------------------------------------------------------------------------
98
99 extern "C" {
100 static void gtk_toolbar_detached_callback( GtkWidget *WXUNUSED(widget), GtkWidget *WXUNUSED(child), wxFrame *win )
101 {
102 if (!win->m_hasVMT) return;
103
104 // Raise the client area area
105 gdk_window_raise( win->m_wxwindow->window );
106
107 win->m_toolBarDetached = true;
108 win->GtkUpdateSize();
109 }
110 }
111 #endif // wxUSE_TOOLBAR
112
113 // ----------------------------------------------------------------------------
114 // wxFrame creation
115 // ----------------------------------------------------------------------------
116
117 void wxFrame::Init()
118 {
119 m_menuBarDetached = false;
120 m_toolBarDetached = false;
121 m_menuBarHeight = 2;
122 m_fsSaveFlag = 0;
123 }
124
125 bool wxFrame::Create( wxWindow *parent,
126 wxWindowID id,
127 const wxString& title,
128 const wxPoint& pos,
129 const wxSize& sizeOrig,
130 long style,
131 const wxString &name )
132 {
133 return wxFrameBase::Create(parent, id, title, pos, sizeOrig, style, name);
134 }
135
136 wxFrame::~wxFrame()
137 {
138 m_isBeingDeleted = true;
139 DeleteAllBars();
140 }
141
142 // ----------------------------------------------------------------------------
143 // overridden wxWindow methods
144 // ----------------------------------------------------------------------------
145
146 void wxFrame::DoGetClientSize( int *width, int *height ) const
147 {
148 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
149
150 wxFrameBase::DoGetClientSize(width, height);
151
152 if (height)
153 {
154 #if wxUSE_MENUS_NATIVE
155 // menu bar
156 if (HasVisibleMenubar() && !m_menuBarDetached)
157 {
158 *height -= m_menuBarHeight;
159 }
160 #endif // wxUSE_MENUS_NATIVE
161
162 #if wxUSE_STATUSBAR
163 // status bar
164 if (m_frameStatusBar && GTK_WIDGET_VISIBLE(m_frameStatusBar->m_widget))
165 *height -= wxSTATUS_HEIGHT;
166 #endif // wxUSE_STATUSBAR
167 }
168
169 #if wxUSE_TOOLBAR
170 // tool bar
171 if (m_frameToolBar &&
172 GTK_WIDGET_VISIBLE(m_frameToolBar->m_widget) && !m_toolBarDetached)
173 {
174 if (m_frameToolBar->IsVertical())
175 {
176 if (width)
177 *width -= m_frameToolBar->GetSize().x;
178 }
179 else
180 {
181 if (height)
182 *height -= m_frameToolBar->GetSize().y;
183 }
184 }
185 #endif // wxUSE_TOOLBAR
186
187 if (width != NULL && *width < 0)
188 *width = 0;
189 if (height != NULL && *height < 0)
190 *height = 0;
191 }
192
193 bool wxFrame::ShowFullScreen(bool show, long style)
194 {
195 if (!wxFrameBase::ShowFullScreen(show, style))
196 return false;
197
198 wxWindow* const bar[] = {
199 #if wxUSE_MENUS
200 m_frameMenuBar,
201 #else
202 NULL,
203 #endif
204 #if wxUSE_TOOLBAR
205 m_frameToolBar,
206 #else
207 NULL,
208 #endif
209 #if wxUSE_STATUSBAR
210 m_frameStatusBar,
211 #else
212 NULL,
213 #endif
214 };
215 const long fsNoBar[] = {
216 wxFULLSCREEN_NOMENUBAR, wxFULLSCREEN_NOTOOLBAR, wxFULLSCREEN_NOSTATUSBAR
217 };
218 for (int i = 0; i < 3; i++)
219 {
220 if (show)
221 {
222 if (bar[i] && (style & fsNoBar[i]))
223 {
224 if (bar[i]->IsShown())
225 bar[i]->Show(false);
226 else
227 style &= ~fsNoBar[i];
228 }
229 }
230 else
231 {
232 if (bar[i] && (m_fsSaveFlag & fsNoBar[i]))
233 bar[i]->Show(true);
234 }
235 }
236 if (show)
237 m_fsSaveFlag = style;
238
239 return true;
240 }
241
242 void wxFrame::GtkOnSize()
243 {
244 // avoid recursions
245 if (m_resizing) return;
246 m_resizing = true;
247
248 // this shouldn't happen: wxFrame, wxMDIParentFrame and wxMDIChildFrame have m_wxwindow
249 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
250
251 // space occupied by m_frameToolBar and m_frameMenuBar
252 int client_area_x_offset = 0,
253 client_area_y_offset = 0;
254
255 /* wxMDIChildFrame derives from wxFrame but it _is_ a wxWindow as it uses
256 wxWindow::Create to create it's GTK equivalent. m_mainWidget is only
257 set in wxFrame::Create so it is used to check what kind of frame we
258 have here. if m_mainWidget is NULL it is a wxMDIChildFrame and so we
259 skip the part which handles m_frameMenuBar, m_frameToolBar and (most
260 importantly) m_mainWidget */
261
262 ConstrainSize();
263
264 int width, height;
265 GTKDoGetSize(&width, &height);
266
267 if (m_mainWidget)
268 {
269 // TODO
270 // Rewrite this terrible code to using GtkVBox
271
272 // m_mainWidget holds the menubar, the toolbar and the client
273 // area, which is represented by m_wxwindow.
274
275 #if wxUSE_MENUS_NATIVE
276 int menubarHeight = 0;
277 #endif
278
279 #if wxUSE_MENUS_NATIVE
280 if (HasVisibleMenubar())
281 {
282 int xx = m_miniEdge;
283 int yy = m_miniEdge + m_miniTitle;
284 int ww = width - 2*m_miniEdge;
285 if (ww < 0)
286 ww = 0;
287 menubarHeight = m_menuBarHeight;
288 if (m_menuBarDetached) menubarHeight = wxPLACE_HOLDER;
289 m_frameMenuBar->m_x = xx;
290 m_frameMenuBar->m_y = yy;
291 m_frameMenuBar->m_width = ww;
292 m_frameMenuBar->m_height = menubarHeight;
293 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
294 m_frameMenuBar->m_widget,
295 xx, yy, ww, menubarHeight);
296 client_area_y_offset += menubarHeight;
297 }
298 #endif // wxUSE_MENUS_NATIVE
299
300 #if wxUSE_TOOLBAR
301 if ((m_frameToolBar) && m_frameToolBar->IsShown() &&
302 (m_frameToolBar->m_widget->parent == m_mainWidget))
303 {
304 int xx = m_miniEdge;
305 int yy = m_miniEdge + m_miniTitle
306 #if wxUSE_MENUS_NATIVE
307 + menubarHeight
308 #endif
309 ;
310
311 m_frameToolBar->m_x = xx;
312 m_frameToolBar->m_y = yy;
313
314 // don't change the toolbar's reported height/width
315 int ww, hh;
316 if ( m_frameToolBar->GetWindowStyle() & wxTB_VERTICAL )
317 {
318 ww = m_toolBarDetached ? wxPLACE_HOLDER
319 : m_frameToolBar->m_width;
320 hh = height - 2*m_miniEdge;
321
322 client_area_x_offset += ww;
323 }
324 else if( m_frameToolBar->HasFlag(wxTB_RIGHT) )
325 {
326 yy += 2;
327 ww = m_toolBarDetached ? wxPLACE_HOLDER
328 : m_frameToolBar->m_width;
329 xx = GetClientSize().x - 1;
330 hh = height - 2*m_miniEdge;
331 if( hh < 0 )
332 hh = 0;
333
334 }
335 else if( m_frameToolBar->GetWindowStyle() & wxTB_BOTTOM )
336 {
337 xx = m_miniEdge;
338 yy = GetClientSize().y;
339 #if wxUSE_MENUS_NATIVE
340 yy += m_menuBarHeight;
341 #endif // wxUSE_MENUS_NATIVE
342 m_frameToolBar->m_x = xx;
343 m_frameToolBar->m_y = yy;
344 ww = width - 2*m_miniEdge;
345 hh = m_toolBarDetached ? wxPLACE_HOLDER
346 : m_frameToolBar->m_height;
347 }
348 else
349 {
350 ww = width - 2*m_miniEdge;
351 hh = m_toolBarDetached ? wxPLACE_HOLDER
352 : m_frameToolBar->m_height;
353
354 client_area_y_offset += hh;
355 }
356
357 if (ww < 0)
358 ww = 0;
359 if (hh < 0)
360 hh = 0;
361 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
362 m_frameToolBar->m_widget,
363 xx, yy, ww, hh );
364 }
365 #endif // wxUSE_TOOLBAR
366
367 int client_x = client_area_x_offset + m_miniEdge;
368 int client_y = client_area_y_offset + m_miniEdge + m_miniTitle;
369 int client_w = width - client_area_x_offset - 2*m_miniEdge;
370 int client_h = height - client_area_y_offset- 2*m_miniEdge - m_miniTitle;
371 if (client_w < 0)
372 client_w = 0;
373 if (client_h < 0)
374 client_h = 0;
375 gtk_pizza_set_size( GTK_PIZZA(m_mainWidget),
376 m_wxwindow,
377 client_x, client_y, client_w, client_h );
378 }
379 else
380 {
381 // If there is no m_mainWidget between m_widget and m_wxwindow there
382 // is no need to set the size or position of m_wxwindow.
383 }
384
385 #if wxUSE_STATUSBAR
386 if (m_frameStatusBar && m_frameStatusBar->IsShown())
387 {
388 int xx = 0 + m_miniEdge;
389 int yy = height - wxSTATUS_HEIGHT - m_miniEdge - client_area_y_offset;
390 int ww = width - 2*m_miniEdge;
391 if (ww < 0)
392 ww = 0;
393 int hh = wxSTATUS_HEIGHT;
394 m_frameStatusBar->m_x = xx;
395 m_frameStatusBar->m_y = yy;
396 m_frameStatusBar->m_width = ww;
397 m_frameStatusBar->m_height = hh;
398 gtk_pizza_set_size( GTK_PIZZA(m_wxwindow),
399 m_frameStatusBar->m_widget,
400 xx, yy, ww, hh );
401 }
402 #endif // wxUSE_STATUSBAR
403
404 m_sizeSet = true;
405
406 // send size event to frame
407 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
408 event.SetEventObject( this );
409 GetEventHandler()->ProcessEvent( event );
410
411 #if wxUSE_STATUSBAR
412 // send size event to status bar
413 if (m_frameStatusBar)
414 {
415 wxSizeEvent event2( wxSize(m_frameStatusBar->m_width,m_frameStatusBar->m_height), m_frameStatusBar->GetId() );
416 event2.SetEventObject( m_frameStatusBar );
417 m_frameStatusBar->GetEventHandler()->ProcessEvent( event2 );
418 }
419 #endif // wxUSE_STATUSBAR
420
421 m_resizing = false;
422 }
423
424 void wxFrame::OnInternalIdle()
425 {
426 wxFrameBase::OnInternalIdle();
427
428 #if wxUSE_MENUS_NATIVE
429 if (m_frameMenuBar) m_frameMenuBar->OnInternalIdle();
430 #endif // wxUSE_MENUS_NATIVE
431 #if wxUSE_TOOLBAR
432 if (m_frameToolBar) m_frameToolBar->OnInternalIdle();
433 #endif
434 #if wxUSE_STATUSBAR
435 if (m_frameStatusBar)
436 {
437 m_frameStatusBar->OnInternalIdle();
438
439 // There may be controls in the status bar that
440 // need to be updated
441 for ( wxWindowList::compatibility_iterator node = m_frameStatusBar->GetChildren().GetFirst();
442 node;
443 node = node->GetNext() )
444 {
445 wxWindow *child = node->GetData();
446 child->OnInternalIdle();
447 }
448 }
449 #endif
450 }
451
452 // ----------------------------------------------------------------------------
453 // menu/tool/status bar stuff
454 // ----------------------------------------------------------------------------
455
456 #if wxUSE_MENUS_NATIVE
457
458 void wxFrame::DetachMenuBar()
459 {
460 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
461 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
462
463 if ( m_frameMenuBar )
464 {
465 m_frameMenuBar->UnsetInvokingWindow( this );
466
467 if (m_frameMenuBar->GetWindowStyle() & wxMB_DOCKABLE)
468 {
469 g_signal_handlers_disconnect_by_func (m_frameMenuBar->m_widget,
470 (gpointer) gtk_menu_attached_callback,
471 this);
472
473 g_signal_handlers_disconnect_by_func (m_frameMenuBar->m_widget,
474 (gpointer) gtk_menu_detached_callback,
475 this);
476 }
477
478 gtk_widget_ref( m_frameMenuBar->m_widget );
479
480 gtk_container_remove( GTK_CONTAINER(m_mainWidget), m_frameMenuBar->m_widget );
481 }
482
483 wxFrameBase::DetachMenuBar();
484 }
485
486 void wxFrame::AttachMenuBar( wxMenuBar *menuBar )
487 {
488 wxFrameBase::AttachMenuBar(menuBar);
489
490 if (m_frameMenuBar)
491 {
492 m_frameMenuBar->SetInvokingWindow( this );
493
494 m_frameMenuBar->SetParent(this);
495 gtk_pizza_put( GTK_PIZZA(m_mainWidget),
496 m_frameMenuBar->m_widget,
497 m_frameMenuBar->m_x,
498 m_frameMenuBar->m_y,
499 m_frameMenuBar->m_width,
500 m_frameMenuBar->m_height );
501
502 if (menuBar->GetWindowStyle() & wxMB_DOCKABLE)
503 {
504 g_signal_connect (menuBar->m_widget, "child_attached",
505 G_CALLBACK (gtk_menu_attached_callback),
506 this);
507 g_signal_connect (menuBar->m_widget, "child_detached",
508 G_CALLBACK (gtk_menu_detached_callback),
509 this);
510 }
511
512 gtk_widget_show( m_frameMenuBar->m_widget );
513
514 UpdateMenuBarSize();
515 }
516 else
517 {
518 m_menuBarHeight = 2;
519 GtkUpdateSize(); // resize window in OnInternalIdle
520 }
521 }
522
523 void wxFrame::UpdateMenuBarSize()
524 {
525 m_menuBarHeight = 2;
526
527 // this is called after Remove with a NULL m_frameMenuBar
528 if ( m_frameMenuBar )
529 {
530 GtkRequisition req;
531 gtk_widget_ensure_style(m_frameMenuBar->m_widget);
532 // have to call class method directly because
533 // "size_request" signal is overridden by wx
534 GTK_WIDGET_GET_CLASS(m_frameMenuBar->m_widget)->size_request(
535 m_frameMenuBar->m_widget, &req);
536
537 m_menuBarHeight = req.height;
538 }
539
540 // resize window in OnInternalIdle
541 GtkUpdateSize();
542 }
543
544 bool wxFrame::HasVisibleMenubar() const
545 {
546 return m_frameMenuBar && m_frameMenuBar->IsShown();
547 }
548 #endif // wxUSE_MENUS_NATIVE
549
550 #if wxUSE_TOOLBAR
551
552 void wxFrame::SetToolBar(wxToolBar *toolbar)
553 {
554 wxFrameBase::SetToolBar(toolbar);
555
556 if ( m_frameToolBar )
557 {
558 // insert into toolbar area if not already there
559 if ((m_frameToolBar->m_widget->parent) &&
560 (m_frameToolBar->m_widget->parent != m_mainWidget))
561 {
562 GetChildren().DeleteObject( m_frameToolBar );
563
564 gtk_widget_reparent( m_frameToolBar->m_widget, m_mainWidget );
565 }
566 #if wxUSE_TOOLBAR_NATIVE
567 if (m_frameToolBar->HasFlag(wxTB_DOCKABLE))
568 {
569 g_signal_connect(m_frameToolBar->m_widget, "child_attached",
570 G_CALLBACK(gtk_toolbar_attached_callback), this);
571 g_signal_connect(m_frameToolBar->m_widget, "child_detached",
572 G_CALLBACK(gtk_toolbar_detached_callback), this);
573 }
574 #endif // wxUSE_TOOLBAR_NATIVE
575 }
576
577 GtkUpdateSize();
578 }
579
580 #endif // wxUSE_TOOLBAR
581
582 #if wxUSE_STATUSBAR
583
584 void wxFrame::SetStatusBar(wxStatusBar *statbar)
585 {
586 wxFrameBase::SetStatusBar(statbar);
587 GtkUpdateSize();
588 }
589 #endif // wxUSE_STATUSBAR