/* * Copyright 2006 The Android Open Source Project * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkDisplayEvent.h" #include "SkAnimateMaker.h" #include "SkDisplayApply.h" #include "SkDisplayInput.h" #include "SkDisplayList.h" #ifdef SK_DEBUG #include "SkDump.h" #endif #include "SkEvent.h" #include "SkDisplayInput.h" #include "SkKey.h" #include "SkMetaData.h" #include "SkScript.h" #include "SkUtils.h" enum SkDisplayEvent_Properties { SK_PROPERTY(key), SK_PROPERTY(keys) }; #if SK_USE_CONDENSED_INFO == 0 const SkMemberInfo SkDisplayEvent::fInfo[] = { SK_MEMBER(code, EventCode), SK_MEMBER(disable, Boolean), SK_MEMBER_PROPERTY(key, String), // a single key (also last key pressed) SK_MEMBER_PROPERTY(keys, String), // a single key or dash-delimited range of keys SK_MEMBER(kind, EventKind), SK_MEMBER(target, String), SK_MEMBER(x, Float), SK_MEMBER(y, Float) }; #endif DEFINE_GET_MEMBER(SkDisplayEvent); SkDisplayEvent::SkDisplayEvent() : code((SkKey) -1), disable(false), kind(kUser), x(0), y(0), fLastCode((SkKey) -1), fMax((SkKey) -1), fTarget(NULL) { } SkDisplayEvent::~SkDisplayEvent() { deleteMembers(); } bool SkDisplayEvent::addChild(SkAnimateMaker& , SkDisplayable* child) { *fChildren.append() = child; return true; } bool SkDisplayEvent::contains(SkDisplayable* match) { for (int index = 0; index < fChildren.count(); index++) { if (fChildren[index] == match || fChildren[index]->contains(match)) return true; } return false; } SkDisplayable* SkDisplayEvent::contains(const SkString& match) { for (int index = 0; index < fChildren.count(); index++) { SkDisplayable* child = fChildren[index]; if (child->contains(match)) return child; } return NULL; } void SkDisplayEvent::deleteMembers() { for (int index = 0; index < fChildren.count(); index++) { SkDisplayable* evt = fChildren[index]; delete evt; } } #ifdef SK_DUMP_ENABLED void SkDisplayEvent::dumpEvent(SkAnimateMaker* maker) { dumpBase(maker); SkString str; SkDump::GetEnumString(SkType_EventKind, kind, &str); SkDebugf("kind=\"%s\" ", str.c_str()); if (kind == SkDisplayEvent::kKeyPress || kind == SkDisplayEvent::kKeyPressUp) { if (code >= 0) SkDump::GetEnumString(SkType_EventCode, code, &str); else str.set("none"); SkDebugf("code=\"%s\" ", str.c_str()); } if (kind == SkDisplayEvent::kKeyChar) { if (fMax != (SkKey) -1 && fMax != code) SkDebugf("keys=\"%c - %c\" ", code, fMax); else SkDebugf("key=\"%c\" ", code); } if (fTarget != NULL) { SkDebugf("target=\"%s\" ", fTarget->id); } if (kind >= SkDisplayEvent::kMouseDown && kind <= SkDisplayEvent::kMouseUp) { SkDebugf("x=\"%g\" y=\"%g\" ", SkScalarToFloat(x), SkScalarToFloat(y)); } if (disable) SkDebugf("disable=\"true\" "); SkDebugf("/>\n"); } #endif bool SkDisplayEvent::enableEvent(SkAnimateMaker& maker) { maker.fActiveEvent = this; if (fChildren.count() == 0) return false; if (disable) return false; #ifdef SK_DUMP_ENABLED if (maker.fDumpEvents) { SkDebugf("enable: "); dumpEvent(&maker); } #endif SkDisplayList& displayList = maker.fDisplayList; for (int index = 0; index < fChildren.count(); index++) { SkDisplayable* displayable = fChildren[index]; if (displayable->isGroup()) { SkTDDrawableArray* parentList = displayList.getDrawList(); *parentList->append() = (SkDrawable*) displayable; // make it findable before children are enabled } if (displayable->enable(maker)) continue; if (maker.hasError()) return true; if (displayable->isDrawable() == false) return true; // error SkDrawable* drawable = (SkDrawable*) displayable; SkTDDrawableArray* parentList = displayList.getDrawList(); *parentList->append() = drawable; } return false; } bool SkDisplayEvent::getProperty(int index, SkScriptValue* value) const { switch (index) { case SK_PROPERTY(key): case SK_PROPERTY(keys): { value->fType = SkType_String; char scratch[8]; SkKey convert = index == SK_PROPERTY(keys) ? code : fLastCode; size_t size = convert > 0 ? SkUTF8_FromUnichar(convert, scratch) : 0; fKeyString.set(scratch, size); value->fOperand.fString = &fKeyString; if (index != SK_PROPERTY(keys) || fMax == (SkKey) -1 || fMax == code) break; value->fOperand.fString->append("-"); size = SkUTF8_FromUnichar(fMax, scratch); value->fOperand.fString->append(scratch, size); } break; default: SkASSERT(0); return false; } return true; } void SkDisplayEvent::onEndElement(SkAnimateMaker& maker) { if (kind == kUser) return; maker.fEvents.addEvent(this); if (kind == kOnEnd) { SkDEBUGCODE(bool found = ) maker.find(target.c_str(), &fTarget); SkASSERT(found); SkASSERT(fTarget && fTarget->isAnimate()); SkAnimateBase* animate = (SkAnimateBase*) fTarget; animate->setHasEndEvent(); } } void SkDisplayEvent::populateInput(SkAnimateMaker& maker, const SkEvent& fEvent) { const SkMetaData& meta = fEvent.getMetaData(); SkMetaData::Iter iter(meta); SkMetaData::Type type; int number; const char* name; while ((name = iter.next(&type, &number)) != NULL) { if (name[0] == '\0') continue; SkDisplayable* displayable; SkInput* input; for (int index = 0; index < fChildren.count(); index++) { displayable = fChildren[index]; if (displayable->getType() != SkType_Input) continue; input = (SkInput*) displayable; if (input->name.equals(name)) goto found; } if (!maker.find(name, &displayable) || displayable->getType() != SkType_Input) continue; input = (SkInput*) displayable; found: switch (type) { case SkMetaData::kS32_Type: meta.findS32(name, &input->fInt); break; case SkMetaData::kScalar_Type: meta.findScalar(name, &input->fFloat); break; case SkMetaData::kPtr_Type: SkASSERT(0); break; // !!! not handled for now case SkMetaData::kString_Type: input->string.set(meta.findString(name)); break; default: SkASSERT(0); } } // re-evaluate all animators that may have built their values from input strings for (SkDisplayable** childPtr = fChildren.begin(); childPtr < fChildren.end(); childPtr++) { SkDisplayable* displayable = *childPtr; if (displayable->isApply() == false) continue; SkApply* apply = (SkApply*) displayable; apply->refresh(maker); } } bool SkDisplayEvent::setProperty(int index, SkScriptValue& value) { SkASSERT(index == SK_PROPERTY(key) || index == SK_PROPERTY(keys)); SkASSERT(value.fType == SkType_String); SkString* string = value.fOperand.fString; const char* chars = string->c_str(); int count = SkUTF8_CountUnichars(chars); SkASSERT(count >= 1); code = (SkKey) SkUTF8_NextUnichar(&chars); fMax = code; SkASSERT(count == 1 || index == SK_PROPERTY(keys)); if (--count > 0) { SkASSERT(*chars == '-'); chars++; fMax = (SkKey) SkUTF8_NextUnichar(&chars); SkASSERT(fMax >= code); } return true; }