/******************************************************************************* * Copyright (c) 2000, 2015 IBM Corporation 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: * IBM Corporation - initial API and implementation * Michael Williamson (eclipse-bugs@magnaworks.com) - patch (see Bugzilla #92545) * *******************************************************************************/ package org.eclipse.ui.forms.widgets; import java.util.Hashtable; import org.eclipse.core.runtime.Assert; import org.eclipse.rap.rwt.theme.BoxDimensions; import org.eclipse.rap.rwt.theme.ControlThemeAdapter; import org.eclipse.swt.SWT; //import org.eclipse.swt.events.PaintEvent; //import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.*; import org.eclipse.swt.internal.widgets.IWidgetGraphicsAdapter; import org.eclipse.swt.internal.widgets.controlkit.ControlThemeAdapterImpl; import org.eclipse.swt.widgets.*; import org.eclipse.ui.internal.forms.widgets.FormImages; //import org.eclipse.ui.internal.forms.widgets.FormUtil; /** * A variation of the expandable composite that adds optional description below * the title. Section is often used as a basic building block in forms because * it provides for logical grouping of information. * <p> * In case of the TITLE_BAR style, Section renders the title bar in a way * compatible with the rest of the workbench. Since it is a widget, all the * colors must be supplied directly. When created by the form toolkit, these * colors are supplied by the toolkit. The toolkit initializes these colors * based on the system colors. For this reason, it is recommended to create the * section by the toolkit instead of through its own constructor. * <p> * Since 3.1, it is possible to set a control to be used for section * description. If used, <code>DESCRIPTION</code> style should not be set. A * typical way to take advantage of the new method is to set an instance of * <code>FormText</code> to provide for hyperlinks and images in the * description area. * * @since 1.0 */ @SuppressWarnings("restriction") public class Section extends ExpandableComposite { /** * Description style. If used, description will be rendered below the title. */ public static final int DESCRIPTION = 1 << 7; private Control descriptionControl; private Control separator; private Hashtable titleColors; private static final String COLOR_BG = "bg"; //$NON-NLS-1$ private static final String COLOR_GBG = "gbg"; //$NON-NLS-1$ private static final String COLOR_BORDER = "border"; //$NON-NLS-1$ /** * Creates a new section instance in the provided parent. * * @param parent * the parent composite * @param style * the style to use */ public Section(Composite parent, int style) { this(parent, SWT.NULL, style); } Section(Composite parent, int cstyle, int style) { super(parent, cstyle | getBackgroundStyle(style), style); // RAP [rh] RIGHT_TO_LEFT not implemented int rtl = cstyle /* & SWT.RIGHT_TO_LEFT */; if ((style & DESCRIPTION) != 0) { descriptionControl = new Text(this, SWT.READ_ONLY | SWT.WRAP | rtl); } if ((style & TITLE_BAR) != 0) { Listener listener = new Listener() { public void handleEvent(Event e) { Image image = Section.super.getBackgroundImage(); if (image != null) { FormImages.getInstance().markFinished(image); } Section.super.setBackgroundImage(null); // RAP [if] Title bar background gradient rendering if( e.type != SWT.Dispose ) { applyBackgroundGradient(); } // ENDRAP [if] } }; addListener(SWT.Dispose, listener); addListener(SWT.Resize, listener); } } private static int getBackgroundStyle(int estyle) { // RAP [rh] NO_BACKGROUND not available // return ((estyle & TITLE_BAR) != 0) ? SWT.NO_BACKGROUND : SWT.NULL; return SWT.NULL; } protected void internalSetExpanded(boolean expanded) { super.internalSetExpanded(expanded); if ((getExpansionStyle() & TITLE_BAR) != 0) { if (!expanded) super.setBackgroundImage(null); } reflow(); } /** * Reflows this section and all the parents up the hierarchy until a * SharedScrolledComposite is reached. */ protected void reflow() { Composite c = this; while (c != null) { c.setRedraw(false); c = c.getParent(); if (c instanceof SharedScrolledComposite || c instanceof Shell) { break; } } c = this; while (c != null) { c.layout(true); c = c.getParent(); if (c instanceof SharedScrolledComposite) { ((SharedScrolledComposite) c).reflow(true); break; } } c = this; while (c != null) { c.setRedraw(true); c = c.getParent(); if (c instanceof SharedScrolledComposite || c instanceof Shell) { break; } } } /** * Sets the description text. Has no effect if DESCRIPTION style was not * used to create the control. * * @param description */ public void setDescription(String description) { if (descriptionControl instanceof Text) ((Text) descriptionControl).setText(description); } /** * Returns the current description text. * * @return description text or <code>null</code> if DESCRIPTION style was * not used to create the control. */ public String getDescription() { if (descriptionControl instanceof Text) return ((Text) descriptionControl).getText(); return null; } /** * Sets the separator control of this section. The separator must not be * <samp>null </samp> and must be a direct child of this container. If * defined, separator will be placed below the title text and will remain * visible regardless of the expansion state. * * @param separator * the separator that will be placed below the title text. */ public void setSeparatorControl(Control separator) { Assert.isTrue(separator != null && separator.getParent().equals(this)); this.separator = separator; } /** * Returns the control that is used as a separator betweeen the title and * the client, or <samp>null </samp> if not set. * * @return separator control or <samp>null </samp> if not set. */ public Control getSeparatorControl() { return separator; } /** * Sets the background of the section. * * @param bg * the new background */ public void setBackground(Color bg) { super.setBackground(bg); if (descriptionControl != null && (getExpansionStyle() & DESCRIPTION) != 0) descriptionControl.setBackground(bg); // RAP [if] Title bar background gradient rendering applyBackgroundGradient(); // ENDRAP [if] } /** * Sets the foreground of the section. * * @param fg * the new foreground. */ public void setForeground(Color fg) { super.setForeground(fg); if (descriptionControl != null && (getExpansionStyle() & DESCRIPTION) != 0) descriptionControl.setForeground(fg); } /** * Returns the control used to render the description. In 3.1, this method * was promoted to public. * * @return description control or <code>null</code> if DESCRIPTION style * was not used to create the control and description control was * not set by the client. * @see #setDescriptionControl(org.eclipse.swt.widgets.Control) */ public Control getDescriptionControl() { return descriptionControl; } /** * Sets the description control of this section. The control must not be * <samp>null</samp> and must be a direct child of this container. If * defined, contol will be placed below the title text and the separator and * will be hidden int he collapsed state. * <p> * This method and <code>DESCRIPTION</code> style are mutually exclusive. * Use the method only if you want to create the description control * yourself. * * @param descriptionControl * the control that will be placed below the title text. */ public void setDescriptionControl(Control descriptionControl) { Assert.isTrue((getExpansionStyle() & DESCRIPTION) == 0); Assert.isTrue(descriptionControl != null && descriptionControl.getParent().equals(this)); this.descriptionControl = descriptionControl; } /** * Sets the color of the title bar border when TITLE_BAR style is used. * * @param color * the title bar border color */ public void setTitleBarBorderColor(Color color) { putTitleBarColor(COLOR_BORDER, color); } /** * Sets the color of the title bar background when TITLE_BAR style is used. * This color is used as a starting color for the vertical gradient. * * @param color * the title bar border background */ public void setTitleBarBackground(Color color) { putTitleBarColor(COLOR_BG, color); // RAP [if] Title bar background gradient rendering applyBackgroundGradient(); // ENDRAP [if] } /** * Sets the color of the title bar gradient background when TITLE_BAR style * is used. This color is used at the height where title controls end * (toggle, tool bar). * * @param color * the title bar gradient background */ public void setTitleBarGradientBackground(Color color) { putTitleBarColor(COLOR_GBG, color); } /** * Returns the title bar border color when TITLE_BAR style is used. * * @return the title bar border color */ public Color getTitleBarBorderColor() { if (titleColors == null) return null; return (Color) titleColors.get(COLOR_BORDER); } /** * Returns the title bar gradient background color when TITLE_BAR style is * used. * * @return the title bar gradient background */ public Color getTitleBarGradientBackground() { if (titleColors == null) return null; if ((getExpansionStyle() & SHORT_TITLE_BAR) != 0) return getBackground(); return (Color) titleColors.get(COLOR_GBG); } /** * Returns the title bar background when TITLE_BAR style is used. * * @return the title bar background */ public Color getTitleBarBackground() { if (titleColors == null) return null; return (Color) titleColors.get(COLOR_BG); } private void putTitleBarColor(String key, Color color) { if (color == null) return; if (titleColors == null) titleColors = new Hashtable(); titleColors.put(key, color); } // RAP [rh] missing Paint events // protected void onPaint(PaintEvent e) { // Color bg = null; // Color fg = null; // Color border = null; // // GC gc = e.gc; // Image buffer = null; // Rectangle bounds = getClientArea(); // // if ((getExpansionStyle() & TITLE_BAR) != 0) { // buffer = new Image(getDisplay(), bounds.width, bounds.height); // buffer.setBackground(getBackground()); // gc = new GC(buffer); // } // if (titleColors != null) { // bg = (Color) titleColors.get(COLOR_BG); // fg = getTitleBarForeground(); // border = (Color) titleColors.get(COLOR_BORDER); // } // if (bg == null) // bg = getBackground(); // if (fg == null) // fg = getForeground(); // if (border == null) // border = fg; // int theight = 0; // int gradientheight = 0; // int tvmargin = IGAP; // if ((getExpansionStyle() & TITLE_BAR) != 0) { // Point tsize = null; // Point tcsize = null; // if (toggle != null) // tsize = toggle.getSize(); // int twidth = bounds.width - marginWidth - marginWidth; // if (tsize != null) // twidth -= tsize.x + IGAP; // if (getTextClient() != null) // tcsize = getTextClient().getSize(); // if (tcsize != null) // twidth -= tcsize.x + IGAP; // Point size = textLabel.getSize(); // if (tsize != null) // theight += Math.max(theight, tsize.y); // gradientheight = theight; // if (tcsize != null) { // theight = Math.max(theight, tcsize.y); // } // theight = Math.max(theight, size.y); // gradientheight = Math.max(gradientheight, size.y); // theight += tvmargin + tvmargin; // gradientheight += tvmargin + tvmargin; // } else { // theight = 5; // } // if ((getExpansionStyle() & TITLE_BAR) != 0) { // if (getBackgroundImage() == null) // updateHeaderImage(bg, bounds, gradientheight, theight); // gc.setBackground(getBackground()); // gc.fillRectangle(bounds.x, bounds.y, bounds.width, bounds.height); // drawBackground(gc, bounds.x, bounds.y, bounds.width, theight); // if (marginWidth > 0) { // // fix up margins // gc.setBackground(getBackground()); // gc.fillRectangle(0, 0, marginWidth, theight); // gc.fillRectangle(bounds.x + bounds.width - marginWidth, 0, // marginWidth, theight); // } // } else if (isExpanded()) { // gc.setForeground(bg); // gc.setBackground(getBackground()); // gc.fillGradientRectangle(marginWidth, marginHeight, bounds.width // - marginWidth - marginWidth, theight, true); // } // gc.setBackground(getBackground()); // FormUtil.setAntialias(gc, SWT.ON); // // repair the upper left corner // gc.fillPolygon(new int[] { marginWidth, marginHeight, marginWidth, // marginHeight + 2, marginWidth + 2, marginHeight }); // // repair the upper right corner // gc.fillPolygon(new int[] { bounds.width - marginWidth - 3, // marginHeight, bounds.width - marginWidth, marginHeight, // bounds.width - marginWidth, marginHeight + 3 }); // gc.setForeground(border); // if (isExpanded() || (getExpansionStyle() & TITLE_BAR) != 0) { // // top left curve // gc.drawLine(marginWidth, marginHeight + 2, marginWidth + 2, // marginHeight); // // top edge // gc.drawLine(marginWidth + 2, marginHeight, bounds.width // - marginWidth - 3, marginHeight); // // top right curve // gc.drawLine(bounds.width - marginWidth - 3, marginHeight, // bounds.width - marginWidth - 1, marginHeight + 2); // } else { // // collapsed short title bar // // top edge // gc.drawLine(marginWidth, marginHeight, bounds.width - 1, // marginHeight); // } // if ((getExpansionStyle() & TITLE_BAR) != 0 || isExpanded()) { // // left vertical edge gradient // gc.fillGradientRectangle(marginWidth, marginHeight + 2, 1, // gradientheight - 2, true); // // right vertical edge gradient // gc.fillGradientRectangle(bounds.width - marginWidth - 1, // marginHeight + 2, 1, gradientheight - 2, true); // } // if ((getExpansionStyle() & TITLE_BAR) != 0) { // // New in 3.3 - edge treatmant // gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_WHITE)); // gc.drawPolyline(new int[] { marginWidth + 1, // marginHeight + gradientheight - 1, marginWidth + 1, // marginHeight + 2, marginWidth + 2, marginHeight + 2, // marginWidth + 2, marginHeight + 1, // bounds.width - marginWidth - 3, marginHeight + 1, // bounds.width - marginWidth - 3, marginHeight + 2, // bounds.width - marginWidth - 2, marginHeight + 2, // bounds.width - marginWidth - 2, // marginHeight + gradientheight - 1 }); // } // if (buffer != null) { // gc.dispose(); // e.gc.drawImage(buffer, 0, 0); // buffer.dispose(); // } // } // // private void updateHeaderImage(Color bg, Rectangle bounds, int theight, // int realtheight) { // Image image = FormImages.getInstance().getGradient(getDisplay(), getBackground(), bg, realtheight, theight, marginHeight); // super.setBackgroundImage(image); // } /** * Background image is used for the title gradient - does nothing. */ public final void setBackgroundImage(Image image) { } // RAP [if] Title bar background gradient rendering private final void applyBackgroundGradient() { if( ( getExpansionStyle() & TITLE_BAR ) != 0 ) { // Code start - onPaint Color bg = null; if (titleColors != null) { bg = (Color) titleColors.get(COLOR_BG); } if (bg == null) bg = getBackground(); Rectangle bounds = getClientArea(); int theight = 0; int gradientheight = 0; int tvmargin = IGAP; Point tsize = null; Point tcsize = null; if (toggle != null) tsize = toggle.getSize(); int twidth = bounds.width - marginWidth - marginWidth; if (tsize != null) twidth -= tsize.x + IGAP; if (getTextClient() != null) tcsize = getTextClient().getSize(); if (tcsize != null) twidth -= tcsize.x + IGAP; Point size = textLabel.getSize(); if (tsize != null) theight += Math.max(theight, tsize.y); gradientheight = theight; if (tcsize != null) { theight = Math.max(theight, tcsize.y); } theight = Math.max(theight, size.y); gradientheight = Math.max(gradientheight, size.y); theight += tvmargin + tvmargin; gradientheight += tvmargin + tvmargin; // Code end - onPaint Object adapter = getAdapter( IWidgetGraphicsAdapter.class ); IWidgetGraphicsAdapter gfxAdapter = ( IWidgetGraphicsAdapter )adapter; Color[] gradientColors = new Color[] { bg, getBackground(), getBackground() }; int gradientPercent = 0; if( bounds.height != 0 ) { gradientPercent = gradientheight * 100 / bounds.height; if( gradientPercent > 100 ) { gradientPercent = 100; } } int[] percents = new int[] { 0, gradientPercent, 100 }; gfxAdapter.setBackgroundGradient( gradientColors, percents, true ); gfxAdapter.setRoundedBorder( 1, getBackground(), 8, 8, 0, 0 ); } } // Fix 1px border introduced by the titlebar rounded border private static final BoxDimensions ONE = new BoxDimensions( 1, 1, 1, 1 ); private ControlThemeAdapter controlThemeAdapter; @Override public <T> T getAdapter( Class<T> adapter ) { if( adapter == ControlThemeAdapter.class ) { if( controlThemeAdapter == null ) { controlThemeAdapter = new ControlThemeAdapterImpl() { @Override public BoxDimensions getBorder( Control control ) { if( ( getExpansionStyle() & TITLE_BAR ) != 0 ) { return ONE; } return super.getBorder( control ); } }; } return ( T )controlThemeAdapter; } return super.getAdapter( adapter ); } // ENDRAP [if] }