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