Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

text.c

00001 /*
00002  *  text.c - Text handling routinges
00003  *           This file is part of the FreeLCD package.
00004  *
00005  *  $Id: text_8c-source.html,v 1.1 2003/02/16 22:50:41 unicorn Exp $
00006  *
00007  *  This program is free software; you can redistribute it and/or modify it
00008  *  under the terms of the GNU General Public License as published by the
00009  *  Free Software Foundation; either version 2 of the License, or (at your
00010  *  option) any later version.
00011  * 
00012  *  This program is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *  GNU General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU General Public License
00018  *  along with this program; if not, write to the Free Software
00019  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00020  *  MA  02111-1307  USA
00021  *
00022  *  Copyright (c) 2002, 2003, Jeroen van den Berg <unicorn@hippie.nu>
00023  */
00024 
00025 #include <stdlib.h>
00026 #include <string.h>
00027 
00028 #include <common/xmalloc.h>
00029 #include "text.h"
00030 
00031 static char *
00032 _find_position (text_buf * b, int x, int y)
00033 {
00034   return b->buf + y * b->width + x;
00035 }
00036 
00037 static const char *
00038 _find_position_const (const text_buf * b, int x, int y)
00039 {
00040   return b->buf + y * b->width + x;
00041 }
00042 
00043 /*-------------------------------------------------- _check_expand_buf --*/
00044 static void
00045 _check_expand_buf (text_buf * b, int ypos)
00046 {
00047   ++ypos;
00048 
00049   if (b->reserved_h < ypos)
00050     {
00051       b->reserved_h = ypos * 1.5;
00052       b->buf = xrealloc (b->buf, b->width * b->reserved_h);
00053     }
00054 
00055   if (b->height < ypos)
00056     b->height = ypos;
00057 }
00058 
00059 /*-------------------------------------------------------- _cursor_ptr --*/
00060 static char *
00061 _cursor_ptr (text_buf * b)
00062 {
00063   int x = b->cursor_x;
00064 
00065   if (x < 0)
00066     x = 0;
00067 
00068   _check_expand_buf (b, b->cursor_y);
00069 
00070   return _find_position (b, x, b->cursor_y);
00071 }
00072 
00073 /*----------------------------------------------------------- _newline --*/
00074 static void
00075 _newline (text_buf * b)
00076 {
00077   if (b->cursor_x == 0)
00078     return;
00079 
00080   b->cursor_x = 0;
00081   ++b->cursor_y;
00082   _check_expand_buf (b, b->cursor_y);
00083   memset (_cursor_ptr (b), ' ', b->width);
00084 }
00085 
00086 /*------------------------------------------ _find_next_word_delimiter --*/
00087 static const char *
00088 _find_next_word_delimiter (const char *text)
00089 {
00090   while (*text && *text != ' ')
00091     ++text;
00092 
00093   return text;
00094 }
00095 
00096 /*----------------------------------------------------- _is_whitespace --*/
00097 static int
00098 _is_whitespace (const char *p, int step, int count)
00099 {
00100   for (; count; --count, p += step)
00101     {
00102       if (*p != ' ')
00103         return 0;
00104     }
00105 
00106   return 1;
00107 }
00108 
00109 /*---------------------------------------------------- text_buf_malloc --*/
00110 text_buf *
00111 text_buf_malloc (int width, int height)
00112 {
00113   text_buf *new = xmalloc (sizeof (text_buf));
00114 
00115   new->width = width;
00116   new->height = height;
00117   new->reserved_h = height;
00118   new->cursor_x = 0;
00119   new->cursor_y = 0;
00120   new->buf = xmalloc (width * height);
00121   memset (new->buf, ' ', width * height);
00122 
00123   return new;
00124 }
00125 
00126 /*------------------------------------------------------ text_buf_free --*/
00127 void
00128 text_buf_free (text_buf * b)
00129 {
00130   free (b->buf);
00131   free (b);
00132 }
00133 
00134 /*--------------------------------------------------------- text_print --*/
00135 void
00136 text_print (text_buf * b, const char *text)
00137 {
00138   int startpos = b->cursor_x < 0 ? -(b->cursor_x) : 0;
00139   int chars = b->width - startpos;
00140   int len = strlen (text);
00141 
00142   if (b->cursor_y < 0 || b->cursor_x >= b->width || b->cursor_x + len <= 0)
00143     {
00144       /*  The text being printed will never show up inside the buffer,
00145        *  so we can just move the cursor and ignore everything else.
00146        */
00147       b->cursor_x += len;
00148       return;
00149     }
00150 
00151   memcpy (_cursor_ptr (b), text + startpos, chars);
00152 }
00153 
00154 /*---------------------------------------------------- text_print_wrap --*/
00155 void
00156 text_print_wrap (text_buf * b, const char *text)
00157 {
00158   char add_hyphen;
00159   const char *pos;
00160   const char *brk;
00161   int wordlen;
00162 
00163   while (*text)
00164     {
00165       pos = _find_next_word_delimiter (text);
00166       wordlen = pos - text;
00167       add_hyphen = 0;
00168 
00169       /*  If the current word does not fit on this line, consider moving
00170        *  to the next line. This might not be necessary in case the word 
00171        *  is too long to fit on a single line, in that case it will be
00172        *  hyphenated. If it contains a hyphen already, use that one. If
00173        *  not, break it right before the end.
00174        */
00175       if (b->cursor_x + wordlen >= b->width)
00176         {
00177           brk = text + b->width - b->cursor_x - 1;
00178           while (brk > text && *brk != '-')
00179             --brk;
00180 
00181           if (brk > text)
00182             wordlen = brk - text + 1;
00183           else
00184             {
00185               if (wordlen > b->width)
00186                 {
00187                   wordlen = (b->width - b->cursor_x - 1);
00188                   if (wordlen < 4)      /* Don't bother with one or two chars */
00189                     wordlen = 0;
00190                   else
00191                     add_hyphen = 1;
00192 
00193                 }
00194               else
00195                 {
00196                   wordlen = 0;
00197                 }
00198             }
00199         }
00200 
00201       if (wordlen == 0)         /* If nothing fits, move to the next line */
00202         {
00203           _newline (b);
00204         }
00205       else
00206         {
00207           memcpy (_cursor_ptr (b), text, wordlen);
00208           b->cursor_x += wordlen;
00209           if (b->cursor_x < b->width)
00210             {
00211               *(_cursor_ptr (b)) = ' ';
00212               ++b->cursor_x;
00213             }
00214           text += wordlen;
00215           while (*text && *text == ' ') /* Go to beginning of next word */
00216             ++text;
00217         }
00218     }
00219 }
00220 
00221 /*--------------------------------------------- text_add_centered_line --*/
00222 void
00223 text_add_centered_line (text_buf * b, const char *text,
00224                         char filler, char left_end, char right_end)
00225 {
00226   int len = strlen (text);
00227   int space;
00228   int i;
00229   char *p;
00230 
00231   if (len > b->width)
00232     {
00233       text += len / 2;
00234       len = b->width;
00235     }
00236 
00237   space = (b->width - len) / 2;
00238   _newline (b);
00239   p = _cursor_ptr (b);
00240 
00241   for (i = 0; i < space - 1; ++i)
00242     *p++ = filler;
00243   for (; i < space; ++i)
00244     *p++ = left_end;
00245   for (; i < b->width - space; ++i)
00246     *p++ = *text ? *text++ : ' ';
00247   for (; i < b->width - (space - 1); ++i)
00248     *p++ = right_end;
00249   for (; i < b->width; ++i)
00250     *p++ = filler;
00251 
00252   ++b->cursor_x;
00253   _newline (b);
00254 }
00255 
00256 /*--------------------------------------------------- text_copy_region --*/
00257 text_buf *
00258 text_copy_region (const text_buf * b, int x, int y, int w, int h)
00259 {
00260   /* TODO: add extra checks for regions outside buffer bounds */
00261 
00262   text_buf *newbuf = text_buf_malloc (w, h);
00263   const char *src = _find_position_const (b, x, y);
00264   char *dest = newbuf->buf;
00265   int i;
00266 
00267   for (i = 0; i < h; ++i)
00268     {
00269       memcpy (dest, src, w);
00270       dest += w;
00271       src += b->width;
00272     }
00273 
00274   return newbuf;
00275 }
00276 
00277 /*-------------------------------------------------- text_paste_region --*/
00278 void
00279 text_paste_region (text_buf * dest, const text_buf * source, int x, int y)
00280 {
00281   /* TODO: add extra checks for regions outside buffer bounds */
00282 
00283   const char *sbuf = source->buf;
00284   char *dbuf = _find_position (dest, x, y);
00285   int i;
00286 
00287   for (i = 0; i < source->height; ++i)
00288     {
00289       memcpy (dbuf, sbuf, source->width);
00290       sbuf += source->width;
00291       dbuf += dest->width;
00292     }
00293 }
00294 
00295 /*---------------------------------------------------------- text_crop --*/
00296 void
00297 text_crop (text_buf * b, int top, int bottom, int left, int right)
00298 {
00299   char *src = _find_position (b, top, left);
00300   char *dest = b->buf;
00301   int new_width = b->width - (left + right);
00302   int new_height = b->height - (top + bottom);
00303   int i;
00304 
00305   for (i = 0; i < new_height; ++i)
00306     {
00307       memcpy (dest, src, new_width);
00308       src += new_width;
00309       dest += b->width;
00310     }
00311 
00312   b->buf = xrealloc (b->buf, new_width * new_height);
00313   b->width = new_width;
00314   b->height = new_height;
00315   b->reserved_h = new_height;
00316   b->cursor_x = 0;
00317   b->cursor_y = 0;
00318 }
00319 
00320 /*------------------------------------------------------ text_autocrop --*/
00321 void
00322 text_autocrop (text_buf * b)
00323 {
00324   int top = 0;
00325   int bottom = 0;
00326   int left = 0;
00327   int right = 0;
00328   int size = b->width * b->height;
00329 
00330   if (size == 0)
00331     return;
00332 
00333   /*  Use the _is_whitespace helper function to find horizontal lines
00334    *  of whitespace at the top and bottom of the buffer. Move down (or
00335    *  up in the case of "bottom") until a non-whitespace line is found.
00336    */
00337   while (top < b->height
00338          && _is_whitespace (_find_position_const (b, top, 0), 1, b->width))
00339     {
00340       ++top;
00341     }
00342 
00343   while (bottom < b->height - top
00344          &&
00345          _is_whitespace (_find_position_const (b, b->height - bottom - 1, 0),
00346                          1, b->width))
00347     {
00348       ++bottom;
00349     }
00350 
00351   /*  Same thing, but for left and right sides. Instead of the value 1,
00352    *  the buffer width is now passed as the step size to _is_whitespace,
00353    *  so a vertical line is checked. Also, the previously found top and
00354    *  bottom values are used here to restrict the searched area.
00355    */
00356   while (left < b->width
00357          && _is_whitespace (_find_position_const (b, top, left), b->width,
00358                             b->height - (top + bottom)))
00359     {
00360       ++left;
00361     }
00362 
00363   while (right < b->width - left
00364          && _is_whitespace (_find_position_const (b, top + 1, -right + 1),
00365                             b->width, b->height - (top + bottom)))
00366     {
00367       ++right;
00368     }
00369 
00370   text_crop (b, top, bottom, left, right);
00371 }

Generated on Sun Feb 16 23:39:49 2003 for FreeLCD by doxygen1.2.18