Files
wxWidgets/src/common/framecmn.cpp
Vadim Zeitlin e1655f5394 Stop duplicating wxFrame dtor in all ports.
wxGTK1, wxGTK, wxMSW and wxOSX all did the same thing in their wxFrame dtor,
so just do it in wxFrameBase instead.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@76804 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2014-07-02 13:28:29 +00:00

684 lines
19 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/common/framecmn.cpp
// Purpose: common (for all platforms) wxFrame functions
// Author: Julian Smart, Vadim Zeitlin
// Created: 01/02/97
// Copyright: (c) 1998 Robert Roebling and Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include "wx/frame.h"
#ifndef WX_PRECOMP
#include "wx/app.h"
#include "wx/menu.h"
#include "wx/menuitem.h"
#include "wx/dcclient.h"
#include "wx/toolbar.h"
#include "wx/statusbr.h"
#endif // WX_PRECOMP
extern WXDLLEXPORT_DATA(const char) wxFrameNameStr[] = "frame";
extern WXDLLEXPORT_DATA(const char) wxStatusLineNameStr[] = "status_line";
// ----------------------------------------------------------------------------
// event table
// ----------------------------------------------------------------------------
#if wxUSE_MENUS
#if wxUSE_STATUSBAR
BEGIN_EVENT_TABLE(wxFrameBase, wxTopLevelWindow)
EVT_MENU_OPEN(wxFrameBase::OnMenuOpen)
EVT_MENU_CLOSE(wxFrameBase::OnMenuClose)
EVT_MENU_HIGHLIGHT_ALL(wxFrameBase::OnMenuHighlight)
END_EVENT_TABLE()
#endif // wxUSE_STATUSBAR
/* static */
bool wxFrameBase::ShouldUpdateMenuFromIdle()
{
// Usually this is determined at compile time and is determined by whether
// the platform supports wxEVT_MENU_OPEN, however in wxGTK we need to also
// check if we're using the global menu bar as we don't get EVT_MENU_OPEN
// for it and need to fall back to idle time updating even if normally
// wxUSE_IDLEMENUUPDATES is set to 0 for wxGTK.
#ifdef __WXGTK20__
if ( wxApp::GTKIsUsingGlobalMenu() )
return true;
#endif // !__WXGTK__
return wxUSE_IDLEMENUUPDATES != 0;
}
#endif // wxUSE_MENUS
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// XTI
// ----------------------------------------------------------------------------
wxDEFINE_FLAGS( wxFrameStyle )
wxBEGIN_FLAGS( wxFrameStyle )
// new style border flags, we put them first to
// use them for streaming out
wxFLAGS_MEMBER(wxBORDER_SIMPLE)
wxFLAGS_MEMBER(wxBORDER_SUNKEN)
wxFLAGS_MEMBER(wxBORDER_DOUBLE)
wxFLAGS_MEMBER(wxBORDER_RAISED)
wxFLAGS_MEMBER(wxBORDER_STATIC)
wxFLAGS_MEMBER(wxBORDER_NONE)
// old style border flags
wxFLAGS_MEMBER(wxSIMPLE_BORDER)
wxFLAGS_MEMBER(wxSUNKEN_BORDER)
wxFLAGS_MEMBER(wxDOUBLE_BORDER)
wxFLAGS_MEMBER(wxRAISED_BORDER)
wxFLAGS_MEMBER(wxSTATIC_BORDER)
wxFLAGS_MEMBER(wxBORDER)
// standard window styles
wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
wxFLAGS_MEMBER(wxCLIP_CHILDREN)
wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
wxFLAGS_MEMBER(wxWANTS_CHARS)
wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
wxFLAGS_MEMBER(wxVSCROLL)
wxFLAGS_MEMBER(wxHSCROLL)
// frame styles
wxFLAGS_MEMBER(wxSTAY_ON_TOP)
wxFLAGS_MEMBER(wxCAPTION)
wxFLAGS_MEMBER(wxSYSTEM_MENU)
wxFLAGS_MEMBER(wxRESIZE_BORDER)
wxFLAGS_MEMBER(wxCLOSE_BOX)
wxFLAGS_MEMBER(wxMAXIMIZE_BOX)
wxFLAGS_MEMBER(wxMINIMIZE_BOX)
wxFLAGS_MEMBER(wxFRAME_TOOL_WINDOW)
wxFLAGS_MEMBER(wxFRAME_FLOAT_ON_PARENT)
wxFLAGS_MEMBER(wxFRAME_SHAPED)
wxEND_FLAGS( wxFrameStyle )
wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxFrame, wxTopLevelWindow, "wx/frame.h")
wxBEGIN_PROPERTIES_TABLE(wxFrame)
wxEVENT_PROPERTY( Menu, wxEVT_MENU, wxCommandEvent)
wxPROPERTY( Title,wxString, SetTitle, GetTitle, wxString(), 0 /*flags*/, \
wxT("Helpstring"), wxT("group"))
wxPROPERTY_FLAGS( WindowStyle, wxFrameStyle, long, SetWindowStyleFlag, \
GetWindowStyleFlag, wxEMPTY_PARAMETER_VALUE, 0 /*flags*/, \
wxT("Helpstring"), wxT("group")) // style
#if wxUSE_MENUS
wxPROPERTY( MenuBar, wxMenuBar *, SetMenuBar, GetMenuBar, wxEMPTY_PARAMETER_VALUE, \
0 /*flags*/, wxT("Helpstring"), wxT("group"))
#endif
wxEND_PROPERTIES_TABLE()
wxEMPTY_HANDLERS_TABLE(wxFrame)
wxCONSTRUCTOR_6( wxFrame, wxWindow*, Parent, wxWindowID, Id, wxString, Title, \
wxPoint, Position, wxSize, Size, long, WindowStyle)
// ----------------------------------------------------------------------------
// construction/destruction
// ----------------------------------------------------------------------------
wxFrameBase::wxFrameBase()
{
#if wxUSE_MENUS
m_frameMenuBar = NULL;
#endif // wxUSE_MENUS
#if wxUSE_TOOLBAR
m_frameToolBar = NULL;
#endif // wxUSE_TOOLBAR
#if wxUSE_STATUSBAR
m_frameStatusBar = NULL;
#endif // wxUSE_STATUSBAR
m_statusBarPane = 0;
}
wxFrameBase::~wxFrameBase()
{
SendDestroyEvent();
DeleteAllBars();
}
wxFrame *wxFrameBase::New(wxWindow *parent,
wxWindowID id,
const wxString& title,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name)
{
return new wxFrame(parent, id, title, pos, size, style, name);
}
void wxFrameBase::DeleteAllBars()
{
#if wxUSE_MENUS
wxDELETE(m_frameMenuBar);
#endif // wxUSE_MENUS
#if wxUSE_STATUSBAR
wxDELETE(m_frameStatusBar);
#endif // wxUSE_STATUSBAR
#if wxUSE_TOOLBAR
wxDELETE(m_frameToolBar);
#endif // wxUSE_TOOLBAR
}
bool wxFrameBase::IsOneOfBars(const wxWindow *win) const
{
#if wxUSE_MENUS
if ( win == GetMenuBar() )
return true;
#endif // wxUSE_MENUS
#if wxUSE_STATUSBAR
if ( win == GetStatusBar() )
return true;
#endif // wxUSE_STATUSBAR
#if wxUSE_TOOLBAR
if ( win == GetToolBar() )
return true;
#endif // wxUSE_TOOLBAR
wxUnusedVar(win);
return false;
}
// ----------------------------------------------------------------------------
// wxFrame size management: we exclude the areas taken by menu/status/toolbars
// from the client area, so the client area is what's really available for the
// frame contents
// ----------------------------------------------------------------------------
// get the origin of the client area in the client coordinates
wxPoint wxFrameBase::GetClientAreaOrigin() const
{
wxPoint pt = wxTopLevelWindow::GetClientAreaOrigin();
#if wxUSE_TOOLBAR && !defined(__WXUNIVERSAL__)
wxToolBar *toolbar = GetToolBar();
if ( toolbar && toolbar->IsShown() )
{
int w, h;
toolbar->GetSize(&w, &h);
if ( toolbar->GetWindowStyleFlag() & wxTB_VERTICAL )
{
pt.x += w;
}
else
{
pt.y += h;
}
}
#endif // wxUSE_TOOLBAR
return pt;
}
// ----------------------------------------------------------------------------
// misc
// ----------------------------------------------------------------------------
#if wxUSE_MENUS
bool wxFrameBase::ProcessCommand(int id)
{
wxMenuItem* const item = FindItemInMenuBar(id);
if ( !item )
return false;
return ProcessCommand(item);
}
bool wxFrameBase::ProcessCommand(wxMenuItem *item)
{
wxCHECK_MSG( item, false, wxS("Menu item can't be NULL") );
if (!item->IsEnabled())
return true;
if ((item->GetKind() == wxITEM_RADIO) && item->IsChecked() )
return true;
int checked;
if (item->IsCheckable())
{
item->Toggle();
// use the new value
checked = item->IsChecked();
}
else // Uncheckable item.
{
checked = -1;
}
wxMenu* const menu = item->GetMenu();
wxCHECK_MSG( menu, false, wxS("Menu item should be attached to a menu") );
return menu->SendEvent(item->GetId(), checked);
}
#endif // wxUSE_MENUS
// Do the UI update processing for this window. This is
// provided for the application to call if it wants to
// force a UI update, particularly for the menus and toolbar.
void wxFrameBase::UpdateWindowUI(long flags)
{
wxWindowBase::UpdateWindowUI(flags);
#if wxUSE_TOOLBAR
if (GetToolBar())
GetToolBar()->UpdateWindowUI(flags);
#endif
#if wxUSE_MENUS
if (GetMenuBar())
{
// If coming from an idle event, we only want to update the menus if
// we're in the wxUSE_IDLEMENUUPDATES configuration, otherwise they
// will be update when the menu is opened later
if ( !(flags & wxUPDATE_UI_FROMIDLE) || ShouldUpdateMenuFromIdle() )
DoMenuUpdates();
}
#endif // wxUSE_MENUS
}
// ----------------------------------------------------------------------------
// event handlers for status bar updates from menus
// ----------------------------------------------------------------------------
#if wxUSE_MENUS && wxUSE_STATUSBAR
void wxFrameBase::OnMenuHighlight(wxMenuEvent& event)
{
#if wxUSE_STATUSBAR
(void)ShowMenuHelp(event.GetMenuId());
#endif // wxUSE_STATUSBAR
}
void wxFrameBase::OnMenuOpen(wxMenuEvent& event)
{
if ( !ShouldUpdateMenuFromIdle() )
{
// as we didn't update the menus from idle time, do it now
DoMenuUpdates(event.GetMenu());
}
}
void wxFrameBase::OnMenuClose(wxMenuEvent& WXUNUSED(event))
{
DoGiveHelp(wxEmptyString, false);
}
#endif // wxUSE_MENUS && wxUSE_STATUSBAR
// Implement internal behaviour (menu updating on some platforms)
void wxFrameBase::OnInternalIdle()
{
wxTopLevelWindow::OnInternalIdle();
#if wxUSE_MENUS
if ( ShouldUpdateMenuFromIdle() && wxUpdateUIEvent::CanUpdate(this) )
DoMenuUpdates();
#endif
}
// ----------------------------------------------------------------------------
// status bar stuff
// ----------------------------------------------------------------------------
#if wxUSE_STATUSBAR
wxStatusBar* wxFrameBase::CreateStatusBar(int number,
long style,
wxWindowID id,
const wxString& name)
{
// the main status bar can only be created once (or else it should be
// deleted before calling CreateStatusBar() again)
wxCHECK_MSG( !m_frameStatusBar, NULL,
wxT("recreating status bar in wxFrame") );
SetStatusBar(OnCreateStatusBar(number, style, id, name));
return m_frameStatusBar;
}
wxStatusBar *wxFrameBase::OnCreateStatusBar(int number,
long style,
wxWindowID id,
const wxString& name)
{
wxStatusBar *statusBar = new wxStatusBar(this, id, style, name);
statusBar->SetFieldsCount(number);
return statusBar;
}
void wxFrameBase::SetStatusText(const wxString& text, int number)
{
wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
m_frameStatusBar->SetStatusText(text, number);
}
void wxFrameBase::SetStatusWidths(int n, const int widths_field[] )
{
wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set widths for") );
m_frameStatusBar->SetStatusWidths(n, widths_field);
PositionStatusBar();
}
void wxFrameBase::PushStatusText(const wxString& text, int number)
{
wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
m_frameStatusBar->PushStatusText(text, number);
}
void wxFrameBase::PopStatusText(int number)
{
wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
m_frameStatusBar->PopStatusText(number);
}
bool wxFrameBase::ShowMenuHelp(int menuId)
{
#if wxUSE_MENUS
// if no help string found, we will clear the status bar text
//
// NB: wxID_NONE is used for (sub)menus themselves by wxMSW
wxString helpString;
if ( menuId != wxID_SEPARATOR && menuId != wxID_NONE )
{
const wxMenuItem * const item = FindItemInMenuBar(menuId);
if ( item && !item->IsSeparator() )
helpString = item->GetHelp();
// notice that it's ok if we don't find the item because it might
// belong to the popup menu, so don't assert here
}
DoGiveHelp(helpString, true);
return !helpString.empty();
#else // !wxUSE_MENUS
return false;
#endif // wxUSE_MENUS/!wxUSE_MENUS
}
void wxFrameBase::SetStatusBar(wxStatusBar *statBar)
{
bool hadBar = m_frameStatusBar != NULL;
m_frameStatusBar = statBar;
if ( (m_frameStatusBar != NULL) != hadBar )
{
PositionStatusBar();
DoLayout();
}
}
#endif // wxUSE_STATUSBAR
#if wxUSE_MENUS || wxUSE_TOOLBAR
void wxFrameBase::DoGiveHelp(const wxString& help, bool show)
{
#if wxUSE_STATUSBAR
if ( m_statusBarPane < 0 )
{
// status bar messages disabled
return;
}
wxStatusBar *statbar = GetStatusBar();
if ( !statbar )
return;
wxString text;
if ( show )
{
// remember the old status bar text if this is the first time we're
// called since the menu has been opened as we're going to overwrite it
// in our DoGiveHelp() and we want to restore it when the menu is
// closed
//
// note that it would be logical to do this in OnMenuOpen() but under
// MSW we get an EVT_MENU_HIGHLIGHT before EVT_MENU_OPEN, strangely
// enough, and so this doesn't work and instead we use the ugly trick
// with using special m_oldStatusText value as "menu opened" (but it is
// arguably better than adding yet another member variable to wxFrame
// on all platforms)
if ( m_oldStatusText.empty() )
{
m_oldStatusText = statbar->GetStatusText(m_statusBarPane);
if ( m_oldStatusText.empty() )
{
// use special value to prevent us from doing this the next time
m_oldStatusText += wxT('\0');
}
}
m_lastHelpShown =
text = help;
}
else // hide help, restore the original text
{
// clear the last shown help string but remember its value
wxString lastHelpShown;
lastHelpShown.swap(m_lastHelpShown);
// also clear the old status text but remember it too to restore it
// below
text.swap(m_oldStatusText);
if ( statbar->GetStatusText(m_statusBarPane) != lastHelpShown )
{
// if the text was changed with an explicit SetStatusText() call
// from the user code in the meanwhile, do not overwrite it with
// the old status bar contents -- this is almost certainly not what
// the user expects and would be very hard to avoid from user code
return;
}
}
statbar->SetStatusText(text, m_statusBarPane);
#else
wxUnusedVar(help);
wxUnusedVar(show);
#endif // wxUSE_STATUSBAR
}
#endif // wxUSE_MENUS || wxUSE_TOOLBAR
// ----------------------------------------------------------------------------
// toolbar stuff
// ----------------------------------------------------------------------------
#if wxUSE_TOOLBAR
wxToolBar* wxFrameBase::CreateToolBar(long style,
wxWindowID id,
const wxString& name)
{
// the main toolbar can't be recreated (unless it was explicitly deleted
// before)
wxCHECK_MSG( !m_frameToolBar, NULL,
wxT("recreating toolbar in wxFrame") );
if ( style == -1 )
{
// use default style
//
// NB: we don't specify the default value in the method declaration
// because
// a) this allows us to have different defaults for different
// platforms (even if we don't have them right now)
// b) we don't need to include wx/toolbar.h in the header then
style = wxTB_DEFAULT_STYLE;
}
SetToolBar(OnCreateToolBar(style, id, name));
return m_frameToolBar;
}
wxToolBar* wxFrameBase::OnCreateToolBar(long style,
wxWindowID id,
const wxString& name)
{
#if defined(__WXWINCE__) && defined(__POCKETPC__)
return new wxToolMenuBar(this, id,
wxDefaultPosition, wxDefaultSize,
style, name);
#else
return new wxToolBar(this, id,
wxDefaultPosition, wxDefaultSize,
style, name);
#endif
}
void wxFrameBase::SetToolBar(wxToolBar *toolbar)
{
if ( (toolbar != NULL) != (m_frameToolBar != NULL) )
{
// the toolbar visibility must have changed so we need to both position
// the toolbar itself (if it appeared) and to relayout the frame
// contents in any case
if ( toolbar )
{
// we need to assign it to m_frameToolBar for PositionToolBar() to
// do anything
m_frameToolBar = toolbar;
PositionToolBar();
}
//else: tricky: do not reset m_frameToolBar yet as otherwise DoLayout()
// wouldn't recognize the (still existing) toolbar as one of our
// bars and wouldn't layout the single child of the frame correctly
// and this is even more tricky: we want DoLayout() to recognize the
// old toolbar for the purpose of not counting it among our non-bar
// children but we don't want to reserve any more space for it so we
// temporarily hide it
if ( m_frameToolBar )
m_frameToolBar->Hide();
DoLayout();
if ( m_frameToolBar )
m_frameToolBar->Show();
}
// this might have been already done above but it's simpler to just always
// do it unconditionally instead of testing for whether we already did it
m_frameToolBar = toolbar;
}
#endif // wxUSE_TOOLBAR
// ----------------------------------------------------------------------------
// menus
// ----------------------------------------------------------------------------
#if wxUSE_MENUS
// update all menus
void wxFrameBase::DoMenuUpdates(wxMenu* menu)
{
if (menu)
{
wxEvtHandler* source = GetEventHandler();
menu->UpdateUI(source);
}
else
{
wxMenuBar* bar = GetMenuBar();
if (bar != NULL)
bar->UpdateMenus();
}
}
void wxFrameBase::DetachMenuBar()
{
if ( m_frameMenuBar )
{
m_frameMenuBar->Detach();
m_frameMenuBar = NULL;
}
}
void wxFrameBase::AttachMenuBar(wxMenuBar *menubar)
{
if ( menubar )
{
menubar->Attach((wxFrame *)this);
m_frameMenuBar = menubar;
}
}
void wxFrameBase::SetMenuBar(wxMenuBar *menubar)
{
if ( menubar == GetMenuBar() )
{
// nothing to do
return;
}
DetachMenuBar();
this->AttachMenuBar(menubar);
}
wxMenuItem *wxFrameBase::FindItemInMenuBar(int menuId) const
{
const wxMenuBar * const menuBar = GetMenuBar();
return menuBar ? menuBar->FindItem(menuId) : NULL;
}
#endif // wxUSE_MENUS