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

source code of gtk/gtk/gtkcellrenderertext.c