// Name: src/gtk/button.cpp
// Purpose:
// Author: Robert Roebling
-// Id: $Id$
// Copyright: (c) 1998 Robert Roebling
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/stockitem.h"
+#include <gtk/gtk.h>
#include "wx/gtk/private.h"
+#include "wx/gtk/private/gtk2-compat.h"
+#include "wx/gtk/private/list.h"
// ----------------------------------------------------------------------------
// GTK callbacks
if ( button->GTKShouldIgnoreEvent() )
return;
- wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, button->GetId());
+ wxCommandEvent event(wxEVT_BUTTON, button->GetId());
event.SetEventObject(button);
button->HandleWindowEvent(event);
}
-static void
-wxgtk_button_enter_callback(GtkWidget *WXUNUSED(widget), wxButton *button)
-{
- if ( button->GTKShouldIgnoreEvent() )
- return;
-
- button->GTKMouseEnters();
-}
-
-static void
-wxgtk_button_leave_callback(GtkWidget *WXUNUSED(widget), wxButton *button)
-{
- if ( button->GTKShouldIgnoreEvent() )
- return;
-
- button->GTKMouseLeaves();
-}
-
-static void
-wxgtk_button_press_callback(GtkWidget *WXUNUSED(widget), wxButton *button)
-{
- if ( button->GTKShouldIgnoreEvent() )
- return;
-
- button->GTKPressed();
-}
-
-static void
-wxgtk_button_released_callback(GtkWidget *WXUNUSED(widget), wxButton *button)
-{
- if ( button->GTKShouldIgnoreEvent() )
- return;
-
- button->GTKReleased();
-}
-
//-----------------------------------------------------------------------------
// "style_set" from m_widget
//-----------------------------------------------------------------------------
{
/* the default button has a border around it */
wxWindow* parent = win->GetParent();
- if (parent && parent->m_wxwindow && GTK_WIDGET_CAN_DEFAULT(widget))
+ if (parent && parent->m_wxwindow && gtk_widget_get_can_default(widget))
{
GtkBorder* border = NULL;
gtk_widget_style_get(widget, "default_border", &border, NULL);
// wxButton
//-----------------------------------------------------------------------------
-IMPLEMENT_DYNAMIC_CLASS(wxButton,wxControl)
-
bool wxButton::Create(wxWindow *parent,
wxWindowID id,
const wxString &label,
return false;
}
- m_widget = gtk_button_new_with_mnemonic("");
+ // create either a standard button with text label (which may still contain
+ // an image under GTK+ 2.6+) or a bitmap-only button if we don't have any
+ // label
+ const bool
+ useLabel = !(style & wxBU_NOTEXT) && (!label.empty() || wxIsStockID(id));
+ if ( useLabel )
+ {
+ m_widget = gtk_button_new_with_mnemonic("");
+ }
+ else // no label, suppose we will have a bitmap
+ {
+ m_widget = gtk_button_new();
+
+ GtkWidget *image = gtk_image_new();
+ gtk_widget_show(image);
+ gtk_container_add(GTK_CONTAINER(m_widget), image);
+ }
+
g_object_ref(m_widget);
float x_alignment = 0.5;
gtk_button_set_alignment(GTK_BUTTON(m_widget), x_alignment, y_alignment);
- SetLabel(label);
+ if ( useLabel )
+ SetLabel(label);
if (style & wxNO_BORDER)
gtk_button_set_relief( GTK_BUTTON(m_widget), GTK_RELIEF_NONE );
{
wxWindow *oldDefault = wxButtonBase::SetDefault();
- GTK_WIDGET_SET_FLAGS( m_widget, GTK_CAN_DEFAULT );
+ gtk_widget_set_can_default(m_widget, TRUE);
gtk_widget_grab_default( m_widget );
// resize for default border
// button's size. We have to retrieve both values and combine them.
GtkWidget *wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- GtkWidget *box = gtk_hbutton_box_new();
+ GtkWidget *box = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
GtkWidget *btn = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
gtk_container_add(GTK_CONTAINER(box), btn);
gtk_container_add(GTK_CONTAINER(wnd), box);
GtkRequisition req;
- gtk_widget_size_request(btn, &req);
+ gtk_widget_get_preferred_size(btn, NULL, &req);
gint minwidth, minheight;
gtk_widget_style_get(box,
if (label.empty() && wxIsStockID(m_windowId))
label = wxGetStockLabel(m_windowId);
- wxControl::SetLabel(label);
+ wxAnyButton::SetLabel(label);
+
+ // don't use label if it was explicitly disabled
+ if ( HasFlag(wxBU_NOTEXT) )
+ return;
if (wxIsStockID(m_windowId) && wxIsStockLabel(m_windowId, label))
{
}
}
+ // this call is necessary if the button had been initially created without
+ // a (text) label -- then we didn't use gtk_button_new_with_mnemonic() and
+ // so "use-underline" GtkButton property remained unset
+ gtk_button_set_use_underline(GTK_BUTTON(m_widget), TRUE);
const wxString labelGTK = GTKConvertMnemonics(label);
gtk_button_set_label(GTK_BUTTON(m_widget), wxGTK_CONV(labelGTK));
gtk_button_set_use_stock(GTK_BUTTON(m_widget), FALSE);
GTKApplyWidgetStyle( false );
}
-bool wxButton::Enable( bool enable )
+#if wxUSE_MARKUP
+bool wxButton::DoSetLabelMarkup(const wxString& markup)
{
- bool isEnabled = IsEnabled();
+ wxCHECK_MSG( m_widget != NULL, false, "invalid button" );
- if ( !wxControl::Enable( enable ) )
+ const wxString stripped = RemoveMarkup(markup);
+ if ( stripped.empty() && !markup.empty() )
return false;
- gtk_widget_set_sensitive(GTK_BIN(m_widget)->child, enable);
+ wxControl::SetLabel(stripped);
- if (!isEnabled && enable)
- {
- GTKFixSensitivity();
- }
+ GtkLabel * const label = GTKGetLabel();
+ wxCHECK_MSG( label, false, "no label in this button?" );
- GTKUpdateBitmap();
+ GTKSetLabelWithMarkupForLabel(label, markup);
return true;
}
-GdkWindow *wxButton::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const
+GtkLabel *wxButton::GTKGetLabel() const
{
- return GTK_BUTTON(m_widget)->event_window;
+ GtkWidget* child = gtk_bin_get_child(GTK_BIN(m_widget));
+ if ( GTK_IS_ALIGNMENT(child) )
+ {
+ GtkWidget* box = gtk_bin_get_child(GTK_BIN(child));
+ GtkLabel* label = NULL;
+ wxGtkList list(gtk_container_get_children(GTK_CONTAINER(box)));
+ for (GList* item = list; item; item = item->next)
+ {
+ if (GTK_IS_LABEL(item->data))
+ label = GTK_LABEL(item->data);
+ }
+
+ return label;
+ }
+
+ return GTK_LABEL(child);
}
+#endif // wxUSE_MARKUP
void wxButton::DoApplyWidgetStyle(GtkRcStyle *style)
{
- gtk_widget_modify_style(m_widget, style);
- GtkWidget *child = GTK_BIN(m_widget)->child;
- gtk_widget_modify_style(child, style);
+ GTKApplyStyle(m_widget, style);
+ GtkWidget* child = gtk_bin_get_child(GTK_BIN(m_widget));
+ GTKApplyStyle(child, style);
// for buttons with images, the path to the label is (at least in 2.12)
// GtkButton -> GtkAlignment -> GtkHBox -> GtkLabel
if ( GTK_IS_ALIGNMENT(child) )
{
- GtkWidget *box = GTK_BIN(child)->child;
+ GtkWidget* box = gtk_bin_get_child(GTK_BIN(child));
if ( GTK_IS_BOX(box) )
{
- for (GList* item = GTK_BOX(box)->children; item; item = item->next)
+ wxGtkList list(gtk_container_get_children(GTK_CONTAINER(box)));
+ for (GList* item = list; item; item = item->next)
{
- GtkBoxChild* boxChild = static_cast<GtkBoxChild*>(item->data);
- gtk_widget_modify_style(boxChild->widget, style);
+ GTKApplyStyle(GTK_WIDGET(item->data), style);
}
}
}
// extra border around it, but we don't want to take it into account in
// our size calculations (otherwise the result is visually ugly), so
// always return the size of non default button from here
- const bool isDefault = GTK_WIDGET_HAS_DEFAULT(m_widget);
+ const bool isDefault = gtk_widget_has_default(m_widget) != 0;
if ( isDefault )
{
// temporarily unset default flag
- GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_DEFAULT );
+ gtk_widget_set_can_default(m_widget, FALSE);
}
- wxSize ret( wxControl::DoGetBestSize() );
+ wxSize ret( wxAnyButton::DoGetBestSize() );
if ( isDefault )
{
// set it back again
- GTK_WIDGET_SET_FLAGS( m_widget, GTK_CAN_DEFAULT );
+ gtk_widget_set_can_default(m_widget, TRUE);
}
if (!HasFlag(wxBU_EXACTFIT))
wxVisualAttributes
wxButton::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
{
- return GetDefaultAttributesFromGTKWidget(gtk_button_new);
-}
-
-// ----------------------------------------------------------------------------
-// bitmaps support
-// ----------------------------------------------------------------------------
-
-void wxButton::GTKMouseEnters()
-{
- m_isCurrent = true;
-
- GTKUpdateBitmap();
-}
-
-void wxButton::GTKMouseLeaves()
-{
- m_isCurrent = false;
-
- GTKUpdateBitmap();
-}
-
-void wxButton::GTKPressed()
-{
- m_isPressed = true;
-
- GTKUpdateBitmap();
-}
-
-void wxButton::GTKReleased()
-{
- m_isPressed = false;
-
- GTKUpdateBitmap();
-}
-
-void wxButton::GTKOnFocus(wxFocusEvent& event)
-{
- event.Skip();
-
- GTKUpdateBitmap();
-}
-
-wxButton::State wxButton::GTKGetCurrentState() const
-{
- if ( !IsThisEnabled() )
- return m_bitmaps[State_Disabled].IsOk() ? State_Disabled : State_Normal;
-
- if ( m_isPressed && m_bitmaps[State_Pressed].IsOk() )
- return State_Pressed;
-
- if ( m_isCurrent && m_bitmaps[State_Current].IsOk() )
- return State_Current;
-
- if ( HasFocus() && m_bitmaps[State_Focused].IsOk() )
- return State_Focused;
-
- return State_Normal;
-}
-
-void wxButton::GTKUpdateBitmap()
-{
- State state = GTKGetCurrentState();
-
- GTKDoShowBitmap(m_bitmaps[state]);
-}
-
-void wxButton::GTKDoShowBitmap(const wxBitmap& bitmap)
-{
- wxASSERT_MSG( bitmap.IsOk(), "invalid bitmap" );
-
-#ifdef __WXGTK26__
- if ( !gtk_check_version(2,6,0) )
- {
- GtkWidget *image = gtk_button_get_image(GTK_BUTTON(m_widget));
- wxCHECK_RET( image, "must have image widget" );
-
- gtk_image_set_from_pixbuf(GTK_IMAGE(image), bitmap.GetPixbuf());
- }
-#endif // __WXGTK26__
-}
-
-wxBitmap wxButton::DoGetBitmap(State which) const
-{
- return m_bitmaps[which];
-}
-
-void wxButton::DoSetBitmap(const wxBitmap& bitmap, State which)
-{
- switch ( which )
- {
- case State_Normal:
-#ifdef __WXGTK26__
- // normal image is special: setting it enables images for the button and
- // resetting it to nothing disables all of them
- if ( !gtk_check_version(2,6,0) )
- {
- GtkWidget *image = gtk_button_get_image(GTK_BUTTON(m_widget));
- if ( image && !bitmap.IsOk() )
- {
- gtk_container_remove(GTK_CONTAINER(m_widget), image);
- }
- else if ( !image && bitmap.IsOk() )
- {
- image = gtk_image_new();
- gtk_button_set_image(GTK_BUTTON(m_widget), image);
- }
- else // image presence or absence didn't change
- {
- // don't invalidate best size below
- break;
- }
-
- InvalidateBestSize();
- }
-#endif // GTK+ 2.6+
- break;
-
- case State_Pressed:
- if ( bitmap.IsOk() )
- {
- if ( !m_bitmaps[which].IsOk() )
- {
- // we need to install the callbacks to be notified about
- // the button pressed state change
- g_signal_connect
- (
- m_widget,
- "pressed",
- G_CALLBACK(wxgtk_button_press_callback),
- this
- );
-
- g_signal_connect
- (
- m_widget,
- "released",
- G_CALLBACK(wxgtk_button_released_callback),
- this
- );
- }
- }
- else // no valid bitmap
- {
- if ( m_bitmaps[which].IsOk() )
- {
- // we don't need to be notified about the button pressed
- // state changes any more
- g_signal_handlers_disconnect_by_func
- (
- m_widget,
- (gpointer)wxgtk_button_press_callback,
- this
- );
-
- g_signal_handlers_disconnect_by_func
- (
- m_widget,
- (gpointer)wxgtk_button_released_callback,
- this
- );
-
- // also make sure we don't remain stuck in pressed state
- if ( m_isPressed )
- {
- m_isPressed = false;
- GTKUpdateBitmap();
- }
- }
- }
- break;
-
- case State_Current:
- // the logic here is the same as above for State_Pressed: we need
- // to connect the handlers if we must be notified about the changes
- // in the button current state and we disconnect them when/if we
- // don't need them any more
- if ( bitmap.IsOk() )
- {
- if ( !m_bitmaps[which].IsOk() )
- {
- g_signal_connect
- (
- m_widget,
- "enter",
- G_CALLBACK(wxgtk_button_enter_callback),
- this
- );
-
- g_signal_connect
- (
- m_widget,
- "leave",
- G_CALLBACK(wxgtk_button_leave_callback),
- this
- );
- }
- }
- else // no valid bitmap
- {
- if ( m_bitmaps[which].IsOk() )
- {
- g_signal_handlers_disconnect_by_func
- (
- m_widget,
- (gpointer)wxgtk_button_enter_callback,
- this
- );
-
- g_signal_handlers_disconnect_by_func
- (
- m_widget,
- (gpointer)wxgtk_button_leave_callback,
- this
- );
-
- if ( m_isCurrent )
- {
- m_isCurrent = false;
- GTKUpdateBitmap();
- }
- }
- }
- break;
-
- case State_Focused:
- if ( bitmap.IsOk() )
- {
- Connect(wxEVT_SET_FOCUS,
- wxFocusEventHandler(wxButton::GTKOnFocus));
- Connect(wxEVT_KILL_FOCUS,
- wxFocusEventHandler(wxButton::GTKOnFocus));
- }
- else // no valid focused bitmap
- {
- Disconnect(wxEVT_SET_FOCUS,
- wxFocusEventHandler(wxButton::GTKOnFocus));
- Disconnect(wxEVT_KILL_FOCUS,
- wxFocusEventHandler(wxButton::GTKOnFocus));
- }
- break;
-
- default:
- // no callbacks to connect/disconnect
- ;
- }
-
- m_bitmaps[which] = bitmap;
-
- // update the bitmap immediately if necessary, otherwise it will be done
- // when the bitmap for the corresponding state is needed the next time by
- // GTKUpdateBitmap()
- if ( bitmap.IsOk() && which == GTKGetCurrentState() )
- {
- GTKDoShowBitmap(bitmap);
- }
-}
-
-void wxButton::DoSetBitmapPosition(wxDirection dir)
-{
-#ifdef __WXGTK210__
- if ( !gtk_check_version(2,10,0) )
- {
- GtkPositionType gtkpos;
- switch ( dir )
- {
- default:
- wxFAIL_MSG( "invalid position" );
- // fall through
-
- case wxLEFT:
- gtkpos = GTK_POS_LEFT;
- break;
-
- case wxRIGHT:
- gtkpos = GTK_POS_RIGHT;
- break;
-
- case wxTOP:
- gtkpos = GTK_POS_TOP;
- break;
-
- case wxBOTTOM:
- gtkpos = GTK_POS_BOTTOM;
- break;
- }
-
- gtk_button_set_image_position(GTK_BUTTON(m_widget), gtkpos);
- }
-#endif // GTK+ 2.10+
+ return GetDefaultAttributesFromGTKWidget(gtk_button_new());
}
#endif // wxUSE_BUTTON