• 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