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