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