Commit 90ff4263 authored by Benjamin Otte's avatar Benjamin Otte

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.
parent 812b32e9
......@@ -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 \
......
/* 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)
/* 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__ */
......@@ -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);
......
......@@ -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 (&parameter[0].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
parameter[1].name = "border-top-right-radius";
g_value_init (&parameter[1].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
parameter[2].name = "border-bottom-right-radius";
g_value_init (&parameter[2].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
parameter[3].name = "border-bottom-left-radius";
g_value_init (&parameter[3].value, GTK_TYPE_CSS_BORDER_CORNER_RADIUS);
if (border)
{
g_value_set_boxed (&parameter[0].value, &border->top_left);
g_value_set_boxed (&parameter[1].value, &border->top_right);
g_value_set_boxed (&parameter[2].value, &border->bottom_right);
g_value_set_boxed (&parameter[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",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment