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