xref: /haiku/src/apps/fontdemo/FontDemoView.cpp (revision 481f986b59e7782458dcc5fe98ad59a57480e5db)
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 			}
294 			break;
295 		}
296 
297 		case BOUNDING_BOX_MSG:
298 		{
299 			bool boundingbox = false;
300 			if (msg->FindBool("_boundingbox", &boundingbox) == B_OK) {
301 				SetDrawBoundingBoxes(boundingbox);
302 				Invalidate(/*&fBoxRegion*/);
303 			}
304 			break;
305 		}
306 
307 		default:
308 			BView::MessageReceived(msg);
309 			break;
310 	}
311 }
312 
313 
314 void
315 FontDemoView::SetString(const char* string)
316 {
317 	free(fString);
318 	fString = strdup(string);
319 	free(fShapes);
320 	_AddShapes(fString);
321 }
322 
323 
324 const char*
325 FontDemoView::String() const
326 {
327 	return fString;
328 }
329 
330 
331 void
332 FontDemoView::SetFontSize(float size)
333 {
334 	fFont.SetSize(size);
335 }
336 
337 
338 void
339 FontDemoView::SetFontShear(float shear)
340 {
341 	fFont.SetShear(shear);
342 }
343 
344 
345 void
346 FontDemoView::SetFontRotation(float rotation)
347 {
348 	fFont.SetRotation(rotation);
349 }
350 
351 
352 void
353 FontDemoView::SetDrawBoundingBoxes(bool state)
354 {
355 	fBoundingBoxes = state;
356 }
357 
358 
359 void
360 FontDemoView::SetAntialiasing(bool state)
361 {
362 	fFont.SetFlags(state ? B_FORCE_ANTIALIASING : B_DISABLE_ANTIALIASING);
363 }
364 
365 
366 void
367 FontDemoView::SetSpacing(float space)
368 {
369 	fSpacing = space;
370 }
371 
372 
373 void
374 FontDemoView::SetOutlineLevel(int8 outline)
375 {
376 	fOutLineLevel = outline;
377 }
378 
379 
380 void
381 FontDemoView::_AddShapes(const char* string)
382 {
383 	const size_t size = strlen(string);
384 	fShapes = (BShape**)malloc(sizeof(BShape*)*size);
385 
386 	for (size_t i = 0; i < size; i++) {
387 		fShapes[i] = new BShape();
388 	}
389 }
390 
391 
392 BView*
393 FontDemoView::_GetView(BRect rect)
394 {
395 	if (!fBitmap || fBitmap->Bounds() != rect)
396 		_NewBitmap(rect);
397 
398 	fBitmap->Lock();
399 	return fBitmap->ChildAt(0);
400 }
401 
402 
403 void
404 FontDemoView::_NewBitmap(BRect rect)
405 {
406 	delete fBitmap;
407 	fBitmap = new BBitmap(rect, B_RGB16, true);
408 
409 	if (fBitmap->Lock()) {
410 		BView* view = new BView(rect, "", B_FOLLOW_NONE, B_WILL_DRAW);
411 		fBitmap->AddChild(view);
412 		fBitmap->Unlock();
413 	} else {
414 		delete fBitmap;
415 		fBitmap = NULL;
416 	}
417 }
418 
419