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