├── Makefile ├── README.md ├── build.bat ├── build.sh ├── docs ├── demo.html ├── jstest.html └── vgaplayer.swf ├── src ├── ControlBar.as ├── FullscreenButton.as ├── Main.as ├── OverlayButton.as ├── PlayPauseButton.as ├── SeekBar.as ├── StatusDisplay.as ├── VolumeSlider.as └── baseui │ ├── Button.as │ ├── Control.as │ ├── MenuItem.as │ ├── MenuItemEvent.as │ ├── MenuPopup.as │ ├── PopupMenuButton.as │ ├── Slider.as │ ├── Style.as │ └── TextMenuItem.as └── vgaplayer.as3proj /Makefile: -------------------------------------------------------------------------------- 1 | # GNUMakefile 2 | RSYNC=/usr/bin/rsync \ 3 | --exclude NOBACKUP/ \ 4 | --exclude LOCAL/ \ 5 | --exclude local/ \ 6 | --exclude tmp/ \ 7 | --exclude obj/ \ 8 | --exclude Makefile \ 9 | --exclude '.??*' \ 10 | --exclude '*~' 11 | 12 | PROJECT=vgaplayer 13 | WWWBASE=../../euske.github.io/$(PROJECT)/ 14 | 15 | all: 16 | 17 | clean: 18 | 19 | upload: bin 20 | -$(RSYNC) -rutv bin/ $(WWWBASE)/ 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | VGA Player 2 | ========== 3 | 4 | VGAPlayer is an open source player for FLV videos (static or RTMP stream). 5 | 6 | Demo: http://euske.github.io/vgaplayer/demo.html 7 | 8 | Typical usage: 9 | 10 | 16 | 17 | FlashVars Parameters: 18 | 19 | It takes a form of `FlashVars="name=value&name=value&..."` 20 | 21 | * url: RTMP URL. (e.g. "rtmp://example.com/live" or "/app/live") 22 | * debug: Indicates if the debug console is displayed. (1: on, 0: off) 23 | * fullscreen: Indicates if the fullscreen button is shown. (1: on, 0: off) 24 | * smoothing: Indicates if the video smoothing is turned on. (1: on, 0: off) 25 | * start: Start position of the stream. (default: 0) 26 | * autoplay: Start playing automatically. (1: on, 0: off) 27 | * bufferTime: Stream buffering time. (default: 1.0 sec) 28 | * bufferTimeMax: Maximum stream buffering time. (default: 1.0 sec) 29 | * bgColor: Background color. (default: "#000000") 30 | * buttonBgColor: Button background color. The upper 8 bits are for alpha. (default: "#448888ff") 31 | * buttonFgColor: Button foreground color. (default: "#cc888888") 32 | * buttonHiFgColor: Button highlighted foreground color. (default: "#ffeeeeee") 33 | * buttonHiBgColor: Button highlighted background color. (default: "#ff444488") 34 | * buttonBorderColor: Button border color. (default: "#88ffffff") 35 | * volumeMutedColor: Color used when the volume is muted. (default: "#ffff0000") 36 | * imageUrl: Background image URL. 37 | * menu: Add a menu. (Explained below.) (1: on, 0: off) 38 | * pid: A string to identify a player in Javascript. (Explained below.) 39 | 40 | Adding a Menu 41 | ------------- 42 | 43 | It is possible to add a menu. (Javascript required.) 44 | There are two Javascript callback functions: 45 | `VGAPlayerOnLoad` and `VGAPlayerOnMenuChoose`. 46 | 47 | Demo: http://euske.github.io/vgaplayer/jstest.html 48 | 49 | 60 | ... 61 | 68 | 69 | 70 | Terms and Conditions 71 | -------------------- 72 | 73 | (This is so-called MIT/X License) 74 | 75 | Copyright (c) 2014 Yusuke Shinyama 76 | 77 | Permission is hereby granted, free of charge, to any person 78 | obtaining a copy of this software and associated documentation 79 | files (the "Software"), to deal in the Software without 80 | restriction, including without limitation the rights to use, 81 | copy, modify, merge, publish, distribute, sublicense, and/or 82 | sell copies of the Software, and to permit persons to whom the 83 | Software is furnished to do so, subject to the following 84 | conditions: 85 | 86 | The above copyright notice and this permission notice shall be 87 | included in all copies or substantial portions of the Software. 88 | 89 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 90 | KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 91 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 92 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 93 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 94 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 95 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 96 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 97 | -------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | @set FLEX_HOME=%UserProfile%\flex_sdk_4.6 2 | java -jar %FLEX_HOME%\lib\mxmlc.jar +flexlib=%FLEX_HOME%\frameworks -static-rsls -o .\bin\vgaplayer.swf -compiler.source-path=./src .\src\Main.as 3 | @if errorlevel 1 ( 4 | pause 5 | exit /b 6 | ) 7 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | JAVA=java 3 | FLEX_HOME=${FLEX_HOME:-$HOME/flex_sdk_4.6} 4 | MXMLC="$JAVA -jar $FLEX_HOME/lib/mxmlc.jar +flexlib=$FLEX_HOME/frameworks" 5 | 6 | $MXMLC -static-rsls -o ./bin/vgaplayer.swf -compiler.source-path=./src/ ./src/Main.as 7 | -------------------------------------------------------------------------------- /docs/demo.html: -------------------------------------------------------------------------------- 1 | 2 | VGAPlayer Test 3 | 4 | 5 | 6 | 7 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/jstest.html: -------------------------------------------------------------------------------- 1 | 2 | VGAPlayer Javascript Test 3 | 4 | 17 | 24 | 25 | -------------------------------------------------------------------------------- /docs/vgaplayer.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/euske/vgaplayer/90fc691370493291cafb5e0a6c39e2bb9fa0beee/docs/vgaplayer.swf -------------------------------------------------------------------------------- /src/ControlBar.as: -------------------------------------------------------------------------------- 1 | package { 2 | 3 | import flash.display.Sprite; 4 | import flash.utils.getTimer; 5 | import baseui.Style; 6 | import baseui.PopupMenuButton; 7 | 8 | // ControlBar 9 | // Bar shown at the bottom of screen containing buttons, etc. 10 | // 11 | public class ControlBar extends Sprite 12 | { 13 | public var margin:int = 4; 14 | public var fadeDuration:int = 1000; 15 | 16 | public var playButton:PlayPauseButton; 17 | public var volumeSlider:VolumeSlider; 18 | public var seekBar:SeekBar; 19 | public var statusDisplay:StatusDisplay; 20 | public var popupMenu:PopupMenuButton; 21 | public var fsButton:FullscreenButton; 22 | 23 | private var _autohide:Boolean; 24 | private var _timeout:int; 25 | 26 | public function ControlBar(fullscreen:Boolean=false, 27 | menu:Boolean=false) 28 | { 29 | super(); 30 | _timeout = -fadeDuration; 31 | 32 | playButton = new PlayPauseButton(); 33 | addChild(playButton); 34 | 35 | volumeSlider = new VolumeSlider(); 36 | volumeSlider.value = 1.0; 37 | addChild(volumeSlider); 38 | 39 | seekBar = new SeekBar(); 40 | seekBar.visible = false; 41 | addChild(seekBar); 42 | 43 | statusDisplay = new StatusDisplay(); 44 | addChild(statusDisplay); 45 | 46 | if (menu) { 47 | popupMenu = new PopupMenuButtonOfDoom(); 48 | addChild(popupMenu); 49 | } 50 | 51 | if (fullscreen) { 52 | fsButton = new FullscreenButton(); 53 | addChild(fsButton); 54 | } 55 | } 56 | 57 | public function get autohide():Boolean 58 | { 59 | return _autohide; 60 | } 61 | 62 | public function set autohide(value:Boolean):void 63 | { 64 | _autohide = value; 65 | } 66 | 67 | public function set style(value:Style):void 68 | { 69 | playButton.style = value; 70 | volumeSlider.style = value; 71 | seekBar.style = value; 72 | statusDisplay.style = value; 73 | if (popupMenu != null) { 74 | popupMenu.style = value; 75 | } 76 | if (fsButton != null) { 77 | fsButton.style = value; 78 | } 79 | } 80 | 81 | public function show(duration:int=2000):void 82 | { 83 | _timeout = getTimer()+duration; 84 | } 85 | 86 | public function resize(w:int, h:int):void 87 | { 88 | var size:int = h - margin*2; 89 | var x0:int = margin; 90 | var x1:int = w - margin; 91 | 92 | graphics.clear(); 93 | graphics.beginFill(0, 0.5); 94 | graphics.drawRect(0, 0, w, h); 95 | graphics.endFill(); 96 | 97 | playButton.resize(size, size); 98 | playButton.x = x0; 99 | playButton.y = margin; 100 | x0 += playButton.width + margin; 101 | 102 | if (fsButton != null) { 103 | fsButton.resize(size, size); 104 | fsButton.x = x1 - fsButton.width; 105 | fsButton.y = margin; 106 | x1 = fsButton.x - margin; 107 | } 108 | 109 | if (popupMenu != null) { 110 | popupMenu.resize(size, size); 111 | popupMenu.x = x1 - popupMenu.width; 112 | popupMenu.y = margin; 113 | x1 = popupMenu.x - margin; 114 | } 115 | 116 | volumeSlider.resize(size*2, size); 117 | volumeSlider.x = x1 - volumeSlider.width; 118 | volumeSlider.y = margin; 119 | x1 = volumeSlider.x - margin; 120 | 121 | seekBar.resize(x1-x0, size); 122 | seekBar.x = x0; 123 | seekBar.y = margin; 124 | 125 | statusDisplay.resize(x1-x0, size); 126 | statusDisplay.x = x0; 127 | statusDisplay.y = margin; 128 | } 129 | 130 | public function update():void 131 | { 132 | if (_autohide) { 133 | var a:Number = (_timeout - getTimer())/fadeDuration + 1.0; 134 | alpha = Math.min(Math.max(a, 0.0), 1.0); 135 | } else { 136 | alpha = 1.0; 137 | } 138 | playButton.update(); 139 | volumeSlider.update(); 140 | seekBar.update(); 141 | statusDisplay.update(); 142 | if (popupMenu != null) { 143 | popupMenu.update(); 144 | } 145 | if (fsButton != null) { 146 | fsButton.update(); 147 | } 148 | } 149 | } 150 | 151 | } // package 152 | 153 | import baseui.PopupMenuButton; 154 | 155 | class PopupMenuButtonOfDoom extends PopupMenuButton 156 | { 157 | public override function repaint():void 158 | { 159 | super.repaint(); 160 | 161 | // draw a gear. 162 | var size:int = buttonSize/8; 163 | var color:uint = (highlit)? style.hiFgColor : style.fgColor; 164 | var cx:int = width/2 + ((pressed)? 1 : 0); 165 | var cy:int = height/2 + ((pressed)? 1 : 0); 166 | 167 | graphics.beginFill(color, (color>>>24)/255); 168 | graphics.moveTo(cx+size*3, cy); 169 | const T:Number = 2.0*Math.PI/32; 170 | for (var i:int = 0; i < 32; i++) { 171 | var r:Number = ((i % 4) < 2)? 3 : 2; 172 | graphics.lineTo(cx+Math.cos(T*i)*size*r, cy+Math.sin(T*i)*size*r); 173 | } 174 | graphics.lineTo(cx+size*3, cy); 175 | graphics.drawCircle(cx, cy, size*1); 176 | graphics.endFill(); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /src/FullscreenButton.as: -------------------------------------------------------------------------------- 1 | package { 2 | 3 | import baseui.Button; 4 | 5 | // FullscreenButton 6 | // Fullscreen/Windowed toggle button. (part of ControlBar) 7 | // 8 | public class FullscreenButton extends Button 9 | { 10 | private var _toFullscreen:Boolean = false; 11 | 12 | public function get toFullscreen():Boolean 13 | { 14 | return _toFullscreen; 15 | } 16 | 17 | public function set toFullscreen(value:Boolean):void 18 | { 19 | _toFullscreen = value; 20 | invalidate(); 21 | } 22 | 23 | public override function repaint():void 24 | { 25 | super.repaint(); 26 | var size:int = buttonSize/16; 27 | var color:uint = (highlit)? style.hiFgColor : style.fgColor; 28 | var cx:int = width/2 + ((pressed)? 1 : 0); 29 | var cy:int = height/2 + ((pressed)? 1 : 0); 30 | 31 | if (_toFullscreen) { 32 | graphics.beginFill(color, (color>>>24)/255); 33 | graphics.drawRect(cx-size*7, cy-size*4, size*14, size*8); 34 | graphics.endFill(); 35 | } else { 36 | graphics.lineStyle(0, color, (color>>>24)/255); 37 | graphics.drawRect(cx-size*7, cy-size*5, size*10, size*6); 38 | graphics.drawRect(cx-size*2, cy-size*1, size*9, size*7); 39 | } 40 | } 41 | } 42 | 43 | } // package 44 | -------------------------------------------------------------------------------- /src/Main.as: -------------------------------------------------------------------------------- 1 | // VGAPlayer 2 | // 3 | 4 | package { 5 | 6 | import flash.display.Sprite; 7 | import flash.display.DisplayObject; 8 | import flash.display.Loader; 9 | import flash.display.LoaderInfo; 10 | import flash.display.StageDisplayState; 11 | import flash.display.StageScaleMode; 12 | import flash.display.StageAlign; 13 | import flash.events.Event; 14 | import flash.events.KeyboardEvent; 15 | import flash.events.MouseEvent; 16 | import flash.events.FullScreenEvent; 17 | import flash.events.NetStatusEvent; 18 | import flash.events.AsyncErrorEvent; 19 | import flash.media.Video; 20 | import flash.media.SoundTransform; 21 | import flash.net.NetConnection; 22 | import flash.net.NetStream; 23 | import flash.net.URLRequest; 24 | import flash.ui.Keyboard; 25 | import flash.external.ExternalInterface; 26 | import flash.system.Security; 27 | import baseui.Style; 28 | import baseui.Slider; 29 | import baseui.MenuItemEvent; 30 | 31 | // Main 32 | // 33 | public class Main extends Sprite 34 | { 35 | private const STARTING:String = "STARTING"; 36 | private const STARTED:String = "STARTED"; 37 | private const STOPPING:String = "STOPPING"; 38 | private const STOPPED:String = "STOPPED"; 39 | private const PAUSED:String = "PAUSED"; // only used for non-remoting streams. 40 | 41 | private var _config:Config; 42 | private var _video:Video; 43 | private var _overlay:OverlayButton; 44 | private var _control:ControlBar; 45 | private var _debugdisp:DebugDisplay; 46 | private var _imageLoader:Loader; 47 | 48 | private var _url:String; 49 | private var _streamPath:String; 50 | private var _remoting:Boolean; // true if connected via RTMP or FMS. 51 | private var _connection:NetConnection; 52 | private var _stream:NetStream; 53 | private var _videoMetaData:Object; 54 | private var _state:String; 55 | 56 | // Main() 57 | public function Main() 58 | { 59 | var info:LoaderInfo = LoaderInfo(this.root.loaderInfo); 60 | _config = new Config(info.parameters); 61 | 62 | stage.color = _config.bgColor; 63 | stage.scaleMode = StageScaleMode.NO_SCALE; 64 | stage.align = StageAlign.TOP_LEFT; 65 | 66 | if (_config.imageUrl != null) { 67 | _imageLoader = new Loader(); 68 | _imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded); 69 | _imageLoader.load(new URLRequest(_config.imageUrl)); 70 | addChild(_imageLoader); 71 | } 72 | 73 | _video = new Video(); 74 | _video.smoothing = _config.smoothing; 75 | addChild(_video); 76 | 77 | _overlay = new OverlayButton(); 78 | _overlay.visible = false; 79 | _overlay.style = _config.style; 80 | _overlay.addEventListener(MouseEvent.CLICK, onOverlayClick); 81 | addChild(_overlay); 82 | 83 | _control = new ControlBar(_config.fullscreen, _config.menu); 84 | _control.style = _config.style; 85 | _control.playButton.addEventListener(MouseEvent.CLICK, onPlayPauseClick); 86 | _control.volumeSlider.addEventListener(Slider.CLICK, onVolumeSliderClick); 87 | _control.volumeSlider.addEventListener(Slider.CHANGED, onVolumeSliderChanged); 88 | _control.seekBar.addEventListener(Slider.CHANGED, onSeekBarChanged); 89 | if (_control.popupMenu != null) { 90 | _control.popupMenu.container = this; 91 | _control.popupMenu.addEventListener(MenuItemEvent.CHOOSE, onMenuItemChoose); 92 | } 93 | if (_control.fsButton != null) { 94 | _control.fsButton.toFullscreen = (stage.displayState == StageDisplayState.NORMAL); 95 | _control.fsButton.addEventListener(MouseEvent.CLICK, onFullscreenClick); 96 | } 97 | addChild(_control); 98 | 99 | _debugdisp = new DebugDisplay(); 100 | _debugdisp.visible = _config.debug; 101 | addChild(_debugdisp); 102 | 103 | addEventListener(Event.ADDED_TO_STAGE, onAdded); 104 | addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); 105 | addEventListener(MouseEvent.MOUSE_UP, onMouseUp); 106 | addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); 107 | stage.addEventListener(Event.RESIZE, onResize); 108 | stage.addEventListener(Event.ENTER_FRAME, onEnterFrame); 109 | stage.addEventListener(FullScreenEvent.FULL_SCREEN, onFullScreen); 110 | stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); 111 | resize(); 112 | 113 | log("FlashVars:", expandAttrs(info.parameters)); 114 | log("url:", _config.url); 115 | log("fullscreen:", _config.fullscreen); 116 | log("bufferTime:", _config.bufferTime); 117 | log("bufferTimeMax:", _config.bufferTimeMax); 118 | log("maxPauseBufferTime:", _config.maxPauseBufferTime); 119 | log("backBufferTime:", _config.backBufferTime); 120 | log("inBufferSeek:", _config.inBufferSeek); 121 | 122 | _connection = new NetConnection(); 123 | _connection.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent); 124 | _connection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncErrorEvent); 125 | 126 | updateStatus(STOPPED); 127 | 128 | if (ExternalInterface.available) { 129 | // Allowing security domains. 130 | // Not sure if this is the right way... 131 | var domain:String = (Security.pageDomain == null)? "*" : Security.pageDomain; 132 | log("ExternalInterface: allowing: "+domain); 133 | Security.allowDomain(domain); 134 | ExternalInterface.addCallback("VGAPlayerAddMenuItem", externalAddMenuItem); 135 | ExternalInterface.addCallback("VGAPlayerConnect", externalConnect); 136 | } 137 | } 138 | 139 | private function log(... args):void 140 | { 141 | var x:String = ""; 142 | for each (var a:Object in args) { 143 | if (x.length != 0) x += " "; 144 | x += a; 145 | } 146 | _debugdisp.writeLine(x); 147 | trace(x); 148 | } 149 | 150 | private function expandAttrs(obj:Object):String 151 | { 152 | var x:String = null; 153 | for (var key:Object in obj) { 154 | var value:Object = obj[key]; 155 | if (x == null) { 156 | x = key+"="+value; 157 | } else { 158 | x += ", "+key+"="+value; 159 | } 160 | } 161 | return x; 162 | } 163 | 164 | private function getCanonicalizedURL(url:String, proto:String="rtmp"):String 165 | { 166 | if (url.indexOf("://") < 0) { 167 | // Resolve a relative url. 168 | var info:LoaderInfo = LoaderInfo(this.root.loaderInfo); 169 | var basehref:String = info.loaderURL; 170 | var i:int; 171 | if (url.substr(0, 1) == "/") { 172 | i = basehref.indexOf("://"); 173 | if (0 < i) { 174 | basehref = basehref.substring(i+3); 175 | i = basehref.indexOf("/"); 176 | if (i < 0) { 177 | i = basehref.length; 178 | } 179 | url = proto+"://"+basehref.substr(0, i)+url; 180 | } 181 | } else { 182 | i = basehref.lastIndexOf("/"); 183 | url = basehref.substr(0, i+1)+url; 184 | } 185 | } 186 | return url; 187 | } 188 | 189 | private function onAdded(e:Event):void 190 | { 191 | init(); 192 | } 193 | 194 | private function onResize(e:Event):void 195 | { 196 | resize(); 197 | } 198 | 199 | private function onFullScreen(e:FullScreenEvent):void 200 | { 201 | _control.fsButton.toFullscreen = !e.fullScreen; 202 | } 203 | 204 | private function onEnterFrame(e:Event):void 205 | { 206 | update(); 207 | } 208 | 209 | private function onMouseDown(e:MouseEvent):void 210 | { 211 | _control.show(); 212 | } 213 | private function onMouseUp(e:MouseEvent):void 214 | { 215 | _control.show(); 216 | } 217 | private function onMouseMove(e:MouseEvent):void 218 | { 219 | _control.show(); 220 | } 221 | 222 | private function onKeyDown(e:KeyboardEvent):void 223 | { 224 | _control.show(); 225 | switch (e.keyCode) { 226 | case Keyboard.ESCAPE: // Esc 227 | case 68: // D 228 | // Toggle the debug window if debug = 1. 229 | if (_config.debug) { 230 | _debugdisp.visible = !_debugdisp.visible; 231 | } 232 | break; 233 | case Keyboard.SPACE: 234 | // Toggle play/stop. 235 | setPlayState(_control.playButton.state == _control.playButton.PLAY); 236 | break; 237 | case Keyboard.LEFT: 238 | // Rewind for 10 sec. 239 | seekDelta(-10); 240 | break; 241 | case Keyboard.RIGHT: 242 | // Fast-forward for 10 sec. 243 | seekDelta(+10); 244 | break; 245 | case Keyboard.UP: 246 | // Rewind for 1 min. 247 | seekDelta(-60); 248 | break; 249 | case Keyboard.DOWN: 250 | // Fast-forward for 1 min. 251 | seekDelta(+60); 252 | break; 253 | case Keyboard.PAGE_UP: 254 | // Rewind for 10 min. 255 | seekDelta(-600); 256 | break; 257 | case Keyboard.PAGE_DOWN: 258 | // Fast-forward for 10 min. 259 | seekDelta(+600); 260 | break; 261 | case Keyboard.HOME: 262 | // Rewind to the beginning. 263 | seek(0); 264 | break; 265 | } 266 | } 267 | 268 | private function onNetStatusEvent(ev:NetStatusEvent):void 269 | { 270 | log("onNetStatusEvent:", expandAttrs(ev.info)); 271 | switch (ev.info.code) { 272 | case "NetConnection.Connect.Failed": 273 | case "NetConnection.Connect.Rejected": 274 | case "NetConnection.Connect.InvalidApp": 275 | updateStatus(STOPPED, "Failed"); 276 | break; 277 | 278 | case "NetConnection.Connect.Success": 279 | var nc:NetConnection = NetConnection(ev.target); 280 | _stream = new NetStream(nc); 281 | _stream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent); 282 | _stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncErrorEvent); 283 | _stream.client = new Object(); 284 | _stream.client.onMetaData = onMetaData; 285 | _stream.client.onCuePoint = onCuePoint; 286 | _stream.client.onPlayStatus = onPlayStatus; 287 | _stream.inBufferSeek = _config.inBufferSeek; 288 | _stream.bufferTime = _config.bufferTime; 289 | _stream.bufferTimeMax = _config.bufferTimeMax; 290 | _stream.maxPauseBufferTime = _config.maxPauseBufferTime; 291 | _stream.backBufferTime = _config.backBufferTime; 292 | _video.attachNetStream(_stream); 293 | _control.seekBar.isStatic = !_remoting; 294 | updateVolume(_control.volumeSlider); 295 | startPlaying(_config.start); 296 | break; 297 | 298 | case "NetConnection.Connect.Closed": 299 | stopPlaying(); 300 | _video.attachNetStream(null); 301 | _stream.removeEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent); 302 | _stream.removeEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncErrorEvent); 303 | _stream.client = null; 304 | _stream = null; 305 | updateStatus(STOPPED, "Disconnected"); 306 | break; 307 | 308 | case "NetStream.Play.Start": 309 | updateStatus(STARTING); 310 | break; 311 | 312 | case "NetStream.Play.Stop": 313 | case "NetStream.Play.Complete": 314 | case "NetStream.Buffer.Flush": 315 | updateStatus(STOPPED); 316 | break; 317 | 318 | case "NetStream.Buffer.Empty": 319 | updateStatus(STARTING); 320 | break; 321 | 322 | case "NetStream.Buffer.Full": 323 | if (_state == STOPPING) { 324 | stopPlaying(); 325 | } else { 326 | updateStatus(STARTED); 327 | } 328 | break; 329 | } 330 | } 331 | 332 | private function onImageLoaded(event:Event):void 333 | { 334 | resize(); 335 | } 336 | 337 | private function onMetaData(info:Object):void 338 | { 339 | log("onMetaData:", expandAttrs(info)); 340 | _videoMetaData = info; 341 | if (0 < _videoMetaData.duration) { 342 | // Show the seek bar when the video duration is defined. 343 | _control.statusDisplay.visible = false; 344 | _control.seekBar.duration = _videoMetaData.duration; 345 | _control.seekBar.bytesTotal = _videoMetaData.filesize; 346 | _control.seekBar.visible = true; 347 | } else { 348 | _control.statusDisplay.visible = true; 349 | _control.seekBar.duration = 0; 350 | _control.seekBar.visible = false; 351 | } 352 | updateStatus(_state); 353 | resize(); 354 | } 355 | 356 | private function onCuePoint(info:Object):void 357 | { 358 | log("onCuePoint:", expandAttrs(info)); 359 | } 360 | 361 | private function onPlayStatus(info:Object):void 362 | { 363 | log("onPlayStatus:", expandAttrs(info)); 364 | } 365 | 366 | private function onAsyncErrorEvent(ev:AsyncErrorEvent):void 367 | { 368 | log("onAsyncErrorEvent:", ev.error); 369 | } 370 | 371 | private function onOverlayClick(e:MouseEvent):void 372 | { 373 | var overlay:OverlayButton = OverlayButton(e.target); 374 | overlay.show(); 375 | setPlayState(overlay.state == overlay.PLAY); 376 | } 377 | 378 | private function onPlayPauseClick(e:Event):void 379 | { 380 | var button:PlayPauseButton = PlayPauseButton(e.target); 381 | setPlayState(button.state == button.PLAY); 382 | } 383 | 384 | private function onVolumeSliderClick(e:Event):void 385 | { 386 | var slider:VolumeSlider = VolumeSlider(e.target); 387 | slider.muted = !slider.muted; 388 | updateVolume(slider); 389 | } 390 | 391 | private function onVolumeSliderChanged(e:Event):void 392 | { 393 | var slider:VolumeSlider = VolumeSlider(e.target); 394 | updateVolume(slider); 395 | } 396 | 397 | private function onSeekBarChanged(e:Event):void 398 | { 399 | var seekbar:SeekBar = SeekBar(e.target); 400 | seek(seekbar.time); 401 | } 402 | 403 | private function onFullscreenClick(e:Event):void 404 | { 405 | var button:FullscreenButton = FullscreenButton(e.target); 406 | stage.displayState = ((button.toFullscreen)? 407 | StageDisplayState.FULL_SCREEN : 408 | StageDisplayState.NORMAL); 409 | } 410 | 411 | private function onMenuItemChoose(e:MenuItemEvent):void 412 | { 413 | log("onMenuItemChoose:", e.item.value); 414 | 415 | if (ExternalInterface.available) { 416 | ExternalInterface.call("VGAPlayerOnMenuChoose", e.item.value); 417 | } 418 | } 419 | 420 | private function proportionalScaleToStage(obj:DisplayObject, w:int, h:int):void 421 | { 422 | var r:Number = Math.min((stage.stageWidth / w), 423 | (stage.stageHeight / h)); 424 | obj.width = w*r; 425 | obj.height = h*r; 426 | obj.x = (stage.stageWidth - obj.width)/2; 427 | obj.y = (stage.stageHeight - obj.height)/2; 428 | } 429 | 430 | private function updateVolume(slider:VolumeSlider):void 431 | { 432 | if (_stream != null) { 433 | var transform:SoundTransform = 434 | new SoundTransform((slider.muted)? 0 : slider.value); 435 | _stream.soundTransform = transform; 436 | } 437 | } 438 | 439 | private function updateStatus(state:String, text:String=null):void 440 | { 441 | _state = state; 442 | switch (_state) { 443 | case STARTING: 444 | _overlay.state = _overlay.BUSY; 445 | _overlay.autohide = false; 446 | _control.playButton.state = _control.playButton.BUSY; 447 | if (text == null) { 448 | text = "Starting..."; 449 | } 450 | break; 451 | 452 | case STARTED: 453 | _control.seekBar.unlock(); 454 | _overlay.state = _overlay.PAUSE; 455 | _overlay.autohide = true; 456 | _control.playButton.state = _control.playButton.PAUSE; 457 | _control.autohide = true; 458 | if (text == null) { 459 | text = "Playing"; 460 | } 461 | break; 462 | 463 | case STOPPING: 464 | _overlay.state = _overlay.BUSY; 465 | _overlay.autohide = false; 466 | _control.playButton.state = _control.playButton.BUSY; 467 | if (text == null) { 468 | text = "Stopping..."; 469 | } 470 | break; 471 | 472 | case STOPPED: 473 | case PAUSED: 474 | _overlay.state = _overlay.PLAY; 475 | _overlay.autohide = false; 476 | _control.playButton.state = _control.playButton.PLAY; 477 | _control.autohide = false; 478 | if (text == null) { 479 | text = "Stopped"; 480 | } 481 | break; 482 | } 483 | 484 | _control.statusDisplay.text = text; 485 | } 486 | 487 | private function startPlaying(start:Number):void 488 | { 489 | if (_streamPath != null && _stream != null) { 490 | updateStatus(STARTING); 491 | log("Starting:", _streamPath, start); 492 | _stream.play(_streamPath, start); 493 | } 494 | } 495 | 496 | private function stopPlaying():void 497 | { 498 | if (_stream != null) { 499 | if (_remoting) { 500 | log("Stopping"); 501 | updateStatus(STOPPING); 502 | _stream.close(); 503 | } else { 504 | updateStatus(PAUSED); 505 | _stream.pause(); 506 | } 507 | } 508 | } 509 | 510 | private function init():void 511 | { 512 | log("init"); 513 | 514 | // Notify the browser if possible. 515 | if (ExternalInterface.available) { 516 | ExternalInterface.call("VGAPlayerOnLoad", _config.pid); 517 | } 518 | 519 | if (_config.url != null) { 520 | _overlay.visible = true; 521 | _overlay.state = _overlay.PLAY; 522 | if (_config.autoplay) { 523 | _url = _config.url; 524 | connect(); 525 | } 526 | } 527 | } 528 | 529 | private function resize():void 530 | { 531 | log("resize:", stage.stageWidth+","+stage.stageHeight); 532 | 533 | if (_videoMetaData != null) { 534 | proportionalScaleToStage(_video, _videoMetaData.width, _videoMetaData.height); 535 | } 536 | if (_imageLoader != null) { 537 | proportionalScaleToStage(_imageLoader, _imageLoader.width, _imageLoader.height); 538 | } 539 | 540 | _overlay.resize(stage.stageWidth, stage.stageHeight); 541 | _overlay.x = 0; 542 | _overlay.y = 0; 543 | 544 | _control.resize(stage.stageWidth, 28); 545 | _control.x = 0; 546 | _control.y = stage.stageHeight-_control.height; 547 | 548 | _debugdisp.resize(stage.stageWidth, stage.stageHeight-_control.height); 549 | _debugdisp.x = 0; 550 | _debugdisp.y = 0; 551 | } 552 | 553 | private function update():void 554 | { 555 | _overlay.update(); 556 | _control.update(); 557 | if (_stream != null) { 558 | if (_state == STARTED) { 559 | _control.seekBar.time = _stream.time; 560 | } 561 | if (0 < _stream.bytesTotal) { 562 | _control.seekBar.bytesLoaded = _stream.bytesLoaded; 563 | } 564 | if (_debugdisp.visible) { 565 | _debugdisp.update(_stream); 566 | } 567 | } 568 | } 569 | 570 | private function externalAddMenuItem(label:String, value:String=null):void 571 | { 572 | log("externalAddMenuItem: "+label+", "+value); 573 | if (_control.popupMenu != null) { 574 | _control.popupMenu.addTextItem(label, value); 575 | } 576 | } 577 | 578 | private function externalConnect(url:String):void 579 | { 580 | stopPlaying(); 581 | _url = url; 582 | connect(); 583 | } 584 | 585 | public function connect():void 586 | { 587 | if (_connection.connected) { 588 | _connection.close(); 589 | } 590 | if (_url != null && !_connection.connected) { 591 | var url:String = getCanonicalizedURL(_url); 592 | if (url.substr(0, 5) == "rtmp:") { 593 | var i:int = url.lastIndexOf("/"); 594 | _streamPath = url.substr(i+1); 595 | _remoting = true; 596 | url = url.substr(0, i); 597 | } else { 598 | _streamPath = url; 599 | _remoting = false; 600 | url = null; 601 | } 602 | log("Connecting:", url); 603 | _overlay.visible = true; 604 | _control.statusDisplay.text = "Connecting..."; 605 | _connection.connect(url); 606 | } 607 | } 608 | 609 | public function setPlayState(playing:Boolean):void 610 | { 611 | log("setPlayState:", playing); 612 | switch (_state) { 613 | case STARTING: 614 | if (!playing) { 615 | updateStatus(STOPPING); 616 | } 617 | break; 618 | case STARTED: 619 | if (!playing) { 620 | stopPlaying(); 621 | } 622 | break; 623 | case STOPPED: 624 | if (playing) { 625 | if (_connection.connected) { 626 | startPlaying(_control.seekBar.time); 627 | } else { 628 | connect(); 629 | } 630 | } 631 | break; 632 | case PAUSED: 633 | if (playing) { 634 | if (_stream != null) { 635 | _stream.resume(); 636 | } 637 | } 638 | break; 639 | } 640 | } 641 | 642 | public function seek(t:Number):void 643 | { 644 | log("seek:", t); 645 | if (_stream != null) { 646 | _stream.seek(t); 647 | } 648 | } 649 | 650 | public function seekDelta(dt:Number):void 651 | { 652 | log("seekDelta:", dt); 653 | if (_stream != null) { 654 | _stream.seek(_stream.time + dt); 655 | } 656 | } 657 | 658 | } 659 | 660 | } // package 661 | 662 | /// Private classes below. 663 | 664 | import flash.display.Sprite; 665 | import flash.text.TextField; 666 | import flash.text.TextFieldType; 667 | import flash.text.TextFormat; 668 | import flash.net.NetStream; 669 | import flash.net.NetStreamInfo; 670 | import baseui.Style; 671 | 672 | // Config 673 | // Object to hold the parameters given by FlashVars. 674 | // 675 | class Config extends Object 676 | { 677 | public var debug:Boolean = false; 678 | public var url:String = null; 679 | public var bufferTime:Number = 1.0; 680 | public var bufferTimeMax:Number = 0.0; 681 | public var maxPauseBufferTime:Number = 30.0; 682 | public var backBufferTime:Number = 30.0; 683 | public var inBufferSeek:Boolean = false; 684 | public var fullscreen:Boolean = false; 685 | public var menu:Boolean = false; 686 | public var smoothing:Boolean = false; 687 | public var start:Number = 0.0; 688 | public var autoplay:Boolean = true; 689 | 690 | public var bgColor:uint = 0x000000; 691 | public var style:Style = new Style(); 692 | public var volumeMutedColor:uint = 0xffff0000; 693 | public var imageUrl:String = null; 694 | public var pid:String = null; 695 | 696 | public function Config(obj:Object) 697 | { 698 | super(); 699 | if (obj != null) { 700 | // debug 701 | if (obj.debug) { 702 | debug = parseBoolean(obj.debug); 703 | } 704 | // url 705 | if (obj.url) { 706 | url = obj.url; 707 | } 708 | // bufferTime 709 | if (obj.bufferTime) { 710 | bufferTime = parseFloat(obj.bufferTime); 711 | bufferTimeMax = bufferTime; 712 | maxPauseBufferTime = bufferTime; 713 | } 714 | // bufferTimeMax 715 | if (obj.bufferTimeMax) { 716 | bufferTimeMax = parseFloat(obj.bufferTimeMax); 717 | } 718 | // maxPauseBufferTime 719 | if (obj.maxPauseBufferTime) { 720 | maxPauseBufferTime = parseFloat(obj.maxPauseBufferTime); 721 | } 722 | // backBufferTime 723 | if (obj.backBufferTime) { 724 | backBufferTime = parseFloat(obj.backBufferTime); 725 | } 726 | // inBufferSeek 727 | if (obj.inBufferSeek) { 728 | inBufferSeek = parseBoolean(obj.inBufferSeek); 729 | } 730 | // fullscreen 731 | if (obj.fullscreen) { 732 | fullscreen = parseBoolean(obj.fullscreen); 733 | } 734 | // menu 735 | if (obj.menu) { 736 | menu = parseBoolean(obj.menu); 737 | } 738 | // smoothing 739 | if (obj.smoothing) { 740 | smoothing = parseBoolean(obj.smoothing); 741 | } 742 | // start 743 | if (obj.start) { 744 | start = parseFloat(obj.start); 745 | } 746 | // autoplay 747 | if (obj.autoplay) { 748 | autoplay = parseBoolean(obj.autoplay); 749 | } 750 | 751 | // bgColor 752 | if (obj.bgColor) { 753 | bgColor = parseColor(obj.bgColor); 754 | } 755 | // buttonBgColor 756 | if (obj.buttonBgColor) { 757 | style.bgColor = parseColor(obj.buttonBgColor); 758 | } 759 | // buttonFgColor 760 | if (obj.buttonFgColor) { 761 | style.fgColor = parseColor(obj.buttonFgColor); 762 | } 763 | // buttonHiFgColor 764 | if (obj.buttonHiFgColor) { 765 | style.hiFgColor = parseColor(obj.buttonHiFgColor); 766 | } 767 | // buttonHiBgColor 768 | if (obj.buttonHiBgColor) { 769 | style.hiBgColor = parseColor(obj.buttonHiBgColor); 770 | } 771 | // buttonBorderColor 772 | if (obj.buttonBorderColor) { 773 | style.borderColor = parseColor(obj.buttonBorderColor); 774 | } 775 | // volumeMutedColor 776 | if (obj.volumeMutedColor) { 777 | volumeMutedColor = parseColor(obj.volumeMutedColor); 778 | } 779 | // imageUrl 780 | if (obj.imageUrl) { 781 | imageUrl = obj.imageUrl; 782 | } 783 | // pid 784 | if (obj.pid) { 785 | pid = obj.pid; 786 | } 787 | } 788 | } 789 | 790 | private function parseBoolean(v:String):Boolean 791 | { 792 | return (parseInt(v) != 0); 793 | } 794 | 795 | private function parseColor(v:String):uint 796 | { 797 | if (v.substr(0, 1) == "#") { 798 | v = v.substr(1); 799 | } 800 | return parseInt(v, 16); 801 | } 802 | } 803 | 804 | 805 | // DebugDisplay 806 | // Text areas showing the debug info. 807 | // 808 | class DebugDisplay extends Sprite 809 | { 810 | private var _logger:TextField; 811 | private var _playstat:TextField; 812 | private var _streaminfo:TextField; 813 | 814 | public function DebugDisplay() 815 | { 816 | super(); 817 | _logger = new TextField(); 818 | _logger.multiline = true; 819 | _logger.wordWrap = true; 820 | _logger.border = true; 821 | _logger.background = true; 822 | _logger.type = TextFieldType.DYNAMIC; 823 | _logger.width = 400; 824 | _logger.height = 100; 825 | addChild(_logger); 826 | 827 | _playstat = new TextField(); 828 | _playstat.multiline = true; 829 | _playstat.textColor = 0xffffff; 830 | _playstat.type = TextFieldType.DYNAMIC; 831 | _playstat.text = "\n\n\n\n\n\n\n\n"; 832 | _playstat.width = 200; 833 | _playstat.height = _playstat.textHeight+1; 834 | addChild(_playstat); 835 | 836 | _streaminfo = new TextField(); 837 | _streaminfo.multiline = true; 838 | _streaminfo.textColor = 0xffff00; 839 | _streaminfo.type = TextFieldType.DYNAMIC; 840 | _streaminfo.text = "\n\n\n\n\n\n\n\n\n\n\n"; 841 | _streaminfo.width = 200; 842 | _streaminfo.height = _streaminfo.textHeight+1; 843 | addChild(_streaminfo); 844 | } 845 | 846 | public function writeLine(x:String):void 847 | { 848 | _logger.appendText(x+"\n"); 849 | _logger.scrollV = _logger.maxScrollV; 850 | } 851 | 852 | public function resize(w:int, h:int):void 853 | { 854 | _playstat.x = w - _playstat.width; 855 | _playstat.y = h - _playstat.height; 856 | _streaminfo.x = 0; 857 | _streaminfo.y = h - _streaminfo.height; 858 | } 859 | 860 | public function update(stream:NetStream):void 861 | { 862 | if (!visible) return; 863 | 864 | var text:String; 865 | text = ("time: "+stream.time+"\n"+ 866 | "bufferLength: "+stream.bufferLength+"\n"+ 867 | "backBufferLength: "+stream.backBufferLength+"\n"+ 868 | "bytesLoaded: "+stream.bytesLoaded+"\n"+ 869 | "bytesTotal: "+stream.bytesTotal+"\n"+ 870 | "currentFPS: "+Math.floor(stream.currentFPS)+"\n"+ 871 | "liveDelay: "+stream.liveDelay+"\n"); 872 | _playstat.text = text; 873 | 874 | var info:NetStreamInfo = stream.info; 875 | text = ("isLive: "+info.isLive+"\n"+ 876 | "byteCount: "+info.byteCount+"\n"+ 877 | "audioBufferLength: "+info.audioBufferLength+"\n"+ 878 | "videoBufferLength: "+info.videoBufferLength+"\n"+ 879 | "currentBytesPerSecond: "+Math.floor(info.currentBytesPerSecond)+"\n"+ 880 | "maxBytesPerSecond: "+Math.floor(info.maxBytesPerSecond)+"\n"+ 881 | "audioBytesPerSecond: "+Math.floor(info.audioBytesPerSecond)+"\n"+ 882 | "videoBytesPerSecond: "+Math.floor(info.videoBytesPerSecond)+"\n"+ 883 | "playbackBytesPerSecond: "+Math.floor(info.playbackBytesPerSecond)+"\n"+ 884 | "droppedFrames: "+info.droppedFrames+"\n"); 885 | _streaminfo.text = text; 886 | } 887 | } 888 | -------------------------------------------------------------------------------- /src/OverlayButton.as: -------------------------------------------------------------------------------- 1 | package { 2 | 3 | import flash.display.Sprite; 4 | import flash.events.MouseEvent; 5 | import flash.utils.getTimer; 6 | import baseui.Style; 7 | 8 | // OverlayButton 9 | // A transparent button shown over the video. 10 | // 11 | public class OverlayButton extends Sprite 12 | { 13 | public const PLAY:String = "PLAY"; 14 | public const PAUSE:String = "PAUSE"; 15 | public const BUSY:String = "BUSY"; 16 | 17 | public var style:Style = new Style(); 18 | public var buttonSize:int = 100; 19 | public var fadeDuration:int = 2000; 20 | 21 | private var _size:int; 22 | private var _width:int; 23 | private var _height:int; 24 | private var _invalidated:Boolean; 25 | private var _highlit:Boolean; 26 | private var _state:String; 27 | private var _autohide:Boolean; 28 | private var _timeout:int; 29 | 30 | public function OverlayButton() 31 | { 32 | super(); 33 | _timeout = 0; 34 | alpha = 0; 35 | addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); 36 | addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); 37 | addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); 38 | } 39 | 40 | public function get state():String 41 | { 42 | return _state; 43 | } 44 | 45 | public function set state(value:String):void 46 | { 47 | _state = value; 48 | _invalidated = true; 49 | } 50 | 51 | public function get autohide():Boolean 52 | { 53 | return _autohide; 54 | } 55 | 56 | public function set autohide(value:Boolean):void 57 | { 58 | _autohide = value; 59 | } 60 | 61 | protected virtual function onMouseOver(e:MouseEvent):void 62 | { 63 | _highlit = true; 64 | _invalidated = true; 65 | } 66 | 67 | protected virtual function onMouseOut(e:MouseEvent):void 68 | { 69 | _highlit = false; 70 | _invalidated = true; 71 | } 72 | 73 | protected virtual function onMouseMove(e:MouseEvent):void 74 | { 75 | if (_timeout < getTimer()) { 76 | show(); 77 | } 78 | } 79 | 80 | public function resize(w:int, h:int):void 81 | { 82 | _width = w; 83 | _height = h; 84 | _invalidated = true; 85 | } 86 | 87 | public function show():void 88 | { 89 | _timeout = getTimer()+fadeDuration; 90 | _invalidated = true; 91 | } 92 | 93 | public function repaint():void 94 | { 95 | graphics.clear(); 96 | graphics.beginFill(0, 0); 97 | graphics.drawRect(0, 0, _width, _height); 98 | graphics.endFill(); 99 | 100 | var size:int = buttonSize/16; 101 | var cx:int = width/2; 102 | var cy:int = height/2; 103 | 104 | var fgcolor:uint = (_highlit)? style.hiFgColor : style.fgColor; 105 | var bgcolor:uint = (_highlit)? style.hiBgColor : style.bgColor; 106 | graphics.beginFill(bgcolor, (bgcolor>>>24)/255); 107 | graphics.drawRect(cx-buttonSize/2, cy-buttonSize/2, buttonSize, buttonSize); 108 | graphics.endFill(); 109 | 110 | switch (_state) { 111 | case PLAY: 112 | graphics.beginFill(fgcolor, (fgcolor>>>24)/255); 113 | graphics.moveTo(cx-size*3, cy-size*4); 114 | graphics.lineTo(cx-size*3, cy+size*4); 115 | graphics.lineTo(cx+size*4, cy); 116 | graphics.endFill(); 117 | break; 118 | case PAUSE: 119 | graphics.beginFill(fgcolor, (fgcolor>>>24)/255); 120 | graphics.drawRect(cx-size*3, cy-size*4, size*2, size*8); 121 | graphics.drawRect(cx+size*1, cy-size*4, size*2, size*8); 122 | graphics.endFill(); 123 | break; 124 | case BUSY: 125 | graphics.beginFill(fgcolor, (fgcolor>>>24)/255); 126 | graphics.drawCircle(cx-size*3, cy, size); 127 | graphics.drawCircle(cx, cy, size); 128 | graphics.drawCircle(cx+size*3, cy, size); 129 | graphics.endFill(); 130 | break; 131 | } 132 | } 133 | 134 | public function update():void 135 | { 136 | if (_invalidated) { 137 | _invalidated = false; 138 | repaint(); 139 | } 140 | 141 | if (_autohide) { 142 | var a:Number = (_timeout - getTimer())/fadeDuration; 143 | alpha = Math.min(Math.max(a, 0.0), 1.0); 144 | } else { 145 | alpha = 1.0; 146 | } 147 | } 148 | } 149 | 150 | } // package 151 | -------------------------------------------------------------------------------- /src/PlayPauseButton.as: -------------------------------------------------------------------------------- 1 | package { 2 | 3 | import baseui.Button; 4 | 5 | // PlayPauseButton 6 | // Play/pause toggle button. (part of ControlBar) 7 | // 8 | public class PlayPauseButton extends Button 9 | { 10 | public const PLAY:String = "PLAY"; 11 | public const PAUSE:String = "PAUSE"; 12 | public const BUSY:String = "BUSY"; 13 | 14 | private var _state:String; 15 | 16 | public function get state():String 17 | { 18 | return _state; 19 | } 20 | 21 | public function set state(value:String):void 22 | { 23 | _state = value; 24 | invalidate(); 25 | } 26 | 27 | public override function repaint():void 28 | { 29 | super.repaint(); 30 | var size:int = buttonSize/16; 31 | var color:uint = (highlit)? style.hiFgColor : style.fgColor; 32 | var cx:int = width/2 + ((pressed)? 1 : 0); 33 | var cy:int = height/2 + ((pressed)? 1 : 0); 34 | 35 | switch (_state) { 36 | case PLAY: 37 | graphics.beginFill(color, (color>>>24)/255); 38 | graphics.moveTo(cx-size*3, cy-size*4); 39 | graphics.lineTo(cx-size*3, cy+size*4); 40 | graphics.lineTo(cx+size*4, cy); 41 | graphics.endFill(); 42 | break; 43 | case PAUSE: 44 | graphics.beginFill(color, (color>>>24)/255); 45 | graphics.drawRect(cx-size*3, cy-size*4, size*2, size*8); 46 | graphics.drawRect(cx+size*1, cy-size*4, size*2, size*8); 47 | graphics.endFill(); 48 | break; 49 | } 50 | } 51 | } 52 | 53 | } // package 54 | -------------------------------------------------------------------------------- /src/SeekBar.as: -------------------------------------------------------------------------------- 1 | package { 2 | 3 | import flash.text.TextField; 4 | import flash.text.TextFieldAutoSize; 5 | import flash.text.TextFormat; 6 | import flash.events.Event; 7 | import flash.events.MouseEvent; 8 | import baseui.Slider; 9 | 10 | // SeekBar 11 | // A horizontal seek bar. (part of ControlBar) 12 | // 13 | public class SeekBar extends Slider 14 | { 15 | public var margin:int = 4; 16 | public var barSize:int = 2; 17 | 18 | private var _text:TextField; 19 | private var _duration:Number = 0; 20 | private var _bytesTotal:uint = 0; 21 | private var _bytesLoaded:uint = 0; 22 | private var _static:Boolean = false; 23 | private var _locked:Boolean = false; 24 | private var _time:Number = 0; 25 | private var _goal:Number = 0; 26 | 27 | public function SeekBar() 28 | { 29 | super(); 30 | _text = new TextField(); 31 | _text.x = margin; 32 | _text.selectable = false; 33 | _text.autoSize = TextFieldAutoSize.LEFT; 34 | addChild(_text); 35 | } 36 | 37 | public function setTextFormat(textFormat:TextFormat, embedFonts:Boolean=false):void 38 | { 39 | _text.defaultTextFormat = textFormat; 40 | _text.embedFonts = embedFonts; 41 | invalidate(); 42 | } 43 | 44 | protected override function onMouseDownLocal(e:MouseEvent):void 45 | { 46 | super.onMouseDownLocal(e); 47 | updateGoal(e.localX); 48 | } 49 | 50 | protected override function onMouseDrag(e:MouseEvent):void 51 | { 52 | super.onMouseDrag(e); 53 | updateGoal(e.localX); 54 | } 55 | 56 | protected override function onMouseUpLocal(e:MouseEvent):void 57 | { 58 | super.onMouseUpLocal(e); 59 | dispatchEvent(new Event(CHANGED)); 60 | } 61 | 62 | private function updateGoal(x:int):void 63 | { 64 | var w:int = (width-margin-leftMargin); 65 | var v:Number = (x-leftMargin)/w; 66 | v = Math.min(v, availableRatio); 67 | _locked = true; 68 | _goal = Math.max(0, Math.min(1, v)) * _duration; 69 | invalidate(); 70 | } 71 | 72 | public function get leftMargin():int 73 | { 74 | return (margin+_text.width); 75 | } 76 | 77 | public function get duration():Number 78 | { 79 | return _duration; 80 | } 81 | 82 | public function set duration(v:Number):void 83 | { 84 | _duration = v; 85 | invalidate(); 86 | } 87 | 88 | public function set isStatic(v:Boolean):void 89 | { 90 | _static = v; 91 | invalidate(); 92 | } 93 | 94 | public function set bytesTotal(v:uint):void 95 | { 96 | _bytesTotal = v; 97 | invalidate(); 98 | } 99 | 100 | public function set bytesLoaded(v:uint):void 101 | { 102 | _bytesLoaded = v; 103 | invalidate(); 104 | } 105 | 106 | public function get availableRatio():Number 107 | { 108 | if (_static && 0 < _bytesTotal) { 109 | return _bytesLoaded / Number(_bytesTotal); 110 | } else { 111 | return 1.0; 112 | } 113 | } 114 | 115 | public function set time(v:Number):void 116 | { 117 | _time = v; 118 | invalidate(); 119 | } 120 | 121 | public function get time():Number 122 | { 123 | return (_locked)? _goal : _time; 124 | } 125 | 126 | public function unlock():void 127 | { 128 | _locked = false; 129 | invalidate(); 130 | } 131 | 132 | public override function repaint():void 133 | { 134 | super.repaint(); 135 | var size:int = barSize; 136 | var color:uint = (highlit)? style.hiFgColor : style.fgColor; 137 | var t:Number = (_locked)? _goal : _time; 138 | 139 | _text.text = (Math.floor(t/3600)+":"+ 140 | format2(Math.floor(t/60)%60, "0")+":"+ 141 | format2(t%60, "0")+" "); 142 | _text.textColor = color; 143 | 144 | var w:int = (width-margin-leftMargin); 145 | var h:int = (height-margin*2); 146 | graphics.beginFill(color, (color>>>24)/255); 147 | graphics.drawRect(leftMargin, (height-size)/2, w*availableRatio, size); 148 | if (0 < _duration) { 149 | graphics.drawRect(leftMargin+w*t/_duration-size, margin, size*2, h); 150 | } 151 | graphics.endFill(); 152 | } 153 | 154 | private function format2(v:int, c:String=" "):String 155 | { 156 | return ((v < 10)? c+v : String(v)); 157 | } 158 | } 159 | 160 | } // package 161 | -------------------------------------------------------------------------------- /src/StatusDisplay.as: -------------------------------------------------------------------------------- 1 | package { 2 | 3 | import baseui.Control; 4 | import flash.text.TextField; 5 | import flash.text.TextFormat; 6 | 7 | // StatusDisplay 8 | // Shows a text status. (part of ControlBar) 9 | // 10 | public class StatusDisplay extends Control 11 | { 12 | private var _text:TextField; 13 | 14 | public function StatusDisplay() 15 | { 16 | super(); 17 | _text = new TextField(); 18 | _text.selectable = false; 19 | addChild(_text); 20 | } 21 | 22 | public function setTextFormat(textFormat:TextFormat, embedFonts:Boolean=false):void 23 | { 24 | _text.defaultTextFormat = textFormat; 25 | _text.embedFonts = embedFonts; 26 | invalidate(); 27 | } 28 | 29 | public function get text():String 30 | { 31 | return _text.text; 32 | } 33 | public function set text(value:String):void 34 | { 35 | _text.text = value; 36 | } 37 | 38 | public override function resize(w:int, h:int):void 39 | { 40 | super.resize(w, h); 41 | _text.width = w; 42 | _text.height = h; 43 | } 44 | 45 | public override function repaint():void 46 | { 47 | super.repaint(); 48 | var color:uint = (highlit)? style.hiFgColor : style.fgColor; 49 | _text.textColor = color; 50 | } 51 | } 52 | 53 | } // package 54 | -------------------------------------------------------------------------------- /src/VolumeSlider.as: -------------------------------------------------------------------------------- 1 | package { 2 | 3 | import flash.events.Event; 4 | import flash.events.MouseEvent; 5 | import baseui.Slider; 6 | 7 | // VolumeSlider 8 | // A volume slider. (part of ControlBar) 9 | // 10 | public class VolumeSlider extends Slider 11 | { 12 | public var muteColor:uint = 0xffff0000; 13 | 14 | private var _value:Number = 0; 15 | private var _muted:Boolean = false; 16 | 17 | protected override function onMouseDrag(e:MouseEvent):void 18 | { 19 | super.onMouseDrag(e); 20 | var size:int = buttonSize/8; 21 | var w:int = (width-size*2); 22 | value = (e.localX-size)/w; 23 | dispatchEvent(new Event(CHANGED)); 24 | } 25 | 26 | public function get value():Number 27 | { 28 | return _value; 29 | } 30 | 31 | public function set value(v:Number):void 32 | { 33 | v = Math.max(0, Math.min(1, v)); 34 | if (_value != v) { 35 | _value = v; 36 | invalidate(); 37 | } 38 | } 39 | 40 | public function get muted():Boolean 41 | { 42 | return _muted; 43 | } 44 | 45 | public function set muted(value:Boolean):void 46 | { 47 | _muted = value; 48 | invalidate(); 49 | } 50 | 51 | public override function repaint():void 52 | { 53 | super.repaint(); 54 | var size:int = buttonSize/4; 55 | var color:uint = (highlit)? style.hiFgColor : style.fgColor; 56 | var cx:int = width/2; 57 | var cy:int = height/2; 58 | 59 | graphics.lineStyle(0, color, (color>>>24)/255); 60 | graphics.moveTo(size, height-size); 61 | graphics.lineTo(width-size, size); 62 | graphics.lineTo(width-size, height-size); 63 | graphics.lineTo(size, height-size); 64 | 65 | var w:int = (width-size*2); 66 | var h:int = (height-size*2); 67 | graphics.beginFill(color, (color>>>24)/255); 68 | graphics.moveTo(size, height-size); 69 | graphics.lineTo(size+_value*w, height-size-_value*h); 70 | graphics.lineTo(size+_value*w, height-size); 71 | graphics.endFill(); 72 | 73 | if (_muted) { 74 | graphics.lineStyle(2, muteColor, (muteColor>>>24)/255); 75 | graphics.moveTo(cx-size, cy-size); 76 | graphics.lineTo(cx+size, cy+size); 77 | } 78 | } 79 | } 80 | 81 | } // package 82 | -------------------------------------------------------------------------------- /src/baseui/Button.as: -------------------------------------------------------------------------------- 1 | package baseui { 2 | 3 | // Button 4 | // Generic button class. 5 | // 6 | public class Button extends Control 7 | { 8 | public function get buttonSize():int 9 | { 10 | return Math.min(controlWidth, controlHeight); 11 | } 12 | 13 | public override function repaint():void 14 | { 15 | super.repaint(); 16 | 17 | if (highlit) { 18 | graphics.lineStyle(0, style.borderColor, (style.borderColor>>>24)/255); 19 | graphics.drawRect(0, 0, controlWidth, controlHeight); 20 | } 21 | } 22 | } 23 | 24 | } // package 25 | -------------------------------------------------------------------------------- /src/baseui/Control.as: -------------------------------------------------------------------------------- 1 | package baseui { 2 | 3 | import flash.events.Event; 4 | import flash.events.MouseEvent; 5 | import flash.display.Sprite; 6 | 7 | // Control 8 | // Base class for buttons/sliders. 9 | // 10 | public class Control extends Sprite 11 | { 12 | private var _style:Style = new Style(); 13 | private var _width:int; 14 | private var _height:int; 15 | 16 | private var _mousedown:Boolean; 17 | private var _mouseover:Boolean; 18 | private var _invalidated:Boolean; 19 | 20 | public function Control() 21 | { 22 | super(); 23 | addEventListener(Event.ADDED_TO_STAGE, onAdded); 24 | addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); 25 | addEventListener(MouseEvent.MOUSE_OUT, onMouseOut); 26 | } 27 | 28 | public function get pressed():Boolean 29 | { 30 | return _mouseover && _mousedown; 31 | } 32 | 33 | public function get highlit():Boolean 34 | { 35 | return _mouseover || _mousedown; 36 | } 37 | 38 | private function onAdded(e:Event):void 39 | { 40 | stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); 41 | stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); 42 | } 43 | 44 | public function get controlWidth():int 45 | { 46 | return _width; 47 | } 48 | 49 | public function get controlHeight():int 50 | { 51 | return _height; 52 | } 53 | 54 | public virtual function get style():Style 55 | { 56 | return _style; 57 | } 58 | 59 | public virtual function set style(value:Style):void 60 | { 61 | _style = value; 62 | } 63 | 64 | protected virtual function onMouseDown(e:MouseEvent):void 65 | { 66 | if (_mouseover) { 67 | _mousedown = true; 68 | _invalidated = true; 69 | onMouseDownLocal(e); 70 | } 71 | } 72 | 73 | protected virtual function onMouseUp(e:MouseEvent):void 74 | { 75 | if (_mousedown) { 76 | onMouseUpLocal(e); 77 | _mousedown = false; 78 | _invalidated = true; 79 | } 80 | } 81 | 82 | protected virtual function onMouseOver(e:MouseEvent):void 83 | { 84 | _mouseover = true; 85 | _invalidated = true; 86 | } 87 | 88 | protected virtual function onMouseOut(e:MouseEvent):void 89 | { 90 | _mouseover = false; 91 | _invalidated = true; 92 | } 93 | 94 | protected virtual function onMouseDownLocal(e:MouseEvent):void 95 | { 96 | } 97 | 98 | protected virtual function onMouseUpLocal(e:MouseEvent):void 99 | { 100 | } 101 | 102 | protected function invalidate():void 103 | { 104 | _invalidated = true; 105 | } 106 | 107 | public virtual function resize(w:int, h:int):void 108 | { 109 | _width = w; 110 | _height = h; 111 | repaint(); 112 | } 113 | 114 | public virtual function repaint():void 115 | { 116 | var color:uint = (highlit)? style.hiBgColor : style.bgColor; 117 | graphics.clear(); 118 | graphics.beginFill(color, (color>>>24)/255); 119 | graphics.drawRect(0, 0, controlWidth, controlHeight); 120 | graphics.endFill(); 121 | } 122 | 123 | public virtual function update():void 124 | { 125 | if (_invalidated) { 126 | _invalidated = false; 127 | repaint(); 128 | } 129 | } 130 | 131 | } 132 | 133 | } // package 134 | -------------------------------------------------------------------------------- /src/baseui/MenuItem.as: -------------------------------------------------------------------------------- 1 | package baseui { 2 | 3 | import flash.events.MouseEvent; 4 | 5 | // MenuItem 6 | // 7 | public class MenuItem extends Control 8 | { 9 | public var value:Object; 10 | 11 | public override function toString():String 12 | { 13 | return (""); 14 | } 15 | 16 | protected override function onMouseOver(e:MouseEvent):void 17 | { 18 | super.onMouseOver(e); 19 | dispatchEvent(new MenuItemEvent(this)); 20 | } 21 | 22 | protected override function onMouseOut(e:MouseEvent):void 23 | { 24 | super.onMouseOut(e); 25 | dispatchEvent(new MenuItemEvent(null)); 26 | } 27 | } 28 | 29 | } // package 30 | -------------------------------------------------------------------------------- /src/baseui/MenuItemEvent.as: -------------------------------------------------------------------------------- 1 | package baseui { 2 | 3 | import flash.events.Event; 4 | 5 | // MenuItemEvent 6 | // 7 | public class MenuItemEvent extends Event 8 | { 9 | public static const CHOOSE:String = "MenuItemEvent.CHOOSE"; 10 | 11 | public var item:MenuItem; 12 | 13 | public function MenuItemEvent(item:MenuItem=null) 14 | { 15 | super(CHOOSE); 16 | this.item = item; 17 | } 18 | } 19 | 20 | } // package 21 | -------------------------------------------------------------------------------- /src/baseui/MenuPopup.as: -------------------------------------------------------------------------------- 1 | package baseui { 2 | 3 | import flash.events.MouseEvent; 4 | 5 | // MenuPopup 6 | // 7 | public class MenuPopup extends Button 8 | { 9 | public var margin:int = 2; 10 | 11 | private var _totalWidth:int; 12 | private var _totalHeight:int; 13 | private var _needResize:Boolean; 14 | private var _items:Vector.; 15 | private var _chosen:MenuItem; 16 | 17 | public function MenuPopup() 18 | { 19 | super(); 20 | _items = new Vector.(); 21 | } 22 | 23 | public override function set style(value:Style):void 24 | { 25 | super.style = value; 26 | for each (var item:MenuItem in _items) { 27 | item.style = value; 28 | } 29 | } 30 | 31 | public function get chosen():MenuItem 32 | { 33 | return _chosen; 34 | } 35 | 36 | public function addTextItem(label:String, value:Object=null):MenuItem 37 | { 38 | var item:TextMenuItem = new TextMenuItem(); 39 | item.label = label; 40 | item.value = (value != null)? value : label; 41 | return addItem(item); 42 | } 43 | 44 | public function addItem(item:MenuItem):MenuItem 45 | { 46 | item.style = style; 47 | item.addEventListener(MenuItemEvent.CHOOSE, onItemChosen); 48 | addChild(item); 49 | _items.push(item); 50 | _needResize = true; 51 | return item; 52 | } 53 | 54 | protected override function onMouseUp(e:MouseEvent):void 55 | { 56 | super.onMouseUp(e); 57 | if (_chosen != null) { 58 | dispatchEvent(new MenuItemEvent(_chosen)); 59 | _chosen = null; 60 | } 61 | } 62 | 63 | private function onItemChosen(e:MenuItemEvent):void 64 | { 65 | if (e.item != null) { 66 | _chosen = e.item; 67 | } else if (e.target == _chosen) { 68 | _chosen = null; 69 | } 70 | } 71 | 72 | private function updateSize():void 73 | { 74 | var item:MenuItem; 75 | _totalWidth = 0; 76 | _totalHeight = 0; 77 | for each (item in _items) { 78 | item.x = margin; 79 | item.y = margin+_totalHeight; 80 | _totalWidth = Math.max(_totalWidth, item.controlWidth); 81 | _totalHeight += item.controlHeight; 82 | } 83 | for each (item in _items) { 84 | item.resize(_totalWidth, item.controlHeight); 85 | } 86 | resize(_totalWidth+margin*2, _totalHeight+margin*2); 87 | _needResize = false; 88 | } 89 | 90 | public override function update():void 91 | { 92 | super.update(); 93 | if (_needResize) { 94 | updateSize(); 95 | } 96 | for each (var item:MenuItem in _items) { 97 | item.update(); 98 | } 99 | } 100 | } 101 | 102 | } // package 103 | -------------------------------------------------------------------------------- /src/baseui/PopupMenuButton.as: -------------------------------------------------------------------------------- 1 | package baseui { 2 | 3 | import flash.display.DisplayObjectContainer; 4 | import flash.events.MouseEvent; 5 | import flash.geom.Point; 6 | import flash.utils.getTimer; 7 | 8 | // PopupMenuButton 9 | // 10 | public class PopupMenuButton extends Button 11 | { 12 | public var minDuration:int = 100; 13 | 14 | private var _popup:MenuPopup; 15 | private var _container:DisplayObjectContainer; 16 | private var _timeout:int; 17 | 18 | public function PopupMenuButton() 19 | { 20 | super(); 21 | _popup = new MenuPopup(); 22 | _popup.addEventListener(MenuItemEvent.CHOOSE, onItemChosen); 23 | } 24 | 25 | public override function set style(value:Style):void 26 | { 27 | super.style = value; 28 | _popup.style = value; 29 | } 30 | 31 | public function set container(value:DisplayObjectContainer):void 32 | { 33 | _container = value; 34 | } 35 | 36 | public function addTextItem(label:String, value:Object=null):MenuItem 37 | { 38 | return _popup.addTextItem(label, value); 39 | } 40 | 41 | public function addItem(item:MenuItem):MenuItem 42 | { 43 | return _popup.addItem(item); 44 | } 45 | 46 | protected virtual function onItemChosen(e:MenuItemEvent):void 47 | { 48 | dispatchEvent(new MenuItemEvent(e.item)); 49 | if (_popup.parent != null) { 50 | _popup.parent.removeChild(_popup); 51 | } 52 | } 53 | 54 | protected override function onMouseDown(e:MouseEvent):void 55 | { 56 | if (_popup.parent != null && !_popup.highlit && !highlit) { 57 | // The menu is still open. 58 | _popup.parent.removeChild(_popup); 59 | } 60 | super.onMouseDown(e); 61 | } 62 | 63 | protected override function onMouseDownLocal(e:MouseEvent):void 64 | { 65 | super.onMouseDownLocal(e); 66 | if (_popup.parent == null) { 67 | var container:DisplayObjectContainer = (_container != null)? _container : parent; 68 | var p:Point = container.globalToLocal(new Point(e.stageX, e.stageY)); 69 | _popup.update(); 70 | _popup.x = p.x; 71 | if (container.width < _popup.x+_popup.width) { 72 | _popup.x -= _popup.width; 73 | } 74 | _popup.y = p.y; 75 | if (container.height < _popup.y+_popup.height) { 76 | _popup.y -= _popup.height; 77 | } 78 | container.addChild(_popup); 79 | _timeout = getTimer() + minDuration; 80 | } 81 | } 82 | 83 | protected override function onMouseUpLocal(e:MouseEvent):void 84 | { 85 | super.onMouseUpLocal(e); 86 | if (_popup.parent != null) { 87 | if (_timeout < getTimer()) { 88 | _popup.parent.removeChild(_popup); 89 | } 90 | } 91 | } 92 | 93 | public override function update():void 94 | { 95 | super.update(); 96 | if (_popup.parent != null) { 97 | _popup.update(); 98 | } 99 | } 100 | } 101 | 102 | } // package 103 | -------------------------------------------------------------------------------- /src/baseui/Slider.as: -------------------------------------------------------------------------------- 1 | package baseui { 2 | 3 | import flash.events.Event; 4 | import flash.events.MouseEvent; 5 | 6 | // Slider 7 | // Generic slider class. 8 | // 9 | public class Slider extends Button 10 | { 11 | public static const CLICK:String = "Slider.Click"; 12 | public static const CHANGED:String = "Slider.Changed"; 13 | 14 | public var minDelta:int = 4; 15 | 16 | private var _x0:int; 17 | private var _y0:int; 18 | private var _changing:Boolean; 19 | 20 | protected override function onMouseDownLocal(e:MouseEvent):void 21 | { 22 | super.onMouseDownLocal(e); 23 | addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); 24 | _x0 = e.localX; 25 | _y0 = e.localY; 26 | _changing = false; 27 | } 28 | 29 | protected override function onMouseUpLocal(e:MouseEvent):void 30 | { 31 | if (!_changing && pressed) { 32 | dispatchEvent(new Event(CLICK)); 33 | } 34 | removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove); 35 | super.onMouseUpLocal(e); 36 | } 37 | 38 | protected virtual function onMouseMove(e:MouseEvent):void 39 | { 40 | if (_changing) { 41 | onMouseDrag(e); 42 | } else { 43 | if (minDelta <= Math.abs(e.localX-_x0) || 44 | minDelta <= Math.abs(e.localY-_y0)) { 45 | _changing = true; 46 | } 47 | } 48 | } 49 | 50 | protected virtual function onMouseDrag(e:MouseEvent):void 51 | { 52 | } 53 | } 54 | 55 | } // package 56 | -------------------------------------------------------------------------------- /src/baseui/Style.as: -------------------------------------------------------------------------------- 1 | package baseui { 2 | 3 | // Style 4 | // Color scheme. 5 | // 6 | public class Style extends Object 7 | { 8 | public var bgColor:uint = 0x448888ff; 9 | public var fgColor:uint = 0xcc888888; 10 | public var hiFgColor:uint = 0xffeeeeee; 11 | public var hiBgColor:uint = 0xff444488; 12 | public var borderColor:uint = 0x88ffffff; 13 | } 14 | 15 | } // package 16 | -------------------------------------------------------------------------------- /src/baseui/TextMenuItem.as: -------------------------------------------------------------------------------- 1 | package baseui { 2 | 3 | import flash.text.TextField; 4 | import flash.text.TextFieldAutoSize; 5 | 6 | // TextMenuItem 7 | // 8 | public class TextMenuItem extends MenuItem 9 | { 10 | private var _text:TextField; 11 | 12 | public function TextMenuItem() 13 | { 14 | super(); 15 | _text = new TextField(); 16 | _text.selectable = false; 17 | _text.autoSize = TextFieldAutoSize.LEFT; 18 | addChild(_text); 19 | } 20 | 21 | public function get label():String 22 | { 23 | return _text.text; 24 | } 25 | 26 | public function set label(v:String):void 27 | { 28 | _text.text = v; 29 | resize(_text.width, _text.height); 30 | } 31 | 32 | public override function repaint():void 33 | { 34 | //super.repaint(); 35 | 36 | graphics.clear(); 37 | if (highlit) { 38 | graphics.beginFill(style.hiFgColor); 39 | } else { 40 | graphics.beginFill(0, 0); 41 | } 42 | graphics.drawRect(0, 0, controlWidth, controlHeight); 43 | graphics.endFill(); 44 | 45 | _text.x = (highlit)? 1 : 0; 46 | _text.y = (highlit)? 1 : 0; 47 | _text.textColor = (highlit)? style.hiBgColor : style.fgColor; 48 | } 49 | } 50 | 51 | } // package 52 | -------------------------------------------------------------------------------- /vgaplayer.as3proj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 95 | 96 | 97 | --------------------------------------------------------------------------------