gtklabel.c 17 KB
Newer Older
1
/* GTK - The GIMP Toolkit
Elliot Lee's avatar
Elliot Lee committed
2 3 4 5 6 7 8 9 10
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library 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
Owen Taylor's avatar
Owen Taylor committed
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Elliot Lee's avatar
Elliot Lee committed
12 13 14
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
Owen Taylor's avatar
Owen Taylor committed
15 16
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Elliot Lee's avatar
Elliot Lee committed
17
 */
18 19 20 21 22 23 24 25

/*
 * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

26
#include <math.h>
Elliot Lee's avatar
Elliot Lee committed
27 28
#include <string.h>
#include "gtklabel.h"
29
#include "gdk/gdkkeysyms.h"
Owen Taylor's avatar
Owen Taylor committed
30
#include "gdk/gdki18n.h"
31 32 33
#include <pango/pango.h>
#include <unicode.h>

Elliot Lee's avatar
Elliot Lee committed
34

35 36 37
enum {
  ARG_0,
  ARG_LABEL,
38
  ARG_PATTERN,
39 40
  ARG_JUSTIFY,
  ARG_WRAP
41 42
};

Elliot Lee's avatar
Elliot Lee committed
43
static void gtk_label_class_init   (GtkLabelClass  *klass);
Tim Janik's avatar
Tim Janik committed
44
static void gtk_label_init	   (GtkLabel	   *label);
45
static void gtk_label_set_arg	   (GtkObject	   *object,
Tim Janik's avatar
Tim Janik committed
46 47
				    GtkArg	   *arg,
				    guint	    arg_id);
48
static void gtk_label_get_arg	   (GtkObject      *object,
Tim Janik's avatar
Tim Janik committed
49 50
				    GtkArg	   *arg,
				    guint	    arg_id);
51
static void gtk_label_finalize	   (GObject	   *object);
Tim Janik's avatar
Tim Janik committed
52
static void gtk_label_size_request (GtkWidget	   *widget,
Elliot Lee's avatar
Elliot Lee committed
53
				    GtkRequisition *requisition);
54 55
static void gtk_label_style_set    (GtkWidget      *widget,
				    GtkStyle       *previous_style);
Tim Janik's avatar
Tim Janik committed
56
static gint gtk_label_expose	   (GtkWidget	   *widget,
Elliot Lee's avatar
Elliot Lee committed
57
				    GdkEventExpose *event);
Owen Taylor's avatar
Owen Taylor committed
58

Elliot Lee's avatar
Elliot Lee committed
59 60 61

static GtkMiscClass *parent_class = NULL;

Tim Janik's avatar
Tim Janik committed
62
GtkType
63
gtk_label_get_type (void)
Elliot Lee's avatar
Elliot Lee committed
64
{
Tim Janik's avatar
Tim Janik committed
65 66
  static GtkType label_type = 0;
  
Elliot Lee's avatar
Elliot Lee committed
67 68
  if (!label_type)
    {
69
      static const GTypeInfo label_info =
Elliot Lee's avatar
Elliot Lee committed
70 71
      {
	sizeof (GtkLabelClass),
72 73 74 75 76 77 78 79
	NULL,           /* base_init */
	NULL,           /* base_finalize */
	(GClassInitFunc) gtk_label_class_init,
	NULL,           /* class_finalize */
	NULL,           /* class_data */
	sizeof (GtkLabel),
	32,             /* n_preallocs */
	(GInstanceInitFunc) gtk_label_init,
Elliot Lee's avatar
Elliot Lee committed
80
      };
81 82

      label_type = g_type_register_static (GTK_TYPE_MISC, "GtkLabel", &label_info);
Elliot Lee's avatar
Elliot Lee committed
83
    }
Tim Janik's avatar
Tim Janik committed
84
  
Elliot Lee's avatar
Elliot Lee committed
85 86 87
  return label_type;
}

