root/trunk/as3/com/jeroenwijering/plugins/Controlbar.as

Revision 586, 13.7 kB (checked in by jeroen, 12 days ago)

added v5 skin, fixed duration overshoot and fixed smil+bitrates combo

  • Property svn:executable set to *
Line 
1/**
2* Display a controlbar with transport buttons and sliders.
3**/
4package com.jeroenwijering.plugins {
5
6
7import com.jeroenwijering.events.*;
8import com.jeroenwijering.utils.*;
9
10import flash.accessibility.*;
11import flash.display.*;
12import flash.events.MouseEvent;
13import flash.geom.ColorTransform;
14import flash.geom.Rectangle;
15import flash.net.URLRequest;
16import flash.text.*;
17import flash.ui.Mouse;
18import flash.utils.clearTimeout;
19import flash.utils.setTimeout;
20
21
22public class Controlbar implements PluginInterface {
23
24
25        /** List with configuration settings. **/
26        public var config:Object = {};
27        /** Reference to the controlbar clip. **/
28        public var clip:MovieClip;
29        /** Reference to the view. **/
30        private var view:AbstractView;
31        /** A list with all controls. **/
32        private var stacker:Stacker;
33        /** Timeout for hiding the clip. **/
34        private var hiding:Number;
35        /** When scrubbing, icon shouldn't be set. **/
36        private var scrubber:MovieClip;
37        /** Color object for frontcolor. **/
38        private var front:ColorTransform;
39        /** Color object for lightcolor. **/
40        private var light:ColorTransform;
41        /** The actions for all controlbar buttons. **/
42        private var BUTTONS:Object = {
43                playButton:'PLAY',
44                pauseButton:'PLAY',
45                stopButton:'STOP',
46                prevButton:'PREV',
47                nextButton:'NEXT',
48                linkButton:'LINK',
49                fullscreenButton:'FULLSCREEN',
50                normalscreenButton:'FULLSCREEN',
51                muteButton:'MUTE',
52                unmuteButton:'MUTE'
53        };
54        /** The actions for all sliders **/
55        private var SLIDERS:Object = {
56                timeSlider:'SEEK',
57                volumeSlider:'VOLUME'
58        }
59        /** The button to clone for all custom buttons. **/
60        private var clonee:MovieClip;
61        /** Saving the block state of the controlbar. **/
62        private var blocking:Boolean;
63
64
65        /** Constructor. **/
66        public function Controlbar():void {};
67
68        /**
69        * Add a new button to the controlclip.
70        *
71        * @param icn    A graphic to show as icon
72        * @param nam    Name of the button
73        * @param hdl    The function to call when clicking the button.
74        **/
75        public function addButton(icn:DisplayObject,nam:String,hdl:Function):void {
76                if(clip['linkButton'] && clip['linkButton'].back) {
77                        var btn:* = Draw.clone(clip['linkButton']);
78                        btn.name = nam+'Button';
79                        btn.visible = true;
80                        btn.tabEnabled = true;
81                        btn.tabIndex = 6;
82                        var acs:AccessibilityProperties = new AccessibilityProperties();
83                        acs.name = nam+'Button';
84                        btn.accessibilityProperties = acs;
85                        clip.addChild(btn);
86                        var off:Number = Math.round((btn.height-icn.height)/2);
87                        Draw.clear(btn.icon);
88                        btn.icon.addChild(icn);
89                        icn.x = icn.y = 0;
90                        btn.icon.x = btn.icon.y = off;
91                        btn.back.width = icn.width+2*off;
92                        btn.buttonMode = true;
93                        btn.mouseChildren = false;
94                        btn.addEventListener(MouseEvent.CLICK,hdl);
95                        if(front) {
96                                btn.icon.transform.colorTransform = front;
97                                btn.addEventListener(MouseEvent.MOUSE_OVER,overHandler);
98                                btn.addEventListener(MouseEvent.MOUSE_OUT,outHandler);
99                        }
100                        stacker.insert(btn,clip['linkButton']);
101                }
102        };
103
104
105        /** Hide the controlbar **/
106        public function block(stt:Boolean):void {
107                blocking = stt;
108                timeHandler();
109        };
110
111
112        /** Handle clicks from all buttons. **/
113        private function clickHandler(evt:MouseEvent):void {
114                var act:String = BUTTONS[evt.target.name];
115                if(blocking != true || act == "FULLSCREEN" || act == "MUTE") {
116                        view.sendEvent(act);
117                }
118        };
119
120
121        /** Handle mouse presses on sliders. **/
122        private function downHandler(evt:MouseEvent):void {
123                scrubber = MovieClip(evt.target);
124                if(blocking != true || scrubber.name == 'volumeSlider') {
125                        var rct:Rectangle = new Rectangle(scrubber.rail.x,scrubber.icon.y,scrubber.rail.width-scrubber.icon.width,0);
126                        scrubber.icon.startDrag(true,rct);
127                clip.stage.addEventListener(MouseEvent.MOUSE_UP,upHandler);
128                } else {
129                        scrubber = undefined;
130                }
131        };
132
133
134        /** Fix the timeline display. **/
135        private function fixTime():void {
136                try {
137                        var scp:Number = clip.timeSlider.scaleX;
138                        clip.timeSlider.scaleX = 1;
139                        clip.timeSlider.icon.x = scp*clip.timeSlider.icon.x;
140                        clip.timeSlider.mark.x = scp*clip.timeSlider.mark.x;
141                        clip.timeSlider.mark.width = scp*clip.timeSlider.mark.width;
142                        clip.timeSlider.rail.width = scp*clip.timeSlider.rail.width;
143                        clip.timeSlider.done.x = scp*clip.timeSlider.done.x;
144                        clip.timeSlider.done.width = scp*clip.timeSlider.done.width;
145                } catch (err:Error) {}
146        };
147
148
149        /** Initialize from view. **/
150        public function initializePlugin(vie:AbstractView):void {
151                view = vie;
152                view.addControllerListener(ControllerEvent.RESIZE,resizeHandler);
153                view.addModelListener(ModelEvent.LOADED,loadedHandler);
154                view.addModelListener(ModelEvent.STATE,stateHandler);
155                view.addModelListener(ModelEvent.TIME,timeHandler);
156                view.addControllerListener(ControllerEvent.PLAYLIST,itemHandler);
157                view.addControllerListener(ControllerEvent.ITEM,itemHandler);
158                view.addControllerListener(ControllerEvent.MUTE,muteHandler);
159                view.addControllerListener(ControllerEvent.VOLUME,volumeHandler);
160                stacker = new Stacker(clip);
161                setButtons();
162                setColors();
163                itemHandler();
164                loadedHandler();
165                muteHandler();
166                stateHandler();
167                timeHandler();
168                volumeHandler();
169        };
170
171
172        /** Handle a change in the current item **/
173        private function itemHandler(evt:ControllerEvent=null):void {
174                try {
175                        if(view.playlist && view.playlist.length > 1) {
176                                clip.prevButton.visible = clip.nextButton.visible = true;
177                        } else {
178                                clip.prevButton.visible = clip.nextButton.visible = false;
179                        }
180                } catch (err:Error) {}
181                try {
182                        if(view.playlist && view.playlist[view.config['item']]['link'] && !view.getPlugin('sharing')) {
183                                clip.linkButton.visible = true;
184                        } else {
185                                clip.linkButton.visible = false;
186                        }
187                } catch (err:Error) {}
188                timeHandler();
189                stacker.rearrange();
190                fixTime();
191                loadedHandler(new ModelEvent(ModelEvent.LOADED,{loaded:0,total:0}))
192        };
193
194
195        /** Process bytesloaded updates given by the model. **/
196        private function loadedHandler(evt:ModelEvent=null):void {
197                var pc1:Number = 0;
198                if(evt && evt.data.total > 0) {
199                        pc1 = evt.data.loaded/evt.data.total;
200                }
201                var pc2:Number = 0;
202                if(evt && evt.data.offset) {
203                        pc2 = evt.data.offset/evt.data.total;
204                }
205                try {
206                        var wid:Number = clip.timeSlider.rail.width;
207                        clip.timeSlider.mark.x = pc2*wid;
208                        clip.timeSlider.mark.width = pc1*wid;
209                        var icw:Number = clip.timeSlider.icon.x + clip.timeSlider.icon.width;
210                } catch (err:Error) {}
211        };
212
213
214        /** Show above controlbar on mousemove. **/
215        private function moveHandler(evt:MouseEvent=null):void {
216                if(clip.alpha == 0) { Animations.fade(clip,1); }
217                clearTimeout(hiding);
218                hiding = setTimeout(moveTimeout,2000);
219                Mouse.show();
220        };
221
222
223        /** Hide above controlbar again when move has timed out. **/
224        private function moveTimeout():void {
225                Animations.fade(clip,0);
226                Mouse.hide();
227        };
228
229
230        /** Show a mute icon if playing. **/
231        private function muteHandler(evt:ControllerEvent=null):void {
232                        if(view.config['mute'] == true) {
233                                try {
234                                        clip.muteButton.visible = false;
235                                        clip.unmuteButton.visible = true;
236                                } catch (err:Error) {}
237                                try {
238                                        clip.volumeSlider.mark.visible = false;
239                                        clip.volumeSlider.icon.x = clip.volumeSlider.rail.x;
240                                } catch (err:Error) {}
241                        } else {
242                                try {
243                                        clip.muteButton.visible = true;
244                                        clip.unmuteButton.visible = false;
245                                } catch (err:Error) {}
246                                try {
247                                        clip.volumeSlider.mark.visible = true;
248                                        volumeHandler();
249                                } catch (err:Error) {}
250                        }
251        };
252
253
254        /** Handle mouseouts from all buttons **/
255        private function outHandler(evt:MouseEvent):void {
256                if(front && evt.target['icon']) {
257                        evt.target['icon'].transform.colorTransform = front;
258                } else {
259                        evt.target.gotoAndPlay('out');
260                }
261        };
262
263
264        /** Handle clicks from all buttons **/
265        private function overHandler(evt:MouseEvent):void {
266                if(front && evt.target['icon']) {
267                        evt.target['icon'].transform.colorTransform = light;
268                } else {
269                        evt.target.gotoAndPlay('over');
270                }
271        };
272
273
274        /** Process resizing requests **/
275        private function resizeHandler(evt:ControllerEvent=null):void {
276                var wid:Number = config['width'];
277                clip.x = config['x'];
278                clip.y = config['y'];
279                clip.visible = config['visible'];
280                if(config['position'] == 'over' || view.config['fullscreen'] == true) {
281                        clip.x = config['x'] + config['margin'];
282                        clip.y = config['y'] + config['height'] - config['margin'] - config['size'];
283                        wid = config['width'] - 2*config['margin'];
284                }
285                try {
286                        clip.fullscreenButton.visible = false;
287                        clip.normalscreenButton.visible = false;
288                        if(clip.stage['displayState'] && view.config['height'] > 40) {
289                                if(view.config['fullscreen']) {
290                                        clip.fullscreenButton.visible = false;
291                                        clip.normalscreenButton.visible = true;
292                                } else {
293                                        clip.fullscreenButton.visible = true;
294                                        clip.normalscreenButton.visible = false;
295                                }
296                        }
297                } catch (err:Error) {}
298                stacker.rearrange(wid);
299                stateHandler();
300                fixTime();
301                Mouse.show();
302        };
303
304
305        /** Clickhandler for all buttons. **/
306        private function setButtons():void {
307                for(var btn:String in BUTTONS) {
308                        if(clip[btn]) {
309                                clip[btn].mouseChildren = false;
310                                clip[btn].buttonMode = true;
311                                clip[btn].addEventListener(MouseEvent.CLICK, clickHandler);
312                                clip[btn].addEventListener(MouseEvent.MOUSE_OVER, overHandler);
313                                clip[btn].addEventListener(MouseEvent.MOUSE_OUT, outHandler);
314                        }
315                }
316                for(var sld:String in SLIDERS) {
317                        if(clip[sld]) {
318                                clip[sld].mouseChildren = false;
319                                clip[sld].buttonMode = true;
320                                clip[sld].addEventListener(MouseEvent.MOUSE_DOWN, downHandler);
321                                clip[sld].addEventListener(MouseEvent.MOUSE_OVER, overHandler);
322                                clip[sld].addEventListener(MouseEvent.MOUSE_OUT, outHandler);
323                        }
324                }
325        };
326
327
328        /** Init the colors. **/
329        private function setColors():void {
330                if(view.config['backcolor'] && clip['playButton'].icon) {
331                        var clr:ColorTransform = new ColorTransform();
332                        clr.color = uint('0x'+view.config['backcolor'].substr(-6));
333                        clip.back.transform.colorTransform = clr;
334                }
335                if(view.config['frontcolor']) {
336                        try {
337                                front = new ColorTransform();
338                                front.color = uint('0x'+view.config['frontcolor'].substr(-6));
339                                for(var btn:String in BUTTONS) {
340                                        if(clip[btn]) {
341                                                clip[btn]['icon'].transform.colorTransform = front;
342                                        }
343                                }
344                                for(var sld:String in SLIDERS) {
345                                        if(clip[sld]) {
346                                                clip[sld]['icon'].transform.colorTransform = front;
347                                                clip[sld]['mark'].transform.colorTransform = front;
348                                                clip[sld]['rail'].transform.colorTransform = front;
349                                        }
350                                }
351                                clip.elapsedText.textColor = front.color;
352                                clip.totalText.textColor = front.color;
353                        } catch (err:Error) {}
354                }
355                if(view.config['lightcolor']) {
356                        light = new ColorTransform();
357                        light.color = uint('0x'+view.config['lightcolor'].substr(-6));
358                } else {
359                        light = front;
360                }
361                if(light) {
362                        try {
363                                clip['timeSlider']['done'].transform.colorTransform = light;
364                                clip['volumeSlider']['mark'].transform.colorTransform = light;
365                        } catch (err:Error) {}
366                }
367        };
368
369
370        /** Process state changes **/
371        private function stateHandler(evt:ModelEvent=undefined):void {
372                clearTimeout(hiding);
373                view.skin.removeEventListener(MouseEvent.MOUSE_MOVE,moveHandler);
374                try {
375                        var dps:String = clip.stage['displayState'];
376                } catch (err:Error) {}
377                switch(view.config['state']) {
378                        case ModelStates.PLAYING:
379                        case ModelStates.BUFFERING:
380                                try {
381                                        clip.playButton.visible = false;
382                                        clip.pauseButton.visible = true;
383                                } catch (err:Error) {}
384                                if(config['position'] == 'over' || (dps == 'fullScreen' && config['position'] != 'none')) {
385                                        hiding = setTimeout(moveTimeout,2000);
386                                        view.skin.addEventListener(MouseEvent.MOUSE_MOVE,moveHandler);
387                                } else {
388                                        Animations.fade(clip,1);
389                                }
390                                break;
391                        default:
392                                try {
393                                        clip.playButton.visible = true;
394                                        clip.pauseButton.visible = false;
395                                } catch (err:Error) {}
396                                if(config['position'] == 'over' || dps == 'fullScreen') {
397                                        Mouse.show();
398                                        Animations.fade(clip,1);
399                                }
400                }
401        };
402
403
404        /** Process time updates given by the model. **/
405        private function timeHandler(evt:ModelEvent=null):void {
406                var dur:Number = 0;
407                var pos:Number = 0;
408                if(evt) {
409                        dur = evt.data.duration;
410                        pos = evt.data.position;
411                } else if(view.playlist) {
412                        dur = view.playlist[view.config['item']]['duration'];
413                        pos = 0;
414                }
415                var pct:Number = pos/dur;
416                if(isNaN(pct)) { pct = 1; }
417                try {
418                        var clr:String = '000000';
419                        if(view.config['frontcolor']) {
420                                clr = view.config['frontcolor'].substr(-6);
421                        }
422                        clip.elapsedText.htmlText = '<font color="#'+clr+'"><b>'+Strings.digits(pos)+'</b></font>';
423                        clip.totalText.htmlText = '<font color="#'+clr+'"><b>'+Strings.digits(dur)+'</b></font>';
424                } catch (err:Error) {}
425                try {
426                        var tsl:MovieClip = clip.timeSlider;
427                        var xps:Number = Math.round(pct*(tsl.rail.width-tsl.icon.width));
428                        if (dur > 0) {
429                                clip.timeSlider.icon.visible = true;
430                                clip.timeSlider.mark.visible = true;
431                                if(!scrubber) {
432                                        clip.timeSlider.icon.x = xps;
433                                        clip.timeSlider.done.width = xps;
434                                }
435                                clip.timeSlider.done.visible = true;
436                        } else {
437                                clip.timeSlider.icon.visible = false;
438                                clip.timeSlider.mark.visible = false;
439                                clip.timeSlider.done.visible = false;
440                        }
441                } catch (err:Error) {}
442        };
443
444
445        /** Handle mouse releases on sliders. **/
446        private function upHandler(evt:MouseEvent):void {
447                var mpl:Number = 0;
448        clip.stage.removeEventListener(MouseEvent.MOUSE_UP,upHandler);
449                scrubber.icon.stopDrag();
450                if(scrubber.name == 'timeSlider' && view.playlist) {
451                        mpl = view.playlist[view.config['item']]['duration'];
452                } else if(scrubber.name == 'volumeSlider') {
453                        mpl = 100;
454                }
455                var pct:Number = (scrubber.icon.x-scrubber.rail.x) / (scrubber.rail.width-scrubber.icon.width) * mpl;
456                view.sendEvent(SLIDERS[scrubber.name],Math.round(pct));
457                scrubber = undefined;
458        };
459
460
461        /** Reflect the new volume in the controlbar **/
462        private function volumeHandler(evt:ControllerEvent=null):void {
463                try {
464                        var vsl:MovieClip = clip.volumeSlider;
465                        vsl.mark.width = view.config['volume']*(vsl.rail.width-vsl.icon.width/2)/100;
466                        vsl.icon.x = vsl.mark.x + view.config['volume']*(vsl.rail.width-vsl.icon.width)/100;
467                } catch (err:Error) {}
468        };
469
470
471};
472
473
474}
Note: See TracBrowser for help on using the browser.