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