88
static void
Elliot Lee's avatar
Elliot Lee committed
89 90
gtk_label_class_init (GtkLabelClass *class)
{
91
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
Elliot Lee's avatar
Elliot Lee committed
92 93
  GtkObjectClass *object_class;
  GtkWidgetClass *widget_class;
Tim Janik's avatar
Tim Janik committed
94
  
Elliot Lee's avatar
Elliot Lee committed
95 96
  object_class = (GtkObjectClass*) class;
  widget_class = (GtkWidgetClass*) class;
Tim Janik's avatar
Tim Janik committed
97
  
98
  parent_class = gtk_type_class (GTK_TYPE_MISC);
Tim Janik's avatar
Tim Janik committed
99
  
100
  gtk_object_add_arg_type ("GtkLabel::label", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_LABEL);
101
  gtk_object_add_arg_type ("GtkLabel::pattern", GTK_TYPE_STRING, GTK_ARG_READWRITE, ARG_PATTERN);
102
  gtk_object_add_arg_type ("GtkLabel::justify", GTK_TYPE_JUSTIFICATION, GTK_ARG_READWRITE, ARG_JUSTIFY);
103
  gtk_object_add_arg_type ("GtkLabel::wrap", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_WRAP);
104
  
105 106
  gobject_class->finalize = gtk_label_finalize;

107 108
  object_class->set_arg = gtk_label_set_arg;
  object_class->get_arg = gtk_label_get_arg;
Tim Janik's avatar
Tim Janik committed
109
  
Elliot Lee's avatar
Elliot Lee committed
110
  widget_class->size_request = gtk_label_size_request;
111
  widget_class->style_set = gtk_label_style_set;
Elliot Lee's avatar
Elliot Lee committed
112 113 114
  widget_class->expose_event = gtk_label_expose;
}

115
static void
116
gtk_label_set_arg (GtkObject	  *object,
Tim Janik's avatar
Tim Janik committed
117 118
		   GtkArg	  *arg,
		   guint	   arg_id)
119
{
120
  GtkLabel *label;
121
  
122
  label = GTK_LABEL (object);
123
  
124 125 126
  switch (arg_id)
    {
    case ARG_LABEL:
127
      gtk_label_set_text (label, GTK_VALUE_STRING (*arg));
128
      break;
129 130 131
    case ARG_PATTERN:
      gtk_label_set_pattern (label, GTK_VALUE_STRING (*arg));
      break;
132 133 134
    case ARG_JUSTIFY:
      gtk_label_set_justify (label, GTK_VALUE_ENUM (*arg));
      break;
135 136 137
    case ARG_WRAP:
      gtk_label_set_line_wrap (label, GTK_VALUE_BOOL (*arg));
      break;	  
Tim Janik's avatar
Tim Janik committed
138 139
    default:
      break;
140 141 142
    }
}

Tim Janik's avatar
Tim Janik committed
143
static void
144
gtk_label_get_arg (GtkObject	  *object,
Tim Janik's avatar
Tim Janik committed
145 146
		   GtkArg	  *arg,
		   guint	   arg_id)
147
{
148
  GtkLabel *label;
149
  
150
  label = GTK_LABEL (object);
151
  
152 153 154 155 156
  switch (arg_id)
    {
    case ARG_LABEL:
      GTK_VALUE_STRING (*arg) = g_strdup (label->label);
      break;
157 158 159
    case ARG_PATTERN:
      GTK_VALUE_STRING (*arg) = g_strdup (label->pattern);
      break;
160 161 162
    case ARG_JUSTIFY:
      GTK_VALUE_ENUM (*arg) = label->jtype;
      break;
163 164 165
    case ARG_WRAP:
      GTK_VALUE_BOOL (*arg) = label->wrap;
      break;
166 167 168 169 170 171
    default:
      arg->type = GTK_TYPE_INVALID;
      break;
    }
}

