/*******************************************************************************
* Copyright 2012 Geoscience Australia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package au.gov.ga.earthsci.common.ui.util;
import java.io.IOException;
import java.io.InputStream;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.TextLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
/**
* Collection of static utility methods for SWT support.
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public class SWTUtil
{
private static final float RGB_VALUE_MULTIPLIER = 0.8f;
//could use the ellipsis glyph on some platforms "\u2026"
private static final String ELLIPSIS = "..."; //$NON-NLS-1$
/**
* Create a color with a darker hue than the given color.
*
* @param color
* @return Darker color
*/
public static Color darker(Color color)
{
return darker(color, RGB_VALUE_MULTIPLIER);
}
/**
* Create a color with a darker hue than the given color.
*
* @param color
* @param multiplier
* Darken multiplier
* @return Darker color
*/
public static Color darker(Color color, float multiplier)
{
return new Color(color.getDevice(),
(int) (color.getRed() * multiplier),
(int) (color.getGreen() * multiplier),
(int) (color.getBlue() * multiplier));
}
/**
* Create a color with a lighter hue than the given color.
*
* @param color
* @return Lighter color
*/
public static Color lighter(Color color)
{
return lighter(color, RGB_VALUE_MULTIPLIER);
}
/**
* Create a color with a lighter hue than the given color.
*
* @param color
* @param multiplier
* Lighten multiplier
* @return Lighter color
*/
public static Color lighter(Color color, float multiplier)
{
return new Color(color.getDevice(),
(int) (255 - (255 - color.getRed()) * multiplier),
(int) (255 - (255 - color.getGreen()) * multiplier),
(int) (255 - (255 - color.getBlue()) * multiplier));
}
/**
* Should the given color be darkened, or lightened? Returns true if the
* average value for the red/green/blue components is greater than 128.
*
* @param color
* @return True if the given color should be darkened
*/
public static boolean shouldDarken(Color color)
{
return (color.getRed() + color.getGreen() + color.getBlue()) > 128 * 3;
}
/**
* Recursively enable/disable all the root control and all of its children.
*
* @param root
* The root node to enable/disable
* @param enabled
*/
public static void setEnabled(Control root, boolean enabled)
{
root.setEnabled(enabled);
if (root instanceof Composite)
{
for (Control c : ((Composite) root).getChildren())
{
setEnabled(c, enabled);
}
}
}
/**
* Add some colour to the provided control to better allow debugging
*/
public static void debug(Control control)
{
control.setBackground(new Color(Display.getCurrent(), new RGB(255, 0, 0)));
}
/**
* Create a TextLayout that contains the given text, shorted to fit within
* the given width (and optional height).
*
* @param device
* Current device
* @param text
* Text to shorten
* @param font
* Font to use when calculating shortened text
* @param maxWidth
* Maximum width available for text; if {@link SWT#DEFAULT}, text
* is unshortened
* @param maxHeight
* Maximum height available for text; only used if multiline is
* <code>true</code>
* @param multiline
* Should the text be wrapped over multiple lines
* @param addEllipsis
* Should an ellipsis be added on the end if the text requires
* shortening
* @return TextLayout containing the shortened and constrained text
*/
public static TextLayout shortenText(Device device, String text, Font font, int maxWidth, int maxHeight,
boolean multiline, boolean addEllipsis)
{
TextLayout layout = new TextLayout(device);
layout.setText(text);
layout.setFont(font);
//multiline can fit into any width, so if no maxHeight is defined return unshortened
if (maxWidth == SWT.DEFAULT || (multiline && maxHeight == SWT.DEFAULT))
{
return layout;
}
if (multiline)
{
layout.setWidth(maxWidth);
}
Rectangle bounds = layout.getBounds();
boolean fits = multiline ? (bounds.height <= maxHeight) : (bounds.width <= maxWidth);
if (fits)
{
return layout;
}
int end = 0;
while (true)
{
int nextEnd = layout.getNextOffset(end, SWT.MOVEMENT_CLUSTER);
bounds = layout.getBounds(0, nextEnd);
fits = multiline ? (bounds.height <= maxHeight) : (bounds.width <= maxWidth);
if (!fits)
{
break;
}
end = nextEnd;
}
String shortenedText = text.substring(0, end);
while (true)
{
String textWithSuffix = shortenedText;
if (addEllipsis)
{
textWithSuffix += ELLIPSIS;
}
layout.setText(textWithSuffix);
bounds = layout.getBounds();
fits = multiline ? (bounds.height <= maxHeight) : (bounds.width <= maxWidth);
if (fits || shortenedText.length() == 0)
{
return layout;
}
shortenedText = shortenedText.substring(0, shortenedText.length() - 1);
}
}
public static Image[] loadAnimatedImage(Display display, InputStream stream) throws IOException
{
ImageLoader imageLoader = new ImageLoader();
imageLoader.load(stream);
Image[] images = new Image[imageLoader.data.length];
for (int i = 0; i < imageLoader.data.length; ++i)
{
ImageData nextFrameData = imageLoader.data[i];
images[i] = new Image(display, nextFrameData);
}
return images;
}
}