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