blob: a14b13ee4b2df105966cc78c5b7af78e5f85c7c4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.custom;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.*;
import org.eclipse.swt.events.*;
/**
* DO NOT USE - UNDER CONSTRUCTION
*
* @ since 3.0
*/
/**
* Instances of this class implement a Composite that ...
* <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>NONE</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 CBanner extends Composite {
Control left;
Control middle;
Control right;
int[] curve;
int curveStart;
static final int OFFSCREEN = -200;
static final int CURVE_WIDTH = 50;
static final int CURVE_RIGHT = 30;
static final int CURVE_LEFT = 30;
static final int LEFT_MIDDLE_GAP = 8;
static final int BORDER_BOTTOM = 2;
static final int BORDER_TOP = 2;
static final int BORDER_LEFT = 2;
static final int BORDER_RIGHT = 2;
static final int BORDER_STRIPE = 2;
static final int INDENT = 5;
static RGB BORDER1 = null;
static RGB BORDER2 = null;
public CBanner(Composite parent, int style) {
super(parent, checkStyle(style));
if (BORDER1 == null) {
BORDER1 = getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW).getRGB();
}
if (BORDER2 == null) {
BORDER2 = getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW).getRGB();
}
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();
}
});
}
static int[] bezier(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3, int count) {
// The parametric equations for a Bezier curve for x[t] and y[t] where 0 <= t <=1 are:
// x[t] = x0+3(x1-x0)t+3(x0+x2-2x1)t^3+(x3-x0+3x1-3x2)t^3
// y[t] = y0+3(y1-y0)t+3(y0+y2-2y1)t^2+(y3-y0+3y1-3y2)t^3
double a0 = x0;
double a1 = 3*(x1 - x0);
double a2 = 3*(x0 + x2 - 2*x1);
double a3 = x3 - x0 + 3*x1 - 3*x2;
double b0 = y0;
double b1 = 3*(y1 - y0);
double b2 = 3*(y0 + y2 - 2*y1);
double b3 = y3 - y0 + 3*y1 - 3*y2;
int[] polygon = new int[2*count + 2];
for (int i = 0; i <= count; i++) {
double t = (double)i / (double)count;
polygon[2*i] = (int)(a0 + a1*t + a2*t*t + a3*t*t*t);
polygon[2*i + 1] = (int)(b0 + b1*t + b2*t*t + b3*t*t*t);
}
return polygon;
}
/**
* Check the style bits to ensure that no invalid styles are applied.
* @private
*/
static int checkStyle (int style) {
return SWT.NO_BACKGROUND;
}
public Point computeSize(int wHint, int hHint, boolean changed) {
checkWidget();
Point rightSize = new Point(0, 0);
if (right != null) {
rightSize = right.computeSize(SWT.DEFAULT, hHint);
}
Point middleSize = new Point(0, 0);
if (middle != null) {
middleSize = middle.computeSize(SWT.DEFAULT, hHint);
}
Point leftSize = new Point(0, 0);
if (left != null) {
int width = wHint - rightSize.x - middleSize.x - CURVE_WIDTH - 2*INDENT - BORDER_LEFT - BORDER_RIGHT;
if (middle != null) width -= LEFT_MIDDLE_GAP;
leftSize = left.computeSize((wHint != SWT.DEFAULT) ? width : SWT.DEFAULT, SWT.DEFAULT);
}
Point size = new Point(0, 0);
size.x = leftSize.x + middleSize.x + CURVE_WIDTH -2*INDENT + rightSize.x;
if (left != null && middle != null) size.x += + LEFT_MIDDLE_GAP;
size.y = Math.max(Math.max(leftSize.y, middleSize.y), rightSize.y);
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 + 2*BORDER_STRIPE;
return new Rectangle(trimX, trimY, trimWidth, trimHeight);
}
public Rectangle getClientArea() {
return new Rectangle(0, 0, 0, 0);
}
public Control getLeft() {
checkWidget();
return left;
}
public Control getMiddle() {
checkWidget();
return middle;
}
public Control getRight() {
checkWidget();
return right;
}
public void layout (boolean changed) {
checkWidget();
Point size = getSize();
Point rightSize = (right == null) ? new Point (0, 0) : right.computeSize(SWT.DEFAULT, SWT.DEFAULT);
Point middleSize = (middle == null) ? new Point (0, 0) : middle.computeSize(SWT.DEFAULT, SWT.DEFAULT);
int width = size.x - rightSize.x - middleSize.x - CURVE_WIDTH + 2*INDENT - BORDER_LEFT - BORDER_RIGHT;
if (middle != null) width -= LEFT_MIDDLE_GAP;
Point leftSize = (left == null) ? new Point (0, 0) : left.computeSize(width, SWT.DEFAULT);
int x = BORDER_LEFT;
int oldStart = curveStart;
Rectangle leftRect = null;
Rectangle middleRect = null;
Rectangle rightRect = null;
if(left != null) {
int height = size.y - BORDER_TOP - BORDER_BOTTOM - BORDER_STRIPE;
int y = BORDER_STRIPE + BORDER_TOP;
leftRect = new Rectangle(x, y, leftSize.x, Math.min(height, leftSize.y));
x += leftSize.x;
}
if (middle != null) {
if (left != null) x += LEFT_MIDDLE_GAP;
int height = Math.min(size.y - BORDER_TOP - BORDER_BOTTOM - 2*BORDER_STRIPE, middleSize.y);
int y = BORDER_STRIPE + BORDER_TOP;
middleRect = new Rectangle(x, y, middleSize.x, height);
x += middleSize.x;
}
curveStart = x - INDENT;
x += CURVE_WIDTH - 2*INDENT;
if (right != null) {
int height = Math.min(size.y - BORDER_TOP - BORDER_BOTTOM - 2*BORDER_STRIPE, rightSize.y);
int y = BORDER_STRIPE + BORDER_TOP;
rightRect = new Rectangle(x, y, rightSize.x, height);
}
if (curveStart < oldStart) {
redraw(curveStart, 0, oldStart + CURVE_WIDTH - curveStart, size.y, false);
}
if (curveStart > oldStart) {
redraw(oldStart, 0, curveStart + CURVE_WIDTH - oldStart, size.y, false);
}
update();
if (leftRect != null) left.setBounds(leftRect);
if (middleRect != null) middle.setBounds(middleRect);
if (rightRect != null) right.setBounds(rightRect);
}
private void onDispose() {
left = null;
right = null;
}
private void onPaint(GC gc) {
if (curve == null) updateCurve();
Point size = getSize();
// TODO Consider a way to not draw background
// under lines
Color background = getBackground();
gc.setBackground(background);
gc.fillRectangle(0, 0, size.x, size.y);
int[] line1 = new int[curve.length+6];
int[] line2 = new int[curve.length+6];
int index = 0;
int x = curveStart;
int y = 0;
line1[index] = x + 1;
line2[index++] = x + 1;
line1[index] = size.y - BORDER_STRIPE;
line2[index++] = size.y - BORDER_STRIPE + 1;
for (int i = 0; i < curve.length/2; i++) {
line1[index]=x+curve[2*i];
line2[index++]=x+curve[2*i];
line1[index]=y+curve[2*i+1];
line2[index++]=y+curve[2*i+1]+1;
}
line1[index] = x + CURVE_WIDTH;
line2[index++] = x + CURVE_WIDTH;
line1[index] = 0;
line2[index++] = 1;
line1[index] = size.x;
line2[index++] = size.x;
line1[index] = 0;
line2[index++] = 1;
int x1 = Math.max(0, curveStart - 200);
Color border2 = new Color(getDisplay(), BORDER2);
gc.setForeground(background);
gc.setBackground(border2);
gc.fillGradientRectangle(x1, size.y - BORDER_STRIPE + 1, curveStart-x1+1, 1, false);
gc.setForeground(border2);
gc.drawPolyline(line2);
border2.dispose();
Color border1 = new Color(getDisplay(), BORDER1);
gc.setForeground(background);
gc.setBackground(border1);
gc.fillGradientRectangle(x1, size.y - BORDER_STRIPE, curveStart-x1+1, 1, false);
gc.setForeground(border1);
gc.drawPolyline(line1);
border1.dispose();
}
private void onResize() {
updateCurve();
layout();
}
/**
* Sets the layout which is associated with the receiver to be
* the argument which may be null.
* <p>
* Note : CBanner 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;
}
public void setLeft(Control leftControl) {
checkWidget();
if (leftControl != null && leftControl.getParent() != this) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
if (left != null && !left.isDisposed()) {
left.setBounds(OFFSCREEN, OFFSCREEN, 0, 0);
}
left = leftControl;
layout();
}
public void setMiddle(Control middleControl) {
checkWidget();
if (middleControl != null && middleControl.getParent() != this) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
if (middle != null && !middle.isDisposed()) {
middle.setBounds(OFFSCREEN, OFFSCREEN, 0, 0);
}
middle = middleControl;
layout();
}
public void setRight(Control rightControl) {
checkWidget();
if (rightControl != null && rightControl.getParent() != this) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
if (right != null && !right.isDisposed()) {
right.setBounds(OFFSCREEN, OFFSCREEN, 0, 0);
}
right = rightControl;
layout();
}
void updateCurve () {
Point size = getSize();
curve = bezier(0, size.y - BORDER_STRIPE + 1,
CURVE_LEFT, size.y - BORDER_STRIPE + 1,
CURVE_WIDTH-CURVE_RIGHT, 0,
CURVE_WIDTH, 0,
CURVE_WIDTH);
// workaround to get rid of blip at end of bezier
int index = -1;
for (int i = 0; i < curve.length/2; i++) {
if (curve[2*i+1] > size.y - BORDER_STRIPE) {
index = i;
} else {
break;
}
}
if (index > -1) {
int[] newCurve = new int[curve.length - 2*(index+1)];
System.arraycopy(curve, 2*(index+1), newCurve, 0, newCurve.length);
curve = newCurve;
}
}
}