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