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 "SkBlurMaskFilter.h"
    238 #include "SkEmbossMaskFilter.h"
    239 
    240 static 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 
    261 void 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 
    312 SkView::Click* SkPushButtonWidget::onFindClickHandler(SkScalar x, SkScalar y, unsigned modi)
    313 {
    314     this->acceptFocus();
    315     return new Click(this);
    316 }
    317 
    318 bool 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 
    337 SkStaticTextView::SkStaticTextView(U32 flags) : SkView(flags)
    338 {
    339     fMargin.set(0, 0);
    340     fMode = kFixedSize_Mode;
    341     fSpacingAlign = SkTextBox::kStart_SpacingAlign;
    342 }
    343 
    344 SkStaticTextView::~SkStaticTextView()
    345 {
    346 }
    347 
    348 void 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 
    367 void 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 
    378 void SkStaticTextView::setSpacingAlign(SkTextBox::SpacingAlign align)
    379 {
    380     fSpacingAlign = SkToU8(align);
    381     this->inval(NULL);
    382 }
    383 
    384 void SkStaticTextView::getMargin(SkPoint* margin) const
    385 {
    386     if (margin)
    387         *margin = fMargin;
    388 }
    389 
    390 void 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 
    400 size_t SkStaticTextView::getText(SkString* text) const
    401 {
    402     if (text)
    403         *text = fText;
    404     return fText.size();
    405 }
    406 
    407 size_t SkStaticTextView::getText(char text[]) const
    408 {
    409     if (text)
    410         memcpy(text, fText.c_str(), fText.size());
    411     return fText.size();
    412 }
    413 
    414 void SkStaticTextView::setText(const SkString& text)
    415 {
    416     this->setText(text.c_str(), text.size());
    417 }
    418 
    419 void SkStaticTextView::setText(const char text[])
    420 {
    421     this->setText(text, strlen(text));
    422 }
    423 
    424 void 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 
    434 void SkStaticTextView::getPaint(SkPaint* paint) const
    435 {
    436     if (paint)
    437         *paint = fPaint;
    438 }
    439 
    440 void SkStaticTextView::setPaint(const SkPaint& paint)
    441 {
    442     if (fPaint != paint)
    443     {
    444         fPaint = paint;
    445         this->computeSize();
    446         this->inval(NULL);
    447     }
    448 }
    449 
    450 void 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 
    465 void 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 
    498 SkBitmapView::SkBitmapView(U32 flags) : SkView(flags)
    499 {
    500 }
    501 
    502 SkBitmapView::~SkBitmapView()
    503 {
    504 }
    505 
    506 bool SkBitmapView::getBitmap(SkBitmap* bitmap) const
    507 {
    508     if (bitmap)
    509         *bitmap = fBitmap;
    510     return fBitmap.getConfig() != SkBitmap::kNo_Config;
    511 }
    512 
    513 void SkBitmapView::setBitmap(const SkBitmap* bitmap, bool viewOwnsPixels)
    514 {
    515     if (bitmap)
    516     {
    517         fBitmap = *bitmap;
    518         fBitmap.setOwnsPixels(viewOwnsPixels);
    519     }
    520 }
    521 
    522 bool 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 
    535 void 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 
    551 void 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