• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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