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