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

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