view dwtx/ui/forms/widgets/Section.d @ 104:04b47443bb01

Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections. These new wrappers now use the tango.util.containers instead of the tango.util.collections.
author Frank Benoit <benoit@tionex.de>
date Thu, 07 Aug 2008 15:01:33 +0200
parents 0953c252a764
children
line wrap: on
line source

/*******************************************************************************
 * Copyright (c) 2000, 2007 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)
 *
 * Port to the D programming language:
 *     Frank Benoit <benoit@tionex.de>
 *******************************************************************************/
module dwtx.ui.forms.widgets.Section;

import dwtx.ui.forms.widgets.ExpandableComposite;
import dwtx.ui.forms.widgets.SharedScrolledComposite;

import dwt.DWT;
import dwt.events.PaintEvent;
import dwt.graphics.Color;
import dwt.graphics.GC;
import dwt.graphics.Image;
import dwt.graphics.Point;
import dwt.graphics.Rectangle;
import dwt.widgets.Composite;
import dwt.widgets.Control;
import dwt.widgets.Event;
import dwt.widgets.Listener;
import dwt.widgets.Text;
import dwtx.core.runtime.Assert;
import dwtx.ui.internal.forms.widgets.FormImages;
import dwtx.ui.internal.forms.widgets.FormUtil;

import dwt.dwthelper.utils;
import dwtx.dwtxhelper.Collection;

/**
 * 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 3.0
 */
public class Section : ExpandableComposite {
    /**
     * Description style. If used, description will be rendered below the title.
     */
    public static const int DESCRIPTION = 1 << 7;

    private Control descriptionControl;

    private Control separator;

    private Hashtable titleColors;

    private static const String COLOR_BG = "bg"; //$NON-NLS-1$

    private static const String COLOR_GBG = "gbg"; //$NON-NLS-1$

    private static const 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 this(Composite parent, int style) {
        this(parent, DWT.NULL, style);
    }

    this(Composite parent, int cstyle, int style) {
        super(parent, cstyle | getBackgroundStyle(style), style);
        int rtl = cstyle & DWT.RIGHT_TO_LEFT;
        if ((style & DESCRIPTION) !is 0) {
            descriptionControl = new Text(this, DWT.READ_ONLY | DWT.WRAP | rtl);
        }
        if ((style & TITLE_BAR) !is 0) {
            Listener listener = new class Listener{
                public void handleEvent(Event e) {
                    Image image = this.outer.callSuperGetBackgroundImage();
                    if (image !is null) {
                        FormImages.getInstance().markFinished(image);
                    }
                    this.outer.callSuperSetBackgroundImage(null);
                }
            };
            addListener(DWT.Dispose, listener);
            addListener(DWT.Resize, listener);
        }
    }

    private static int getBackgroundStyle(int estyle) {
        return ((estyle & TITLE_BAR) !is 0) ? DWT.NO_BACKGROUND : DWT.NULL;
    }

    private Image callSuperGetBackgroundImage(){
        return super.getBackgroundImage();
    }
    private void callSuperSetBackgroundImage(Image image){
        return super.setBackgroundImage(image);
    }
    protected void internalSetExpanded(bool expanded) {
        super.internalSetExpanded(expanded);
        if ((getExpansionStyle() & TITLE_BAR) !is 0) {
            if (!expanded)
                super.setBackgroundImage(cast(Image)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 !is null) {
            c.setRedraw(false);
            c = c.getParent();
            if (null !is cast(SharedScrolledComposite)c ) {
                break;
            }
        }
        c = this;
        while (c !is null) {
            c.layout(true);
            c = c.getParent();
            if (null !is cast(SharedScrolledComposite)c ) {
                (cast(SharedScrolledComposite) c).reflow(true);
                break;
            }
        }
        c = this;
        while (c !is null) {
            c.setRedraw(true);
            c = c.getParent();
            if (null !is cast(SharedScrolledComposite)c ) {
                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 (null !is cast(Text)descriptionControl )
            (cast(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 (null !is cast(Text)descriptionControl )
            return (cast(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 !is null && separator.getParent().opEquals(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 !is null
                && (getExpansionStyle() & DESCRIPTION) !is 0)
            descriptionControl.setBackground(bg);
    }

    /**
     * Sets the foreground of the section.
     *
     * @param fg
     *            the new foreground.
     */
    public void setForeground(Color fg) {
        super.setForeground(fg);
        if (descriptionControl !is null
                && (getExpansionStyle() & DESCRIPTION) !is 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(dwt.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.
     *
     * @since 3.1
     * @param descriptionControl
     *            the control that will be placed below the title text.
     */
    public void setDescriptionControl(Control descriptionControl) {
        Assert.isTrue((getExpansionStyle() & DESCRIPTION) is 0);
        Assert.isTrue(descriptionControl !is null
                && descriptionControl.getParent().opEquals(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);
    }

    /**
     * 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 is null)
            return null;
        return cast(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 is null)
            return null;
        if ((getExpansionStyle() & SHORT_TITLE_BAR) !is 0)
            return getBackground();
        return cast(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 is null)
            return null;
        return cast(Color) titleColors.get(COLOR_BG);
    }

    private void putTitleBarColor(String key, Color color) {
        if (color is null)
            return;
        if (titleColors is null)
            titleColors = new Hashtable();
        titleColors.put(key, color);
    }

    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) !is 0) {
            buffer = new Image(getDisplay(), bounds.width, bounds.height);
            buffer.setBackground(getBackground());
            gc = new GC(buffer);
        }
        if (titleColors !is null) {
            bg = cast(Color) titleColors.get(COLOR_BG);
            fg = getTitleBarForeground();
            border = cast(Color) titleColors.get(COLOR_BORDER);
        }
        if (bg is null)
            bg = getBackground();
        if (fg is null)
            fg = getForeground();
        if (border is null)
            border = fg;
        int theight = 0;
        int gradientheight = 0;
        int tvmargin = IGAP;
        if ((getExpansionStyle() & TITLE_BAR) !is 0) {
            Point tsize = null;
            Point tcsize = null;
            if (toggle !is null)
                tsize = toggle.getSize();
            int twidth = bounds.width - marginWidth - marginWidth;
            if (tsize !is null)
                twidth -= tsize.x + IGAP;
            if (getTextClient() !is null)
                tcsize = getTextClient().getSize();
            if (tcsize !is null)
                twidth -= tcsize.x + IGAP;
            Point size = textLabel.getSize();
            if (tsize !is null)
                theight += Math.max(theight, tsize.y);
            gradientheight = theight;
            if (tcsize !is 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) !is 0) {
            if (getBackgroundImage() is 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, DWT.ON);
        // repair the upper left corner
        gc.fillPolygon([ marginWidth, marginHeight, marginWidth,
                marginHeight + 2, marginWidth + 2, marginHeight ]);
        // repair the upper right corner
        gc.fillPolygon([ bounds.width - marginWidth - 3,
                marginHeight, bounds.width - marginWidth, marginHeight,
                bounds.width - marginWidth, marginHeight + 3 ]);
        gc.setForeground(border);
        if (isExpanded() || (getExpansionStyle() & TITLE_BAR) !is 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) !is 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) !is 0) {
            // New in 3.3 - edge treatmant
            gc.setForeground(getDisplay().getSystemColor(DWT.COLOR_WHITE));
            gc.drawPolyline([ 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 !is 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) {
    }
}