1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 #include "SkWidget.h" 9 #include "SkCanvas.h" 10 #include "SkKey.h" 11 #include "SkParsePaint.h" 12 #include "SkSystemEventTypes.h" 13 #include "SkTextBox.h" 14 15 #if 0 16 17 #ifdef SK_DEBUG 18 static void assert_no_attr(const SkDOM& dom, const SkDOM::Node* node, const char attr[]) 19 { 20 const char* value = dom.findAttr(node, attr); 21 if (value) 22 SkDebugf("unknown attribute %s=\"%s\"\n", attr, value); 23 } 24 #else 25 #define assert_no_attr(dom, node, attr) 26 #endif 27 28 #include "SkAnimator.h" 29 #include "SkTime.h" 30 31 /////////////////////////////////////////////////////////////////////////////// 32 33 enum SkinType { 34 kPushButton_SkinType, 35 kStaticText_SkinType, 36 37 kSkinTypeCount 38 }; 39 40 struct SkinSuite { 41 SkinSuite(); 42 ~SkinSuite() 43 { 44 for (int i = 0; i < kSkinTypeCount; i++) 45 delete fAnimators[i]; 46 } 47 48 SkAnimator* get(SkinType); 49 50 private: 51 SkAnimator* fAnimators[kSkinTypeCount]; 52 }; 53 54 SkinSuite::SkinSuite() 55 { 56 static const char kSkinPath[] = "skins/"; 57 58 static const char* gSkinNames[] = { 59 "pushbutton_skin.xml", 60 "statictext_skin.xml" 61 }; 62 63 for (unsigned i = 0; i < SK_ARRAY_COUNT(gSkinNames); i++) 64 { 65 size_t len = strlen(gSkinNames[i]); 66 SkString path(sizeof(kSkinPath) - 1 + len); 67 68 memcpy(path.writable_str(), kSkinPath, sizeof(kSkinPath) - 1); 69 memcpy(path.writable_str() + sizeof(kSkinPath) - 1, gSkinNames[i], len); 70 71 fAnimators[i] = new SkAnimator; 72 if (!fAnimators[i]->decodeURI(path.c_str())) 73 { 74 delete fAnimators[i]; 75 fAnimators[i] = nullptr; 76 } 77 } 78 } 79 80 SkAnimator* SkinSuite::get(SkinType st) 81 { 82 SkASSERT((unsigned)st < kSkinTypeCount); 83 return fAnimators[st]; 84 } 85 86 static SkinSuite* gSkinSuite; 87 88 static SkAnimator* get_skin_animator(SkinType st) 89 { 90 #if 0 91 if (gSkinSuite == nullptr) 92 gSkinSuite = new SkinSuite; 93 return gSkinSuite->get(st); 94 #else 95 return nullptr; 96 #endif 97 } 98 99 /////////////////////////////////////////////////////////////////////////////// 100 101 void SkWidget::Init() 102 { 103 } 104 105 void SkWidget::Term() 106 { 107 delete gSkinSuite; 108 } 109 110 void SkWidget::onEnabledChange() 111 { 112 this->inval(nullptr); 113 } 114 115 void SkWidget::postWidgetEvent() 116 { 117 if (!fEvent.isType("") && this->hasListeners()) 118 { 119 this->prepareWidgetEvent(&fEvent); 120 this->postToListeners(fEvent); 121 } 122 } 123 124 void SkWidget::prepareWidgetEvent(SkEvent*) 125 { 126 // override in subclass to add any additional fields before posting 127 } 128 129 void SkWidget::onInflate(const SkDOM& dom, const SkDOM::Node* node) 130 { 131 this->INHERITED::onInflate(dom, node); 132 133 if ((node = dom.getFirstChild(node, "event")) != nullptr) 134 fEvent.inflate(dom, node); 135 } 136 137 /////////////////////////////////////////////////////////////////////////////// 138 139 size_t SkHasLabelWidget::getLabel(SkString* str) const 140 { 141 if (str) 142 *str = fLabel; 143 return fLabel.size(); 144 } 145 146 size_t SkHasLabelWidget::getLabel(char buffer[]) const 147 { 148 if (buffer) 149 memcpy(buffer, fLabel.c_str(), fLabel.size()); 150 return fLabel.size(); 151 } 152 153 void SkHasLabelWidget::setLabel(const SkString& str) 154 { 155 this->setLabel(str.c_str(), str.size()); 156 } 157 158 void SkHasLabelWidget::setLabel(const char label[]) 159 { 160 this->setLabel(label, strlen(label)); 161 } 162 163 void SkHasLabelWidget::setLabel(const char label[], size_t len) 164 { 165 if (!fLabel.equals(label, len)) 166 { 167 fLabel.set(label, len); 168 this->onLabelChange(); 169 } 170 } 171 172 void SkHasLabelWidget::onLabelChange() 173 { 174 // override in subclass 175 } 176 177 void SkHasLabelWidget::onInflate(const SkDOM& dom, const SkDOM::Node* node) 178 { 179 this->INHERITED::onInflate(dom, node); 180 181 const char* text = dom.findAttr(node, "label"); 182 if (text) 183 this->setLabel(text); 184 } 185 186 ///////////////////////////////////////////////////////////////////////////////////// 187 188 void SkButtonWidget::setButtonState(State state) 189 { 190 if (fState != state) 191 { 192 fState = state; 193 this->onButtonStateChange(); 194 } 195 } 196 197 void SkButtonWidget::onButtonStateChange() 198 { 199 this->inval(nullptr); 200 } 201 202 void SkButtonWidget::onInflate(const SkDOM& dom, const SkDOM::Node* node) 203 { 204 this->INHERITED::onInflate(dom, node); 205 206 int index; 207 if ((index = dom.findList(node, "buttonState", "off,on,unknown")) >= 0) 208 this->setButtonState((State)index); 209 } 210 211 ///////////////////////////////////////////////////////////////////////////////////// 212 213 bool SkPushButtonWidget::onEvent(const SkEvent& evt) 214 { 215 if (evt.isType(SK_EventType_Key) && evt.getFast32() == kOK_SkKey) 216 { 217 this->postWidgetEvent(); 218 return true; 219 } 220 return this->INHERITED::onEvent(evt); 221 } 222 223 static const char* computeAnimatorState(int enabled, int focused, SkButtonWidget::State state) 224 { 225 if (!enabled) 226 return "disabled"; 227 if (state == SkButtonWidget::kOn_State) 228 { 229 SkASSERT(focused); 230 return "enabled-pressed"; 231 } 232 if (focused) 233 return "enabled-focused"; 234 return "enabled"; 235 } 236 237 #include "SkBlurMask.h" 238 #include "SkBlurMaskFilter.h" 239 #include "SkEmbossMaskFilter.h" 240 241 static void create_emboss(SkPaint* paint, SkScalar radius, bool focus, bool pressed) 242 { 243 SkEmbossMaskFilter::Light light; 244 245 light.fDirection[0] = SK_Scalar1/2; 246 light.fDirection[1] = SK_Scalar1/2; 247 light.fDirection[2] = SK_Scalar1/3; 248 light.fAmbient = 0x48; 249 light.fSpecular = 0x80; 250 251 if (pressed) 252 { 253 light.fDirection[0] = -light.fDirection[0]; 254 light.fDirection[1] = -light.fDirection[1]; 255 } 256 if (focus) 257 light.fDirection[2] += SK_Scalar1/4; 258 259 SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius); 260 paint->setMaskFilter(new SkEmbossMaskFilter(sigma, light))->unref(); 261 } 262 263 void SkPushButtonWidget::onDraw(SkCanvas* canvas) 264 { 265 this->INHERITED::onDraw(canvas); 266 267 SkString label; 268 this->getLabel(&label); 269 270 SkAnimator* anim = get_skin_animator(kPushButton_SkinType); 271 272 if (anim) 273 { 274 SkEvent evt("user"); 275 276 evt.setString("id", "prime"); 277 evt.setScalar("prime-width", this->width()); 278 evt.setScalar("prime-height", this->height()); 279 evt.setString("prime-text", label); 280 evt.setString("prime-state", computeAnimatorState(this->isEnabled(), this->hasFocus(), this->getButtonState())); 281 282 (void)anim->doUserEvent(evt); 283 SkPaint paint; 284 anim->draw(canvas, &paint, SkTime::GetMSecs()); 285 } 286 else 287 { 288 SkRect r; 289 SkPaint p; 290 291 r.set(0, 0, this->width(), this->height()); 292 p.setAntiAliasOn(true); 293 p.setColor(SK_ColorBLUE); 294 create_emboss(&p, SkIntToScalar(12)/5, this->hasFocus(), this->getButtonState() == kOn_State); 295 canvas->drawRoundRect(r, SkScalarHalf(this->height()), SkScalarHalf(this->height()), p); 296 p.setMaskFilter(nullptr); 297 298 p.setTextAlign(SkPaint::kCenter_Align); 299 300 SkTextBox box; 301 box.setMode(SkTextBox::kOneLine_Mode); 302 box.setSpacingAlign(SkTextBox::kCenter_SpacingAlign); 303 box.setBox(0, 0, this->width(), this->height()); 304 305 // if (this->getButtonState() == kOn_State) 306 // p.setColor(SK_ColorRED); 307 // else 308 p.setColor(SK_ColorWHITE); 309 310 box.draw(canvas, label.c_str(), label.size(), p); 311 } 312 } 313 314 SkView::Click* SkPushButtonWidget::onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) 315 { 316 this->acceptFocus(); 317 return new Click(this); 318 } 319 320 bool SkPushButtonWidget::onClick(Click* click) 321 { 322 SkRect r; 323 State state = kOff_State; 324 325 this->getLocalBounds(&r); 326 if (r.contains(click->fCurr)) 327 { 328 if (click->fState == Click::kUp_State) 329 this->postWidgetEvent(); 330 else 331 state = kOn_State; 332 } 333 this->setButtonState(state); 334 return true; 335 } 336 337 ////////////////////////////////////////////////////////////////////////////////////////// 338 339 SkStaticTextView::SkStaticTextView(U32 flags) : SkView(flags) 340 { 341 fMargin.set(0, 0); 342 fMode = kFixedSize_Mode; 343 fSpacingAlign = SkTextBox::kStart_SpacingAlign; 344 } 345 346 SkStaticTextView::~SkStaticTextView() 347 { 348 } 349 350 void SkStaticTextView::computeSize() 351 { 352 if (fMode == kAutoWidth_Mode) 353 { 354 SkScalar width = fPaint.measureText(fText.c_str(), fText.size(), nullptr, nullptr); 355 this->setWidth(width + fMargin.fX * 2); 356 } 357 else if (fMode == kAutoHeight_Mode) 358 { 359 SkScalar width = this->width() - fMargin.fX * 2; 360 int lines = width > 0 ? SkTextLineBreaker::CountLines(fText.c_str(), fText.size(), fPaint, width) : 0; 361 362 SkScalar before, after; 363 (void)fPaint.measureText(0, nullptr, &before, &after); 364 365 this->setHeight(lines * (after - before) + fMargin.fY * 2); 366 } 367 } 368 369 void SkStaticTextView::setMode(Mode mode) 370 { 371 SkASSERT((unsigned)mode < kModeCount); 372 373 if (fMode != mode) 374 { 375 fMode = SkToU8(mode); 376 this->computeSize(); 377 } 378 } 379 380 void SkStaticTextView::setSpacingAlign(SkTextBox::SpacingAlign align) 381 { 382 fSpacingAlign = SkToU8(align); 383 this->inval(nullptr); 384 } 385 386 void SkStaticTextView::getMargin(SkPoint* margin) const 387 { 388 if (margin) 389 *margin = fMargin; 390 } 391 392 void SkStaticTextView::setMargin(SkScalar dx, SkScalar dy) 393 { 394 if (fMargin.fX != dx || fMargin.fY != dy) 395 { 396 fMargin.set(dx, dy); 397 this->computeSize(); 398 this->inval(nullptr); 399 } 400 } 401 402 size_t SkStaticTextView::getText(SkString* text) const 403 { 404 if (text) 405 *text = fText; 406 return fText.size(); 407 } 408 409 size_t SkStaticTextView::getText(char text[]) const 410 { 411 if (text) 412 memcpy(text, fText.c_str(), fText.size()); 413 return fText.size(); 414 } 415 416 void SkStaticTextView::setText(const SkString& text) 417 { 418 this->setText(text.c_str(), text.size()); 419 } 420 421 void SkStaticTextView::setText(const char text[]) 422 { 423 this->setText(text, strlen(text)); 424 } 425 426 void SkStaticTextView::setText(const char text[], size_t len) 427 { 428 if (!fText.equals(text, len)) 429 { 430 fText.set(text, len); 431 this->computeSize(); 432 this->inval(nullptr); 433 } 434 } 435 436 void SkStaticTextView::getPaint(SkPaint* paint) const 437 { 438 if (paint) 439 *paint = fPaint; 440 } 441 442 void SkStaticTextView::setPaint(const SkPaint& paint) 443 { 444 if (fPaint != paint) 445 { 446 fPaint = paint; 447 this->computeSize(); 448 this->inval(nullptr); 449 } 450 } 451 452 void SkStaticTextView::onDraw(SkCanvas* canvas) 453 { 454 this->INHERITED::onDraw(canvas); 455 456 if (fText.isEmpty()) 457 return; 458 459 SkTextBox box; 460 461 box.setMode(fMode == kAutoWidth_Mode ? SkTextBox::kOneLine_Mode : SkTextBox::kLineBreak_Mode); 462 box.setSpacingAlign(this->getSpacingAlign()); 463 box.setBox(fMargin.fX, fMargin.fY, this->width() - fMargin.fX, this->height() - fMargin.fY); 464 box.draw(canvas, fText.c_str(), fText.size(), fPaint); 465 } 466 467 void SkStaticTextView::onInflate(const SkDOM& dom, const SkDOM::Node* node) 468 { 469 this->INHERITED::onInflate(dom, node); 470 471 int index; 472 if ((index = dom.findList(node, "mode", "fixed,auto-width,auto-height")) >= 0) 473 this->setMode((Mode)index); 474 else 475 assert_no_attr(dom, node, "mode"); 476 477 if ((index = dom.findList(node, "spacing-align", "start,center,end")) >= 0) 478 this->setSpacingAlign((SkTextBox::SpacingAlign)index); 479 else 480 assert_no_attr(dom, node, "mode"); 481 482 SkScalar s[2]; 483 if (dom.findScalars(node, "margin", s, 2)) 484 this->setMargin(s[0], s[1]); 485 else 486 assert_no_attr(dom, node, "margin"); 487 488 const char* text = dom.findAttr(node, "text"); 489 if (text) 490 this->setText(text); 491 492 if ((node = dom.getFirstChild(node, "paint")) != nullptr) 493 SkPaint_Inflate(&fPaint, dom, node); 494 } 495 496 ///////////////////////////////////////////////////////////////////////////////////////////////////// 497 498 #include "SkImageDecoder.h" 499 500 SkBitmapView::SkBitmapView(U32 flags) : SkView(flags) 501 { 502 } 503 504 SkBitmapView::~SkBitmapView() 505 { 506 } 507 508 bool SkBitmapView::getBitmap(SkBitmap* bitmap) const 509 { 510 if (bitmap) 511 *bitmap = fBitmap; 512 return fBitmap.colorType() != kUnknown_SkColorType; 513 } 514 515 void SkBitmapView::setBitmap(const SkBitmap* bitmap, bool viewOwnsPixels) 516 { 517 if (bitmap) 518 { 519 fBitmap = *bitmap; 520 fBitmap.setOwnsPixels(viewOwnsPixels); 521 } 522 } 523 524 bool SkBitmapView::loadBitmapFromFile(const char path[]) 525 { 526 SkBitmap bitmap; 527 528 if (SkImageDecoder::DecodeFile(path, &bitmap)) 529 { 530 this->setBitmap(&bitmap, true); 531 bitmap.setOwnsPixels(false); 532 return true; 533 } 534 return false; 535 } 536 537 void SkBitmapView::onDraw(SkCanvas* canvas) 538 { 539 if (fBitmap.colorType() != kUnknown_SkColorType && 540 fBitmap.width() && fBitmap.height()) 541 { 542 SkAutoCanvasRestore restore(canvas, true); 543 SkPaint p; 544 545 p.setFilterType(SkPaint::kBilinear_FilterType); 546 canvas->scale( this->width() / fBitmap.width(), 547 this->height() / fBitmap.height(), 548 0, 0); 549 canvas->drawBitmap(fBitmap, 0, 0, p); 550 } 551 } 552 553 void SkBitmapView::onInflate(const SkDOM& dom, const SkDOM::Node* node) 554 { 555 this->INHERITED::onInflate(dom, node); 556 557 const char* src = dom.findAttr(node, "src"); 558 if (src) 559 (void)this->loadBitmapFromFile(src); 560 } 561 562 #endif 563