scrollViewer.ts 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. import { Nullable } from "babylonjs/types";
  2. import { Observer } from "babylonjs/Misc/observable";
  3. import { PointerInfo, PointerEventTypes } from "babylonjs/Events/pointerEvents";
  4. import { Rectangle } from "../rectangle";
  5. import { Grid } from "../grid";
  6. import { Image } from "../image";
  7. import { Control } from "../control";
  8. import { Container } from "../container";
  9. import { Measure } from "../../measure";
  10. import { AdvancedDynamicTexture } from "../../advancedDynamicTexture";
  11. import { _ScrollViewerWindow } from "./scrollViewerWindow";
  12. import { ScrollBar } from "../sliders/scrollBar";
  13. import { ImageScrollBar } from "../sliders/imageScrollBar";
  14. import { _TypeStore } from 'babylonjs/Misc/typeStore';
  15. /**
  16. * Class used to hold a viewer window and sliders in a grid
  17. */
  18. export class ScrollViewer extends Rectangle {
  19. private _grid: Grid;
  20. private _horizontalBarSpace: Rectangle;
  21. private _verticalBarSpace: Rectangle;
  22. private _dragSpace: Rectangle;
  23. private _horizontalBar: ScrollBar | ImageScrollBar;
  24. private _verticalBar: ScrollBar | ImageScrollBar;
  25. private _barColor: string;
  26. private _barBackground: string;
  27. private _barImage: Image;
  28. private _horizontalBarImage: Image;
  29. private _verticalBarImage: Image;
  30. private _barBackgroundImage: Image;
  31. private _horizontalBarBackgroundImage: Image;
  32. private _verticalBarBackgroundImage: Image;
  33. private _barSize: number = 20;
  34. private _window: _ScrollViewerWindow;
  35. private _pointerIsOver: Boolean = false;
  36. private _wheelPrecision: number = 0.05;
  37. private _onPointerObserver: Nullable<Observer<PointerInfo>>;
  38. private _clientWidth: number;
  39. private _clientHeight: number;
  40. private _useImageBar: Boolean;
  41. private _thumbLength: number = 0.5;
  42. private _thumbHeight: number = 1;
  43. private _barImageHeight: number = 1;
  44. private _horizontalBarImageHeight: number = 1;
  45. private _verticalBarImageHeight: number = 1;
  46. /**
  47. * Gets the horizontal scrollbar
  48. */
  49. public get horizontalBar(): ScrollBar | ImageScrollBar {
  50. return this._horizontalBar;
  51. }
  52. /**
  53. * Gets the vertical scrollbar
  54. */
  55. public get verticalBar(): ScrollBar | ImageScrollBar {
  56. return this._verticalBar;
  57. }
  58. /**
  59. * Adds a new control to the current container
  60. * @param control defines the control to add
  61. * @returns the current container
  62. */
  63. public addControl(control: Nullable<Control>): Container {
  64. if (!control) {
  65. return this;
  66. }
  67. this._window.addControl(control);
  68. return this;
  69. }
  70. /**
  71. * Removes a control from the current container
  72. * @param control defines the control to remove
  73. * @returns the current container
  74. */
  75. public removeControl(control: Control): Container {
  76. this._window.removeControl(control);
  77. return this;
  78. }
  79. /** Gets the list of children */
  80. public get children(): Control[] {
  81. return this._window.children;
  82. }
  83. public _flagDescendantsAsMatrixDirty(): void {
  84. for (var child of this._children) {
  85. child._markMatrixAsDirty();
  86. }
  87. }
  88. /**
  89. * Freezes or unfreezes the controls in the window.
  90. * When controls are frozen, the scroll viewer can render a lot more quickly but updates to positions/sizes of controls
  91. * are not taken into account. If you want to change positions/sizes, unfreeze, perform the changes then freeze again
  92. */
  93. public get freezeControls(): boolean {
  94. return this._window.freezeControls;
  95. }
  96. public set freezeControls(value: boolean) {
  97. this._window.freezeControls = value;
  98. }
  99. /** Gets the bucket width */
  100. public get bucketWidth(): number {
  101. return this._window.bucketWidth;
  102. }
  103. /** Gets the bucket height */
  104. public get bucketHeight(): number {
  105. return this._window.bucketHeight;
  106. }
  107. /**
  108. * Sets the bucket sizes.
  109. * When freezeControls is true, setting a non-zero bucket size will improve performances by updating only
  110. * controls that are visible. The bucket sizes is used to subdivide (internally) the window area to smaller areas into which
  111. * controls are dispatched. So, the size should be roughly equals to the mean size of all the controls of
  112. * the window. To disable the usage of buckets, sets either width or height (or both) to 0.
  113. * Please note that using this option will raise the memory usage (the higher the bucket sizes, the less memory
  114. * used), that's why it is not enabled by default.
  115. * @param width width of the bucket
  116. * @param height height of the bucket
  117. */
  118. public setBucketSizes(width: number, height: number): void {
  119. this._window.setBucketSizes(width, height);
  120. }
  121. private _forceHorizontalBar: boolean = false;
  122. private _forceVerticalBar: boolean = false;
  123. /**
  124. * Forces the horizontal scroll bar to be displayed
  125. */
  126. public get forceHorizontalBar(): boolean {
  127. return this._forceHorizontalBar;
  128. }
  129. public set forceHorizontalBar(value: boolean) {
  130. this._grid.setRowDefinition(1, value ? this._barSize : 0, true);
  131. this._horizontalBar.isVisible = value;
  132. this._forceHorizontalBar = value;
  133. }
  134. /**
  135. * Forces the vertical scroll bar to be displayed
  136. */
  137. public get forceVerticalBar(): boolean {
  138. return this._forceVerticalBar;
  139. }
  140. public set forceVerticalBar(value: boolean) {
  141. this._grid.setColumnDefinition(1, value ? this._barSize : 0, true);
  142. this._verticalBar.isVisible = value;
  143. this._forceVerticalBar = value;
  144. }
  145. /**
  146. * Creates a new ScrollViewer
  147. * @param name of ScrollViewer
  148. */
  149. constructor(name?: string, isImageBased?: boolean) {
  150. super(name);
  151. this._useImageBar = isImageBased ? isImageBased : false;
  152. this.onDirtyObservable.add(() => {
  153. this._horizontalBarSpace.color = this.color;
  154. this._verticalBarSpace.color = this.color;
  155. this._dragSpace.color = this.color;
  156. });
  157. this.onPointerEnterObservable.add(() => {
  158. this._pointerIsOver = true;
  159. });
  160. this.onPointerOutObservable.add(() => {
  161. this._pointerIsOver = false;
  162. });
  163. this._grid = new Grid();
  164. if (this._useImageBar) {
  165. this._horizontalBar = new ImageScrollBar();
  166. this._verticalBar = new ImageScrollBar();
  167. }
  168. else {
  169. this._horizontalBar = new ScrollBar();
  170. this._verticalBar = new ScrollBar();
  171. }
  172. this._window = new _ScrollViewerWindow("scrollViewer_window");
  173. this._window.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  174. this._window.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
  175. this._grid.addColumnDefinition(1);
  176. this._grid.addColumnDefinition(0, true);
  177. this._grid.addRowDefinition(1);
  178. this._grid.addRowDefinition(0, true);
  179. super.addControl(this._grid);
  180. this._grid.addControl(this._window, 0, 0);
  181. this._verticalBarSpace = new Rectangle();
  182. this._verticalBarSpace.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  183. this._verticalBarSpace.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
  184. this._verticalBarSpace.thickness = 1;
  185. this._grid.addControl(this._verticalBarSpace, 0, 1);
  186. this._addBar(this._verticalBar, this._verticalBarSpace, true, Math.PI);
  187. this._horizontalBarSpace = new Rectangle();
  188. this._horizontalBarSpace.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
  189. this._horizontalBarSpace.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
  190. this._horizontalBarSpace.thickness = 1;
  191. this._grid.addControl(this._horizontalBarSpace, 1, 0);
  192. this._addBar(this._horizontalBar, this._horizontalBarSpace, false, 0);
  193. this._dragSpace = new Rectangle();
  194. this._dragSpace.thickness = 1;
  195. this._grid.addControl(this._dragSpace, 1, 1);
  196. // Colors
  197. if (!this._useImageBar) {
  198. this.barColor = "grey";
  199. this.barBackground = "transparent";
  200. }
  201. }
  202. /** Reset the scroll viewer window to initial size */
  203. public resetWindow() {
  204. this._window.width = "100%";
  205. this._window.height = "100%";
  206. }
  207. protected _getTypeName(): string {
  208. return "ScrollViewer";
  209. }
  210. private _buildClientSizes() {
  211. let ratio = this.host.idealRatio;
  212. this._window.parentClientWidth = this._currentMeasure.width - (this._verticalBar.isVisible || this.forceVerticalBar ? this._barSize * ratio : 0) - 2 * this.thickness;
  213. this._window.parentClientHeight = this._currentMeasure.height - (this._horizontalBar.isVisible || this.forceHorizontalBar ? this._barSize * ratio : 0) - 2 * this.thickness;
  214. this._clientWidth = this._window.parentClientWidth;
  215. this._clientHeight = this._window.parentClientHeight;
  216. }
  217. protected _additionalProcessing(parentMeasure: Measure, context: CanvasRenderingContext2D): void {
  218. super._additionalProcessing(parentMeasure, context);
  219. this._buildClientSizes();
  220. }
  221. protected _postMeasure(): void {
  222. super._postMeasure();
  223. this._updateScroller();
  224. }
  225. /**
  226. * Gets or sets the mouse wheel precision
  227. * from 0 to 1 with a default value of 0.05
  228. * */
  229. public get wheelPrecision(): number {
  230. return this._wheelPrecision;
  231. }
  232. public set wheelPrecision(value: number) {
  233. if (this._wheelPrecision === value) {
  234. return;
  235. }
  236. if (value < 0) {
  237. value = 0;
  238. }
  239. if (value > 1) {
  240. value = 1;
  241. }
  242. this._wheelPrecision = value;
  243. }
  244. /** Gets or sets the scroll bar container background color */
  245. public get scrollBackground(): string {
  246. return this._horizontalBarSpace.background;
  247. }
  248. public set scrollBackground(color: string) {
  249. if (this._horizontalBarSpace.background === color) {
  250. return;
  251. }
  252. this._horizontalBarSpace.background = color;
  253. this._verticalBarSpace.background = color;
  254. }
  255. /** Gets or sets the bar color */
  256. public get barColor(): string {
  257. return this._barColor;
  258. }
  259. public set barColor(color: string) {
  260. if (this._barColor === color) {
  261. return;
  262. }
  263. this._barColor = color;
  264. this._horizontalBar.color = color;
  265. this._verticalBar.color = color;
  266. }
  267. /** Gets or sets the bar image */
  268. public get thumbImage(): Image {
  269. return this._barImage;
  270. }
  271. public set thumbImage(value: Image) {
  272. if (this._barImage === value) {
  273. return;
  274. }
  275. this._barImage = value;
  276. let hb = <ImageScrollBar>this._horizontalBar;
  277. let vb = <ImageScrollBar>this._verticalBar;
  278. hb.thumbImage = value;
  279. vb.thumbImage = value;
  280. }
  281. /** Gets or sets the horizontal bar image */
  282. public get horizontalThumbImage(): Image {
  283. return this._horizontalBarImage;
  284. }
  285. public set horizontalThumbImage(value: Image) {
  286. if (this._horizontalBarImage === value) {
  287. return;
  288. }
  289. this._horizontalBarImage = value;
  290. let hb = <ImageScrollBar>this._horizontalBar;
  291. hb.thumbImage = value;
  292. }
  293. /** Gets or sets the vertical bar image */
  294. public get verticalThumbImage(): Image {
  295. return this._verticalBarImage;
  296. }
  297. public set verticalThumbImage(value: Image) {
  298. if (this._verticalBarImage === value) {
  299. return;
  300. }
  301. this._verticalBarImage = value;
  302. let vb = <ImageScrollBar>this._verticalBar;
  303. vb.thumbImage = value;
  304. }
  305. /** Gets or sets the size of the bar */
  306. public get barSize(): number {
  307. return this._barSize;
  308. }
  309. public set barSize(value: number) {
  310. if (this._barSize === value) {
  311. return;
  312. }
  313. this._barSize = value;
  314. this._markAsDirty();
  315. if (this._horizontalBar.isVisible) {
  316. this._grid.setRowDefinition(1, this._barSize, true);
  317. }
  318. if (this._verticalBar.isVisible) {
  319. this._grid.setColumnDefinition(1, this._barSize, true);
  320. }
  321. }
  322. /** Gets or sets the length of the thumb */
  323. public get thumbLength(): number {
  324. return this._thumbLength;
  325. }
  326. public set thumbLength(value: number) {
  327. if (this._thumbLength === value) {
  328. return;
  329. }
  330. if (value <= 0) {
  331. value = 0.1;
  332. }
  333. if (value > 1) {
  334. value = 1;
  335. }
  336. this._thumbLength = value;
  337. var hb = <ImageScrollBar>this._horizontalBar;
  338. var vb = <ImageScrollBar>this._verticalBar;
  339. hb.thumbLength = value;
  340. vb.thumbLength = value;
  341. this._markAsDirty();
  342. }
  343. /** Gets or sets the height of the thumb */
  344. public get thumbHeight(): number {
  345. return this._thumbHeight;
  346. }
  347. public set thumbHeight(value: number) {
  348. if (this._thumbHeight === value) {
  349. return;
  350. }
  351. if (value <= 0) {
  352. value = 0.1;
  353. }
  354. if (value > 1) {
  355. value = 1;
  356. }
  357. this._thumbHeight = value;
  358. var hb = <ImageScrollBar>this._horizontalBar;
  359. var vb = <ImageScrollBar>this._verticalBar;
  360. hb.thumbHeight = value;
  361. vb.thumbHeight = value;
  362. this._markAsDirty();
  363. }
  364. /** Gets or sets the height of the bar image */
  365. public get barImageHeight(): number {
  366. return this._barImageHeight;
  367. }
  368. public set barImageHeight(value: number) {
  369. if (this._barImageHeight === value) {
  370. return;
  371. }
  372. if (value <= 0) {
  373. value = 0.1;
  374. }
  375. if (value > 1) {
  376. value = 1;
  377. }
  378. this._barImageHeight = value;
  379. var hb = <ImageScrollBar>this._horizontalBar;
  380. var vb = <ImageScrollBar>this._verticalBar;
  381. hb.barImageHeight = value;
  382. vb.barImageHeight = value;
  383. this._markAsDirty();
  384. }
  385. /** Gets or sets the height of the horizontal bar image */
  386. public get horizontalBarImageHeight(): number {
  387. return this._horizontalBarImageHeight;
  388. }
  389. public set horizontalBarImageHeight(value: number) {
  390. if (this._horizontalBarImageHeight === value) {
  391. return;
  392. }
  393. if (value <= 0) {
  394. value = 0.1;
  395. }
  396. if (value > 1) {
  397. value = 1;
  398. }
  399. this._horizontalBarImageHeight = value;
  400. var hb = <ImageScrollBar>this._horizontalBar;
  401. hb.barImageHeight = value;
  402. this._markAsDirty();
  403. }
  404. /** Gets or sets the height of the vertical bar image */
  405. public get verticalBarImageHeight(): number {
  406. return this._verticalBarImageHeight;
  407. }
  408. public set verticalBarImageHeight(value: number) {
  409. if (this._verticalBarImageHeight === value) {
  410. return;
  411. }
  412. if (value <= 0) {
  413. value = 0.1;
  414. }
  415. if (value > 1) {
  416. value = 1;
  417. }
  418. this._verticalBarImageHeight = value;
  419. var vb = <ImageScrollBar>this._verticalBar;
  420. vb.barImageHeight = value;
  421. this._markAsDirty();
  422. }
  423. /** Gets or sets the bar background */
  424. public get barBackground(): string {
  425. return this._barBackground;
  426. }
  427. public set barBackground(color: string) {
  428. if (this._barBackground === color) {
  429. return;
  430. }
  431. this._barBackground = color;
  432. let hb = <ScrollBar>this._horizontalBar;
  433. let vb = <ScrollBar>this._verticalBar;
  434. hb.background = color;
  435. vb.background = color;
  436. this._dragSpace.background = color;
  437. }
  438. /** Gets or sets the bar background image */
  439. public get barImage(): Image {
  440. return this._barBackgroundImage;
  441. }
  442. public set barImage(value: Image) {
  443. if (this._barBackgroundImage === value) {
  444. }
  445. this._barBackgroundImage = value;
  446. let hb = <ImageScrollBar>this._horizontalBar;
  447. let vb = <ImageScrollBar>this._verticalBar;
  448. hb.backgroundImage = value;
  449. vb.backgroundImage = value;
  450. }
  451. /** Gets or sets the horizontal bar background image */
  452. public get horizontalBarImage(): Image {
  453. return this._horizontalBarBackgroundImage;
  454. }
  455. public set horizontalBarImage(value: Image) {
  456. if (this._horizontalBarBackgroundImage === value) {
  457. }
  458. this._horizontalBarBackgroundImage = value;
  459. let hb = <ImageScrollBar>this._horizontalBar;
  460. hb.backgroundImage = value;
  461. }
  462. /** Gets or sets the vertical bar background image */
  463. public get verticalBarImage(): Image {
  464. return this._verticalBarBackgroundImage;
  465. }
  466. public set verticalBarImage(value: Image) {
  467. if (this._verticalBarBackgroundImage === value) {
  468. }
  469. this._verticalBarBackgroundImage = value;
  470. let vb = <ImageScrollBar>this._verticalBar;
  471. vb.backgroundImage = value;
  472. }
  473. private _setWindowPosition(): void {
  474. let ratio = this.host.idealRatio;
  475. let windowContentsWidth = this._window._currentMeasure.width;
  476. let windowContentsHeight = this._window._currentMeasure.height;
  477. const _endLeft = this._clientWidth - windowContentsWidth;
  478. const _endTop = this._clientHeight - windowContentsHeight;
  479. const newLeft = (this._horizontalBar.value / ratio) * _endLeft + "px";
  480. const newTop = (this._verticalBar.value / ratio) * _endTop + "px";
  481. if (newLeft !== this._window.left) {
  482. this._window.left = newLeft;
  483. if (!this.freezeControls) {
  484. this._rebuildLayout = true;
  485. }
  486. }
  487. if (newTop !== this._window.top) {
  488. this._window.top = newTop;
  489. if (!this.freezeControls) {
  490. this._rebuildLayout = true;
  491. }
  492. }
  493. }
  494. /** @hidden */
  495. private _updateScroller(): void {
  496. let windowContentsWidth = this._window._currentMeasure.width;
  497. let windowContentsHeight = this._window._currentMeasure.height;
  498. if (this._horizontalBar.isVisible && windowContentsWidth <= this._clientWidth && !this.forceHorizontalBar) {
  499. this._grid.setRowDefinition(1, 0, true);
  500. this._horizontalBar.isVisible = false;
  501. this._horizontalBar.value = 0;
  502. this._rebuildLayout = true;
  503. }
  504. else if (!this._horizontalBar.isVisible && (windowContentsWidth > this._clientWidth || this.forceHorizontalBar)) {
  505. this._grid.setRowDefinition(1, this._barSize, true);
  506. this._horizontalBar.isVisible = true;
  507. this._rebuildLayout = true;
  508. }
  509. if (this._verticalBar.isVisible && windowContentsHeight <= this._clientHeight && !this.forceVerticalBar) {
  510. this._grid.setColumnDefinition(1, 0, true);
  511. this._verticalBar.isVisible = false;
  512. this._verticalBar.value = 0;
  513. this._rebuildLayout = true;
  514. }
  515. else if (!this._verticalBar.isVisible && (windowContentsHeight > this._clientHeight || this.forceVerticalBar)) {
  516. this._grid.setColumnDefinition(1, this._barSize, true);
  517. this._verticalBar.isVisible = true;
  518. this._rebuildLayout = true;
  519. }
  520. this._buildClientSizes();
  521. let ratio = this.host.idealRatio;
  522. this._horizontalBar.thumbWidth = this._thumbLength * 0.9 * (this._clientWidth / ratio) + "px";
  523. this._verticalBar.thumbWidth = this._thumbLength * 0.9 * (this._clientHeight / ratio) + "px";
  524. }
  525. public _link(host: AdvancedDynamicTexture): void {
  526. super._link(host);
  527. this._attachWheel();
  528. }
  529. /** @hidden */
  530. private _addBar(barControl: ScrollBar | ImageScrollBar, barContainer: Rectangle, isVertical: boolean, rotation: number) {
  531. barControl.paddingLeft = 0;
  532. barControl.width = "100%";
  533. barControl.height = "100%";
  534. barControl.barOffset = 0;
  535. barControl.value = 0;
  536. barControl.maximum = 1;
  537. barControl.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
  538. barControl.verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
  539. barControl.isVertical = isVertical;
  540. barControl.rotation = rotation;
  541. barControl.isVisible = false;
  542. barContainer.addControl(barControl);
  543. barControl.onValueChangedObservable.add((value) => {
  544. this._setWindowPosition();
  545. });
  546. }
  547. /** @hidden */
  548. private _attachWheel() {
  549. if (!this._host || this._onPointerObserver) {
  550. return;
  551. }
  552. let scene = this._host.getScene();
  553. this._onPointerObserver = scene!.onPointerObservable.add((pi, state) => {
  554. if (!this._pointerIsOver || pi.type !== PointerEventTypes.POINTERWHEEL) {
  555. return;
  556. }
  557. if (this._verticalBar.isVisible == true) {
  558. if ((<MouseWheelEvent>pi.event).deltaY < 0 && this._verticalBar.value > 0) {
  559. this._verticalBar.value -= this._wheelPrecision;
  560. } else if ((<MouseWheelEvent>pi.event).deltaY > 0 && this._verticalBar.value < this._verticalBar.maximum) {
  561. this._verticalBar.value += this._wheelPrecision;
  562. }
  563. }
  564. if (this._horizontalBar.isVisible == true) {
  565. if ((<MouseWheelEvent>pi.event).deltaX < 0 && this._horizontalBar.value < this._horizontalBar.maximum) {
  566. this._horizontalBar.value += this._wheelPrecision;
  567. } else if ((<MouseWheelEvent>pi.event).deltaX > 0 && this._horizontalBar.value > 0) {
  568. this._horizontalBar.value -= this._wheelPrecision;
  569. }
  570. }
  571. });
  572. }
  573. public _renderHighlightSpecific(context: CanvasRenderingContext2D): void {
  574. if (!this.isHighlighted) {
  575. return;
  576. }
  577. super._renderHighlightSpecific(context);
  578. this._grid._renderHighlightSpecific(context);
  579. context.restore();
  580. }
  581. /** Releases associated resources */
  582. public dispose() {
  583. let scene = this._host.getScene();
  584. if (scene && this._onPointerObserver) {
  585. scene.onPointerObservable.remove(this._onPointerObserver);
  586. this._onPointerObserver = null;
  587. }
  588. super.dispose();
  589. }
  590. }
  591. _TypeStore.RegisteredTypes["BABYLON.GUI.ScrollViewer"] = ScrollViewer;