|  |  | 
|  | /* | 
|  | * 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 "SkWidgetViews.h" | 
|  | #include "SkAnimator.h" | 
|  | #include "SkCanvas.h" | 
|  | #include "SkPaint.h" | 
|  | #include "SkStream.h" | 
|  | #include "SkSystemEventTypes.h" | 
|  |  | 
|  | /* | 
|  | I have moved this to SkWidgetViews.h | 
|  | enum SkinEnum { | 
|  | kButton_SkinEnum, | 
|  | kProgress_SkinEnum, | 
|  | kScroll_SkinEnum, | 
|  | kStaticText_SkinEnum, | 
|  |  | 
|  | kSkinEnumCount | 
|  | }; | 
|  | */ | 
|  |  | 
|  | const char* get_skin_enum_path(SkinEnum se) | 
|  | { | 
|  | SkASSERT((unsigned)se < kSkinEnumCount); | 
|  |  | 
|  | static const char* gSkinPaths[] = { | 
|  | "common/default/default/skins/border3.xml", | 
|  | "common/default/default/skins/button.xml", | 
|  | "common/default/default/skins/progressBar.xml", | 
|  | "common/default/default/skins/scrollBar.xml", | 
|  | "common/default/default/skins/statictextpaint.xml" | 
|  | }; | 
|  |  | 
|  | return gSkinPaths[se]; | 
|  | } | 
|  |  | 
|  | void init_skin_anim(const char path[], SkAnimator* anim) { | 
|  | SkASSERT(path && anim); | 
|  |  | 
|  | SkAutoTUnref<SkStream> stream(SkStream::NewFromFile(path)); | 
|  | if (!stream.get()) { | 
|  | SkDEBUGF(("init_skin_anim: loading skin failed <%s>\n", path)); | 
|  | sk_throw(); | 
|  | } | 
|  |  | 
|  | if (!anim->decodeStream(stream)) { | 
|  | SkDEBUGF(("init_skin_anim: decoding skin failed <%s>\n", path)); | 
|  | sk_throw(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void init_skin_anim(SkinEnum se, SkAnimator* anim) | 
|  | { | 
|  | init_skin_anim(get_skin_enum_path(se), anim); | 
|  | } | 
|  |  | 
|  | void init_skin_paint(SkinEnum se, SkPaint* paint) | 
|  | { | 
|  | SkASSERT(paint); | 
|  |  | 
|  | SkAnimator    anim; | 
|  | SkCanvas    canvas; | 
|  |  | 
|  | init_skin_anim(se, &anim); | 
|  | anim.draw(&canvas, paint, 0); | 
|  | } | 
|  |  | 
|  | void inflate_paint(const SkDOM& dom, const SkDOM::Node* node, SkPaint* paint) | 
|  | { | 
|  | SkASSERT(paint); | 
|  |  | 
|  | SkAnimator    anim; | 
|  | SkCanvas    canvas; | 
|  |  | 
|  | if (!anim.decodeDOM(dom, node)) | 
|  | { | 
|  | SkDEBUGF(("inflate_paint: decoding dom failed\n")); | 
|  | SkDEBUGCODE(dom.dump(node);) | 
|  | sk_throw(); | 
|  | } | 
|  | anim.draw(&canvas, paint, 0); | 
|  | } | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | SkWidgetView::SkWidgetView() : SkView(SkView::kFocusable_Mask | SkView::kEnabled_Mask) | 
|  | { | 
|  | } | 
|  |  | 
|  | const char* SkWidgetView::getLabel() const | 
|  | { | 
|  | return fLabel.c_str(); | 
|  | } | 
|  |  | 
|  | void SkWidgetView::getLabel(SkString* label) const | 
|  | { | 
|  | if (label) | 
|  | *label = fLabel; | 
|  | } | 
|  |  | 
|  | void SkWidgetView::setLabel(const char label[]) | 
|  | { | 
|  | this->setLabel(label, label ? strlen(label) : 0); | 
|  | } | 
|  |  | 
|  | void SkWidgetView::setLabel(const char label[], size_t len) | 
|  | { | 
|  | if ((label == NULL && fLabel.size() != 0) || !fLabel.equals(label, len)) | 
|  | { | 
|  | SkString    tmp(label, len); | 
|  |  | 
|  | this->onLabelChange(fLabel.c_str(), tmp.c_str()); | 
|  | fLabel.swap(tmp); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SkWidgetView::setLabel(const SkString& label) | 
|  | { | 
|  | if (fLabel != label) | 
|  | { | 
|  | this->onLabelChange(fLabel.c_str(), label.c_str()); | 
|  | fLabel = label; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool SkWidgetView::postWidgetEvent() | 
|  | { | 
|  | if (!fEvent.isType("")) | 
|  | { | 
|  | SkEvent    evt(fEvent);    // make a copy since onPrepareWidgetEvent may edit the event | 
|  |  | 
|  | if (this->onPrepareWidgetEvent(&evt)) | 
|  | { | 
|  | SkDEBUGCODE(evt.dump("SkWidgetView::postWidgetEvent");) | 
|  |  | 
|  | this->postToListeners(evt);    // wonder if this should return true if there are > 0 listeners... | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /*virtual*/ void SkWidgetView::onInflate(const SkDOM& dom, const SkDOM::Node* node) | 
|  | { | 
|  | this->INHERITED::onInflate(dom, node); | 
|  |  | 
|  | const char* label = dom.findAttr(node, "label"); | 
|  | if (label) | 
|  | this->setLabel(label); | 
|  |  | 
|  | if ((node = dom.getFirstChild(node, "event")) != NULL) | 
|  | fEvent.inflate(dom, node); | 
|  | } | 
|  |  | 
|  | /*virtual*/ void SkWidgetView::onLabelChange(const char oldLabel[], const char newLabel[]) | 
|  | { | 
|  | this->inval(NULL); | 
|  | } | 
|  |  | 
|  | static const char gWidgetEventSinkIDSlotName[] = "sk-widget-sinkid-slot"; | 
|  |  | 
|  | /*virtual*/ bool SkWidgetView::onPrepareWidgetEvent(SkEvent* evt) | 
|  | { | 
|  | evt->setS32(gWidgetEventSinkIDSlotName, this->getSinkID()); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | SkEventSinkID SkWidgetView::GetWidgetEventSinkID(const SkEvent& evt) | 
|  | { | 
|  | int32_t    sinkID; | 
|  |  | 
|  | return evt.findS32(gWidgetEventSinkIDSlotName, &sinkID) ? (SkEventSinkID)sinkID : 0; | 
|  | } | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | /*virtual*/ bool SkButtonView::onEvent(const SkEvent& evt) | 
|  | { | 
|  | if (evt.isType(SK_EventType_Key) && evt.getFast32() == kOK_SkKey) | 
|  | { | 
|  | this->postWidgetEvent(); | 
|  | return true; | 
|  | } | 
|  | return this->INHERITED::onEvent(evt); | 
|  | } | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | SkCheckButtonView::SkCheckButtonView() : fCheckState(kOff_CheckState) | 
|  | { | 
|  | } | 
|  |  | 
|  | void SkCheckButtonView::setCheckState(CheckState state) | 
|  | { | 
|  | SkASSERT((unsigned)state <= kUnknown_CheckState); | 
|  |  | 
|  | if (fCheckState != state) | 
|  | { | 
|  | this->onCheckStateChange(this->getCheckState(), state); | 
|  | fCheckState = SkToU8(state); | 
|  | } | 
|  | } | 
|  |  | 
|  | /*virtual*/ void SkCheckButtonView::onCheckStateChange(CheckState oldState, CheckState newState) | 
|  | { | 
|  | this->inval(NULL); | 
|  | } | 
|  |  | 
|  | /*virtual*/ void SkCheckButtonView::onInflate(const SkDOM& dom, const SkDOM::Node* node) | 
|  | { | 
|  | this->INHERITED::onInflate(dom, node); | 
|  |  | 
|  | int index = dom.findList(node, "check-state", "off,on,unknown"); | 
|  | if (index >= 0) | 
|  | this->setCheckState((CheckState)index); | 
|  | } | 
|  |  | 
|  | static const char gCheckStateSlotName[] = "sk-checkbutton-check-slot"; | 
|  |  | 
|  | /*virtual*/ bool SkCheckButtonView::onPrepareWidgetEvent(SkEvent* evt) | 
|  | { | 
|  | // could check if we're "disabled", and return false... | 
|  |  | 
|  | evt->setS32(gCheckStateSlotName, this->getCheckState()); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool SkCheckButtonView::GetWidgetEventCheckState(const SkEvent& evt, CheckState* state) | 
|  | { | 
|  | int32_t    state32; | 
|  |  | 
|  | if (evt.findS32(gCheckStateSlotName, &state32)) | 
|  | { | 
|  | if (state) | 
|  | *state = (CheckState)state32; | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /////////////////////////////////////////////////////////////////////////////////////////////////// | 
|  | /////////////////////////////////////////////////////////////////////////////////////////////////// | 
|  | /////////////////////////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | #include "SkTime.h" | 
|  | #include <stdio.h> | 
|  |  | 
|  | class SkAnimButtonView : public SkButtonView { | 
|  | public: | 
|  | SkAnimButtonView() | 
|  | { | 
|  | fAnim.setHostEventSink(this); | 
|  | init_skin_anim(kButton_SkinEnum, &fAnim); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | virtual void onLabelChange(const char oldLabel[], const char newLabel[]) | 
|  | { | 
|  | this->INHERITED::onLabelChange(oldLabel, newLabel); | 
|  |  | 
|  | SkEvent evt("user"); | 
|  | evt.setString("id", "setLabel"); | 
|  | evt.setString("LABEL", newLabel); | 
|  | fAnim.doUserEvent(evt); | 
|  | } | 
|  |  | 
|  | virtual void onFocusChange(bool gainFocus) | 
|  | { | 
|  | this->INHERITED::onFocusChange(gainFocus); | 
|  |  | 
|  | SkEvent evt("user"); | 
|  | evt.setString("id", "setFocus"); | 
|  | evt.setS32("FOCUS", gainFocus); | 
|  | fAnim.doUserEvent(evt); | 
|  | } | 
|  |  | 
|  | virtual void onSizeChange() | 
|  | { | 
|  | this->INHERITED::onSizeChange(); | 
|  |  | 
|  | SkEvent evt("user"); | 
|  | evt.setString("id", "setDim"); | 
|  | evt.setScalar("dimX", this->width()); | 
|  | evt.setScalar("dimY", this->height()); | 
|  | fAnim.doUserEvent(evt); | 
|  | } | 
|  |  | 
|  | virtual void onDraw(SkCanvas* canvas) | 
|  | { | 
|  | SkPaint                        paint; | 
|  | SkAnimator::DifferenceType    diff = fAnim.draw(canvas, &paint, SkTime::GetMSecs()); | 
|  |  | 
|  | if (diff == SkAnimator::kDifferent) | 
|  | this->inval(NULL); | 
|  | else if (diff == SkAnimator::kPartiallyDifferent) | 
|  | { | 
|  | SkRect    bounds; | 
|  | fAnim.getInvalBounds(&bounds); | 
|  | this->inval(&bounds); | 
|  | } | 
|  | } | 
|  |  | 
|  | virtual bool onEvent(const SkEvent& evt) | 
|  | { | 
|  | if (evt.isType(SK_EventType_Inval)) | 
|  | { | 
|  | this->inval(NULL); | 
|  | return true; | 
|  | } | 
|  | if (evt.isType("recommendDim")) | 
|  | { | 
|  | SkScalar    height; | 
|  |  | 
|  | if (evt.findScalar("y", &height)) | 
|  | this->setHeight(height); | 
|  | return true; | 
|  | } | 
|  | return this->INHERITED::onEvent(evt); | 
|  | } | 
|  |  | 
|  | virtual bool onPrepareWidgetEvent(SkEvent* evt) | 
|  | { | 
|  | if (this->INHERITED::onPrepareWidgetEvent(evt)) | 
|  | { | 
|  | SkEvent    e("user"); | 
|  | e.setString("id", "handlePress"); | 
|  | (void)fAnim.doUserEvent(e); | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | private: | 
|  | SkAnimator    fAnim; | 
|  |  | 
|  | typedef SkButtonView INHERITED; | 
|  | }; | 
|  |  | 
|  | //////////////////////////////////////////////////////////////////////////////////////////// | 
|  | //////////////////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | SkView* SkWidgetFactory(const char name[]) | 
|  | { | 
|  | if (name == NULL) | 
|  | return NULL; | 
|  |  | 
|  | // must be in the same order as the SkSkinWidgetEnum is declared | 
|  | static const char* gNames[] = { | 
|  | "sk-border", | 
|  | "sk-button", | 
|  | "sk-image", | 
|  | "sk-list", | 
|  | "sk-progress", | 
|  | "sk-scroll", | 
|  | "sk-text" | 
|  |  | 
|  | }; | 
|  |  | 
|  | for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); i++) | 
|  | if (!strcmp(gNames[i], name)) | 
|  | return SkWidgetFactory((SkWidgetEnum)i); | 
|  |  | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | #include "SkImageView.h" | 
|  | #include "SkProgressBarView.h" | 
|  | #include "SkScrollBarView.h" | 
|  | #include "SkBorderView.h" | 
|  |  | 
|  | SkView* SkWidgetFactory(SkWidgetEnum sw) | 
|  | { | 
|  | switch (sw) { | 
|  | case kBorder_WidgetEnum: | 
|  | return new SkBorderView; | 
|  | case kButton_WidgetEnum: | 
|  | return new SkAnimButtonView; | 
|  | case kImage_WidgetEnum: | 
|  | return new SkImageView; | 
|  | case kList_WidgetEnum: | 
|  | return new SkListView; | 
|  | case kProgress_WidgetEnum: | 
|  | return new SkProgressBarView; | 
|  | case kScroll_WidgetEnum: | 
|  | return new SkScrollBarView; | 
|  | case kText_WidgetEnum: | 
|  | return new SkStaticTextView; | 
|  | default: | 
|  | SkDEBUGFAIL("unknown enum passed to SkWidgetFactory"); | 
|  | break; | 
|  | } | 
|  | return NULL; | 
|  | } |