1 // Rotated text drawing with X.
4 // Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma) */
6 // Modifications for fltk:
7 // Copyright (c) 1997 Bill Spitzak (spitzak@d2.com)
8 // Modifications are to draw using the current fl_font. All fonts
9 // used are cached in local structures. This can get real expensive,
12 /* xvertext, Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma)
14 * Permission to use, copy, modify, and distribute this software and its
15 * documentation for any purpose and without fee is hereby granted, provided
16 * that the above copyright notice appear in all copies and that both the
17 * copyright notice and this permission notice appear in supporting
18 * documentation. All work developed as a consequence of the use of
19 * this program should duly acknowledge such use. No representations are
20 * made about the suitability of this software for any purpose. It is
21 * provided "as is" without express or implied warranty.
24 // if not defined then portions not used by flwm are included:
27 /* ********************************************************************** */
30 #include <FL/fl_draw.H>
42 struct XRotCharStruct
{
51 struct XRotFontStruct
{
58 XFontStruct
* xfontstruct
;
59 XRotCharStruct per_char
[256];
62 /* *** Load the rotated version of a given font *** */
64 static XRotFontStruct
*
65 XRotLoadFont(Display
*dpy
, XFontStruct
* fontstruct
, int dir
)
73 char text
[3];/*, errstr[300];*/
75 XRotFontStruct
*rotfont
;
76 int ichar
, i
, j
, index
, boxlen
= 60;
77 int vert_w
, vert_h
, vert_len
, bit_w
, bit_h
, bit_len
;
78 int min_char
, max_char
;
79 unsigned char *vertdata
, *bitdata
;
80 int ascent
, descent
, lbearing
, rbearing
;
83 /* useful macros ... */
84 screen
= DefaultScreen(dpy
);
85 root
= DefaultRootWindow(dpy
);
87 /* create the depth 1 canvas bitmap ... */
88 canvas
= XCreatePixmap(dpy
, root
, boxlen
, boxlen
, 1);
91 font_gc
= XCreateGC(dpy
, canvas
, 0, 0);
92 XSetBackground(dpy
, font_gc
, off
);
94 XSetFont(dpy
, font_gc
, fontstruct
->fid
);
96 /* allocate space for rotated font ... */
97 rotfont
= (XRotFontStruct
*)malloc((unsigned)sizeof(XRotFontStruct
));
99 /* determine which characters are defined in font ... */
100 min_char
= fontstruct
->min_char_or_byte2
;
101 if (min_char
<0) min_char
= 0;
102 rotfont
->min_char
= min_char
;
103 max_char
= fontstruct
->max_char_or_byte2
;
104 if (max_char
>255) max_char
= 255;
105 rotfont
->max_char
= max_char
;
107 /* some overall font data ... */
109 rotfont
->max_ascent
= fontstruct
->max_bounds
.ascent
;
110 rotfont
->max_descent
= fontstruct
->max_bounds
.descent
;
111 rotfont
->height
= rotfont
->max_ascent
+rotfont
->max_descent
;
113 rotfont
->xfontstruct
= fontstruct
;
114 /* remember xfontstruct for `normal' text ... */
116 /* font needs rotation ... */
117 /* loop through each character ... */
118 for (ichar
= min_char
; ichar
<= max_char
; ichar
++) {
120 index
= ichar
-fontstruct
->min_char_or_byte2
;
122 /* per char dimensions ... */
123 ascent
= rotfont
->per_char
[ichar
].ascent
=
124 fontstruct
->per_char
[index
].ascent
;
125 descent
= rotfont
->per_char
[ichar
].descent
=
126 fontstruct
->per_char
[index
].descent
;
127 lbearing
= rotfont
->per_char
[ichar
].lbearing
=
128 fontstruct
->per_char
[index
].lbearing
;
129 rbearing
= rotfont
->per_char
[ichar
].rbearing
=
130 fontstruct
->per_char
[index
].rbearing
;
131 rotfont
->per_char
[ichar
].width
=
132 fontstruct
->per_char
[index
].width
;
134 /* some space chars have zero body, but a bitmap can't have ... */
135 if (!ascent
&& !descent
)
136 ascent
= rotfont
->per_char
[ichar
].ascent
= 1;
137 if (!lbearing
&& !rbearing
)
138 rbearing
= rotfont
->per_char
[ichar
].rbearing
= 1;
140 /* glyph width and height when vertical ... */
141 vert_w
= rbearing
-lbearing
;
142 vert_h
= ascent
+descent
;
144 /* width in bytes ... */
145 vert_len
= (vert_w
-1)/8+1;
147 XSetForeground(dpy
, font_gc
, off
);
148 XFillRectangle(dpy
, canvas
, font_gc
, 0, 0, boxlen
, boxlen
);
150 /* draw the character centre top right on canvas ... */
151 sprintf(text
, "%c", ichar
);
152 XSetForeground(dpy
, font_gc
, on
);
153 XDrawImageString(dpy
, canvas
, font_gc
, boxlen
/2 - lbearing
,
154 boxlen
/2 - descent
, text
, 1);
156 /* reserve memory for first XImage ... */
157 vertdata
= (unsigned char *) malloc((unsigned)(vert_len
*vert_h
));
159 /* create the XImage ... */
160 I1
= XCreateImage(dpy
, DefaultVisual(dpy
, screen
), 1, XYBitmap
,
161 0, (char *)vertdata
, vert_w
, vert_h
, 8, 0);
163 // if (I1 == NULL) ... do something here
165 I1
->byte_order
= I1
->bitmap_bit_order
= MSBFirst
;
167 /* extract character from canvas ... */
168 XGetSubImage(dpy
, canvas
, boxlen
/2, boxlen
/2-vert_h
,
169 vert_w
, vert_h
, 1, XYPixmap
, I1
, 0, 0);
170 I1
->format
= XYBitmap
;
172 /* width, height of rotated character ... */
181 /* width in bytes ... */
182 bit_len
= (bit_w
-1)/8 + 1;
184 rotfont
->per_char
[ichar
].glyph
.bit_w
= bit_w
;
185 rotfont
->per_char
[ichar
].glyph
.bit_h
= bit_h
;
187 /* reserve memory for the rotated image ... */
188 bitdata
= (unsigned char *)calloc((unsigned)(bit_h
*bit_len
), 1);
190 /* create the image ... */
191 I2
= XCreateImage(dpy
, DefaultVisual(dpy
, screen
), 1, XYBitmap
, 0,
192 (char *)bitdata
, bit_w
, bit_h
, 8, 0);
194 // if (I2 == NULL) ... error
196 I2
->byte_order
= I2
->bitmap_bit_order
= MSBFirst
;
198 /* map vertical data to rotated character ... */
199 for (j
= 0; j
< bit_h
; j
++) {
200 for (i
= 0; i
< bit_w
; i
++) {
203 val
= vertdata
[i
*vert_len
+ (vert_w
-j
-1)/8] &
204 (128>>((vert_w
-j
-1)%8));
207 val
= vertdata
[(vert_h
-j
-1)*vert_len
+ (vert_w
-i
-1)/8] &
208 (128>>((vert_w
-i
-1)%8));
211 val
= vertdata
[(vert_h
-i
-1)*vert_len
+ j
/8] &
215 bitdata
[j
*bit_len
+ i
/8] = bitdata
[j
*bit_len
+ i
/8] |
220 /* create this character's bitmap ... */
221 rotfont
->per_char
[ichar
].glyph
.bm
=
222 XCreatePixmap(dpy
, root
, bit_w
, bit_h
, 1);
224 /* put the image into the bitmap ... */
225 XPutImage(dpy
, rotfont
->per_char
[ichar
].glyph
.bm
,
226 font_gc
, I2
, 0, 0, 0, 0, bit_w
, bit_h
);
228 /* free the image and data ... */
231 /* free((char *)bitdata); -- XDestroyImage does this
232 free((char *)vertdata);*/
237 for (ichar
= 0; ichar
< min_char
; ichar
++)
238 rotfont
->per_char
[ichar
] = rotfont
->per_char
[(int)'?'];
239 for (ichar
= max_char
+1; ichar
< 256; ichar
++)
240 rotfont
->per_char
[ichar
] = rotfont
->per_char
[(int)'?'];
242 /* free pixmap and GC ... */
243 XFreePixmap(dpy
, canvas
);
244 XFreeGC(dpy
, font_gc
);
249 /* *** Free the resources associated with a rotated font *** */
251 static void XRotUnloadFont(Display
*dpy
, XRotFontStruct
*rotfont
)
255 if (rotfont
->dir
!= 0) {
256 /* loop through each character, freeing its pixmap ... */
257 for (ichar
= rotfont
->min_char
; ichar
<= rotfont
->max_char
; ichar
++)
258 XFreePixmap(dpy
, rotfont
->per_char
[ichar
].glyph
.bm
);
260 /* rotfont should never be referenced again ... */
261 free((char *)rotfont
);
264 /* ---------------------------------------------------------------------- */
266 /* *** A front end to XRotPaintString : mimics XDrawString *** */
269 XRotDrawString(Display
*dpy
, XRotFontStruct
*rotfont
, Drawable drawable
,
270 GC gc
, int x
, int y
, const char *str
, int len
)
272 int i
, xp
, yp
, dir
, ichar
;
274 if (str
== NULL
|| len
<1) return;
278 /* a horizontal string is easy ... */
280 XSetFont(dpy
, gc
, rotfont
->xfontstruct
->fid
);
281 XDrawString(dpy
, drawable
, gc
, x
, y
, str
, len
);
285 /* vertical or upside down ... */
287 XSetFillStyle(dpy
, gc
, FillStippled
);
289 /* loop through each character in string ... */
290 for (i
= 0; i
<len
; i
++) {
291 ichar
= ((unsigned char*)str
)[i
];
293 /* suitable offset ... */
295 xp
= x
-rotfont
->per_char
[ichar
].ascent
;
296 yp
= y
-rotfont
->per_char
[ichar
].rbearing
;
299 xp
= x
-rotfont
->per_char
[ichar
].rbearing
;
300 yp
= y
-rotfont
->per_char
[ichar
].descent
+1;
303 xp
= x
-rotfont
->per_char
[ichar
].descent
+1;
304 yp
= y
+rotfont
->per_char
[ichar
].lbearing
;
307 /* draw the glyph ... */
308 XSetStipple(dpy
, gc
, rotfont
->per_char
[ichar
].glyph
.bm
);
310 XSetTSOrigin(dpy
, gc
, xp
, yp
);
312 XFillRectangle(dpy
, drawable
, gc
, xp
, yp
,
313 rotfont
->per_char
[ichar
].glyph
.bit_w
,
314 rotfont
->per_char
[ichar
].glyph
.bit_h
);
316 /* advance position ... */
318 y
-= rotfont
->per_char
[ichar
].width
;
320 x
-= rotfont
->per_char
[ichar
].width
;
322 y
+= rotfont
->per_char
[ichar
].width
;
324 XSetFillStyle(dpy
, gc
, FillSolid
);
328 /* *** Return the width of a string *** */
330 static int XRotTextWidth(XRotFontStruct
*rotfont
, const char *str
, int len
)
332 int i
, width
= 0, ichar
;
334 if (str
== NULL
) return 0;
336 if (rotfont
->dir
== 0)
337 width
= XTextWidth(rotfont
->xfontstruct
, str
, strlen(str
));
340 for (i
= 0; i
<len
; i
++) {
341 width
+= rotfont
->per_char
[((unsigned char*)str
)[i
]].width
;
348 /* ---------------------------------------------------------------------- */
350 // the public functions use the fltk global variables for font & gc:
352 static XRotFontStruct
* font
;
354 void draw_rotated(const char* text
, int n
, int x
, int y
, int angle
) {
355 if (!text
|| !*text
) return;
356 /* make angle positive ... */
357 if (angle
< 0) do angle
+= 360; while (angle
< 0);
358 /* get nearest vertical or horizontal direction ... */
359 int dir
= ((angle
+45)/90)%4;
361 if (font
&& font
->xfontstruct
== fl_xfont
&& font
->dir
== dir
) {
364 if (font
) XRotUnloadFont(fl_display
, font
);
365 font
= XRotLoadFont(fl_display
, fl_xfont
, dir
);
367 XRotDrawString(fl_display
, font
, fl_window
, fl_gc
, x
, y
, text
, n
);
371 void draw_rotated(const char* text
, int x
, int y
, int angle
) {
372 if (!text
|| !*text
) return;
373 draw_rotated(text
, strlen(text
), x
, y
, angle
);
377 static void draw_rot90(const char* str
, int n
, int x
, int y
) {
378 draw_rotated(str
, n
, y
, -x
, 90);
381 const char* str
, // the (multi-line) string
382 int x
, int y
, int w
, int h
, // bounding box
384 if (!str
|| !*str
) return;
385 if (w
&& h
&& !fl_not_clipped(x
, y
, w
, h
)) return;
386 if (align
& FL_ALIGN_CLIP
) fl_clip(x
, y
, w
, h
);
387 int a1
= align
&(-16);
388 if (align
& FL_ALIGN_LEFT
) a1
|= FL_ALIGN_TOP
;
389 if (align
& FL_ALIGN_RIGHT
) a1
|= FL_ALIGN_BOTTOM
;
390 if (align
& FL_ALIGN_TOP
) a1
|= FL_ALIGN_RIGHT
;
391 if (align
& FL_ALIGN_BOTTOM
) a1
|= FL_ALIGN_LEFT
;
392 fl_draw(str
, -(y
+h
), x
, h
, w
, (Fl_Align
)a1
, draw_rot90
);
393 if (align
& FL_ALIGN_CLIP
) fl_pop_clip();
397 static void draw_rot180(const char* str
, int n
, int x
, int y
) {
398 draw_rotated(str
, n
, -x
, -y
, 180);
400 void draw_rotated180(
401 const char* str
, // the (multi-line) string
402 int x
, int y
, int w
, int h
, // bounding box
404 int a1
= align
&(-16);
405 if (align
& FL_ALIGN_LEFT
) a1
|= FL_ALIGN_RIGHT
;
406 if (align
& FL_ALIGN_RIGHT
) a1
|= FL_ALIGN_LEFT
;
407 if (align
& FL_ALIGN_TOP
) a1
|= FL_ALIGN_BOTTOM
;
408 if (align
& FL_ALIGN_BOTTOM
) a1
|= FL_ALIGN_TOP
;
409 fl_draw(str
, -(x
+w
), -(y
+h
), w
, h
, (Fl_Align
)a1
, draw_rot180
);
412 static void draw_rot270(const char* str
, int n
, int x
, int y
) {
413 draw_rotated(str
, n
, -y
, x
, 270);
415 void draw_rotated270(
416 const char* str
, // the (multi-line) string
417 int x
, int y
, int w
, int h
, // bounding box
419 int a1
= align
&(-16);
420 if (align
& FL_ALIGN_LEFT
) a1
|= FL_ALIGN_BOTTOM
;
421 if (align
& FL_ALIGN_RIGHT
) a1
|= FL_ALIGN_TOP
;
422 if (align
& FL_ALIGN_TOP
) a1
|= FL_ALIGN_LEFT
;
423 if (align
& FL_ALIGN_BOTTOM
) a1
|= FL_ALIGN_RIGHT
;
424 fl_draw(str
, y
, -(x
+w
), h
, w
, (Fl_Align
)a1
, draw_rot270
);