diff options
author | Veronika Irvine <veronika> | 2004-02-16 19:11:11 +0000 |
---|---|---|
committer | Veronika Irvine <veronika> | 2004-02-16 19:11:11 +0000 |
commit | bbeab947327689cb203638e742e58f555e6c1b64 (patch) | |
tree | 07d655a590fec9396850bec7b79636dd73ea4415 | |
parent | 2cef3fa78da7f2885ce55fa509348982e00b2225 (diff) | |
download | eclipse.platform.swt-bbeab947327689cb203638e742e58f555e6c1b64.tar.gz eclipse.platform.swt-bbeab947327689cb203638e742e58f555e6c1b64.tar.xz eclipse.platform.swt-bbeab947327689cb203638e742e58f555e6c1b64.zip |
Cut over to new look
2 files changed, 2880 insertions, 1494 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java index 22b9bb1e66..4cd8ff51f3 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabFolder.java @@ -10,12 +10,16 @@ *******************************************************************************/ 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.*; -import org.eclipse.swt.accessibility.*; + +/** +* UNDER CONSTRUCTION +*/ /** * Instances of this class implement the notebook user interface @@ -32,7 +36,7 @@ import org.eclipse.swt.accessibility.*; * </p><p> * <dl> * <dt><b>Styles:</b></dt> - * <dd>TOP, BOTTOM, FLAT</dd> + * <dd>CLOSE, TOP, BOTTOM, FLAT, BORDER, SINGLE, MULTI</dd> * <dt><b>Events:</b></dt> * <dd>Selection</dd> * <dd>"CTabFolder"</dd> @@ -62,92 +66,138 @@ public class CTabFolder extends Composite { */ 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 = 3; + /** * Color of innermost line of drop shadow border. + * + * @deprecated */ public static RGB borderInsideRGB = new RGB (132, 130, 132); /** * Color of middle line of drop shadow border. + * + * @deprecated */ public static RGB borderMiddleRGB = new RGB (143, 141, 138); /** * Color of outermost line of drop shadow border. + * + * @deprecated */ public static RGB borderOutsideRGB = new RGB (171, 168, 165); - - /* - * 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. - */ - public int MIN_TAB_WIDTH = 3; /* sizing, positioning */ int xClient, yClient; boolean onBottom = false; + boolean single = false; boolean fixedTabHeight; int tabHeight; /* item management */ - private CTabItem items[] = new CTabItem[0]; - private int selectedIndex = -1; + CTabItem items[] = new CTabItem[0]; + int selectedIndex = -1; int topTabIndex = -1; // index of the left most visible tab. /* External Listener management */ - private CTabFolderListener[] tabListeners = new CTabFolderListener[0]; + CTabFolderCloseListener[] closeListeners = new CTabFolderCloseListener[0]; + CTabFolderMinMaxListener[] minmaxListeners = new CTabFolderMinMaxListener[0]; + CTabFolderListListener[] listListeners = new CTabFolderListListener[0]; + + /* Selected item appearance */ + Image selectionBgImage; + Color[] selectionGradientColors; + int[] selectionGradientPercents; + boolean selectionGradientVertical; + Color selectionForeground; + Color selectionBackground; - /* Color appearance */ - Image backgroundImage; + /* Unselected item appearance */ + Image bgImage; Color[] gradientColors; int[] gradientPercents; - Color selectionForeground; - Color background; - - // internal constants - private static final int DEFAULT_WIDTH = 64; - private static final int DEFAULT_HEIGHT = 64; + boolean gradientVertical; - // scrolling arrows - private ToolBar arrowBar; - private Image arrowLeftImage; - private Image arrowRightImage; - - private Control topRight; - - // close button + static Color borderColor; + + // close, min/max and chevron buttons boolean showClose = false; - private Image closeImage; - ToolBar closeBar; - private ToolBar inactiveCloseBar; - private CTabItem inactiveItem; - - // borders - boolean showBorders = false; - private int borderBottom = 0; - private int borderLeft = 0; - private int borderRight = 0; - private int borderTop = 0; - private Color borderColor1; - private Color borderColor2; - private Color borderColor3; - + + 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; + + // 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. - private boolean inDispose = false; + boolean inDispose = false; // keep track of size changes in order to redraw only affected area // on Resize - private Point oldSize; - private Font oldFont; + Point oldSize; + Font oldFont; // insertion marker int insertionIndex = -2; // Index of insert marker. Marker always shown after index. // -2 means no insert marker - - // tool tip - private Shell tip; - private Label label; - private boolean showToolTip = false; - private CTabItem toolTipItem; + + // 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,9, 1,8, 1,7, 2,6, 2,5, 3,4, 4,3, 5,2, 6,2, 7,1, 8,1, 9,0}; + static final int[] TOP_RIGHT_CORNER = new int[] {-9,0, -8,1, -7,1, -6,2, -5,2, -4,3, -3,4, -2,5, -2,6, -1,7, -1,8, 0,9}; + static final int[] BOTTOM_LEFT_CORNER = new int[] {0,-9, 1,-8, 1,-7, 2,-6, 2,-5, 3,-4, 4,-3, 5,-2, 6,-2, 7,-1, 8,-1, 9,0}; + static final int[] BOTTOM_RIGHT_CORNER = new int[] {-9,0, -8,-1, -7,-1, -6,-2, -5,-2, -4,-3, -3,-4, -2,-5, -2,-6, -1,-7, -1,-8, 0,-9}; + + static final int SELECTION_FOREGROUND = SWT.COLOR_LIST_FOREGROUND; + static final int SELECTION_BACKGROUND = SWT.COLOR_LIST_BACKGROUND; + static final int BORDER1_COLOR = SWT.COLOR_WIDGET_NORMAL_SHADOW; + static final int FOREGROUND = SWT.COLOR_WIDGET_FOREGROUND; + static final int BACKGROUND = SWT.COLOR_WIDGET_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 @@ -175,107 +225,170 @@ public class CTabFolder extends Composite { * @see SWT#TOP * @see SWT#BOTTOM * @see SWT#FLAT - * @see #getStyle + * @see SWT#BORDER + * @see SWT#SINGLE + * @see SWT#MULTI + * @see #getStyle() */ public CTabFolder(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); + borderColor = display.getSystemColor(BORDER1_COLOR); + setForeground(display.getSystemColor(FOREGROUND)); + setBackground(display.getSystemColor(BACKGROUND)); - onBottom = (getStyle() & SWT.BOTTOM) != 0; - - borderColor1 = new Color(getDisplay(), borderInsideRGB); - borderColor2 = new Color(getDisplay(), borderMiddleRGB); - borderColor3 = new Color(getDisplay(), borderOutsideRGB); - - // tool tip support - tip = new Shell (getShell(), SWT.ON_TOP); - label = new Label (tip, SWT.CENTER); + initAccessible(); // Add all listeners Listener listener = new Listener() { public void handleEvent(Event event) { switch (event.type) { - case SWT.Dispose: onDispose(); break; - case SWT.Paint: onPaint(event); break; - case SWT.Resize: onResize(); break; - case SWT.MouseDoubleClick: onMouseDoubleClick(event); break; - case SWT.MouseDown: onMouseDown(event); break; - case SWT.MouseExit: onMouseExit(event); break; - case SWT.MouseHover: onMouseHover(event); break; - case SWT.MouseMove: onMouseMove(event); break; - case SWT.FocusIn: onFocus(event); break; - case SWT.FocusOut: onFocus(event); break; - case SWT.KeyDown: onKeyDown(event); break; - case SWT.Traverse: onTraverse(event); break; + 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.Paint, - SWT.Resize, + SWT.FocusIn, + SWT.FocusOut, + SWT.KeyDown, + SWT.MenuDetect, SWT.MouseDoubleClick, - SWT.MouseDown, + SWT.MouseDown, SWT.MouseExit, SWT.MouseHover, SWT.MouseMove, - SWT.FocusIn, - SWT.FocusOut, - SWT.KeyDown, + SWT.MouseUp, + SWT.Paint, + SWT.Resize, SWT.Traverse, }; for (int i = 0; i < folderEvents.length; i++) { addListener(folderEvents[i], listener); } - - createArrowBar(); - createCloseBar(); - - setBorderVisible((style & SWT.BORDER) != 0); - - initAccessible(); - } -private static int checkStyle (int style) { - int mask = SWT.TOP | SWT.BOTTOM | SWT.FLAT | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; +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; + style |= SWT.NO_REDRAW_RESIZE | SWT.NO_BACKGROUND; return style; } - -//protected void checkSubclass () { -// String name = getClass().getName (); -// String validName = CTabFolder.class.getName(); -// if (!validName.equals(name)) { -// SWT.error (SWT.ERROR_INVALID_SUBCLASS); -// } -//} - -/** -* Adds the listener to receive events. -* <p> -* -* @param listener the listener -* -* @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> -* <li>ERROR_NULL_ARGUMENT when listener is null</li> -* </ul> -*/ -public void addSelectionListener(SelectionListener listener) { +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); - } - TypedListener typedListener = new TypedListener(listener); - addListener(SWT.Selection, typedListener); - addListener(SWT.DefaultSelection, typedListener); + 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 @@ -284,51 +397,149 @@ public void addSelectionListener(SelectionListener listener) { * @param listener the listener which should be notified * * @exception IllegalArgumentException <ul> - * <li>ERROR_THREAD_INVALID_ACCESS when called from the wrong thread</li> - * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li> - * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * <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 + * @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 - CTabFolderListener[] newTabListeners = new CTabFolderListener[tabListeners.length + 1]; - System.arraycopy(tabListeners, 0, newTabListeners, 0, tabListeners.length); - tabListeners = newTabListeners; - tabListeners[tabListeners.length - 1] = listener; - showClose = true; - setButtonBounds(); + CTabFolderListListener[] newListeners = new CTabFolderListListener[listListeners.length + 1]; + System.arraycopy(listListeners, 0, newListeners, 0, listListeners.length); + listListeners = newListeners; + listListeners[listListeners.length - 1] = listener; } -private void closeNotify(CTabItem item, int time) { - if (item == null) return; - - CTabFolderEvent event = new CTabFolderEvent(this); - event.widget = this; - event.time = time; - event.item = item; - event.doit = true; - if (tabListeners != null) { - for (int i = 0; i < tabListeners.length; i++) { - tabListeners[i].itemClosed(event); - } +/** + * 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); } - if (event.doit) { - item.dispose(); + 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){ + //don't perform anti-aliasing on Mac because the platform + // already does it. + if ("carbon".equals(SWT.getPlatform())) return; + 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++) { - minWidth += items[i].preferredWidth(gc); + 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(); @@ -341,9 +552,12 @@ public Point computeSize (int wHint, int hHint, boolean changed) { 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; @@ -352,28 +566,26 @@ public Point computeSize (int wHint, int hHint, boolean changed) { } public Rectangle computeTrim (int x, int y, int width, int height) { checkWidget(); - if (items.length == 0) { - if (!showBorders) return new Rectangle(x, y, width, height); - int trimX = x - borderRight - 1; - int trimY = y - borderBottom - 1; - int trimWidth = width + borderRight + 2; - int trimHeight = height + borderBottom + 2; + 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; - int trimY = y - marginHeight - tabHeight - borderTop - 1; - // -1 is for the line at the bottom of the tabs - if (onBottom) { - trimY = y - marginHeight - borderTop; - } + 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; - int trimHeight = height + borderTop + borderBottom + 2*marginHeight + tabHeight + 1; + 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); } } -/** - * Create the specified item at 'index'. - */ void createItem (CTabItem item, int index) { if (0 > index || index > getItemCount ()){ SWT.error (SWT.ERROR_INVALID_RANGE); @@ -392,89 +604,21 @@ void createItem (CTabItem item, int index) { } if (items.length == 1) { topTabIndex = 0; - resetTabSize(true); - } else { - setItemBounds(); - showItem(item); - } - - if (items.length == 1) { + if (!updateTabHeight(tabHeight, false)) updateItems(); redraw(); } else { - redrawTabArea(-1); - } -} - -private void createArrowBar() { - // create arrow buttons for scrolling - arrowBar = new ToolBar(this, SWT.FLAT); - arrowBar.setVisible(false); - arrowBar.setBackground(background); - ToolItem scrollLeft = new ToolItem(arrowBar, SWT.PUSH); - scrollLeft.setEnabled(false); - ToolItem scrollRight = new ToolItem(arrowBar, SWT.PUSH); - scrollRight.setEnabled(false); - - scrollLeft.addListener(SWT.Selection, new Listener() { - public void handleEvent(Event event) { - scroll_scrollLeft(); - } - }); - scrollRight.addListener(SWT.Selection, new Listener() { - public void handleEvent(Event event) { - scroll_scrollRight(); + updateItems(); + // redraw tabs if new item visible + if (index == topTabIndex || + (index > topTabIndex && item.x + item.width < getRightItemEdge())){ + redraw(); } - }); - -} -private void createCloseBar() { - closeBar = new ToolBar(this, SWT.FLAT); - closeBar.setVisible(false); - if (gradientColors != null && gradientColors.length > 0) { - closeBar.setBackground(gradientColors[gradientColors.length - 1]); - } else { - closeBar.setBackground(background); } - ToolItem closeItem = new ToolItem(closeBar, SWT.PUSH); - - inactiveCloseBar = new ToolBar(this, SWT.FLAT); - inactiveCloseBar.setVisible(false); - inactiveCloseBar.setBackground(background); - ToolItem inactiveCloseItem = new ToolItem(inactiveCloseBar, SWT.PUSH); - - closeItem.addListener(SWT.Selection, new Listener() { - public void handleEvent(Event event) { - closeNotify(getSelection(), event.time); - } - }); - inactiveCloseItem.addListener(SWT.Selection, new Listener() { - public void handleEvent(Event event) { - closeNotify(inactiveItem, event.time); - inactiveCloseBar.setVisible(false); - inactiveItem = null; - } - }); - inactiveCloseBar.addListener (SWT.MouseExit, new Listener() { - public void handleEvent(Event event) { - if (inactiveItem != null) { - Rectangle itemBounds = inactiveItem.getBounds(); - if (itemBounds.contains(event.x, event.y)) return; - } - inactiveCloseBar.setVisible(false); - inactiveItem = null; - } - }); - } -/** - * Destroy the specified item. - */ void destroyItem (CTabItem item) { if (inDispose) return; - int index = indexOf(item); - if (index == -1) return; // should this trigger an error? - + if (index == -1) return; insertionIndex = -2; if (items.length == 1) { @@ -486,7 +630,6 @@ void destroyItem (CTabItem item) { if (control != null && !control.isDisposed()) { control.setVisible(false); } - closeBar.setVisible(false); if (!fixedTabHeight) tabHeight = 0; redraw(); return; @@ -504,9 +647,9 @@ void destroyItem (CTabItem item) { // move the selection if this item is selected if (selectedIndex == index) { + Control control = item.getControl(); selectedIndex = -1; setSelection(Math.max(0, index - 1), true); - Control control = item.getControl(); if (control != null && !control.isDisposed()) { control.setVisible(false); } @@ -514,154 +657,614 @@ void destroyItem (CTabItem item) { selectedIndex --; } - setItemBounds(); - redrawTabArea(-1); + if (updateItems()) redraw(); } -private void onKeyDown(Event e) { - if (e.keyCode != SWT.ARROW_LEFT && e.keyCode != SWT.ARROW_RIGHT) return; - int leadKey = (getStyle() & SWT.MIRRORED) != 0 ? SWT.ARROW_RIGHT : SWT.ARROW_LEFT; - if (e.keyCode == leadKey) { - if (selectedIndex > 0) { - setSelection(selectedIndex - 1, true); +void drawBackground(GC gc, int[] shape, boolean selected) { + 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); + + Color defaultBackground = selected ? selectionBackground : getBackground(); + Image image = selected ? selectionBgImage : bgImage; + Color[] colors = selected ? selectionGradientColors : gradientColors; + boolean vertical = selected ? selectionGradientVertical : gradientVertical; + int[] percents = selected ? selectionGradientPercents : gradientPercents; + + if (image != null) { + // draw the background image in shape + gc.setBackground(defaultBackground); + gc.fillRectangle(x, y, width, height); + Rectangle imageRect = image.getBounds(); + gc.drawImage(image, imageRect.x, imageRect.y, imageRect.width, imageRect.height, x, y, width, height); + } else if (colors != null) { + // draw gradient + if (colors.length == 1) { + Color background = colors[0] != null ? colors[0] : defaultBackground; + gc.setBackground(background); + gc.fillRectangle(x, y, width, height); + } else { + if (vertical) { + if (onBottom) { + int pos = 0; + if (percents[percents.length - 1] < 100) { + pos = percents[percents.length - 1] * height / 100; + gc.setBackground(defaultBackground); + gc.fillRectangle(x, y, width, pos); + } + Color lastColor = colors[colors.length-1]; + if (lastColor == null) lastColor = defaultBackground; + for (int i = percents.length-1; i >= 0; i--) { + gc.setForeground(lastColor); + lastColor = colors[i]; + if (lastColor == null) lastColor = defaultBackground; + gc.setBackground(lastColor); + int gradientHeight = percents[i] * height / 100; + gc.fillGradientRectangle(x, y+pos, width, gradientHeight, true); + pos += gradientHeight; + } + } else { + Color lastColor = colors[0]; + if (lastColor == null) lastColor = defaultBackground; + int pos = 0; + for (int i = 0; i < percents.length; i++) { + gc.setForeground(lastColor); + lastColor = colors[i + 1]; + if (lastColor == null) lastColor = defaultBackground; + gc.setBackground(lastColor); + int gradientHeight = percents[i] * height / 100; + gc.fillGradientRectangle(x, y+pos, width, gradientHeight, true); + pos += gradientHeight; + } + if (pos < height) { + gc.setBackground(defaultBackground); + gc.fillRectangle(x, pos, width, height-pos); + } + } + } else { //horizontal gradient + Color lastColor = colors[0]; + if (lastColor == null) lastColor = defaultBackground; + int pos = 0; + for (int i = 0; i < percents.length; ++i) { + gc.setForeground(lastColor); + lastColor = colors[i + 1]; + if (lastColor == null) lastColor = defaultBackground; + gc.setBackground(lastColor); + int gradientWidth = (percents[i] * width / 100) - pos; + gc.fillGradientRectangle(x+pos, y, gradientWidth, height, false); + pos += gradientWidth; + } + if (pos < width) { + gc.setBackground(defaultBackground); + gc.fillRectangle(x+pos, y, width-pos, height); + } + } } } else { - if (selectedIndex < items.length - 1) { - setSelection(selectedIndex + 1, true); - } + // draw a solid background using default background in shape + gc.setBackground(defaultBackground); + gc.fillRectangle(x, y, width, height); } + gc.setClipping(clipping); + clipping.dispose(); + region.dispose(); } -/** - * Dispose the items of the receiver - */ -private 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; +void drawBody(Event event) { + GC gc = event.gc; + Point size = getSize(); - int length = items.length; - for (int i = 0; i < length; i++) { - if (items[i] != null) { - items[i].dispose(); + //draw 1 pixel border around outside + if (borderLeft > 0) { + gc.setForeground(borderColor); + int x1 = borderLeft - 1; + int x2 = size.x - borderRight; + int y1 = onBottom ? borderTop - 1 : borderTop + tabHeight; + int y2 = onBottom ? size.y - tabHeight - borderBottom - 1 : size.y - borderBottom; + gc.drawLine(x1, y1, x1, y2); // left + gc.drawLine(x2, y1, x2, y2); // right + if (onBottom) { + gc.drawLine(x1, y1, x2, y1); // top + } else { + gc.drawLine(x1, y2, x2, y2); // bottom } } - // clean up resources - if (tip != null && !tip.isDisposed()) { - tip.dispose(); - tip = null; - label = null; + // 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); } - - if (arrowLeftImage != null) arrowLeftImage.dispose(); - arrowLeftImage = null; - if (arrowRightImage != null) arrowRightImage.dispose(); - arrowRightImage = null; - if (closeImage != null) closeImage.dispose(); - closeImage = null; - - gradientColors = null; - gradientPercents = null; - backgroundImage = null; +} - if (borderColor1 != null) borderColor1.dispose(); - borderColor1 = null; - - if (borderColor2 != null) borderColor2.dispose(); - borderColor2 = null; - - if (borderColor3 != null) borderColor3.dispose(); - borderColor3 = null; +void drawChevron(GC gc) { + if (chevronRect.width == 0 || chevronRect.height == 0) return; + Display display = getDisplay(); + // 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(borderColor); + 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; + } + } } -private void onFocus(Event e) { - checkWidget(); - if (selectedIndex >= 0) { - redrawTabArea(selectedIndex); - } else { - setSelection(0, true); +void drawMaximize(GC gc) { + if (maxRect.width == 0 || maxRect.height == 0) return; + Display display = getDisplay(); + 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(borderColor); + 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(borderColor); + 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; + } } } -/** - * Draw a border around the receiver. - */ -private void drawBorder(GC gc) { - - Rectangle d = super.getClientArea(); - - if (showBorders) { - if ((getStyle() & SWT.FLAT) != 0) { - gc.setForeground(borderColor1); - gc.drawRectangle(d.x, d.y, d.x + d.width - 1, d.y + d.height - 1); - } else { - gc.setForeground(borderColor1); - gc.drawRectangle(d.x, d.y, d.x + d.width - 3, d.y + d.height - 3); - - gc.setForeground(borderColor2); - gc.drawLine(d.x + 1, d.y + d.height - 2, d.x + d.width - 1, d.y + d.height - 2); - gc.drawLine(d.x + d.width - 2, d.y + 1, d.x + d.width - 2, d.y + d.height - 1); - - gc.setForeground(borderColor3); - gc.drawLine(d.x + 2, d.y + d.height - 1, d.x + d.width - 2, d.y + d.height - 1); - gc.drawLine(d.x + d.width - 1, d.y + 2, d.x + d.width - 1, d.y + d.height - 2); - - // fill in corners with parent's background - gc.setForeground(getParent().getBackground()); - gc.drawLine(d.x + d.width - 2, d.y, d.x + d.width - 1, d.y); - gc.drawLine(d.x + d.width - 1, d.y + 1, d.x + d.width - 1, d.y + 1); - - gc.drawLine(d.x, d.y + d.height - 2, d.x, d.y + d.height - 2); - gc.drawLine(d.x, d.y + d.height - 1, d.x + 1, d.y + d.height - 1); - - gc.drawLine(d.x + d.width - 1, d.y + d.height - 1, d.x + d.width - 1, d.y + d.height - 1); +void drawMinimize(GC gc) { + if (minRect.width == 0 || minRect.height == 0) return; + Display display = getDisplay(); + 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(borderColor); + 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(borderColor); + 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; } - } - - // draw a separator line - if (items.length > 0) { - int lineY = d.y + borderTop + tabHeight; - if (onBottom) { - lineY = d.y + d.height - borderBottom - tabHeight - 1; +} +void drawTabArea(Event event) { + GC gc = event.gc; + Point size = getSize(); + int[] shape = null; + int x = Math.max(0, borderLeft - 1); + int y = onBottom ? size.y - borderBottom - tabHeight : borderTop; + int width = size.x - borderLeft - borderRight + 1; + int height = tabHeight - 1; + + // Fill in the empty spaces to the right and left of the tabs + if (single) { + int[] shapeLeft = null; + int[] shapeRight = null; + if (onBottom) { // single with tabs on bototm + //left side + shapeLeft = new int[BOTTOM_LEFT_CORNER.length+6]; + int index = 0; + int width2 = (selectedIndex == -1) ? size.x/2 : items[selectedIndex].x - x; + shapeLeft[index++] = x; + shapeLeft[index++] = y; + for (int i = 0; i < BOTTOM_LEFT_CORNER.length/2; i++) { + shapeLeft[index++] = x+BOTTOM_LEFT_CORNER[2*i]; + shapeLeft[index++] = y+height+1+BOTTOM_LEFT_CORNER[2*i+1]; + } + shapeLeft[index++] = x+width2; + shapeLeft[index++] = y+height+1; + shapeLeft[index++] = x+width2; + shapeLeft[index++] = y; + //right side + int x2 = (selectedIndex == -1) ? x + size.x/2 : items[selectedIndex].x + items[selectedIndex].width; + width2 = size.x - borderRight - x2; + if (borderLeft == 0) width2 += 1; + shapeRight = new int[BOTTOM_RIGHT_CORNER.length+6]; + index = 0; + shapeRight[index++] = x2; + shapeRight[index++] = y; + shapeRight[index++] = x2; + shapeRight[index++] = y+height+1; + for (int i = 0; i < BOTTOM_RIGHT_CORNER.length/2; i++) { + shapeRight[index++] = x2+width2+BOTTOM_RIGHT_CORNER[2*i]; + shapeRight[index++] = y+height+1+BOTTOM_RIGHT_CORNER[2*i+1]; + } + shapeRight[index++] = x2+width2; + shapeRight[index++] = y; + } else { // single with tabs on top + //left side + shapeLeft = new int[TOP_LEFT_CORNER.length+6]; + int index = 0; + int width2 = (selectedIndex == -1) ? size.x/2 : items[selectedIndex].x - x; + shapeLeft[index++] = x; + shapeLeft[index++] = y+height+1; + for (int i = 0; i < TOP_LEFT_CORNER.length/2; i++) { + shapeLeft[index++] = x+TOP_LEFT_CORNER[2*i]; + shapeLeft[index++] = y+TOP_LEFT_CORNER[2*i+1]; + } + shapeLeft[index++] = x+width2; + shapeLeft[index++] = y; + shapeLeft[index++] = x+width2; + shapeLeft[index++] = y+height+1; + //right side + int x2 = (selectedIndex == -1) ? x + size.x/2 : items[selectedIndex].x + items[selectedIndex].width; + width2 = size.x - borderRight - x2; + if (borderLeft == 0) width2 += 1; + shapeRight = new int[TOP_RIGHT_CORNER.length+6]; + index = 0; + shapeRight[index++] = x2; + shapeRight[index++] = y+height+1; + shapeRight[index++] = x2; + shapeRight[index++] = y; + for (int i = 0; i < TOP_RIGHT_CORNER.length/2; i++) { + shapeRight[index++] = x2+width2+TOP_RIGHT_CORNER[2*i]; + shapeRight[index++] = y+TOP_RIGHT_CORNER[2*i+1]; + } + shapeRight[index++] = x2+width2; + shapeRight[index++] = y+height+1; + } + drawBackground(gc, shapeLeft, false); + drawBackground(gc, shapeRight, false); + } else { // SWT.MULTI + // Fill in the empty space to the right of the last tab + CTabItem lastItem = items[items.length -1]; + int edge = lastItem.x+lastItem.width; + if (edge < size.x) { + shape = null; + if (onBottom) { + shape = new int[BOTTOM_RIGHT_CORNER.length+6]; + int index = 0; + shape[index++] = edge; + shape[index++] = size.y - borderBottom - tabHeight - 1; + shape[index++] = edge; + shape[index++] = size.y - borderBottom; + for (int i = 0; i < BOTTOM_RIGHT_CORNER.length/2; i++) { + shape[index++] = size.x- borderRight + 1+BOTTOM_RIGHT_CORNER[2*i]; + shape[index++] = size.y - borderBottom + BOTTOM_RIGHT_CORNER[2*i+1]; + } + shape[index++] = size.x - borderRight + 1; + shape[index++] = size.y - borderBottom - tabHeight - 1; + } else { + shape = new int[TOP_RIGHT_CORNER.length+6]; + int index = 0; + shape[index++] = edge; + shape[index++] = borderTop + tabHeight + 1; + shape[index++] = edge; + shape[index++] = borderTop; + for (int i = 0; i < TOP_RIGHT_CORNER.length/2; i++) { + shape[index++] = size.x - borderRight + 1+TOP_RIGHT_CORNER[2*i]; + shape[index++] = borderTop+TOP_RIGHT_CORNER[2*i+1]; + } + shape[index++] = size.x - borderRight + 1; + shape[index++] = borderTop + tabHeight + 1; + } + drawBackground(gc, shape, false); + } + } + + // 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); + } } - gc.setForeground(borderColor1); - gc.drawLine(d.x + borderLeft, lineY, d.x + d.width - borderRight, lineY); } + + // Draw selected tab + if (selectedIndex != -1) { + CTabItem item = items[selectedIndex]; + item.onPaint(gc, true); + } else { + // if no selected tab - draw line across bottom of all tabs + int x2 = borderLeft; + int y2 = onBottom ? size.y - borderBottom - tabHeight - HIGHLIGHT_HEADER : borderTop + tabHeight + 1; + int width2 = size.x - borderLeft - borderRight; + int height2 = HIGHLIGHT_HEADER - 1; + gc.setBackground(getBackground()); + gc.fillRectangle(x2, y2, width2, height2); + x2 = borderLeft; + y2 = (onBottom) ? size.y - borderBottom - tabHeight - 1 : borderTop + tabHeight; + gc.setForeground(borderColor); + gc.drawLine(x2, y2, x2 + width2, y2); + } + + drawChevron(gc); + drawMinimize(gc); + drawMaximize(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()); + + // draw outside border area + if (onBottom) { + shape = new int[BOTTOM_LEFT_CORNER.length + BOTTOM_RIGHT_CORNER.length + 4]; + int index = 0; + shape[index++] = x; + shape[index++] = y; + for (int i = 0; i < BOTTOM_LEFT_CORNER.length/2; i++) { + shape[index++] = x+BOTTOM_LEFT_CORNER[2*i]; + shape[index++] = y+height+BOTTOM_LEFT_CORNER[2*i+1]; + if (borderLeft == 0) shape[index-1] += 1; + } + for (int i = 0; i < BOTTOM_RIGHT_CORNER.length/2; i++) { + shape[index++] = x+width+BOTTOM_RIGHT_CORNER[2*i]; + shape[index++] = y+height+BOTTOM_RIGHT_CORNER[2*i+1]; + if (borderLeft == 0) shape[index-1] += 1; + } + shape[index++] = x+width; + shape[index++] = y-1; + } else { + shape = new int[TOP_LEFT_CORNER.length + TOP_RIGHT_CORNER.length + 4]; + int index = 0; + shape[index++] = x; + shape[index++] = y+height; + for (int i = 0; i < TOP_LEFT_CORNER.length/2; i++) { + shape[index++] = x+TOP_LEFT_CORNER[2*i]; + shape[index++] = y+TOP_LEFT_CORNER[2*i+1]; + } + for (int i = 0; i < TOP_RIGHT_CORNER.length/2; i++) { + shape[index++] = x+width+TOP_RIGHT_CORNER[2*i]; + shape[index++] = y+TOP_RIGHT_CORNER[2*i+1]; + } + shape[index++] = x+width; + shape[index++] = y+height+1; + } + // fill in space outside border line with parent background + Region r = new Region(); + r.add(new Rectangle(x, y, width + 1, height + 1)); + r.subtract(shape); + gc.setBackground(getParent().getBackground()); + fillRegion(gc, r); + r.dispose(); + + // draw border line + if (borderLeft > 0) { + RGB inside = getBackground().getRGB(); + if (bgImage != null || (gradientColors != null && gradientColors.length > 1 && !gradientVertical)) inside = null; + RGB outside = getParent().getBackground().getRGB(); + antialias(shape, borderColor.getRGB(), inside, outside, gc); + gc.setForeground(borderColor); + gc.drawPolyline(shape); + } +} +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 + 1; //+1 for line under tabs + height -= tabHeight+HIGHLIGHT_HEADER; return new Rectangle(xClient, yClient, width, height); } + /** - * 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> + * 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 int getTabHeight(){ - checkWidget(); - return tabHeight; +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 CTabItem getItem (int index) { //checkWidget(); @@ -670,19 +1273,25 @@ public CTabItem getItem (int index) { return items [index]; } /** -* Gets the item at a point in the widget. -* <p> -* -* @return the item at a point -*/ + * 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 CTabItem getItem (Point pt) { //checkWidget(); if (items.length == 0) return null; - int lastItem = getLastItem(); - lastItem = Math.min(items.length - 1, lastItem + 1); - for (int i = topTabIndex; i <= lastItem; i++) { - Rectangle bounds = items[i].getBounds(); - if (bounds.contains(pt)) return items[i]; + Point size = getSize(); + if (size.x <= borderLeft + borderRight) return null; + for (int index = topTabIndex; index < items.length; index++) { + CTabItem item = items[index]; + Rectangle rect = item.getBounds(); + if (rect.contains(pt)) return item; } return null; } @@ -690,6 +1299,11 @@ public CTabItem getItem (Point pt) { * 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(); @@ -699,6 +1313,11 @@ public int getItemCount(){ * 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 CTabItem [] getItems() { //checkWidget(); @@ -706,28 +1325,62 @@ public CTabItem [] getItems() { System.arraycopy(items, 0, tabItems, 0, items.length); return tabItems; } - -private int getLastItem(){ - if (items.length == 0) return -1; - Rectangle area = getClientArea(); - if (area.width <= 0) return 0; - Rectangle toolspace = getToolSpace(); - if (toolspace.width == 0) return items.length -1; - int width = area.width - toolspace.width; - int index = topTabIndex; - int tabWidth = items[index].width; - while (index < items.length - 1) { - tabWidth += items[index + 1].width; - if (tabWidth > width) break; +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++; - } - return 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> + */ +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> + */ +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 CTabItem getSelection() { //checkWidget(); @@ -739,24 +1392,38 @@ public CTabItem getSelection() { * 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; } -private Rectangle getToolSpace() { - boolean showArrows = scroll_leftVisible() || scroll_rightVisible(); - if (!showArrows && topRight == null) return new Rectangle(0, 0, 0, 0); - Rectangle toolspace; - if (showArrows) { - toolspace = arrowBar.getBounds(); - toolspace.width += borderRight; - if (topRight != null) toolspace.width += topRight.getSize().x; - } else { - toolspace = topRight.getBounds(); - toolspace.width += borderRight; - } - return toolspace; +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. @@ -780,14 +1447,21 @@ public Control getTopRight() { * 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_NULL_ARGUMENT when the item is null</li> - * </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(CTabItem item) { - //checkWidget(); + checkWidget(); if (item == null) { SWT.error(SWT.ERROR_NULL_ARGUMENT); } @@ -796,8 +1470,7 @@ public int indexOf(CTabItem item) { } return -1; } - -private void initAccessible() { +void initAccessible() { final Accessible accessible = getAccessible(); accessible.addAccessibleListener(new AccessibleAdapter() { public void getName(AccessibleEvent e) { @@ -970,174 +1643,66 @@ private void initAccessible() { } }); } - -private void setButtonBounds() { - - updateArrowBar(); - updateCloseBar(); - - Rectangle area = super.getClientArea(); - - int offset = 0; - if (topRight != null) { - Point size = topRight.computeSize(SWT.DEFAULT, tabHeight); - int x = area.x + area.width - borderRight - size.x; - int y = onBottom ? area.y + area.height - borderBottom - size.y : area.y + borderTop; - topRight.setBounds(x, y, size.x, size.y); - offset = size.x; - } - boolean leftVisible = scroll_leftVisible(); - boolean rightVisible = scroll_rightVisible(); - if (leftVisible || rightVisible) { - Point size = arrowBar.computeSize(SWT.DEFAULT, tabHeight); - int x = area.x + area.width - borderRight - size.x - offset; - int y = (onBottom) ? area.y + area.height - borderBottom - size.y : area.y + borderTop; - - arrowBar.setBounds(x, y, size.x, size.y); - ToolItem[] items = arrowBar.getItems(); - items[0].setEnabled(leftVisible); - items[1].setEnabled(rightVisible); - arrowBar.setVisible(true); - } else { - arrowBar.setVisible(false); - } - - // When the close button is right at the edge of the Tab folder, hide it because - // otherwise it may block off a part of the border on the right - if (showClose) { - inactiveCloseBar.setVisible(false); - CTabItem item = getSelection(); - if (item == null) { - closeBar.setVisible(false); - } else { - int toolbarHeight = tabHeight - CTabItem.TOP_MARGIN - CTabItem.BOTTOM_MARGIN + 2; // +2 to ignore gap between focus rectangle - Point size = closeBar.computeSize(SWT.DEFAULT, toolbarHeight); - int x = item.x + item.width - size.x - 2; // -2 to not overlap focus rectangle and trim - int y = item.y + Math.max(0, (item.height - toolbarHeight)/2); - closeBar.setBounds(x, y, size.x, toolbarHeight); - Rectangle toolspace = getToolSpace(); - Point folderSize = getSize(); - boolean visible = (toolspace.width == 0 || x < toolspace.x) && x + size.x < folderSize.x - borderRight; - closeBar.setVisible(visible); - } - } +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; } -private boolean setItemLocation() { - if (items.length == 0) return false; - Rectangle area = super.getClientArea(); - int x = area.x; - int y = area.y + borderTop; - if (onBottom) y = Math.max(0, area.y + area.height - borderBottom - tabHeight); +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; - boolean changed = false; - for (int i = topTabIndex - 1; i>=0; i--) { - // if the first visible tab is not the first tab - CTabItem 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; + int length = items.length; + for (int i = 0; i < length; i++) { + if (items[i] != null) { + items[i].dispose(); + } } - x = area.x + borderLeft; - for (int i = topTabIndex; i < items.length; i++) { - // continue laying out remaining, visible items left to right - CTabItem tab = items[i]; - tab.x = x; - tab.y = y; - x = x + tab.width; - } - setButtonBounds(); - return changed; -} -private void setLastItem(int index) { - if (index < 0 || index > items.length - 1) return; - Rectangle area = getClientArea(); - if (area.width <= 0) return; - int maxWidth = area.width; - Rectangle toolspace = getToolSpace(); - if (toolspace.width > 0){ - maxWidth -= toolspace.width; - } - int tabWidth = items[index].width; - while (index > 0) { - tabWidth += items[index - 1].width; - if (tabWidth > maxWidth) break; - index--; - } - topTabIndex = index; - setItemLocation(); - redrawTabArea(-1); -} -/** - * Layout the items and store the client area size. - */ -boolean setItemBounds() { - boolean changed = false; - if (isDisposed()) return changed; - Rectangle area = super.getClientArea(); + selectionGradientColors = null; + selectionGradientPercents = null; + selectionBgImage = null; - xClient = area.x + borderLeft + marginWidth; - if (onBottom) { - yClient = area.y + borderTop + marginHeight; + selectionBackground = null; + selectionForeground = null; +} +void onFocus(Event event) { + checkWidget(); + if (selectedIndex >= 0) { + redraw(); } else { - yClient = area.y + borderTop + tabHeight + 1 + marginHeight; - // +1 is for the line at the bottom of the tabs - } - - if (area.width <= 0 || area.height <= 0 || items.length == 0) return changed; - - 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); + setSelection(0, true); } - gc.dispose(); - - int oldAverageWidth = 0; - int averageWidth = (area.width - borderLeft - borderRight) / items.length; - while (averageWidth > oldAverageWidth) { - int width = area.width - borderLeft - borderRight; - int count = items.length; - for (int i = 0; i < items.length; i++) { - if (widths[i] < averageWidth) { - width -= widths[i]; - count--; +} +void onMenu(Event event) { + if (single && selectedIndex != -1) { + final CTabFolderEvent e = new CTabFolderEvent(CTabFolder.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); } } - 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 (widths[i] > averageWidth) { - widths[i] = averageWidth; - } - } - - int totalWidth = 0; - for (int i = 0; i < items.length; i++) { - CTabItem tab = items[i]; - if (tab.height != tabHeight || tab.width != widths[i]) changed = true; - tab.height = tabHeight; - tab.width = widths[i]; - totalWidth += widths[i]; - } - - int areaWidth = area.x + area.width - borderRight; - if (totalWidth <= areaWidth) { - topTabIndex = 0; - } - if (setItemLocation()) changed = true; - - // Is there a gap after last item showing - if (correctLastItem()) changed = true; - return changed; } -private boolean onMnemonic (Event event) { +boolean onMnemonic (Event event) { char key = event.character; for (int i = 0; i < items.length; i++) { if (items[i] != null) { @@ -1152,169 +1717,336 @@ private boolean onMnemonic (Event event) { } return false; } -/** - * Paint the receiver. - */ -private void onPaint(Event event) { - Font font = getFont(); - if (oldFont == null || !oldFont.equals(font)) { - oldFont = font; - resetTabSize(true); - } - GC gc = event.gc; - Rectangle rect = super.getClientArea(); - if (items.length == 0) { - if (showBorders) { - if ((getStyle() & SWT.FLAT) != 0) { - gc.setForeground(borderColor1); - gc.drawRectangle(rect.x, rect.y, rect.x + rect.width - 1, rect.y + rect.height - 1); +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 { - gc.setForeground(borderColor1); - gc.drawRectangle(rect.x, rect.y, rect.x + rect.width - 3, rect.y + rect.height - 3); - - // fill in right and bottom edges with parent's background - gc.setBackground(getParent().getBackground()); - gc.fillRectangle(rect.x + rect.width - 2, rect.y, 2, rect.height); - gc.fillRectangle(rect.x, rect.y + rect.height - 2, rect.width, 2); + minmaxListeners[i].maximize(e); } - gc.setForeground(getForeground()); - } - return; - } - - // redraw the Border - drawBorder(gc); - - rect.x += borderLeft; - rect.y += borderTop; - rect.width -= borderLeft + borderRight; - rect.height -= borderTop + borderBottom; - Rectangle clip = gc.getClipping (); - gc.setClipping(clip.intersection(rect)); - - // Draw the unselected tabs first. - for (int i=0; i < items.length; i++) { - if (i != selectedIndex && event.getBounds().intersects(items[i].getBounds())) { - items[i].onPaint(gc, false); } + if (e.doit) setMaximized(!restore); } - // Selected tab comes last - if (selectedIndex != -1) { - items[selectedIndex].onPaint(gc, true); - } + - // 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); - } + Event e = new Event(); + e.item = getItem(new Point(event.x, event.y)); + if (e.item != null) { + notifyListeners(SWT.DefaultSelection, e); } - - gc.setForeground(getForeground()); - gc.setBackground(getBackground()); } -private void redrawTabArea(int index) { - int x = 0, y = 0, width = 0, height = 0; - if (index == -1) { - Rectangle area = super.getClientArea(); - if (area.width == 0 || area.height == 0) return; - width = area.x + area.width - borderLeft - borderRight; - height = tabHeight + 1; // +1 causes top line between content and tabs to be redrawn - x = area.x + borderLeft; - y = area.y + borderTop; - if (onBottom) { - y = Math.max(0, area.y + area.height - borderBottom - height); +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 (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++) { + CTabItem 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++) { + CTabItem 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(); + 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++) { + CTabItem 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 (event.button != 1) return; + if (chevronRect.contains(x, y)) { + boolean selected = chevronImageState == SELECTED; + chevronImageState = HOT; + redraw(chevronRect.x, chevronRect.y, chevronRect.width, chevronRect.height, false); + update(); + if (!selected) return; + 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)) { + boolean selected = minImageState == SELECTED; + minImageState = HOT; + redraw(minRect.x, minRect.y, minRect.width, minRect.height, false); + update(); + if (!selected) return; + 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 && !isDisposed()) setMinimized(!restore); + return; + } + if (maxRect.contains(x, y)) { + boolean selected = maxImageState == SELECTED; + maxImageState = HOT; + redraw(maxRect.x, maxRect.y, maxRect.width, maxRect.height, false); + update(); + if (!selected) return; + 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 && !isDisposed()) setMaximized(!restore); + return; + } + for (int i=0; i<items.length; i++) { + CTabItem item = items[i]; + if (item.closeRect.contains(x,y)){ + boolean selected = item.closeImageState == SELECTED; + item.closeImageState = HOT; + redraw(item.closeRect.x, item.closeRect.y, item.closeRect.width, item.closeRect.height, false); + update(); + if (!selected) return; + 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; } - } else { - CTabItem item = items[index]; - x = item.x; - y = item.y; - Rectangle area = super.getClientArea(); - width = area.x + area.width - x; - height = item.height; } - redraw(x, y, width, height, false); } - -/** - * Removes the listener. - * - * @param listener the listener - * - * @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> - * <li>ERROR_NULL_ARGUMENT when listener is null</li></ul> - */ -public void removeSelectionListener(SelectionListener listener) { - checkWidget(); - if (listener == null) { - SWT.error(SWT.ERROR_NULL_ARGUMENT); +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; } - removeListener(SWT.Selection, listener); - removeListener(SWT.DefaultSelection, listener); + setSelection (index, true); + //setFocus(); + return true; } -/** - * Removes the listener. - * - * @param listener the listener - * - * @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> - * <li>ERROR_NULL_ARGUMENT when listener is null</li></ul> - */ -public void removeCTabFolderListener(CTabFolderListener listener) { - checkWidget(); - if (listener == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); - if (tabListeners.length == 0) return; - int index = -1; - for (int i = 0; i < tabListeners.length; i++) { - if (listener == tabListeners[i]){ - index = i; - break; +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(); + return; } } - if (index == -1) return; - if (tabListeners.length == 1) { - tabListeners = new CTabFolderListener[0]; - showClose = false; - setButtonBounds(); + +// Useful for debugging paint problems +//{ +//GC gc = event.gc; +//Point size = getSize(); +//gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_GREEN)); +//gc.fillRectangle(-10, -10, size.x + 20, size.y+20); +//} + + GC gc = event.gc; + if (items.length == 0) { + Point size = getSize(); + gc.setBackground(getParent().getBackground()); + gc.fillRectangle(0, 0, size.x, size.y); return; } - CTabFolderListener[] newTabListeners = new CTabFolderListener[tabListeners.length - 1]; - System.arraycopy(tabListeners, 0, newTabListeners, 0, index); - System.arraycopy(tabListeners, index + 1, newTabListeners, index, tabListeners.length - index - 1); - tabListeners = newTabListeners; + + drawBody(event); + drawTabArea(event); + + gc.setForeground(getForeground()); + gc.setBackground(getBackground()); } -/** - * The widget was resized. Adjust the size of the currently selected page. - */ -private void onResize() { - +void onResize() { if (items.length == 0) { redraw(); return; } - - if (setItemBounds()) { - redrawTabArea(-1); - } + if (updateItems()) redraw(); + showSelection(); Point size = getSize(); if (oldSize == null) { @@ -1343,27 +2075,185 @@ private void onResize() { } } } - +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); - background = color; - // init inactive close button - inactiveCloseBar.setBackground(color); - - // init scroll buttons - arrowBar.setBackground(color); - - //init topRight control - if (topRight != null) - topRight.setBackground(color); - - // init close button - if (gradientColors == null) { - closeBar.setBackground(color); - } + redraw(); } /** - * Specify a gradient of colours to be draw in the background of the selected tab. + * Specify a gradient of colours to be draw in the background of the unselected tabs. * For example to draw a gradient that varies from dark blue to blue and then to * white, use the following call to setBackground: * <pre> @@ -1387,18 +2277,44 @@ public void setBackground (Color color) { * <li>ERROR_WIDGET_DISPOSED when the widget has been disposed</li> * </ul> */ - -public void setSelectionBackground(Color[] colors, int[] percents) { +public void setBackground(Color[] colors, int[] percents) { + setBackground(colors, percents, false); +} +/** + * Specify a gradient of colours to be draw in the background of the unselected 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 setBackground(Color[] colors, int[] percents, boolean vertical) { checkWidget(); if (colors != null) { if (percents == null || percents.length != colors.length - 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[] { }; - } for (int i = 0; i < percents.length; i++) { if (percents[i] < 0 || percents[i] > 100) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); @@ -1407,10 +2323,15 @@ public void setSelectionBackground(Color[] colors, int[] percents) { 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 (bgImage == null) { if ((gradientColors != null) && (colors != null) && (gradientColors.length == colors.length)) { boolean same = false; @@ -1428,33 +2349,37 @@ public void setSelectionBackground(Color[] colors, int[] percents) { if (!same) break; } } - if (same) return; + if (same && this.gradientVertical == vertical) return; } } else { - backgroundImage = null; + bgImage = null; } // Store the new settings if (colors == null) { gradientColors = null; gradientPercents = null; - closeBar.setBackground(background); + gradientVertical = false; + setBackground((Color)null); } else { gradientColors = new Color[colors.length]; - for (int i = 0; i < colors.length; ++i) + 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) + for (int i = 0; i < percents.length; ++i) { gradientPercents[i] = percents[i]; - if (getDisplay().getDepth() < 15) closeBar.setBackground(background); - else closeBar.setBackground(gradientColors[gradientColors.length - 1]); + } + gradientVertical = vertical; + setBackground(gradientColors[gradientColors.length-1]); } // Refresh with the new settings - if (selectedIndex > -1) redrawTabArea(selectedIndex); + redraw(); } /** - * Set the image to be drawn in the background of the selected tab. + * Set the image to be drawn in the background of the unselected tab. Image + * is stretched or compressed to cover entire unselected tab area. * * @param image the image to be drawn in the background * @@ -1463,15 +2388,15 @@ public void setSelectionBackground(Color[] colors, int[] percents) { * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ -public void setSelectionBackground(Image image) { +public void setBackground(Image image) { checkWidget(); - if (image == backgroundImage) return; + if (image == bgImage) return; if (image != null) { gradientColors = null; gradientPercents = null; } - backgroundImage = image; - redrawTabArea(selectedIndex); + bgImage = image; + redraw(); } /** * Toggle the visibility of the border @@ -1485,48 +2410,144 @@ public void setSelectionBackground(Image image) { */ public void setBorderVisible(boolean show) { checkWidget(); - if (showBorders == show) return; + 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(); - showBorders = show; - if (showBorders) { - if ((getStyle() & SWT.FLAT) != 0) { - borderBottom = borderTop = borderLeft = borderRight = 1; + 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 - 3; + if (borderRight > 0) maxRect.x += 1; + maxRect.y = onBottom ? size.y - borderBottom - tabHeight: borderTop + 1; + maxRect.width = BUTTON_SIZE; + maxRect.height = tabHeight - 1; + } + 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 - 3; + if (borderRight > 0) minRect.x += 1; + minRect.y = onBottom ? size.y - borderBottom - tabHeight: borderTop + 1; + minRect.width = BUTTON_SIZE; + minRect.height = tabHeight - 1; + } + 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) { + CTabItem item = items[selectedIndex]; + topRightRect.x = Math.min(item.x +item.width + BUTTON_SIZE, size.x - borderRight - minRect.width - maxRect.width - topRightSize.x - 3); } else { - borderLeft = borderTop = 1; - borderRight = borderBottom = 3; + topRightRect.x = size.x - borderRight - minRect.width - maxRect.width - topRightSize.x - 3; } - } else { - borderBottom = borderTop = borderLeft = borderRight = 0; + topRightRect.y = onBottom ? size.y - borderBottom - tabHeight: borderTop + 1; + topRightRect.width = topRightSize.x; + topRightRect.height = tabHeight - 1; + topRight.setBounds(topRightRect); } - oldSize = null; - notifyListeners(SWT.Resize, new Event()); -} -public void setFont(Font font) { - checkWidget(); - if (font != null && font.equals(getFont())) return; - super.setFont(font); - oldFont = getFont(); - resetTabSize(true); + 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){ + CTabItem 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 - 1; + } else { + int rightEdge = getRightItemEdge(); + CTabItem 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 - 3; + if (borderRight > 0) chevronRect.x += 1; + chevronRect.y = onBottom ? size.y - borderBottom - tabHeight: borderTop + 1; + chevronRect.width = BUTTON_SIZE; + chevronRect.height = tabHeight - 1; + } + } + } + if (oldX != chevronRect.x || oldWidth != chevronRect.width || + oldY != chevronRect.y || oldHeight != chevronRect.height) changed = true; + + return changed; } /** - * Set the foreground color of the selected tab. - * - * @param color the color of the text displayed in the selected tab - * + * Sets the minimized state of the receiver. + * <p> + * + * @param expanded 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> + * + * @deprecated use setMinimized(boolean) */ -public void setSelectionForeground (Color color) { +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 (selectionForeground == color) return; - if (color == null) color = getForeground(); - selectionForeground = color; - if (selectedIndex > -1) { - redrawTabArea(selectedIndex); + 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. * @@ -1554,10 +2575,13 @@ public void setInsertMark(CTabItem item, boolean after) { * * A value of -1 will clear the mark. * - * @param item the index of the item with which the mark is associated or null + * @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> @@ -1569,19 +2593,231 @@ public void setInsertMark(int index, boolean after) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } - if (index == -1) { - index = -2; +// 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) { + CTabItem 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 - CTabItem.RIGHT_MARGIN - 8; + item.closeRect.y = onBottom ? y : y + CTabItem.TOP_MARGIN; + } + if (item.x != oldX || item.y != oldY) changed = true; + } } else { - index = after ? index : --index; + int x = -1; + for (int i = topTabIndex - 1; i >= 0; i--) { + // if the first visible tab is not the first tab + CTabItem item = items[i]; + x -= item.width; + if (!changed && (item.x != x || item.y != y) ) changed = true; + // layout tab items from right to left thus making them invisible + item.x = x; + item.y = y; + item.closeRect.x = item.x + item.width - BUTTON_SIZE - CTabItem.RIGHT_MARGIN; + if (i == selectedIndex) item.closeRect.x -= 8; + item.closeRect.y = onBottom ? y : y + CTabItem.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 + CTabItem item = items[i]; + item.x = x; + item.y = y; + item.closeRect.x = item.x + item.width - BUTTON_SIZE - CTabItem.RIGHT_MARGIN; + if (i == selectedIndex) item.closeRect.x -= 8; + item.closeRect.y = onBottom ? y : y + CTabItem.TOP_MARGIN; + x = x + item.width; + } + + int rightEdge = getRightItemEdge(); + if (rightEdge > 0) { + CTabItem 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; } - if (insertionIndex == index) return; - int oldIndex = insertionIndex; - insertionIndex = index; - if (index > -1) redrawTabArea(index); - if (oldIndex > 1) redrawTabArea(oldIndex); + 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++) { + CTabItem 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(CTabItem 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. * @@ -1595,10 +2831,17 @@ public void setInsertMark(int index, boolean after) { public void setSelection(int index) { checkWidget(); if (index < 0 || index >= items.length) return; - if (selectedIndex == index) 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()) { @@ -1612,9 +2855,272 @@ public void setSelection(int index) { control.setVisible(false); } } - showItem(items[selectedIndex]); - setButtonBounds(); - redrawTabArea(-1); + 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 (selectionBgImage == null) { + if ((selectionGradientColors != null) && (colors != null) && + (selectionGradientColors.length == colors.length)) { + boolean same = false; + for (int i = 0; i < selectionGradientColors.length; i++) { + if (selectionGradientColors[i] == null) { + same = colors[i] == null; + } else { + same = selectionGradientColors[i].equals(colors[i]); + } + if (!same) break; + } + if (same) { + for (int i = 0; i < selectionGradientPercents.length; i++) { + same = selectionGradientPercents[i] == percents[i]; + if (!same) break; + } + } + if (same && this.selectionGradientVertical == vertical) return; + } + } else { + selectionBgImage = null; + } + // Store the new settings + if (colors == null) { + selectionGradientColors = null; + selectionGradientPercents = null; + selectionGradientVertical = false; + setSelectionBackground((Color)null); + } else { + selectionGradientColors = new Color[colors.length]; + for (int i = 0; i < colors.length; ++i) { + selectionGradientColors[i] = colors[i]; + } + selectionGradientPercents = new int[percents.length]; + for (int i = 0; i < percents.length; ++i) { + selectionGradientPercents[i] = percents[i]; + } + selectionGradientVertical = vertical; + setSelectionBackground(selectionGradientColors[selectionGradientColors.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) { + checkWidget(); + if (image == selectionBgImage) return; + if (image != null) { + selectionGradientColors = null; + selectionGradientPercents = null; + } + selectionBgImage = 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. @@ -1630,6 +3136,7 @@ public void setSelection(int index) { * <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(); @@ -1637,9 +3144,8 @@ public void setTopRight(Control control) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } topRight = control; - resetTabSize(true); + 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 @@ -1665,26 +3171,78 @@ public void showItem (CTabItem item) { 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 (index < topTabIndex) { - topTabIndex = index; - setItemLocation(); - redrawTabArea(-1); + if (size.x <= borderLeft + borderRight || index < topTabIndex) { + setFirstItem(index); return; } - Rectangle area = getClientArea(); - if (area.width <= 0) { - topTabIndex = index; - return; - } - int rightEdge = area.x + area.width; - Rectangle rect = getToolSpace(); - if (rect.width > 0) { - rightEdge -= rect.width; - } + 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++) { + CTabItem 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 @@ -1706,472 +3264,150 @@ public void showSelection () { showItem(getSelection()); } } - -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'; -} -/** - * Set the selection to the tab at the specified item. - * - * @param index 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> - * <li>ERROR_NULL_ARGUMENT - if argument is null</li> - * </ul> - */ -public void setSelection(CTabItem 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. - */ -private 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); - } -} - -private Image scaleImage (Image image, int oldSize, int newSize) { - Display display = getDisplay(); - Color foreground = getForeground(); - Color black = display.getSystemColor(SWT.COLOR_BLACK); - Color background = getBackground(); - PaletteData palette = new PaletteData(new RGB[]{foreground.getRGB(), background.getRGB(), black.getRGB()}); - ImageData imageData = new ImageData(newSize, newSize, 4, palette); - imageData.transparentPixel = 1; - Image temp = new Image(display, imageData); - GC gc = new GC(temp); - gc.setBackground(background); - gc.fillRectangle(0, 0, newSize, newSize); - gc.drawImage(image, 0, 0, oldSize, oldSize, 0, 0, newSize, newSize); - gc.dispose(); - return temp; -} -private void updateCloseBar() { - //Temporary code - need a better way to determine toolBar trim - int toolbarTrim = 4; - String platform = SWT.getPlatform(); - if ("photon".equals(platform)) toolbarTrim = 6; //$NON-NLS-1$ - if ("gtk".equals(platform)) toolbarTrim = 8; //$NON-NLS-1$ - - int maxHeight = tabHeight - CTabItem.TOP_MARGIN - CTabItem.BOTTOM_MARGIN - toolbarTrim; - if (maxHeight < 3) return; - int imageHeight = Math.max(9, maxHeight); - - if (closeImage != null) { - int height = closeImage.getBounds().height; - if (height == imageHeight) return; - if (imageHeight > maxHeight && height == maxHeight) return; - } - - if (closeBar != null) closeBar.dispose(); - closeBar = null; - if (inactiveCloseBar != null) inactiveCloseBar.dispose(); - inactiveCloseBar = null; - createCloseBar(); - - ToolItem closeItem = closeBar.getItems()[0]; - ToolItem inactiveCloseItem = inactiveCloseBar.getItems()[0]; - - if (closeImage != null) closeImage.dispose(); - - Display display = getDisplay(); - Color foreground = getForeground(); - Color black = display.getSystemColor(SWT.COLOR_BLACK); - Color background = getBackground(); - - PaletteData palette = new PaletteData(new RGB[]{foreground.getRGB(), background.getRGB(), black.getRGB()}); - ImageData imageData = new ImageData(imageHeight, imageHeight, 4, palette); - imageData.transparentPixel = 1; - closeImage = new Image(display, imageData); - GC gc = new GC(closeImage); - gc.setBackground(background); - gc.fillRectangle(0, 0, imageHeight, imageHeight); - gc.setForeground(black); - - //draw an 9x8 'x' centered in image - int h = (imageHeight / 2 )* 2; - int inset = (h - 8) / 2; - gc.drawLine( inset, inset, h - inset - 1, h - inset - 1); - gc.drawLine( inset + 1, inset, h - inset, h - inset - 1); - gc.drawLine( inset, h - inset - 1, h - inset - 1, inset); - gc.drawLine( inset + 1, h - inset - 1, h - inset, inset); - - gc.dispose(); +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 (maxHeight < imageHeight) { - try { - //rescale image - Image temp = scaleImage(closeImage, imageHeight, maxHeight); - closeImage.dispose(); - closeImage = temp; - } catch (IllegalArgumentException e) { - } catch (SWTException e) { - } - } - closeItem.setImage(closeImage); - inactiveCloseItem.setImage(closeImage); -} -private void updateArrowBar() { - //Temporary code - need a better way to determine toolBar trim - int toolbarTrim = 4; - String platform = SWT.getPlatform(); - if ("photon".equals(platform)) toolbarTrim = 6; //$NON-NLS-1$ - if ("gtk".equals(platform)) toolbarTrim = 8; //$NON-NLS-1$ - - int maxHeight = tabHeight - toolbarTrim; - if (maxHeight < 3) return; - int imageHeight = Math.max(9, maxHeight); - - if (arrowLeftImage != null) { - int height = arrowLeftImage.getBounds().height; - if (height == imageHeight) return; - if (imageHeight > maxHeight && height == maxHeight) return; + if (!updateToolTip(x, y, label)) { + tip.dispose(); + return; } - - if (arrowBar != null) arrowBar.dispose(); - arrowBar = null; - if (arrowLeftImage != null) arrowLeftImage.dispose(); - if (arrowRightImage != null) arrowRightImage.dispose(); - createArrowBar(); - ToolItem[] items = arrowBar.getItems(); - ToolItem left = items[0]; - ToolItem right = items[1]; - - Display display = getDisplay(); - Color foreground = getForeground(); - Color black = display.getSystemColor(SWT.COLOR_BLACK); - Color background = getBackground(); - - PaletteData palette = new PaletteData(new RGB[]{foreground.getRGB(), background.getRGB(), black.getRGB()}); - ImageData imageData = new ImageData(7, imageHeight, 4, palette); - imageData.transparentPixel = 1; - arrowLeftImage = new Image(display, imageData); - GC gc = new GC(arrowLeftImage); - gc.setBackground(background); - gc.fillRectangle(0, 0, 7, imageHeight); - gc.setBackground(black); - //draw a 9x5 '<' centered vertically in image - int h = (imageHeight / 2 )* 2; - int midpoint = h / 2 - 1; - int[] pointArr = new int[] {6, midpoint - 5, - 1, midpoint, - 6, midpoint + 5,}; - gc.fillPolygon(pointArr); - gc.dispose(); - - palette = new PaletteData(new RGB[]{foreground.getRGB(), background.getRGB(), black.getRGB()}); - imageData = new ImageData(7, imageHeight, 4, palette); - imageData.transparentPixel = 1; - arrowRightImage = new Image(display, imageData); - gc = new GC(arrowRightImage); - gc.setBackground(background); - gc.fillRectangle(0, 0, 7, imageHeight); - gc.setBackground(black); - //draw a 9x5 '>' centered vertically in image - pointArr = new int[] {1, midpoint - 5, - 6, midpoint, - 1, midpoint + 5,}; - gc.fillPolygon(pointArr); - gc.dispose(); - - if (maxHeight < imageHeight) { - try { - //rescale image - Image leftTemp = scaleImage(arrowLeftImage, imageHeight, maxHeight); - arrowLeftImage.dispose(); - arrowLeftImage = leftTemp; - } catch (IllegalArgumentException e) { - } catch (SWTException e) { - } - - try { - Image rightTemp = scaleImage(arrowRightImage, imageHeight, maxHeight); - arrowRightImage.dispose(); - arrowRightImage = rightTemp; - } catch (IllegalArgumentException e) { - } catch (SWTException e) { - } - } - left.setImage(arrowLeftImage); - right.setImage(arrowRightImage); -} - -private void onMouseDoubleClick(Event event) { - Event e = new Event(); - e.item = getItem(new Point(event.x, event.y)); - notifyListeners(SWT.DefaultSelection, e); -} -/** - * A mouse button was pressed down. - * If a tab was hit select the tab. - */ -private void onMouseDown(Event event) { - for (int i=0; i<items.length; i++) { - if (items[i].getBounds().contains(new Point(event.x, event.y))) { - if (i == selectedIndex) { - showSelection(); - 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; } - forceFocus(); - setSelection(i, true); - if (isFocusControl()) setFocus(); - return; - } - } -} - -private void onMouseExit(Event event) { - Rectangle inactiveBounds = inactiveCloseBar.getBounds(); - if (inactiveBounds.contains(event.x, event.y)) return; - inactiveCloseBar.setVisible(false); - inactiveItem = null; - - showToolTip = false; - toolTipItem = null; - if (tip != null && !tip.isDisposed() && tip.isVisible()) tip.setVisible(false); -} - -private void onMouseHover(Event event) { - if (tip == null || tip.isDisposed()) return; - showToolTip = true; - showToolTip(event.x, event.y); -} -private void showToolTip (int x, int y) { - CTabItem item = getItem(new Point (x, y)); - if (item != null) { - if (item == toolTipItem) return; - toolTipItem = item; - String tooltip = item.getToolTipText(); - if (tooltip != null) { - Display display = tip.getDisplay(); - label.setForeground (display.getSystemColor (SWT.COLOR_INFO_FOREGROUND)); - label.setBackground (display.getSystemColor (SWT.COLOR_INFO_BACKGROUND)); - 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 pt = new Point(item.x + item.width / 4, item.y + item.height + 2); - pt = toDisplay(pt); - Rectangle rect = display.getBounds(); - Point tipSize = tip.getSize(); - pt.x = Math.max (0, Math.min (pt.x, rect.width - tipSize.x)); - pt.y = Math.max (0, Math.min (pt.y, rect.height - tipSize.y)); - tip.setLocation(pt); - tip.setVisible(true); - return; - } - } - - toolTipItem = null; - if (tip != null && !tip.isDisposed() && tip.isVisible()) tip.setVisible(false); -} -private void onMouseMove(Event event) { - if (showToolTip) { - showToolTip(event.x, event.y); - } - - if (!showClose) return; - - CTabItem item = null; - for (int i=0; i<items.length; i++) { - Rectangle rect = items[i].getBounds(); - if (rect.contains(new Point(event.x, event.y))) { - item = items[i]; - break; } + }; + for (int i = 0; i < events.length; i++) { + addListener(events[i], listener[0]); } - if (item == inactiveItem) return; - - inactiveCloseBar.setVisible(false); - inactiveItem = null; - - if (item == null || item == getSelection()) return; - - int toolbarHeight = tabHeight - CTabItem.TOP_MARGIN - CTabItem.BOTTOM_MARGIN + 2; // +2 to ignore gap between focus rectangle - Point size = inactiveCloseBar.computeSize(SWT.DEFAULT, toolbarHeight); - int x = item.x + item.width - size.x - 2; // -2 to not overlap focus rectangle and trim - int y = item.y + Math.max(0, (item.height - toolbarHeight)/2); - Rectangle toolspace = getToolSpace(); - Point folderSize = getSize(); - if ((toolspace.width == 0 || x < toolspace.x) && x + size.x < folderSize.x - borderRight) { - inactiveCloseBar.setBounds(x, y, size.x, toolbarHeight); - inactiveCloseBar.setVisible(true); - inactiveItem = item; - } -} -private void onTraverse (Event event) { - switch (event.detail) { - case SWT.TRAVERSE_ESCAPE: -// TEMPORARY CODE See bug report 17372 -// 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); - if (event.doit) event.detail = SWT.TRAVERSE_NONE; - break; - } -} - -private boolean onPageTraversal(Event event) { - int count = getItemCount (); - if (count == 0) return false; - int index = getSelectionIndex (); - if (index == -1) { - index = 0; - } else { - int offset = (event.detail == SWT.TRAVERSE_PAGE_NEXT) ? 1 : -1; - index = (index + offset + count) % count; - } - setSelection (index, true); - return true; -} - -/** - * Answer true if not all tabs can be visible in the receive - * thus requiring the scroll buttons to be visible. - */ -private boolean scroll_leftVisible() { - return topTabIndex > 0; -} - -/** - * Answer true if not all tabs can be visible in the receive - * thus requiring the scroll buttons to be visible. - */ -private boolean scroll_rightVisible() { - // only show Scroll buttons if there is more than one item - // and if we are not already at the last item - if (items.length < 2) return false; - Rectangle area = getClientArea(); - int rightEdge = area.x + area.width; - if (rightEdge <= 0) return false; - if (topTabIndex > 0) { - rightEdge -= arrowBar.getSize().x; - } - if (topRight != null) { - rightEdge -= topRight.getSize().x; - } - CTabItem item = items[items.length-1]; - return (item.x + item.width > rightEdge); -} - -/** - * Scroll the tab items to the left. - */ -private void scroll_scrollLeft() { - if (items.length == 0) return; - setLastItem(topTabIndex - 1); -} - -/** - * Scroll the tab items to the right. - */ -private void scroll_scrollRight() { - int lastIndex = getLastItem(); - topTabIndex = lastIndex + 1; - setItemLocation(); - correctLastItem(); - redrawTabArea(-1); -} -private boolean correctLastItem() { - Rectangle area = getClientArea(); - int rightEdge = area.x + area.width; - if (rightEdge <= 0) return false; - Rectangle toolspace = getToolSpace(); - if (toolspace.width > 0) { - rightEdge -= toolspace.width; - } - CTabItem item = items[items.length - 1]; - if (item.x + item.width < rightEdge) { - setLastItem(items.length - 1); - return true; - } - return false; + tipShowing = true; + tip.setVisible(true); } -/** - * 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 0 will revert to the default height. - * - * @param height the pixel value of the height or 0 - * - * @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 < 0) { - SWT.error(SWT.ERROR_INVALID_ARGUMENT); +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; } - fixedTabHeight = true; - if (tabHeight == height) return; - tabHeight = height; - oldSize = null; - notifyListeners(SWT.Resize, new Event()); + return changed; } -void resetTabSize(boolean checkHeight){ - int oldHeight = tabHeight; - if (!fixedTabHeight && checkHeight) { +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(); - if (topRight != null) tempHeight = Math.max(tempHeight, topRight.computeSize(SWT.DEFAULT, SWT.DEFAULT).y); tabHeight = tempHeight; } - - if (tabHeight != oldHeight){ - oldSize = null; - notifyListeners(SWT.Resize, new Event()); + 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 { - setItemBounds(); - redraw(); + 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) { + CTabItem 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; } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabItem.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabItem.java index 5dd95f90b1..35ab2f0c79 100755 --- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabItem.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/CTabItem.java @@ -15,26 +15,35 @@ import org.eclipse.swt.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.widgets.*; + +/** +* DO NOT USE - UNDER CONSTRUCTION +* +*/ + public class CTabItem extends Item { CTabFolder parent; int x,y,width,height = 0; - String toolTipText; Control control; // the tab page - - private Image disabledImage; - - // internal constants - static final int LEFT_MARGIN = 4; - static final int RIGHT_MARGIN = 4; - static final int TOP_MARGIN = 3; - static final int BOTTOM_MARGIN = 3; - private static final int INTERNAL_SPACING = 2; - - private static final String ellipsis = "..."; //$NON-NLS-1$ + String toolTipText; + Image disabledImage; String shortenedText; int shortenedTextWidth; + Rectangle closeRect = new Rectangle(0, 0, 0, 0); + int closeImageState = CTabFolder.NONE; + boolean showClose = false; + + // internal constants + static final int LEFT_MARGIN = 7; + static final int RIGHT_MARGIN = 6; + static final int TOP_MARGIN = 2; + static final int BOTTOM_MARGIN = 2; + static final int INTERNAL_SPACING = 2; + static final int FLAGS = SWT.DRAW_TRANSPARENT | SWT.DRAW_MNEMONIC; + static final String ellipsis = "..."; //$NON-NLS-1$ + /** * Constructs a new instance of this class given its parent * (which must be a <code>CTabFolder</code>) and a style value @@ -61,7 +70,7 @@ public class CTabItem extends Item { * </ul> * * @see SWT - * @see Widget#getStyle + * @see Widget#getStyle() */ public CTabItem (CTabFolder parent, int style) { this(parent, style, parent.getItemCount()); @@ -93,30 +102,367 @@ public CTabItem (CTabFolder parent, int style) { * </ul> * * @see SWT - * @see Widget#getStyle + * @see Widget#getStyle() */ public CTabItem (CTabFolder parent, int style, int index) { super (parent, checkStyle(style)); + showClose = (style & SWT.CLOSE) != 0; parent.createItem (this, index); } -private static int checkStyle(int style) { +static int checkStyle(int style) { return SWT.NONE; } - -public void dispose () { - if (isDisposed()) return; +static String shortenText(GC gc, String text, int width) { + if (gc.textExtent(text, FLAGS).x <= width) return text; + + int ellipseWidth = gc.textExtent(ellipsis, FLAGS).x; + int length = text.length(); + int end = length - 1; + while (end > 0) { + text = text.substring(0, end); + int l1 = gc.textExtent(text, FLAGS).x; + if (l1 + ellipseWidth <= width) { + return text + ellipsis; + } + end--; + } + return text + ellipsis; +} +public void dispose() { + if (isDisposed ()) return; + //if (!isValidThread ()) error (SWT.ERROR_THREAD_INVALID_ACCESS); parent.destroyItem(this); super.dispose(); parent = null; control = null; toolTipText = null; + shortenedText = null; } +void drawClose(GC gc) { + if (closeRect.width == 0 || closeRect.height == 0) return; + Display display = getDisplay(); + + // draw X (10x10 or 11x11) + int indent = Math.max(1, (parent.tabHeight-11)/2); + int x = closeRect.x + indent - 1; + int y = closeRect.y + indent; + switch (closeImageState) { + case CTabFolder.NORMAL: { + int[] shape = new int[] {x,y, x+2,y, x+4,y+2, x+5,y+2, x+7,y, x+9,y, + x+9,y+2, x+7,y+4, x+7,y+5, x+9,y+7, x+9,y+9, + x+7,y+9, x+5,y+7, x+4,y+7, x+2,y+9, x,y+9, + x,y+7, x+2,y+5, x+2,y+4, x,y+2}; + gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE)); + gc.fillPolygon(shape); + gc.setForeground(CTabFolder.borderColor); + gc.drawPolygon(shape); + break; + } + case CTabFolder.HOT: { + int[] shape = new int[] {x,y, x+2,y, x+4,y+2, x+5,y+2, x+7,y, x+9,y, + x+9,y+2, x+7,y+4, x+7,y+5, x+9,y+7, x+9,y+9, + x+7,y+9, x+5,y+7, x+4,y+7, x+2,y+9, x,y+9, + x,y+7, x+2,y+5, x+2,y+4, x,y+2}; + gc.setBackground(display.getSystemColor(SWT.COLOR_WHITE)); + gc.fillPolygon(shape); + Color border = new Color(display, CTabFolder.CLOSE_BORDER); + gc.setForeground(border); + gc.drawPolygon(shape); + border.dispose(); + break; + } + case CTabFolder.SELECTED: { + int[] shape = new int[] {x+1,y+1, x+3,y+1, x+5,y+3, x+6,y+3, x+8,y+1, x+10,y+1, + x+10,y+3, x+8,y+5, x+8,y+6, x+10,y+8, x+10,y+10, + x+8,y+10, x+6,y+8, x+5,y+8, x+3,y+10, x+1,y+10, + x+1,y+8, x+3,y+6, x+3,y+5, x+1,y+3}; + Color fill = new Color(display, CTabFolder.CLOSE_FILL); + gc.setBackground(fill); + gc.fillPolygon(shape); + fill.dispose(); + Color border = new Color(display, CTabFolder.CLOSE_BORDER); + gc.setForeground(border); + gc.drawPolygon(shape); + border.dispose(); + break; + } + case CTabFolder.NONE: { + int[] shape = new int[] {x,y, x+10,y, x+10,y+10, x,y+10}; + parent.drawBackground(gc, shape, false); + break; + } + } +} +void drawSelected(GC gc ) { + Point size = parent.getSize(); + // Draw selection border across all tabs + int parentX = parent.borderLeft; + int parentY = parent.onBottom ? size.y - parent.borderBottom - parent.tabHeight - CTabFolder.HIGHLIGHT_HEADER : parent.borderTop + parent.tabHeight + 1; + int parentWidth = size.x - parent.borderLeft - parent.borderRight; + int parentHeight = CTabFolder.HIGHLIGHT_HEADER - 1; + int[] shape = new int[] {parentX,parentY, parentX+parentWidth,parentY, parentX+parentWidth,parentY+parentHeight, parentX,parentY+parentHeight}; + parent.drawBackground(gc, shape, true); + + // if selected tab scrolled out of view or partially out of view + // draw line and clean up partial tab area + int rightTabEdge = parent.getRightItemEdge(); + if (!parent.single && parent.selectedIndex != parent.topTabIndex && x + width >= rightTabEdge){ + if (parent.onBottom) { + shape = new int[4]; + int index = 0; + shape[index++] = Math.max(0, parent.borderLeft - 1); + shape[index++] = y - 1; + shape[index++] = size.x - parent.borderRight; + shape[index++] = y - 1; + } else { + shape = new int[4]; + int index = 0; + shape[index++] = Math.max(0, parent.borderLeft - 1); + shape[index++] = y + height; + shape[index++] = size.x - parent.borderRight; + shape[index++] = y + height; + } + // draw line + gc.setForeground(CTabFolder.borderColor); + gc.drawPolyline(shape); + // if tab partially visible, fill in background for tab + shape = new int[] {x,y-1, x,y+height, size.x,y+height, size.x,y-1}; + parent.drawBackground(gc, shape, false); + return; + } + + // fill in background for non-rectangular shape + shape = new int[] {x,y, x+width,y, x+width,y+height, x,y+height}; + parent.drawBackground(gc, shape, false); + + // draw selected tab background and outline + int extra = CTabFolder.CURVE_WIDTH/2 + 4; // +4 to avoid overlapping with text in next tab + shape = null; + if (this.parent.onBottom) { + int[] left = CTabFolder.BOTTOM_LEFT_CORNER; + int[] right = parent.curve; + shape = new int[left.length+right.length+8]; + int index = 0; + shape[index++] = x; // first point repeated here because below we reuse shape to draw outline + shape[index++] = y - 1; + shape[index++] = x; + shape[index++] = y - 1; + for (int i = 0; i < left.length/2; i++) { + shape[index++] = x + left[2*i]; + shape[index++] = y + height + left[2*i+1] - 1; + } + for (int i = 0; i < right.length/2; i++) { + shape[index++] = x + width - extra + right[2*i]; + shape[index++] = y + 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 = y - 1; + } + shape[2*i] = rightTabEdge; + shape[2*i+1] = temp; + } + } + shape[index++] = rightTabEdge; + shape[index++] = y - 1; + shape[index++] = x + width + extra; + shape[index++] = y - 1; + } else { + int[] left = CTabFolder.TOP_LEFT_CORNER; + int[] right = parent.curve; + shape = new int[left.length+right.length+8]; + int index = 0; + shape[index++] = x; // first point repeated here because below we reuse shape to draw outline + shape[index++] = y + height; + shape[index++] = x; + shape[index++] = y + height; + for (int i = 0; i < left.length/2; i++) { + shape[index++] = x + left[2*i]; + shape[index++] = y + left[2*i+1]; + } + for (int i = 0; i < right.length/2; i++) { + shape[index++] = x + width - extra + right[2*i]; + shape[index++] = y + 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 = y + height + 1; + } + shape[2*i] = rightTabEdge; + shape[2*i+1] = temp; + } + } + shape[index++] = rightTabEdge; + shape[index++] = y + height + 1; + shape[index++] = x + width + extra; + shape[index++] = y + height + 1; + } + parent.drawBackground(gc, shape, true); + + // Limit drawing area of tab + Region r = new Region(); + r.subtract(r); //clear + Region clipping = new Region(); + gc.getClipping(clipping); + r.add(clipping); + r.intersect(new Rectangle(x, y, Math.min(width, rightTabEdge-x), height)); + gc.setClipping(r); + // draw Image + int xDraw = x + LEFT_MARGIN; + Image image = getImage(); + if (image != null) { + Rectangle imageBounds = image.getBounds(); + int imageX = xDraw; + int imageHeight = imageBounds.height; + int imageY = y + (height - imageHeight) / 2; + imageY += parent.onBottom ? -1 : 1; + int imageWidth = imageBounds.width * imageHeight / imageBounds.height; + gc.drawImage(image, + imageBounds.x, imageBounds.y, imageBounds.width, imageBounds.height, + imageX, imageY, imageWidth, imageHeight); + xDraw += imageWidth + INTERNAL_SPACING; + } + + // draw Text + int textWidth = x + width - xDraw - RIGHT_MARGIN; + if (closeRect.width > 0) textWidth -= closeRect.width + INTERNAL_SPACING; + if (shortenedText == null || shortenedTextWidth != textWidth) { + shortenedText = shortenText(gc, getText(), textWidth); + shortenedTextWidth = textWidth; + } + Point extent = gc.textExtent(shortenedText, FLAGS); + int textY = y + (height - extent.y) / 2; + textY += parent.onBottom ? -1 : 1; + + gc.setForeground(parent.selectionForeground); + gc.drawText(shortenedText, xDraw, textY, FLAGS); + + if (parent.showClose || showClose) drawClose(gc); + + // draw a Focus rectangle + if (parent.isFocusControl()) { + Display display = getDisplay(); + gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK)); + gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); + gc.drawFocus(xDraw-3, textY-2, extent.x+6, extent.y+4); + } + + gc.setClipping(clipping); + r.dispose(); + clipping.dispose(); + + // draw outline + shape[0] = Math.max(0, parent.borderLeft - 1); + shape[shape.length - 2] = size.x - parent.borderRight + 1; + for (int i = 0; i < shape.length/2; i++) { + if (shape[2*i + 1] == y + height + 1) shape[2*i + 1] -= 1; + } + RGB inside = parent.selectionBackground.getRGB(); + if (parent.selectionBgImage != null || (parent.selectionGradientColors != null && parent.selectionGradientColors.length > 1 && !parent.selectionGradientVertical)) inside = null; + RGB outside = parent.getBackground().getRGB(); + if (parent.bgImage != null || (parent.gradientColors != null && parent.gradientColors.length > 1 && !parent.gradientVertical)) outside = null; + parent.antialias(shape, CTabFolder.borderColor.getRGB(), inside, outside, gc); + gc.setForeground(CTabFolder.borderColor); + gc.drawPolyline(shape); +} +void drawUnselected(GC gc) { + int rightTabEdge = parent.getRightItemEdge(); + if (x >= parent.getSize().x) return; + // Do not draw partial items + if (parent.items[parent.topTabIndex] != this && x + width >= rightTabEdge){ + int x1 = x, y1 = y-1; + int x2 = parent.getSize().x, y2 = y + height; + int[] shape = new int[]{x1,y1, x1,y2, x2,y2, x2,y1}; + parent.drawBackground(gc, shape, false); + return; + } + // draw background + int[] shape = null; + if (parent.indexOf(this) == parent.topTabIndex) { + if (this.parent.onBottom) { + int[] left = CTabFolder.BOTTOM_LEFT_CORNER; + shape = new int[left.length + 6]; + int index = 0; + shape[index++] = x; + shape[index++] = y; + for(int i = 0; i < left.length/2; i++) { + shape[index++] = x + left[2*i]; + shape[index++] = y + height + left[2*i+1]; + } + shape[index++]= x + width; + shape[index++]= y + height; + shape[index++]= x + width; + shape[index++]= y; + } else { + int[] left = CTabFolder.TOP_LEFT_CORNER; + shape = new int[left.length + 6]; + int index = 0; + shape[index++] = x; + shape[index++] = y + height; + for(int i = 0; i < left.length/2; i++) { + shape[index++] = x + left[2*i]; + shape[index++] = y + left[2*i+1]; + } + shape[index++] = x + width; + shape[index++] = y; + shape[index++] = x + width; + shape[index++] = y + height; + } + parent.drawBackground(gc, shape, false); + // Shape is non-rectangular, fill in gaps with parent colours + Region r = new Region(); + r.add(new Rectangle(x, y, width, height)); + r.subtract(shape); + gc.setBackground(parent.getParent().getBackground()); + CTabFolder.fillRegion(gc, r); + r.dispose(); + } else { + shape = new int[8]; + shape[0] = x; + shape[1] = y; + shape[2] = x; + shape[3] = y + height; + shape[4] = x + width; + shape[5] = y + height; + shape[6] = x + width; + shape[7] = y; + parent.drawBackground(gc, shape, false); + } + + // draw border + if (parent.indexOf(this) != parent.selectedIndex - 1) { + gc.setForeground(CTabFolder.borderColor); + gc.drawLine(x + width - 1, y, x + width - 1, y + height); + } + + // draw Text + int textWidth = width - LEFT_MARGIN - RIGHT_MARGIN; + if (closeRect.width > 0) textWidth -= closeRect.width + INTERNAL_SPACING; + if (shortenedText == null || shortenedTextWidth != textWidth) { + shortenedText = shortenText(gc, getText(), textWidth); + shortenedTextWidth = textWidth; + } + Point extent = gc.textExtent(shortenedText, FLAGS); + int textY = y + (height - extent.y) / 2; + textY += parent.onBottom ? -1 : 1; + gc.setForeground(parent.getForeground()); + gc.drawText(shortenedText, x + LEFT_MARGIN, textY, FLAGS); + + if (parent.showClose || showClose) drawClose(gc); +} /** * Returns a rectangle describing the receiver's size and location * relative to its parent. * - * @param index the index that specifies the column * @return the receiver's bounding column rectangle * * @exception SWTException <ul> @@ -133,10 +479,10 @@ public Rectangle getBounds () { * * @return the control * -* @exception SWTError(ERROR_THREAD_INVALID_ACCESS) -* when called from the wrong thread -* @exception SWTError(ERROR_WIDGET_DISPOSED) -* when the widget has been disposed +* @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 Control getControl () { checkWidget(); @@ -146,6 +492,11 @@ public Control getControl () { * Get the image displayed in the tab if the tab is disabled. * * @return the disabled image or null + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> */ public Image getDisabledImage(){ //checkWidget(); @@ -155,6 +506,11 @@ public Image getDisabledImage(){ * Returns the receiver's parent, which must be a <code>CTabFolder</code>. * * @return the receiver's parent + * + * @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 CTabFolder getParent () { //checkWidget(); @@ -173,249 +529,42 @@ public CTabFolder getParent () { */ public String getToolTipText () { checkWidget(); + if (toolTipText == null && shortenedText != null) { + String text = getText(); + if (!shortenedText.equals(text)) return text; + } return toolTipText; } -/** - * Paint the receiver. - */ void onPaint(GC gc, boolean isSelected) { - if (width == 0 || height == 0) return; - - Display display = getDisplay(); - Color highlightShadow = display.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW); - Color normalShadow = display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); - - int index = parent.indexOf(this); - if (isSelected) { - - Rectangle bounds = null; - if (!parent.onBottom) { - if (index == parent.topTabIndex) { - bounds = new Rectangle(x + 1, y + 1, width - 2, height - 1); - } else { - bounds = new Rectangle(x + 2, y + 1, width - 3, height - 1); - } - } else { - if (index == parent.topTabIndex) { - bounds = new Rectangle(x + 1, y + 1, width - 2, height - 2); - } else { - bounds = new Rectangle(x + 2, y + 1, width - 3, height - 2); - } - } - if (parent.backgroundImage != null) { - // draw a background image behind the text - Rectangle imageRect = parent.backgroundImage.getBounds(); - gc.drawImage(parent.backgroundImage, 0, 0, imageRect.width, imageRect.height, - bounds.x, bounds.y, bounds.width, bounds.height); - } else if (parent.gradientColors != null) { - // draw a gradient behind the text - Color oldBackground = gc.getBackground(); - if (parent.gradientColors.length == 1) { - if (parent.gradientColors[0] != null) gc.setBackground(parent.gradientColors[0]); - gc.fillRectangle(bounds.x, bounds.y, bounds.width, bounds.height); - } else { - Color oldForeground = gc.getForeground(); - Color lastColor = parent.gradientColors[0]; - if (lastColor == null) lastColor = oldBackground; - for (int i = 0, pos = 0; i < parent.gradientPercents.length; ++i) { - gc.setForeground(lastColor); - lastColor = parent.gradientColors[i + 1]; - if (lastColor == null) lastColor = oldBackground; - gc.setBackground(lastColor); - int gradientWidth = (parent.gradientPercents[i] * bounds.width / 100) - pos; - gc.fillGradientRectangle(bounds.x + pos, bounds.y, gradientWidth, bounds.height, false); - pos += gradientWidth; - } - gc.setForeground(oldForeground); - } - gc.setBackground(oldBackground); - } - - // draw tab lines - if (!parent.onBottom) { - gc.setForeground(normalShadow); - if (index != parent.topTabIndex) { - gc.drawLine(x + 1, y, x + 1, y); - gc.drawLine(x, y + 1, x, y + height - 2); - gc.drawLine(x, y + height - 1, x, y + height - 1); - } - gc.drawLine(x + width - 1, y, x + width - 1, y); - gc.drawLine(x + width, y + 1, x + width, y + height - 2); - gc.drawLine(x + width, y + height - 1, x + width, y + height - 1); - - gc.setForeground(highlightShadow); - if (index != parent.topTabIndex) { - gc.drawLine(x + 2, y, x + 2, y); - gc.drawLine(x + 1, y + 1, x + 1, y + height - 2); - gc.drawLine(x + 1, y + height - 1, x + 1, y + height - 1); - } else { - gc.drawLine(x, y, x, y + height - 1); - } - - gc.drawLine(x + width - 2, y, x + width - 2, y); - gc.drawLine(x + width - 1, y + 1, x + width - 1, y + height - 2); - gc.drawLine(x + width - 1, y + height - 1, x + width - 1, y + height - 1); - - // light line across top - if (index != parent.topTabIndex) { - gc.drawLine(x + 3, y, x + width - 3, y); - } else { - gc.drawLine(x + 1, y, x + width - 3, y); - } - } else { - gc.setForeground(normalShadow); - if (index != parent.topTabIndex) { - gc.drawLine(x, y, x, y); - gc.drawLine(x, y + 1, x, y + height - 2); - gc.drawLine(x + 1, y + height - 1, x + 1, y + height - 1); - } - gc.drawLine(x + width, y, x + width, y); - gc.drawLine(x + width, y + 1, x + width, y + height - 2); - gc.drawLine(x + width - 1, y + height - 1, x + width - 1, y + height - 1); - - gc.setForeground(highlightShadow); - if (index != parent.topTabIndex) { - gc.drawLine(x + 1, y, x + 1, y); - gc.drawLine(x + 1, y + 1, x + 1, y + height - 2); - gc.drawLine(x + 2, y + height - 1, x + 2, y + height - 1); - } else { - gc.drawLine(x, y, x, y + height - 1); - } - - gc.drawLine(x + width - 1, y, x + width - 1, y); - gc.drawLine(x + width - 1, y + 1, x + width - 1, y + height - 2); - gc.drawLine(x + width - 2, y + height - 1, x + width - 2, y + height - 1); - - // light line across top and bottom - if (index != parent.topTabIndex) { - gc.drawLine(x + 1, y, x + width - 2, y); - gc.drawLine(x + 2, y + height - 1, x + width - 3, y + height - 1); - } else { - gc.drawLine(x + 1, y, x + width - 2, y); - gc.drawLine(x + 1, y + height - 1, x + width - 3, y + height - 1); - } - } - if (parent.isFocusControl()) { - // draw a focus rectangle - int x1, y1, width1, height1; - if (!parent.onBottom) { - if (index == parent.topTabIndex) { - x1 = x + 1; y1 = y + 1; width1 = width - 2; height1 = height - 1; - } else { - x1 = x + 2; y1 = y + 1; width1 = width - 3; height1 = height - 1; - } - } else { - if (index == parent.topTabIndex) { - x1 = x + 1; y1 = y + 1; width1 = width - 2; height1 = height - 2; - } else { - x1 = x + 2; y1 = y + 1; width1 = width - 3; height1 = height - 2; - } - } - gc.setBackground(display.getSystemColor(SWT.COLOR_BLACK)); - gc.setForeground(display.getSystemColor(SWT.COLOR_WHITE)); - gc.drawFocus(x1, y1, width1, height1); - } + drawSelected(gc); } else { - // draw tab lines for unselected items - gc.setForeground(normalShadow); - if (!parent.onBottom) { - if (index != parent.topTabIndex && index != parent.getSelectionIndex() + 1) { - gc.drawLine(x, y, x, y + (height / 2)); - } - } else { - if (index != parent.topTabIndex && index != parent.getSelectionIndex() + 1) { - gc.drawLine(x, y + (height / 2), x, y + height - 1); - } - } - + drawUnselected(gc); } - - // draw Image - int xDraw = x + LEFT_MARGIN; - - Image image = getImage(); - if (!isSelected && image != null) { - Image temp = getDisabledImage(); - if (temp != null){ - image = temp; - } - } - if (image != null) { - Rectangle imageBounds = image.getBounds(); - int imageX = xDraw; - int imageHeight = Math.min(height - BOTTOM_MARGIN - TOP_MARGIN, imageBounds.height); - int imageY = y + (height - imageHeight) / 2; - int imageWidth = imageBounds.width * imageHeight / imageBounds.height; - gc.drawImage(image, - imageBounds.x, imageBounds.y, imageBounds.width, imageBounds.height, - imageX, imageY, imageWidth, imageHeight); - xDraw += imageWidth + INTERNAL_SPACING; - } - - // draw Text - int textWidth = x + width - xDraw - RIGHT_MARGIN; - if (isSelected && parent.showClose) { - textWidth = x + width - xDraw - parent.closeBar.getSize().x - RIGHT_MARGIN; - } - if (shortenedText == null || shortenedTextWidth != textWidth) { - shortenedText = shortenText(gc, getText(), textWidth); - shortenedTextWidth = textWidth; - } - String text = shortenedText; - - if (isSelected && parent.selectionForeground != null) { - gc.setForeground(parent.selectionForeground); - } else { - gc.setForeground(parent.getForeground()); - } - int textY = y + (height - gc.textExtent(text, SWT.DRAW_MNEMONIC).y) / 2; - gc.drawText(text, xDraw, textY, SWT.DRAW_TRANSPARENT | SWT.DRAW_MNEMONIC); - - gc.setForeground(parent.getForeground()); } -private static String shortenText(GC gc, String text, int width) { - if (gc.textExtent(text, SWT.DRAW_MNEMONIC).x <= width) return text; - - int ellipseWidth = gc.textExtent(ellipsis, SWT.DRAW_MNEMONIC).x; - int length = text.length(); - int end = length - 1; - while (end > 0) { - text = text.substring(0, end); - int l1 = gc.textExtent(text, SWT.DRAW_MNEMONIC).x; - if (l1 + ellipseWidth <= width) { - return text + ellipsis; - } - end--; - } - return text + ellipsis; -} -/** - * Answer the preferred height of the receiver for the GC. - */ int preferredHeight(GC gc) { Image image = getImage(); - int height = 0; - if (image != null) height = image.getBounds().height; + int h = (image == null) ? 0 : image.getBounds().height; String text = getText(); - height = Math.max(height, gc.textExtent(text, SWT.DRAW_MNEMONIC).y); - return height + TOP_MARGIN + BOTTOM_MARGIN; + h = Math.max(h, gc.textExtent(text, FLAGS).y); + return h + TOP_MARGIN + BOTTOM_MARGIN; } -/** - * Answer the preferred width of the receiver for the GC. - */ -int preferredWidth(GC gc) { - int width = 0; +int preferredWidth(GC gc, boolean isSelected) { + int w = 0; Image image = getImage(); - if (image != null) width += image.getBounds().width; + if (isSelected && image != null) w += image.getBounds().width; String text = getText(); if (text != null) { - if (image != null) width += INTERNAL_SPACING; - width += gc.textExtent(text, SWT.DRAW_MNEMONIC).x; + if (w > 0) w += INTERNAL_SPACING; + w += gc.textExtent(text, FLAGS).x; + } + if (parent.showClose || showClose) { + if (w > 0) w += INTERNAL_SPACING; + w += CTabFolder.BUTTON_SIZE; } - if (parent.showClose) width += INTERNAL_SPACING + preferredHeight(gc); // closebar will be square and will fill preferred height - return width + LEFT_MARGIN + RIGHT_MARGIN; + if (isSelected) w += 8; // why 8? + return w + LEFT_MARGIN + RIGHT_MARGIN; } /** * Sets the control that is used to fill the client area of @@ -451,12 +600,6 @@ public void setControl (Control control) { this.control.setVisible(false); } } -} -public void setImage (Image image) { - checkWidget(); - if (image != null && image.equals(getImage())) return; - super.setImage(image); - parent.resetTabSize(true); } /** * Sets the image that is displayed if the tab item is disabled. @@ -471,19 +614,25 @@ public void setImage (Image image) { */ public void setDisabledImage (Image image) { checkWidget(); + // !!! this image is never being used if (image != null && image.equals(getDisabledImage())) return; disabledImage = image; + //parent.redraw(); +} +public void setImage (Image image) { + checkWidget(); + if (image != null && image.equals(getImage())) return; + super.setImage(image); + if (!parent.updateTabHeight(parent.tabHeight, false)) { + parent.updateItems(); + } parent.redraw(); } - /** * Set the widget text. * <p> * This method sets the widget label. The label may include * mnemonic characters but must not contain line delimiters. - * The mnemonic indicator character '&' can be escaped by - * doubling it in the string, causing a single '&' to be - * displayed. * * @param string the new label for the widget * @@ -501,7 +650,8 @@ public void setText (String string) { super.setText(string); shortenedText = null; shortenedTextWidth = 0; - parent.resetTabSize(false); + parent.updateItems(); + parent.redraw(); } /** * Sets the receiver's tool tip text to the argument, which |