1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/views/SkWidgets.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,562 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2011 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 +#include "SkWidget.h" 1.12 +#include "SkCanvas.h" 1.13 +#include "SkKey.h" 1.14 +#include "SkParsePaint.h" 1.15 +#include "SkSystemEventTypes.h" 1.16 +#include "SkTextBox.h" 1.17 + 1.18 +#if 0 1.19 + 1.20 +#ifdef SK_DEBUG 1.21 + static void assert_no_attr(const SkDOM& dom, const SkDOM::Node* node, const char attr[]) 1.22 + { 1.23 + const char* value = dom.findAttr(node, attr); 1.24 + if (value) 1.25 + SkDebugf("unknown attribute %s=\"%s\"\n", attr, value); 1.26 + } 1.27 +#else 1.28 + #define assert_no_attr(dom, node, attr) 1.29 +#endif 1.30 + 1.31 +#include "SkAnimator.h" 1.32 +#include "SkTime.h" 1.33 + 1.34 +/////////////////////////////////////////////////////////////////////////////// 1.35 + 1.36 +enum SkinType { 1.37 + kPushButton_SkinType, 1.38 + kStaticText_SkinType, 1.39 + 1.40 + kSkinTypeCount 1.41 +}; 1.42 + 1.43 +struct SkinSuite { 1.44 + SkinSuite(); 1.45 + ~SkinSuite() 1.46 + { 1.47 + for (int i = 0; i < kSkinTypeCount; i++) 1.48 + delete fAnimators[i]; 1.49 + } 1.50 + 1.51 + SkAnimator* get(SkinType); 1.52 + 1.53 +private: 1.54 + SkAnimator* fAnimators[kSkinTypeCount]; 1.55 +}; 1.56 + 1.57 +SkinSuite::SkinSuite() 1.58 +{ 1.59 + static const char kSkinPath[] = "skins/"; 1.60 + 1.61 + static const char* gSkinNames[] = { 1.62 + "pushbutton_skin.xml", 1.63 + "statictext_skin.xml" 1.64 + }; 1.65 + 1.66 + for (unsigned i = 0; i < SK_ARRAY_COUNT(gSkinNames); i++) 1.67 + { 1.68 + size_t len = strlen(gSkinNames[i]); 1.69 + SkString path(sizeof(kSkinPath) - 1 + len); 1.70 + 1.71 + memcpy(path.writable_str(), kSkinPath, sizeof(kSkinPath) - 1); 1.72 + memcpy(path.writable_str() + sizeof(kSkinPath) - 1, gSkinNames[i], len); 1.73 + 1.74 + fAnimators[i] = new SkAnimator; 1.75 + if (!fAnimators[i]->decodeURI(path.c_str())) 1.76 + { 1.77 + delete fAnimators[i]; 1.78 + fAnimators[i] = NULL; 1.79 + } 1.80 + } 1.81 +} 1.82 + 1.83 +SkAnimator* SkinSuite::get(SkinType st) 1.84 +{ 1.85 + SkASSERT((unsigned)st < kSkinTypeCount); 1.86 + return fAnimators[st]; 1.87 +} 1.88 + 1.89 +static SkinSuite* gSkinSuite; 1.90 + 1.91 +static SkAnimator* get_skin_animator(SkinType st) 1.92 +{ 1.93 +#if 0 1.94 + if (gSkinSuite == NULL) 1.95 + gSkinSuite = new SkinSuite; 1.96 + return gSkinSuite->get(st); 1.97 +#else 1.98 + return NULL; 1.99 +#endif 1.100 +} 1.101 + 1.102 +/////////////////////////////////////////////////////////////////////////////// 1.103 + 1.104 +void SkWidget::Init() 1.105 +{ 1.106 +} 1.107 + 1.108 +void SkWidget::Term() 1.109 +{ 1.110 + delete gSkinSuite; 1.111 +} 1.112 + 1.113 +void SkWidget::onEnabledChange() 1.114 +{ 1.115 + this->inval(NULL); 1.116 +} 1.117 + 1.118 +void SkWidget::postWidgetEvent() 1.119 +{ 1.120 + if (!fEvent.isType("") && this->hasListeners()) 1.121 + { 1.122 + this->prepareWidgetEvent(&fEvent); 1.123 + this->postToListeners(fEvent); 1.124 + } 1.125 +} 1.126 + 1.127 +void SkWidget::prepareWidgetEvent(SkEvent*) 1.128 +{ 1.129 + // override in subclass to add any additional fields before posting 1.130 +} 1.131 + 1.132 +void SkWidget::onInflate(const SkDOM& dom, const SkDOM::Node* node) 1.133 +{ 1.134 + this->INHERITED::onInflate(dom, node); 1.135 + 1.136 + if ((node = dom.getFirstChild(node, "event")) != NULL) 1.137 + fEvent.inflate(dom, node); 1.138 +} 1.139 + 1.140 +/////////////////////////////////////////////////////////////////////////////// 1.141 + 1.142 +size_t SkHasLabelWidget::getLabel(SkString* str) const 1.143 +{ 1.144 + if (str) 1.145 + *str = fLabel; 1.146 + return fLabel.size(); 1.147 +} 1.148 + 1.149 +size_t SkHasLabelWidget::getLabel(char buffer[]) const 1.150 +{ 1.151 + if (buffer) 1.152 + memcpy(buffer, fLabel.c_str(), fLabel.size()); 1.153 + return fLabel.size(); 1.154 +} 1.155 + 1.156 +void SkHasLabelWidget::setLabel(const SkString& str) 1.157 +{ 1.158 + this->setLabel(str.c_str(), str.size()); 1.159 +} 1.160 + 1.161 +void SkHasLabelWidget::setLabel(const char label[]) 1.162 +{ 1.163 + this->setLabel(label, strlen(label)); 1.164 +} 1.165 + 1.166 +void SkHasLabelWidget::setLabel(const char label[], size_t len) 1.167 +{ 1.168 + if (!fLabel.equals(label, len)) 1.169 + { 1.170 + fLabel.set(label, len); 1.171 + this->onLabelChange(); 1.172 + } 1.173 +} 1.174 + 1.175 +void SkHasLabelWidget::onLabelChange() 1.176 +{ 1.177 + // override in subclass 1.178 +} 1.179 + 1.180 +void SkHasLabelWidget::onInflate(const SkDOM& dom, const SkDOM::Node* node) 1.181 +{ 1.182 + this->INHERITED::onInflate(dom, node); 1.183 + 1.184 + const char* text = dom.findAttr(node, "label"); 1.185 + if (text) 1.186 + this->setLabel(text); 1.187 +} 1.188 + 1.189 +///////////////////////////////////////////////////////////////////////////////////// 1.190 + 1.191 +void SkButtonWidget::setButtonState(State state) 1.192 +{ 1.193 + if (fState != state) 1.194 + { 1.195 + fState = state; 1.196 + this->onButtonStateChange(); 1.197 + } 1.198 +} 1.199 + 1.200 +void SkButtonWidget::onButtonStateChange() 1.201 +{ 1.202 + this->inval(NULL); 1.203 +} 1.204 + 1.205 +void SkButtonWidget::onInflate(const SkDOM& dom, const SkDOM::Node* node) 1.206 +{ 1.207 + this->INHERITED::onInflate(dom, node); 1.208 + 1.209 + int index; 1.210 + if ((index = dom.findList(node, "buttonState", "off,on,unknown")) >= 0) 1.211 + this->setButtonState((State)index); 1.212 +} 1.213 + 1.214 +///////////////////////////////////////////////////////////////////////////////////// 1.215 + 1.216 +bool SkPushButtonWidget::onEvent(const SkEvent& evt) 1.217 +{ 1.218 + if (evt.isType(SK_EventType_Key) && evt.getFast32() == kOK_SkKey) 1.219 + { 1.220 + this->postWidgetEvent(); 1.221 + return true; 1.222 + } 1.223 + return this->INHERITED::onEvent(evt); 1.224 +} 1.225 + 1.226 +static const char* computeAnimatorState(int enabled, int focused, SkButtonWidget::State state) 1.227 +{ 1.228 + if (!enabled) 1.229 + return "disabled"; 1.230 + if (state == SkButtonWidget::kOn_State) 1.231 + { 1.232 + SkASSERT(focused); 1.233 + return "enabled-pressed"; 1.234 + } 1.235 + if (focused) 1.236 + return "enabled-focused"; 1.237 + return "enabled"; 1.238 +} 1.239 + 1.240 +#include "SkBlurMask.h" 1.241 +#include "SkBlurMaskFilter.h" 1.242 +#include "SkEmbossMaskFilter.h" 1.243 + 1.244 +static void create_emboss(SkPaint* paint, SkScalar radius, bool focus, bool pressed) 1.245 +{ 1.246 + SkEmbossMaskFilter::Light light; 1.247 + 1.248 + light.fDirection[0] = SK_Scalar1/2; 1.249 + light.fDirection[1] = SK_Scalar1/2; 1.250 + light.fDirection[2] = SK_Scalar1/3; 1.251 + light.fAmbient = 0x48; 1.252 + light.fSpecular = 0x80; 1.253 + 1.254 + if (pressed) 1.255 + { 1.256 + light.fDirection[0] = -light.fDirection[0]; 1.257 + light.fDirection[1] = -light.fDirection[1]; 1.258 + } 1.259 + if (focus) 1.260 + light.fDirection[2] += SK_Scalar1/4; 1.261 + 1.262 + SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(radius); 1.263 + paint->setMaskFilter(new SkEmbossMaskFilter(sigma, light))->unref(); 1.264 +} 1.265 + 1.266 +void SkPushButtonWidget::onDraw(SkCanvas* canvas) 1.267 +{ 1.268 + this->INHERITED::onDraw(canvas); 1.269 + 1.270 + SkString label; 1.271 + this->getLabel(&label); 1.272 + 1.273 + SkAnimator* anim = get_skin_animator(kPushButton_SkinType); 1.274 + 1.275 + if (anim) 1.276 + { 1.277 + SkEvent evt("user"); 1.278 + 1.279 + evt.setString("id", "prime"); 1.280 + evt.setScalar("prime-width", this->width()); 1.281 + evt.setScalar("prime-height", this->height()); 1.282 + evt.setString("prime-text", label); 1.283 + evt.setString("prime-state", computeAnimatorState(this->isEnabled(), this->hasFocus(), this->getButtonState())); 1.284 + 1.285 + (void)anim->doUserEvent(evt); 1.286 + SkPaint paint; 1.287 + anim->draw(canvas, &paint, SkTime::GetMSecs()); 1.288 + } 1.289 + else 1.290 + { 1.291 + SkRect r; 1.292 + SkPaint p; 1.293 + 1.294 + r.set(0, 0, this->width(), this->height()); 1.295 + p.setAntiAliasOn(true); 1.296 + p.setColor(SK_ColorBLUE); 1.297 + create_emboss(&p, SkIntToScalar(12)/5, this->hasFocus(), this->getButtonState() == kOn_State); 1.298 + canvas->drawRoundRect(r, SkScalarHalf(this->height()), SkScalarHalf(this->height()), p); 1.299 + p.setMaskFilter(NULL); 1.300 + 1.301 + p.setTextAlign(SkPaint::kCenter_Align); 1.302 + 1.303 + SkTextBox box; 1.304 + box.setMode(SkTextBox::kOneLine_Mode); 1.305 + box.setSpacingAlign(SkTextBox::kCenter_SpacingAlign); 1.306 + box.setBox(0, 0, this->width(), this->height()); 1.307 + 1.308 +// if (this->getButtonState() == kOn_State) 1.309 +// p.setColor(SK_ColorRED); 1.310 +// else 1.311 + p.setColor(SK_ColorWHITE); 1.312 + 1.313 + box.draw(canvas, label.c_str(), label.size(), p); 1.314 + } 1.315 +} 1.316 + 1.317 +SkView::Click* SkPushButtonWidget::onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) 1.318 +{ 1.319 + this->acceptFocus(); 1.320 + return new Click(this); 1.321 +} 1.322 + 1.323 +bool SkPushButtonWidget::onClick(Click* click) 1.324 +{ 1.325 + SkRect r; 1.326 + State state = kOff_State; 1.327 + 1.328 + this->getLocalBounds(&r); 1.329 + if (r.contains(click->fCurr)) 1.330 + { 1.331 + if (click->fState == Click::kUp_State) 1.332 + this->postWidgetEvent(); 1.333 + else 1.334 + state = kOn_State; 1.335 + } 1.336 + this->setButtonState(state); 1.337 + return true; 1.338 +} 1.339 + 1.340 +////////////////////////////////////////////////////////////////////////////////////////// 1.341 + 1.342 +SkStaticTextView::SkStaticTextView(U32 flags) : SkView(flags) 1.343 +{ 1.344 + fMargin.set(0, 0); 1.345 + fMode = kFixedSize_Mode; 1.346 + fSpacingAlign = SkTextBox::kStart_SpacingAlign; 1.347 +} 1.348 + 1.349 +SkStaticTextView::~SkStaticTextView() 1.350 +{ 1.351 +} 1.352 + 1.353 +void SkStaticTextView::computeSize() 1.354 +{ 1.355 + if (fMode == kAutoWidth_Mode) 1.356 + { 1.357 + SkScalar width = fPaint.measureText(fText.c_str(), fText.size(), NULL, NULL); 1.358 + this->setWidth(width + fMargin.fX * 2); 1.359 + } 1.360 + else if (fMode == kAutoHeight_Mode) 1.361 + { 1.362 + SkScalar width = this->width() - fMargin.fX * 2; 1.363 + int lines = width > 0 ? SkTextLineBreaker::CountLines(fText.c_str(), fText.size(), fPaint, width) : 0; 1.364 + 1.365 + SkScalar before, after; 1.366 + (void)fPaint.measureText(0, NULL, &before, &after); 1.367 + 1.368 + this->setHeight(lines * (after - before) + fMargin.fY * 2); 1.369 + } 1.370 +} 1.371 + 1.372 +void SkStaticTextView::setMode(Mode mode) 1.373 +{ 1.374 + SkASSERT((unsigned)mode < kModeCount); 1.375 + 1.376 + if (fMode != mode) 1.377 + { 1.378 + fMode = SkToU8(mode); 1.379 + this->computeSize(); 1.380 + } 1.381 +} 1.382 + 1.383 +void SkStaticTextView::setSpacingAlign(SkTextBox::SpacingAlign align) 1.384 +{ 1.385 + fSpacingAlign = SkToU8(align); 1.386 + this->inval(NULL); 1.387 +} 1.388 + 1.389 +void SkStaticTextView::getMargin(SkPoint* margin) const 1.390 +{ 1.391 + if (margin) 1.392 + *margin = fMargin; 1.393 +} 1.394 + 1.395 +void SkStaticTextView::setMargin(SkScalar dx, SkScalar dy) 1.396 +{ 1.397 + if (fMargin.fX != dx || fMargin.fY != dy) 1.398 + { 1.399 + fMargin.set(dx, dy); 1.400 + this->computeSize(); 1.401 + this->inval(NULL); 1.402 + } 1.403 +} 1.404 + 1.405 +size_t SkStaticTextView::getText(SkString* text) const 1.406 +{ 1.407 + if (text) 1.408 + *text = fText; 1.409 + return fText.size(); 1.410 +} 1.411 + 1.412 +size_t SkStaticTextView::getText(char text[]) const 1.413 +{ 1.414 + if (text) 1.415 + memcpy(text, fText.c_str(), fText.size()); 1.416 + return fText.size(); 1.417 +} 1.418 + 1.419 +void SkStaticTextView::setText(const SkString& text) 1.420 +{ 1.421 + this->setText(text.c_str(), text.size()); 1.422 +} 1.423 + 1.424 +void SkStaticTextView::setText(const char text[]) 1.425 +{ 1.426 + this->setText(text, strlen(text)); 1.427 +} 1.428 + 1.429 +void SkStaticTextView::setText(const char text[], size_t len) 1.430 +{ 1.431 + if (!fText.equals(text, len)) 1.432 + { 1.433 + fText.set(text, len); 1.434 + this->computeSize(); 1.435 + this->inval(NULL); 1.436 + } 1.437 +} 1.438 + 1.439 +void SkStaticTextView::getPaint(SkPaint* paint) const 1.440 +{ 1.441 + if (paint) 1.442 + *paint = fPaint; 1.443 +} 1.444 + 1.445 +void SkStaticTextView::setPaint(const SkPaint& paint) 1.446 +{ 1.447 + if (fPaint != paint) 1.448 + { 1.449 + fPaint = paint; 1.450 + this->computeSize(); 1.451 + this->inval(NULL); 1.452 + } 1.453 +} 1.454 + 1.455 +void SkStaticTextView::onDraw(SkCanvas* canvas) 1.456 +{ 1.457 + this->INHERITED::onDraw(canvas); 1.458 + 1.459 + if (fText.isEmpty()) 1.460 + return; 1.461 + 1.462 + SkTextBox box; 1.463 + 1.464 + box.setMode(fMode == kAutoWidth_Mode ? SkTextBox::kOneLine_Mode : SkTextBox::kLineBreak_Mode); 1.465 + box.setSpacingAlign(this->getSpacingAlign()); 1.466 + box.setBox(fMargin.fX, fMargin.fY, this->width() - fMargin.fX, this->height() - fMargin.fY); 1.467 + box.draw(canvas, fText.c_str(), fText.size(), fPaint); 1.468 +} 1.469 + 1.470 +void SkStaticTextView::onInflate(const SkDOM& dom, const SkDOM::Node* node) 1.471 +{ 1.472 + this->INHERITED::onInflate(dom, node); 1.473 + 1.474 + int index; 1.475 + if ((index = dom.findList(node, "mode", "fixed,auto-width,auto-height")) >= 0) 1.476 + this->setMode((Mode)index); 1.477 + else 1.478 + assert_no_attr(dom, node, "mode"); 1.479 + 1.480 + if ((index = dom.findList(node, "spacing-align", "start,center,end")) >= 0) 1.481 + this->setSpacingAlign((SkTextBox::SpacingAlign)index); 1.482 + else 1.483 + assert_no_attr(dom, node, "mode"); 1.484 + 1.485 + SkScalar s[2]; 1.486 + if (dom.findScalars(node, "margin", s, 2)) 1.487 + this->setMargin(s[0], s[1]); 1.488 + else 1.489 + assert_no_attr(dom, node, "margin"); 1.490 + 1.491 + const char* text = dom.findAttr(node, "text"); 1.492 + if (text) 1.493 + this->setText(text); 1.494 + 1.495 + if ((node = dom.getFirstChild(node, "paint")) != NULL) 1.496 + SkPaint_Inflate(&fPaint, dom, node); 1.497 +} 1.498 + 1.499 +///////////////////////////////////////////////////////////////////////////////////////////////////// 1.500 + 1.501 +#include "SkImageDecoder.h" 1.502 + 1.503 +SkBitmapView::SkBitmapView(U32 flags) : SkView(flags) 1.504 +{ 1.505 +} 1.506 + 1.507 +SkBitmapView::~SkBitmapView() 1.508 +{ 1.509 +} 1.510 + 1.511 +bool SkBitmapView::getBitmap(SkBitmap* bitmap) const 1.512 +{ 1.513 + if (bitmap) 1.514 + *bitmap = fBitmap; 1.515 + return fBitmap.colorType() != kUnknown_SkColorType; 1.516 +} 1.517 + 1.518 +void SkBitmapView::setBitmap(const SkBitmap* bitmap, bool viewOwnsPixels) 1.519 +{ 1.520 + if (bitmap) 1.521 + { 1.522 + fBitmap = *bitmap; 1.523 + fBitmap.setOwnsPixels(viewOwnsPixels); 1.524 + } 1.525 +} 1.526 + 1.527 +bool SkBitmapView::loadBitmapFromFile(const char path[]) 1.528 +{ 1.529 + SkBitmap bitmap; 1.530 + 1.531 + if (SkImageDecoder::DecodeFile(path, &bitmap)) 1.532 + { 1.533 + this->setBitmap(&bitmap, true); 1.534 + bitmap.setOwnsPixels(false); 1.535 + return true; 1.536 + } 1.537 + return false; 1.538 +} 1.539 + 1.540 +void SkBitmapView::onDraw(SkCanvas* canvas) 1.541 +{ 1.542 + if (fBitmap.colorType() != kUnknown_SkColorType && 1.543 + fBitmap.width() && fBitmap.height()) 1.544 + { 1.545 + SkAutoCanvasRestore restore(canvas, true); 1.546 + SkPaint p; 1.547 + 1.548 + p.setFilterType(SkPaint::kBilinear_FilterType); 1.549 + canvas->scale( this->width() / fBitmap.width(), 1.550 + this->height() / fBitmap.height(), 1.551 + 0, 0); 1.552 + canvas->drawBitmap(fBitmap, 0, 0, p); 1.553 + } 1.554 +} 1.555 + 1.556 +void SkBitmapView::onInflate(const SkDOM& dom, const SkDOM::Node* node) 1.557 +{ 1.558 + this->INHERITED::onInflate(dom, node); 1.559 + 1.560 + const char* src = dom.findAttr(node, "src"); 1.561 + if (src) 1.562 + (void)this->loadBitmapFromFile(src); 1.563 +} 1.564 + 1.565 +#endif