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