| OLD | NEW |
| (Empty) |
| 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 pres
sed) | |
| 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(), thi
s->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->getButton
State() == 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, un
signed 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(), fTe
xt.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 | |
| OLD | NEW |