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 "SampleCode.h"
9 #include "SkView.h"
10 #include "SkCanvas.h"
11 #include "SkGraphics.h"
12 #include "SkRandom.h"
13 
test_clearonlayers(SkCanvas * canvas)14 static void test_clearonlayers(SkCanvas* canvas) {
15     SkCanvas& c = *canvas;
16 
17     SkPaint paint;
18     paint.setColor(SK_ColorBLUE);
19     paint.setStyle(SkPaint::kStrokeAndFill_Style);
20     SkRect rect = SkRect::MakeXYWH(25, 25, 50, 50);
21     c.drawRect(rect, paint);
22 
23     c.clipRect(rect);
24 
25     c.saveLayer(nullptr, nullptr);
26     rect = SkRect::MakeXYWH(50, 10, 40, 80);
27     c.clipRect(rect, SkRegion::kUnion_Op);
28 
29     rect = SkRect::MakeXYWH(50, 0, 50, 100);
30     // You might draw something here, but it's not necessary.
31     // paint.setColor(SK_ColorRED);
32     // c.drawRect(rect, paint);
33     paint.setXfermodeMode(SkXfermode::kClear_Mode);
34     c.drawRect(rect, paint);
35     c.restore();
36 }
37 
test_strokerect(SkCanvas * canvas,const SkRect & r)38 static void test_strokerect(SkCanvas* canvas, const SkRect& r) {
39     SkPaint p;
40 
41     p.setAntiAlias(true);
42     p.setStyle(SkPaint::kStroke_Style);
43     p.setStrokeWidth(4);
44 
45     canvas->drawRect(r, p);
46 
47     SkPath path;
48     SkRect r2(r);
49     r2.offset(18, 0);
50     path.addRect(r2);
51 
52     canvas->drawPath(path, p);
53 }
54 
test_strokerect(SkCanvas * canvas)55 static void test_strokerect(SkCanvas* canvas) {
56     canvas->drawColor(SK_ColorWHITE);
57 
58     SkRect r;
59 
60     r.set(10, 10, 14, 14);
61     r.offset(0.25f, 0.3333f);
62     test_strokerect(canvas, r);
63     canvas->translate(0, 20);
64 
65     r.set(10, 10, 14.5f, 14.5f);
66     r.offset(0.25f, 0.3333f);
67     test_strokerect(canvas, r);
68     canvas->translate(0, 20);
69 
70     r.set(10, 10, 14.5f, 20);
71     r.offset(0.25f, 0.3333f);
72     test_strokerect(canvas, r);
73     canvas->translate(0, 20);
74 
75     r.set(10, 10, 20, 14.5f);
76     r.offset(0.25f, 0.3333f);
77     test_strokerect(canvas, r);
78     canvas->translate(0, 20);
79 
80     r.set(10, 10, 20, 20);
81     r.offset(0.25f, 0.3333f);
82     test_strokerect(canvas, r);
83     canvas->translate(0, 20);
84 
85 }
86 
87 class Draw : public SkRefCnt {
88 public:
Draw()89     Draw() : fFlags(0) {}
90 
91     enum Flags {
92         kSelected_Flag  = 1 << 0
93     };
getFlags() const94     int getFlags() const { return fFlags; }
95     void setFlags(int flags);
96 
isSelected() const97     bool isSelected() const { return SkToBool(fFlags & kSelected_Flag); }
setSelected(bool pred)98     void setSelected(bool pred) {
99         if (pred) {
100             fFlags |= kSelected_Flag;
101         } else {
102             fFlags &= ~kSelected_Flag;
103         }
104     }
105 
draw(SkCanvas * canvas)106     void draw(SkCanvas* canvas) {
107         int sc = canvas->save();
108         this->onDraw(canvas);
109         canvas->restoreToCount(sc);
110 
111         if (this->isSelected()) {
112             this->drawSelection(canvas);
113         }
114     }
115 
drawSelection(SkCanvas * canvas)116     void drawSelection(SkCanvas* canvas) {
117         int sc = canvas->save();
118         this->onDrawSelection(canvas);
119         canvas->restoreToCount(sc);
120     }
121 
getBounds(SkRect * bounds)122     void getBounds(SkRect* bounds) {
123         this->onGetBounds(bounds);
124     }
125 
hitTest(SkScalar x,SkScalar y)126     bool hitTest(SkScalar x, SkScalar y) {
127         return this->onHitTest(x, y);
128     }
129 
offset(SkScalar dx,SkScalar dy)130     void offset(SkScalar dx, SkScalar dy) {
131         if (dx || dy) {
132             this->onOffset(dx, dy);
133         }
134     }
135 
136 protected:
137     virtual void onDraw(SkCanvas*) = 0;
138     virtual void onGetBounds(SkRect*) = 0;
139     virtual void onOffset(SkScalar dx, SkScalar dy) = 0;
onDrawSelection(SkCanvas * canvas)140     virtual void onDrawSelection(SkCanvas* canvas) {
141         SkRect r;
142         this->getBounds(&r);
143         SkPaint paint;
144         SkPoint pts[4];
145         r.toQuad(pts);
146         paint.setStrokeWidth(SkIntToScalar(10));
147         paint.setColor(0x80FF8844);
148         paint.setStrokeCap(SkPaint::kRound_Cap);
149         canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, pts, paint);
150     }
onHitTest(SkScalar x,SkScalar y)151     virtual bool onHitTest(SkScalar x, SkScalar y) {
152         SkRect bounds;
153         this->getBounds(&bounds);
154         return bounds.contains(x, y);
155     }
156 
157 private:
158     int fFlags;
159 };
160 
161 class RDraw : public Draw {
162 public:
163     enum Style {
164         kRect_Style,
165         kOval_Style,
166         kRRect_Style,
167         kFrame_Style
168     };
169 
RDraw(const SkRect & r,Style s)170     RDraw(const SkRect& r, Style s) : fRect(r), fStyle(s) {}
171 
setRect(const SkRect & r)172     void setRect(const SkRect& r) {
173         fRect = r;
174     }
175 
setPaint(const SkPaint & p)176     void setPaint(const SkPaint& p) {
177         fPaint = p;
178     }
179 
180 protected:
onDraw(SkCanvas * canvas)181     virtual void onDraw(SkCanvas* canvas) {
182         switch (fStyle) {
183             case kRect_Style:
184                 canvas->drawRect(fRect, fPaint);
185                 break;
186             case kOval_Style:
187                 canvas->drawOval(fRect, fPaint);
188                 break;
189             case kRRect_Style: {
190                 SkScalar rx = fRect.width() / 5;
191                 SkScalar ry = fRect.height() / 5;
192                 if (rx < ry) {
193                     ry = rx;
194                 } else {
195                     rx = ry;
196                 }
197                 canvas->drawRoundRect(fRect, rx, ry, fPaint);
198                 break;
199             }
200             case kFrame_Style: {
201                 SkPath path;
202                 path.addOval(fRect, SkPath::kCW_Direction);
203                 SkRect r = fRect;
204                 r.inset(fRect.width()/6, 0);
205                 path.addOval(r, SkPath::kCCW_Direction);
206                 canvas->drawPath(path, fPaint);
207                 break;
208             }
209         }
210     }
211 
onGetBounds(SkRect * bounds)212     virtual void onGetBounds(SkRect* bounds) {
213         *bounds = fRect;
214     }
215 
onOffset(SkScalar dx,SkScalar dy)216     virtual void onOffset(SkScalar dx, SkScalar dy) {
217         fRect.offset(dx, dy);
218     }
219 
220 private:
221     SkRect  fRect;
222     SkPaint fPaint;
223     Style   fStyle;
224 };
225 
226 class DrawFactory {
227 public:
DrawFactory()228     DrawFactory() {
229         fPaint.setAntiAlias(true);
230     }
231 
getPaint() const232     const SkPaint& getPaint() const { return fPaint; }
233 
setPaint(const SkPaint & p)234     void setPaint(const SkPaint& p) {
235         fPaint = p;
236     }
237 
238     virtual Draw* create(const SkPoint&, const SkPoint&) = 0;
239 
240 private:
241     SkPaint fPaint;
242 };
243 
244 class RectFactory : public DrawFactory {
245 public:
create(const SkPoint & p0,const SkPoint & p1)246     virtual Draw* create(const SkPoint& p0, const SkPoint& p1) {
247         SkRect r;
248         r.set(p0.x(), p0.y(), p1.x(), p1.y());
249         r.sort();
250 
251 //        RDraw* d = new RDraw(r, RDraw::kRRect_Style);
252         RDraw* d = new RDraw(r, RDraw::kFrame_Style);
253         d->setPaint(this->getPaint());
254         return d;
255     }
256 };
257 
258 class DrawView : public SkView {
259     Draw*           fDraw;
260     DrawFactory*    fFactory;
261     SkRandom        fRand;
262     SkTDArray<Draw*> fList;
263 
264 public:
DrawView()265     DrawView() : fDraw(nullptr) {
266         fFactory = new RectFactory;
267     }
268 
~DrawView()269     virtual ~DrawView() {
270         fList.unrefAll();
271         SkSafeUnref(fDraw);
272         delete fFactory;
273     }
274 
setDraw(Draw * d)275     Draw* setDraw(Draw* d) {
276         SkRefCnt_SafeAssign(fDraw, d);
277         return d;
278     }
279 
randColor()280     SkColor randColor() {
281         return (SkColor)fRand.nextU() | 0xFF000000;
282     }
283 
hitTestList(SkScalar x,SkScalar y) const284     Draw* hitTestList(SkScalar x, SkScalar y) const {
285         Draw** first = fList.begin();
286         for (Draw** iter = fList.end(); iter > first;) {
287             --iter;
288             if ((*iter)->hitTest(x, y)) {
289                 return *iter;
290             }
291         }
292         return nullptr;
293     }
294 
295 protected:
296     // overrides from SkEventSink
onQuery(SkEvent * evt)297     virtual bool onQuery(SkEvent* evt) {
298         if (SampleCode::TitleQ(*evt)) {
299             SampleCode::TitleR(evt, "Draw");
300             return true;
301         }
302         return this->INHERITED::onQuery(evt);
303     }
304 
drawBG(SkCanvas * canvas)305     void drawBG(SkCanvas* canvas) {
306         canvas->drawColor(0xFFDDDDDD);
307 //        canvas->drawColor(SK_ColorWHITE);
308     }
309 
onDraw(SkCanvas * canvas)310     virtual void onDraw(SkCanvas* canvas) {
311         this->drawBG(canvas);
312         test_clearonlayers(canvas); return;
313      //   test_strokerect(canvas); return;
314 
315         for (Draw** iter = fList.begin(); iter < fList.end(); iter++) {
316             (*iter)->draw(canvas);
317         }
318         if (fDraw) {
319             fDraw->draw(canvas);
320         }
321     }
322 
onFindClickHandler(SkScalar x,SkScalar y)323     virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
324         for (Draw** iter = fList.begin(); iter < fList.end(); iter++) {
325             (*iter)->setSelected(false);
326         }
327 
328         Click* c = new Click(this);
329         Draw* d = this->hitTestList(x, y);
330         if (d) {
331             d->setSelected(true);
332             c->setType("dragger");
333         } else {
334             c->setType("maker");
335         }
336         return c;
337     }
338 
onClick(Click * click)339     virtual bool onClick(Click* click) {
340         if (Click::kUp_State == click->fState) {
341             if (click->isType("maker")) {
342                 if (SkPoint::Distance(click->fOrig, click->fCurr) > SkIntToScalar(3)) {
343                     *fList.append() = fDraw;
344                 } else {
345                     fDraw->unref();
346                 }
347                 fDraw = nullptr;
348             }
349             return true;
350         }
351 
352         if (Click::kDown_State == click->fState) {
353             SkPaint p = fFactory->getPaint();
354             p.setColor(this->randColor());
355             fFactory->setPaint(p);
356         }
357 
358         if (click->isType("maker")) {
359             this->setDraw(fFactory->create(click->fOrig, click->fCurr))->unref();
360         } else if (click->isType("dragger")) {
361             for (Draw** iter = fList.begin(); iter < fList.end(); iter++) {
362                 if ((*iter)->isSelected()) {
363                     (*iter)->offset(click->fCurr.x() - click->fPrev.x(),
364                                     click->fCurr.y() - click->fPrev.y());
365                 }
366             }
367         }
368         this->inval(nullptr);
369         return true;
370     }
371 
372 private:
373     typedef SkView INHERITED;
374 };
375 
376 //////////////////////////////////////////////////////////////////////////////
377 
MyFactory()378 static SkView* MyFactory() { return new DrawView; }
379 static SkViewRegister reg(MyFactory);
380