PageRenderTime 1963ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/src/temperate/components/CScrollBar.hx

http://github.com/cser/temperate
Haxe | 787 lines | 676 code | 91 blank | 20 comment | 58 complexity | 155a756d54e9377bcf786c2c4e0be66b MD5 | raw file
  1. package temperate.components;
  2. import flash.display.DisplayObject;
  3. import flash.display.DisplayObjectContainer;
  4. import flash.display.Sprite;
  5. import flash.errors.ArgumentError;
  6. import flash.events.Event;
  7. import flash.events.MouseEvent;
  8. import temperate.components.helpers.CTimerChanger;
  9. import temperate.components.helpers.ICTimerChanger;
  10. import temperate.core.CMath;
  11. import temperate.core.CMouseWheelUtil;
  12. import temperate.core.CSprite;
  13. import temperate.skins.ICScrollSkin;
  14. /**
  15. * Events:
  16. * flash.events.Event.CHANGE
  17. */
  18. class CScrollBar extends CSprite, implements ICSlider
  19. {
  20. var _horizontal:Bool;
  21. var _leftArrow:ICButton;
  22. var _rightArrow:ICButton;
  23. var _thumb:ICButton;
  24. var _bgSkin:ICScrollSkin;
  25. var _isThumbResizable:Bool;
  26. var _bg:Sprite;
  27. var _size_pageValid:Bool;
  28. var _view_positionValid:Bool;
  29. var _timerChanger:ICTimerChanger;
  30. var _pageTimerChanger:ICTimerChanger;
  31. var _isBgDown:Bool;
  32. var _isBgDownLeft:Bool;
  33. var _guideCrossOffset:Int;
  34. var _guideDirectOffset:Int;
  35. var _guideSize:Int;
  36. public function new(
  37. horizontal:Bool, leftArrow:ICButton, rightArrow:ICButton, thumb:ICButton,
  38. bgSkin:ICScrollSkin, isThumbResizable:Bool = true)
  39. {
  40. _horizontal = horizontal;
  41. _leftArrow = leftArrow;
  42. _rightArrow = rightArrow;
  43. _thumb = thumb;
  44. _bgSkin = bgSkin;
  45. _isThumbResizable = isThumbResizable;
  46. super();
  47. view = this;
  48. _minValue = 0;
  49. _maxValue = 100;
  50. _value = 0;
  51. _step = 1;
  52. _pageSize = Math.NaN;
  53. _pageStep = Math.NaN;
  54. updateOnMove = false;
  55. mouseWheelDimRatio = 1;
  56. _isBgDown = false;
  57. _isBgDownLeft = false;
  58. _bg = new Sprite();
  59. addChild(_bg);
  60. _bgSkin.link(_horizontal, _bg.addChild, _bg.removeChild, _bg.graphics);
  61. addChild(_thumb.view);
  62. addChild(_leftArrow.view);
  63. addChild(_rightArrow.view);
  64. _timerChanger = newTimerChanger();
  65. _timerChanger.onIncrease = onIncrease;
  66. _timerChanger.onDecrease = onDecrease;
  67. _leftArrow.addEventListener(MouseEvent.MOUSE_DOWN, onLeftMouseDown);
  68. _rightArrow.addEventListener(MouseEvent.MOUSE_DOWN, onRightMouseDown);
  69. _thumb.addEventListener(MouseEvent.MOUSE_DOWN, onThumbMouseDown);
  70. _pageTimerChanger = newPageTimerChanger();
  71. _pageTimerChanger.onIncrease = onPageIncrease;
  72. _pageTimerChanger.onDecrease = onPageDecrease;
  73. updateEnabledListeners();
  74. setUseHandCursor(false);
  75. _settedWidth = _horizontal ? 100 : 0;
  76. _settedHeight = _horizontal ? 0 : 100;
  77. _size_valid = false;
  78. _view_valid = false;
  79. postponeSize();
  80. }
  81. public var view(default, null):DisplayObject;
  82. function newTimerChanger():ICTimerChanger
  83. {
  84. return new CTimerChanger();
  85. }
  86. function newPageTimerChanger():ICTimerChanger
  87. {
  88. return newTimerChanger();
  89. }
  90. function onIncrease()
  91. {
  92. setValue(_value + _step, true);
  93. }
  94. function onDecrease()
  95. {
  96. setValue(_value - _step, true);
  97. }
  98. function onLeftMouseDown(event:MouseEvent)
  99. {
  100. stage.addEventListener(MouseEvent.MOUSE_UP, onStageLeftMouseUp);
  101. _leftArrow.addEventListener(MouseEvent.ROLL_OVER, onLeftRollOver);
  102. _leftArrow.addEventListener(MouseEvent.ROLL_OUT, onLeftRollOut);
  103. _timerChanger.decreaseDown(false);
  104. }
  105. function onStageLeftMouseUp(event:MouseEvent)
  106. {
  107. stage.removeEventListener(MouseEvent.MOUSE_UP, onStageLeftMouseUp);
  108. _leftArrow.removeEventListener(MouseEvent.ROLL_OVER, onLeftRollOver);
  109. _leftArrow.removeEventListener(MouseEvent.ROLL_OUT, onLeftRollOut);
  110. _timerChanger.up();
  111. }
  112. function onLeftRollOver(event:MouseEvent)
  113. {
  114. _timerChanger.decreaseDown(true);
  115. }
  116. function onLeftRollOut(event:MouseEvent)
  117. {
  118. _timerChanger.up();
  119. }
  120. function onRightMouseDown(event:MouseEvent)
  121. {
  122. stage.addEventListener(MouseEvent.MOUSE_UP, onStageRightMouseUp);
  123. _rightArrow.addEventListener(MouseEvent.ROLL_OVER, onRightRollOver);
  124. _rightArrow.addEventListener(MouseEvent.ROLL_OUT, onRightRollOut);
  125. _timerChanger.increaseDown(false);
  126. }
  127. function onStageRightMouseUp(event:MouseEvent)
  128. {
  129. stage.removeEventListener(MouseEvent.MOUSE_UP, onStageRightMouseUp);
  130. _rightArrow.removeEventListener(MouseEvent.ROLL_OVER, onRightRollOver);
  131. _rightArrow.removeEventListener(MouseEvent.ROLL_OUT, onRightRollOut);
  132. _timerChanger.up();
  133. }
  134. function onRightRollOver(event:MouseEvent)
  135. {
  136. _timerChanger.increaseDown(true);
  137. }
  138. function onRightRollOut(event:MouseEvent)
  139. {
  140. _timerChanger.up();
  141. }
  142. function updateEnabledListeners()
  143. {
  144. if (_isEnabled)
  145. {
  146. addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
  147. _bg.addEventListener(MouseEvent.MOUSE_DOWN, onBgMouseDown);
  148. }
  149. else
  150. {
  151. removeEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
  152. _bg.removeEventListener(MouseEvent.MOUSE_DOWN, onBgMouseDown);
  153. }
  154. }
  155. function onPageDecrease()
  156. {
  157. checkPageMouseAndChange(false);
  158. }
  159. function onPageIncrease()
  160. {
  161. checkPageMouseAndChange(true);
  162. }
  163. function checkPageMouseAndChange(isIncrease:Bool)
  164. {
  165. var mousePosition;
  166. var thumbPosition;
  167. var thumbSize;
  168. if (_horizontal)
  169. {
  170. mousePosition = _bg.mouseX;
  171. thumbPosition = _thumb.view.x;
  172. thumbSize = _thumb.view.width;
  173. }
  174. else
  175. {
  176. mousePosition = _bg.mouseY;
  177. thumbPosition = _thumb.view.y;
  178. thumbSize = _thumb.view.height;
  179. }
  180. if (isIncrease && mousePosition < thumbPosition + thumbSize ||
  181. !isIncrease && mousePosition > thumbPosition)
  182. {
  183. _pageTimerChanger.up();
  184. _isBgDown = false;
  185. redrawBg();
  186. }
  187. else
  188. {
  189. setValue(_value + (isIncrease ? pageStep : -pageStep), true);
  190. redrawBg();
  191. }
  192. }
  193. function getMousePosition()
  194. {
  195. return _horizontal ? _bg.mouseX : _bg.mouseY;
  196. }
  197. function getThumbCenter()
  198. {
  199. var thumbView = _thumb.view;
  200. return Std.int(
  201. _horizontal ?
  202. thumbView.x + thumbView.width * .5 :
  203. thumbView.y + thumbView.height * .5);
  204. }
  205. function onBgMouseDown(event:MouseEvent)
  206. {
  207. _isBgDown = true;
  208. _isBgDownLeft = getMousePosition() < getThumbCenter();
  209. if (_isBgDownLeft)
  210. {
  211. _pageTimerChanger.decreaseDown(false);
  212. }
  213. else
  214. {
  215. _pageTimerChanger.increaseDown(false);
  216. }
  217. redrawBg();
  218. stage.addEventListener(MouseEvent.MOUSE_UP, onStagePageMouseUp);
  219. _bg.addEventListener(MouseEvent.ROLL_OVER, onBgRollOver);
  220. _bg.addEventListener(MouseEvent.ROLL_OUT, onBgRollOut);
  221. }
  222. function onStagePageMouseUp(event:MouseEvent)
  223. {
  224. _bg.removeEventListener(MouseEvent.ROLL_OVER, onBgRollOver);
  225. _bg.removeEventListener(MouseEvent.ROLL_OUT, onBgRollOut);
  226. _pageTimerChanger.up();
  227. _isBgDown = false;
  228. redrawBg();
  229. }
  230. function onBgRollOver(event:MouseEvent)
  231. {
  232. var currentIsBgDownLeft = getMousePosition() < getThumbCenter();
  233. if (currentIsBgDownLeft != _isBgDownLeft)
  234. {
  235. return;
  236. }
  237. _isBgDown = true;
  238. if (_isBgDownLeft)
  239. {
  240. _pageTimerChanger.decreaseDown(true);
  241. }
  242. else
  243. {
  244. _pageTimerChanger.increaseDown(true);
  245. }
  246. redrawBg();
  247. }
  248. function onBgRollOut(event:MouseEvent)
  249. {
  250. _pageTimerChanger.up();
  251. _isBgDown = false;
  252. redrawBg();
  253. }
  254. var _mouseOffsetX:Float;
  255. var _mouseOffsetY:Float;
  256. function onThumbMouseDown(event:MouseEvent)
  257. {
  258. _mouseOffsetX = _thumb.view.mouseX;
  259. _mouseOffsetY = _thumb.view.mouseY;
  260. stage.addEventListener(MouseEvent.MOUSE_MOVE, onStageMouseMove);
  261. stage.addEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
  262. }
  263. function onStageMouseUp(event:MouseEvent)
  264. {
  265. stage.removeEventListener(MouseEvent.MOUSE_MOVE, onStageMouseMove);
  266. stage.removeEventListener(MouseEvent.MOUSE_UP, onStageMouseUp);
  267. setThumbPositionByValue();
  268. }
  269. function onStageMouseMove(event:MouseEvent)
  270. {
  271. var thumbView = _thumb.view;
  272. var value = Std.int(_horizontal ? mouseX - _mouseOffsetX : mouseY - _mouseOffsetY);
  273. if (value < _guideDirectOffset)
  274. {
  275. value = _guideDirectOffset;
  276. }
  277. else
  278. {
  279. var maxValue = _guideDirectOffset + _guideSize -
  280. Std.int(_horizontal ? thumbView.width : thumbView.height);
  281. if (value > maxValue)
  282. {
  283. value = maxValue;
  284. }
  285. }
  286. if (_horizontal)
  287. {
  288. thumbView.x = value;
  289. }
  290. else
  291. {
  292. thumbView.y = value;
  293. }
  294. if (updateOnMove)
  295. {
  296. event.updateAfterEvent();
  297. }
  298. setValueByThumbPosition();
  299. }
  300. function onMouseWheel(event:MouseEvent)
  301. {
  302. setValue(
  303. _value -
  304. _step * CMouseWheelUtil.getDimDelta(event.delta, mouseWheelDimRatio), true);
  305. }
  306. override function doValidateSize()
  307. {
  308. if (!_size_valid)
  309. {
  310. _size_valid = true;
  311. updateSize();
  312. updateBaseArrange();
  313. _size_pageValid = false;
  314. _view_positionValid = false;
  315. _view_valid = false;
  316. }
  317. if (!_size_pageValid)
  318. {
  319. _size_pageValid = true;
  320. updateThumbSize();
  321. updateThumbVisible();
  322. _view_positionValid = false;
  323. }
  324. if (!_view_positionValid || !_view_valid)
  325. {
  326. postponeView();
  327. }
  328. }
  329. override function doValidateView()
  330. {
  331. var needValidateComponents = false;
  332. if (!_view_positionValid)
  333. {
  334. _view_positionValid = true;
  335. setThumbPositionByValue();
  336. needValidateComponents = true;
  337. }
  338. if (!_view_valid)
  339. {
  340. _view_valid = true;
  341. updateBg();
  342. needValidateComponents = true;
  343. }
  344. if (needValidateComponents)
  345. {
  346. // Validation system is not ideal :(
  347. _thumb.validate();
  348. _leftArrow.validate();
  349. _rightArrow.validate();
  350. }
  351. }
  352. function updateSize()
  353. {
  354. var leftWidth = _leftArrow.view.width;
  355. var leftHeight = _leftArrow.view.height;
  356. var rightWidth = _rightArrow.view.width;
  357. var rightHeight = _rightArrow.view.height;
  358. var minWidth;
  359. var minHeight;
  360. if (_horizontal)
  361. {
  362. minWidth = leftWidth + rightWidth;
  363. minHeight = CMath.max3(leftHeight, rightHeight, _thumb.view.height);
  364. }
  365. else
  366. {
  367. minWidth = CMath.max3(leftWidth, rightWidth, _thumb.view.width);
  368. minHeight = leftHeight + rightHeight;
  369. }
  370. if (_horizontal)
  371. {
  372. _width = _isCompactWidth ?
  373. minWidth :
  374. CMath.max(_settedWidth, leftWidth + rightWidth);
  375. _height = minHeight;
  376. }
  377. else
  378. {
  379. _width = minWidth;
  380. _height = _isCompactHeight ?
  381. minHeight :
  382. CMath.max(_settedHeight, leftHeight + rightHeight);
  383. }
  384. }
  385. function updateBaseArrange()
  386. {
  387. _leftArrow.view.x = 0;
  388. _leftArrow.view.y = 0;
  389. _guideCrossOffset = 0;
  390. if (_horizontal)
  391. {
  392. _rightArrow.view.x = _width - _rightArrow.view.width;
  393. _rightArrow.view.y = 0;
  394. _guideDirectOffset = Std.int(_leftArrow.view.width);
  395. _guideSize = Std.int(_width - _leftArrow.view.width - _rightArrow.view.width);
  396. }
  397. else
  398. {
  399. _rightArrow.view.x = 0;
  400. _rightArrow.view.y = _height - _rightArrow.view.height;
  401. _guideDirectOffset = Std.int(_leftArrow.view.height);
  402. _guideSize = Std.int(_height - _leftArrow.view.height - _rightArrow.view.height);
  403. }
  404. }
  405. function updateThumbVisible()
  406. {
  407. var thumbSize = _horizontal ? _thumb.view.width : _thumb.view.height;
  408. _thumb.view.visible = _isEnabled && thumbSize < _guideSize && _maxValue > _minValue;
  409. }
  410. function updateBg()
  411. {
  412. _bgSkin.setSize(_guideDirectOffset, _guideSize, Std.int(_horizontal ? _width : _height));
  413. redrawBg();
  414. }
  415. function redrawBg()
  416. {
  417. if (_isBgDown)
  418. {
  419. _bgSkin.redrawDown(_isBgDownLeft, getThumbCenter());
  420. }
  421. else
  422. {
  423. _bgSkin.redrawUp();
  424. }
  425. }
  426. function updateThumbSize()
  427. {
  428. var pageSize = this.pageSize;
  429. var delta = _maxValue - _minValue + pageSize;
  430. var size = Std.int(_guideSize * pageSize / delta);
  431. if (size < 0 || size > _guideSize)
  432. {
  433. size = CMath.intMax(_guideSize - 1, 0);
  434. }
  435. if (_isThumbResizable)
  436. {
  437. if (_horizontal)
  438. {
  439. _thumb.view.width = size;
  440. }
  441. else
  442. {
  443. _thumb.view.height = size;
  444. }
  445. }
  446. }
  447. function fixedValue(value:Float)
  448. {
  449. if (value <= _minValue)
  450. {
  451. return _minValue;
  452. }
  453. if (value >= _maxValue)
  454. {
  455. return _maxValue;
  456. }
  457. value = Math.round(value / _step) * _step;
  458. if (value < _minValue)
  459. {
  460. return _minValue;
  461. }
  462. if (value > _maxValue)
  463. {
  464. return _maxValue;
  465. }
  466. return value;
  467. }
  468. override function set_isEnabled(value)
  469. {
  470. if (_isEnabled != value)
  471. {
  472. _isEnabled = value;
  473. _leftArrow.isEnabled = _isEnabled;
  474. _rightArrow.isEnabled = _isEnabled;
  475. updateThumbVisible();
  476. updateEnabledListeners();
  477. }
  478. return _isEnabled;
  479. }
  480. var _useHandCursor:Bool;
  481. @:getter(useHandCursor)
  482. function get_useHandCursor()
  483. {
  484. return _useHandCursor;
  485. }
  486. @:setter(useHandCursor)
  487. function set_useHandCursor(value)
  488. {
  489. if (_useHandCursor != value)
  490. {
  491. setUseHandCursor(value);
  492. }
  493. }
  494. function setUseHandCursor(value:Bool)
  495. {
  496. _useHandCursor = value;
  497. _leftArrow.setUseHandCursor(_useHandCursor);
  498. _rightArrow.setUseHandCursor(_useHandCursor);
  499. _thumb.setUseHandCursor(_useHandCursor);
  500. }
  501. //----------------------------------------------------------------------------------------------
  502. //
  503. // Convertion between value and position
  504. //
  505. //----------------------------------------------------------------------------------------------
  506. function setThumbPositionByValue()
  507. {
  508. var thumbSize = Std.int(_horizontal ? _thumb.view.width : _thumb.view.height);
  509. var delta = _maxValue - _minValue;
  510. var thumbOffset = _guideDirectOffset +
  511. (delta > 0 ?
  512. Std.int((_guideSize - thumbSize) * (_value - _minValue) / (_maxValue - _minValue)) :
  513. 0);
  514. if (_horizontal)
  515. {
  516. _thumb.view.x = thumbOffset;
  517. _thumb.view.y = _guideCrossOffset;
  518. }
  519. else
  520. {
  521. _thumb.view.x = _guideCrossOffset;
  522. _thumb.view.y = thumbOffset;
  523. }
  524. }
  525. function setValueByThumbPosition()
  526. {
  527. var thumbSize = Std.int(_horizontal ? _thumb.view.width : _thumb.view.height);
  528. var thumbOffset = Std.int(_horizontal ? _thumb.view.x : _thumb.view.y);
  529. var rawValue = _minValue + (thumbOffset - _guideDirectOffset)
  530. * (_maxValue - _minValue) / (_guideSize - thumbSize);
  531. var newValue = fixedValue(rawValue);
  532. if (_value != newValue)
  533. {
  534. _value = newValue;
  535. dispatchEvent(new Event(Event.CHANGE));
  536. }
  537. }
  538. //----------------------------------------------------------------------------------------------
  539. //
  540. // Params
  541. //
  542. //----------------------------------------------------------------------------------------------
  543. public var updateOnMove:Bool;
  544. public var mouseWheelDimRatio:Int;
  545. public var value(get_value, set_value):Float;
  546. var _value:Float;
  547. function get_value()
  548. {
  549. return _value;
  550. }
  551. function set_value(value:Float)
  552. {
  553. setValue(value, false);
  554. return _value;
  555. }
  556. function setValue(value:Float, needDispatch:Bool)
  557. {
  558. var newValue = fixedValue(value);
  559. if (_value != newValue)
  560. {
  561. _value = newValue;
  562. setThumbPositionByValue();
  563. if (needDispatch)
  564. {
  565. dispatchEvent(new Event(Event.CHANGE));
  566. }
  567. }
  568. }
  569. public var minValue(get_minValue, set_minValue):Float;
  570. var _minValue:Float;
  571. function get_minValue()
  572. {
  573. return _minValue;
  574. }
  575. function set_minValue(value:Float)
  576. {
  577. if (_minValue != value)
  578. {
  579. _minValue = value;
  580. _size_pageValid = false;
  581. _view_positionValid = false;
  582. _value = fixedValue(_value);
  583. postponeSize();
  584. }
  585. return _minValue;
  586. }
  587. public var maxValue(get_maxValue, set_maxValue):Float;
  588. var _maxValue:Float;
  589. function get_maxValue()
  590. {
  591. return _maxValue;
  592. }
  593. function set_maxValue(value:Float)
  594. {
  595. if (_maxValue != value)
  596. {
  597. _maxValue = value;
  598. _size_pageValid = false;
  599. _view_positionValid = false;
  600. _value = fixedValue(_value);
  601. postponeSize();
  602. }
  603. return _maxValue;
  604. }
  605. public var pageSize(get_pageSize, set_pageSize):Float;
  606. var _pageSize:Float;
  607. function get_pageSize()
  608. {
  609. return Math.isFinite(_pageSize) ? _pageSize : _step;
  610. }
  611. function set_pageSize(value:Float)
  612. {
  613. if (_pageSize != value)
  614. {
  615. if (value <= 0)
  616. {
  617. throw new ArgumentError("pageSize mast be positive or NaN");
  618. }
  619. _pageSize = value;
  620. _size_pageValid = false;
  621. _view_positionValid = false;
  622. postponeSize();
  623. }
  624. return _pageSize;
  625. }
  626. public var pageStep(get_pageStep, set_pageStep):Float;
  627. var _pageStep:Float;
  628. function get_pageStep()
  629. {
  630. return Math.isFinite(_pageStep) ? _pageStep : pageSize;
  631. }
  632. function set_pageStep(value)
  633. {
  634. if (_pageStep != value)
  635. {
  636. if (value <= 0)
  637. {
  638. throw new ArgumentError("pageScrollSize mast be positive or NaN");
  639. }
  640. _pageStep = value;
  641. _size_pageValid = false;
  642. _view_positionValid = false;
  643. postponeSize();
  644. }
  645. return _pageStep;
  646. }
  647. public var step(get_step, set_step):Float;
  648. var _step:Float;
  649. function get_step()
  650. {
  651. return _step;
  652. }
  653. function set_step(value)
  654. {
  655. if (!Math.isFinite(value))
  656. {
  657. throw new ArgumentError("step mast be finite");
  658. }
  659. if (_step != value)
  660. {
  661. if (value <= 0)
  662. {
  663. throw new ArgumentError("step mast be positive");
  664. }
  665. _step = value;
  666. _size_pageValid = false;
  667. _view_positionValid = false;
  668. postponeSize();
  669. }
  670. return _step;
  671. }
  672. //----------------------------------------------------------------------------------------------
  673. //
  674. // Helped
  675. //
  676. //----------------------------------------------------------------------------------------------
  677. public function setValues(minValue:Float, maxValue:Float, value:Float = 0)
  678. {
  679. this.minValue = minValue;
  680. this.maxValue = maxValue;
  681. this.value = value;
  682. return this;
  683. }
  684. public function addChangeHandler(handler:Event->Dynamic)
  685. {
  686. addEventListener(Event.CHANGE, handler);
  687. return this;
  688. }
  689. public function addTo(parent:DisplayObjectContainer, x:Float = 0, y:Float = 0)
  690. {
  691. this.x = x;
  692. this.y = y;
  693. parent.addChild(this);
  694. return this;
  695. }
  696. }