Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/text/textFont.cxx

Go to the documentation of this file.
00001 // Filename: textFont.cxx
00002 // Created by:  drose (08Feb02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "textFont.h"
00020 #include "config_text.h"
00021 #include "ctype.h"
00022 
00023 TypeHandle TextFont::_type_handle;
00024 
00025 
00026 ////////////////////////////////////////////////////////////////////
00027 //     Function: isblank
00028 //  Description: An internal function, similar to isspace(), except it
00029 //               does not consider newlines to be whitespace.
00030 ////////////////////////////////////////////////////////////////////
00031 INLINE bool
00032 isblank(unsigned int ch) {
00033   return (ch == ' ' || ch == '\t');
00034 }
00035 
00036 ////////////////////////////////////////////////////////////////////
00037 //     Function: isspacew
00038 //  Description: An internal function that works like isspace() but is
00039 //               safe to call for a wide character.
00040 ////////////////////////////////////////////////////////////////////
00041 INLINE bool
00042 isspacew(unsigned int ch) {
00043   return isascii(ch) && isspace(ch);
00044 }
00045 
00046 ////////////////////////////////////////////////////////////////////
00047 //     Function: TextFont::Constructor
00048 //       Access: Public
00049 //  Description: 
00050 ////////////////////////////////////////////////////////////////////
00051 TextFont::
00052 TextFont() {
00053   _is_valid = false;
00054   _line_height = 1.0f;
00055   _space_advance = 0.25f;
00056 }
00057 
00058 ////////////////////////////////////////////////////////////////////
00059 //     Function: TextFont::Destructor
00060 //       Access: Published, Virtual
00061 //  Description:
00062 ////////////////////////////////////////////////////////////////////
00063 TextFont::
00064 ~TextFont() {
00065 }
00066 
00067 ////////////////////////////////////////////////////////////////////
00068 //     Function: TextFont::calc_width
00069 //       Access: Published
00070 //  Description: Returns the width of a single character of the font,
00071 //               or 0.0 if the character is not known.
00072 ////////////////////////////////////////////////////////////////////
00073 float TextFont::
00074 calc_width(int character) {
00075   if (character == ' ') {
00076     // A space is a special case.
00077     return _space_advance;
00078   }
00079 
00080   const TextGlyph *glyph;
00081   get_glyph(character, glyph);
00082   if (glyph == (TextGlyph *)NULL) {
00083     // Unknown character.
00084     return 0.0f;
00085   }
00086 
00087   return glyph->get_advance();
00088 }
00089 
00090 ////////////////////////////////////////////////////////////////////
00091 //     Function: TextFont::calc_width
00092 //       Access: Published
00093 //  Description: Returns the width of a line of text of arbitrary
00094 //               characters.  The line should not include the newline
00095 //               character.
00096 ////////////////////////////////////////////////////////////////////
00097 float TextFont::
00098 calc_width(const string &line) {
00099   float width = 0.0f;
00100 
00101   string::const_iterator si;
00102   for (si = line.begin(); si != line.end(); ++si) {
00103     width += calc_width(*si);
00104   }
00105 
00106   return width;
00107 }
00108 
00109 ////////////////////////////////////////////////////////////////////
00110 //     Function: TextFont::wordwrap_to
00111 //       Access: Published
00112 //  Description: Inserts newlines into the given text at the
00113 //               appropriate places in order to make each line be the
00114 //               longest possible line that is not longer than
00115 //               wordwrap_width (and does not break any words, if
00116 //               possible).  Returns the new string.
00117 ////////////////////////////////////////////////////////////////////
00118 string TextFont::
00119 wordwrap_to(const string &text, float wordwrap_width, 
00120             bool preserve_trailing_whitespace) {
00121   string output_text;
00122 
00123   size_t p = 0;
00124 
00125   // Preserve any initial whitespace and newlines.
00126   float initial_width = 0.0f;
00127   while (p < text.length() && isspace((unsigned int)text[p])) {  // dbg runtime will bomb if text[p]>=128 without (unsigned int) cast
00128     if (text[p] == '\n') {
00129       initial_width = 0.0f;
00130     } else {
00131       initial_width += calc_width(text[p]);
00132     }
00133     output_text += text[p];
00134     p++;
00135   }
00136   bool needs_newline = false;
00137 
00138   while (p < text.length()) {
00139     nassertr(!isspace((unsigned int)text[p]), string());
00140 
00141     // Scan the next n characters, until the end of the string or an
00142     // embedded newline character, or we exceed wordwrap_width.
00143 
00144     size_t q = p;
00145     bool any_spaces = false;
00146     bool overflow = false;
00147 
00148     float width = initial_width;
00149     while (q < text.length() && text[q] != '\n') {
00150       if (isspace((unsigned int)text[q])) {
00151         any_spaces = true;
00152       }
00153 
00154       width += calc_width(text[q]);
00155       q++;
00156 
00157       if (width > wordwrap_width) {
00158         // Oops, too many.
00159         q--;
00160         overflow = true;
00161         break;
00162       }
00163     }
00164 
00165     if (overflow && any_spaces) {
00166       // If we stopped because we exceeded the wordwrap width, then
00167       // back up to the end of the last complete word.
00168       while (q > p && !isspace((unsigned int)text[q])) {
00169         q--;
00170       }
00171     }
00172 
00173     // Skip additional whitespace between the lines.
00174     size_t next_start = q;
00175     while (next_start < text.length() && isblank(text[next_start])) {
00176       next_start++;
00177     }
00178 
00179     // Trim off any more blanks on the end.
00180     while (q > p && isspace(text[q - 1])) {
00181       q--;
00182     }
00183 
00184     if (next_start == p) {
00185       // No characters got in at all.  This could only happen if the
00186       // wordwrap width is narrower than a single character, or if we
00187       // have a substantial number of leading spaces in a line.
00188       q++;
00189       next_start++;
00190       while (next_start < text.length() && isblank(text[next_start])) {
00191         next_start++;
00192       }
00193     }
00194     
00195     if (needs_newline) {
00196       output_text += '\n';
00197     }
00198     needs_newline = true;
00199 
00200     if (preserve_trailing_whitespace) {
00201       q = next_start;
00202     }
00203     output_text += text.substr(p, q - p);
00204 
00205     // Now prepare to wrap the next line.
00206 
00207     if (next_start < text.length() && text[next_start] == '\n') {
00208       // Preserve a single embedded newline.
00209       output_text += '\n';
00210       next_start++;
00211       needs_newline = false;
00212     }
00213     p = next_start;
00214 
00215     // Preserve any initial whitespace and newlines.
00216     initial_width = 0.0f;
00217     while (p < text.length() && isspace((unsigned int)text[p])) {
00218       if (text[p] == '\n') {
00219         initial_width = 0.0f;
00220       } else {
00221         initial_width += calc_width(text[p]);
00222       }
00223       output_text += text[p];
00224       p++;
00225     }
00226   }
00227 
00228   return output_text;
00229 }
00230 
00231 ////////////////////////////////////////////////////////////////////
00232 //     Function: TextFont::write
00233 //       Access: Published, Virtual
00234 //  Description:
00235 ////////////////////////////////////////////////////////////////////
00236 void TextFont::
00237 write(ostream &out, int indent_level) const {
00238   indent(out, indent_level)
00239     << "TextFont " << get_name() << "\n";
00240 }
00241 
00242 ////////////////////////////////////////////////////////////////////
00243 //     Function: TextFont::calc_width (wide char)
00244 //       Access: Public
00245 //  Description: Returns the width of a line of text of arbitrary
00246 //               characters.  The line should not include the newline
00247 //               character.
00248 ////////////////////////////////////////////////////////////////////
00249 float TextFont::
00250 calc_width(const wstring &line) {
00251   float width = 0.0f;
00252 
00253   wstring::const_iterator si;
00254   for (si = line.begin(); si != line.end(); ++si) {
00255     width += calc_width(*si);
00256   }
00257 
00258   return width;
00259 }
00260 
00261 ////////////////////////////////////////////////////////////////////
00262 //     Function: TextFont::wordwrap_to (wide char)
00263 //       Access: Public
00264 //  Description: Inserts newlines into the given text at the
00265 //               appropriate places in order to make each line be the
00266 //               longest possible line that is not longer than
00267 //               wordwrap_width (and does not break any words, if
00268 //               possible).  Returns the new string.
00269 ////////////////////////////////////////////////////////////////////
00270 wstring TextFont::
00271 wordwrap_to(const wstring &text, float wordwrap_width, 
00272             bool preserve_trailing_whitespace) {
00273   wstring output_text;
00274 
00275   size_t p = 0;
00276 
00277   // Preserve any initial whitespace and newlines.
00278   float initial_width = 0.0f;
00279   while (p < text.length() && isspacew(text[p])) {
00280     if (text[p] == '\n') {
00281       initial_width = 0.0f;
00282     } else {
00283       initial_width += calc_width(text[p]);
00284     }
00285     output_text += text[p];
00286     p++;
00287   }
00288   bool needs_newline = false;
00289 
00290   while (p < text.length()) {
00291     nassertr(!isspacew(text[p]), wstring());
00292 
00293     // Scan the next n characters, until the end of the string or an
00294     // embedded newline character, or we exceed wordwrap_width.
00295 
00296     size_t q = p;
00297     bool any_spaces = false;
00298     bool overflow = false;
00299 
00300     float width = initial_width;
00301     while (q < text.length() && text[q] != '\n') {
00302       if (isspacew(text[q])) {
00303         any_spaces = true;
00304       }
00305 
00306       width += calc_width(text[q]);
00307       q++;
00308 
00309       if (width > wordwrap_width) {
00310         // Oops, too many.
00311         q--;
00312         overflow = true;
00313         break;
00314       }
00315     }
00316     
00317     if (overflow && any_spaces) {
00318       // If we stopped because we exceeded the wordwrap width, then
00319       // back up to the end of the last complete word.
00320       while (q > p && !isspacew(text[q])) {
00321         q--;
00322       }
00323     }
00324 
00325     // Skip additional whitespace between the lines.
00326     size_t next_start = q;
00327     while (next_start < text.length() && isblank(text[next_start])) {
00328       next_start++;
00329     }
00330 
00331     // Trim off any more blanks on the end.
00332     while (q > p && isspacew(text[q - 1])) {
00333       q--;
00334     }
00335 
00336     if (next_start == p) {
00337       // No characters got in at all.  This could only happen if the
00338       // wordwrap width is narrower than a single character, or if we
00339       // have a substantial number of leading spaces in a line.
00340       q++;
00341       next_start++;
00342       while (next_start < text.length() && isblank(text[next_start])) {
00343         next_start++;
00344       }
00345     }
00346     
00347     if (needs_newline) {
00348       output_text += '\n';
00349     }
00350     needs_newline = true;
00351 
00352     if (preserve_trailing_whitespace) {
00353       q = next_start;
00354     }
00355     output_text += text.substr(p, q - p);
00356 
00357     // Now prepare to wrap the next line.
00358 
00359     if (next_start < text.length() && text[next_start] == '\n') {
00360       // Preserve a single embedded newline.
00361       output_text += '\n';
00362       next_start++;
00363       needs_newline = false;
00364     }
00365     p = next_start;
00366 
00367     // Preserve any initial whitespace and newlines.
00368     initial_width = 0.0f;
00369     while (p < text.length() && isspacew(text[p])) {
00370       if (text[p] == '\n') {
00371         initial_width = 0.0f;
00372       } else {
00373         initial_width += calc_width(text[p]);
00374       }
00375       output_text += text[p];
00376       p++;
00377     }
00378   }
00379 
00380   return output_text;
00381 }

Generated on Fri May 2 00:44:18 2003 for Panda by doxygen1.3