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