Files
wxWidgets/src/generic/infobar.cpp
Vadim Zeitlin a68fb3fc38 Use the correct window as parent of wxInfoBar close button.
Fix breakage of r72474 that used the parent window instead of wxInfoBar itself
as the parent of its close button.

Closes #14750.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@72690 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2012-10-16 14:06:05 +00:00

322 lines
9.1 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/generic/infobar.cpp
// Purpose: generic wxInfoBar implementation
// Author: Vadim Zeitlin
// Created: 2009-07-28
// RCS-ID: $Id$
// Copyright: (c) 2009 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_INFOBAR
#include "wx/infobar.h"
#ifndef WX_PRECOMP
#include "wx/bmpbuttn.h"
#include "wx/button.h"
#include "wx/dcmemory.h"
#include "wx/settings.h"
#include "wx/statbmp.h"
#include "wx/stattext.h"
#include "wx/sizer.h"
#endif // WX_PRECOMP
#include "wx/artprov.h"
#include "wx/scopeguard.h"
BEGIN_EVENT_TABLE(wxInfoBarGeneric, wxInfoBarBase)
EVT_BUTTON(wxID_ANY, wxInfoBarGeneric::OnButton)
END_EVENT_TABLE()
// ============================================================================
// implementation
// ============================================================================
void wxInfoBarGeneric::Init()
{
m_icon = NULL;
m_text = NULL;
m_button = NULL;
m_showEffect =
m_hideEffect = wxSHOW_EFFECT_MAX;
// use default effect duration
m_effectDuration = 0;
}
bool wxInfoBarGeneric::Create(wxWindow *parent, wxWindowID winid)
{
// calling Hide() before Create() ensures that we're created initially
// hidden
Hide();
if ( !wxWindow::Create(parent, winid) )
return false;
// use special, easy to notice, colours
const wxColour colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK);
SetBackgroundColour(colBg);
SetOwnForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT));
// create the controls: icon, text and the button to dismiss the
// message.
// the icon is not shown unless it's assigned a valid bitmap
m_icon = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap);
m_text = new wxStaticText(this, wxID_ANY, "");
m_button = wxBitmapButton::NewCloseButton(this, wxID_ANY);
m_button->SetToolTip(_("Hide this notification message."));
// center the text inside the sizer with an icon to the left of it and a
// button at the very right
//
// NB: AddButton() relies on the button being the last control in the sizer
// and being preceded by a spacer
wxSizer * const sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(m_icon, wxSizerFlags().Centre().Border());
sizer->Add(m_text, wxSizerFlags().Centre());
sizer->AddStretchSpacer();
sizer->Add(m_button, wxSizerFlags().Centre().Border());
SetSizer(sizer);
return true;
}
bool wxInfoBarGeneric::SetFont(const wxFont& font)
{
if ( !wxInfoBarBase::SetFont(font) )
return false;
// check that we're not called before Create()
if ( m_text )
m_text->SetFont(font);
return true;
}
wxInfoBarGeneric::BarPlacement wxInfoBarGeneric::GetBarPlacement() const
{
wxSizer * const sizer = GetContainingSizer();
if ( !sizer )
return BarPlacement_Unknown;
// FIXME-VC6: can't compare "const wxInfoBarGeneric *" and "wxWindow *",
// so need this workaround
wxWindow * const self = const_cast<wxInfoBarGeneric *>(this);
const wxSizerItemList& siblings = sizer->GetChildren();
if ( siblings.GetFirst()->GetData()->GetWindow() == self )
return BarPlacement_Top;
else if ( siblings.GetLast()->GetData()->GetWindow() == self )
return BarPlacement_Bottom;
else
return BarPlacement_Unknown;
}
wxShowEffect wxInfoBarGeneric::GetShowEffect() const
{
if ( m_showEffect != wxSHOW_EFFECT_MAX )
return m_showEffect;
switch ( GetBarPlacement() )
{
case BarPlacement_Top:
return wxSHOW_EFFECT_SLIDE_TO_BOTTOM;
case BarPlacement_Bottom:
return wxSHOW_EFFECT_SLIDE_TO_TOP;
default:
wxFAIL_MSG( "unknown info bar placement" );
// fall through
case BarPlacement_Unknown:
return wxSHOW_EFFECT_NONE;
}
}
wxShowEffect wxInfoBarGeneric::GetHideEffect() const
{
if ( m_hideEffect != wxSHOW_EFFECT_MAX )
return m_hideEffect;
switch ( GetBarPlacement() )
{
case BarPlacement_Top:
return wxSHOW_EFFECT_SLIDE_TO_TOP;
case BarPlacement_Bottom:
return wxSHOW_EFFECT_SLIDE_TO_BOTTOM;
default:
wxFAIL_MSG( "unknown info bar placement" );
// fall through
case BarPlacement_Unknown:
return wxSHOW_EFFECT_NONE;
}
}
void wxInfoBarGeneric::UpdateParent()
{
wxWindow * const parent = GetParent();
parent->Layout();
}
void wxInfoBarGeneric::DoHide()
{
HideWithEffect(GetHideEffect(), GetEffectDuration());
UpdateParent();
}
void wxInfoBarGeneric::DoShow()
{
// re-layout the parent first so that the window expands into an already
// unoccupied by the other controls area: for this we need to change our
// internal visibility flag to force Layout() to take us into account (an
// alternative solution to this hack would be to temporarily set
// wxRESERVE_SPACE_EVEN_IF_HIDDEN flag but it's not really batter)
// just change the internal flag indicating that the window is visible,
// without really showing it
wxWindowBase::Show();
// adjust the parent layout to account for us
UpdateParent();
// reset the flag back before really showing the window or it wouldn't be
// shown at all because it would believe itself already visible
wxWindowBase::Show(false);
// finally do really show the window.
ShowWithEffect(GetShowEffect(), GetEffectDuration());
}
void wxInfoBarGeneric::ShowMessage(const wxString& msg, int flags)
{
// first update the controls
const int icon = flags & wxICON_MASK;
if ( !icon || (icon == wxICON_NONE) )
{
m_icon->Hide();
}
else // do show an icon
{
m_icon->SetBitmap(wxArtProvider::GetBitmap(
wxArtProvider::GetMessageBoxIconId(flags),
wxART_BUTTON));
m_icon->Show();
}
// notice the use of EscapeMnemonics() to ensure that "&" come through
// correctly
m_text->SetLabel(wxControl::EscapeMnemonics(msg));
// then show this entire window if not done yet
if ( !IsShown() )
{
DoShow();
}
else // we're already shown
{
// just update the layout to correspond to the new message
Layout();
}
}
void wxInfoBarGeneric::Dismiss()
{
DoHide();
}
void wxInfoBarGeneric::AddButton(wxWindowID btnid, const wxString& label)
{
wxSizer * const sizer = GetSizer();
wxCHECK_RET( sizer, "must be created first" );
// user-added buttons replace the standard close button so remove it if we
// hadn't done it yet
if ( sizer->Detach(m_button) )
{
m_button->Hide();
}
wxButton * const button = new wxButton(this, btnid, label);
#ifdef __WXMAC__
// smaller buttons look better in the (narrow) info bar under OS X
button->SetWindowVariant(wxWINDOW_VARIANT_SMALL);
#endif // __WXMAC__
sizer->Add(button, wxSizerFlags().Centre().DoubleBorder());
}
void wxInfoBarGeneric::RemoveButton(wxWindowID btnid)
{
wxSizer * const sizer = GetSizer();
wxCHECK_RET( sizer, "must be created first" );
// iterate over the sizer items in reverse order to find the last added
// button with this id (ids of all buttons should be unique anyhow but if
// they are repeated removing the last added one probably makes more sense)
const wxSizerItemList& items = sizer->GetChildren();
for ( wxSizerItemList::compatibility_iterator node = items.GetLast();
node != items.GetFirst();
node = node->GetPrevious() )
{
const wxSizerItem * const item = node->GetData();
// if we reached the spacer separating the buttons from the text
// preceding them without finding our button, it must mean it's not
// there at all
if ( item->IsSpacer() )
{
wxFAIL_MSG( wxString::Format("button with id %d not found", btnid) );
return;
}
// check if we found our button
if ( item->GetWindow()->GetId() == btnid )
{
delete item->GetWindow();
break;
}
}
// check if there are any custom buttons left
if ( sizer->GetChildren().GetLast()->GetData()->IsSpacer() )
{
// if the last item is the spacer, none are left so restore the
// standard close button
sizer->Add(m_button, wxSizerFlags().Centre().DoubleBorder());
m_button->Show();
}
}
void wxInfoBarGeneric::OnButton(wxCommandEvent& WXUNUSED(event))
{
DoHide();
}
#endif // wxUSE_INFOBAR