// Rotated text drawing with X. // Original code: // Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma) */ // // Modifications for fltk: // Copyright (c) 1997 Bill Spitzak (spitzak@d2.com) // Modifications are to draw using the current fl_font. All fonts // used are cached in local structures. This can get real expensive, // use " /* xvertext, Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma) * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both the * copyright notice and this permission notice appear in supporting * documentation. All work developed as a consequence of the use of * this program should duly acknowledge such use. No representations are * made about the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty. */ #ifndef WIN32 // if not defined then portions not used by flwm are included: //#define FLWM 1 /* ********************************************************************** */ #include #include #include "Rotated.H" #include #include #include struct BitmapStruct { int bit_w; int bit_h; Pixmap bm; }; struct XRotCharStruct { int ascent; int descent; int lbearing; int rbearing; int width; BitmapStruct glyph; }; struct XRotFontStruct { int dir; int height; int max_ascent; int max_descent; int max_char; int min_char; XFontStruct* xfontstruct; XRotCharStruct per_char[256]; }; /* *** Load the rotated version of a given font *** */ static XRotFontStruct* XRotLoadFont(Display *dpy, XFontStruct* fontstruct, int dir) { char val; XImage *I1, *I2; Pixmap canvas; Window root; int screen; GC font_gc; char text[3];/*, errstr[300];*/ XRotFontStruct *rotfont; int ichar, i, j, index, boxlen = 60; int vert_w, vert_h, vert_len, bit_w, bit_h, bit_len; int min_char, max_char; unsigned char *vertdata, *bitdata; int ascent, descent, lbearing, rbearing; int on = 1, off = 0; /* useful macros ... */ screen = DefaultScreen(dpy); root = DefaultRootWindow(dpy); /* create the depth 1 canvas bitmap ... */ canvas = XCreatePixmap(dpy, root, boxlen, boxlen, 1); /* create a GC ... */ font_gc = XCreateGC(dpy, canvas, 0, 0); XSetBackground(dpy, font_gc, off); XSetFont(dpy, font_gc, fontstruct->fid); /* allocate space for rotated font ... */ rotfont = (XRotFontStruct *)malloc((unsigned)sizeof(XRotFontStruct)); /* determine which characters are defined in font ... */ min_char = fontstruct->min_char_or_byte2; if (min_char<0) min_char = 0; rotfont->min_char = min_char; max_char = fontstruct->max_char_or_byte2; if (max_char>255) max_char = 255; rotfont->max_char = max_char; /* some overall font data ... */ rotfont->dir = dir; rotfont->max_ascent = fontstruct->max_bounds.ascent; rotfont->max_descent = fontstruct->max_bounds.descent; rotfont->height = rotfont->max_ascent+rotfont->max_descent; rotfont->xfontstruct = fontstruct; /* remember xfontstruct for `normal' text ... */ if (dir != 0) { /* font needs rotation ... */ /* loop through each character ... */ for (ichar = min_char; ichar <= max_char; ichar++) { index = ichar-fontstruct->min_char_or_byte2; /* per char dimensions ... */ ascent = rotfont->per_char[ichar].ascent = fontstruct->per_char[index].ascent; descent = rotfont->per_char[ichar].descent = fontstruct->per_char[index].descent; lbearing = rotfont->per_char[ichar].lbearing = fontstruct->per_char[index].lbearing; rbearing = rotfont->per_char[ichar].rbearing = fontstruct->per_char[index].rbearing; rotfont->per_char[ichar].width = fontstruct->per_char[index].width; /* some space chars have zero body, but a bitmap can't have ... */ if (!ascent && !descent) ascent = rotfont->per_char[ichar].ascent = 1; if (!lbearing && !rbearing) rbearing = rotfont->per_char[ichar].rbearing = 1; /* glyph width and height when vertical ... */ vert_w = rbearing-lbearing; vert_h = ascent+descent; /* width in bytes ... */ vert_len = (vert_w-1)/8+1; XSetForeground(dpy, font_gc, off); XFillRectangle(dpy, canvas, font_gc, 0, 0, boxlen, boxlen); /* draw the character centre top right on canvas ... */ sprintf(text, "%c", ichar); XSetForeground(dpy, font_gc, on); XDrawImageString(dpy, canvas, font_gc, boxlen/2 - lbearing, boxlen/2 - descent, text, 1); /* reserve memory for first XImage ... */ vertdata = (unsigned char *) malloc((unsigned)(vert_len*vert_h)); /* create the XImage ... */ I1 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0, (char *)vertdata, vert_w, vert_h, 8, 0); // if (I1 == NULL) ... do something here I1->byte_order = I1->bitmap_bit_order = MSBFirst; /* extract character from canvas ... */ XGetSubImage(dpy, canvas, boxlen/2, boxlen/2-vert_h, vert_w, vert_h, 1, XYPixmap, I1, 0, 0); I1->format = XYBitmap; /* width, height of rotated character ... */ if (dir == 2) { bit_w = vert_w; bit_h = vert_h; } else { bit_w = vert_h; bit_h = vert_w; } /* width in bytes ... */ bit_len = (bit_w-1)/8 + 1; rotfont->per_char[ichar].glyph.bit_w = bit_w; rotfont->per_char[ichar].glyph.bit_h = bit_h; /* reserve memory for the rotated image ... */ bitdata = (unsigned char *)calloc((unsigned)(bit_h*bit_len), 1); /* create the image ... */ I2 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0, (char *)bitdata, bit_w, bit_h, 8, 0); // if (I2 == NULL) ... error I2->byte_order = I2->bitmap_bit_order = MSBFirst; /* map vertical data to rotated character ... */ for (j = 0; j < bit_h; j++) { for (i = 0; i < bit_w; i++) { /* map bits ... */ if (dir == 1) val = vertdata[i*vert_len + (vert_w-j-1)/8] & (128>>((vert_w-j-1)%8)); else if (dir == 2) val = vertdata[(vert_h-j-1)*vert_len + (vert_w-i-1)/8] & (128>>((vert_w-i-1)%8)); else val = vertdata[(vert_h-i-1)*vert_len + j/8] & (128>>(j%8)); if (val) bitdata[j*bit_len + i/8] = bitdata[j*bit_len + i/8] | (128>>(i%8)); } } /* create this character's bitmap ... */ rotfont->per_char[ichar].glyph.bm = XCreatePixmap(dpy, root, bit_w, bit_h, 1); /* put the image into the bitmap ... */ XPutImage(dpy, rotfont->per_char[ichar].glyph.bm, font_gc, I2, 0, 0, 0, 0, bit_w, bit_h); /* free the image and data ... */ XDestroyImage(I1); XDestroyImage(I2); /* free((char *)bitdata); -- XDestroyImage does this free((char *)vertdata);*/ } } for (ichar = 0; ichar < min_char; ichar++) rotfont->per_char[ichar] = rotfont->per_char['?']; for (ichar = max_char+1; ichar < 256; ichar++) rotfont->per_char[ichar] = rotfont->per_char['?']; /* free pixmap and GC ... */ XFreePixmap(dpy, canvas); XFreeGC(dpy, font_gc); return rotfont; } /* *** Free the resources associated with a rotated font *** */ static void XRotUnloadFont(Display *dpy, XRotFontStruct *rotfont) { int ichar; if (rotfont->dir != 0) { /* loop through each character, freeing its pixmap ... */ for (ichar = rotfont->min_char; ichar <= rotfont->max_char; ichar++) XFreePixmap(dpy, rotfont->per_char[ichar].glyph.bm); } /* rotfont should never be referenced again ... */ free((char *)rotfont); } /* ---------------------------------------------------------------------- */ /* *** A front end to XRotPaintString : mimics XDrawString *** */ static void XRotDrawString(Display *dpy, XRotFontStruct *rotfont, Drawable drawable, GC gc, int x, int y, const char *str, int len) { int i, xp, yp, dir, ichar; if (str == NULL || len<1) return; dir = rotfont->dir; /* a horizontal string is easy ... */ if (dir == 0) { XSetFont(dpy, gc, rotfont->xfontstruct->fid); XDrawString(dpy, drawable, gc, x, y, str, len); return; } /* vertical or upside down ... */ XSetFillStyle(dpy, gc, FillStippled); /* loop through each character in string ... */ for (i = 0; iper_char[ichar].ascent; yp = y-rotfont->per_char[ichar].rbearing; } else if (dir == 2) { xp = x-rotfont->per_char[ichar].rbearing; yp = y-rotfont->per_char[ichar].descent+1; } else { xp = x-rotfont->per_char[ichar].descent+1; yp = y+rotfont->per_char[ichar].lbearing; } /* draw the glyph ... */ XSetStipple(dpy, gc, rotfont->per_char[ichar].glyph.bm); XSetTSOrigin(dpy, gc, xp, yp); XFillRectangle(dpy, drawable, gc, xp, yp, rotfont->per_char[ichar].glyph.bit_w, rotfont->per_char[ichar].glyph.bit_h); /* advance position ... */ if (dir == 1) y -= rotfont->per_char[ichar].width; else if (dir == 2) x -= rotfont->per_char[ichar].width; else y += rotfont->per_char[ichar].width; } XSetFillStyle(dpy, gc, FillSolid); } #if 0 #ifndef FLWM /* *** Return the width of a string *** */ static int XRotTextWidth(XRotFontStruct *rotfont, const char *str, int len) { int i, width = 0, ichar; if (str == NULL) return 0; if (rotfont->dir == 0) width = XTextWidth(rotfont->xfontstruct, str, strlen(str)); else for (i = 0; iper_char[((unsigned char*)str)[i]].width; } return width; } #endif #endif /* ---------------------------------------------------------------------- */ // the public functions use the fltk global variables for font & gc: static XRotFontStruct* font; void draw_rotated(const char* text, int n, int x, int y, int angle) { if (!text || !*text) return; /* make angle positive ... */ if (angle < 0) do angle += 360; while (angle < 0); /* get nearest vertical or horizontal direction ... */ int dir = ((angle+45)/90)%4; if (font && font->xfontstruct == fl_xfont && font->dir == dir) { ; } else { if (font) XRotUnloadFont(fl_display, font); font = XRotLoadFont(fl_display, fl_xfont, dir); } XRotDrawString(fl_display, font, fl_window, fl_gc, x, y, text, n); } #ifndef FLWM void draw_rotated(const char* text, int x, int y, int angle) { if (!text || !*text) return; draw_rotated(text, strlen(text), x, y, angle); } #endif static void draw_rot90(const char* str, int n, int x, int y) { draw_rotated(str, n, y, -x, 90); } void draw_rotated90( const char* str, // the (multi-line) string int x, int y, int w, int h, // bounding box Fl_Align align) { if (!str || !*str) return; if (w && h && !fl_not_clipped(x, y, w, h)) return; if (align & FL_ALIGN_CLIP) fl_clip(x, y, w, h); int a1 = align&(-16); if (align & FL_ALIGN_LEFT) a1 |= FL_ALIGN_TOP; if (align & FL_ALIGN_RIGHT) a1 |= FL_ALIGN_BOTTOM; if (align & FL_ALIGN_TOP) a1 |= FL_ALIGN_RIGHT; if (align & FL_ALIGN_BOTTOM) a1 |= FL_ALIGN_LEFT; fl_draw(str, -(y+h), x, h, w, (Fl_Align)a1, draw_rot90); if (align & FL_ALIGN_CLIP) fl_pop_clip(); } #ifndef FLWM static void draw_rot180(const char* str, int n, int x, int y) { draw_rotated(str, n, -x, -y, 180); } void draw_rotated180( const char* str, // the (multi-line) string int x, int y, int w, int h, // bounding box Fl_Align align) { int a1 = align&(-16); if (align & FL_ALIGN_LEFT) a1 |= FL_ALIGN_RIGHT; if (align & FL_ALIGN_RIGHT) a1 |= FL_ALIGN_LEFT; if (align & FL_ALIGN_TOP) a1 |= FL_ALIGN_BOTTOM; if (align & FL_ALIGN_BOTTOM) a1 |= FL_ALIGN_TOP; fl_draw(str, -(x+w), -(y+h), w, h, (Fl_Align)a1, draw_rot180); } static void draw_rot270(const char* str, int n, int x, int y) { draw_rotated(str, n, -y, x, 270); } void draw_rotated270( const char* str, // the (multi-line) string int x, int y, int w, int h, // bounding box Fl_Align align) { int a1 = align&(-16); if (align & FL_ALIGN_LEFT) a1 |= FL_ALIGN_BOTTOM; if (align & FL_ALIGN_RIGHT) a1 |= FL_ALIGN_TOP; if (align & FL_ALIGN_TOP) a1 |= FL_ALIGN_LEFT; if (align & FL_ALIGN_BOTTOM) a1 |= FL_ALIGN_RIGHT; fl_draw(str, y, -(x+w), h, w, (Fl_Align)a1, draw_rot270); } #endif #endif /* _linux */