1/*
2 * Copyright 2011 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#include "SampleCode.h"
8#include "SkView.h"
9#include "SkCanvas.h"
10#include "SkTime.h"
11#include "SkInterpolator.h"
12
13extern bool is_overview(SkView* view);
14
15static const char gIsTransitionQuery[] = "is-transition";
16static const char gReplaceTransitionEvt[] = "replace-transition-view";
17
18bool is_transition(SkView* view) {
19    SkEvent isTransition(gIsTransitionQuery);
20    return view->doQuery(&isTransition);
21}
22
23class TransitionView : public SampleView {
24public:
25    TransitionView(SkView* prev, SkView* next, int direction) : fInterp(4, 2){
26        fAnimationDirection = (Direction)(1 << (direction % 8));
27
28        fPrev = prev;
29        fPrev->setClipToBounds(false);
30        fPrev->setVisibleP(true);
31        (void)SampleView::SetUsePipe(fPrev, false);
32        //Not calling unref because fPrev is assumed to have been created, so
33        //this will result in a transfer of ownership
34        this->attachChildToBack(fPrev);
35
36        fNext = next;
37        fNext->setClipToBounds(true);
38        fNext->setVisibleP(true);
39        (void)SampleView::SetUsePipe(fNext, false);
40        //Calling unref because next is a newly created view and TransitionView
41        //is now the sole owner of fNext
42        this->attachChildToFront(fNext)->unref();
43
44        fDone = false;
45        //SkDebugf("--created transition\n");
46    }
47
48    ~TransitionView(){
49        //SkDebugf("--deleted transition\n");
50    }
51
52    virtual void requestMenu(SkOSMenu* menu) {
53        if (SampleView::IsSampleView(fNext))
54            ((SampleView*)fNext)->requestMenu(menu);
55    }
56
57protected:
58    virtual bool onQuery(SkEvent* evt) {
59        if (SampleCode::TitleQ(*evt)) {
60            SkString title;
61            if (SampleCode::RequestTitle(fNext, &title)) {
62                SampleCode::TitleR(evt, title.c_str());
63                return true;
64            }
65            return false;
66        }
67        if (evt->isType(gIsTransitionQuery)) {
68            return true;
69        }
70        return this->INHERITED::onQuery(evt);
71    }
72    virtual bool onEvent(const SkEvent& evt) {
73        if (evt.isType(gReplaceTransitionEvt)) {
74            fPrev->detachFromParent();
75            fPrev = (SkView*)SkEventSink::FindSink(evt.getFast32());
76            (void)SampleView::SetUsePipe(fPrev, false);
77            //attach the new fPrev and call unref to balance the ref in onDraw
78            this->attachChildToBack(fPrev)->unref();
79            this->inval(NULL);
80            return true;
81        }
82        if (evt.isType("transition-done")) {
83            fNext->setLoc(0, 0);
84            fNext->setClipToBounds(false);
85            SkEvent* evt = new SkEvent(gReplaceTransitionEvt,
86                                       this->getParent()->getSinkID());
87            evt->setFast32(fNext->getSinkID());
88            //increate ref count of fNext so it survives detachAllChildren
89            fNext->ref();
90            this->detachAllChildren();
91            evt->post();
92            return true;
93        }
94        return this->INHERITED::onEvent(evt);
95    }
96    virtual void onDrawBackground(SkCanvas* canvas) {}
97    virtual void onDrawContent(SkCanvas* canvas) {
98        if (fDone)
99            return;
100
101        if (is_overview(fNext) || is_overview(fPrev)) {
102            fUsePipe = false;
103        }
104
105        SkScalar values[4];
106        SkInterpolator::Result result = fInterp.timeToValues(SkTime::GetMSecs(), values);
107        //SkDebugf("transition %x %d pipe:%d\n", this, result, fUsePipe);
108        //SkDebugf("%f %f %f %f %d\n", values[0], values[1], values[2], values[3], result);
109        if (SkInterpolator::kNormal_Result == result) {
110            fPrev->setLocX(values[kPrevX]);
111            fPrev->setLocY(values[kPrevY]);
112            fNext->setLocX(values[kNextX]);
113            fNext->setLocY(values[kNextY]);
114            this->inval(NULL);
115        }
116        else {
117            (new SkEvent("transition-done", this->getSinkID()))->post();
118            fDone = true;
119        }
120    }
121
122    virtual void onSizeChange() {
123        this->INHERITED::onSizeChange();
124
125        fNext->setSize(this->width(), this->height());
126        fPrev->setSize(this->width(), this->height());
127
128        SkScalar lr = 0, ud = 0;
129        if (fAnimationDirection & (kLeftDirection|kULDirection|kDLDirection))
130            lr = this->width();
131        if (fAnimationDirection & (kRightDirection|kURDirection|kDRDirection))
132            lr = -this->width();
133        if (fAnimationDirection & (kUpDirection|kULDirection|kURDirection))
134            ud = this->height();
135        if (fAnimationDirection & (kDownDirection|kDLDirection|kDRDirection))
136            ud = -this->height();
137
138        fBegin[kPrevX] = fBegin[kPrevY] = 0;
139        fBegin[kNextX] = lr;
140        fBegin[kNextY] = ud;
141        fNext->setLocX(lr);
142        fNext->setLocY(ud);
143
144        if (is_transition(fPrev))
145            lr = ud = 0;
146        fEnd[kPrevX] = -lr;
147        fEnd[kPrevY] = -ud;
148        fEnd[kNextX] = fEnd[kNextY] = 0;
149        SkScalar blend[] = {0.8, 0.0, 0.0, 1.0};
150        fInterp.setKeyFrame(0, SkTime::GetMSecs(), fBegin, blend);
151        fInterp.setKeyFrame(1, SkTime::GetMSecs()+500, fEnd, blend);
152    }
153
154private:
155    enum {
156        kPrevX = 0,
157        kPrevY = 1,
158        kNextX = 2,
159        kNextY = 3
160    };
161    SkView* fPrev;
162    SkView* fNext;
163    bool    fDone;
164    SkInterpolator fInterp;
165
166    enum Direction{
167        kUpDirection    = 1,
168        kURDirection    = 1 << 1,
169        kRightDirection = 1 << 2,
170        kDRDirection    = 1 << 3,
171        kDownDirection  = 1 << 4,
172        kDLDirection    = 1 << 5,
173        kLeftDirection  = 1 << 6,
174        kULDirection    = 1 << 7
175    };
176
177    Direction fAnimationDirection;
178    SkScalar fBegin[4];
179    SkScalar fEnd[4];
180
181    typedef SampleView INHERITED;
182};
183
184SkView* create_transition(SkView* prev, SkView* next, int direction) {
185    return SkNEW_ARGS(TransitionView, (prev, next, direction));
186};