From ec023e99774d90e3ac16a3a5b4e55c6cdf9fb3c1 Mon Sep 17 00:00:00 2001 From: Paul Cornett Date: Sat, 10 Dec 2016 21:49:06 -0800 Subject: [PATCH] Fix rendering of check and radio buttons with GTK+ >= 3.20 (cherry picked from commit e627970ba6126113fdf09db69c50582b369d0d8a) --- src/gtk/renderer.cpp | 184 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 153 insertions(+), 31 deletions(-) diff --git a/src/gtk/renderer.cpp b/src/gtk/renderer.cpp index 965d5fe..c89b0d3 100644 --- a/src/gtk/renderer.cpp +++ b/src/gtk/renderer.cpp @@ -503,6 +503,49 @@ wxRendererGTK::DrawComboBoxDropButton(wxWindow *win, wxSize wxRendererGTK::GetCheckBoxSize(wxWindow *WXUNUSED(win)) { +#ifdef __WXGTK3__ + int min_width, min_height; + GtkWidgetPath* path = gtk_widget_path_new(); + GtkStyleContext* sc = gtk_style_context_new(); + GtkStyleContext* sc1 = NULL; + gtk_widget_path_append_type(path, GTK_TYPE_CHECK_BUTTON); +#if GTK_CHECK_VERSION(3,20,0) + if (gtk_check_version(3,20,0) == NULL) + { + gtk_widget_path_iter_set_object_name(path, -1, "checkbutton"); + sc1 = gtk_style_context_new(); + gtk_style_context_set_path(sc1, path); + gtk_widget_path_append_type(path, G_TYPE_NONE); + gtk_widget_path_iter_set_object_name(path, -1, "check"); + gtk_style_context_set_path(sc, path); + gtk_style_context_set_parent(sc, sc1); + gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL, + "min-width", &min_width, "min-height", &min_height, NULL); + GtkBorder margin; + gtk_style_context_get_margin(sc, GTK_STATE_FLAG_NORMAL, &margin); + min_width += margin.left + margin.right; + min_height += margin.top + margin.bottom; + } + else +#endif + { + gtk_style_context_set_path(sc, path); + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + gtk_style_context_get_style_property(sc, "indicator-size", &value); + min_width = g_value_get_int(&value); + gtk_style_context_get_style_property(sc, "indicator-spacing", &value); + min_width += 2 * g_value_get_int(&value); + min_height = min_width; + g_value_unset(&value); + } + gtk_widget_path_unref(path); + g_object_unref(sc); + if (sc1) + g_object_unref(sc1); + + return wxSize(min_width, min_height); +#else // !__WXGTK3__ gint indicator_size, indicator_spacing; gtk_widget_style_get(wxGTKPrivate::GetCheckButtonWidget(), "indicator_size", &indicator_size, @@ -511,6 +554,7 @@ wxRendererGTK::GetCheckBoxSize(wxWindow *WXUNUSED(win)) int size = indicator_size + indicator_spacing * 2; return wxSize(size, size); +#endif // !__WXGTK3__ } void @@ -519,6 +563,7 @@ wxRendererGTK::DrawCheckBox(wxWindow* win, const wxRect& rect, int flags ) { +#ifndef __WXGTK3__ GtkWidget *button = wxGTKPrivate::GetCheckButtonWidget(); gint indicator_size, indicator_spacing; @@ -527,7 +572,6 @@ wxRendererGTK::DrawCheckBox(wxWindow* win, "indicator_spacing", &indicator_spacing, NULL); -#ifndef __WXGTK3__ GtkStateType state; if ( flags & wxCONTROL_PRESSED ) @@ -551,31 +595,68 @@ wxRendererGTK::DrawCheckBox(wxWindow* win, #ifdef __WXGTK3__ cairo_t* cr = wxGetGTKDrawable(win, dc); - if (cr) + if (cr == NULL) + return; + + int state = GTK_STATE_FLAG_NORMAL; + if (flags & wxCONTROL_CHECKED) { - int stateFlags = GTK_STATE_FLAG_NORMAL; - if (flags & wxCONTROL_CHECKED) - { - stateFlags = GTK_STATE_FLAG_ACTIVE; - if (gtk_check_version(3,14,0) == NULL) - stateFlags = GTK_STATE_FLAG_CHECKED; - } - if (flags & wxCONTROL_DISABLED) - stateFlags |= GTK_STATE_FLAG_INSENSITIVE; - if (flags & wxCONTROL_UNDETERMINED) - stateFlags |= GTK_STATE_FLAG_INCONSISTENT; - if (flags & wxCONTROL_CURRENT) - stateFlags |= GTK_STATE_FLAG_PRELIGHT; - GtkStyleContext* sc = gtk_widget_get_style_context(button); - gtk_style_context_save(sc); - gtk_style_context_set_state(sc, GtkStateFlags(stateFlags)); - gtk_style_context_add_class(sc, GTK_STYLE_CLASS_CHECK); - gtk_render_check(sc, cr, - rect.x + (rect.width - indicator_size) / 2, - rect.y + (rect.height - indicator_size) / 2, - indicator_size, indicator_size); - gtk_style_context_restore(sc); + state = GTK_STATE_FLAG_ACTIVE; + if (gtk_check_version(3,14,0) == NULL) + state = GTK_STATE_FLAG_CHECKED; + } + if (flags & wxCONTROL_DISABLED) + state |= GTK_STATE_FLAG_INSENSITIVE; + if (flags & wxCONTROL_UNDETERMINED) + state |= GTK_STATE_FLAG_INCONSISTENT; + if (flags & wxCONTROL_CURRENT) + state |= GTK_STATE_FLAG_PRELIGHT; + + int min_width, min_height; + GtkWidgetPath* path = gtk_widget_path_new(); + GtkStyleContext* sc = gtk_style_context_new(); + GtkStyleContext* sc1 = NULL; + gtk_widget_path_append_type(path, GTK_TYPE_CHECK_BUTTON); +#if GTK_CHECK_VERSION(3,20,0) + if (gtk_check_version(3,20,0) == NULL) + { + gtk_widget_path_iter_set_object_name(path, -1, "checkbutton"); + sc1 = gtk_style_context_new(); + gtk_style_context_set_path(sc1, path); + gtk_widget_path_append_type(path, G_TYPE_NONE); + gtk_widget_path_iter_set_object_name(path, -1, "check"); + gtk_style_context_set_path(sc, path); + gtk_style_context_set_parent(sc, sc1); + gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL, + "min-width", &min_width, "min-height", &min_height, NULL); + } + else +#endif + { + gtk_style_context_set_path(sc, path); + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + gtk_style_context_get_style_property(sc, "indicator-size", &value); + min_width = g_value_get_int(&value); + min_height = min_width; + g_value_unset(&value); } + + // need save/restore for GTK+ 3.6 & 3.8 + gtk_style_context_save(sc); + gtk_style_context_set_state(sc, GtkStateFlags(state)); + const int x = rect.x + (rect.width - min_width) / 2; + const int y = rect.y + (rect.height - min_height) / 2; + gtk_render_background(sc, cr, x, y, min_width, min_height); + gtk_render_frame(sc, cr, x, y, min_width, min_height); + gtk_style_context_add_class(sc, "check"); + gtk_render_check(sc, cr, x, y, min_width, min_height); + gtk_style_context_restore(sc); + + gtk_widget_path_unref(path); + g_object_unref(sc); + if (sc1) + g_object_unref(sc1); #else GdkWindow* gdk_window = wxGetGTKDrawable(win, dc); if (gdk_window == NULL) @@ -869,8 +950,6 @@ void wxRendererGTK::DrawRadioBitmap(wxWindow* win, wxDC& dc, const wxRect& rect, if (drawable == NULL) return; - GtkWidget* button = wxGTKPrivate::GetRadioButtonWidget(); - #ifdef __WXGTK3__ int state = GTK_STATE_FLAG_NORMAL; if (flags & wxCONTROL_CHECKED) @@ -879,18 +958,61 @@ void wxRendererGTK::DrawRadioBitmap(wxWindow* win, wxDC& dc, const wxRect& rect, if (gtk_check_version(3,14,0) == NULL) state = GTK_STATE_FLAG_CHECKED; } - else if (flags & wxCONTROL_UNDETERMINED) - state = GTK_STATE_FLAG_INCONSISTENT; if (flags & wxCONTROL_DISABLED) state |= GTK_STATE_FLAG_INSENSITIVE; + if (flags & wxCONTROL_UNDETERMINED) + state |= GTK_STATE_FLAG_INCONSISTENT; + if (flags & wxCONTROL_CURRENT) + state |= GTK_STATE_FLAG_PRELIGHT; + + int min_width, min_height; + GtkWidgetPath* path = gtk_widget_path_new(); + GtkStyleContext* sc = gtk_style_context_new(); + GtkStyleContext* sc1 = NULL; + gtk_widget_path_append_type(path, GTK_TYPE_RADIO_BUTTON); +#if GTK_CHECK_VERSION(3,20,0) + if (gtk_check_version(3,20,0) == NULL) + { + gtk_widget_path_iter_set_object_name(path, -1, "radiobutton"); + sc1 = gtk_style_context_new(); + gtk_style_context_set_path(sc1, path); + gtk_widget_path_append_type(path, G_TYPE_NONE); + gtk_widget_path_iter_set_object_name(path, -1, "radio"); + gtk_style_context_set_path(sc, path); + gtk_style_context_set_parent(sc, sc1); + gtk_style_context_get(sc, GTK_STATE_FLAG_NORMAL, + "min-width", &min_width, "min-height", &min_height, NULL); + } + else +#endif + { + gtk_style_context_set_path(sc, path); + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + gtk_style_context_get_style_property(sc, "indicator-size", &value); + min_width = g_value_get_int(&value); + min_height = min_width; + g_value_unset(&value); + } - GtkStyleContext* sc = gtk_widget_get_style_context(button); + // need save/restore for GTK+ 3.6 & 3.8 gtk_style_context_save(sc); - gtk_style_context_add_class(sc, GTK_STYLE_CLASS_RADIO); gtk_style_context_set_state(sc, GtkStateFlags(state)); - gtk_render_option(sc, drawable, rect.x, rect.y, rect.width, rect.height); + const int x = rect.x + (rect.width - min_width) / 2; + const int y = rect.y + (rect.height - min_height) / 2; + gtk_render_background(sc, drawable, x, y, min_width, min_height); + gtk_render_frame(sc, drawable, x, y, min_width, min_height); + gtk_style_context_add_class(sc, "radio"); + gtk_render_option(sc, drawable, x, y, min_width, min_height); gtk_style_context_restore(sc); + + gtk_widget_path_unref(path); + g_object_unref(sc); + if (sc1) + g_object_unref(sc1); #else + GtkWidget* button = wxGTKPrivate::GetRadioButtonWidget(); + GtkShadowType shadow_type = GTK_SHADOW_OUT; if ( flags & wxCONTROL_CHECKED ) shadow_type = GTK_SHADOW_IN;