export AnimationEffect::set and ::cancel to script

Also harmonize script parsing - any combination of animationarray
and global animation setting that results in a valid animation is
possible using the global settings as default on the array values

REVIEW: 109212
This commit is contained in:
Thomas Lübking 2013-02-28 19:52:16 +01:00
parent 9a3a7c8824
commit 77bcadc5b4
3 changed files with 203 additions and 56 deletions

View file

@ -50,8 +50,8 @@
</sectiondef> </sectiondef>
<sectiondef kind="public-func"> <sectiondef kind="public-func">
<memberdef kind="function"> <memberdef kind="function">
<type>Q_SCRIPTABLE void</type> <type>Q_SCRIPTABLE QList&lt;quint64&gt;</type>
<definition>void KWin::ScriptedEffect::animate</definition> <definition>QList&lt;quint64&gt; KWin::ScriptedEffect::animate</definition>
<argsstring>(settings)</argsstring> <argsstring>(settings)</argsstring>
<name>animate</name> <name>animate</name>
<read></read> <read></read>
@ -79,7 +79,29 @@ supports the following attributes:
] ]
} }
&lt;/syntaxhighlight&gt; &lt;/syntaxhighlight&gt;
At least one animation needs to be specified either with the top-level properties or in the animations list. At least one animation or attribute setter (see below) needs to be specified either with the top-level properties or in the animations list.
</detaileddescription>
</memberdef>
<memberdef kind="function">
<type>Q_SCRIPTABLE QList&lt;quint64&gt;</type>
<definition>QList&lt;quint64&gt; KWin::ScriptedEffect::set</definition>
<argsstring>(settings)</argsstring>
<name>set</name>
<read></read>
<detaileddescription>
Like animate, just that the manipulation does not implicitly end with the animation. You have to explicitly cancel it.
Until then, the manipulated attribute will remain at animation target value.
</detaileddescription>
</memberdef>
<memberdef kind="function">
<type>Q_SCRIPTABLE bool</type>
<definition>bool KWin::ScriptedEffect::cancel</definition>
<argsstring>(QList&lt;quint64&gt;)</argsstring>
<name>cancel</name>
<read></read>
<detaileddescription>
Cancel one or more present animations caused and returned by KWin::ScriptedEffect::animate or KWin::ScriptedEffect::set.
For convenience you can pass a single quint64 as well.
</detaileddescription> </detaileddescription>
</memberdef> </memberdef>
<memberdef kind="function"> <memberdef kind="function">

View file

