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