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 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: 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 54 ~TransitionView(){ 55 //SkDebugf("--deleted transition\n"); 56 } 57 58 virtual void requestMenu(SkOSMenu* menu) { 59 if (SampleView::IsSampleView(fNext)) 60 ((SampleView*)fNext)->requestMenu(menu); 61 } 62 63 protected: 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 } 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 } 108 virtual void onDrawBackground(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 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 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