]> git.saurik.com Git - wxWidgets.git/blob - src/common/framecmn.cpp
Applied patch [ 1378183 ] Mac: wxNotebook::HitTest off by one
[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 and Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #ifndef WX_PRECOMP
27 #include "wx/frame.h"
28 #include "wx/menu.h"
29 #include "wx/menuitem.h"
30 #include "wx/dcclient.h"
31 #endif // WX_PRECOMP
32
33 #if wxUSE_TOOLBAR
34 #include "wx/toolbar.h"
35 #endif
36 #if wxUSE_STATUSBAR
37 #include "wx/statusbr.h"
38 #endif
39
40 // ----------------------------------------------------------------------------
41 // event table
42 // ----------------------------------------------------------------------------
43
44 #if wxUSE_MENUS && wxUSE_STATUSBAR
45
46 BEGIN_EVENT_TABLE(wxFrameBase, wxTopLevelWindow)
47 EVT_MENU_OPEN(wxFrameBase::OnMenuOpen)
48 EVT_MENU_CLOSE(wxFrameBase::OnMenuClose)
49
50 EVT_MENU_HIGHLIGHT_ALL(wxFrameBase::OnMenuHighlight)
51 END_EVENT_TABLE()
52
53 #endif // wxUSE_MENUS && wxUSE_STATUSBAR
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 m_statusBarPane = 0;
78 }
79
80 wxFrameBase::~wxFrameBase()
81 {
82 // this destructor is required for Darwin
83 }
84
85 wxFrame *wxFrameBase::New(wxWindow *parent,
86 wxWindowID id,
87 const wxString& title,
88 const wxPoint& pos,
89 const wxSize& size,
90 long style,
91 const wxString& name)
92 {
93 return new wxFrame(parent, id, title, pos, size, style, name);
94 }
95
96 void wxFrameBase::DeleteAllBars()
97 {
98 #if wxUSE_MENUS
99 if ( m_frameMenuBar )
100 {
101 delete m_frameMenuBar;
102 m_frameMenuBar = (wxMenuBar *) NULL;
103 }
104 #endif // wxUSE_MENUS
105
106 #if wxUSE_STATUSBAR
107 if ( m_frameStatusBar )
108 {
109 delete m_frameStatusBar;
110 m_frameStatusBar = (wxStatusBar *) NULL;
111 }
112 #endif // wxUSE_STATUSBAR
113
114 #if wxUSE_TOOLBAR
115 if ( m_frameToolBar )
116 {
117 delete m_frameToolBar;
118 m_frameToolBar = (wxToolBar *) NULL;
119 }
120 #endif // wxUSE_TOOLBAR
121 }
122
123 bool wxFrameBase::IsOneOfBars(const wxWindow *win) const
124 {
125 #if wxUSE_MENUS
126 if ( win == GetMenuBar() )
127 return true;
128 #endif // wxUSE_MENUS
129
130 #if wxUSE_STATUSBAR
131 if ( win == GetStatusBar() )
132 return true;
133 #endif // wxUSE_STATUSBAR
134
135 #if wxUSE_TOOLBAR
136 if ( win == GetToolBar() )
137 return true;
138 #endif // wxUSE_TOOLBAR
139
140 return false;
141 }
142
143 // ----------------------------------------------------------------------------
144 // wxFrame size management: we exclude the areas taken by menu/status/toolbars
145 // from the client area, so the client area is what's really available for the
146 // frame contents
147 // ----------------------------------------------------------------------------
148
149 // get the origin of the client area in the client coordinates
150 wxPoint wxFrameBase::GetClientAreaOrigin() const
151 {
152 wxPoint pt = wxTopLevelWindow::GetClientAreaOrigin();
153
154 #if wxUSE_TOOLBAR && !defined(__WXUNIVERSAL__)
155 wxToolBar *toolbar = GetToolBar();
156 if ( toolbar && toolbar->IsShown() )
157 {
158 int w, h;
159 toolbar->GetSize(&w, &h);
160
161 if ( toolbar->GetWindowStyleFlag() & wxTB_VERTICAL )
162 {
163 pt.x += w;
164 }
165 else
166 {
167 pt.y += h;
168 }
169 }
170 #endif // wxUSE_TOOLBAR
171
172 return pt;
173 }
174
175
176 void wxFrameBase::SendSizeEvent()
177 {
178 wxSizeEvent event( GetSize(), GetId() );
179 event.SetEventObject( this );
180 GetEventHandler()->AddPendingEvent( event );
181 }
182
183
184 // ----------------------------------------------------------------------------
185 // misc
186 // ----------------------------------------------------------------------------
187
188 bool wxFrameBase::ProcessCommand(int id)
189 {
190 #if wxUSE_MENUS
191 wxMenuBar *bar = GetMenuBar();
192 if ( !bar )
193 return false;
194
195 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id);
196 commandEvent.SetEventObject(this);
197
198 wxMenuItem *item = bar->FindItem(id);
199 if (item)
200 {
201 if (!item->IsEnabled())
202 return true;
203
204 if ((item->GetKind() == wxITEM_RADIO) && item->IsChecked() )
205 return true;
206
207 if (item->IsCheckable())
208 {
209 item->Toggle();
210
211 // use the new value
212 commandEvent.SetInt(item->IsChecked());
213 }
214 }
215
216 GetEventHandler()->ProcessEvent(commandEvent);
217 return true;
218 #else // !wxUSE_MENUS
219 return false;
220 #endif // wxUSE_MENUS/!wxUSE_MENUS
221 }
222
223 // Do the UI update processing for this window. This is
224 // provided for the application to call if it wants to
225 // force a UI update, particularly for the menus and toolbar.
226 void wxFrameBase::UpdateWindowUI(long flags)
227 {
228 wxWindowBase::UpdateWindowUI(flags);
229
230 #if wxUSE_TOOLBAR
231 if (GetToolBar())
232 GetToolBar()->UpdateWindowUI(flags);
233 #endif
234
235 #if wxUSE_MENUS
236 if (GetMenuBar())
237 {
238 if ((flags & wxUPDATE_UI_FROMIDLE) && !wxUSE_IDLEMENUUPDATES)
239 {
240 // If coming from an idle event, we only
241 // want to update the menus if we're
242 // in the wxUSE_IDLEMENUUPDATES configuration:
243 // so if we're not, do nothing
244 }
245 else
246 DoMenuUpdates();
247 }
248 #endif // wxUSE_MENUS
249 }
250
251 // ----------------------------------------------------------------------------
252 // event handlers for status bar updates from menus
253 // ----------------------------------------------------------------------------
254
255 #if wxUSE_MENUS && wxUSE_STATUSBAR
256
257 void wxFrameBase::OnMenuHighlight(wxMenuEvent& event)
258 {
259 #if wxUSE_STATUSBAR
260 (void)ShowMenuHelp(GetStatusBar(), event.GetMenuId());
261 #endif // wxUSE_STATUSBAR
262 }
263
264 #if !wxUSE_IDLEMENUUPDATES
265 void wxFrameBase::OnMenuOpen(wxMenuEvent& event)
266 #else
267 void wxFrameBase::OnMenuOpen(wxMenuEvent& WXUNUSED(event))
268 #endif
269 {
270 #if !wxUSE_IDLEMENUUPDATES
271 DoMenuUpdates(event.GetMenu());
272 #endif // !wxUSE_IDLEMENUUPDATES
273 }
274
275 void wxFrameBase::OnMenuClose(wxMenuEvent& WXUNUSED(event))
276 {
277 // do we have real status text to restore?
278 if ( !m_oldStatusText.empty() )
279 {
280 if ( m_statusBarPane >= 0 )
281 {
282 wxStatusBar *statbar = GetStatusBar();
283 if ( statbar )
284 statbar->SetStatusText(m_oldStatusText, m_statusBarPane);
285 }
286
287 m_oldStatusText.clear();
288 }
289 }
290
291 #endif // wxUSE_MENUS && wxUSE_STATUSBAR
292
293 // Implement internal behaviour (menu updating on some platforms)
294 void wxFrameBase::OnInternalIdle()
295 {
296 wxTopLevelWindow::OnInternalIdle();
297
298 #if wxUSE_MENUS && wxUSE_IDLEMENUUPDATES
299 if (wxUpdateUIEvent::CanUpdate(this))
300 DoMenuUpdates();
301 #endif
302 }
303
304 // ----------------------------------------------------------------------------
305 // status bar stuff
306 // ----------------------------------------------------------------------------
307
308 #if wxUSE_STATUSBAR
309
310 wxStatusBar* wxFrameBase::CreateStatusBar(int number,
311 long style,
312 wxWindowID id,
313 const wxString& name)
314 {
315 // the main status bar can only be created once (or else it should be
316 // deleted before calling CreateStatusBar() again)
317 wxCHECK_MSG( !m_frameStatusBar, (wxStatusBar *)NULL,
318 wxT("recreating status bar in wxFrame") );
319
320 SetStatusBar(OnCreateStatusBar(number, style, id, name));
321
322 return m_frameStatusBar;
323 }
324
325 wxStatusBar *wxFrameBase::OnCreateStatusBar(int number,
326 long style,
327 wxWindowID id,
328 const wxString& name)
329 {
330 wxStatusBar *statusBar = new wxStatusBar(this, id, style, name);
331
332 statusBar->SetFieldsCount(number);
333
334 return statusBar;
335 }
336
337 void wxFrameBase::SetStatusText(const wxString& text, int number)
338 {
339 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
340
341 m_frameStatusBar->SetStatusText(text, number);
342 }
343
344 void wxFrameBase::SetStatusWidths(int n, const int widths_field[] )
345 {
346 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set widths for") );
347
348 m_frameStatusBar->SetStatusWidths(n, widths_field);
349
350 PositionStatusBar();
351 }
352
353 void wxFrameBase::PushStatusText(const wxString& text, int number)
354 {
355 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
356
357 m_frameStatusBar->PushStatusText(text, number);
358 }
359
360 void wxFrameBase::PopStatusText(int number)
361 {
362 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
363
364 m_frameStatusBar->PopStatusText(number);
365 }
366
367 bool wxFrameBase::ShowMenuHelp(wxStatusBar *WXUNUSED(statbar), int menuId)
368 {
369 #if wxUSE_MENUS
370 // if no help string found, we will clear the status bar text
371 wxString helpString;
372 bool show = menuId != wxID_SEPARATOR && menuId != -2 /* wxID_TITLE */;
373
374 if ( show )
375 {
376 wxMenuBar *menuBar = GetMenuBar();
377 if ( menuBar )
378 {
379 // it's ok if we don't find the item because it might belong
380 // to the popup menu
381 wxMenuItem *item = menuBar->FindItem(menuId);
382 if ( item )
383 helpString = item->GetHelp();
384 }
385 }
386
387 DoGiveHelp(helpString, show);
388
389 return !helpString.empty();
390 #else // !wxUSE_MENUS
391 return false;
392 #endif // wxUSE_MENUS/!wxUSE_MENUS
393 }
394
395 void wxFrameBase::SetStatusBar(wxStatusBar *statBar)
396 {
397 bool hadBar = m_frameStatusBar != NULL;
398 m_frameStatusBar = statBar;
399
400 if ( (m_frameStatusBar != NULL) != hadBar )
401 {
402 PositionStatusBar();
403
404 DoLayout();
405 }
406 }
407
408 #endif // wxUSE_STATUSBAR
409
410 void wxFrameBase::DoGiveHelp(const wxString& text, bool show)
411 {
412 #if wxUSE_STATUSBAR
413 if ( m_statusBarPane < 0 )
414 {
415 // status bar messages disabled
416 return;
417 }
418
419 wxStatusBar *statbar = GetStatusBar();
420 if ( !statbar )
421 return;
422
423 wxString help;
424 if ( show )
425 help = text;
426
427 // remember the old status bar text if this is the first time we're called
428 // since the menu has been opened as we're going to overwrite it in our
429 // DoGiveHelp() and we want to restore it when the menu is closed
430 //
431 // note that it would be logical to do this in OnMenuOpen() but under MSW
432 // we get an EVT_MENU_HIGHLIGHT before EVT_MENU_OPEN, strangely enough, and
433 // so this doesn't work and instead we use the ugly trick with using
434 // special m_oldStatusText value as "menu opened" (but it is arguably
435 // better than adding yet another member variable to wxFrame on all
436 // platforms)
437 if ( m_oldStatusText.empty() )
438 {
439 m_oldStatusText = statbar->GetStatusText(m_statusBarPane);
440 if ( m_oldStatusText.empty() )
441 {
442 // use special value to prevent us from doing this the next time
443 m_oldStatusText += _T('\0');
444 }
445 }
446
447 statbar->SetStatusText(help, m_statusBarPane);
448 #else
449 wxUnusedVar(text);
450 wxUnusedVar(show);
451 #endif // wxUSE_STATUSBAR
452 }
453
454
455 // ----------------------------------------------------------------------------
456 // toolbar stuff
457 // ----------------------------------------------------------------------------
458
459 #if wxUSE_TOOLBAR
460
461 wxToolBar* wxFrameBase::CreateToolBar(long style,
462 wxWindowID id,
463 const wxString& name)
464 {
465 // the main toolbar can't be recreated (unless it was explicitly deeleted
466 // before)
467 wxCHECK_MSG( !m_frameToolBar, (wxToolBar *)NULL,
468 wxT("recreating toolbar in wxFrame") );
469
470 if ( style == -1 )
471 {
472 // use default style
473 //
474 // NB: we don't specify the default value in the method declaration
475 // because
476 // a) this allows us to have different defaults for different
477 // platforms (even if we don't have them right now)
478 // b) we don't need to include wx/toolbar.h in the header then
479 style = wxBORDER_NONE | wxTB_HORIZONTAL | wxTB_FLAT;
480 }
481
482 SetToolBar(OnCreateToolBar(style, id, name));
483
484 return m_frameToolBar;
485 }
486
487 wxToolBar* wxFrameBase::OnCreateToolBar(long style,
488 wxWindowID id,
489 const wxString& name)
490 {
491 #if defined(__WXWINCE__) && defined(__POCKETPC__)
492 return new wxToolMenuBar(this, id,
493 wxDefaultPosition, wxDefaultSize,
494 style, name);
495 #else
496 return new wxToolBar(this, id,
497 wxDefaultPosition, wxDefaultSize,
498 style, name);
499 #endif
500 }
501
502 void wxFrameBase::SetToolBar(wxToolBar *toolbar)
503 {
504 bool hadBar = m_frameToolBar != NULL;
505 m_frameToolBar = toolbar;
506
507 if ( (m_frameToolBar != NULL) != hadBar )
508 {
509 PositionToolBar();
510
511 DoLayout();
512 }
513 }
514
515 #endif // wxUSE_TOOLBAR
516
517 // ----------------------------------------------------------------------------
518 // menus
519 // ----------------------------------------------------------------------------
520
521 #if wxUSE_MENUS
522
523 // update all menus
524 void wxFrameBase::DoMenuUpdates(wxMenu* menu)
525 {
526 if (menu)
527 {
528 wxEvtHandler* source = GetEventHandler();
529 menu->UpdateUI(source);
530 }
531 else
532 {
533 wxMenuBar* bar = GetMenuBar();
534 if (bar != NULL)
535 bar->UpdateMenus();
536 }
537 }
538
539 void wxFrameBase::DetachMenuBar()
540 {
541 if ( m_frameMenuBar )
542 {
543 m_frameMenuBar->Detach();
544 m_frameMenuBar = NULL;
545 }
546 }
547
548 void wxFrameBase::AttachMenuBar(wxMenuBar *menubar)
549 {
550 if ( menubar )
551 {
552 menubar->Attach((wxFrame *)this);
553 m_frameMenuBar = menubar;
554 }
555 }
556
557 void wxFrameBase::SetMenuBar(wxMenuBar *menubar)
558 {
559 if ( menubar == GetMenuBar() )
560 {
561 // nothing to do
562 return;
563 }
564
565 DetachMenuBar();
566
567 this->AttachMenuBar(menubar);
568 }
569
570 #endif // wxUSE_MENUS