xref: /haiku/src/apps/fontdemo/FontDemoView.cpp (revision a629567a9001547736cfe892cdf992be16868fed)
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 
30 FontDemoView::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 
52 FontDemoView::~FontDemoView()
53 {
54 	free(fShapes);
55 
56 	fBitmap->Lock();
57 	delete fBitmap;
58 }
59 
60 
61 void
62 FontDemoView::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 
71 void
72 FontDemoView::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 
84 void
85 FontDemoView::_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 
187 void
188 FontDemoView::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 
358 void
359 FontDemoView::SetString(BString string)
360 {
361 	fString = string;
362 	free(fShapes);
363 	_AddShapes(fString);
364 }
365 
366 
367 BString
368 FontDemoView::String() const
369 {
370 	return fString;
371 }
372 
373 
374 void
375 FontDemoView::SetFontSize(float size)
376 {
377 	fFont.SetSize(size);
378 }
379 
380 
381 void
382 FontDemoView::SetFontShear(float shear)
383 {
384 	fFont.SetShear(shear);
385 }
386 
387 
388 void
389 FontDemoView::SetFontRotation(float rotation)
390 {
391 	fFont.SetRotation(rotation);
392 }
393 
394 
395 void
396 FontDemoView::SetDrawBoundingBoxes(bool state)
397 {
398 	fBoundingBoxes = state;
399 }
400 
401 
402 void
403 FontDemoView::SetAntialiasing(bool state)
404 {
405 	fFont.SetFlags(state ? B_FORCE_ANTIALIASING : B_DISABLE_ANTIALIASING);
406 }
407 
408 
409 void
410 FontDemoView::SetSpacing(float space)
411 {
412 	fSpacing = space;
413 }
414 
415 
416 void
417 FontDemoView::SetOutlineLevel(int8 outline)
418 {
419 	fOutLineLevel = outline;
420 }
421 
422 
423 void
424 FontDemoView::_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 
435 BView*
436 FontDemoView::_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 
446 void
447 FontDemoView::_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