#include "SkWidgetViews.h" #include "SkAnimator.h" #include "SkCanvas.h" #include "SkPaint.h" #include "SkStream.h" #include "SkSystemEventTypes.h" #ifdef SK_DEBUG static void assert_no_attr(const SkDOM& dom, const SkDOM::Node* node, const char attr[]) { const char* value = dom.findAttr(node, attr); if (value) SkDebugf("unknown attribute %s=\"%s\"\n", attr, value); } #else #define assert_no_attr(dom, node, attr) #endif /* 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); SkFILEStream stream(path); if (!stream.isValid()) { 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 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; }; //////////////////////////////////////////////////////////////////////////////////////////// #include "SkTextBox.h" SkStaticTextView::SkStaticTextView() { fMargin.set(0, 0); fMode = kFixedSize_Mode; fSpacingAlign = SkTextBox::kStart_SpacingAlign; init_skin_paint(kStaticText_SkinEnum, &fPaint); } SkStaticTextView::~SkStaticTextView() { } void SkStaticTextView::computeSize() { if (fMode == kAutoWidth_Mode) { SkScalar width = fPaint.measureText(fText.c_str(), fText.size()); this->setWidth(width + fMargin.fX * 2); } else if (fMode == kAutoHeight_Mode) { SkScalar width = this->width() - fMargin.fX * 2; int lines = width > 0 ? SkTextLineBreaker::CountLines(fText.c_str(), fText.size(), fPaint, width) : 0; this->setHeight(lines * fPaint.getFontSpacing() + fMargin.fY * 2); } } void SkStaticTextView::setMode(Mode mode) { SkASSERT((unsigned)mode < kModeCount); if (fMode != mode) { fMode = SkToU8(mode); this->computeSize(); } } void SkStaticTextView::setSpacingAlign(SkTextBox::SpacingAlign align) { fSpacingAlign = SkToU8(align); this->inval(NULL); } void SkStaticTextView::getMargin(SkPoint* margin) const { if (margin) *margin = fMargin; } void SkStaticTextView::setMargin(SkScalar dx, SkScalar dy) { if (fMargin.fX != dx || fMargin.fY != dy) { fMargin.set(dx, dy); this->computeSize(); this->inval(NULL); } } size_t SkStaticTextView::getText(SkString* text) const { if (text) *text = fText; return fText.size(); } size_t SkStaticTextView::getText(char text[]) const { if (text) memcpy(text, fText.c_str(), fText.size()); return fText.size(); } void SkStaticTextView::setText(const SkString& text) { this->setText(text.c_str(), text.size()); } void SkStaticTextView::setText(const char text[]) { if (text == NULL) text = ""; this->setText(text, strlen(text)); } void SkStaticTextView::setText(const char text[], size_t len) { if (!fText.equals(text, len)) { fText.set(text, len); this->computeSize(); this->inval(NULL); } } void SkStaticTextView::getPaint(SkPaint* paint) const { if (paint) *paint = fPaint; } void SkStaticTextView::setPaint(const SkPaint& paint) { if (fPaint != paint) { fPaint = paint; this->computeSize(); this->inval(NULL); } } void SkStaticTextView::onDraw(SkCanvas* canvas) { this->INHERITED::onDraw(canvas); if (fText.isEmpty()) return; SkTextBox box; box.setMode(fMode == kAutoWidth_Mode ? SkTextBox::kOneLine_Mode : SkTextBox::kLineBreak_Mode); box.setSpacingAlign(this->getSpacingAlign()); box.setBox(fMargin.fX, fMargin.fY, this->width() - fMargin.fX, this->height() - fMargin.fY); box.draw(canvas, fText.c_str(), fText.size(), fPaint); } void SkStaticTextView::onInflate(const SkDOM& dom, const SkDOM::Node* node) { this->INHERITED::onInflate(dom, node); int index; if ((index = dom.findList(node, "mode", "fixed,auto-width,auto-height")) >= 0) this->setMode((Mode)index); else assert_no_attr(dom, node, "mode"); if ((index = dom.findList(node, "spacing-align", "start,center,end")) >= 0) this->setSpacingAlign((SkTextBox::SpacingAlign)index); else assert_no_attr(dom, node, "spacing-align"); SkScalar s[2]; if (dom.findScalars(node, "margin", s, 2)) this->setMargin(s[0], s[1]); else assert_no_attr(dom, node, "margin"); const char* text = dom.findAttr(node, "text"); if (text) this->setText(text); if ((node = dom.getFirstChild(node, "paint")) != NULL && (node = dom.getFirstChild(node, "screenplay")) != NULL) { inflate_paint(dom, node, &fPaint); } } //////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////// 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 (int 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: SkASSERT(!"unknown enum passed to SkWidgetFactory"); break; } return NULL; }