]> git.saurik.com Git - wxWidgets.git/blob - src/common/framecmn.cpp
8f3d81c6e4f2710ab7058f1722745d723cad00a4
[wxWidgets.git] / src / common / framecmn.cpp
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$
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
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 // XTI
57 // ----------------------------------------------------------------------------
58
59 wxDEFINE_FLAGS( wxFrameStyle )
60 wxBEGIN_FLAGS( wxFrameStyle )
61 // new style border flags, we put them first to
62 // use them for streaming out
63 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
64 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
65 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
66 wxFLAGS_MEMBER(wxBORDER_RAISED)
67 wxFLAGS_MEMBER(wxBORDER_STATIC)
68 wxFLAGS_MEMBER(wxBORDER_NONE)
69
70 // old style border flags
71 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
72 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
73 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
74 wxFLAGS_MEMBER(wxRAISED_BORDER)
75 wxFLAGS_MEMBER(wxSTATIC_BORDER)
76 wxFLAGS_MEMBER(wxBORDER)
77
78 // standard window styles
79 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
80 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
81 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
82 wxFLAGS_MEMBER(wxWANTS_CHARS)
83 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
84 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
85 wxFLAGS_MEMBER(wxVSCROLL)
86 wxFLAGS_MEMBER(wxHSCROLL)
87
88 // frame styles
89 wxFLAGS_MEMBER(wxSTAY_ON_TOP)
90 wxFLAGS_MEMBER(wxCAPTION)
91 #if WXWIN_COMPATIBILITY_2_6
92 wxFLAGS_MEMBER(wxTHICK_FRAME)
93 #endif // WXWIN_COMPATIBILITY_2_6
94 wxFLAGS_MEMBER(wxSYSTEM_MENU)
95 wxFLAGS_MEMBER(wxRESIZE_BORDER)
96 #if WXWIN_COMPATIBILITY_2_6
97 wxFLAGS_MEMBER(wxRESIZE_BOX)
98 #endif // WXWIN_COMPATIBILITY_2_6
99 wxFLAGS_MEMBER(wxCLOSE_BOX)
100 wxFLAGS_MEMBER(wxMAXIMIZE_BOX)
101 wxFLAGS_MEMBER(wxMINIMIZE_BOX)
102
103 wxFLAGS_MEMBER(wxFRAME_TOOL_WINDOW)
104 wxFLAGS_MEMBER(wxFRAME_FLOAT_ON_PARENT)
105
106 wxFLAGS_MEMBER(wxFRAME_SHAPED)
107 wxEND_FLAGS( wxFrameStyle )
108
109 wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxFrame, wxTopLevelWindow, "wx/frame.h")
110
111 wxBEGIN_PROPERTIES_TABLE(wxFrame)
112 wxEVENT_PROPERTY( Menu, wxEVT_COMMAND_MENU_SELECTED, wxCommandEvent)
113
114 wxPROPERTY( Title,wxString, SetTitle, GetTitle, wxString(), 0 /*flags*/, \
115 wxT("Helpstring"), wxT("group"))
116 wxPROPERTY_FLAGS( WindowStyle, wxFrameStyle, long, SetWindowStyleFlag, \
117 GetWindowStyleFlag, wxEMPTY_PARAMETER_VALUE, 0 /*flags*/, \
118 wxT("Helpstring"), wxT("group")) // style
119 wxPROPERTY( MenuBar, wxMenuBar *, SetMenuBar, GetMenuBar, wxEMPTY_PARAMETER_VALUE, \
120 0 /*flags*/, wxT("Helpstring"), wxT("group"))
121 wxEND_PROPERTIES_TABLE()
122
123 wxEMPTY_HANDLERS_TABLE(wxFrame)
124
125 wxCONSTRUCTOR_6( wxFrame, wxWindow*, Parent, wxWindowID, Id, wxString, Title, \
126 wxPoint, Position, wxSize, Size, long, WindowStyle)
127
128 // ----------------------------------------------------------------------------
129 // construction/destruction
130 // ----------------------------------------------------------------------------
131
132 wxFrameBase::wxFrameBase()
133 {
134 #if wxUSE_MENUS
135 m_frameMenuBar = NULL;
136 #endif // wxUSE_MENUS
137
138 #if wxUSE_TOOLBAR
139 m_frameToolBar = NULL;
140 #endif // wxUSE_TOOLBAR
141
142 #if wxUSE_STATUSBAR
143 m_frameStatusBar = NULL;
144 #endif // wxUSE_STATUSBAR
145
146 m_statusBarPane = 0;
147 }
148
149 wxFrameBase::~wxFrameBase()
150 {
151 // this destructor is required for Darwin
152 }
153
154 wxFrame *wxFrameBase::New(wxWindow *parent,
155 wxWindowID id,
156 const wxString& title,
157 const wxPoint& pos,
158 const wxSize& size,
159 long style,
160 const wxString& name)
161 {
162 return new wxFrame(parent, id, title, pos, size, style, name);
163 }
164
165 void wxFrameBase::DeleteAllBars()
166 {
167 #if wxUSE_MENUS
168 wxDELETE(m_frameMenuBar);
169 #endif // wxUSE_MENUS
170
171 #if wxUSE_STATUSBAR
172 wxDELETE(m_frameStatusBar);
173 #endif // wxUSE_STATUSBAR
174
175 #if wxUSE_TOOLBAR
176 wxDELETE(m_frameToolBar);
177 #endif // wxUSE_TOOLBAR
178 }
179
180 bool wxFrameBase::IsOneOfBars(const wxWindow *win) const
181 {
182 #if wxUSE_MENUS
183 if ( win == GetMenuBar() )
184 return true;
185 #endif // wxUSE_MENUS
186
187 #if wxUSE_STATUSBAR
188 if ( win == GetStatusBar() )
189 return true;
190 #endif // wxUSE_STATUSBAR
191
192 #if wxUSE_TOOLBAR
193 if ( win == GetToolBar() )
194 return true;
195 #endif // wxUSE_TOOLBAR
196
197 wxUnusedVar(win);
198
199 return false;
200 }
201
202 // ----------------------------------------------------------------------------
203 // wxFrame size management: we exclude the areas taken by menu/status/toolbars
204 // from the client area, so the client area is what's really available for the
205 // frame contents
206 // ----------------------------------------------------------------------------
207
208 // get the origin of the client area in the client coordinates
209 wxPoint wxFrameBase::GetClientAreaOrigin() const
210 {
211 wxPoint pt = wxTopLevelWindow::GetClientAreaOrigin();
212
213 #if wxUSE_TOOLBAR && !defined(__WXUNIVERSAL__)
214 wxToolBar *toolbar = GetToolBar();
215 if ( toolbar && toolbar->IsShown() )
216 {
217 int w, h;
218 toolbar->GetSize(&w, &h);
219
220 if ( toolbar->GetWindowStyleFlag() & wxTB_VERTICAL )
221 {
222 pt.x += w;
223 }
224 else
225 {
226 pt.y += h;
227 }
228 }
229 #endif // wxUSE_TOOLBAR
230
231 return pt;
232 }
233
234 // ----------------------------------------------------------------------------
235 // misc
236 // ----------------------------------------------------------------------------
237
238 #if wxUSE_MENUS
239
240 bool wxFrameBase::ProcessCommand(int id)
241 {
242 wxMenuBar *bar = GetMenuBar();
243 if ( !bar )
244 return false;
245
246 wxMenuItem *item = bar->FindItem(id);
247 if ( !item )
248 return false;
249
250 return ProcessCommand(item);
251 }
252
253 bool wxFrameBase::ProcessCommand(wxMenuItem *item)
254 {
255 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, item->GetId());
256 commandEvent.SetEventObject(this);
257
258 if (!item->IsEnabled())
259 return true;
260
261 if ((item->GetKind() == wxITEM_RADIO) && item->IsChecked() )
262 return true;
263
264 if (item->IsCheckable())
265 {
266 item->Toggle();
267
268 // use the new value
269 commandEvent.SetInt(item->IsChecked());
270 }
271
272 return HandleWindowEvent(commandEvent);
273 }
274
275 #endif // wxUSE_MENUS
276
277 // Do the UI update processing for this window. This is
278 // provided for the application to call if it wants to
279 // force a UI update, particularly for the menus and toolbar.
280 void wxFrameBase::UpdateWindowUI(long flags)
281 {
282 wxWindowBase::UpdateWindowUI(flags);
283
284 #if wxUSE_TOOLBAR
285 if (GetToolBar())
286 GetToolBar()->UpdateWindowUI(flags);
287 #endif
288
289 #if wxUSE_MENUS
290 if (GetMenuBar())
291 {
292 // If coming from an idle event, we only want to update the menus if
293 // we're in the wxUSE_IDLEMENUUPDATES configuration, otherwise they
294 // will be update when the menu is opened later
295 #if !wxUSE_IDLEMENUUPDATES
296 if ( !(flags & wxUPDATE_UI_FROMIDLE) )
297 #endif // wxUSE_IDLEMENUUPDATES
298 DoMenuUpdates();
299 }
300 #endif // wxUSE_MENUS
301 }
302
303 // ----------------------------------------------------------------------------
304 // event handlers for status bar updates from menus
305 // ----------------------------------------------------------------------------
306
307 #if wxUSE_MENUS && wxUSE_STATUSBAR
308
309 void wxFrameBase::OnMenuHighlight(wxMenuEvent& event)
310 {
311 #if wxUSE_STATUSBAR
312 (void)ShowMenuHelp(event.GetMenuId());
313 #endif // wxUSE_STATUSBAR
314 }
315
316 void wxFrameBase::OnMenuOpen(wxMenuEvent& event)
317 {
318 #if wxUSE_IDLEMENUUPDATES
319 wxUnusedVar(event);
320 #else // !wxUSE_IDLEMENUUPDATES
321 // as we didn't update the menus from idle time, do it now
322 DoMenuUpdates(event.GetMenu());
323 #endif // wxUSE_IDLEMENUUPDATES/!wxUSE_IDLEMENUUPDATES
324 }
325
326 void wxFrameBase::OnMenuClose(wxMenuEvent& WXUNUSED(event))
327 {
328 DoGiveHelp(wxEmptyString, false);
329 }
330
331 #endif // wxUSE_MENUS && wxUSE_STATUSBAR
332
333 // Implement internal behaviour (menu updating on some platforms)
334 void wxFrameBase::OnInternalIdle()
335 {
336 wxTopLevelWindow::OnInternalIdle();
337
338 #if wxUSE_MENUS && wxUSE_IDLEMENUUPDATES
339 if (wxUpdateUIEvent::CanUpdate(this))
340 DoMenuUpdates();
341 #endif
342 }
343
344 // ----------------------------------------------------------------------------
345 // status bar stuff
346 // ----------------------------------------------------------------------------
347
348 #if wxUSE_STATUSBAR
349
350 wxStatusBar* wxFrameBase::CreateStatusBar(int number,
351 long style,
352 wxWindowID id,
353 const wxString& name)
354 {
355 // the main status bar can only be created once (or else it should be
356 // deleted before calling CreateStatusBar() again)
357 wxCHECK_MSG( !m_frameStatusBar, NULL,
358 wxT("recreating status bar in wxFrame") );
359
360 SetStatusBar(OnCreateStatusBar(number, style, id, name));
361
362 return m_frameStatusBar;
363 }
364
365 wxStatusBar *wxFrameBase::OnCreateStatusBar(int number,
366 long style,
367 wxWindowID id,
368 const wxString& name)
369 {
370 wxStatusBar *statusBar = new wxStatusBar(this, id, style, name);
371
372 statusBar->SetFieldsCount(number);
373
374 return statusBar;
375 }
376
377 void wxFrameBase::SetStatusText(const wxString& text, int number)
378 {
379 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
380
381 m_frameStatusBar->SetStatusText(text, number);
382 }
383
384 void wxFrameBase::SetStatusWidths(int n, const int widths_field[] )
385 {
386 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set widths for") );
387
388 m_frameStatusBar->SetStatusWidths(n, widths_field);
389
390 PositionStatusBar();
391 }
392
393 void wxFrameBase::PushStatusText(const wxString& text, int number)
394 {
395 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
396
397 m_frameStatusBar->PushStatusText(text, number);
398 }
399
400 void wxFrameBase::PopStatusText(int number)
401 {
402 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
403
404 m_frameStatusBar->PopStatusText(number);
405 }
406
407 bool wxFrameBase::ShowMenuHelp(int menuId)
408 {
409 #if wxUSE_MENUS
410 // if no help string found, we will clear the status bar text
411 //
412 // NB: wxID_NONE is used for (sub)menus themselves by wxMSW
413 wxString helpString;
414 if ( menuId != wxID_SEPARATOR && menuId != wxID_NONE )
415 {
416 const wxMenuItem * const item = FindItemInMenuBar(menuId);
417 if ( item && !item->IsSeparator() )
418 helpString = item->GetHelp();
419
420 // notice that it's ok if we don't find the item because it might
421 // belong to the popup menu, so don't assert here
422 }
423
424 DoGiveHelp(helpString, true);
425
426 return !helpString.empty();
427 #else // !wxUSE_MENUS
428 return false;
429 #endif // wxUSE_MENUS/!wxUSE_MENUS
430 }
431
432 void wxFrameBase::SetStatusBar(wxStatusBar *statBar)
433 {
434 bool hadBar = m_frameStatusBar != NULL;
435 m_frameStatusBar = statBar;
436
437 if ( (m_frameStatusBar != NULL) != hadBar )
438 {
439 PositionStatusBar();
440
441 DoLayout();
442 }
443 }
444
445 #endif // wxUSE_STATUSBAR
446
447 #if wxUSE_MENUS || wxUSE_TOOLBAR
448 void wxFrameBase::DoGiveHelp(const wxString& help, bool show)
449 {
450 #if wxUSE_STATUSBAR
451 if ( m_statusBarPane < 0 )
452 {
453 // status bar messages disabled
454 return;
455 }
456
457 wxStatusBar *statbar = GetStatusBar();
458 if ( !statbar )
459 return;
460
461 wxString text;
462 if ( show )
463 {
464 // remember the old status bar text if this is the first time we're
465 // called since the menu has been opened as we're going to overwrite it
466 // in our DoGiveHelp() and we want to restore it when the menu is
467 // closed
468 //
469 // note that it would be logical to do this in OnMenuOpen() but under
470 // MSW we get an EVT_MENU_HIGHLIGHT before EVT_MENU_OPEN, strangely
471 // enough, and so this doesn't work and instead we use the ugly trick
472 // with using special m_oldStatusText value as "menu opened" (but it is
473 // arguably better than adding yet another member variable to wxFrame
474 // on all platforms)
475 if ( m_oldStatusText.empty() )
476 {
477 m_oldStatusText = statbar->GetStatusText(m_statusBarPane);
478 if ( m_oldStatusText.empty() )
479 {
480 // use special value to prevent us from doing this the next time
481 m_oldStatusText += wxT('\0');
482 }
483 }
484
485 m_lastHelpShown =
486 text = help;
487 }
488 else // hide help, restore the original text
489 {
490 // clear the last shown help string but remember its value
491 wxString lastHelpShown;
492 lastHelpShown.swap(m_lastHelpShown);
493
494 // also clear the old status text but remember it too to restore it
495 // below
496 text.swap(m_oldStatusText);
497
498 if ( statbar->GetStatusText(m_statusBarPane) != lastHelpShown )
499 {
500 // if the text was changed with an explicit SetStatusText() call
501 // from the user code in the meanwhile, do not overwrite it with
502 // the old status bar contents -- this is almost certainly not what
503 // the user expects and would be very hard to avoid from user code
504 return;
505 }
506 }
507
508 statbar->SetStatusText(text, m_statusBarPane);
509 #else
510 wxUnusedVar(help);
511 wxUnusedVar(show);
512 #endif // wxUSE_STATUSBAR
513 }
514 #endif // wxUSE_MENUS || wxUSE_TOOLBAR
515
516
517 // ----------------------------------------------------------------------------
518 // toolbar stuff
519 // ----------------------------------------------------------------------------
520
521 #if wxUSE_TOOLBAR
522
523 wxToolBar* wxFrameBase::CreateToolBar(long style,
524 wxWindowID id,
525 const wxString& name)
526 {
527 // the main toolbar can't be recreated (unless it was explicitly deleted
528 // before)
529 wxCHECK_MSG( !m_frameToolBar, NULL,
530 wxT("recreating toolbar in wxFrame") );
531
532 if ( style == -1 )
533 {
534 // use default style
535 //
536 // NB: we don't specify the default value in the method declaration
537 // because
538 // a) this allows us to have different defaults for different
539 // platforms (even if we don't have them right now)
540 // b) we don't need to include wx/toolbar.h in the header then
541 style = wxBORDER_NONE | wxTB_HORIZONTAL | wxTB_FLAT;
542 }
543
544 SetToolBar(OnCreateToolBar(style, id, name));
545
546 return m_frameToolBar;
547 }
548
549 wxToolBar* wxFrameBase::OnCreateToolBar(long style,
550 wxWindowID id,
551 const wxString& name)
552 {
553 #if defined(__WXWINCE__) && defined(__POCKETPC__)
554 return new wxToolMenuBar(this, id,
555 wxDefaultPosition, wxDefaultSize,
556 style, name);
557 #else
558 return new wxToolBar(this, id,
559 wxDefaultPosition, wxDefaultSize,
560 style, name);
561 #endif
562 }
563
564 void wxFrameBase::SetToolBar(wxToolBar *toolbar)
565 {
566 if ( (toolbar != NULL) != (m_frameToolBar != NULL) )
567 {
568 // the toolbar visibility must have changed so we need to both position
569 // the toolbar itself (if it appeared) and to relayout the frame
570 // contents in any case
571
572 if ( toolbar )
573 {
574 // we need to assign it to m_frameToolBar for PositionToolBar() to
575 // do anything
576 m_frameToolBar = toolbar;
577 PositionToolBar();
578 }
579 //else: tricky: do not reset m_frameToolBar yet as otherwise DoLayout()
580 // wouldn't recognize the (still existing) toolbar as one of our
581 // bars and wouldn't layout the single child of the frame correctly
582
583
584 // and this is even more tricky: we want DoLayout() to recognize the
585 // old toolbar for the purpose of not counting it among our non-bar
586 // children but we don't want to reserve any more space for it so we
587 // temporarily hide it
588 if ( m_frameToolBar )
589 m_frameToolBar->Hide();
590
591 DoLayout();
592
593 if ( m_frameToolBar )
594 m_frameToolBar->Show();
595 }
596
597 // this might have been already done above but it's simpler to just always
598 // do it unconditionally instead of testing for whether we already did it
599 m_frameToolBar = toolbar;
600 }
601
602 #endif // wxUSE_TOOLBAR
603
604 // ----------------------------------------------------------------------------
605 // menus
606 // ----------------------------------------------------------------------------
607
608 #if wxUSE_MENUS
609
610 // update all menus
611 void wxFrameBase::DoMenuUpdates(wxMenu* menu)
612 {
613 if (menu)
614 {
615 wxEvtHandler* source = GetEventHandler();
616 menu->UpdateUI(source);
617 }
618 else
619 {
620 wxMenuBar* bar = GetMenuBar();
621 if (bar != NULL)
622 bar->UpdateMenus();
623 }
624 }
625
626 void wxFrameBase::DetachMenuBar()
627 {
628 if ( m_frameMenuBar )
629 {
630 m_frameMenuBar->Detach();
631 m_frameMenuBar = NULL;
632 }
633 }
634
635 void wxFrameBase::AttachMenuBar(wxMenuBar *menubar)
636 {
637 if ( menubar )
638 {
639 menubar->Attach((wxFrame *)this);
640 m_frameMenuBar = menubar;
641 }
642 }
643
644 void wxFrameBase::SetMenuBar(wxMenuBar *menubar)
645 {
646 if ( menubar == GetMenuBar() )
647 {
648 // nothing to do
649 return;
650 }
651
652 DetachMenuBar();
653
654 this->AttachMenuBar(menubar);
655 }
656
657 wxMenuItem *wxFrameBase::FindItemInMenuBar(int menuId) const
658 {
659 const wxMenuBar * const menuBar = GetMenuBar();
660
661 return menuBar ? menuBar->FindItem(menuId) : NULL;
662 }
663
664 #endif // wxUSE_MENUS