/******************************************************************************* * Copyright (c) 2006 Chris Gross. * 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: * schtoo@schtoo.com (Chris Gross) - initial API and implementation * Tom Schindl <tom.schindl@bestsolution.at> - added support for PGroupToolItem ******************************************************************************/ package org.eclipse.nebula.widgets.pgroup; import org.eclipse.nebula.widgets.pgroup.internal.GraphicUtils; import org.eclipse.nebula.widgets.pgroup.internal.TextUtils; import org.eclipse.swt.SWT; 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.graphics.Region; /** * RectangleGroupStrategy is a very flexible painting strategy that displays a * (rounded) rectangle around the PGroup's body. * * @since 1.0 * @author chris */ public class RectangleGroupStrategy extends AbstractGroupStrategy { private int vMargin = 2; private int hMargin = 5; private int titleTextMargin = 2; private int betweenSpacing = 4; private int margin = 1; private Color gradientColors[] = null; private int gradientPercents[] = null; private boolean gradientVertical = false; private Color borderColor = null; private Color g1; private Color g2; private int titleHeight; private int fontHeight; private int titleAreaHeight; private Rectangle toolItemArea; /** * Constructs a RectangleGroupStrategy with the given toggle and style. * * @param toggleStrategy * @param style */ public RectangleGroupStrategy() { super(); } /* * (non-Javadoc) * * @see com.swtplus.widgets.AbstractGroupStrategy#initialize(com.swtplus.widgets.PGroup) */ public void initialize(PGroup sg) { super.initialize(sg); getGroup() .setForeground(getGroup().getDisplay().getSystemColor(SWT.COLOR_TITLE_FOREGROUND)); g1 = getGroup().getDisplay().getSystemColor(SWT.COLOR_TITLE_BACKGROUND_GRADIENT); g2 = getGroup().getDisplay().getSystemColor(SWT.COLOR_TITLE_BACKGROUND); setBackground(new Color[] {g1, g2 }, new int[] {100 }, true); setBorderColor(g2); } /* * (non-Javadoc) * * @see com.swtplus.widgets.AbstractGroupStrategy#paintGroup(org.eclipse.swt.graphics.GC) */ public void paint(GC gc) { Point imagePoint = new Point(0, 0); Image image = getGroup().getImage(); if (getGroup().getToggleRenderer() != null) { Point p = getGroup().getToggleRenderer().getSize(); int toggleY = 0; if ((getGroup().getImagePosition() & SWT.TOP) == 0) { toggleY = (titleHeight - p.y) / 2; } else { toggleY = (titleHeight - titleAreaHeight) + (titleAreaHeight - p.y) / 2; } if ((getGroup().getTogglePosition() & SWT.LEAD) != 0) { getGroup().getToggleRenderer().setLocation(new Point(hMargin, toggleY)); } else { getGroup().getToggleRenderer().setLocation( new Point(getGroup().getSize().x - hMargin - p.x, toggleY)); } } Color back = getGroup().internalGetBackground(); if (back != null) { gc.fillRectangle(0,0,getGroup().getSize().x,getGroup().getSize().y); int yOffset = 0; if ((getGroup().getImagePosition() & SWT.TOP) != 0 && image != null) { yOffset = titleHeight - titleAreaHeight; } Region reg = new Region(); reg.add(0,yOffset + 0, 5, 1); reg.add(0,yOffset + 1, 3, 1); reg.add(0,yOffset + 2, 2, 1); reg.add(0,yOffset + 3, 1, 1); reg.add(0,yOffset + 4, 1, 1); reg.add(getGroup().getSize().x - 5,yOffset + 0, 5, 1); reg.add(getGroup().getSize().x - 3,yOffset + 1, 3, 1); reg.add(getGroup().getSize().x - 2,yOffset + 2, 2, 1); reg.add(getGroup().getSize().x - 1,yOffset + 3, 1, 1); reg.add(getGroup().getSize().x - 1,yOffset + 4, 1, 1); int height = getGroup().getSize().y; if (!getGroup().getExpanded()) { height = titleHeight; } reg.add(0, height - 1, 5, 1); reg.add(0, height - 2, 3, 1); reg.add(0, height - 3, 2, 1); reg.add(0, height - 4, 1, 1); reg.add(0, height - 5, 1, 1); reg.add(getGroup().getSize().x - 5, height - 1, 5, 1); reg.add(getGroup().getSize().x - 3, height - 2, 3, 1); reg.add(getGroup().getSize().x - 2, height - 3, 2, 1); reg.add(getGroup().getSize().x - 1, height - 4, 1, 1); reg.add(getGroup().getSize().x - 1, height - 5, 1, 1); if (yOffset != 0) { reg.add(0,0,getGroup().getSize().x,yOffset); } if (!getGroup().getExpanded()) { int regionHeight = getGroup().getSize().y - titleHeight; if( regionHeight < 0 ) regionHeight = 0; reg.add(new Rectangle(0,titleHeight,getGroup().getSize().x,regionHeight)); } gc.setClipping(reg); getGroup().drawBackground(gc, 0, 0, getGroup().getSize().x,getGroup().getSize().y); gc.setClipping((Region)null); reg.dispose(); } // Paint rectangle int toggleHeight = 0; if (getGroup().getToggleRenderer() != null) { toggleHeight = getGroup().getToggleRenderer().getSize().y + (2 * vMargin); } Region reg = null; if ((getGroup().getStyle() & SWT.SMOOTH) != 0) { reg = new Region(getGroup().getDisplay()); reg.add(0, 0, getGroup().getSize().x, titleHeight); int yOffset = 0; if ((getGroup().getImagePosition() & SWT.TOP) != 0 && image != null) { yOffset = titleHeight - titleAreaHeight; } reg.subtract(0, yOffset + 0, 5, 1); reg.subtract(0, yOffset + 1, 3, 1); reg.subtract(0, yOffset + 2, 2, 1); reg.subtract(0, yOffset + 3, 1, 1); reg.subtract(0, yOffset + 4, 1, 1); reg.subtract(getGroup().getSize().x - 5, yOffset + 0, 5, 1); reg.subtract(getGroup().getSize().x - 3, yOffset + 1, 3, 1); reg.subtract(getGroup().getSize().x - 2, yOffset + 2, 2, 1); reg.subtract(getGroup().getSize().x - 1, yOffset + 3, 1, 1); reg.subtract(getGroup().getSize().x - 1, yOffset + 4, 1, 1); if (!getGroup().getExpanded()) { yOffset = titleHeight; reg.subtract(0, yOffset - 1, 5, 1); reg.subtract(0, yOffset - 2, 3, 1); reg.subtract(0, yOffset - 3, 2, 1); reg.subtract(0, yOffset - 4, 1, 1); reg.subtract(0, yOffset - 5, 1, 1); reg.subtract(getGroup().getSize().x - 5, yOffset - 1, 5, 1); reg.subtract(getGroup().getSize().x - 3, yOffset - 2, 3, 1); reg.subtract(getGroup().getSize().x - 2, yOffset - 3, 2, 1); reg.subtract(getGroup().getSize().x - 1, yOffset - 4, 1, 1); reg.subtract(getGroup().getSize().x - 1, yOffset - 5, 1, 1); } gc.setClipping(reg); } if ((getGroup().getImagePosition() & SWT.TOP) == 0 || image == null) { if (gradientColors != null) { GraphicUtils.fillGradientRectangle(gc, 0, 0, getGroup().getSize().x, Math .max(titleHeight, toggleHeight), gradientColors, gradientPercents, gradientVertical); } else { gc.fillRectangle(0, 0, getGroup().getSize().x, Math.max(titleHeight, toggleHeight)); GraphicUtils.fillRoundRectangle(gc, 0, 0, getGroup().getSize().x, Math .max(titleHeight, toggleHeight), null, true, !getGroup().getExpanded()); } if ((getGroup().getStyle() & SWT.SMOOTH) != 0) { GraphicUtils.drawRoundRectangle(gc, 0, 0, getGroup().getSize().x, Math .max(titleHeight, toggleHeight), null, null, true, !getGroup().getExpanded()); } } else { // gc.setBackground(getGroup().getParent().getBackground()); // gc.fillRectangle(0,0,getGroup().getSize().x,getTitleHeight() - // titleAreaHeight); if (gradientColors != null) { GraphicUtils.fillGradientRectangle(gc, 0, titleHeight - titleAreaHeight, getGroup() .getSize().x, Math.max(titleAreaHeight, toggleHeight), gradientColors, gradientPercents, gradientVertical); } else { gc.setBackground(getGroup().getBackground()); gc.fillRectangle(0, titleHeight - titleAreaHeight, getGroup().getSize().x, Math .max(titleAreaHeight, toggleHeight)); } // if ((getGroup().getStyle() & SWT.SMOOTH) != 0){ // GraphicUtils.drawRoundRectangle(gc,0,getTitleHeight() - // titleAreaHeight,getGroup().getSize().x // -1,Math.max(titleAreaHeight,toggleHeight) // ,getGroup().getParent().getBackground(),null,true,!getGroup().isExpanded()); // } } if ((getGroup().getStyle() & SWT.SMOOTH) != 0) { gc.setClipping((Region)null); reg.dispose(); } // Paint Image if (image != null) { if ((getGroup().getImagePosition() & SWT.LEAD) != 0) { if (getGroup().getToggleRenderer() != null) { if (getGroup().getTogglePosition() == SWT.LEAD) { imagePoint.x = hMargin + getGroup().getToggleRenderer().getSize().x + betweenSpacing; } else { imagePoint.x = hMargin; } } else { imagePoint.x = hMargin; } } else { if (getGroup().getToggleRenderer() != null) { if ((getGroup().getTogglePosition() & SWT.LEAD) != 0) { imagePoint.x = getGroup().getSize().x - (hMargin + image.getBounds().width); } else { imagePoint.x = getGroup().getSize().x - (hMargin + image.getBounds().width + getGroup().getToggleRenderer().getSize().x + betweenSpacing); } } else { imagePoint.x = getGroup().getSize().x - (hMargin + image.getBounds().width); } } if ((getGroup().getImagePosition() & SWT.TOP) == 0 && image.getImageData().height > titleHeight) { imagePoint.y = (titleHeight - image.getImageData().height) / 2; } else { imagePoint.y = (titleHeight - image.getImageData().height) / 2; } gc.drawImage(image, imagePoint.x, imagePoint.y); } Rectangle textBounds = getTextBounds(); String shortened = TextUtils.getShortString(gc, getGroup().getText(), textBounds.width); if( getGroup().getToolItems().length > 0 && getGroup().getToolItemRenderer() != null ) { PGroupToolItem[] items = getGroup().getToolItems(); AbstractToolItemRenderer renderer = getGroup().getToolItemRenderer(); Point size = new Point(0, 0); Point minSize = new Point(0, 0); int spacing = 3; for(int i = 0; i < items.length; i++ ) { PGroupToolItem item = items[i]; Point s0 = renderer.computeSize(gc, item, AbstractToolItemRenderer.DEFAULT); Point s1 = renderer.computeSize(gc, item, AbstractToolItemRenderer.MIN); size.x += s0.x + spacing; minSize.x += s1.x + spacing; } boolean min = false; if( shortened.length() != getGroup().getText().length() ) { textBounds.width -= minSize.x; min = true; } else { if( ! TextUtils.getShortString(gc, getGroup().getText(), textBounds.width - size.x).equals(getGroup().getText()) ) { textBounds.width -= minSize.x; min = true; } else { textBounds.width -= size.x; } } shortened = TextUtils.getShortString(gc, getGroup().getText(), textBounds.width); int x = textBounds.x + textBounds.width; if( min ) { toolItemArea = new Rectangle(x, titleHeight - titleAreaHeight + 2, minSize.x, Math.max(titleAreaHeight, toggleHeight)-4); } else { toolItemArea = new Rectangle(x, titleHeight - titleAreaHeight + 2, size.x, Math.max(titleAreaHeight, toggleHeight)-4); } } gc.setForeground(getGroup().getForeground()); gc.drawText(shortened, textBounds.x, textBounds.y, true); if (!getGroup().getExpanded()) { gc.setBackground(getGroup().getParent().getBackground()); // gc.fillRectangle(0,getTitleHeight(),getGroup().getBounds().width,getGroup().getBounds().height); } else { Color _borderColor; if (borderColor == null) { _borderColor = getGroup().getBackground(); } else { _borderColor = borderColor; } if ((getGroup().getStyle() & SWT.SMOOTH) != 0) { gc.setBackground(getGroup().getBackground()); // gc.fillRectangle(0,getGroup().getSize().y - // 5,getGroup().getSize().x -1,5); gc.setForeground(_borderColor); reg = new Region(getGroup().getDisplay()); reg.add(0, 0, getGroup().getSize().x, getGroup().getSize().y); int yOffset = getGroup().getSize().y; reg.subtract(0, yOffset - 1, 5, 1); reg.subtract(0, yOffset - 2, 3, 1); reg.subtract(0, yOffset - 3, 2, 1); reg.subtract(0, yOffset - 4, 1, 1); reg.subtract(0, yOffset - 5, 1, 1); reg.subtract(getGroup().getSize().x - 5, yOffset - 1, 5, 1); reg.subtract(getGroup().getSize().x - 3, yOffset - 2, 3, 1); reg.subtract(getGroup().getSize().x - 2, yOffset - 3, 2, 1); reg.subtract(getGroup().getSize().x - 1, yOffset - 4, 1, 1); reg.subtract(getGroup().getSize().x - 1, yOffset - 5, 1, 1); gc.setClipping(reg); GraphicUtils.drawRoundRectangle(gc, 0, titleHeight, getGroup().getSize().x - 1, getGroup().getSize().y - titleHeight, null, false, true); reg.dispose(); gc.setClipping((Region)null); } else { gc.setForeground(_borderColor); gc.drawRectangle(0, titleHeight, getGroup().getBounds().width - 1, getGroup() .getBounds().height - titleHeight - 1); } } gc.setBackground(getGroup().getBackground()); gc.setForeground(getGroup().getForeground()); } public Rectangle getToolItemArea() { return toolItemArea; } /** * {@inheritDoc} */ public boolean isToggleLocation(int x, int y) { if( getGroup().getToolItems().length == 0 ) { if (y >= titleHeight - titleAreaHeight && y <= titleHeight) { return true; } else { return false; } } else { return super.isToggleLocation(x, y); } } protected Rectangle getTextBounds() { Point textPoint = new Point(0, 0); int textWidth = 0; Image image = getGroup().getImage(); int titleAreaHeight = 0; if (image != null && !((getGroup().getImagePosition() & SWT.TOP) == 0)) { titleAreaHeight = fontHeight + (2 * titleTextMargin) + (2 * vMargin); if (getGroup().getToggleRenderer() != null) { titleAreaHeight = Math.max(titleAreaHeight, getGroup().getToggleRenderer() .getSize().y + (2 * vMargin)); } } textPoint.x = hMargin; if (image != null) { if ((getGroup().getImagePosition() & SWT.LEAD) != 0) { textPoint.x += image.getBounds().width + betweenSpacing; } if ((getGroup().getImagePosition() & SWT.TOP) == 0) { textPoint.y = (titleHeight - fontHeight) / 2; } else { textPoint.y = (titleHeight - titleAreaHeight) + (titleAreaHeight - fontHeight) / 2; } } else { textPoint.y = (titleHeight - fontHeight) / 2; } // Part 2, Toggle if (getGroup().getToggleRenderer() != null) { if ((getGroup().getTogglePosition() & SWT.LEAD) != 0) { textPoint.x += getGroup().getToggleRenderer().getSize().x + betweenSpacing; } } textWidth = getGroup().getSize().x - (hMargin * 2); if (image != null) { textWidth -= (image.getBounds().width + betweenSpacing); } if (getGroup().getToggleRenderer() != null) { textWidth -= getGroup().getToggleRenderer().getSize().x + betweenSpacing; } return new Rectangle(textPoint.x, textPoint.y, textWidth, fontHeight); } /** * {@inheritDoc} */ public Rectangle getClientArea() { Rectangle area = getGroup().getBounds(); area.x = margin; area.y = titleHeight +1; area.width -= (2 * margin); if ((getGroup().getStyle() & SWT.SMOOTH) != 0) { area.height -= titleHeight + 5 + 1; } else { area.height -= titleHeight + margin + 1; } return area; } /** * {@inheritDoc} */ public Rectangle computeTrim(int x, int y, int width, int height) { Rectangle area = new Rectangle(x, y, width, height); area.x -= margin; area.y -= titleHeight; area.width += (2 * margin); area.height += titleHeight; if (getGroup().getExpanded()) { if ((getGroup().getStyle() & SWT.SMOOTH) != 0) { area.height += 5; } else { area.height += margin; } } return area; } /* * (non-Javadoc) * * @see com.swtplus.widgets.IGroupStrategy#dispose() */ public void dispose() { g1.dispose(); g2.dispose(); } /** * Specify a gradient of colours to be drawn in the background of the group. * <p> * For example, to draw a gradient that varies from dark blue to blue and * then to white and stays white for the right half of the label, use the * following call to setBackground: * </p> * * <pre> * setBackground(new Color[] {display.getSystemColor(SWT.COLOR_DARK_BLUE), * display.getSystemColor(SWT.COLOR_BLUE), * display.getSystemColor(SWT.COLOR_WHITE), * display.getSystemColor(SWT.COLOR_WHITE) }, new int[] {25, 50, 100 }); * </pre> * * @param colors an array of Color that specifies the colors to appear in * the gradient in order of appearance from left to right; The value * <code>null</code> clears the background gradient; the value * <code>null</code> can be used inside the array of Color to specify the * background color. * @param percents an array of integers between 0 and 100 specifying the * percent of the width of the widget at which the color should change; the * size of the percents array must be one less than the size of the colors * array. */ public void setBackground(Color[] colors, int[] percents) { setBackground(colors, percents, false); } /** * Specify a gradient of colours to be drawn in the background of the group. * <p> * For example, to draw a gradient that varies from dark blue to white in * the vertical, direction use the following call to setBackground: * </p> * * <pre> * setBackground(new Color[] {display.getSystemColor(SWT.COLOR_DARK_BLUE), * display.getSystemColor(SWT.COLOR_WHITE) }, new int[] {100 }, true); * </pre> * * @param colors an array of Color that specifies the colors to appear in * the gradient in order of appearance from left/top to right/bottom; The * value <code>null</code> clears the background gradient; the value * <code>null</code> can be used inside the array of Color to specify the * background color. * @param percents an array of integers between 0 and 100 specifying the * percent of the width/height of the widget at which the color should * change; the size of the percents array must be one less than the size of * the colors array. * @param vertical indicate the direction of the gradient. True is vertical * and false is horizontal. */ public void setBackground(Color[] colors, int[] percents, boolean vertical) { if (colors != null) { if (percents == null || percents.length != colors.length - 1) { throw new RuntimeException( "Percents array must be one item less than the colors array"); } if (getGroup().getDisplay().getDepth() < 15) { // Don't use gradients on low color displays colors = new Color[] {colors[colors.length - 1] }; percents = new int[] {}; } for (int i = 0; i < percents.length; i++) { if (percents[i] < 0 || percents[i] > 100) { throw new RuntimeException("Percent array item out of range"); } if (i > 0 && percents[i] < percents[i - 1]) { // throw new RuntimeException("huh?"); } } } // Are these settings the same as before? final Color background = getGroup().getBackground(); if ((gradientColors != null) && (colors != null) && (gradientColors.length == colors.length)) { boolean same = false; for (int i = 0; i < gradientColors.length; i++) { same = (gradientColors[i] == colors[i]) || ((gradientColors[i] == null) && (colors[i] == background)) || ((gradientColors[i] == background) && (colors[i] == null)); if (!same) break; } if (same) { for (int i = 0; i < gradientPercents.length; i++) { same = gradientPercents[i] == percents[i]; if (!same) break; } } if (same && this.gradientVertical == vertical) return; } // Store the new settings if (colors == null) { gradientColors = null; gradientPercents = null; gradientVertical = false; } else { gradientColors = new Color[colors.length]; for (int i = 0; i < colors.length; ++i) gradientColors[i] = (colors[i] != null) ? colors[i] : background; gradientPercents = new int[percents.length]; for (int i = 0; i < percents.length; ++i) gradientPercents[i] = percents[i]; gradientVertical = vertical; } // Refresh with the new settings getGroup().redraw(); } /** * Returns the color of the one pixel border drawn around the body when the * group is expanded. * * @return the border color */ public Color getBorderColor() { return borderColor; } /** * Sets the border color. The border is the one pixel border drawn around * the body when the group is expanded. * * @param borderColor the border color, or null for no border */ public void setBorderColor(Color borderColor) { this.borderColor = borderColor; } public void update() { GC gc = new GC(getGroup()); titleHeight = 0; int imageHeight = 0; if (getGroup().getImage() != null) imageHeight = getGroup().getImage().getBounds().height; if ((getGroup().getImagePosition() & SWT.TOP) == 0) { titleHeight = Math.max(gc.getFontMetrics().getHeight() + (2 * titleTextMargin), imageHeight); titleHeight += (2 * vMargin); } else { titleHeight = Math.max(gc.getFontMetrics().getHeight() + (2 * titleTextMargin) + (2 * vMargin), imageHeight + 1); } if (getGroup().getToggleRenderer() != null) { int toggleHeight = getGroup().getToggleRenderer().getSize().y; titleHeight = Math.max(toggleHeight + (2 * vMargin), titleHeight); } fontHeight = gc.getFontMetrics().getHeight(); titleAreaHeight = fontHeight + (2 * titleTextMargin) + (2 * vMargin); if (getGroup().getToggleRenderer() != null) { titleAreaHeight = Math.max(titleAreaHeight, getGroup().getToggleRenderer() .getSize().y + (2 * vMargin)); } gc.dispose(); } }