A number of times, people have been asking for support for rotated text in
dia.  The usual response was that X didn't support rotated text, which
would make it difficult to edit a diagram with rotated text.

It turns out that since X11R6, X has had support for rotated text
on the server side through the XLFD matrix extension (this was pointed out
on the list).  I don't know how widely supported this extension is
however, so don't know whether it would be good to use in dia.

For this reason, I wrote a attached test program that demonstrates the
extension.  I would like to hear if anyone has difficulties running it on
their system.  It should display a small window with the string "Hello
World" printed at 4 different angles and sizes.  It can be compiled with
the following command:
  cc -o rotfont rotfont.c `gtk-config --cflags --libs`

On my system it takes a little while to draw the text the first time, and
after that it draws at an acceptable speed (I can't tell the difference
between the rotated rendering and normal rendering speeds).  This is
partly because the font has to be rendered in rotated form the first time,
and my code doesn't unref the GdkFont at the moment (hey its just a test
program :), so character metrics only need be transmitted once.  This
indicates that if we are going to add support for this to dia, some form
of caching will be required.

If anyone has problems with it not rendering correctly, or not rendering
with acceptable performance, let me know.

The only other problem I can see is for non X platforms (such as the win32
port).  Win32 has its own form of doing rotated text, but it is probably
not available through the GTK port.

James.

--
Email: [EMAIL PROTECTED]
WWW:   http://www.daa.com.au/~james/

#include <math.h>
#include <string.h>

#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <X11/Xlib.h>

/* for test program */
#include <gtk/gtk.h>

/* a test of server side rotated text */

#define IROUND(x) (int)((x) > 0 ? (x) + .5 : (x) - .5)

void
gdk_draw_rotated_text(GdkDrawable *drawable,
                      const gchar *xlfdtemplate, guint points,
                      GdkGC *gc,
                      gint x,
                      gint y,
                      gdouble angle, /* in radians */
                      const gchar *text,
                      guint text_length)
{
  gdouble matrix[4];
  gchar *smatrix, *xlfd;
  GdkFont *font;
  XFontStruct *fontinfo;
  gdouble offset;
  guint i;

  g_return_if_fail(drawable != NULL);
  g_return_if_fail(xlfdtemplate != NULL);
  g_return_if_fail(gc != NULL);
  g_return_if_fail(text != NULL);

  /* build up rotated font XLFD */
  matrix[0] = matrix[3] = points * cos(angle);
  matrix[1] = points * sin(angle);
  matrix[2] = -matrix[1];

  smatrix = g_strdup_printf("[%g %g %g %g]", matrix[0], matrix[1],
                            matrix[2], matrix[3]);
  for (i = 0; smatrix[i] != '\0'; i++)
    if (smatrix[i] == '-')
      smatrix[i] = '~';
  xlfd = g_strdup_printf(xlfdtemplate, smatrix);
  g_free(smatrix);
  font = gdk_font_load(xlfd);
  g_free(xlfd);

  g_return_if_fail(font != NULL);

  fontinfo = GDK_FONT_XFONT(font);

  /* draw rotated text */
  offset = 0.0;
  for (i = 0; i < text_length; i++) {
    int charno = (unsigned char)text[i];
    int char_metric_offset = charno - fontinfo->min_char_or_byte2;

    gdk_draw_text(drawable, font, gc,
                  IROUND((double)x + offset * matrix[0] / 1000.0),
                  IROUND((double)y - offset * matrix[1] / 1000.0),
                  &text[i], 1);

    offset += (double)(fontinfo->per_char ?
                       fontinfo->per_char[char_metric_offset].attributes :
                       fontinfo->min_bounds.attributes);
  }
}

void
gdk_draw_rotated_string(GdkDrawable *drawable,
                        const gchar *xlfdtemplate, guint points,
                        GdkGC *gc,
                        gint x,
                        gint y,
                        gdouble angle, /* in radians */
                        const gchar *string)
{
  gdk_draw_rotated_text(drawable, xlfdtemplate, points, gc, x, y, angle,
                        string, strlen(string));
}

static gint
expose_event(GtkWidget *drawing_area, GdkEventExpose *event)
{
  GdkDrawable *drw = drawing_area->window;

  if (!drw)
    return;

  gdk_window_clear(drw);
  gdk_draw_rotated_text(drw,
                "-*-times-medium-r-normal-*-%s-*-*-*-p-*-iso8859-1", 48,
                drawing_area->style->text_gc[GTK_WIDGET_STATE(drawing_area)],
                50, 40, 0, "Hello World", 11);
  gdk_draw_rotated_text(drw,
                "-*-times-medium-r-normal-*-%s-*-*-*-p-*-iso8859-1", 36,
                drawing_area->style->text_gc[GTK_WIDGET_STATE(drawing_area)],
                36, 65, -M_PI/6.0, "Hello World", 11);
  gdk_draw_rotated_text(drw,
                "-*-times-medium-r-normal-*-%s-*-*-*-p-*-iso8859-1", 24,
                drawing_area->style->text_gc[GTK_WIDGET_STATE(drawing_area)],
                20, 73, -M_PI/3.0, "Hello World", 11);
  gdk_draw_rotated_text(drw,
                "-*-times-medium-r-normal-*-%s-*-*-*-p-*-iso8859-1", 18,
                drawing_area->style->text_gc[GTK_WIDGET_STATE(drawing_area)],
                5, 75, -M_PI/2.0, "Hello World", 11);
}

gint
main(int argc, char **argv)
{
  GtkWidget *window;
  GtkWidget *da;

  gtk_init(&argc, &argv);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_signal_connect(GTK_OBJECT(window), "destroy",
                     GTK_SIGNAL_FUNC(gtk_main_quit), NULL);

  da = gtk_drawing_area_new();
  gtk_drawing_area_size(GTK_DRAWING_AREA(da), 300, 200);
  gtk_signal_connect(GTK_OBJECT(da), "expose_event",
                     GTK_SIGNAL_FUNC(expose_event), NULL);

  gtk_container_add(GTK_CONTAINER(window), da);
  gtk_widget_show_all(window);

  gtk_main();

  return 0;
}

Reply via email to