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
14static 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(NULL, NULL);
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
38static 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
55static 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
87class Draw : public SkRefCnt {
88public:
89    Draw() : fFlags(0) {}
90
91    enum Flags {
92        kSelected_Flag  = 1 << 0
93    };
94    int getFlags() const { return fFlags; }
95    void setFlags(int flags);
96
97    bool isSelected() const { return SkToBool(fFlags & kSelected_Flag); }
98    void setSelected(bool pred) {
99        if (pred) {
100            fFlags |= kSelected_Flag;
101        } else {
102            fFlags &= ~kSelected_Flag;
103        }
104    }
105
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
116    void drawSelection(SkCanvas* canvas) {
117        int sc = canvas->save();
118        this->onDrawSelection(canvas);
119        canvas->restoreToCount(sc);
120    }
121
122    void getBounds(SkRect* bounds) {
123        this->onGetBounds(bounds);
124    }
125
126    bool hitTest(SkScalar x, SkScalar y) {
127        return this->onHitTest(x, y);
128    }
129
130    void offset(SkScalar dx, SkScalar dy) {
131        if (dx || dy) {
132            this->onOffset(dx, dy);
133        }
134    }
135
136protected:
137    virtual void onDraw(SkCanvas*) = 0;
138    virtual void onGetBounds(SkRect*) = 0;
139    virtual void onOffset(SkScalar dx, SkScalar dy) = 0;
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    }
151    virtual bool onHitTest(SkScalar x, SkScalar y) {
152        SkRect bounds;
153        this->getBounds(&bounds);
154        return bounds.contains(x, y);
155    }
156
157private:
158    int fFlags;
159};
160
161class RDraw : public Draw {
162public:
163    enum Style {
164        kRect_Style,
165        kOval_Style,
166        kRRect_Style,
167        kFrame_Style
168    };
169
170    RDraw(const SkRect& r, Style s) : fRect(r), fStyle(s) {}
171
172    void setRect(const SkRect& r) {
173        fRect = r;
174    }
175
176    void setPaint(const SkPaint& p) {
177        fPaint = p;
178    }
179
180protected:
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
212    virtual void onGetBounds(SkRect* bounds) {
213        *bounds = fRect;
214    }
215
216    virtual void onOffset(SkScalar dx, SkScalar dy) {
217        fRect.offset(dx, dy);
218    }
219
220private:
221    SkRect  fRect;
222    SkPaint fPaint;
223    Style   fStyle;
224};
225
226class DrawFactory {
227public:
228    DrawFactory() {
229        fPaint.setAntiAlias(true);
230    }
231
232    const SkPaint& getPaint() const { return fPaint; }
233
234    void setPaint(const SkPaint& p) {
235        fPaint = p;
236    }
237
238    virtual Draw* create(const SkPoint&, const SkPoint&) = 0;
239
240private:
241    SkPaint fPaint;
242};
243
244class RectFactory : public DrawFactory {
245public:
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
258class DrawView : public SkView {
259    Draw*           fDraw;
260    DrawFactory*    fFactory;
261    SkRandom        fRand;
262    SkTDArray<Draw*> fList;
263
264public:
265    DrawView() : fDraw(NULL) {
266        fFactory = new RectFactory;
267    }
268
269    virtual ~DrawView() {
270        fList.unrefAll();
271        SkSafeUnref(fDraw);
272        delete fFactory;
273    }
274
275    Draw* setDraw(Draw* d) {
276        SkRefCnt_SafeAssign(fDraw, d);
277        return d;
278    }
279
280    SkColor randColor() {
281        return (SkColor)fRand.nextU() | 0xFF000000;
282    }
283
284    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 NULL;
293    }
294
295protected:
296    // overrides from SkEventSink
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
305    void drawBG(SkCanvas* canvas) {
306        canvas->drawColor(0xFFDDDDDD);
307//        canvas->drawColor(SK_ColorWHITE);
308    }
309
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
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
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 = NULL;
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(NULL);
369        return true;
370    }
371
372private:
373    typedef SkView INHERITED;
374};
375
376//////////////////////////////////////////////////////////////////////////////
377
378static SkView* MyFactory() { return new DrawView; }
379static SkViewRegister reg(MyFactory);
380