fltk  1.3.5-source
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X.
  Fossies Dox: fltk-1.3.5-source.tar.bz2  ("inofficial" and yet experimental doxygen-generated source code documentation)  

fl_draw.cxx
Go to the documentation of this file.
1 //
2 // "$Id$"
3 //
4 // Label drawing code for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2016 by Bill Spitzak and others.
7 //
8 // This library is free software. Distribution and use rights are outlined in
9 // the file "COPYING" which should have been included with this file. If this
10 // file is missing or damaged, see the license at:
11 //
12 // http://www.fltk.org/COPYING.php
13 //
14 // Please report all bugs and problems on the following page:
15 //
16 // http://www.fltk.org/str.php
17 //
18 
19 // Implementation of fl_draw(const char*,int,int,int,int,Fl_Align)
20 // Used to draw all the labels and text, this routine:
21 // Word wraps the labels to fit into their bounding box.
22 // Breaks them into lines at the newlines.
23 // Expands all unprintable characters to ^X or \nnn notation
24 // Aligns them against the inside of the box.
25 
26 #include <FL/fl_utf8.h>
27 #include <FL/Fl.H>
28 #include <FL/fl_draw.H>
29 #include <FL/Fl_Image.H>
30 
31 #include "flstring.h"
32 #include <ctype.h>
33 #include <math.h>
34 
35 
36 char fl_draw_shortcut; // set by fl_labeltypes.cxx
37 
38 static char* underline_at;
39 
40 /* If called with maxbuf==0, use an internally allocated buffer and enlarge it as needed.
41  Otherwise, use buf as buffer but don't go beyond its length of maxbuf.
42  */
43 static const char* expand_text_(const char* from, char*& buf, int maxbuf, double maxw, int& n,
44  double &width, int wrap, int draw_symbols) {
45  char* e = buf+(maxbuf-4);
46  underline_at = 0;
47  double w = 0;
48  static int l_local_buff = 500;
49  static char *local_buf = (char*)malloc(l_local_buff); // initial buffer allocation
50  if (maxbuf == 0) {
51  buf = local_buf;
52  e = buf + l_local_buff - 4;
53  }
54  char* o = buf;
55  char* word_end = o;
56  const char* word_start = from;
57 
58  const char* p = from;
59  for (;; p++) {
60 
61  int c = *p & 255;
62 
63  if (!c || c == ' ' || c == '\n') {
64  // test for word-wrap:
65  if (word_start < p && wrap) {
66  double newwidth = w + fl_width(word_end, (int) (o-word_end) );
67  if (word_end > buf && newwidth > maxw) { // break before this word
68  o = word_end;
69  p = word_start;
70  break;
71  }
72  word_end = o;
73  w = newwidth;
74  }
75  if (!c) break;
76  else if (c == '\n') {p++; break;}
77  word_start = p+1;
78  }
79 
80  if (o > e) {
81  if (maxbuf) break; // don't overflow buffer
82  l_local_buff += (o - e) + 200; // enlarge buffer
83  buf = (char*)realloc(local_buf, l_local_buff);
84  e = buf + l_local_buff - 4; // update pointers to buffer content
85  o = buf + (o - local_buf);
86  word_end = buf + (word_end - local_buf);
87  local_buf = buf;
88  }
89 
90  if (c == '\t') {
91  for (c = fl_utf_nb_char((uchar*)buf, (int) (o-buf) )%8; c<8 && o<e; c++)
92  *o++ = ' ';
93  } else if (c == '&' && fl_draw_shortcut && *(p+1)) {
94  if (*(p+1) == '&') {p++; *o++ = '&';}
95  else if (fl_draw_shortcut != 2) underline_at = o;
96  } else if (c < ' ' || c == 127) { // ^X
97  *o++ = '^';
98  *o++ = c ^ 0x40;
99 /* This is in fact not useful: the point is that a valid UTF-8 sequence for a non-ascii char contains no ascii char,
100  thus no tab, space, control, & or @ we want to process differently.
101  Also, invalid UTF-8 sequences are copied unchanged by this procedure.
102  Therefore, checking for tab, space, control, & or @, and copying the byte otherwise, is enough.
103  } else if (handle_utf8_seq(p, o)) { // figure out if we have an utf8 valid sequence before we determine the nbsp test validity:
104 #ifdef __APPLE__
105  } else if (c == 0xCA) { // non-breaking space in MacRoman
106 #else
107  } else if (c == 0xA0) { // non-breaking space in ISO 8859
108 #endif
109  *o++ = ' ';*/
110  } else if (c == '@' && draw_symbols) { // Symbol???
111  if (p[1] && p[1] != '@') break;
112  *o++ = c;
113  if (p[1]) p++;
114  } else {
115  *o++ = c;
116  }
117  }
118 
119  width = w + fl_width(word_end, (int) (o-word_end));
120  *o = 0;
121  n = (int) (o-buf);
122  return p;
123 }
124 
134 const char*
135 fl_expand_text(const char* from, char* buf, int maxbuf, double maxw, int& n,
136  double &width, int wrap, int draw_symbols) {
137  return expand_text_(from, buf, maxbuf, maxw, n, width, wrap, draw_symbols);
138 }
139 
145 void fl_draw(
146  const char* str, // the (multi-line) string
147  int x, int y, int w, int h, // bounding box
148  Fl_Align align,
149  void (*callthis)(const char*,int,int,int),
150  Fl_Image* img, int draw_symbols)
151 {
152  char *linebuf = NULL;
153  const char* p;
154  const char* e;
155  int buflen;
156  char symbol[2][255], *symptr;
157  int symwidth[2], symoffset, symtotal, imgtotal;
158 
159  // count how many lines and put the last one into the buffer:
160  int lines;
161  double width;
162 
163  // if the image is set as a backdrop, ignore it here
164  if (img && (align & FL_ALIGN_IMAGE_BACKDROP)) img = 0;
165 
166  symbol[0][0] = '\0';
167  symwidth[0] = 0;
168 
169  symbol[1][0] = '\0';
170  symwidth[1] = 0;
171 
172  if (draw_symbols) {
173  if (str && str[0] == '@' && str[1] && str[1] != '@') {
174  // Start with a symbol...
175  for (symptr = symbol[0];
176  *str && !isspace(*str) && symptr < (symbol[0] + sizeof(symbol[0]) - 1);
177  *symptr++ = *str++) {/*empty*/}
178  *symptr = '\0';
179  if (isspace(*str)) str++;
180  symwidth[0] = (w < h ? w : h);
181  }
182 
183  if (str && (p = strrchr(str, '@')) != NULL && p > (str + 1) && p[-1] != '@') {
184  strlcpy(symbol[1], p, sizeof(symbol[1]));
185  symwidth[1] = (w < h ? w : h);
186  }
187  }
188 
189  symtotal = symwidth[0] + symwidth[1];
190  imgtotal = (img && (align&FL_ALIGN_IMAGE_NEXT_TO_TEXT)) ? img->w() : 0;
191 
192  int strw = 0;
193  int strh;
194 
195  if (str) {
196  for (p = str, lines=0; p;) {
197  e = expand_text_(p, linebuf, 0, w - symtotal - imgtotal, buflen, width,
198  align&FL_ALIGN_WRAP, draw_symbols);
199  if (strw<width) strw = (int)width;
200  lines++;
201  if (!*e || (*e == '@' && e[1] != '@' && draw_symbols)) break;
202  p = e;
203  }
204  } else lines = 0;
205 
206  if ((symwidth[0] || symwidth[1]) && lines) {
207  if (symwidth[0]) symwidth[0] = lines * fl_height();
208  if (symwidth[1]) symwidth[1] = lines * fl_height();
209  }
210 
211  symtotal = symwidth[0] + symwidth[1];
212  strh = lines * fl_height();
213 
214  // figure out vertical position of the first line:
215  int xpos;
216  int ypos;
217  int height = fl_height();
218  int imgvert = ((align&FL_ALIGN_IMAGE_NEXT_TO_TEXT)==0);
219  int imgh = img && imgvert ? img->h() : 0;
220  int imgw[2] = {0, 0};
221 
222  symoffset = 0;
223 
224  if (align & FL_ALIGN_BOTTOM) ypos = y+h-(lines-1)*height-imgh;
225  else if (align & FL_ALIGN_TOP) ypos = y+height;
226  else ypos = y+(h-lines*height-imgh)/2+height;
227 
228  // draw the image unless the "text over image" alignment flag is set...
229  if (img && imgvert && !(align & FL_ALIGN_TEXT_OVER_IMAGE)) {
230  if (img->w() > symoffset) symoffset = img->w();
231 
232  if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0];
233  else if (align & FL_ALIGN_RIGHT) xpos = x + w - img->w() - symwidth[1];
234  else xpos = x + (w - img->w() - symtotal) / 2 + symwidth[0];
235 
236  img->draw(xpos, ypos - height);
237  ypos += img->h();
238  }
239 
240  // draw the image to the side of the text
241  if (img && !imgvert /* && (align & !FL_ALIGN_TEXT_NEXT_TO_IMAGE)*/ ) {
242  if (align & FL_ALIGN_TEXT_OVER_IMAGE) { // image is right of text
243  imgw[1] = img->w();
244  if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0] + strw + 1;
245  else if (align & FL_ALIGN_RIGHT) xpos = x + w - symwidth[1] - imgw[1] + 1;
246  else xpos = x + (w - strw - symtotal - imgw[1]) / 2 + symwidth[0] + strw + 1;
247  } else { // image is to the left of the text
248  imgw[0] = img->w();
249  if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0] - 1;
250  else if (align & FL_ALIGN_RIGHT) xpos = x + w - symwidth[1] - strw - imgw[0] - 1;
251  else xpos = x + (w - strw - symtotal - imgw[0]) / 2 - 1;
252  }
253  int yimg = ypos - height;
254  if (align & FL_ALIGN_TOP) ;
255  else if (align & FL_ALIGN_BOTTOM) yimg += strh - img->h() - 1;
256  else yimg += (strh - img->h() - 1) / 2;
257  img->draw(xpos, yimg);
258  }
259 
260  // now draw all the lines:
261  if (str) {
262  int desc = fl_descent();
263  for (p=str; ; ypos += height) {
264  if (lines>1) e = expand_text_(p, linebuf, 0, w - symtotal - imgtotal, buflen,
265  width, align&FL_ALIGN_WRAP, draw_symbols);
266  else e = "";
267 
268  if (width > symoffset) symoffset = (int)(width + 0.5);
269 
270  if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0] + imgw[0];
271  else if (align & FL_ALIGN_RIGHT) xpos = x + w - (int)(width + .5) - symwidth[1] - imgw[1];
272  else xpos = x + (w - (int)(width + .5) - symtotal - imgw[0] - imgw[1]) / 2 + symwidth[0] + imgw[0];
273 
274  callthis(linebuf,buflen,xpos,ypos-desc);
275 
277  callthis("_",1,xpos+int(fl_width(linebuf,(int) (underline_at-linebuf))),ypos-desc);
278 
279  if (!*e || (*e == '@' && e[1] != '@')) break;
280  p = e;
281  }
282  }
283 
284  // draw the image if the "text over image" alignment flag is set...
285  if (img && imgvert && (align & FL_ALIGN_TEXT_OVER_IMAGE)) {
286  if (img->w() > symoffset) symoffset = img->w();
287 
288  if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0];
289  else if (align & FL_ALIGN_RIGHT) xpos = x + w - img->w() - symwidth[1];
290  else xpos = x + (w - img->w() - symtotal) / 2 + symwidth[0];
291 
292  img->draw(xpos, ypos);
293  }
294 
295  // draw the symbols, if any...
296  if (symwidth[0]) {
297  // draw to the left
298  if (align & FL_ALIGN_LEFT) xpos = x;
299  else if (align & FL_ALIGN_RIGHT) xpos = x + w - symtotal - symoffset;
300  else xpos = x + (w - symoffset - symtotal) / 2;
301 
302  if (align & FL_ALIGN_BOTTOM) ypos = y + h - symwidth[0];
303  else if (align & FL_ALIGN_TOP) ypos = y;
304  else ypos = y + (h - symwidth[0]) / 2;
305 
306  fl_draw_symbol(symbol[0], xpos, ypos, symwidth[0], symwidth[0], fl_color());
307  }
308 
309  if (symwidth[1]) {
310  // draw to the right
311  if (align & FL_ALIGN_LEFT) xpos = x + symoffset + symwidth[0];
312  else if (align & FL_ALIGN_RIGHT) xpos = x + w - symwidth[1];
313  else xpos = x + (w - symoffset - symtotal) / 2 + symoffset + symwidth[0];
314 
315  if (align & FL_ALIGN_BOTTOM) ypos = y + h - symwidth[1];
316  else if (align & FL_ALIGN_TOP) ypos = y;
317  else ypos = y + (h - symwidth[1]) / 2;
318 
319  fl_draw_symbol(symbol[1], xpos, ypos, symwidth[1], symwidth[1], fl_color());
320  }
321 }
322 
336 void fl_draw(
337  const char* str,
338  int x, int y, int w, int h,
339  Fl_Align align,
340  Fl_Image* img,
341  int draw_symbols)
342 {
343  if ((!str || !*str) && !img) return;
344  if (w && h && !fl_not_clipped(x, y, w, h) && (align & FL_ALIGN_INSIDE)) return;
345  if (align & FL_ALIGN_CLIP)
346  fl_push_clip(x, y, w, h);
347  fl_draw(str, x, y, w, h, align, fl_draw, img, draw_symbols);
348  if (align & FL_ALIGN_CLIP)
349  fl_pop_clip();
350 }
351 
380 void fl_measure(const char* str, int& w, int& h, int draw_symbols) {
381  if (!str || !*str) {w = 0; h = 0; return;}
382  h = fl_height();
383  char *linebuf = NULL;
384  const char* p;
385  const char* e;
386  int buflen;
387  int lines;
388  double width=0;
389  int W = 0;
390  int symwidth[2], symtotal;
391 
392  symwidth[0] = 0; // size of symbol at beginning of string (if any)
393  symwidth[1] = 0; // size of symbol at end of string (if any)
394 
395  if (draw_symbols) {
396  // Symbol at beginning of string?
397  const char *sym2 = (str[0]=='@' && str[1]=='@') ? str+2 : str; // sym2 check will skip leading @@
398  if (str[0] == '@' && str[1] != '@') {
399  while (*str && !isspace(*str)) { ++str; } // skip over symbol
400  if (isspace(*str)) ++str; // skip over trailing space
401  sym2 = str; // sym2 check will skip leading symbol
402  symwidth[0] = h;
403  }
404  // Symbol at end of string?
405  if ((p=strchr(sym2,'@')) != NULL && p[1] != '@') {
406  symwidth[1] = h;
407  }
408  }
409 
410  symtotal = symwidth[0] + symwidth[1];
411 
412  for (p = str, lines=0; p;) {
413 // e = expand(p, linebuf, w - symtotal, buflen, width, w != 0, draw_symbols);
414  e = expand_text_(p, linebuf, 0, w - symtotal, buflen, width,
415  w != 0, draw_symbols);
416  if ((int)ceil(width) > W) W = (int)ceil(width);
417  lines++;
418  if (!*e || (*e == '@' && e[1] != '@' && draw_symbols)) break;
419  p = e;
420  }
421 
422  if ((symwidth[0] || symwidth[1]) && lines) {
423  if (symwidth[0]) symwidth[0] = lines * fl_height();
424  if (symwidth[1]) symwidth[1] = lines * fl_height();
425  }
426 
427  symtotal = symwidth[0] + symwidth[1];
428 
429  w = W + symtotal;
430  h = lines*h;
431 }
432 
449 int fl_height(int font, int size) {
450  if ( font == fl_font() && size == fl_size() ) return(fl_height());
451  int tf = fl_font(), ts = fl_size(); // save
452  fl_font(font,size);
453  int height = fl_height();
454  fl_font(tf,ts); // restore
455  return(height);
456 }
457 
458 //
459 // End of "$Id$".
460 //
fl_not_clipped
int fl_not_clipped(int x, int y, int w, int h)
Definition: fl_draw.H:114
fl_font
void fl_font(Fl_Font face, Fl_Fontsize fsize)
Definition: fl_draw.H:509
fl_width
FL_EXPORT double fl_width(const char *txt)
Definition: fl_font.cxx:65
FL_ALIGN_LEFT
const Fl_Align FL_ALIGN_LEFT
Definition: Enumerations.H:839
Fl.H
buf
static char * buf
Definition: fl_encoding_mac_roman.cxx:76
fl_height
int fl_height(int font, int size)
Definition: fl_draw.cxx:449
Fl_Image::h
void h(int H)
Definition: Fl_Image.H:80
Fl_Image
Base class for image caching and drawing.
Definition: Fl_Image.H:55
fl_descent
int fl_descent()
Definition: fl_draw.H:533
fl_color
void fl_color(Fl_Color c)
Definition: fl_draw.H:52
fl_expand_text
const char * fl_expand_text(const char *from, char *buf, int maxbuf, double maxw, int &n, double &width, int wrap, int draw_symbols)
Definition: fl_draw.cxx:135
NULL
#define NULL
Definition: forms.H:34
FL_ALIGN_TEXT_OVER_IMAGE
const Fl_Align FL_ALIGN_TEXT_OVER_IMAGE
Definition: Enumerations.H:845
Fl_Image::w
void w(int W)
Definition: Fl_Image.H:76
fl_draw_symbol
FL_EXPORT int fl_draw_symbol(const char *label, int x, int y, int w, int h, Fl_Color)
Definition: fl_symbols.cxx:103
FL_ALIGN_INSIDE
const Fl_Align FL_ALIGN_INSIDE
Definition: Enumerations.H:843
math.h
p
static menustate * p
Definition: Fl_Menu.cxx:606
fl_draw
void fl_draw(const char *str, int x, int y, int w, int h, Fl_Align align, void(*callthis)(const char *, int, int, int), Fl_Image *img, int draw_symbols)
Definition: fl_draw.cxx:145
fl_draw_shortcut
char fl_draw_shortcut
Definition: fl_draw.cxx:36
fl_utf8.h
header for Unicode and UTF-8 character handling
underline_at
static char * underline_at
Definition: fl_draw.cxx:38
fl_size
Fl_Fontsize fl_size()
Definition: fl_draw.H:520
fl_draw.H
utility header to pull drawing functions together
strlcpy
#define strlcpy
Definition: flstring.h:84
fl_measure
void fl_measure(const char *str, int &w, int &h, int draw_symbols)
Definition: fl_draw.cxx:380
fl_push_clip
void fl_push_clip(int x, int y, int w, int h)
Definition: fl_draw.H:82
FL_ALIGN_BOTTOM
const Fl_Align FL_ALIGN_BOTTOM
Definition: Enumerations.H:835
fl_utf_nb_char
int fl_utf_nb_char(const unsigned char *buf, int len)
Definition: fl_utf8.cxx:167
fl_pop_clip
void fl_pop_clip()
Definition: fl_draw.H:103
x
int x
Definition: test.c:73
Fl_Image::draw
virtual void draw(int X, int Y, int W, int H, int cx=0, int cy=0)
Definition: Fl_Image.cxx:66
symbol
Definition: factory.cxx:1107
FL_ALIGN_WRAP
const Fl_Align FL_ALIGN_WRAP
Definition: Enumerations.H:851
FL_ALIGN_TOP
const Fl_Align FL_ALIGN_TOP
Definition: Enumerations.H:833
y
int y
Definition: test.c:74
malloc
voidp malloc()
Fl_Image.H
flstring.h
expand_text_
static const char * expand_text_(const char *from, char *&buf, int maxbuf, double maxw, int &n, double &width, int wrap, int draw_symbols)
Definition: fl_draw.cxx:43
FL_ALIGN_RIGHT
const Fl_Align FL_ALIGN_RIGHT
Definition: Enumerations.H:841
Fl_Align
unsigned Fl_Align
Definition: Enumerations.H:828
uchar
unsigned char uchar
Definition: fl_types.h:30
linebuf
char linebuf[1024]
Definition: doxystar.cxx:22
FL_ALIGN_CLIP
const Fl_Align FL_ALIGN_CLIP
Definition: Enumerations.H:849
buflen
static int buflen
Definition: file.cxx:216
FL_ALIGN_IMAGE_NEXT_TO_TEXT
const Fl_Align FL_ALIGN_IMAGE_NEXT_TO_TEXT
Definition: Enumerations.H:853
FL_ALIGN_IMAGE_BACKDROP
const Fl_Align FL_ALIGN_IMAGE_BACKDROP
Definition: Enumerations.H:857