Home | History | Annotate | Download | only in samplecode
      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