/*
* 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(nullptr) {
}
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 nullptr;
}
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 != nullptr) {
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() = (SkADrawable*) 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
SkADrawable* drawable = (SkADrawable*) 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)) != nullptr) {
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;
}