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