]> git.saurik.com Git - wxWidgets.git/blob - src/common/framecmn.cpp
tons of fixes for wxGTK/Univ - seems to work, more or less, now
[wxWidgets.git] / src / common / framecmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: common/framecmn.cpp
3 // Purpose: common (for all platforms) wxFrame functions
4 // Author: Julian Smart, Vadim Zeitlin
5 // Created: 01/02/97
6 // Id: $Id$
7 // Copyright: (c) 1998 Robert Roebling, Julian Smart and Markus Holzem
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 #ifdef __GNUG__
20 #pragma implementation "framebase.h"
21 #endif
22
23 // For compilers that support precompilation, includes "wx.h".
24 #include "wx/wxprec.h"
25
26 #ifdef __BORLANDC__
27 #pragma hdrstop
28 #endif
29
30 #ifndef WX_PRECOMP
31 #include "wx/frame.h"
32 #include "wx/menu.h"
33 #include "wx/menuitem.h"
34 #include "wx/dcclient.h"
35 #endif // WX_PRECOMP
36
37 #if wxUSE_TOOLBAR
38 #include "wx/toolbar.h"
39 #endif
40 #if wxUSE_STATUSBAR
41 #include "wx/statusbr.h"
42 #endif
43
44 // ----------------------------------------------------------------------------
45 // event table
46 // ----------------------------------------------------------------------------
47
48 BEGIN_EVENT_TABLE(wxFrameBase, wxWindow)
49 EVT_IDLE(wxFrameBase::OnIdle)
50 EVT_CLOSE(wxFrameBase::OnCloseWindow)
51 EVT_MENU_HIGHLIGHT_ALL(wxFrameBase::OnMenuHighlight)
52 EVT_SIZE(wxFrameBase::OnSize)
53 END_EVENT_TABLE()
54
55 // ============================================================================
56 // implementation
57 // ============================================================================
58
59 // ----------------------------------------------------------------------------
60 // construction/destruction
61 // ----------------------------------------------------------------------------
62
63 wxFrameBase::wxFrameBase()
64 {
65 #if wxUSE_MENUS
66 m_frameMenuBar = NULL;
67 #endif // wxUSE_MENUS
68
69 #if wxUSE_TOOLBAR
70 m_frameToolBar = NULL;
71 #endif // wxUSE_TOOLBAR
72
73 #if wxUSE_STATUSBAR
74 m_frameStatusBar = NULL;
75 #endif // wxUSE_STATUSBAR
76 }
77
78 bool wxFrameBase::Destroy()
79 {
80 // delayed destruction: the frame will be deleted during the next idle
81 // loop iteration
82 if ( !wxPendingDelete.Member(this) )
83 wxPendingDelete.Append(this);
84
85 return TRUE;
86 }
87
88 wxFrame *wxFrameBase::New(wxWindow *parent,
89 wxWindowID id,
90 const wxString& title,
91 const wxPoint& pos,
92 const wxSize& size,
93 long style,
94 const wxString& name)
95 {
96 return new wxFrame(parent, id, title, pos, size, style, name);
97 }
98
99 void wxFrameBase::DeleteAllBars()
100 {
101 #if wxUSE_MENUS
102 if ( m_frameMenuBar )
103 {
104 delete m_frameMenuBar;
105 m_frameMenuBar = (wxMenuBar *) NULL;
106 }
107 #endif // wxUSE_MENUS
108
109 #if wxUSE_STATUSBAR
110 if ( m_frameStatusBar )
111 {
112 delete m_frameStatusBar;
113 m_frameStatusBar = (wxStatusBar *) NULL;
114 }
115 #endif // wxUSE_STATUSBAR
116
117 #if wxUSE_TOOLBAR
118 if ( m_frameToolBar )
119 {
120 delete m_frameToolBar;
121 m_frameToolBar = (wxToolBar *) NULL;
122 }
123 #endif // wxUSE_TOOLBAR
124 }
125
126 bool wxFrameBase::IsOneOfBars(const wxWindow *win) const
127 {
128 #if wxUSE_MENUS
129 if ( win == GetMenuBar() )
130 return TRUE;
131 #endif // wxUSE_MENUS
132
133 #if wxUSE_STATUSBAR
134 if ( win == GetStatusBar() )
135 return TRUE;
136 #endif // wxUSE_STATUSBAR
137
138 #if wxUSE_TOOLBAR
139 if ( win == GetToolBar() )
140 return TRUE;
141 #endif // wxUSE_TOOLBAR
142
143 return FALSE;
144 }
145
146 // ----------------------------------------------------------------------------
147 // wxFrame size management: we exclude the areas taken by menu/status/toolbars
148 // from the client area, so the client area is what's really available for the
149 // frame contents
150 // ----------------------------------------------------------------------------
151
152 // get the origin of the client area in the client coordinates
153 wxPoint wxFrameBase::GetClientAreaOrigin() const
154 {
155 wxPoint pt(0, 0);
156
157 #if wxUSE_TOOLBAR
158 if ( GetToolBar() && GetToolBar()->IsShown() )
159 {
160 int w, h;
161 GetToolBar()->GetSize(& w, & h);
162
163 if ( GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL )
164 {
165 pt.x += w;
166 }
167 else
168 {
169 pt.y += h;
170 }
171 }
172 #endif // wxUSE_TOOLBAR
173
174 return pt;
175 }
176
177 void wxFrameBase::DoScreenToClient(int *x, int *y) const
178 {
179 wxWindow::DoScreenToClient(x, y);
180
181 // We may be faking the client origin.
182 // So a window that's really at (0, 30) may appear
183 // (to wxWin apps) to be at (0, 0).
184 wxPoint pt(GetClientAreaOrigin());
185 *x -= pt.x;
186 *y -= pt.y;
187 }
188
189 void wxFrameBase::DoClientToScreen(int *x, int *y) const
190 {
191 // We may be faking the client origin.
192 // So a window that's really at (0, 30) may appear
193 // (to wxWin apps) to be at (0, 0).
194 wxPoint pt1(GetClientAreaOrigin());
195 *x += pt1.x;
196 *y += pt1.y;
197
198 wxWindow::DoClientToScreen(x, y);
199 }
200
201 // ----------------------------------------------------------------------------
202 // misc
203 // ----------------------------------------------------------------------------
204
205 // make the window modal (all other windows unresponsive)
206 void wxFrameBase::MakeModal(bool modal)
207 {
208 if ( modal )
209 {
210 wxEnableTopLevelWindows(FALSE);
211 Enable(TRUE); // keep this window enabled
212 }
213 else
214 {
215 wxEnableTopLevelWindows(TRUE);
216 }
217 }
218
219 bool wxFrameBase::ProcessCommand(int id)
220 {
221 #if wxUSE_MENUS
222 wxMenuBar *bar = GetMenuBar();
223 if ( !bar )
224 return FALSE;
225
226 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id);
227 commandEvent.SetEventObject(this);
228
229 wxMenuItem *item = bar->FindItem(id);
230 if ( item && item->IsCheckable() )
231 {
232 item->Toggle();
233
234 // use the new value
235 commandEvent.SetInt(item->IsChecked());
236 }
237
238 return GetEventHandler()->ProcessEvent(commandEvent);
239 #else // !wxUSE_MENUS
240 return FALSE;
241 #endif // wxUSE_MENUS/!wxUSE_MENUS
242 }
243
244 // ----------------------------------------------------------------------------
245 // event handlers
246 // ----------------------------------------------------------------------------
247
248 // default resizing behaviour - if only ONE subwindow, resize to fill the
249 // whole client area
250 void wxFrameBase::OnSize(wxSizeEvent& WXUNUSED(event))
251 {
252 // if we're using constraints - do use them
253 #if wxUSE_CONSTRAINTS
254 if ( GetAutoLayout() )
255 {
256 Layout();
257 }
258 else
259 #endif // wxUSE_CONSTRAINTS
260 {
261 // do we have _exactly_ one child?
262 wxWindow *child = (wxWindow *)NULL;
263 for ( wxWindowList::Node *node = GetChildren().GetFirst();
264 node;
265 node = node->GetNext() )
266 {
267 wxWindow *win = node->GetData();
268
269 // exclude top level and managed windows (status bar isn't
270 // currently in the children list except under wxMac anyhow, but
271 // it makes no harm to test for it)
272 if ( !win->IsTopLevel() && !IsOneOfBars(win) )
273 {
274 if ( child )
275 {
276 return; // it's our second subwindow - nothing to do
277 }
278
279 child = win;
280 }
281 }
282
283 // do we have any children at all?
284 if ( child )
285 {
286 // exactly one child - set it's size to fill the whole frame
287 int clientW, clientH;
288 DoGetClientSize(&clientW, &clientH);
289
290 // for whatever reasons, wxGTK wants to have a small offset - it
291 // probably looks better with it?
292 #ifdef __WXGTK__
293 static const int ofs = 1;
294 #else
295 static const int ofs = 0;
296 #endif
297
298 child->SetSize(ofs, ofs, clientW - 2*ofs, clientH - 2*ofs);
299 }
300 }
301 }
302
303 // The default implementation for the close window event.
304 void wxFrameBase::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
305 {
306 Destroy();
307 }
308
309 void wxFrameBase::OnMenuHighlight(wxMenuEvent& event)
310 {
311 #if wxUSE_STATUSBAR
312 (void)ShowMenuHelp(GetStatusBar(), event.GetMenuId());
313 #endif // wxUSE_STATUSBAR
314 }
315
316 bool wxFrameBase::SendIconizeEvent(bool iconized)
317 {
318 wxIconizeEvent event(GetId(), iconized);
319 event.SetEventObject(this);
320
321 return GetEventHandler()->ProcessEvent(event);
322 }
323
324 // ----------------------------------------------------------------------------
325 // status bar stuff
326 // ----------------------------------------------------------------------------
327
328 #if wxUSE_STATUSBAR
329
330 wxStatusBar* wxFrameBase::CreateStatusBar(int number,
331 long style,
332 wxWindowID id,
333 const wxString& name)
334 {
335 // the main status bar can only be created once (or else it should be
336 // deleted before calling CreateStatusBar() again)
337 wxCHECK_MSG( !m_frameStatusBar, (wxStatusBar *)NULL,
338 wxT("recreating status bar in wxFrame") );
339
340 m_frameStatusBar = OnCreateStatusBar( number, style, id, name );
341 if ( m_frameStatusBar )
342 PositionStatusBar();
343
344 return m_frameStatusBar;
345 }
346
347 wxStatusBar *wxFrameBase::OnCreateStatusBar(int number,
348 long style,
349 wxWindowID id,
350 const wxString& name)
351 {
352 wxStatusBar *statusBar = new wxStatusBar(this, id, style, name);
353
354 // Set the height according to the font and the border size
355 wxClientDC dc(statusBar);
356 dc.SetFont(statusBar->GetFont());
357
358 wxCoord y;
359 dc.GetTextExtent( "X", NULL, &y );
360
361 int height = (int)( (11*y)/10 + 2*statusBar->GetBorderY());
362
363 statusBar->SetSize( -1, -1, -1, height );
364
365 statusBar->SetFieldsCount(number);
366
367 return statusBar;
368 }
369
370 void wxFrameBase::SetStatusText(const wxString& text, int number)
371 {
372 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
373
374 m_frameStatusBar->SetStatusText(text, number);
375 }
376
377 void wxFrameBase::SetStatusWidths(int n, const int widths_field[] )
378 {
379 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set widths for") );
380
381 m_frameStatusBar->SetStatusWidths(n, widths_field);
382
383 PositionStatusBar();
384 }
385
386 bool wxFrameBase::ShowMenuHelp(wxStatusBar *statbar, int menuId)
387 {
388 #if wxUSE_MENUS
389 if ( !statbar )
390 return FALSE;
391
392 // if no help string found, we will clear the status bar text
393 wxString helpString;
394
395 if ( menuId != wxID_SEPARATOR && menuId != -2 /* wxID_TITLE */ )
396 {
397 wxMenuBar *menuBar = GetMenuBar();
398 if ( menuBar )
399 {
400 // it's ok if we don't find the item because it might belong
401 // to the popup menu
402 wxMenuItem *item = menuBar->FindItem(menuId);
403 if ( item )
404 helpString = item->GetHelp();
405 }
406 }
407
408 // set status text even if the string is empty - this will at least
409 // remove the string from the item which was previously selected
410 statbar->SetStatusText(helpString);
411
412 return !helpString.IsEmpty();
413 #else // !wxUSE_MENUS
414 return FALSE;
415 #endif // wxUSE_MENUS/!wxUSE_MENUS
416 }
417
418 #endif // wxUSE_STATUSBAR
419
420 // ----------------------------------------------------------------------------
421 // toolbar stuff
422 // ----------------------------------------------------------------------------
423
424 #if wxUSE_TOOLBAR
425
426 wxToolBar* wxFrameBase::CreateToolBar(long style,
427 wxWindowID id,
428 const wxString& name)
429 {
430 // the main toolbar can't be recreated (unless it was explicitly deeleted
431 // before)
432 wxCHECK_MSG( !m_frameToolBar, (wxToolBar *)NULL,
433 wxT("recreating toolbar in wxFrame") );
434
435 m_frameToolBar = OnCreateToolBar(style, id, name);
436
437 return m_frameToolBar;
438 }
439
440 wxToolBar* wxFrameBase::OnCreateToolBar(long style,
441 wxWindowID id,
442 const wxString& name)
443 {
444 return new wxToolBar(this, id,
445 wxDefaultPosition, wxDefaultSize,
446 style, name);
447 }
448
449 #endif // wxUSE_TOOLBAR
450
451 // ----------------------------------------------------------------------------
452 // Menu UI updating
453 // ----------------------------------------------------------------------------
454
455 void wxFrameBase::OnIdle(wxIdleEvent& WXUNUSED(event) )
456 {
457 #if wxUSE_MENUS
458 DoMenuUpdates();
459 #endif // wxUSE_MENUS
460 }
461
462 #if wxUSE_MENUS
463
464 // update all menus
465 void wxFrameBase::DoMenuUpdates()
466 {
467 wxMenuBar* bar = GetMenuBar();
468
469 #ifdef __WXMSW__
470 wxWindow* focusWin = wxFindFocusDescendant((wxWindow*) this);
471 #else
472 wxWindow* focusWin = (wxWindow*) NULL;
473 #endif
474 if ( bar != NULL )
475 {
476 int nCount = bar->GetMenuCount();
477 for (int n = 0; n < nCount; n++)
478 DoMenuUpdates(bar->GetMenu(n), focusWin);
479 }
480 }
481
482 // update a menu and all submenus recursively
483 void wxFrameBase::DoMenuUpdates(wxMenu* menu, wxWindow* focusWin)
484 {
485 wxEvtHandler* evtHandler = focusWin ? focusWin->GetEventHandler() : GetEventHandler();
486 wxMenuItemList::Node* node = menu->GetMenuItems().GetFirst();
487 while (node)
488 {
489 wxMenuItem* item = node->GetData();
490 if ( !item->IsSeparator() )
491 {
492 wxWindowID id = item->GetId();
493 wxUpdateUIEvent event(id);
494 event.SetEventObject( this );
495
496 if (evtHandler->ProcessEvent(event))
497 {
498 if (event.GetSetText())
499 menu->SetLabel(id, event.GetText());
500 if (event.GetSetChecked())
501 menu->Check(id, event.GetChecked());
502 if (event.GetSetEnabled())
503 menu->Enable(id, event.GetEnabled());
504 }
505
506 if (item->GetSubMenu())
507 DoMenuUpdates(item->GetSubMenu(), (wxWindow*) NULL);
508 }
509 node = node->GetNext();
510 }
511 }
512
513 #endif // wxUSE_MENUS