/*******************************************************************************
* Copyright (c) 2010 The Eclipse Foundation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* The Eclipse Foundation - initial API and implementation
*******************************************************************************/
package org.eclipse.epp.internal.mpc.ui.wizards;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
public class DropDownButton {
private boolean showArrow;
private Rectangle arrowBounds;
private String padding = null;
private final Button button;
private List<DropDownSelectionListenerWrapper> selectionListenerWrappers;
private final PaintListener paintListener = new PaintListener() {
Color shadowColor;
Color black;
public void paintControl(PaintEvent e) {
if (shadowColor == null) {
shadowColor = e.display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
}
if (black == null) {
black = e.display.getSystemColor(SWT.COLOR_BLACK);
}
Rectangle buttonBounds = button.getBounds();
int arrowAreaWidth = 20;
arrowBounds = new Rectangle(e.x + buttonBounds.width - arrowAreaWidth, e.y, arrowAreaWidth,
buttonBounds.height);
GC gc = e.gc;
Color oldForeground = gc.getForeground();
Color oldBackground = gc.getBackground();
try {
int inset = 3;
int lineX = arrowBounds.x;
gc.setLineWidth(1);
gc.setForeground(shadowColor);
gc.setBackground(shadowColor);
gc.drawLine(lineX, arrowBounds.y + inset - 1, lineX, e.y + buttonBounds.height - inset);
gc.setForeground(black);
gc.setBackground(black);
int arrowWidth = 7;
int arrowHeight = 4;
int arrowX = lineX + (arrowAreaWidth - arrowWidth) / 2;
int arrowY = arrowBounds.height / 2 - arrowHeight / 2 + 1;
gc.fillPolygon(new int[] { arrowX, arrowY, arrowX + arrowWidth, arrowY, arrowX + arrowWidth / 2,
arrowY + arrowHeight });
} finally {
gc.setForeground(oldForeground);
gc.setBackground(oldBackground);
}
}
};
public DropDownButton(Composite parent, int style) {
button = new Button(parent, SWT.PUSH);
}
private boolean isShowMenu(int x, int y) {
return showArrow && arrowBounds != null && arrowBounds.contains(x, y);
}
public void setShowArrow(boolean showArrow) {
this.showArrow = showArrow;
updatePadding();
if (showArrow) {
button.addPaintListener(paintListener);
} else {
button.removePaintListener(paintListener);
}
}
public boolean isShowArrow() {
return showArrow;
}
public void setText(String string) {
button.setText(pad(string));
}
private String pad(String string) {
return string == null ? null : padding == null ? string : string + padding;
}
private String unpad(String string) {
return string == null ? null : padding == null || !string.endsWith(padding) ? string : string.substring(0,
string.length() - padding.length());
}
public String getText() {
String text = button.getText();
return unpad(text);
}
public void setFont(Font font) {
button.setFont(font);
updatePadding();
}
private void updatePadding() {
String text = getText();
String currentPadding = padding;
String newPadding = showArrow ? calculatePadding(22) : null;
if ((newPadding == null && currentPadding != null)
|| (newPadding != null && !newPadding.equals(currentPadding))) {
this.padding = newPadding;
setText(text);
}
}
private String calculatePadding(int width) {
int padSpaceWidth = calculateSpaceWidth();
int count = (2 * width + padSpaceWidth - 1) / (2 * padSpaceWidth); //round up on 0.5
switch (count) {
case 0:
return null;
case 1:
return " "; //$NON-NLS-1$
case 2:
return " "; //$NON-NLS-1$
case 3:
return " "; //$NON-NLS-1$
case 4:
return " "; //$NON-NLS-1$
case 5:
return " "; //$NON-NLS-1$
case 6:
return " "; //$NON-NLS-1$
case 7:
return " "; //$NON-NLS-1$
case 8:
return " "; //$NON-NLS-1$
case 9:
return " "; //$NON-NLS-1$
case 10:
return " "; //$NON-NLS-1$
default:
//fall-through
}
StringBuilder bldr = new StringBuilder(" "); //$NON-NLS-1$
for (int i = 10; i < count; i++) {
bldr.append(' ');
}
return bldr.toString();
}
private int calculateSpaceWidth() {
GC gc = new GC(button);
try {
gc.setFont(button.getFont());
return gc.getAdvanceWidth(' ');
} finally {
gc.dispose();
}
}
public Button getButton() {
return button;
}
public void dispose() {
button.dispose();
}
public Image getImage() {
return button.getImage();
}
public void setImage(Image image) {
button.setImage(image);
}
public Shell getShell() {
return button.getShell();
}
public boolean isEnabled() {
return button.isEnabled();
}
public boolean isVisible() {
return button.isVisible();
}
public void addSelectionListener(final SelectionListener listener) {
DropDownSelectionListenerWrapper wrapper = findWrapper(listener);
if (wrapper == null) {
wrapper = new DropDownSelectionListenerWrapper(listener);
selectionListenerWrappers.add(wrapper);
}
button.addSelectionListener(wrapper);
button.addMouseListener(wrapper);
}
private DropDownSelectionListenerWrapper findWrapper(final SelectionListener listener) {
DropDownSelectionListenerWrapper wrapper = null;
if (selectionListenerWrappers == null) {
selectionListenerWrappers = new ArrayList<DropDownButton.DropDownSelectionListenerWrapper>();
}
for (DropDownSelectionListenerWrapper existingWrapper : selectionListenerWrappers) {
if (existingWrapper.getDelegate() == listener) {
wrapper = existingWrapper;
break;
}
}
return wrapper;
}
public void removeSelectionListener(SelectionListener listener) {
DropDownSelectionListenerWrapper wrapper = findWrapper(listener);
if (wrapper != null) {
button.removeSelectionListener(wrapper);
}
button.removeSelectionListener(listener);
}
private final class DropDownSelectionListenerWrapper extends MouseAdapter implements SelectionListener {
private final SelectionListener delegate;
private boolean isShowMenu;
public DropDownSelectionListenerWrapper(SelectionListener delegate) {
this.delegate = delegate;
}
public SelectionListener getDelegate() {
return delegate;
}
public void widgetSelected(SelectionEvent e) {
setArrowDetail(e);
delegate.widgetSelected(e);
}
public void widgetDefaultSelected(SelectionEvent e) {
setArrowDetail(e);
delegate.widgetDefaultSelected(e);
}
private void setArrowDetail(SelectionEvent e) {
e.detail = isShowMenu ? SWT.ARROW : 0;
isShowMenu = false;
}
@Override
public void mouseDown(MouseEvent e) {
isShowMenu = isShowMenu(e.x, e.y);
}
}
}