172
static void
Elliot Lee's avatar
Elliot Lee committed
173 174 175
gtk_label_init (GtkLabel *label)
{
  GTK_WIDGET_SET_FLAGS (label, GTK_NO_WINDOW);
Tim Janik's avatar
Tim Janik committed
176
  
Elliot Lee's avatar
Elliot Lee committed
177
  label->label = NULL;
178 179
  label->pattern = NULL;

Elliot Lee's avatar
Elliot Lee committed
180
  label->jtype = GTK_JUSTIFY_CENTER;
Owen Taylor's avatar
Owen Taylor committed
181
  label->wrap = FALSE;
182 183 184

  label->layout = NULL;
  label->rtl = (gtk_widget_get_direction (GTK_WIDGET (label)) == GTK_TEXT_DIR_RTL);
185
  
Owen Taylor's avatar
Owen Taylor committed
186
  gtk_label_set_text (label, "");
Elliot Lee's avatar
Elliot Lee committed
187 188 189
}

GtkWidget*
190
gtk_label_new (const gchar *str)
Elliot Lee's avatar
Elliot Lee committed
191 192
{
  GtkLabel *label;
193
  
194 195 196 197
  label = gtk_type_new (GTK_TYPE_LABEL);

  if (str && *str)
    gtk_label_set_text (label, str);
198
  
Elliot Lee's avatar
Elliot Lee committed
199 200 201
  return GTK_WIDGET (label);
}

202
static inline void
203
gtk_label_set_text_internal (GtkLabel *label,
204
			     gchar    *str)
Elliot Lee's avatar
Elliot Lee committed
205
{
206
  g_free (label->label);
207

208
  label->label = str;
209 210
  if (label->layout)
    pango_layout_set_text (label->layout, str, -1);
211
  
212
  gtk_widget_queue_resize (GTK_WIDGET (label));
213 214
}

215
void
216 217
gtk_label_set_text (GtkLabel    *label,
		    const gchar *str)
218 219
{
  g_return_if_fail (GTK_IS_LABEL (label));
220

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
  gtk_label_set_text_internal (label, g_strdup (str ? str : ""));
}

/**
 * gtk_label_get_text:
 * @label: a #GtkLabel
 * 
 * Fetches the text from a label widget
 * 
 * Return value: the text in the label widget. This value must
 * be freed with g_free().
 **/
gchar *
gtk_label_get_text (GtkLabel *label)
{
  g_return_if_fail (label != NULL);
  g_return_if_fail (GTK_IS_LABEL (label));

  return g_strdup (label->label);
240 241
}

242 243 244 245 246 247
void
gtk_label_set_pattern (GtkLabel	   *label,
		       const gchar *pattern)
{
  g_return_if_fail (GTK_IS_LABEL (label));
  
248 249 250 251
  g_free (label->pattern);
  label->pattern = g_strdup (pattern);

  gtk_widget_queue_resize (GTK_WIDGET (label));
Elliot Lee's avatar
Elliot Lee committed
252 253 254
}

void
255 256
gtk_label_set_justify (GtkLabel        *label,
		       GtkJustification jtype)
Elliot Lee's avatar
Elliot Lee committed
257 258
{
  g_return_if_fail (GTK_IS_LABEL (label));
259
  g_return_if_fail (jtype >= GTK_JUSTIFY_LEFT && jtype <= GTK_JUSTIFY_FILL);
260
  
Elliot Lee's avatar
Elliot Lee committed
261 262 263
  if ((GtkJustification) label->jtype != jtype)
    {
      label->jtype = jtype;
264

265 266 267 268 269 270 271
      if (label->layout)
	{
	  /* No real need to be this drastic, but easier than duplicating the code */
	  pango_layout_unref (label->layout);
	  label->layout = NULL;
	}
      
272
      gtk_widget_queue_resize (GTK_WIDGET (label));
Elliot Lee's avatar
Elliot Lee committed
273 274 275 276
    }
}

void
277 278
gtk_label_set_line_wrap (GtkLabel *label,
			 gboolean  wrap)
