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