Blob Blame History Raw
/*
 * Copyright (C) 2013 Intel Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 */

const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Gettext = imports.gettext;
const _ = imports.gettext.gettext;

const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Clutter = imports.gi.Clutter;
const ClutterGst = imports.gi.ClutterGst;

const COLUMNS = 3;
const ROWS = 3;

if (ARGV.length < 2)
    throw "Need 2 arguments : video-wall.js videofile1 videofile2";

Clutter.init(null, null);
ClutterGst.init(null, null);


let stage = new Clutter.Stage();
stage.set_background_color(new Clutter.Color({ red: 0,
                                               green: 0,
                                               blue: 0,
                                               alpha: 0xff }));
stage.connect('destroy',
              Lang.bind(this, function() { Clutter.main_quit(); }));

let player1 = new ClutterGst.Playback();
player1.set_filename(ARGV[0]);
player1.set_audio_volume(0);
player1.set_progress(0.20);

let player2 = new ClutterGst.Playback();
player2.set_filename(ARGV[1]);
player2.set_audio_volume(0);
player2.set_progress(0.20);

let animateActor = function(actor, params) {
    let diffPropName = null;

    actor.save_easing_state();
    actor.set_easing_duration(params.duration);
    actor.set_easing_mode(params.mode);

    for (let p in params.properties) {
        let t = actor.get_transition(p);
        if (t != null && t.is_playing())
            return true;

        if (actor[p] != params.properties[p]) {
            actor[p] = params.properties[p];
            diffPropName = p;
        }
    }

    actor.restore_easing_state();

    if (diffPropName != null && params.onCompleted) {
        let transition = actor.get_transition(diffPropName);
        actor.connect('transition-stopped::' + diffPropName,
                      Lang.bind(params.scope, function() {
                          params.onCompleted(actor);
                      }));
    }

    return (diffPropName != null);
};

let actors = [];

let positionActor = function(actorId) {
    let actor = actors[actorId % actors.length];

    let stageWidth = stage.get_width();
    let stageHeight = stage.get_height();

    animateActor(actor,
                 { duration: 500,
                   mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
                   properties: {
                       'x': actor._myXPos * actor.width + (stageWidth / 2) - (COLUMNS * actor.width) / 2,
                       'y': actor._myYPos * actor.height + (stageHeight / 2) - (ROWS * actor.height) / 2,
                   },
                 });
    animateActor(actor._backActor,
                 { duration: 500,
                   mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
                   properties: {
                       'x': actor._myXPos * actor.width + (stageWidth / 2) - (COLUMNS * actor.width) / 2,
                       'y': actor._myYPos * actor.height + (stageHeight / 2) - (ROWS * actor.height) / 2,
                   },
                 });
};

let positionActors = function() {
    for (let i = 0; i < actors.length; i++)
        positionActor(i);
};

for (let i = 0; i < ROWS; i++) {
    for (let j = 0; j < COLUMNS; j++) {
        let input = new ClutterGst.Box({ x1: j / COLUMNS,
                                         x2: (j + 1) / COLUMNS,
                                         y1: i / ROWS,
                                         y2: (i + 1) / ROWS,
                                       })
        let actor =
            new Clutter.Actor({
                reactive: true,
                pivot_point: new Clutter.Point({ x: 0.5,
                                                 y: 0.5 }),
                width: 200,
                height: 200,
                x: -200,
                y: -200,
                content: new ClutterGst.Crop({
                    cull_backface: true,
                    input_region: input,
                    player: player1,
                }),
            });
        actor._backActor =
            new Clutter.Actor({
                reactive: false,
                pivot_point: new Clutter.Point({ x: 0.5,
                                                 y: 0.5 }),
                rotation_angle_y: 180,
                width: 200,
                height: 200,
                x: -200,
                y: -200,
                content: new ClutterGst.Crop({
                    cull_backface: true,
                    input_region: input,
                    player: player2,
                }),
            });
        stage.add_child(actor);
        stage.add_child(actor._backActor);

        actor._myXPos = j;
        actor._myYPos = i;
        actor._backActor._myXPos = j;
        actor._backActor._myYPos = i;

        actors.push(actor);

        let animEnterParams = {
            duration: 350,
            mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
            properties: {
                'rotation-angle-y': 180,
            },
            scope: this,
            onCompleted: function(actor) {
                if (actor._nextParams) {
                    actor._inAnimation = animateActor(actor, actor._nextParams);
                    actor._nextParams = null;
                } else {
                    actor._inAnimation = false;
                }
            },
        };
        let animLeaveParams = {
            duration: 350,
            mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
            properties: {
                'rotation-angle-y': 0,
            },
            scope: this,
            onCompleted: function(actor) {
                if (actor._nextParams) {
                    actor._inAnimation = animateActor(actor, actor._nextParams);
                    actor._nextParams = null;
                } else {
                    actor._inAnimation = false;
                }
            },
        };

        actor.connect('enter-event', Lang.bind(this, function(actor, event) {
            if (!actor._inAnimation) {
                actor._inAnimation = animateActor(actor, animEnterParams);
                actor._backActor._inAnimation = animateActor(actor._backActor, animLeaveParams);
            } else {
                actor._nextParams = animEnterParams;
                actor._backActor._nextParams = animLeaveParams;
            }
        }));
        actor.connect('leave-event', Lang.bind(this, function(actor, event) {
            if (!actor._inAnimation) {
                actor._inAnimation = animateActor(actor, animLeaveParams);
                actor._backActor._inAnimation = animateActor(actor._backActor, animEnterParams);
            } else {
                actor._nextParams = animLeaveParams;
                actor._backActor._nextParams = animEnterParams;
            }
        }));
    }
}

stage.connect('allocation-changed', Lang.bind(this, function() {
    positionActors();
}));
stage.set_user_resizable(true);

player1.set_playing(true);
player2.set_playing(true);

stage.show();

Clutter.main();