Owen Taylor's avatar
Owen Taylor committed
279 280
{
  g_return_if_fail (GTK_IS_LABEL (label));
281
  
282 283 284 285 286 287 288 289
  wrap = wrap != FALSE;
  
  if (label->wrap != wrap)
    {
      label->wrap = wrap;

      gtk_widget_queue_resize (GTK_WIDGET (label));
    }
Owen Taylor's avatar
Owen Taylor committed
290 291 292
}

void
293 294
gtk_label_get (GtkLabel *label,
	       gchar   **str)
Elliot Lee's avatar
Elliot Lee committed
295 296 297 298
{
  g_return_if_fail (label != NULL);
  g_return_if_fail (GTK_IS_LABEL (label));
  g_return_if_fail (str != NULL);
299
  
Elliot Lee's avatar
Elliot Lee committed
300 301 302 303
  *str = label->label;
}

static void
304
gtk_label_finalize (GObject *object)
Elliot Lee's avatar
Elliot Lee committed
305 306
{
  GtkLabel *label;
307
  
Elliot Lee's avatar
Elliot Lee committed
308
  g_return_if_fail (GTK_IS_LABEL (object));
309
  
Elliot Lee's avatar
Elliot Lee committed
310
  label = GTK_LABEL (object);
311
  
Elliot Lee's avatar
Elliot Lee committed
312
  g_free (label->label);
313 314
  g_free (label->pattern);

315 316
  if (label->layout)
    pango_layout_unref (label->layout);
317

318
  G_OBJECT_CLASS (parent_class)->finalize (object);
Elliot Lee's avatar
Elliot Lee committed
319 320
}

321 322
static PangoAttrList *
gtk_label_pattern_to_attrs (GtkLabel *label)
323
{
324
  PangoAttrList *attrs = pango_attr_list_new ();
325

326
  if (label->pattern)
Owen Taylor's avatar
Owen Taylor committed
327
    {
328 329 330
      const char *start;
      const char *p = label->label;
      const char *q = label->pattern;
331

332
      while (1)
Owen Taylor's avatar
Owen Taylor committed
333
	{
334
	  while (*p && *q && *q != '_')
Owen Taylor's avatar
Owen Taylor committed
335
	    {
336 337
	      p = unicode_next_utf8 (p);
	      q++;
Owen Taylor's avatar
Owen Taylor committed
338
	    }
339 340
	  start = p;
	  while (*p && *q && *q == '_')
341
	    {
342 343
	      p = unicode_next_utf8 (p);
	      q++;
344
	    }
Owen Taylor's avatar
Owen Taylor committed
345

346
	  if (p > start)
347
	    {
348 349 350 351 352
	      PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
	      attr->start_index = start - label->label;
	      attr->end_index = p - label->label;

	      pango_attr_list_insert (attrs, attr);
353
	    }
Owen Taylor's avatar
Owen Taylor committed
354
	  else
355
	    break;
356 357
	}
    }
358 359

  return attrs;
360
}
361

