This is an automated email from the ASF dual-hosted git repository.
SolidSoft-Lda pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-asjs.git
The following commit(s) were added to refs/heads/develop by this push:
new c5fb5a08db VirtualDataGrid: move column sync into wheelHandler
c5fb5a08db is described below
commit c5fb5a08db34368038c12df4e80079f9df4feae6
Author: Hugo Ferreira <[email protected]>
AuthorDate: Wed May 6 20:38:32 2026 +0100
VirtualDataGrid: move column sync into wheelHandler
- scrollHandler relied on the async scroll event to propagate scrollTop and
call layout() on sibling columns; on slow machines with heavy renderers one
frame was visible with the column under the cursor already scrolled while the
others lagged behind
- wheelHandler now applies scrollTop + layout() on every column inside the
handler itself, before paint, so the browser commits a single aligned frame
- scrollHandler still covers non-wheel paths (keyboard, scrollbar drag,
programmatic scroll), reusing the new syncSiblings helper
- Dropped isAreaFocus and the mouseover/mouseleave listeners: they had
become redundant (wheel events only fire where the cursor is) and blocked
legitimate sync whenever the flag stayed stuck on false
---
.../beads/layouts/VirtualDataGridListAreaLayout.as | 86 +++++++++++-----------
1 file changed, 44 insertions(+), 42 deletions(-)
diff --git
a/frameworks/projects/Jewel/src/main/royale/org/apache/royale/jewel/beads/layouts/VirtualDataGridListAreaLayout.as
b/frameworks/projects/Jewel/src/main/royale/org/apache/royale/jewel/beads/layouts/VirtualDataGridListAreaLayout.as
index a0f4c2bf13..1aae86d8d8 100644
---
a/frameworks/projects/Jewel/src/main/royale/org/apache/royale/jewel/beads/layouts/VirtualDataGridListAreaLayout.as
+++
b/frameworks/projects/Jewel/src/main/royale/org/apache/royale/jewel/beads/layouts/VirtualDataGridListAreaLayout.as
@@ -36,8 +36,6 @@ package org.apache.royale.jewel.beads.layouts
*/
public class VirtualDataGridListAreaLayout extends
VirtualListVerticalLayout
{
- private var isAreaFocus:Boolean;
-
// Tracks which DataGrid is currently syncing columns, to suppress
redundant
// layout() calls from scroll events triggered by programmatic
scrollTop changes.
private static var _syncingDataGrid:IDataGrid = null;
@@ -62,13 +60,10 @@ package org.apache.royale.jewel.beads.layouts
COMPILE::JS
{
- host.element.addEventListener("mouseover", function():void {
isAreaFocus = true });
- host.element.addEventListener("mouseleave", function():void {
isAreaFocus = false });
-
// Non-passive wheel listener so preventDefault() can block
the browser's
// compositor thread from scrolling this column ahead of its
siblings.
// Without this, the compositor moves this column visually
before our
- // scrollHandler fires, producing one frame of cross-column
misalignment.
+ // handler fires, producing one frame of cross-column
misalignment.
var wheelOptions:Object = new Object();
wheelOptions["passive"] = false;
host.element.addEventListener("wheel", wheelHandler,
wheelOptions);
@@ -78,15 +73,50 @@ package org.apache.royale.jewel.beads.layouts
COMPILE::JS
private function wheelHandler(e:*):void
{
- if (!isAreaFocus || e.deltaY == 0) return;
+ if (e.deltaY == 0) return;
e.preventDefault();
// deltaMode: 0 = pixels (trackpad/modern), 1 = lines (mouse wheel
on Firefox)
var delta:Number = (e.deltaMode == 0) ? e.deltaY : e.deltaY * 40;
var limitY:Number = host.element.scrollHeight -
host.element.clientHeight;
- host.element.scrollTop = Math.max(0,
Math.min(host.element.scrollTop + delta, limitY));
- // The resulting scroll event triggers scrollHandler which syncs
all other columns.
+ var newScrollTop:Number = Math.max(0,
Math.min(host.element.scrollTop + delta, limitY));
+ if (newScrollTop == host.element.scrollTop) return;
+
+ // Apply scroll + layout on host and siblings synchronously inside
this
+ // handler so the browser paints a single frame with all columns
aligned.
+ // Going through the async scroll event leaves a gap visible on
slower
+ // machines, especially with heavy renderers such as editable
checkboxes.
+ host.element.scrollTop = newScrollTop;
+ layout();
+ syncSiblings(newScrollTop);
+ }
+
+ COMPILE::JS
+ private function syncSiblings(scrollTop:Number):void
+ {
+ var myDataGrid:IDataGrid = (host as IDataGridColumnList).datagrid;
+ _syncingDataGrid = myDataGrid;
+
+ var listArea:Container = getListArea();
+ for (var i:int = 0; i < listArea.numElements; i++)
+ {
+ var column:* = listArea.getElementAt(i);
+ if (column == host) continue;
+
+ column.element.scrollTop = scrollTop;
+ var columnLayout:IBeadLayout =
column.getBeadByType(IBeadLayout) as IBeadLayout;
+ if (columnLayout)
+ columnLayout.layout();
+ }
+
+ // Clear the flag after any queued scroll events from the
programmatic
+ // scrollTop changes above have been processed and suppressed.
+ setTimeout(function():void
+ {
+ if (_syncingDataGrid == myDataGrid)
+ _syncingDataGrid = null;
+ }, 0);
}
private function getListArea():Container
@@ -98,52 +128,24 @@ package org.apache.royale.jewel.beads.layouts
override protected function scrollHandler(e:Event):void
{
- // Check if we're being synced by another column's scroll handler
COMPILE::JS
{
if (_syncingDataGrid != null && _syncingDataGrid == (host as
IDataGridColumnList).datagrid)
{
- // Being synced - just update layout without syncing others
+ // Being synced from another column or from wheelHandler -
just
+ // update own layout without re-syncing siblings.
super.scrollHandler(e);
return;
}
}
- // Update own layout
+ // Non-wheel scroll path (keyboard, scrollbar drag, programmatic).
+ // wheelHandler covers the wheel path; this branch keeps the rest
in sync.
super.scrollHandler(e);
COMPILE::JS
{
- // Any scroll event on this column triggers sync to all others,
- // regardless of mouse position. This handles cases where the
browser
- // window regains focus without a mouseover event.
- var myDataGrid:IDataGrid = (host as
IDataGridColumnList).datagrid;
- _syncingDataGrid = myDataGrid;
-
- var listArea:Container = getListArea();
- var scrollTop:Number = host.element.scrollTop;
-
- for (var i:int = 0; i < listArea.numElements; i++)
- {
- var otherColumn:* = listArea.getElementAt(i);
- if (otherColumn != host)
- {
- otherColumn.element.scrollTop = scrollTop;
- // Immediately call layout() so all columns are
visually aligned
- // before the browser paints — without waiting for the
async scroll event.
- var otherLayout:IBeadLayout =
otherColumn.getBeadByType(IBeadLayout) as IBeadLayout;
- if (otherLayout)
- otherLayout.layout();
- }
- }
-
- // Clear the flag after any queued scroll events from the
programmatic
- // scrollTop changes above have been processed and suppressed.
- setTimeout(function():void
- {
- if (_syncingDataGrid == myDataGrid)
- _syncingDataGrid = null;
- }, 0);
+ syncSiblings(host.element.scrollTop);
}
}
}