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