// Purpose: generic wxInfoBar implementation
// Author: Vadim Zeitlin
// Created: 2009-07-28
-// RCS-ID: $Id: wxhead.cpp,v 1.10 2009-06-29 10:23:04 zeitlin Exp $
+// RCS-ID: $Id$
// Copyright: (c) 2009 Vadim Zeitlin <vadim@wxwidgets.org>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#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/infobar.h"
-
#include "wx/artprov.h"
+#include "wx/renderer.h"
#include "wx/scopeguard.h"
-#include "wx/sizer.h"
+
+BEGIN_EVENT_TABLE(wxInfoBarGeneric, wxInfoBarBase)
+ EVT_BUTTON(wxID_ANY, wxInfoBarGeneric::OnButton)
+END_EVENT_TABLE()
+
+// ----------------------------------------------------------------------------
+// local helpers
+// ----------------------------------------------------------------------------
+
+namespace
+{
+
+#ifdef wxHAS_DRAW_TITLE_BAR_BITMAP
+
+wxBitmap
+GetCloseButtonBitmap(wxWindow *win,
+ const wxSize& size,
+ const wxColour& colBg,
+ int flags = 0)
+{
+ wxBitmap bmp(size);
+ wxMemoryDC dc(bmp);
+ dc.SetBackground(colBg);
+ dc.Clear();
+ wxRendererNative::Get().
+ DrawTitleBarBitmap(win, dc, size, wxTITLEBAR_BUTTON_CLOSE, flags);
+ return bmp;
+}
+
+#endif // wxHAS_DRAW_TITLE_BAR_BITMAP
+
+} // anonymous namespace
// ============================================================================
// implementation
m_text = NULL;
m_button = NULL;
- m_showEffect = wxSHOW_EFFECT_SLIDE_TO_BOTTOM;
- m_hideEffect = wxSHOW_EFFECT_SLIDE_TO_TOP;
+ m_showEffect =
+ m_hideEffect = wxSHOW_EFFECT_MAX;
// use default effect duration
m_effectDuration = 0;
return false;
// use special, easy to notice, colours
- SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK));
+ 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
// the icon is not shown unless it's assigned a valid bitmap
m_icon = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap);
- // by default, the text uses a larger, more noticeable, font
m_text = new wxStaticText(this, wxID_ANY, "");
- m_text->SetFont(m_text->GetFont().Bold().Larger());
+#ifdef wxHAS_DRAW_TITLE_BAR_BITMAP
+ const wxSize sizeBmp = wxArtProvider::GetSizeHint(wxART_BUTTON);
+ wxBitmap bmp = GetCloseButtonBitmap(this, sizeBmp, colBg);
+#else // !wxHAS_DRAW_TITLE_BAR_BITMAP
+ wxBitmap bmp = wxArtProvider::GetBitmap(wxART_CLOSE, wxART_BUTTON);
+#endif // wxHAS_DRAW_TITLE_BAR_BITMAP
m_button = new wxBitmapButton
(
this,
wxID_ANY,
- wxArtProvider::GetBitmap(wxART_CROSS_MARK),
+ bmp,
wxDefaultPosition,
wxDefaultSize,
wxBORDER_NONE
);
- m_button->SetToolTip(_("Hide this notification message."));
- Connect
- (
- wxEVT_COMMAND_BUTTON_CLICKED,
- wxCommandEventHandler(wxInfoBarGeneric::OnButton),
- NULL,
- this
- );
+#ifdef wxHAS_DRAW_TITLE_BAR_BITMAP
+ m_button->SetBitmapPressed(
+ GetCloseButtonBitmap(this, sizeBmp, colBg, wxCONTROL_PRESSED));
+
+ m_button->SetBitmapCurrent(
+ GetCloseButtonBitmap(this, sizeBmp, colBg, wxCONTROL_CURRENT));
+#endif // wxHAS_DRAW_TITLE_BAR_BITMAP
+
+ m_button->SetBackgroundColour(colBg);
+ 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_icon, wxSizerFlags().Centre().DoubleBorder());
- sizer->Add(m_text, wxSizerFlags().Centre().DoubleBorder());
- sizer->AddStretchSpacer();
- sizer->Add(m_button, wxSizerFlags().Centre().DoubleBorder());
+ sizer->Add(m_button, wxSizerFlags().Centre().Border());
SetSizer(sizer);
return true;
return true;
}
-void wxInfoBarGeneric::UpdateParent()
+wxInfoBarGeneric::BarPlacement wxInfoBarGeneric::GetBarPlacement() const
{
- wxWindow * const parent = wxGetTopLevelParent(GetParent());
- parent->Layout();
+ 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;
}
-void wxInfoBarGeneric::ChangeParentBackground()
+wxShowEffect wxInfoBarGeneric::GetShowEffect() const
{
- wxWindow * const parent = GetParent();
- m_origParentBgCol = parent->GetBackgroundColour();
-
- wxSizer * const sizer = GetContainingSizer();
- if ( !sizer )
- return;
+ if ( m_showEffect != wxSHOW_EFFECT_MAX )
+ return m_showEffect;
- wxWindow *sibling = NULL;
- for ( wxSizerItemList::compatibility_iterator
- node = sizer->GetChildren().GetFirst();
- node;
- node = node->GetNext() )
+ switch ( GetBarPlacement() )
{
- if ( node->GetData()->GetWindow() == this )
- {
- // find the next window following us
- for ( node = node->GetNext();
- node;
- node = node->GetNext() )
- {
- wxSizerItem * const item = node->GetData();
- if ( item->IsWindow() )
- {
- sibling = item->GetWindow();
- break;
- }
- }
+ case BarPlacement_Top:
+ return wxSHOW_EFFECT_SLIDE_TO_BOTTOM;
- break;
- }
+ 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;
- if ( sibling )
- parent->SetOwnBackgroundColour(sibling->GetBackgroundColour());
+ 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::RestoreParentBackground()
+void wxInfoBarGeneric::UpdateParent()
{
- GetParent()->SetOwnBackgroundColour(m_origParentBgCol);
+ wxWindow * const parent = GetParent();
+ parent->Layout();
}
void wxInfoBarGeneric::DoHide()
{
- ChangeParentBackground();
- wxON_BLOCK_EXIT_THIS0( wxInfoBarGeneric::RestoreParentBackground );
+ HideWithEffect(GetHideEffect(), GetEffectDuration());
- HideWithEffect(m_hideEffect, m_effectDuration);
UpdateParent();
}
// without really showing it
wxWindowBase::Show();
- // an extra hack: we want the temporarily uncovered area in which we're
- // going to expand to look like part of this sibling for a better effect so
- // temporarily change the background of our parent to the same colour
- ChangeParentBackground();
- wxON_BLOCK_EXIT_THIS0( wxInfoBarGeneric::RestoreParentBackground );
-
// adjust the parent layout to account for us
UpdateParent();
// finally do really show the window.
- ShowWithEffect(m_showEffect, m_effectDuration);
+ ShowWithEffect(GetShowEffect(), GetEffectDuration());
}
void wxInfoBarGeneric::ShowMessage(const wxString& msg, int flags)
}
else // do show an icon
{
- m_icon->SetBitmap(wxArtProvider::GetMessageBoxIcon(icon));
+ m_icon->SetBitmap(wxArtProvider::GetBitmap(
+ wxArtProvider::GetMessageBoxIconId(flags),
+ wxART_BUTTON));
m_icon->Show();
}
}
}
+void wxInfoBarGeneric::Dismiss()
+{
+ DoHide();
+}
+
void wxInfoBarGeneric::AddButton(wxWindowID btnid, const wxString& label)
{
wxSizer * const sizer = GetSizer();
wxCHECK_RET( sizer, "must be created first" );
- sizer->Insert(sizer->GetItemCount() - 2,
- new wxButton(this, btnid, label),
- wxSizerFlags().Centre().DoubleBorder());
+ // 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))