sclass ButtonIconLoader { DynamicStack stack; Set loadedButtons = weakIdentityHashSet(); DeQ loadQ; JScrollPane scrollPane; ChangeListener changeListener; *(final DynamicStack *stack) { bindToComponent(stack, r { scrollPane = enclosingScrollPane(stack); changeListener = scrollPaneOnScroll(scrollPane, r { update() }); update(); }, r { if (scrollPane != null) { scrollPane.getViewport().removeChangeListener(changeListener); scrollPane = null; changeListener = null; } }); } void update() swing { for (final JButton b : reversed((L) (L) stackElementsShowing(stack))) { if (add_byContains(loadedButtons, b)) pcall { TextImageAction tia = cast metaGet(TextImageAction.class, b); fS imageID = (S) mapGet(tia.more, 'lazyImageID); if (empty(imageID)) continue; qAdd(r { setButtonImage(b, scaleBufferedImageToMaxWidthOrHeight(loadImage2(imageID), niceButtons_maxImageSize()); }); } } } void qAdd(Runnable r) { if (loadQ == null) loadQ = startDeQ(); loadQ.addFirst(r); } }