/******************************************************************************* * Copyright (c) 2007, 2014 compeople AG 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: * compeople AG - initial API and implementation *******************************************************************************/ package org.eclipse.riena.ui.swt; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.widgets.Display; import org.eclipse.riena.ui.swt.facades.GCFacade; import org.eclipse.riena.ui.swt.lnf.LnfKeyConstants; import org.eclipse.riena.ui.swt.lnf.LnfManager; import org.eclipse.riena.ui.swt.lnf.rienadefault.RienaDefaultLnf; /** * The StatusMeter is intended to visualize processes that run for much longer * periods than those that are usually visualized by a <code>ProgressBar</code>. * In difference to the <code>ProgressBar</code>, it offers the ability to * change colors and it can be used in tables. * <p> * <b>NOTE:</b> This is an image factory for use in {@link ColumnFormatter} and * alike. See {@link StatusMeterWidget} for an actual widget implementation. * </p> * <p> * StatusMeter uses a builder pattern. Use one of the static methods to create a * builder. * * @since 3.0 */ public class StatusMeter { protected StatusMeter() { } /** * Creates an empty builder instance. * * @return A builder instance */ public static StatusMeterBuilder empty() { return new StatusMeterBuilder(); } /** * Creates a builder instance with the following values * <ul> * <li>maximum = 100 * <li>width = 100 * <li>height = 16 * <li>leftIndent = 1 * <li>margin = 1 * </ul> * * @return A builder instance */ public static StatusMeterBuilder imageDefault() { return new StatusMeterBuilder().maximum(100).width(100).height(16).leftIndent(1).margin(1); } /** * Creates a builder instance with the following values * <ul> * <li>value = 100 * <li>maximum = 100 * <li>width = 100 * <li>height = 16 * <li>leftIndent = 1 * <li>margin = 1 * </ul> * * @return A builder instance */ public static StatusMeterBuilder imageFinished() { return new StatusMeterBuilder().value(100).maximum(100).width(100).height(16).leftIndent(1).margin(1); } /** * Creates a builder instance with the following values * <ul> * <li>maximum = 100 * <li>width = 100 * <li>height = 16 * <li>leftIndent = 0 * <li>margin = 0 * </ul> * * @return A builder instance */ public static StatusMeterBuilder widgetDefault() { return StatusMeter.imageDefault().leftIndent(0).margin(0); } /** * Creates a builder instance with the following values * <ul> * <li>value = 100 * <li>maximum = 100 * <li>width = 100 * <li>height = 16 * <li>leftIndent = 0 * <li>margin = 0 * </ul> * * @return A builder instance */ public static StatusMeterBuilder widgetFinished() { return StatusMeter.imageFinished().leftIndent(0).margin(0); } /** * Builder for StatusMeter * * @see StatusMeter */ public static final class StatusMeterBuilder { private int value = 0; private int maximum = 100; private int minimum = 0; private int width = 0; private int height = 0; private int indent = 0; private int margin = 0; private Color borderColor; private Color gradientStartColor; private Color gradientEndColor; private Color backgroundColor; private final Color transparentColor; private static final int BORDER_WIDTH = 1; private StatusMeterBuilder() { final RienaDefaultLnf lnf = LnfManager.getLnf(); borderColor = lnf.getColor(LnfKeyConstants.STATUS_METER_BORDER_COLOR); gradientStartColor = lnf.getColor(LnfKeyConstants.STATUS_METER_GRADIENT_START_COLOR); gradientEndColor = lnf.getColor(LnfKeyConstants.STATUS_METER_GRADIENT_END_COLOR); backgroundColor = lnf.getColor(LnfKeyConstants.STATUS_METER_BACKGROUND_COLOR); transparentColor = lnf.getColor(LnfKeyConstants.STATUS_METER_TRANSPARENT_COLOR); } /** * Returns a StatusMeter as image (data). * * @return An image (data) according to the values set to the builder * @throws IllegalArgumentException * if conditions that are described in the setter methods * are violated * @since 4.0 */ public ImageData getImageData() { if (width <= 0 || height <= 0) { throw new IllegalArgumentException("Width and height must be values greater than 0 to draw."); //$NON-NLS-1$ } if (value < 0 || value > maximum) { throw new IllegalArgumentException("Value must be positive and smaller or equal to the maximum value."); //$NON-NLS-1$ } if (minimum < 0) { throw new IllegalArgumentException("Minimum must be positive."); //$NON-NLS-1$ } if (margin < 0 || margin > (height / 2) || margin > (width / 2)) { throw new IllegalArgumentException( "Margin must be positive and must not be greater than half of the height and half of the width."); //$NON-NLS-1$ } if (indent < 0 || indent > width) { throw new IllegalArgumentException( "Indentation must be positive and must not be greater than the total width."); //$NON-NLS-1$ } // TODO sma@2010-08-17 Is this the Riena way? final Display display = Display.getCurrent(); final Image tempImage = GCFacade.getDefault().createImage(display, width, height); //final Image image = new Image(display, width, height); //final GC gc = new GC(image); final GC gc = GCFacade.getDefault().createGCFromImage(tempImage); final int start = margin + indent + BORDER_WIDTH; final int end = width - (margin * 2) - BORDER_WIDTH - 1; final int barHeight = height - (margin * 2) - (BORDER_WIDTH * 2); final int actualWidth = end - start + 1; final float scale = (float) actualWidth / (maximum - minimum); final int actualValue = (int) ((value - minimum) * scale); // Background gc.setBackground(transparentColor); gc.fillRectangle(0, 0, width, height); // Progress gc.setForeground(gradientStartColor); gc.setBackground(gradientEndColor); gc.fillGradientRectangle(start, margin + BORDER_WIDTH, actualValue, barHeight, true); // Background gc.setBackground(backgroundColor); gc.fillRectangle(start + actualValue, margin + BORDER_WIDTH, actualWidth - actualValue, barHeight); // Border gc.setForeground(borderColor); final int bottom = height - margin - 1; // horizontal lines gc.drawLine(start, margin, end, margin); gc.drawLine(start, bottom, end, bottom); // vertical lines gc.drawLine(start - BORDER_WIDTH, margin + BORDER_WIDTH, start - BORDER_WIDTH, bottom - BORDER_WIDTH); gc.drawLine(end + BORDER_WIDTH, margin + BORDER_WIDTH, end + BORDER_WIDTH, bottom - BORDER_WIDTH); final ImageData imageData = tempImage.getImageData(); gc.dispose(); tempImage.dispose(); imageData.transparentPixel = imageData.palette.getPixel(transparentColor.getRGB()); return imageData; } /** * Value must be positive and must not exceed the set maximum. * * @param value * @return The builder */ public StatusMeterBuilder value(final int value) { this.value = value; return this; } /** * Maximum must be positive and greater or equal to the set value. * * @param max * @return The builder */ public StatusMeterBuilder maximum(final int max) { this.maximum = max; return this; } /** * Minimum must be positive. * * @param min * @return The builder */ public StatusMeterBuilder minimum(final int min) { this.minimum = min; return this; } /** * Width must be greater than 0. * * @param width * @return The builder */ public StatusMeterBuilder width(final int width) { this.width = width; return this; } /** * Height must be greater than 0. * * @param height * @return The builder */ public StatusMeterBuilder height(final int height) { this.height = height; return this; } /** * Indent must be positive and smaller than the set width. * * @param indent * @return The builder */ public StatusMeterBuilder leftIndent(final int indent) { this.indent = indent; return this; } /** * Margin must be positive and smaller than half of the set height and * half of the set width. * * @param margin * @return The builder */ public StatusMeterBuilder margin(final int margin) { this.margin = margin; return this; } /** * The color that is used for the border. Default is set in * {@link RienaDefaultLnf}. * * @param color * @return The builder */ public StatusMeterBuilder borderColor(final Color color) { this.borderColor = color; return this; } /** * The color that is used for the background area that is not filed with * the bar. Default is set in {@link RienaDefaultLnf}. * * @param color * @return The builder */ public StatusMeterBuilder backgroundColor(final Color color) { this.backgroundColor = color; return this; } /** * The start color that makes the gradient of the bar. Default is set in * {@link RienaDefaultLnf}. * * @param color * @return The builder */ public StatusMeterBuilder gradientStartColor(final Color color) { this.gradientStartColor = color; return this; } /** * The end color that makes the gradient of the bar. Default is set in * {@link RienaDefaultLnf}. * * @param color * @return The builder */ public StatusMeterBuilder gradientEndColor(final Color color) { this.gradientEndColor = color; return this; } } }