1/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SampleCode.h"
9#include "SkAnimTimer.h"
10#include "SkDrawable.h"
11#include "SkView.h"
12#include "SkCanvas.h"
13#include "SkDrawable.h"
14#include "SkPath.h"
15#include "SkRandom.h"
16#include "SkRSXform.h"
17#include "SkSurface.h"
18#include "SkGradientShader.h"
19
20const SkBlendMode gModes[] = {
21    SkBlendMode::kSrcOver,
22    SkBlendMode::kSrc,
23    SkBlendMode::kSrcIn,
24    SkBlendMode::kSrcOut,
25    SkBlendMode::kSrcATop,
26    SkBlendMode::kDstOver,
27    SkBlendMode::kDstIn,
28    SkBlendMode::kDstOut,
29    SkBlendMode::kDstATop,
30};
31const int N_Modes = SK_ARRAY_COUNT(gModes);
32
33class HasEventWig : public SkView {
34public:
35    void postWidgetEvent() {
36        SkEvent evt;
37        this->onPrepareWidEvent(&evt);
38        this->postToListeners(evt, 0);
39    }
40
41protected:
42    virtual void onPrepareWidEvent(SkEvent*) {}
43};
44
45static SkRandom gRand;
46
47class PushButtonWig : public HasEventWig {
48    SkString fLabel;
49    SkColor  fColor;
50    uint32_t fFast32;
51
52public:
53    PushButtonWig(const char label[], uint32_t fast) : fLabel(label) {
54        fColor = (gRand.nextU() & 0x7F7F7F7F) | SkColorSetARGB(0xFF, 0, 0, 0x80);
55        fFast32 = fast;
56    }
57
58protected:
59    void onPrepareWidEvent(SkEvent* evt) override {
60        evt->setType("push-button");
61        evt->setFast32(fFast32);
62        evt->setString("label", fLabel.c_str());
63    }
64
65//    bool onEvent(const SkEvent&) override;
66    void onDraw(SkCanvas* canvas) override {
67        SkRect r;
68        this->getLocalBounds(&r);
69        SkPaint paint;
70        paint.setAntiAlias(true);
71        paint.setColor(fColor);
72        canvas->drawRoundRect(r, 8, 8, paint);
73
74        paint.setColor(0xFFFFFFFF);
75        paint.setTextSize(16);
76        paint.setTextAlign(SkPaint::kCenter_Align);
77        paint.setLCDRenderText(true);
78        canvas->drawText(fLabel.c_str(), fLabel.size(), r.centerX(), r.fTop + 0.68f * r.height(), paint);
79    }
80
81    Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
82        return new Click(this);
83    }
84
85    bool onClick(Click* click) override {
86        SkRect target = SkRect::MakeXYWH(click->fCurr.x() - 1, click->fCurr.y() - 1, 3, 3);
87        SkRect r;
88        this->getLocalBounds(&r);
89        if (r.intersects(target)) {
90            fColor = SkColorSetA(fColor, 0x99);
91        } else {
92            fColor = SkColorSetA(fColor, 0xFF);
93        }
94        this->inval(nullptr);
95
96        if (click->fState == SkView::Click::kUp_State) {
97            this->postWidgetEvent();
98        }
99        return true;
100    }
101
102private:
103    typedef HasEventWig INHERITED;
104};
105
106
107class ModeDrawable : public SkDrawable {
108public:
109    ModeDrawable() : fMode(SkBlendMode::kSrcOver), fLoc(SkPoint::Make(0, 0)) {}
110
111    SkBlendMode fMode;
112    SkPoint     fLoc;
113
114    bool hitTest(SkScalar x, SkScalar y) {
115        SkRect target = SkRect::MakeXYWH(x - fLoc.x() - 1, y - fLoc.y() - 1, 3, 3);
116        return this->getBounds().intersects(target);
117    }
118};
119
120class CircDrawable : public ModeDrawable {
121    SkPaint fPaint;
122    SkRect  fBounds;
123
124public:
125    CircDrawable(SkScalar size, SkColor c) {
126        const SkColor colors[] = { 0, c };
127        fPaint.setShader(SkGradientShader::MakeRadial(SkPoint::Make(size/2, size/2), size/2,
128                                                                     colors, nullptr, 2,
129                                                                     SkShader::kClamp_TileMode));
130        fBounds = SkRect::MakeWH(size, size);
131    }
132
133protected:
134    SkRect onGetBounds() override {
135        return fBounds;
136    }
137
138    void onDraw(SkCanvas* canvas) override {
139        fPaint.setBlendMode(fMode);
140        canvas->save();
141        canvas->translate(fLoc.x(), fLoc.y());
142        canvas->drawOval(fBounds, fPaint);
143        canvas->restore();
144    }
145};
146
147class XferDemo : public SampleView {
148    enum {
149        N = 4
150    };
151
152    SkRect        fModeRect[N_Modes];
153    sk_sp<CircDrawable> fDrs[N];
154    CircDrawable* fSelected;
155
156    void addButtons() {
157        SkScalar x = 10;
158        SkScalar y = 10;
159        for (int i = 0; i < N_Modes; ++i) {
160            sk_sp<SkView> v(new PushButtonWig(SkBlendMode_Name(gModes[i]), (int)gModes[i]));
161            v->setSize(70, 25);
162            v->setLoc(x, y);
163            v->setVisibleP(true);
164            v->setEnabledP(true);
165            v->addListenerID(this->getSinkID());
166            this->attachChildToFront(v.get());
167            fModeRect[i] = SkRect::MakeXYWH(x, y + 28, 70, 2);
168            x += 80;
169        }
170    }
171
172public:
173    XferDemo() {
174        const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorBLACK };
175        for (int i = 0; i < N; ++i) {
176            fDrs[i].reset(new CircDrawable(200, colors[i]));
177            fDrs[i]->fLoc.set(100.f + i * 100, 100.f + i * 100);
178            fDrs[i]->fMode = SkBlendMode::kSrcOver;
179        }
180        fSelected = nullptr;
181
182        this->addButtons();
183    }
184
185protected:
186    bool onEvent(const SkEvent& evt) override {
187        if (evt.isType("push-button")) {
188            if (fSelected) {
189                fSelected->fMode = (SkBlendMode)evt.getFast32();
190                this->inval(nullptr);
191            }
192            return true;
193        }
194        return this->INHERITED::onEvent(evt);
195    }
196
197    bool onQuery(SkEvent* evt) override {
198        if (SampleCode::TitleQ(*evt)) {
199            SampleCode::TitleR(evt, "XferDemo");
200            return true;
201        }
202        return this->INHERITED::onQuery(evt);
203    }
204
205    void onDrawContent(SkCanvas* canvas) override {
206        SkPaint paint;
207        if (fSelected) {
208            for (int i = 0; i < N_Modes; ++i) {
209                if (fSelected->fMode == gModes[i]) {
210                    canvas->drawRect(fModeRect[i], paint);
211                    break;
212                }
213            }
214        }
215
216        canvas->saveLayer(nullptr, nullptr);
217        for (int i = 0; i < N; ++i) {
218            fDrs[i]->draw(canvas);
219        }
220        canvas->restore();
221    }
222
223    SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned) override {
224        fSelected = nullptr;
225        for (int i = N - 1; i >= 0; --i) {
226            if (fDrs[i]->hitTest(x, y)) {
227                fSelected = fDrs[i].get();
228                break;
229            }
230        }
231        this->inval(nullptr);
232        return fSelected ? new Click(this) : nullptr;
233    }
234
235    bool onClick(Click* click) override {
236        fSelected->fLoc.fX += click->fCurr.fX - click->fPrev.fX;
237        fSelected->fLoc.fY += click->fCurr.fY - click->fPrev.fY;
238        this->inval(nullptr);
239        return true;
240    }
241
242private:
243    typedef SampleView INHERITED;
244};
245
246//////////////////////////////////////////////////////////////////////////////
247
248DEF_SAMPLE( return new XferDemo; )
249