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