| /******************************************************************************* |
| * Copyright (c) 2011 Laurent CARON |
| * 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: |
| * Laurent CARON (laurent.caron at gmail dot com) - initial API and implementation |
| *******************************************************************************/ |
| package org.mihalis.opal.flatButton; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.SWTException; |
| 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.GC; |
| 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.Event; |
| import org.eclipse.swt.widgets.Listener; |
| import org.mihalis.opal.utils.SWTGraphicUtil; |
| |
| /** |
| * Instances of this class represent a flat button. |
| * <dl> |
| * <dt><b>Styles:</b></dt> |
| * <dd>UP, DOWN, LEFT, RIGHT, CENTER</dd> |
| * <dt><b>Events:</b></dt> |
| * <dd>Selection</dd> |
| * </dl> |
| * <p> |
| * Note: Only one of the styles LEFT, RIGHT, and CENTER may be specified. |
| * </p> |
| * |
| */ |
| public class FlatButton extends Canvas { |
| |
| /** The Constant DEFAULT_PADDING. */ |
| private static final int DEFAULT_PADDING = 5; |
| |
| /** The image. */ |
| private Image image; |
| |
| /** The text. */ |
| private String text; |
| |
| /** The selection. */ |
| private boolean selection; |
| |
| /** The alignment. */ |
| private int alignment; |
| |
| /** The listeners. */ |
| private final List<SelectionListener> listeners; |
| |
| /** The mouse in. */ |
| private boolean mouseIn; |
| |
| /** The background color. */ |
| private Color backgroundColor; |
| |
| /** The selected color. */ |
| private Color selectedColor; |
| |
| /** The selected text color. */ |
| private Color selectedTextColor; |
| |
| /** The mouse over color. */ |
| private Color mouseOverColor; |
| |
| /** |
| * Constructs a new instance of this class given its parent and a style |
| * value describing its behavior and appearance. |
| * <p> |
| * The style value is either one of the style constants defined in class |
| * <code>SWT</code> which is applicable to instances of this class, or must |
| * be built by <em>bitwise OR</em>'ing together (that is, using the |
| * <code>int</code> "|" operator) two or more of those <code>SWT</code> |
| * style constants. The class description lists the style constants that are |
| * applicable to the class. Style bits are also inherited from superclasses. |
| * </p> |
| * |
| * @param parent a composite control which will be the parent of the new |
| * instance (cannot be null) |
| * @param style the style of control to construct |
| * @see SWT#DOWN |
| * @see SWT#LEFT |
| * @see SWT#RIGHT |
| * @see SWT#CENTER |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the parent</li> |
| * <li>ERROR_INVALID_SUBCLASS - if this class is not an |
| * allowed subclass</li> |
| * </ul> |
| */ |
| public FlatButton(final Composite parent, final int style) { |
| super(parent, style); |
| this.listeners = new ArrayList<SelectionListener>(); |
| buildAlignmentFromStyle(style); |
| addListeners(); |
| initializeDefaultColors(); |
| } |
| |
| /** |
| * Builds the alignment from style. |
| * |
| * @param style the style |
| */ |
| private void buildAlignmentFromStyle(final int style) { |
| if ((style & SWT.LEFT) == SWT.LEFT) { |
| this.alignment = SWT.LEFT; |
| } else if ((style & SWT.RIGHT) == SWT.RIGHT) { |
| this.alignment = SWT.RIGHT; |
| } else { |
| this.alignment = SWT.CENTER; |
| |
| } |
| } |
| |
| /** |
| * Adds the listeners. |
| */ |
| private void addListeners() { |
| addPaintListener(new PaintListener() { |
| @Override |
| public void paintControl(final PaintEvent e) { |
| FlatButton.this.paintControl(e); |
| } |
| }); |
| |
| addListener(SWT.MouseEnter, new Listener() { |
| @Override |
| public void handleEvent(final Event event) { |
| FlatButton.this.mouseIn = true; |
| redraw(); |
| } |
| }); |
| |
| addListener(SWT.MouseExit, new Listener() { |
| @Override |
| public void handleEvent(final Event event) { |
| FlatButton.this.mouseIn = false; |
| redraw(); |
| } |
| }); |
| |
| addListener(SWT.MouseUp, new Listener() { |
| @Override |
| public void handleEvent(final Event event) { |
| boolean doIt = true; |
| FlatButton.this.selection = !FlatButton.this.selection; |
| for (final SelectionListener listener : FlatButton.this.listeners) { |
| final SelectionEvent sEvent = new SelectionEvent(event); |
| listener.widgetSelected(sEvent); |
| doIt = doIt && sEvent.doit; |
| } |
| if (!doIt) { |
| FlatButton.this.selection = !FlatButton.this.selection; |
| } |
| } |
| |
| }); |
| } |
| |
| /** |
| * Initialize default colors. |
| */ |
| private void initializeDefaultColors() { |
| this.backgroundColor = getDisplay().getSystemColor(SWT.COLOR_WHITE); |
| this.selectedColor = new Color(getDisplay(), 0, 112, 192); |
| this.selectedTextColor = getDisplay().getSystemColor(SWT.COLOR_WHITE); |
| this.mouseOverColor = new Color(getDisplay(), 235, 234, 226); |
| |
| SWTGraphicUtil.addDisposer(this, this.selectedColor); |
| SWTGraphicUtil.addDisposer(this, this.mouseOverColor); |
| SWTGraphicUtil.addDisposer(this, this.image); |
| } |
| |
| /** |
| * Paint control. |
| * |
| * @param e the e |
| */ |
| private void paintControl(final PaintEvent e) { |
| final GC gc = e.gc; |
| drawBackground(gc); |
| if (this.image != null) { |
| drawImage(gc); |
| } |
| if (this.text != null) { |
| drawText(gc); |
| } |
| } |
| |
| /** |
| * Draw background. |
| * |
| * @param gc the gc |
| */ |
| private void drawBackground(final GC gc) { |
| Color color; |
| if (this.selection) { |
| color = this.selectedColor; |
| } else if (this.mouseIn) { |
| color = this.mouseOverColor; |
| } else { |
| color = this.backgroundColor; |
| } |
| gc.setBackground(color); |
| gc.fillRectangle(getClientArea()); |
| |
| } |
| |
| /** |
| * Draw image. |
| * |
| * @param gc the gc |
| */ |
| private void drawImage(final GC gc) { |
| final Rectangle rect = getClientArea(); |
| final Point imageSize = new Point(this.image.getBounds().width, this.image.getBounds().height); |
| |
| int x; |
| if (this.alignment == SWT.LEFT) { |
| x = DEFAULT_PADDING; |
| } else if (this.alignment == SWT.RIGHT) { |
| x = rect.width - imageSize.x - DEFAULT_PADDING; |
| } else { |
| x = (rect.width - imageSize.x) / 2; |
| } |
| gc.drawImage(this.image, x, DEFAULT_PADDING); |
| } |
| |
| /** |
| * Draw text. |
| * |
| * @param gc the gc |
| */ |
| private void drawText(final GC gc) { |
| final Rectangle rect = getClientArea(); |
| |
| if (this.selection) { |
| gc.setForeground(this.selectedTextColor); |
| } else { |
| gc.setForeground(getForeground()); |
| } |
| |
| gc.setFont(getFont()); |
| final Point textSize = gc.stringExtent(this.text); |
| int x, y; |
| |
| if (this.alignment == SWT.LEFT) { |
| x = DEFAULT_PADDING; |
| } else if (this.alignment == SWT.RIGHT) { |
| x = rect.width - textSize.x - DEFAULT_PADDING; |
| } else { |
| x = (rect.width - textSize.x) / 2; |
| } |
| if (this.image == null) { |
| y = DEFAULT_PADDING; |
| } else { |
| y = 2 * DEFAULT_PADDING + this.image.getBounds().height; |
| } |
| gc.drawString(this.text, x, y, true); |
| } |
| |
| /** |
| * Adds the listener to the collection of listeners who will be notified |
| * when the control is selected by the user, by sending it one of the |
| * messages defined in the <code>SelectionListener</code> interface. |
| * <p> |
| * <code>widgetSelected</code> is called when the control is selected by the |
| * user. <code>widgetDefaultSelected</code> is not called. |
| * </p> |
| * |
| * @param listener the listener which should be notified |
| * @see SelectionListener |
| * @see #removeSelectionListener |
| * @see SelectionEvent |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been |
| * disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public void addSelectionListener(final SelectionListener listener) { |
| checkWidget(); |
| this.listeners.add(listener); |
| } |
| |
| /** |
| * Compute size. |
| * |
| * @param wHint the w hint |
| * @param hHint the h hint |
| * @param changed the changed |
| * @return the point |
| * @see org.eclipse.swt.widgets.Composite#computeSize(int, int, boolean) |
| */ |
| @Override |
| public Point computeSize(final int wHint, final int hHint, final boolean changed) { |
| int width = 2 * DEFAULT_PADDING, height = 3 * DEFAULT_PADDING; |
| if (this.image != null) { |
| final Rectangle bounds = this.image.getBounds(); |
| width += bounds.width; |
| height += bounds.height; |
| } |
| |
| if (this.text != null) { |
| final GC gc = new GC(this); |
| final Point extent = gc.stringExtent(this.text); |
| gc.dispose(); |
| width = Math.max(width, extent.x + 2 * DEFAULT_PADDING); |
| height = height + extent.y; |
| } |
| |
| return new Point(Math.max(width, wHint), Math.max(height, hHint)); |
| } |
| |
| /** |
| * Returns a value which describes the position of the text in the receiver. |
| * The value will be one of <code>LEFT</code>, <code>RIGHT</code> or |
| * <code>CENTER</code>. |
| * |
| * @return the alignment |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been |
| * disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public int getAlignment() { |
| checkWidget(); |
| return this.alignment; |
| } |
| |
| /** |
| * Returns a value which describes the default background color. |
| * |
| * @return the default background color |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been |
| * disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public Color getBackgroundColor() { |
| checkWidget(); |
| return this.backgroundColor; |
| } |
| |
| /** |
| * Returns the receiver's image if it has one, or null if it does not. |
| * |
| * @return the receiver's image |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been |
| * disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public Image getImage() { |
| checkWidget(); |
| return this.image; |
| } |
| |
| /** |
| * Returns a value which describes the color when the mouse is over the |
| * button. |
| * |
| * @return the color when the mouse is over the button |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been |
| * disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public Color getMouseOverColor() { |
| checkWidget(); |
| return this.mouseOverColor; |
| } |
| |
| /** |
| * Returns a value which describes the color when the button is selected. |
| * |
| * @return the color when the button is selected |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been |
| * disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public Color getSelectedColor() { |
| checkWidget(); |
| return this.selectedColor; |
| } |
| |
| /** |
| * Returns a value which describes the color of the text when the button is |
| * selected. |
| * |
| * @return the color of the text when the button is selected |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been |
| * disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| |
| public Color getSelectedTextColor() { |
| return this.selectedTextColor; |
| } |
| |
| /** |
| * Returns <code>true</code> if the receiver is selected, and false |
| * otherwise. |
| * <p> |
| * |
| * @return the selection state |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been |
| * disposed</li> <li>ERROR_THREAD_INVALID_ACCESS - if not |
| * called from the thread that created the receiver</li> |
| * </ul> |
| */ |
| public boolean getSelection() { |
| checkWidget(); |
| return this.selection; |
| } |
| |
| /** |
| * Returns the receiver's text. |
| * |
| * @return the receiver's text |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public String getText() { |
| checkWidget(); |
| return this.text; |
| } |
| |
| /** |
| * Removes the listener from the collection of listeners who will be |
| * notified when the control is selected by the user. |
| * |
| * @param listener the listener which should no longer be notified |
| * @see SelectionListener |
| * @see #addSelectionListener |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been |
| * disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public void removeSelectionListener(final SelectionListener listener) { |
| checkWidget(); |
| this.listeners.remove(listener); |
| } |
| |
| /** |
| * Controls how text, images and arrows will be displayed in the receiver. |
| * The argument should be one of <code>LEFT</code>, <code>RIGHT</code> or |
| * <code>CENTER</code>. |
| * |
| * @param alignment the new alignment |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been |
| * disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public void setAlignment(final int alignment) { |
| checkWidget(); |
| if ((alignment & (SWT.LEFT | SWT.RIGHT | SWT.CENTER)) == 0) { |
| return; |
| } |
| this.alignment = alignment; |
| redraw(); |
| } |
| |
| /** |
| * Sets the receiver's background color to the color specified by the |
| * argument. |
| * |
| * @param backgroundColor the new background color |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_INVALID_ARGUMENT - if the argument has been |
| * disposed</li> |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been |
| * disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public void setBackgroundColor(final Color backgroundColor) { |
| checkWidget(); |
| this.backgroundColor = backgroundColor; |
| } |
| |
| /** |
| * Sets the receiver's image to the argument, which may be <code>null</code> |
| * indicating that no image should be displayed. |
| * <p> |
| * Note that a Button can display an image and text simultaneously on |
| * Windows (starting with XP), GTK+ and OSX. On other platforms, a Button |
| * that has an image and text set into it will display the image or text |
| * that was set most recently. |
| * </p> |
| * |
| * @param image the image to display on the receiver (may be |
| * <code>null</code>) |
| * |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li> |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public void setImage(final Image image) { |
| checkWidget(); |
| this.image = image; |
| redraw(); |
| } |
| |
| /** |
| * Sets the receiver's color when the mouse if over the button. |
| * |
| * @param mouseOverColor the new mouse over color |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_INVALID_ARGUMENT - if the argument has been |
| * disposed</li> |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been |
| * disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public void setMouseOverColor(final Color mouseOverColor) { |
| checkWidget(); |
| this.mouseOverColor = mouseOverColor; |
| } |
| |
| /** |
| * Sets the receiver's color when the button is selected. |
| * |
| * @param selectedColor the new selected color |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_INVALID_ARGUMENT - if the argument has been |
| * disposed</li> |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been |
| * disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public void setSelectedColor(final Color selectedColor) { |
| checkWidget(); |
| this.selectedColor = selectedColor; |
| } |
| |
| /** |
| * Sets the receiver's text color when the button is selected. |
| * |
| * @param selectedTextColor the new selected text color |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_INVALID_ARGUMENT - if the argument has been |
| * disposed</li> |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been |
| * disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public void setSelectedTextColor(final Color selectedTextColor) { |
| this.selectedTextColor = selectedTextColor; |
| } |
| |
| /** |
| * Sets the selection state of the receiver. |
| * |
| * @param selected the new selection state |
| * |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public void setSelection(final boolean selected) { |
| checkWidget(); |
| this.selection = selected; |
| redraw(); |
| } |
| |
| /** |
| * Sets the receiver's text. |
| * |
| * @param text the new text |
| * @exception IllegalArgumentException <ul> |
| * <li>ERROR_NULL_ARGUMENT - if the text is null</li> |
| * </ul> |
| * @exception SWTException <ul> |
| * <li>ERROR_WIDGET_DISPOSED - if the receiver has been |
| * disposed</li> |
| * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the |
| * thread that created the receiver</li> |
| * </ul> |
| */ |
| public void setText(final String text) { |
| checkWidget(); |
| this.text = text; |
| redraw(); |
| } |
| |
| } |