UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

773 lines (772 loc) 26.3 kB
import { math } from "../../../core/math/math.js"; import { Vec2 } from "../../../core/math/vec2.js"; import { Vec3 } from "../../../core/math/vec3.js"; import { ORIENTATION_HORIZONTAL, ORIENTATION_VERTICAL } from "../../../scene/constants.js"; import { GraphNode } from "../../../scene/graph-node.js"; import { ElementDragHelper } from "../element/element-drag-helper.js"; import { SCROLL_MODE_BOUNCE, SCROLL_MODE_CLAMP, SCROLL_MODE_INFINITE, SCROLLBAR_VISIBILITY_SHOW_ALWAYS, SCROLLBAR_VISIBILITY_SHOW_WHEN_REQUIRED } from "./constants.js"; import { Component } from "../component.js"; const _tempScrollValue = new Vec2(); class ScrollViewComponent extends Component { static EVENT_SETSCROLL = "set:scroll"; _horizontal; _vertical; _scrollMode; _bounceAmount; _friction; _dragThreshold = 10; _useMouseWheel = true; _mouseWheelSensitivity = new Vec2(1, 1); _horizontalScrollbarVisibility = 0; _verticalScrollbarVisibility = 0; _viewportEntity = null; _contentEntity = null; _horizontalScrollbarEntity = null; _verticalScrollbarEntity = null; _evtElementAdd = null; _evtElementRemove = null; _evtViewportEntityElementAdd = null; _evtViewportElementRemove = null; _evtViewportResize = null; _evtContentEntityElementAdd = null; _evtContentElementRemove = null; _evtContentResize = null; _evtHorizontalScrollbarAdd = null; _evtHorizontalScrollbarRemove = null; _evtHorizontalScrollbarValue = null; _evtVerticalScrollbarAdd = null; _evtVerticalScrollbarRemove = null; _evtVerticalScrollbarValue = null; constructor(system, entity) { super(system, entity); this._scrollbarUpdateFlags = {}; this._scrollbarEntities = {}; this._prevContentSizes = {}; this._prevContentSizes[ORIENTATION_HORIZONTAL] = null; this._prevContentSizes[ORIENTATION_VERTICAL] = null; this._scroll = new Vec2(); this._velocity = new Vec3(); this._dragStartPosition = new Vec3(); this._disabledContentInput = false; this._disabledContentInputEntities = []; this._evtElementAdd = this.entity.on("element:add", this._onElementComponentAdd, this); this._toggleElementListeners("on"); } set horizontal(arg) { if (this._horizontal === arg) { return; } this._horizontal = arg; this._syncScrollbarEnabledState(ORIENTATION_HORIZONTAL); } get horizontal() { return this._horizontal; } set vertical(arg) { if (this._vertical === arg) { return; } this._vertical = arg; this._syncScrollbarEnabledState(ORIENTATION_VERTICAL); } get vertical() { return this._vertical; } set scrollMode(arg) { this._scrollMode = arg; } get scrollMode() { return this._scrollMode; } set bounceAmount(arg) { this._bounceAmount = arg; } get bounceAmount() { return this._bounceAmount; } set friction(arg) { this._friction = arg; } get friction() { return this._friction; } set dragThreshold(arg) { this._dragThreshold = arg; } get dragThreshold() { return this._dragThreshold; } set useMouseWheel(arg) { this._useMouseWheel = arg; } get useMouseWheel() { return this._useMouseWheel; } set mouseWheelSensitivity(arg) { if (!arg) { this._mouseWheelSensitivity = arg; } else if (arg instanceof Vec2) { this._mouseWheelSensitivity = arg.clone(); } else { this._mouseWheelSensitivity = new Vec2(arg[0], arg[1]); } } get mouseWheelSensitivity() { return this._mouseWheelSensitivity; } set horizontalScrollbarVisibility(arg) { this._horizontalScrollbarVisibility = arg; } get horizontalScrollbarVisibility() { return this._horizontalScrollbarVisibility; } set verticalScrollbarVisibility(arg) { this._verticalScrollbarVisibility = arg; } get verticalScrollbarVisibility() { return this._verticalScrollbarVisibility; } set viewportEntity(arg) { if (this._viewportEntity === arg) { return; } const isString = typeof arg === "string"; if (this._viewportEntity && isString && this._viewportEntity.guid === arg) { return; } if (this._viewportEntity) { this._viewportEntityUnsubscribe(); } if (arg instanceof GraphNode) { this._viewportEntity = arg; } else if (isString) { this._viewportEntity = this.system.app.getEntityFromIndex(arg) || null; } else { this._viewportEntity = null; } if (this._viewportEntity) { this._viewportEntitySubscribe(); } } get viewportEntity() { return this._viewportEntity; } set contentEntity(arg) { if (this._contentEntity === arg) { return; } const isString = typeof arg === "string"; if (this._contentEntity && isString && this._contentEntity.guid === arg) { return; } if (this._contentEntity) { this._contentEntityUnsubscribe(); } if (arg instanceof GraphNode) { this._contentEntity = arg; } else if (isString) { this._contentEntity = this.system.app.getEntityFromIndex(arg) || null; } else { this._contentEntity = null; } if (this._contentEntity) { this._contentEntitySubscribe(); } } get contentEntity() { return this._contentEntity; } set horizontalScrollbarEntity(arg) { if (this._horizontalScrollbarEntity === arg) { return; } const isString = typeof arg === "string"; if (this._horizontalScrollbarEntity && isString && this._horizontalScrollbarEntity.guid === arg) { return; } if (this._horizontalScrollbarEntity) { this._horizontalScrollbarEntityUnsubscribe(); } if (arg instanceof GraphNode) { this._horizontalScrollbarEntity = arg; } else if (isString) { this._horizontalScrollbarEntity = this.system.app.getEntityFromIndex(arg) || null; } else { this._horizontalScrollbarEntity = null; } this._scrollbarEntities[ORIENTATION_HORIZONTAL] = this._horizontalScrollbarEntity; if (this._horizontalScrollbarEntity) { this._horizontalScrollbarEntitySubscribe(); } } get horizontalScrollbarEntity() { return this._horizontalScrollbarEntity; } set verticalScrollbarEntity(arg) { if (this._verticalScrollbarEntity === arg) { return; } const isString = typeof arg === "string"; if (this._verticalScrollbarEntity && isString && this._verticalScrollbarEntity.guid === arg) { return; } if (this._verticalScrollbarEntity) { this._verticalScrollbarEntityUnsubscribe(); } if (arg instanceof GraphNode) { this._verticalScrollbarEntity = arg; } else if (isString) { this._verticalScrollbarEntity = this.system.app.getEntityFromIndex(arg) || null; } else { this._verticalScrollbarEntity = null; } this._scrollbarEntities[ORIENTATION_VERTICAL] = this._verticalScrollbarEntity; if (this._verticalScrollbarEntity) { this._verticalScrollbarEntitySubscribe(); } } get verticalScrollbarEntity() { return this._verticalScrollbarEntity; } set scroll(value) { this._onSetScroll(value.x, value.y); } get scroll() { return this._scroll; } _toggleElementListeners(onOrOff) { if (this.entity.element) { if (onOrOff === "on" && this._hasElementListeners) { return; } this.entity.element[onOrOff]("resize", this._syncAll, this); this.entity.element[onOrOff]("mousewheel", this._onMouseWheel, this); this._hasElementListeners = onOrOff === "on"; } } _onElementComponentAdd(entity) { this._evtElementRemove = this.entity.element.once("beforeremove", this._onElementComponentRemove, this); this._toggleElementListeners("on"); } _onElementComponentRemove(entity) { this._evtElementRemove?.off(); this._evtElementRemove = null; this._toggleElementListeners("off"); } _viewportEntitySubscribe() { this._evtViewportEntityElementAdd = this._viewportEntity.on("element:add", this._onViewportElementGain, this); if (this._viewportEntity.element) { this._onViewportElementGain(); } } _viewportEntityUnsubscribe() { this._evtViewportEntityElementAdd?.off(); this._evtViewportEntityElementAdd = null; if (this._viewportEntity?.element) { this._onViewportElementLose(); } } _viewportEntityElementSubscribe() { const element = this._viewportEntity.element; this._evtViewportElementRemove = element.once("beforeremove", this._onViewportElementLose, this); this._evtViewportResize = element.on("resize", this._syncAll, this); } _viewportEntityElementUnsubscribe() { this._evtViewportElementRemove?.off(); this._evtViewportElementRemove = null; this._evtViewportResize?.off(); this._evtViewportResize = null; } _onViewportElementGain() { this._viewportEntityElementSubscribe(); this._syncAll(); } _onViewportElementLose() { this._viewportEntityElementUnsubscribe(); } _contentEntitySubscribe() { this._evtContentEntityElementAdd = this._contentEntity.on("element:add", this._onContentElementGain, this); if (this._contentEntity.element) { this._onContentElementGain(); } } _contentEntityUnsubscribe() { this._evtContentEntityElementAdd?.off(); this._evtContentEntityElementAdd = null; if (this._contentEntity?.element) { this._onContentElementLose(); } } _contentEntityElementSubscribe() { const element = this._contentEntity.element; this._evtContentElementRemove = element.once("beforeremove", this._onContentElementLose, this); this._evtContentResize = element.on("resize", this._syncAll, this); } _contentEntityElementUnsubscribe() { this._evtContentElementRemove?.off(); this._evtContentElementRemove = null; this._evtContentResize?.off(); this._evtContentResize = null; } _onContentElementGain() { this._contentEntityElementSubscribe(); this._destroyDragHelper(); this._contentDragHelper = new ElementDragHelper(this._contentEntity.element); this._contentDragHelper.on("drag:start", this._onContentDragStart, this); this._contentDragHelper.on("drag:end", this._onContentDragEnd, this); this._contentDragHelper.on("drag:move", this._onContentDragMove, this); this._prevContentSizes[ORIENTATION_HORIZONTAL] = null; this._prevContentSizes[ORIENTATION_VERTICAL] = null; this._syncAll(); } _onContentElementLose() { this._contentEntityElementUnsubscribe(); this._destroyDragHelper(); } _onContentDragStart() { if (this._contentEntity && this.enabled && this.entity.enabled) { this._dragStartPosition.copy(this._contentEntity.getLocalPosition()); } } _onContentDragEnd() { this._prevContentDragPosition = null; this._enableContentInput(); } _onContentDragMove(position) { if (this._contentEntity && this.enabled && this.entity.enabled) { this._wasDragged = true; this._setScrollFromContentPosition(position); this._setVelocityFromContentPositionDelta(position); if (!this._disabledContentInput) { const dx = position.x - this._dragStartPosition.x; const dy = position.y - this._dragStartPosition.y; if (Math.abs(dx) > this.dragThreshold || Math.abs(dy) > this.dragThreshold) { this._disableContentInput(); } } } } _horizontalScrollbarEntitySubscribe() { this._evtHorizontalScrollbarAdd = this._horizontalScrollbarEntity.on("scrollbar:add", this._onHorizontalScrollbarGain, this); if (this._horizontalScrollbarEntity.scrollbar) { this._onHorizontalScrollbarGain(); } } _verticalScrollbarEntitySubscribe() { this._evtVerticalScrollbarAdd = this._verticalScrollbarEntity.on("scrollbar:add", this._onVerticalScrollbarGain, this); if (this._verticalScrollbarEntity.scrollbar) { this._onVerticalScrollbarGain(); } } _horizontalScrollbarEntityUnsubscribe() { this._evtHorizontalScrollbarAdd?.off(); this._evtHorizontalScrollbarAdd = null; if (this._horizontalScrollbarEntity.scrollbar) { this._onHorizontalScrollbarLose(); } } _verticalScrollbarEntityUnsubscribe() { this._evtVerticalScrollbarAdd?.off(); this._evtVerticalScrollbarAdd = null; if (this._verticalScrollbarEntity.scrollbar) { this._onVerticalScrollbarLose(); } } _onSetHorizontalScrollbarValue(scrollValueX) { if (!this._scrollbarUpdateFlags[ORIENTATION_HORIZONTAL] && this.enabled && this.entity.enabled) { this._onSetScroll(scrollValueX, null); } } _onSetVerticalScrollbarValue(scrollValueY) { if (!this._scrollbarUpdateFlags[ORIENTATION_VERTICAL] && this.enabled && this.entity.enabled) { this._onSetScroll(null, scrollValueY); } } _onHorizontalScrollbarGain() { const scrollbar = this._horizontalScrollbarEntity?.scrollbar; this._evtHorizontalScrollbarRemove = scrollbar.on("beforeremove", this._onHorizontalScrollbarLose, this); this._evtHorizontalScrollbarValue = scrollbar.on("set:value", this._onSetHorizontalScrollbarValue, this); this._syncScrollbarEnabledState(ORIENTATION_HORIZONTAL); this._syncScrollbarPosition(ORIENTATION_HORIZONTAL); } _onVerticalScrollbarGain() { const scrollbar = this._verticalScrollbarEntity?.scrollbar; this._evtVerticalScrollbarRemove = scrollbar.on("beforeremove", this._onVerticalScrollbarLose, this); this._evtVerticalScrollbarValue = scrollbar.on("set:value", this._onSetVerticalScrollbarValue, this); this._syncScrollbarEnabledState(ORIENTATION_VERTICAL); this._syncScrollbarPosition(ORIENTATION_VERTICAL); } _onHorizontalScrollbarLose() { this._evtHorizontalScrollbarRemove?.off(); this._evtHorizontalScrollbarRemove = null; this._evtHorizontalScrollbarValue?.off(); this._evtHorizontalScrollbarValue = null; } _onVerticalScrollbarLose() { this._evtVerticalScrollbarRemove?.off(); this._evtVerticalScrollbarRemove = null; this._evtVerticalScrollbarValue?.off(); this._evtVerticalScrollbarValue = null; } _onSetScroll(x, y, resetVelocity) { if (resetVelocity !== false) { this._velocity.set(0, 0, 0); } const xChanged = this._updateAxis(x, "x", ORIENTATION_HORIZONTAL); const yChanged = this._updateAxis(y, "y", ORIENTATION_VERTICAL); if (xChanged || yChanged) { this.fire("set:scroll", this._scroll); } } _updateAxis(scrollValue, axis, orientation) { const hasChanged = scrollValue !== null && Math.abs(scrollValue - this._scroll[axis]) > 1e-5; if (hasChanged || this._isDragging() || scrollValue === 0) { this._scroll[axis] = this._determineNewScrollValue(scrollValue, axis, orientation); this._syncContentPosition(orientation); this._syncScrollbarPosition(orientation); } return hasChanged; } _determineNewScrollValue(scrollValue, axis, orientation) { if (!this._getScrollingEnabled(orientation)) { return this._scroll[axis]; } switch (this.scrollMode) { case SCROLL_MODE_CLAMP: return math.clamp(scrollValue, 0, this._getMaxScrollValue(orientation)); case SCROLL_MODE_BOUNCE: this._setVelocityFromOvershoot(scrollValue, axis, orientation); return scrollValue; case SCROLL_MODE_INFINITE: return scrollValue; default: console.warn(`Unhandled scroll mode:${this.scrollMode}`); return scrollValue; } } _syncAll() { this._syncContentPosition(ORIENTATION_HORIZONTAL); this._syncContentPosition(ORIENTATION_VERTICAL); this._syncScrollbarPosition(ORIENTATION_HORIZONTAL); this._syncScrollbarPosition(ORIENTATION_VERTICAL); this._syncScrollbarEnabledState(ORIENTATION_HORIZONTAL); this._syncScrollbarEnabledState(ORIENTATION_VERTICAL); } _syncContentPosition(orientation) { if (!this._contentEntity) { return; } const axis = this._getAxis(orientation); const sign = this._getSign(orientation); const prevContentSize = this._prevContentSizes[orientation]; const currContentSize = this._getContentSize(orientation); if (prevContentSize !== null && Math.abs(prevContentSize - currContentSize) > 1e-4) { const prevMaxOffset = this._getMaxOffset(orientation, prevContentSize); const currMaxOffset = this._getMaxOffset(orientation, currContentSize); if (currMaxOffset === 0) { this._scroll[axis] = 1; } else { this._scroll[axis] = math.clamp(this._scroll[axis] * prevMaxOffset / currMaxOffset, 0, 1); } } const offset = this._scroll[axis] * this._getMaxOffset(orientation); const contentPosition = this._contentEntity.getLocalPosition(); contentPosition[axis] = offset * sign; this._contentEntity.setLocalPosition(contentPosition); this._prevContentSizes[orientation] = currContentSize; } _syncScrollbarPosition(orientation) { const scrollbarEntity = this._scrollbarEntities[orientation]; if (!scrollbarEntity?.scrollbar) { return; } const axis = this._getAxis(orientation); this._scrollbarUpdateFlags[orientation] = true; scrollbarEntity.scrollbar.value = this._scroll[axis]; scrollbarEntity.scrollbar.handleSize = this._getScrollbarHandleSize(axis, orientation); this._scrollbarUpdateFlags[orientation] = false; } // Toggles the scrollbar entities themselves to be enabled/disabled based // on whether the user has enabled horizontal/vertical scrolling on the // scroll view. _syncScrollbarEnabledState(orientation) { const entity = this._scrollbarEntities[orientation]; if (!entity) { return; } const isScrollingEnabled = this._getScrollingEnabled(orientation); const requestedVisibility = this._getScrollbarVisibility(orientation); switch (requestedVisibility) { case SCROLLBAR_VISIBILITY_SHOW_ALWAYS: entity.enabled = isScrollingEnabled; return; case SCROLLBAR_VISIBILITY_SHOW_WHEN_REQUIRED: entity.enabled = isScrollingEnabled && this._contentIsLargerThanViewport(orientation); return; default: console.warn(`Unhandled scrollbar visibility:${requestedVisibility}`); entity.enabled = isScrollingEnabled; } } _contentIsLargerThanViewport(orientation) { return this._getContentSize(orientation) > this._getViewportSize(orientation); } _contentPositionToScrollValue(contentPosition) { const maxOffsetH = this._getMaxOffset(ORIENTATION_HORIZONTAL); const maxOffsetV = this._getMaxOffset(ORIENTATION_VERTICAL); if (maxOffsetH === 0) { _tempScrollValue.x = 0; } else { _tempScrollValue.x = contentPosition.x / maxOffsetH; } if (maxOffsetV === 0) { _tempScrollValue.y = 0; } else { _tempScrollValue.y = contentPosition.y / -maxOffsetV; } return _tempScrollValue; } _getMaxOffset(orientation, contentSize) { contentSize = contentSize === void 0 ? this._getContentSize(orientation) : contentSize; const viewportSize = this._getViewportSize(orientation); if (contentSize < viewportSize) { return -this._getViewportSize(orientation); } return viewportSize - contentSize; } _getMaxScrollValue(orientation) { return this._contentIsLargerThanViewport(orientation) ? 1 : 0; } _getScrollbarHandleSize(axis, orientation) { const viewportSize = this._getViewportSize(orientation); const contentSize = this._getContentSize(orientation); if (Math.abs(contentSize) < 1e-3) { return 1; } const handleSize = Math.min(viewportSize / contentSize, 1); const overshoot = this._toOvershoot(this._scroll[axis], orientation); if (overshoot === 0) { return handleSize; } return handleSize / (1 + Math.abs(overshoot)); } _getViewportSize(orientation) { return this._getSize(orientation, this._viewportEntity); } _getContentSize(orientation) { return this._getSize(orientation, this._contentEntity); } _getSize(orientation, entity) { if (entity?.element) { return entity.element[this._getCalculatedDimension(orientation)]; } return 0; } _getScrollingEnabled(orientation) { if (orientation === ORIENTATION_HORIZONTAL) { return this.horizontal; } else if (orientation === ORIENTATION_VERTICAL) { return this.vertical; } return void 0; } _getScrollbarVisibility(orientation) { if (orientation === ORIENTATION_HORIZONTAL) { return this.horizontalScrollbarVisibility; } else if (orientation === ORIENTATION_VERTICAL) { return this.verticalScrollbarVisibility; } return void 0; } _getSign(orientation) { return orientation === ORIENTATION_HORIZONTAL ? 1 : -1; } _getAxis(orientation) { return orientation === ORIENTATION_HORIZONTAL ? "x" : "y"; } _getCalculatedDimension(orientation) { return orientation === ORIENTATION_HORIZONTAL ? "calculatedWidth" : "calculatedHeight"; } _destroyDragHelper() { if (this._contentDragHelper) { this._contentDragHelper.destroy(); } } onUpdate() { if (this._contentEntity) { this._updateVelocity(); this._syncScrollbarEnabledState(ORIENTATION_HORIZONTAL); this._syncScrollbarEnabledState(ORIENTATION_VERTICAL); } } _updateVelocity() { if (!this._isDragging()) { if (this.scrollMode === SCROLL_MODE_BOUNCE) { if (this._hasOvershoot("x", ORIENTATION_HORIZONTAL)) { this._setVelocityFromOvershoot(this.scroll.x, "x", ORIENTATION_HORIZONTAL); } if (this._hasOvershoot("y", ORIENTATION_VERTICAL)) { this._setVelocityFromOvershoot(this.scroll.y, "y", ORIENTATION_VERTICAL); } } if (Math.abs(this._velocity.x) > 1e-4 || Math.abs(this._velocity.y) > 1e-4) { const position = this._contentEntity.getLocalPosition(); position.x += this._velocity.x; position.y += this._velocity.y; this._contentEntity.setLocalPosition(position); this._setScrollFromContentPosition(position); } this._velocity.x *= 1 - this.friction; this._velocity.y *= 1 - this.friction; } } _hasOvershoot(axis, orientation) { return Math.abs(this._toOvershoot(this.scroll[axis], orientation)) > 1e-3; } _toOvershoot(scrollValue, orientation) { const maxScrollValue = this._getMaxScrollValue(orientation); if (scrollValue < 0) { return scrollValue; } else if (scrollValue > maxScrollValue) { return scrollValue - maxScrollValue; } return 0; } _setVelocityFromOvershoot(scrollValue, axis, orientation) { const overshootValue = this._toOvershoot(scrollValue, orientation); const overshootPixels = overshootValue * this._getMaxOffset(orientation) * this._getSign(orientation); if (Math.abs(overshootPixels) > 0) { this._velocity[axis] = -overshootPixels / (this.bounceAmount * 50 + 1); } } _setVelocityFromContentPositionDelta(position) { if (this._prevContentDragPosition) { this._velocity.sub2(position, this._prevContentDragPosition); this._prevContentDragPosition.copy(position); } else { this._velocity.set(0, 0, 0); this._prevContentDragPosition = position.clone(); } } _setScrollFromContentPosition(position) { let scrollValue = this._contentPositionToScrollValue(position); if (this._isDragging()) { scrollValue = this._applyScrollValueTension(scrollValue); } this._onSetScroll(scrollValue.x, scrollValue.y, false); } // Create nice tension effect when dragging past the extents of the viewport _applyScrollValueTension(scrollValue) { const factor = 1; let max = this._getMaxScrollValue(ORIENTATION_HORIZONTAL); let overshoot = this._toOvershoot(scrollValue.x, ORIENTATION_HORIZONTAL); if (overshoot > 0) { scrollValue.x = max + factor * Math.log10(1 + overshoot); } else if (overshoot < 0) { scrollValue.x = -factor * Math.log10(1 - overshoot); } max = this._getMaxScrollValue(ORIENTATION_VERTICAL); overshoot = this._toOvershoot(scrollValue.y, ORIENTATION_VERTICAL); if (overshoot > 0) { scrollValue.y = max + factor * Math.log10(1 + overshoot); } else if (overshoot < 0) { scrollValue.y = -factor * Math.log10(1 - overshoot); } return scrollValue; } _isDragging() { return this._contentDragHelper && this._contentDragHelper.isDragging; } _setScrollbarComponentsEnabled(enabled) { if (this._horizontalScrollbarEntity?.scrollbar) { this._horizontalScrollbarEntity.scrollbar.enabled = enabled; } if (this._verticalScrollbarEntity?.scrollbar) { this._verticalScrollbarEntity.scrollbar.enabled = enabled; } } _setContentDraggingEnabled(enabled) { if (this._contentDragHelper) { this._contentDragHelper.enabled = enabled; } } _onMouseWheel(event) { if (!this.useMouseWheel || !this._contentEntity?.element) { return; } const wheelEvent = event.event; const normalizedDeltaX = wheelEvent.deltaX / this._contentEntity.element.calculatedWidth * this.mouseWheelSensitivity.x; const normalizedDeltaY = wheelEvent.deltaY / this._contentEntity.element.calculatedHeight * this.mouseWheelSensitivity.y; const scrollX = math.clamp(this._scroll.x + normalizedDeltaX, 0, this._getMaxScrollValue(ORIENTATION_HORIZONTAL)); const scrollY = math.clamp(this._scroll.y + normalizedDeltaY, 0, this._getMaxScrollValue(ORIENTATION_VERTICAL)); this.scroll = new Vec2(scrollX, scrollY); } // re-enable useInput flag on any descendant that was disabled _enableContentInput() { while (this._disabledContentInputEntities.length) { const e = this._disabledContentInputEntities.pop(); if (e.element) { e.element.useInput = true; } } this._disabledContentInput = false; } // disable useInput flag on all descendants of this contentEntity _disableContentInput() { const _disableInput = (e) => { if (e.element && e.element.useInput) { this._disabledContentInputEntities.push(e); e.element.useInput = false; } const children = e.children; for (let i = 0, l = children.length; i < l; i++) { _disableInput(children[i]); } }; if (this._contentEntity) { const children = this._contentEntity.children; for (let i = 0, l = children.length; i < l; i++) { _disableInput(children[i]); } } this._disabledContentInput = true; } onEnable() { this._setScrollbarComponentsEnabled(true); this._setContentDraggingEnabled(true); this._syncAll(); } onDisable() { this._setScrollbarComponentsEnabled(false); this._setContentDraggingEnabled(false); } onRemove() { this._evtElementAdd?.off(); this._evtElementAdd = null; this._evtElementRemove?.off(); this._evtElementRemove = null; this.viewportEntity = null; this.contentEntity = null; this.horizontalScrollbarEntity = null; this.verticalScrollbarEntity = null; this._toggleElementListeners("off"); this._destroyDragHelper(); } resolveDuplicatedEntityReferenceProperties(oldScrollView, duplicatedIdsMap) { if (oldScrollView.viewportEntity) { this.viewportEntity = duplicatedIdsMap[oldScrollView.viewportEntity.guid]; } if (oldScrollView.contentEntity) { this.contentEntity = duplicatedIdsMap[oldScrollView.contentEntity.guid]; } if (oldScrollView.horizontalScrollbarEntity) { this.horizontalScrollbarEntity = duplicatedIdsMap[oldScrollView.horizontalScrollbarEntity.guid]; } if (oldScrollView.verticalScrollbarEntity) { this.verticalScrollbarEntity = duplicatedIdsMap[oldScrollView.verticalScrollbarEntity.guid]; } } } export { ScrollViewComponent };