1 /*
2 * GraphApp - Cross-Platform Graphics Programming Library.
3 *
4 * File: drawtext.c -- cross-platform portable drawing functions.
5 * Platform: Neutral Version: 2.30 Date: 1998/01/01
6 *
7 * Version: 1.00 Changes: Original version by Lachlan Patrick.
8 * Version: 1.50 Changes: gprintf now has internal state.
9 * Version: 1.60 Changes: Major bugfixes!
10 * Version: 2.00 Changes: Update to version 2.
11 * Version: 2.01 Changes: Changed unnecessary longs to ints.
12 * Version: 2.20 Changes: Added underlining ability.
13 * Version: 2.30 Changes: Now uses getheight, getdescent.
14 */
15
16 /* Copyright (C) 1993-1998 Lachlan Patrick
17
18 This file is part of GraphApp, a cross-platform C graphics library.
19
20 GraphApp is free software; you can redistribute it and/or modify it
21 under the terms of the GNU Library General Public License.
22 GraphApp is distributed in the hope that it will be useful, but
23 WITHOUT ANY WARRANTY.
24
25 See the file COPYLIB.TXT for details.
26 */
27
28 #include "internal.h"
29 #include <stdarg.h>
30
31 #define COMPRESS_WHITESPACE 0
32
get_next_line(char * line,int width,const char * s)33 static const char *get_next_line(char *line, int width, const char *s)
34 {
35 const char *t; char *k;
36 int word_width, line_width;
37 int sp, tab, nl;
38
39 line_width = 0;
40
41 for (t=s, k=line; *t!='\0'; line=k, s=t)
42 {
43 for (nl=tab=sp=0; (*t!='\0') && isspace(*t) && !nl; t++)
44 {
45 #if COMPRESS_WHITESPACE
46 if (*t == '\n') nl++;
47 else if (*t == '\t') tab++;
48 else sp++;
49 #else
50 if (*t == '\n') nl++;
51 else if (*t == '\t') { /* expand tabs */
52 for (tab=4; tab; tab--)
53 *k++ = ' ';
54 }
55 else
56 *k++ = *t;
57 #endif
58 }
59
60 s = t;
61
62 if (nl) { *k++ = '\n'; break; }
63 else if (tab) { *k++ = ' '; *k++ = ' '; }
64 else if (sp) { *k++ = ' '; }
65
66 /* fetch the next word to draw */
67
68 for (*k='\0'; (*t!='\0') && !isspace(*t); *k='\0') {
69 if (*t == '-') {
70 *k++ = *t++;
71 *k = '\0';
72 break;
73 }
74 *k++ = *t++;
75 }
76
77 /* determine where the word should be drawn */
78
79 while (((word_width = strwidth(current->fnt,line)) > width)
80 && (k>line))
81 {
82 *(--k) = '\0';
83 --t;
84 }
85
86 if (word_width > (width - line_width)) {
87 k = line;
88 break;
89 } else
90 line_width += word_width;
91 }
92
93 *k = '\0';
94
95 return (*s == '\0') ? NULL : s;
96 }
97
textheight(int width,const char * s)98 int textheight(int width, const char *s)
99 {
100 int y;
101 char line[256];
102 int height;
103
104 height = getheight(current->fnt);
105
106 for(y=0; s; y+=height)
107 {
108 s = get_next_line(line, width, s);
109 }
110
111 return y;
112 }
113
draw_text_left(char * line,rect r,int line_height,int underline,const char * s)114 static const char *draw_text_left(char *line, rect r, int line_height,
115 int underline, const char *s)
116 {
117 char *k;
118 point p;
119 int width, height;
120 font f;
121
122 f = current->fnt;
123
124 for(p=pt(r.x,r.y); (p.y<=r.y+r.height) && (s); p.y+=line_height)
125 {
126 s = get_next_line(line, r.width, s);
127
128 for (k=line; *k!='\0'; k++)
129 continue;
130 for (--k; (k>=line) && isspace(*k); k--)
131 *k = '\0';
132
133 drawstr(p, line);
134
135 if (underline) {
136 width = strwidth(f, line);
137 height = p.y+getheight(f)-getdescent(f)+2;
138 drawline(pt(p.x+1, height), pt(p.x+width-1, height));
139 }
140 }
141
142 return s;
143 }
144
draw_text_right(char * line,rect r,int line_height,int underline,const char * s)145 static const char *draw_text_right(char *line, rect r, int line_height,
146 int underline, const char *s)
147 {
148 char *k;
149 int w;
150 point p;
151 int width, height;
152 font f;
153
154 f = current->fnt;
155
156 for(p=pt(r.x,r.y); (p.y<=r.y+r.height) && (s); p.y+=line_height)
157 {
158 s = get_next_line(line, r.width, s);
159
160 for (k=line; *k!='\0'; k++)
161 continue;
162 for (--k; (k>=line) && isspace(*k); k--)
163 *k = '\0';
164 for (k=line; (*k!='\0') && isspace(*k); k++)
165 continue;
166
167 w = strwidth(current->fnt, k);
168 p.x = r.x+r.width - w;
169
170 drawstr(p, k);
171
172 if (underline) {
173 width = strwidth(f, k);
174 height = p.y+getheight(f)-getdescent(f)+2;
175 drawline(pt(p.x+1, height), pt(p.x+width-1, height));
176 }
177 }
178
179 return s;
180 }
181
draw_text_centered(char * line,rect r,int line_height,int underline,const char * s)182 static const char *draw_text_centered(char *line, rect r, int line_height,
183 int underline, const char *s)
184 {
185 char *k;
186 int w;
187 point p;
188 int width, height;
189 font f;
190
191 f = current->fnt;
192
193 for(p=pt(r.x,r.y); (p.y<=r.y+r.height) && (s); p.y+=line_height)
194 {
195 s = get_next_line(line, r.width, s);
196
197 for (k=line; *k!='\0'; k++)
198 continue;
199 for (--k; (k>=line) && isspace(*k); k--)
200 *k = '\0';
201 for(k=line; (*k!='\0') && isspace(*k); k++)
202 continue;
203
204 w = strwidth(current->fnt, k);
205 p.x = r.x + (r.width-w)/2;
206
207 drawstr(p, k);
208
209 if (underline) {
210 width = strwidth(f, k);
211 height = p.y+getheight(f)-getdescent(f)+2;
212 drawline(pt(p.x+1, height), pt(p.x+width-1, height));
213 }
214 }
215
216 return s;
217 }
218
draw_text_justified(char * line,rect r,int line_height,int underline,const char * s)219 static const char *draw_text_justified(char *line, rect r, int line_height,
220 int underline, const char *s)
221 {
222 char *j, *k;
223 int w, xw, nl, sc, sw, space_width;
224 point p;
225 int width, height;
226 font f;
227
228 space_width = strwidth(current->fnt, " ");
229 f = current->fnt;
230
231 for(p=pt(r.x,r.y); (p.y<=r.y+r.height) && (s); p.y+=line_height)
232 {
233 s = get_next_line(line, r.width, s);
234
235 p.x = r.x;
236
237 for(j=line; (*j!='\0') && isspace(*j); j++)
238 p.x += space_width;
239 for (sc=0, k=j; *k!='\0'; k++)
240 if (isspace(*k))
241 sc++;
242 for (nl=0, --k; (k>=j) && isspace(*k); k--) {
243 if (*k == '\n')
244 nl++;
245 *k = '\0';
246 sc--;
247 }
248
249 if ((sc==0) || nl || (! s)) {
250 drawstr(p, j);
251 width = strwidth(f, j);
252 }
253 else {
254 w = strwidth(f, j);
255 sw = space_width + (r.x+r.width-p.x-w)/sc;
256 xw = (r.x+r.width-p.x-w)%sc;
257
258 for(j=strtok(j," "); j; j=strtok(NULL," "))
259 {
260 drawstr(p, j);
261 p.x += sw + strwidth(f, j);
262 if (xw) {
263 p.x++;
264 xw--;
265 }
266 }
267 width = r.width;
268 }
269 if (underline) {
270 height = p.y+getheight(f)-getdescent(f)+2;
271 drawline(pt(p.x+1, height), pt(p.x+width-1, height));
272 }
273 }
274
275 return s;
276 }
277
drawtext(rect r,int alignment,const char * s)278 const char *drawtext(rect r, int alignment, const char *s)
279 {
280 int h;
281 int nlines;
282 int line_height;
283 int u = 0;
284 rect clip;
285 const char *remains;
286 char line[256];
287
288 initapp(0,0);
289 if (! s) return (char *) NULL;
290 if (! current->fnt)
291 current->fnt = SystemFont;
292
293 clip = getcliprect();
294 setcliprect(r);
295
296 line_height = getheight(current->fnt);
297
298 if ((alignment & VCenter) == VCenter) {
299 h = textheight(r.width, s);
300 if (h < r.height)
301 r.y += (r.height-h)/2;
302 }
303 else if ((alignment & VJustify) == VJustify) {
304 h = textheight(r.width, s);
305 if (h < r.height) {
306 nlines = h / line_height;
307 if (nlines > 1)
308 line_height += ((r.height-h) / (nlines-1));
309 }
310 }
311 else if ((alignment & AlignBottom) == AlignBottom) {
312 h = textheight(r.width, s);
313 if (h < r.height)
314 r.y += (r.height-h);
315 }
316
317 u = (alignment & Underline);
318
319 if ((alignment & Center) == Center)
320 remains = draw_text_centered(line, r, line_height, u, s);
321 else if ((alignment & Justify) == Justify)
322 remains = draw_text_justified(line, r, line_height, u, s);
323 else if ((alignment & AlignRight) == AlignRight)
324 remains = draw_text_right(line, r, line_height, u, s);
325 else
326 remains = draw_text_left(line, r, line_height, u, s);
327
328 setcliprect(clip);
329 return remains;
330 }
331
gprintf(const char * fmt,...)332 int gprintf(const char *fmt, ...)
333 {
334 static point p = {0,0};
335 int count;
336 int line_height;
337 char *s, *t;
338 va_list argptr;
339 char str[256];
340
341 va_start(argptr, fmt);
342 count = vsprintf(str, fmt, argptr);
343
344 initapp(0,0);
345 if (! current->fnt)
346 current->fnt = SystemFont;
347 line_height = getheight(current->fnt);
348
349 for (s=t=str; *s!='\0'; t++) {
350 if (current->p.y != p.y) {
351 /* typewriter ping! */
352 p = current->p;
353 }
354 if (*t == '\n') {
355 /* print everything from s to t and move point down */
356 *t = '\0';
357 drawstr(p, s);
358 current->p.y += line_height;
359 /* go past the substring just printed */
360 s = t+1;
361 }
362 else if (*t == '\0') {
363 /* print final string without newline */
364 p.x += drawstr(p, s);
365 /* go to end of string, signal termination */
366 s = t;
367 }
368 }
369
370 va_end(argptr);
371
372 return count;
373 }
374