source: trunk/fl5/src/com/longtailvideo/jwplayer/view/components/ControlbarComponentV4.as @ 819

Revision 819, 19.3 KB checked in by pablo, 3 years ago (diff)
  • Fixed bug in HTTP and YouTube where seeking could result in strange buffering behavior in the controlbar.
  • Try/catch Arthropod log.
  • MediaProviders send position w/ jwplayerMediaBuffer events
  • Fixed bug in PNG Skins where the buffer wouldn't show correctly with a seek/offset.
Line 
1package com.longtailvideo.jwplayer.view.components {
2        import com.longtailvideo.jwplayer.events.MediaEvent;
3        import com.longtailvideo.jwplayer.events.PlayerEvent;
4        import com.longtailvideo.jwplayer.events.PlayerStateEvent;
5        import com.longtailvideo.jwplayer.events.PlaylistEvent;
6        import com.longtailvideo.jwplayer.events.ViewEvent;
7        import com.longtailvideo.jwplayer.player.IPlayer;
8        import com.longtailvideo.jwplayer.player.PlayerState;
9        import com.longtailvideo.jwplayer.plugins.PluginConfig;
10        import com.longtailvideo.jwplayer.utils.Animations;
11        import com.longtailvideo.jwplayer.utils.Draw;
12        import com.longtailvideo.jwplayer.utils.Logger;
13        import com.longtailvideo.jwplayer.utils.Stacker;
14        import com.longtailvideo.jwplayer.utils.Strings;
15        import com.longtailvideo.jwplayer.view.PlayerLayoutManager;
16        import com.longtailvideo.jwplayer.view.interfaces.IControlbarComponent;
17       
18        import flash.accessibility.AccessibilityProperties;
19        import flash.display.DisplayObject;
20        import flash.display.MovieClip;
21        import flash.display.Sprite;
22        import flash.events.MouseEvent;
23        import flash.geom.ColorTransform;
24        import flash.geom.Rectangle;
25        import flash.text.TextField;
26        import flash.ui.Mouse;
27        import flash.utils.clearTimeout;
28        import flash.utils.setTimeout;
29
30
31        public class ControlbarComponentV4 extends CoreComponent implements IControlbarComponent {
32                /** Reference to the original skin **/
33                private var skin:Sprite;
34                /** A list with all controls. **/
35                private var stacker:Stacker;
36                /** Timeout for hiding the  **/
37                private var hiding:Number;
38                /** When scrubbing, icon shouldn't be set. **/
39                private var scrubber:MovieClip;
40                /** Color object for frontcolor. **/
41                private var front:ColorTransform;
42                /** Color object for lightcolor. **/
43                private var light:ColorTransform;
44                /** The actions for all controlbar buttons. **/
45                private var BUTTONS:Object;
46                /** The actions for all sliders **/
47                private var SLIDERS:Object = {timeSlider: ViewEvent.JWPLAYER_VIEW_SEEK,
48                                volumeSlider: ViewEvent.JWPLAYER_VIEW_VOLUME};
49                /** The button to clone for all custom buttons. **/
50                private var clonee:MovieClip;
51                /** Saving the block state of the controlbar. **/
52                private var blocking:Boolean;
53                /** Controlbar config **/
54                private var controlbarConfig:PluginConfig;
55                /** Animations handler **/
56                private var animations:Animations;
57                /** Last inserted button **/
58                private var lastInsert:MovieClip;
59
60
61                public function ControlbarComponentV4(player:IPlayer) {
62                        super(player, "controlbar");
63                        animations = new Animations(this);
64                        controlbarConfig = _player.config.pluginConfig("controlbar");
65                        if (!controlbarConfig['margin']) controlbarConfig['margin'] = 0;       
66                        // TODO: Remove Link button
67                        BUTTONS = {playButton: ViewEvent.JWPLAYER_VIEW_PLAY,
68                                        pauseButton: ViewEvent.JWPLAYER_VIEW_PAUSE,
69                                        stopButton: ViewEvent.JWPLAYER_VIEW_STOP,
70                                        prevButton: ViewEvent.JWPLAYER_VIEW_PREV,
71                                        nextButton: ViewEvent.JWPLAYER_VIEW_NEXT,
72                                        fullscreenButton: ViewEvent.JWPLAYER_VIEW_FULLSCREEN,
73                                        normalscreenButton: ViewEvent.JWPLAYER_VIEW_FULLSCREEN,
74                                        muteButton: ViewEvent.JWPLAYER_VIEW_MUTE,
75                                        unmuteButton: ViewEvent.JWPLAYER_VIEW_MUTE};
76                        skin = _player.skin.getSWFSkin().getChildByName('controlbar') as Sprite;
77                        skin.x = 0;
78                        skin.y = 0;
79                        addChild(skin);
80                        _player.addEventListener(PlayerStateEvent.JWPLAYER_PLAYER_STATE, stateHandler);
81                        _player.addEventListener(MediaEvent.JWPLAYER_MEDIA_TIME, timeHandler);
82                        _player.addEventListener(MediaEvent.JWPLAYER_MEDIA_MUTE, muteHandler);
83                        _player.addEventListener(MediaEvent.JWPLAYER_MEDIA_VOLUME, volumeHandler);
84                        _player.addEventListener(MediaEvent.JWPLAYER_MEDIA_BUFFER, timeHandler);
85                        _player.addEventListener(PlaylistEvent.JWPLAYER_PLAYLIST_LOADED, itemHandler);
86                        _player.addEventListener(PlaylistEvent.JWPLAYER_PLAYLIST_UPDATED, itemHandler);
87                        _player.addEventListener(PlaylistEvent.JWPLAYER_PLAYLIST_ITEM, itemHandler);
88                        stacker = new Stacker(skin as MovieClip);
89                        try {
90                                getSkinComponent("linkButton").visible = false;
91                        } catch (e:Error) {}
92                       
93                        setButtons();
94                        setColors();
95                        itemHandler();
96                        muteHandler();
97                        stateHandler();
98                        timeHandler();
99                        volumeHandler();
100                }
101
102
103                /**
104                 * Add a new button to the control
105                 *
106                 * @param icn   A graphic to show as icon
107                 * @param nam   Name of the button
108                   getSkinComponent('* @param hdl       The function to call when clicking the Button').
109                 **/
110                public function addButton(icon:DisplayObject, name:String, handler:Function=null):MovieClip {
111                        var btn:MovieClip;
112                        if (getSkinComponent('linkButton') && getSkinElementChild('linkButton', 'back')) {
113                                btn = Draw.clone(getSkinComponent('linkButton') as MovieClip) as MovieClip;
114                                btn.name = name + 'Button';
115                                btn.visible = true;
116                                btn.tabEnabled = true;
117                                btn.tabIndex = 6;
118                                var acs:AccessibilityProperties = new AccessibilityProperties();
119                                acs.name = name + 'Button';
120                                btn.accessibilityProperties = acs;
121                                skin.addChild(btn);
122                                var off:Number = Math.round((btn.height - icon.height) / 2);
123                                Draw.clear(btn['icon']);
124                                btn['icon'].addChild(icon);
125                                icon.x = icon.y = 0;
126                                btn['icon'].x = btn['icon'].y = off;
127                                btn['back'].width = icon.width + 2 * off;
128                                btn.buttonMode = true;
129                                btn.mouseChildren = false;
130                                btn.addEventListener(MouseEvent.CLICK, handler);
131                                if (front) {
132                                        btn['icon'].transform.colorTransform = front;
133                                        btn.addEventListener(MouseEvent.MOUSE_OVER, overHandler);
134                                        btn.addEventListener(MouseEvent.MOUSE_OUT, outHandler);
135                                }
136                                if (lastInsert) {
137                                        stacker.insert(btn, lastInsert);
138                                } else {
139                                        stacker.insert(btn, getSkinComponent('linkButton') as MovieClip);
140                                }
141                                lastInsert = btn;
142                        }
143                        return btn;
144                }
145
146
147                public function removeButton(name:String):void {
148                        skin.removeChild(getSkinComponent(name));
149                }
150
151                public function resize(width:Number, height:Number):void {
152                        if (!(PlayerLayoutManager.testPosition(controlbarConfig['position']) || controlbarConfig['position'] == "over")) {
153                                skin.visible = false;
154                                return;
155                        }
156
157                        var wid:Number = width;
158                        var margin:Number = controlbarConfig['margin'];
159
160                        if (controlbarConfig['position'] == 'over' || _player.fullscreen == true) {
161                                x = margin;
162                                y = height - skin.height - margin;
163                                wid = width - 2 * margin;
164                        }
165
166                        try {
167                                getSkinComponent('fullscreenButton').visible = false;
168                                getSkinComponent('normalscreenButton').visible = false;
169                                if (stage['displayState'] && _player.config.height > 40) {
170                                        if (_player.fullscreen) {
171                                                getSkinComponent('fullscreenButton').visible = false;
172                                                getSkinComponent('normalscreenButton').visible = true;
173                                        } else {
174                                                getSkinComponent('fullscreenButton').visible = true;
175                                                getSkinComponent('normalscreenButton').visible = false;
176                                        }
177                                }
178                        } catch (err:Error) {
179                        }
180                        stacker.rearrange(wid);
181                        stopFader();
182                        stateHandler();
183                        fixTime();
184                }
185
186
187                public function getButton(buttonName:String):DisplayObject {
188                        return null;
189                }
190
191
192                /** Hide the controlbar **/
193                public function block(stt:Boolean):void {
194                        blocking = stt;
195                        timeHandler();
196                }
197
198
199                /** Handle clicks from all buttons. **/
200                private function clickHandler(evt:MouseEvent):void {
201                        var act:String = BUTTONS[evt.target.name];
202                        var data:Object = null;
203                        if (blocking != true || act == ViewEvent.JWPLAYER_VIEW_FULLSCREEN || act == ViewEvent.JWPLAYER_VIEW_MUTE) {
204                                switch (act) {
205                                        case ViewEvent.JWPLAYER_VIEW_FULLSCREEN:
206                                                data = Boolean(!_player.fullscreen);
207                                                break;
208                                        case ViewEvent.JWPLAYER_VIEW_PAUSE:
209                                                data = Boolean(_player.state == PlayerState.IDLE || _player.state == PlayerState.PAUSED);
210                                                break;
211                                        case ViewEvent.JWPLAYER_VIEW_MUTE:
212                                                data = Boolean(!_player.mute);
213                                                break;
214                                }
215                                var event:ViewEvent = new ViewEvent(act, data);
216                                dispatchEvent(event);
217                        }
218                }
219
220
221                /** Handle mouse presses on sliders. **/
222                private function downHandler(evt:MouseEvent):void {
223                        if (!_player.locked) {
224                                scrubber = MovieClip(evt.target);
225                                if (blocking != true || scrubber.name == 'volumeSlider') {
226                                        var rct:Rectangle = new Rectangle(scrubber.rail.x, scrubber.icon.y, scrubber.rail.width - scrubber.icon.width, 0);
227                                        scrubber.icon.startDrag(true, rct);
228                                        stage.addEventListener(MouseEvent.MOUSE_UP, upHandler);
229                                } else {
230                                        scrubber = null;
231                                }
232                        }
233                }
234
235
236                /** Handle a change in the current item **/
237                private function itemHandler(evt:PlaylistEvent=null):void {
238                        try {
239                                if (_player.playlist && _player.playlist.length > 1) {
240                                        getSkinComponent('prevButton').visible = getSkinComponent('nextButton').visible = true;
241                                } else {
242                                        getSkinComponent('prevButton').visible = getSkinComponent('nextButton').visible = false;
243                                }
244                        } catch (err:Error) {
245                        }
246                        timeHandler();
247                        stacker.rearrange();
248                        fixTime();
249                }
250
251                /** Show a mute icon if playing. **/
252                private function muteHandler(evt:MediaEvent=null):void {
253                        if (_player.mute == true) {
254                                try {
255                                        getSkinComponent('muteButton').visible = false;
256                                        getSkinComponent('unmuteButton').visible = true;
257                                } catch (err:Error) {
258                                }
259                                try {
260                                        getSkinElementChild('volumeSlider', 'mark').visible = false;
261                                        getSkinElementChild('volumeSlider', 'icon').x = getSkinElementChild('volumeSlider', 'rail').x;
262                                } catch (err:Error) {
263                                }
264                        } else {
265                                try {
266                                        getSkinComponent('muteButton').visible = true;
267                                        getSkinComponent('unmuteButton').visible = false;
268                                } catch (err:Error) {
269                                }
270                                try {
271                                        getSkinElementChild('volumeSlider', 'mark').visible = true;
272                                        volumeHandler();
273                                } catch (err:Error) {
274                                }
275                        }
276                }
277
278
279                /** Handle mouseouts from all buttons **/
280                private function outHandler(evt:MouseEvent):void {
281                        if (front && evt.target['icon']) {
282                                evt.target['icon'].transform.colorTransform = front;
283                        } else {
284                                evt.target.gotoAndPlay('out');
285                        }
286                }
287
288
289                /** Handle clicks from all buttons **/
290                private function overHandler(evt:MouseEvent):void {
291                        if (front && evt.target['icon']) {
292                                evt.target['icon'].transform.colorTransform = light;
293                        } else {
294                                evt.target.gotoAndPlay('over');
295                        }
296                }
297
298
299                /** Clickhandler for all buttons. **/
300                private function setButtons():void {
301                        for (var btn:String in BUTTONS) {
302                                if (getSkinComponent(btn)) {
303                                        (getSkinComponent(btn) as MovieClip).mouseChildren = false;
304                                        (getSkinComponent(btn) as MovieClip).buttonMode = true;
305                                        getSkinComponent(btn).addEventListener(MouseEvent.CLICK, clickHandler);
306                                        getSkinComponent(btn).addEventListener(MouseEvent.MOUSE_OVER, overHandler);
307                                        getSkinComponent(btn).addEventListener(MouseEvent.MOUSE_OUT, outHandler);
308                                }
309                        }
310                        for (var sld:String in SLIDERS) {
311                                if (getSkinComponent(sld)) {
312                                        (getSkinComponent(sld) as MovieClip).mouseChildren = false;
313                                        (getSkinComponent(sld) as MovieClip).buttonMode = true;
314                                        getSkinComponent(sld).addEventListener(MouseEvent.MOUSE_DOWN, downHandler);
315                                        getSkinComponent(sld).addEventListener(MouseEvent.MOUSE_OVER, overHandler);
316                                        getSkinComponent(sld).addEventListener(MouseEvent.MOUSE_OUT, outHandler);
317                                }
318                        }
319                }
320
321
322                /** Init the colors. **/
323                private function setColors():void {
324                        if (_player.config.backcolor && getSkinElementChild('playButton', 'icon')) {
325                                var clr:ColorTransform = new ColorTransform();
326                                clr.color = _player.config.backcolor.color;
327                                getSkinComponent('back').transform.colorTransform = clr;
328                        }
329                        if (_player.config.frontcolor) {
330                                try {
331                                        front = new ColorTransform();
332                                        front.color = _player.config.frontcolor.color;
333                                        for (var btn:String in BUTTONS) {
334                                                if (getSkinComponent(btn)) {
335                                                        getSkinElementChild(btn, 'icon').transform.colorTransform = front;
336                                                }
337                                        }
338                                        for (var sld:String in SLIDERS) {
339                                                if (getSkinComponent(sld)) {
340                                                        getSkinElementChild(sld, 'icon').transform.colorTransform = front;
341                                                        getSkinElementChild(sld, 'mark').transform.colorTransform = front;
342                                                        getSkinElementChild(sld, 'rail').transform.colorTransform = front;
343                                                }
344                                        }
345                                        (getSkinComponent('elapsedText') as TextField).textColor = front.color;
346                                        (getSkinComponent('totalText') as TextField).textColor = front.color;
347                                } catch (err:Error) {
348                                }
349                        }
350                        if (_player.config.lightcolor) {
351                                light = new ColorTransform();
352                                light.color = _player.config.lightcolor.color;
353                        } else {
354                                light = front;
355                        }
356                        if (light) {
357                                try {
358                                        getSkinElementChild('timeSlider', 'done').transform.colorTransform = light;
359                                        getSkinElementChild('volumeSlider', 'mark').transform.colorTransform = light;
360                                } catch (err:Error) {
361                                }
362                        }
363                }
364
365               
366                private function startFader():void {
367                        if (controlbarConfig['position'] == 'over' || (_player.fullscreen && controlbarConfig['position'] != 'none')) {
368                                if (!isNaN(hiding)) {
369                                        clearTimeout(hiding);
370                                }
371                                hiding = setTimeout(moveTimeout, 2000);
372                                _player.controls.display.addEventListener(MouseEvent.MOUSE_MOVE, moveHandler);
373                        }
374                }
375               
376                private function stopFader():void {
377                        if (!isNaN(hiding)) {
378                                clearTimeout(hiding);
379                                try {
380                                        _player.controls.display.removeEventListener(MouseEvent.MOUSE_MOVE, moveHandler);
381                                } catch (e:Error) {}
382                        }
383                        Mouse.show();
384                        animations.fade(1);
385                }
386               
387                /** Show above controlbar on mousemove. **/
388                private function moveHandler(evt:MouseEvent=null):void {
389                        if (alpha == 0) {
390                                animations.fade(1);
391                        }
392                        clearTimeout(hiding);
393                        hiding = setTimeout(moveTimeout, 2000);
394                        Mouse.show();
395                }
396               
397               
398                /** Hide above controlbar again when move has timed out. **/
399                private function moveTimeout():void {
400                        animations.fade(0);
401                        Mouse.hide();
402                }
403               
404                /** Process state changes **/
405                private function stateHandler(evt:PlayerEvent=null):void {
406                        // TODO: Fix non-working fading
407                        clearTimeout(hiding);
408                        try {
409                                switch (_player.state) {
410                                        case PlayerState.PLAYING:
411                                                getSkinComponent('playButton').visible = false;
412                                                getSkinComponent('pauseButton').visible = true;
413                                                startFader();
414                                                break;
415                                        case PlayerState.PAUSED:
416                                                getSkinComponent('playButton').visible = true;
417                                                getSkinComponent('pauseButton').visible = false;
418                                                stopFader();
419                                                break;
420                                        case PlayerState.BUFFERING:
421                                                getSkinComponent('playButton').visible = false;
422                                                getSkinComponent('pauseButton').visible = true;
423                                                stopFader();
424                                                break;
425                                        case PlayerState.IDLE:
426                                                getSkinComponent('playButton').visible = true;
427                                                getSkinComponent('pauseButton').visible = false;
428                                                timeHandler();
429                                                stopFader();
430                                                break;
431                                }
432                        } catch (e:Error) {
433                        }
434                }
435
436
437                /** Process time updates given by the model. **/
438                private function timeHandler(evt:MediaEvent=null):void {
439                        var dur:Number = 0;
440                        var pos:Number = 0;
441                        if (evt) {
442                                if (evt.duration >= 0) {
443                                        dur = evt.duration;
444                                }
445                                if (evt.position >= 0) {
446                                        pos = evt.position;
447                                }
448                        } else if (_player.playlist.length > 0 && _player.playlist.currentItem) {
449                                if (_player.playlist.currentItem.duration >= 0) {
450                                        dur = _player.playlist.currentItem.duration;
451                                }
452                        }
453                        var pct:Number = pos / dur;
454                        if (isNaN(pct)) {
455                                pct = 1;
456                        }
457                        try {
458                                (getSkinComponent('elapsedText') as TextField).text = Strings.digits(pos);
459                                (getSkinComponent('totalText') as TextField).text = Strings.digits(dur);
460                        } catch (err:Error) {
461                                Logger.log(err);
462                        }
463                        try {
464                                var xps:Number = Math.round(pct * (getSkinElementChild('timeSlider', 'rail').width - getSkinElementChild('timeSlider', 'icon').width));
465                                bufferHandler(evt);
466                                if (dur > 0) {
467                                        getSkinElementChild('timeSlider', 'icon').visible = _player.state != PlayerState.IDLE;
468                                        getSkinElementChild('timeSlider', 'mark').visible = _player.state != PlayerState.IDLE;
469                                        if (!scrubber) {
470                                                getSkinElementChild('timeSlider', 'icon').x = xps;
471                                                getSkinElementChild('timeSlider', 'done').width = xps;
472                                        }
473                                        getSkinElementChild('timeSlider', 'done').visible = _player.state != PlayerState.IDLE;
474                                } else {
475                                        if (_player.state != PlayerState.PLAYING) {
476                                                getSkinElementChild('timeSlider', 'icon').visible = false;
477                                                getSkinElementChild('timeSlider', 'mark').visible = false;
478                                                getSkinElementChild('timeSlider', 'done').visible = false;
479                                        }
480                                }
481                        } catch (err:Error) {
482                        }
483                }
484
485
486                private function bufferHandler(evt:MediaEvent):void {
487                        if (!evt || evt.bufferPercent < 0)
488                                return;
489
490                        var mark:DisplayObject = getSkinElementChild('timeSlider', 'mark');
491                        var railWidth:Number = getSkinElementChild('timeSlider', 'rail').width;
492                        var markWidth:Number = _player.state == PlayerState.IDLE ? 0 : Math.round(evt.bufferPercent / 100 * railWidth);
493                        var offset:Number = evt.offset / evt.duration;
494
495                        try {
496                                mark.x = evt.duration > 0 ? Math.round(railWidth * offset) : 0;
497                                mark.width = markWidth;
498                                mark.visible = _player.state != PlayerState.IDLE;
499                        } catch (e:Error) {
500                                Logger.log(e);
501                        }
502                }
503
504
505                /** Fix the timeline display. **/
506                private function fixTime():void {
507                        try {
508                                var scp:Number = getSkinComponent('timeSlider').scaleX;
509                                getSkinComponent('timeSlider').scaleX = 1;
510                                getSkinElementChild('timeSlider', 'icon').x = scp * getSkinElementChild('timeSlider', 'icon').x;
511                                getSkinElementChild('timeSlider', 'mark').x = scp * getSkinElementChild('timeSlider', 'mark').x;
512                                getSkinElementChild('timeSlider', 'mark').width = scp * getSkinElementChild('timeSlider', 'mark').width;
513                                getSkinElementChild('timeSlider', 'rail').width = scp * getSkinElementChild('timeSlider', 'rail').width;
514                                getSkinElementChild('timeSlider', 'done').x = scp * getSkinElementChild('timeSlider', 'done').x;
515                                getSkinElementChild('timeSlider', 'done').width = scp * getSkinElementChild('timeSlider', 'done').width;
516                        } catch (err:Error) {
517                        }
518                }
519
520
521                /** Handle mouse releases on sliders. **/
522                private function upHandler(evt:MouseEvent):void {
523                        var mpl:Number = 0;
524                        var sliderType:String = scrubber.name;
525
526                        stage.removeEventListener(MouseEvent.MOUSE_UP, upHandler);
527                        scrubber.icon.stopDrag();
528                        if (sliderType == 'timeSlider' && _player.playlist) {
529                                mpl = _player.playlist.currentItem.duration;
530                        } else if (sliderType == 'volumeSlider') {
531                                mpl = 100;
532                        }
533                        var pct:Number = (scrubber.icon.x - scrubber.rail.x) / (scrubber.rail.width - scrubber.icon.width) * mpl;
534                        scrubber = null;
535                        if (sliderType == 'volumeSlider') {
536                                var volumeEvent:MediaEvent = new MediaEvent(MediaEvent.JWPLAYER_MEDIA_VOLUME);
537                                volumeEvent.volume = Math.round(pct);
538                                volumeHandler(volumeEvent);
539                        }
540                        dispatchEvent(new ViewEvent(SLIDERS[sliderType], Math.round(pct)));
541                }
542
543
544                /** Reflect the new volume in the controlbar **/
545                private function volumeHandler(evt:MediaEvent=null):void {
546                        try {
547                                var vsl:MovieClip = getSkinComponent('volumeSlider') as MovieClip;
548                                vsl.mark.width = _player.config.volume * (vsl.rail.width - vsl.icon.width / 2) / 100;
549                                vsl.icon.x = vsl.mark.x + _player.config.volume * (vsl.rail.width - vsl.icon.width) / 100;
550                        } catch (err:Error) {
551                        }
552                }
553
554
555                private function getSkinComponent(element:String):DisplayObject {
556                        return skin.getChildByName(element) as DisplayObject;
557                }
558
559
560                private function getSkinElementChild(element:String, child:String):DisplayObject {
561                        return (skin.getChildByName(element) as MovieClip).getChildByName(child);
562                }
563        }
564}
Note: See TracBrowser for help on using the repository browser.