package org.xmind.ui.tabfolder; import java.util.ArrayList; import java.util.List; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.graphics.Transform; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Layout; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Widget; import org.xmind.ui.util.IStyleProvider; import org.xmind.ui.util.StyleProvider; /** * * <dl> * <dt>Styles</dt> * <dd>(none)</dd> * <dt>Style Keys:</dt> * <dd>MARGIN, BORDER, PADDING, SEPARATOR, CORNER</dd> * </dl> * * @author Frank Shaka * @since 3.6.0 */ public class MTabBar extends Composite { public static final String MARGIN = IStyleProvider.MARGIN; public static final String BORDER = IStyleProvider.BORDER; public static final String PADDING = IStyleProvider.PADDING; public static final String SEPARATOR = IStyleProvider.SEPARATOR; public static final String CORNER = IStyleProvider.CORNER; private class MTabBarLayout extends Layout { @Override protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) { return computeTabBarSize(wHint, hHint); } @Override protected void layout(Composite composite, boolean flushCache) { layoutTabBar(); } } private List<MTabBarItem> items; private int selectedIndex = -1; private boolean vertical = false; private IStyleProvider styleProvider = new StyleProvider(); private boolean usingDefaultStyles = true; private MTabBarItem trackedItem = null; // Layout caches, validated by layout, used by paint private int marginWidth = 0; private int marginHeight = 0; private int borderWidth = 0; private int paddingWidth = 0; private int paddingHeight = 0; private int hSpacing = 0; private int vSpacing = 0; private int cornerWidth = 0; private int cornerHeight = 0; private Rectangle[] separators = null; private Listener listener; private boolean inDispose; public MTabBar(Composite parent, int style) { super(parent, style | SWT.DOUBLE_BUFFERED); this.items = new ArrayList<MTabBarItem>(); super.setLayout(new MTabBarLayout()); listener = new Listener() { public void handleEvent(Event event) { switch (event.type) { case SWT.Dispose: onDispose(event); break; case SWT.Resize: onResize(event); break; case SWT.Paint: onPaint(event); break; case SWT.MouseEnter: onMouseEnter(event); break; case SWT.MouseExit: onMouseExit(event); break; case SWT.MouseMove: onMouseMove(event); break; case SWT.MouseDown: onMouseDown(event); break; case SWT.MouseUp: onMouseUp(event); break; } } }; addListener(SWT.Dispose, listener); addListener(SWT.Resize, listener); addListener(SWT.Paint, listener); addListener(SWT.MouseEnter, listener); addListener(SWT.MouseExit, listener); addListener(SWT.MouseMove, listener); addListener(SWT.MouseDown, listener); addListener(SWT.MouseUp, listener); } @Override public void setLayout(Layout layout) { checkWidget(); // prevents layout from being changed by clients } public MTabBarItem[] getItems() { checkWidget(); return items.toArray(new MTabBarItem[items.size()]); } public int getItemCount() { checkWidget(); return items.size(); } public MTabBarItem getSelection() { checkWidget(); return selectedIndex < 0 ? null : items.get(selectedIndex); } public int getSelectionIndex() { checkWidget(); return selectedIndex; } public int indexOf(MTabBarItem item) { checkWidget(); if (item == null) return -1; return items.indexOf(item); } public MTabBarItem getItem(int index) { checkWidget(); return index < 0 || index >= items.size() ? null : items.get(index); } public MTabBarItem getItem(Point pt) { checkWidget(); return getItem(pt.x, pt.y); } private MTabBarItem getItem(int x, int y) { for (MTabBarItem item : items) { if (item.getVisible() && item.getBounds().contains(x, y)) return item; } return null; } public void setSelection(MTabBarItem item) { checkWidget(); if (item != null && !item.isRadioButton()) return; MTabBarItem oldItem = getSelection(); selectedIndex = indexOf(item); if (oldItem != null) { oldItem.setSelected(false); } if (item != null) { item.setSelected(true); } } public boolean isVertical() { checkWidget(); return vertical; } public void setVertical(boolean vertical) { checkWidget(); if (vertical == this.vertical) return; this.vertical = vertical; updateTabBar(); } public IStyleProvider getStyleProvider() { checkWidget(); return styleProvider; } public void setStyleProvider(IStyleProvider styleProvider) { checkWidget(); IStyleProvider oldStyleProvider = usingDefaultStyles ? null : this.styleProvider; if (styleProvider == oldStyleProvider) return; if (styleProvider != null) { this.styleProvider = styleProvider; usingDefaultStyles = false; } else { this.styleProvider = new StyleProvider(); usingDefaultStyles = true; } reskin(SWT.NONE); pack(false); updateTabBar(); } protected void createItem(MTabBarItem item, int index) { items.add(index, item); if (item.isRadioButton()) { boolean isPrimary = true; for (MTabBarItem it : items) { if (it != item && it.isRadioButton()) { isPrimary = false; break; } } if (isPrimary) { selectedIndex = items.indexOf(item); item.setSelected(true); } } layout(true); redraw(); } protected void destroyItem(MTabBarItem item) { if (inDispose) return; int index = indexOf(item); if (index < 0) { return; } if (index == selectedIndex) { int nextIndex = -1; MTabBarItem next = null; for (int j = index + 1; j < items.size(); j++) { next = items.get(j); if (next.isRadioButton()) { nextIndex = j; break; } } if (nextIndex < 0) { for (int j = index - 1; j >= 0; j--) { next = items.get(j); if (next.isRadioButton()) { nextIndex = j; break; } } } if (nextIndex >= 0) { next.setSelected(true); } selectedIndex = nextIndex; } items.remove(index); layout(true); redraw(); } protected void updateItem(MTabBarItem item) { layout(true); redraw(); } protected Point computeTabBarSize(int wHint, int hHint) { Point size; if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT) { size = new Point(wHint, hHint); } else { boolean tabBarVertical = isVertical(); IStyleProvider styles = getStyleProvider(); int marginWidth = styles.getWidth(this, MARGIN, 0); int marginHeight = styles.getHeight(this, MARGIN, 0); int borderWidth = Math.max(styles.getWidth(this, BORDER, 0), styles.getHeight(this, BORDER, 0)); int paddingWidth = styles.getWidth(this, PADDING, 0); int paddingHeight = styles.getHeight(this, PADDING, 0); int trimWidth = marginWidth + borderWidth + paddingWidth + marginWidth + borderWidth + paddingWidth; int trimHeight = marginHeight + borderWidth + paddingHeight + marginHeight + borderWidth + paddingHeight; if (wHint != SWT.DEFAULT) wHint = Math.max(0, wHint - trimWidth); if (hHint != SWT.DEFAULT) hHint = Math.max(0, hHint - trimHeight); int hSpacing = styles.getWidth(this, SEPARATOR, 0); int vSpacing = styles.getHeight(this, SEPARATOR, 0); int itemCount = getItemCount(); int width = 0, height = 0; MTabBarItem item; Point itemSize; for (int i = 0; i < itemCount; i++) { item = getItem(i); if (!item.getVisible()) continue; itemSize = computeItemSize(item, styles, tabBarVertical, tabBarVertical ? wHint : SWT.DEFAULT, tabBarVertical ? SWT.DEFAULT : hHint, false); if (tabBarVertical) { if (i > 0) height += vSpacing; width = Math.max(width, itemSize.x); height += itemSize.y; } else { if (i > 0) width += hSpacing; width += itemSize.x; height = Math.max(height, itemSize.y); } } size = new Point(width + trimWidth, height + trimHeight); } Rectangle trimmed = computeTrim(0, 0, size.x, size.y); return new Point(trimmed.width, trimmed.height); } private Point computeItemSize(MTabBarItem item, IStyleProvider styles, boolean tabBarVertical, int wHint, int hHint, boolean cache) { boolean separator = item.isSeparator(); Image image = item.getImage(); String text = item.getText(); boolean imageVisible = !separator && image != null && styles.getVisibility(item, MTabBarItem.IMAGE, true); boolean textVisible = !separator && text != null && !"".equals(text) //$NON-NLS-1$ && styles.getVisibility(item, MTabBarItem.TEXT, true); int textPosition = styles.getPosition(item, MTabBarItem.TEXT, SWT.BOTTOM); boolean itemVertical = (textPosition & (SWT.TOP | SWT.BOTTOM)) != 0; int marginWidth = styles.getWidth(item, MTabBarItem.MARGIN, 0); int marginHeight = styles.getHeight(item, MTabBarItem.MARGIN, 0); int hSpacing = styles.getWidth(item, MTabBarItem.SEPARATOR, 0); int vSpacing = styles.getHeight(item, MTabBarItem.SEPARATOR, 0); Font font = styles.getFont(item, MTabBarItem.TEXT); if (font == null) font = getFont(); if (cache) { item.marginWidth = marginWidth; item.marginHeight = marginHeight; item.hSpacing = hSpacing; item.vSpacing = vSpacing; item.textPosition = textPosition; item.imageVisible = imageVisible; item.textVisible = textVisible; item.font = font; } if (separator) { int separatorWidth = item.getWidth(); if (separatorWidth == SWT.SEPARATOR_FILL) return new Point(0, 0); return tabBarVertical ? new Point(1, separatorWidth) : new Point(separatorWidth, 1); } wHint = styles.getWidth(item, null, itemVertical ? wHint : SWT.DEFAULT); hHint = styles.getHeight(item, null, itemVertical ? SWT.DEFAULT : hHint); if (wHint >= 0) wHint = Math.max(0, wHint - marginWidth - marginWidth); if (hHint >= 0) hHint = Math.max(0, hHint - marginHeight - marginHeight); int imageWHint = styles.getWidth(item, MTabBarItem.IMAGE, itemVertical ? wHint : SWT.DEFAULT); int imageHHint = styles.getHeight(item, MTabBarItem.IMAGE, itemVertical ? SWT.DEFAULT : hHint); int textWHint = styles.getWidth(item, MTabBarItem.TEXT, itemVertical ? wHint : SWT.DEFAULT); int textHHint = styles.getHeight(item, MTabBarItem.TEXT, itemVertical ? SWT.DEFAULT : hHint); Point imageSize = imageVisible ? computeImageSize(item.getImage()) : new Point(0, 0); Point textSize = textVisible ? computeTextSize(item.getText(), font) : new Point(0, 0); Point imageAreaSize = imageVisible ? computePreferredSize(imageSize.x, imageSize.y, imageWHint, imageHHint) : new Point(0, 0); Point textAreaSize = textVisible ? computePreferredSize(textSize.x, textSize.y, textWHint, textHHint) : new Point(0, 0); int itemWidth, itemHeight; if (itemVertical) { itemWidth = wHint < 0 ? Math.max(imageAreaSize.x, textAreaSize.x) : wHint; if (hHint < 0) { if (imageVisible && textVisible) { itemHeight = imageAreaSize.y + vSpacing + textAreaSize.y; } else if (imageVisible) { itemHeight = imageAreaSize.y; } else if (textVisible) { itemHeight = textAreaSize.y; } else { itemHeight = 0; } } else { itemHeight = hHint; } } else { if (wHint < 0) { if (imageVisible && textVisible) { itemWidth = imageAreaSize.x + hSpacing + textAreaSize.x; } else if (imageVisible) { itemWidth = imageAreaSize.x; } else if (textVisible) { itemWidth = textAreaSize.x; } else { itemWidth = 0; } } else { itemWidth = wHint; } itemHeight = hHint < 0 ? Math.max(imageAreaSize.y, textAreaSize.y) : hHint; } return new Point(itemWidth + marginWidth + marginWidth, itemHeight + marginHeight + marginHeight); } private Point computeImageSize(Image image) { if (image == null) return new Point(0, 0); Rectangle b = image.getBounds(); return new Point(b.width, b.height); } private Point computeTextSize(String text, Font font) { if (text == null || "".equals(text)) //$NON-NLS-1$ return new Point(0, 0); Point textSize; GC gc = new GC(this); try { gc.setFont(font); textSize = gc.textExtent(text); } finally { gc.dispose(); } return textSize; } private static Point computePreferredSize(int srcWidth, int srcHeight, int wHint, int hHint) { if (wHint == 0 || hHint == 0) return new Point(0, 0); if (wHint > 0 && hHint > 0) return new Point(wHint, hHint); if (srcWidth == 0 || srcHeight == 0) return new Point(0, 0); if (wHint < 0 && hHint < 0) return new Point(srcWidth, srcHeight); if (wHint < 0) { if (srcHeight <= hHint) return new Point(srcWidth, hHint); int width = srcWidth * hHint / srcHeight; if (width <= 0) return new Point(0, 0); return new Point(width, hHint); } // if (hHint < 0) if (srcWidth <= wHint) return new Point(wHint, srcHeight); int height = srcHeight * wHint / srcWidth; if (height <= 0) return new Point(0, 0); return new Point(wHint, height); } private static Point computeConstrainedSize(int srcWidth, int srcHeight, int wHint, int hHint) { float scaleX = (wHint < 0 || srcWidth <= wHint) ? 1 : ((float) wHint) / srcWidth; float scaleY = (hHint < 0 || srcHeight <= hHint) ? 1 : ((float) hHint) / srcHeight; float scale = Math.min(scaleX, scaleY); int destWidth = (int) Math.ceil(srcWidth * scale); int destHeight = (int) Math.ceil(srcHeight * scale); return new Point(destWidth, destHeight); } protected void layoutTabBar() { IStyleProvider styles = getStyleProvider(); marginWidth = styles.getWidth(this, MARGIN, 0); marginHeight = styles.getHeight(this, MARGIN, 0); borderWidth = Math.max(styles.getWidth(this, BORDER, 0), styles.getHeight(this, BORDER, 0)); paddingWidth = styles.getWidth(this, PADDING, 0); paddingHeight = styles.getHeight(this, PADDING, 0); hSpacing = styles.getWidth(this, SEPARATOR, 0); vSpacing = styles.getHeight(this, SEPARATOR, 0); cornerWidth = styles.getWidth(this, CORNER, 0); cornerHeight = styles.getHeight(this, CORNER, 0); layoutItems(styles); layoutChildren(styles); } protected void layoutChildren(IStyleProvider styles) { // to be implemented by subclasses } protected void layoutItems(IStyleProvider styles) { int itemCount = getItemCount(); if (itemCount == 0) { separators = null; return; } Rectangle area = getClientArea(); boolean tabBarVertical = isVertical(); int contentWidth = Math.max(0, area.width - marginWidth - marginWidth - borderWidth - borderWidth - paddingWidth - paddingWidth); int contentHeight = Math.max(0, area.height - marginHeight - marginHeight - borderWidth - borderWidth - paddingHeight - paddingHeight); int contentX = area.x + marginWidth + borderWidth + paddingWidth; int contentY = area.y + marginHeight + borderWidth + paddingHeight; Point contentSize; int itemX, itemY, itemWidth, itemHeight; boolean itemBoundsChanged = false; MTabBarItem item; Point[] contentSizes = new Point[itemCount]; int expansion = 0; int expandingItemCount = 0; for (int i = 0; i < itemCount; i++) { item = getItem(i); if (!item.getVisible()) continue; contentSize = computeItemSize(item, styles, tabBarVertical, contentWidth, contentHeight, true); contentSizes[i] = contentSize; if (expansion > 0) { expansion += tabBarVertical ? vSpacing : hSpacing; } expansion += tabBarVertical ? contentSize.y : contentSize.x; if (item.isSeparator() && item.getWidth() == SWT.SEPARATOR_FILL) { expandingItemCount++; } } if (expansion > 0) { expansion = Math.max(0, tabBarVertical ? (contentHeight - expansion) : (contentWidth - expansion)); } int itemExpansion; separators = new Rectangle[itemCount - 1]; for (int i = 0; i < itemCount; i++) { item = getItem(i); if (!item.getVisible()) continue; contentSize = contentSizes[i]; if (i > 0) { if (tabBarVertical) contentY += vSpacing; else contentX += hSpacing; } if (expansion > 0 && item.isSeparator() && item.getWidth() == SWT.SEPARATOR_FILL) { itemExpansion = expansion / expandingItemCount; expansion -= itemExpansion; expandingItemCount--; if (tabBarVertical) contentSize.y += itemExpansion; else contentSize.x += itemExpansion; } itemX = contentX; itemY = contentY; itemWidth = contentSize.x; itemHeight = contentSize.y; item.contentBounds.x = contentX; item.contentBounds.y = contentY; item.contentBounds.width = contentSize.x; item.contentBounds.height = contentSize.y; if (!item.isSeparator()) layoutItem(item, styles); if (tabBarVertical) { contentY += contentSize.y; itemX -= borderWidth + paddingWidth; itemWidth += borderWidth + borderWidth + paddingWidth + paddingWidth; if (i == 0) { itemY -= borderWidth + paddingHeight; itemHeight += borderWidth + paddingHeight; } if (i == itemCount - 1) { itemHeight += borderWidth + paddingHeight; } } else { contentX += contentSize.x; itemY -= borderWidth + paddingHeight; itemHeight += borderWidth + borderWidth + paddingHeight + paddingHeight; if (i == 0) { itemX -= borderWidth + paddingWidth; itemWidth += borderWidth + paddingWidth; } if (i == itemCount - 1) { itemWidth += borderWidth + paddingWidth; } } itemBoundsChanged |= item.setBounds(itemX, itemY, itemWidth, itemHeight); if (i < itemCount - 1) { if (tabBarVertical) { separators[i] = new Rectangle( contentX - borderWidth - paddingWidth, contentY, contentWidth + borderWidth + borderWidth + paddingWidth + paddingWidth, vSpacing); } else { separators[i] = new Rectangle(contentX, contentY - borderWidth - paddingWidth, hSpacing, contentHeight + borderWidth + borderWidth + paddingHeight + paddingHeight); } } } if (itemBoundsChanged) { redraw(); } } /** * Validates bounds of item image and text. * * @param item * @param styles */ private void layoutItem(MTabBarItem item, IStyleProvider styles) { int contentX = item.contentBounds.x + item.marginWidth; int contentY = item.contentBounds.y + item.marginHeight; int contentWidth = item.contentBounds.width - item.marginWidth - item.marginWidth; int contentHeight = item.contentBounds.height - item.marginHeight - item.marginHeight; if (item.imageVisible && item.textVisible) { boolean itemVertical = (item.textPosition & (SWT.TOP | SWT.BOTTOM)) != 0; boolean imageLeading = (item.textPosition & (SWT.RIGHT | SWT.BOTTOM)) != 0; Point imageSize = item.imageVisible ? computeImageSize(item.getImage()) : new Point(0, 0); Point textSize = item.textVisible ? computeTextSize(item.getText(), item.font) : new Point(0, 0); int imageWHint = styles.getWidth(item, MTabBarItem.IMAGE, itemVertical ? contentWidth : SWT.DEFAULT); int imageHHint = styles.getHeight(item, MTabBarItem.IMAGE, itemVertical ? SWT.DEFAULT : contentHeight); int textWHint = styles.getWidth(item, MTabBarItem.TEXT, itemVertical ? contentWidth : SWT.DEFAULT); int textHHint = styles.getHeight(item, MTabBarItem.TEXT, itemVertical ? SWT.DEFAULT : contentHeight); Point imageAreaSize = item.imageVisible ? computePreferredSize(imageSize.x, imageSize.y, imageWHint, imageHHint) : new Point(0, 0); Point textAreaSize = item.textVisible ? computePreferredSize(textSize.x, textSize.y, textWHint, textHHint) : new Point(0, 0); if (itemVertical) { if (imageHHint > 0 && textHHint < 0) { textAreaSize.y = Math.max(0, contentHeight - imageAreaSize.y - item.vSpacing); } else if (imageHHint < 0 && textHHint > 0) { imageAreaSize.y = Math.max(0, contentHeight - textAreaSize.y - item.vSpacing); } } else { if (imageWHint > 0 && textWHint < 0) { textAreaSize.x = Math.max(0, contentWidth - imageAreaSize.x - item.hSpacing); } else if (imageWHint < 0 && textWHint > 0) { imageAreaSize.x = Math.max(0, contentWidth - textAreaSize.x - item.hSpacing); } } imageSize = computeConstrainedSize(imageSize.x, imageSize.y, imageAreaSize.x, imageAreaSize.y); textSize = computeConstrainedSize(textSize.x, textSize.y, textAreaSize.x, textAreaSize.y); if (itemVertical) { item.imageBounds.x = contentX + (contentWidth - imageSize.x) / 2; item.imageBounds.y = contentY + (imageAreaSize.y - imageSize.y) / 2; item.textBounds.x = contentX + (contentWidth - textSize.x) / 2; item.textBounds.y = contentY + (textAreaSize.y - textSize.y) / 2; if (imageLeading) { item.textBounds.y += imageAreaSize.y + item.vSpacing; } else { item.imageBounds.y += textAreaSize.y + item.vSpacing; } } else { // item.imageBounds.x = contentX // + (imageAreaSize.x - imageSize.x) / 2; // item.imageBounds.y = contentY // + (contentHeight - imageSize.y) / 2; // item.textBounds.x = contentX // + (textAreaSize.x - textSize.x) / 2; // item.textBounds.y = contentY // + (textAreaSize.y - textSize.y) / 2; // if (imageLeading) { // item.textBounds.x += imageAreaSize.x + item.hSpacing; // } else { // item.imageBounds.x += textAreaSize.x + item.hSpacing; // } if (imageLeading) { item.imageBounds.x = contentX; item.imageBounds.y = contentY + (contentHeight - imageSize.y) / 2; item.imageBounds.width = imageAreaSize.x; item.imageBounds.height = imageSize.y; item.textBounds.x = contentX + item.imageBounds.width + item.hSpacing; item.textBounds.y = item.imageBounds.y; item.textBounds.width = item.contentBounds.width - item.imageBounds.width - item.hSpacing; item.textBounds.height = item.imageBounds.height; // System.out.println("imageBouns:" + item.imageBounds + "-->" // + "textBounds:" + item.textBounds // + " contentBounds:" + item.contentBounds); } else { item.textBounds.x = contentX; item.textBounds.y = contentY; item.textBounds.width = imageAreaSize.x; item.textBounds.height = item.contentBounds.height; item.imageBounds.x = contentX + item.textBounds.width + item.hSpacing; item.imageBounds.y = contentY; item.imageBounds.width = item.contentBounds.width - item.imageBounds.width - item.hSpacing; item.imageBounds.height = item.contentBounds.height; } return; } item.imageBounds.width = imageSize.x; item.imageBounds.height = imageSize.y; item.textBounds.width = textSize.x; item.textBounds.height = textSize.y; } else if (item.imageVisible) { Point imageSize = computeImageSize(item.getImage()); Point constrainedSize = computeConstrainedSize(imageSize.x, imageSize.y, contentWidth, contentHeight); item.imageBounds.x = contentX + (contentWidth - constrainedSize.x) / 2; item.imageBounds.y = contentY + (contentHeight - constrainedSize.y) / 2; item.imageBounds.width = constrainedSize.x; item.imageBounds.height = constrainedSize.y; item.textBounds.x = 0; item.textBounds.y = 0; item.textBounds.width = 0; item.textBounds.height = 0; } else if (item.textVisible) { Point textSize = computeTextSize(item.getText(), item.font); Point constrainedSize = computeConstrainedSize(textSize.x, textSize.y, contentWidth, contentHeight); item.imageBounds.x = 0; item.imageBounds.y = 0; item.imageBounds.width = 0; item.imageBounds.height = 0; item.textBounds.x = contentX + (contentWidth - constrainedSize.x) / 2; item.textBounds.y = contentY + (contentHeight - constrainedSize.y) / 2; item.textBounds.width = constrainedSize.x; item.textBounds.height = constrainedSize.y; } else { item.imageBounds.x = 0; item.imageBounds.y = 0; item.imageBounds.width = 0; item.imageBounds.height = 0; item.textBounds.x = 0; item.textBounds.y = 0; item.textBounds.width = 0; item.textBounds.height = 0; } } protected void updateTabBar() { layout(true); redraw(); } private void paintTabBar(GC gc) { int itemCount = getItemCount(); if (itemCount == 0) return; Rectangle borderArea = getClientArea(); borderArea.x += marginWidth; borderArea.y += marginHeight; borderArea.width -= marginWidth + marginWidth; borderArea.height -= marginHeight + marginHeight; Rectangle borderFillArea = new Rectangle(borderArea.x + borderWidth, borderArea.y + borderWidth, borderArea.width - borderWidth - borderWidth, borderArea.height - borderWidth - borderWidth); MTabBarItem item; for (int i = 0; i < itemCount; i++) { item = getItem(i); if (!item.getVisible()) continue; paintItemFill(gc, item, borderFillArea, i == 0, i == itemCount - 1); } paintBorderAndSeparators(gc, borderArea); for (int i = 0; i < itemCount; i++) { item = getItem(i); if (!item.getVisible()) continue; paintItem(gc, item); } } private void paintBorderAndSeparators(GC gc, Rectangle borderArea) { IStyleProvider styles = getStyleProvider(); Color borderColor = styles.getColor(this, BORDER); if (borderColor == null || borderColor.getAlpha() <= 0) return; int borderAlpha = styles.getAlpha(this, BORDER, 0xff); if (borderAlpha <= 0) return; Color oldForeground = gc.getForeground(); Color oldBackground = gc.getBackground(); int oldAlpha = gc.getAlpha(); int oldLineWidth = gc.getLineWidth(); int oldLineStyle = gc.getLineStyle(); int oldLineCap = gc.getLineCap(); gc.setForeground(borderColor); gc.setBackground(borderColor); gc.setAlpha(borderAlpha); gc.setLineWidth(borderWidth); gc.setLineStyle(SWT.LINE_SOLID); gc.setLineCap(SWT.CAP_SQUARE); if (cornerWidth > 0 && cornerHeight > 0) { gc.drawRoundRectangle(borderArea.x + borderWidth / 2, borderArea.y + borderWidth / 2, borderArea.width - borderWidth, borderArea.height - borderWidth, cornerWidth + cornerWidth, cornerHeight + cornerHeight); } else { gc.drawRectangle(borderArea.x + borderWidth / 2, borderArea.y + borderWidth / 2, borderArea.width - borderWidth, borderArea.height - borderWidth); } boolean tabBarVertical = isVertical(); if (separators != null && separators.length > 0) { for (int i = 0; i < separators.length; i++) { Rectangle sep = separators[i]; if (tabBarVertical) { gc.fillRectangle(sep.x + borderWidth, sep.y, sep.width - borderWidth - borderWidth, sep.height); } else { gc.fillRectangle(sep.x, sep.y + borderWidth, sep.width, sep.height - borderWidth - borderWidth); } } } gc.setLineCap(oldLineCap); gc.setLineStyle(oldLineStyle); gc.setLineWidth(oldLineWidth); gc.setAlpha(oldAlpha); gc.setBackground(oldBackground); gc.setForeground(oldForeground); } private void paintItem(GC gc, MTabBarItem item) { if (item.contentBounds.width <= 0 || item.contentBounds.height <= 0) // empty client area, paint nothing return; if (!item.imageVisible && !item.textVisible) // neither image nor text is available for painting return; Rectangle oldClipping = gc.getClipping(); gc.setClipping(item.bounds); gc.setAntialias(SWT.ON); gc.setTextAntialias(SWT.ON); if (item.imageVisible) { paintItemImage(gc, item); } if (item.textVisible) { paintItemText(gc, item); } gc.setClipping(oldClipping); } private void paintItemImage(GC gc, MTabBarItem item) { Image image = item.getImage(); if (image == null) return; Rectangle dest = item.imageBounds; if (dest.width <= 0 || dest.height <= 0) return; Rectangle src = image.getBounds(); gc.drawImage(image, src.x, src.y, src.width, src.height, dest.x, dest.y, dest.width, dest.height); } private void paintItemText(GC gc, MTabBarItem item) { String text = item.getText(); if (text == null || "".equals(text)) //$NON-NLS-1$ return; Rectangle dest = item.textBounds; if (dest.width <= 0 || dest.height <= 0) return; Color textColor = getStyleProvider().getColor(item, MTabBarItem.TEXT); if (textColor == null) textColor = getForeground(); Color oldForeground = gc.getForeground(); gc.setForeground(textColor); gc.setFont(item.font); Point textSize = gc.textExtent(text); IStyleProvider styles = getStyleProvider(); int textAlign = styles.getTextAlign(item, MTabBarItem.TEXT_ALIGN, SWT.CENTER); Transform t = new Transform(gc.getDevice()); float scaleX = Math.min(1, ((float) dest.width) / textSize.x); float scaleY = Math.min(1, ((float) dest.height) / textSize.y); float scale = Math.min(scaleX, scaleY); float offsetX = dest.x + ((float) dest.width) / 2; float offsetY = dest.y + ((float) dest.height) / 2; float offsetX2 = 0; float offsetY2 = -((float) textSize.y) / 2; switch (textAlign) { case SWT.LEFT: offsetX2 = -dest.width / 2 + item.hSpacing * 5; break; case SWT.CENTER: offsetX2 = -((float) textSize.x) / 2; break; case SWT.RIGHT: offsetX2 = -dest.width / 2 + (dest.width - textSize.x) / 2; break; } t.translate(offsetX, offsetY); t.scale(scale, scale); t.translate(offsetX2, offsetY2 / scale); Transform oldTransform = new Transform(gc.getDevice()); try { gc.getTransform(oldTransform); try { gc.setTransform(t); gc.drawText(text, 0, 0, true); } finally { t.dispose(); } gc.setTransform(oldTransform); } finally { oldTransform.dispose(); } gc.setForeground(oldForeground); } private void paintItemFill(GC gc, MTabBarItem item, Rectangle borderArea, boolean first, boolean last) { IStyleProvider styles = getStyleProvider(); Color fillColor = styles.getColor(item, MTabBarItem.FILL); if (fillColor == null || fillColor.getAlpha() <= 0) return; int alpha = styles.getAlpha(item, MTabBarItem.FILL, 0xFF); if (alpha <= 0) return; Rectangle oldClipping = gc.getClipping(); int oldAlpha = gc.getAlpha(); Color oldBackground = gc.getBackground(); gc.setAntialias(SWT.ON); gc.setTextAntialias(SWT.ON); gc.setClipping(item.bounds); gc.setAlpha(alpha); gc.setBackground(fillColor); if (cornerWidth > 0 && cornerHeight > 0) { gc.fillRoundRectangle(borderArea.x, borderArea.y, borderArea.width, borderArea.height, cornerWidth + cornerWidth - borderWidth, cornerWidth + cornerWidth - borderWidth); } else { gc.fillRectangle(borderArea); } gc.setBackground(oldBackground); gc.setAlpha(oldAlpha); gc.setClipping(oldClipping); } private void onDispose(Event event) { removeListener(SWT.Dispose, listener); notifyListeners(SWT.Dispose, event); event.type = SWT.None; inDispose = true; for (MTabBarItem item : items) { if (!item.isDisposed()) item.dispose(); } } private void onResize(Event event) { if (inDispose) return; layout(true); } private void onPaint(Event event) { if (inDispose) return; paintTabBar(event.gc); } private void onMouseEnter(Event event) { MTabBarItem item = getItem(event.x, event.y); if (item != null) { item.setPreselected(true); } } private void onMouseExit(Event event) { for (MTabBarItem item : items) { item.setPreselected(false); } } private void onMouseMove(Event event) { MTabBarItem newTarget = null; MTabBarItem oldTarget = null; for (MTabBarItem item : items) { if (item.getBounds().contains(event.x, event.y)) newTarget = item; if (item.isPreselected()) oldTarget = item; } if (newTarget == oldTarget) return; if (oldTarget != null) { oldTarget.setPreselected(false); if (oldTarget == trackedItem) { oldTarget.setSelected(false); } } if (newTarget != null) { newTarget.setPreselected(true); if (newTarget == trackedItem) { newTarget.setSelected(true); } } } private void onMouseDown(Event event) { trackedItem = null; MTabBarItem item = getItem(event.x, event.y); if (item != null && (item.isPushButton() || item.isRadioButton())) { item.setSelected(true); if (item.isRadioButton()) { mouseSelect(item, event); } else { trackedItem = item; } } } private void onMouseUp(Event event) { MTabBarItem item = getItem(event.x, event.y); if (item != null && item.isPushButton()) { item.setSelected(false); if (item == trackedItem) { update(); mouseSelect(item, event); } } trackedItem = null; } private void mouseSelect(MTabBarItem item, Event event) { if (item.isSeparator()) return; int index = indexOf(item); Widget target; if (item.isPushButton()) { target = item; } else { setSelection(item); target = this; } Event e = new Event(); e.item = item; e.index = index; e.detail = event.detail; e.x = event.x; e.y = event.y; target.notifyListeners(SWT.Selection, e); } @Override public void setBounds(int x, int y, int width, int height) { // TODO Auto-generated method stub super.setBounds(x, y, width, height); } @Override public void setBounds(Rectangle rect) { // TODO Auto-generated method stub super.setBounds(rect); } }