// params = text, image, action, text, image, action, ... // or TextImageAction... // or a list of above stuff static A makeNiceButtons_usingStack(A stack, O... params) { params = flattenArray2(params); for (int i = 0; i < l(params); ) { TextImageAction tia = null; if (params[i] instanceof TextImageAction) { tia = (TextImageAction) params[i]; i++; } else { tia = TextImageAction( str(get(params, i)), str(get(params, i+1)), get(params, i+2)); i += 3; } final TextImageAction _tia = tia; O action = tia.action; fS buttonDesc = action == null ? "actionless button " + sfu(_tia) : "button " + sfu(cloneWithoutField(_tia, 'action)) + " with action " + trim(simpleSpaces(newLinesToSpaces(shorten(str(tia.action), 40)))); action = r { appendToLocalMechLog("User actions", "User clicked on " + buttonDesc); callF(_tia.action); }; JButton b = jImageAndTextButton(tia.imageID, tia.text, action); if (nempty(tia.toolTip)) setToolTip(b, tia.toolTip); componentPopupMenu(b, tia.popupMenuMaker); resizeImageButtonToMax(b, niceButtons_maxImageSize()); setVerticalTextPosition(JButton.TOP, setFontSize(15, makeBold(b))); setVerticalAlignment(JButton.TOP, b); setMargin(10, b); onMouseEnter(b, r { appendToLocalMechLog("Mouse hovers", "Mouse hovered over " + buttonDesc) }); onMouseExit(b, r { appendToLocalMechLog("Mouse hovers", "Mouse no longer hovers over " + buttonDesc) }); metaSet(b, TextImageAction.class, tia); stack.addComponent(b); } ret stack; } static DynamicHStack makeNiceButtons(O... params) { ret makeNiceButtons_usingStack((DynamicHStack) dynamicHStack().spacing(20), params); }