diff options
Diffstat (limited to 'propertysheet/src/org/eclipse/wb/internal/core/utils/ui/DrawUtils.java')
-rw-r--r-- | propertysheet/src/org/eclipse/wb/internal/core/utils/ui/DrawUtils.java | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/propertysheet/src/org/eclipse/wb/internal/core/utils/ui/DrawUtils.java b/propertysheet/src/org/eclipse/wb/internal/core/utils/ui/DrawUtils.java new file mode 100644 index 0000000..f7cc09d --- /dev/null +++ b/propertysheet/src/org/eclipse/wb/internal/core/utils/ui/DrawUtils.java @@ -0,0 +1,337 @@ +/******************************************************************************* + * Copyright (c) 2011 Google, Inc. + * 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: + * Google, Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.wb.internal.core.utils.ui; + +import com.google.common.io.Closeables; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Display; +import org.eclipse.wb.draw2d.IColorConstants; + +import java.io.InputStream; +import java.net.URL; + +/** + * Utilities for drawing on {@link GC}. + * + * @author scheglov_ke + * @coverage core.ui + */ +public class DrawUtils { + private static final String DOTS = "..."; + + //////////////////////////////////////////////////////////////////////////// + // + // Drawing + // + //////////////////////////////////////////////////////////////////////////// + /** + * Draws given text clipped horizontally and centered vertically. + */ + public static final void drawStringCV(GC gc, String text, int x, int y, int width, int height) { + Rectangle oldClipping = gc.getClipping(); + try { + gc.setClipping(new Rectangle(x, y, width, height)); + // + int textStartY = y + (height - gc.getFontMetrics().getHeight()) / 2; + gc.drawString(clipString(gc, text, width), x, textStartY, true); + } finally { + gc.setClipping(oldClipping); + } + } + + /** + * Draws given text clipped or centered horizontally and centered vertically. + */ + public static final void drawStringCHCV(GC gc, String text, int x, int y, int width, int height) { + int textStartY = y + (height - gc.getFontMetrics().getHeight()) / 2; + Point textSize = gc.stringExtent(text); + // + if (textSize.x > width) { + gc.drawString(clipString(gc, text, width), x, textStartY); + } else { + gc.drawString(text, x + (width - textSize.x) / 2, textStartY); + } + } + + /** + * Draws image at given <code>x</code> and centered vertically. + */ + public static final void drawImageCV(GC gc, Image image, int x, int y, int height) { + if (image != null) { + Rectangle imageBounds = image.getBounds(); + gc.drawImage(image, x, y + (height - imageBounds.height) / 2); + } + } + + /** + * Draws image at given <code>x</code> and centered vertically. + */ + public static final void drawImageCHCV(GC gc, Image image, int x, int y, int width, int height) { + if (image != null) { + Rectangle imageBounds = image.getBounds(); + int centerX = (width - imageBounds.width) / 2; + int centerY = y + (height - imageBounds.height) / 2; + gc.drawImage(image, x + centerX, centerY); + } + } + + /** + * Draws {@link Image} on {@link GC} centered in given {@link Rectangle}. If {@link Image} is + * bigger that {@link Rectangle}, {@link Image} will be scaled down as needed with keeping + * proportions. + */ + public static void drawScaledImage(GC gc, Image image, Rectangle targetRectangle) { + int imageWidth = image.getBounds().width; + int imageHeight = image.getBounds().height; + // prepare scaled image size + int newImageWidth; + int newImageHeight; + if (imageWidth <= targetRectangle.width && imageHeight <= targetRectangle.height) { + newImageWidth = imageWidth; + newImageHeight = imageHeight; + } else { + // prepare minimal scale + double k; + { + double k_w = targetRectangle.width / (double) imageWidth; + double k_h = targetRectangle.height / (double) imageHeight; + k = Math.min(k_w, k_h); + } + // calculate scaled image size + newImageWidth = (int) (imageWidth * k); + newImageHeight = (int) (imageHeight * k); + } + // draw image centered in target rectangle + int destX = targetRectangle.x + (targetRectangle.width - newImageWidth) / 2; + int destY = targetRectangle.y + (targetRectangle.height - newImageHeight) / 2; + gc.drawImage(image, 0, 0, imageWidth, imageHeight, destX, destY, newImageWidth, newImageHeight); + } + + /** + * @return the string clipped to have width less than given. Clipping is done as trailing "...". + */ + public static String clipString(GC gc, String text, int width) { + if (width <= 0) { + return ""; + } + // check if text already fits in given width + if (gc.stringExtent(text).x <= width) { + return text; + } + // use average count of characters as base + int count = Math.min(width / gc.getFontMetrics().getAverageCharWidth(), text.length()); + if (gc.stringExtent(text.substring(0, count) + DOTS).x > width) { + while (count > 0 && gc.stringExtent(text.substring(0, count) + DOTS).x > width) { + count--; + } + } else { + while (count < text.length() - 1 + && gc.stringExtent(text.substring(0, count + 1) + DOTS).x < width) { + count++; + } + } + return text.substring(0, count) + DOTS; + } + + /** + * Draws {@link String} in rectangle, wraps at any character (not by words). + */ + public static void drawTextWrap(GC gc, String text, int x, int y, int width, int height) { + int y_ = y; + int x_ = x; + int lineHeight = 0; + for (int i = 0; i < text.length(); i++) { + String c = text.substring(i, i + 1); + Point extent = gc.stringExtent(c); + if (x_ + extent.x > x + width) { + y_ += lineHeight; + if (y_ > y + height) { + return; + } + x_ = x; + } + gc.drawText(c, x_, y_); + x_ += extent.x; + lineHeight = Math.max(lineHeight, extent.y); + } + } + + /** + * Draws 3D highlight rectangle. + */ + public static void drawHighlightRectangle(GC gc, int x, int y, int width, int height) { + int right = x + width - 1; + int bottom = y + height - 1; + // + Color oldForeground = gc.getForeground(); + try { + gc.setForeground(IColorConstants.buttonLightest); + gc.drawLine(x, y, right, y); + gc.drawLine(x, y, x, bottom); + // + gc.setForeground(IColorConstants.buttonDarker); + gc.drawLine(right, y, right, bottom); + gc.drawLine(x, bottom, right, bottom); + } finally { + gc.setForeground(oldForeground); + } + } + + //////////////////////////////////////////////////////////////////////////// + // + // Images + // + //////////////////////////////////////////////////////////////////////////// + /** + * @return the {@link Image} loaded relative to given {@link Class}. + */ + public static Image loadImage(Class<?> clazz, String path) { + try { + URL resource = clazz.getResource(path); + if (resource != null) { + InputStream stream = resource.openStream(); + try { + return new Image(null, stream); + } finally { + Closeables.closeQuietly(stream); + } + } + } catch (Throwable e) { + } + return null; + } + + /** + * @return the thumbnail {@link Image} of required size for given "big" {@link Image}, centered or + * scaled down. + */ + public static Image getThubmnail(Image image, + int minWidth, + int minHeight, + int maxWidth, + int maxHeight) { + Rectangle imageBounds = image.getBounds(); + int imageWidth = imageBounds.width; + int imageHeight = imageBounds.height; + if (imageWidth < minWidth && imageHeight < minHeight) { + // create "thumbnail" Image with required size + Image thumbnail = new Image(null, minWidth, minHeight); + GC gc = new GC(thumbnail); + try { + drawImageCHCV(gc, image, 0, 0, minWidth, minHeight); + } finally { + gc.dispose(); + } + // recreate "thumbnail" Image with transparent pixel + try { + ImageData thumbnailData = thumbnail.getImageData(); + thumbnailData.transparentPixel = thumbnailData.getPixel(0, 0); + return new Image(null, thumbnailData); + } finally { + thumbnail.dispose(); + } + } else if (imageWidth <= maxWidth && imageHeight <= maxHeight) { + return new Image(null, image, SWT.IMAGE_COPY); + } else { + double kX = (double) maxWidth / imageWidth; + double kY = (double) maxHeight / imageHeight; + double k = Math.max(kX, kY); + int dWidth = (int) (imageWidth * k); + int dHeight = (int) (imageHeight * k); + ImageData scaledImageData = image.getImageData().scaledTo(dWidth, dHeight); + return new Image(null, scaledImageData); + } + } + + //////////////////////////////////////////////////////////////////////////// + // + // Colors + // + //////////////////////////////////////////////////////////////////////////// + /** + * @return new {@link Color} based on given {@link Color} and shifted on given value to make it + * darker or lighter. + */ + public static Color getShiftedColor(Color color, int delta) { + int r = Math.max(0, Math.min(color.getRed() + delta, 255)); + int g = Math.max(0, Math.min(color.getGreen() + delta, 255)); + int b = Math.max(0, Math.min(color.getBlue() + delta, 255)); + return new Color(color.getDevice(), r, g, b); + } + + /** + * @return <code>true</code> if the given <code>color</code> is dark. + */ + public static boolean isDarkColor(Color c) { + int value = + (int) Math.sqrt(c.getRed() + * c.getRed() + * .241 + + c.getGreen() + * c.getGreen() + * .691 + + c.getBlue() + * c.getBlue() + * .068); + return value < 130; + } + + //////////////////////////////////////////////////////////////////////////// + // + // Fonts + // + //////////////////////////////////////////////////////////////////////////// + /** + * @return the bold version of given {@link Font}. + */ + public static Font getBoldFont(Font baseFont) { + FontData[] boldData = getModifiedFontData(baseFont, SWT.BOLD); + return new Font(Display.getCurrent(), boldData); + } + + /** + * @return the italic version of given {@link Font}. + */ + public static Font getBoldItalicFont(Font baseFont) { + FontData[] boldData = getModifiedFontData(baseFont, SWT.BOLD | SWT.ITALIC); + return new Font(Display.getCurrent(), boldData); + } + + /** + * @return the italic version of given {@link Font}. + */ + public static Font getItalicFont(Font baseFont) { + FontData[] boldData = getModifiedFontData(baseFont, SWT.ITALIC); + return new Font(Display.getCurrent(), boldData); + } + + /** + * @return the array of {@link FontData} with the specified style. + */ + private static FontData[] getModifiedFontData(Font baseFont, int style) { + FontData[] baseData = baseFont.getFontData(); + FontData[] styleData = new FontData[baseData.length]; + for (int i = 0; i < styleData.length; i++) { + FontData base = baseData[i]; + styleData[i] = new FontData(base.getName(), base.getHeight(), base.getStyle() | style); + } + return styleData; + } +} |