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