Home | History | Annotate | Download | only in views
      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] = NULL;
     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 == NULL)
     92         gSkinSuite = new SkinSuite;
     93     return gSkinSuite->get(st);
     94 #else
     95     return NULL;
     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(NULL);
    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")) != NULL)
    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(NULL);
    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(NULL);
    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(), NULL, NULL);
    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, NULL, &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(NULL);
    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(NULL);
    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(NULL);
    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(NULL);
    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")) != NULL)
    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