1 /*
2  *  label-text.c
3  *  Copyright (C) 2001-2009  Jim Evins <evins@snaught.com>.
4  *
5  *  This file is part of gLabels.
6  *
7  *  gLabels is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  gLabels is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with gLabels.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 
23 #include "label-text.h"
24 
25 #include <glib/gi18n.h>
26 #include <glib.h>
27 #include <pango/pango.h>
28 #include <math.h>
29 #include <string.h>
30 
31 #include "font-util.h"
32 #include "font-history.h"
33 
34 #include "debug.h"
35 
36 
37 /*========================================================*/
38 /* Private macros and constants.                          */
39 /*========================================================*/
40 
41 #define FONT_SCALE (72.0/96.0)
42 
43 #define HANDLE_OUTLINE_RGBA_ARGS   0.5,   0.5,   0.5,   0.75
44 #define HANDLE_OUTLINE_WIDTH_PIXELS   2.0
45 
46 #define SELECTION_SLOP_PIXELS 4.0
47 
48 
49 /*========================================================*/
50 /* Private types.                                         */
51 /*========================================================*/
52 
53 struct _glLabelTextPrivate {
54 
55         GtkTextTagTable *tag_table;
56         GtkTextBuffer   *buffer;
57 
58 	gchar           *font_family;
59 	gdouble          font_size;
60 	PangoWeight      font_weight;
61 	gboolean         font_italic_flag;
62 	PangoAlignment   align;
63 	glValignment     valign;
64 	glColorNode     *color_node;
65 	gdouble          line_spacing;
66 	gboolean         auto_shrink;
67 
68         gboolean         size_changed;
69         gdouble          w;
70         gdouble          h;
71 
72         gboolean         checkpoint_flag;
73 };
74 
75 
76 /*========================================================*/
77 /* Private globals.                                       */
78 /*========================================================*/
79 
80 
81 /*========================================================*/
82 /* Private function prototypes.                           */
83 /*========================================================*/
84 
85 static void gl_label_text_finalize      (GObject          *object);
86 
87 static void copy                        (glLabelObject    *dst_object,
88 					 glLabelObject    *src_object);
89 
90 static void buffer_begin_user_action_cb (GtkTextBuffer    *textbuffer,
91                                          glLabelText      *ltext);
92 
93 static void buffer_changed_cb           (GtkTextBuffer    *textbuffer,
94 					 glLabelText      *ltext);
95 
96 static void get_size                    (glLabelObject    *object,
97 					 gdouble          *w,
98 					 gdouble          *h);
99 
100 static void set_font_family             (glLabelObject    *object,
101 					 const gchar      *font_family,
102                                          gboolean          checkpoint);
103 
104 static void set_font_size               (glLabelObject    *object,
105 					 gdouble           font_size,
106                                          gboolean          checkpoint);
107 
108 static void set_font_weight             (glLabelObject    *object,
109 					 PangoWeight       font_weight,
110                                          gboolean          checkpoint);
111 
112 static void set_font_italic_flag        (glLabelObject    *object,
113 					 gboolean          font_italic_flag,
114                                          gboolean          checkpoint);
115 
116 static void set_text_alignment          (glLabelObject    *object,
117 					 PangoAlignment    text_alignment,
118                                          gboolean          checkpoint);
119 
120 static void set_text_valignment         (glLabelObject    *object,
121 					 glValignment      text_valignment,
122                                          gboolean          checkpoint);
123 
124 static void set_text_line_spacing       (glLabelObject    *object,
125 					 gdouble           text_line_spacing,
126                                          gboolean          checkpoint);
127 
128 static void set_text_color              (glLabelObject    *object,
129 					 glColorNode      *text_color_node,
130                                          gboolean          checkpoint);
131 
132 static gchar          *get_font_family             (glLabelObject    *object);
133 
134 static gdouble         get_font_size               (glLabelObject    *object);
135 
136 static PangoWeight     get_font_weight             (glLabelObject    *object);
137 
138 static gboolean        get_font_italic_flag        (glLabelObject    *object);
139 
140 static PangoAlignment  get_text_alignment          (glLabelObject    *object);
141 
142 static glValignment    get_text_valignment         (glLabelObject    *object);
143 
144 static gdouble         get_text_line_spacing       (glLabelObject    *object);
145 
146 static glColorNode*    get_text_color              (glLabelObject    *object);
147 
148 static void            layout_text                 (glLabelText      *this,
149                                                     cairo_t          *cr,
150                                                     gboolean          screen_flag,
151                                                     glMergeRecord    *record,
152                                                     gboolean          path_only_flag);
153 
154 static void            draw_object                 (glLabelObject    *object,
155                                                     cairo_t          *cr,
156                                                     gboolean          screen_flag,
157                                                     glMergeRecord    *record);
158 
159 static void            draw_shadow                 (glLabelObject    *object,
160                                                     cairo_t          *cr,
161                                                     gboolean          screen_flag,
162                                                     glMergeRecord    *record);
163 
164 static void            draw_text_real              (glLabelObject    *object,
165                                                     cairo_t          *cr,
166                                                     gboolean          screen_flag,
167                                                     glMergeRecord    *record,
168                                                     guint             color);
169 
170 static gdouble         auto_shrink_font_size       (cairo_t          *cr,
171                                                     gchar            *family,
172                                                     gdouble           size,
173                                                     PangoWeight       weight,
174                                                     PangoStyle        style,
175                                                     gdouble           line_spacing,
176                                                     gchar            *text,
177                                                     gdouble           width,
178                                                     gdouble           height);
179 
180 static gboolean        object_at                   (glLabelObject    *object,
181                                                     cairo_t          *cr,
182                                                     gdouble           x_pixels,
183                                                     gdouble           y_pixels);
184 
185 static void            draw_handles                (glLabelObject    *object,
186                                                     cairo_t          *cr);
187 
188 
189 /*****************************************************************************/
190 /* Object infrastructure.                                                    */
191 /*****************************************************************************/
G_DEFINE_TYPE(glLabelText,gl_label_text,GL_TYPE_LABEL_OBJECT)192 G_DEFINE_TYPE (glLabelText, gl_label_text, GL_TYPE_LABEL_OBJECT)
193 
194 
195 /*****************************************************************************/
196 /* Class Init Function.                                                      */
197 /*****************************************************************************/
198 static void
199 gl_label_text_class_init (glLabelTextClass *class)
200 {
201 	GObjectClass       *object_class       = G_OBJECT_CLASS (class);
202 	glLabelObjectClass *label_object_class = GL_LABEL_OBJECT_CLASS (class);
203 
204 	gl_label_text_parent_class = g_type_class_peek_parent (class);
205 
206 	label_object_class->copy                  = copy;
207 
208 	label_object_class->get_size              = get_size;
209 
210 	label_object_class->set_font_family       = set_font_family;
211 	label_object_class->set_font_size         = set_font_size;
212 	label_object_class->set_font_weight       = set_font_weight;
213 	label_object_class->set_font_italic_flag  = set_font_italic_flag;
214 	label_object_class->set_text_alignment    = set_text_alignment;
215 	label_object_class->set_text_valignment   = set_text_valignment;
216 	label_object_class->set_text_line_spacing = set_text_line_spacing;
217 	label_object_class->set_text_color        = set_text_color;
218 	label_object_class->get_font_family       = get_font_family;
219 	label_object_class->get_font_size         = get_font_size;
220 	label_object_class->get_font_weight       = get_font_weight;
221 	label_object_class->get_font_italic_flag  = get_font_italic_flag;
222 	label_object_class->get_text_alignment    = get_text_alignment;
223 	label_object_class->get_text_valignment   = get_text_valignment;
224 	label_object_class->get_text_line_spacing = get_text_line_spacing;
225 	label_object_class->get_text_color        = get_text_color;
226         label_object_class->draw_object           = draw_object;
227         label_object_class->draw_shadow           = draw_shadow;
228         label_object_class->object_at             = object_at;
229         label_object_class->draw_handles          = draw_handles;
230 
231 	object_class->finalize = gl_label_text_finalize;
232 }
233 
234 
235 /*****************************************************************************/
236 /* Object Instance Init Function.                                            */
237 /*****************************************************************************/
238 static void
gl_label_text_init(glLabelText * ltext)239 gl_label_text_init (glLabelText *ltext)
240 {
241 	ltext->priv = g_new0 (glLabelTextPrivate, 1);
242 
243 	ltext->priv->tag_table         = gtk_text_tag_table_new ();
244 	ltext->priv->buffer            = gtk_text_buffer_new (ltext->priv->tag_table);
245 
246         ltext->priv->size_changed      = TRUE;
247 
248         ltext->priv->checkpoint_flag   = TRUE;
249 
250 	g_signal_connect (G_OBJECT(ltext->priv->buffer), "begin-user-action",
251 			  G_CALLBACK(buffer_begin_user_action_cb), ltext);
252 	g_signal_connect (G_OBJECT(ltext->priv->buffer), "changed",
253 			  G_CALLBACK(buffer_changed_cb), ltext);
254 }
255 
256 
257 /*****************************************************************************/
258 /* Finalize Method.                                                          */
259 /*****************************************************************************/
260 static void
gl_label_text_finalize(GObject * object)261 gl_label_text_finalize (GObject *object)
262 {
263 	glLabelText *ltext = GL_LABEL_TEXT (object);
264 
265 	g_return_if_fail (object && GL_IS_LABEL_TEXT (object));
266 
267 	g_object_unref (ltext->priv->tag_table);
268 	g_object_unref (ltext->priv->buffer);
269 	g_free (ltext->priv->font_family);
270 	gl_color_node_free (&(ltext->priv->color_node));
271 	g_free (ltext->priv);
272 
273 	G_OBJECT_CLASS (gl_label_text_parent_class)->finalize (object);
274 }
275 
276 
277 /*****************************************************************************/
278 /** New Object Generator.                                                    */
279 /*****************************************************************************/
280 GObject *
gl_label_text_new(glLabel * label,gboolean checkpoint)281 gl_label_text_new (glLabel *label,
282                    gboolean checkpoint)
283 {
284 	glLabelText   *ltext;
285         glColorNode   *color_node;
286 
287 	ltext = g_object_new (gl_label_text_get_type(), NULL);
288 
289         if (label != NULL)
290         {
291                 if ( checkpoint )
292                 {
293                         gl_label_checkpoint (label, _("Create text object"));
294                 }
295 
296                 color_node = gl_color_node_new_default ();
297 
298                 color_node->color = gl_label_get_default_text_color (label);
299 
300                 ltext->priv->font_family      = gl_label_get_default_font_family (label);
301                 ltext->priv->font_size        = gl_label_get_default_font_size (label);
302                 ltext->priv->font_weight      = gl_label_get_default_font_weight (label);
303                 ltext->priv->font_italic_flag = gl_label_get_default_font_italic_flag (label);
304                 ltext->priv->align            = gl_label_get_default_text_alignment (label);
305                 ltext->priv->valign           = gl_label_get_default_text_valignment (label);
306 		ltext->priv->color_node       = color_node;
307                 ltext->priv->line_spacing     = gl_label_get_default_text_line_spacing (label);
308 
309                 gl_label_add_object (label, GL_LABEL_OBJECT (ltext));
310                 gl_label_object_set_parent (GL_LABEL_OBJECT (ltext), label);
311         }
312 
313 	return G_OBJECT (ltext);
314 }
315 
316 
317 /*****************************************************************************/
318 /* Copy object contents.                                                     */
319 /*****************************************************************************/
320 static void
copy(glLabelObject * dst_object,glLabelObject * src_object)321 copy (glLabelObject *dst_object,
322       glLabelObject *src_object)
323 {
324 	glLabelText      *ltext     = (glLabelText *)src_object;
325 	glLabelText      *new_ltext = (glLabelText *)dst_object;
326 	GList            *lines;
327 	glColorNode      *text_color_node;
328 
329 	gl_debug (DEBUG_LABEL, "START");
330 
331 	g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
332 	g_return_if_fail (new_ltext && GL_IS_LABEL_TEXT (new_ltext));
333 
334 	lines = gl_label_text_get_lines (ltext);
335 	text_color_node = get_text_color (src_object);
336 	gl_label_text_set_lines (new_ltext, lines, FALSE);
337 
338 	new_ltext->priv->font_family      = g_strdup (ltext->priv->font_family);
339 	new_ltext->priv->font_size        = ltext->priv->font_size;
340 	new_ltext->priv->font_weight      = ltext->priv->font_weight;
341 	new_ltext->priv->font_italic_flag = ltext->priv->font_italic_flag;
342 	set_text_color (dst_object, text_color_node, FALSE);
343 	new_ltext->priv->align            = ltext->priv->align;
344 	new_ltext->priv->valign           = ltext->priv->valign;
345 	new_ltext->priv->line_spacing     = ltext->priv->line_spacing;
346 	new_ltext->priv->auto_shrink      = ltext->priv->auto_shrink;
347 
348         new_ltext->priv->size_changed     = ltext->priv->size_changed;
349         new_ltext->priv->w                = ltext->priv->w;
350         new_ltext->priv->h                = ltext->priv->h;
351 
352 	gl_color_node_free (&text_color_node);
353 	gl_text_node_lines_free (&lines);
354 
355 	gl_debug (DEBUG_LABEL, "END");
356 }
357 
358 
359 /*****************************************************************************/
360 /* Set object params.                                                        */
361 /*****************************************************************************/
362 void
gl_label_text_set_lines(glLabelText * ltext,GList * lines,gboolean checkpoint)363 gl_label_text_set_lines (glLabelText *ltext,
364 			 GList       *lines,
365                          gboolean     checkpoint)
366 {
367 	gchar *text;
368 
369 	gl_debug (DEBUG_LABEL, "START");
370 
371 	g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
372 
373         ltext->priv->checkpoint_flag = checkpoint;
374 
375 	text = gl_text_node_lines_expand (lines, NULL);
376 	gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
377 	g_free (text);
378 
379         ltext->priv->size_changed = TRUE;
380 
381         ltext->priv->checkpoint_flag = TRUE;
382 
383 	gl_debug (DEBUG_LABEL, "END");
384 }
385 
386 
387 void
gl_label_text_set_text(glLabelText * ltext,const gchar * text,gboolean checkpoint)388 gl_label_text_set_text (glLabelText *ltext,
389                         const gchar *text,
390                         gboolean     checkpoint)
391 {
392 	gl_debug (DEBUG_LABEL, "START");
393 
394 	g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
395 
396         ltext->priv->checkpoint_flag = checkpoint;
397 
398 	gtk_text_buffer_set_text (ltext->priv->buffer, text, -1);
399 
400         ltext->priv->size_changed = TRUE;
401 
402         ltext->priv->checkpoint_flag = TRUE;
403 
404 	gl_debug (DEBUG_LABEL, "END");
405 }
406 
407 
408 /*****************************************************************************/
409 /* Get object params.                                                        */
410 /*****************************************************************************/
411 GtkTextBuffer *
gl_label_text_get_buffer(glLabelText * ltext)412 gl_label_text_get_buffer (glLabelText *ltext)
413 {
414 	g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
415 
416 	return ltext->priv->buffer;
417 }
418 
419 
420 GList *
gl_label_text_get_lines(glLabelText * ltext)421 gl_label_text_get_lines (glLabelText *ltext)
422 {
423 	GtkTextIter  start, end;
424 	gchar       *text;
425 	GList       *lines;
426 
427 	g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
428 
429 	gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
430 	text = gtk_text_buffer_get_text (ltext->priv->buffer,
431 					 &start, &end, FALSE);
432 	lines = gl_text_node_lines_new_from_text (text);
433 	g_free (text);
434 
435 	return lines;
436 }
437 
438 
439 gchar *
gl_label_text_get_text(glLabelText * ltext)440 gl_label_text_get_text (glLabelText      *ltext)
441 {
442 	GtkTextIter  start, end;
443 	gchar       *text;
444 
445 	g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
446 
447 	gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
448 	text = gtk_text_buffer_get_text (ltext->priv->buffer,
449 					 &start, &end, FALSE);
450 
451 	return text;
452 }
453 
454 
455 /*****************************************************************************/
456 /* Text buffer "changed" callback.                                           */
457 /*****************************************************************************/
458 static void
buffer_begin_user_action_cb(GtkTextBuffer * textbuffer,glLabelText * ltext)459 buffer_begin_user_action_cb (GtkTextBuffer *textbuffer,
460                              glLabelText   *ltext)
461 {
462         glLabel *label;
463 
464         if ( ltext->priv->checkpoint_flag )
465         {
466                 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
467                 gl_label_checkpoint (label, _("Typing"));
468         }
469 }
470 
471 
472 /*****************************************************************************/
473 /* Text buffer "changed" callback.                                           */
474 /*****************************************************************************/
475 static void
buffer_changed_cb(GtkTextBuffer * textbuffer,glLabelText * ltext)476 buffer_changed_cb (GtkTextBuffer *textbuffer,
477                    glLabelText   *ltext)
478 {
479         ltext->priv->size_changed = TRUE;
480 
481 	gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
482 }
483 
484 
485 /*****************************************************************************/
486 /* Get object size method.                                                   */
487 /*****************************************************************************/
488 static void
get_size(glLabelObject * object,gdouble * w,gdouble * h)489 get_size (glLabelObject *object,
490 	  gdouble       *w,
491 	  gdouble       *h)
492 {
493 	glLabelText          *ltext = (glLabelText *)object;
494 	PangoFontMap         *fontmap;
495 	PangoContext         *context;
496 	cairo_font_options_t *options;
497         PangoStyle            style;
498         PangoLayout          *layout;
499         PangoFontDescription *desc;
500         gdouble               font_size;
501         gdouble               line_spacing;
502 	GtkTextIter           start, end;
503 	gchar                *text;
504 	gdouble               w_parent, h_parent;
505 	gint                  iw, ih;
506 
507 	gl_debug (DEBUG_LABEL, "START");
508 
509 	g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
510 
511 	gl_label_object_get_raw_size (object, &w_parent, &h_parent);
512 
513 	if ( (w_parent != 0.0) || (h_parent != 0.0) ) {
514 		*w = w_parent;
515 		*h = h_parent;
516 		return;
517 	}
518 
519         if (!ltext->priv->size_changed)
520         {
521                 *w = ltext->priv->w;
522                 *h = ltext->priv->h;
523 		return;
524         }
525 
526         font_size = GL_LABEL_TEXT (object)->priv->font_size * FONT_SCALE;
527         line_spacing = GL_LABEL_TEXT (object)->priv->line_spacing;
528 
529 	gtk_text_buffer_get_bounds (ltext->priv->buffer, &start, &end);
530 	text = gtk_text_buffer_get_text (ltext->priv->buffer,
531 					 &start, &end, FALSE);
532 
533 
534 	fontmap = pango_cairo_font_map_new ();
535 	context = pango_font_map_create_context (PANGO_FONT_MAP (fontmap));
536 	options = cairo_font_options_create ();
537         cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE);
538         cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
539 	pango_cairo_context_set_font_options (context, options);
540 	cairo_font_options_destroy (options);
541 
542 	layout = pango_layout_new (context);
543 
544         style = GL_LABEL_TEXT (object)->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
545 
546 	desc = pango_font_description_new ();
547 	pango_font_description_set_family (desc, GL_LABEL_TEXT (object)->priv->font_family);
548 	pango_font_description_set_weight (desc, GL_LABEL_TEXT (object)->priv->font_weight);
549 	pango_font_description_set_style  (desc, style);
550 	pango_font_description_set_size   (desc, font_size * PANGO_SCALE);
551 	pango_layout_set_font_description (layout, desc);
552 	pango_font_description_free       (desc);
553 
554         pango_layout_set_spacing (layout, font_size * (line_spacing-1) * PANGO_SCALE);
555 	pango_layout_set_text (layout, text, -1);
556 	pango_layout_get_size (layout, &iw, &ih);
557 	*w = ltext->priv->w = iw / PANGO_SCALE + 2*GL_LABEL_TEXT_MARGIN;
558 	*h = ltext->priv->h = ih / PANGO_SCALE;
559         ltext->priv->size_changed = FALSE;
560 
561 	g_object_unref (layout);
562 	g_object_unref (context);
563 	g_object_unref (fontmap);
564 	g_free (text);
565 
566 	gl_debug (DEBUG_LABEL, "END");
567 }
568 
569 
570 /*****************************************************************************/
571 /* Set font family method.                                                   */
572 /*****************************************************************************/
573 static void
set_font_family(glLabelObject * object,const gchar * font_family,gboolean checkpoint)574 set_font_family (glLabelObject *object,
575 		 const gchar   *font_family,
576                  gboolean       checkpoint)
577 {
578 	glLabelText    *ltext = (glLabelText *)object;
579 	gchar          *good_font_family;
580         glLabel        *label;
581 
582 	gl_debug (DEBUG_LABEL, "START");
583 
584 	g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
585 	g_return_if_fail (font_family);
586 
587         good_font_family = gl_font_util_validate_family (font_family);
588 
589 	if (ltext->priv->font_family) {
590 		if (strcmp (ltext->priv->font_family, good_font_family) == 0) {
591 			g_free (good_font_family);
592 			gl_debug (DEBUG_LABEL, "END (no change)");
593 			return;
594 		}
595 		g_free (ltext->priv->font_family);
596 	}
597 
598         if ( checkpoint )
599         {
600                 label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
601                 gl_label_checkpoint (label, _("Font family"));
602         }
603 
604 	ltext->priv->font_family = g_strdup (good_font_family);
605 	g_free (good_font_family);
606 
607 	gl_debug (DEBUG_LABEL, "new font family = %s", ltext->priv->font_family);
608 
609         ltext->priv->size_changed = TRUE;
610 
611         gl_font_history_model_add_family (gl_font_history, ltext->priv->font_family);
612 
613 	gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
614 
615 	gl_debug (DEBUG_LABEL, "END");
616 }
617 
618 
619 /*****************************************************************************/
620 /* Set font size method.                                                     */
621 /*****************************************************************************/
622 static void
set_font_size(glLabelObject * object,gdouble font_size,gboolean checkpoint)623 set_font_size (glLabelObject *object,
624 	       gdouble        font_size,
625                gboolean       checkpoint)
626 {
627 	glLabelText    *ltext = (glLabelText *)object;
628         glLabel        *label;
629 
630 	gl_debug (DEBUG_LABEL, "START");
631 
632 	g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
633 
634 	if (ltext->priv->font_size != font_size)
635         {
636                 if ( checkpoint )
637                 {
638                         label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
639                         gl_label_checkpoint (label, _("Font size"));
640                 }
641 
642                 ltext->priv->size_changed = TRUE;
643 
644 		ltext->priv->font_size = font_size;
645 		gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
646 	}
647 
648 	gl_debug (DEBUG_LABEL, "END");
649 }
650 
651 
652 /*****************************************************************************/
653 /* Set font weight method.                                                   */
654 /*****************************************************************************/
655 static void
set_font_weight(glLabelObject * object,PangoWeight font_weight,gboolean checkpoint)656 set_font_weight (glLabelObject   *object,
657 		 PangoWeight      font_weight,
658                  gboolean         checkpoint)
659 {
660 	glLabelText    *ltext = (glLabelText *)object;
661         glLabel        *label;
662 
663 	gl_debug (DEBUG_LABEL, "START");
664 
665 	g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
666 
667 	if (ltext->priv->font_weight != font_weight)
668         {
669                 if ( checkpoint )
670                 {
671                         label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
672                         gl_label_checkpoint (label, _("Font weight"));
673                 }
674 
675                 ltext->priv->size_changed = TRUE;
676 
677 		ltext->priv->font_weight = font_weight;
678 		gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
679 	}
680 
681 	gl_debug (DEBUG_LABEL, "END");
682 }
683 
684 
685 /*****************************************************************************/
686 /* Set font italic flag method.                                              */
687 /*****************************************************************************/
688 static void
set_font_italic_flag(glLabelObject * object,gboolean font_italic_flag,gboolean checkpoint)689 set_font_italic_flag (glLabelObject *object,
690 		      gboolean       font_italic_flag,
691                       gboolean       checkpoint)
692 {
693 	glLabelText    *ltext = (glLabelText *)object;
694         glLabel        *label;
695 
696 	gl_debug (DEBUG_LABEL, "START");
697 
698 	g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
699 
700 	if (ltext->priv->font_italic_flag != font_italic_flag)
701         {
702                 if ( checkpoint )
703                 {
704                         label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
705                         gl_label_checkpoint (label, _("Italic"));
706                 }
707 
708                 ltext->priv->size_changed = TRUE;
709 
710 		ltext->priv->font_italic_flag = font_italic_flag;
711 		gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
712 	}
713 
714 	gl_debug (DEBUG_LABEL, "END");
715 }
716 
717 
718 /*****************************************************************************/
719 /* Set text alignment method.                                                */
720 /*****************************************************************************/
721 static void
set_text_alignment(glLabelObject * object,PangoAlignment text_alignment,gboolean checkpoint)722 set_text_alignment (glLabelObject    *object,
723 		    PangoAlignment    text_alignment,
724                     gboolean          checkpoint)
725 {
726 	glLabelText    *ltext = (glLabelText *)object;
727         glLabel        *label;
728 
729 	gl_debug (DEBUG_LABEL, "START");
730 
731 	g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
732 
733 	if (ltext->priv->align != text_alignment)
734         {
735                 if ( checkpoint )
736                 {
737                         label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
738                         gl_label_checkpoint (label, _("Align text"));
739                 }
740 
741                 ltext->priv->size_changed = TRUE;
742 
743 		ltext->priv->align = text_alignment;
744 		gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
745 	}
746 
747 	gl_debug (DEBUG_LABEL, "END");
748 }
749 
750 
751 /*****************************************************************************/
752 /* Set vertical text alignment method.                                       */
753 /*****************************************************************************/
754 static void
set_text_valignment(glLabelObject * object,glValignment text_valignment,gboolean checkpoint)755 set_text_valignment (glLabelObject    *object,
756 		     glValignment      text_valignment,
757                      gboolean          checkpoint)
758 {
759 	glLabelText    *ltext = (glLabelText *)object;
760         glLabel        *label;
761 
762 	gl_debug (DEBUG_LABEL, "START");
763 
764 	g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
765 
766 	if (ltext->priv->valign != text_valignment)
767         {
768                 if ( checkpoint )
769                 {
770                         label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
771                         gl_label_checkpoint (label, _("Vertically align text"));
772                 }
773 
774                 ltext->priv->size_changed = TRUE;
775 
776 		ltext->priv->valign = text_valignment;
777 		gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
778 	}
779 
780 	gl_debug (DEBUG_LABEL, "END");
781 }
782 
783 
784 /*****************************************************************************/
785 /* Set text line spacing method.                                             */
786 /*****************************************************************************/
787 static void
set_text_line_spacing(glLabelObject * object,gdouble line_spacing,gboolean checkpoint)788 set_text_line_spacing (glLabelObject *object,
789 	               gdouble        line_spacing,
790                        gboolean       checkpoint)
791 {
792 	glLabelText    *ltext = (glLabelText *)object;
793         glLabel        *label;
794 
795 	gl_debug (DEBUG_LABEL, "START");
796 
797 	g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
798 
799 	if (ltext->priv->line_spacing != line_spacing)
800         {
801                 if ( checkpoint )
802                 {
803                         label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
804                         gl_label_checkpoint (label, _("Line spacing"));
805                 }
806 
807                 ltext->priv->size_changed = TRUE;
808 
809 		ltext->priv->line_spacing = line_spacing;
810 		gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
811 	}
812 
813 	gl_debug (DEBUG_LABEL, "END");
814 }
815 
816 
817 /*****************************************************************************/
818 /* Set text color method.                                                    */
819 /*****************************************************************************/
820 static void
set_text_color(glLabelObject * object,glColorNode * text_color_node,gboolean checkpoint)821 set_text_color (glLabelObject *object,
822 		glColorNode   *text_color_node,
823                 gboolean       checkpoint)
824 {
825 	glLabelText    *ltext = (glLabelText *)object;
826         glLabel        *label;
827 
828 	gl_debug (DEBUG_LABEL, "START");
829 
830 	g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
831 
832 	if (!gl_color_node_equal (ltext->priv->color_node, text_color_node))
833         {
834                 if ( checkpoint )
835                 {
836                         label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
837                         gl_label_checkpoint (label, _("Text color"));
838                 }
839 
840 		gl_color_node_free (&(ltext->priv->color_node));
841 		ltext->priv->color_node = gl_color_node_dup (text_color_node);
842 
843 		gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
844 	}
845 
846 	gl_debug (DEBUG_LABEL, "END");
847 }
848 
849 
850 /*****************************************************************************/
851 /* Get font family method.                                                   */
852 /*****************************************************************************/
853 static gchar *
get_font_family(glLabelObject * object)854 get_font_family (glLabelObject *object)
855 {
856 	glLabelText    *ltext = (glLabelText *)object;
857 
858 	gl_debug (DEBUG_LABEL, "");
859 
860 	g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), NULL);
861 
862 	return g_strdup (ltext->priv->font_family);
863 }
864 
865 
866 /*****************************************************************************/
867 /* Get font size method.                                                     */
868 /*****************************************************************************/
869 static gdouble
get_font_size(glLabelObject * object)870 get_font_size (glLabelObject *object)
871 {
872 	glLabelText    *ltext = (glLabelText *)object;
873 
874 	gl_debug (DEBUG_LABEL, "");
875 
876 	g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
877 
878 	return ltext->priv->font_size;
879 }
880 
881 
882 /*****************************************************************************/
883 /* Get font weight method.                                                   */
884 /*****************************************************************************/
885 static PangoWeight
get_font_weight(glLabelObject * object)886 get_font_weight (glLabelObject   *object)
887 {
888 	glLabelText    *ltext = (glLabelText *)object;
889 
890 	gl_debug (DEBUG_LABEL, "");
891 
892 	g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), PANGO_WEIGHT_NORMAL);
893 
894 	return ltext->priv->font_weight;
895 }
896 
897 
898 /*****************************************************************************/
899 /* Get font italic flag method.                                              */
900 /*****************************************************************************/
901 static gboolean
get_font_italic_flag(glLabelObject * object)902 get_font_italic_flag (glLabelObject *object)
903 {
904 	glLabelText    *ltext = (glLabelText *)object;
905 
906 	gl_debug (DEBUG_LABEL, "");
907 
908 	g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), FALSE);
909 
910 	return ltext->priv->font_italic_flag;
911 }
912 
913 
914 /*****************************************************************************/
915 /* Get text alignment method.                                                */
916 /*****************************************************************************/
917 static PangoAlignment
get_text_alignment(glLabelObject * object)918 get_text_alignment (glLabelObject    *object)
919 {
920 	glLabelText    *ltext = (glLabelText *)object;
921 
922 	gl_debug (DEBUG_LABEL, "");
923 
924 	g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
925 
926 	return ltext->priv->align;
927 }
928 
929 
930 /*****************************************************************************/
931 /* Get vertical text alignment method.                                       */
932 /*****************************************************************************/
933 static glValignment
get_text_valignment(glLabelObject * object)934 get_text_valignment (glLabelObject    *object)
935 {
936 	glLabelText    *ltext = (glLabelText *)object;
937 
938 	gl_debug (DEBUG_LABEL, "");
939 
940 	g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), GTK_JUSTIFY_LEFT);
941 
942 	return ltext->priv->valign;
943 }
944 
945 
946 /*****************************************************************************/
947 /* Get text line spacing method.                                             */
948 /*****************************************************************************/
949 static gdouble
get_text_line_spacing(glLabelObject * object)950 get_text_line_spacing (glLabelObject *object)
951 {
952 	glLabelText    *ltext = (glLabelText *)object;
953 
954 	gl_debug (DEBUG_LABEL, "");
955 
956 	g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0.0);
957 
958 	return ltext->priv->line_spacing;
959 }
960 
961 
962 /*****************************************************************************/
963 /* Get text color method.                                                    */
964 /*****************************************************************************/
965 static glColorNode*
get_text_color(glLabelObject * object)966 get_text_color (glLabelObject *object)
967 {
968 	glLabelText    *ltext = (glLabelText *)object;
969 
970 	gl_debug (DEBUG_LABEL, "");
971 
972 	g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
973 
974 	return gl_color_node_dup (ltext->priv->color_node);
975 }
976 
977 
978 /*****************************************************************************/
979 /* Set auto shrink flag.                                                     */
980 /*****************************************************************************/
981 void
gl_label_text_set_auto_shrink(glLabelText * ltext,gboolean auto_shrink,gboolean checkpoint)982 gl_label_text_set_auto_shrink (glLabelText      *ltext,
983 			       gboolean          auto_shrink,
984                                gboolean          checkpoint)
985 {
986         glLabel *label;
987 
988 	gl_debug (DEBUG_LABEL, "BEGIN");
989 
990 	g_return_if_fail (ltext && GL_IS_LABEL_TEXT (ltext));
991 
992 	if (ltext->priv->auto_shrink != auto_shrink)
993         {
994                 if ( checkpoint )
995                 {
996                         label = gl_label_object_get_parent (GL_LABEL_OBJECT (ltext));
997                         gl_label_checkpoint (label, _("Auto shrink"));
998                 }
999 
1000 		ltext->priv->auto_shrink = auto_shrink;
1001 		gl_label_object_emit_changed (GL_LABEL_OBJECT(ltext));
1002 	}
1003 
1004 	gl_debug (DEBUG_LABEL, "END");
1005 }
1006 
1007 
1008 /*****************************************************************************/
1009 /* Query auto shrink flag.                                                   */
1010 /*****************************************************************************/
1011 gboolean
gl_label_text_get_auto_shrink(glLabelText * ltext)1012 gl_label_text_get_auto_shrink (glLabelText      *ltext)
1013 {
1014 	gl_debug (DEBUG_LABEL, "");
1015 
1016 	g_return_val_if_fail (ltext && GL_IS_LABEL_TEXT (ltext), 0);
1017 
1018 	return ltext->priv->auto_shrink;
1019 }
1020 
1021 
1022 /*****************************************************************************/
1023 /* Automatically shrink text size to fit within bounding box.                */
1024 /*****************************************************************************/
1025 static gdouble
auto_shrink_font_size(cairo_t * cr,gchar * family,gdouble size,PangoWeight weight,PangoStyle style,gdouble line_spacing,gchar * text,gdouble width,gdouble height)1026 auto_shrink_font_size (cairo_t     *cr,
1027                        gchar       *family,
1028                        gdouble      size,
1029                        PangoWeight  weight,
1030                        PangoStyle   style,
1031                        gdouble      line_spacing,
1032                        gchar       *text,
1033                        gdouble      width,
1034                        gdouble      height)
1035 {
1036         PangoLayout          *layout;
1037         PangoFontDescription *desc;
1038         gint                  iw, ih;
1039         gdouble               layout_width, layout_height;
1040         gdouble               new_wsize, new_hsize;
1041 
1042         layout = pango_cairo_create_layout (cr);
1043 
1044         desc = pango_font_description_new ();
1045         pango_font_description_set_family (desc, family);
1046         pango_font_description_set_weight (desc, weight);
1047         pango_font_description_set_style  (desc, style);
1048         pango_font_description_set_size   (desc, size * PANGO_SCALE);
1049 
1050         pango_layout_set_font_description (layout, desc);
1051         pango_font_description_free       (desc);
1052 
1053         pango_layout_set_spacing (layout, size * (line_spacing-1) * PANGO_SCALE);
1054         pango_layout_set_width (layout, -1);
1055         pango_layout_set_text (layout, text, -1);
1056         pango_layout_get_size (layout, &iw, &ih);
1057         layout_width = (gdouble)iw / (gdouble)PANGO_SCALE;
1058         layout_height = (gdouble)ih / (gdouble)PANGO_SCALE;
1059 
1060         g_object_unref (layout);
1061 
1062         g_print ("Object w = %g, layout w = %g\n", width, layout_width);
1063         g_print ("Object h = %g, layout h = %g\n", height, layout_height);
1064 
1065         new_wsize = new_hsize = size;
1066         if ( layout_width > width )
1067         {
1068                 /* Scale down. */
1069                 new_wsize = size * (width-2*GL_LABEL_TEXT_MARGIN) / layout_width;
1070 
1071                 /* Round down to nearest 1/2 point */
1072                 new_wsize = (int)(new_wsize*2.0) / 2.0;
1073 
1074                 /* don't get ridiculously small. */
1075                 if (new_wsize < 1.0)
1076                 {
1077                         new_wsize = 1.0;
1078                 }
1079         }
1080 
1081         if ( layout_height > height )
1082         {
1083                 /* Scale down. */
1084                 new_hsize = size * height / layout_height;
1085 
1086                 /* Round down to nearest 1/2 point */
1087                 new_hsize = (int)(new_hsize*2.0) / 2.0;
1088 
1089                 /* don't get ridiculously small. */
1090                 if (new_hsize < 1.0)
1091                 {
1092                         new_hsize = 1.0;
1093                 }
1094         }
1095 
1096         return (new_wsize < new_hsize ? new_wsize : new_hsize);
1097 }
1098 
1099 
1100 /*****************************************************************************/
1101 /* Update pango layout.                                                      */
1102 /*****************************************************************************/
1103 static void
layout_text(glLabelText * this,cairo_t * cr,gboolean screen_flag,glMergeRecord * record,gboolean path_only_flag)1104 layout_text (glLabelText      *this,
1105              cairo_t          *cr,
1106              gboolean          screen_flag,
1107              glMergeRecord    *record,
1108              gboolean          path_only_flag)
1109 {
1110         gint                  iw, ih, y;
1111         gdouble               object_w, object_h;
1112         gdouble               raw_w, raw_h;
1113         gchar                *text;
1114         GList                *lines;
1115         gdouble               font_size;
1116         gboolean              auto_shrink;
1117         PangoLayout          *layout;
1118         PangoStyle            style;
1119         PangoFontDescription *desc;
1120         gdouble               scale_x, scale_y;
1121         cairo_font_options_t *font_options;
1122         PangoContext         *context;
1123 
1124 
1125         gl_debug (DEBUG_LABEL, "START");
1126 
1127         /*
1128          * Workaround for pango Bug#700592, which is a regression of Bug#341481.
1129          * Render font at device scale and scale font size accordingly.
1130          */
1131         scale_x = 1.0;
1132         scale_y = 1.0;
1133         cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1134         scale_x = fabs (scale_x);
1135         scale_y = fabs (scale_y);
1136         cairo_save (cr);
1137         cairo_scale (cr, scale_x, scale_y);
1138 
1139         gl_label_object_get_size (GL_LABEL_OBJECT (this), &object_w, &object_h);
1140         gl_label_object_get_raw_size (GL_LABEL_OBJECT (this), &raw_w, &raw_h);
1141 
1142         lines = gl_label_text_get_lines (this);
1143         text = gl_text_node_lines_expand (lines, record);
1144 
1145         style = this->priv->font_italic_flag ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
1146 
1147         font_size   = this->priv->font_size * FONT_SCALE;
1148         auto_shrink = gl_label_text_get_auto_shrink (this);
1149         if (!screen_flag && record && auto_shrink && (raw_w != 0.0))
1150         {
1151                 font_size = auto_shrink_font_size (cr,
1152                                                    this->priv->font_family,
1153                                                    font_size,
1154                                                    this->priv->font_weight,
1155                                                    style,
1156                                                    this->priv->line_spacing,
1157                                                    text,
1158                                                    object_w,
1159                                                    object_h);
1160         }
1161 
1162 
1163         layout = pango_cairo_create_layout (cr);
1164 
1165         font_options = cairo_font_options_create ();
1166         cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
1167         cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
1168         context = pango_layout_get_context (layout);
1169         pango_cairo_context_set_font_options (context, font_options);
1170         cairo_font_options_destroy (font_options);
1171 
1172         desc = pango_font_description_new ();
1173         pango_font_description_set_family (desc, this->priv->font_family);
1174         pango_font_description_set_weight (desc, this->priv->font_weight);
1175         pango_font_description_set_size   (desc, font_size * PANGO_SCALE / scale_x);
1176         pango_font_description_set_style  (desc, style);
1177         pango_layout_set_font_description (layout, desc);
1178         pango_font_description_free       (desc);
1179 
1180         pango_layout_set_text (layout, text, -1);
1181         pango_layout_set_spacing (layout, font_size * (this->priv->line_spacing-1) * PANGO_SCALE / scale_x);
1182         if ( (raw_w == 0.0) || auto_shrink )
1183         {
1184                 pango_layout_set_width (layout, -1);
1185         }
1186         else
1187         {
1188                 pango_layout_set_width (layout, (object_w - 2*GL_LABEL_TEXT_MARGIN) * PANGO_SCALE / scale_x);
1189         }
1190         pango_layout_set_wrap (layout, PANGO_WRAP_WORD);
1191         pango_layout_set_alignment (layout, this->priv->align);
1192         pango_layout_get_pixel_size (layout, &iw, &ih);
1193 
1194         switch (this->priv->valign)
1195         {
1196         case GL_VALIGN_VCENTER:
1197                 y = (object_h/scale_x - ih) / 2;
1198                 break;
1199         case GL_VALIGN_BOTTOM:
1200                 y = object_h/scale_x - ih;
1201                 break;
1202         default:
1203                 y = 0;
1204                 break;
1205         }
1206 
1207         cairo_move_to (cr, GL_LABEL_TEXT_MARGIN/scale_x, y);
1208         if ( path_only_flag )
1209         {
1210                 pango_cairo_layout_path (cr, layout);
1211         }
1212         else
1213         {
1214                 pango_cairo_show_layout (cr, layout);
1215         }
1216 
1217         g_object_unref (layout);
1218         gl_text_node_lines_free (&lines);
1219 
1220         cairo_restore (cr);
1221 
1222         gl_debug (DEBUG_LABEL, "END");
1223 }
1224 
1225 
1226 /*****************************************************************************/
1227 /* Draw object method.                                                       */
1228 /*****************************************************************************/
1229 static void
draw_object(glLabelObject * object,cairo_t * cr,gboolean screen_flag,glMergeRecord * record)1230 draw_object (glLabelObject *object,
1231              cairo_t       *cr,
1232              gboolean       screen_flag,
1233              glMergeRecord *record)
1234 {
1235         glColorNode     *color_node;
1236         guint            color;
1237 
1238         gl_debug (DEBUG_LABEL, "START");
1239 
1240         color_node = gl_label_object_get_text_color (object);
1241         color = gl_color_node_expand (color_node, record);
1242         if (color_node->field_flag && screen_flag)
1243         {
1244                 color = GL_COLOR_MERGE_DEFAULT;
1245         }
1246         gl_color_node_free (&color_node);
1247 
1248         draw_text_real (object, cr, screen_flag, record, color);
1249 
1250         gl_debug (DEBUG_LABEL, "END");
1251 }
1252 
1253 
1254 /*****************************************************************************/
1255 /* Draw shadow method.                                                       */
1256 /*****************************************************************************/
1257 static void
draw_shadow(glLabelObject * object,cairo_t * cr,gboolean screen_flag,glMergeRecord * record)1258 draw_shadow (glLabelObject *object,
1259              cairo_t       *cr,
1260              gboolean       screen_flag,
1261              glMergeRecord *record)
1262 {
1263         glColorNode     *color_node;
1264         guint            color;
1265         glColorNode     *shadow_color_node;
1266         gdouble          shadow_opacity;
1267         guint            shadow_color;
1268 
1269         gl_debug (DEBUG_LABEL, "START");
1270 
1271         color_node = gl_label_object_get_text_color (object);
1272         color = gl_color_node_expand (color_node, record);
1273         if (color_node->field_flag && screen_flag)
1274         {
1275                 color = GL_COLOR_MERGE_DEFAULT;
1276         }
1277         gl_color_node_free (&color_node);
1278 
1279         shadow_color_node = gl_label_object_get_shadow_color (object);
1280 	shadow_color = gl_color_node_expand (shadow_color_node, record);
1281         if (shadow_color_node->field_flag)
1282         {
1283                 shadow_color_node->color = GL_COLOR_SHADOW_MERGE_DEFAULT;
1284         }
1285         shadow_opacity = gl_label_object_get_shadow_opacity (object);
1286 	shadow_color = gl_color_set_opacity (shadow_color, shadow_opacity);
1287         gl_color_node_free (&shadow_color_node);
1288 
1289         draw_text_real (object, cr, screen_flag, record, shadow_color);
1290 
1291         gl_debug (DEBUG_LABEL, "END");
1292 }
1293 
1294 
1295 /*****************************************************************************/
1296 /* Draw text.                                                                */
1297 /*****************************************************************************/
1298 static void
draw_text_real(glLabelObject * object,cairo_t * cr,gboolean screen_flag,glMergeRecord * record,guint color)1299 draw_text_real (glLabelObject *object,
1300                 cairo_t       *cr,
1301                 gboolean       screen_flag,
1302                 glMergeRecord *record,
1303                 guint          color)
1304 {
1305         gl_debug (DEBUG_LABEL, "START");
1306 
1307         cairo_set_source_rgba (cr, GL_COLOR_RGBA_ARGS (color));
1308         layout_text (GL_LABEL_TEXT (object), cr, screen_flag, record, FALSE);
1309 
1310         gl_debug (DEBUG_LABEL, "END");
1311 }
1312 
1313 
1314 /*****************************************************************************/
1315 /* Is object at coordinates?                                                 */
1316 /*****************************************************************************/
1317 static gboolean
object_at(glLabelObject * object,cairo_t * cr,gdouble x,gdouble y)1318 object_at (glLabelObject *object,
1319            cairo_t       *cr,
1320            gdouble        x,
1321            gdouble        y)
1322 {
1323         gdouble           w, h;
1324         gdouble           scale_x, scale_y;
1325 
1326         gl_label_object_get_size (object, &w, &h);
1327 
1328         if ( (x >= 0) && (x <= w) && (y >= 0) && (y <= h) )
1329         {
1330                 cairo_new_path (cr);
1331                 layout_text (GL_LABEL_TEXT (object), cr, TRUE, NULL, TRUE);
1332                 if (cairo_in_fill (cr, x, y))
1333                 {
1334                         return TRUE;
1335                 }
1336 
1337 
1338                 scale_x = 1.0;
1339                 scale_y = 1.0;
1340                 cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1341 
1342                 cairo_set_line_width (cr, 2*SELECTION_SLOP_PIXELS*scale_x);
1343 
1344                 if (cairo_in_stroke (cr, x, y))
1345                 {
1346                         return TRUE;
1347                 }
1348 
1349 
1350                 if (gl_label_object_is_selected (object))
1351                 {
1352                         cairo_new_path (cr);
1353                         cairo_rectangle (cr, 0, 0, w, h);
1354 
1355                         scale_x = 1.0;
1356                         scale_y = 1.0;
1357                         cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1358 
1359                         cairo_set_line_width (cr, 2*SELECTION_SLOP_PIXELS*scale_x);
1360 
1361                         if (cairo_in_stroke (cr, x, y))
1362                         {
1363                                 return TRUE;
1364                         }
1365                 }
1366 
1367         }
1368 
1369         return FALSE;
1370 }
1371 
1372 
1373 /*****************************************************************************/
1374 /* Draw text style handles.                                                  */
1375 /*****************************************************************************/
1376 static void
draw_handles(glLabelObject * object,cairo_t * cr)1377 draw_handles (glLabelObject     *object,
1378               cairo_t           *cr)
1379 {
1380         gdouble w, h;
1381         gdouble scale_x, scale_y;
1382         gdouble dashes[2] = { 2, 2 };
1383 
1384         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
1385 
1386         cairo_save (cr);
1387 
1388         cairo_rectangle (cr, 0, 0, w, h);
1389 
1390         scale_x = 1.0;
1391         scale_y = 1.0;
1392         cairo_device_to_user_distance (cr, &scale_x, &scale_y);
1393         cairo_scale (cr, scale_x, scale_y);
1394 
1395         cairo_set_dash (cr, dashes, 2, 0);
1396         cairo_set_line_width (cr, HANDLE_OUTLINE_WIDTH_PIXELS);
1397         cairo_set_source_rgba (cr, HANDLE_OUTLINE_RGBA_ARGS);
1398         cairo_stroke (cr);
1399 
1400         cairo_restore (cr);
1401 
1402         gl_label_object_draw_handles_box (object, cr);
1403 }
1404 
1405 
1406 
1407 
1408 /*
1409  * Local Variables:       -- emacs
1410  * mode: C                -- emacs
1411  * c-basic-offset: 8      -- emacs
1412  * tab-width: 8           -- emacs
1413  * indent-tabs-mode: nil  -- emacs
1414  * End:                   -- emacs
1415  */
1416