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