import { Measure } from "../../measure" ; import { Container } from "../container" ; import { ValueAndUnit } from "../../valueAndUnit" ; import { Control } from "../control" ; import { ICanvasRenderingContext } from 'babylonjs/Engines/ICanvas' ; hidden export class _ScrollViewerWindow extends Container { public parentClientWidth : number ; public parentClientHeight : number ; private _freezeControls = false ; private _parentMeasure : Measure ; private _oldLeft : number | null ; private _oldTop : number | null ; public get freezeControls ( ) : boolean { return this . _freezeControls ; } public set freezeControls ( value ) { if ( this . _freezeControls === value ) { return ; } if ( ! value ) { this . _restoreMeasures ( ) ; } this . _freezeControls = false ; var textureSize = this . host . getSize ( ) ; var renderWidth = textureSize . width ; var renderHeight = textureSize . height ; var context = this . host . getContext ( ) ; var measure = new Measure ( 0 , 0 , renderWidth , renderHeight ) ; this . host . _numLayoutCalls = 0 ; this . host . _rootContainer . _layout ( measure , context ) ; if ( value ) { this . _updateMeasures ( ) ; if ( this . _useBuckets ( ) ) { this . _makeBuckets ( ) ; } } this . _freezeControls = value ; this . host . markAsDirty ( ) ; } private _bucketWidth : number = 0 ; private _bucketHeight : number = 0 ; private _buckets : { [ key ] : Array < Control > ; } = { } ; private _bucketLen : number ; public get bucketWidth ( ) : number { return this . _bucketWidth ; } public get bucketHeight ( ) : number { return this . _bucketHeight ; } public setBucketSizes ( width , height ) { this . _bucketWidth = width ; this . _bucketHeight = height ; if ( this . _useBuckets ( ) ) { if ( this . _freezeControls ) { this . _makeBuckets ( ) ; } } else { this . _buckets = { } ; } } private _useBuckets ( ) { return this . _bucketWidth > 0 && this . _bucketHeight > 0 ; } private _makeBuckets ( ) { this . _buckets = { } ; this . _bucketLen = Math . ceil ( this . widthInPixels / this . _bucketWidth ) ; this . _dispatchInBuckets ( this . _children ) ; this . _oldLeft = null ; this . _oldTop = null ; } private _dispatchInBuckets ( children ) { for ( let i = 0 ; i < children . length ; ++ i ) { let child = children [ i ] ; let bStartX = Math . max ( 0 , Math . floor ( ( child . _customData . _origLeft - this . _customData . origLeft ) / this . _bucketWidth ) ) , bEndX = Math . floor ( ( child . _customData . _origLeft - this . _customData . origLeft + child . _currentMeasure . width - 1 ) / this . _bucketWidth ) , bStartY = Math . max ( 0 , Math . floor ( ( child . _customData . _origTop - this . _customData . origTop ) / this . _bucketHeight ) ) , bEndY = Math . floor ( ( child . _customData . _origTop - this . _customData . origTop + child . _currentMeasure . height - 1 ) / this . _bucketHeight ) ; while ( bStartY <= bEndY ) { for ( let x = bStartX ; x <= bEndX ; ++ x ) { let bucket = bStartY * this . _bucketLen + x , lstc = this . _buckets [ bucket ] ; if ( ! lstc ) { lstc = [ ] ; this . _buckets [ bucket ] = lstc ; } lstc . push ( child ) ; } bStartY ++ ; } if ( child instanceof Container && child . _children . length > 0 ) { this . _dispatchInBuckets ( child . _children ) ; } } } private _updateMeasures ( ) { let left = this . leftInPixels | 0 , top = this . topInPixels | 0 ; this . _measureForChildren . left -= left ; this . _measureForChildren . top -= top ; this . _currentMeasure . left -= left ; this . _currentMeasure . top -= top ; this . _customData . origLeftForChildren = this . _measureForChildren . left ; this . _customData . origTopForChildren = this . _measureForChildren . top ; this . _customData . origLeft = this . _currentMeasure . left ; this . _customData . origTop = this . _currentMeasure . top ; this . _updateChildrenMeasures ( this . _children , left , top ) ; } private _updateChildrenMeasures ( children , left , top ) { for ( let i = 0 ; i < children . length ; ++ i ) { let child = children [ i ] ; child . _currentMeasure . left -= left ; child . _currentMeasure . top -= top ; child . _customData . _origLeft = child . _currentMeasure . left ; child . _customData . _origTop = child . _currentMeasure . top ; if ( child instanceof Container && child . _children . length > 0 ) { this . _updateChildrenMeasures ( child . _children , left , top ) ; } } } private _restoreMeasures ( ) { let left = this . leftInPixels | 0 , top = this . topInPixels | 0 ; this . _measureForChildren . left = this . _customData . origLeftForChildren + left ; this . _measureForChildren . top = this . _customData . origTopForChildren + top ; this . _currentMeasure . left = this . _customData . origLeft + left ; this . _currentMeasure . top = this . _customData . origTop + top ; } param name constructor ( name ? ) { super ( name ) ; } protected _getTypeName ( ) { return "ScrollViewerWindow" ; } hidden protected _additionalProcessing ( parentMeasure , context ) { super . _additionalProcessing ( parentMeasure , context ) ; this . _parentMeasure = parentMeasure ; this . _measureForChildren . left = this . _currentMeasure . left ; this . _measureForChildren . top = this . _currentMeasure . top ; this . _measureForChildren . width = parentMeasure . width ; this . _measureForChildren . height = parentMeasure . height ; } hidden public _layout ( parentMeasure , context ) { if ( this . _freezeControls ) { this . invalidateRect ( ) ; return false ; } return super . _layout ( parentMeasure , context ) ; } private _scrollChildren ( children , left , top ) { for ( let i = 0 ; i < children . length ; ++ i ) { let child = children [ i ] ; child . _currentMeasure . left = child . _customData . _origLeft + left ; child . _currentMeasure . top = child . _customData . _origTop + top ; child . _isClipped = false ; if ( child instanceof Container && child . _children . length > 0 ) { this . _scrollChildren ( child . _children , left , top ) ; } } } private _scrollChildrenWithBuckets ( left , top , scrollLeft , scrollTop ) { let bStartX = Math . max ( 0 , Math . floor ( - left / this . _bucketWidth ) ) , bEndX = Math . floor ( ( - left + this . _parentMeasure . width - 1 ) / this . _bucketWidth ) , bStartY = Math . max ( 0 , Math . floor ( - top / this . _bucketHeight ) ) , bEndY = Math . floor ( ( - top + this . _parentMeasure . height - 1 ) / this . _bucketHeight ) ; while ( bStartY <= bEndY ) { for ( let x = bStartX ; x <= bEndX ; ++ x ) { let bucket = bStartY * this . _bucketLen + x , lstc = this . _buckets [ bucket ] ; if ( lstc ) { for ( let i = 0 ; i < lstc . length ; ++ i ) { let child = lstc [ i ] ; child . _currentMeasure . left = child . _customData . _origLeft + scrollLeft ; child . _currentMeasure . top = child . _customData . _origTop + scrollTop ; child . _isClipped = false ; } } } bStartY ++ ; } } hidden public _draw ( context , invalidatedRectangle ? ) { if ( ! this . _freezeControls ) { super . _draw ( context , invalidatedRectangle ) ; return ; } this . _localDraw ( context ) ; if ( this . clipChildren ) { this . _clipForChildren ( context ) ; } let left = this . leftInPixels | 0 , top = this . topInPixels | 0 ; if ( this . _useBuckets ( ) ) { if ( this . _oldLeft !== null && this . _oldTop !== null ) { this . _scrollChildrenWithBuckets ( this . _oldLeft , this . _oldTop , left , top ) ; this . _scrollChildrenWithBuckets ( left , top , left , top ) ; } else { this . _scrollChildren ( this . _children , left , top ) ; } } else { this . _scrollChildren ( this . _children , left , top ) ; } this . _oldLeft = left ; this . _oldTop = top ; for ( var child of this . _children ) { if ( ! child . _intersectsRect ( this . _parentMeasure ) ) { continue ; } child . _render ( context , this . _parentMeasure ) ; } } protected _postMeasure ( ) { if ( this . _freezeControls ) { super . _postMeasure ( ) ; return ; } var maxWidth = this . parentClientWidth ; var maxHeight = this . parentClientHeight ; for ( var child of this . children ) { if ( ! child . isVisible || child . notRenderable ) { continue ; } if ( child . horizontalAlignment === Control . HORIZONTAL_ALIGNMENT_CENTER ) { child . _offsetLeft ( this . _currentMeasure . left - child . _currentMeasure . left ) ; } if ( child . verticalAlignment === Control . VERTICAL_ALIGNMENT_CENTER ) { child . _offsetTop ( this . _currentMeasure . top - child . _currentMeasure . top ) ; } maxWidth = Math . max ( maxWidth , child . _currentMeasure . left - this . _currentMeasure . left + child . _currentMeasure . width + child . paddingRightInPixels ) ; maxHeight = Math . max ( maxHeight , child . _currentMeasure . top - this . _currentMeasure . top + child . _currentMeasure . height + child . paddingBottomInPixels ) ; } if ( this . _currentMeasure . width !== maxWidth ) { this . _width . updateInPlace ( maxWidth , ValueAndUnit . UNITMODE_PIXEL ) ; this . _currentMeasure . width = maxWidth ; this . _rebuildLayout = true ; this . _isDirty = true ; } if ( this . _currentMeasure . height !== maxHeight ) { this . _height . updateInPlace ( maxHeight , ValueAndUnit . UNITMODE_PIXEL ) ; this . _currentMeasure . height = maxHeight ; this . _rebuildLayout = true ; this . _isDirty = true ; } super . _postMeasure ( ) ; } }