]> git.0d.be Git - empathy.git/blob - src/empathy-rounded-rectangle.c
Don't clip overflowing border when drawing rounded rectangles
[empathy.git] / src / empathy-rounded-rectangle.c
1 /*
2  * empathy-rounded-rectangle.c - Source for EmpathyRoundedRectangle
3  * Copyright (C) 2011 Collabora Ltd.
4  * @author Emilio Pozuelo Monfort <emilio.pozuelo@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 #include "config.h"
22
23 #include <math.h>
24
25 #include <clutter/clutter.h>
26
27 #include "empathy-rounded-rectangle.h"
28
29 G_DEFINE_TYPE (EmpathyRoundedRectangle,
30     empathy_rounded_rectangle,
31     CLUTTER_TYPE_CAIRO_TEXTURE)
32
33 struct _EmpathyRoundedRectanglePriv
34 {
35   guint width, height;
36   ClutterColor border_color;
37   guint border_width;
38 };
39
40 static void
41 empathy_rounded_rectangle_paint (EmpathyRoundedRectangle *self)
42 {
43   guint width, height;
44   guint tmp_alpha;
45   cairo_t *cr;
46
47 #define RADIUS (height / 8.)
48
49   width = self->priv->width;
50   height = self->priv->height;
51
52   /* compute the composited opacity of the actor taking into
53    * account the opacity of the color set by the user */
54   tmp_alpha = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (self))
55             * self->priv->border_color.alpha
56             / 255;
57
58   cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (self));
59
60   cairo_set_source_rgba (cr,
61       self->priv->border_color.red,
62       self->priv->border_color.green,
63       self->priv->border_color.blue,
64       tmp_alpha);
65
66   cairo_set_line_width (cr, self->priv->border_width);
67
68   cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
69   cairo_paint (cr);
70   cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
71
72   /* make room for the portion of the border drawn on the outside */
73   cairo_translate (cr, self->priv->border_width/2.0, self->priv->border_width/2.0);
74
75   cairo_new_sub_path (cr);
76   cairo_arc (cr, width - RADIUS, RADIUS, RADIUS,
77       -M_PI/2.0, 0);
78   cairo_arc (cr, width - RADIUS, height - RADIUS, RADIUS,
79       0, M_PI/2.0);
80   cairo_arc (cr, RADIUS, height - RADIUS, RADIUS,
81       M_PI/2.0, M_PI);
82   cairo_arc (cr, RADIUS, RADIUS, RADIUS,
83       M_PI, -M_PI/2.0);
84   cairo_close_path (cr);
85
86   cairo_stroke (cr);
87   cairo_destroy (cr);
88
89 #undef RADIUS
90 }
91
92 static void
93 empathy_rounded_rectangle_init (EmpathyRoundedRectangle *self)
94 {
95   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
96       EMPATHY_TYPE_ROUNDED_RECTANGLE, EmpathyRoundedRectanglePriv);
97
98   self->priv->border_width = 1;
99 }
100
101 static void
102 empathy_rounded_rectangle_class_init (EmpathyRoundedRectangleClass *klass)
103 {
104   g_type_class_add_private (klass, sizeof (EmpathyRoundedRectanglePriv));
105 }
106
107 static void
108 empathy_rounded_rectangle_update_surface_size (EmpathyRoundedRectangle *self)
109 {
110   clutter_cairo_texture_set_surface_size (CLUTTER_CAIRO_TEXTURE (self),
111       self->priv->width + self->priv->border_width,
112       self->priv->height + self->priv->border_width);
113 }
114
115 ClutterActor *
116 empathy_rounded_rectangle_new (guint width,
117     guint height)
118 {
119   EmpathyRoundedRectangle *self;
120
121   self = EMPATHY_ROUNDED_RECTANGLE (g_object_new (EMPATHY_TYPE_ROUNDED_RECTANGLE, NULL));
122
123   self->priv->width = width;
124   self->priv->height = height;
125
126   empathy_rounded_rectangle_update_surface_size (self);
127   empathy_rounded_rectangle_paint (self);
128
129   return CLUTTER_ACTOR (self);
130 }
131
132 void
133 empathy_rounded_rectangle_set_border_width (EmpathyRoundedRectangle *self,
134     guint border_width)
135 {
136   self->priv->border_width = border_width;
137
138   empathy_rounded_rectangle_update_surface_size (self);
139   empathy_rounded_rectangle_paint (self);
140 }
141
142 void
143 empathy_rounded_rectangle_set_border_color (EmpathyRoundedRectangle *self,
144     const ClutterColor *color)
145 {
146   self->priv->border_color = *color;
147
148   empathy_rounded_rectangle_paint (self);
149 }