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