1/* Pango/Rotated Text
2 *
3 * This demo shows how to use PangoCairo to draw rotated and transformed
4 * text. The right pane shows a rotated GtkLabel widget.
5 *
6 * In both cases, a custom PangoCairo shape renderer is installed to draw
7 * a red heart using cairo drawing operations instead of the Unicode heart
8 * character.
9 */
10
11#include <gtk/gtk.h>
12#include <string.h>
13
14#define HEART "♥"
15const char text[] = "I ♥ GTK";
16
17static void
18fancy_shape_renderer (cairo_t *cr,
19 PangoAttrShape *attr,
20 gboolean do_path,
21 gpointer data)
22{
23 double x, y;
24 cairo_get_current_point (cr, x: &x, y: &y);
25 cairo_translate (cr, tx: x, ty: y);
26
27 cairo_scale (cr,
28 sx: (double) attr->ink_rect.width / PANGO_SCALE,
29 sy: (double) attr->ink_rect.height / PANGO_SCALE);
30
31 if (GPOINTER_TO_UINT (attr->data) == 0x2665) /* U+2665 BLACK HEART SUIT */
32 {
33 cairo_move_to (cr, x: .5, y: .0);
34 cairo_line_to (cr, x: .9, y: -.4);
35 cairo_curve_to (cr, x1: 1.1, y1: -.8, x2: .5, y2: -.9, x3: .5, y3: -.5);
36 cairo_curve_to (cr, x1: .5, y1: -.9, x2: -.1, y2: -.8, x3: .1, y3: -.4);
37 cairo_close_path (cr);
38 }
39
40 if (!do_path)
41 {
42 cairo_set_source_rgb (cr, red: 1., green: 0., blue: 0.);
43 cairo_fill (cr);
44 }
45}
46
47static PangoAttrList *
48create_fancy_attr_list_for_layout (PangoLayout *layout)
49{
50 PangoAttrList *attrs;
51 PangoFontMetrics *metrics;
52 int ascent;
53 PangoRectangle ink_rect, logical_rect;
54 const char *p;
55
56 /* Get font metrics and prepare fancy shape size */
57 metrics = pango_context_get_metrics (context: pango_layout_get_context (layout),
58 desc: pango_layout_get_font_description (layout),
59 NULL);
60 ascent = pango_font_metrics_get_ascent (metrics);
61 logical_rect.x = 0;
62 logical_rect.width = ascent;
63 logical_rect.y = -ascent;
64 logical_rect.height = ascent;
65 ink_rect = logical_rect;
66 pango_font_metrics_unref (metrics);
67
68 /* Set fancy shape attributes for all hearts */
69 attrs = pango_attr_list_new ();
70 for (p = text; (p = strstr (haystack: p, HEART)); p += strlen (HEART))
71 {
72 PangoAttribute *attr;
73
74 attr = pango_attr_shape_new_with_data (ink_rect: &ink_rect,
75 logical_rect: &logical_rect,
76 GUINT_TO_POINTER (g_utf8_get_char (p)),
77 NULL, NULL);
78
79 attr->start_index = p - text;
80 attr->end_index = attr->start_index + strlen (HEART);
81
82 pango_attr_list_insert (list: attrs, attr);
83 }
84
85 return attrs;
86}
87
88static void
89rotated_text_draw (GtkDrawingArea *da,
90 cairo_t *cr,
91 int width,
92 int height,
93 gpointer data)
94{
95#define RADIUS 150
96#define N_WORDS 5
97#define FONT "Serif 18"
98
99 PangoContext *context;
100 PangoLayout *layout;
101 PangoFontDescription *desc;
102
103 cairo_pattern_t *pattern;
104
105 PangoAttrList *attrs;
106
107 double device_radius;
108 int i;
109
110 /* Create a cairo context and set up a transformation matrix so that the user
111 * space coordinates for the centered square where we draw are [-RADIUS, RADIUS],
112 * [-RADIUS, RADIUS].
113 * We first center, then change the scale. */
114 device_radius = MIN (width, height) / 2.;
115 cairo_translate (cr,
116 tx: device_radius + (width - 2 * device_radius) / 2,
117 ty: device_radius + (height - 2 * device_radius) / 2);
118 cairo_scale (cr, sx: device_radius / RADIUS, sy: device_radius / RADIUS);
119
120 /* Create and a subtle gradient source and use it. */
121 pattern = cairo_pattern_create_linear (x0: -RADIUS, y0: -RADIUS, RADIUS, RADIUS);
122 cairo_pattern_add_color_stop_rgb (pattern, offset: 0., red: .5, green: .0, blue: .0);
123 cairo_pattern_add_color_stop_rgb (pattern, offset: 1., red: .0, green: .0, blue: .5);
124 cairo_set_source (cr, source: pattern);
125
126 /* Create a PangoContext and set up our shape renderer */
127 context = gtk_widget_create_pango_context (GTK_WIDGET (da));
128 pango_cairo_context_set_shape_renderer (context,
129 func: fancy_shape_renderer,
130 NULL, NULL);
131
132 /* Create a PangoLayout, set the text, font, and attributes */
133 layout = pango_layout_new (context);
134 pango_layout_set_text (layout, text, length: -1);
135 desc = pango_font_description_from_string (FONT);
136 pango_layout_set_font_description (layout, desc);
137
138 attrs = create_fancy_attr_list_for_layout (layout);
139 pango_layout_set_attributes (layout, attrs);
140 pango_attr_list_unref (list: attrs);
141
142 /* Draw the layout N_WORDS times in a circle */
143 for (i = 0; i < N_WORDS; i++)
144 {
145 int layout_width, layout_height;
146
147 /* Inform Pango to re-layout the text with the new transformation matrix */
148 pango_cairo_update_layout (cr, layout);
149
150 pango_layout_get_pixel_size (layout, width: &layout_width, height: &layout_height);
151 cairo_move_to (cr, x: - layout_width / 2, y: - RADIUS * .9);
152 pango_cairo_show_layout (cr, layout);
153
154 /* Rotate for the next turn */
155 cairo_rotate (cr, G_PI*2 / N_WORDS);
156 }
157
158 /* free the objects we created */
159 pango_font_description_free (desc);
160 g_object_unref (object: layout);
161 g_object_unref (object: context);
162 cairo_pattern_destroy (pattern);
163}
164
165GtkWidget *
166do_rotated_text (GtkWidget *do_widget)
167{
168 static GtkWidget *window = NULL;
169
170 if (!window)
171 {
172 GtkWidget *box;
173 GtkWidget *drawing_area;
174 GtkWidget *label;
175 PangoLayout *layout;
176 PangoAttrList *attrs;
177
178 window = gtk_window_new ();
179 gtk_window_set_display (GTK_WINDOW (window),
180 display: gtk_widget_get_display (widget: do_widget));
181 gtk_window_set_title (GTK_WINDOW (window), title: "Rotated Text");
182 gtk_window_set_default_size (GTK_WINDOW (window), width: 4 * RADIUS, height: 2 * RADIUS);
183 g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: (gpointer *)&window);
184
185 box = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 0);
186 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
187 gtk_window_set_child (GTK_WINDOW (window), child: box);
188
189 /* Add a drawing area */
190 drawing_area = gtk_drawing_area_new ();
191 gtk_box_append (GTK_BOX (box), child: drawing_area);
192 gtk_widget_add_css_class (widget: drawing_area, css_class: "view");
193
194 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (drawing_area),
195 draw_func: rotated_text_draw,
196 NULL, NULL);
197
198 /* And a label */
199 label = gtk_label_new (str: text);
200 gtk_box_append (GTK_BOX (box), child: label);
201
202 /* Set up fancy stuff on the label */
203 layout = gtk_label_get_layout (GTK_LABEL (label));
204 pango_cairo_context_set_shape_renderer (context: pango_layout_get_context (layout),
205 func: fancy_shape_renderer,
206 NULL, NULL);
207 attrs = create_fancy_attr_list_for_layout (layout);
208 gtk_label_set_attributes (GTK_LABEL (label), attrs);
209 pango_attr_list_unref (list: attrs);
210 }
211
212 if (!gtk_widget_get_visible (widget: window))
213 gtk_widget_show (widget: window);
214 else
215 gtk_window_destroy (GTK_WINDOW (window));
216
217 return window;
218}
219

source code of gtk/demos/gtk-demo/rotated_text.c