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