Elliot Lee's avatar
Elliot Lee committed
362 363 364 365 366
static void
gtk_label_size_request (GtkWidget      *widget,
			GtkRequisition *requisition)
{
  GtkLabel *label;
367
  PangoRectangle logical_rect;
Tim Janik's avatar
Tim Janik committed
368
  
Elliot Lee's avatar
Elliot Lee committed
369 370
  g_return_if_fail (GTK_IS_LABEL (widget));
  g_return_if_fail (requisition != NULL);
371
  
Elliot Lee's avatar
Elliot Lee committed
372
  label = GTK_LABEL (widget);
373

Owen Taylor's avatar
Owen Taylor committed
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
  /*
   * There are a number of conditions which will necessitate re-filling
   * our text:
   *
   *     1. text changed.
   *     2. justification changed either from to to GTK_JUSTIFY_FILL.
   *     3. font changed.
   *
   * These have been detected elsewhere, and label->words will be zero,
   * if one of the above has occured.
   *
   * Additionally, though, if GTK_JUSTIFY_FILL, we need to re-fill if:
   *
   *     4. gtk_widget_set_usize has changed the requested width.
   *     5. gtk_misc_set_padding has changed xpad.
   *     6.  maybe others?...
   *
   * Too much of a pain to detect all these case, so always re-fill.  I
   * don't think it's really that slow.
   */
394 395 396 397 398 399 400 401 402 403 404 405 406

  requisition->width = label->misc.xpad;
  requisition->height = label->misc.ypad;

  /* Detect direction changes. FIXME: make this a signal
   */
  if (label->rtl != (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) &&
      label->layout)
    {
      label->rtl = !label->rtl;
      pango_layout_unref (label->layout);
      label->layout = NULL;
    }
407
  
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
  if (!label->layout)
    {
      PangoAlignment align = PANGO_ALIGN_LEFT; /* Quiet gcc */
      PangoAttrList *attrs = gtk_label_pattern_to_attrs (label);

      label->layout = gtk_widget_create_pango_layout (widget);
      pango_layout_set_attributes (label->layout, attrs);
      pango_attr_list_unref (attrs);

      pango_layout_set_text (label->layout, label->label, -1);

      switch (label->jtype)
	{
	case GTK_JUSTIFY_LEFT:
	  align = PANGO_ALIGN_LEFT;
	  break;
	case GTK_JUSTIFY_RIGHT:
	  align = PANGO_ALIGN_RIGHT;
	  break;
	case GTK_JUSTIFY_CENTER:
	  align = PANGO_ALIGN_LEFT;
	  break;
	case GTK_JUSTIFY_FILL:
	  /* FIXME: This just doesn't work to do this */
	  align = PANGO_ALIGN_LEFT;
	  pango_layout_set_justify (label->layout, TRUE);
	  break;
	default:
	  g_assert_not_reached();
	}

      pango_layout_set_alignment (label->layout, align);
    }

Owen Taylor's avatar
Owen Taylor committed
442
  if (label->wrap)
Elliot Lee's avatar
Elliot Lee committed
443
    {
Owen Taylor's avatar
Owen Taylor committed
444 445
      GtkWidgetAuxInfo *aux_info;
      gint longest_paragraph;
446 447 448
      gint width, height;
      gint real_width;

Owen Taylor's avatar
Owen Taylor committed
449 450 451
      aux_info = gtk_object_get_data (GTK_OBJECT (widget), "gtk-aux-info");
      if (aux_info && aux_info->width > 0)
	{
452 453 454 455 456
	  pango_layout_set_width (label->layout, aux_info->width * PANGO_SCALE);
	  pango_layout_get_extents (label->layout, NULL, &logical_rect);

	  requisition->width += aux_info->width;
	  requisition->height += logical_rect.height / PANGO_SCALE;
Owen Taylor's avatar
Owen Taylor committed
457 458 459
	}
      else
	{
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
	  pango_layout_set_width (label->layout, -1);
	  pango_layout_get_extents (label->layout, NULL, &logical_rect);
      
	  width = logical_rect.width;
	  height = logical_rect.height;
	  
	  /* Try to guess a reasonable maximum width
	   */
	  longest_paragraph = width;

	  width = MIN (width,
		       PANGO_SCALE * gdk_string_width (GTK_WIDGET (label)->style->font,
						"This long string gives a good enough length for any line to have."));
	  width = MIN (width,
		       PANGO_SCALE * (gdk_screen_width () + 1) / 2);

	  pango_layout_set_width (label->layout, width);
	  pango_layout_get_extents (label->layout, NULL, &logical_rect);
	  real_width = logical_rect.width;
	  height = logical_rect.height;
	  
	  /* Unfortunately, the above may leave us with a very unbalanced looking paragraph,
	   * so we try short search for a narrower width that leaves us with the same height
	   */
Owen Taylor's avatar
Owen Taylor committed
484 485 486
	  if (longest_paragraph > 0)
	    {
	      gint nlines, perfect_width;
487 488

	      nlines = pango_layout_get_line_count (label->layout);
Owen Taylor's avatar
Owen Taylor committed
489
	      perfect_width = (longest_paragraph + nlines - 1) / nlines;
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
	      
	      if (perfect_width < width)
		{
		  pango_layout_set_width (label->layout, perfect_width);
		  pango_layout_get_extents (label->layout, NULL, &logical_rect);
		  
		  if (logical_rect.height <= height)
		    {
		      width = perfect_width;
		      real_width = logical_rect.width;
		      height = logical_rect.height;
		    }
		  else
		    {
		      gint mid_width = (perfect_width + width) / 2;

		      if (mid_width > perfect_width)
			{
			  pango_layout_set_width (label->layout, mid_width);
			  pango_layout_get_extents (label->layout, NULL, &logical_rect);

			  if (logical_rect.height <= height)
			    {
			      width = mid_width;
			      real_width = logical_rect.width;
			      height = logical_rect.height;
			    }
			}
		    }
		}
Owen Taylor's avatar
Owen Taylor committed
520
	    }
521 522 523 524
	  pango_layout_set_width (label->layout, width);

	  requisition->width += real_width / PANGO_SCALE;
	  requisition->height += height / PANGO_SCALE;
Owen Taylor's avatar
Owen Taylor committed
525 526
	}
    }
527
  else				/* !label->wrap */
Owen Taylor's avatar
Owen Taylor committed
528
    {
529 530 531 532 533
      pango_layout_set_width (label->layout, -1);
      pango_layout_get_extents (label->layout, NULL, &logical_rect);

      requisition->width += logical_rect.width / PANGO_SCALE;
      requisition->height += logical_rect.height / PANGO_SCALE;
Owen Taylor's avatar
Owen Taylor committed
534 535
    }
}
536

