diff --git a/effects/maximize/package/contents/code/maximize.js b/effects/maximize/package/contents/code/maximize.js index 75413b7d3f..744021b8cd 100644 --- a/effects/maximize/package/contents/code/maximize.js +++ b/effects/maximize/package/contents/code/maximize.js @@ -16,7 +16,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ -/*global effect, effects, animationTime, Effect*/ +/*global effect, effects, animate, animationTime, Effect*/ var maximizeEffect = { duration: animationTime(250), loadConfig: function () { @@ -31,19 +31,30 @@ var maximizeEffect = { var oldGeometry, newGeometry; oldGeometry = window.oldGeometry; newGeometry = window.geometry; - effect.animate(window, Effect.Scale, maximizeEffect.duration, { - value1: 1.0, - value2: 1.0 - }, { - value1: oldGeometry.width / newGeometry.width, - value2: oldGeometry.height / newGeometry.height - }); - effect.animate(window, Effect.Translation, maximizeEffect.duration, { - value1: 0, - value2: 0 - }, { - value1: oldGeometry.x - newGeometry.x - (newGeometry.width / 2 - oldGeometry.width / 2), - value2: oldGeometry.y - newGeometry.y - (newGeometry.height / 2 - oldGeometry.height / 2) + animate({ + window: window, + duration: maximizeEffect.duration, + animations: [{ + type: Effect.Scale, + to: { + value1: 1.0, + value2: 1.0 + }, + from: { + value1: oldGeometry.width / newGeometry.width, + value2: oldGeometry.height / newGeometry.height + } + }, { + type: Effect.Translation, + to: { + value1: 0, + value2: 0 + }, + from: { + value1: oldGeometry.x - newGeometry.x - (newGeometry.width / 2 - oldGeometry.width / 2), + value2: oldGeometry.y - newGeometry.y - (newGeometry.height / 2 - oldGeometry.height / 2) + } + }] }); }, geometryChange: function (window, oldGeometry) { diff --git a/scripting/documentation-effect-global.xml b/scripting/documentation-effect-global.xml index 983827fa5f..e5440e0ba5 100644 --- a/scripting/documentation-effect-global.xml +++ b/scripting/documentation-effect-global.xml @@ -41,6 +41,39 @@ + + Q_SCRIPTABLE void + void KWin::ScriptedEffect::animate + (settings) + animate + + +Schedules one or many animations for one window. The animations are defined through the settings object providing +a more declarative way to specify the animations than the animate call on the effect object. The settings object +supports the following attributes: +<syntaxhighlight lang="javascript"> +{ + window: EffectWindow, /* the window to animate, required */ + duration: int, /* duration in msec, required */ + curve: QEasingCurve.Type, /* global easing curve, optional */ + type: Effect.Attribute, /* for first animation, optional */ + from: FPx2, /* for first animation, optional */ + to: FPx2, /* for first animation, optional */ + delay: int, /* for first animation, optional */ + animations: [ /* additional animations, optional */ + { + curve: QEasingCurve.Type, /* overrides global */ + type: Effect.Attribute, + from: FPx2, + to: FPx2, + delay: int + } + ] +} +</syntaxhighlight> +At least one animation needs to be specified either with the top-level properties or in the animations list. + + Q_SCRIPTABLE void void KWin::ScriptedEffect::print diff --git a/scripting/scriptedeffect.cpp b/scripting/scriptedeffect.cpp index 610f02a81d..4a7e8e1607 100644 --- a/scripting/scriptedeffect.cpp +++ b/scripting/scriptedeffect.cpp @@ -89,6 +89,128 @@ QScriptValue kwinScriptScreenEdge(QScriptContext *context, QScriptEngine *engine return registerScreenEdge(context, engine); } +struct AnimationSettings { + AnimationEffect::Attribute a; + QEasingCurve curve; + bool curveSet; + FPx2 from; + FPx2 to; + int delay; + bool valid; +}; + +AnimationSettings animationSettingsFromObject(QScriptValue &object) +{ + AnimationSettings settings; + settings.valid = true; + settings.curveSet = false; + + settings.to = qscriptvalue_cast(object.property("to")); + settings.from = qscriptvalue_cast(object.property("from")); + + QScriptValue delay = object.property("delay"); + if (delay.isValid() && delay.isNumber()) { + settings.delay = delay.toInt32(); + } else { + settings.delay = 0; + } + + QScriptValue curve = object.property("curve"); + if (curve.isValid() && curve.isNumber()) { + settings.curve = QEasingCurve(static_cast(curve.toInt32())); + settings.curveSet = true; + } + + QScriptValue type = object.property("type"); + if (!type.isValid() || !type.isNumber()) { + settings.valid = false; + } + settings.a = static_cast(type.toInt32()); + + return settings; +} + +QScriptValue kwinEffectAnimate(QScriptContext *context, QScriptEngine *engine) +{ + ScriptedEffect *effect = qobject_cast(context->callee().data().toQObject()); + if (!effect) { + context->throwError(QScriptContext::ReferenceError, "Internal Scripted KWin Effect error"); + return engine->undefinedValue(); + } + if (context->argumentCount() != 1) { + context->throwError(QScriptContext::SyntaxError, "Exactly one argument expected"); + return engine->undefinedValue(); + } + if (!context->argument(0).isObject()) { + context->throwError(QScriptContext::TypeError, "Argument needs to be an object"); + return engine->undefinedValue(); + } + QScriptValue object = context->argument(0); + QScriptValue windowProperty = object.property("window"); + if (!windowProperty.isValid() || !windowProperty.isObject()) { + context->throwError(QScriptContext::TypeError, "Window property missing in animation options"); + return engine->undefinedValue(); + } + EffectWindow *window = qobject_cast(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 curve; + QList settings; + AnimationSettings globalSettings = animationSettingsFromObject(object); + if (globalSettings.valid) { + settings << globalSettings; + if (globalSettings.curveSet) { + curve = globalSettings.curve; + } + } + QScriptValue animations = object.property("animations"); + if (animations.isValid()) { + if (!animations.isArray()) { + context->throwError(QScriptContext::TypeError, "Animations provided but not an array"); + return engine->undefinedValue(); + } + const int length = static_cast(animations.property("length").toInteger()); + for (int i=0; ithrowError(QScriptContext::TypeError, "No animations provided"); + return engine->undefinedValue(); + } + foreach (const AnimationSettings &setting, settings) { + effect->animate(window, + setting.a, + duration, + setting.to, + setting.from, + NULL, + setting.curveSet ? setting.curve : curve, + setting.delay); + } + + return engine->newVariant(true); +} + QScriptValue effectWindowToScriptValue(QScriptEngine *eng, const KEffectWindowRef &window) { return eng->newQObject(window, QScriptEngine::QtOwnership, @@ -198,6 +320,10 @@ bool ScriptedEffect::init(const QString &effectName, const QString &pathToScript // add global Shortcut registerGlobalShortcutFunction(this, m_engine, kwinScriptGlobalShortcut); registerScreenEdgeFunction(this, m_engine, kwinScriptScreenEdge); + // add the animate method + QScriptValue animateFunc = m_engine->newFunction(kwinEffectAnimate); + animateFunc.setData(m_engine->newQObject(this)); + m_engine->globalObject().setProperty("animate", animateFunc); QScriptValue ret = m_engine->evaluate(scriptFile.readAll());