3 * This demo shows how to use PangoCairo to draw rotated and transformed
4 * text. The right pane shows a rotated GtkLabel widget.
6 * In both cases, a custom PangoCairo shape renderer is installed to draw
7 * a red heard using cairo drawing operations instead of the Unicode heart
14 static GtkWidget *window = NULL;
17 const char text[] = "I ♥ GTK+";
20 fancy_shape_renderer (cairo_t *cr,
26 cairo_get_current_point (cr, &x, &y);
27 cairo_translate (cr, x, y);
30 (double) attr->ink_rect.width / PANGO_SCALE,
31 (double) attr->ink_rect.height / PANGO_SCALE);
33 switch (GPOINTER_TO_UINT (attr->data))
35 case 0x2665: /* U+2665 BLACK HEART SUIT */
37 cairo_move_to (cr, .5, .0);
38 cairo_line_to (cr, .9, -.4);
39 cairo_curve_to (cr, 1.1, -.8, .5, -.9, .5, -.5);
40 cairo_curve_to (cr, .5, -.9, -.1, -.8, .1, -.4);
41 cairo_close_path (cr);
47 cairo_set_source_rgb (cr, 1., 0., 0.);
53 create_fancy_attr_list_for_layout (PangoLayout *layout)
56 PangoFontMetrics *metrics;
58 PangoRectangle ink_rect, logical_rect;
61 /* Get font metrics and prepare fancy shape size */
62 metrics = pango_context_get_metrics (pango_layout_get_context (layout),
63 pango_layout_get_font_description (layout),
65 ascent = pango_font_metrics_get_ascent (metrics);
67 logical_rect.width = ascent;
68 logical_rect.y = -ascent;
69 logical_rect.height = ascent;
70 ink_rect = logical_rect;
71 pango_font_metrics_unref (metrics);
73 /* Set fancy shape attributes for all hearts */
74 attrs = pango_attr_list_new ();
75 for (p = text; (p = strstr (p, HEART)); p += strlen (HEART))
79 attr = pango_attr_shape_new_with_data (&ink_rect,
81 GUINT_TO_POINTER (g_utf8_get_char (p)),
84 attr->start_index = p - text;
85 attr->end_index = attr->start_index + strlen (HEART);
87 pango_attr_list_insert (attrs, attr);
94 rotated_text_expose_event (GtkWidget *widget,
95 GdkEventExpose *event,
100 #define FONT "Serif 18"
102 PangoContext *context;
104 PangoFontDescription *desc;
107 cairo_pattern_t *pattern;
109 PangoAttrList *attrs;
111 int width = widget->allocation.width;
112 int height = widget->allocation.height;
113 double device_radius;
116 /* Create a cairo context and set up a transformation matrix so that the user
117 * space coordinates for the centered square where we draw are [-RADIUS, RADIUS],
119 * We first center, then change the scale. */
120 cr = gdk_cairo_create (widget->window);
121 device_radius = MIN (width, height) / 2.;
123 device_radius + (width - 2 * device_radius) / 2,
124 device_radius + (height - 2 * device_radius) / 2);
125 cairo_scale (cr, device_radius / RADIUS, device_radius / RADIUS);
127 /* Create and a subtle gradient source and use it. */
128 pattern = cairo_pattern_create_linear (-RADIUS, -RADIUS, RADIUS, RADIUS);
129 cairo_pattern_add_color_stop_rgb (pattern, 0., .5, .0, .0);
130 cairo_pattern_add_color_stop_rgb (pattern, 1., .0, .0, .5);
131 cairo_set_source (cr, pattern);
133 /* Create a PangoContext and set up our shape renderer */
134 context = gtk_widget_create_pango_context (widget);
135 pango_cairo_context_set_shape_renderer (context,
136 fancy_shape_renderer,
139 /* Create a PangoLayout, set the text, font, and attributes */
140 layout = pango_layout_new (context);
141 pango_layout_set_text (layout, text, -1);
142 desc = pango_font_description_from_string (FONT);
143 pango_layout_set_font_description (layout, desc);
145 attrs = create_fancy_attr_list_for_layout (layout);
146 pango_layout_set_attributes (layout, attrs);
147 pango_attr_list_unref (attrs);
149 /* Draw the layout N_WORDS times in a circle */
150 for (i = 0; i < N_WORDS; i++)
154 /* Inform Pango to re-layout the text with the new transformation matrix */
155 pango_cairo_update_layout (cr, layout);
157 pango_layout_get_pixel_size (layout, &width, &height);
158 cairo_move_to (cr, - width / 2, - RADIUS * .9);
159 pango_cairo_show_layout (cr, layout);
161 /* Rotate for the next turn */
162 cairo_rotate (cr, G_PI*2 / N_WORDS);
165 /* free the objects we created */
166 pango_font_description_free (desc);
167 g_object_unref (layout);
168 g_object_unref (context);
169 cairo_pattern_destroy (pattern);
176 do_rotated_text (GtkWidget *do_widget)
181 GtkWidget *drawing_area;
184 PangoAttrList *attrs;
186 const GdkColor white = { 0, 0xffff, 0xffff, 0xffff };
188 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
189 gtk_window_set_screen (GTK_WINDOW (window),
190 gtk_widget_get_screen (do_widget));
191 gtk_window_set_title (GTK_WINDOW (window), "Rotated Text");
192 gtk_window_set_default_size (GTK_WINDOW (window), 4 * RADIUS, 2 * RADIUS);
193 g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
195 box = gtk_hbox_new (TRUE, 0);
196 gtk_container_add (GTK_CONTAINER (window), box);
198 /* Add a drawing area */
200 drawing_area = gtk_drawing_area_new ();
201 gtk_container_add (GTK_CONTAINER (box), drawing_area);
203 /* This overrides the background color from the theme */
204 gtk_widget_modify_bg (drawing_area, GTK_STATE_NORMAL, &white);
206 g_signal_connect (drawing_area, "expose-event",
207 G_CALLBACK (rotated_text_expose_event), NULL);
211 label = gtk_label_new (text);
212 gtk_container_add (GTK_CONTAINER (box), label);
214 gtk_label_set_angle (GTK_LABEL (label), 45);
216 /* Set up fancy stuff on the label */
217 layout = gtk_label_get_layout (GTK_LABEL (label));
218 pango_cairo_context_set_shape_renderer (pango_layout_get_context (layout),
219 fancy_shape_renderer,
221 attrs = create_fancy_attr_list_for_layout (layout);
222 gtk_label_set_attributes (GTK_LABEL (label), attrs);
223 pango_attr_list_unref (attrs);
226 if (!gtk_widget_get_visible (window))
228 gtk_widget_show_all (window);
232 gtk_widget_destroy (window);