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