1 /*
2 *
3 * Author: Giacomo Lozito <james@develia.org>, (C) 2005-2007
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21 #include "aosd_style.h"
22 #include "aosd_style_private.h"
23 #include "aosd_cfg.h"
24
25 #include <libaudcore/i18n.h>
26 #include <X11/Xlib.h>
27 #include <cairo/cairo.h>
28 #include <pango/pangocairo.h>
29 #include "ghosd.h"
30
31
32 /* HOW TO ADD A NEW DECORATION STYLE
33 --------------------------------------------------------------------------
34 First, add a new decoration style code; then, provide the decoration style
35 information by adding a new entry in the aosd_deco_styles[] array (name,
36 render function, etc.); add the new decoration style code in the array
37 of decoration style codes, and update the define containing the array size.
38 The render function uses three parameters; the Ghosd instance, the cairo
39 object you use to draw, and a aosd_deco_style_data_t object that contains
40 user-defined options (look into aosd_style.h and aosd_cfg.h for details).
41 Have fun! :)
42 */
43
44 /* prototypes of render functions */
45 static void aosd_deco_rfunc_rect ( Ghosd * , cairo_t * , aosd_deco_style_data_t * );
46 static void aosd_deco_rfunc_roundrect ( Ghosd * , cairo_t * , aosd_deco_style_data_t * );
47 static void aosd_deco_rfunc_concaverect ( Ghosd * , cairo_t * , aosd_deco_style_data_t * );
48 static void aosd_deco_rfunc_none ( Ghosd * , cairo_t * , aosd_deco_style_data_t * );
49
50 /* map decoration style codes to decoration objects */
51 aosd_deco_style_t aosd_deco_styles[] =
52 {
53 // AOSD_DECO_STYLE_RECT
54 { N_("Rectangle") ,
55 aosd_deco_rfunc_rect ,
56 2 , { 10 , 10 , 10 , 10 } },
57
58 // AOSD_DECO_STYLE_ROUNDRECT
59 { N_("Rounded Rectangle") ,
60 aosd_deco_rfunc_roundrect ,
61 2 , { 10 , 10 , 10 , 10 } },
62
63 // AOSD_DECO_STYLE_CONCAVERECT
64 { N_("Concave Rectangle") ,
65 aosd_deco_rfunc_concaverect ,
66 2 , { 10 , 10 , 10 , 10 } },
67
68 // AOSD_DECO_STYLE_NONE
69 { N_("None") ,
70 aosd_deco_rfunc_none ,
71 0 , { 2 , 2 , 2 , 2 } }
72 };
73
74 static_assert (aud::n_elems (aosd_deco_styles) == AOSD_NUM_DECO_STYLES, "update aosd_deco_styles");
75
76
77 /* DECORATION STYLE API */
78
79 void
aosd_deco_style_get_padding(int deco_code,int * ptop,int * pbottom,int * pleft,int * pright)80 aosd_deco_style_get_padding ( int deco_code ,
81 int * ptop , int * pbottom ,
82 int * pleft , int * pright )
83 {
84 if ( ptop != nullptr ) *ptop = aosd_deco_styles[deco_code].padding.top;
85 if ( pbottom != nullptr ) *pbottom = aosd_deco_styles[deco_code].padding.bottom;
86 if ( pleft != nullptr ) *pleft = aosd_deco_styles[deco_code].padding.left;
87 if ( pright != nullptr ) *pright = aosd_deco_styles[deco_code].padding.right;
88 return;
89 }
90
91
92 const char *
aosd_deco_style_get_desc(int deco_code)93 aosd_deco_style_get_desc ( int deco_code )
94 {
95 return aosd_deco_styles[deco_code].desc;
96 }
97
98
99 int
aosd_deco_style_get_numcol(int deco_code)100 aosd_deco_style_get_numcol ( int deco_code )
101 {
102 return aosd_deco_styles[deco_code].colors_num;
103 }
104
105
106 void
aosd_deco_style_render(int deco_code,void * ghosd,void * cr,void * user_data)107 aosd_deco_style_render ( int deco_code , void * ghosd , void * cr , void * user_data )
108 {
109 aosd_deco_styles[deco_code].render_func ((Ghosd *) ghosd, (cairo_t *) cr,
110 (aosd_deco_style_data_t *) user_data);
111 }
112
113
114 // sizing helper
115 static void
aosd_layout_size(PangoLayout * layout,int * width,int * height,int * bearing)116 aosd_layout_size( PangoLayout * layout , int * width , int * height , int * bearing )
117 {
118 PangoRectangle ink, log;
119
120 pango_layout_get_pixel_extents( layout , &ink , &log );
121
122 if ( width != nullptr )
123 *width = ink.width;
124 if ( height != nullptr )
125 *height = log.height;
126 if ( bearing != nullptr )
127 *bearing = -ink.x;
128 }
129
130
131 /* RENDER FUNCTIONS */
132
133 static void
aosd_deco_rfunc_rect(Ghosd * osd,cairo_t * cr,aosd_deco_style_data_t * data)134 aosd_deco_rfunc_rect( Ghosd * osd , cairo_t * cr , aosd_deco_style_data_t * data )
135 {
136 /* decoration information
137 ----------------------
138 draws a simple rectangular decoration; uses 2 colors
139 (user color 1 and 2) and 1 font (user font 1), with optional shadow
140 */
141 PangoLayout *osd_layout = data->layout;
142 aosd_color_t color0 = data->decoration->colors[0];
143 aosd_color_t color1 = data->decoration->colors[1];
144 aosd_color_t textcolor0 = data->text->fonts_color[0];
145 aosd_color_t shadowcolor0 = data->text->fonts_shadow_color[0];
146 gboolean draw_shadow = data->text->fonts_draw_shadow[0];
147 int width = 0, height = 0, bearing = 0;
148
149 aosd_layout_size( osd_layout , &width , &height , &bearing );
150
151 /* draw rectangle container */
152 cairo_set_source_rgba( cr , (double)color0.red / 65535 , (double)color0.green / 65535 ,
153 (double)color0.blue / 65535 , (double)color0.alpha / 65535 );
154 cairo_rectangle( cr , 0 , 0 ,
155 aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.left + width +
156 aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.right,
157 aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.top + height +
158 aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.bottom );
159 cairo_fill_preserve( cr );
160 cairo_set_source_rgba( cr , (double)color1.red / 65535 , (double)color1.green / 65535 ,
161 (double)color1.blue / 65535 , (double)color1.alpha / 65535 );
162 cairo_stroke( cr );
163
164 if ( draw_shadow == true )
165 {
166 /* draw text shadow */
167 cairo_set_source_rgba( cr , (double)shadowcolor0.red / 65535 , (double)shadowcolor0.green / 65535 ,
168 (double)shadowcolor0.blue / 65535 , (double)shadowcolor0.alpha / 65535 );
169 cairo_move_to( cr,
170 aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.left + bearing + 2 ,
171 aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.top + 2 );
172 pango_cairo_show_layout( cr , osd_layout );
173 }
174
175 /* draw text */
176 cairo_set_source_rgba( cr , (double)textcolor0.red / 65535 , (double)textcolor0.green / 65535 ,
177 (double)textcolor0.blue / 65535 , (double)textcolor0.alpha / 65535 );
178 cairo_move_to( cr,
179 aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.left + bearing ,
180 aosd_deco_styles[AOSD_DECO_STYLE_RECT].padding.top );
181 pango_cairo_show_layout( cr , osd_layout );
182 }
183
184
185 static void
aosd_deco_rfunc_roundrect(Ghosd * osd,cairo_t * cr,aosd_deco_style_data_t * data)186 aosd_deco_rfunc_roundrect ( Ghosd * osd , cairo_t * cr , aosd_deco_style_data_t * data )
187 {
188 /* decoration information
189 ----------------------
190 draws a rectangular decoration with rounded angles; uses 2 colors
191 (user color 1 and 2) and 1 font (user font 1), with optional shadow
192 */
193 PangoLayout *osd_layout = data->layout;
194 aosd_color_t color0 = data->decoration->colors[0];
195 aosd_color_t color1 = data->decoration->colors[1];
196 aosd_color_t textcolor0 = data->text->fonts_color[0];
197 aosd_color_t shadowcolor0 = data->text->fonts_shadow_color[0];
198 gboolean draw_shadow = data->text->fonts_draw_shadow[0];
199 int width = 0, height = 0, bearing = 0;
200
201 aosd_layout_size( osd_layout , &width , &height , &bearing );
202
203 /* draw rounded-rectangle container */
204 cairo_set_source_rgba( cr , (double)color0.red / 65535 , (double)color0.green / 65535 ,
205 (double)color0.blue / 65535 , (double)color0.alpha / 65535 );
206 cairo_move_to( cr , aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.left , 0 );
207 cairo_arc( cr , width + aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.left ,
208 aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.top ,
209 10. , -G_PI_2 , 0. );
210 cairo_arc( cr , width + aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.left ,
211 aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.top + height ,
212 10. , -4. * G_PI_2 , -3. * G_PI_2 );
213 cairo_arc( cr , aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.left ,
214 aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.top + height ,
215 10. , -3. * G_PI_2 , -2. * G_PI_2 );
216 cairo_arc( cr , aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.left ,
217 aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.top ,
218 10. , -2. * G_PI_2 , -G_PI_2 );
219 cairo_close_path( cr );
220 cairo_fill_preserve( cr );
221 cairo_set_source_rgba( cr , (double)color1.red / 65535 , (double)color1.green / 65535 ,
222 (double)color1.blue / 65535 , (double)color1.alpha / 65535 );
223 cairo_stroke( cr );
224
225 if ( draw_shadow == true )
226 {
227 /* draw text shadow */
228 cairo_set_source_rgba( cr , (double)shadowcolor0.red / 65535 , (double)shadowcolor0.green / 65535 ,
229 (double)shadowcolor0.blue / 65535 , (double)shadowcolor0.alpha / 65535 );
230 cairo_move_to( cr ,
231 aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.left + bearing + 2 ,
232 aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.top + 2 );
233 pango_cairo_show_layout( cr , osd_layout );
234 }
235
236 /* draw text */
237 cairo_set_source_rgba( cr , (double)textcolor0.red / 65535 , (double)textcolor0.green / 65535 ,
238 (double)textcolor0.blue / 65535 , (double)textcolor0.alpha / 65535 );
239 cairo_move_to( cr ,
240 aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.left + bearing ,
241 aosd_deco_styles[AOSD_DECO_STYLE_ROUNDRECT].padding.top );
242 pango_cairo_show_layout( cr , osd_layout );
243 }
244
245
246 static void
aosd_deco_rfunc_concaverect(Ghosd * osd,cairo_t * cr,aosd_deco_style_data_t * data)247 aosd_deco_rfunc_concaverect ( Ghosd * osd , cairo_t * cr , aosd_deco_style_data_t * data )
248 {
249 /* decoration information
250 ----------------------
251 draws a rectangle with concave angles; uses 2 colors
252 (user color 1 and 2) and 1 font (user font 1), with optional shadow
253 */
254 PangoLayout *osd_layout = data->layout;
255 aosd_color_t color0 = data->decoration->colors[0];
256 aosd_color_t color1 = data->decoration->colors[1];
257 aosd_color_t textcolor0 = data->text->fonts_color[0];
258 aosd_color_t shadowcolor0 = data->text->fonts_shadow_color[0];
259 gboolean draw_shadow = data->text->fonts_draw_shadow[0];
260 int width = 0, height = 0, bearing = 0;
261
262 aosd_layout_size( osd_layout , &width , &height , &bearing );
263
264 /* draw jigsaw-piece-like container */
265 cairo_set_source_rgba( cr , (double)color0.red / 65535 , (double)color0.green / 65535 ,
266 (double)color0.blue / 65535 , (double)color0.alpha / 65535 );
267 cairo_move_to( cr , aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.left , 0 );
268 cairo_arc_negative( cr , width + aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.left + 2 ,
269 aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.top - 2 ,
270 8. , -G_PI_2 , 0. );
271 cairo_arc_negative( cr , width + aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.left + 2 ,
272 aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.top + height + 2 ,
273 8. , -4. * G_PI_2 , -3. * G_PI_2 );
274 cairo_arc_negative( cr , aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.left - 2 ,
275 aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.top + height + 2 ,
276 8. , -3. * G_PI_2 , -2. * G_PI_2 );
277 cairo_arc_negative( cr , aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.left - 2 ,
278 aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.top - 2 ,
279 8. , -2. * G_PI_2 , -G_PI_2 );
280 cairo_close_path( cr );
281 cairo_fill_preserve( cr );
282 cairo_set_source_rgba( cr , (double)color1.red / 65535 , (double)color1.green / 65535 ,
283 (double)color1.blue / 65535 , (double)color1.alpha / 65535 );
284 cairo_stroke( cr );
285
286 if ( draw_shadow == true )
287 {
288 /* draw text shadow */
289 cairo_set_source_rgba( cr , (double)shadowcolor0.red / 65535 , (double)shadowcolor0.green / 65535 ,
290 (double)shadowcolor0.blue / 65535 , (double)shadowcolor0.alpha / 65535 );
291 cairo_move_to( cr ,
292 aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.left + bearing + 2 ,
293 aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.top + 2 );
294 pango_cairo_show_layout( cr , osd_layout );
295 }
296
297 /* draw text */
298 cairo_set_source_rgba( cr , (double)textcolor0.red / 65535 , (double)textcolor0.green / 65535 ,
299 (double)textcolor0.blue / 65535 , (double)textcolor0.alpha / 65535 );
300 cairo_move_to( cr ,
301 aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.left + bearing ,
302 aosd_deco_styles[AOSD_DECO_STYLE_CONCAVERECT].padding.top );
303 pango_cairo_show_layout( cr , osd_layout );
304 }
305
306
307 static void
aosd_deco_rfunc_none(Ghosd * osd,cairo_t * cr,aosd_deco_style_data_t * data)308 aosd_deco_rfunc_none ( Ghosd * osd , cairo_t * cr , aosd_deco_style_data_t * data )
309 {
310 /* decoration information
311 ----------------------
312 does not draw any decoration around text; uses 0 colors
313 and 1 font (user font 1), with optional shadow
314 */
315 PangoLayout *osd_layout = data->layout;
316 aosd_color_t textcolor0 = data->text->fonts_color[0];
317 aosd_color_t shadowcolor0 = data->text->fonts_shadow_color[0];
318 gboolean draw_shadow = data->text->fonts_draw_shadow[0];
319 int width = 0, height = 0, bearing = 0;
320
321 aosd_layout_size( osd_layout , &width , &height , &bearing );
322
323 if ( draw_shadow == true )
324 {
325 /* draw text shadow */
326 cairo_set_source_rgba( cr , (double)shadowcolor0.red / 65535 , (double)shadowcolor0.green / 65535 ,
327 (double)shadowcolor0.blue / 65535 , (double)shadowcolor0.alpha / 65535 );
328 cairo_move_to( cr ,
329 aosd_deco_styles[AOSD_DECO_STYLE_NONE].padding.left + bearing + 2 ,
330 aosd_deco_styles[AOSD_DECO_STYLE_NONE].padding.top + 2 );
331 pango_cairo_show_layout( cr , osd_layout );
332 }
333
334 /* draw text */
335 cairo_set_source_rgba( cr , (double)textcolor0.red / 65535 , (double)textcolor0.green / 65535 ,
336 (double)textcolor0.blue / 65535 , (double)textcolor0.alpha / 65535 );
337 cairo_move_to( cr ,
338 aosd_deco_styles[AOSD_DECO_STYLE_NONE].padding.left + bearing ,
339 aosd_deco_styles[AOSD_DECO_STYLE_NONE].padding.top );
340 pango_cairo_show_layout( cr , osd_layout );
341 }
342