forked from AuroraMiddleware/gtk
Bug 437533 – Implement draw_shape PangoRenderer method
2009-03-27 Behdad Esfahbod <behdad@gnome.org> Bug 437533 – Implement draw_shape PangoRenderer method * gdk/gdkpango.c (gdk_pango_renderer_draw_shape), (gdk_pango_renderer_class_init): Implement draw_shape * demos/gtk-demo/rotated_text.c (fancy_shape_renderer), (create_fancy_attr_list_for_layout), (rotated_text_expose_event), (do_rotated_text): 1) Port to pangocairo 2) Also show a rotated label 3) Install a custom shape renderer on both. The second one goes through gdkpango and hence tests the patch above. It's working. svn path=/trunk/; revision=22592
This commit is contained in:
parent
4d520f241d
commit
d21f55fe9a
15
ChangeLog
15
ChangeLog
@ -1,3 +1,18 @@
|
||||
2009-03-27 Behdad Esfahbod <behdad@gnome.org>
|
||||
|
||||
Bug 437533 – Implement draw_shape PangoRenderer method
|
||||
|
||||
* gdk/gdkpango.c (gdk_pango_renderer_draw_shape),
|
||||
(gdk_pango_renderer_class_init): Implement draw_shape
|
||||
|
||||
* demos/gtk-demo/rotated_text.c (fancy_shape_renderer),
|
||||
(create_fancy_attr_list_for_layout), (rotated_text_expose_event),
|
||||
(do_rotated_text):
|
||||
1) Port to pangocairo
|
||||
2) Also show a rotated label
|
||||
3) Install a custom shape renderer on both. The second one goes
|
||||
through gdkpango and hence tests the patch above. It's working.
|
||||
|
||||
2009-03-26 Stef Walter <stef@memberwebs.com>
|
||||
|
||||
* gtk/gtkfilechooserentry.c
|
||||
|
@ -1,101 +1,173 @@
|
||||
/* Rotated Text
|
||||
*
|
||||
* This demo shows how to use GDK and Pango to draw rotated and transformed
|
||||
* text. The use of GdkPangoRenderer in this example is a somewhat advanced
|
||||
* technique; most applications can simply use gdk_draw_layout(). We use
|
||||
* it here mostly because that allows us to work in user coordinates - that is,
|
||||
* coordinates prior to the application of the transformation matrix, rather
|
||||
* than device coordinates.
|
||||
* This demo shows how to use PangoCairo to draw rotated and transformed
|
||||
* text. The right pane shows a rotated GtkLabel widget.
|
||||
*
|
||||
* As of GTK+-2.6, the ability to draw transformed and anti-aliased graphics
|
||||
* as shown in this example is only present for text. With GTK+-2.8, a new
|
||||
* graphics system called "Cairo" will be introduced that provides these
|
||||
* capabilities and many more for all types of graphics.
|
||||
* In both cases, a custom PangoCairo shape renderer is installed to draw
|
||||
* a red heard using cairo drawing operations instead of the Unicode heart
|
||||
* character.
|
||||
*/
|
||||
#include <math.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <string.h>
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
#define HEART "♥"
|
||||
const char text[] = "I ♥ GTK+";
|
||||
|
||||
static void
|
||||
fancy_shape_renderer (cairo_t *cr,
|
||||
PangoAttrShape *attr,
|
||||
gboolean do_path,
|
||||
gpointer data)
|
||||
{
|
||||
double x, y;
|
||||
cairo_get_current_point (cr, &x, &y);
|
||||
cairo_translate (cr, x, y);
|
||||
|
||||
cairo_scale (cr,
|
||||
(double) attr->ink_rect.width / PANGO_SCALE,
|
||||
(double) attr->ink_rect.height / PANGO_SCALE);
|
||||
|
||||
switch (GPOINTER_TO_UINT (attr->data))
|
||||
{
|
||||
case 0x2665: /* U+2665 BLACK HEART SUIT */
|
||||
{
|
||||
cairo_move_to (cr, .5, .0);
|
||||
cairo_line_to (cr, .9, -.4);
|
||||
cairo_curve_to (cr, 1.1, -.8, .5, -.9, .5, -.5);
|
||||
cairo_curve_to (cr, .5, -.9, -.1, -.8, .1, -.4);
|
||||
cairo_close_path (cr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!do_path) {
|
||||
cairo_set_source_rgb (cr, 1., 0., 0.);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
}
|
||||
|
||||
PangoAttrList *
|
||||
create_fancy_attr_list_for_layout (PangoLayout *layout)
|
||||
{
|
||||
PangoAttrList *attrs;
|
||||
PangoFontMetrics *metrics;
|
||||
int ascent;
|
||||
PangoRectangle ink_rect, logical_rect;
|
||||
const char *p;
|
||||
|
||||
/* Get font metrics and prepare fancy shape size */
|
||||
metrics = pango_context_get_metrics (pango_layout_get_context (layout),
|
||||
pango_layout_get_font_description (layout),
|
||||
NULL);
|
||||
ascent = pango_font_metrics_get_ascent (metrics);
|
||||
logical_rect.x = 0;
|
||||
logical_rect.width = ascent;
|
||||
logical_rect.y = -ascent;
|
||||
logical_rect.height = ascent;
|
||||
ink_rect = logical_rect;
|
||||
pango_font_metrics_unref (metrics);
|
||||
|
||||
/* Set fancy shape attributes for all hearts */
|
||||
attrs = pango_attr_list_new ();
|
||||
for (p = text; (p = strstr (p, HEART)); p += strlen (HEART))
|
||||
{
|
||||
PangoAttribute *attr;
|
||||
|
||||
attr = pango_attr_shape_new_with_data (&ink_rect,
|
||||
&logical_rect,
|
||||
GUINT_TO_POINTER (g_utf8_get_char (p)),
|
||||
NULL, NULL);
|
||||
|
||||
attr->start_index = p - text;
|
||||
attr->end_index = attr->start_index + strlen (HEART);
|
||||
|
||||
pango_attr_list_insert (attrs, attr);
|
||||
}
|
||||
|
||||
return attrs;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
rotated_text_expose_event (GtkWidget *widget,
|
||||
GdkEventExpose *event,
|
||||
gpointer data)
|
||||
{
|
||||
#define RADIUS 150
|
||||
#define N_WORDS 10
|
||||
#define FONT "Sans Bold 27"
|
||||
#define N_WORDS 5
|
||||
#define FONT "Serif 18"
|
||||
|
||||
PangoRenderer *renderer;
|
||||
PangoMatrix matrix = PANGO_MATRIX_INIT;
|
||||
PangoContext *context;
|
||||
PangoLayout *layout;
|
||||
PangoFontDescription *desc;
|
||||
|
||||
cairo_t *cr;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
PangoAttrList *attrs;
|
||||
|
||||
int width = widget->allocation.width;
|
||||
int height = widget->allocation.height;
|
||||
double device_radius;
|
||||
int i;
|
||||
|
||||
/* Get the default renderer for the screen, and set it up for drawing */
|
||||
renderer = gdk_pango_renderer_get_default (gtk_widget_get_screen (widget));
|
||||
gdk_pango_renderer_set_drawable (GDK_PANGO_RENDERER (renderer), widget->window);
|
||||
gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (renderer), widget->style->black_gc);
|
||||
|
||||
/* Set up a transformation matrix so that the user space coordinates for
|
||||
* the centered square where we draw are [-RADIUS, RADIUS], [-RADIUS, RADIUS]
|
||||
* We first center, then change the scale */
|
||||
/* Create a cairo context and set up a transformation matrix so that the user
|
||||
* space coordinates for the centered square where we draw are [-RADIUS, RADIUS],
|
||||
* [-RADIUS, RADIUS].
|
||||
* We first center, then change the scale. */
|
||||
cr = gdk_cairo_create (widget->window);
|
||||
device_radius = MIN (width, height) / 2.;
|
||||
pango_matrix_translate (&matrix,
|
||||
cairo_translate (cr,
|
||||
device_radius + (width - 2 * device_radius) / 2,
|
||||
device_radius + (height - 2 * device_radius) / 2);
|
||||
pango_matrix_scale (&matrix, device_radius / RADIUS, device_radius / RADIUS);
|
||||
cairo_scale (cr, device_radius / RADIUS, device_radius / RADIUS);
|
||||
|
||||
/* Create a PangoLayout, set the font and text */
|
||||
/* Create and a subtle gradient source and use it. */
|
||||
pattern = cairo_pattern_create_linear (-RADIUS, -RADIUS, RADIUS, RADIUS);
|
||||
cairo_pattern_add_color_stop_rgb (pattern, 0., .5, .0, .0);
|
||||
cairo_pattern_add_color_stop_rgb (pattern, 1., .0, .0, .5);
|
||||
cairo_set_source (cr, pattern);
|
||||
|
||||
/* Create a PangoContext and set up our shape renderer */
|
||||
context = gtk_widget_create_pango_context (widget);
|
||||
pango_cairo_context_set_shape_renderer (context,
|
||||
fancy_shape_renderer,
|
||||
NULL, NULL);
|
||||
|
||||
/* Create a PangoLayout, set the text, font, and attributes */
|
||||
layout = pango_layout_new (context);
|
||||
pango_layout_set_text (layout, "Text", -1);
|
||||
pango_layout_set_text (layout, text, -1);
|
||||
desc = pango_font_description_from_string (FONT);
|
||||
pango_layout_set_font_description (layout, desc);
|
||||
pango_font_description_free (desc);
|
||||
|
||||
attrs = create_fancy_attr_list_for_layout (layout);
|
||||
pango_layout_set_attributes (layout, attrs);
|
||||
pango_attr_list_unref (attrs);
|
||||
|
||||
/* Draw the layout N_WORDS times in a circle */
|
||||
for (i = 0; i < N_WORDS; i++)
|
||||
{
|
||||
GdkColor color;
|
||||
PangoMatrix rotated_matrix = matrix;
|
||||
int width, height;
|
||||
double angle = (360. * i) / N_WORDS;
|
||||
|
||||
/* Gradient from red at angle == 60 to blue at angle == 300 */
|
||||
color.red = 65535 * (1 + cos ((angle - 60) * G_PI / 180.)) / 2;
|
||||
color.green = 0;
|
||||
color.blue = 65535 - color.red;
|
||||
|
||||
gdk_pango_renderer_set_override_color (GDK_PANGO_RENDERER (renderer),
|
||||
PANGO_RENDER_PART_FOREGROUND, &color);
|
||||
|
||||
pango_matrix_rotate (&rotated_matrix, angle);
|
||||
|
||||
pango_context_set_matrix (context, &rotated_matrix);
|
||||
|
||||
/* Inform Pango to re-layout the text with the new transformation matrix */
|
||||
pango_layout_context_changed (layout);
|
||||
pango_cairo_update_layout (cr, layout);
|
||||
|
||||
pango_layout_get_size (layout, &width, &height);
|
||||
pango_renderer_draw_layout (renderer, layout,
|
||||
- width / 2, - RADIUS * PANGO_SCALE);
|
||||
pango_layout_get_pixel_size (layout, &width, &height);
|
||||
cairo_move_to (cr, - width / 2, - RADIUS * .9);
|
||||
pango_cairo_show_layout (cr, layout);
|
||||
|
||||
/* Rotate for the next turn */
|
||||
cairo_rotate (cr, G_PI*2 / N_WORDS);
|
||||
}
|
||||
|
||||
/* Clean up default renderer, since it is shared */
|
||||
gdk_pango_renderer_set_override_color (GDK_PANGO_RENDERER (renderer),
|
||||
PANGO_RENDER_PART_FOREGROUND, NULL);
|
||||
gdk_pango_renderer_set_drawable (GDK_PANGO_RENDERER (renderer), NULL);
|
||||
gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (renderer), NULL);
|
||||
|
||||
/* free the objects we created */
|
||||
pango_font_description_free (desc);
|
||||
g_object_unref (layout);
|
||||
g_object_unref (context);
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_destroy (cr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@ -103,21 +175,30 @@ rotated_text_expose_event (GtkWidget *widget,
|
||||
GtkWidget *
|
||||
do_rotated_text (GtkWidget *do_widget)
|
||||
{
|
||||
GtkWidget *drawing_area;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *box;
|
||||
GtkWidget *drawing_area;
|
||||
GtkWidget *label;
|
||||
PangoLayout *layout;
|
||||
PangoAttrList *attrs;
|
||||
|
||||
const GdkColor white = { 0, 0xffff, 0xffff, 0xffff };
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_screen (GTK_WINDOW (window),
|
||||
gtk_widget_get_screen (do_widget));
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Rotated Text");
|
||||
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 4 * RADIUS, 2 * RADIUS);
|
||||
g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
box = gtk_hbox_new (TRUE, 0);
|
||||
gtk_container_add (GTK_CONTAINER (window), box);
|
||||
|
||||
/* Add a drawing area */
|
||||
|
||||
drawing_area = gtk_drawing_area_new ();
|
||||
gtk_container_add (GTK_CONTAINER (window), drawing_area);
|
||||
gtk_container_add (GTK_CONTAINER (box), drawing_area);
|
||||
|
||||
/* This overrides the background color from the theme */
|
||||
gtk_widget_modify_bg (drawing_area, GTK_STATE_NORMAL, &white);
|
||||
@ -125,7 +206,21 @@ do_rotated_text (GtkWidget *do_widget)
|
||||
g_signal_connect (drawing_area, "expose-event",
|
||||
G_CALLBACK (rotated_text_expose_event), NULL);
|
||||
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 2 * RADIUS, 2 * RADIUS);
|
||||
/* And a label */
|
||||
|
||||
label = gtk_label_new (text);
|
||||
gtk_container_add (GTK_CONTAINER (box), label);
|
||||
|
||||
gtk_label_set_angle (label, 45);
|
||||
|
||||
/* Set up fancy stuff on the label */
|
||||
layout = gtk_label_get_layout (label);
|
||||
pango_cairo_context_set_shape_renderer (pango_layout_get_context (layout),
|
||||
fancy_shape_renderer,
|
||||
NULL, NULL);
|
||||
attrs = create_fancy_attr_list_for_layout (layout);
|
||||
gtk_label_set_attributes (label, attrs);
|
||||
pango_attr_list_unref (attrs);
|
||||
}
|
||||
|
||||
if (!GTK_WIDGET_VISIBLE (window))
|
||||
|
@ -311,6 +311,52 @@ gdk_pango_renderer_draw_error_underline (PangoRenderer *renderer,
|
||||
(double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pango_renderer_draw_shape (PangoRenderer *renderer,
|
||||
PangoAttrShape *attr,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
|
||||
GdkPangoRendererPrivate *priv = gdk_renderer->priv;
|
||||
PangoLayout *layout;
|
||||
PangoCairoShapeRendererFunc shape_renderer;
|
||||
gpointer shape_renderer_data;
|
||||
cairo_t *cr;
|
||||
double dx = (double)x / PANGO_SCALE, dy = (double)y / PANGO_SCALE;
|
||||
|
||||
layout = pango_renderer_get_layout (renderer);
|
||||
|
||||
if (!layout)
|
||||
return;
|
||||
|
||||
shape_renderer = pango_cairo_context_get_shape_renderer (pango_layout_get_context (layout),
|
||||
&shape_renderer_data);
|
||||
|
||||
if (!shape_renderer)
|
||||
return;
|
||||
|
||||
cr = get_cairo_context (gdk_renderer, PANGO_RENDER_PART_FOREGROUND);
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
if (priv->embossed)
|
||||
{
|
||||
cairo_save (cr);
|
||||
emboss_context (gdk_renderer, cr);
|
||||
|
||||
cairo_move_to (cr, dx, dy);
|
||||
shape_renderer (cr, attr, FALSE, shape_renderer_data);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
cairo_move_to (cr, dx, dy);
|
||||
shape_renderer (cr, attr, FALSE, shape_renderer_data);
|
||||
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_pango_renderer_part_changed (PangoRenderer *renderer,
|
||||
PangoRenderPart part)
|
||||
@ -474,6 +520,7 @@ gdk_pango_renderer_class_init (GdkPangoRendererClass *klass)
|
||||
renderer_class->draw_glyphs = gdk_pango_renderer_draw_glyphs;
|
||||
renderer_class->draw_rectangle = gdk_pango_renderer_draw_rectangle;
|
||||
renderer_class->draw_error_underline = gdk_pango_renderer_draw_error_underline;
|
||||
renderer_class->draw_shape = gdk_pango_renderer_draw_shape;
|
||||
renderer_class->part_changed = gdk_pango_renderer_part_changed;
|
||||
renderer_class->begin = gdk_pango_renderer_begin;
|
||||
renderer_class->end = gdk_pango_renderer_end;
|
||||
|
Loading…
Reference in New Issue
Block a user