1
4
5 import org.aswing.ASColor;
6 import org.aswing.BoundedRangeModel;
7 import org.aswing.Component;
8 import org.aswing.Container;
9 import org.aswing.Event;
10 import org.aswing.geom.Dimension;
11 import org.aswing.geom.Point;
12 import org.aswing.geom.Rectangle;
13 import org.aswing.graphices.Graphics;
14 import org.aswing.graphices.Pen;
15 import org.aswing.graphices.SolidBrush;
16 import org.aswing.Icon;
17 import org.aswing.JButton;
18 import org.aswing.JScrollBar;
19 import org.aswing.LayoutManager;
20 import org.aswing.LookAndFeel;
21 import org.aswing.plaf.basic.icon.ArrowIcon;
22 import org.aswing.plaf.ScrollBarUI;
23 import org.aswing.UIManager;
24 import org.aswing.utils.Delegate;
25 import org.aswing.utils.MCUtils;
26 import org.aswing.utils.Timer;
27
28
32 class org.aswing.plaf.basic.BasicScrollBarUI extends ScrollBarUI
33 implements LayoutManager{
34
35 private var scrollBarWidth:Number;
36 private var minimumThumbLength:Number;
37 private var thumbRect:Rectangle;
38 private var isDragging:Boolean;
39 private var offset:Number;
40
41 private var thumbHighlightColor:ASColor;
42 private var thumbLightShadowColor:ASColor;
43 private var thumbDarkShadowColor:ASColor;
44 private var thumbColor:ASColor;
45
46 private var scrollbar:JScrollBar;
47 private var incrButton:JButton;
48 private var decrButton:JButton;
49
50 private var adjusterListener:Object;
51 private var incrButtonListener:Object;
52 private var decrButtonListener:Object;
53 private var blockListener:Object;
54
55 private static var scrollSpeedThrottle:Number = 60;
56 private static var initialScrollSpeedThrottle:Number = 300;
57 private var scrollTimer:Timer;
58 private var scrollIncrement:Number;
59 private var scrollContinueDestination:Number;
60
61 public function BasicScrollBarUI(){
62 scrollBarWidth = 16;
63 minimumThumbLength = 16;
64 thumbRect = new Rectangle();
65 isDragging = false;
66 offset = 0;
67 scrollIncrement = 0;
68 scrollTimer = new Timer(scrollSpeedThrottle);
69 scrollTimer.setInitialDelay(initialScrollSpeedThrottle);
70 scrollTimer.addActionListener(__scrollTimerPerformed, this);
71 }
72
73 public function installUI(c:Component):Void{
74 scrollbar = JScrollBar(c);
75 installDefaults();
76 installComponents();
77 installListeners();
78 }
79
80 public function uninstallUI(c:Component):Void{
81 scrollbar = JScrollBar(c);
82 uninstallDefaults();
83 uninstallComponents();
84 uninstallListeners();
85 removeMCs(c);
86 scrollTimer.stop();
87 }
88
89 private function installDefaults():Void{
90 configureScrollBarColors();
91 scrollbar.setLayout(this);
92 LookAndFeel.installBasicProperties(scrollbar, "ScrollBar.border");
93 LookAndFeel.installBorder(scrollbar, "ScrollBar.border");
94 }
95 private function configureScrollBarColors():Void{
96 LookAndFeel.installColorsAndFont(scrollbar, "ScrollBar.background", "ScrollBar.foreground", "ScrollBar.font");
97 thumbHighlightColor = UIManager.getColor("ScrollBar.thumbHighlight");
98 thumbLightShadowColor = UIManager.getColor("ScrollBar.thumbShadow");
99 thumbDarkShadowColor = UIManager.getColor("ScrollBar.thumbDarkShadow");
100 thumbColor = UIManager.getColor("ScrollBar.thumb");
101 }
102
103 private function createArrowIcon(direction:Number):Icon{
104 var icon:Icon = new ArrowIcon(direction, scrollBarWidth/3-1,
105 new ASColor(0x000000,100),
106 new ASColor(0x666666,100),
107 new ASColor(0x666666,100),
108 new ASColor(0xFF0000,100));
109 return icon;
110 }
111
112 private function createArrowButton(direction:Number):JButton{
113 var b:JButton = new JButton(null, createArrowIcon(direction));
114 return b;
115 }
116
117 private function uninstallDefaults():Void{
118 LookAndFeel.uninstallBorder(scrollbar);
119 scrollbar.setLayout(null);
120 }
121
122 private function installComponents():Void{
123 if(isVertical()){
124 incrButton = createArrowButton(Math.PI/2);
125 decrButton = createArrowButton(-Math.PI/2);
126 }else{
127 incrButton = createArrowButton(0);
128 decrButton = createArrowButton(-Math.PI);
129 }
130
131 scrollbar.append(incrButton);
132 scrollbar.append(decrButton);
133 scrollbar.setEnabled(scrollbar.isEnabled());
134 }
135 private function uninstallComponents():Void{
136 scrollbar.remove(incrButton);
137 scrollbar.remove(decrButton);
138 }
139
140 private function installListeners():Void{
141 adjusterListener = scrollbar.addAdjustmentListener(__adjustChanged, this);
142
143 incrButtonListener = new Object();
144 incrButtonListener[Component.ON_PRESS] = Delegate.create(this, __incrButtonPress);
145 incrButtonListener[Component.ON_RELEASE] = Delegate.create(this, __incrButtonReleased);
146 incrButtonListener[Component.ON_RELEASEOUTSIDE] = incrButtonListener[Component.ON_RELEASE];
147 incrButton.addEventListener(incrButtonListener);
148
149 decrButtonListener = new Object();
150 decrButtonListener[Component.ON_PRESS] = Delegate.create(this, __decrButtonPress);
151 decrButtonListener[Component.ON_RELEASE] = Delegate.create(this, __decrButtonReleased);
152 decrButtonListener[Component.ON_RELEASEOUTSIDE] = decrButtonListener[Component.ON_RELEASE];
153 decrButton.addEventListener(decrButtonListener);
154
155 blockListener = new Object();
156 blockListener[Component.ON_PRESS] = Delegate.create(this, __trackPress);
157 blockListener[Component.ON_RELEASE] = Delegate.create(this, __trackReleased);
158 blockListener[Component.ON_RELEASEOUTSIDE] = blockListener[Component.ON_RELEASE];
159 scrollbar.addEventListener(blockListener);
160 }
161
162 private function uninstallListeners():Void{
163 scrollbar.removeEventListener(adjusterListener);
164 scrollbar.removeEventListener(incrButtonListener);
165 scrollbar.removeEventListener(decrButtonListener);
166 scrollbar.removeEventListener(blockListener);
167 }
168
169 private function createButtonListener():Object{
170 var l:Object = new Object();
171 return l;
172 }
173
174 private var thumMC:MovieClip;
175
176 private function removeMCs(c:Component):Void{
177 thumMC.removeMovieClip();
178 }
179
180 public function create(c:Component):Void{
181 thumMC = c.createMovieClip("ui");
182 thumMC.onPress = Delegate.create(this, __startDragThumb);
183 thumMC.onRelease = thumMC.onReleaseOutside = Delegate.create(this, __stopDragThumb);
184 thumbRect.setRect(0,0,0,0);
185 }
186
187 private function isVertical():Boolean{
188 return scrollbar.getOrientation() == JScrollBar.VERTICAL;
189 }
190
191 private function getThumbRect():Rectangle{
192 return new Rectangle(thumbRect);
193 }
194
195
196
197 private function __scrollTimerPerformed(event:Event):Void{
198 var value:Number = scrollbar.getValue() + scrollIncrement;
199 var finished:Boolean = false;
200 if(scrollIncrement > 0){
201 if(value >= scrollContinueDestination){
202 finished = true;
203 }
204 }else{
205 if(value <= scrollContinueDestination){
206 finished = true;
207 }
208 }
209 if(finished){
210 scrollbar.setValue(scrollContinueDestination);
211 scrollTimer.stop();
212 }else{
213 scrollByIncrement(scrollIncrement);
214 }
215 }
216
217 private function __adjustChanged(event:Event):Void{
218 if(!isDragging)
219 paintAndLocateThumb(scrollbar.getPaintBounds());
220 }
221
222 private function __incrButtonPress(event:Event):Void{
223 scrollIncrement = scrollbar.getUnitIncrement();
224 scrollByIncrement(scrollIncrement);
225 scrollContinueDestination = scrollbar.getMaximum() - scrollbar.getVisibleAmount();
226 scrollTimer.restart();
227 }
228
229 private function __incrButtonReleased(event:Event):Void{
230 scrollTimer.stop();
231 }
232
233 private function __decrButtonPress(event:Event):Void{
234 scrollIncrement = -scrollbar.getUnitIncrement();
235 scrollByIncrement(scrollIncrement);
236 scrollContinueDestination = scrollbar.getMinimum();
237 scrollTimer.restart();
238 }
239
240 private function __decrButtonReleased(event:Event):Void{
241 scrollTimer.stop();
242 }
243
244 private function __trackPress(event:Event):Void{
245 var aimPoint:Point = scrollbar.getMousePosition();
246 var isPressedInRange:Boolean = false;
247 var tr:Rectangle = getThumbRect();
248 if(isVertical()){
249 var mousePos:Number = aimPoint.y;
250 aimPoint.y -= tr.height/2;
251 if(mousePos < tr.y){
252 isPressedInRange = true;
253 }else if(mousePos > tr.y + tr.height){
254 isPressedInRange = true;
255 }
256 }else{
257 var mousePos:Number = aimPoint.x;
258 aimPoint.x -= tr.width/2;
259 if(mousePos < tr.x){
260 isPressedInRange = true;
261 }else if(mousePos > tr.x + tr.width){
262 isPressedInRange = true;
263 }
264 }
265
266 if(isPressedInRange){
267 scrollContinueDestination = getValueWithPosition(aimPoint);
268 if(scrollContinueDestination > scrollbar.getValue()){
269 scrollIncrement = scrollbar.getBlockIncrement();
270 }else{
271 scrollIncrement = -scrollbar.getBlockIncrement();
272 }
273 scrollByIncrement(scrollIncrement);
274 scrollTimer.restart();
275 }
276 }
277
278 private function __trackReleased():Void{
279 scrollTimer.stop();
280 }
281
282 private function scrollByIncrement(increment:Number):Void{
283 scrollbar.setValue(scrollbar.getValue() + increment);
284 }
285
286 private function __startDragThumb():Void{
287
288
289 scrollbar.__onChildPressed(null);
290
291 if(!scrollbar.isEnabled()){
292 return;
293 }
294 scrollbar.setValueIsAdjusting(true);
295 var mp:Point = scrollbar.getMousePosition();
296 var mx:Number = mp.x;
297 var my:Number = mp.y;
298 var tr:Rectangle = getThumbRect();
299 if(isVertical()){
300 offset = my - tr.y;
301 }else{
302 offset = mx - tr.x;
303 }
304 isDragging = true;
305 __startHandleDrag();
306 }
307
308 private function __stopDragThumb():Void{
309 if(!scrollbar.isEnabled()){
310 return;
311 }
312 if(isDragging){
313 scrollThumbToCurrentMousePosition();
314 }
315 offset = 0;
316 scrollbar.setValueIsAdjusting(false);
317 isDragging = false;
318 __stopHandleDrag();
319 }
320
321 private function __startHandleDrag():Void{
322 thumMC.onMouseMove = Delegate.create(this, __onMoveThumb);
323 }
324 private function __stopHandleDrag():Void{
325 thumMC.onMouseMove = undefined;
326 }
327
328 private function __onMoveThumb():Void{
329 if(!scrollbar.isEnabled()){
330 return;
331 }
332 scrollThumbToCurrentMousePosition();
333 }
334
335 private function scrollThumbToCurrentMousePosition():Void{
336 var mp:Point = scrollbar.getMousePosition();
337 var mx:Number = mp.x;
338 var my:Number = mp.y;
339 var thumbR:Rectangle = getThumbRect();
340
341 var thumbMin:Number, thumbMax:Number, thumbPos:Number;
342
343 if(isVertical()){
344 thumbMin = decrButton.getY() + decrButton.getHeight();
345 thumbMax = incrButton.getY() - thumbR.height;
346 thumbPos = Math.min(thumbMax, Math.max(thumbMin, (my - offset)));
347 setThumbRect(thumbR.x, thumbPos, thumbR.width, thumbR.height);
348 }else{
349 thumbMin = decrButton.getX() + decrButton.getWidth();
350 thumbMax = incrButton.getX() - thumbR.width;
351 thumbPos = Math.min(thumbMax, Math.max(thumbMin, (mx - offset)));
352 setThumbRect(thumbPos, thumbR.y, thumbR.width, thumbR.height);
353 }
354
355 var scrollBarValue:Number = getValueWithThumbMaxMinPos(thumbMin, thumbMax, thumbPos);
356 scrollbar.setValue(scrollBarValue);
357 updateAfterEvent();
358 }
359
360 private function getValueWithPosition(point:Point):Number{
361 var mx:Number = point.x;
362 var my:Number = point.y;
363 var thumbR:Rectangle = getThumbRect();
364
365 var thumbMin:Number, thumbMax:Number, thumbPos:Number;
366
367 if(isVertical()){
368 thumbMin = decrButton.getY() + decrButton.getHeight();
369 thumbMax = incrButton.getY() - thumbR.height;
370 thumbPos = my;
371 }else{
372 thumbMin = decrButton.getX() + decrButton.getWidth();
373 thumbMax = incrButton.getX() - thumbR.width;
374 thumbPos = mx;
375 }
376 return getValueWithThumbMaxMinPos(thumbMin, thumbMax, thumbPos);
377 }
378
379 private function getValueWithThumbMaxMinPos(thumbMin:Number, thumbMax:Number, thumbPos:Number):Number{
380 var model:BoundedRangeModel = scrollbar.getModel();
381 var scrollBarValue:Number;
382 if (thumbPos >= thumbMax) {
383 scrollBarValue = model.getMaximum() - model.getExtent();
384 }else{
385 var valueMax:Number = model.getMaximum() - model.getExtent();
386 var valueRange:Number = valueMax - model.getMinimum();
387 var thumbValue:Number = thumbPos - thumbMin;
388 var thumbRange:Number = thumbMax - thumbMin;
389 var value:Number = (thumbValue / thumbRange) * valueRange;
390 scrollBarValue = value + model.getMinimum();
391 }
392 return scrollBarValue;
393 }
394
395
396
397 public function paint(c:Component, g:Graphics, b:Rectangle):Void{
398 paintBackGround(c, g, b);
399
400 paintAndLocateThumb(b);
401 }
402
403 private function paintAndLocateThumb(b:Rectangle):Void{
404 if(!scrollbar.isEnabled()){
405 if(isVertical()){
406 if(incrButton.isEnabled()){
407 trace("Logic Wrong : Scrollbar range is not enabled, but its button enabled ");
408 }
409 }
410 thumMC._visible = false;
411 return;
412 }
413 thumMC._visible = true;
414 var min:Number = scrollbar.getMinimum();
415 var extent:Number = scrollbar.getVisibleAmount();
416 var range:Number = scrollbar.getMaximum() - min;
417 var value:Number = scrollbar.getValue();
418
419 if(range <= 0){
420 if(isVertical())
421 trace("Logic Wrong : Scrollbar range = " + range + ", max="+scrollbar.getMaximum()+", min="+min);
422 thumMC._visible = false;
423 return;
424 }
425
426 var trackLength:Number;
427 var thumbLength:Number;
428 if(isVertical()){
429 trackLength = b.height - incrButton.getHeight() - decrButton.getHeight();
430 thumbLength = trackLength*(extent/range);
431 }else{
432 trackLength = b.width - incrButton.getWidth() - decrButton.getWidth();
433 thumbLength = trackLength*(extent/range);
434 }
435 thumbLength = Math.max(thumbLength, minimumThumbLength);
436
437 if(thumbLength >= trackLength){
438 if(isVertical())
439 trace("Logic Wrong : Scrollbar exent="+extent+", range="+range);
440 thumMC._visible = false;
441 return;
442 }
443
444 var thumbRange:Number = trackLength - thumbLength;
445 var thumbPos:Number = Math.round(thumbRange * ((value - min) / (range - extent)));
446 if(isVertical()){
447 setThumbRect(b.x, thumbPos + b.y + decrButton.getHeight(),
448 scrollBarWidth, thumbLength);
449 }else{
450 setThumbRect(thumbPos + b.x + decrButton.getWidth(), b.y,
451 thumbLength, scrollBarWidth);
452 }
453 }
454
455 private function setThumbRect(x:Number, y:Number, w:Number, h:Number):Void{
456 if(!MCUtils.isMovieClipExist(thumMC)){
457 return;
458 }
459
460 var oldW:Number = thumbRect.width;
461 var oldH:Number = thumbRect.height;
462
463 thumbRect.setRect(x, y, w, h);
464
465 if(w != oldW || h != oldH){
466 paintThumb(thumMC, thumbRect.getSize());
467 }
468 thumMC._x = x;
469 thumMC._y = y;
470 }
471
472
477 private function paintThumb(thumMC:MovieClip, size:Dimension):Void{
478 var w:Number = size.width;
479 var h:Number = size.height;
480 thumMC.clear();
481 var g:Graphics = new Graphics(thumMC);
482 var b:SolidBrush = new SolidBrush(thumbDarkShadowColor);
483 g.fillRectangle(b, 0, 0, w, h);
484 b.setASColor(this.thumbColor);
485 g.fillRectangle(b, 1, 1, w-2, h-2);
486
487 var p:Pen = new Pen(thumbDarkShadowColor, 0);
488 if(isVertical()){
489 var ch:Number = h/2;
490 g.drawLine(p, 3, ch, w-3, ch);
491 g.drawLine(p, 3, ch+2, w-3, ch+2);
492 g.drawLine(p, 3, ch-2, w-3, ch-2);
493 }else{
494 var cw:Number = w/2;
495 g.drawLine(p, cw, 3, cw, h-3);
496 g.drawLine(p, cw+2, 3, cw+2, h-3);
497 g.drawLine(p, cw-2, 3, cw-2, h-3);
498 }
499 }
500
501
502
503 public function getPreferredSize(c:Component):Dimension{
504 return preferredLayoutSize(Container(c));
505 }
506
507 public function getMaximumSize(c:Component):Dimension{
508 return maximumLayoutSize(Container(c));
509 }
510
511 public function getMinimumSize(c:Component):Dimension{
512 return getPreferredSize(c);
513 }
514
515
516 private function layoutVScrollbar(sb:JScrollBar):Void{
517 var rd:Rectangle = sb.getPaintBounds();
518 var w:Number = scrollBarWidth;
519 decrButton.setBounds(rd.x, rd.y, w, w);
520 incrButton.setBounds(rd.x, rd.y + rd.height - w, w, w);
521 }
522
523 private function layoutHScrollbar(sb:JScrollBar):Void{
524 var rd:Rectangle = sb.getPaintBounds();
525 var w:Number = scrollBarWidth;
526 decrButton.setBounds(rd.x, rd.y, w, w);
527 incrButton.setBounds(rd.x + rd.width - w, rd.y, w, w);
528 }
529
530 public function layoutContainer(target:Container):Void{
531 if(isDragging){
532 return;
533 }
534 if(target == scrollbar){
535 if(isVertical()){
536 layoutVScrollbar(scrollbar);
537 }else{
538 layoutHScrollbar(scrollbar);
539 }
540 }else{
541 trace("BasicScrollBarUI just can be JScrollBar's Layout : " + target);
542 }
543 }
544
545
549 public function preferredLayoutSize(target:Container):Dimension{
550 if(target == scrollbar){
551 var w:Number, h:Number;
552 if(isVertical()){
553 w = scrollBarWidth;
554 h = scrollBarWidth*2 + minimumThumbLength;
555 }else{
556 w = scrollBarWidth*2 + minimumThumbLength;
557 h = scrollBarWidth;
558 }
559 return scrollbar.getInsets().roundsSize(new Dimension(w, h));
560 }else{
561 trace("BasicScrollBarUI just can be JScrollBar's Layout : " + target);
562 throw new Error("BasicScrollBarUI just can be JScrollBar's Layout : " + target);
563 }
564 }
565
566
570 public function maximumLayoutSize(target:Container):Dimension{
571 if(target == scrollbar){
572 var w:Number, h:Number;
573 if(isVertical()){
574 w = scrollBarWidth;
575 h = Number.MAX_VALUE;
576 }else{
577 w = Number.MAX_VALUE;
578 h = scrollBarWidth;
579 }
580 return scrollbar.getInsets().roundsSize(new Dimension(w, h));
581 }else{
582 trace("BasicScrollBarUI just can be JScrollBar's Layout : " + target);
583 throw new Error("BasicScrollBarUI just can be JScrollBar's Layout : " + target);
584 }
585 }
586
587 public function minimumLayoutSize(target:Container):Dimension{
588 return preferredLayoutSize(target);
589 }
590 public function getLayoutAlignmentX(target:Container):Number{
591 return 0;
592 }
593 public function getLayoutAlignmentY(target:Container):Number{
594 return 0;
595 }
596
597 public function addLayoutComponent(comp:Component, constraints:Object):Void{}
598 public function removeLayoutComponent(comp:Component):Void{}
599 public function invalidateLayout(target:Container):Void{}
600
601 }
602