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