50b6cf11a11121e3c268c8a4229b3e21f58a968b
[bertos.git] / 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
41 #include "text.h"
42
43 #include <mware/formatwr.h> /* _formatted_write() */
44 #include <gfx/font.h>
45 #include <gfx/gfx.h>
46
47 #include <stdio.h> /* vsprintf() */
48 #include <stdarg.h>
49 #include <string.h> /* strlen() */
50
51 /**
52  * Render string \a str in Bitmap \a bm at current cursor position
53  *
54  * \note Text formatting functions are also available with an _P suffix
55  *       accepting the source string from program memory.  This feature
56  *       is only available (and useful) on Harvard microprocessors such
57  *       as the AVR.
58  *
59  * \see text_putchar()
60  */
61 int PGM_FUNC(text_puts)(const char * PGM_ATTR str, struct Bitmap *bm)
62 {
63         char c;
64
65         while ((c = PGM_READ_CHAR(str++)))
66                 text_putchar(c, bm);
67
68         return 0;
69 }
70
71
72 /**
73  * vprintf()-like formatter to render text in a Bitmap.
74  *
75  * Perform vprintf()-like formatting on the \a fmt format string using the
76  * variable-argument list \a ap.
77  * Render the resulting string in Bitmap \a bm starting at the current
78  * cursor position.
79  *
80  * \see text_puts() text_putchar() text_printf()
81  */
82 int PGM_FUNC(text_vprintf)(struct Bitmap *bm, const char * PGM_ATTR fmt, va_list ap)
83 {
84         return PGM_FUNC(_formatted_write)(fmt, (void (*)(char, void *))text_putchar, bm, ap);
85 }
86
87 /**
88  * printf()-like formatter to render text in a Bitmap.
89  *
90  * Perform printf()-like formatting on the \a fmt format string.
91  * Render the resulting string in Bitmap \a bm starting at the
92  * current cursor position.
93  *
94  * \see text_puts() text_putchar() text_vprintf()
95  */
96 int PGM_FUNC(text_printf)(struct Bitmap *bm, const char * PGM_ATTR fmt, ...)
97 {
98         int len;
99
100         va_list ap;
101         va_start(ap, fmt);
102         len = PGM_FUNC(text_vprintf)(bm, fmt, ap);
103         va_end(ap);
104
105         return len;
106 }
107
108 /**
109  * Render text with vprintf()-like formatting at a specified pixel position.
110  *
111  * \see text_xyprintf()
112  */
113 int PGM_FUNC(text_xyvprintf)(struct Bitmap *bm,
114                 coord_t x, coord_t y, uint16_t style, const char * PGM_ATTR fmt, va_list ap)
115 {
116         int len;
117         uint8_t oldstyle = 0;
118
119         text_setCoord(bm, x, y);
120
121         if (style & STYLEF_MASK)
122                 oldstyle = text_style(bm, style, STYLEF_MASK);
123
124         if (style & (TEXT_CENTER | TEXT_RIGHT))
125         {
126                 uint8_t pad = bm->width - PGM_FUNC(text_vwidthf)(bm, fmt, ap);
127
128                 if (style & TEXT_CENTER)
129                         pad /= 2;
130
131                 if (style & TEXT_FILL)
132                         gfx_rectFillC(bm, 0, y, pad, y + bm->font->height,
133                                 (style & STYLEF_INVERT) ? 0xFF : 0x00);
134
135                 text_setCoord(bm, pad, y);
136         }
137
138         len = PGM_FUNC(text_vprintf)(bm, fmt, ap);
139
140         if (style & TEXT_FILL)
141                 gfx_rectFillC(bm, bm->penX, y, bm->width, y + bm->font->height,
142                         (style & STYLEF_INVERT) ? 0xFF : 0x00);
143
144         /* Restore old style */
145         if (style & STYLEF_MASK)
146                 text_style(bm, oldstyle, STYLEF_MASK);
147
148         return len;
149 }
150
151
152 /**
153  * Render text with printf()-like formatting at a specified pixel position.
154  *
155  * \param bm Bitmap where to render the text
156  * \param x     [pixels] Initial X coordinate of text.
157  * \param y     [pixels] Coordinate of top border of text.
158  * \param style Formatting style to use.  In addition to any STYLEF_
159  *        flag, it can be TEXT_NORMAL, TEXT_FILL, TEXT_INVERT or
160  *        TEXT_RIGHT, or a combination of these flags ORed together.
161  * \param fmt  String possibly containing printf() formatting commands.
162  *
163  * \see text_puts() text_putchar() text_printf() text_vprintf()
164  * \see text_moveTo() text_style()
165  */
166 int PGM_FUNC(text_xyprintf)(struct Bitmap *bm,
167                 coord_t x, coord_t y, uint16_t style, const char * PGM_ATTR fmt, ...)
168 {
169         int len;
170         va_list ap;
171
172         va_start(ap, fmt);
173         len = PGM_FUNC(text_xyvprintf)(bm, x, y, style, fmt, ap);
174         va_end(ap);
175
176         return len;
177 }
178
179
180 /**
181  * Render text with printf()-like formatting at a specified row/column position.
182  *
183  * \see text_xyprintf()
184  */
185 int PGM_FUNC(text_xprintf)(struct Bitmap *bm,
186                 uint8_t row, uint8_t col, uint16_t style, const char * PGM_ATTR fmt, ...)
187 {
188         int len;
189         va_list ap;
190
191         va_start(ap, fmt);
192         len = PGM_FUNC(text_xyvprintf)(
193                         bm, col * bm->font->width, row * bm->font->height,
194                         style, fmt, ap);
195         va_end(ap);
196
197         return len;
198 }
199
200
201 struct TextWidthData
202 {
203         Bitmap *bitmap;
204         coord_t width;
205 };
206
207 /**
208  * Compute width in pixels of a character.
209  *
210  * Compute the on screen width of a character, taking the
211  * current style and font into account.
212  *
213  * The width is accumulated in the WidthData structure
214  * passed as second argument.
215  *
216  * This is a formatted_write() callback used by text_vwidthf()
217  * to compute the length of a formatted string.
218  */
219 static int text_charWidth(int c, struct TextWidthData *twd)
220 {
221         unsigned char index = (unsigned char)c;
222         Bitmap *bm = twd->bitmap;
223         coord_t glyph_width;
224
225
226         if (UNLIKELY(!FONT_HAS_GLYPH(bm->font, index)))
227         {
228                 if (!FONT_HAS_GLYPH(bm->font, '?'))
229                         index = '?';
230                 else
231                         index = bm->font->first;
232         }
233
234         /* Make character relative to font start */
235         index -= bm->font->first;
236
237         if (bm->font->offset)
238                 /* Proportional font */
239                 glyph_width = bm->font->widths[index]; /* TODO: optimize away */
240         else
241                 /* Fixed width font */
242                 glyph_width = bm->font->width;
243
244         if (bm->styles & STYLEF_CONDENSED)
245                 --glyph_width;
246
247         if (bm->styles & STYLEF_EXPANDED)
248                 glyph_width *= 2;
249
250         twd->width += glyph_width;
251
252         return c;
253 }
254
255 /**
256  * Return the width in pixels of a vprintf()-formatted string.
257  */
258 int PGM_FUNC(text_vwidthf)(
259         UNUSED_ARG(struct Bitmap *, bm),
260         const char * PGM_ATTR fmt,
261         va_list ap)
262 {
263         /* Fixed font with no styles affecting the width? */
264         if (!bm->font->offset && !(bm->styles & (STYLEF_CONDENSED | STYLEF_EXPANDED)))
265                 return PGM_FUNC(vsprintf)(NULL, fmt, ap) * bm->font->width;
266         else
267         {
268                 struct TextWidthData twd;
269                 twd.bitmap = bm;
270                 twd.width = 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 }