1 /*
2  * file w32_text.c - drawing strings and boxes
3  *
4  * $Id: w32_text.c,v 1.5 2006/02/19 13:33:01 lodott Exp $
5  *
6  * Program XBLAST
7  * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net)
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published
11  * by the Free Software Foundation; either version 2; or (at your option)
12  * any later version
13  *
14  * This program is distributed in the hope that it will be entertaining,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17  * Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.
21  * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 #include "xblast.h"
24 #include "w32_text.h"
25 #include "gui.h"
26 
27 #include "w32_color.h"
28 #include "w32_image.h"
29 
30 #include "geom.h"
31 
32 /*
33  * local macros
34  */
35 #define COLOR_LIGHT (SET_COLOR(31,29,0))
36 #define COLOR_DARK  (SET_COLOR( 0, 0,0))
37 
38 /*
39  * local types
40  */
41 /* pen types */
42 enum
43 {
44 	PEN_LightThick,
45 	PEN_LightThin,
46 	PEN_DarkThick,
47 	PEN_DarkThin,
48   /*---*/
49 	NUM_PEN
50 };
51 /* brush types */
52 enum
53 {
54 	BRUSH_Light,
55 	BRUSH_Dark,
56   /*---*/
57 	NUM_BRUSH
58 };
59 /* pen init data */
60 typedef struct
61 {
62 	int style;
63 	int width;
64 	XBColor color;
65 } XBInitPen;
66 
67 /*
68  * local variables
69  */
70 static HDC hdcLight;
71 static HDC hdcDark;
72 static HPEN hPen[NUM_PEN];
73 static HBRUSH hBrush[NUM_BRUSH];
74 static HFONT hfont[NUM_FONTS];
75 
76 #ifdef MINI_XBLAST
77 static int fontSize[NUM_FONTS] = {
78 	14, 12, 10
79 };
80 #else
81 static int fontSize[NUM_FONTS] = {
82 	32, 24, 18
83 };
84 #endif
85 static int fontHeight[NUM_FONTS] = {
86 	0, 0, 0
87 };
88 static XBInitPen initPen[NUM_PEN] = {
89 	{PS_SOLID, 3 * BASE_X / 8, COLOR_LIGHT,},
90 	{PS_SOLID, 1, COLOR_LIGHT,},
91 	{PS_SOLID, 3 * BASE_X / 8, COLOR_DARK,},
92 	{PS_SOLID, 1, COLOR_DARK,},
93 };
94 static XBColor initBrush[NUM_BRUSH] = {
95 	COLOR_LIGHT,
96 	COLOR_DARK,
97 };
98 
99 /*
100  * create dc for drwaing textbox
101  */
102 static HDC
CreateTextDC(HDC hdc,HPEN hPen,HBRUSH hBrush,XBColor textColor)103 CreateTextDC (HDC hdc, HPEN hPen, HBRUSH hBrush, XBColor textColor)
104 {
105 	HDC hdcText;
106 
107 	hdcText = CreateCompatibleDC (hdc);
108 	if (NULL == hdcText) {
109 		return NULL;
110 	}
111 	SelectObject (hdcText, hPen);
112 	SelectObject (hdcText, hBrush);
113 	SetTextColor (hdcText, COLOR_TO_COLORREF (textColor));
114 	SetBkMode (hdcText, TRANSPARENT);
115 	SetTextAlign (hdcText, TA_CENTER | TA_TOP);
116 	SetPolyFillMode (hdcText, WINDING);
117 	/* that's all */
118 	return hdcText;
119 }								/* CreateTextDC */
120 
121 /*
122  * library function: InitText
123  * description:      initizialize windows resources for drawingh text
124  * parameters:       none
125  * return value:     XBTrue on success, XBFalse on error
126  */
127 XBBool
InitText(void)128 InitText (void)
129 {
130 	int i;
131 	HDC hdc;
132 	HGDIOBJ old;
133 	SIZE size;
134 
135 	/* initialize fields */
136 	hdcLight = hdcDark = NULL;
137 	memset (hPen, 0, sizeof (hPen));
138 	memset (hBrush, 0, sizeof (hBrush));
139 	memset (hfont, 0, sizeof (hfont));
140 	/* create pens */
141 	for (i = 0; i < NUM_PEN; i++) {
142 		hPen[i] =
143 			CreatePen (initPen[i].style, initPen[i].width, COLOR_TO_COLORREF (initPen[i].color));
144 	}
145 	/* create brushes */
146 	for (i = 0; i < NUM_BRUSH; i++) {
147 		hBrush[i] = CreateSolidBrush (COLOR_TO_COLORREF (initBrush[i]));
148 	}
149 	/* create logical fonts */
150 	hdc = GetDC (window);
151 	for (i = 0; i < NUM_FONTS; i++) {
152 		hfont[i] = CreateFont (fontSize[i], 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
153 							   OUT_DEVICE_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY,
154 							   VARIABLE_PITCH | FF_SWISS, "MS SansSerif");
155 		if (NULL == hfont[i]) {
156 			return XBFalse;
157 		}
158 		/* get default height */
159 		old = SelectObject (hdc, hfont[i]);
160 		GetTextExtentPoint32 (hdc, "Xj", 2, &size);
161 		SelectObject (hdc, old);
162 		fontHeight[i] = size.cy;
163 	}
164 	/* create and config DC for light text */
165 	hdcLight = CreateTextDC (hdc, hPen[PEN_LightThick], hBrush[BRUSH_Dark], COLOR_LIGHT);
166 	/* create and config DC for dark text */
167 	hdcDark = CreateTextDC (hdc, hPen[PEN_DarkThick], hBrush[BRUSH_Light], COLOR_DARK);
168 	/* thats's all */
169 	ReleaseDC (window, hdc);
170 	return XBTrue;
171 }								/* InitText */
172 
173 /*
174  *
175  */
176 void
FinishText(void)177 FinishText (void)
178 {
179 	int i;
180 
181 	/* pens */
182 	for (i = 0; i < NUM_PEN; i++) {
183 		if (NULL != hPen[i]) {
184 			DeleteObject (hPen[i]);
185 		}
186 	}
187 	/* brushes */
188 	for (i = 0; i < NUM_BRUSH; i++) {
189 		if (NULL != hBrush[i]) {
190 			DeleteObject (hBrush[i]);
191 		}
192 	}
193 	/* fonts */
194 	for (i = 0; i < NUM_FONTS; i++) {
195 		if (NULL != hfont[i]) {
196 			DeleteObject (hfont[i]);
197 		}
198 	}
199 	/* device contextes */
200 	if (NULL != hdcLight) {
201 		DeleteDC (hdcLight);
202 	}
203 	if (NULL != hdcDark) {
204 		DeleteDC (hdcDark);
205 	}
206 }								/* FinishText */
207 
208 /*
209  * global function: GUI_DrawSimpleTextbox
210  * description:     draw a text string with optional box
211  * parameters:      text  - 0 terminated string to draw
212  *                  flags - draw mode flags see xblast.h FF_*
213                     rect  - where to draw
214  * return value:    none
215  */
216 void
GUI_DrawSimpleTextbox(const char * text,unsigned flags,const BMRectangle * rect)217 GUI_DrawSimpleTextbox (const char *text, unsigned flags, const BMRectangle * rect)
218 {
219 	HGDIOBJ old;
220 	int len;
221 	int ypos;
222 	int xpos;
223 	HDC hdc;
224 
225 	/* sanity checks */
226 	assert (rect != NULL);
227 	/* get device context */
228 	hdc = (flags & FM_Color) ? hdcLight : hdcDark;
229 	old = SelectObject (hdc, pix);
230 	/* draw boxes */
231 	if (flags & FM_Boxed) {
232 		Rectangle (hdc, rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
233 	}
234 	/* Draw text */
235 	if (text != NULL) {
236 		len = strlen (text);
237 		ypos = rect->y + (rect->h - fontHeight[flags & FM_Size]) / 2;
238 		xpos = rect->x + rect->w / 2;
239 		/* x position */
240 		SetTextAlign (hdcLight, TA_CENTER | TA_TOP);
241 		SetTextAlign (hdcDark, TA_CENTER | TA_TOP);
242 		SelectObject (hdc, hfont[flags & FM_Size]);
243 		ExtTextOut (hdc, xpos, ypos, ETO_OPAQUE, NULL, text, len, NULL);
244 	}
245 	/* clean up */
246 	SelectObject (hdc, old);
247 }								/* GUI_DrawSimpleTextbox */
248 
249 /*
250  *
251  */
252 static int
DrawAlignedText(const char * text,int len,unsigned flags,int x,int y,int w,HDC hdc_fg,HDC hdc_bg,HGDIOBJ * pOld)253 DrawAlignedText (const char *text, int len, unsigned flags, int x, int y, int w, HDC hdc_fg,
254 				 HDC hdc_bg, HGDIOBJ * pOld)
255 {
256 	SIZE textSize;
257 	int xpos;
258 	int dx, dy;
259 	int step;
260 	int right;
261 
262 	assert (text != NULL);
263 	assert (pOld != NULL);
264 	/* Set Font */
265 	SelectObject (hdc_fg, hfont[flags & FM_Size]);
266 	/* determine length */
267 	len++;
268 	do {
269 		len--;
270 		GetTextExtentPoint32 (hdc_fg, text, len, &textSize);
271 	} while (textSize.cx > w - 2 * BASE_X);
272 	/* set text alignment */
273 	switch (flags & FM_Align) {
274 	case FF_Right:
275 		SetTextAlign (hdc_fg, TA_TOP | TA_RIGHT);
276 		SetTextAlign (hdc_bg, TA_TOP | TA_RIGHT);
277 		xpos = x + w - BASE_X;
278 		right = xpos;
279 		break;
280 	case FF_Left:
281 		SetTextAlign (hdc_fg, TA_TOP | TA_LEFT);
282 		SetTextAlign (hdc_bg, TA_TOP | TA_LEFT);
283 		xpos = x + BASE_X;
284 		right = xpos + textSize.cx;
285 		break;
286 	default:
287 		SetTextAlign (hdc_fg, TA_CENTER | TA_TOP);
288 		SetTextAlign (hdc_bg, TA_CENTER | TA_TOP);
289 		xpos = x + w / 2;
290 		right = xpos + textSize.cx / 2;
291 		break;
292 	}
293 	/* out lined output */
294 	if (flags & FM_Outlined) {
295 		/* determine size of outlining */
296 		if ((flags & FM_Size) == FF_Small) {
297 			step = 1;
298 		}
299 		else {
300 			step = BASE_X / 4;
301 		}
302 		SelectObject (hdc_fg, *pOld);
303 		*pOld = SelectObject (hdc_bg, pix);
304 		SelectObject (hdc_bg, hfont[flags & FM_Size]);
305 		for (dx = -step; dx <= step; dx += step) {
306 			for (dy = -step; dy <= step; dy += step) {
307 				if (dx || dy) {
308 					ExtTextOut (hdc_bg, xpos + dx, y + dy, ETO_OPAQUE, NULL, text, len, NULL);
309 				}
310 			}
311 		}
312 		SelectObject (hdc_bg, *pOld);
313 		*pOld = SelectObject (hdc_fg, pix);
314 	}
315 	/* text output */
316 	ExtTextOut (hdc_fg, xpos, y, ETO_OPAQUE, NULL, text, len, NULL);
317 	/* that's all */
318 	return right;
319 }								/* DrawAlignedText */
320 
321 /*
322  * global function: GUI_DrawTextbox
323  * description:     draw a text string with optional box and outlining
324  * parameters:      text  - 0 terminated string to draw
325  *                  flags - draw mode flags see xblast.h FF_*
326                     rect  - where to draw
327  * return value:    none
328  */
329 void
GUI_DrawTextbox(const char * text,unsigned flags,const BMRectangle * rect)330 GUI_DrawTextbox (const char *text, unsigned flags, const BMRectangle * rect)
331 {
332 	HGDIOBJ old;
333 	int len;
334 	int ypos;
335 	HDC hdc;
336 
337 	/* sanity checks */
338 	assert (rect != NULL);
339 	/* get device context */
340 	hdc = (flags & FM_Color) ? hdcLight : hdcDark;
341 	old = SelectObject (hdc, pix);
342 	/* draw boxes */
343 	if (flags & FM_Boxed) {
344 		if (flags & FM_Transparent) {
345 			HGDIOBJ oldPen;
346 			if (flags & FM_Color) {
347 				oldPen = SelectObject (hdc, hPen[PEN_DarkThin]);
348 			}
349 			else {
350 				oldPen = SelectObject (hdc, hPen[PEN_LightThin]);
351 			}
352 			for (ypos = 0; ypos < rect->h; ypos += 2) {
353 				MoveToEx (hdc, rect->x, rect->y + ypos, NULL);
354 				LineTo (hdc, rect->x + rect->w - 1, rect->y + ypos);
355 			}
356 			SelectObject (hdc, oldPen);
357 			MoveToEx (hdc, rect->x, rect->y, NULL);
358 			LineTo (hdc, rect->x + rect->w - 1, rect->y);
359 			LineTo (hdc, rect->x + rect->w - 1, rect->y + rect->h - 1);
360 			LineTo (hdc, rect->x, rect->y + rect->h - 1);
361 			LineTo (hdc, rect->x, rect->y);
362 		}
363 		else {
364 			Rectangle (hdc, rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
365 		}
366 	}
367 	/* Draw text */
368 	if (text != NULL) {
369 		HDC hdcInv;
370 		int right;
371 
372 		len = strlen (text);
373 		ypos = rect->y + (rect->h - fontHeight[flags & FM_Size]) / 2;
374 		hdcInv = (flags & FM_Color) ? hdcDark : hdcLight;
375 		if (flags & FF_Vertical) {
376 			/* vertcial text layout */
377 			int i;
378 			for (i = 0; i < len; i++) {
379 				int h2 = fontHeight[flags & FM_Size];
380 				int y2 = rect->y + ( /*height + */ rect->h) / 2 + (2 * i - len + 1) * (h2) / 2;
381 				right =
382 					DrawAlignedText (text + i, 1, flags, rect->x, y2, rect->w, hdc, hdcInv, &old);
383 			}
384 		}
385 		else {
386 			right = DrawAlignedText (text, len, flags, rect->x, ypos, rect->w, hdc, hdcInv, &old);
387 			/* draw cursor if needed */
388 			if (flags & FF_Cursor) {
389 				MoveToEx (hdc, right + 2, rect->y + 4, NULL);
390 				LineTo (hdc, right + 2, rect->y + rect->h - 5);
391 			}
392 		}
393 	}
394 	/* clean up */
395 	SelectObject (hdc, old);
396 }								/* GUI_DrawTextbox */
397 
398 /*
399  * global function: GUI_DrawPolygon
400  * description:     draw an outlined polygon
401  * parameters:      x           - left side of draw region
402  *                  y           - top side of draw region
403  *                  w           - width of draw region
404  *                  h           - height of draw region
405  *                  lw          - width of outline
406  *                  points      - relative coordinates (0,0 to 1,1)
407  *                  npoints     - number of points
408  *                  black_white - dark or light fill pattern
409  * return value:    none
410  */
411 void
GUI_DrawPolygon(int x,int y,int w,int h,int lw,const BMPoint * points,int npoints,XBBool blackWhite)412 GUI_DrawPolygon (int x, int y, int w, int h, int lw,
413 				 const BMPoint * points, int npoints, XBBool blackWhite)
414 {
415 	int i;
416 	POINT *wp;
417 	HDC hdc;
418 	HGDIOBJ old;
419 
420 	assert (points != NULL);
421 	/* copy points to windows structure */
422 	wp = calloc (sizeof (POINT), npoints + 1);
423 	assert (wp != NULL);
424 	for (i = 0; i < npoints; i++) {
425 		wp[i].x = (LONG) (x + w * points[i].x);
426 		wp[i].y = (LONG) (y + h * points[i].y);
427 	}
428 	wp[npoints] = wp[0];
429 	/* get device context */
430 	hdc = blackWhite ? hdcLight : hdcDark;
431 	old = SelectObject (hdc, pix);
432 	/* draw polygon */
433 	Polygon (hdc, wp, npoints);
434 	/* clean up */
435 	free (wp);
436 	SelectObject (hdc, old);
437 }								/* GUI_DrawPolygon */
438 
439 /*
440  * end of file w32_text.c
441  */
442