|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: fl_draw.cxx 7903 2010-11-28 21:06:39Z matt $" 00003 // 00004 // Label drawing code for the Fast Light Tool Kit (FLTK). 00005 // 00006 // Copyright 1998-2010 by Bill Spitzak and others. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 // 00027 00028 // Implementation of fl_draw(const char*,int,int,int,int,Fl_Align) 00029 // Used to draw all the labels and text, this routine: 00030 // Word wraps the labels to fit into their bounding box. 00031 // Breaks them into lines at the newlines. 00032 // Expands all unprintable characters to ^X or \nnn notation 00033 // Aligns them against the inside of the box. 00034 00035 #define min(a,b) ((a)<(b)?(a):(b)) 00036 #include <FL/fl_utf8.h> 00037 #include <FL/Fl.H> 00038 #include <FL/fl_draw.H> 00039 #include <FL/Fl_Image.H> 00040 00041 #include "flstring.h" 00042 #include <ctype.h> 00043 #include <math.h> 00044 00045 #define MAXBUF 1024 00046 00047 char fl_draw_shortcut; // set by fl_labeltypes.cxx 00048 00049 static char* underline_at; 00050 00056 #define C_IN(c,a,b) ((c)>=(a) && (c)<=(b)) 00057 #define C_UTF8(c) C_IN(c,0x80,0xBF) 00058 00059 static bool handle_utf8_seq(const char * &s,char * &d) { 00060 register const unsigned char* p=(const unsigned char*)s; 00061 if (p[0] < 0xc2 || p[0] > 0xf4) 00062 return false; // not adressed in this function 00063 else if ( C_IN(p[0], 0xc2, 0xdf) && C_UTF8(p[1]) ) { 00064 d[0]=s[0]; d[1]=s[1]; 00065 d+=2; s++; 00066 // non-overlong 2-byte 00067 } 00068 else if ( p[0]==0xe0 && C_IN(p[1], 0xa0, 0xbf) && C_UTF8(p[2]) ) { 00069 d[0]=s[0]; d[1]=s[1];d[2]=s[2]; 00070 d+=3; s+=2; 00071 // excluding overlongs 00072 } 00073 else if (p[0]==0xed && C_IN(p[1], 0x80, 0x9f) && C_UTF8(p[2]) ) { 00074 d[0]=s[0]; d[1]=s[1];d[2]=s[2]; 00075 d+=3; s+=2; 00076 // excluding surrogates 00077 } 00078 else if (p[0]!=0xed && C_IN(p[0], 0xe1, 0xef) && C_UTF8(p[1]) && C_UTF8(p[2]) ) { 00079 d[0]=s[0]; d[1]=s[1];d[2]=s[2]; 00080 d+=3; s+=2; 00081 // straight 3-byte 00082 } 00083 else if (p[0]==0xf0 && C_IN(p[1], 0x90, 0xbf) && C_UTF8(p[2]) && C_UTF8(p[3]) ) { 00084 d[0]=s[0]; d[1]=s[1]; d[2]=s[2]; d[3]=s[3]; 00085 d+=4; s+=3; 00086 // planes 1-3 00087 } 00088 else if (C_IN(p[0], 0xf1, 0xf3) && C_UTF8(p[1]) && C_UTF8(p[2]) && C_UTF8(p[3]) ) { 00089 d[0]=s[0]; d[1]=s[1]; d[2]=s[2]; d[3]=s[3]; 00090 d+=4; s+=3; 00091 // planes 4-15 00092 } 00093 else if (p[0]==0xf4 && C_IN(p[1], 0x80, 0x8f) && C_UTF8(p[2]) && C_UTF8(p[3]) ) { 00094 d[0]=s[0]; d[1]=s[1]; d[2]=s[2]; d[3]=s[3]; 00095 d+=4; s+=3; 00096 // planes 16 00097 } else { // non utf8 compliant, maybe CP125x or broken utf8 string 00098 // fprintf(stderr, "Not UTF8 char \n"); 00099 return false; 00100 } 00101 return true; // we did handled and copied the utf8 multibyte char seq. 00102 } 00103 00113 const char* 00114 fl_expand_text(const char* from, char* buf, int maxbuf, double maxw, int& n, 00115 double &width, int wrap, int draw_symbols) { 00116 char* o = buf; 00117 char* e = buf+(maxbuf-4); 00118 underline_at = 0; 00119 char* word_end = o; 00120 const char* word_start = from; 00121 double w = 0; 00122 00123 const char* p = from; 00124 for (;; p++) { 00125 00126 int c = *p & 255; 00127 00128 if (!c || c == ' ' || c == '\n') { 00129 // test for word-wrap: 00130 if (word_start < p && wrap) { 00131 double newwidth = w + fl_width(word_end, o-word_end); 00132 if (word_end > buf && newwidth > maxw) { // break before this word 00133 o = word_end; 00134 p = word_start; 00135 break; 00136 } 00137 word_end = o; 00138 w = newwidth; 00139 } 00140 if (!c) break; 00141 else if (c == '\n') {p++; break;} 00142 word_start = p+1; 00143 } 00144 00145 if (o > e) break; // don't overflow buffer 00146 00147 if (c == '\t') { 00148 for (c = fl_utf_nb_char((uchar*)buf, o-buf)%8; c<8 && o<e; c++) 00149 *o++ = ' '; 00150 } else if (c == '&' && fl_draw_shortcut && *(p+1)) { 00151 if (*(p+1) == '&') {p++; *o++ = '&';} 00152 else if (fl_draw_shortcut != 2) underline_at = o; 00153 } else if (c < ' ' || c == 127) { // ^X 00154 *o++ = '^'; 00155 *o++ = c ^ 0x40; 00156 } else if (handle_utf8_seq(p, o)) { // figure out if we have an utf8 valid sequence before we determine the nbsp test validity: 00157 #ifdef __APPLE__ 00158 } else if (c == 0xCA) { // non-breaking space in MacRoman 00159 #else 00160 } else if (c == 0xA0) { // non-breaking space in ISO 8859 00161 #endif 00162 *o++ = ' '; 00163 00164 } else if (c == '@' && draw_symbols) { // Symbol??? 00165 if (p[1] && p[1] != '@') break; 00166 *o++ = c; 00167 if (p[1]) p++; 00168 } else { 00169 *o++ = c; 00170 } 00171 } 00172 00173 width = w + fl_width(word_end, o-word_end); 00174 *o = 0; 00175 n = o-buf; 00176 return p; 00177 } 00178 00184 void fl_draw( 00185 const char* str, // the (multi-line) string 00186 int x, int y, int w, int h, // bounding box 00187 Fl_Align align, 00188 void (*callthis)(const char*,int,int,int), 00189 Fl_Image* img, int draw_symbols) 00190 { 00191 const char* p; 00192 const char* e; 00193 char buf[MAXBUF]; 00194 int buflen; 00195 char symbol[2][255], *symptr; 00196 int symwidth[2], symoffset, symtotal, imgtotal; 00197 00198 // count how many lines and put the last one into the buffer: 00199 int lines; 00200 double width; 00201 00202 // if the image is set as a backdrop, ignore it here 00203 if (img && (align & FL_ALIGN_IMAGE_BACKDROP)) img = 0; 00204 00205 symbol[0][0] = '\0'; 00206 symwidth[0] = 0; 00207 00208 symbol[1][0] = '\0'; 00209 symwidth[1] = 0; 00210 00211 if (draw_symbols) { 00212 if (str && str[0] == '@' && str[1] && str[1] != '@') { 00213 // Start with a symbol... 00214 for (symptr = symbol[0]; 00215 *str && !isspace(*str) && symptr < (symbol[0] + sizeof(symbol[0]) - 1); 00216 *symptr++ = *str++); 00217 *symptr = '\0'; 00218 if (isspace(*str)) str++; 00219 symwidth[0] = min(w,h); 00220 } 00221 00222 if (str && (p = strrchr(str, '@')) != NULL && p > (str + 1) && p[-1] != '@') { 00223 strlcpy(symbol[1], p, sizeof(symbol[1])); 00224 symwidth[1] = min(w,h); 00225 } 00226 } 00227 00228 symtotal = symwidth[0] + symwidth[1]; 00229 imgtotal = (img && (align&FL_ALIGN_IMAGE_NEXT_TO_TEXT)) ? img->w() : 0; 00230 00231 int strw = 0; 00232 int strh; 00233 00234 if (str) { 00235 for (p = str, lines=0; p;) { 00236 e = fl_expand_text(p, buf, MAXBUF, w - symtotal - imgtotal, buflen, width, 00237 align&FL_ALIGN_WRAP, draw_symbols); 00238 if (strw<width) strw = (int)width; 00239 lines++; 00240 if (!*e || (*e == '@' && e[1] != '@' && draw_symbols)) break; 00241 p = e; 00242 } 00243 } else lines = 0; 00244 00245 if ((symwidth[0] || symwidth[1]) && lines) { 00246 if (symwidth[0]) symwidth[0] = lines * fl_height(); 00247 if (symwidth[1]) symwidth[1] = lines * fl_height(); 00248 } 00249 00250 symtotal = symwidth[0] + symwidth[1]; 00251 strh = lines * fl_height(); 00252 00253 // figure out vertical position of the first line: 00254 int xpos; 00255 int ypos; 00256 int height = fl_height(); 00257 int imgvert = ((align&FL_ALIGN_IMAGE_NEXT_TO_TEXT)==0); 00258 int imgh = img && imgvert ? img->h() : 0; 00259 int imgw[2] = {0, 0}; 00260 00261 symoffset = 0; 00262 00263 if (align & FL_ALIGN_BOTTOM) ypos = y+h-(lines-1)*height-imgh; 00264 else if (align & FL_ALIGN_TOP) ypos = y+height; 00265 else ypos = y+(h-lines*height-imgh)/2+height; 00266 00267 // draw the image unless the "text over image" alignment flag is set... 00268 if (img && imgvert && !(align & FL_ALIGN_TEXT_OVER_IMAGE)) { 00269 if (img->w() > symoffset) symoffset = img->w(); 00270 00271 if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0]; 00272 else if (align & FL_ALIGN_RIGHT) xpos = x + w - img->w() - symwidth[1]; 00273 else xpos = x + (w - img->w() - symtotal) / 2 + symwidth[0]; 00274 00275 img->draw(xpos, ypos - height); 00276 ypos += img->h(); 00277 } 00278 00279 // draw the image to the side of the text 00280 if (img && !imgvert /* && (align & !FL_ALIGN_TEXT_NEXT_TO_IMAGE)*/ ) { 00281 if (align & FL_ALIGN_TEXT_OVER_IMAGE) { // image is right of text 00282 imgw[1] = img->w(); 00283 if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0] + strw + 1; 00284 else if (align & FL_ALIGN_RIGHT) xpos = x + w - symwidth[1] - imgw[1] + 1; 00285 else xpos = x + (w - strw - symtotal - imgw[1]) / 2 + symwidth[0] + strw + 1; 00286 } else { // image is to the left of the text 00287 imgw[0] = img->w(); 00288 if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0] - 1; 00289 else if (align & FL_ALIGN_RIGHT) xpos = x + w - symwidth[1] - strw - imgw[0] - 1; 00290 else xpos = x + (w - strw - symtotal - imgw[0]) / 2 - 1; 00291 } 00292 int yimg = ypos - height; 00293 if (align & FL_ALIGN_TOP) ; 00294 else if (align & FL_ALIGN_BOTTOM) yimg += strh - img->h() - 1; 00295 else yimg += (strh - img->h() - 1) / 2; 00296 img->draw(xpos, yimg); 00297 } 00298 00299 // now draw all the lines: 00300 if (str) { 00301 int desc = fl_descent(); 00302 for (p=str; ; ypos += height) { 00303 if (lines>1) e = fl_expand_text(p, buf, MAXBUF, w - symtotal - imgtotal, buflen, 00304 width, align&FL_ALIGN_WRAP, draw_symbols); 00305 else e = ""; 00306 00307 if (width > symoffset) symoffset = (int)(width + 0.5); 00308 00309 if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0] + imgw[0]; 00310 else if (align & FL_ALIGN_RIGHT) xpos = x + w - (int)(width + .5) - symwidth[1] - imgw[1]; 00311 else xpos = x + (w - (int)(width + .5) - symtotal - imgw[0] - imgw[1]) / 2 + symwidth[0] + imgw[0]; 00312 00313 callthis(buf,buflen,xpos,ypos-desc); 00314 00315 if (underline_at && underline_at >= buf && underline_at < (buf + buflen)) 00316 callthis("_",1,xpos+int(fl_width(buf,underline_at-buf)),ypos-desc); 00317 00318 if (!*e || (*e == '@' && e[1] != '@')) break; 00319 p = e; 00320 } 00321 } 00322 00323 // draw the image if the "text over image" alignment flag is set... 00324 if (img && imgvert && (align & FL_ALIGN_TEXT_OVER_IMAGE)) { 00325 if (img->w() > symoffset) symoffset = img->w(); 00326 00327 if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0]; 00328 else if (align & FL_ALIGN_RIGHT) xpos = x + w - img->w() - symwidth[1]; 00329 else xpos = x + (w - img->w() - symtotal) / 2 + symwidth[0]; 00330 00331 img->draw(xpos, ypos); 00332 } 00333 00334 // draw the symbols, if any... 00335 if (symwidth[0]) { 00336 // draw to the left 00337 if (align & FL_ALIGN_LEFT) xpos = x; 00338 else if (align & FL_ALIGN_RIGHT) xpos = x + w - symtotal - symoffset; 00339 else xpos = x + (w - symoffset - symtotal) / 2; 00340 00341 if (align & FL_ALIGN_BOTTOM) ypos = y + h - symwidth[0]; 00342 else if (align & FL_ALIGN_TOP) ypos = y; 00343 else ypos = y + (h - symwidth[0]) / 2; 00344 00345 fl_draw_symbol(symbol[0], xpos, ypos, symwidth[0], symwidth[0], fl_color()); 00346 } 00347 00348 if (symwidth[1]) { 00349 // draw to the right 00350 if (align & FL_ALIGN_LEFT) xpos = x + symoffset + symwidth[0]; 00351 else if (align & FL_ALIGN_RIGHT) xpos = x + w - symwidth[1]; 00352 else xpos = x + (w - symoffset - symtotal) / 2 + symoffset + symwidth[0]; 00353 00354 if (align & FL_ALIGN_BOTTOM) ypos = y + h - symwidth[1]; 00355 else if (align & FL_ALIGN_TOP) ypos = y; 00356 else ypos = y + (h - symwidth[1]) / 2; 00357 00358 fl_draw_symbol(symbol[1], xpos, ypos, symwidth[1], symwidth[1], fl_color()); 00359 } 00360 } 00361 00376 void fl_draw( 00377 const char* str, 00378 int x, int y, int w, int h, 00379 Fl_Align align, 00380 Fl_Image* img, 00381 int draw_symbols) 00382 { 00383 if ((!str || !*str) && !img) return; 00384 if (w && h && !fl_not_clipped(x, y, w, h) && (align & FL_ALIGN_INSIDE)) return; 00385 if (align & FL_ALIGN_CLIP) 00386 fl_push_clip(x, y, w, h); 00387 fl_draw(str, x, y, w, h, align, fl_draw, img, draw_symbols); 00388 if (align & FL_ALIGN_CLIP) 00389 fl_pop_clip(); 00390 } 00391 00400 void fl_measure(const char* str, int& w, int& h, int draw_symbols) { 00401 if (!str || !*str) {w = 0; h = 0; return;} 00402 h = fl_height(); 00403 const char* p; 00404 const char* e; 00405 char buf[MAXBUF]; 00406 int buflen; 00407 int lines; 00408 double width=0; 00409 int W = 0; 00410 char symbol[2][255], *symptr; 00411 int symwidth[2], symtotal; 00412 00413 // count how many lines and put the last one into the buffer: 00414 symbol[0][0] = '\0'; 00415 symwidth[0] = 0; 00416 00417 symbol[1][0] = '\0'; 00418 symwidth[1] = 0; 00419 00420 if (draw_symbols) { 00421 if (str && str[0] == '@' && str[1] && str[1] != '@') { 00422 // Start with a symbol... 00423 for (symptr = symbol[0]; 00424 *str && !isspace(*str) && symptr < (symbol[0] + sizeof(symbol[0]) - 1); 00425 *symptr++ = *str++); 00426 *symptr = '\0'; 00427 if (isspace(*str)) str++; 00428 symwidth[0] = h; 00429 } 00430 00431 if (str && (p = strrchr(str, '@')) != NULL && p > (str + 1) && p[-1]!='@') { 00432 strlcpy(symbol[1], p, sizeof(symbol[1])); 00433 symwidth[1] = h; 00434 } 00435 } 00436 00437 symtotal = symwidth[0] + symwidth[1]; 00438 00439 for (p = str, lines=0; p;) { 00440 // e = expand(p, buf, w - symtotal, buflen, width, w != 0, draw_symbols); 00441 e = fl_expand_text(p, buf, MAXBUF, w - symtotal, buflen, width, 00442 w != 0, draw_symbols); 00443 if ((int)ceil(width) > W) W = (int)ceil(width); 00444 lines++; 00445 if (!*e || (*e == '@' && draw_symbols)) break; 00446 p = e; 00447 } 00448 00449 if ((symwidth[0] || symwidth[1]) && lines) { 00450 if (symwidth[0]) symwidth[0] = lines * fl_height(); 00451 if (symwidth[1]) symwidth[1] = lines * fl_height(); 00452 } 00453 00454 symtotal = symwidth[0] + symwidth[1]; 00455 00456 w = W + symtotal; 00457 h = lines*h; 00458 } 00459 00476 int fl_height(int font, int size) { 00477 if ( font == fl_font() && size == fl_size() ) return(fl_height()); 00478 int tf = fl_font(), ts = fl_size(); // save 00479 fl_font(font,size); 00480 int height = fl_height(); 00481 fl_font(tf,ts); // restore 00482 return(height); 00483 } 00484 00485 // 00486 // End of "$Id: fl_draw.cxx 7903 2010-11-28 21:06:39Z matt $". 00487 //