gfx/skia/trunk/src/views/SkWidgets.cpp

changeset 0
6474c204b198
     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

mercurial