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