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