/* ****************************************************************************** * Copyright (c) 2006-2012 XMind Ltd. and others. * * This file is a part of XMind 3. XMind releases 3 and * above are dual-licensed under the Eclipse Public License (EPL), * which is available at http://www.eclipse.org/legal/epl-v10.html * and the GNU Lesser General Public License (LGPL), * which is available at http://www.gnu.org/licenses/lgpl.html * See http://www.xmind.net/license.html for details. * * Contributors: * XMind Ltd. - initial API and implementation *******************************************************************************/ package org.xmind.ui.viewers; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.util.SafeRunnable; import org.eclipse.jface.viewers.IOpenListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.OpenEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Layout; import org.eclipse.swt.widgets.Listener; /** * @author Frank Shaka */ public class ImageButton extends Viewer { private final class ImageLayout extends Layout { protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) { Image img = getNormalImage(); if (img == null) return new Point(1, 1); Rectangle bounds = img.getBounds(); return new Point(bounds.width, bounds.height); } protected void layout(Composite composite, boolean flushCache) { } } private final class EventHandler implements Listener { public void handleEvent(Event event) { switch (event.type) { case SWT.Paint: handlePaint(event); break; case SWT.Dispose: handleDispose(event); break; case SWT.MouseDown: handleMouseDown(event); break; case SWT.MouseUp: handleMouseUp(event); break; case SWT.MouseEnter: handleMouseEnter(event); break; case SWT.MouseExit: handleMouseExit(event); break; case SWT.MouseMove: handleMouseMove(event); break; } } } private Object input = null; private ImageDescriptor normalImageDescriptor = null; private ImageDescriptor pressedImageDescriptor = null; private ImageDescriptor disabledImageDescriptor = null; private ImageDescriptor hoveredImageDescriptor = null; private Image normalImage = null; private Image pressedImage = null; private Image disabledImage = null; private Image hoveredImage = null; private Canvas canvas; private boolean pressed = false; private boolean hovered = false; // private boolean enabled = true; private Point sourcePos = null; private List<IOpenListener> openListeners = null; /** * TODO complete 'check' style feature later */ private boolean check = false; private boolean filled = false; public ImageButton(Composite parent, int style) { canvas = new Canvas(parent, checkStyle(style) | SWT.DOUBLE_BUFFERED) { @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); refresh(); } }; configureControl(parent, canvas); hookControl(canvas); } private int checkStyle(int style) { check = (style & SWT.CHECK) != 0; filled = (style & SWT.FILL) != 0; int mask = SWT.PUSH | SWT.RADIO | SWT.CHECK | SWT.CASCADE | SWT.FILL; style &= ~mask; return style; } protected void configureControl(Composite parent, Control control) { control.setBackground(parent.getBackground()); ((Composite) control).setLayout(new ImageLayout()); } protected void hookControl(Control control) { Listener eventHandler = new EventHandler(); control.addListener(SWT.Paint, eventHandler); control.addListener(SWT.Dispose, eventHandler); control.addListener(SWT.MouseDown, eventHandler); control.addListener(SWT.MouseUp, eventHandler); control.addListener(SWT.MouseEnter, eventHandler); control.addListener(SWT.MouseExit, eventHandler); control.addListener(SWT.MouseMove, eventHandler); } protected void handlePaint(Event event) { Image img = null; if (!isEnabled()) img = getDisabledImage(); if (img == null) { if (hovered) img = getHoveredImage(); if (img == null) { if (pressed) img = getPressedImage(); if (img == null) img = getNormalImage(); if (img == null) img = getDisabledImage(); } } if (img != null) { if (filled) { Rectangle r1 = img.getBounds(); Rectangle r2 = canvas.getBounds(); event.gc.drawImage(img, r1.x, r1.y, r1.width, r1.height, 0, 0, r2.width, r2.height); } else { event.gc.drawImage(img, 0, 0); } } } protected void handleDispose(Event event) { dispose(); } protected void handleMouseDown(Event event) { if (isEnabled()) { if (event.button == 1) { pressed = true; sourcePos = new Point(event.x, event.y); refresh(); } } } protected void handleMouseUp(Event event) { if (isEnabled()) { OpenEvent oe = null; if (pressed) { oe = new OpenEvent(this, getSelection()); } pressed = false; sourcePos = null; refresh(); if (oe != null) { asyncFireOpen(oe); } } } protected void handleMouseEnter(Event event) { if (isEnabled()) { if (event.button == 1) { pressed = true; refresh(); } else { hovered = true; refresh(); } } } protected void handleMouseExit(Event event) { if (isEnabled()) { if (event.button == 1) { pressed = false; refresh(); } else { hovered = false; refresh(); } } } protected void handleMouseMove(Event event) { if (isEnabled() && sourcePos != null) { int x = event.x; int y = event.y; boolean prevInside = containsPoint(sourcePos); boolean currInside = containsPoint(x, y); if (prevInside && !currInside) { handleMouseExit(event); } else if (!prevInside && currInside) { handleMouseEnter(event); } sourcePos.x = x; sourcePos.y = y; } } protected boolean isEnabled() { return canvas != null && !canvas.isDisposed() && canvas.isEnabled(); } private boolean containsPoint(Point p) { return getBounds().contains(p); } private boolean containsPoint(int x, int y) { return getBounds().contains(x, y); } private Rectangle getBounds() { Rectangle bounds = canvas.getBounds(); bounds.x = 0; bounds.y = 0; return bounds; } public Control getControl() { return canvas; } public ImageDescriptor getNormalImageDescriptor() { return normalImageDescriptor; } public ImageDescriptor getPressedImageDescriptor() { return pressedImageDescriptor; } public ImageDescriptor getDisabledImageDescriptor() { return disabledImageDescriptor; } public ImageDescriptor getHoveredImageDescriptor() { return hoveredImageDescriptor; } public void setNormalImageDescriptor(ImageDescriptor normalImageDescriptor) { if (normalImageDescriptor == this.normalImageDescriptor) return; if (normalImage != null) { normalImage.dispose(); normalImage = null; } this.normalImageDescriptor = normalImageDescriptor; refresh(); } public void setPressedImageDescriptor(ImageDescriptor pressedImageDescriptor) { if (pressedImageDescriptor == this.pressedImageDescriptor) return; if (pressedImage != null) { pressedImage.dispose(); pressedImage = null; } this.pressedImageDescriptor = pressedImageDescriptor; refresh(); } public void setDisabledImageDescriptor( ImageDescriptor disabledImageDescriptor) { if (disabledImageDescriptor == this.disabledImageDescriptor) return; if (disabledImage != null) { disabledImage.dispose(); disabledImage = null; } this.disabledImageDescriptor = disabledImageDescriptor; refresh(); } public void setHoveredImageDescriptor(ImageDescriptor hoveredImageDescriptor) { if (hoveredImageDescriptor == this.hoveredImageDescriptor) return; if (hoveredImage != null) { hoveredImage.dispose(); hoveredImage = null; } this.hoveredImageDescriptor = hoveredImageDescriptor; refresh(); } public void refresh() { if (!canvas.isDisposed()) canvas.redraw(); } protected Image getNormalImage() { if (normalImage == null) { if (normalImageDescriptor != null) { normalImage = normalImageDescriptor.createImage(false); } } return normalImage; } protected Image getPressedImage() { if (pressedImage == null) { if (pressedImageDescriptor != null) { pressedImage = pressedImageDescriptor.createImage(false); } } return pressedImage; } protected Image getDisabledImage() { if (disabledImage == null) { if (disabledImageDescriptor != null) { disabledImage = disabledImageDescriptor.createImage(false); } } return disabledImage; } protected Image getHoveredImage() { if (hoveredImage == null) { if (hoveredImageDescriptor != null) { hoveredImage = hoveredImageDescriptor.createImage(false); } } return hoveredImage; } public void addOpenListener(IOpenListener listener) { if (openListeners == null) { openListeners = new ArrayList<IOpenListener>(); } openListeners.add(listener); } public void removeOpenListener(IOpenListener listener) { if (openListeners == null) return; openListeners.remove(listener); } private void asyncFireOpen(final OpenEvent event) { if (canvas.isDisposed()) return; final Display display = canvas.getDisplay(); if (display == null || display.isDisposed()) return; display.asyncExec(new Runnable() { public void run() { if (canvas.isDisposed() || display.isDisposed()) return; fireOpen(event); } }); } protected void fireOpen() { fireOpen(new OpenEvent(this, getSelection())); } protected void fireOpen(final OpenEvent event) { if (openListeners == null || event == null) return; Object[] listeners = openListeners.toArray(); for (int i = 0; i < listeners.length; i++) { final IOpenListener listener = (IOpenListener) listeners[i]; SafeRunner.run(new SafeRunnable() { public void run() throws Exception { listener.open(event); } }); } } protected void dispose() { if (normalImage != null) { normalImage.dispose(); normalImage = null; } if (pressedImage != null) { pressedImage.dispose(); pressedImage = null; } if (disabledImage != null) { disabledImage.dispose(); disabledImage = null; } if (hoveredImage != null) { hoveredImage.dispose(); hoveredImage = null; } } public boolean isCheck() { return check; } public Object getInput() { return input; } public ISelection getSelection() { if (pressed) { if (getInput() != null) return new StructuredSelection(getInput()); return new StructuredSelection(this); } return StructuredSelection.EMPTY; } public void setInput(Object input) { this.input = input; } public void setSelection(ISelection selection, boolean reveal) { if (selection == null) return; boolean newState = !selection.isEmpty(); if (newState == this.pressed) return; this.pressed = newState; refresh(); } }