blob: 54f56a4243c1c68701845a8886a4fa69419ddf5f [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.*;
import org.eclipse.swt.accessibility.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
/**
* DO NOT USE - UNDER CONSTRUCTION
*
* @ since 3.0
*/
/**
* Instances of this class implement the notebook user interface
* metaphor. It allows the user to select a notebook page from
* set of pages.
* <p>
* The item children that may be added to instances of this class
* must be of type <code>CTabItem</code>.
* <code>Control</code> children are created and then set into a
* tab item using <code>CTabItem#setControl</code>.
* </p><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>CLOSE, TOP, BOTTOM, FLAT, BORDER, SINGLE, MULTI</dd>
* <dt><b>Events:</b></dt>
* <dd>Selection</dd>
* <dd>"CTabFolder"</dd>
* </dl>
* <p>
* Note: Only one of the styles TOP and BOTTOM
* may be specified.
* </p><p>
* IMPORTANT: This class is <em>not</em> intended to be subclassed.
* </p>
*/
public class CTabFolder2 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;
/**
* A multiple of the tab height that specifies the minimum width to which a tab
* will be compressed before scrolling arrows are used to navigate the tabs.
*
* NOTE This field is badly named for historical reasons. It is not static.
*/
public int MIN_TAB_WIDTH = 8;
/**
* 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);
/* sizing, positioning, appearance */
int xClient, yClient;
boolean onBottom = false;
boolean single = false;
boolean fixedTabHeight;
int tabHeight;
/* item management */
CTabItem2 items[] = new CTabItem2[0];
int selectedIndex = -1;
int topTabIndex = -1; // index of the left most visible tab.
/* External Listener management */
CTabFolderCloseListener[] closeListeners = new CTabFolderCloseListener[0];
CTabFolderMinMaxListener[] minmaxListeners = new CTabFolderMinMaxListener[0];
CTabFolderListListener[] listListeners = new CTabFolderListListener[0];
/* Color appearance */
Image backgroundImage;
boolean tiled;
Color[] gradientColors;
int[] gradientPercents;
boolean gradientVertical;
Color selectionForeground;
Color selectionBackground;
static Color borderColor1;
static Color borderColor2;
static Color borderColor3;
// close, min/max and chevron buttons
boolean showClose = false;
Rectangle chevronRect = new Rectangle(0, 0, 0, 0);
int chevronImageState = NORMAL;
boolean showMin = false;
Rectangle minRect = new Rectangle(0, 0, 0, 0);
boolean minimized = false;
int minImageState = NORMAL;
boolean showMax = false;
Rectangle maxRect = new Rectangle(0, 0, 0, 0);
boolean maximized = false;
int maxImageState = NORMAL;
Control topRight;
Rectangle topRightRect = new Rectangle(0, 0, 0, 0);
boolean tipShowing;
boolean ignoreUp;
// borders and shapes
int borderLeft = 0;
int borderRight = 0;
int borderTop = 0;
int borderBottom = 0;
int[] curve;
// when disposing CTabFolder, don't try to layout the items or
// change the selection as each child is destroyed.
boolean inDispose = false;
// keep track of size changes in order to redraw only affected area
// on Resize
Point oldSize;
Font oldFont;
// insertion marker
int insertionIndex = -2; // Index of insert marker. Marker always shown after index.
// -2 means no insert marker
// internal constants
static final int DEFAULT_WIDTH = 64;
static final int DEFAULT_HEIGHT = 64;
static final int HIGHLIGHT_HEADER = 5;
static final int HIGHLIGHT_MARGIN = 3;
static final int CURVE_WIDTH = 50;
static final int CURVE_RIGHT = 30;
static final int CURVE_LEFT = 30;
static final int BUTTON_SIZE = 16;
static final int[] TOP_LEFT_CORNER = new int[] {0,5, 1,4, 1,3, 2,2, 3,1, 4,1, 5,0};
static final int[] TOP_RIGHT_CORNER = new int[] {-5,0, -4,1, -3,1, -2,2, -1,3, -1,4, 0,5};
static final int[] BOTTOM_LEFT_CORNER = new int[] {0,-5, 1,-4, 1,-3, 2,-2, 3,-1, 4,-1, 5,0};
static final int[] BOTTOM_RIGHT_CORNER = new int[] {-5,0, -4,-1, -3,-1, -2,-2, -1,-3, -1,-4, 0,-5};
static final int[] TOP_LEFT_OUTSIDE_CORNER = new int[] {0,6, 1,5, 1,4, 4,1, 5,1, 6,0};
static final int[] TOP_RIGHT_OUTSIDE_CORNER = new int[] {-6,0, -5,1, -4,1, -1,4, -1,5, 0,6};
static final int[] BOTTOM_LEFT_OUTSIDE_CORNER = new int[] {0,-6, 1,-5, 1,-4, 4,-1, 5,-1, 6,0};
static final int[] BOTTOM_RIGHT_OUTSIDE_CORNER = new int[] {-6,0, -5,-1, -4,-1, -1,-4, -1,-5, 0,-6};
static final int SELECTION_FOREGROUND = SWT.COLOR_TITLE_FOREGROUND;
static final int SELECTION_BACKGROUND = SWT.COLOR_TITLE_BACKGROUND;
static final int BORDER1_COLOR = SWT.COLOR_WIDGET_NORMAL_SHADOW;
static final int BORDER2_COLOR = SWT.COLOR_WIDGET_DARK_SHADOW;
static final int BORDER3_COLOR = SWT.COLOR_WIDGET_NORMAL_SHADOW;
static final int FOREGROUND = SWT.COLOR_TITLE_INACTIVE_FOREGROUND;
static final int BACKGROUND = SWT.COLOR_TITLE_INACTIVE_BACKGROUND;
static final int NONE = 0;
static final int NORMAL = 1;
static final int HOT = 2;
static final int SELECTED = 3;
static final RGB CLOSE_BORDER = new RGB(221, 106, 106);
static final RGB CLOSE_FILL = new RGB(214, 195, 195);
static final RGB MINMAX_BORDER = new RGB(114, 106, 221);
static final RGB MINMAX_FILL = new RGB(199, 196, 242);
static final RGB CHEVRON_BORDER = new RGB(111, 220, 106);
static final RGB CHEVRON_FILL = new RGB(199, 242, 196);
/**
* 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#TOP
* @see SWT#BOTTOM
* @see SWT#FLAT
* @see SWT#BORDER
* @see SWT#SINGLE
* @see SWT#MULTI
* @see #getStyle()
*/
public CTabFolder2(Composite parent, int style) {
super(parent, checkStyle (style));
int style2 = super.getStyle();
onBottom = (style2 & SWT.BOTTOM) != 0;
showClose = (style2 & SWT.CLOSE) != 0;
// showMin = (style2 & SWT.MIN) != 0; - conflicts with SWT.TOP
// showMax = (style2 & SWT.MAX) != 0; - conflicts with SWT.BOTTOM
single = (style2 & SWT.SINGLE) != 0;
borderLeft = borderRight = (style & SWT.BORDER) != 0 ? 1 : 0;
borderTop = onBottom ? borderLeft : 0;
borderBottom = onBottom ? 0 : borderLeft;
//set up default colors
Display display = getDisplay();
selectionForeground = display.getSystemColor(SELECTION_FOREGROUND);
selectionBackground = display.getSystemColor(SELECTION_BACKGROUND);
borderColor1 = new Color(getDisplay(), borderInsideRGB);
borderColor2 = new Color(getDisplay(), borderMiddleRGB);
borderColor3 = new Color(getDisplay(), borderOutsideRGB);
setForeground(display.getSystemColor(FOREGROUND));
setBackground(display.getSystemColor(BACKGROUND));
initAccessible();
// Add all listeners
Listener listener = new Listener() {
public void handleEvent(Event event) {
switch (event.type) {
case SWT.Dispose: onDispose(); break;
case SWT.FocusIn: onFocus(event); break;
case SWT.FocusOut: onFocus(event); break;
case SWT.MenuDetect: onMenu(event); break;
case SWT.MouseDoubleClick: onMouseDoubleClick(event); break;
case SWT.MouseDown: onMouse(event); break;
case SWT.MouseExit: onMouse(event); break;
case SWT.MouseHover: onMouseHover(event); break;
case SWT.MouseMove: onMouse(event); break;
case SWT.MouseUp: onMouse(event); break;
case SWT.Paint: onPaint(event); break;
case SWT.Resize: onResize(); break;
case SWT.Traverse: onTraverse(event); break;
}
}
};
int[] folderEvents = new int[]{
SWT.Dispose,
SWT.FocusIn,
SWT.FocusOut,
SWT.KeyDown,
SWT.MenuDetect,
SWT.MouseDoubleClick,
SWT.MouseDown,
SWT.MouseExit,
SWT.MouseHover,
SWT.MouseMove,
SWT.MouseUp,
SWT.Paint,
SWT.Resize,
SWT.Traverse,
};
for (int i = 0; i < folderEvents.length; i++) {
addListener(folderEvents[i], listener);
}
}
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;
}
static int checkStyle (int style) {
int mask = SWT.CLOSE | SWT.TOP | SWT.BOTTOM | SWT.FLAT | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT | SWT.SINGLE | SWT.MULTI;
style = style & mask;
// TOP and BOTTOM are mutually exlusive.
// TOP is the default
if ((style & SWT.TOP) != 0)
style = style & ~(SWT.TOP | SWT.BOTTOM) | SWT.TOP;
// SINGLE and MULTI are mutually exlusive.
// MULTI is the default
if ((style & SWT.MULTI) != 0)
style = style & ~(SWT.SINGLE | SWT.MULTI) | SWT.MULTI;
// reduce the flash by not redrawing the entire area on a Resize event
style |= SWT.NO_REDRAW_RESIZE | SWT.NO_BACKGROUND;
return style;
}
static void fillRegion(GC gc, Region region) {
// NOTE: region passed in to this function will be modified
Region clipping = new Region();
gc.getClipping(clipping);
region.intersect(clipping);
gc.setClipping(region);
gc.fillRectangle(region.getBounds());
gc.setClipping(clipping);
clipping.dispose();
}
/**
* Adds the listener to the collection of listeners who will
* be notified when a tab item is closed.
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @see CTabFolderCloseListener
* @see #removeCTabFolderCloseListener(CTabFolderCloseListener)
*
* @since 3.0
*/
public void addCTabFolderCloseListener(CTabFolderCloseListener listener) {
checkWidget();
if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
// add to array
CTabFolderCloseListener[] newListeners = new CTabFolderCloseListener[closeListeners.length + 1];
System.arraycopy(closeListeners, 0, newListeners, 0, closeListeners.length);
closeListeners = newListeners;
closeListeners[closeListeners.length - 1] = listener;
}
/**
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void addCTabFolderMinMaxListener(CTabFolderMinMaxListener listener) {
checkWidget();
if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
// add to array
CTabFolderMinMaxListener[] newListeners = new CTabFolderMinMaxListener[minmaxListeners.length + 1];
System.arraycopy(minmaxListeners, 0, newListeners, 0, minmaxListeners.length);
minmaxListeners = newListeners;
minmaxListeners[minmaxListeners.length - 1] = listener;
}
/**
* Adds the listener to the collection of listeners who will
* be notified when a tab item is closed.
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @see CTabFolderListener
* @see #removeCTabFolderListener(CTabFolderListener)
*
* @deprecated use addCTabFolderCloseListener
*/
public void addCTabFolderListener(CTabFolderListener listener) {
addCTabFolderCloseListener(listener);
if (closeListeners.length == 1) {
// display close button
showClose = true;
updateItems();
redraw();
}
}
/**
* Adds the listener to the collection of listeners who will
* be notified when a the selection list is displayed.
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @see CTabFolderListListener
* @see #removeCTabFolderListListener(CTabFolderListListener)
*
* @since 3.0
*/
public void addCTabFolderListListener(CTabFolderListListener listener) {
checkWidget();
if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
// add to array
CTabFolderListListener[] newListeners = new CTabFolderListListener[listListeners.length + 1];
System.arraycopy(listListeners, 0, newListeners, 0, listListeners.length);
listListeners = newListeners;
listListeners[listListeners.length - 1] = listener;
}
/**
* Adds the listener to receive events.
* <p>
*
* @param listener the listener
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*/
public void addSelectionListener(SelectionListener listener) {
checkWidget();
if (listener == null) {
SWT.error(SWT.ERROR_NULL_ARGUMENT);
}
TypedListener typedListener = new TypedListener(listener);
addListener(SWT.Selection, typedListener);
addListener(SWT.DefaultSelection, typedListener);
}
void antialias (int[] shape, RGB lineRGB, RGB innerRGB, RGB outerRGB, GC gc){
if (outerRGB != null) {
int index = 0;
boolean left = true;
int oldY = onBottom ? 0 : getSize().y;
int[] outer = new int[shape.length];
for (int i = 0; i < shape.length/2; i++) {
if (left && (index + 3 < shape.length)) {
left = onBottom ? oldY <= shape[index+3] : oldY >= shape[index+3];
oldY = shape[index+1];
}
outer[index] = shape[index++] + (left ? -1 : +1);
outer[index] = shape[index++];
}
RGB from = lineRGB;
RGB to = outerRGB;
int red = from.red + 4*(to.red - from.red)/5;
int green = from.green + 4*(to.green - from.green)/5;
int blue = from.blue + 4*(to.blue - from.blue)/5;
Color color = new Color(getDisplay(), red, green, blue);
gc.setForeground(color);
gc.drawPolyline(outer);
color.dispose();
}
if (innerRGB != null) {
int[] inner = new int[shape.length];
int index = 0;
boolean left = true;
int oldY = onBottom ? 0 : getSize().y;
for (int i = 0; i < shape.length/2; i++) {
if (left && (index + 3 < shape.length)) {
left = onBottom ? oldY <= shape[index+3] : oldY >= shape[index+3];
oldY = shape[index+1];
}
inner[index] = shape[index++] + (left ? +1 : -1);
inner[index] = shape[index++];
}
RGB from = lineRGB;
RGB to = innerRGB;
int red = from.red + 4*(to.red - from.red)/5;
int green = from.green + 4*(to.green - from.green)/5;
int blue = from.blue + 4*(to.blue - from.blue)/5;
Color color = new Color(getDisplay(), red, green, blue);
gc.setForeground(color);
gc.drawPolyline(inner);
color.dispose();
}
}
public Point computeSize (int wHint, int hHint, boolean changed) {
checkWidget();
int minWidth = 0;
int minHeight = 0;
// preferred width of tab area to show all tabs
GC gc = new GC(this);
int selectedMax = 0;
int selectedMaxIndex = -1;
for (int i = 0; i < items.length; i++) {
int width = items[i].preferredWidth(gc, true);
if ( width > selectedMax) {
selectedMax = width;
selectedMaxIndex = i;
}
}
for (int i = 0; i < items.length; i++) {
minWidth += items[i].preferredWidth(gc, i == selectedMaxIndex);
}
gc.dispose();
// preferred size of controls in tab items
for (int i = 0; i < items.length; i++) {
Control control = items[i].getControl();
if (control != null && !control.isDisposed()){
Point size = control.computeSize (wHint, hHint);
minWidth = Math.max (minWidth, size.x);
minHeight = Math.max (minHeight, size.y);
}
}
if (minWidth == 0) minWidth = DEFAULT_WIDTH;
if (minHeight == 0) minHeight = DEFAULT_HEIGHT;
if (minimized) minHeight = 0;
if (wHint != SWT.DEFAULT) minWidth = wHint;
if (hHint != SWT.DEFAULT) minHeight = hHint;
Rectangle trim = computeTrim(0, 0, minWidth, minHeight);
return new Point (trim.width, trim.height);
}
public Rectangle computeTrim (int x, int y, int width, int height) {
checkWidget();
if (minimized) {
int trimX = x - borderLeft;
int trimY = onBottom ? y - borderTop : y - HIGHLIGHT_HEADER - tabHeight - borderTop;
int trimWidth = width + borderLeft + borderRight;
int trimHeight = borderTop + borderBottom + tabHeight + HIGHLIGHT_HEADER;
return new Rectangle (trimX, trimY, trimWidth, trimHeight);
} else {
int style = getStyle();
boolean highlight = (style & SWT.BORDER) != 0 && (style & SWT.FLAT) == 0;
int trimX = x - marginWidth - borderLeft;
if (highlight) trimX -= HIGHLIGHT_MARGIN;
int trimY = onBottom ? y - marginHeight - borderTop : y - marginHeight - HIGHLIGHT_HEADER - tabHeight - borderTop;
if (highlight && onBottom) trimX -= HIGHLIGHT_MARGIN;
int trimWidth = width + borderLeft + borderRight + 2*marginWidth;
if (highlight) trimWidth += 2*HIGHLIGHT_MARGIN;
int trimHeight = height + borderTop + borderBottom + 2*marginHeight + tabHeight + HIGHLIGHT_HEADER;
if (highlight) trimHeight += HIGHLIGHT_HEADER + HIGHLIGHT_MARGIN;
return new Rectangle (trimX, trimY, trimWidth, trimHeight);
}
}
void createItem (CTabItem2 item, int index) {
if (0 > index || index > getItemCount ()){
SWT.error (SWT.ERROR_INVALID_RANGE);
}
// grow by one and rearrange the array.
CTabItem2[] newItems = new CTabItem2 [items.length + 1];
System.arraycopy(items, 0, newItems, 0, index);
newItems[index] = item;
System.arraycopy(items, index, newItems, index + 1, items.length - index);
items = newItems;
item.parent = this;
if (selectedIndex >= index) {
selectedIndex ++;
}
if (items.length == 1) {
topTabIndex = 0;
if (!updateTabHeight(tabHeight, false)) updateItems();
redraw();
} else {
updateItems();
// redraw tabs if new item visible
if (index == topTabIndex ||
(index > topTabIndex && item.x + item.width < getRightItemEdge())){
redraw();
}
}
}
void destroyItem (CTabItem2 item) {
if (inDispose) return;
int index = indexOf(item);
if (index == -1) return;
insertionIndex = -2;
if (items.length == 1) {
items = new CTabItem2[0];
selectedIndex = -1;
topTabIndex = 0;
Control control = item.getControl();
if (control != null && !control.isDisposed()) {
control.setVisible(false);
}
if (!fixedTabHeight) tabHeight = 0;
redraw();
return;
}
// shrink by one and rearrange the array.
CTabItem2[] newItems = new CTabItem2 [items.length - 1];
System.arraycopy(items, 0, newItems, 0, index);
System.arraycopy(items, index + 1, newItems, index, items.length - index - 1);
items = newItems;
if (topTabIndex == items.length) {
--topTabIndex;
}
// move the selection if this item is selected
if (selectedIndex == index) {
Control control = item.getControl();
selectedIndex = -1;
setSelection(Math.max(0, index - 1), true);
if (control != null && !control.isDisposed()) {
control.setVisible(false);
}
} else if (selectedIndex > index) {
selectedIndex --;
}
if (updateItems()) redraw();
}
void drawBorder(GC gc) {
Point size = getSize();
// Draw selection border across all tabs
if (selectedIndex == -1) { // no selected item
int x = borderLeft;
int y = onBottom ? size.y - borderBottom - tabHeight - HIGHLIGHT_HEADER : borderTop + tabHeight + 1;
int width = size.x - borderLeft - borderRight;
int height = HIGHLIGHT_HEADER - 1;
gc.setBackground(getBackground());
gc.fillRectangle(x, y, width, height);
x = borderLeft;
y = (onBottom) ? size.y - borderBottom - tabHeight - 1 : borderTop + tabHeight;
gc.setForeground(borderColor1);
gc.drawLine(x, y, x + width, y);
} else { //selected item
int x = borderLeft;
int y = onBottom ? size.y - borderBottom - tabHeight - HIGHLIGHT_HEADER : borderTop + tabHeight + 1;
int width = size.x - borderLeft - borderRight;
int height = HIGHLIGHT_HEADER - 1;
int[] shape = new int[] {x,y, x+width,y, x+width,y+height, x,y+height};
drawSelectionBackground(gc, shape);
CTabItem2 item = items[selectedIndex];
int itemX = item.x;
int itemY = item.y;
int itemW = item.width;
int itemH = item.height;
int extra = CTabFolder2.CURVE_WIDTH/2 + 4; // +4 to avoid overlapping with text in next tab
if (onBottom) {
int rightTabEdge = getRightItemEdge();
if (!single && selectedIndex != topTabIndex && itemX + itemW >= rightTabEdge){
shape = new int[4];
int index = 0;
shape[index++] = Math.max(0, borderLeft - 1);
shape[index++] = itemY - 1;
shape[index++] = size.x - borderRight;
shape[index++] = itemY - 1;
} else {
int[] left = BOTTOM_LEFT_CORNER;
int[] right = curve;
shape = new int[left.length + right.length + 8];
int index = 0;
shape[index++] = Math.max(0, borderLeft - 1);
shape[index++] = itemY - 1;
shape[index++] = itemX;
shape[index++] = itemY - 1;
for (int i = 0; i < left.length/2; i++) {
shape[index++] = itemX + left[2*i];
shape[index++] = itemY + itemH + left[2*i+1]-1;
}
for (int i = 0; i < right.length/2; i++) {
shape[index++] = itemX + itemW - extra + right[2*i];
shape[index++] = itemY + right[2*i+1] - 2;
}
int temp = 0;
for (int i = 0; i < shape.length/2; i++) {
if (shape[2*i] > rightTabEdge) {
if (temp == 0 && i > 0) {
temp = shape[2*i-1];
} else {
temp = itemY - 1;
}
shape[2*i] = rightTabEdge;
shape[2*i+1] = temp;
}
}
shape[index++] = rightTabEdge;
shape[index++] = itemY - 1;
shape[index++] = size.x - borderRight;
shape[index++] = itemY - 1;
}
} else {
int rightTabEdge = getRightItemEdge();
if (!single && selectedIndex != topTabIndex && itemX + itemW >= rightTabEdge){
shape = new int[4];
int index = 0;
shape[index++] = Math.max(0, borderLeft - 1);
shape[index++] = itemY + itemH;
shape[index++] = size.x - borderRight;
shape[index++] = itemY + itemH;
} else {
int[] left = TOP_LEFT_CORNER;
int[] right = curve;
shape = new int[left.length+right.length+8];
int index = 0;
shape[index++] = Math.max(0, borderLeft - 1);
shape[index++] = itemY + itemH;
shape[index++] = itemX;
shape[index++] = itemY + itemH;
for (int i = 0; i < left.length/2; i++) {
shape[index++] = itemX + left[2*i];
shape[index++] = itemY + left[2*i+1];
}
for (int i = 0; i < right.length/2; i++) {
shape[index++] = itemX + itemW - extra + right[2*i];
shape[index++] = itemY + right[2*i+1];
}
int temp = 0;
for (int i = 0; i < shape.length/2; i++) {
if (shape[2*i] > rightTabEdge) {
if (temp == 0 && i > 0) {
temp = shape[2*i-1];
} else {
temp = itemY + itemH;
}
shape[2*i] = rightTabEdge;
shape[2*i+1] = temp;
}
}
shape[index++] = rightTabEdge;
shape[index++] = itemY + itemH;
shape[index++] = size.x - borderRight;
shape[index++] = itemY + itemH;
}
}
// draw line
RGB inside = selectionBackground.getRGB();
if (backgroundImage != null || (gradientColors != null && gradientColors.length > 1)) inside = null;
RGB outside = single ? getBackground().getRGB() : getParent().getBackground().getRGB();
antialias(shape, borderColor1.getRGB(), inside, outside, gc);
gc.setForeground(borderColor1);
gc.drawPolyline(shape);
}
//draw 1 pixel border around outside for flat look
if (borderLeft > 0) drawFlatBorder(gc);
// fill in client area
if (!minimized){
int style = getStyle();
int width = size.x - borderLeft - borderRight;
int height = size.y - borderTop - borderBottom - tabHeight - HIGHLIGHT_HEADER;
int x = xClient - marginWidth;
int y = yClient - marginHeight;
if (borderLeft > 0 && (style & SWT.FLAT) == 0) {
width -= 2*HIGHLIGHT_MARGIN;
height -= HIGHLIGHT_MARGIN;
if (onBottom) {
int x1 = 1;
int x2 = size.x - 1;
int y1 = size.y - borderBottom - tabHeight - HIGHLIGHT_HEADER;
gc.setForeground(selectedIndex == -1 ? getBackground() : selectionBackground);
for (int i = 0; i < HIGHLIGHT_MARGIN; i++) {
gc.drawPolyline(new int[] {x1+i, y1-1, x1+i, 1+i, x2-1-i, 1+i, x2-1-i, y1});
}
} else {
int x1 = 1;
int x2 = size.x - 1;
int y2 = borderTop + tabHeight + HIGHLIGHT_HEADER;
gc.setForeground(selectedIndex == -1 ? getBackground() : selectionBackground);
for (int i = 0; i < HIGHLIGHT_MARGIN; i++) {
gc.drawPolyline(new int[] {x1+i, y2, x1+i, size.y-2-i, x2-1-i, size.y-2-i, x2-1-i, y2-1});
}
}
}
gc.setBackground(getBackground());
gc.fillRectangle(x, y, width, height);
}
}
void drawFlatBorder(GC gc) {
Point size = getSize();
Color parentBackground = getParent().getBackground();
Color color = borderColor1;
gc.setForeground(color);
if (onBottom) {
int x1 = 0;
int x2 = size.x - borderRight;
int y1 = borderTop - 1;
int y2 = size.y - tabHeight - borderBottom - 1;
gc.drawLine(x1, y1, x1, y2); // left
gc.drawLine(x2, y1, x2, y2); // right
gc.drawLine(x1, y1, x2, y1); // top
if (single) {
int x = Math.max(0, borderLeft - 1);
int y = size.y - borderBottom - tabHeight;
int width = size.x - borderLeft - borderRight + 1;
int height = tabHeight - 1;
int[] shape = new int[BOTTOM_LEFT_OUTSIDE_CORNER.length + BOTTOM_RIGHT_OUTSIDE_CORNER.length + 4];
int index = 0;
shape[index++] = x;
shape[index++] = y;
for (int i = 0; i < BOTTOM_LEFT_OUTSIDE_CORNER.length/2; i++) {
shape[index++] = x+BOTTOM_LEFT_OUTSIDE_CORNER[2*i];
shape[index++] = y+height+BOTTOM_LEFT_OUTSIDE_CORNER[2*i+1];
}
for (int i = 0; i < BOTTOM_RIGHT_OUTSIDE_CORNER.length/2; i++) {
shape[index++] = x+width+BOTTOM_RIGHT_OUTSIDE_CORNER[2*i];
shape[index++] = y+height+BOTTOM_RIGHT_OUTSIDE_CORNER[2*i+1];
}
shape[index++] = x+width;
shape[index++] = y-1;
antialias(shape, borderColor1.getRGB(), getBackground().getRGB(), parentBackground.getRGB(), gc);
gc.setForeground(borderColor1);
gc.drawPolyline(shape);
}
} else {
int x1 = borderLeft - 1;
int x2 = size.x - borderRight;
int y1 = borderTop + tabHeight;
int y2 = size.y - borderBottom;
gc.drawLine(x1, y1, x1, y2); // left
gc.drawLine(x2, y1, x2, y2); // right
gc.drawLine(x1, y2, x2, y2); //bottom
if (single) {
int x = Math.max(0, borderLeft - 1);
int y = borderTop;
int width = size.x - borderLeft - borderRight + 1;
int height = tabHeight - 1;
int[] shape = new int[TOP_LEFT_OUTSIDE_CORNER.length + TOP_RIGHT_OUTSIDE_CORNER.length + 4];
int index = 0;
shape[index++] = x;
shape[index++] = y+height;
for (int i = 0; i < TOP_LEFT_OUTSIDE_CORNER.length/2; i++) {
shape[index++] = x+TOP_LEFT_OUTSIDE_CORNER[2*i];
shape[index++] = y+TOP_LEFT_OUTSIDE_CORNER[2*i+1];
}
for (int i = 0; i < TOP_RIGHT_OUTSIDE_CORNER.length/2; i++) {
shape[index++] = x+width+TOP_RIGHT_OUTSIDE_CORNER[2*i];
shape[index++] = y+TOP_RIGHT_OUTSIDE_CORNER[2*i+1];
}
shape[index++] = x+width;
shape[index++] = y+height+1;
antialias(shape, borderColor1.getRGB(), getBackground().getRGB(), parentBackground.getRGB(), gc);
gc.setForeground(borderColor1);
gc.drawPolyline(shape);
}
}
}
void drawChevron(GC gc) {
if (chevronRect.width == 0 || chevronRect.height == 0) return;
Display display = getDisplay();
if (!single) {
gc.setBackground(getParent().getBackground());
gc.fillRectangle(chevronRect);
}
// draw chevron (10x7)
int indent = Math.max(1, (tabHeight-11)/2);
int x = chevronRect.x + indent - 1;
int y = chevronRect.y + indent;
switch (chevronImageState) {
case NORMAL: {
int[] shape = onBottom ? new int[]{x,y+9, x+9,y+9, x+9,y+7, x+5,y+3, x+4,y+3, x,y+7, x,y+9} : new int[]{x,y, x+9,y, x+9,y+2, x+5,y+6, x+4,y+6, x,y+2, x,y};
gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
gc.fillPolygon(shape);
gc.setForeground(borderColor1);
gc.drawPolygon(shape);
break;
}
case HOT: {
int[] shape = onBottom ? new int[]{x,y+9, x+9,y+9, x+9,y+7, x+5,y+3, x+4,y+3, x,y+7, x,y+9} : new int[] {x,y, x+9,y, x+9,y+2, x+5,y+6, x+4,y+6, x,y+2, x,y};
gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE));
gc.fillPolygon(shape);
Color border = new Color(display, CHEVRON_BORDER);
gc.setForeground(border);
gc.drawPolygon(shape);
border.dispose();
break;
}
case SELECTED: {
int[] shape = onBottom ? new int[]{x+1,y+10, x+10,y+10, x+10,y+8, x+6,y+4, x+5,y+4, x+1,y+8, x+1,y+10} : new int[] {x+1,y+1, x+10,y+1, x+10,y+3, x+6,y+7, x+5,y+7, x+1,y+3, x+1,y+1};
Color fill = new Color(display, CHEVRON_FILL);
gc.setBackground(fill);
gc.fillPolygon(shape);
fill.dispose();
Color border = new Color(display, CHEVRON_BORDER);
gc.setForeground(border);
gc.drawPolygon(shape);
border.dispose();
break;
}
}
}
void drawMaximize(GC gc) {
if (maxRect.width == 0 || maxRect.height == 0) return;
Display display = getDisplay();
if (!single) {
gc.setBackground(getParent().getBackground());
gc.fillRectangle(maxRect);
}
int indent = Math.max(1, (tabHeight-11)/2);
int x = maxRect.x + indent - 1;
int y = maxRect.y + indent;
switch (maxImageState) {
case NORMAL: {
if (!maximized) {
gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
gc.fillRectangle(x, y, 7, 9);
gc.setForeground(borderColor1);
gc.drawRectangle(x, y, 7, 9);
gc.drawLine(x+1, y+2, x+6, y+2);
} else {
gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
gc.fillRectangle(x, y+3, 5, 4);
gc.fillRectangle(x+2, y, 5, 4);
gc.setForeground(borderColor1);
gc.drawRectangle(x, y+3, 5, 4);
gc.drawRectangle(x+2, y, 5, 4);
gc.drawLine(x+3, y+1, x+6, y+1);
gc.drawLine(x+1, y+4, x+4, y+4);
}
break;
}
case HOT: {
Color border = new Color(display, MINMAX_BORDER);
if (!maximized) {
gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
gc.fillRectangle(x, y, 7, 9);
gc.setForeground(border);
gc.drawRectangle(x, y, 7, 9);
gc.drawLine(x+1, y+2, x+6, y+2);
} else {
gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
gc.fillRectangle(x, y+3, 5, 4);
gc.fillRectangle(x+2, y, 5, 4);
gc.setForeground(border);
gc.drawRectangle(x, y+3, 5, 4);
gc.drawRectangle(x+2, y, 5, 4);
gc.drawLine(x+3, y+1, x+6, y+1);
gc.drawLine(x+1, y+4, x+4, y+4);
}
border.dispose();
break;
}
case SELECTED: {
Color fill = new Color(display, MINMAX_FILL);
Color border = new Color(display, MINMAX_BORDER);
if (!maximized) {
gc.setBackground(fill);
gc.fillRectangle(x+1, y+1, 7, 9);
gc.setForeground(border);
gc.drawRectangle(x+1, y+1, 7, 9);
gc.drawLine(x+2, y+3, x+7, y+3);
} else {
gc.setBackground(fill);
gc.fillRectangle(x+1, y+4, 5, 4);
gc.fillRectangle(x+3, y+1, 5, 4);
gc.setForeground(border);
gc.drawRectangle(x+1, y+4, 5, 4);
gc.drawRectangle(x+3, y+1, 5, 4);
gc.drawLine(x+4, y+2, x+7, y+2);
gc.drawLine(x+2, y+5, x+5, y+5);
}
fill.dispose();
border.dispose();
break;
}
}
}
void drawMinimize(GC gc) {
if (minRect.width == 0 || minRect.height == 0) return;
Display display = getDisplay();
if (!single) {
gc.setBackground(getParent().getBackground());
gc.fillRectangle(minRect);
}
int indent = Math.max(1, (tabHeight-11)/2);
int x = minRect.x + indent - 1;
int y = minRect.y + indent;
switch (minImageState) {
case NORMAL: {
if (!minimized) {
gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
gc.fillRectangle(x, y, 9, 3);
gc.setForeground(borderColor1);
gc.drawRectangle(x, y, 9, 3);
} else {
gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
gc.fillRectangle(x, y+3, 5, 4);
gc.fillRectangle(x+2, y, 5, 4);
gc.setForeground(borderColor1);
gc.drawRectangle(x, y+3, 5, 4);
gc.drawRectangle(x+2, y, 5, 4);
gc.drawLine(x+3, y+1, x+6, y+1);
gc.drawLine(x+1, y+4, x+4, y+4);
}
break;
}
case HOT: {
Color border = new Color(display, MINMAX_BORDER);
if (!minimized) {
gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
gc.fillRectangle(x, y, 9, 3);
gc.setForeground(border);
gc.drawRectangle(x, y, 9, 3);
} else {
gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
gc.fillRectangle(x, y+3, 5, 4);
gc.fillRectangle(x+2, y, 5, 4);
gc.setForeground(border);
gc.drawRectangle(x, y+3, 5, 4);
gc.drawRectangle(x+2, y, 5, 4);
gc.drawLine(x+3, y+1, x+6, y+1);
gc.drawLine(x+1, y+4, x+4, y+4);
}
border.dispose();
break;
}
case SELECTED: {
Color fill = new Color(display, MINMAX_FILL);
Color border = new Color(display, MINMAX_BORDER);
if (!minimized) {
gc.setBackground(fill);
gc.fillRectangle(x+1, y+1, 9, 3);
gc.setForeground(border);
gc.drawRectangle(x+1, y+1, 9, 3);
} else {
gc.setBackground(fill);
gc.fillRectangle(x+1, y+4, 5, 4);
gc.fillRectangle(x+3, y+1, 5, 4);
gc.setForeground(border);
gc.drawRectangle(x+1, y+4, 5, 4);
gc.drawRectangle(x+3, y+1, 5, 4);
gc.drawLine(x+4, y+2, x+7, y+2);
gc.drawLine(x+2, y+5, x+5, y+5);
}
fill.dispose();
border.dispose();
break;
}
}
}
void drawSelectionBackground(GC gc, int[] shape) {
Point size = getSize();
int height = tabHeight + HIGHLIGHT_HEADER;
int y = onBottom ? size.y - borderBottom - height : borderTop;
int x = 0;
int width = size.x;
if (borderLeft > 0) {
x += 1; width -= 2;
}
Region clipping = new Region();
gc.getClipping(clipping);
Region region = new Region();
region.add(shape);
gc.setClipping(region);
if (backgroundImage != null) {
// draw the background image in shape
gc.setBackground(selectionBackground);
gc.fillRectangle(x, y, width, height);
Rectangle imageRect = backgroundImage.getBounds();
if (tiled) {
// tile image to fill space
int xPos = x;
while (xPos < x+width) {
int yPos = y;
while (yPos < y+height) {
gc.drawImage(backgroundImage, xPos, yPos);
yPos += imageRect.height;
}
xPos += imageRect.width;
}
} else {
gc.drawImage(backgroundImage, imageRect.x, imageRect.y, imageRect.width, imageRect.height, x, y, width, height);
}
} else if (gradientColors != null) {
// draw gradient
if (gradientColors.length == 1) {
Color background = gradientColors[0] != null ? gradientColors[0] : selectionBackground;
gc.setBackground(background);
gc.fillRectangle(x, y, width, height);
} else {
if (gradientVertical) {
if (onBottom) {
int pos = 0;
if (gradientPercents[gradientPercents.length - 1] < 100) {
pos = gradientPercents[gradientPercents.length - 1] * height / 100;
gc.setBackground(selectionBackground);
gc.fillRectangle(x, y, width, pos);
}
Color lastColor = gradientColors[gradientColors.length-1];
if (lastColor == null) lastColor = selectionBackground;
for (int i = gradientPercents.length-1; i >= 0; i--) {
gc.setForeground(lastColor);
lastColor = gradientColors[i];
if (lastColor == null) lastColor = selectionBackground;
gc.setBackground(lastColor);
int gradientHeight = gradientPercents[i] * height / 100;
gc.fillGradientRectangle(x, y+pos, width, gradientHeight, true);
pos += gradientHeight;
}
} else {
Color lastColor = gradientColors[0];
if (lastColor == null) lastColor = selectionBackground;
int pos = 0;
for (int i = 0; i < gradientPercents.length; i++) {
gc.setForeground(lastColor);
lastColor = gradientColors[i + 1];
if (lastColor == null) lastColor = selectionBackground;
gc.setBackground(lastColor);
int gradientHeight = gradientPercents[i] * height / 100;
gc.fillGradientRectangle(x, y+pos, width, gradientHeight, true);
pos += gradientHeight;
}
if (pos < height) {
gc.setBackground(selectionBackground);
gc.fillRectangle(x, pos, width, height-pos);
}
}
} else { //horizontal gradient
Color lastColor = gradientColors[0];
if (lastColor == null) lastColor = selectionBackground;
int pos = 0;
for (int i = 0; i < gradientPercents.length; ++i) {
gc.setForeground(lastColor);
lastColor = gradientColors[i + 1];
if (lastColor == null) lastColor = selectionBackground;
gc.setBackground(lastColor);
int gradientWidth = (gradientPercents[i] * width / 100) - pos;
gc.fillGradientRectangle(x+pos, y, gradientWidth, height, false);
pos += gradientWidth;
}
if (pos < width) {
gc.setBackground(selectionBackground);
gc.fillRectangle(x+pos, y, width-pos, height);
}
}
}
} else {
// draw a solid background using selectionBackground in shape
gc.setBackground(selectionBackground);
gc.fillRectangle(x, y, width, height);
}
gc.setClipping(clipping);
clipping.dispose();
region.dispose();
}
public boolean getBorderVisible() {
checkWidget();
return borderLeft == 1;
}
public Rectangle getClientArea() {
checkWidget();
if (minimized) return new Rectangle(xClient, yClient, 0, 0);
int style = getStyle();
boolean highlight = (style & SWT.BORDER) != 0 && (style & SWT.FLAT) == 0;
Point size = getSize();
int width = size.x - borderLeft - borderRight - 2*marginWidth;
if (highlight)width -= 2*HIGHLIGHT_MARGIN;
int height = size.y - borderTop - borderBottom - 2*marginHeight;
if (highlight)height -= + HIGHLIGHT_MARGIN;
if (items.length == 0) {
return new Rectangle(borderLeft + marginWidth, borderTop + marginHeight, width, height);
}
height -= tabHeight+HIGHLIGHT_HEADER;
return new Rectangle(xClient, yClient, width, height);
}
/**
* Returns <code>false</code> if the receiver is minimized,
* and true otherwise.
* <p>
*
* @return the minimized state
*
* @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>
*
* @deprecated use getMinimized(boolean)
*/
public boolean getExpanded() {
return getMinimized();
}
/**
* Return the tab that is located at the specified index.
*
* @param index the index of the tab item
* @return the item at the specified index
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_INVALID_RANGE - if the index is out of range</li>
* </ul>
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*/
public CTabItem2 getItem (int index) {
//checkWidget();
if (index < 0 || index >= items.length)
SWT.error(SWT.ERROR_INVALID_RANGE);
return items [index];
}
/**
* Gets the item at a point in the widget.
*
* @param pt the point in coordinates relative to the CTabFolder
* @return the item at a point or null
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*/
public CTabItem2 getItem (Point pt) {
//checkWidget();
if (items.length == 0) return null;
Point size = getSize();
if (size.x <= borderLeft + borderRight) return null;
for (int index = topTabIndex; index < items.length; index++) {
CTabItem2 item = items[index];
Rectangle rect = item.getBounds();
if (rect.contains(pt)) return item;
}
return null;
}
/**
* Return the number of tabs in the folder.
*
* @return the number of tabs in the folder
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*/
public int getItemCount(){
//checkWidget();
return items.length;
}
/**
* Return the tab items.
*
* @return the tab items
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*/
public CTabItem2 [] getItems() {
//checkWidget();
CTabItem2[] tabItems = new CTabItem2 [items.length];
System.arraycopy(items, 0, tabItems, 0, items.length);
return tabItems;
}
char getMnemonic (String string) {
int index = 0;
int length = string.length ();
do {
while ((index < length) && (string.charAt (index) != '&')) index++;
if (++index >= length) return '\0';
if (string.charAt (index) != '&') return string.charAt (index);
index++;
} while (index < length);
return '\0';
}
/**
* Returns <code>true</code> if the receiver is minimized,
* and false otherwise.
* <p>
*
* @return the minimized state
*
* @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>
*
* @deprecated
*/
public boolean getMinimized() {
checkWidget();
return minimized;
}
/**
* Returns <code>true</code> if the receiver is maximized,
* and false otherwise.
* <p>
*
* @return the maximized state
*
* @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>
*
* @deprecated
*/
public boolean getMaximized() {
checkWidget();
return maximized;
}
int getRightItemEdge (){
return getSize().x - borderRight - minRect.width - maxRect.width - topRightRect.width - chevronRect.width - 1;
}
/**
* Return the selected tab item, or an empty array if there
* is no selection.
*
* @return the selected tab item
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*/
public CTabItem2 getSelection() {
//checkWidget();
if (selectedIndex == -1) return null;
return items[selectedIndex];
}
/**
* Return the index of the selected tab item, or -1 if there
* is no selection.
*
* @return the index of the selected tab item or -1
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*/
public int getSelectionIndex() {
//checkWidget();
return selectedIndex;
}
public int getStyle() {
int style = super.getStyle();
style &= ~(SWT.TOP | SWT.BOTTOM);
style |= onBottom ? SWT.BOTTOM : SWT.TOP;
style &= ~(SWT.SINGLE | SWT.MULTI);
style |= single ? SWT.SINGLE : SWT.MULTI;
if (borderLeft != 0) style |= SWT.BORDER;
return style;
}
/**
* Returns the height of the tab
*
* @return the height of the tab
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*/
public int getTabHeight(){
checkWidget();
return tabHeight;
}
/**
* Returns the control in the top right corner of the tab folder.
* Typically this is a close button or a composite with a menu and close button.
*
* @since 2.1
*
* @return the control in the top right corner of the tab folder or null
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @deprecated
*/
public Control getTopRight() {
checkWidget();
return topRight;
}
/**
* Return the index of the specified tab or -1 if the tab is not
* in the receiver.
*
* @param item the tab item for which the index is required
*
* @return the index of the specified tab item or -1
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*/
public int indexOf(CTabItem2 item) {
checkWidget();
if (item == null) {
SWT.error(SWT.ERROR_NULL_ARGUMENT);
}
for (int i = 0; i < items.length; i++) {
if (items[i] == item) return i;
}
return -1;
}
void initAccessible() {
final Accessible accessible = getAccessible();
accessible.addAccessibleListener(new AccessibleAdapter() {
public void getName(AccessibleEvent e) {
String name = null;
int childID = e.childID;
if (childID >= 0 && childID < items.length) {
name = items[childID].getText();
int index = name.indexOf('&');
if (index > 0) {
name = name.substring(0, index) + name.substring(index + 1);
}
}
e.result = name;
}
public void getHelp(AccessibleEvent e) {
String help = null;
int childID = e.childID;
if (childID == ACC.CHILDID_SELF) {
help = getToolTipText();
} else if (childID >= 0 && childID < items.length) {
help = items[childID].getToolTipText();
}
e.result = help;
}
public void getKeyboardShortcut(AccessibleEvent e) {
String shortcut = null;
int childID = e.childID;
if (childID >= 0 && childID < items.length) {
String text = items[childID].getText();
if (text != null) {
char mnemonic = getMnemonic(text);
if (mnemonic != '\0') {
shortcut = "Alt+"+mnemonic; //$NON-NLS-1$
}
}
}
e.result = shortcut;
}
});
accessible.addAccessibleControlListener(new AccessibleControlAdapter() {
public void getChildAtPoint(AccessibleControlEvent e) {
Point testPoint = toControl(new Point(e.x, e.y));
int childID = ACC.CHILDID_NONE;
for (int i = 0; i < items.length; i++) {
if (items[i].getBounds().contains(testPoint)) {
childID = i;
break;
}
}
if (childID == ACC.CHILDID_NONE) {
Rectangle location = getBounds();
location.height = location.height - getClientArea().height;
if (location.contains(testPoint)) {
childID = ACC.CHILDID_SELF;
}
}
e.childID = childID;
}
public void getLocation(AccessibleControlEvent e) {
Rectangle location = null;
int childID = e.childID;
if (childID == ACC.CHILDID_SELF) {
location = getBounds();
}
if (childID >= 0 && childID < items.length) {
location = items[childID].getBounds();
}
if (location != null) {
Point pt = toDisplay(new Point(location.x, location.y));
e.x = pt.x;
e.y = pt.y;
e.width = location.width;
e.height = location.height;
}
}
public void getChildCount(AccessibleControlEvent e) {
e.detail = items.length;
}
public void getDefaultAction(AccessibleControlEvent e) {
String action = null;
int childID = e.childID;
if (childID >= 0 && childID < items.length) {
action = "Switch"; //$NON-NLS-1$
}
e.result = action;
}
public void getFocus(AccessibleControlEvent e) {
int childID = ACC.CHILDID_NONE;
if (isFocusControl()) {
if (selectedIndex == -1) {
childID = ACC.CHILDID_SELF;
} else {
childID = selectedIndex;
}
}
e.childID = childID;
}
public void getRole(AccessibleControlEvent e) {
int role = 0;
int childID = e.childID;
if (childID == ACC.CHILDID_SELF) {
role = ACC.ROLE_TABFOLDER;
} else if (childID >= 0 && childID < items.length) {
role = ACC.ROLE_TABITEM;
}
e.detail = role;
}
public void getSelection(AccessibleControlEvent e) {
e.childID = (selectedIndex == -1) ? ACC.CHILDID_NONE : selectedIndex;
}
public void getState(AccessibleControlEvent e) {
int state = 0;
int childID = e.childID;
if (childID == ACC.CHILDID_SELF) {
state = ACC.STATE_NORMAL;
} else if (childID >= 0 && childID < items.length) {
state = ACC.STATE_SELECTABLE;
if (isFocusControl()) {
state |= ACC.STATE_FOCUSABLE;
}
if (selectedIndex == childID) {
state |= ACC.STATE_SELECTED;
if (isFocusControl()) {
state |= ACC.STATE_FOCUSED;
}
}
}
e.detail = state;
}
public void getChildren(AccessibleControlEvent e) {
Object[] children = new Object[items.length];
for (int i = 0; i < items.length; i++) {
children[i] = new Integer(i);
}
e.children = children;
}
});
addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
if (isFocusControl()) {
if (selectedIndex == -1) {
accessible.setFocus(ACC.CHILDID_SELF);
} else {
accessible.setFocus(selectedIndex);
}
}
}
});
addListener(SWT.FocusIn, new Listener() {
public void handleEvent(Event event) {
if (selectedIndex == -1) {
accessible.setFocus(ACC.CHILDID_SELF);
} else {
accessible.setFocus(selectedIndex);
}
}
});
}
boolean onArrowTraversal (Event event) {
int count = items.length;
if (count == 0) return false;
if (selectedIndex == -1) return false;
int offset = (event.detail == SWT.TRAVERSE_ARROW_NEXT) ? 1 : -1;
int index = selectedIndex + offset;
if (index < 0 || index >= count) return false;
setSelection (index, true);
//setFocus();
return true;
}
void onDispose() {
/*
* Usually when an item is disposed, destroyItem will change the size of the items array,
* reset the bounds of all the tabs and manage the widget associated with the tab.
* Since the whole folder is being disposed, this is not necessary. For speed
* the inDispose flag is used to skip over this part of the item dispose.
*/
inDispose = true;
int length = items.length;
for (int i = 0; i < length; i++) {
if (items[i] != null) {
items[i].dispose();
}
}
gradientColors = null;
gradientPercents = null;
backgroundImage = null;
selectionBackground = null;
selectionForeground = null;
}
void onFocus(Event event) {
checkWidget();
if (selectedIndex >= 0) {
redraw();
} else {
setSelection(0, true);
}
}
void onMenu(Event event) {
if (single && selectedIndex != -1) {
final CTabFolderEvent e = new CTabFolderEvent(CTabFolder2.this);
e.widget = this;
e.time = event.time;
Rectangle rect = items[selectedIndex].getBounds();
rect.y += onBottom ? -HIGHLIGHT_HEADER : HIGHLIGHT_HEADER;
e.rect = rect;
if (listListeners.length == 0) {
showList(e.rect, SWT.LEFT);
} else {
for (int j = 0; j < listListeners.length; j++) {
listListeners[j].showList(e);
}
}
}
}
boolean onMnemonic (Event event) {
char key = event.character;
for (int i = 0; i < items.length; i++) {
if (items[i] != null) {
char mnemonic = getMnemonic (items[i].getText ());
if (mnemonic != '\0') {
if (Character.toUpperCase (key) == Character.toUpperCase (mnemonic)) {
setSelection(i, true);
return true;
}
}
}
}
return false;
}
void onMouseDoubleClick(Event event) {
int x = event.x, y = event.y;
if (minRect.contains(x, y)) return;
if (maxRect.contains(x, y)) return;
if (chevronRect.contains(x, y)) return;
if (showMax) {
CTabFolderEvent e = new CTabFolderEvent(this);
e.widget = this;
e.time = event.time;
e.doit = true;
boolean restore = maximized;
for (int i = 0; i < minmaxListeners.length; i++) {
if (restore) {
minmaxListeners[i].restore(e);
} else {
minmaxListeners[i].maximize(e);
}
}
if (e.doit) setMaximized(!restore);
}
Event e = new Event();
e.item = getItem(new Point(event.x, event.y));
if (e.item != null) {
notifyListeners(SWT.DefaultSelection, e);
}
}
void onMouseHover(Event event) {
if (tipShowing) return;
showToolTip(event.x, event.y);
}
void onMouse(Event event) {
int x = event.x, y = event.y;
switch (event.type) {
case SWT.MouseExit: {
if (ignoreUp) ignoreUp = false;
if (minImageState != NORMAL) {
minImageState = NORMAL;
redraw(minRect.x, minRect.y, minRect.width, minRect.height, false);
update();
}
if (maxImageState != NORMAL) {
maxImageState = NORMAL;
redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height, false);
update();
}
if (chevronImageState != NORMAL) {
chevronImageState = NORMAL;
redraw(chevronRect.x, chevronRect.y, chevronRect.width, chevronRect.height, false);
update();
}
for (int i=0; i<items.length; i++) {
CTabItem2 item = items[i];
if (i != selectedIndex && item.closeImageState != NONE) {
item.closeImageState = NONE;
redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
update();
}
if (i == selectedIndex && item.closeImageState != NORMAL) {
item.closeImageState = NORMAL;
redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
update();
}
}
break;
}
case SWT.MouseDown: {
if (minRect.contains(x, y)) {
if (event.button != 1) return;
minImageState = SELECTED;
redraw(minRect.x, minRect.y, minRect.width, minRect.height, false);
update();
return;
}
if (maxRect.contains(x, y)) {
if (event.button != 1) return;
maxImageState = SELECTED;
redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height, false);
update();
return;
}
if (chevronRect.contains(x, y)) {
if (event.button != 1) return;
chevronImageState = SELECTED;
redraw(chevronRect.x, chevronRect.y, chevronRect.width, chevronRect.height, false);
update();
return;
}
for (int i=0; i<items.length; i++) {
CTabItem2 item = items[i];
Rectangle bounds = item.getBounds();
if (item.closeRect.contains(x,y)){
if (event.button != 1) return;
item.closeImageState = SELECTED;
redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
update();
return;
}
if (bounds.contains(x, y)) {
if (!single && i != topTabIndex && bounds.x + bounds.width >= getRightItemEdge())return;
setSelection(i, true);
setFocus();
ignoreUp = true;
return;
}
}
break;
}
case SWT.MouseMove: {
boolean close = false, minimize = false, maximize = false, chevron = false;
if (minRect.contains(x, y)) {
minimize = true;
if (minImageState != HOT) {
minImageState = HOT;
redraw(minRect.x, minRect.y, minRect.width, minRect.height, false);
update();
}
}
if (maxRect.contains(x, y)) {
maximize = true;
if (maxImageState != HOT) {
maxImageState = HOT;
redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height, false);
update();
}
}
if (chevronRect.contains(x, y)) {
chevron = true;
if (chevronImageState != HOT) {
chevronImageState = HOT;
redraw(chevronRect.x, chevronRect.y, chevronRect.width, chevronRect.height, false);
update();
}
}
if (minImageState == HOT && !minimize) {
minImageState = NORMAL;
redraw(minRect.x, minRect.y, minRect.width, minRect.height, false);
update();
}
if (maxImageState == HOT && !maximize) {
maxImageState = NORMAL;
redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height, false);
update();
}
if (chevronImageState == HOT && !chevron) {
chevronImageState = NORMAL;
redraw(chevronRect.x, chevronRect.y, chevronRect.width, chevronRect.height, false);
update();
}
for (int i=0; i<items.length; i++) {
CTabItem2 item = items[i];
close = false;
if (item.getBounds().contains(x, y)) {
close = true;
if (item.closeRect.contains(x, y)) {
if (item.closeImageState != HOT) {
item.closeImageState = HOT;
redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
update();
}
} else {
if (item.closeImageState != NORMAL) {
item.closeImageState = NORMAL;
redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
update();
}
}
}
if (i != selectedIndex && item.closeImageState != NONE && !close) {
item.closeImageState = NONE;
redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
update();
}
if (i == selectedIndex && item.closeImageState != NORMAL && !close) {
item.closeImageState = NORMAL;
redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
update();
}
}
break;
}
case SWT.MouseUp: {
if (ignoreUp) {
ignoreUp = false;
return;
}
if (event.button != 1) return;
Display display = getDisplay();
if (chevronRect.contains(x, y)) {
chevronImageState = HOT;
redraw(chevronRect.x, chevronRect.y, chevronRect.width, chevronRect.height, false);
update();
Rectangle rect = new Rectangle(chevronRect.x, chevronRect.y, chevronRect.width, chevronRect.height);
if (single && selectedIndex != -1){
rect = items[selectedIndex].getBounds();
}
rect.y += onBottom ? -HIGHLIGHT_HEADER :HIGHLIGHT_HEADER;
if (listListeners.length == 0) {
showList(rect, single ? SWT.LEFT : SWT.RIGHT);
} else {
CTabFolderEvent e = new CTabFolderEvent(this);
e.widget = this;
e.time = event.time;
e.rect = rect;
for (int i = 0; i < listListeners.length; i++) {
listListeners[i].showList(e);
}
}
return;
}
if (minRect.contains(x, y)) {
minImageState = HOT;
redraw(minRect.x, minRect.y, minRect.width, minRect.height, false);
update();
CTabFolderEvent e = new CTabFolderEvent(this);
e.widget = this;
e.time = event.time;
e.doit = true;
boolean restore = minimized;
for (int i = 0; i < minmaxListeners.length; i++) {
if (restore) {
minmaxListeners[i].restore(e);
} else {
minmaxListeners[i].minimize(e);
}
}
if (e.doit) setMinimized(!restore);
return;
}
if (maxRect.contains(x, y)) {
maxImageState = HOT;
redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height, false);
update();
CTabFolderEvent e = new CTabFolderEvent(this);
e.widget = this;
e.time = event.time;
e.doit = true;
boolean restore = maximized;
for (int i = 0; i < minmaxListeners.length; i++) {
if (restore) {
minmaxListeners[i].restore(e);
} else {
minmaxListeners[i].maximize(e);
}
}
if (e.doit) setMaximized(!restore);
return;
}
for (int i=0; i<items.length; i++) {
CTabItem2 item = items[i];
if (item.closeRect.contains(x,y)){
item.closeImageState = HOT;
redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false);
update();
CTabFolderEvent e = new CTabFolderEvent(this);
e.widget = this;
e.time = event.time;
e.item = item;
e.doit = true;
for (int j = 0; j < closeListeners.length; j++) {
closeListeners[j].itemClosed(e);
}
if (e.doit) item.dispose();
return;
}
}
break;
}
}
}
boolean onPageTraversal(Event event) {
int count = items.length;
if (count == 0) return false;
int index = selectedIndex;
if (index == -1) {
index = 0;
} else {
int offset = (event.detail == SWT.TRAVERSE_PAGE_NEXT) ? 1 : -1;
index = (selectedIndex + offset + count) % count;
}
setSelection (index, true);
//setFocus();
return true;
}
void onPaint(Event event) {
Font font = getFont();
if (oldFont == null || !oldFont.equals(font)) {
// handle case where default font changes
oldFont = font;
if (!updateTabHeight(tabHeight, false)) {
updateItems();
redraw();
}
}
GC gc = event.gc;
Point size = getSize();
Color parentBackground = getParent().getBackground();
Color background = getBackground();
if (items.length == 0) {
gc.setBackground(parentBackground);
gc.fillRectangle(0, 0, size.x, size.y);
return;
}
if (single) {
// Fill in the empty spaces to the right and left of the tab
// with the background color
if (selectedIndex != -1) {
CTabItem2 item = items[selectedIndex];
int[] shapeLeft = null;
int[] shapeRight = null;
if (onBottom) {
int x = Math.max(0, borderLeft - 1);
int y = size.y - borderBottom - tabHeight;
int width = item.x - x;
int height = tabHeight;
if (borderRight > 0) height -= 1; // fill in behind border
shapeLeft = new int[BOTTOM_LEFT_OUTSIDE_CORNER.length+6];
int index = 0;
shapeLeft[index++] = x;
shapeLeft[index++] = y;
for (int i = 0; i < BOTTOM_LEFT_OUTSIDE_CORNER.length/2; i++) {
shapeLeft[index++] = x+BOTTOM_LEFT_OUTSIDE_CORNER[2*i];
shapeLeft[index++] = y+height+BOTTOM_LEFT_OUTSIDE_CORNER[2*i+1];
}
shapeLeft[index++] = x+width;
shapeLeft[index++] = y + height;
shapeLeft[index++] = x+width;
shapeLeft[index++] = y;
x = item.x + item.width;
width = size.x - borderRight - x;
if (borderRight > 0) width += 1; // +1 overlap with border
shapeRight = new int[BOTTOM_RIGHT_OUTSIDE_CORNER.length+6];
index = 0;
shapeRight[index++] = x;
shapeRight[index++] = y;
shapeRight[index++] = x;
shapeRight[index++] = y+height;
for (int i = 0; i < BOTTOM_RIGHT_OUTSIDE_CORNER.length/2; i++) {
shapeRight[index++] = x+width+BOTTOM_RIGHT_OUTSIDE_CORNER[2*i];
shapeRight[index++] = y+height+BOTTOM_RIGHT_OUTSIDE_CORNER[2*i+1];
}
shapeRight[index++] = x+width;
shapeRight[index++] = y;
} else { // tabs on top
int x = Math.max(0, borderLeft - 1);
int y = borderTop;
int width = item.x - x;
int height = tabHeight;
shapeLeft = new int[TOP_LEFT_OUTSIDE_CORNER.length+6];
int index = 0;
shapeLeft[index++] = x;
shapeLeft[index++] = y+height;
for (int i = 0; i < TOP_LEFT_OUTSIDE_CORNER.length/2; i++) {
shapeLeft[index++] = x+TOP_LEFT_OUTSIDE_CORNER[2*i];
shapeLeft[index++] = y+TOP_LEFT_OUTSIDE_CORNER[2*i+1];
}
shapeLeft[index++] = x+width;
shapeLeft[index++] = y;
shapeLeft[index++] = x+width;
shapeLeft[index++] = y+height;
x = item.x + item.width;
width = size.x - borderRight - x;
if (borderRight > 0) width += 1; // +1 overlap with border
shapeRight = new int[TOP_RIGHT_OUTSIDE_CORNER.length+6];
index = 0;
shapeRight[index++] = x;
shapeRight[index++] = y+height;
shapeRight[index++] = x;
shapeRight[index++] = y;
for (int i = 0; i < TOP_RIGHT_OUTSIDE_CORNER.length/2; i++) {
shapeRight[index++] = x+width+TOP_RIGHT_OUTSIDE_CORNER[2*i];
shapeRight[index++] = y+TOP_RIGHT_OUTSIDE_CORNER[2*i+1];
}
shapeRight[index++] = x+width;
shapeRight[index++] = y+height;
}
// Shape is non-rectangular, fill in gaps with parent colours
Region r = new Region();
int x = Math.max(0, borderLeft - 1);
int y = onBottom ? size.y - borderBottom - tabHeight : borderTop;
int width = item.x - x;
int height = tabHeight;
r.add(new Rectangle(x, y, width, height));
r.subtract(shapeLeft);
gc.setBackground(getParent().getBackground());
fillRegion(gc, r);
gc.setBackground(background);
gc.fillPolygon(shapeLeft);
x = item.x + item.width;
width = size.x - borderRight - x;
if (width > 0) {
if (borderRight > 0) width += 1; // +1 overlap with border
r.subtract(r); // clear region
r.add(new Rectangle(x, y, width, height));
r.subtract(shapeRight);
gc.setBackground(getParent().getBackground());
fillRegion(gc, r);
gc.setBackground(background);
gc.fillPolygon(shapeRight);
}
r.dispose();
}
} else {
// Fill in the empty space to the right of the last tab
// with the parent background color
CTabItem2 lastItem = items[items.length -1];
int edge = lastItem.x+lastItem.width;
if (edge < size.x) {
int x = edge;
int y = onBottom ? size.y - borderBottom - tabHeight - 1 : borderTop;
int width = size.x - edge - borderRight + 1;
int height = tabHeight + 1;
gc.setBackground(parentBackground);
gc.fillRectangle(x, y, width, height);
}
}
// Draw the unselected tabs.
if (!single) {
for (int i=0; i < items.length; i++) {
if (i != selectedIndex && event.getBounds().intersects(items[i].getBounds())) {
items[i].onPaint(gc, false);
}
}
}
// Draw selected tab
if (selectedIndex != -1) {
CTabItem2 item = items[selectedIndex];
Rectangle rect = item.getBounds();
if (event.getBounds().intersects(rect.x, rect.y, rect.width + CURVE_WIDTH, rect.height)) {
item.onPaint(gc, true);
}
}
drawChevron(gc);
drawMinimize(gc);
drawMaximize(gc);
drawBorder(gc);
// draw insertion mark
// if (insertionIndex > -2) {
// gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION));
// if (insertionIndex == -1) {
// Rectangle bounds = items[0].getBounds();
// gc.drawLine(bounds.x, bounds.y, bounds.x, bounds.y + bounds.height - 1);
// gc.drawLine(bounds.x - 2, bounds.y, bounds.x + 2, bounds.y);
// gc.drawLine(bounds.x - 1, bounds.y + 1, bounds.x + 1, bounds.y + 1);
// gc.drawLine(bounds.x - 1, bounds.y + bounds.height - 2, bounds.x + 1, bounds.y + bounds.height - 2);
// gc.drawLine(bounds.x - 2, bounds.y + bounds.height - 1, bounds.x + 2, bounds.y + bounds.height - 1);
//
// } else {
// Rectangle bounds = items[insertionIndex].getBounds();
// gc.drawLine(bounds.x + bounds.width, bounds.y, bounds.x + bounds.width, bounds.y + bounds.height - 1);
// gc.drawLine(bounds.x + bounds.width - 2, bounds.y, bounds.x + bounds.width + 2, bounds.y);
// gc.drawLine(bounds.x + bounds.width - 1, bounds.y + 1, bounds.x + bounds.width + 1, bounds.y + 1);
// gc.drawLine(bounds.x + bounds.width - 1, bounds.y + bounds.height - 2, bounds.x + bounds.width + 1, bounds.y + bounds.height - 2);
// gc.drawLine(bounds.x + bounds.width - 2, bounds.y + bounds.height - 1, bounds.x + bounds.width + 2, bounds.y + bounds.height - 1);
// }
// }
gc.setForeground(getForeground());
gc.setBackground(getBackground());
}
void onResize() {
if (items.length == 0) {
redraw();
return;
}
if (updateItems()) redraw();
showSelection();
Point size = getSize();
if (oldSize == null) {
redraw();
} else {
if (onBottom && size.y != oldSize.y) {
redraw();
} else {
int x1 = Math.min(size.x, oldSize.x);
if (size.x != oldSize.x) x1 -= 10;
int y1 = Math.min(size.y, oldSize.y);
if (size.y != oldSize.y) y1 -= 10;
int x2 = Math.max(size.x, oldSize.x);
int y2 = Math.max(size.y, oldSize.y);
redraw(0, y1, x2 + 10, y2 - y1, false);
redraw(x1, 0, x2 - x1, y2, false);
}
}
oldSize = size;
// resize content
if (selectedIndex != -1) {
Control control = items[selectedIndex].getControl();
if (control != null && !control.isDisposed()) {
control.setBounds(getClientArea());
}
}
}
void onTraverse (Event event) {
switch (event.detail) {
case SWT.TRAVERSE_ARROW_NEXT:
case SWT.TRAVERSE_ARROW_PREVIOUS:
event.doit = onArrowTraversal(event);
event.detail = SWT.TRAVERSE_NONE;
break;
case SWT.TRAVERSE_ESCAPE:
case SWT.TRAVERSE_RETURN:
case SWT.TRAVERSE_TAB_NEXT:
case SWT.TRAVERSE_TAB_PREVIOUS:
event.doit = true;
break;
case SWT.TRAVERSE_MNEMONIC:
event.doit = onMnemonic(event);
if (event.doit) event.detail = SWT.TRAVERSE_NONE;
break;
case SWT.TRAVERSE_PAGE_NEXT:
case SWT.TRAVERSE_PAGE_PREVIOUS:
event.doit = onPageTraversal(event);
event.detail = SWT.TRAVERSE_NONE;
break;
}
}
/**
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void removeCTabFolderCloseListener(CTabFolderCloseListener listener) {
checkWidget();
if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
if (closeListeners.length == 0) return;
int index = -1;
for (int i = 0; i < closeListeners.length; i++) {
if (listener == closeListeners[i]){
index = i;
break;
}
}
if (index == -1) return;
if (closeListeners.length == 1) {
closeListeners = new CTabFolderCloseListener[0];
return;
}
CTabFolderCloseListener[] newTabListeners = new CTabFolderCloseListener[closeListeners.length - 1];
System.arraycopy(closeListeners, 0, newTabListeners, 0, index);
System.arraycopy(closeListeners, index + 1, newTabListeners, index, closeListeners.length - index - 1);
closeListeners = newTabListeners;
}
/**
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void removeCTabFolderMinMaxListener(CTabFolderMinMaxListener listener) {
checkWidget();
if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
if (minmaxListeners.length == 0) return;
int index = -1;
for (int i = 0; i < minmaxListeners.length; i++) {
if (listener == minmaxListeners[i]){
index = i;
break;
}
}
if (index == -1) return;
if (minmaxListeners.length == 1) {
minmaxListeners = new CTabFolderMinMaxListener[0];
return;
}
CTabFolderMinMaxListener[] newListeners = new CTabFolderMinMaxListener[minmaxListeners.length - 1];
System.arraycopy(minmaxListeners, 0, newListeners, 0, index);
System.arraycopy(minmaxListeners, index + 1, newListeners, index, minmaxListeners.length - index - 1);
minmaxListeners = newListeners;
}
/**
* Removes the listener.
*
* @param listener the listener
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @deprecated see removeCTabFolderCloseListener(CTabFolderListener)
*/
public void removeCTabFolderListener(CTabFolderListener listener) {
removeCTabFolderCloseListener(listener);
if (closeListeners.length == 0) {
// hide close button
closeListeners = new CTabFolderCloseListener[0];
showClose = false;
updateItems();
redraw();
return;
}
}
/**
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
* @since 3.0
*/
public void removeCTabFolderListListener(CTabFolderListListener listener) {
checkWidget();
if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
if (listListeners.length == 0) return;
int index = -1;
for (int i = 0; i < listListeners.length; i++) {
if (listener == listListeners[i]){
index = i;
break;
}
}
if (index == -1) return;
if (listListeners.length == 1) {
listListeners = new CTabFolderListListener[0];
return;
}
CTabFolderListListener[] newListeners = new CTabFolderListListener[listListeners.length - 1];
System.arraycopy(listListeners, 0, newListeners, 0, index);
System.arraycopy(listListeners, index + 1, newListeners, index, listListeners.length - index - 1);
listListeners = newListeners;
}
/**
* Removes the listener.
*
* @param listener the listener
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*/
public void removeSelectionListener(SelectionListener listener) {
checkWidget();
if (listener == null) {
SWT.error(SWT.ERROR_NULL_ARGUMENT);
}
removeListener(SWT.Selection, listener);
removeListener(SWT.DefaultSelection, listener);
}
public void setBackground (Color color) {
if (color == null) color = getDisplay().getSystemColor(BACKGROUND);
super.setBackground(color);
redraw();
}
/**
* Toggle the visibility of the border
*
* @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 ((borderLeft == 1) == show) return;
borderLeft = borderRight = show ? 1 : 0;
borderTop = onBottom ? borderLeft : 0;
borderBottom = onBottom ? 0 : borderLeft;
Rectangle rectBefore = getClientArea();
updateItems();
Rectangle rectAfter = getClientArea();
if (!rectBefore.equals(rectAfter)) {
notifyListeners(SWT.Resize, new Event());
}
redraw();
}
boolean setButtonBounds() {
int oldX, oldY, oldWidth, oldHeight;
boolean changed = false;
Point size = getSize();
oldX = maxRect.x;
oldY = maxRect.y;
oldWidth = maxRect.width;
oldHeight = maxRect.height;
maxRect.x = maxRect.y = maxRect.width = maxRect.height = 0;
if (showMax) {
maxRect.x = size.x - borderRight - BUTTON_SIZE;
if (borderRight > 0) maxRect.x += 1;
if (single) maxRect.x -= 3;
maxRect.y = onBottom ? size.y - borderBottom - tabHeight: borderTop + 1;
maxRect.width = BUTTON_SIZE;
maxRect.height = tabHeight;
}
if (oldX != maxRect.x || oldWidth != maxRect.width ||
oldY != maxRect.y || oldHeight != maxRect.height) changed = true;
oldX = minRect.x;
oldY = minRect.y;
oldWidth = minRect.width;
oldHeight = minRect.height;
minRect.x = minRect.y = minRect.width = minRect.height = 0;
if (showMin) {
minRect.x = size.x - borderRight - maxRect.width - BUTTON_SIZE;
if (borderRight > 0) minRect.x += 1;
if (single) minRect.x -= 3;
minRect.y = onBottom ? size.y - borderBottom - tabHeight: borderTop + 1;
minRect.width = BUTTON_SIZE;
minRect.height = tabHeight;
}
if (oldX != minRect.x || oldWidth != minRect.width ||
oldY != minRect.y || oldHeight != minRect.height) changed = true;
oldX = topRightRect.x;
oldY = topRightRect.y;
oldWidth = topRightRect.width;
oldHeight = topRightRect.height;
topRightRect.x = topRightRect.y = topRightRect.width = topRightRect.height = 0;
if (topRight != null) {
Point topRightSize = topRight.computeSize(SWT.DEFAULT, tabHeight);
if (single && selectedIndex > -1) {
CTabItem2 item = items[selectedIndex];
topRightRect.x = Math.min(item.x +item.width + BUTTON_SIZE, size.x - borderRight - minRect.width - maxRect.width - topRightSize.x - 3);
} else {
topRightRect.x = size.x - borderRight - minRect.width - maxRect.width - topRightSize.x;
}
topRightRect.y = onBottom ? size.y - borderBottom - tabHeight: borderTop + 1;
topRightRect.width = topRightSize.x;
topRightRect.height = tabHeight - 1;
topRight.setBounds(topRightRect);
}
if (oldX != topRightRect.x || oldWidth != topRightRect.width ||
oldY != topRightRect.y || oldHeight != topRightRect.height) {
changed = true;
}
oldX = chevronRect.x;
oldY = chevronRect.y;
oldWidth = chevronRect.width;
oldHeight = chevronRect.height;
chevronRect.x = chevronRect.y = chevronRect.height = chevronRect.width = 0;
if (items.length > 1) {
if (single && selectedIndex != -1){
CTabItem2 item = items[selectedIndex];
chevronRect.x = Math.min(item.x +item.width - 3, size.x - borderRight - minRect.width - maxRect.width - topRightRect.width - BUTTON_SIZE - 3);
if (borderRight > 0) chevronRect.x += 1;
chevronRect.y = onBottom ? size.y - borderBottom - tabHeight: borderTop + 1;
chevronRect.width = BUTTON_SIZE;
chevronRect.height = tabHeight;
} else {
int rightEdge = getRightItemEdge();
CTabItem2 item = items[items.length-1];
if (topTabIndex > 0 || item.x + item.width >= rightEdge) {
chevronRect.x = size.x - borderRight - minRect.width - maxRect.width - topRightRect.width - BUTTON_SIZE;
if (borderRight > 0) chevronRect.x += 1;
chevronRect.y = onBottom ? size.y - borderBottom - tabHeight: borderTop + 1;
chevronRect.width = BUTTON_SIZE;
chevronRect.height = tabHeight;
}
}
}
if (oldX != chevronRect.x || oldWidth != chevronRect.width ||
oldY != chevronRect.y || oldHeight != chevronRect.height) changed = true;
return changed;
}
/**
* Sets the minimized state of the receiver.
* <p>
*
* @deprecated
* @param minimized false if folder is to be minimized
*
* @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 setExpanded (boolean expanded) {
setMinimized(!expanded);
}
void setFirstItem(int index) {
if (index < 0 || index > items.length - 1) return;
if (index == topTabIndex) return;
topTabIndex = index;
setItemLocation();
redraw();
}
public void setFont(Font font) {
checkWidget();
if (font != null && font.equals(getFont())) return;
super.setFont(font);
oldFont = getFont();
if (!updateTabHeight(tabHeight, false)) {
updateItems();
redraw();
}
}
public void setForeground (Color color) {
if (color == null) color = getDisplay().getSystemColor(FOREGROUND);
super.setForeground(color);
redraw();
}
/**
* Display an insert marker before or after the specified tab item.
*
* A value of null will clear the mark.
*
* @param item the item with which the mark is associated or null
*
* @param after true if the mark should be displayed after the specified item
*
* @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 setInsertMark(CTabItem2 item, boolean after) {
checkWidget();
int index = -1;
if (item != null) {
index = indexOf(item);
}
setInsertMark(index, after);
}
/**
* Display an insert marker before or after the specified tab item.
*
* A value of -1 will clear the mark.
*
* @param index the index of the item with which the mark is associated or null
*
* @param after true if the mark should be displayed after the specified item
*
* @exception IllegalArgumentException<ul>
* </ul>
*
* @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 setInsertMark(int index, boolean after) {
checkWidget();
if (index < -1 || index >= getItemCount()) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
// if (index == -1) {
// index = -2;
// } else {
// index = after ? index : --index;
// }
//
// if (insertionIndex == index) return;
// int oldIndex = insertionIndex;
// insertionIndex = index;
// if (index > -1) redrawTabArea(index);
// if (oldIndex > 1) redrawTabArea(oldIndex);
}
boolean setItemLocation() {
if (items.length == 0) return false;
Point size = getSize();
int y = onBottom ? Math.max(borderBottom, size.y - borderBottom - tabHeight) : borderTop;
boolean changed = false;
if (single) {
int defaultX = size.x + 10; // off screen
for (int i = 0; i < items.length; i++) {
if (items[i].x != defaultX) changed = true;
items[i].x = defaultX;
}
if (selectedIndex > -1) {
CTabItem2 item = items[selectedIndex];
int oldX = item.x, oldY = item.y;
int tabWidth = size.x - borderLeft - borderRight - minRect.width - maxRect.width - chevronRect.width;
int indent = Math.max(0, (tabWidth-item.width)/2);
item.x = borderLeft + indent;
item.y = y;
if (showClose || item.showClose) {
item.closeRect.x = item.x + item.width - BUTTON_SIZE - CTabItem2.RIGHT_MARGIN - 8;
item.closeRect.y = onBottom ? y : y + CTabItem2.TOP_MARGIN;
}
if (item.x != oldX || item.y != oldY) changed = true;
}
} else {
int x = -1;
for (int i = topTabIndex - 1; i >= 0; i--) {
// if the first visible tab is not the first tab
CTabItem2 tab = items[i];
x -= tab.width;
if (!changed && (tab.x != x || tab.y != y) ) changed = true;
// layout tab items from right to left thus making them invisible
tab.x = x;
tab.y = y;
tab.closeRect.x = tab.x + tab.width - BUTTON_SIZE - CTabItem2.RIGHT_MARGIN;
if (i == selectedIndex) tab.closeRect.x -= 8;
tab.closeRect.y = onBottom ? y : y + CTabItem2.TOP_MARGIN;
}
x = borderLeft <= 1 ? 0 : HIGHLIGHT_MARGIN;
for (int i = topTabIndex; i < items.length; i++) {
// continue laying out remaining, visible items left to right
CTabItem2 tab = items[i];
tab.x = x;
tab.y = y;
tab.closeRect.x = tab.x + tab.width - BUTTON_SIZE - CTabItem2.RIGHT_MARGIN;
if (i == selectedIndex) tab.closeRect.x -= 8;
tab.closeRect.y = onBottom ? y : y + CTabItem2.TOP_MARGIN;
x = x + tab.width;
}
int rightEdge = getRightItemEdge();
if (rightEdge > 0) {
CTabItem2 item = items[items.length - 1];
if (item.x + item.width < rightEdge) {
setLastItem(items.length - 1);
changed = true;
}
}
}
return changed;
}
boolean setItemSize() {
if (isDisposed()) return false;
Point size = getSize();
if (size.x <= 0 || size.y <= 0 || items.length == 0) return false;
int style = getStyle();
boolean highlight = borderLeft > 0 && (style & SWT.FLAT) == 0;
boolean changed = false;
xClient = borderLeft + marginWidth;
if (highlight) xClient += HIGHLIGHT_MARGIN;
if (onBottom) {
yClient = borderTop + marginHeight;
if (highlight) yClient += HIGHLIGHT_MARGIN;
} else {
yClient = borderTop + tabHeight + HIGHLIGHT_HEADER + marginHeight;
}
int[] widths = new int[items.length];
GC gc = new GC(this);
for (int i = 0; i < items.length; i++) {
widths[i] = items[i].preferredWidth(gc, i == selectedIndex);
}
gc.dispose();
int tabAreaWidth = size.x - borderLeft - borderRight - minRect.width - maxRect.width - chevronRect.width;
if (items.length > 1) {
int selectedWidth = selectedIndex == -1 ? 0 : widths[selectedIndex];
int count = selectedIndex == -1 ? items.length : items.length - 1;
int averageWidth = (tabAreaWidth - selectedWidth) / count;
int oldAverageWidth = 0;
while (averageWidth > oldAverageWidth) {
int width = tabAreaWidth - selectedWidth;
for (int i = 0; i < items.length; i++) {
if (i == selectedIndex) continue;
if (widths[i] < averageWidth) {
width -= widths[i];
count--;
}
}
oldAverageWidth = averageWidth;
if (count > 0) {
averageWidth = width / count;
}
}
averageWidth = Math.max(averageWidth, MIN_TAB_WIDTH * tabHeight);
for (int i = 0; i < items.length; i++) {
if (i == selectedIndex) continue;
if (widths[i] > averageWidth) {
widths[i] = averageWidth;
}
}
}
int totalWidth = 0;
for (int i = 0; i < items.length; i++) {
CTabItem2 tab = items[i];
if (tab.height != tabHeight || tab.width != widths[i]) changed = true;
tab.height = tabHeight;
tab.width = widths[i];
tab.closeRect.width = tab.closeRect.height = 0;
if (showClose || tab.showClose) {
tab.closeRect.width = BUTTON_SIZE;
tab.closeRect.height = BUTTON_SIZE;
}
totalWidth += widths[i];
}
if (totalWidth <= tabAreaWidth) {
topTabIndex = 0;
}
return changed;
}
void setLastItem(int index) {
if (index < 0 || index > items.length - 1) return;
Point size = getSize();
if (size.x <= 0) return;
int maxWidth = getRightItemEdge() - borderLeft;
int tabWidth = items[index].width;
while (index > 0) {
tabWidth += items[index - 1].width;
if (tabWidth >= maxWidth) break;
index--;
}
if (topTabIndex == index) return;
topTabIndex = index;
setItemLocation();
redraw();
}
/**
*
*
*/
public void setMaximizeVisible(boolean visible) {
checkWidget();
if (showMax == visible) return;
// display maximize button
showMax = visible;
updateItems();
redraw();
}
/**
*
*/
public void setMaximized(boolean maximize) {
checkWidget ();
if (this.maximized == maximize) return;
if (maximize && this.minimized) setMinimized(false);
this.maximized = maximize;
redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height, false);
update();
}
/**
*
*
*/
public void setMinimizeVisible(boolean visible) {
checkWidget();
if (showMin == visible) return;
// display maximize button
showMin = visible;
updateItems();
redraw();
}
/**
*
*/
public void setMinimized(boolean minimize) {
checkWidget ();
if (this.minimized == minimize) return;
if (minimize && this.maximized) setMaximized(false);
this.minimized = minimize;
redraw(minRect.x, minRect.y, minRect.width, minRect.height, false);
update();
}
/**
* Set the selection to the tab at the specified item.
*
* @param item the tab item to be selected
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*/
public void setSelection(CTabItem2 item) {
checkWidget();
if (item == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
int index = indexOf(item);
setSelection(index);
}
/**
* Set the selection to the tab at the specified index.
*
* @param index the index of the tab item to be selected
*
* @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 setSelection(int index) {
checkWidget();
if (index < 0 || index >= items.length) return;
if (selectedIndex == index) {
showItem(items[index]);
return;
}
int oldIndex = selectedIndex;
selectedIndex = index;
if (oldIndex != -1) {
items[oldIndex].closeImageState = NONE;
}
items[selectedIndex].closeImageState = NORMAL;
Control control = items[index].control;
if (control != null && !control.isDisposed()) {
control.setBounds(getClientArea());
control.setVisible(true);
}
if (oldIndex != -1) {
control = items[oldIndex].control;
if (control != null && !control.isDisposed()) {
control.setVisible(false);
}
}
updateItems();
redraw();
}
void setSelection(int index, boolean notify) {
int oldSelectedIndex = selectedIndex;
setSelection(index);
if (notify && selectedIndex != oldSelectedIndex && selectedIndex != -1) {
Event event = new Event();
event.item = getItem(selectedIndex);
notifyListeners(SWT.Selection, event);
}
}
/**
* @since 3.0
*/
public void setSelectionBackground (Color color) {
checkWidget();
if (selectionBackground == color) return;
if (color == null) color = getDisplay().getSystemColor(SELECTION_BACKGROUND);
selectionBackground = color;
if (selectedIndex > -1) redraw();
}
/**
* Specify a gradient of colours to be draw in the background of the selected tab.
* For example to draw a gradient that varies from dark blue to blue and then to
* white, use the following call to setBackground:
* <pre>
* cfolder.setBackground(new Color[]{display.getSystemColor(SWT.COLOR_DARK_BLUE),
* display.getSystemColor(SWT.COLOR_BLUE),
* display.getSystemColor(SWT.COLOR_WHITE),
* display.getSystemColor(SWT.COLOR_WHITE)},
* new int[] {25, 50, 100});
* </pre>
*
* @param colors an array of Color that specifies the colors to appear in the gradient
* in order of appearance left to right. The value <code>null</code> clears the
* background gradient. The value <code>null</code> can be used inside the array of
* Color to specify the background color.
* @param percents an array of integers between 0 and 100 specifying the percent of the width
* of the widget at which the color should change. The size of the percents array must be one
* less than the size of the colors array.
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*/
public void setSelectionBackground(Color[] colors, int[] percents) {
setSelectionBackground(colors, percents, false);
}
/**
* Specify a gradient of colours to be draw in the background of the selected tab.
* For example to draw a vertical gradient that varies from dark blue to blue and then to
* white, use the following call to setBackground:
* <pre>
* cfolder.setBackground(new Color[]{display.getSystemColor(SWT.COLOR_DARK_BLUE),
* display.getSystemColor(SWT.COLOR_BLUE),
* display.getSystemColor(SWT.COLOR_WHITE),
* display.getSystemColor(SWT.COLOR_WHITE)},
* new int[] {25, 50, 100}, true);
* </pre>
*
* @param colors an array of Color that specifies the colors to appear in the gradient
* in order of appearance left to right. The value <code>null</code> clears the
* background gradient. The value <code>null</code> can be used inside the array of
* Color to specify the background color.
* @param percents an array of integers between 0 and 100 specifying the percent of the width
* of the widget at which the color should change. The size of the percents array must be one
* less than the size of the colors array.
*
* @param vertical indicate the direction of the gradient. True is vertical and false is horizontal.
*
* @exception SWTError <ul>
* <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li>
* <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li>
* </ul>
*
*@since 3.0
*/
public void setSelectionBackground(Color[] colors, int[] percents, boolean vertical) {
checkWidget();
if (colors != null) {
if (percents == null || percents.length != colors.length - 1) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
for (int i = 0; i < percents.length; i++) {
if (percents[i] < 0 || percents[i] > 100) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
if (i > 0 && percents[i] < percents[i-1]) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
}
if (getDisplay().getDepth() < 15) {
// Don't use gradients on low color displays
colors = new Color[] {colors[0]};
percents = new int[] {};
}
}
// Are these settings the same as before?
if (backgroundImage == null) {
if ((gradientColors != null) && (colors != null) &&
(gradientColors.length == colors.length)) {
boolean same = false;
for (int i = 0; i < gradientColors.length; i++) {
if (gradientColors[i] == null) {
same = colors[i] == null;
} else {
same = gradientColors[i].equals(colors[i]);
}
if (!same) break;
}
if (same) {
for (int i = 0; i < gradientPercents.length; i++) {
same = gradientPercents[i] == percents[i];
if (!same) break;
}
}
if (same && this.gradientVertical == vertical) return;
}
} else {
backgroundImage = null;
}
// Store the new settings
if (colors == null) {
gradientColors = null;
gradientPercents = null;
gradientVertical = false;
setSelectionBackground((Color)null);
} else {
gradientColors = new Color[colors.length];
for (int i = 0; i < colors.length; ++i) {
gradientColors[i] = colors[i];
}
gradientPercents = new int[percents.length];
for (int i = 0; i < percents.length; ++i) {
gradientPercents[i] = percents[i];
}
gradientVertical = vertical;
setSelectionBackground(gradientColors[gradientColors.length-1]);
}
// Refresh with the new settings
if (selectedIndex > -1) redraw();
}
/**
* Set the image to be drawn in the background of the selected tab. Image
* is stretched or compressed to cover entire selection tab area.
*
* @param image the image to be drawn in the background
*
* @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 setSelectionBackground(Image image) {
setSelectionBackground(image, false);
}
/**
* Set the image to be drawn in the background of the selected tab area.
*
* @param image the image to be drawn in the background
* @param tile if true the image is tiled over the selection tab area, otherwise the image is stretched/compressed
*
* @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 setSelectionBackground(Image image, boolean tile) {
checkWidget();
if (image == backgroundImage && tiled == tile) return;
if (image != null) {
gradientColors = null;
gradientPercents = null;
}
tiled = tile;
backgroundImage = image;
if (selectedIndex > -1) redraw();
}
/**
* Set the foreground color of the selected tab.
*
* @param color the color of the text displayed in the selected tab
*
* @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 setSelectionForeground (Color color) {
checkWidget();
if (selectionForeground == color) return;
if (color == null) color = getDisplay().getSystemColor(SELECTION_FOREGROUND);
selectionForeground = color;
if (selectedIndex > -1) redraw();
}
/**
*
* @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>
*
* @since 3.0
*/
public void setStyle(int style) {
checkWidget();
int mask = SWT.TOP | SWT.BOTTOM | SWT.SINGLE | SWT.MULTI;
style = style & mask;
// TOP and BOTTOM are mutually exlusive.
// TOP is the default
if ((style & SWT.TOP) != 0)
style = style & ~SWT.BOTTOM | SWT.TOP;
// SINGLE and MULTI are mutually exlusive.
// MULTI is the default
if ((style & SWT.MULTI) != 0)
style = style & ~SWT.SINGLE | SWT.MULTI;
boolean changed = false;
if ((style & SWT.TOP) != 0 || (style & SWT.BOTTOM) != 0) {
if (onBottom != ((style & SWT.BOTTOM) != 0)) {
onBottom = (style & SWT.BOTTOM) != 0;
borderTop = onBottom ? borderLeft : 0;
borderBottom = onBottom ? 0 : borderRight;
updateTabHeight(tabHeight, true);
changed = true;
}
}
if ((style & SWT.SINGLE) != 0 || (style & SWT.MULTI) != 0) {
if (single != ((style & SWT.SINGLE) != 0)) {
single = (style & SWT.SINGLE) != 0;
if (single && selectedIndex == -1 && items.length > 0) {
setSelection(0, true);
}
for (int i = 0; i < items.length; i++) {
if (i != selectedIndex && items[i].closeImageState == NORMAL) {
items[i].closeImageState = NONE;
}
if (i == selectedIndex && items[i].closeImageState == NONE) {
items[i].closeImageState = NORMAL;
}
}
changed = true;
}
}
if (changed) {
Rectangle rectBefore = getClientArea();
updateItems();
Rectangle rectAfter = getClientArea();
if (!rectBefore.equals(rectAfter)) {
notifyListeners(SWT.Resize, new Event());
}
redraw();
}
}
/**
* Specify a fixed height for the tab items. If no height is specified,
* the default height is the height of the text or the image, whichever
* is greater. Specifying a height of -1 will revert to the default height.
*
* @param height the pixel value of the height or -1
*
* @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 called with a height of less than 0</li>
* </ul>
*/
public void setTabHeight(int height) {
checkWidget();
if (height < -1) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
fixedTabHeight = height > -1;
int oldHeight = tabHeight;
tabHeight = height;
updateTabHeight(oldHeight, false);
}
/**
* Set the control that appears in the top right corner of the tab folder.
* Typically this is a close button or a composite with a Menu and close button.
* The topRight control is optional. Setting the top right control to null will remove it from the tab folder.
*
* @since 2.1
*
* @param control 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 CTabFolder</li>
* </ul>
*
*/
public void setTopRight(Control control) {
checkWidget();
if (control != null && control.getParent() != this) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
topRight = control;
if (updateItems()) redraw();
}
/**
* Shows the item. If the item is already showing in the receiver,
* this method simply returns. Otherwise, the items are scrolled until
* the item is visible.
*
* @param item the item to be shown
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the item is null</li>
* <li>ERROR_INVALID_ARGUMENT - if the item has been disposed</li>
* </ul>
* @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>
*
* @see CTabFolder#showSelection()
*
* @since 2.0
*/
public void showItem (CTabItem2 item) {
checkWidget();
if (item == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
if (item.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
Point size = getSize();
int index = indexOf(item);
if (size.x <= borderLeft + borderRight || index < topTabIndex) {
setFirstItem(index);
return;
}
int rightEdge = getRightItemEdge();
if (item.x + item.width < rightEdge) return;
setLastItem(index);
}
void showList (Rectangle rect, int alignment) {
final Shell shell = new Shell(getShell(), SWT.BORDER | SWT.ON_TOP);
shell.setLayout(new FillLayout());
final Table table = new Table(shell, SWT.NONE);
// table.setBackground(selectionBackground);
// table.setForeground(selectionForeground);
for (int i = 0; i < items.length; i++) {
CTabItem2 tab = items[i];
TableItem item = new TableItem(table, SWT.NONE);
item.setText(tab.getText());
item.setImage(tab.getImage());
}
if (selectedIndex != -1) {
table.setSelection(selectedIndex);
}
Listener listener = new Listener() {
public void handleEvent(Event e) {
switch (e.type) {
case SWT.FocusOut:
shell.dispose();
break;
case SWT.DefaultSelection:
case SWT.MouseUp:
int index = table.getSelectionIndex();
if (index != -1) {
setSelection(index, true);
//setFocus();
}
shell.dispose();
break;
}
}
};
table.addListener(SWT.MouseUp, listener);
table.addListener(SWT.DefaultSelection, listener);
table.addListener(SWT.FocusOut, listener);
Point size = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT);
Rectangle displayRect = getMonitor().getClientArea();
Rectangle clientArea = getClientArea();
size.y = Math.min(displayRect.height/3, size.y);
shell.setSize(size);
Point p1 = getDisplay().map(this, null, clientArea.x, clientArea.y);
Point p2 = getDisplay().map(this, null, rect.x, rect.y);
int x = 0, y = 0;
if (alignment == SWT.LEFT) {
x = p2.x;
} else { // Left
x = p2.x + rect.width - size.x;
}
if (x < displayRect.x) x = displayRect.x;
if (x + size.x > displayRect.x + displayRect.width) x = displayRect.x + displayRect.width - size.x;
if (onBottom) {
y = p1.y + clientArea.height - size.y;
if (y < displayRect.y) y = p2.y + rect.height;
} else {
y = p1.y;
if (y + size.y > displayRect.y + displayRect.height) y = p2.y - size.y;
}
shell.setLocation(x, y);
shell.open();
table.setFocus();
}
/**
* Shows the selection. If the selection is already showing in the receiver,
* this method simply returns. Otherwise, the items are scrolled until
* the selection is visible.
*
* @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>
*
* @see CTabFolder#showItem(CTabItem)
*
* @since 2.0
*
*/
public void showSelection () {
checkWidget ();
if (selectedIndex != -1) {
showItem(getSelection());
}
}
void showToolTip (int x, int y) {
final Shell tip = new Shell (getShell(), SWT.ON_TOP);
final Label label = new Label (tip, SWT.CENTER);
Display display = tip.getDisplay();
label.setForeground (display.getSystemColor (SWT.COLOR_INFO_FOREGROUND));
label.setBackground (display.getSystemColor (SWT.COLOR_INFO_BACKGROUND));
if (!updateToolTip(x, y, label)) {
tip.dispose();
return;
}
final int [] events = new int[] {SWT.MouseExit, SWT.MouseHover, SWT.MouseMove};
final Listener[] listener = new Listener[1];
listener[0] = new Listener() {
public void handleEvent(Event event) {
switch (event.type) {
case SWT.MouseHover:
case SWT.MouseMove:
if (updateToolTip(event.x, event.y, label)) break;
// FALL THROUGH
case SWT.MouseExit:
for (int i = 0; i < events.length; i++) {
removeListener(events[i], listener[0]);
}
tip.dispose();
tipShowing = false;
break;
}
}
};
for (int i = 0; i < events.length; i++) {
addListener(events[i], listener[0]);
}
tipShowing = true;
tip.setVisible(true);
}
boolean updateItems() {
boolean changed = false;
if (setItemSize()) changed = true;
if (setItemLocation()) changed = true;
if (setButtonBounds()) changed = true;
if (selectedIndex != -1) {
int top = topTabIndex;
showItem(items[selectedIndex]);
if (top != topTabIndex) changed = true;
}
return changed;
}
boolean updateTabHeight(int oldHeight, boolean force){
if (!fixedTabHeight) {
int tempHeight = 0;
GC gc = new GC(this);
for (int i=0; i < items.length; i++) {
tempHeight = Math.max(tempHeight, items[i].preferredHeight(gc));
}
gc.dispose();
tabHeight = tempHeight;
}
if (!force && tabHeight == oldHeight) return false;
oldSize = null;
if (onBottom) {
curve = bezier(0, tabHeight+2,
CURVE_LEFT, tabHeight+2,
CURVE_WIDTH - CURVE_RIGHT, 1,
CURVE_WIDTH, 1,
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] > tabHeight) {
index = i;
} else {
break;
}
}
if (index > 0) {
int[] newCurve = new int[curve.length - 2*(index-1)];
System.arraycopy(curve, 2*(index-1), newCurve, 0, newCurve.length);
curve = newCurve;
}
} else {
curve = bezier(0, 0,
CURVE_LEFT, 0,
CURVE_WIDTH - CURVE_RIGHT, tabHeight + 2,
CURVE_WIDTH, tabHeight + 2,
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] > tabHeight) {
index = i;
break;
}
}
if (index > 0) {
int[] newCurve = new int[2*(index-1)];
System.arraycopy(curve, 0, newCurve, 0, newCurve.length);
curve = newCurve;
}
}
notifyListeners(SWT.Resize, new Event());
return true;
}
boolean updateToolTip (int x, int y, Label label) {
CTabItem2 item = getItem(new Point (x, y));
if (item == null) return false;
String tooltip = item.getToolTipText();
if (tooltip == null) return false;
if (tooltip.equals(label.getText())) return true;
Shell tip = label.getShell();
label.setText(tooltip);
Point labelSize = label.computeSize(SWT.DEFAULT, SWT.DEFAULT);
labelSize.x += 2; labelSize.y += 2;
label.setSize(labelSize);
tip.pack();
/*
* On some platforms, there is a minimum size for a shell
* which may be greater than the label size.
* To avoid having the background of the tip shell showing
* around the label, force the label to fill the entire client area.
*/
Rectangle area = tip.getClientArea();
label.setSize(area.width, area.height);
/*
* Position the tooltip and ensure that it is not located off
* the screen.
*/
Point cursorLocation = getDisplay().getCursorLocation();
// Assuming cursor is 21x21 because this is the size of
// the arrow cursor on Windows
int cursorHeight = 21;
Point size = tip.getSize();
Rectangle rect = tip.getMonitor().getBounds();
Point pt = new Point(cursorLocation.x, cursorLocation.y + cursorHeight + 2);
pt.x = Math.max(pt.x, rect.x);
if (pt.x + size.x > rect.x + rect.width) pt.x = rect.x + rect.width - size.x;
if (pt.y + size.y > rect.y + rect.height) {
pt.y = cursorLocation.y - 2 - size.y;
}
tip.setLocation(pt);
return true;
}
}