SampleDraw.cpp revision dd0cd34067d103ace7c6739405cb7885d8ad3fb2
1ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include "SampleCode.h"
2ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include "SkView.h"
3ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include "SkCanvas.h"
4ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include "SkGraphics.h"
5ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include "SkRandom.h"
6ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
7ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuangclass Draw : public SkRefCnt {
8ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuangpublic:
9ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    Draw() : fFlags(0) {}
10ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
11ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    enum Flags {
12ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        kSelected_Flag  = 1 << 0
13ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    };
14ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    int getFlags() const { return fFlags; }
15ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    void setFlags(int flags);
16ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
17ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    bool isSelected() const { return SkToBool(fFlags & kSelected_Flag); }
18ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    void setSelected(bool pred) {
19ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        if (pred) {
20ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang            fFlags |= kSelected_Flag;
21ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        } else {
22ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang            fFlags &= ~kSelected_Flag;
23ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        }
24ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    }
25ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
26ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    void draw(SkCanvas* canvas) {
27ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        int sc = canvas->save();
28ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        this->onDraw(canvas);
29ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        canvas->restoreToCount(sc);
30ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
31ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        if (this->isSelected()) {
32ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang            this->drawSelection(canvas);
33ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        }
34ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    }
35ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
36ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    void drawSelection(SkCanvas* canvas) {
37ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        int sc = canvas->save();
38ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        this->onDrawSelection(canvas);
39ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        canvas->restoreToCount(sc);
40ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    }
41ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
42ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    void getBounds(SkRect* bounds) {
43ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        this->onGetBounds(bounds);
44ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    }
45ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
46ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    bool hitTest(SkScalar x, SkScalar y) {
47ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        return this->onHitTest(x, y);
48ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    }
49ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
50ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    void offset(SkScalar dx, SkScalar dy) {
51ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        if (dx || dy) {
52ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang            this->onOffset(dx, dy);
53ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang        }
54ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    }
55ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
56ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuangprotected:
57ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    virtual void onDraw(SkCanvas*) = 0;
58ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang    virtual void onGetBounds(SkRect*) = 0;
59    virtual void onOffset(SkScalar dx, SkScalar dy) = 0;
60    virtual void onDrawSelection(SkCanvas* canvas) {
61        SkRect r;
62        this->getBounds(&r);
63        SkPaint paint;
64        SkPoint pts[4];
65        r.toQuad(pts);
66        paint.setStrokeWidth(SkIntToScalar(10));
67        paint.setColor(0x80FF8844);
68        paint.setStrokeCap(SkPaint::kRound_Cap);
69        canvas->drawPoints(SkCanvas::kPoints_PointMode, 4, pts, paint);
70    }
71    virtual bool onHitTest(SkScalar x, SkScalar y) {
72        SkRect bounds;
73        this->getBounds(&bounds);
74        return bounds.contains(x, y);
75    }
76
77private:
78    int fFlags;
79};
80
81class RDraw : public Draw {
82public:
83    enum Style {
84        kRect_Style,
85        kOval_Style,
86        kRRect_Style
87    };
88
89    RDraw(const SkRect& r, Style s) : fRect(r), fStyle(s) {}
90
91    void setRect(const SkRect& r) {
92        fRect = r;
93    }
94
95    void setPaint(const SkPaint& p) {
96        fPaint = p;
97    }
98
99protected:
100    virtual void onDraw(SkCanvas* canvas) {
101        switch (fStyle) {
102            case kRect_Style:
103                canvas->drawRect(fRect, fPaint);
104                break;
105            case kOval_Style:
106                canvas->drawOval(fRect, fPaint);
107                break;
108            case kRRect_Style: {
109                SkScalar rx = fRect.width() / 5;
110                SkScalar ry = fRect.height() / 5;
111                if (rx < ry) {
112                    ry = rx;
113                } else {
114                    rx = ry;
115                }
116                canvas->drawRoundRect(fRect, rx, ry, fPaint);
117                break;
118            }
119        }
120    }
121
122    virtual void onGetBounds(SkRect* bounds) {
123        *bounds = fRect;
124    }
125
126    virtual void onOffset(SkScalar dx, SkScalar dy) {
127        fRect.offset(dx, dy);
128    }
129
130private:
131    SkRect  fRect;
132    SkPaint fPaint;
133    Style   fStyle;
134};
135
136class DrawFactory {
137public:
138    DrawFactory() {
139        fPaint.setAntiAlias(true);
140    }
141
142    const SkPaint& getPaint() const { return fPaint; }
143
144    void setPaint(const SkPaint& p) {
145        fPaint = p;
146    }
147
148    virtual Draw* create(const SkPoint&, const SkPoint&) = 0;
149
150private:
151    SkPaint fPaint;
152};
153
154class RectFactory : public DrawFactory {
155public:
156    virtual Draw* create(const SkPoint& p0, const SkPoint& p1) {
157        SkRect r;
158        r.set(p0.x(), p0.y(), p1.x(), p1.y());
159        r.sort();
160
161        RDraw* d = new RDraw(r, RDraw::kRRect_Style);
162        d->setPaint(this->getPaint());
163        return d;
164    }
165};
166
167class DrawView : public SkView {
168    Draw*           fDraw;
169    DrawFactory*    fFactory;
170    SkRandom        fRand;
171    SkTDArray<Draw*> fList;
172
173public:
174    DrawView() : fDraw(NULL) {
175        fFactory = new RectFactory;
176    }
177
178    virtual ~DrawView() {
179        fList.unrefAll();
180        SkSafeUnref(fDraw);
181    }
182
183    Draw* setDraw(Draw* d) {
184        SkRefCnt_SafeAssign(fDraw, d);
185        return d;
186    }
187
188    SkColor randColor() {
189        return (SkColor)fRand.nextU() | 0xFF000000;
190    }
191
192    Draw* hitTestList(SkScalar x, SkScalar y) const {
193        Draw** first = fList.begin();
194        for (Draw** iter = fList.end(); iter > first;) {
195            --iter;
196            if ((*iter)->hitTest(x, y)) {
197                return *iter;
198            }
199        }
200        return NULL;
201    }
202
203protected:
204    // overrides from SkEventSink
205    virtual bool onQuery(SkEvent* evt) {
206        if (SampleCode::TitleQ(*evt)) {
207            SampleCode::TitleR(evt, "Draw");
208            return true;
209        }
210        return this->INHERITED::onQuery(evt);
211    }
212
213    void drawBG(SkCanvas* canvas) {
214        canvas->drawColor(0xFFDDDDDD);
215//        canvas->drawColor(SK_ColorWHITE);
216    }
217
218    virtual void onDraw(SkCanvas* canvas) {
219        this->drawBG(canvas);
220
221        for (Draw** iter = fList.begin(); iter < fList.end(); iter++) {
222            (*iter)->draw(canvas);
223        }
224        if (fDraw) {
225            fDraw->draw(canvas);
226        }
227    }
228
229    virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
230        for (Draw** iter = fList.begin(); iter < fList.end(); iter++) {
231            (*iter)->setSelected(false);
232        }
233
234        Click* c = new Click(this);
235        Draw* d = this->hitTestList(x, y);
236        if (d) {
237            d->setSelected(true);
238            c->setType("dragger");
239        } else {
240            c->setType("maker");
241        }
242        return c;
243    }
244
245    virtual bool onClick(Click* click) {
246        if (Click::kUp_State == click->fState) {
247            if (click->isType("maker")) {
248                if (SkPoint::Distance(click->fOrig, click->fCurr) > SkIntToScalar(3)) {
249                    *fList.append() = fDraw;
250                } else {
251                    fDraw->unref();
252                }
253                fDraw = NULL;
254            }
255            return true;
256        }
257
258        if (Click::kDown_State == click->fState) {
259            SkPaint p = fFactory->getPaint();
260            p.setColor(this->randColor());
261            fFactory->setPaint(p);
262        }
263
264        if (click->isType("maker")) {
265            this->setDraw(fFactory->create(click->fOrig, click->fCurr))->unref();
266        } else if (click->isType("dragger")) {
267            for (Draw** iter = fList.begin(); iter < fList.end(); iter++) {
268                if ((*iter)->isSelected()) {
269                    (*iter)->offset(click->fCurr.x() - click->fPrev.x(),
270                                    click->fCurr.y() - click->fPrev.y());
271                }
272            }
273        }
274        this->inval(NULL);
275        return true;
276    }
277
278private:
279    typedef SkView INHERITED;
280};
281
282//////////////////////////////////////////////////////////////////////////////
283
284static SkView* MyFactory() { return new DrawView; }
285static SkViewRegister reg(MyFactory);
286
287