package org.eclipse.swt.custom; | |
/* | |
* Copyright (c) 2000, 2002 IBM Corp. All rights reserved. | |
* This file is made available under the terms of the Common Public License v1.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/cpl-v10.html | |
*/ | |
import org.eclipse.swt.graphics.*; | |
import org.eclipse.swt.widgets.*; | |
import org.eclipse.swt.*; | |
import org.eclipse.swt.events.*; | |
/** | |
* Instances of this class implement a Composite that lays out three | |
* children horizontally and allows programmatic control of layout and | |
* border parameters. ViewForm is used in the workbench to implement a | |
* view's label/menu/toolbar local bar. | |
* <p> | |
* Note that although this class is a subclass of <code>Composite</code>, | |
* it does not make sense to set a layout on it. | |
* </p><p> | |
* <dl> | |
* <dt><b>Styles:</b></dt> | |
* <dd>BORDER, FLAT</dd> | |
* <dt><b>Events:</b></dt> | |
* <dd>(None)</dd> | |
* </dl> | |
* <p> | |
* IMPORTANT: This class is <em>not</em> intended to be subclassed. | |
* </p> | |
*/ | |
public class ViewForm extends Composite { | |
/** | |
* marginWidth specifies the number of pixels of horizontal margin | |
* that will be placed along the left and right edges of the form. | |
* | |
* The default value is 0. | |
*/ | |
public int marginWidth = 0; | |
/** | |
* marginHeight specifies the number of pixels of vertical margin | |
* that will be placed along the top and bottom edges of the form. | |
* | |
* The default value is 0. | |
*/ | |
public int marginHeight = 0; | |
/** | |
* Color of innermost line of drop shadow border. | |
*/ | |
public static RGB borderInsideRGB = new RGB (132, 130, 132); | |
/** | |
* Color of middle line of drop shadow border. | |
*/ | |
public static RGB borderMiddleRGB = new RGB (143, 141, 138); | |
/** | |
* Color of outermost line of drop shadow border. | |
*/ | |
public static RGB borderOutsideRGB = new RGB (171, 168, 165); | |
// SWT widgets | |
private Control topLeft; | |
private Control topCenter; | |
private Control topRight; | |
private Control content; | |
// Configuration and state info | |
private boolean separateTopCenter = false; | |
private int drawLine1 = -1; | |
private int drawLine2 = -1; | |
private boolean showBorder = false; | |
private int BORDER_TOP = 0; | |
private int BORDER_BOTTOM = 0; | |
private int BORDER_LEFT = 0; | |
private int BORDER_RIGHT = 0; | |
private Color borderColor1; | |
private Color borderColor2; | |
private Color borderColor3; | |
private Rectangle oldArea; | |
private static final int OFFSCREEN = -200; | |
/** | |
* Constructs a new instance of this class given its parent | |
* and a style value describing its behavior and appearance. | |
* <p> | |
* The style value is either one of the style constants defined in | |
* class <code>SWT</code> which is applicable to instances of this | |
* class, or must be built by <em>bitwise OR</em>'ing together | |
* (that is, using the <code>int</code> "|" operator) two or more | |
* of those <code>SWT</code> style constants. The class description | |
* lists the style constants that are applicable to the class. | |
* Style bits are also inherited from superclasses. | |
* </p> | |
* | |
* @param parent a widget which will be the parent of the new instance (cannot be null) | |
* @param style the style of widget to construct | |
* | |
* @exception IllegalArgumentException <ul> | |
* <li>ERROR_NULL_ARGUMENT - if the parent is null</li> | |
* </ul> | |
* @exception SWTException <ul> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
* </ul> | |
* | |
* @see SWT#BORDER | |
* @see SWT#FLAT | |
* @see #getStyle | |
*/ | |
public ViewForm(Composite parent, int style) { | |
super(parent, checkStyle(style)); | |
borderColor1 = new Color(getDisplay(), borderInsideRGB); | |
borderColor2 = new Color(getDisplay(), borderMiddleRGB); | |
borderColor3 = new Color(getDisplay(), borderOutsideRGB); | |
setBorderVisible((style & SWT.BORDER) != 0); | |
addPaintListener(new PaintListener() { | |
public void paintControl(PaintEvent event) { | |
onPaint(event.gc); | |
} | |
}); | |
addControlListener(new ControlAdapter(){ | |
public void controlResized(ControlEvent e) { | |
onResize(); | |
} | |
}); | |
addListener(SWT.Dispose, new Listener() { | |
public void handleEvent(Event e) { | |
onDispose(); | |
} | |
}); | |
} | |
/** | |
* Check the style bits to ensure that no invalid styles are applied. | |
* @private | |
*/ | |
private static int checkStyle (int style) { | |
int mask = SWT.FLAT; | |
return style & mask | SWT.NO_REDRAW_RESIZE; | |
} | |
public Point computeSize(int wHint, int hHint, boolean changed) { | |
checkWidget(); | |
// size of title bar area | |
Point leftSize = new Point(0, 0); | |
if (topLeft != null) { | |
leftSize = topLeft.computeSize(SWT.DEFAULT, SWT.DEFAULT); | |
leftSize.x += 1; // +1 for highlight line | |
} | |
Point centerSize = new Point(0, 0); | |
if (topCenter != null) { | |
centerSize = topCenter.computeSize(SWT.DEFAULT, SWT.DEFAULT); | |
} | |
Point rightSize = new Point(0, 0); | |
if (topRight != null) { | |
rightSize = topRight.computeSize(SWT.DEFAULT, SWT.DEFAULT); | |
} | |
Point size = new Point(0, 0); | |
// calculate width of title bar | |
if (separateTopCenter || | |
(wHint != SWT.DEFAULT && leftSize.x + centerSize.x + rightSize.x > wHint)) { | |
size.x = leftSize.x + rightSize.x; | |
size.x = Math.max(centerSize.x, size.x); | |
size.y = Math.max(leftSize.y, rightSize.y) + 1; // +1 for highlight line | |
if (topCenter != null){ | |
size.y += centerSize.y; | |
} | |
} else { | |
size.x = leftSize.x + centerSize.x + rightSize.x; | |
size.y = Math.max(leftSize.y, Math.max(centerSize.y, rightSize.y)) + 1; // +1 for highlight line | |
} | |
if (content != null) { | |
Point contentSize = new Point(0, 0); | |
contentSize = content.computeSize(SWT.DEFAULT, SWT.DEFAULT); | |
size.x = Math.max (size.x, contentSize.x); | |
size.y += contentSize.y + 1; // +1 for line bewteen content and header | |
} | |
size.x += 2 * marginWidth; | |
size.y += 2 * marginHeight; | |
if (wHint != SWT.DEFAULT) size.x = wHint; | |
if (hHint != SWT.DEFAULT) size.y = hHint; | |
Rectangle trim = computeTrim(0, 0, size.x, size.y); | |
return new Point (trim.width, trim.height); | |
} | |
public Rectangle computeTrim (int x, int y, int width, int height) { | |
checkWidget (); | |
int trimX = x - BORDER_LEFT; | |
int trimY = y - BORDER_TOP; | |
int trimWidth = width + BORDER_LEFT + BORDER_RIGHT; | |
int trimHeight = height + BORDER_TOP + BORDER_BOTTOM; | |
return new Rectangle(trimX, trimY, trimWidth, trimHeight); | |
} | |
public Rectangle getClientArea() { | |
checkWidget(); | |
Rectangle clientArea = super.getClientArea(); | |
clientArea.x += BORDER_LEFT; | |
clientArea.y += BORDER_TOP; | |
clientArea.width -= BORDER_LEFT + BORDER_RIGHT; | |
clientArea.height -= BORDER_TOP + BORDER_BOTTOM; | |
return clientArea; | |
} | |
/** | |
* Returns the content area. | |
* | |
* @return the control in the content area of the pane or null | |
*/ | |
public Control getContent() { | |
//checkWidget(); | |
return content; | |
} | |
/** | |
* Returns Control that appears in the top center of the pane. | |
* Typically this is a toolbar. | |
* | |
* @return the control in the top center of the pane or null | |
*/ | |
public Control getTopCenter() { | |
//checkWidget(); | |
return topCenter; | |
} | |
/** | |
* Returns the Control that appears in the top left corner of the pane. | |
* Typically this is a label such as CLabel. | |
* | |
* @return the control in the top left corner of the pane or null | |
*/ | |
public Control getTopLeft() { | |
//checkWidget(); | |
return topLeft; | |
} | |
/** | |
* Returns the control in the top right corner of the pane. | |
* Typically this is a Close button or a composite with a Menu and Close button. | |
* | |
* @return the control in the top right corner of the pane or null | |
*/ | |
public Control getTopRight() { | |
//checkWidget(); | |
return topRight; | |
} | |
public void layout (boolean changed) { | |
checkWidget(); | |
Rectangle rect = getClientArea(); | |
drawLine1 = -1; | |
drawLine2 = -1; | |
Point leftSize = new Point(0, 0); | |
if (topLeft != null && !topLeft.isDisposed()) { | |
leftSize = topLeft.computeSize(SWT.DEFAULT, SWT.DEFAULT); | |
} | |
Point centerSize = new Point(0, 0); | |
if (topCenter != null && !topCenter.isDisposed()) { | |
centerSize = topCenter.computeSize(SWT.DEFAULT, SWT.DEFAULT); | |
} | |
Point rightSize = new Point(0, 0); | |
if (topRight != null && !topRight.isDisposed()) { | |
rightSize = topRight.computeSize(SWT.DEFAULT, SWT.DEFAULT); | |
} | |
int minTopWidth = leftSize.x + centerSize.x + rightSize.x + 2*marginWidth + 1; // +1 for highlight line | |
int height = rect.y + marginHeight; | |
boolean top = false; | |
if (separateTopCenter || minTopWidth > rect.width) {; | |
int topHeight = Math.max(rightSize.y, leftSize.y); | |
if (topRight != null && !topRight.isDisposed()) { | |
top = true; | |
topRight.setBounds(rect.x + rect.width - marginWidth - rightSize.x, | |
rect.y + 1 + marginHeight, | |
rightSize.x, topHeight); | |
height += 1 + topHeight; // +1 for highlight line | |
} | |
if (topLeft != null && !topLeft.isDisposed()) { | |
top = true; | |
leftSize = topLeft.computeSize(rect.width - 2* marginWidth - rightSize.x - 1, SWT.DEFAULT); | |
topLeft.setBounds(rect.x + 1 + marginWidth, | |
rect.y + 1 + marginHeight, | |
leftSize.x, topHeight); | |
height = Math.max(height, rect.y + marginHeight + 1 + topHeight); // +1 for highlight line | |
} | |
if (topCenter != null && !topCenter.isDisposed()) { | |
top = true; | |
if (height > rect.y + marginHeight) { | |
drawLine1 = height; | |
height += 1; // +1 for divider line | |
} | |
centerSize = topCenter.computeSize(rect.width - 2 * marginWidth, SWT.DEFAULT); | |
topCenter.setBounds(rect.x + rect.width - marginWidth - centerSize.x, | |
height, | |
centerSize.x, centerSize.y); | |
height += centerSize.y; | |
} | |
} else { | |
int topHeight = Math.max(rightSize.y, Math.max(centerSize.y, leftSize.y)); | |
if (topRight != null && !topRight.isDisposed()) { | |
top = true; | |
topRight.setBounds(rect.x + rect.width - marginWidth - rightSize.x, | |
rect.y + marginHeight + 1, // +1 for highlight line | |
rightSize.x, topHeight); | |
height += 1 + topHeight; // +1 for highlight line | |
} | |
if (topCenter != null && !topCenter.isDisposed()) { | |
top = true; | |
topCenter.setBounds(rect.x + rect.width - marginWidth - rightSize.x - centerSize.x, | |
rect.y + marginHeight + 1, // +1 for highlight line | |
centerSize.x, topHeight); | |
height = Math.max(height, rect.y + marginHeight + 1 + topHeight); // +1 for highlight line | |
} | |
if (topLeft != null && !topLeft.isDisposed()) { | |
top = true; | |
leftSize = topLeft.computeSize(rect.width - 2 * marginWidth - rightSize.x - centerSize.x - 1, topHeight); | |
topLeft.setBounds(rect.x + marginWidth + 1, // +1 for highlight line | |
rect.y + marginHeight + 1, // +1 for highlight line | |
leftSize.x, topHeight); | |
height = Math.max(height, rect.y + marginHeight + 1 + topHeight); // +1 for highlight line | |
} | |
} | |
if (content != null && !content.isDisposed()) { | |
if (top) { | |
drawLine2 = height; | |
height += 1; // +1 for divider line | |
} | |
content.setBounds(rect.x + marginWidth, | |
height, | |
rect.width - 2 * marginWidth, | |
rect.y + rect.height - height - marginHeight); | |
} | |
} | |
private void onDispose() { | |
if (borderColor1 != null) { | |
borderColor1.dispose(); | |
} | |
borderColor1 = null; | |
if (borderColor2 != null) { | |
borderColor2.dispose(); | |
} | |
borderColor2 = null; | |
if (borderColor3 != null) { | |
borderColor3.dispose(); | |
} | |
borderColor3 = null; | |
topLeft = null; | |
topCenter = null; | |
topRight = null; | |
content = null; | |
oldArea = null; | |
} | |
/** | |
* Draws the focus border. | |
*/ | |
private void onPaint(GC gc) { | |
Rectangle d = super.getClientArea(); | |
if (showBorder) { | |
if ((getStyle() & SWT.FLAT) !=0) { | |
gc.setForeground(borderColor1); | |
gc.drawRectangle(d.x, d.y, d.x + d.width - 1, d.y + d.height - 1); | |
} else { | |
gc.setForeground(borderColor1); | |
gc.drawRectangle(d.x, d.y, d.x + d.width - 3, d.y + d.height - 3); | |
gc.setForeground(borderColor2); | |
gc.drawLine(d.x + 1, d.y + d.height - 2, d.x + d.width - 1, d.y + d.height - 2); | |
gc.drawLine(d.x + d.width - 2, d.y + 1, d.x + d.width - 2, d.y + d.height - 1); | |
gc.setForeground(borderColor3); | |
gc.drawLine(d.x + 2, d.y + d.height - 1, d.x + d.width - 2, d.y + d.height - 1); | |
gc.drawLine(d.x + d.width - 1, d.y + 2, d.x + d.width - 1, d.y + d.height - 2); | |
} | |
} | |
if (drawLine1 != -1) { | |
// top seperator line | |
gc.setForeground(borderColor1); | |
gc.drawLine(d.x + BORDER_LEFT, drawLine1, d.x + d.width - BORDER_RIGHT, drawLine1); | |
} | |
if (drawLine2 != -1) { | |
// content separator line | |
gc.setForeground(borderColor1); | |
gc.drawLine(d.x + BORDER_LEFT, drawLine2, d.x + d.width - BORDER_RIGHT, drawLine2); | |
} | |
// highlight on top | |
int y = drawLine1; | |
if (y == -1){ | |
y = drawLine2; | |
} | |
if (y != -1) { | |
gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW)); | |
gc.drawLine(d.x + BORDER_LEFT + marginWidth, d.y + BORDER_TOP + marginHeight, | |
d.x + BORDER_LEFT + marginWidth, y - 1); | |
gc.drawLine(d.x + BORDER_LEFT + marginWidth, d.y + BORDER_TOP + marginHeight, | |
d.x + d.width - BORDER_RIGHT - marginWidth - 1, d.y + BORDER_TOP + marginHeight); | |
} | |
gc.setForeground(getForeground()); | |
} | |
private void onResize() { | |
layout(); | |
Rectangle area = super.getClientArea(); | |
if (oldArea == null || oldArea.width == 0 || oldArea.height == 0) { | |
redraw(); | |
} else { | |
int width = 0; | |
if (oldArea.width < area.width) { | |
width = area.width - oldArea.width + BORDER_RIGHT; | |
} else if (oldArea.width > area.width) { | |
width = BORDER_RIGHT; | |
} | |
redraw(area.x + area.width - width, area.y, width, area.height, false); | |
int height = 0; | |
if (oldArea.height < area.height) { | |
height = area.height - oldArea.height + BORDER_BOTTOM; | |
} | |
if (oldArea.height > area.height) { | |
height = BORDER_BOTTOM; | |
} | |
redraw(area.x, area.y + area.height - height, area.width, height, false); | |
} | |
oldArea = area; | |
} | |
/** | |
* Sets the content. | |
* Setting the content to null will remove it from | |
* the pane - however, the creator of the content must dispose of the content. | |
* | |
* @param c the control to be displayed in the content area or null | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
*/ | |
public void setContent(Control content) { | |
checkWidget(); | |
if (content != null && content.getParent() != this) { | |
SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
} | |
if (this.content != null && !this.content.isDisposed()) { | |
this.content.setBounds(OFFSCREEN, OFFSCREEN, 0, 0); | |
} | |
this.content = content; | |
layout(); | |
} | |
/** | |
* Set the widget font. | |
* This will apply the font to the topLeft, topRight and topCenter widgets. | |
*/ | |
public void setFont(Font f) { | |
super.setFont(f); | |
if (topLeft != null && !topLeft.isDisposed()) topLeft.setFont(f); | |
if (topCenter != null && !topCenter.isDisposed()) topCenter.setFont(f); | |
if (topRight != null && !topRight.isDisposed()) topRight.setFont(f); | |
layout(); | |
} | |
/** | |
* Sets the layout which is associated with the receiver to be | |
* the argument which may be null. | |
* <p> | |
* Note : ViewForm does not use a layout class to size and position its children. | |
* </p> | |
* | |
* @param the receiver's new layout or null | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
*/ | |
public void setLayout (Layout layout) { | |
checkWidget(); | |
return; | |
} | |
/** | |
* Set the control that appears in the top center of the pane. | |
* Typically this is a toolbar. | |
* The topCenter is optional. Setting the topCenter to null will remove it from | |
* the pane - however, the creator of the topCenter must dispose of the topCenter. | |
* | |
* @param c the control to be displayed in the top center or null | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
*/ | |
public void setTopCenter(Control topCenter) { | |
checkWidget(); | |
if (topCenter != null && topCenter.getParent() != this) { | |
SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
} | |
if (this.topCenter != null && !this.topCenter.isDisposed()) { | |
this.topCenter.setBounds(OFFSCREEN, OFFSCREEN, 0, 0); | |
} | |
this.topCenter = topCenter; | |
layout(); | |
} | |
/** | |
* Set the control that appears in the top left corner of the pane. | |
* Typically this is a label such as CLabel. | |
* The topLeft is optional. Setting the top left control to null will remove it from | |
* the pane - however, the creator of the control must dispose of the control. | |
* | |
* @param c the control to be displayed in the top left corner or null | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
*/ | |
public void setTopLeft(Control c) { | |
checkWidget(); | |
if (c != null && c.getParent() != this) { | |
SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
} | |
if (this.topLeft != null && !this.topLeft.isDisposed()) { | |
this.topLeft.setBounds(OFFSCREEN, OFFSCREEN, 0, 0); | |
} | |
this.topLeft = c; | |
layout(); | |
} | |
/** | |
* Set the control that appears in the top right corner of the pane. | |
* Typically this is a Close button or a composite with a Menu and Close button. | |
* The topRight is optional. Setting the top right control to null will remove it from | |
* the pane - however, the creator of the control must dispose of the control. | |
* | |
* @param c the control to be displayed in the top right corner or null | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* <li>ERROR_INVALID_ARGUMENT - if the control is not a child of this ViewForm</li> | |
* </ul> | |
*/ | |
public void setTopRight(Control c) { | |
checkWidget(); | |
if (c != null && c.getParent() != this) { | |
SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
} | |
if (this.topRight != null && !this.topRight.isDisposed()) { | |
this.topRight.setBounds(OFFSCREEN, OFFSCREEN, 0, 0); | |
} | |
this.topRight = c; | |
layout(); | |
} | |
/** | |
* Specify whether the border should be displayed or not. | |
* | |
* @param show true if the border should be displayed | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
*/ | |
public void setBorderVisible(boolean show) { | |
checkWidget(); | |
if (showBorder == show) return; | |
showBorder = show; | |
if (showBorder) { | |
if ((getStyle() & SWT.FLAT)!= 0) { | |
BORDER_LEFT = BORDER_TOP = BORDER_RIGHT = BORDER_BOTTOM = 1; | |
} else { | |
BORDER_LEFT = BORDER_TOP = 1; | |
BORDER_RIGHT = BORDER_BOTTOM = 3; | |
} | |
} else { | |
BORDER_BOTTOM = BORDER_TOP = BORDER_LEFT = BORDER_RIGHT = 0; | |
} | |
layout(); | |
redraw(); | |
} | |
/** | |
* If true, the topCenter will always appear on a separate line by itself, otherwise the | |
* topCenter will appear in the top row if there is room and will be moved to the second row if | |
* required. | |
* | |
* @param show true if the topCenter will always appear on a separate line by itself | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
* </ul> | |
*/ | |
public void setTopCenterSeparate(boolean show) { | |
checkWidget(); | |
separateTopCenter = show; | |
layout(); | |
} | |
} |