aboutsummaryrefslogtreecommitdiff
path: root/src/DrawUtil.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/DrawUtil.cc')
-rw-r--r--src/DrawUtil.cc462
1 files changed, 462 insertions, 0 deletions
diff --git a/src/DrawUtil.cc b/src/DrawUtil.cc
new file mode 100644
index 0000000..c9527de
--- /dev/null
+++ b/src/DrawUtil.cc
@@ -0,0 +1,462 @@
1// DrawUtil.cc for fluxbox
2// Copyright (c) 2001 Henrik Kinnunen (fluxgen@linuxmail.org)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22#ifdef HAVE_CONFIG_H
23# include "config.h"
24#endif //HAVE_CONFIG_H
25
26#include "DrawUtil.hh"
27#include "StringUtil.hh"
28#include "i18n.hh"
29
30#include <iostream>
31#include <X11/Xutil.h>
32
33using namespace std;
34
35// ----------------------------------------------------------------------
36// xvertext, Copyright (c) 1992 Alan Richardson (mppa3@uk.ac.sussex.syma)
37// ----------------------------------------------------------------------
38
39//------- XRotLoadFont -------------------
40// Load the rotated version of a given font
41//----------------------------------------
42DrawUtil::XRotFontStruct *DrawUtil::XRotLoadFont(Display *dpy, char *fontname, float angle) {
43 char val;
44 XImage *I1, *I2;
45 Pixmap canvas;
46 Window root;
47 int screen;
48 GC font_gc;
49 char text[3];/*, errstr[300];*/
50 XFontStruct *fontstruct;
51 XRotFontStruct *rotfont;
52 int ichar, i, j, index, boxlen = 60, dir;
53 int vert_w, vert_h, vert_len, bit_w, bit_h, bit_len;
54 int min_char, max_char;
55 unsigned char *vertdata, *bitdata;
56 int ascent, descent, lbearing, rbearing;
57 int on = 1, off = 0;
58
59 /* make angle positive ... */
60 if (angle < 0) do angle += 360; while (angle < 0);
61
62 /* get nearest vertical or horizontal direction ... */
63 dir = (int)((angle+45.)/90.)%4;
64
65 /* useful macros ... */
66 screen = DefaultScreen(dpy);
67 root = DefaultRootWindow(dpy);
68
69 /* create the depth 1 canvas bitmap ... */
70 canvas = XCreatePixmap(dpy, root, boxlen, boxlen, 1);
71
72 /* create a GC ... */
73 font_gc = XCreateGC(dpy, canvas, 0, 0);
74 XSetBackground(dpy, font_gc, off);
75
76 /* load the font ... */
77 fontstruct = XLoadQueryFont(dpy, fontname);
78 if (fontstruct == NULL) {
79 cerr<<"Fluxbox::DrawUtil: No font"<<endl;
80 return 0;
81 }
82
83 XSetFont(dpy, font_gc, fontstruct->fid);
84
85 /* allocate space for rotated font ... */
86 rotfont = (XRotFontStruct *)malloc((unsigned)sizeof(XRotFontStruct));
87
88 if (rotfont == 0) {
89 cerr<<"Fluxbox::DrawUtil: out of memory"<<endl;
90 return 0;
91 }
92
93 /* determine which characters are defined in font ... */
94 min_char = fontstruct->min_char_or_byte2;
95 max_char = fontstruct->max_char_or_byte2;
96
97 /* we only want printing characters ... */
98 if (min_char<32) min_char = 32;
99 if (max_char>126) max_char = 126;
100
101 /* some overall font data ... */
102 rotfont->name = StringUtil::strdup(fontname);
103 rotfont->dir = dir;
104 rotfont->min_char = min_char;
105 rotfont->max_char = max_char;
106 rotfont->max_ascent = fontstruct->max_bounds.ascent;
107 rotfont->max_descent = fontstruct->max_bounds.descent;
108 rotfont->height = rotfont->max_ascent+rotfont->max_descent;
109
110 /* remember xfontstruct for `normal' text ... */
111 if (dir == 0)
112 rotfont->xfontstruct = fontstruct;
113 else {
114 /* font needs rotation ... */
115 /* loop through each character ... */
116 for (ichar = min_char; ichar <= max_char; ichar++) {
117 index = ichar-fontstruct->min_char_or_byte2;
118
119 /* per char dimensions ... */
120 ascent = rotfont->per_char[ichar-32].ascent =
121 fontstruct->per_char[index].ascent;
122 descent = rotfont->per_char[ichar-32].descent =
123 fontstruct->per_char[index].descent;
124 lbearing = rotfont->per_char[ichar-32].lbearing =
125 fontstruct->per_char[index].lbearing;
126 rbearing = rotfont->per_char[ichar-32].rbearing =
127 fontstruct->per_char[index].rbearing;
128 rotfont->per_char[ichar-32].width =
129 fontstruct->per_char[index].width;
130
131 /* some space chars have zero body, but a bitmap can't have ... */
132 if (!ascent && !descent)
133 ascent = rotfont->per_char[ichar-32].ascent = 1;
134 if (!lbearing && !rbearing)
135 rbearing = rotfont->per_char[ichar-32].rbearing = 1;
136
137 /* glyph width and height when vertical ... */
138 vert_w = rbearing-lbearing;
139 vert_h = ascent+descent;
140
141 /* width in bytes ... */
142 vert_len = (vert_w-1)/8+1;
143
144 XSetForeground(dpy, font_gc, off);
145 XFillRectangle(dpy, canvas, font_gc, 0, 0, boxlen, boxlen);
146
147 /* draw the character centre top right on canvas ... */
148 sprintf(text, "%c", ichar);
149 XSetForeground(dpy, font_gc, on);
150 XDrawImageString(dpy, canvas, font_gc, boxlen/2 - lbearing,
151 boxlen/2 - descent, text, 1);
152
153 /* reserve memory for first XImage ... */
154 vertdata = (unsigned char *) malloc((unsigned)(vert_len*vert_h));
155
156 /* create the XImage ... */
157 I1 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap,
158 0, (char *)vertdata, vert_w, vert_h, 8, 0);
159
160 if (I1 == NULL) {
161 cerr<<"Fluxbox::DrawUtil: Cant create ximage."<<endl;
162 return NULL;
163 }
164
165 I1->byte_order = I1->bitmap_bit_order = MSBFirst;
166
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;
171
172 /* width, height of rotated character ... */
173 if (dir == 2) {
174 bit_w = vert_w;
175 bit_h = vert_h;
176 } else {
177 bit_w = vert_h;
178 bit_h = vert_w;
179 }
180
181 /* width in bytes ... */
182 bit_len = (bit_w-1)/8 + 1;
183
184 rotfont->per_char[ichar-32].glyph.bit_w = bit_w;
185 rotfont->per_char[ichar-32].glyph.bit_h = bit_h;
186
187 /* reserve memory for the rotated image ... */
188 bitdata = (unsigned char *)calloc((unsigned)(bit_h*bit_len), 1);
189
190 /* create the image ... */
191 I2 = XCreateImage(dpy, DefaultVisual(dpy, screen), 1, XYBitmap, 0,
192 (char *)bitdata, bit_w, bit_h, 8, 0);
193
194 if (I2 == NULL) {
195 cerr<<"Font::DrawUtil: Cant create ximage!"<<endl;
196 return 0;
197 }
198
199 I2->byte_order = I2->bitmap_bit_order = MSBFirst;
200
201 /* map vertical data to rotated character ... */
202 for (j = 0; j < bit_h; j++) {
203 for (i = 0; i < bit_w; i++) {
204 /* map bits ... */
205 if (dir == 1) {
206 val = vertdata[i*vert_len + (vert_w-j-1)/8] &
207 (128>>((vert_w-j-1)%8));
208 } else if (dir == 2) {
209 val = vertdata[(vert_h-j-1)*vert_len +
210 (vert_w-i-1)/8] & (128>>((vert_w-i-1)%8));
211 } else {
212 val = vertdata[(vert_h-i-1)*vert_len + j/8] &
213 (128>>(j%8));
214 }
215 if (val) {
216 bitdata[j*bit_len + i/8] = bitdata[j*bit_len + i/8] |
217 (128>>(i%8));
218 }
219 }
220 }
221
222 /* create this character's bitmap ... */
223 rotfont->per_char[ichar-32].glyph.bm =
224 XCreatePixmap(dpy, root, bit_w, bit_h, 1);
225
226 /* put the image into the bitmap ... */
227 XPutImage(dpy, rotfont->per_char[ichar-32].glyph.bm,
228 font_gc, I2, 0, 0, 0, 0, bit_w, bit_h);
229
230 /* free the image and data ... */
231 XDestroyImage(I1);
232 XDestroyImage(I2);
233 /* free((char *)bitdata); -- XDestroyImage does this
234 free((char *)vertdata);*/
235 }
236 XFreeFont(dpy, fontstruct);
237 }
238
239 /* free pixmap and GC ... */
240 XFreePixmap(dpy, canvas);
241 XFreeGC(dpy, font_gc);
242
243 return rotfont;
244}
245
246//------- XRotUnloadFont -----------------
247// Free the resources associated with a
248// rotated font
249//----------------------------------------
250void DrawUtil::XRotUnloadFont(Display *dpy, XRotFontStruct *rotfont)
251{
252 int ichar;
253
254 if (rotfont->dir == 0)
255 XFreeFont(dpy, rotfont->xfontstruct);
256 else {
257 /* loop through each character, freeing its pixmap ... */
258 for (ichar = rotfont->min_char-32; ichar <= rotfont->max_char-32;
259 ichar++)
260 XFreePixmap(dpy, rotfont->per_char[ichar].glyph.bm);
261 }
262
263 free((char *)rotfont->name);
264 free((char *)rotfont);
265}
266
267//------- XRotTextWidth ------------------
268// Returns the width of a rotated string
269//----------------------------------------
270unsigned int DrawUtil::XRotTextWidth(XRotFontStruct *rotfont, char *str, int len)
271{
272 int i, width = 0, ichar;
273
274 if (str == NULL)
275 return 0;
276
277 if (rotfont->dir == 0)
278 width = XTextWidth(rotfont->xfontstruct, str, strlen(str));
279 else {
280 for (i = 0; i<len; i++) {
281 ichar = str[i]-32;
282
283 /* make sure it's a printing character ... */
284 if (ichar >= 0 && ichar<95)
285 width += rotfont->per_char[ichar].width;
286 }
287 }
288 return width;
289}
290
291
292//------- XRotDrawString -----------------
293// A front end to XRotDrawString : mimics XDrawString
294//----------------------------------------
295void DrawUtil::XRotDrawString(Display *dpy, XRotFontStruct *rotfont, Drawable drawable,
296 GC gc, int x, int y, char *str, int len)
297{
298 static GC my_gc = 0;
299 int i, xp, yp, dir, ichar;
300
301 if (str == NULL || len<1)
302 return;
303
304 dir = rotfont->dir;
305 if (my_gc == 0)
306 my_gc = XCreateGC(dpy, drawable, 0, 0);
307
308 XCopyGC(dpy, gc, GCForeground|GCBackground, my_gc);
309
310 /* a horizontal string is easy ... */
311 if (dir == 0) {
312 XSetFillStyle(dpy, my_gc, FillSolid);
313 XSetFont(dpy, my_gc, rotfont->xfontstruct->fid);
314 XDrawString(dpy, drawable, my_gc, x, y, str, len);
315 return;
316 }
317
318 /* vertical or upside down ... */
319
320 XSetFillStyle(dpy, my_gc, FillStippled);
321
322 /* loop through each character in string ... */
323 for (i = 0; i<len; i++) {
324 ichar = str[i]-32;
325
326 /* make sure it's a printing character ... */
327 if (ichar >= 0 && ichar<95) {
328 /* suitable offset ... */
329 if (dir == 1) {
330 xp = x-rotfont->per_char[ichar].ascent;
331 yp = y-rotfont->per_char[ichar].rbearing;
332 } else if (dir == 2) {
333 xp = x-rotfont->per_char[ichar].rbearing;
334 yp = y-rotfont->per_char[ichar].descent+1;
335 } else {
336 xp = x-rotfont->per_char[ichar].descent+1;
337 yp = y+rotfont->per_char[ichar].lbearing;
338 }
339
340 /* draw the glyph ... */
341 XSetStipple(dpy, my_gc, rotfont->per_char[ichar].glyph.bm);
342
343 XSetTSOrigin(dpy, my_gc, xp, yp);
344
345 XFillRectangle(dpy, drawable, my_gc, xp, yp,
346 rotfont->per_char[ichar].glyph.bit_w,
347 rotfont->per_char[ichar].glyph.bit_h);
348
349 /* advance position ... */
350 if (dir == 1)
351 y -= rotfont->per_char[ichar].width;
352 else if (dir == 2)
353 x -= rotfont->per_char[ichar].width;
354 else
355 y += rotfont->per_char[ichar].width;
356 }
357 }
358}
359
360
361//Draw title string
362void DrawUtil::DrawString(Display *display, Window w, GC gc, DrawUtil::Font *font,
363 unsigned int text_w, unsigned int size_w,
364 unsigned int bevel_w, char *text) {
365
366 assert(display);
367 assert(font);
368
369 if (!text || text_w<1 || size_w < 1)
370 return;
371
372 unsigned int l = text_w;
373 int dlen=strlen(text);
374 int dx=bevel_w*2;
375
376
377 if (text_w > size_w) {
378 for (; dlen >= 0; dlen--) {
379 if (I18n::instance()->multibyte()) {
380 XRectangle ink, logical;
381 XmbTextExtents(font->set, text, dlen,
382 &ink, &logical);
383 l = logical.width;
384 } else
385 l = XTextWidth(font->fontstruct, text, dlen);
386
387 l += (dx * 4);
388
389 if (l < size_w)
390 break;
391 }
392 }
393
394 switch (font->justify) {
395 case DrawUtil::Font::RIGHT:
396 dx += size_w - l;
397 break;
398
399 case DrawUtil::Font::CENTER:
400 dx += (size_w - l) / 2;
401 break;
402 default:
403 break;
404 }
405
406 //Draw title to m_tabwin
407
408 XClearWindow(display, w);
409
410 if (I18n::instance()->multibyte()) {
411 XmbDrawString(display, w,
412 font->set, gc, dx, 1 - font->set_extents->max_ink_extent.y,
413 text, dlen);
414 } else {
415 XDrawString(display, w,
416 gc, dx, font->fontstruct->ascent + 1,
417 text, dlen);
418 }
419
420}
421
422
423void DrawUtil::DrawRotString(Display *display, Window w, GC gc, XRotFontStruct *font,
424 unsigned int align, unsigned int text_w,
425 unsigned int size_w, unsigned int size_h,
426 unsigned int bevel_w, char *text) {
427
428 assert(display);
429 assert(font);
430
431 if (!text || text_w<1 || size_w < 1)
432 return;
433
434 unsigned int l = text_w;
435 int dlen = strlen(text);
436 int dx = bevel_w * 2;
437
438 if (text_w > size_w) {
439 for (; dlen >= 0; dlen--) {
440 l = XRotTextWidth(font, text, dlen);
441
442 l += (dx * 4);
443
444 if (l < size_h)
445 break;
446 }
447 }
448
449 if (align == DrawUtil::Font::RIGHT)
450 size_h = l;
451 else if (align == DrawUtil::Font::CENTER)
452 size_h = (size_h + l) / 2;
453 else //LEFT
454 size_h -= (dx * 4);
455
456 // To get it in the "center" of the tab
457 size_w = (size_w + XRotTextWidth(font, "/", 1)) / 2;
458
459 //Draw title to m_tabwin
460 XClearWindow(display, w);
461 XRotDrawString(display, font, w, gc, size_w, size_h, text, dlen);
462}