537
static void 
538 539
gtk_label_style_set (GtkWidget *widget,
		     GtkStyle  *previous_style)
540 541 542 543
{
  GtkLabel *label;

  g_return_if_fail (GTK_IS_LABEL (widget));
544
  
545
  label = GTK_LABEL (widget);
546 547 548 549 550 551

  if (previous_style && label->layout)
    {
      pango_layout_unref (label->layout);
      label->layout = NULL;
    }
552 553
}

554
#if 0
Owen Taylor's avatar
Owen Taylor committed
555
static void
556 557 558
gtk_label_paint_word (GtkLabel     *label,
		      gint          x,
		      gint          y,
Owen Taylor's avatar
Owen Taylor committed
559 560 561 562 563 564
		      GtkLabelWord *word,
		      GdkRectangle *area)
{
  GtkWidget *widget = GTK_WIDGET (label);
  GtkLabelULine *uline;
  gchar *tmp_str;
565
  
Owen Taylor's avatar
Owen Taylor committed
566
  tmp_str = gdk_wcstombs (word->beginning);
567 568 569 570 571 572 573 574 575
  if (tmp_str)
    {
      gtk_paint_string (widget->style, widget->window, widget->state,
			area, widget, "label", 
			x + word->x,
			y + word->y,
			tmp_str);
      g_free (tmp_str);
    }
Owen Taylor's avatar
Owen Taylor committed
576
  
577
  for (uline = word->uline; uline; uline = uline->next)
Owen Taylor's avatar
Owen Taylor committed
578 579 580
    gtk_paint_hline (widget->style, widget->window, 
		     widget->state, area,
		     widget, "label", 
581
		     x + uline->x1, x + uline->x2, y + uline->y);
Elliot Lee's avatar
Elliot Lee committed
582
}
583
#endif
584

Elliot Lee's avatar
Elliot Lee committed
585
static gint
Owen Taylor's avatar
Owen Taylor committed
586
gtk_label_expose (GtkWidget      *widget,
Elliot Lee's avatar
Elliot Lee committed
587 588 589 590 591
		  GdkEventExpose *event)
{
  GtkLabel *label;
  GtkMisc *misc;
  gint x, y;
592
  gfloat xalign;
593
  
Elliot Lee's avatar
Elliot Lee committed
594 595
  g_return_val_if_fail (GTK_IS_LABEL (widget), FALSE);
  g_return_val_if_fail (event != NULL, FALSE);
596
  
Arturo Espinosa's avatar
Arturo Espinosa committed
597
  label = GTK_LABEL (widget);
Tim Janik's avatar
Tim Janik committed
598
  
599 600
  if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
      label->label && (*label->label != '\0'))
