Skip to content

Commit

Permalink
Scrollview remove entity reference (#7206)
Browse files Browse the repository at this point in the history
* optimize render component rootBone property

* expose rootBone property

* Update src/framework/components/render/component.js

Co-authored-by: Will Eastcott <willeastcott@gmail.com>

* use jsdo import

* .

* ButtonComponent remove EntityReference

* remove reliance on component system global event lists

* remove EntityReference from ScrollbarComponent

* remove EntityReference, optimize ScrollVeiw and Scrollbar

* lint

---------

Co-authored-by: Will Eastcott <willeastcott@gmail.com>
  • Loading branch information
Maksims and willeastcott authored Jan 13, 2025
1 parent f868729 commit a2f360d
Show file tree
Hide file tree
Showing 10 changed files with 625 additions and 1,045 deletions.
618 changes: 479 additions & 139 deletions src/framework/components/scroll-view/component.js

Large diffs are not rendered by default.

24 changes: 14 additions & 10 deletions src/framework/components/scroll-view/data.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { Vec2 } from '../../../core/math/vec2.js';

/**
* @import { Entity } from '../../../framework/entity.js'
*/

const DEFAULT_DRAG_THRESHOLD = 10;

class ScrollViewComponentData {
Expand Down Expand Up @@ -27,22 +31,22 @@ class ScrollViewComponentData {
mouseWheelSensitivity = new Vec2(1, 1);

/** @type {number} */
horizontalScrollbarVisibility;
horizontalScrollbarVisibility = 0;

/** @type {number} */
verticalScrollbarVisibility;
verticalScrollbarVisibility = 0;

/** @type {import('../../../framework/entity.js').Entity} */
viewportEntity;
/** @type {Entity|null} */
viewportEntity = null;

/** @type {import('../../../framework/entity.js').Entity} */
contentEntity;
/** @type {Entity|null} */
contentEntity = null;

/** @type {import('../../../framework/entity.js').Entity} */
horizontalScrollbarEntity;
/** @type {Entity|null} */
horizontalScrollbarEntity = null;

/** @type {import('../../../framework/entity.js').Entity} */
verticalScrollbarEntity;
/** @type {Entity|null} */
verticalScrollbarEntity = null;
}

export { ScrollViewComponentData };
11 changes: 6 additions & 5 deletions src/framework/components/scroll-view/system.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@ const _schema = [
{ name: 'useMouseWheel', type: 'boolean' },
{ name: 'mouseWheelSensitivity', type: 'vec2' },
{ name: 'horizontalScrollbarVisibility', type: 'number' },
{ name: 'verticalScrollbarVisibility', type: 'number' },
{ name: 'viewportEntity', type: 'entity' },
{ name: 'contentEntity', type: 'entity' },
{ name: 'horizontalScrollbarEntity', type: 'entity' },
{ name: 'verticalScrollbarEntity', type: 'entity' }
{ name: 'verticalScrollbarVisibility', type: 'number' }
];

const DEFAULT_DRAG_THRESHOLD = 10;
Expand Down Expand Up @@ -64,6 +60,11 @@ class ScrollViewComponentSystem extends ComponentSystem {
}

super.initializeComponentData(component, data, _schema);

component.viewportEntity = data.viewportEntity;
component.contentEntity = data.contentEntity;
component.horizontalScrollbarEntity = data.horizontalScrollbarEntity;
component.verticalScrollbarEntity = data.verticalScrollbarEntity;
}

onUpdate(dt) {
Expand Down
131 changes: 107 additions & 24 deletions src/framework/components/scrollbar/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@ import { math } from '../../../core/math/math.js';

import { ORIENTATION_HORIZONTAL } from '../../../scene/constants.js';

import { GraphNode } from '../../../scene/graph-node.js';

import { Component } from '../component.js';

import { ElementDragHelper } from '../element/element-drag-helper.js';

import { EntityReference } from '../../utils/entity-reference.js';
/**
* @import { EventHandle } from '../../../core/event-handle.js'
* @import { Entity } from '../../entity.js'
*/

/**
* A ScrollbarComponent enables a group of entities to behave like a draggable scrollbar.
Expand All @@ -26,25 +31,33 @@ class ScrollbarComponent extends Component {
*/
static EVENT_SETVALUE = 'set:value';

/**
* @type {Entity|null}
* @private
*/
_handleEntity = null;

/**
* @type {EventHandle|null}
* @private
*/
_evtHandleEntityElementAdd = null;

/**
* @type {EventHandle[]}
* @private
*/
_evtHandleEntityChanges = [];

/**
* Create a new ScrollbarComponent.
*
* @param {import('./system.js').ScrollbarComponentSystem} system - The ComponentSystem that
* created this Component.
* @param {import('../../entity.js').Entity} entity - The Entity that this Component is
* attached to.
* @param {Entity} entity - The Entity that this Component is attached to.
*/
constructor(system, entity) {
super(system, entity);

this._handleReference = new EntityReference(this, 'handleEntity', {
'element#gain': this._onHandleElementGain,
'element#lose': this._onHandleElementLose,
'element#set:anchor': this._onSetHandleAlignment,
'element#set:margin': this._onSetHandleAlignment,
'element#set:pivot': this._onSetHandleAlignment
});

this._toggleLifecycleListeners('on');
}

Expand Down Expand Up @@ -141,19 +154,48 @@ class ScrollbarComponent extends Component {
* Sets the entity to be used as the scrollbar handle. This entity must have a
* {@link ScrollbarComponent}.
*
* @type {import('../../../framework/entity.js').Entity}
* @type {Entity|string|null}
*/
set handleEntity(arg) {
this._setValue('handleEntity', arg);
if (this._handleEntity === arg) {
return;
}

const isString = typeof arg === 'string';
if (this._handleEntity && isString && this._handleEntity.getGuid() === arg) {
return;
}

if (this._handleEntity) {
this._handleEntityUnsubscribe();
}

if (arg instanceof GraphNode) {
this._handleEntity = arg;
} else if (isString) {
this._handleEntity = this.system.app.getEntityFromIndex(arg) || null;
} else {
this._handleEntity = null;
}

if (this._handleEntity) {
this._handleEntitySubscribe();
}

if (this._handleEntity) {
this.data.handleEntity = this._handleEntity.getGuid();
} else if (isString && arg) {
this.data.handleEntity = arg;
}
}

/**
* Gets the entity to be used as the scrollbar handle.
*
* @type {import('../../../framework/entity.js').Entity}
* @type {Entity|null}
*/
get handleEntity() {
return this.data.handleEntity;
return this._handleEntity;
}

/** @ignore */
Expand All @@ -176,20 +218,56 @@ class ScrollbarComponent extends Component {
// TODO Handle scrollwheel events
}

_handleEntitySubscribe() {
this._evtHandleEntityElementAdd = this._handleEntity.on('element:add', this._onHandleElementGain, this);

if (this._handleEntity.element) {
this._onHandleElementGain();
}
}

_handleEntityUnsubscribe() {
this._evtHandleEntityElementAdd?.off();
this._evtHandleEntityElementAdd = null;

if (this._handleEntity?.element) {
this._onHandleElementLose();
}
}

_handleEntityElementSubscribe() {
const element = this._handleEntity.element;

const handles = this._evtHandleEntityChanges;
handles.push(element.once('beforeremove', this._onHandleElementLose, this));
handles.push(element.on('set:anchor', this._onSetHandleAlignment, this));
handles.push(element.on('set:margin', this._onSetHandleAlignment, this));
handles.push(element.on('set:pivot', this._onSetHandleAlignment, this));
}

_handleEntityElementUnsubscribe() {
for (let i = 0; i < this._evtHandleEntityChanges.length; i++) {
this._evtHandleEntityChanges[i].off();
}
this._evtHandleEntityChanges.length = 0;
}

_onHandleElementGain() {
this._handleEntityElementSubscribe();
this._destroyDragHelper();
this._handleDragHelper = new ElementDragHelper(this._handleReference.entity.element, this._getAxis());
this._handleDragHelper = new ElementDragHelper(this._handleEntity.element, this._getAxis());
this._handleDragHelper.on('drag:move', this._onHandleDrag, this);

this._updateHandlePositionAndSize();
}

_onHandleElementLose() {
this._handleEntityElementUnsubscribe();
this._destroyDragHelper();
}

_onHandleDrag(position) {
if (this._handleReference.entity && this.enabled && this.entity.enabled) {
if (this._handleEntity && this.enabled && this.entity.enabled) {
this.value = this._handlePositionToScrollValue(position[this._getAxis()]);
}
}
Expand All @@ -214,19 +292,19 @@ class ScrollbarComponent extends Component {
}

_onSetOrientation(name, oldValue, newValue) {
if (newValue !== oldValue && this._handleReference.hasComponent('element')) {
this._handleReference.entity.element[this._getOppositeDimension()] = 0;
if (newValue !== oldValue && this._handleEntity?.element) {
this._handleEntity.element[this._getOppositeDimension()] = 0;
}
}

_updateHandlePositionAndSize() {
const handleEntity = this._handleReference.entity;
const handleElement = handleEntity && handleEntity.element;
const handleEntity = this._handleEntity;
const handleElement = handleEntity?.element;

if (handleEntity) {
const position = handleEntity.getLocalPosition();
position[this._getAxis()] = this._getHandlePosition();
this._handleReference.entity.setLocalPosition(position);
handleEntity.setLocalPosition(position);
}

if (handleElement) {
Expand Down Expand Up @@ -291,7 +369,6 @@ class ScrollbarComponent extends Component {
}

onEnable() {
this._handleReference.onParentComponentEnable();
this._setHandleDraggingEnabled(true);
}

Expand All @@ -303,6 +380,12 @@ class ScrollbarComponent extends Component {
this._destroyDragHelper();
this._toggleLifecycleListeners('off');
}

resolveDuplicatedEntityReferenceProperties(oldScrollbar, duplicatedIdsMap) {
if (oldScrollbar.handleEntity) {
this.handleEntity = duplicatedIdsMap[oldScrollbar.handleEntity.getGuid()];
}
}
}

export { ScrollbarComponent };
4 changes: 2 additions & 2 deletions src/framework/components/scrollbar/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ class ScrollbarComponentData {
value = 0;

/** @type {number} */
handleSize;
handleSize = 0;

/** @type {import('../../../framework/entity').Entity} */
handleEntity;
handleEntity = null;
}

export { ScrollbarComponentData };
9 changes: 7 additions & 2 deletions src/framework/components/scrollbar/system.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ const _schema = [
{ name: 'enabled', type: 'boolean' },
{ name: 'orientation', type: 'number' },
{ name: 'value', type: 'number' },
{ name: 'handleSize', type: 'number' },
{ name: 'handleEntity', type: 'entity' }
{ name: 'handleSize', type: 'number' }
];

/**
Expand All @@ -33,11 +32,17 @@ class ScrollbarComponentSystem extends ComponentSystem {

this.schema = _schema;

this.on('add', this._onAddComponent, this);
this.on('beforeremove', this._onRemoveComponent, this);
}

initializeComponentData(component, data, properties) {
super.initializeComponentData(component, data, _schema);
component.handleEntity = data.handleEntity;
}

_onAddComponent(entity) {
entity.fire('scrollbar:add');
}

_onRemoveComponent(entity, component) {
Expand Down
10 changes: 10 additions & 0 deletions src/framework/entity.js
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,16 @@ function resolveDuplicatedEntityReferenceProperties(oldSubtreeRoot, oldEntity, n
newEntity.button.resolveDuplicatedEntityReferenceProperties(components.button, duplicatedIdsMap);
}

// Handle entity scrollview attributes
if (components.scrollview) {
newEntity.scrollview.resolveDuplicatedEntityReferenceProperties(components.scrollview, duplicatedIdsMap);
}

// Handle entity scrollbar attributes
if (components.scrollbar) {
newEntity.scrollbar.resolveDuplicatedEntityReferenceProperties(components.scrollbar, duplicatedIdsMap);
}

// Handle entity anim attributes
if (components.anim) {
newEntity.anim.resolveDuplicatedEntityReferenceProperties(components.anim, duplicatedIdsMap);
Expand Down
Loading

0 comments on commit a2f360d

Please sign in to comment.