!7 cm CurrentAction { transient JPanel stack; transient new RestartableCountdown deleteIfUnused; start { startCountdown(); if (dm_getBounds() == null) { int w = getWidth(dm_desktopPane()), h = getHeight(dm_desktopPane()); dm_setBounds(this, w-300, h-200, 300, 200); } } visualize { ret withRightMargin(stack = dynamicVStack2()); } // start countdown to delete module if unused void startCountdown { deleteIfUnused.start(60.0, rEnter deleteIfUnused); } // API interface AnAction extends AutoCloseable { void setText(S text); } // Note: cancelMe will be called in GUI thread AutoCloseable showAction(S action, Runnable cancelMe) { deleteIfUnused.stop(); final JLabel lbl = jlabel(action); final JComponent c = centerAndEast(lbl, jbutton("Cancel", cancelMe)); addAndValidate(stack, c); ret new AnAction { public void close() enter { removeAndValidate(c); //print("Remaining components: " + componentCount(stack)); if (emptyContainer(stack)) dm_hideModule(); startCountdown(); } public void setText(S text) { main.setText(lbl, text); } }; } void deleteIfUnused { // TODO: minimal race condition if (countComponents(stack) == 0) dm_deleteModule(); } }