Elliot Lee's avatar
Elliot Lee committed
601 602
    {
      misc = GTK_MISC (widget);
603
      
604 605 606 607 608
      if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR)
	xalign = misc->xalign;
      else
	xalign = 1. - misc->xalign;

609 610
      /*
       * GC Clipping
Elliot Lee's avatar
Elliot Lee committed
611
       */
612
      gdk_gc_set_clip_rectangle (widget->style->white_gc, &event->area);
613
      gdk_gc_set_clip_rectangle (widget->style->fg_gc[widget->state], &event->area);
614
      
615
      x = floor (widget->allocation.x + (gint)misc->xpad
616 617
		 + ((widget->allocation.width - widget->requisition.width) * xalign)
		 + 0.5);
618 619
      
      y = floor (widget->allocation.y + (gint)misc->ypad 
620 621
		 + ((widget->allocation.height - widget->requisition.height) * misc->yalign)
		 + 0.5);
622

623
      gdk_draw_layout (widget->window, widget->style->fg_gc [widget->state], x, y, label->layout);
624
      
625
      gdk_gc_set_clip_mask (widget->style->white_gc, NULL);
626
      gdk_gc_set_clip_mask (widget->style->fg_gc[widget->state], NULL);
627
    }
628

Elliot Lee's avatar
Elliot Lee committed
629 630
  return TRUE;
}
631

632
guint      
633
gtk_label_parse_uline (GtkLabel    *label,
634
		       const gchar *str)
635 636
{
  guint accel_key = GDK_VoidSymbol;
637 638

  gchar *new_str;
Owen Taylor's avatar
Owen Taylor committed
639
  gchar *pattern;
640 641
  const gchar *src;
  gchar *dest, *pattern_dest;
642
  gboolean underscore;
643
      
644
  g_return_val_if_fail (GTK_IS_LABEL (label), GDK_VoidSymbol);
645
  g_return_val_if_fail (str != NULL, GDK_VoidSymbol);
646

647
  /* Convert text to wide characters */
648

649 650
  new_str = g_new (gchar, strlen (str) + 1);
  pattern = g_new (gchar, unicode_strlen (str, -1) + 1);
651
  
652
  underscore = FALSE;
653 654 655 656

  src = str;
  dest = new_str;
  pattern_dest = pattern;
657
  
658
  while (*src)
659
    {
660 661 662 663 664 665 666 667 668 669 670 671
      unicode_char_t c;
      gchar *next_src;
    
      next_src = unicode_get_utf8 (src, &c);
      if (!next_src)
	{
	  g_warning ("Invalid input string");
	  g_free (new_str);
	  g_free (pattern);
	  return GDK_VoidSymbol;
	}
      
672 673
      if (underscore)
	{
674 675
	  if (c == '_')
	    *pattern_dest++ = ' ';
676 677
	  else
	    {
678
	      *pattern_dest++ = '_';
679
	      if (accel_key == GDK_VoidSymbol)
680
		accel_key = gdk_keyval_to_lower (c);
681
	    }
682 683 684

	  while (src < next_src)
	    *dest++ = *src++;
685
	  
686 687 688 689
	  underscore = FALSE;
	}
      else
	{
690 691 692 693 694
	  if (c == '_')
	    {
	      underscore = TRUE;
	      src = next_src;
	    }
695 696
	  else
	    {
697 698 699 700
	      while (src < next_src)
		*dest++ = *src++;
	  
	      *pattern_dest++ = ' ';
701 702 703
	    }
	}
    }
704 705
  *dest = 0;
  *pattern_dest = 0;
706
  
707
  gtk_label_set_text_internal (label, new_str);
708 709 710
  gtk_label_set_pattern (label, pattern);
  
  g_free (pattern);
711
  
712 713
  return accel_key;
}