package ie.dcu.swt; import org.eclipse.swt.*; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.layout.*; import org.eclipse.swt.widgets.*; /** * Class for displaying a pop-up control in its own shell. The control behaves * similar to a pop-up menu, but is a composite so can contain arbitrary * controls. * *
* Sample Usage: * *
* PopupComposite popup = new PopupComposite(getShell()); * Text text = new Text(popup, SWT.BORDER); * popup.pack(); * popup.show(shell.toDisplay(new Point(10, 10))); ** * @author Kevin McGuinness */ public class PopupComposite extends Composite { /** * Style of the shell that will house the composite */ private static final int SHELL_STYLE = SWT.MODELESS | SWT.NO_TRIM | SWT.ON_TOP | SWT.BORDER; /** * Shell that will house the composite */ private final Shell shell; /** * Create a Pop-up composite with the default {@link SWT#BORDER} style. * * @param parent * The parent shell. */ public PopupComposite(Shell parent) { this(parent, SWT.BORDER); } /** * Create a Pop-up composite. The default layout is a fill layout. * * @param parent * The parent shell. * @param style * The composite style. */ public PopupComposite(Shell parent, int style) { super(new Shell(parent, SHELL_STYLE), style); shell = getShell(); shell.setLayout(new FillLayout());; shell.addShellListener(new ActivationListener()); setLayout(createLayout()); } /** * Display the composite below the given tool item. The item will be sized * such that it's width is at least the width of the given tool item. * * @param bar * The tool bar. * @param item * The tool item. */ public void showBelow(ToolBar bar, ToolItem item) { Rectangle r = item.getBounds(); Point p = bar.toDisplay(new Point(r.x, r.y + r.height)); setSize(computeSize(item)); show(p); } /** * Display the composite in its own shell at the given point. * * @param pt * The point where the pop-up should appear. */ public void show(Point pt) { // Match shell and component sizes shell.setSize(getSize()); if (pt != null) { shell.setLocation(pt); } shell.open(); } /** * Display the pop-up where it was last displayed. */ public void show() { show(null); } /** * Hide the pop-up. */ public void hide() { shell.setVisible(false); } /** * Returns
true
if the shell is currently activated.
*
* @return true
if the shell is visible.
*/
public boolean isDisplayed() {
return shell.isVisible();
}
/**
* Creates the default layout for the composite.
*
* @return the default layout.
*/
private FillLayout createLayout() {
FillLayout layout = new FillLayout();
layout.marginWidth = 5;
layout.marginHeight = 5;
return layout;
}
/**
* Computes the optimal size with respect to the given tool item.
*
* @param item
* The tool item.
* @return The optimal size.
*/
private Point computeSize(ToolItem item) {
Point s2 = computeSize(item.getWidth(), SWT.DEFAULT);
Point s1 = computeSize(SWT.DEFAULT, SWT.DEFAULT);
return s1.x > s2.x ? s1 : s2;
}
/**
* Class that handles shell appearance and disappearance appropriately.
* Specifically, it hides the shell when it becomes de-activated (for example,
* when the user clicks on the parent shell). Also, there is a minimum delay
* which is enforced between showing and hiding the pop-up, to prevent
* undesirable behavior such as hiding and immediately re-displaying the
* pop-up when the user selects a button responsible for showing the tool
* item.
*/
private final class ActivationListener extends ShellAdapter {
private static final int TIMEOUT = 500;
private long time = -1;
@Override
public void shellDeactivated(ShellEvent e) {
// Record time of event
time = (e.time & 0xFFFFFFFFL);
// Hide
hide();
}
@Override
public void shellActivated(ShellEvent e) {
if (time > 0) {
// Find elapsed time
long elapsed = ((e.time & 0xFFFFFFFFL) - time);
// If less than a timeout, don't activate
if (elapsed < TIMEOUT) {
hide();
// Next activation event is fine
time = -1;
}
}
}
};
}