X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a21175918ecedbae7d04a58acca5e90a6b59633d..05942059ef5ba8ebb6c7829776796a5be4e61262:/src/gtk/button.cpp diff --git a/src/gtk/button.cpp b/src/gtk/button.cpp index 0a6a838f90..f5f76a7b10 100644 --- a/src/gtk/button.cpp +++ b/src/gtk/button.cpp @@ -18,7 +18,10 @@ #include "wx/stockitem.h" +#include #include "wx/gtk/private.h" +#include "wx/gtk/private/gtk2-compat.h" +#include "wx/gtk/private/list.h" // ---------------------------------------------------------------------------- // GTK callbacks @@ -38,42 +41,6 @@ wxgtk_button_clicked_callback(GtkWidget *WXUNUSED(widget), wxButton *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 //----------------------------------------------------------------------------- @@ -83,7 +50,7 @@ wxgtk_button_style_set_callback(GtkWidget* widget, GtkStyle*, wxButton* win) { /* 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); @@ -105,8 +72,6 @@ wxgtk_button_style_set_callback(GtkWidget* widget, GtkStyle*, wxButton* win) // wxButton //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxButton,wxControl) - bool wxButton::Create(wxWindow *parent, wxWindowID id, const wxString &label, @@ -183,7 +148,7 @@ wxWindow *wxButton::SetDefault() { 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 @@ -206,12 +171,12 @@ wxSize wxButtonBase::GetDefaultSize() // 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, @@ -236,7 +201,7 @@ void wxButton::SetLabel( const wxString &lbl ) 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) ) @@ -253,6 +218,10 @@ void wxButton::SetLabel( const wxString &lbl ) } } + // 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); @@ -260,47 +229,63 @@ void wxButton::SetLabel( const wxString &lbl ) 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(item->data); - gtk_widget_modify_style(boxChild->widget, style); + GTKApplyStyle(GTK_WIDGET(item->data), style); } } } @@ -312,19 +297,19 @@ wxSize wxButton::DoGetBestSize() const // 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)) @@ -344,322 +329,7 @@ wxSize wxButton::DoGetBestSize() const 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" ); - - GtkWidget *image; - if ( DontShowLabel() ) - { - image = GTK_BIN(m_widget)->child; - } - else // have both label and bitmap - { -#ifdef __WXGTK26__ - if ( !gtk_check_version(2,6,0) ) - { - image = gtk_button_get_image(GTK_BUTTON(m_widget)); - } - else -#endif // __WXGTK26__ - { - // buttons with both label and bitmap are only supported with GTK+ - // 2.6 so far - // - // it shouldn't be difficult to implement them ourselves for the - // previous GTK+ versions by stuffing a container with a label and - // an image inside GtkButton but there doesn't seem to be much - // point in doing this for ancient GTK+ versions - return; - } - } - - wxCHECK_RET( image && GTK_IS_IMAGE(image), "must have image widget" ); - - gtk_image_set_from_pixbuf(GTK_IMAGE(image), bitmap.GetPixbuf()); -} - -wxBitmap wxButton::DoGetBitmap(State which) const -{ - return m_bitmaps[which]; -} - -void wxButton::DoSetBitmap(const wxBitmap& bitmap, State which) -{ - switch ( which ) - { - case State_Normal: - if ( DontShowLabel() ) - { - // we only have the bitmap in this button, never remove it but - // do invalidate the best size when the bitmap (and presumably - // its size) changes - InvalidateBestSize(); - } -#ifdef __WXGTK26__ - // normal image is special: setting it enables images for the button and - // resetting it to nothing disables all of them - else 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