diff options
Diffstat (limited to 'src/views/SkWidgets.cpp')
-rw-r--r-- | src/views/SkWidgets.cpp | 554 |
1 files changed, 554 insertions, 0 deletions
diff --git a/src/views/SkWidgets.cpp b/src/views/SkWidgets.cpp new file mode 100644 index 0000000000..fe87cd6e19 --- /dev/null +++ b/src/views/SkWidgets.cpp @@ -0,0 +1,554 @@ +#include "SkWidget.h" +#include "SkCanvas.h" +#include "SkKey.h" +#include "SkParsePaint.h" +#include "SkSystemEventTypes.h" +#include "SkTextBox.h" + +#if 0 + +#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 + +#include "SkAnimator.h" +#include "SkTime.h" + +/////////////////////////////////////////////////////////////////////////////// + +enum SkinType { + kPushButton_SkinType, + kStaticText_SkinType, + + kSkinTypeCount +}; + +struct SkinSuite { + SkinSuite(); + ~SkinSuite() + { + for (int i = 0; i < kSkinTypeCount; i++) + delete fAnimators[i]; + } + + SkAnimator* get(SkinType); + +private: + SkAnimator* fAnimators[kSkinTypeCount]; +}; + +SkinSuite::SkinSuite() +{ + static const char kSkinPath[] = "skins/"; + + static const char* gSkinNames[] = { + "pushbutton_skin.xml", + "statictext_skin.xml" + }; + + for (unsigned i = 0; i < SK_ARRAY_COUNT(gSkinNames); i++) + { + size_t len = strlen(gSkinNames[i]); + SkString path(sizeof(kSkinPath) - 1 + len); + + memcpy(path.writable_str(), kSkinPath, sizeof(kSkinPath) - 1); + memcpy(path.writable_str() + sizeof(kSkinPath) - 1, gSkinNames[i], len); + + fAnimators[i] = new SkAnimator; + if (!fAnimators[i]->decodeURI(path.c_str())) + { + delete fAnimators[i]; + fAnimators[i] = nil; + } + } +} + +SkAnimator* SkinSuite::get(SkinType st) +{ + SkASSERT((unsigned)st < kSkinTypeCount); + return fAnimators[st]; +} + +static SkinSuite* gSkinSuite; + +static SkAnimator* get_skin_animator(SkinType st) +{ +#if 0 + if (gSkinSuite == nil) + gSkinSuite = new SkinSuite; + return gSkinSuite->get(st); +#else + return nil; +#endif +} + +/////////////////////////////////////////////////////////////////////////////// + +void SkWidget::Init() +{ +} + +void SkWidget::Term() +{ + delete gSkinSuite; +} + +void SkWidget::onEnabledChange() +{ + this->inval(nil); +} + +void SkWidget::postWidgetEvent() +{ + if (!fEvent.isType("") && this->hasListeners()) + { + this->prepareWidgetEvent(&fEvent); + this->postToListeners(fEvent); + } +} + +void SkWidget::prepareWidgetEvent(SkEvent*) +{ + // override in subclass to add any additional fields before posting +} + +void SkWidget::onInflate(const SkDOM& dom, const SkDOM::Node* node) +{ + this->INHERITED::onInflate(dom, node); + + if ((node = dom.getFirstChild(node, "event")) != nil) + fEvent.inflate(dom, node); +} + +/////////////////////////////////////////////////////////////////////////////// + +size_t SkHasLabelWidget::getLabel(SkString* str) const +{ + if (str) + *str = fLabel; + return fLabel.size(); +} + +size_t SkHasLabelWidget::getLabel(char buffer[]) const +{ + if (buffer) + memcpy(buffer, fLabel.c_str(), fLabel.size()); + return fLabel.size(); +} + +void SkHasLabelWidget::setLabel(const SkString& str) +{ + this->setLabel(str.c_str(), str.size()); +} + +void SkHasLabelWidget::setLabel(const char label[]) +{ + this->setLabel(label, strlen(label)); +} + +void SkHasLabelWidget::setLabel(const char label[], size_t len) +{ + if (!fLabel.equals(label, len)) + { + fLabel.set(label, len); + this->onLabelChange(); + } +} + +void SkHasLabelWidget::onLabelChange() +{ + // override in subclass +} + +void SkHasLabelWidget::onInflate(const SkDOM& dom, const SkDOM::Node* node) +{ + this->INHERITED::onInflate(dom, node); + + const char* text = dom.findAttr(node, "label"); + if (text) + this->setLabel(text); +} + +///////////////////////////////////////////////////////////////////////////////////// + +void SkButtonWidget::setButtonState(State state) +{ + if (fState != state) + { + fState = state; + this->onButtonStateChange(); + } +} + +void SkButtonWidget::onButtonStateChange() +{ + this->inval(nil); +} + +void SkButtonWidget::onInflate(const SkDOM& dom, const SkDOM::Node* node) +{ + this->INHERITED::onInflate(dom, node); + + int index; + if ((index = dom.findList(node, "buttonState", "off,on,unknown")) >= 0) + this->setButtonState((State)index); +} + +///////////////////////////////////////////////////////////////////////////////////// + +bool SkPushButtonWidget::onEvent(const SkEvent& evt) +{ + if (evt.isType(SK_EventType_Key) && evt.getFast32() == kOK_SkKey) + { + this->postWidgetEvent(); + return true; + } + return this->INHERITED::onEvent(evt); +} + +static const char* computeAnimatorState(int enabled, int focused, SkButtonWidget::State state) +{ + if (!enabled) + return "disabled"; + if (state == SkButtonWidget::kOn_State) + { + SkASSERT(focused); + return "enabled-pressed"; + } + if (focused) + return "enabled-focused"; + return "enabled"; +} + +#include "SkBlurMaskFilter.h" +#include "SkEmbossMaskFilter.h" + +static void create_emboss(SkPaint* paint, SkScalar radius, bool focus, bool pressed) +{ + SkEmbossMaskFilter::Light light; + + light.fDirection[0] = SK_Scalar1/2; + light.fDirection[1] = SK_Scalar1/2; + light.fDirection[2] = SK_Scalar1/3; + light.fAmbient = 0x48; + light.fSpecular = 0x80; + + if (pressed) + { + light.fDirection[0] = -light.fDirection[0]; + light.fDirection[1] = -light.fDirection[1]; + } + if (focus) + light.fDirection[2] += SK_Scalar1/4; + + paint->setMaskFilter(new SkEmbossMaskFilter(light, radius))->unref(); +} + +void SkPushButtonWidget::onDraw(SkCanvas* canvas) +{ + this->INHERITED::onDraw(canvas); + + SkString label; + this->getLabel(&label); + + SkAnimator* anim = get_skin_animator(kPushButton_SkinType); + + if (anim) + { + SkEvent evt("user"); + + evt.setString("id", "prime"); + evt.setScalar("prime-width", this->width()); + evt.setScalar("prime-height", this->height()); + evt.setString("prime-text", label); + evt.setString("prime-state", computeAnimatorState(this->isEnabled(), this->hasFocus(), this->getButtonState())); + + (void)anim->doUserEvent(evt); + SkPaint paint; + anim->draw(canvas, &paint, SkTime::GetMSecs()); + } + else + { + SkRect r; + SkPaint p; + + r.set(0, 0, this->width(), this->height()); + p.setAntiAliasOn(true); + p.setColor(SK_ColorBLUE); + create_emboss(&p, SkIntToScalar(12)/5, this->hasFocus(), this->getButtonState() == kOn_State); + canvas->drawRoundRect(r, SkScalarHalf(this->height()), SkScalarHalf(this->height()), p); + p.setMaskFilter(nil); + + p.setTextAlign(SkPaint::kCenter_Align); + + SkTextBox box; + box.setMode(SkTextBox::kOneLine_Mode); + box.setSpacingAlign(SkTextBox::kCenter_SpacingAlign); + box.setBox(0, 0, this->width(), this->height()); + +// if (this->getButtonState() == kOn_State) +// p.setColor(SK_ColorRED); +// else + p.setColor(SK_ColorWHITE); + + box.draw(canvas, label.c_str(), label.size(), p); + } +} + +SkView::Click* SkPushButtonWidget::onFindClickHandler(SkScalar x, SkScalar y) +{ + this->acceptFocus(); + return new Click(this); +} + +bool SkPushButtonWidget::onClick(Click* click) +{ + SkRect r; + State state = kOff_State; + + this->getLocalBounds(&r); + if (r.contains(click->fCurr)) + { + if (click->fState == Click::kUp_State) + this->postWidgetEvent(); + else + state = kOn_State; + } + this->setButtonState(state); + return true; +} + +////////////////////////////////////////////////////////////////////////////////////////// + +SkStaticTextView::SkStaticTextView(U32 flags) : SkView(flags) +{ + fMargin.set(0, 0); + fMode = kFixedSize_Mode; + fSpacingAlign = SkTextBox::kStart_SpacingAlign; +} + +SkStaticTextView::~SkStaticTextView() +{ +} + +void SkStaticTextView::computeSize() +{ + if (fMode == kAutoWidth_Mode) + { + SkScalar width = fPaint.measureText(fText.c_str(), fText.size(), nil, nil); + 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; + + SkScalar before, after; + (void)fPaint.measureText(0, nil, &before, &after); + + this->setHeight(lines * (after - before) + 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(nil); +} + +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(nil); + } +} + +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[]) +{ + 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(nil); + } +} + +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(nil); + } +} + +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, "mode"); + + 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")) != nil) + SkPaint_Inflate(&fPaint, dom, node); +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "SkImageDecoder.h" + +SkBitmapView::SkBitmapView(U32 flags) : SkView(flags) +{ +} + +SkBitmapView::~SkBitmapView() +{ +} + +bool SkBitmapView::getBitmap(SkBitmap* bitmap) const +{ + if (bitmap) + *bitmap = fBitmap; + return fBitmap.getConfig() != SkBitmap::kNo_Config; +} + +void SkBitmapView::setBitmap(const SkBitmap* bitmap, bool viewOwnsPixels) +{ + if (bitmap) + { + fBitmap = *bitmap; + fBitmap.setOwnsPixels(viewOwnsPixels); + } +} + +bool SkBitmapView::loadBitmapFromFile(const char path[]) +{ + SkBitmap bitmap; + + if (SkImageDecoder::DecodeFile(path, &bitmap)) + { + this->setBitmap(&bitmap, true); + bitmap.setOwnsPixels(false); + return true; + } + return false; +} + +void SkBitmapView::onDraw(SkCanvas* canvas) +{ + if (fBitmap.getConfig() != SkBitmap::kNo_Config && + fBitmap.width() && fBitmap.height()) + { + SkAutoCanvasRestore restore(canvas, true); + SkPaint p; + + p.setFilterType(SkPaint::kBilinear_FilterType); + canvas->scale( this->width() / fBitmap.width(), + this->height() / fBitmap.height(), + 0, 0); + canvas->drawBitmap(fBitmap, 0, 0, p); + } +} + +void SkBitmapView::onInflate(const SkDOM& dom, const SkDOM::Node* node) +{ + this->INHERITED::onInflate(dom, node); + + const char* src = dom.findAttr(node, "src"); + if (src) + (void)this->loadBitmapFromFile(src); +} + +#endif + |