]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellrenderertext.c
gtkcellrenderertext: Move public members to private structure
[~andy/gtk] / gtk / gtkcellrenderertext.c
1 /* gtkcellrenderertext.c
2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21 #include <stdlib.h>
22 #include "gtkcellrenderertext.h"
23 #include "gtkeditable.h"
24 #include "gtkentry.h"
25 #include "gtkmarshalers.h"
26 #include "gtkintl.h"
27 #include "gtkprivate.h"
28 #include "gtktreeprivate.h"
29
30
31 static void gtk_cell_renderer_text_finalize   (GObject                  *object);
32
33 static void gtk_cell_renderer_text_get_property  (GObject                  *object,
34                                                   guint                     param_id,
35                                                   GValue                   *value,
36                                                   GParamSpec               *pspec);
37 static void gtk_cell_renderer_text_set_property  (GObject                  *object,
38                                                   guint                     param_id,
39                                                   const GValue             *value,
40                                                   GParamSpec               *pspec);
41 static void gtk_cell_renderer_text_get_size   (GtkCellRenderer          *cell,
42                                                GtkWidget                *widget,
43                                                GdkRectangle             *cell_area,
44                                                gint                     *x_offset,
45                                                gint                     *y_offset,
46                                                gint                     *width,
47                                                gint                     *height);
48 static void gtk_cell_renderer_text_render     (GtkCellRenderer          *cell,
49                                                GdkWindow                *window,
50                                                GtkWidget                *widget,
51                                                GdkRectangle             *background_area,
52                                                GdkRectangle             *cell_area,
53                                                GdkRectangle             *expose_area,
54                                                GtkCellRendererState      flags);
55
56 static GtkCellEditable *gtk_cell_renderer_text_start_editing (GtkCellRenderer      *cell,
57                                                               GdkEvent             *event,
58                                                               GtkWidget            *widget,
59                                                               const gchar          *path,
60                                                               GdkRectangle         *background_area,
61                                                               GdkRectangle         *cell_area,
62                                                               GtkCellRendererState  flags);
63
64 enum {
65   EDITED,
66   LAST_SIGNAL
67 };
68
69 enum {
70   PROP_0,
71
72   PROP_TEXT,
73   PROP_MARKUP,
74   PROP_ATTRIBUTES,
75   PROP_SINGLE_PARAGRAPH_MODE,
76   PROP_WIDTH_CHARS,
77   PROP_WRAP_WIDTH,
78   PROP_ALIGN,
79   
80   /* Style args */
81   PROP_BACKGROUND,
82   PROP_FOREGROUND,
83   PROP_BACKGROUND_GDK,
84   PROP_FOREGROUND_GDK,
85   PROP_FONT,
86   PROP_FONT_DESC,
87   PROP_FAMILY,
88   PROP_STYLE,
89   PROP_VARIANT,
90   PROP_WEIGHT,
91   PROP_STRETCH,
92   PROP_SIZE,
93   PROP_SIZE_POINTS,
94   PROP_SCALE,
95   PROP_EDITABLE,
96   PROP_STRIKETHROUGH,
97   PROP_UNDERLINE,
98   PROP_RISE,
99   PROP_LANGUAGE,
100   PROP_ELLIPSIZE,
101   PROP_WRAP_MODE,
102   
103   /* Whether-a-style-arg-is-set args */
104   PROP_BACKGROUND_SET,
105   PROP_FOREGROUND_SET,
106   PROP_FAMILY_SET,
107   PROP_STYLE_SET,
108   PROP_VARIANT_SET,
109   PROP_WEIGHT_SET,
110   PROP_STRETCH_SET,
111   PROP_SIZE_SET,
112   PROP_SCALE_SET,
113   PROP_EDITABLE_SET,
114   PROP_STRIKETHROUGH_SET,
115   PROP_UNDERLINE_SET,
116   PROP_RISE_SET,
117   PROP_LANGUAGE_SET,
118   PROP_ELLIPSIZE_SET,
119   PROP_ALIGN_SET
120 };
121
122 static guint text_cell_renderer_signals [LAST_SIGNAL];
123
124 #define GTK_CELL_RENDERER_TEXT_PATH "gtk-cell-renderer-text-path"
125
126 struct _GtkCellRendererTextPriv
127 {
128   GtkWidget *entry;
129
130   PangoAlignment        align;
131   PangoAttrList        *extra_attrs;
132   PangoColor            foreground;
133   PangoColor            background;
134   PangoEllipsizeMode    ellipsize;
135   PangoFontDescription *font;
136   PangoLanguage        *language;
137   PangoUnderline        underline_style;
138   PangoWrapMode         wrap_mode;
139
140   gboolean in_entry_menu;
141
142   gchar *text;
143
144   gdouble font_scale;
145
146   gint rise;
147   gint fixed_height_rows;
148   gint width_chars;
149   gint wrap_width;
150
151   guint strikethrough     : 1;
152   guint editable          : 1;
153   guint scale_set         : 1;
154   guint foreground_set    : 1;
155   guint background_set    : 1;
156   guint underline_set     : 1;
157   guint rise_set          : 1;
158   guint strikethrough_set : 1;
159   guint editable_set      : 1;
160   guint calc_fixed_height : 1;
161   guint single_paragraph  : 1;
162   guint language_set      : 1;
163   guint markup_set        : 1;
164   guint ellipsize_set     : 1;
165   guint align_set         : 1;
166
167   gulong focus_out_id;
168   gulong populate_popup_id;
169   gulong entry_menu_popdown_timeout;
170 };
171
172 G_DEFINE_TYPE (GtkCellRendererText, gtk_cell_renderer_text, GTK_TYPE_CELL_RENDERER)
173
174 static void
175 gtk_cell_renderer_text_init (GtkCellRendererText *celltext)
176 {
177   GtkCellRendererTextPriv *priv;
178   GtkCellRenderer *cell = GTK_CELL_RENDERER (celltext);
179
180   celltext->priv = G_TYPE_INSTANCE_GET_PRIVATE (celltext,
181                                                 GTK_TYPE_CELL_RENDERER_TEXT,
182                                                 GtkCellRendererTextPriv);
183   priv = celltext->priv;
184
185   gtk_cell_renderer_set_alignment (cell, 0.0, 0.5);
186   gtk_cell_renderer_set_padding (cell, 2, 2);
187   priv->font_scale = 1.0;
188   priv->fixed_height_rows = -1;
189   priv->font = pango_font_description_new ();
190
191   priv->width_chars = -1;
192   priv->wrap_width = -1;
193   priv->wrap_mode = PANGO_WRAP_CHAR;
194   priv->align = PANGO_ALIGN_LEFT;
195   priv->align_set = FALSE;
196 }
197
198 static void
199 gtk_cell_renderer_text_class_init (GtkCellRendererTextClass *class)
200 {
201   GObjectClass *object_class = G_OBJECT_CLASS (class);
202   GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
203
204   object_class->finalize = gtk_cell_renderer_text_finalize;
205   
206   object_class->get_property = gtk_cell_renderer_text_get_property;
207   object_class->set_property = gtk_cell_renderer_text_set_property;
208
209   cell_class->get_size = gtk_cell_renderer_text_get_size;
210   cell_class->render = gtk_cell_renderer_text_render;
211   cell_class->start_editing = gtk_cell_renderer_text_start_editing;
212
213   g_object_class_install_property (object_class,
214                                    PROP_TEXT,
215                                    g_param_spec_string ("text",
216                                                         P_("Text"),
217                                                         P_("Text to render"),
218                                                         NULL,
219                                                         GTK_PARAM_READWRITE));
220   
221   g_object_class_install_property (object_class,
222                                    PROP_MARKUP,
223                                    g_param_spec_string ("markup",
224                                                         P_("Markup"),
225                                                         P_("Marked up text to render"),
226                                                         NULL,
227                                                         GTK_PARAM_WRITABLE));
228
229   g_object_class_install_property (object_class,
230                                    PROP_ATTRIBUTES,
231                                    g_param_spec_boxed ("attributes",
232                                                        P_("Attributes"),
233                                                        P_("A list of style attributes to apply to the text of the renderer"),
234                                                        PANGO_TYPE_ATTR_LIST,
235                                                        GTK_PARAM_READWRITE));
236
237   g_object_class_install_property (object_class,
238                                    PROP_SINGLE_PARAGRAPH_MODE,
239                                    g_param_spec_boolean ("single-paragraph-mode",
240                                                          P_("Single Paragraph Mode"),
241                                                          P_("Whether or not to keep all text in a single paragraph"),
242                                                          FALSE,
243                                                          GTK_PARAM_READWRITE));
244
245   
246   g_object_class_install_property (object_class,
247                                    PROP_BACKGROUND,
248                                    g_param_spec_string ("background",
249                                                         P_("Background color name"),
250                                                         P_("Background color as a string"),
251                                                         NULL,
252                                                         GTK_PARAM_WRITABLE));
253
254   g_object_class_install_property (object_class,
255                                    PROP_BACKGROUND_GDK,
256                                    g_param_spec_boxed ("background-gdk",
257                                                        P_("Background color"),
258                                                        P_("Background color as a GdkColor"),
259                                                        GDK_TYPE_COLOR,
260                                                        GTK_PARAM_READWRITE));  
261
262   g_object_class_install_property (object_class,
263                                    PROP_FOREGROUND,
264                                    g_param_spec_string ("foreground",
265                                                         P_("Foreground color name"),
266                                                         P_("Foreground color as a string"),
267                                                         NULL,
268                                                         GTK_PARAM_WRITABLE));
269
270   g_object_class_install_property (object_class,
271                                    PROP_FOREGROUND_GDK,
272                                    g_param_spec_boxed ("foreground-gdk",
273                                                        P_("Foreground color"),
274                                                        P_("Foreground color as a GdkColor"),
275                                                        GDK_TYPE_COLOR,
276                                                        GTK_PARAM_READWRITE));
277
278
279   g_object_class_install_property (object_class,
280                                    PROP_EDITABLE,
281                                    g_param_spec_boolean ("editable",
282                                                          P_("Editable"),
283                                                          P_("Whether the text can be modified by the user"),
284                                                          FALSE,
285                                                          GTK_PARAM_READWRITE));
286
287   g_object_class_install_property (object_class,
288                                    PROP_FONT,
289                                    g_param_spec_string ("font",
290                                                         P_("Font"),
291                                                         P_("Font description as a string, e.g. \"Sans Italic 12\""),
292                                                         NULL,
293                                                         GTK_PARAM_READWRITE));
294
295   g_object_class_install_property (object_class,
296                                    PROP_FONT_DESC,
297                                    g_param_spec_boxed ("font-desc",
298                                                        P_("Font"),
299                                                        P_("Font description as a PangoFontDescription struct"),
300                                                        PANGO_TYPE_FONT_DESCRIPTION,
301                                                        GTK_PARAM_READWRITE));
302
303   
304   g_object_class_install_property (object_class,
305                                    PROP_FAMILY,
306                                    g_param_spec_string ("family",
307                                                         P_("Font family"),
308                                                         P_("Name of the font family, e.g. Sans, Helvetica, Times, Monospace"),
309                                                         NULL,
310                                                         GTK_PARAM_READWRITE));
311
312   g_object_class_install_property (object_class,
313                                    PROP_STYLE,
314                                    g_param_spec_enum ("style",
315                                                       P_("Font style"),
316                                                       P_("Font style"),
317                                                       PANGO_TYPE_STYLE,
318                                                       PANGO_STYLE_NORMAL,
319                                                       GTK_PARAM_READWRITE));
320
321   g_object_class_install_property (object_class,
322                                    PROP_VARIANT,
323                                    g_param_spec_enum ("variant",
324                                                      P_("Font variant"),
325                                                      P_("Font variant"),
326                                                       PANGO_TYPE_VARIANT,
327                                                       PANGO_VARIANT_NORMAL,
328                                                       GTK_PARAM_READWRITE));
329   
330   g_object_class_install_property (object_class,
331                                    PROP_WEIGHT,
332                                    g_param_spec_int ("weight",
333                                                      P_("Font weight"),
334                                                      P_("Font weight"),
335                                                      0,
336                                                      G_MAXINT,
337                                                      PANGO_WEIGHT_NORMAL,
338                                                      GTK_PARAM_READWRITE));
339
340    g_object_class_install_property (object_class,
341                                    PROP_STRETCH,
342                                    g_param_spec_enum ("stretch",
343                                                       P_("Font stretch"),
344                                                       P_("Font stretch"),
345                                                       PANGO_TYPE_STRETCH,
346                                                       PANGO_STRETCH_NORMAL,
347                                                       GTK_PARAM_READWRITE));
348   
349   g_object_class_install_property (object_class,
350                                    PROP_SIZE,
351                                    g_param_spec_int ("size",
352                                                      P_("Font size"),
353                                                      P_("Font size"),
354                                                      0,
355                                                      G_MAXINT,
356                                                      0,
357                                                      GTK_PARAM_READWRITE));
358
359   g_object_class_install_property (object_class,
360                                    PROP_SIZE_POINTS,
361                                    g_param_spec_double ("size-points",
362                                                         P_("Font points"),
363                                                         P_("Font size in points"),
364                                                         0.0,
365                                                         G_MAXDOUBLE,
366                                                         0.0,
367                                                         GTK_PARAM_READWRITE));  
368
369   g_object_class_install_property (object_class,
370                                    PROP_SCALE,
371                                    g_param_spec_double ("scale",
372                                                         P_("Font scale"),
373                                                         P_("Font scaling factor"),
374                                                         0.0,
375                                                         G_MAXDOUBLE,
376                                                         1.0,
377                                                         GTK_PARAM_READWRITE));
378   
379   g_object_class_install_property (object_class,
380                                    PROP_RISE,
381                                    g_param_spec_int ("rise",
382                                                      P_("Rise"),
383                                                      P_("Offset of text above the baseline "
384                                                         "(below the baseline if rise is negative)"),
385                                                      -G_MAXINT,
386                                                      G_MAXINT,
387                                                      0,
388                                                      GTK_PARAM_READWRITE));
389
390
391   g_object_class_install_property (object_class,
392                                    PROP_STRIKETHROUGH,
393                                    g_param_spec_boolean ("strikethrough",
394                                                          P_("Strikethrough"),
395                                                          P_("Whether to strike through the text"),
396                                                          FALSE,
397                                                          GTK_PARAM_READWRITE));
398   
399   g_object_class_install_property (object_class,
400                                    PROP_UNDERLINE,
401                                    g_param_spec_enum ("underline",
402                                                       P_("Underline"),
403                                                       P_("Style of underline for this text"),
404                                                       PANGO_TYPE_UNDERLINE,
405                                                       PANGO_UNDERLINE_NONE,
406                                                       GTK_PARAM_READWRITE));
407
408   g_object_class_install_property (object_class,
409                                    PROP_LANGUAGE,
410                                    g_param_spec_string ("language",
411                                                         P_("Language"),
412                                                         P_("The language this text is in, as an ISO code. "
413                                                            "Pango can use this as a hint when rendering the text. "
414                                                            "If you don't understand this parameter, you probably don't need it"),
415                                                         NULL,
416                                                         GTK_PARAM_READWRITE));
417
418
419   /**
420    * GtkCellRendererText:ellipsize:
421    *
422    * Specifies the preferred place to ellipsize the string, if the cell renderer 
423    * does not have enough room to display the entire string. Setting it to 
424    * %PANGO_ELLIPSIZE_NONE turns off ellipsizing. See the wrap-width property
425    * for another way of making the text fit into a given width.
426    *
427    * Since: 2.6
428    */
429   g_object_class_install_property (object_class,
430                                    PROP_ELLIPSIZE,
431                                    g_param_spec_enum ("ellipsize",
432                                                       P_("Ellipsize"),
433                                                       P_("The preferred place to ellipsize the string, "
434                                                          "if the cell renderer does not have enough room "
435                                                          "to display the entire string"),
436                                                       PANGO_TYPE_ELLIPSIZE_MODE,
437                                                       PANGO_ELLIPSIZE_NONE,
438                                                       GTK_PARAM_READWRITE));
439
440   /**
441    * GtkCellRendererText:width-chars:
442    * 
443    * The desired width of the cell, in characters. If this property is set to
444    * -1, the width will be calculated automatically, otherwise the cell will
445    * request either 3 characters or the property value, whichever is greater.
446    * 
447    * Since: 2.6
448    **/
449   g_object_class_install_property (object_class,
450                                    PROP_WIDTH_CHARS,
451                                    g_param_spec_int ("width-chars",
452                                                      P_("Width In Characters"),
453                                                      P_("The desired width of the label, in characters"),
454                                                      -1,
455                                                      G_MAXINT,
456                                                      -1,
457                                                      GTK_PARAM_READWRITE));
458   
459   /**
460    * GtkCellRendererText:wrap-mode:
461    *
462    * Specifies how to break the string into multiple lines, if the cell 
463    * renderer does not have enough room to display the entire string. 
464    * This property has no effect unless the wrap-width property is set.
465    *
466    * Since: 2.8
467    */
468   g_object_class_install_property (object_class,
469                                    PROP_WRAP_MODE,
470                                    g_param_spec_enum ("wrap-mode",
471                                                       P_("Wrap mode"),
472                                                       P_("How to break the string into multiple lines, "
473                                                          "if the cell renderer does not have enough room "
474                                                          "to display the entire string"),
475                                                       PANGO_TYPE_WRAP_MODE,
476                                                       PANGO_WRAP_CHAR,
477                                                       GTK_PARAM_READWRITE));
478
479   /**
480    * GtkCellRendererText:wrap-width:
481    *
482    * Specifies the width at which the text is wrapped. The wrap-mode property can 
483    * be used to influence at what character positions the line breaks can be placed.
484    * Setting wrap-width to -1 turns wrapping off.
485    *
486    * Since: 2.8
487    */
488   g_object_class_install_property (object_class,
489                                    PROP_WRAP_WIDTH,
490                                    g_param_spec_int ("wrap-width",
491                                                      P_("Wrap width"),
492                                                      P_("The width at which the text is wrapped"),
493                                                      -1,
494                                                      G_MAXINT,
495                                                      -1,
496                                                      GTK_PARAM_READWRITE));
497
498   /**
499    * GtkCellRendererText:alignment:
500    *
501    * Specifies how to align the lines of text with respect to each other. 
502    *
503    * Note that this property describes how to align the lines of text in 
504    * case there are several of them. The "xalign" property of #GtkCellRenderer, 
505    * on the other hand, sets the horizontal alignment of the whole text.
506    *
507    * Since: 2.10
508    */
509   g_object_class_install_property (object_class,
510                                    PROP_ALIGN,
511                                    g_param_spec_enum ("alignment",
512                                                       P_("Alignment"),
513                                                       P_("How to align the lines"),
514                                                       PANGO_TYPE_ALIGNMENT,
515                                                       PANGO_ALIGN_LEFT,
516                                                       GTK_PARAM_READWRITE));
517   
518   /* Style props are set or not */
519
520 #define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (object_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, GTK_PARAM_READWRITE))
521
522   ADD_SET_PROP ("background-set", PROP_BACKGROUND_SET,
523                 P_("Background set"),
524                 P_("Whether this tag affects the background color"));
525
526   ADD_SET_PROP ("foreground-set", PROP_FOREGROUND_SET,
527                 P_("Foreground set"),
528                 P_("Whether this tag affects the foreground color"));
529   
530   ADD_SET_PROP ("editable-set", PROP_EDITABLE_SET,
531                 P_("Editability set"),
532                 P_("Whether this tag affects text editability"));
533
534   ADD_SET_PROP ("family-set", PROP_FAMILY_SET,
535                 P_("Font family set"),
536                 P_("Whether this tag affects the font family"));  
537
538   ADD_SET_PROP ("style-set", PROP_STYLE_SET,
539                 P_("Font style set"),
540                 P_("Whether this tag affects the font style"));
541
542   ADD_SET_PROP ("variant-set", PROP_VARIANT_SET,
543                 P_("Font variant set"),
544                 P_("Whether this tag affects the font variant"));
545
546   ADD_SET_PROP ("weight-set", PROP_WEIGHT_SET,
547                 P_("Font weight set"),
548                 P_("Whether this tag affects the font weight"));
549
550   ADD_SET_PROP ("stretch-set", PROP_STRETCH_SET,
551                 P_("Font stretch set"),
552                 P_("Whether this tag affects the font stretch"));
553
554   ADD_SET_PROP ("size-set", PROP_SIZE_SET,
555                 P_("Font size set"),
556                 P_("Whether this tag affects the font size"));
557
558   ADD_SET_PROP ("scale-set", PROP_SCALE_SET,
559                 P_("Font scale set"),
560                 P_("Whether this tag scales the font size by a factor"));
561   
562   ADD_SET_PROP ("rise-set", PROP_RISE_SET,
563                 P_("Rise set"),
564                 P_("Whether this tag affects the rise"));
565
566   ADD_SET_PROP ("strikethrough-set", PROP_STRIKETHROUGH_SET,
567                 P_("Strikethrough set"),
568                 P_("Whether this tag affects strikethrough"));
569
570   ADD_SET_PROP ("underline-set", PROP_UNDERLINE_SET,
571                 P_("Underline set"),
572                 P_("Whether this tag affects underlining"));
573
574   ADD_SET_PROP ("language-set", PROP_LANGUAGE_SET,
575                 P_("Language set"),
576                 P_("Whether this tag affects the language the text is rendered as"));
577
578   ADD_SET_PROP ("ellipsize-set", PROP_ELLIPSIZE_SET,
579                 P_("Ellipsize set"),
580                 P_("Whether this tag affects the ellipsize mode"));
581
582   ADD_SET_PROP ("align-set", PROP_ALIGN_SET,
583                 P_("Align set"),
584                 P_("Whether this tag affects the alignment mode"));
585
586   /**
587    * GtkCellRendererText::edited
588    * @renderer: the object which received the signal
589    * @path: the path identifying the edited cell
590    * @new_text: the new text
591    *
592    * This signal is emitted after @renderer has been edited.
593    *
594    * It is the responsibility of the application to update the model
595    * and store @new_text at the position indicated by @path.
596    */
597   text_cell_renderer_signals [EDITED] =
598     g_signal_new (I_("edited"),
599                   G_OBJECT_CLASS_TYPE (object_class),
600                   G_SIGNAL_RUN_LAST,
601                   G_STRUCT_OFFSET (GtkCellRendererTextClass, edited),
602                   NULL, NULL,
603                   _gtk_marshal_VOID__STRING_STRING,
604                   G_TYPE_NONE, 2,
605                   G_TYPE_STRING,
606                   G_TYPE_STRING);
607
608   g_type_class_add_private (object_class, sizeof (GtkCellRendererTextPriv));
609 }
610
611 static void
612 gtk_cell_renderer_text_finalize (GObject *object)
613 {
614   GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (object);
615   GtkCellRendererTextPriv *priv = celltext->priv;
616
617   pango_font_description_free (priv->font);
618
619   g_free (priv->text);
620
621   if (priv->extra_attrs)
622     pango_attr_list_unref (priv->extra_attrs);
623
624   if (priv->language)
625     g_object_unref (priv->language);
626
627   G_OBJECT_CLASS (gtk_cell_renderer_text_parent_class)->finalize (object);
628 }
629
630 static PangoFontMask
631 get_property_font_set_mask (guint prop_id)
632 {
633   switch (prop_id)
634     {
635     case PROP_FAMILY_SET:
636       return PANGO_FONT_MASK_FAMILY;
637     case PROP_STYLE_SET:
638       return PANGO_FONT_MASK_STYLE;
639     case PROP_VARIANT_SET:
640       return PANGO_FONT_MASK_VARIANT;
641     case PROP_WEIGHT_SET:
642       return PANGO_FONT_MASK_WEIGHT;
643     case PROP_STRETCH_SET:
644       return PANGO_FONT_MASK_STRETCH;
645     case PROP_SIZE_SET:
646       return PANGO_FONT_MASK_SIZE;
647     }
648
649   return 0;
650 }
651
652 static void
653 gtk_cell_renderer_text_get_property (GObject        *object,
654                                      guint           param_id,
655                                      GValue         *value,
656                                      GParamSpec     *pspec)
657 {
658   GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (object);
659   GtkCellRendererTextPriv *priv = celltext->priv;
660
661   switch (param_id)
662     {
663     case PROP_TEXT:
664       g_value_set_string (value, priv->text);
665       break;
666
667     case PROP_ATTRIBUTES:
668       g_value_set_boxed (value, priv->extra_attrs);
669       break;
670
671     case PROP_SINGLE_PARAGRAPH_MODE:
672       g_value_set_boolean (value, priv->single_paragraph);
673       break;
674
675     case PROP_BACKGROUND_GDK:
676       {
677         GdkColor color;
678         
679         color.red = priv->background.red;
680         color.green = priv->background.green;
681         color.blue = priv->background.blue;
682         
683         g_value_set_boxed (value, &color);
684       }
685       break;
686
687     case PROP_FOREGROUND_GDK:
688       {
689         GdkColor color;
690         
691         color.red = priv->foreground.red;
692         color.green = priv->foreground.green;
693         color.blue = priv->foreground.blue;
694         
695         g_value_set_boxed (value, &color);
696       }
697       break;
698
699     case PROP_FONT:
700         g_value_take_string (value, pango_font_description_to_string (priv->font));
701       break;
702       
703     case PROP_FONT_DESC:
704       g_value_set_boxed (value, priv->font);
705       break;
706
707     case PROP_FAMILY:
708       g_value_set_string (value, pango_font_description_get_family (priv->font));
709       break;
710
711     case PROP_STYLE:
712       g_value_set_enum (value, pango_font_description_get_style (priv->font));
713       break;
714
715     case PROP_VARIANT:
716       g_value_set_enum (value, pango_font_description_get_variant (priv->font));
717       break;
718
719     case PROP_WEIGHT:
720       g_value_set_int (value, pango_font_description_get_weight (priv->font));
721       break;
722
723     case PROP_STRETCH:
724       g_value_set_enum (value, pango_font_description_get_stretch (priv->font));
725       break;
726
727     case PROP_SIZE:
728       g_value_set_int (value, pango_font_description_get_size (priv->font));
729       break;
730
731     case PROP_SIZE_POINTS:
732       g_value_set_double (value, ((double)pango_font_description_get_size (priv->font)) / (double)PANGO_SCALE);
733       break;
734
735     case PROP_SCALE:
736       g_value_set_double (value, priv->font_scale);
737       break;
738       
739     case PROP_EDITABLE:
740       g_value_set_boolean (value, priv->editable);
741       break;
742
743     case PROP_STRIKETHROUGH:
744       g_value_set_boolean (value, priv->strikethrough);
745       break;
746
747     case PROP_UNDERLINE:
748       g_value_set_enum (value, priv->underline_style);
749       break;
750
751     case PROP_RISE:
752       g_value_set_int (value, priv->rise);
753       break;  
754
755     case PROP_LANGUAGE:
756       g_value_set_static_string (value, pango_language_to_string (priv->language));
757       break;
758
759     case PROP_ELLIPSIZE:
760       g_value_set_enum (value, priv->ellipsize);
761       break;
762       
763     case PROP_WRAP_MODE:
764       g_value_set_enum (value, priv->wrap_mode);
765       break;
766
767     case PROP_WRAP_WIDTH:
768       g_value_set_int (value, priv->wrap_width);
769       break;
770       
771     case PROP_ALIGN:
772       g_value_set_enum (value, priv->align);
773       break;
774
775     case PROP_BACKGROUND_SET:
776       g_value_set_boolean (value, priv->background_set);
777       break;
778
779     case PROP_FOREGROUND_SET:
780       g_value_set_boolean (value, priv->foreground_set);
781       break;
782
783     case PROP_FAMILY_SET:
784     case PROP_STYLE_SET:
785     case PROP_VARIANT_SET:
786     case PROP_WEIGHT_SET:
787     case PROP_STRETCH_SET:
788     case PROP_SIZE_SET:
789       {
790         PangoFontMask mask = get_property_font_set_mask (param_id);
791         g_value_set_boolean (value, (pango_font_description_get_set_fields (priv->font) & mask) != 0);
792         
793         break;
794       }
795
796     case PROP_SCALE_SET:
797       g_value_set_boolean (value, priv->scale_set);
798       break;
799       
800     case PROP_EDITABLE_SET:
801       g_value_set_boolean (value, priv->editable_set);
802       break;
803
804     case PROP_STRIKETHROUGH_SET:
805       g_value_set_boolean (value, priv->strikethrough_set);
806       break;
807
808     case PROP_UNDERLINE_SET:
809       g_value_set_boolean (value, priv->underline_set);
810       break;
811
812     case  PROP_RISE_SET:
813       g_value_set_boolean (value, priv->rise_set);
814       break;
815
816     case PROP_LANGUAGE_SET:
817       g_value_set_boolean (value, priv->language_set);
818       break;
819
820     case PROP_ELLIPSIZE_SET:
821       g_value_set_boolean (value, priv->ellipsize_set);
822       break;
823
824     case PROP_ALIGN_SET:
825       g_value_set_boolean (value, priv->align_set);
826       break;
827       
828     case PROP_WIDTH_CHARS:
829       g_value_set_int (value, priv->width_chars);
830       break;  
831
832     case PROP_BACKGROUND:
833     case PROP_FOREGROUND:
834     case PROP_MARKUP:
835     default:
836       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
837       break;
838     }
839 }
840
841
842 static void
843 set_bg_color (GtkCellRendererText *celltext,
844               GdkColor            *color)
845 {
846   GtkCellRendererTextPriv *priv = celltext->priv;
847
848   if (color)
849     {
850       if (!priv->background_set)
851         {
852           priv->background_set = TRUE;
853           g_object_notify (G_OBJECT (celltext), "background-set");
854         }
855       
856       priv->background.red = color->red;
857       priv->background.green = color->green;
858       priv->background.blue = color->blue;
859     }
860   else
861     {
862       if (priv->background_set)
863         {
864           priv->background_set = FALSE;
865           g_object_notify (G_OBJECT (celltext), "background-set");
866         }
867     }
868 }
869
870
871 static void
872 set_fg_color (GtkCellRendererText *celltext,
873               GdkColor            *color)
874 {
875   GtkCellRendererTextPriv *priv = celltext->priv;
876
877   if (color)
878     {
879       if (!priv->foreground_set)
880         {
881           priv->foreground_set = TRUE;
882           g_object_notify (G_OBJECT (celltext), "foreground-set");
883         }
884       
885       priv->foreground.red = color->red;
886       priv->foreground.green = color->green;
887       priv->foreground.blue = color->blue;
888     }
889   else
890     {
891       if (priv->foreground_set)
892         {
893           priv->foreground_set = FALSE;
894           g_object_notify (G_OBJECT (celltext), "foreground-set");
895         }
896     }
897 }
898
899 static PangoFontMask
900 set_font_desc_fields (PangoFontDescription *desc,
901                       PangoFontMask         to_set)
902 {
903   PangoFontMask changed_mask = 0;
904   
905   if (to_set & PANGO_FONT_MASK_FAMILY)
906     {
907       const char *family = pango_font_description_get_family (desc);
908       if (!family)
909         {
910           family = "sans";
911           changed_mask |= PANGO_FONT_MASK_FAMILY;
912         }
913
914       pango_font_description_set_family (desc, family);
915     }
916   if (to_set & PANGO_FONT_MASK_STYLE)
917     pango_font_description_set_style (desc, pango_font_description_get_style (desc));
918   if (to_set & PANGO_FONT_MASK_VARIANT)
919     pango_font_description_set_variant (desc, pango_font_description_get_variant (desc));
920   if (to_set & PANGO_FONT_MASK_WEIGHT)
921     pango_font_description_set_weight (desc, pango_font_description_get_weight (desc));
922   if (to_set & PANGO_FONT_MASK_STRETCH)
923     pango_font_description_set_stretch (desc, pango_font_description_get_stretch (desc));
924   if (to_set & PANGO_FONT_MASK_SIZE)
925     {
926       gint size = pango_font_description_get_size (desc);
927       if (size <= 0)
928         {
929           size = 10 * PANGO_SCALE;
930           changed_mask |= PANGO_FONT_MASK_SIZE;
931         }
932       
933       pango_font_description_set_size (desc, size);
934     }
935
936   return changed_mask;
937 }
938
939 static void
940 notify_set_changed (GObject       *object,
941                     PangoFontMask  changed_mask)
942 {
943   if (changed_mask & PANGO_FONT_MASK_FAMILY)
944     g_object_notify (object, "family-set");
945   if (changed_mask & PANGO_FONT_MASK_STYLE)
946     g_object_notify (object, "style-set");
947   if (changed_mask & PANGO_FONT_MASK_VARIANT)
948     g_object_notify (object, "variant-set");
949   if (changed_mask & PANGO_FONT_MASK_WEIGHT)
950     g_object_notify (object, "weight-set");
951   if (changed_mask & PANGO_FONT_MASK_STRETCH)
952     g_object_notify (object, "stretch-set");
953   if (changed_mask & PANGO_FONT_MASK_SIZE)
954     g_object_notify (object, "size-set");
955 }
956
957 static void
958 notify_fields_changed (GObject       *object,
959                        PangoFontMask  changed_mask)
960 {
961   if (changed_mask & PANGO_FONT_MASK_FAMILY)
962     g_object_notify (object, "family");
963   if (changed_mask & PANGO_FONT_MASK_STYLE)
964     g_object_notify (object, "style");
965   if (changed_mask & PANGO_FONT_MASK_VARIANT)
966     g_object_notify (object, "variant");
967   if (changed_mask & PANGO_FONT_MASK_WEIGHT)
968     g_object_notify (object, "weight");
969   if (changed_mask & PANGO_FONT_MASK_STRETCH)
970     g_object_notify (object, "stretch");
971   if (changed_mask & PANGO_FONT_MASK_SIZE)
972     g_object_notify (object, "size");
973 }
974
975 static void
976 set_font_description (GtkCellRendererText  *celltext,
977                       PangoFontDescription *font_desc)
978 {
979   GtkCellRendererTextPriv *priv = celltext->priv;
980   GObject *object = G_OBJECT (celltext);
981   PangoFontDescription *new_font_desc;
982   PangoFontMask old_mask, new_mask, changed_mask, set_changed_mask;
983   
984   if (font_desc)
985     new_font_desc = pango_font_description_copy (font_desc);
986   else
987     new_font_desc = pango_font_description_new ();
988
989   old_mask = pango_font_description_get_set_fields (priv->font);
990   new_mask = pango_font_description_get_set_fields (new_font_desc);
991
992   changed_mask = old_mask | new_mask;
993   set_changed_mask = old_mask ^ new_mask;
994
995   pango_font_description_free (priv->font);
996   priv->font = new_font_desc;
997   
998   g_object_freeze_notify (object);
999
1000   g_object_notify (object, "font-desc");
1001   g_object_notify (object, "font");
1002   
1003   if (changed_mask & PANGO_FONT_MASK_FAMILY)
1004     g_object_notify (object, "family");
1005   if (changed_mask & PANGO_FONT_MASK_STYLE)
1006     g_object_notify (object, "style");
1007   if (changed_mask & PANGO_FONT_MASK_VARIANT)
1008     g_object_notify (object, "variant");
1009   if (changed_mask & PANGO_FONT_MASK_WEIGHT)
1010     g_object_notify (object, "weight");
1011   if (changed_mask & PANGO_FONT_MASK_STRETCH)
1012     g_object_notify (object, "stretch");
1013   if (changed_mask & PANGO_FONT_MASK_SIZE)
1014     {
1015       g_object_notify (object, "size");
1016       g_object_notify (object, "size-points");
1017     }
1018
1019   notify_set_changed (object, set_changed_mask);
1020   
1021   g_object_thaw_notify (object);
1022 }
1023
1024 static void
1025 gtk_cell_renderer_text_set_property (GObject      *object,
1026                                      guint         param_id,
1027                                      const GValue *value,
1028                                      GParamSpec   *pspec)
1029 {
1030   GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (object);
1031   GtkCellRendererTextPriv *priv = celltext->priv;
1032
1033   switch (param_id)
1034     {
1035     case PROP_TEXT:
1036       g_free (priv->text);
1037
1038       if (priv->markup_set)
1039         {
1040           if (priv->extra_attrs)
1041             pango_attr_list_unref (priv->extra_attrs);
1042           priv->extra_attrs = NULL;
1043           priv->markup_set = FALSE;
1044         }
1045
1046       priv->text = g_value_dup_string (value);
1047       g_object_notify (object, "text");
1048       break;
1049
1050     case PROP_ATTRIBUTES:
1051       if (priv->extra_attrs)
1052         pango_attr_list_unref (priv->extra_attrs);
1053
1054       priv->extra_attrs = g_value_get_boxed (value);
1055       if (priv->extra_attrs)
1056         pango_attr_list_ref (priv->extra_attrs);
1057       break;
1058     case PROP_MARKUP:
1059       {
1060         const gchar *str;
1061         gchar *text = NULL;
1062         GError *error = NULL;
1063         PangoAttrList *attrs = NULL;
1064
1065         str = g_value_get_string (value);
1066         if (str && !pango_parse_markup (str,
1067                                         -1,
1068                                         0,
1069                                         &attrs,
1070                                         &text,
1071                                         NULL,
1072                                         &error))
1073           {
1074             g_warning ("Failed to set text from markup due to error parsing markup: %s",
1075                        error->message);
1076             g_error_free (error);
1077             return;
1078           }
1079
1080         g_free (priv->text);
1081
1082         if (priv->extra_attrs)
1083           pango_attr_list_unref (priv->extra_attrs);
1084
1085         priv->text = text;
1086         priv->extra_attrs = attrs;
1087         priv->markup_set = TRUE;
1088       }
1089       break;
1090
1091     case PROP_SINGLE_PARAGRAPH_MODE:
1092       priv->single_paragraph = g_value_get_boolean (value);
1093       break;
1094       
1095     case PROP_BACKGROUND:
1096       {
1097         GdkColor color;
1098
1099         if (!g_value_get_string (value))
1100           set_bg_color (celltext, NULL);       /* reset to background_set to FALSE */
1101         else if (gdk_color_parse (g_value_get_string (value), &color))
1102           set_bg_color (celltext, &color);
1103         else
1104           g_warning ("Don't know color `%s'", g_value_get_string (value));
1105
1106         g_object_notify (object, "background-gdk");
1107       }
1108       break;
1109       
1110     case PROP_FOREGROUND:
1111       {
1112         GdkColor color;
1113
1114         if (!g_value_get_string (value))
1115           set_fg_color (celltext, NULL);       /* reset to foreground_set to FALSE */
1116         else if (gdk_color_parse (g_value_get_string (value), &color))
1117           set_fg_color (celltext, &color);
1118         else
1119           g_warning ("Don't know color `%s'", g_value_get_string (value));
1120
1121         g_object_notify (object, "foreground-gdk");
1122       }
1123       break;
1124
1125     case PROP_BACKGROUND_GDK:
1126       /* This notifies the GObject itself. */
1127       set_bg_color (celltext, g_value_get_boxed (value));
1128       break;
1129
1130     case PROP_FOREGROUND_GDK:
1131       /* This notifies the GObject itself. */
1132       set_fg_color (celltext, g_value_get_boxed (value));
1133       break;
1134
1135     case PROP_FONT:
1136       {
1137         PangoFontDescription *font_desc = NULL;
1138         const gchar *name;
1139
1140         name = g_value_get_string (value);
1141
1142         if (name)
1143           font_desc = pango_font_description_from_string (name);
1144
1145         set_font_description (celltext, font_desc);
1146
1147         pango_font_description_free (font_desc);
1148         
1149         if (priv->fixed_height_rows != -1)
1150           priv->calc_fixed_height = TRUE;
1151       }
1152       break;
1153
1154     case PROP_FONT_DESC:
1155       set_font_description (celltext, g_value_get_boxed (value));
1156       
1157       if (priv->fixed_height_rows != -1)
1158         priv->calc_fixed_height = TRUE;
1159       break;
1160
1161     case PROP_FAMILY:
1162     case PROP_STYLE:
1163     case PROP_VARIANT:
1164     case PROP_WEIGHT:
1165     case PROP_STRETCH:
1166     case PROP_SIZE:
1167     case PROP_SIZE_POINTS:
1168       {
1169         PangoFontMask old_set_mask = pango_font_description_get_set_fields (priv->font);
1170         
1171         switch (param_id)
1172           {
1173           case PROP_FAMILY:
1174             pango_font_description_set_family (priv->font,
1175                                                g_value_get_string (value));
1176             break;
1177           case PROP_STYLE:
1178             pango_font_description_set_style (priv->font,
1179                                               g_value_get_enum (value));
1180             break;
1181           case PROP_VARIANT:
1182             pango_font_description_set_variant (priv->font,
1183                                                 g_value_get_enum (value));
1184             break;
1185           case PROP_WEIGHT:
1186             pango_font_description_set_weight (priv->font,
1187                                                g_value_get_int (value));
1188             break;
1189           case PROP_STRETCH:
1190             pango_font_description_set_stretch (priv->font,
1191                                                 g_value_get_enum (value));
1192             break;
1193           case PROP_SIZE:
1194             pango_font_description_set_size (priv->font,
1195                                              g_value_get_int (value));
1196             g_object_notify (object, "size-points");
1197             break;
1198           case PROP_SIZE_POINTS:
1199             pango_font_description_set_size (priv->font,
1200                                              g_value_get_double (value) * PANGO_SCALE);
1201             g_object_notify (object, "size");
1202             break;
1203           }
1204         
1205         if (priv->fixed_height_rows != -1)
1206           priv->calc_fixed_height = TRUE;
1207         
1208         notify_set_changed (object, old_set_mask & pango_font_description_get_set_fields (priv->font));
1209         g_object_notify (object, "font-desc");
1210         g_object_notify (object, "font");
1211
1212         break;
1213       }
1214       
1215     case PROP_SCALE:
1216       priv->font_scale = g_value_get_double (value);
1217       priv->scale_set = TRUE;
1218       if (priv->fixed_height_rows != -1)
1219         priv->calc_fixed_height = TRUE;
1220       g_object_notify (object, "scale-set");
1221       break;
1222       
1223     case PROP_EDITABLE:
1224       priv->editable = g_value_get_boolean (value);
1225       priv->editable_set = TRUE;
1226       if (priv->editable)
1227         g_object_set (celltext, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL);
1228       else
1229         g_object_set (celltext, "mode", GTK_CELL_RENDERER_MODE_INERT, NULL);
1230       g_object_notify (object, "editable-set");
1231       break;
1232
1233     case PROP_STRIKETHROUGH:
1234       priv->strikethrough = g_value_get_boolean (value);
1235       priv->strikethrough_set = TRUE;
1236       g_object_notify (object, "strikethrough-set");
1237       break;
1238
1239     case PROP_UNDERLINE:
1240       priv->underline_style = g_value_get_enum (value);
1241       priv->underline_set = TRUE;
1242       g_object_notify (object, "underline-set");
1243             
1244       break;
1245
1246     case PROP_RISE:
1247       priv->rise = g_value_get_int (value);
1248       priv->rise_set = TRUE;
1249       g_object_notify (object, "rise-set");
1250       if (priv->fixed_height_rows != -1)
1251         priv->calc_fixed_height = TRUE;
1252       break;  
1253
1254     case PROP_LANGUAGE:
1255       priv->language_set = TRUE;
1256       if (priv->language)
1257         g_object_unref (priv->language);
1258       priv->language = pango_language_from_string (g_value_get_string (value));
1259       g_object_notify (object, "language-set");
1260       break;
1261
1262     case PROP_ELLIPSIZE:
1263       priv->ellipsize = g_value_get_enum (value);
1264       priv->ellipsize_set = TRUE;
1265       g_object_notify (object, "ellipsize-set");
1266       break;
1267       
1268     case PROP_WRAP_MODE:
1269       priv->wrap_mode = g_value_get_enum (value);
1270       break;
1271       
1272     case PROP_WRAP_WIDTH:
1273       priv->wrap_width = g_value_get_int (value);
1274       break;
1275             
1276     case PROP_WIDTH_CHARS:
1277       priv->width_chars = g_value_get_int (value);
1278       break;  
1279
1280     case PROP_ALIGN:
1281       priv->align = g_value_get_enum (value);
1282       priv->align_set = TRUE;
1283       g_object_notify (object, "align-set");
1284       break;
1285
1286     case PROP_BACKGROUND_SET:
1287       priv->background_set = g_value_get_boolean (value);
1288       break;
1289
1290     case PROP_FOREGROUND_SET:
1291       priv->foreground_set = g_value_get_boolean (value);
1292       break;
1293
1294     case PROP_FAMILY_SET:
1295     case PROP_STYLE_SET:
1296     case PROP_VARIANT_SET:
1297     case PROP_WEIGHT_SET:
1298     case PROP_STRETCH_SET:
1299     case PROP_SIZE_SET:
1300       if (!g_value_get_boolean (value))
1301         {
1302           pango_font_description_unset_fields (priv->font,
1303                                                get_property_font_set_mask (param_id));
1304         }
1305       else
1306         {
1307           PangoFontMask changed_mask;
1308           
1309           changed_mask = set_font_desc_fields (priv->font,
1310                                                get_property_font_set_mask (param_id));
1311           notify_fields_changed (G_OBJECT (celltext), changed_mask);
1312         }
1313       break;
1314
1315     case PROP_SCALE_SET:
1316       priv->scale_set = g_value_get_boolean (value);
1317       break;
1318       
1319     case PROP_EDITABLE_SET:
1320       priv->editable_set = g_value_get_boolean (value);
1321       break;
1322
1323     case PROP_STRIKETHROUGH_SET:
1324       priv->strikethrough_set = g_value_get_boolean (value);
1325       break;
1326
1327     case PROP_UNDERLINE_SET:
1328       priv->underline_set = g_value_get_boolean (value);
1329       break;
1330
1331     case PROP_RISE_SET:
1332       priv->rise_set = g_value_get_boolean (value);
1333       break;
1334
1335     case PROP_LANGUAGE_SET:
1336       priv->language_set = g_value_get_boolean (value);
1337       break;
1338
1339     case PROP_ELLIPSIZE_SET:
1340       priv->ellipsize_set = g_value_get_boolean (value);
1341       break;
1342
1343     case PROP_ALIGN_SET:
1344       priv->align_set = g_value_get_boolean (value);
1345       break;
1346       
1347     default:
1348       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1349       break;
1350     }
1351 }
1352
1353 /**
1354  * gtk_cell_renderer_text_new:
1355  * 
1356  * Creates a new #GtkCellRendererText. Adjust how text is drawn using
1357  * object properties. Object properties can be
1358  * set globally (with g_object_set()). Also, with #GtkTreeViewColumn,
1359  * you can bind a property to a value in a #GtkTreeModel. For example,
1360  * you can bind the "text" property on the cell renderer to a string
1361  * value in the model, thus rendering a different string in each row
1362  * of the #GtkTreeView
1363  * 
1364  * Return value: the new cell renderer
1365  **/
1366 GtkCellRenderer *
1367 gtk_cell_renderer_text_new (void)
1368 {
1369   return g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, NULL);
1370 }
1371
1372 static void
1373 add_attr (PangoAttrList  *attr_list,
1374           PangoAttribute *attr)
1375 {
1376   attr->start_index = 0;
1377   attr->end_index = G_MAXINT;
1378   
1379   pango_attr_list_insert (attr_list, attr);
1380 }
1381
1382 static PangoLayout*
1383 get_layout (GtkCellRendererText *celltext,
1384             GtkWidget           *widget,
1385             gboolean             will_render,
1386             GtkCellRendererState flags)
1387 {
1388   GtkCellRendererTextPriv *priv = celltext->priv;
1389   PangoAttrList *attr_list;
1390   PangoLayout *layout;
1391   PangoUnderline uline;
1392
1393   layout = gtk_widget_create_pango_layout (widget, priv->text);
1394
1395   if (priv->extra_attrs)
1396     attr_list = pango_attr_list_copy (priv->extra_attrs);
1397   else
1398     attr_list = pango_attr_list_new ();
1399
1400   pango_layout_set_single_paragraph_mode (layout, priv->single_paragraph);
1401
1402   if (will_render)
1403     {
1404       /* Add options that affect appearance but not size */
1405       
1406       /* note that background doesn't go here, since it affects
1407        * background_area not the PangoLayout area
1408        */
1409       
1410       if (priv->foreground_set
1411           && (flags & GTK_CELL_RENDERER_SELECTED) == 0)
1412         {
1413           PangoColor color;
1414
1415           color = priv->foreground;
1416           
1417           add_attr (attr_list,
1418                     pango_attr_foreground_new (color.red, color.green, color.blue));
1419         }
1420
1421       if (priv->strikethrough_set)
1422         add_attr (attr_list,
1423                   pango_attr_strikethrough_new (priv->strikethrough));
1424     }
1425
1426   add_attr (attr_list, pango_attr_font_desc_new (priv->font));
1427
1428   if (priv->scale_set &&
1429       priv->font_scale != 1.0)
1430     add_attr (attr_list, pango_attr_scale_new (priv->font_scale));
1431   
1432   if (priv->underline_set)
1433     uline = priv->underline_style;
1434   else
1435     uline = PANGO_UNDERLINE_NONE;
1436
1437   if (priv->language_set)
1438     add_attr (attr_list, pango_attr_language_new (priv->language));
1439   
1440   if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT)
1441     {
1442       switch (uline)
1443         {
1444         case PANGO_UNDERLINE_NONE:
1445           uline = PANGO_UNDERLINE_SINGLE;
1446           break;
1447
1448         case PANGO_UNDERLINE_SINGLE:
1449           uline = PANGO_UNDERLINE_DOUBLE;
1450           break;
1451
1452         default:
1453           break;
1454         }
1455     }
1456
1457   if (uline != PANGO_UNDERLINE_NONE)
1458     add_attr (attr_list, pango_attr_underline_new (priv->underline_style));
1459
1460   if (priv->rise_set)
1461     add_attr (attr_list, pango_attr_rise_new (priv->rise));
1462
1463   if (priv->ellipsize_set)
1464     pango_layout_set_ellipsize (layout, priv->ellipsize);
1465   else
1466     pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE);
1467
1468   if (priv->wrap_width != -1)
1469     {
1470       pango_layout_set_width (layout, priv->wrap_width * PANGO_SCALE);
1471       pango_layout_set_wrap (layout, priv->wrap_mode);
1472     }
1473   else
1474     {
1475       pango_layout_set_width (layout, -1);
1476       pango_layout_set_wrap (layout, PANGO_WRAP_CHAR);
1477     }
1478
1479   if (priv->align_set)
1480     pango_layout_set_alignment (layout, priv->align);
1481   else
1482     {
1483       PangoAlignment align;
1484
1485       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1486         align = PANGO_ALIGN_RIGHT;
1487       else
1488         align = PANGO_ALIGN_LEFT;
1489
1490       pango_layout_set_alignment (layout, align);
1491     }
1492
1493   pango_layout_set_attributes (layout, attr_list);
1494
1495   pango_attr_list_unref (attr_list);
1496   
1497   return layout;
1498 }
1499
1500 static void
1501 get_size (GtkCellRenderer *cell,
1502           GtkWidget       *widget,
1503           GdkRectangle    *cell_area,
1504           PangoLayout     *layout,
1505           gint            *x_offset,
1506           gint            *y_offset,
1507           gint            *width,
1508           gint            *height)
1509 {
1510   GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (cell);
1511   GtkCellRendererTextPriv *priv = celltext->priv;
1512   PangoRectangle rect;
1513   gint xpad, ypad;
1514   gint cell_width, cell_height;
1515
1516   gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
1517
1518   if (priv->calc_fixed_height)
1519     {
1520       PangoContext *context;
1521       PangoFontMetrics *metrics;
1522       PangoFontDescription *font_desc;
1523       gint row_height;
1524
1525       font_desc = pango_font_description_copy_static (widget->style->font_desc);
1526       pango_font_description_merge_static (font_desc, priv->font, TRUE);
1527
1528       if (priv->scale_set)
1529         pango_font_description_set_size (font_desc,
1530                                          priv->font_scale * pango_font_description_get_size (font_desc));
1531
1532       context = gtk_widget_get_pango_context (widget);
1533
1534       metrics = pango_context_get_metrics (context,
1535                                            font_desc,
1536                                            pango_context_get_language (context));
1537       row_height = (pango_font_metrics_get_ascent (metrics) +
1538                     pango_font_metrics_get_descent (metrics));
1539       pango_font_metrics_unref (metrics);
1540
1541       pango_font_description_free (font_desc);
1542
1543       gtk_cell_renderer_get_fixed_size (cell, &cell_width, &cell_height);
1544
1545       gtk_cell_renderer_set_fixed_size (cell,
1546                                         cell_width, 2 * ypad +
1547                                         priv->fixed_height_rows * PANGO_PIXELS (row_height));
1548       
1549       if (height)
1550         {
1551           *height = cell_height;
1552           height = NULL;
1553         }
1554       priv->calc_fixed_height = FALSE;
1555       if (width == NULL)
1556         return;
1557     }
1558   
1559   if (layout)
1560     g_object_ref (layout);
1561   else
1562     layout = get_layout (celltext, widget, FALSE, 0);
1563
1564   pango_layout_get_pixel_extents (layout, NULL, &rect);
1565
1566   if (height)
1567     *height = ypad * 2 + rect.height;
1568
1569   /* The minimum size for ellipsized labels is ~ 3 chars */
1570   if (width)
1571     {
1572       if (priv->ellipsize || priv->width_chars > 0)
1573         {
1574           PangoContext *context;
1575           PangoFontMetrics *metrics;
1576           gint char_width;
1577
1578           context = pango_layout_get_context (layout);
1579           metrics = pango_context_get_metrics (context, widget->style->font_desc, pango_context_get_language (context));
1580
1581           char_width = pango_font_metrics_get_approximate_char_width (metrics);
1582           pango_font_metrics_unref (metrics);
1583           
1584           *width = xpad * 2 + (PANGO_PIXELS (char_width) * MAX (priv->width_chars, 3));
1585         }
1586       else
1587         {
1588           *width = xpad * 2 + rect.x + rect.width;
1589         }         
1590     }
1591
1592   if (cell_area)
1593     {
1594       gfloat xalign, yalign;
1595
1596       gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
1597
1598       if (x_offset)
1599         {
1600           if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1601             *x_offset = (1.0 - xalign) * (cell_area->width - (rect.x + rect.width + (2 * xpad)));
1602           else 
1603             *x_offset = xalign * (cell_area->width - (rect.x + rect.width + (2 * xpad)));
1604
1605           if ((priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) || priv->wrap_width != -1)
1606             *x_offset = MAX(*x_offset, 0);
1607         }
1608       if (y_offset)
1609         {
1610           *y_offset = yalign * (cell_area->height - (rect.height + (2 * ypad)));
1611           *y_offset = MAX (*y_offset, 0);
1612         }
1613     }
1614   else
1615     {
1616       if (x_offset) *x_offset = 0;
1617       if (y_offset) *y_offset = 0;
1618     }
1619
1620   g_object_unref (layout);
1621 }
1622
1623
1624 static void
1625 gtk_cell_renderer_text_get_size (GtkCellRenderer *cell,
1626                                  GtkWidget       *widget,
1627                                  GdkRectangle    *cell_area,
1628                                  gint            *x_offset,
1629                                  gint            *y_offset,
1630                                  gint            *width,
1631                                  gint            *height)
1632 {
1633   get_size (cell, widget, cell_area, NULL,
1634             x_offset, y_offset, width, height);
1635 }
1636
1637 static void
1638 gtk_cell_renderer_text_render (GtkCellRenderer      *cell,
1639                                GdkDrawable          *window,
1640                                GtkWidget            *widget,
1641                                GdkRectangle         *background_area,
1642                                GdkRectangle         *cell_area,
1643                                GdkRectangle         *expose_area,
1644                                GtkCellRendererState  flags)
1645
1646 {
1647   GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (cell);
1648   GtkCellRendererTextPriv *priv = celltext->priv;
1649   PangoLayout *layout;
1650   GtkStateType state;
1651   gint x_offset;
1652   gint y_offset;
1653   gint xpad, ypad;
1654
1655   layout = get_layout (celltext, widget, TRUE, flags);
1656   get_size (cell, widget, cell_area, layout, &x_offset, &y_offset, NULL, NULL);
1657
1658   if (!gtk_cell_renderer_get_sensitive (cell))
1659     {
1660       state = GTK_STATE_INSENSITIVE;
1661     }
1662   else if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)
1663     {
1664       if (gtk_widget_has_focus (widget))
1665         state = GTK_STATE_SELECTED;
1666       else
1667         state = GTK_STATE_ACTIVE;
1668     }
1669   else if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT &&
1670            gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT)
1671     {
1672       state = GTK_STATE_PRELIGHT;
1673     }
1674   else
1675     {
1676       if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
1677         state = GTK_STATE_INSENSITIVE;
1678       else
1679         state = GTK_STATE_NORMAL;
1680     }
1681
1682   if (priv->background_set && 
1683       (flags & GTK_CELL_RENDERER_SELECTED) == 0)
1684     {
1685       cairo_t *cr = gdk_cairo_create (window);
1686
1687       if (expose_area)
1688         {
1689           gdk_cairo_rectangle (cr, expose_area);
1690           cairo_clip (cr);
1691         }
1692
1693       gdk_cairo_rectangle (cr, background_area);
1694       cairo_set_source_rgb (cr,
1695                             priv->background.red / 65535.,
1696                             priv->background.green / 65535.,
1697                             priv->background.blue / 65535.);
1698       cairo_fill (cr);
1699       
1700       cairo_destroy (cr);
1701     }
1702
1703   gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
1704
1705   if (priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE)
1706     pango_layout_set_width (layout, 
1707                             (cell_area->width - x_offset - 2 * xpad) * PANGO_SCALE);
1708   else if (priv->wrap_width == -1)
1709     pango_layout_set_width (layout, -1);
1710
1711   gtk_paint_layout (widget->style,
1712                     window,
1713                     state,
1714                     TRUE,
1715                     expose_area,
1716                     widget,
1717                     "cellrenderertext",
1718                     cell_area->x + x_offset + xpad,
1719                     cell_area->y + y_offset + ypad,
1720                     layout);
1721
1722   g_object_unref (layout);
1723 }
1724
1725 static void
1726 gtk_cell_renderer_text_editing_done (GtkCellEditable *entry,
1727                                      gpointer         data)
1728 {
1729   GtkCellRendererTextPriv *priv;
1730   const gchar *path;
1731   const gchar *new_text;
1732   gboolean canceled;
1733
1734   priv = GTK_CELL_RENDERER_TEXT (data)->priv;
1735
1736   priv->entry = NULL;
1737
1738   if (priv->focus_out_id > 0)
1739     {
1740       g_signal_handler_disconnect (entry, priv->focus_out_id);
1741       priv->focus_out_id = 0;
1742     }
1743
1744   if (priv->populate_popup_id > 0)
1745     {
1746       g_signal_handler_disconnect (entry, priv->populate_popup_id);
1747       priv->populate_popup_id = 0;
1748     }
1749
1750   if (priv->entry_menu_popdown_timeout)
1751     {
1752       g_source_remove (priv->entry_menu_popdown_timeout);
1753       priv->entry_menu_popdown_timeout = 0;
1754     }
1755
1756   g_object_get (entry,
1757                 "editing-canceled", &canceled,
1758                 NULL);
1759   gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (data), canceled);
1760
1761   if (canceled)
1762     return;
1763
1764   path = g_object_get_data (G_OBJECT (entry), GTK_CELL_RENDERER_TEXT_PATH);
1765   new_text = gtk_entry_get_text (GTK_ENTRY (entry));
1766
1767   g_signal_emit (data, text_cell_renderer_signals[EDITED], 0, path, new_text);
1768 }
1769
1770 static gboolean
1771 popdown_timeout (gpointer data)
1772 {
1773   GtkCellRendererTextPriv *priv;
1774
1775   priv = GTK_CELL_RENDERER_TEXT (data)->priv;
1776
1777   priv->entry_menu_popdown_timeout = 0;
1778
1779   if (!gtk_widget_has_focus (priv->entry))
1780     gtk_cell_renderer_text_editing_done (GTK_CELL_EDITABLE (priv->entry), data);
1781
1782   return FALSE;
1783 }
1784
1785 static void
1786 gtk_cell_renderer_text_popup_unmap (GtkMenu *menu,
1787                                     gpointer data)
1788 {
1789   GtkCellRendererTextPriv *priv;
1790
1791   priv = GTK_CELL_RENDERER_TEXT (data)->priv;
1792
1793   priv->in_entry_menu = FALSE;
1794
1795   if (priv->entry_menu_popdown_timeout)
1796     return;
1797
1798   priv->entry_menu_popdown_timeout = gdk_threads_add_timeout (500, popdown_timeout,
1799                                                     data);
1800 }
1801
1802 static void
1803 gtk_cell_renderer_text_populate_popup (GtkEntry *entry,
1804                                        GtkMenu  *menu,
1805                                        gpointer  data)
1806 {
1807   GtkCellRendererTextPriv *priv;
1808
1809   priv = GTK_CELL_RENDERER_TEXT (data)->priv;
1810
1811   if (priv->entry_menu_popdown_timeout)
1812     {
1813       g_source_remove (priv->entry_menu_popdown_timeout);
1814       priv->entry_menu_popdown_timeout = 0;
1815     }
1816
1817   priv->in_entry_menu = TRUE;
1818
1819   g_signal_connect (menu, "unmap",
1820                     G_CALLBACK (gtk_cell_renderer_text_popup_unmap), data);
1821 }
1822
1823 static gboolean
1824 gtk_cell_renderer_text_focus_out_event (GtkWidget *entry,
1825                                         GdkEvent  *event,
1826                                         gpointer   data)
1827 {
1828   GtkCellRendererTextPriv *priv;
1829
1830   priv = GTK_CELL_RENDERER_TEXT (data)->priv;
1831
1832   if (priv->in_entry_menu)
1833     return FALSE;
1834
1835   g_object_set (entry,
1836                 "editing-canceled", TRUE,
1837                 NULL);
1838   gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
1839   gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
1840
1841   /* entry needs focus-out-event */
1842   return FALSE;
1843 }
1844
1845 static GtkCellEditable *
1846 gtk_cell_renderer_text_start_editing (GtkCellRenderer      *cell,
1847                                       GdkEvent             *event,
1848                                       GtkWidget            *widget,
1849                                       const gchar          *path,
1850                                       GdkRectangle         *background_area,
1851                                       GdkRectangle         *cell_area,
1852                                       GtkCellRendererState  flags)
1853 {
1854   GtkRequisition requisition;
1855   GtkCellRendererText *celltext;
1856   GtkCellRendererTextPriv *priv;
1857   gfloat xalign, yalign;
1858
1859   celltext = GTK_CELL_RENDERER_TEXT (cell);
1860   priv = celltext->priv;
1861
1862   /* If the cell isn't editable we return NULL. */
1863   if (priv->editable == FALSE)
1864     return NULL;
1865
1866   gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
1867
1868   priv->entry = gtk_entry_new ();
1869   gtk_entry_set_has_frame (GTK_ENTRY (priv->entry), FALSE);
1870   gtk_entry_set_alignment (GTK_ENTRY (priv->entry), xalign);
1871
1872   if (priv->text)
1873     gtk_entry_set_text (GTK_ENTRY (priv->entry), priv->text);
1874   g_object_set_data_full (G_OBJECT (priv->entry), I_(GTK_CELL_RENDERER_TEXT_PATH), g_strdup (path), g_free);
1875   
1876   gtk_editable_select_region (GTK_EDITABLE (priv->entry), 0, -1);
1877   
1878   gtk_widget_size_request (priv->entry, &requisition);
1879   if (requisition.height < cell_area->height)
1880     {
1881       GtkBorder *style_border;
1882       GtkBorder border;
1883
1884       gtk_widget_style_get (priv->entry,
1885                             "inner-border", &style_border,
1886                             NULL);
1887
1888       if (style_border)
1889         {
1890           border = *style_border;
1891           g_boxed_free (GTK_TYPE_BORDER, style_border);
1892         }
1893       else
1894         {
1895           /* Since boxed style properties can't have default values ... */
1896           border.left = 2;
1897           border.right = 2;
1898         }
1899
1900       border.top = (cell_area->height - requisition.height) / 2;
1901       border.bottom = (cell_area->height - requisition.height) / 2;
1902       gtk_entry_set_inner_border (GTK_ENTRY (priv->entry), &border);
1903     }
1904
1905   priv->in_entry_menu = FALSE;
1906   if (priv->entry_menu_popdown_timeout)
1907     {
1908       g_source_remove (priv->entry_menu_popdown_timeout);
1909       priv->entry_menu_popdown_timeout = 0;
1910     }
1911
1912   g_signal_connect (priv->entry,
1913                     "editing-done",
1914                     G_CALLBACK (gtk_cell_renderer_text_editing_done),
1915                     celltext);
1916   priv->focus_out_id = g_signal_connect_after (priv->entry, "focus-out-event",
1917                                                G_CALLBACK (gtk_cell_renderer_text_focus_out_event),
1918                                                celltext);
1919   priv->populate_popup_id =
1920     g_signal_connect (priv->entry, "populate-popup",
1921                       G_CALLBACK (gtk_cell_renderer_text_populate_popup),
1922                       celltext);
1923  
1924   gtk_widget_show (priv->entry);
1925
1926   return GTK_CELL_EDITABLE (priv->entry);
1927 }
1928
1929 /**
1930  * gtk_cell_renderer_text_set_fixed_height_from_font:
1931  * @renderer: A #GtkCellRendererText
1932  * @number_of_rows: Number of rows of text each cell renderer is allocated, or -1
1933  * 
1934  * Sets the height of a renderer to explicitly be determined by the "font" and
1935  * "y_pad" property set on it.  Further changes in these properties do not
1936  * affect the height, so they must be accompanied by a subsequent call to this
1937  * function.  Using this function is unflexible, and should really only be used
1938  * if calculating the size of a cell is too slow (ie, a massive number of cells
1939  * displayed).  If @number_of_rows is -1, then the fixed height is unset, and
1940  * the height is determined by the properties again.
1941  **/
1942 void
1943 gtk_cell_renderer_text_set_fixed_height_from_font (GtkCellRendererText *renderer,
1944                                                    gint                 number_of_rows)
1945 {
1946   GtkCellRendererTextPriv *priv;
1947   GtkCellRenderer *cell;
1948
1949   g_return_if_fail (GTK_IS_CELL_RENDERER_TEXT (renderer));
1950   g_return_if_fail (number_of_rows == -1 || number_of_rows > 0);
1951
1952   cell = GTK_CELL_RENDERER (renderer);
1953   priv = renderer->priv;
1954
1955   if (number_of_rows == -1)
1956     {
1957       gint width, height;
1958
1959       gtk_cell_renderer_get_fixed_size (cell, &width, &height);
1960       gtk_cell_renderer_set_fixed_size (cell, width, -1);
1961     }
1962   else
1963     {
1964       priv->fixed_height_rows = number_of_rows;
1965       priv->calc_fixed_height = TRUE;
1966     }
1967 }