Make more generic and adapt to new gfx functions.
[bertos.git] / mware / text.c
1 /*!
2  * \file
3  * <!--
4  * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
5  * Copyright 1999 Bernardo Innocenti <bernie@develer.com>
6  * This file is part of DevLib - See devlib/README for information.
7  * -->
8  *
9  * \version $Id$
10  *
11  * \author Bernardo Innocenti <bernie@develer.com>
12  * \author Stefano Fedrigo <aleph@develer.com>
13  *
14  * \brief Text graphic routines
15  */
16
17 /*#*
18  *#* $Log$
19  *#* Revision 1.5  2004/09/06 21:51:26  bernie
20  *#* Extend interface to allow any algorithmic style.
21  *#*
22  *#* Revision 1.2  2004/06/03 11:27:09  bernie
23  *#* Add dual-license information.
24  *#*
25  *#* Revision 1.1  2004/05/23 15:43:16  bernie
26  *#* Import mware modules.
27  *#*
28  *#* Revision 1.17  2004/05/15 16:57:01  aleph
29  *#* Fixes for non-DEBUG build
30  *#*
31  *#* Revision 1.16  2004/04/03 20:42:49  aleph
32  *#* Add text_clear()
33  *#*
34  *#* Revision 1.15  2004/03/24 15:03:45  bernie
35  *#* Use explicit include paths; clean Doxygen comments
36  *#*
37  *#* Revision 1.14  2004/03/19 16:52:28  bernie
38  *#* Move printf() like functions from text.c to text_format.c and add PROGMEM versions.
39  *#*
40  *#* Revision 1.13  2004/03/17 18:23:32  bernie
41  *#* Oops.
42  *#*
43  *#* Revision 1.12  2004/03/17 18:03:22  bernie
44  *#* Make diagnostic message shorter
45  *#*
46  *#* Revision 1.11  2004/03/13 22:52:54  aleph
47  *#* documentation fixes
48  *#*/
49
50 #include "gfx.h"
51 #include "font.h"
52 #include "text.h"
53 #include <drv/kdebug.h>
54
55 /*!
56  * Flags degli stili algoritmici
57  *
58  * La routine di rendering del testo e' in grado di applicare
59  * delle semplici trasformazioni al font interno per generare
60  * automaticamente degli stili predefiniti (bold, italic,
61  * underline) a partire dal set di caratteri plain.
62  */
63 static uint8_t text_styles;
64
65 /*! ANSI escape sequences flag: true for ESC state on */
66 static bool ansi_mode = false;
67
68
69 /*!
70  * Move (imaginary) cursor to column and row specified.
71  * Next text write will start a that row and col.
72  */
73 void text_moveto(struct Bitmap *bm, int row, int col)
74 {
75         ASSERT(col >= 0);
76         ASSERT(col < bm->width / FONT_WIDTH);
77         ASSERT(row >= 0);
78         ASSERT(row < bm->height / FONT_HEIGHT);
79
80         bm->penX = col * FONT_WIDTH;
81         bm->penY = row * FONT_HEIGHT;
82 }
83
84
85 /*!
86  * Move (imaginary) cursor to coordinates specified.
87  */
88 void text_setcoord(struct Bitmap *bm, int x, int y)
89 {
90         bm->penX = x;
91         bm->penY = y;
92 }
93
94
95 /*!
96  * Render char \a c on Bitmap \a bm
97  */
98 static int text_putglyph(char c, struct Bitmap *bm)
99 {
100         const uint8_t * PROGMEM glyph;  /* font is in progmem */
101         uint8_t glyph_width;
102         uint8_t i;
103         uint8_t *buf;
104
105         /*
106          * Il carattere da stampare viene usato come indice per prelevare
107          * la prima colonna di dots del glyph all'interno del font.
108          */
109         glyph = font + (((unsigned char)c) * FONT_WIDTH);
110         glyph_width = FONT_WIDTH;
111
112         if (text_styles & STYLEF_CONDENSED)
113                 --glyph_width;
114
115         if (text_styles & STYLEF_EXPANDED)
116                 glyph_width *= 2;
117
118         /* The y coord is rounded at multiples of 8 for simplicity */
119         bm->penY &= ~((coord_t)7);
120
121         /* Check if glyph to write fits in the bitmap */
122         if ((bm->penX < 0) || (bm->penX + glyph_width > bm->width) ||
123                 (bm->penY < 0) || (bm->penY + FONT_HEIGHT > bm->height))
124         {
125                 DB(kprintf("bad coords x=%d y=%d\n", bm->penX, bm->penY);)
126                 return 0;
127         }
128
129         /* Locate position where to write in the raster */
130         buf = bm->raster + bm->penY / 8 * bm->width + bm->penX;
131
132         bm->penX += glyph_width;
133
134         /* If some styles are set */
135         if (text_styles)
136         {
137                 uint8_t prev_dots = 0, italic_prev_dots = 0, new_dots;
138                 uint8_t dots;
139
140                 /* Per ogni colonna di dot del glyph... */
141                 for (i = 0; i < glyph_width; ++i)
142                 {
143                         dots = pgm_read_byte(glyph);
144
145                         /* Advance to next column in glyph.
146                          * Expand: advances only once every two columns
147                          */
148                         if (!(text_styles & STYLEF_EXPANDED) || (i & 1))
149                                 glyph++;
150
151                         /* Italic: get lower 4 dots from previous column */
152                         if (text_styles & STYLEF_ITALIC)
153                         {
154                                 new_dots = dots;
155                                 dots = (dots & 0xF0) | italic_prev_dots;
156                                 italic_prev_dots = new_dots & 0x0F;
157                         }
158
159                         /* Bold: "or" pixels with the previous column */
160                         if (text_styles & STYLEF_BOLD)
161                         {
162                                 new_dots = dots;
163                                 dots |= prev_dots;
164                                 prev_dots = new_dots;
165                         }
166
167                         /* Underlined: turn on base pixel */
168                         if (text_styles & STYLEF_UNDERLINE)
169                                 dots |= 0x80;
170
171                         /* Inverted: invert pixels */
172                         if (text_styles & STYLEF_INVERT)
173                                 dots = ~dots;
174
175                         /* Output dots */
176                         *buf++ = dots;
177                 }
178         }
179         else /* No style: fast vanilla copy of glyph to line buffer */
180                 while (glyph_width--)
181                         *buf++ = pgm_read_byte(glyph++);
182
183         return c;
184 }
185
186
187 /*!
188  * Render char \c c, with (currently) limited ANSI escapes
189  * emulation support and '\n' for newline.
190  */
191 int text_putchar(char c, struct Bitmap *bm)
192 {
193         /* Handle ANSI escape sequences */
194         if (ansi_mode)
195         {
196                 switch (c)
197                 {
198                 case ANSI_ESC_CLEARSCREEN:
199                         gfx_ClearBitmap(bm);
200                         bm->penX = 0;
201                         bm->penY = 0;
202                         text_style(0, STYLEF_MASK);
203                         break;
204                 DB(default:
205                         kprintf("Unknown ANSI esc code: %x\n", c);)
206                 }
207                 ansi_mode = false;
208         }
209         else if (c == '\033')  /* Enter ANSI ESC mode */
210         {
211                 ansi_mode = true;
212         }
213         else if (c == '\n')  /* Go one line down on a line-feed */
214         {
215                 if (bm->penY + FONT_HEIGHT < bm->height)
216                 {
217                         bm->penY += FONT_HEIGHT;
218                         bm->penX = 0;
219                 }
220         }
221         else
222         {
223                 text_putglyph(c, bm);
224         }
225         return c;
226 }
227
228
229 /*!
230  * Clear the screen and reset cursor position
231  */
232 void text_clear(struct Bitmap *bmp)
233 {
234         text_putchar('\x1b', bmp);
235         text_putchar('c', bmp);
236 }
237
238
239 void text_clearLine(struct Bitmap *bmp, int line)
240 {
241         gfx_ClearRect(bmp, 0, line * FONT_HEIGHT, bmp->width, (line + 1) * FONT_HEIGHT);
242 }
243
244
245 /*!
246  * Set/clear algorithmic font style bits.
247  *
248  * \param flags  Style flags to set
249  * \param mask   Mask of flags to modify
250  * \return       Old style flags
251  *
252  * Examples:
253  * Turn on bold, leave other styles alone
254  *   \code prt_style(STYLEF_BOLD, STYLEF_BOLD); \endcode
255  *
256  * Turn off bold and turn on italic, leave others as they are
257  *   \code prt_style(STYLEF_ITALIC, STYLEF_BOLD | STYLEF_ITALIC); \endcode
258  *
259  * Query current style without chaning it
260  *   \code style = prt_style(0, 0); \endcode
261  *
262  * Reset all styles (plain text)
263  *   \code prt_style(0, STYLE_MASK); \endcode
264  */
265 uint8_t text_style(uint8_t flags, uint8_t mask)
266 {
267         uint8_t old = text_styles;
268         text_styles = (text_styles & ~mask) | flags;
269         return old;
270 }