/* * 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 = 5; const ROWS = 4; const TILE_WIDTH = 200; const TILE_HEIGHT = 200; const AUDIO_VOLUME_MAX = 0.30; if (ARGV.length < 2) throw "Need at least 2 arguments : video-wall.js videofile1 videofile2 ..."; // Players.prototype = { _init: function() { this._current = 1; this._currentFilename = 0; this._players = []; this._players[0] = new ClutterGst.Playback(); this._players[0].set_audio_volume(0); this._players[1] = new ClutterGst.Playback(); this._players[1].set_audio_volume(0); this._players[2] = new ClutterGst.Playback(); this._players[2].set_audio_volume(0); }, // switchFilenamesForward: function() { this._currentFilename += 1; this._currentFilename %= ARGV.length; }, switchFilenamesBackward: function() { this._currentFilename += ARGV.length - 1; this._currentFilename %= ARGV.length; }, getCurrentFilename: function() { return ARGV[this._currentFilename]; }, getNextFilename: function() { return ARGV[(this._currentFilename + 1) % ARGV.length]; }, getPreviousFilename: function() { return ARGV[(this._currentFilename + ARGV.length - 1) % ARGV.length]; }, // getCurrentPlayer: function() { return this._players[this._current]; }, getNextPlayer: function() { return this._players[(this._current + 1) % this._players.length]; }, getPreviousPlayer: function() { return this._players[(this._current + this._players.length - 1) % this._players.length]; }, switchPlayersForward: function() { this.switchFilenamesForward(); this.getPreviousPlayer().set_playing(false); this.getPreviousPlayer().set_filename(this.getNextFilename()); this.getPreviousPlayer().set_playing(true); this.getPreviousPlayer().set_playing(false); this.getPreviousPlayer().set_audio_volume(0); this._current++; this._current %= this._players.length; }, switchPlayersBackward: function() { this.switchFilenamesBackward(); this.getNextPlayer().set_playing(false); this.getNextPlayer().set_filename(this.getPreviousFilename()); this.getNextPlayer().set_playing(true); this.getPreviousPlayer().set_playing(false); this.getNextPlayer().set_audio_volume(0); this._current += this._players.length - 1; this._current %= this._players.length; }, // updateActorsCurrent: function(actors, back) { for (let i in actors) { if (back) actors[i]._backActor.content.player = this.getCurrentPlayer(); else actors[i].content.player = this.getCurrentPlayer(); } }, updateActorsNext: function(actors, back) { for (let i in actors) { if (back) actors[i]._backActor.content.player = this.getNextPlayer(); else actors[i].content.player = this.getNextPlayer(); } }, updateActorsPrevious: function(actors, back) { for (let i in actors) { if (back) actors[i]._backActor.content.player = this.getPreviousPlayer(); else actors[i].content.player = this.getPreviousPlayer(); } }, dumpFilenames: function() { log(this.getPreviousPlayer().uri + "/" + this.getPreviousPlayer().get_playing()); log(this.getCurrentPlayer().uri + "/" + this.getCurrentPlayer().get_playing()); log(this.getNextPlayer().uri + "/" + this.getNextPlayer().get_playing()); log("---------------"); }, }; function Players() { this._init(); } // Clutter.init(null, null); ClutterGst.init(null, null); let animateActor = function(actor, params) { let diffPropName = null; actor.save_easing_state(); if (params.duration) actor.set_easing_duration(params.duration); if (params.mode) actor.set_easing_mode(params.mode); if (params.delay) actor.set_easing_delay(params.delay); 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 stage = new Clutter.Stage({ width: TILE_WIDTH * COLUMNS, height: TILE_HEIGHT * ROWS, }); log(stage.width + "x" + stage.height); stage.set_background_color(new Clutter.Color({ red: 0, green: 0, blue: 0, alpha: 0xff })); stage.set_user_resizable(true); stage.connect('destroy', Lang.bind(this, function() { Clutter.main_quit(); })); let players = new Players(); players.switchPlayersForward(); players.switchPlayersForward(); players.switchPlayersForward(); players.switchPlayersBackward(); let actors = []; let positionActor = function(actorId) { let actor = actors[actorId % actors.length]; let stageWidth = stage.get_width(); let stageHeight = stage.get_height(); actor._backActor.x = actor.x = actor._myXPos * actor.width + (stageWidth / 2) - (COLUMNS * actor.width) / 2; actor._backActor.y = actor.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({ pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }), width: TILE_WIDTH, height: TILE_HEIGHT, content: new ClutterGst.Crop({ cull_backface: true, input_region: input, }), }); actor._backActor = new Clutter.Actor({ pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }), rotation_angle_y: 180, width: TILE_WIDTH, height: TILE_HEIGHT, content: new ClutterGst.Crop({ cull_backface: true, input_region: input, }), }); 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); } } players.updateActorsCurrent(actors, false); players.getCurrentPlayer().set_audio_volume(AUDIO_VOLUME_MAX); players.getCurrentPlayer().set_playing(true); // // // let animateSound = function(duration, mode, newPlayer, oldPlayer) { let tl = new Clutter.Timeline({ duration: duration, progress_mode: mode, }); let oldLevel = oldPlayer.get_audio_volume(); tl.connect('new-frame', Lang.bind(this, function() { newPlayer.set_audio_volume(oldLevel * tl.get_progress()); oldPlayer.set_audio_volume(oldLevel * (1 - tl.get_progress())) })); tl.start(); }; let animateForward = function(duration, mode, delay) { for (let i in actors) { let actor = actors[i]; let actorDelay = delay * (((actor._myXPos + actor._myYPos * COLUMNS / ROWS) / (2 * COLUMNS))); let props = { duration: duration, mode: mode, delay: actorDelay, properties: { 'rotation-angle-y': actor.rotation_angle_y + 180, }, }; animateActor(actor, props); props.properties['rotation-angle-y'] = actor._backActor.rotation_angle_y + 180; animateActor(actor._backActor, props); } }; let animateBackward = function(duration, mode, delay) { for (let i in actors) { let actor = actors[i]; let actorDelay = delay * (1 - ((actor._myXPos + actor._myYPos * COLUMNS / ROWS) / (2 * COLUMNS))); let props = { duration: duration, mode: mode, delay: actorDelay, properties: { 'rotation-angle-y': actor.rotation_angle_y - 180, }, }; animateActor(actor, props); props.properties['rotation-angle-y'] = actor._backActor.rotation_angle_y - 180; animateActor(actor._backActor, props); } }; stage.connect('allocation-changed', Lang.bind(this, function() { positionActors(); })); let inAnimation = false; let nextSide = true; stage.connect('key-press-event', Lang.bind(this, function(actor, event) { if (inAnimation) return false; log('event processing!'); let currentPlayer = players.getCurrentPlayer(); let nextPlayer; //players.dumpFilenames(); switch (event.get_key_symbol()) { default: return false; case Clutter.Up: players.updateActorsNext(actors, nextSide); animateForward(400, Clutter.AnimationMode.EASE_IN_OUT_CUBIC, 1000); nextPlayer = players.getNextPlayer(); players.switchPlayersForward(); break; case Clutter.Down: players.updateActorsPrevious(actors, nextSide); animateBackward(400, Clutter.AnimationMode.EASE_IN_OUT_CUBIC, 1000); nextPlayer = players.getPreviousPlayer(); players.switchPlayersBackward(); break; } inAnimation = true; nextSide = !nextSide; animateSound(400 + 1000, Clutter.AnimationMode.EASE_IN_OUT_CUBIC, nextPlayer, currentPlayer); nextPlayer.set_playing(true); Mainloop.timeout_add(400 + 1000 + 50, Lang.bind(this, function() { players.getPreviousPlayer().set_playing(false); //players.dumpFilenames(); inAnimation = false; log('event ended'); })); return true; })); stage.show(); Clutter.main();