@ -94,28 +94,36 @@ QScriptValue kwinScriptScreenEdge(QScriptContext *context, QScriptEngine *engine
} }
struct AnimationSettings { struct AnimationSettings {
AnimationEffect::Attribute a; enum { Type = 1<<0, Curve = 1<<1, Delay = 1<<2, Duration = 1<<3 };
AnimationEffect::Attribute type;
QEasingCurve::Type curve; QEasingCurve::Type curve;
bool curveSet;
FPx2 from; FPx2 from;
FPx2 to; FPx2 to;
int delay; int delay;
bool valid; uint duration;
uint set;
}; };
AnimationSettings animationSettingsFromObject(QScriptValue &object) AnimationSettings animationSettingsFromObject(QScriptValue &object)
{ {
AnimationSettings settings; AnimationSettings settings;
settings.curve = QEasingCurve::Linear; settings.set = 0;
settings.valid = true;
settings.curveSet = false;
settings.to = qscriptvalue_cast<FPx2>(object.property("to")); settings.to = qscriptvalue_cast<FPx2>(object.property("to"));
settings.from = qscriptvalue_cast<FPx2>(object.property("from")); settings.from = qscriptvalue_cast<FPx2>(object.property("from"));
QScriptValue duration = object.property("duration");
if (duration.isValid() && duration.isNumber()) {
settings.duration = duration.toUInt32();
settings.set |= AnimationSettings::Duration;
} else {
settings.duration = 0;
}
QScriptValue delay = object.property("delay"); QScriptValue delay = object.property("delay");
if (delay.isValid() && delay.isNumber()) { if (delay.isValid() && delay.isNumber()) {
settings.delay = delay.toInt32(); settings.delay = delay.toInt32();
settings.set |= AnimationSettings::Delay;
} else { } else {
settings.delay = 0; settings.delay = 0;
} }
@ -123,65 +131,53 @@ AnimationSettings animationSettingsFromObject(QScriptValue &object)
QScriptValue curve = object.property("curve"); QScriptValue curve = object.property("curve");
if (curve.isValid() && curve.isNumber()) { if (curve.isValid() && curve.isNumber()) {
settings.curve = static_cast<QEasingCurve::Type>(curve.toInt32()); settings.curve = static_cast<QEasingCurve::Type>(curve.toInt32());
settings.curveSet = true; settings.set |= AnimationSettings::Curve;
} else {
settings.curve = QEasingCurve::Linear;
} }
QScriptValue type = object.property("type"); QScriptValue type = object.property("type");
if (!type.isValid() || !type.isNumber()) { if (type.isValid() && type.isNumber()) {
settings.valid = false; settings.type = static_cast<AnimationEffect::Attribute>(type.toInt32());
settings.set |= AnimationSettings::Type;
} else {
settings.type = static_cast<AnimationEffect::Attribute>(-1);
} }
settings.a = static_cast<AnimationEffect::Attribute>(type.toInt32());
return settings; return settings;
} }
QScriptValue kwinEffectAnimate(QScriptContext *context, QScriptEngine *engine) QList<AnimationSettings> animationSettings(QScriptContext *context, ScriptedEffect *effect, EffectWindow **window)
{ {
ScriptedEffect *effect = qobject_cast<ScriptedEffect*>(context->callee().data().toQObject()); QList<AnimationSettings> settings;
if (!effect) { if (!effect) {
context->throwError(QScriptContext::ReferenceError, "Internal Scripted KWin Effect error"); context->throwError(QScriptContext::ReferenceError, "Internal Scripted KWin Effect error");
return engine->undefinedValue(); return settings;
} }
if (context->argumentCount() != 1) { if (context->argumentCount() != 1) {
context->throwError(QScriptContext::SyntaxError, "Exactly one argument expected"); context->throwError(QScriptContext::SyntaxError, "Exactly one argument expected");
return engine->undefinedValue(); return settings;
} }
if (!context->argument(0).isObject()) { if (!context->argument(0).isObject()) {
context->throwError(QScriptContext::TypeError, "Argument needs to be an object"); context->throwError(QScriptContext::TypeError, "Argument needs to be an object");
return engine->undefinedValue(); return settings;
} }
QScriptValue object = context->argument(0); QScriptValue object = context->argument(0);
QScriptValue windowProperty = object.property("window"); QScriptValue windowProperty = object.property("window");
if (!windowProperty.isValid() || !windowProperty.isObject()) { if (!windowProperty.isValid() || !windowProperty.isObject()) {
context->throwError(QScriptContext::TypeError, "Window property missing in animation options"); context->throwError(QScriptContext::TypeError, "Window property missing in animation options");
return engine->undefinedValue(); return settings;
} }
EffectWindow *window = qobject_cast<EffectWindow*>(windowProperty.toQObject()); *window = qobject_cast<EffectWindow*>(windowProperty.toQObject());
if (!window) {
context->throwError(QScriptContext::TypeError, "Window property does not contain an EffectWindow");
return engine->undefinedValue();
}
QScriptValue durationProperty = object.property("duration");
if (!durationProperty.isValid() || !durationProperty.isNumber()) {
context->throwError(QScriptContext::TypeError, "Duration property missing in animation options");
return engine->undefinedValue();
}
const int duration = durationProperty.toInt32();
QEasingCurve::Type curve = QEasingCurve::Linear; settings << animationSettingsFromObject(object); // global
QList<AnimationSettings> settings;
AnimationSettings globalSettings = animationSettingsFromObject(object); QScriptValue animations = object.property("animations"); // array
if (globalSettings.valid) {
settings << globalSettings;
if (globalSettings.curveSet) {
curve = globalSettings.curve;
}
}
QScriptValue animations = object.property("animations");
if (animations.isValid()) { if (animations.isValid()) {
if (!animations.isArray()) { if (!animations.isArray()) {
context->throwError(QScriptContext::TypeError, "Animations provided but not an array"); context->throwError(QScriptContext::TypeError, "Animations provided but not an array");
return engine->undefinedValue(); settings.clear();
return settings;
} }
const int length = static_cast<int>(animations.property("length").toInteger()); const int length = static_cast<int>(animations.property("length").toInteger());
for (int i=0; i<length; ++i) { for (int i=0; i<length; ++i) {
@ -191,29 +187,136 @@ QScriptValue kwinEffectAnimate(QScriptContext *context, QScriptEngine *engine)
} }
if (value.isObject()) { if (value.isObject()) {
AnimationSettings s = animationSettingsFromObject(value); AnimationSettings s = animationSettingsFromObject(value);
if (s.valid) { const uint set = s.set | settings.at(0).set;
if (!(set & AnimationSettings::Type)) {
context->throwError(QScriptContext::TypeError, "Type property missing in animation options");
continue;
}
if (!(set & AnimationSettings::Duration)) {
context->throwError(QScriptContext::TypeError, "Duration property missing in animation options");
continue;
}
if (!s.set & AnimationSettings::Curve) {
s.curve = settings.at(0).curve;
}
if (!s.set & AnimationSettings::Delay) {
s.delay = settings.at(0).delay;
}
settings << s; settings << s;
} }
} }
} }
if (settings.count() == 1) {
const uint set = settings.at(0).set;
if (!(set & AnimationSettings::Type)) {
context->throwError(QScriptContext::TypeError, "Type property missing in animation options");
settings.clear();
}
if (!(set & AnimationSettings::Duration)) {
context->throwError(QScriptContext::TypeError, "Duration property missing in animation options");
settings.clear();
}
} }
return settings;
}
QScriptValue kwinEffectAnimate(QScriptContext *context, QScriptEngine *engine)
{
ScriptedEffect *effect = qobject_cast<ScriptedEffect*>(context->callee().data().toQObject());
EffectWindow *window;
QList<AnimationSettings> settings = animationSettings(context, effect, &window);
if (settings.empty()) { if (settings.empty()) {
context->throwError(QScriptContext::TypeError, "No animations provided"); context->throwError(QScriptContext::TypeError, "No animations provided");
return engine->undefinedValue(); return engine->undefinedValue();
} }
if (!window) {
context->throwError(QScriptContext::TypeError, "Window property does not contain an EffectWindow");
return engine->undefinedValue();
}
QList<QVariant> animIds;
foreach (const AnimationSettings &setting, settings) { foreach (const AnimationSettings &setting, settings) {
effect->animate(window, animIds << QVariant(effect->animate(window,
setting.a, setting.type,
duration, setting.duration,
setting.to, setting.to,
setting.from, setting.from,
NULL, NULL,
setting.curveSet ? setting.curve : curve, setting.curve,
setting.delay); setting.delay));
} }
return engine->newVariant(true); return engine->newVariant(animIds);
}
QScriptValue kwinEffectSet(QScriptContext *context, QScriptEngine *engine)
{
ScriptedEffect *effect = qobject_cast<ScriptedEffect*>(context->callee().data().toQObject());
EffectWindow *window;
QList<AnimationSettings> settings = animationSettings(context, effect, &window);
if (settings.empty()) {
context->throwError(QScriptContext::TypeError, "No animations provided");
return engine->undefinedValue();
}
if (!window) {
context->throwError(QScriptContext::TypeError, "Window property does not contain an EffectWindow");
return engine->undefinedValue();
}
QList<QVariant> animIds;
foreach (const AnimationSettings &setting, settings) {
animIds << QVariant(effect->set(window,
setting.type,
setting.duration,
setting.to,
setting.from,
NULL,
setting.curve,
setting.delay));
}
return engine->newVariant(animIds);
}
QScriptValue kwinEffectCancel(QScriptContext *context, QScriptEngine *engine)
{
ScriptedEffect *effect = qobject_cast<ScriptedEffect*>(context->callee().data().toQObject());
if (context->argumentCount() != 1) {
context->throwError(QScriptContext::SyntaxError, "Exactly one argument expected");
return engine->undefinedValue();
}
QVariant v = context->argument(0).toVariant();
QList<quint64> animIds;
bool ok = false;
if (v.isValid()) {
quint64 animId = v.toULongLong(&ok);
if (ok)
animIds << animId;
}
if (!ok) { // may still be a variantlist of variants being quint64
QList<QVariant> list = v.toList();
if (!list.isEmpty()) {
foreach (const QVariant &vv, list) {
quint64 animId = vv.toULongLong(&ok);
if (ok)
animIds << animId;
}
ok = !animIds.isEmpty();
}
}
if (!ok) {
context->throwError(QScriptContext::TypeError, "Argument needs to be one or several quint64");
return engine->undefinedValue();
}
foreach (const quint64 &animId, animIds) {
ok |= engine->newVariant(effect->cancel(animId)).toBool();
}
return engine->newVariant(ok);
} }
QScriptValue effectWindowToScriptValue(QScriptEngine *eng, const KEffectWindowRef &window) QScriptValue effectWindowToScriptValue(QScriptEngine *eng, const KEffectWindowRef &window)
@ -331,6 +434,16 @@ bool ScriptedEffect::init(const QString &effectName, const QString &pathToScript
animateFunc.setData(m_engine->newQObject(this)); animateFunc.setData(m_engine->newQObject(this));
m_engine->globalObject().setProperty("animate", animateFunc); m_engine->globalObject().setProperty("animate", animateFunc);
// and the set variant
QScriptValue setFunc = m_engine->newFunction(kwinEffectSet);
setFunc.setData(m_engine->newQObject(this));
m_engine->globalObject().setProperty("set", setFunc);
// cancel...
QScriptValue cancelFunc = m_engine->newFunction(kwinEffectCancel);
cancelFunc.setData(m_engine->newQObject(this));
m_engine->globalObject().setProperty("cancel", cancelFunc);
QScriptValue ret = m_engine->evaluate(scriptFile.readAll()); QScriptValue ret = m_engine->evaluate(scriptFile.readAll());
if (ret.isError()) { if (ret.isError()) {
@ -355,7 +468,7 @@ void ScriptedEffect::signalHandlerException(const QScriptValue &value)
} }
} }
void ScriptedEffect::animate(KWin::EffectWindow* w, KWin::AnimationEffect::Attribute a, int ms, KWin::FPx2 to, KWin::FPx2 from, KWin::AnimationData* data, QEasingCurve::Type curve, int delay) uint metaFromData(KWin::AnimationData* data)
{ {
uint meta = 0; uint meta = 0;
if (data) { if (data) {
@ -381,7 +494,17 @@ void ScriptedEffect::animate(KWin::EffectWindow* w, KWin::AnimationEffect::Attri
AnimationEffect::setMetaData(AnimationEffect::RelativeTargetY, data->relativeTargetY(), meta); AnimationEffect::setMetaData(AnimationEffect::RelativeTargetY, data->relativeTargetY(), meta);
} }
} }
AnimationEffect::animate(w, a, meta, ms, to, QEasingCurve(curve), delay, from); return meta;
}
quint64 ScriptedEffect::animate(KWin::EffectWindow* w, KWin::AnimationEffect::Attribute a, int ms, KWin::FPx2 to, KWin::FPx2 from, KWin::AnimationData* data, QEasingCurve::Type curve, int delay)
{
return AnimationEffect::animate(w, a, metaFromData(data), ms, to, QEasingCurve(curve), delay, from);
}
quint64 ScriptedEffect::set(KWin::EffectWindow* w, KWin::AnimationEffect::Attribute a, int ms, KWin::FPx2 to, KWin::FPx2 from, KWin::AnimationData* data, QEasingCurve::Type curve, int delay)
{
return AnimationEffect::set(w, a, metaFromData(data), ms, to, QEasingCurve(curve), delay, from);
} }
bool ScriptedEffect::isGrabbed(EffectWindow* w, ScriptedEffect::DataRole grabRole) bool ScriptedEffect::isGrabbed(EffectWindow* w, ScriptedEffect::DataRole grabRole)

View file

@ -131,7 +131,9 @@ public:
} }
public Q_SLOTS: public Q_SLOTS:
void animate(KWin::EffectWindow *w, Attribute a, int ms, KWin::FPx2 to, KWin::FPx2 from = KWin::FPx2(), KWin::AnimationData *data = NULL, QEasingCurve::Type curve = QEasingCurve::Linear, int delay = 0); quint64 animate(KWin::EffectWindow *w, Attribute a, int ms, KWin::FPx2 to, KWin::FPx2 from = KWin::FPx2(), KWin::AnimationData *data = NULL, QEasingCurve::Type curve = QEasingCurve::Linear, int delay = 0);
quint64 set(KWin::EffectWindow *w, Attribute a, int ms, KWin::FPx2 to, KWin::FPx2 from = KWin::FPx2(), KWin::AnimationData *data = NULL, QEasingCurve::Type curve = QEasingCurve::Linear, int delay = 0);
bool cancel(quint64 animationId) { return AnimationEffect::cancel(animationId); }
virtual bool borderActivated(ElectricBorder border); virtual bool borderActivated(ElectricBorder border);
Q_SIGNALS: Q_SIGNALS: