Release version 2.5.1.
[bertos.git] / 2.5 / bertos / gfx / text_format.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
30  * Copyright 1999 Bernie Innocenti <bernie@codewiz.org>
31  *
32  * -->
33  *
34  * \version $Id$
35  * \author Bernie Innocenti <bernie@codewiz.org>
36  * \author Stefano Fedrigo <aleph@develer.com>
37  *
38  * \brief printf-family routines for text output
39  *
40  * $WIZ$ module_name = "text_format"
41  * $WIZ$ module_depends = "sprintf", "formatwr", "text"
42  * $WIZ$ module_harvard = "both"
43  */
44
45 #include "text.h"
46
47 #include <mware/formatwr.h> /* _formatted_write() */
48 #include <gfx/font.h>
49 #include <gfx/gfx.h>
50
51 #include <stdio.h> /* vsprintf() */
52 #include <stdarg.h>
53 #include <string.h> /* strlen() */
54
55 /**
56  * Render string \a str in Bitmap \a bm at current cursor position
57  *
58  * \note Text formatting functions are also available with an _P suffix
59  *       accepting the source string from program memory.  This feature
60  *       is only available (and useful) on Harvard microprocessors such
61  *       as the AVR.
62  *
63  * \see text_putchar()
64  */
65 int PGM_FUNC(text_puts)(const char * PGM_ATTR str, struct Bitmap *bm)
66 {
67         char c;
68
69         while ((c = PGM_READ_CHAR(str++)))
70                 text_putchar(c, bm);
71
72         return 0;
73 }
74
75
76 /**
77  * vprintf()-like formatter to render text in a Bitmap.
78  *
79  * Perform vprintf()-like formatting on the \a fmt format string using the
80  * variable-argument list \a ap.
81  * Render the resulting string in Bitmap \a bm starting at the current
82  * cursor position.
83  *
84  * \see text_puts() text_putchar() text_printf()
85  */
86 int PGM_FUNC(text_vprintf)(struct Bitmap *bm, const char * PGM_ATTR fmt, va_list ap)
87 {
88         return PGM_FUNC(_formatted_write)(fmt, (void (*)(char, void *))text_putchar, bm, ap);
89 }
90
91 /**
92  * printf()-like formatter to render text in a Bitmap.
93  *
94  * Perform printf()-like formatting on the \a fmt format string.
95  * Render the resulting string in Bitmap \a bm starting at the
96  * current cursor position.
97  *
98  * \see text_puts() text_putchar() text_vprintf()
99  */
100 int PGM_FUNC(text_printf)(struct Bitmap *bm, const char * PGM_ATTR fmt, ...)
101 {
102         int len;
103
104         va_list ap;
105         va_start(ap, fmt);
106         len = PGM_FUNC(text_vprintf)(bm, fmt, ap);
107         va_end(ap);
108
109         return len;
110 }
111
112 /**
113  * Render text with vprintf()-like formatting at a specified pixel position.
114  *
115  * \see text_xyprintf()
116  */
117 int PGM_FUNC(text_xyvprintf)(struct Bitmap *bm,
118                 coord_t x, coord_t y, uint16_t style, const char * PGM_ATTR fmt, va_list ap)
119 {
120         int len;
121         uint8_t oldstyle = 0;
122
123         text_setCoord(bm, x, y);
124
125         if (style & STYLEF_MASK)
126                 oldstyle = text_style(bm, style, STYLEF_MASK);
127
128         if (style & (TEXT_CENTER | TEXT_RIGHT))
129         {
130                 uint8_t pad = bm->width - PGM_FUNC(text_vwidthf)(bm, fmt, ap);
131
132                 if (style & TEXT_CENTER)
133                         pad /= 2;
134
135                 if (style & TEXT_FILL)
136                         gfx_rectFillC(bm, 0, y, pad, y + bm->font->height,
137                                 (style & STYLEF_INVERT) ? 0xFF : 0x00);
138
139                 text_setCoord(bm, pad, y);
140         }
141
142         len = PGM_FUNC(text_vprintf)(bm, fmt, ap);
143
144         if (style & TEXT_FILL)
145                 gfx_rectFillC(bm, bm->penX, y, bm->width, y + bm->font->height,
146                         (style & STYLEF_INVERT) ? 0xFF : 0x00);
147
148         /* Restore old style */
149         if (style & STYLEF_MASK)
150                 text_style(bm, oldstyle, STYLEF_MASK);
151
152         return len;
153 }
154
155
156 /**
157  * Render text with printf()-like formatting at a specified pixel position.
158  *
159  * \param bm Bitmap where to render the text
160  * \param x     [pixels] Initial X coordinate of text.
161  * \param y     [pixels] Coordinate of top border of text.
162  * \param style Formatting style to use.  In addition to any STYLEF_
163  *        flag, it can be TEXT_NORMAL, TEXT_FILL, TEXT_INVERT or
164  *        TEXT_RIGHT, or a combination of these flags ORed together.
165  * \param fmt  String possibly containing printf() formatting commands.
166  *
167  * \see text_puts() text_putchar() text_printf() text_vprintf()
168  * \see text_moveTo() text_style()
169  */
170 int PGM_FUNC(text_xyprintf)(struct Bitmap *bm,
171                 coord_t x, coord_t y, uint16_t style, const char * PGM_ATTR fmt, ...)
172 {
173         int len;
174         va_list ap;
175
176         va_start(ap, fmt);
177         len = PGM_FUNC(text_xyvprintf)(bm, x, y, style, fmt, ap);
178         va_end(ap);
179
180         return len;
181 }
182
183
184 /**
185  * Render text with printf()-like formatting at a specified row/column position.
186  *
187  * \see text_xyprintf()
188  */
189 int PGM_FUNC(text_xprintf)(struct Bitmap *bm,
190                 uint8_t row, uint8_t col, uint16_t style, const char * PGM_ATTR fmt, ...)
191 {
192         int len;
193         va_list ap;
194
195         va_start(ap, fmt);
196         len = PGM_FUNC(text_xyvprintf)(
197                         bm, col * bm->font->width, row * bm->font->height,
198                         style, fmt, ap);
199         va_end(ap);
200
201         return len;
202 }
203
204
205 struct TextWidthData
206 {
207         Bitmap *bitmap;
208         coord_t width;
209 };
210
211 /**
212  * Compute width in pixels of a character.
213  *
214  * Compute the on screen width of a character, taking the
215  * current style and font into account.
216  *
217  * The width is accumulated in the WidthData structure
218  * passed as second argument.
219  *
220  * This is a formatted_write() callback used by text_vwidthf()
221  * to compute the length of a formatted string.
222  */
223 static int text_charWidth(int c, struct TextWidthData *twd)
224 {
225         unsigned char index = (unsigned char)c;
226         Bitmap *bm = twd->bitmap;
227         coord_t glyph_width;
228
229
230         if (UNLIKELY(!FONT_HAS_GLYPH(bm->font, index)))
231         {
232                 if (!FONT_HAS_GLYPH(bm->font, '?'))
233                         index = '?';
234                 else
235                         index = bm->font->first;
236         }
237
238         /* Make character relative to font start */
239         index -= bm->font->first;
240
241         if (bm->font->offset)
242                 /* Proportional font */
243                 glyph_width = bm->font->widths[index]; /* TODO: optimize away */
244         else
245                 /* Fixed width font */
246                 glyph_width = bm->font->width;
247
248         if (bm->styles & STYLEF_CONDENSED)
249                 --glyph_width;
250
251         if (bm->styles & STYLEF_EXPANDED)
252                 glyph_width *= 2;
253
254         twd->width += glyph_width;
255
256         return c;
257 }
258
259 /**
260  * Return the width in pixels of a vprintf()-formatted string.
261  */
262 int PGM_FUNC(text_vwidthf)(
263         UNUSED_ARG(struct Bitmap *, bm),
264         const char * PGM_ATTR fmt,
265         va_list ap)
266 {
267         /* Fixed font with no styles affecting the width? */
268         if (!bm->font->offset && !(bm->styles & (STYLEF_CONDENSED | STYLEF_EXPANDED)))
269                 return PGM_FUNC(vsprintf)(NULL, fmt, ap) * bm->font->width;
270         else
271         {
272                 struct TextWidthData twd;
273                 twd.bitmap = bm;
274                 twd.width = 0;
275                 _formatted_write(fmt, (void (*)(char, void *))text_charWidth, &twd, ap);
276                 return twd.width;
277         }
278 }
279
280
281 /**
282  * Return the width in pixels of a printf()-formatted string.
283  */
284 int PGM_FUNC(text_widthf)(struct Bitmap *bm, const char * PGM_ATTR fmt, ...)
285 {
286         int width;
287
288         va_list ap;
289         va_start(ap, fmt);
290         width = PGM_FUNC(text_vwidthf)(bm, fmt, ap);
291         va_end(ap);
292
293         return width;
294 }