Files
wxWidgets/src/gtk/infobar.cpp
Igor Korot 32d8b5954a Wrap label if necessary in wxInfoBar in wxGTK
Also update the sample to test showing an overlong message in wxInfoBar.

Closes https://github.com/wxWidgets/wxWidgets/pull/1443

See #14121.
2019-08-05 13:50:11 +02:00

347 lines
9.4 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/gtk/infobar.cpp
// Purpose: wxInfoBar implementation for GTK
// Author: Vadim Zeitlin
// Created: 2009-09-27
// 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
#include "wx/infobar.h"
#if wxUSE_INFOBAR && defined(wxHAS_NATIVE_INFOBAR)
#ifndef WX_PRECOMP
#endif // WX_PRECOMP
#include "wx/vector.h"
#include "wx/stockitem.h"
#include "wx/gtk/private.h"
#include "wx/gtk/private/messagetype.h"
#include "wx/gtk/private/mnemonics.h"
// ----------------------------------------------------------------------------
// local classes
// ----------------------------------------------------------------------------
class wxInfoBarGTKImpl
{
public:
wxInfoBarGTKImpl()
{
m_label = NULL;
m_close = NULL;
}
// label for the text shown in the bar
GtkWidget *m_label;
// the default close button, NULL if not needed (m_buttons is not empty) or
// not created yet
GtkWidget *m_close;
// information about the buttons added using AddButton()
struct Button
{
Button(GtkWidget *button_, int id_)
: button(button_),
id(id_)
{
}
GtkWidget *button;
int id;
};
typedef wxVector<Button> Buttons;
Buttons m_buttons;
};
// ----------------------------------------------------------------------------
// local functions
// ----------------------------------------------------------------------------
namespace
{
inline bool UseNative()
{
// native GtkInfoBar widget is only available in GTK+ 2.18 and later
return wx_is_at_least_gtk2(18);
}
} // anonymous namespace
extern "C"
{
static void wxgtk_infobar_response(GtkInfoBar * WXUNUSED(infobar),
gint btnid,
wxInfoBar *win)
{
win->GTKResponse(btnid);
}
static void wxgtk_infobar_close(GtkInfoBar * WXUNUSED(infobar),
wxInfoBar *win)
{
win->GTKResponse(wxID_CANCEL);
}
} // extern "C" section with GTK+ callbacks
// ============================================================================
// wxInfoBar implementation
// ============================================================================
bool wxInfoBar::Create(wxWindow *parent, wxWindowID winid)
{
if ( !UseNative() )
return wxInfoBarGeneric::Create(parent, winid);
m_impl = new wxInfoBarGTKImpl;
// this control is created initially hidden
Hide();
if ( !CreateBase(parent, winid) )
return false;
// create the info bar widget itself
m_widget = gtk_info_bar_new();
wxCHECK_MSG( m_widget, false, "failed to create GtkInfoBar" );
g_object_ref(m_widget);
// also create a label which will be used to show our message
m_impl->m_label = gtk_label_new("");
gtk_widget_show(m_impl->m_label);
GtkWidget * const
contentArea = gtk_info_bar_get_content_area(GTK_INFO_BAR(m_widget));
wxCHECK_MSG( contentArea, false, "failed to get GtkInfoBar content area" );
gtk_container_add(GTK_CONTAINER(contentArea), m_impl->m_label);
// finish creation and connect to all the signals we're interested in
m_parent->DoAddChild(this);
PostCreation(wxDefaultSize);
GTKConnectWidget("response", G_CALLBACK(wxgtk_infobar_response));
GTKConnectWidget("close", G_CALLBACK(wxgtk_infobar_close));
// Work around GTK+ bug https://bugzilla.gnome.org/show_bug.cgi?id=710888
// by disabling the transition when showing it: without this, it's not
// shown at all.
//
// Compile-time check is needed because GtkRevealer is new in 3.10.
#if GTK_CHECK_VERSION(3, 10, 0)
// Run-time check is needed because the bug was introduced in 3.10 and
// fixed in 3.22.29 (see 6b4d95e86dabfcdaa805fbf068a99e19736a39a4 and a
// couple of previous commits in GTK+ repository).
if ( gtk_check_version(3, 10, 0) == NULL &&
gtk_check_version(3, 22, 29) != NULL )
{
GObject* const
revealer = gtk_widget_get_template_child(GTK_WIDGET(m_widget),
GTK_TYPE_INFO_BAR,
"revealer");
if ( revealer )
{
gtk_revealer_set_transition_type(GTK_REVEALER (revealer),
GTK_REVEALER_TRANSITION_TYPE_NONE);
gtk_revealer_set_transition_duration(GTK_REVEALER (revealer), 0);
}
}
#endif // GTK+ >= 3.10
return true;
}
wxInfoBar::~wxInfoBar()
{
delete m_impl;
}
void wxInfoBar::ShowMessage(const wxString& msg, int flags)
{
if ( !UseNative() )
{
wxInfoBarGeneric::ShowMessage(msg, flags);
return;
}
// if we don't have any buttons, create a standard close one to give the
// user at least some way to close the bar
if ( m_impl->m_buttons.empty() && !m_impl->m_close )
{
m_impl->m_close = GTKAddButton(wxID_CLOSE);
}
GtkMessageType type;
if ( wxGTKImpl::ConvertMessageTypeFromWX(flags, &type) )
gtk_info_bar_set_message_type(GTK_INFO_BAR(m_widget), type);
gtk_label_set_text(GTK_LABEL(m_impl->m_label), wxGTK_CONV(msg));
gtk_label_set_line_wrap(GTK_LABEL(m_impl->m_label), TRUE );
#if GTK_CHECK_VERSION(2,10,0)
if( wx_is_at_least_gtk2( 10 ) )
gtk_label_set_line_wrap_mode(GTK_LABEL(m_impl->m_label), PANGO_WRAP_WORD);
#endif
if ( !IsShown() )
Show();
UpdateParent();
}
void wxInfoBar::Dismiss()
{
if ( !UseNative() )
{
wxInfoBarGeneric::Dismiss();
return;
}
Hide();
UpdateParent();
}
void wxInfoBar::GTKResponse(int btnid)
{
wxCommandEvent event(wxEVT_BUTTON, btnid);
event.SetEventObject(this);
if ( !HandleWindowEvent(event) )
Dismiss();
}
GtkWidget *wxInfoBar::GTKAddButton(wxWindowID btnid, const wxString& label)
{
// as GTK+ lays out the buttons vertically, adding another button changes
// our best size (at least in vertical direction)
InvalidateBestSize();
GtkWidget* button = gtk_info_bar_add_button(GTK_INFO_BAR(m_widget),
#ifdef __WXGTK4__
wxGTK_CONV(label.empty() ? wxConvertMnemonicsToGTK(wxGetStockLabel(btnid)) : label),
#else
label.empty() ? wxGetStockGtkID(btnid) : static_cast<const char*>(wxGTK_CONV(label)),
#endif
btnid);
wxASSERT_MSG( button, "unexpectedly failed to add button to info bar" );
return button;
}
size_t wxInfoBar::GetButtonCount() const
{
if ( !UseNative() )
return wxInfoBarGeneric::GetButtonCount();
return m_impl->m_buttons.size();
}
wxWindowID wxInfoBar::GetButtonId(size_t idx) const
{
if ( !UseNative() )
return wxInfoBarGeneric::GetButtonId(idx);
wxCHECK_MSG( idx < m_impl->m_buttons.size(), wxID_NONE,
"Invalid infobar button position" );
return m_impl->m_buttons[idx].id;
}
void wxInfoBar::AddButton(wxWindowID btnid, const wxString& label)
{
if ( !UseNative() )
{
wxInfoBarGeneric::AddButton(btnid, label);
return;
}
// if we had created the default close button before, remove it now that we
// have some user-defined button
if ( m_impl->m_close )
{
gtk_widget_destroy(m_impl->m_close);
m_impl->m_close = NULL;
}
GtkWidget * const button = GTKAddButton(btnid, label);
if ( button )
m_impl->m_buttons.push_back(wxInfoBarGTKImpl::Button(button, btnid));
}
bool wxInfoBar::HasButtonId(wxWindowID btnid) const
{
if ( !UseNative() )
return wxInfoBarGeneric::HasButtonId(btnid);
// as in the generic version, look for the button starting from the end
const wxInfoBarGTKImpl::Buttons& buttons = m_impl->m_buttons;
for ( wxInfoBarGTKImpl::Buttons::const_reverse_iterator i = buttons.rbegin();
i != buttons.rend();
++i )
{
if ( i->id == btnid )
return true;
}
return false;
}
void wxInfoBar::RemoveButton(wxWindowID btnid)
{
if ( !UseNative() )
{
wxInfoBarGeneric::RemoveButton(btnid);
return;
}
// as in the generic version, look for the button starting from the end
wxInfoBarGTKImpl::Buttons& buttons = m_impl->m_buttons;
for ( wxInfoBarGTKImpl::Buttons::reverse_iterator i = buttons.rbegin();
i != buttons.rend();
++i )
{
if (i->id == btnid)
{
gtk_widget_destroy(i->button);
buttons.erase(i.base());
// see comment in GTKAddButton()
InvalidateBestSize();
return;
}
}
wxFAIL_MSG( wxString::Format("button with id %d not found", btnid) );
}
void wxInfoBar::DoApplyWidgetStyle(GtkRcStyle *style)
{
wxInfoBarGeneric::DoApplyWidgetStyle(style);
if ( UseNative() )
GTKApplyStyle(m_impl->m_label, style);
}
#endif // wxUSE_INFOBAR