1
8 import com.sekati.core.CoreObject;
9 import com.sekati.events.FramePulse;
10 import com.sekati.except.FatalArgumentException;
11 import com.sekati.external.MouseWheel;
12 import com.sekati.ui.IScrollable;
13 import com.sekati.utils.Delegate;
14
15 import mx.transitions.easing.Strong;
16 import mx.transitions.Tween;
17
18
27 class com.sekati.ui.Scroll extends CoreObject implements IScrollable {
28
29 private var _this:Scroll;
30 private var _axis:String;
31 private var _prop:String;
32 private var _content:Object;
33 private var _mask:MovieClip;
34 private var _gutter:MovieClip;
35 private var _bar:MovieClip;
36 private var _isDrag:Boolean;
37 private var _isResizeGutter:Boolean;
38 private var _isResizeBar:Boolean;
39 private var _isMouseWheel:Boolean;
40 private var _contentSizeTracker:Object;
41 private var _contentTop:Number;
42 private var _contentBot:Number;
43 private var _gutterTop:Number;
44 private var _gutterBot:Number;
45 private var _oldPos:Number;
46 private var _newPos:Number;
47 private var _friction:Number;
48 private var _ratio:Number;
49 private var _speed:Number;
50 private var _slide:Tween;
51
52
72 public function Scroll(axis:String, content:Object, mask:MovieClip, gutter:MovieClip, bar:MovieClip, isResizeGutter:Boolean, isResizeBar:Boolean, isMouseWheel:Boolean, isInit:Boolean, contentSizeTracker:Object, friction:Number, ratio:Number) {
73 super( );
74
75 if (axis != "_x" && axis != "_y") {
76
77 throw new FatalArgumentException( this, "Scroll Constructor expects axis param: '_x' or '_y'.", arguments );
78 return;
79 }
80
81 _this = this;
82 _axis = axis;
83 _content = content;
84 _gutter = gutter;
85 _bar = bar;
86 _mask = mask;
87 _contentSizeTracker = (!contentSizeTracker) ? content : contentSizeTracker;
88 _isResizeBar = (!isResizeBar) ? false : true;
89 _isResizeGutter = (!isResizeGutter) ? false : true;
90 _isMouseWheel = (!isMouseWheel) ? false : true;
91 _friction = (friction) ? friction : 0.8;
92 _ratio = (ratio) ? ratio : 0.5;
93
94 _speed = 0;
95 _prop = (_axis == "_y") ? "_height" : "_width";
96 _isDrag = false;
97
98
99 if (isInit) {
100 init( );
101 }
102 }
103
104
108 public function init():Void {
109
110 setConfines( );
111 setMouseWheel( );
112
113 _bar.onPress = Delegate.create( _this, bar_onPress );
114 _bar.onRelease = _bar.onReleaseOutside = Delegate.create( _this, bar_onRelease );
115 _gutter.onPress = Delegate.create( _this, gutter_onPress );
116
117 FramePulse.getInstance( ).addFrameListener( _this );
118 }
119
120
126 public function slideContent(pos:Number, sec:Number):Void {
127 var newScrollPos:Number = (_contentTop - pos) * (_gutterBot - _gutterTop) / (_gutterBot - _contentBot + _bar[_prop]) + _gutterTop;
128 slideScroller( newScrollPos, sec );
129 }
130
131
137 public function slideScroller(pos:Number, sec:Number):Void {
138 stopScroller( );
139 updateConfines( );
140 var s:Number = (!sec) ? 0.5 : sec;
141 _slide = new Tween( _bar, _axis, Strong.easeOut, _bar[_axis], resolveScrollerPos( pos ), s, true );
142 }
143
144
152 public function moveScroller(amount:Number):Void {
153 stopScroller( );
154 updateConfines( );
155 _bar._y = resolveScrollerPos( _bar._y + amount );
156 }
157
158
162 public function isScrollable():Boolean {
163
164 var _isScrollable:Boolean = (_content[_axis] <= _mask[_axis] && _contentSizeTracker[_prop] < _mask[_prop]) ? false : true;
165 return _isScrollable;
166 }
167
168
172 public function isDragging():Boolean {
173 return _isDrag;
174 }
175
176
177
178
182 public function isMouseInArea():Boolean {
183 var x:Number = _content._parent._xmouse;
184 var y:Number = _content._parent._ymouse;
185 return (x >= 0 && x <= _mask._width && y >= 0 && y <= _mask._height);
186 }
187
188 private function setMouseWheel():Void {
189 if (_isMouseWheel) {
190
191 _content.mouseWheelEnabled = false;
192
193 MouseWheel.init( _this );
194 }
195 }
196
197 private function onMouseWheel(delta:Number):Void {
198 if (isMouseInArea( ) && isScrollable( )) {
199 var m:Number = _bar[_axis] - ((_gutter[_prop] / 5) * (delta / 3));
200 slideScroller( m );
201 }
202 }
203
204
205 private function setConfines():Void {
206 _contentTop = _content[_axis];
207 _gutterTop = _gutter[_axis];
208 _gutterBot = _gutter[_axis] + _gutter[_prop];
209 if (!_isResizeBar) {
210 _gutterBot -= _bar[_prop];
211 }
212
213 _gutter[_prop] = (_isResizeGutter) ? _mask[_prop] : _gutter[_prop];
214
215 updateConfines( );
216 }
217
218 private function updateConfines():Void {
219 _contentBot = _contentTop + _contentSizeTracker[_prop];
220
221 if (_isResizeBar) {
222
223
224 var percent:Number = Math.ceil( (_mask[_prop] / _contentSizeTracker[_prop]) * 100 );
225 _bar[_prop] = _gutter[_prop] * percent / 100;
226
227
228 _gutterBot = _gutter[_axis] + _gutter[_prop] - _bar[_prop];
229 }
230 }
231
232 private function resolveScrollerPos(pos:Number):Number {
233
234 return Math.max( Math.min( pos, _gutterBot ), _gutterTop );
235 }
236
237 private function stopScroller():Void {
238 _speed = 0;
239 _slide.stop( );
240 }
241
242
243 private function _onEnterFrame():Void {
244 _bar._visible = isScrollable( );
245
246 if (_contentBot != _contentTop + _contentSizeTracker[_prop]) {
247 _contentBot = _contentTop + _contentSizeTracker[_prop];
248 updateConfines( );
249 _bar[_axis] = resolveScrollerPos( (_contentTop + _content[_axis]) * (_gutterBot - _gutterTop) / (_gutterBot - _contentBot + _bar[_prop]) + _gutterTop );
250 }
251
252 if (!_isDrag) {
253 _oldPos = _bar[_axis];
254 _newPos = _oldPos + _speed;
255 if (_newPos > _gutterBot || _newPos < _gutterTop) {
256
257 _speed = -_speed;
258 _newPos = _oldPos;
259 }
260 _speed = Math.round( _speed * _friction * 100 ) / 100;
261 } else {
262 _oldPos = _newPos;
263 _newPos = _bar[_axis];
264 }
265
266 _bar[_axis] = _newPos;
267
268 var percent:Number = (_bar[_axis] - _gutterTop) / (_gutterBot - _gutterTop);
269 _content[_axis] = Math.round( (percent * (_gutterBot - _contentBot + _bar[_prop])) + _contentTop );
270
271 if (_speed < 0.1 && _speed > -0.1) {
272 _speed = 0;
273 }
274 }
275
276 private function bar_onPress():Void {
277 stopScroller( );
278 _isDrag = true;
279 if(_axis == "_y") {
280 _bar.startDrag( false, _bar._x, _gutterTop, _bar._x, _gutterBot );
281 } else {
282 _bar.startDrag( false, _gutterTop, _bar._y, _gutterBot, _bar._y );
283 }
284 }
285
286 private function bar_onRelease():Void {
287 _bar.stopDrag( );
288 _isDrag = false;
289
290 _speed = (_newPos - _oldPos) * _ratio;
291 }
292
293 private function gutter_onPress():Void {
294 if (isScrollable( )) {
295 _gutter.useHandCursor = true;
296 var mousePos:Number = (_axis == "_y") ? _gutter._parent._ymouse : _gutter._parent._xmouse;
297 slideScroller( mousePos - (_bar[_prop] / 2) );
298 } else {
299 _gutter.useHandCursor = false;
300 }
301 }
302
303
307 public function destroy():Void {
308 FramePulse.getInstance( ).removeFrameListener( _this );
309 super.destroy( );
310 }
311 }