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