Use a GtkVBox to do TLW layout. Rework some of the remaining sizing 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
23 // ----------------------------------------------------------------------------
24 // event tables
25 // ----------------------------------------------------------------------------
26
27 IMPLEMENT_DYNAMIC_CLASS(wxFrame, wxTopLevelWindow)
28
29 // ============================================================================
30 // implementation
31 // ============================================================================
32
33 // ----------------------------------------------------------------------------
34 // wxFrame creation
35 // ----------------------------------------------------------------------------
36
37 void wxFrame::Init()
38 {
39 m_fsSaveFlag = 0;
40 }
41
42 bool wxFrame::Create( wxWindow *parent,
43 wxWindowID id,
44 const wxString& title,
45 const wxPoint& pos,
46 const wxSize& sizeOrig,
47 long style,
48 const wxString &name )
49 {
50 return wxFrameBase::Create(parent, id, title, pos, sizeOrig, style, name);
51 }
52
53 wxFrame::~wxFrame()
54 {
55 m_isBeingDeleted = true;
56 DeleteAllBars();
57 }
58
59 // ----------------------------------------------------------------------------
60 // overridden wxWindow methods
61 // ----------------------------------------------------------------------------
62
63 void wxFrame::DoGetClientSize( int *width, int *height ) const
64 {
65 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
66
67 wxFrameBase::DoGetClientSize(width, height);
68
69 if (height)
70 {
71 #if wxUSE_MENUS_NATIVE
72 // menu bar
73 if (m_frameMenuBar && m_frameMenuBar->IsShown())
74 {
75 GtkRequisition req;
76 gtk_widget_size_request(m_frameMenuBar->m_widget, &req);
77 *height -= req.height;
78 }
79 #endif // wxUSE_MENUS_NATIVE
80
81 #if wxUSE_STATUSBAR
82 // status bar
83 if (m_frameStatusBar && m_frameStatusBar->IsShown())
84 *height -= m_frameStatusBar->m_height;
85 #endif // wxUSE_STATUSBAR
86 }
87
88 #if wxUSE_TOOLBAR
89 // tool bar
90 if (m_frameToolBar && m_frameToolBar->IsShown())
91 {
92 GtkRequisition req;
93 gtk_widget_size_request(m_frameToolBar->m_widget, &req);
94 if (m_frameToolBar->IsVertical())
95 {
96 if (width)
97 *width -= req.width;
98 }
99 else
100 {
101 if (height)
102 *height -= req.height;
103 }
104 }
105 #endif // wxUSE_TOOLBAR
106
107 if (width != NULL && *width < 0)
108 *width = 0;
109 if (height != NULL && *height < 0)
110 *height = 0;
111 }
112
113 bool wxFrame::ShowFullScreen(bool show, long style)
114 {
115 if (!wxFrameBase::ShowFullScreen(show, style))
116 return false;
117
118 wxWindow* const bar[] = {
119 #if wxUSE_MENUS
120 m_frameMenuBar,
121 #else
122 NULL,
123 #endif
124 #if wxUSE_TOOLBAR
125 m_frameToolBar,
126 #else
127 NULL,
128 #endif
129 #if wxUSE_STATUSBAR
130 m_frameStatusBar,
131 #else
132 NULL,
133 #endif
134 };
135 const long fsNoBar[] = {
136 wxFULLSCREEN_NOMENUBAR, wxFULLSCREEN_NOTOOLBAR, wxFULLSCREEN_NOSTATUSBAR
137 };
138 for (int i = 0; i < 3; i++)
139 {
140 if (show)
141 {
142 if (bar[i] && (style & fsNoBar[i]))
143 {
144 if (bar[i]->IsShown())
145 bar[i]->Show(false);
146 else
147 style &= ~fsNoBar[i];
148 }
149 }
150 else
151 {
152 if (bar[i] && (m_fsSaveFlag & fsNoBar[i]))
153 bar[i]->Show(true);
154 }
155 }
156 if (show)
157 m_fsSaveFlag = style;
158
159 return true;
160 }
161
162 void wxFrame::OnInternalIdle()
163 {
164 wxFrameBase::OnInternalIdle();
165
166 #if wxUSE_MENUS_NATIVE
167 if (m_frameMenuBar) m_frameMenuBar->OnInternalIdle();
168 #endif // wxUSE_MENUS_NATIVE
169 #if wxUSE_TOOLBAR
170 if (m_frameToolBar) m_frameToolBar->OnInternalIdle();
171 #endif
172 #if wxUSE_STATUSBAR
173 if (m_frameStatusBar)
174 {
175 m_frameStatusBar->OnInternalIdle();
176
177 // There may be controls in the status bar that
178 // need to be updated
179 for ( wxWindowList::compatibility_iterator node = m_frameStatusBar->GetChildren().GetFirst();
180 node;
181 node = node->GetNext() )
182 {
183 wxWindow *child = node->GetData();
184 child->OnInternalIdle();
185 }
186 }
187 #endif
188 }
189
190 // ----------------------------------------------------------------------------
191 // menu/tool/status bar stuff
192 // ----------------------------------------------------------------------------
193
194 #if wxUSE_MENUS_NATIVE
195
196 void wxFrame::DetachMenuBar()
197 {
198 wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") );
199 wxASSERT_MSG( (m_wxwindow != NULL), wxT("invalid frame") );
200
201 if ( m_frameMenuBar )
202 {
203 m_frameMenuBar->UnsetInvokingWindow( this );
204
205 gtk_widget_ref( m_frameMenuBar->m_widget );
206
207 gtk_container_remove( GTK_CONTAINER(m_mainWidget), m_frameMenuBar->m_widget );
208 }
209
210 wxFrameBase::DetachMenuBar();
211
212 // make sure next size_allocate causes a wxSizeEvent
213 m_oldClientWidth = 0;
214 }
215
216 void wxFrame::AttachMenuBar( wxMenuBar *menuBar )
217 {
218 wxFrameBase::AttachMenuBar(menuBar);
219
220 if (m_frameMenuBar)
221 {
222 m_frameMenuBar->SetInvokingWindow( this );
223
224 m_frameMenuBar->SetParent(this);
225
226 // menubar goes into top of vbox (m_mainWidget)
227 gtk_box_pack_start(
228 GTK_BOX(m_mainWidget), menuBar->m_widget, false, false, 0);
229 gtk_box_reorder_child(GTK_BOX(m_mainWidget), menuBar->m_widget, 0);
230
231 // disconnect wxWindowGTK "size_request" handler,
232 // it interferes with sizing of detached GtkHandleBox
233 gulong handler_id = g_signal_handler_find(
234 menuBar->m_widget,
235 GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DATA),
236 g_signal_lookup("size_request", GTK_TYPE_WIDGET),
237 0, NULL, NULL, menuBar);
238 if (handler_id != 0)
239 g_signal_handler_disconnect(menuBar->m_widget, handler_id);
240
241 // reset size request to allow native sizing to work
242 gtk_widget_set_size_request(menuBar->m_widget, -1, -1);
243
244 gtk_widget_show( m_frameMenuBar->m_widget );
245 }
246 // make sure next size_allocate causes a wxSizeEvent
247 m_oldClientWidth = 0;
248 }
249 #endif // wxUSE_MENUS_NATIVE
250
251 #if wxUSE_TOOLBAR
252
253 void wxFrame::SetToolBar(wxToolBar *toolbar)
254 {
255 m_frameToolBar = toolbar;
256 if (toolbar)
257 {
258 if (toolbar->IsVertical())
259 {
260 // Vertical toolbar and m_wxwindow go into an hbox, inside the
261 // vbox (m_mainWidget). hbox is created on demand.
262 GtkWidget* hbox = m_wxwindow->parent;
263 if (!GTK_IS_HBOX(hbox))
264 {
265 hbox = gtk_hbox_new(false, 0);
266 gtk_widget_show(hbox);
267 gtk_container_add(GTK_CONTAINER(m_mainWidget), hbox);
268 gtk_widget_reparent(m_wxwindow, hbox);
269 }
270 gtk_widget_reparent(toolbar->m_widget, hbox);
271 gtk_box_set_child_packing(GTK_BOX(hbox),
272 toolbar->m_widget, false, false, 0, GTK_PACK_START);
273
274 int pos = 0; // left
275 if (toolbar->HasFlag(wxTB_RIGHT))
276 pos = 1; // right
277 gtk_box_reorder_child(GTK_BOX(hbox), toolbar->m_widget, pos);
278 }
279 else
280 {
281 // Horizontal toolbar goes into vbox (m_mainWidget)
282 gtk_widget_reparent(toolbar->m_widget, m_mainWidget);
283 gtk_box_set_child_packing(GTK_BOX(m_mainWidget),
284 toolbar->m_widget, false, false, 0, GTK_PACK_START);
285
286 int pos = 0; // top
287 if (m_frameMenuBar)
288 pos = 1; // below menubar
289 if (toolbar->HasFlag(wxTB_BOTTOM))
290 pos += 2; // below client area (m_wxwindow)
291 gtk_box_reorder_child(
292 GTK_BOX(m_mainWidget), toolbar->m_widget, pos);
293 }
294
295 // disconnect wxWindowGTK "size_request" handler,
296 // it interferes with sizing of detached GtkHandleBox
297 gulong handler_id = g_signal_handler_find(
298 toolbar->m_widget,
299 GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DATA),
300 g_signal_lookup("size_request", GTK_TYPE_WIDGET),
301 0, NULL, NULL, toolbar);
302 if (handler_id != 0)
303 g_signal_handler_disconnect(toolbar->m_widget, handler_id);
304
305 // reset size request to allow native sizing to work
306 gtk_widget_set_size_request(toolbar->m_widget, -1, -1);
307 }
308 // make sure next size_allocate causes a wxSizeEvent
309 m_oldClientWidth = 0;
310 }
311
312 #endif // wxUSE_TOOLBAR
313
314 #if wxUSE_STATUSBAR
315
316 void wxFrame::SetStatusBar(wxStatusBar *statbar)
317 {
318 m_frameStatusBar = statbar;
319 if (statbar)
320 {
321 // statusbar goes into bottom of vbox (m_mainWidget)
322 gtk_widget_reparent(statbar->m_widget, m_mainWidget);
323 gtk_box_set_child_packing(GTK_BOX(m_mainWidget),
324 statbar->m_widget, false, false, 0, GTK_PACK_END);
325 // make sure next size_allocate on statusbar causes a size event
326 statbar->m_oldClientWidth = 0;
327 }
328 // make sure next size_allocate causes a wxSizeEvent
329 m_oldClientWidth = 0;
330 }
331 #endif // wxUSE_STATUSBAR