xref: /haiku/src/apps/fontdemo/FontDemoView.cpp (revision 85fb3e7df81f8d5b6e47a9a64a53873ea906ea6e)
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 
23 #include "messages.h"
24 
25 #undef B_TRANSLATION_CONTEXT
26 #define B_TRANSLATION_CONTEXT "FontDemoView"
27 
28 FontDemoView::FontDemoView(BRect rect)
29 	: BView(rect, "FontDemoView", B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS),
30 	fBitmap(NULL),
31 	fBufferView(NULL),
32 	fString(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(fString);
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 = strlen(fString);
103 	BRect 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, size, edgeInfo);
120 	fFont.GetEscapements(fString, 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 			view->DrawChar(fString[i], BPoint(xCoordArray[i], yCoordArray[i]));
163 		}
164 
165 		if (BoundingBoxes() && !OutLineLevel()) {
166 			if (i % 2)
167 				view->SetHighColor(0, 255, 0);
168 			else
169 				view->SetHighColor(255, 0, 0);
170 			view->SetDrawingMode(B_OP_COPY);
171 			view->StrokeRect(boundBoxes[i]);
172 		}
173 
174 		// add the bounding to the region.
175 		fBoxRegion.Include(boundBoxes[i]);
176 
177 		xCoord += (escapementArray[i] /*+ escapeDeltas[i].nonspace + escapeDeltas[i].space*/)
178 			* FontSize() + Spacing();
179 		//printf("xCoord %f\n", xCoord);
180 	}
181 }
182 
183 
184 void
185 FontDemoView::MessageReceived(BMessage* msg)
186 {
187 	switch (msg->what) {
188 		case TEXT_CHANGED_MSG:
189 		{
190 			const char* text = NULL;
191 			if (msg->FindString("_text", &text) == B_OK) {
192 				SetString(text);
193 				Invalidate(/*&fBoxRegion*/);
194 			}
195 			break;
196 		}
197 
198 		case FONTSTYLE_CHANGED_MSG:
199 		{
200 			BMessage fontMessage;
201 			if (msg->FindMessage("_fontMessage", &fontMessage) != B_OK)
202 				return;
203 
204 			const char* family;
205 			const char* style;
206 			if (fontMessage.FindString("_family", &family) != B_OK
207 				|| fontMessage.FindString("_style", &style) != B_OK)
208 				return;
209 
210 			fFont.SetFamilyAndStyle(family, style);
211 			Invalidate();
212 			break;
213 		}
214 
215 		case FONTFAMILY_CHANGED_MSG:
216 		{
217 			BMessage fontMessage;
218 			if (msg->FindMessage("_fontMessage", &fontMessage) != B_OK)
219 				return;
220 
221 			const char* family;
222 			if (fontMessage.FindString("_family", &family) != B_OK)
223 				return;
224 
225 			font_style style;
226 			if (get_font_style(const_cast<char*>(family), 0, &style) == B_OK) {
227 				fFont.SetFamilyAndStyle(family, style);
228 				Invalidate(/*&fBoxRegion*/);
229 			}
230 			break;
231 		}
232 
233 		case FONTSIZE_MSG:
234 		{
235 			float size = 0.0;
236 			if (msg->FindFloat("_size", &size) == B_OK) {
237 				SetFontSize(size);
238 				Invalidate(/*&fBoxRegion*/);
239 			}
240 			break;
241 		}
242 
243 		case FONTSHEAR_MSG:
244 		{
245 			float shear = 90.0;
246 			if (msg->FindFloat("_shear", &shear) == B_OK) {
247 				SetFontShear(shear);
248 				Invalidate(/*&fBoxRegion*/);
249 			 }
250 			break;
251 		}
252 
253 		case ROTATION_MSG:
254 		{
255 			float rotation = 0.0;
256 			if (msg->FindFloat("_rotation", &rotation) == B_OK) {
257 				SetFontRotation(rotation);
258 				Invalidate(/*&fBoxRegion*/);
259 			 }
260 			break;
261 		}
262 
263 		case SPACING_MSG:
264 		{
265 			float space = 0.0;
266 			if (msg->FindFloat("_spacing", &space) == B_OK) {
267 				SetSpacing(space);
268 				Invalidate(/*&fBoxRegion*/);
269 			 }
270 			break;
271 		}
272 
273 		case OUTLINE_MSG:
274 		{
275 			int8 outline = 0;
276 			if (msg->FindInt8("_outline", &outline) == B_OK) {
277 				SetOutlineLevel(outline);
278 				Invalidate(/*&fBoxRegion*/);
279 			 }
280 			break;
281 		}
282 
283 		case ALIASING_MSG:
284 		{
285 			bool aliased = false;
286 			if (msg->FindBool("_aliased", &aliased) == B_OK) {
287 				SetAntialiasing(aliased);
288 				Invalidate(/*&fBoxRegion*/);
289 			}
290 			break;
291 		}
292 
293 		case DRAWINGMODE_CHANGED_MSG:
294 		{
295 			if (msg->FindInt32("_mode", (int32 *)&fDrawingMode) == B_OK) {
296 				Invalidate(/*&fBoxRegion*/);
297 				switch (fDrawingMode) {
298 					case B_OP_COPY:
299 						printf("Drawing mode: B_OP_COPY\n");
300 						break;
301 					case B_OP_OVER:
302 						printf("Drawing mode: B_OP_OVER\n");
303 						break;
304 					case B_OP_ERASE:
305 						printf("Drawing mode: B_OP_ERASE\n");
306 						break;
307 					case B_OP_INVERT:
308 						printf("Drawing mode: B_OP_INVERT\n");
309 						break;
310 					case B_OP_ADD:
311 						printf("Drawing mode: B_OP_ADD\n");
312 						break;
313 					case B_OP_SUBTRACT:
314 						printf("Drawing mode: B_OP_SUBTRACT\n");
315 						break;
316 					case B_OP_BLEND:
317 						printf("Drawing mode: B_OP_BLEND\n");
318 						break;
319  					case B_OP_MIN:
320 						printf("Drawing mode: B_OP_MIN\n");
321 						break;
322 					case B_OP_MAX:
323 						printf("Drawing mode: B_OP_MAX\n");
324 						break;
325 					case B_OP_SELECT:
326 						printf("Drawing mode: B_OP_SELECT\n");
327 						break;
328 					case B_OP_ALPHA:
329 						printf("Drawing mode: B_OP_ALPHA\n");
330 						break;
331 					default:
332 						printf("Drawing mode: %d\n", fDrawingMode);
333 				}
334 			}
335 			break;
336 		}
337 
338 		case BOUNDING_BOX_MSG:
339 		{
340 			bool boundingbox = false;
341 			if (msg->FindBool("_boundingbox", &boundingbox) == B_OK) {
342 				SetDrawBoundingBoxes(boundingbox);
343 				Invalidate(/*&fBoxRegion*/);
344 			}
345 			break;
346 		}
347 
348 		default:
349 			BView::MessageReceived(msg);
350 			break;
351 	}
352 }
353 
354 
355 void
356 FontDemoView::SetString(const char* string)
357 {
358 	free(fString);
359 	fString = strdup(string);
360 	free(fShapes);
361 	_AddShapes(fString);
362 }
363 
364 
365 const char*
366 FontDemoView::String() const
367 {
368 	return fString;
369 }
370 
371 
372 void
373 FontDemoView::SetFontSize(float size)
374 {
375 	fFont.SetSize(size);
376 }
377 
378 
379 void
380 FontDemoView::SetFontShear(float shear)
381 {
382 	fFont.SetShear(shear);
383 }
384 
385 
386 void
387 FontDemoView::SetFontRotation(float rotation)
388 {
389 	fFont.SetRotation(rotation);
390 }
391 
392 
393 void
394 FontDemoView::SetDrawBoundingBoxes(bool state)
395 {
396 	fBoundingBoxes = state;
397 }
398 
399 
400 void
401 FontDemoView::SetAntialiasing(bool state)
402 {
403 	fFont.SetFlags(state ? B_FORCE_ANTIALIASING : B_DISABLE_ANTIALIASING);
404 }
405 
406 
407 void
408 FontDemoView::SetSpacing(float space)
409 {
410 	fSpacing = space;
411 }
412 
413 
414 void
415 FontDemoView::SetOutlineLevel(int8 outline)
416 {
417 	fOutLineLevel = outline;
418 }
419 
420 
421 void
422 FontDemoView::_AddShapes(const char* string)
423 {
424 	const size_t size = strlen(string);
425 	fShapes = (BShape**)malloc(sizeof(BShape*)*size);
426 
427 	for (size_t i = 0; i < size; i++) {
428 		fShapes[i] = new BShape();
429 	}
430 }
431 
432 
433 BView*
434 FontDemoView::_GetView(BRect rect)
435 {
436 	if (!fBitmap || fBitmap->Bounds() != rect)
437 		_NewBitmap(rect);
438 
439 	fBitmap->Lock();
440 	return fBitmap->ChildAt(0);
441 }
442 
443 
444 void
445 FontDemoView::_NewBitmap(BRect rect)
446 {
447 	delete fBitmap;
448 	fBitmap = new BBitmap(rect, B_RGB16, true);
449 
450 	if (fBitmap->Lock()) {
451 		BView* view = new BView(rect, "", B_FOLLOW_NONE, B_WILL_DRAW);
452 		fBitmap->AddChild(view);
453 		fBitmap->Unlock();
454 	} else {
455 		delete fBitmap;
456 		fBitmap = NULL;
457 	}
458 }
459 
460