Blame demos/gtk-demo/rotated_text.c

Packit Service fb6fa5
/* Rotated Text
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * This demo shows how to use PangoCairo to draw rotated and transformed
Packit Service fb6fa5
 * text.  The right pane shows a rotated GtkLabel widget.
Packit Service fb6fa5
 *
Packit Service fb6fa5
 * In both cases, a custom PangoCairo shape renderer is installed to draw
Packit Service fb6fa5
 * a red heard using cairo drawing operations instead of the Unicode heart
Packit Service fb6fa5
 * character.
Packit Service fb6fa5
 */
Packit Service fb6fa5
Packit Service fb6fa5
#include <gtk/gtk.h>
Packit Service fb6fa5
#include <string.h>
Packit Service fb6fa5
Packit Service fb6fa5
static GtkWidget *window = NULL;
Packit Service fb6fa5
Packit Service fb6fa5
#define HEART "♥"
Packit Service fb6fa5
const char text[] = "I ♥ GTK+";
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
fancy_shape_renderer (cairo_t        *cr,
Packit Service fb6fa5
		      PangoAttrShape *attr,
Packit Service fb6fa5
		      gboolean        do_path,
Packit Service fb6fa5
		      gpointer        data)
Packit Service fb6fa5
{
Packit Service fb6fa5
  double x, y;
Packit Service fb6fa5
  cairo_get_current_point (cr, &x, &y);
Packit Service fb6fa5
  cairo_translate (cr, x, y);
Packit Service fb6fa5
Packit Service fb6fa5
  cairo_scale (cr,
Packit Service fb6fa5
	       (double) attr->ink_rect.width  / PANGO_SCALE,
Packit Service fb6fa5
	       (double) attr->ink_rect.height / PANGO_SCALE);
Packit Service fb6fa5
Packit Service fb6fa5
  switch (GPOINTER_TO_UINT (attr->data))
Packit Service fb6fa5
    {
Packit Service fb6fa5
    case 0x2665: /* U+2665 BLACK HEART SUIT */
Packit Service fb6fa5
      {
Packit Service fb6fa5
        cairo_move_to (cr, .5, .0);
Packit Service fb6fa5
        cairo_line_to (cr, .9, -.4);
Packit Service fb6fa5
	cairo_curve_to (cr, 1.1, -.8, .5, -.9, .5, -.5);
Packit Service fb6fa5
	cairo_curve_to (cr, .5, -.9, -.1, -.8, .1, -.4);
Packit Service fb6fa5
	cairo_close_path (cr);
Packit Service fb6fa5
      }
Packit Service fb6fa5
      break;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (!do_path) {
Packit Service fb6fa5
    cairo_set_source_rgb (cr, 1., 0., 0.);
Packit Service fb6fa5
    cairo_fill (cr);
Packit Service fb6fa5
  }
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
PangoAttrList *
Packit Service fb6fa5
create_fancy_attr_list_for_layout (PangoLayout *layout)
Packit Service fb6fa5
{
Packit Service fb6fa5
  PangoAttrList *attrs;
Packit Service fb6fa5
  PangoFontMetrics *metrics;
Packit Service fb6fa5
  int ascent;
Packit Service fb6fa5
  PangoRectangle ink_rect, logical_rect;
Packit Service fb6fa5
  const char *p;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Get font metrics and prepare fancy shape size */
Packit Service fb6fa5
  metrics = pango_context_get_metrics (pango_layout_get_context (layout),
Packit Service fb6fa5
				       pango_layout_get_font_description (layout),
Packit Service fb6fa5
				       NULL);
Packit Service fb6fa5
  ascent = pango_font_metrics_get_ascent (metrics);
Packit Service fb6fa5
  logical_rect.x = 0;
Packit Service fb6fa5
  logical_rect.width = ascent;
Packit Service fb6fa5
  logical_rect.y = -ascent;
Packit Service fb6fa5
  logical_rect.height = ascent;
Packit Service fb6fa5
  ink_rect = logical_rect;
Packit Service fb6fa5
  pango_font_metrics_unref (metrics);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Set fancy shape attributes for all hearts */
Packit Service fb6fa5
  attrs = pango_attr_list_new ();
Packit Service fb6fa5
  for (p = text; (p = strstr (p, HEART)); p += strlen (HEART))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      PangoAttribute *attr;
Packit Service fb6fa5
      
Packit Service fb6fa5
      attr = pango_attr_shape_new_with_data (&ink_rect,
Packit Service fb6fa5
					     &logical_rect,
Packit Service fb6fa5
					     GUINT_TO_POINTER (g_utf8_get_char (p)),
Packit Service fb6fa5
					     NULL, NULL);
Packit Service fb6fa5
Packit Service fb6fa5
      attr->start_index = p - text;
Packit Service fb6fa5
      attr->end_index = attr->start_index + strlen (HEART);
Packit Service fb6fa5
Packit Service fb6fa5
      pango_attr_list_insert (attrs, attr);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return attrs;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static gboolean
Packit Service fb6fa5
rotated_text_expose_event (GtkWidget      *widget,
Packit Service fb6fa5
			   GdkEventExpose *event,
Packit Service fb6fa5
			   gpointer	   data)
Packit Service fb6fa5
{
Packit Service fb6fa5
#define RADIUS 150
Packit Service fb6fa5
#define N_WORDS 5
Packit Service fb6fa5
#define FONT "Serif 18"
Packit Service fb6fa5
Packit Service fb6fa5
  PangoContext *context;
Packit Service fb6fa5
  PangoLayout *layout;
Packit Service fb6fa5
  PangoFontDescription *desc;
Packit Service fb6fa5
Packit Service fb6fa5
  cairo_t *cr;
Packit Service fb6fa5
  cairo_pattern_t *pattern;
Packit Service fb6fa5
Packit Service fb6fa5
  PangoAttrList *attrs;
Packit Service fb6fa5
  GtkAllocation allocation;
Packit Service fb6fa5
  int width, height;
Packit Service fb6fa5
  double device_radius;
Packit Service fb6fa5
  int i;
Packit Service fb6fa5
  
Packit Service fb6fa5
  gtk_widget_get_allocation (widget, &allocation);
Packit Service fb6fa5
Packit Service fb6fa5
  width = allocation.width;
Packit Service fb6fa5
  height = allocation.height;
Packit Service fb6fa5
Packit Service fb6fa5
  /* Create a cairo context and set up a transformation matrix so that the user
Packit Service fb6fa5
   * space coordinates for the centered square where we draw are [-RADIUS, RADIUS],
Packit Service fb6fa5
   * [-RADIUS, RADIUS].
Packit Service fb6fa5
   * We first center, then change the scale. */
Packit Service fb6fa5
  cr = gdk_cairo_create (gtk_widget_get_window (widget));
Packit Service fb6fa5
  device_radius = MIN (width, height) / 2.;
Packit Service fb6fa5
  cairo_translate (cr,
Packit Service fb6fa5
		   device_radius + (width - 2 * device_radius) / 2,
Packit Service fb6fa5
		   device_radius + (height - 2 * device_radius) / 2);
Packit Service fb6fa5
  cairo_scale (cr, device_radius / RADIUS, device_radius / RADIUS);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Create and a subtle gradient source and use it. */
Packit Service fb6fa5
  pattern = cairo_pattern_create_linear (-RADIUS, -RADIUS, RADIUS, RADIUS);
Packit Service fb6fa5
  cairo_pattern_add_color_stop_rgb (pattern, 0., .5, .0, .0);
Packit Service fb6fa5
  cairo_pattern_add_color_stop_rgb (pattern, 1., .0, .0, .5);
Packit Service fb6fa5
  cairo_set_source (cr, pattern);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Create a PangoContext and set up our shape renderer */
Packit Service fb6fa5
  context = gtk_widget_create_pango_context (widget);
Packit Service fb6fa5
  pango_cairo_context_set_shape_renderer (context,
Packit Service fb6fa5
					  fancy_shape_renderer,
Packit Service fb6fa5
					  NULL, NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Create a PangoLayout, set the text, font, and attributes */
Packit Service fb6fa5
  layout = pango_layout_new (context);
Packit Service fb6fa5
  pango_layout_set_text (layout, text, -1);
Packit Service fb6fa5
  desc = pango_font_description_from_string (FONT);
Packit Service fb6fa5
  pango_layout_set_font_description (layout, desc);
Packit Service fb6fa5
Packit Service fb6fa5
  attrs = create_fancy_attr_list_for_layout (layout);
Packit Service fb6fa5
  pango_layout_set_attributes (layout, attrs);
Packit Service fb6fa5
  pango_attr_list_unref (attrs);
Packit Service fb6fa5
Packit Service fb6fa5
  /* Draw the layout N_WORDS times in a circle */
Packit Service fb6fa5
  for (i = 0; i < N_WORDS; i++)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      int width, height;
Packit Service fb6fa5
Packit Service fb6fa5
      /* Inform Pango to re-layout the text with the new transformation matrix */
Packit Service fb6fa5
      pango_cairo_update_layout (cr, layout);
Packit Service fb6fa5
    
Packit Service fb6fa5
      pango_layout_get_pixel_size (layout, &width, &height);
Packit Service fb6fa5
      cairo_move_to (cr, - width / 2, - RADIUS * .9);
Packit Service fb6fa5
      pango_cairo_show_layout (cr, layout);
Packit Service fb6fa5
Packit Service fb6fa5
      /* Rotate for the next turn */
Packit Service fb6fa5
      cairo_rotate (cr, G_PI*2 / N_WORDS);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  /* free the objects we created */
Packit Service fb6fa5
  pango_font_description_free (desc);
Packit Service fb6fa5
  g_object_unref (layout);
Packit Service fb6fa5
  g_object_unref (context);
Packit Service fb6fa5
  cairo_pattern_destroy (pattern);
Packit Service fb6fa5
  cairo_destroy (cr);
Packit Service fb6fa5
  
Packit Service fb6fa5
  return FALSE;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
GtkWidget *
Packit Service fb6fa5
do_rotated_text (GtkWidget *do_widget)
Packit Service fb6fa5
{
Packit Service fb6fa5
  if (!window)
Packit Service fb6fa5
    {
Packit Service fb6fa5
      GtkWidget *box;
Packit Service fb6fa5
      GtkWidget *drawing_area;
Packit Service fb6fa5
      GtkWidget *label;
Packit Service fb6fa5
      PangoLayout *layout;
Packit Service fb6fa5
      PangoAttrList *attrs;
Packit Service fb6fa5
Packit Service fb6fa5
      const GdkColor white = { 0, 0xffff, 0xffff, 0xffff };
Packit Service fb6fa5
      
Packit Service fb6fa5
      window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
Packit Service fb6fa5
      gtk_window_set_screen (GTK_WINDOW (window),
Packit Service fb6fa5
			     gtk_widget_get_screen (do_widget));
Packit Service fb6fa5
      gtk_window_set_title (GTK_WINDOW (window), "Rotated Text");
Packit Service fb6fa5
      gtk_window_set_default_size (GTK_WINDOW (window), 4 * RADIUS, 2 * RADIUS);
Packit Service fb6fa5
      g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
Packit Service fb6fa5
Packit Service fb6fa5
      box = gtk_hbox_new (TRUE, 0);
Packit Service fb6fa5
      gtk_container_add (GTK_CONTAINER (window), box);
Packit Service fb6fa5
Packit Service fb6fa5
      /* Add a drawing area */
Packit Service fb6fa5
Packit Service fb6fa5
      drawing_area = gtk_drawing_area_new ();
Packit Service fb6fa5
      gtk_container_add (GTK_CONTAINER (box), drawing_area);
Packit Service fb6fa5
Packit Service fb6fa5
      /* This overrides the background color from the theme */
Packit Service fb6fa5
      gtk_widget_modify_bg (drawing_area, GTK_STATE_NORMAL, &white);
Packit Service fb6fa5
Packit Service fb6fa5
      g_signal_connect (drawing_area, "expose-event",
Packit Service fb6fa5
			G_CALLBACK (rotated_text_expose_event), NULL);
Packit Service fb6fa5
Packit Service fb6fa5
      /* And a label */
Packit Service fb6fa5
Packit Service fb6fa5
      label = gtk_label_new (text);
Packit Service fb6fa5
      gtk_container_add (GTK_CONTAINER (box), label);
Packit Service fb6fa5
Packit Service fb6fa5
      gtk_label_set_angle (GTK_LABEL (label), 45);
Packit Service fb6fa5
Packit Service fb6fa5
      /* Set up fancy stuff on the label */
Packit Service fb6fa5
      layout = gtk_label_get_layout (GTK_LABEL (label));
Packit Service fb6fa5
      pango_cairo_context_set_shape_renderer (pango_layout_get_context (layout),
Packit Service fb6fa5
					      fancy_shape_renderer,
Packit Service fb6fa5
					      NULL, NULL);
Packit Service fb6fa5
      attrs = create_fancy_attr_list_for_layout (layout);
Packit Service fb6fa5
      gtk_label_set_attributes (GTK_LABEL (label), attrs);
Packit Service fb6fa5
      pango_attr_list_unref (attrs);
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  if (!gtk_widget_get_visible (window))
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gtk_widget_show_all (window);
Packit Service fb6fa5
    }
Packit Service fb6fa5
  else
Packit Service fb6fa5
    {
Packit Service fb6fa5
      gtk_widget_destroy (window);
Packit Service fb6fa5
      window = NULL;
Packit Service fb6fa5
    }
Packit Service fb6fa5
Packit Service fb6fa5
  return window;
Packit Service fb6fa5
}