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 | |
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_snapshot (GtkCellRenderer *cell, |
61 | GtkSnapshot *snapshot, |
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 char *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 | int *minimal_size, |
78 | int *natural_size); |
79 | static void gtk_cell_renderer_text_get_preferred_height (GtkCellRenderer *cell, |
80 | GtkWidget *widget, |
81 | int *minimal_size, |
82 | int *natural_size); |
83 | static 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); |
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 | 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 | |
158 | static guint text_cell_renderer_signals [LAST_SIGNAL]; |
159 | static GParamSpec *text_cell_renderer_props [LAST_PROP]; |
160 | |
161 | #define GTK_CELL_RENDERER_TEXT_PATH "gtk-cell-renderer-text-path" |
162 | |
163 | typedef struct _GtkCellRendererTextPrivate GtkCellRendererTextPrivate; |
164 | |
165 | struct _GtkCellRendererTextPrivate |
166 | { |
167 | GtkWidget *entry; |
168 | |
169 | PangoAttrList *; |
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 : 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 ; |
209 | }; |
210 | |
211 | G_DEFINE_TYPE_WITH_PRIVATE (GtkCellRendererText, gtk_cell_renderer_text, GTK_TYPE_CELL_RENDERER) |
212 | |
213 | static void |
214 | gtk_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 | |
233 | static void |
234 | gtk_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 | |
645 | static void |
646 | gtk_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 | |
667 | static PangoFontMask |
668 | get_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 | |
689 | static void |
690 | gtk_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 | |
871 | static void |
872 | set_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 | |
897 | static void |
898 | set_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 | |
923 | static PangoFontMask |
924 | set_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 | |
963 | static void |
964 | notify_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 | |
981 | static void |
982 | notify_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 | |
1002 | static void |
1003 | set_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 | |
1036 | static void |
1037 | gtk_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 | **/ |
1401 | GtkCellRenderer * |
1402 | gtk_cell_renderer_text_new (void) |
1403 | { |
1404 | return g_object_new (GTK_TYPE_CELL_RENDERER_TEXT, NULL); |
1405 | } |
1406 | |
1407 | static inline gboolean |
1408 | show_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 | |
1416 | static void |
1417 | add_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 | |
1426 | static PangoLayout* |
1427 | get_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 | |
1600 | static void |
1601 | get_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 | |
1688 | static void |
1689 | gtk_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 | |
1747 | static void |
1748 | gtk_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 | |
1784 | static void |
1785 | gtk_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 | |
1800 | static GtkCellEditable * |
1801 | gtk_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 | **/ |
1861 | void |
1862 | gtk_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 | |
1885 | static void |
1886 | gtk_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 | |
1967 | static void |
1968 | gtk_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 | |
1994 | static void |
1995 | gtk_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 | |
2014 | static void |
2015 | gtk_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 | |