1/*
2 * Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Mikael Konradson, mikael.konradson@gmail.com
7 */
8
9
10#include "FontDemoView.h"
11
12#include <math.h>
13#include <stdlib.h>
14#include <stdio.h>
15#include <string.h>
16
17#include <Catalog.h>
18#include <Bitmap.h>
19#include <Font.h>
20#include <Message.h>
21#include <Shape.h>
22#include <String.h>
23#include <StackOrHeapArray.h>
24
25#include "messages.h"
26
27#undef B_TRANSLATION_CONTEXT
28#define B_TRANSLATION_CONTEXT "FontDemoView"
29
30FontDemoView::FontDemoView(BRect rect)
31	: BView(rect, "FontDemoView", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS),
32	fFontSize(50.0),
33	fSpacing(0.0),
34	fOutLineLevel(0),
35	fDrawingMode(B_OP_COPY),
36	fBoundingBoxes(false),
37	fDrawShapes(false),
38	fShapes(NULL)
39{
40	BString setStr = B_TRANSLATE("Haiku, Inc.");
41	SetString(setStr);
42	SetFontSize(fFontSize);
43	SetAntialiasing(true);
44}
45
46
47FontDemoView::~FontDemoView()
48{
49	free(fShapes);
50}
51
52
53void
54FontDemoView::FrameResized(float width, float height)
55{
56	// TODO: We shouldnt invalidate the whole view when bounding boxes are
57	// working as wanted
58	Invalidate(/*fBoxRegion.Frame()*/);
59	BView::FrameResized(width, height);
60}
61
62
63void
64FontDemoView::Draw(BRect updateRect)
65{
66	SetDrawingMode(B_OP_COPY);
67
68	BRect rect = Bounds();
69	SetHighColor(255, 255, 255);
70
71	if (!fString)
72		return;
73
74	SetFont(&fFont, B_FONT_ALL);
75
76	const size_t size = fString.CountChars();
77	BStackOrHeapArray<BRect, 64> boundBoxes(size);
78
79	if (OutLineLevel())
80		fFont.GetGlyphShapes(fString, size, fShapes);
81	else
82		fFont.GetBoundingBoxesAsGlyphs(fString, size, B_SCREEN_METRIC, boundBoxes);
83
84	float escapementArray[size];
85	//struct escapement_delta escapeDeltas[size];
86	struct edge_info edgeInfo[size];
87/*
88	for (size_t j = 0; j < size; j++) {
89		escapeDeltas[j].nonspace = 0.0f;
90		escapeDeltas[j].space = 0.0f;
91	}
92*/
93	fFont.GetEdges(fString.String(), size, edgeInfo);
94	fFont.GetEscapements(fString.String(), size, /*escapeDeltas,*/ escapementArray);
95
96	font_height fh;
97	fFont.GetHeight(&fh);
98
99	float xCoordArray[size];
100	float yCoordArray[size];
101
102	float yCoord = (rect.Height() + fh.ascent - fh.descent) / 2;
103	float xCoord = -rect.Width() / 2;
104	const float xCenter = xCoord * -1;
105	const float r = Rotation() * (M_PI / 180.0);
106	const float cosinus = cos(r);
107	const float sinus = -sin(r);
108
109	// When the bounding boxes workes properly we will invalidate only the
110	// region area instead of the whole view.
111
112	fBoxRegion.MakeEmpty();
113
114	for (size_t i = 0; i < size; i++) {
115		xCoordArray[i] = 0.0f;
116		yCoordArray[i] = 0.0f;
117
118		yCoordArray[i] = sinus * (xCoord - xCoordArray[i]);
119		xCoordArray[i] = cosinus * xCoord;
120
121		xCoordArray[i] += xCenter;
122		yCoordArray[i] += yCoord;
123
124		boundBoxes[i].OffsetBy(xCoordArray[i], yCoordArray[i]);
125
126		if (OutLineLevel()) {
127			MovePenTo(xCoordArray[i], yCoordArray[i]);
128			SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
129			FillShape(fShapes[i]);
130			SetPenSize(OutLineLevel());
131			SetHighColor(0, 0, 0);
132			StrokeShape(fShapes[i]);
133		} else {
134			SetHighColor(0, 0, 0);
135			SetDrawingMode(fDrawingMode);
136			int32 charLength;
137			const char* charAt = fString.CharAt(i, &charLength);
138			DrawString(charAt, charLength,
139				BPoint(xCoordArray[i], yCoordArray[i]));
140		}
141
142		if (BoundingBoxes() && !OutLineLevel()) {
143			if (i % 2)
144				SetHighColor(0, 255, 0);
145			else
146				SetHighColor(255, 0, 0);
147			SetDrawingMode(B_OP_COPY);
148			StrokeRect(boundBoxes[i]);
149		}
150
151		// add the bounding to the region.
152		fBoxRegion.Include(boundBoxes[i]);
153
154		xCoord += (escapementArray[i] /*+ escapeDeltas[i].nonspace + escapeDeltas[i].space*/)
155			* FontSize() + Spacing();
156		//printf("xCoord %f\n", xCoord);
157	}
158}
159
160
161void
162FontDemoView::MessageReceived(BMessage* msg)
163{
164	switch (msg->what) {
165		case TEXT_CHANGED_MSG:
166		{
167			BString text;
168			if (msg->FindString("_text", &text) == B_OK) {
169				SetString(text);
170				Invalidate(/*&fBoxRegion*/);
171			}
172			break;
173		}
174
175		case FONTSTYLE_CHANGED_MSG:
176		{
177			BMessage fontMessage;
178			if (msg->FindMessage("_fontMessage", &fontMessage) != B_OK)
179				return;
180
181			const char* family;
182			const char* style;
183			if (fontMessage.FindString("_family", &family) != B_OK
184				|| fontMessage.FindString("_style", &style) != B_OK)
185				return;
186
187			fFont.SetFamilyAndStyle(family, style);
188			Invalidate();
189			break;
190		}
191
192		case FONTFAMILY_CHANGED_MSG:
193		{
194			BMessage fontMessage;
195			if (msg->FindMessage("_fontMessage", &fontMessage) != B_OK)
196				return;
197
198			const char* family;
199			if (fontMessage.FindString("_family", &family) != B_OK)
200				return;
201
202			font_style style;
203			if (get_font_style(const_cast<char*>(family), 0, &style) == B_OK) {
204				fFont.SetFamilyAndStyle(family, style);
205				Invalidate(/*&fBoxRegion*/);
206			}
207			break;
208		}
209
210		case FONTSIZE_MSG:
211		{
212			float size = 0.0;
213			if (msg->FindFloat("_size", &size) == B_OK) {
214				SetFontSize(size);
215				Invalidate(/*&fBoxRegion*/);
216			}
217			break;
218		}
219
220		case FONTSHEAR_MSG:
221		{
222			float shear = 90.0;
223			if (msg->FindFloat("_shear", &shear) == B_OK) {
224				SetFontShear(shear);
225				Invalidate(/*&fBoxRegion*/);
226			 }
227			break;
228		}
229
230		case ROTATION_MSG:
231		{
232			float rotation = 0.0;
233			if (msg->FindFloat("_rotation", &rotation) == B_OK) {
234				SetFontRotation(rotation);
235				Invalidate(/*&fBoxRegion*/);
236			 }
237			break;
238		}
239
240		case SPACING_MSG:
241		{
242			float space = 0.0;
243			if (msg->FindFloat("_spacing", &space) == B_OK) {
244				SetSpacing(space);
245				Invalidate(/*&fBoxRegion*/);
246			 }
247			break;
248		}
249
250		case OUTLINE_MSG:
251		{
252			int8 outline = 0;
253			if (msg->FindInt8("_outline", &outline) == B_OK) {
254				SetOutlineLevel(outline);
255				Invalidate(/*&fBoxRegion*/);
256			 }
257			break;
258		}
259
260		case ALIASING_MSG:
261		{
262			bool aliased = false;
263			if (msg->FindBool("_aliased", &aliased) == B_OK) {
264				SetAntialiasing(aliased);
265				Invalidate(/*&fBoxRegion*/);
266			}
267			break;
268		}
269
270		case DRAWINGMODE_CHANGED_MSG:
271		{
272			if (msg->FindInt32("_mode", (int32 *)&fDrawingMode) == B_OK) {
273				Invalidate(/*&fBoxRegion*/);
274				switch (fDrawingMode) {
275					case B_OP_COPY:
276						printf("Drawing mode: B_OP_COPY\n");
277						break;
278					case B_OP_OVER:
279						printf("Drawing mode: B_OP_OVER\n");
280						break;
281					case B_OP_ERASE:
282						printf("Drawing mode: B_OP_ERASE\n");
283						break;
284					case B_OP_INVERT:
285						printf("Drawing mode: B_OP_INVERT\n");
286						break;
287					case B_OP_ADD:
288						printf("Drawing mode: B_OP_ADD\n");
289						break;
290					case B_OP_SUBTRACT:
291						printf("Drawing mode: B_OP_SUBTRACT\n");
292						break;
293					case B_OP_BLEND:
294						printf("Drawing mode: B_OP_BLEND\n");
295						break;
296 					case B_OP_MIN:
297						printf("Drawing mode: B_OP_MIN\n");
298						break;
299					case B_OP_MAX:
300						printf("Drawing mode: B_OP_MAX\n");
301						break;
302					case B_OP_SELECT:
303						printf("Drawing mode: B_OP_SELECT\n");
304						break;
305					case B_OP_ALPHA:
306						printf("Drawing mode: B_OP_ALPHA\n");
307						break;
308					default:
309						printf("Drawing mode: %d\n", fDrawingMode);
310				}
311			}
312			break;
313		}
314
315		case BOUNDING_BOX_MSG:
316		{
317			bool boundingbox = false;
318			if (msg->FindBool("_boundingbox", &boundingbox) == B_OK) {
319				SetDrawBoundingBoxes(boundingbox);
320				Invalidate(/*&fBoxRegion*/);
321			}
322			break;
323		}
324
325		default:
326			BView::MessageReceived(msg);
327			break;
328	}
329}
330
331
332void
333FontDemoView::SetString(BString string)
334{
335	fString = string;
336	free(fShapes);
337	_AddShapes(fString);
338}
339
340
341BString
342FontDemoView::String() const
343{
344	return fString;
345}
346
347
348void
349FontDemoView::SetFontSize(float size)
350{
351	fFont.SetSize(size);
352}
353
354
355void
356FontDemoView::SetFontShear(float shear)
357{
358	fFont.SetShear(shear);
359}
360
361
362void
363FontDemoView::SetFontRotation(float rotation)
364{
365	fFont.SetRotation(rotation);
366}
367
368
369void
370FontDemoView::SetDrawBoundingBoxes(bool state)
371{
372	fBoundingBoxes = state;
373}
374
375
376void
377FontDemoView::SetAntialiasing(bool state)
378{
379	fFont.SetFlags(state ? B_FORCE_ANTIALIASING : B_DISABLE_ANTIALIASING);
380}
381
382
383void
384FontDemoView::SetSpacing(float space)
385{
386	fSpacing = space;
387}
388
389
390void
391FontDemoView::SetOutlineLevel(int8 outline)
392{
393	fOutLineLevel = outline;
394}
395
396
397void
398FontDemoView::_AddShapes(BString string)
399{
400	const size_t size = string.CountChars();
401	fShapes = (BShape**)malloc(sizeof(BShape*) * size);
402
403	for (size_t i = 0; i < size; i++) {
404		fShapes[i] = new BShape();
405	}
406}
407