package org.eclipse.update.ui.forms.internal;
/*
 * (c) Copyright IBM Corp. 2000, 2001.
 * All Rights Reserved.
 */

import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.*;
import org.eclipse.swt.events.*;
import org.eclipse.jface.resource.*;
import org.eclipse.jface.util.PropertyChangeEvent;

/**
 * This form implementation assumes that it contains
 * form sections and that they fill up the screen.
 * Typically, the form client will use up the entire
 * parent area below the heading. Sections must
 * be able to return their preferred size in both
 * dimensions. If they contain wrappable text,
 * WebForm should be used instead.
 */

public class SectionForm extends AbstractSectionForm implements PaintListener {
	private Composite control;
	private int TITLE_HMARGIN = 10;
	private int TITLE_VMARGIN = 5;

	class FormLayout extends Layout {
		protected Point computeSize(
			Composite composite,
			int wHint,
			int hHint,
			boolean flushCache) {
			if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT)
				return new Point(wHint, hHint);
			Control client = composite.getChildren()[0];
			Point csize = client.computeSize(widthHint, heightHint, flushCache);
			if (headingVisible)
				csize.y += getTitleHeight();
			return csize;
		}
		protected void layout(Composite composite, boolean flushCache) {
			Rectangle clientArea = composite.getClientArea();
			Control client = composite.getChildren()[0];
			int theight = headingVisible ? getTitleHeight() : 0;
			client.setBounds(
				clientArea.x,
				clientArea.y + theight,
				clientArea.width,
				clientArea.height - theight);
		}
	}
	private int widthHint = SWT.DEFAULT;
	private int heightHint = SWT.DEFAULT;

	public SectionForm() {
	}

	public Control createControl(Composite parent) {
		Composite canvas = new Composite(parent, SWT.NONE);
		canvas.setBackground(factory.getBackgroundColor());
		canvas.setForeground(factory.getForegroundColor());
		canvas.addPaintListener(this);
		canvas.setLayout(new FormLayout());
		canvas.setMenu(parent.getMenu());
		Composite formParent = factory.createComposite(canvas);
		createFormClient(formParent);
		this.control = canvas;
		//canvas.setFocus();
		return canvas;
	}

	protected void createFormClient(Composite parent) {
		factory.createComposite(parent);
	}

	public Control getControl() {
		return control;
	}

	private int getTitleHeight() {
		int imageHeight = 0;
		if (headingImage != null
			&& SWT.getPlatform().equals("motif") == false) {
			imageHeight = headingImage.getBounds().height;
		}
		GC gc = new GC(control);
		gc.setFont(titleFont);
		FontMetrics fm = gc.getFontMetrics();
		int fontHeight = fm.getHeight();
		gc.dispose();

		int height = fontHeight + TITLE_VMARGIN + TITLE_VMARGIN;
		return Math.max(height, imageHeight);
	}

	private void paint(Control form, GC gc) {
		Rectangle bounds = form.getBounds();
		int height = getTitleHeight();
		if (headingImage != null) {
			Rectangle imageBounds = headingImage.getBounds();
			int x = bounds.width - imageBounds.width;
			int y = 0;
			//x = Math.max(x, 0);
			x = 0;
			if (headingBackground != null) {
				gc.setBackground(headingBackground);
				gc.fillRectangle(0, 0, bounds.width, height);
			}
			if (SWT.getPlatform().equals("motif") == false) {
				gc.drawImage(headingImage, x, y);
			}
			if (headingForeground != null)
				gc.setForeground(headingForeground);
			else
				gc.setForeground(factory.getForegroundColor());
			gc.setFont(titleFont);
			gc.drawText(getHeadingText(), TITLE_HMARGIN, TITLE_VMARGIN, true);
		} else {
			gc.setFont(titleFont);
			gc.setBackground(factory.getColor(FormWidgetFactory.DEFAULT_HEADER_COLOR));
			//gc.fillRectangle(TITLE_HMARGIN, TITLE_VMARGIN, bounds.width-TITLE_HMARGIN*2, height-TITLE_VMARGIN*2);
			gc.setForeground(factory.getForegroundColor());
			gc.drawText(getHeadingText(), TITLE_HMARGIN, TITLE_VMARGIN, true);
		}
	}

	public final void paintControl(PaintEvent event) {
		if (!headingVisible)
			return;
		GC gc = event.gc;
		Control form = (Control) event.widget;
		paint(form, gc);
	}

	public void setHeadingVisible(boolean newHeadingVisible) {
		super.setHeadingVisible(newHeadingVisible);
		if (control != null)
			control.layout(true);
	}
	public void setHeadingText(String headingText) {
		super.setHeadingText(headingText);
		if (control != null) {
			control.layout(true);
			control.redraw();
		}
	}

	public void propertyChange(PropertyChangeEvent event) {
		titleFont = JFaceResources.getHeaderFont();
		if (control != null) {
			control.layout(true);
			control.redraw();
		}
	}

}