Bug #11294
Widget is overlapped by another widget after the parent frame is made visible
100%
History
#1 Updated by Delia Mitric 4 months ago
This testcase:
DEF VAR fill1 AS CHARACTER NO-UNDO.
DEF BUTTON hidden_btn SIZE 4 BY .81.
DEFINE FRAME fmain
fill1 AT ROW 2.71 COL 11.8 COLON-ALIGNED
VIEW-AS FILL-IN
SIZE 13.2 BY 1
hidden_btn AT ROW 2.86 COL 22.6 NO-TAB-STOP
WITH 1 DOWN KEEP-TAB-ORDER
AT COL 1 ROW 1 SCROLLABLE SIZE 50 BY 10.
hidden_btn:HIDDEN = TRUE.
fill1:HIDDEN = TRUE.
fill1:VISIBLE = TRUE.
FRAME fmain:HIDDEN = FALSE.
ENABLE ALL WITH FRAME fmain.
WAIT-FOR CLOSE OF CURRENT-WINDOW.
In OE:
--- In FWD: 
#2 Updated by Delia Mitric 4 months ago
- % Done changed from 0 to 100
- Status changed from New to WIP
- reviewer Hynek Cihlar added
- move the hidden widgets (not frames) on the top of the parent frame when the frame is set to visible (even if it is still visible)
Committed the changes to 11294a branch rev. 16469
Hynek, please review. Thanks!
#4 Updated by Hynek Cihlar 4 months ago
- Status changed from Review to WIP
- % Done changed from 100 to 90
With the changes makeFrameVisible duplicates the logic already in setChildrenVisible. Can these be deduplicated?
Also makeFrameVisible uses widgets for the z-order logic, but should fieldGroup.getWidgets() be used instead? See setChildrenVisible.
#5 Updated by Delia Mitric 4 months ago
- Status changed from WIP to Review
- % Done changed from 90 to 100
Hynek Cihlar wrote:
With the changes
makeFrameVisibleduplicates the logic already insetChildrenVisible. Can these be deduplicated?
I've added a method findHiddenWidgets that returns the list of the hidden widget of the frame to use it in setChildrenVisible and makeFrameVisible in moveToBatchWorker call to "deduplicate" that part of the code, but I think we should let the moveToBatchWorker call at the end of the methods to ensure the moving is made correctly.
Also
makeFrameVisibleuseswidgetsfor the z-order logic, but shouldfieldGroup.getWidgets()be used instead? SeesetChildrenVisible.
Done. findHiddenWidgets method uses fieldGroup.getWidgets().
Please review rev. 16470.
Thank you!
#6 Updated by Hynek Cihlar 3 months ago
- Status changed from Review to WIP
- % Done changed from 100 to 90
- [MAJOR] functional
GenericFrame.setChildrenVisible:findHiddenWidgetsis called unconditionally regardless of thevalueparameter. The old code only populatedmoveToTopWidgetsinside theif (isHidden[i++] && value)block, so hidden widgets were collected only when making children visible. Now when hiding children (value false),moveToBatchWorkerwill still unnecessarily move hidden widgets to the top of z-order. Guard the call withvalue trueor pass an empty list when hiding. - [MAJOR] style
GenericFrame.makeFrameVisible: ThefindHiddenWidgetscall at line 11700 exceeds the 110-character line length limit (116 characters). It should be wrapped, e.g.:List<GenericWidget<?>> moveToTopWidgets = findHiddenWidgets((List<GenericWidget<?>>) fieldGroup.getWidgets()); - [MINOR] performance
GenericFrame.setChildrenVisible: Redundant iteration over the widget list. TheisHidden[]array already caches each widget's_isHidden()state from a prior loop, butfindHiddenWidgetsre-queries_isHidden()on every widget. This adds a third pass over the widget list where the old code only had two. Consider reusing theisHidden[]array to build the move-to-top list. - [MINOR] performance
GenericFrame.makeFrameVisible:findHiddenWidgetscalls_isHidden()on every widget, and the subsequent visibility loop also calls_isHidden()on each widget again. Since_isHidden()withflush=truetriggersflushEnqueuedWidgetAttrs()on every invocation, this doubles the flush cost. Consider caching the hidden state.
#7 Updated by Delia Mitric 3 months ago
- Status changed from WIP to Review
- % Done changed from 90 to 100
Hynek Cihlar wrote:
- [MAJOR] functional
GenericFrame.setChildrenVisible:findHiddenWidgetsis called unconditionally regardless of thevalueparameter. The old code only populatedmoveToTopWidgetsinside theif (isHidden[i++] && value)block, so hidden widgets were collected only when making children visible. Now when hiding children (value false),moveToBatchWorkerwill still unnecessarily move hidden widgets to the top of z-order. Guard the call withvalue trueor pass an empty list when hiding.- [MAJOR] style
GenericFrame.makeFrameVisible: ThefindHiddenWidgetscall at line 11700 exceeds the 110-character line length limit (116 characters). It should be wrapped, e.g.:
[...]- [MINOR] performance
GenericFrame.setChildrenVisible: Redundant iteration over the widget list. TheisHidden[]array already caches each widget's_isHidden()state from a prior loop, butfindHiddenWidgetsre-queries_isHidden()on every widget. This adds a third pass over the widget list where the old code only had two. Consider reusing theisHidden[]array to build the move-to-top list.- [MINOR] performance
GenericFrame.makeFrameVisible:findHiddenWidgetscalls_isHidden()on every widget, and the subsequent visibility loop also calls_isHidden()on each widget again. Since_isHidden()withflush=truetriggersflushEnqueuedWidgetAttrs()on every invocation, this doubles the flush cost. Consider caching the hidden state.
Fixed all of these and committed the changes to 11294a branch rev. 16471 .
Hynek, please review. Thanks!
#8 Updated by Hynek Cihlar 3 months ago
- Status changed from Review to WIP
- % Done changed from 100 to 90
Code review 11294a revisions 16468..16471
- [MAJOR] functional
GenericFrame.makeFrameVisible: ThehiddenIdscache is populated by iteratingthis.widgets[], butfindHiddenWidgetsis later called withfieldGroup.getWidgets(). The two collections are not guaranteed to hold the same widget set -GenericFrame.addDynamicWidgetcan skip thewidgets[]array on a name hit-test (earlyreturn), whileFieldGroup.addWidgetunconditionally receives the widget viaGenericWidget.setFrame. Widgets present only infieldGroup.getWidgets()returnnullfrom the map and are silently treated as "not hidden" by the!= null ? ... : falseguard, so such hidden widgets will never be moved to top - reintroducing the exact z-order bug the patch is meant to fix. Please check whether this can be an issue when the two lists are not identical. - [MAJOR] style
GenericFrame.findHiddenWidgets: The method signature exceeds the project's 110-character line-length limit; wrap the parameter list onto additional lines. - [MINOR] performance
GenericFrame.findHiddenWidgets:hiddenIds.get(widget.getId())is called twice per widget (once for null check, once for the value). Store the result once in a localBooleanor usehiddenIds.getOrDefault(widget.getId(), false). - [MINOR] performance
GenericFrame.setChildrenVisible: The refactor replaced a primitiveboolean[](O(1) indexed access, no boxing) withHashMap<Integer, Boolean>, incurringInteger/Booleanautoboxing, hash computation, andNodeallocation per entry. Since both loops iterate the samewidgetslist in the same order, the original parallelboolean[]suffices and should be restored; onlymakeFrameVisiblegenuinely needs the id-keyed map because its two passes iterate different lists. - [MINOR] style
GenericFrame.setChildrenVisible: Whenvalue == falsethe expressionvalue ? findHiddenWidgets(...) : new ArrayList<>()still allocates a throwaway empty list that is immediately discarded bymoveToBatchWorker(which short-circuits on empty input). Guard just thefindHiddenWidgets/moveToBatchWorkerpair withif (value), or useCollections.emptyList(), to avoid the allocation and make the intent explicit.
#9 Updated by Delia Mitric 3 months ago
- % Done changed from 90 to 100
- Status changed from WIP to Review
Committed the new changes to 11294a rev. 16531.
I've tried to de-duplicate the logic of moving the widget to the top as you said in #11294-4, to use the fieldGroup widget list to be consistent with the client side (as in setChildrenVisible method), to introduce a cache for the hidden state in GenericFrame.makeFrameVisible method and keep the one from GenericFrame.setChildrenVisible as it is.
Hynek, please review.
#10 Updated by Hynek Cihlar 3 months ago
- Status changed from Review to WIP
- % Done changed from 100 to 90
Code review 11294a revisions 16527..16531
- [MAJOR] performance
GenericFrame.makeFrameVisible:hiddenIds.getOrDefault(widget.getId(), widget._isHidden())evaluates the default argument unconditionally (Java is strict), so_isHidden()runs for everyfgWidgetsentry even on cache hits. Since_isHidden()routes throughgetAttr(..., true)which performsflushEnqueuedWidgetAttrs(), this defeats the very cache the diff introduces. UsecontainsKey()/get()(orcomputeIfAbsent) so_isHidden()only runs on genuine cache misses.
- [MAJOR] style
GenericFrame.moveHiddenWidgets: Javadoc declares@param hiddenIdsbut the actual parameter is namedhidden. Update the Javadoc tag to@param hidden(or rename the parameter) so they match.
- [MAJOR] style
GenericFrame.setChildrenVisible: The new callmoveHiddenWidgets(widgets, isHidden);is indented with 8 spaces. The enclosingif (value)block opens at 6 spaces, so its body should be at 9 spaces per the project's 3-space indent convention. Re-indent the block body and closing brace accordingly.
- [MINOR] performance
GenericFrame.makeFrameVisible: After buildinghidden[]via one pass overfgWidgets,moveHiddenWidgetsiteratesfgWidgetsa second time to filter intohiddenWidgets. The two passes can be fused into one at this call site (buildhiddenWidgetsdirectly during the cache-resolution loop), saving a full traversal and theboolean[]bridge allocation. ThemoveHiddenWidgetshelper can still be kept forsetChildrenVisible, which genuinely needs the cache captured before its mutating loop.
- [MINOR] performance
GenericFrame.setChildrenVisible: The move-to-top collection is now computed in a second pass insidemoveHiddenWidgets. Previously it was produced as a side effect of the single pass that flipped visibility. Restoring the single-pass accumulation insetChildrenVisible(while still reusing the helper frommakeFrameVisible) avoids N extra iterations and N redundantinstanceof FrameWidgetchecks on every frame un-hide.
#11 Updated by Razvan-Nicolae Chichirau 5 days ago
- Assignee changed from Delia Mitric to Razvan-Nicolae Chichirau
- Status changed from WIP to Review
- % Done changed from 90 to 100
The changes from 11294a were overcomplicating things. I rebased the branch and switched to a cleaner approach.
Hynek: Please do a review for 11294a.