1 #include "cb-border-effect.h"
2
3 G_DEFINE_TYPE (CbBorderEffect, cb_border_effect, CLUTTER_TYPE_EFFECT);
4
5 #define CB_BORDER_EFFECT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
6 CB_TYPE_BORDER_EFFECT, \
7 CbBorderEffectPrivate))
8
9 static const ClutterColor grey = { 0xaa, 0xaa, 0xaa, 0xff };
10
11 struct _CbBorderEffectPrivate
12 {
13 CoglMaterial *border;
14 ClutterColor color;
15 gfloat width;
16 };
17
18 enum {
19 PROP_0,
20
21 PROP_COLOR,
22 PROP_WIDTH,
23
24 PROP_LAST
25 };
26
27 static GParamSpec *obj_props[PROP_LAST];
28
29 /* ClutterEffect implementation */
30 static void
cb_border_effect_post_paint(ClutterEffect * self)31 cb_border_effect_post_paint (ClutterEffect *self)
32 {
33 ClutterActor *actor;
34 gfloat width;
35 gfloat height;
36 CbBorderEffectPrivate *priv;
37
38 priv = CB_BORDER_EFFECT (self)->priv;
39
40 /* get the associated actor's dimensions */
41 actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self));
42 clutter_actor_get_size (actor, &width, &height);
43
44 /* draw Cogl rectangles on top */
45 cogl_set_source (priv->border);
46 cogl_path_new ();
47
48 /* left rectangle */
49 cogl_path_rectangle (0, 0, priv->width, height);
50
51 /* top rectangle */
52 cogl_path_rectangle (priv->width, 0, width, priv->width);
53
54 /* right rectangle */
55 cogl_path_rectangle (width - priv->width, priv->width, width, height);
56
57 /* bottom rectangle */
58 cogl_path_rectangle (priv->width,
59 height - priv->width,
60 width - priv->width,
61 height);
62
63 cogl_path_fill ();
64 }
65
66 /* GObject implementation */
67 static void
cb_border_effect_dispose(GObject * gobject)68 cb_border_effect_dispose (GObject *gobject)
69 {
70 CbBorderEffectPrivate *priv = CB_BORDER_EFFECT (gobject)->priv;
71
72 if (priv->border != COGL_INVALID_HANDLE)
73 {
74 cogl_handle_unref (priv->border);
75 priv->border = COGL_INVALID_HANDLE;
76 }
77
78 G_OBJECT_CLASS (cb_border_effect_parent_class)->dispose (gobject);
79 }
80
81 static void
cb_border_effect_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * pspec)82 cb_border_effect_set_property (GObject *gobject,
83 guint prop_id,
84 const GValue *value,
85 GParamSpec *pspec)
86 {
87 CbBorderEffect *effect = CB_BORDER_EFFECT (gobject);
88
89 switch (prop_id)
90 {
91 case PROP_COLOR:
92 cb_border_effect_set_color (effect, clutter_value_get_color (value));
93 break;
94
95 case PROP_WIDTH:
96 cb_border_effect_set_width (effect, g_value_get_float (value));
97 break;
98
99 default:
100 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
101 break;
102 }
103 }
104
105 static void
cb_border_effect_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * pspec)106 cb_border_effect_get_property (GObject *gobject,
107 guint prop_id,
108 GValue *value,
109 GParamSpec *pspec)
110 {
111 CbBorderEffectPrivate *priv = CB_BORDER_EFFECT (gobject)->priv;
112
113 switch (prop_id)
114 {
115 case PROP_COLOR:
116 g_value_set_object (value, &(priv->color));
117 break;
118
119 case PROP_WIDTH:
120 g_value_set_float (value, priv->width);
121 break;
122
123 default:
124 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
125 break;
126 }
127 }
128
129 /* GObject class and instance init */
130 static void
cb_border_effect_class_init(CbBorderEffectClass * klass)131 cb_border_effect_class_init (CbBorderEffectClass *klass)
132 {
133 ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
134 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
135 GParamSpec *pspec;
136
137 effect_class->post_paint = cb_border_effect_post_paint;
138
139 gobject_class->set_property = cb_border_effect_set_property;
140 gobject_class->get_property = cb_border_effect_get_property;
141 gobject_class->dispose = cb_border_effect_dispose;
142
143 g_type_class_add_private (klass, sizeof (CbBorderEffectPrivate));
144
145 /**
146 * CbBorderEffect:width:
147 *
148 * The width of the border
149 */
150 pspec = g_param_spec_float ("width",
151 "Width",
152 "The width of the border (in pixels)",
153 1.0, 100.0,
154 10.0,
155 G_PARAM_READWRITE);
156 obj_props[PROP_WIDTH] = pspec;
157 g_object_class_install_property (gobject_class, PROP_WIDTH, pspec);
158
159 /**
160 * CbBorderEffect:color:
161 *
162 * The color of the border
163 */
164 pspec = clutter_param_spec_color ("color",
165 "Color",
166 "The border color",
167 &grey,
168 G_PARAM_READWRITE);
169 obj_props[PROP_COLOR] = pspec;
170 g_object_class_install_property (gobject_class, PROP_COLOR, pspec);
171 }
172
173 static void
cb_border_effect_init(CbBorderEffect * self)174 cb_border_effect_init (CbBorderEffect *self)
175 {
176 CbBorderEffectPrivate *priv;
177
178 priv = self->priv = CB_BORDER_EFFECT_GET_PRIVATE (self);
179
180 priv->border = cogl_material_new ();
181
182 priv->color = grey;
183 }
184
185 /* called each time a property is set on the effect */
186 static void
cb_border_effect_update(CbBorderEffect * self)187 cb_border_effect_update (CbBorderEffect *self)
188 {
189 ClutterActor *actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (self));
190
191 if (actor != NULL)
192 clutter_actor_queue_redraw (actor);
193 }
194
195 /* public API */
196
197 /**
198 * cb_border_effect_new:
199 * @width: width of the border applied by the effect
200 * @color: a #ClutterColor
201 *
202 * Creates a new #ClutterEffect with the given @width
203 * and of the given @color.
204 */
205 ClutterEffect *
cb_border_effect_new(gfloat width,const ClutterColor * color)206 cb_border_effect_new (gfloat width,
207 const ClutterColor *color)
208 {
209 return g_object_new (CB_TYPE_BORDER_EFFECT,
210 "width", width,
211 "color", color,
212 NULL);
213 }
214
215 /**
216 * cb_border_effect_set_color:
217 * @self: a #CbBorderEffect
218 * @color: a #ClutterColor
219 *
220 * Sets the color of the border provided by the effect @self.
221 */
222 void
cb_border_effect_set_color(CbBorderEffect * self,const ClutterColor * color)223 cb_border_effect_set_color (CbBorderEffect *self,
224 const ClutterColor *color)
225 {
226 CbBorderEffectPrivate *priv;
227
228 g_return_if_fail (CB_IS_BORDER_EFFECT (self));
229 g_return_if_fail (color != NULL);
230
231 priv = CB_BORDER_EFFECT_GET_PRIVATE (self);
232
233 priv->color.red = color->red;
234 priv->color.green = color->green;
235 priv->color.blue = color->blue;
236 priv->color.alpha = color->alpha;
237
238 cogl_material_set_color4ub (priv->border,
239 color->red,
240 color->green,
241 color->blue,
242 color->alpha);
243
244 cb_border_effect_update (self);
245 }
246
247 /**
248 * cb_border_effect_get_color:
249 * @self: a #CbBorderEffect
250 * @color: return location for a #ClutterColor
251 *
252 * Retrieves the color of the border applied by the effect @self.
253 */
254 void
cb_border_effect_get_color(CbBorderEffect * self,ClutterColor * color)255 cb_border_effect_get_color (CbBorderEffect *self,
256 ClutterColor *color)
257 {
258 CbBorderEffectPrivate *priv;
259
260 g_return_if_fail (CB_IS_BORDER_EFFECT (self));
261
262 priv = CB_BORDER_EFFECT_GET_PRIVATE (self);
263
264 color->red = priv->color.red;
265 color->green = priv->color.green;
266 color->blue = priv->color.blue;
267 color->alpha = priv->color.alpha;
268 }
269
270 /**
271 * cb_border_effect_set_width:
272 * @self: a #CbBorderEffect
273 * @width: the width of the border
274 *
275 * Sets the width (in pixels) of the border applied by the effect @self.
276 */
277 void
cb_border_effect_set_width(CbBorderEffect * self,gfloat width)278 cb_border_effect_set_width (CbBorderEffect *self,
279 gfloat width)
280 {
281 CbBorderEffectPrivate *priv;
282
283 g_return_if_fail (CB_IS_BORDER_EFFECT (self));
284
285 priv = CB_BORDER_EFFECT_GET_PRIVATE (self);
286
287 priv->width = width;
288
289 cb_border_effect_update (self);
290 }
291
292 /**
293 * cb_border_effect_get_width:
294 * @self: a #CbBorderEffect
295 *
296 * Gets the width (in pixels) of the border applied by the effect @self.
297 *
298 * Return value: the border's width, or 0.0 if @self is not
299 * a #CbBorderEffect
300 */
301 gfloat
cb_border_effect_get_width(CbBorderEffect * self)302 cb_border_effect_get_width (CbBorderEffect *self)
303 {
304 CbBorderEffectPrivate *priv;
305
306 g_return_val_if_fail (CB_IS_BORDER_EFFECT (self), 0.0);
307
308 priv = CB_BORDER_EFFECT_GET_PRIVATE (self);
309
310 return priv->width;
311 }
312