| /* | |
| * 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 | |
| } |