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