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