diff options
author | Benjamin Otte <otte@redhat.com> | 2011-05-26 03:50:53 +0200 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2011-06-02 02:03:51 +0200 |
commit | 90ff426396da18cbe376377c969466c09b11e136 (patch) | |
tree | 73558e48862e3c7f6878b20b364b9f154f5a2c2e /gtk | |
parent | 812b32e9e5400b6e2de9963a72034aca0b31e8e3 (diff) | |
download | gtk+-90ff426396da18cbe376377c969466c09b11e136.tar.gz |
css: Add all border-radius properties
Implement all border-radisu properties as specified by
http://www.w3.org/TR/css3-background/#the-border-radius
The end goal here is to get joined buttons to really look joined.
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/Makefile.am | 2 | ||||
-rw-r--r-- | gtk/gtkcsstypes.c | 35 | ||||
-rw-r--r-- | gtk/gtkcsstypesprivate.h | 50 | ||||
-rw-r--r-- | gtk/gtkstyleproperties.c | 6 | ||||
-rw-r--r-- | gtk/gtkstyleproperty.c | 313 |
5 files changed, 403 insertions, 3 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am index a9e623e752..19b187a45a 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -389,6 +389,7 @@ gtk_private_h_sources = \ gtkcssparserprivate.h \ gtkcssproviderprivate.h \ gtkcssselectorprivate.h \ + gtkcsstypesprivate.h \ gtkcustompaperunixdialog.h \ gtkdndcursors.h \ gtkentryprivate.h \ @@ -518,6 +519,7 @@ gtk_base_c_sources = \ gtkcssparser.c \ gtkcssprovider.c \ gtkcssselector.c \ + gtkcsstypes.c \ gtkdialog.c \ gtkdrawingarea.c \ gtkeditable.c \ diff --git a/gtk/gtkcsstypes.c b/gtk/gtkcsstypes.c new file mode 100644 index 0000000000..44b0d28bb8 --- /dev/null +++ b/gtk/gtkcsstypes.c @@ -0,0 +1,35 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2011 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "gtkcsstypesprivate.h" + +#define DEFINE_BOXED_TYPE_WITH_COPY_FUNC(TypeName, type_name) \ +\ +static TypeName * \ +type_name ## _copy (const TypeName *foo) \ +{ \ + return g_memdup (foo, sizeof (TypeName)); \ +} \ +\ +G_DEFINE_BOXED_TYPE (TypeName, type_name, type_name ## _copy, g_free) + +DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBorderCornerRadius, _gtk_css_border_corner_radius) +DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBorderRadius, _gtk_css_border_radius) diff --git a/gtk/gtkcsstypesprivate.h b/gtk/gtkcsstypesprivate.h new file mode 100644 index 0000000000..db3e274a29 --- /dev/null +++ b/gtk/gtkcsstypesprivate.h @@ -0,0 +1,50 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2011 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTK_CSS_TYPES_PRIVATE_H__ +#define __GTK_CSS_TYPES_PRIVATE_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS + +typedef struct _GtkCssBorderCornerRadius GtkCssBorderCornerRadius; +typedef struct _GtkCssBorderRadius GtkCssBorderRadius; + +struct _GtkCssBorderCornerRadius { + double horizontal; + double vertical; +}; + +struct _GtkCssBorderRadius { + GtkCssBorderCornerRadius top_left; + GtkCssBorderCornerRadius top_right; + GtkCssBorderCornerRadius bottom_right; + GtkCssBorderCornerRadius bottom_left; +}; + +#define GTK_TYPE_CSS_BORDER_CORNER_RADIUS _gtk_css_border_corner_radius_get_type () +#define GTK_TYPE_CSS_BORDER_RADIUS _gtk_css_border_radius_get_type () + +GType _gtk_css_border_corner_radius_get_type (void); +GType _gtk_css_border_radius_get_type (void); + +G_END_DECLS + +#endif /* __GTK_CSS_TYPES_PRIVATE_H__ */ diff --git a/gtk/gtkstyleproperties.c b/gtk/gtkstyleproperties.c index ce7f805211..7e1cb29241 100644 --- a/gtk/gtkstyleproperties.c +++ b/gtk/gtkstyleproperties.c @@ -31,6 +31,7 @@ #include "gtkanimationdescription.h" #include "gtkgradient.h" #include "gtkshadowprivate.h" +#include "gtkcsstypesprivate.h" #include "gtkstylepropertyprivate.h" #include "gtkintl.h" @@ -512,6 +513,11 @@ _gtk_style_properties_set_property_by_property (GtkStyleProperties *props, g_return_if_fail (value_type == CAIRO_GOBJECT_TYPE_PATTERN || value_type == GTK_TYPE_GRADIENT); } + else if (style_prop->pspec->value_type == G_TYPE_INT) + { + g_return_if_fail (value_type == G_TYPE_INT || + value_type == GTK_TYPE_CSS_BORDER_RADIUS); + } else g_return_if_fail (style_prop->pspec->value_type == value_type); diff --git a/gtk/gtkstyleproperty.c b/gtk/gtkstyleproperty.c index 5fa9d777f9..ee5128fa39 100644 --- a/gtk/gtkstyleproperty.c +++ b/gtk/gtkstyleproperty.c @@ -30,6 +30,7 @@ #include "gtkcssprovider.h" #include "gtkcssparserprivate.h" +#include "gtkcsstypesprivate.h" /* the actual parsers we have */ #include "gtkanimationdescription.h" @@ -1184,6 +1185,216 @@ bindings_value_print (const GValue *value, } } +static gboolean +border_corner_radius_value_parse (GtkCssParser *parser, + GFile *base, + GValue *value) +{ + GtkCssBorderCornerRadius corner; + + if (!_gtk_css_parser_try_double (parser, &corner.horizontal)) + { + _gtk_css_parser_error (parser, "Expected a number"); + return FALSE; + } + else if (corner.horizontal < 0) + goto negative; + + if (!_gtk_css_parser_try_double (parser, &corner.vertical)) + corner.vertical = corner.horizontal; + else if (corner.vertical < 0) + goto negative; + + g_value_set_boxed (value, &corner); + return TRUE; + +negative: + _gtk_css_parser_error (parser, "Border radius values cannot be negative"); + return FALSE; +} + +static void +border_corner_radius_value_print (const GValue *value, + GString *string) +{ + GtkCssBorderCornerRadius *corner; + + corner = g_value_get_boxed (value); + + if (corner == NULL) + { + g_string_append (string, "none"); + return; + } + + string_append_double (string, corner->horizontal); + if (corner->horizontal != corner->vertical) + { + g_string_append_c (string, ' '); + string_append_double (string, corner->vertical); + } +} + +static gboolean +border_radius_value_parse (GtkCssParser *parser, + GFile *base, + GValue *value) +{ + GtkCssBorderRadius border; + + if (!_gtk_css_parser_try_double (parser, &border.top_left.horizontal)) + { + _gtk_css_parser_error (parser, "Expected a number"); + return FALSE; + } + else if (border.top_left.horizontal < 0) + goto negative; + + if (_gtk_css_parser_try_double (parser, &border.top_right.horizontal)) + { + if (border.top_right.horizontal < 0) + goto negative; + if (_gtk_css_parser_try_double (parser, &border.bottom_right.horizontal)) + { + if (border.bottom_right.horizontal < 0) + goto negative; + if (!_gtk_css_parser_try_double (parser, &border.bottom_left.horizontal)) + border.bottom_left.horizontal = border.top_right.horizontal; + else if (border.bottom_left.horizontal < 0) + goto negative; + } + else + { + border.bottom_right.horizontal = border.top_left.horizontal; + border.bottom_left.horizontal = border.top_right.horizontal; + } + } + else + { + border.top_right.horizontal = border.top_left.horizontal; + border.bottom_right.horizontal = border.top_left.horizontal; + border.bottom_left.horizontal = border.top_left.horizontal; + } + + if (_gtk_css_parser_try (parser, "/", TRUE)) + { + if (!_gtk_css_parser_try_double (parser, &border.top_left.vertical)) + { + _gtk_css_parser_error (parser, "Expected a number"); + return FALSE; + } + else if (border.top_left.vertical < 0) + goto negative; + + if (_gtk_css_parser_try_double (parser, &border.top_right.vertical)) + { + if (border.top_right.vertical < 0) + goto negative; + if (_gtk_css_parser_try_double (parser, &border.bottom_right.vertical)) + { + if (border.bottom_right.vertical < 0) + goto negative; + if (!_gtk_css_parser_try_double (parser, &border.bottom_left.vertical)) + border.bottom_left.vertical = border.top_right.vertical; + else if (border.bottom_left.vertical < 0) + goto negative; + } + else + { + border.bottom_right.vertical = border.top_left.vertical; + border.bottom_left.vertical = border.top_right.vertical; + } + } + else + { + border.top_right.vertical = border.top_left.vertical; + border.bottom_right.vertical = border.top_left.vertical; + border.bottom_left.vertical = border.top_left.vertical; + } + } + else + { + border.top_left.vertical = border.top_left.horizontal; + border.top_right.vertical = border.top_right.horizontal; + border.bottom_right.vertical = border.bottom_right.horizontal; + border.bottom_left.vertical = border.bottom_left.horizontal; + } + + /* border-radius is an int property for backwards-compat reasons */ + g_value_unset (value); + g_value_init (value, GTK_TYPE_CSS_BORDER_RADIUS); + g_value_set_boxed (value, &border); + + return TRUE; + +negative: + _gtk_css_parser_error (parser, "Border radius values cannot be negative"); + return FALSE; +} + +static void +border_radius_value_print (const GValue *value, + GString *string) +{ + GtkCssBorderRadius *border; + + border = g_value_get_boxed (value); + + if (border == NULL) + { + g_string_append (string, "none"); + return; + } + + string_append_double (string, border->top_left.horizontal); + if (border->top_left.horizontal != border->top_right.horizontal || + border->top_left.horizontal != border->bottom_right.horizontal || + border->top_left.horizontal != border->bottom_left.horizontal) + { + g_string_append_c (string, ' '); + string_append_double (string, border->top_right.horizontal); + if (border->top_left.horizontal != border->bottom_right.horizontal || + border->top_right.horizontal != border->bottom_left.horizontal) + { + g_string_append_c (string, ' '); + string_append_double (string, border->bottom_right.horizontal); + if (border->top_right.horizontal != border->bottom_left.horizontal) + { + g_string_append_c (string, ' '); + string_append_double (string, border->bottom_left.horizontal); + } + } + } + + if (border->top_left.horizontal != border->top_left.vertical || + border->top_right.horizontal != border->top_right.vertical || + border->bottom_right.horizontal != border->bottom_right.vertical || + border->bottom_left.horizontal != border->bottom_left.vertical) + { + g_string_append (string, " / "); + string_append_double (string, border->top_left.vertical); + if (border->top_left.vertical != border->top_right.vertical || + border->top_left.vertical != border->bottom_right.vertical || + border->top_left.vertical != border->bottom_left.vertical) + { + g_string_append_c (string, ' '); + string_append_double (string, border->top_right.vertical); + if (border->top_left.vertical != border->bottom_right.vertical || + border->top_right.vertical != border->bottom_left.vertical) + { + g_string_append_c (string, ' '); + string_append_double (string, border->bottom_right.vertical); + if (border->top_right.vertical != border->bottom_left.vertical) + { + g_string_append_c (string, ' '); + string_append_double (string, border->bottom_left.vertical); + } + } + } + + } +} + /*** PACKING ***/ static GParameter * @@ -1299,6 +1510,60 @@ pack_margin (GValue *value, "margin-bottom", "margin-right"); } +static GParameter * +unpack_border_radius (const GValue *value, + guint *n_params) +{ + GParameter *parameter = g_new0 (GParameter, 4); + GtkCssBorderRadius *border; + + if (G_VALUE_HOLDS_BOXED (value)) + border = g_value_get_boxed (value); + else + border = NULL; + + parameter[0].name = "border-top-left-radius"; + g_value_init (¶meter[0].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS); + parameter[1].name = "border-top-right-radius"; + g_value_init (¶meter[1].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS); + parameter[2].name = "border-bottom-right-radius"; + g_value_init (¶meter[2].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS); + parameter[3].name = "border-bottom-left-radius"; + g_value_init (¶meter[3].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS); + if (border) + { + g_value_set_boxed (¶meter[0].value, &border->top_left); + g_value_set_boxed (¶meter[1].value, &border->top_right); + g_value_set_boxed (¶meter[2].value, &border->bottom_right); + g_value_set_boxed (¶meter[3].value, &border->bottom_left); + } + + *n_params = 4; + return parameter; +} + +static void +pack_border_radius (GValue *value, + GtkStyleProperties *props, + GtkStateFlags state) +{ + GtkCssBorderCornerRadius *top_left; + + /* NB: We are an int property, so we have to resolve to an int here. + * So we just resolve to an int. We pick one and stick to it. + * Lesson learned: Don't query border-radius shorthand, query the + * real properties instead. */ + gtk_style_properties_get (props, + state, + "border-top-left-radius", &top_left, + NULL); + + if (top_left) + g_value_set_int (value, top_left->horizontal); + + g_free (top_left); +} + /*** API ***/ static void @@ -1627,11 +1892,53 @@ gtk_style_property_init (void) pack_border_width, NULL, NULL); - gtk_style_properties_register_property (NULL, - g_param_spec_int ("border-radius", + + _gtk_style_property_register (g_param_spec_boxed ("border-top-left-radius", + "Border top left radius", + "Border radius of top left corner, in pixels", + GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0), + NULL, + NULL, + NULL, + border_corner_radius_value_parse, + border_corner_radius_value_print); + _gtk_style_property_register (g_param_spec_boxed ("border-top-right-radius", + "Border top right radius", + "Border radius of top right corner, in pixels", + GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0), + NULL, + NULL, + NULL, + border_corner_radius_value_parse, + border_corner_radius_value_print); + _gtk_style_property_register (g_param_spec_boxed ("border-bottom-right-radius", + "Border bottom right radius", + "Border radius of bottom right corner, in pixels", + GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0), + NULL, + NULL, + NULL, + border_corner_radius_value_parse, + border_corner_radius_value_print); + _gtk_style_property_register (g_param_spec_boxed ("border-bottom-left-radius", + "Border bottom left radius", + "Border radius of bottom left corner, in pixels", + GTK_TYPE_CSS_BORDER_CORNER_RADIUS, 0), + NULL, + NULL, + NULL, + border_corner_radius_value_parse, + border_corner_radius_value_print); + _gtk_style_property_register (g_param_spec_int ("border-radius", "Border radius", "Border radius, in pixels", - 0, G_MAXINT, 0, 0)); + 0, G_MAXINT, 0, 0), + NULL, + unpack_border_radius, + pack_border_radius, + border_radius_value_parse, + border_radius_value_print); + gtk_style_properties_register_property (NULL, g_param_spec_enum ("border-style", "Border style", |