433794add1ff315c1ad817288f000f6dcf8ccc3b
[bertos.git] / gfx / text_format.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 printf-family routines for text output
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.9  2006/04/27 05:39:24  bernie
19  *#* Enhance text rendering to arbitrary x,y coords.
20  *#*
21  *#* Revision 1.8  2006/03/22 09:50:11  bernie
22  *#* Don't use C99 stuff.
23  *#*
24  *#* Revision 1.7  2006/03/20 17:51:55  bernie
25  *#* Cleanups.
26  *#*
27  *#* Revision 1.6  2006/03/13 02:05:54  bernie
28  *#* Mark slow paths as UNLIKELY.
29  *#*
30  *#* Revision 1.5  2006/03/07 22:18:04  bernie
31  *#* Correctly compute text width for prop fonts; Make styles a per-bitmap attribute.
32  *#*
33  *#* Revision 1.4  2006/02/10 12:31:33  bernie
34  *#* Add multiple font support in bitmaps.
35  *#*
36  *#* Revision 1.3  2005/11/27 23:31:58  bernie
37  *#* Reorder includes.
38  *#*
39  *#* Revision 1.2  2005/11/04 18:17:45  bernie
40  *#* Fix header guards and includes for new location of gfx module.
41  *#*
42  *#* Revision 1.1  2005/11/04 18:11:35  bernie
43  *#* Move graphics stuff from mware/ to gfx/.
44  *#*
45  *#* Revision 1.10  2005/11/04 16:20:02  bernie
46  *#* Fix reference to README.devlib in header.
47  *#*
48  *#* Revision 1.9  2004/12/31 17:47:45  bernie
49  *#* Rename UNUSED() to UNUSED_ARG().
50  *#*
51  *#* Revision 1.8  2004/11/16 21:16:56  bernie
52  *#* Update to new naming scheme in mware/gfx.c.
53  *#*
54  *#* Revision 1.7  2004/10/03 19:05:04  bernie
55  *#* text_widthf(), text_vwidthf(): New functions.
56  *#*
57  *#* Revision 1.6  2004/09/14 20:59:04  bernie
58  *#* text_xprintf(): Support all styles; Pixel-wise text centering.
59  *#*
60  *#* Revision 1.5  2004/08/25 14:12:09  rasky
61  *#* Aggiornato il comment block dei log RCS
62  *#*
63  *#* Revision 1.4  2004/08/05 18:46:44  bernie
64  *#* Documentation improvements.
65  *#*
66  *#* Revision 1.3  2004/08/03 15:57:18  aleph
67  *#* Add include to fix warning for vsprintf()
68  *#*
69  *#* Revision 1.2  2004/06/03 11:27:09  bernie
70  *#* Add dual-license information.
71  *#*
72  *#* Revision 1.1  2004/05/23 15:43:16  bernie
73  *#* Import mware modules.
74  *#*
75  *#* Revision 1.2  2004/03/26 18:50:50  bernie
76  *#* Move _PROGMEM stuff to compiler.h
77  *#*
78  *#* Revision 1.1  2004/03/19 16:52:28  bernie
79  *#* Move printf() like functions from text.c to text_format.c and add PROGMEM versions.
80  *#*
81  *#*/
82
83 #include "text.h"
84
85 #include <mware/formatwr.h> /* _formatted_write() */
86 #include <gfx/font.h>
87 #include <gfx/gfx.h>
88
89 #include <stdio.h> /* vsprintf() */
90 #include <stdarg.h>
91 #include <string.h> /* strlen() */
92
93 /*!
94  * Render string \a str in Bitmap \a bm at current cursor position
95  *
96  * \note Text formatting functions are also available with an _P suffix
97  *       accepting the source string from program memory.  This feature
98  *       is only available (and useful) on Harvard microprocessors such
99  *       as the AVR.
100  *
101  * \see text_putchar()
102  */
103 int PGM_FUNC(text_puts)(const char * PGM_ATTR str, struct Bitmap *bm)
104 {
105         char c;
106
107         while ((c = PGM_READ_CHAR(str++)))
108                 text_putchar(c, bm);
109
110         return 0;
111 }
112
113
114 /*!
115  * vprintf()-like formatter to render text in a Bitmap.
116  *
117  * Perform vprintf()-like formatting on the \a fmt format string using the
118  * variable-argument list \a ap.
119  * Render the resulting string in Bitmap \a bm starting at the current
120  * cursor position.
121  *
122  * \see text_puts() text_putchar() text_printf()
123  */
124 int PGM_FUNC(text_vprintf)(struct Bitmap *bm, const char * PGM_ATTR fmt, va_list ap)
125 {
126         return PGM_FUNC(_formatted_write)(fmt, (void (*)(char, void *))text_putchar, bm, ap);
127 }
128
129 /*!
130  * printf()-like formatter to render text in a Bitmap.
131  *
132  * Perform printf()-like formatting on the \a fmt format string.
133  * Render the resulting string in Bitmap \a bm starting at the
134  * current cursor position.
135  *
136  * \see text_puts() text_putchar() text_vprintf()
137  */
138 int PGM_FUNC(text_printf)(struct Bitmap *bm, const char * PGM_ATTR fmt, ...)
139 {
140         int len;
141
142         va_list ap;
143         va_start(ap, fmt);
144         len = PGM_FUNC(text_vprintf)(bm, fmt, ap);
145         va_end(ap);
146
147         return len;
148 }
149
150 /**
151  * Render text with vprintf()-like formatting at a specified pixel position.
152  *
153  * \see text_xyprintf()
154  */
155 int PGM_FUNC(text_xyvprintf)(struct Bitmap *bm,
156                 coord_t x, coord_t y, uint16_t style, const char * PGM_ATTR fmt, va_list ap)
157 {
158         int len;
159         uint8_t oldstyle = 0;
160
161         text_setCoord(bm, x, y);
162
163         if (style & STYLEF_MASK)
164                 oldstyle = text_style(bm, style, STYLEF_MASK);
165
166         if (style & (TEXT_CENTER | TEXT_RIGHT))
167         {
168                 uint8_t pad = bm->width - PGM_FUNC(text_vwidthf)(bm, fmt, ap);
169
170                 if (style & TEXT_CENTER)
171                         pad /= 2;
172
173                 if (style & TEXT_FILL)
174                         gfx_rectFillC(bm, 0, y, pad, y + bm->font->height,
175                                 (style & STYLEF_INVERT) ? 0xFF : 0x00);
176
177                 text_setCoord(bm, pad, y);
178         }
179
180         len = PGM_FUNC(text_vprintf)(bm, fmt, ap);
181
182         if (style & TEXT_FILL)
183                 gfx_rectFillC(bm, bm->penX, y, bm->width, y + bm->font->height,
184                         (style & STYLEF_INVERT) ? 0xFF : 0x00);
185
186         /* Restore old style */
187         if (style & STYLEF_MASK)
188                 text_style(bm, oldstyle, STYLEF_MASK);
189
190         return len;
191 }
192
193
194 /**
195  * Render text with printf()-like formatting at a specified pixel position.
196  *
197  * \param bm Bitmap where to render the text
198  * \param x     [pixels] Initial X coordinate of text.
199  * \param y     [pixels] Coordinate of top border of text.
200  * \param style Formatting style to use.  In addition to any STYLEF_
201  *        flag, it can be TEXT_NORMAL, TEXT_FILL, TEXT_INVERT or
202  *        TEXT_RIGHT, or a combination of these flags ORed together.
203  * \param fmt  String possibly containing printf() formatting commands.
204  *
205  * \see text_puts() text_putchar() text_printf() text_vprintf()
206  * \see text_moveTo() text_style()
207  */
208 int PGM_FUNC(text_xyprintf)(struct Bitmap *bm,
209                 coord_t x, coord_t y, uint16_t style, const char * PGM_ATTR fmt, ...)
210 {
211         int len;
212         va_list ap;
213
214         va_start(ap, fmt);
215         len = PGM_FUNC(text_xyvprintf)(bm, x, y, style, fmt, ap);
216         va_end(ap);
217
218         return len;
219 }
220
221
222 /**
223  * Render text with printf()-like formatting at a specified row/column position.
224  *
225  * \see text_xyprintf()
226  */
227 int PGM_FUNC(text_xprintf)(struct Bitmap *bm,
228                 uint8_t row, uint8_t col, uint16_t style, const char * PGM_ATTR fmt, ...)
229 {
230         int len;
231         va_list ap;
232
233         va_start(ap, fmt);
234         len = PGM_FUNC(text_xyvprintf)(
235                         bm, col * bm->font->width, row * bm->font->height,
236                         style, fmt, ap);
237         va_end(ap);
238
239         return len;
240 }
241
242
243 struct TextWidthData
244 {
245         Bitmap *bitmap;
246         coord_t width;
247 };
248
249 /**
250  * Compute width in pixels of a character.
251  *
252  * Compute the on screen width of a character, taking the
253  * current style and font into account.
254  *
255  * The width is accumulated in the WidthData structure
256  * passed as second argument.
257  *
258  * This is a formatted_write() callback used by text_vwidthf()
259  * to compute the length of a formatted string.
260  */
261 static int text_charWidth(int c, struct TextWidthData *twd)
262 {
263         unsigned char index = (unsigned char)c;
264         Bitmap *bm = twd->bitmap;
265         coord_t glyph_width;
266
267
268         if (UNLIKELY(!FONT_HAS_GLYPH(bm->font, index)))
269         {
270                 if (!FONT_HAS_GLYPH(bm->font, '?'))
271                         index = '?';
272                 else
273                         index = bm->font->first;
274         }
275
276         /* Make character relative to font start */
277         index -= bm->font->first;
278
279         if (bm->font->offset)
280                 /* Proportional font */
281                 glyph_width = bm->font->widths[index]; /* TODO: optimize away */
282         else
283                 /* Fixed width font */
284                 glyph_width = bm->font->width;
285
286         if (bm->styles & STYLEF_CONDENSED)
287                 --glyph_width;
288
289         if (bm->styles & STYLEF_EXPANDED)
290                 glyph_width *= 2;
291
292         twd->width += glyph_width;
293
294         return c;
295 }
296
297 /*!
298  * Return the width in pixels of a vprintf()-formatted string.
299  */
300 int PGM_FUNC(text_vwidthf)(
301         UNUSED_ARG(struct Bitmap *, bm),
302         const char * PGM_ATTR fmt,
303         va_list ap)
304 {
305         /* Fixed font with no styles affecting the width? */
306         if (!bm->font->offset && !(bm->styles & (STYLEF_CONDENSED | STYLEF_EXPANDED)))
307                 return PGM_FUNC(vsprintf)(NULL, fmt, ap) * bm->font->width;
308         else
309         {
310                 struct TextWidthData twd;
311                 twd.bitmap = bm;
312                 twd.width = 0;
313                 _formatted_write(fmt, (void (*)(char, void *))text_charWidth, &twd, ap);
314                 return twd.width;
315         }
316 }
317
318
319 /*!
320  * Return the width in pixels of a printf()-formatted string.
321  */
322 int PGM_FUNC(text_widthf)(struct Bitmap *bm, const char * PGM_ATTR fmt, ...)
323 {
324         int width;
325
326         va_list ap;
327         va_start(ap, fmt);
328         width = PGM_FUNC(text_vwidthf)(bm, fmt, ap);
329         va_end(ap);
330
331         return width;
332 }