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