| /* | 
 |  * Copyright 2011 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 | #include "TransitionView.h" | 
 |  | 
 | #include "OverView.h" | 
 | #include "SampleCode.h" | 
 | #include "SkView.h" | 
 | #include "SkCanvas.h" | 
 | #include "SkTime.h" | 
 | #include "SkInterpolator.h" | 
 |  | 
 | static const char gIsTransitionQuery[] = "is-transition"; | 
 | static const char gReplaceTransitionEvt[] = "replace-transition-view"; | 
 |  | 
 | bool is_transition(SkView* view) { | 
 |     SkEvent isTransition(gIsTransitionQuery); | 
 |     return view->doQuery(&isTransition); | 
 | } | 
 |  | 
 | class TransitionView : public SampleView { | 
 |     enum { | 
 |         // kDurationMS = 500 | 
 |         kDurationMS = 1 | 
 |     }; | 
 |  | 
 | public: | 
 |     TransitionView(SkView* prev, SkView* next, int direction) : fInterp(4, 2){ | 
 |         fAnimationDirection = (Direction)(1 << (direction % 8)); | 
 |  | 
 |         fPrev = prev; | 
 |         fPrev->setClipToBounds(false); | 
 |         fPrev->setVisibleP(true); | 
 |         (void)SampleView::SetUsePipe(fPrev, SkOSMenu::kOffState); | 
 |         //Not calling unref because fPrev is assumed to have been created, so | 
 |         //this will result in a transfer of ownership | 
 |         this->attachChildToBack(fPrev); | 
 |  | 
 |         fNext = next; | 
 |         fNext->setClipToBounds(true); | 
 |         fNext->setVisibleP(true); | 
 |         (void)SampleView::SetUsePipe(fNext, SkOSMenu::kOffState); | 
 |         //Calling unref because next is a newly created view and TransitionView | 
 |         //is now the sole owner of fNext | 
 |         this->attachChildToFront(fNext)->unref(); | 
 |  | 
 |         fDone = false; | 
 |         //SkDebugf("--created transition\n"); | 
 |     } | 
 |  | 
 |     ~TransitionView(){ | 
 |         //SkDebugf("--deleted transition\n"); | 
 |     } | 
 |  | 
 |     virtual void requestMenu(SkOSMenu* menu) { | 
 |         if (SampleView::IsSampleView(fNext)) | 
 |             ((SampleView*)fNext)->requestMenu(menu); | 
 |     } | 
 |  | 
 | protected: | 
 |     virtual bool onQuery(SkEvent* evt) { | 
 |         if (SampleCode::TitleQ(*evt)) { | 
 |             SkString title; | 
 |             if (SampleCode::RequestTitle(fNext, &title)) { | 
 |                 SampleCode::TitleR(evt, title.c_str()); | 
 |                 return true; | 
 |             } | 
 |             return false; | 
 |         } | 
 |         if (evt->isType(gIsTransitionQuery)) { | 
 |             return true; | 
 |         } | 
 |         return this->INHERITED::onQuery(evt); | 
 |     } | 
 |     virtual bool onEvent(const SkEvent& evt) { | 
 |         if (evt.isType(gReplaceTransitionEvt)) { | 
 |             SkView* prev = fPrev; | 
 |             prev->ref(); | 
 |  | 
 |             fPrev->detachFromParent(); | 
 |             fPrev = (SkView*)SkEventSink::FindSink(evt.getFast32()); | 
 |             (void)SampleView::SetUsePipe(fPrev, SkOSMenu::kOffState); | 
 |             //attach the new fPrev and call unref to balance the ref in onDraw | 
 |             this->attachChildToBack(fPrev)->unref(); | 
 |             this->inval(NULL); | 
 |  | 
 |             SkASSERT(1 == prev->getRefCnt()); | 
 |             prev->unref(); | 
 |             return true; | 
 |         } | 
 |         if (evt.isType("transition-done")) { | 
 |             fNext->setLoc(0, 0); | 
 |             fNext->setClipToBounds(false); | 
 |             SkEvent* evt = new SkEvent(gReplaceTransitionEvt, | 
 |                                        this->getParent()->getSinkID()); | 
 |             evt->setFast32(fNext->getSinkID()); | 
 |             //increate ref count of fNext so it survives detachAllChildren | 
 |             fNext->ref(); | 
 |             this->detachAllChildren(); | 
 |             evt->post(); | 
 |             return true; | 
 |         } | 
 |         return this->INHERITED::onEvent(evt); | 
 |     } | 
 |     virtual void onDrawBackground(SkCanvas* canvas) {} | 
 |     virtual void onDrawContent(SkCanvas* canvas) { | 
 |         if (fDone) | 
 |             return; | 
 |  | 
 |         if (is_overview(fNext) || is_overview(fPrev)) { | 
 |             fPipeState = SkOSMenu::kOffState; | 
 |         } | 
 |  | 
 |         SkScalar values[4]; | 
 |         SkInterpolator::Result result = fInterp.timeToValues(SkTime::GetMSecs(), values); | 
 |         //SkDebugf("transition %x %d pipe:%d\n", this, result, fUsePipe); | 
 |         //SkDebugf("%f %f %f %f %d\n", values[0], values[1], values[2], values[3], result); | 
 |         if (SkInterpolator::kNormal_Result == result) { | 
 |             fPrev->setLocX(values[kPrevX]); | 
 |             fPrev->setLocY(values[kPrevY]); | 
 |             fNext->setLocX(values[kNextX]); | 
 |             fNext->setLocY(values[kNextY]); | 
 |             this->inval(NULL); | 
 |         } | 
 |         else { | 
 |             (new SkEvent("transition-done", this->getSinkID()))->post(); | 
 |             fDone = true; | 
 |         } | 
 |     } | 
 |  | 
 |     virtual void onSizeChange() { | 
 |         this->INHERITED::onSizeChange(); | 
 |  | 
 |         fNext->setSize(this->width(), this->height()); | 
 |         fPrev->setSize(this->width(), this->height()); | 
 |  | 
 |         SkScalar lr = 0, ud = 0; | 
 |         if (fAnimationDirection & (kLeftDirection|kULDirection|kDLDirection)) | 
 |             lr = this->width(); | 
 |         if (fAnimationDirection & (kRightDirection|kURDirection|kDRDirection)) | 
 |             lr = -this->width(); | 
 |         if (fAnimationDirection & (kUpDirection|kULDirection|kURDirection)) | 
 |             ud = this->height(); | 
 |         if (fAnimationDirection & (kDownDirection|kDLDirection|kDRDirection)) | 
 |             ud = -this->height(); | 
 |  | 
 |         fBegin[kPrevX] = fBegin[kPrevY] = 0; | 
 |         fBegin[kNextX] = lr; | 
 |         fBegin[kNextY] = ud; | 
 |         fNext->setLocX(lr); | 
 |         fNext->setLocY(ud); | 
 |  | 
 |         if (is_transition(fPrev)) | 
 |             lr = ud = 0; | 
 |         fEnd[kPrevX] = -lr; | 
 |         fEnd[kPrevY] = -ud; | 
 |         fEnd[kNextX] = fEnd[kNextY] = 0; | 
 |         SkScalar blend[] = { 0.8f, 0.0f, | 
 |                              0.0f, SK_Scalar1 }; | 
 |         fInterp.setKeyFrame(0, SkTime::GetMSecs(), fBegin, blend); | 
 |         fInterp.setKeyFrame(1, SkTime::GetMSecs()+kDurationMS, fEnd, blend); | 
 |     } | 
 |  | 
 | private: | 
 |     enum { | 
 |         kPrevX = 0, | 
 |         kPrevY = 1, | 
 |         kNextX = 2, | 
 |         kNextY = 3 | 
 |     }; | 
 |     SkView* fPrev; | 
 |     SkView* fNext; | 
 |     bool    fDone; | 
 |     SkInterpolator fInterp; | 
 |  | 
 |     enum Direction{ | 
 |         kUpDirection    = 1, | 
 |         kURDirection    = 1 << 1, | 
 |         kRightDirection = 1 << 2, | 
 |         kDRDirection    = 1 << 3, | 
 |         kDownDirection  = 1 << 4, | 
 |         kDLDirection    = 1 << 5, | 
 |         kLeftDirection  = 1 << 6, | 
 |         kULDirection    = 1 << 7 | 
 |     }; | 
 |  | 
 |     Direction fAnimationDirection; | 
 |     SkScalar fBegin[4]; | 
 |     SkScalar fEnd[4]; | 
 |  | 
 |     typedef SampleView INHERITED; | 
 | }; | 
 |  | 
 | SkView* create_transition(SkView* prev, SkView* next, int direction) { | 
 | #ifdef SK_BUILD_FOR_ANDROID | 
 |     // Disable transitions for Android | 
 |     return next; | 
 | #else | 
 |     return SkNEW_ARGS(TransitionView, (prev, next, direction)); | 
 | #endif | 
 | } |