/* * Bibliothek - DockingFrames * Library built on Java/Swing, allows the user to "drag and drop" * panels containing any Swing-Component the developer likes to add. * * Copyright (C) 2007 Benjamin Sigg * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Benjamin Sigg * benjamin_sigg@gmx.ch * CH - Switzerland */ package glass.eclipse.theme; import java.awt.*; import java.awt.geom.*; import java.awt.image.*; import java.util.*; import javax.swing.*; import javax.swing.border.*; import bibliothek.extension.gui.dock.theme.eclipse.stack.*; import bibliothek.extension.gui.dock.theme.eclipse.stack.tab.*; import bibliothek.gui.*; import bibliothek.gui.dock.*; import bibliothek.gui.dock.station.stack.tab.layouting.*; import bibliothek.gui.dock.themes.color.*; import bibliothek.gui.dock.util.*; import bibliothek.gui.dock.util.color.*; import kux.glass.*; import kux.utils.*; import glass.eclipse.*; import glass.eclipse.theme.factory.*; import glass.eclipse.theme.utils.*; /** * Eclipse tab painter with glass look. * * Based on ArchPainter of Janni Kovacs. * * @author Thomas Hilbert */ @ColorCodes({ "glass.selected.light", "glass.selected.boundary", "glass.selected.center", "glass.unselected.light", "glass.unselected.boundary", "glass.unselected.center", "glass.focused.light", "glass.focused.boundary", "glass.focused.center", "glass.disabled.light", "glass.disabled.boundary", "glass.disabled.center", "stack.tab.border.glass", "stack.tab.border.selected.glass", "stack.tab.border.selected.focused.glass", "stack.tab.border.selected.focuslost.glass", "stack.tab.border.disabled.glass", "stack.tab.top.glass", "stack.tab.top.selected.glass", "stack.tab.top.selected.focused.glass", "stack.tab.top.selected.focuslost.glass", "stack.tab.top.disabled.glass", "stack.tab.bottom.glass", "stack.tab.bottom.selected.glass", "stack.tab.bottom.selected.focused.glass", "stack.tab.bottom.selected.focuslost.glass", "stack.tab.bottom.disabled.glass", "stack.tab.text.glass", "stack.tab.text.selected.glass", "stack.tab.text.selected.focused.glass", "stack.tab.text.selected.focuslost.glass", "stack.tab.text.disabled.glass", "stack.border.glass"}) public class CGlassEclipseTabPainter extends BaseTabComponent { /***/ private static final long serialVersionUID = -3944491545940520488L; /** * Glass parameters for inactive tabs and tab strip background. */ private IGlassFactory.SGlassParameter glassUnSelected; /** * Glass parameter for selected tab background. */ private IGlassFactory.SGlassParameter glassSelected; /** * Glass parameter for focused tab background. */ private IGlassFactory.SGlassParameter glassFocused; /** * Glass parameter for disabled tab background. */ private IGlassFactory.SGlassParameter glassDisabled; private boolean wasPreviousSelected = false; private final IGlassFactory glass = CGlassFactoryGenerator.Create(); public static final int CORNER_RADIUS = 6; protected TabColor colGlassCenterFocused, colGlassBoundaryFocused, colGlassLightFocused; protected TabColor colGlassCenterSelected, colGlassBoundarySelected, colGlassLightSelected; protected TabColor colGlassCenterUnSelected, colGlassBoundaryUnSelected, colGlassLightUnSelected; protected TabColor colGlassCenterDisabled, colGlassBoundaryDisabled, colGlassLightDisabled; /** number of pixels at the left side that are empty and under the selected predecessor of this tab */ private final int TAB_OVERLAP = 24; PropertyValue<Boolean> propValueSmall = new PropertyValue<Boolean>(CGlassExtension.SMALL_TAB_SIZE) { @Override protected void valueChanged (Boolean oldVal, Boolean newVal) { CGlassEclipseTabPainter.this.setSmallTabs(newVal); } }; PropertyValue<IGlassParameterFactory> propValueFactory = new PropertyValue<IGlassParameterFactory>(EclipseThemeExtension.GLASS_FACTORY) { @Override protected void valueChanged (IGlassParameterFactory paramA1, IGlassParameterFactory paramA2) { CGlassEclipseTabPainter.this.update(); } }; private boolean bSmallerTabs = false; /** * Creates a new painter. * @param pane the owner of this painter * @param dockable the dockable which this painter represents */ public CGlassEclipseTabPainter (EclipseTabPane pane, Dockable dockable) { super(pane, dockable, ".glass"); setOpaque(false); initAdditionalColors(); update(); updateFont(); updateBorder(); if (getController() != null) { propValueSmall.setProperties(getController()); propValueFactory.setProperties(getController()); } bSmallerTabs = propValueSmall.getValue(); } public void setSmallTabs (boolean smallTabs) { bSmallerTabs = smallTabs; update(); } @Override public void unbind () { super.unbind(); // unregister listener propValueSmall.setProperties((DockController)null); propValueFactory.setProperties((DockController)null); } protected IGlassParameterFactory getGlassParameterFactory () { return (propValueFactory.getValue()); } /** * Initializes additional colors for painting the glass effect. */ protected void initAdditionalColors () { colGlassCenterSelected = new CGlassColor("glass.selected.center", getStation(), getDockable(), new Color(222, 222, 222)); colGlassBoundarySelected = new CGlassColor("glass.selected.boundary", getStation(), getDockable(), new Color(0, 40, 255)); colGlassLightSelected = new CGlassColor("glass.selected.light", getStation(), getDockable(), new Color(222, 222, 222)); colGlassCenterUnSelected = new CGlassColor("glass.unselected.center", getStation(), getDockable(), new Color(222, 222, 222)); colGlassBoundaryUnSelected = new CGlassColor("glass.unselected.boundary", getStation(), getDockable(), new Color(0, 40, 255)); colGlassLightUnSelected = new CGlassColor("glass.unselected.light", getStation(), getDockable(), new Color(222, 222, 222)); colGlassCenterFocused = new CGlassColor("glass.focused.center", getStation(), getDockable(), new Color(0, 0, 150)); colGlassBoundaryFocused = new CGlassColor("glass.focused.boundary", getStation(), getDockable(), new Color(0, 40, 80)); colGlassLightFocused = new CGlassColor("glass.focused.light", getStation(), getDockable(), new Color(100, 200, 255)); colGlassCenterDisabled = new CGlassColor("glass.disabled.center", getStation(), getDockable(), new Color(150, 150, 150)); colGlassBoundaryDisabled = new CGlassColor("glass.disabled.boundary", getStation(), getDockable(), new Color(0, 40, 80)); colGlassLightDisabled = new CGlassColor("glass.disabled.light", getStation(), getDockable(), new Color(150, 150, 150)); addAdditionalColors(colGlassBoundaryFocused, colGlassBoundarySelected, colGlassCenterFocused, colGlassCenterSelected, colGlassLightFocused, colGlassLightSelected, colGlassLightUnSelected, colGlassCenterUnSelected, colGlassBoundaryUnSelected, colGlassCenterDisabled, colGlassBoundaryDisabled, colGlassLightDisabled ); } @Override public void updateBorder () { EclipseTabPane pane = getPane(); int index = getDockableIndex(); if (isBound() && pane != null && index >= 0) { Color color2; Window window = SwingUtilities.getWindowAncestor(getComponent()); boolean focusTemporarilyLost = false; if (window != null) { focusTemporarilyLost = !window.isActive(); } if( !isEnabled() ){ color2 = colorStackTabBorderDisabled.value(); } else if (isSelected()) { if (isFocused()) { if (focusTemporarilyLost) { color2 = colorStackTabBorderSelectedFocusLost.value(); } else { color2 = colorStackTabBorderSelectedFocused.value(); } } else { color2 = colorStackTabBorderSelected.value(); } } else { color2 = colorStackTabBorder.value(); } // set border around tab content pane.setContentBorderAt(index, BorderFactory.createMatteBorder(1, 1, 1, 1, color2)); } } public Insets getOverlap (TabComponent other) { if (other instanceof CGlassEclipseTabPainter) { CGlassEclipseTabPainter painter = (CGlassEclipseTabPainter)other; if (painter.isSelected()) { if (getOrientation().isHorizontal()) { return new Insets(0, 10 + TAB_OVERLAP, 0, 0); } else { return new Insets(10 + TAB_OVERLAP, 0, 0, 0); } } } return new Insets(0, 0, 0, 0); } @Override public Dimension getPreferredSize () { boolean previousSelected = isPreviousTabSelected(); if (wasPreviousSelected != previousSelected) { update(); } return super.getPreferredSize(); } @Override public Dimension getMinimumSize () { boolean previousSelected = isPreviousTabSelected(); if (wasPreviousSelected != previousSelected) { update(); } return super.getMinimumSize(); } @Override public void updateFocus () { update(); updateBorder(); updateFont(); } @Override protected void updateOrientation () { update(); } @Override protected void updateSelected () { update(); updateBorder(); updateFont(); } @Override protected void updateColors () { update(); } @Override protected void updateEnabled(){ updateBorder(); update(); } /** * Updates the layout information of this painter. */ protected void update () { wasPreviousSelected = isPreviousTabSelected(); Insets labelInsets = null; Insets buttonInsets = null; int iInsets = bSmallerTabs ? 1 : 3; switch (getOrientation()) { case TOP_OF_DOCKABLE: case BOTTOM_OF_DOCKABLE: labelInsets = new Insets(iInsets, 5, iInsets, 2); buttonInsets = new Insets(1, 0, 1, 5); break; case LEFT_OF_DOCKABLE: case RIGHT_OF_DOCKABLE: labelInsets = new Insets(5, iInsets, 2, iInsets); buttonInsets = new Insets(0, 1, 5, 1); break; } boolean horizontal = getOrientation().isHorizontal(); if (isSelected()) { if (horizontal) { buttonInsets.right += 24; } else { buttonInsets.bottom += 24; } } if (wasPreviousSelected) { if (horizontal) { labelInsets.left += TAB_OVERLAP; } else { labelInsets.top += TAB_OVERLAP; } } getLabel().setIconOffset(0); getLabel().setForeground(getTextColor()); setLabelInsets(labelInsets); setButtonInsets(buttonInsets); updateGlass(); revalidate(); repaint(); } protected void updateGlass () { Color c1, c2, c3; c1 = colGlassCenterFocused.value(); c2 = colGlassLightFocused.value(); c3 = colGlassBoundaryFocused.value(); c1 = c1 == null ? colorStackTabTopSelectedFocused.value() : c1; c2 = c2 == null ? CColor.BrighterColor(colorStackTabTopSelectedFocused.value()) : c2; c3 = c3 == null ? colorStackTabBottomSelectedFocused.value() : c3; IGlassParameterFactory f = getGlassParameterFactory(); glassFocused = f.getFocusedGlassParameters(); if (glassFocused != null) { glassFocused.colorCenter = c1; glassFocused.colorSuperLight = c2; glassFocused.colorBoundary = c3; } c1 = colGlassCenterSelected.value(); c2 = colGlassLightSelected.value(); c3 = colGlassBoundarySelected.value(); c1 = c1 == null ? colorStackTabTopSelected.value() : c1; c2 = c2 == null ? CColor.BrighterColor(colorStackTabTopSelected.value()) : c2; c3 = c3 == null ? colorStackTabBottomSelected.value() : c3; glassSelected = f.getSelectedGlassParameters(); if (glassSelected != null) { glassSelected.colorCenter = c1; glassSelected.colorSuperLight = c2; glassSelected.colorBoundary = c3; } c1 = colGlassCenterUnSelected.value(); c2 = colGlassLightUnSelected.value(); c3 = colGlassBoundaryUnSelected.value(); c1 = c1 == null ? colorStackTabTop.value() : c1; c2 = c2 == null ? CColor.BrighterColor(colorStackTabTop.value()) : c2; c3 = c3 == null ? colorStackTabBottom.value() : c3; glassUnSelected = f.getUnSelectedGlassParameters(); if (glassUnSelected != null) { glassUnSelected.colorCenter = c1; glassUnSelected.colorSuperLight = c2; glassUnSelected.colorBoundary = c3; } c1 = colGlassCenterDisabled.value(); c2 = colGlassLightDisabled.value(); c3 = colGlassBoundaryDisabled.value(); c1 = c1 == null ? colorStackTabTopDisabled.value() : c1; c2 = c2 == null ? CColor.BrighterColor(colorStackTabTopDisabled.value()) : c2; c3 = c3 == null ? colorStackTabBottomDisabled.value() : c3; glassDisabled = f.getDisabledGlassParameters(); if (glassUnSelected != null) { glassUnSelected.colorCenter = c1; glassUnSelected.colorSuperLight = c2; glassUnSelected.colorBoundary = c3; } try { if (getButtons() != null) { if (isSelected() && isFocused()) { c2 = colGlassLightFocused.value(); c2 = c2 == null ? CColor.BrighterColor(colorStackTabTopSelectedFocused.value()) : c2; getButtons().setBackground(CColor.GradientColor(Color.BLACK, c2, 0.55)); } else if (isSelected()) { c2 = colGlassLightSelected.value(); c2 = c2 == null ? CColor.BrighterColor(colorStackTabTopSelected.value()) : c2; getButtons().setBackground(CColor.GradientColor(Color.LIGHT_GRAY, c2, 0.55)); } else { getButtons().setBackground(Color.LIGHT_GRAY); } } } catch (Exception e) {} } private Color getTextColor () { boolean focusTemporarilyLost = isFocusTemporarilyLost(); Color c; if( !isEnabled() ){ c = colorStackTabTextDisabled.value(); } else if (isFocused() && !focusTemporarilyLost) { c = colorStackTabTextSelectedFocused.value(); } else if (isFocused() && focusTemporarilyLost) { c = colorStackTabTextSelectedFocusLost.value(); } else if (isSelected()) { c = colorStackTabTextSelected.value(); } else { c = colorStackTabText.value(); } return (c); } @Override public boolean contains (int x, int y) { if ( !super.contains(x, y)) { return (false); } if( containsButton( x, y )){ return true; } boolean bRet = true; if (isSelected()) { Shape s = createSelectedTabShape(getWidth(), getHeight(), false); bRet = (s.contains(x, y)); } else { bRet = super.contains(x, y); } return (bRet); } @Override public void paintBackground (Graphics g) { if (getWidth() != 0 && getHeight() != 0) { updateGlass(); Graphics2D g2d = (Graphics2D)g.create(); int iState = 0; if (isFocused() && !isFocusTemporarilyLost()) { iState = 2; } else if (isFocused() && isFocusTemporarilyLost() || isSelected()) { iState = 1; } else { iState = 0; } if (iState == 2 || iState == 1) { paintSelected(g2d, iState == 2); } else { paintUnselected(g2d); } g2d.dispose(); } } protected int getSelectedIndex () { return (getPane().getSelectedIndex()); } protected boolean isHorizontal () { return (getOrientation() == TabPlacement.TOP_OF_DOCKABLE || getOrientation() == TabPlacement.BOTTOM_OF_DOCKABLE); } /** * Paints a unselected / unfocused tab. * @param g */ protected void paintUnselected (Graphics g) { Dimension dImg; Color lineColor = colorStackBorder.value(); int x = 0; int y = 0; int w = getWidth(); int h = getHeight(); if (w > 0 && h > 0) { Graphics2D g2d = (Graphics2D)g.create(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); Shape sTab = createUnSelectedTabShape(isHorizontal() ? w : w, isHorizontal() ? h : h, false, true); BufferedImage img; dImg = new Dimension(isHorizontal() ? w + CORNER_RADIUS : h + CORNER_RADIUS, isHorizontal() ? h : w); if (glassUnSelected != null) { img = new BufferedImage(dImg.width, dImg.height, BufferedImage.TYPE_INT_ARGB); Graphics2D gg = img.createGraphics(); gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); gg.setColor(Color.WHITE); gg.fill(sTab); gg.setComposite(AlphaComposite.SrcIn); try { glass.Render2Graphics(dImg, gg, glassUnSelected, true); } catch (Exception e) { glass.Render2Graphics(dImg, gg, CGlassFactory.VALUE_STEEL, true); } gg.dispose(); if ( !isHorizontal()) { AffineTransform atTrans = AffineTransform.getTranslateInstance(x/* + w*/, y + h); atTrans.concatenate(COutlineHelper.tRot90CCW); g2d.drawImage(img, atTrans, null); } else { g2d.drawImage(img, 0, 0, null); } } // restore default clipping sTab = createUnSelectedTabShape(w, h, getTabIndex() == 0, false); // draw Border g2d.setColor(lineColor); g2d.draw(sTab); switch (getOrientation()) { case TOP_OF_DOCKABLE: g2d.drawLine(0, h - 1, w - 1, h - 1); break; case BOTTOM_OF_DOCKABLE: g2d.drawLine(0, 0, w - 1, 0); break; case LEFT_OF_DOCKABLE: g2d.drawLine(w - 1, 0, w - 1, h - 1); break; case RIGHT_OF_DOCKABLE: g2d.drawLine(0, 0, 0, h - 1); break; } g2d.dispose(); } } /** * Paints the selected or focused tab (with round edges) * @param g * @param bActive */ protected void paintSelected (Graphics g, boolean bActive) { int x = 0; int y = 0; int w = getWidth(); int h = getHeight(); Dimension dImg; if (w > 0 && h > 0) { Shape sTab = createSelectedTabShape(w, h, false); Color lineColor = colorStackBorder.value(); Graphics2D g2d = (Graphics2D)g.create(); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); if (getTabIndex() > 0) { // paint a little bit of the previous tab, because previous tab should also overlap at the begin of the selected tab paintWorkAround(g2d); } // draw glass // first render to image because glass is transparent and we would see the inactive tab in background BufferedImage bimg = null; dImg = new Dimension(isHorizontal() ? w : h, isHorizontal() ? h : w); if( !isEnabled() ){ if(glassDisabled != null){ try { bimg = glass.RenderBufferedImage(glassDisabled, dImg, true); } catch( Exception e ) { bimg = glass.RenderBufferedImage( CGlassFactory.VALUE_GRAY, dImg, true ); } } } else if (bActive) { if (glassFocused != null) { try { bimg = glass.RenderBufferedImage(glassFocused, dImg, true); } catch (Exception e) { bimg = glass.RenderBufferedImage(CGlassFactory.VALUE_STEEL, dImg, true); } } } else { if (glassSelected != null) { try { bimg = glass.RenderBufferedImage(glassSelected, dImg, true); } catch (Exception e) { bimg = glass.RenderBufferedImage(CGlassFactory.VALUE_DARKENED_PLAIN, dImg, true); } } } if (bimg != null) { // glass is translucent, so we could see the sharp edge of an unselected tab behind // So, we paint the glass image onto a other image were only the glass part is visible (white) BufferedImage b = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); Graphics2D gg2d = b.createGraphics(); gg2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); gg2d.setColor(Color.WHITE); gg2d.fill(sTab); gg2d.setClip(sTab); gg2d.setComposite(AlphaComposite.SrcAtop); if ( !isHorizontal()) { AffineTransform atTrans = AffineTransform.getTranslateInstance(0/*w*/, h); atTrans.concatenate(COutlineHelper.tRot90CCW); gg2d.drawImage(bimg, atTrans, null); } else { gg2d.drawImage(bimg, 0, 0, null); } gg2d.dispose(); g2d.drawImage(b, x, y, null); } // draw Border g2d.setColor(lineColor); sTab = createSelectedTabShape(w, h, getTabIndex() == 0); g2d.draw(sTab); switch (getOrientation()) { case TOP_OF_DOCKABLE: g2d.drawLine(0, h - 1, w - 1, h - 1); break; case BOTTOM_OF_DOCKABLE: g2d.drawLine(0, 0, w - 1, 0); break; case LEFT_OF_DOCKABLE: g2d.drawLine(w - 1, 0, w - 1, h - 1); break; case RIGHT_OF_DOCKABLE: g2d.drawLine(0, 0, 0, h - 1); break; } g2d.dispose(); } } /** * An unselected tab before the selected tab is not painted behind the selected tab. * When we draw the selected tab, we first draw a little bit of the unselected tab in * background. * * @param g2d */ private void paintWorkAround (Graphics2D g2d) { Dimension dImg; Rectangle r = getPane().getTabsList().get(getTabIndex() - 1).getComponent().getBounds(); BufferedImage bimg = null; dImg = new Dimension(isHorizontal() ? r.width + CORNER_RADIUS : getHeight() + CORNER_RADIUS, isHorizontal() ? getHeight() : r.width); if (dImg.width > 0 && dImg.height > 0) { if (glassUnSelected != null) { try { bimg = glass.RenderBufferedImage(glassUnSelected, dImg, true); } catch (Exception e) { bimg = glass.RenderBufferedImage(CGlassFactory.VALUE_RED, dImg, true); } if ( !isHorizontal()) { AffineTransform atTrans = AffineTransform.getTranslateInstance(/*r.width*/0, CORNER_RADIUS/*-getHeight()*/); atTrans.concatenate(COutlineHelper.tRot90CCW); g2d.drawImage(bimg, atTrans, null); } else { g2d.drawImage(bimg, -r.width, 0, null); } } } } /** * Creates the tab outline for an unselected tab. * @param w * @param h * @param bFirst * @param forClip * @return */ protected Shape createUnSelectedTabShape (int w, int h, boolean bFirst, boolean forClip) { Shape sTab = null; int x, y; boolean bBeforeSelected = getTabIndex() < getSelectedIndex(); switch (getOrientation()) { case LEFT_OF_DOCKABLE: x = -1; y = bBeforeSelected ? 0 : -1; sTab = COutlineHelper.CreateUnselectedTabShape(CORNER_RADIUS, h + 1, w + 1, bFirst, forClip, bBeforeSelected); if ( !forClip) { sTab = COutlineHelper.Modify4LeftSide(sTab); } else { sTab = COutlineHelper.tSclX.createTransformedShape(sTab); sTab = COutlineHelper.TranslateShapeTo(h + 1, 0, sTab); } sTab = COutlineHelper.TranslateShapeTo(x, y, sTab); break; case RIGHT_OF_DOCKABLE: x = 0; y = bBeforeSelected ? 0 : -1; sTab = COutlineHelper.CreateUnselectedTabShape(CORNER_RADIUS, h + 1, w + 1, bFirst, forClip, bBeforeSelected); if ( !forClip) { sTab = COutlineHelper.Modify4RightSide(sTab); } else { sTab = COutlineHelper.tSclX.createTransformedShape(sTab); sTab = COutlineHelper.tSclY.createTransformedShape(sTab); sTab = COutlineHelper.TranslateShapeTo(h, w, sTab); } sTab = COutlineHelper.TranslateShapeTo(x, y, sTab); break; case BOTTOM_OF_DOCKABLE: x = bBeforeSelected ? 0 : -1; y = 0; sTab = COutlineHelper.CreateUnselectedTabShape(CORNER_RADIUS, w + 1, h + 1, bFirst, forClip, bBeforeSelected); sTab = COutlineHelper.Modify4BottomSide(sTab); sTab = COutlineHelper.TranslateShapeTo(x, y, sTab); break; case TOP_OF_DOCKABLE: x = bBeforeSelected ? 0 : -1; y = -1; sTab = COutlineHelper.CreateUnselectedTabShape(CORNER_RADIUS, w + 1, h + 1, bFirst, forClip, bBeforeSelected); sTab = COutlineHelper.TranslateShapeTo(x, y, sTab); break; } return (sTab); } /** * Creates the tab outline for the selected tab. * @param w * @param h * @param bFirst Is it the first tab. * @return */ protected Shape createSelectedTabShape (int w, int h, boolean bFirst) { Shape sTab = null; int x, y; switch (getOrientation()) { case LEFT_OF_DOCKABLE: x = -1; y = getTabIndex() == 0 ? -1 : 0; sTab = COutlineHelper.CreateSelectedTabShape(CORNER_RADIUS, h, w + 1, bFirst); sTab = COutlineHelper.Modify4LeftSide(sTab); sTab = COutlineHelper.TranslateShapeTo(x, y, sTab); break; case RIGHT_OF_DOCKABLE: x = 0; y = getTabIndex() == 0 ? -1 : 0; sTab = COutlineHelper.CreateSelectedTabShape(CORNER_RADIUS, h, w + 1, bFirst); sTab = COutlineHelper.Modify4RightSide(sTab); sTab = COutlineHelper.TranslateShapeTo(x, y, sTab); break; case BOTTOM_OF_DOCKABLE: x = getTabIndex() == 0 ? -1 : 0; y = 0; sTab = COutlineHelper.CreateSelectedTabShape(CORNER_RADIUS, w, h + 1, bFirst); sTab = COutlineHelper.Modify4BottomSide(sTab); sTab = COutlineHelper.TranslateShapeTo(x, y, sTab); break; case TOP_OF_DOCKABLE: x = getTabIndex() == 0 ? -1 : 0; y = -1; sTab = COutlineHelper.CreateSelectedTabShape(CORNER_RADIUS, w, h + 1, bFirst); sTab = COutlineHelper.TranslateShapeTo(x, y, sTab); break; } return (sTab); } /** * Special glass color. * @author Thomas Hilbert * */ protected class CGlassColor extends TabColor { public CGlassColor (String id, DockStation station, Dockable dock, Color backup) { super(id, station, dock, backup); } @Override protected void changed (Color oldColor, Color newColor) { updateGlass(); repaint(); } } protected static class CTabPainter implements TabPainter { CBorderListener placementListener; /** * Listens to changes of the TabPlacement property and updates all used CEclipseBorder's. * The borders are stored in a WeakHashMap so there will be no strong reference and unused borders * are removed automatically by the garbage collector. * @author Thomas Hilbert * */ protected class CBorderListener implements DockPropertyListener<TabPlacement> { protected WeakHashMap<CEclipseBorder, Void> wmap = new WeakHashMap<CEclipseBorder, Void>(); public void addBorder (CEclipseBorder border) { wmap.put(border, null); } public void propertyChanged (DockProperties properties, PropertyKey<TabPlacement> property, TabPlacement oldValue, TabPlacement newValue) { for (CEclipseBorder b : wmap.keySet()) { b.update4Placement(newValue); } } } public CTabPainter () { placementListener = new CBorderListener(); } public TabComponent createTabComponent (EclipseTabPane pane, Dockable dockable) { return new CGlassEclipseTabPainter(pane, dockable); } public TabPanePainter createDecorationPainter (EclipseTabPane pane) { return new CGlassStripPainter(pane); } public InvisibleTab createInvisibleTab (InvisibleTabPane pane, Dockable dockable) { return new DefaultInvisibleTab(pane, dockable); } public Border getFullBorder (BorderedComponent owner, DockController controller, Dockable dockable) { controller.getProperties().removeListener(StackDockStation.TAB_PLACEMENT, placementListener); controller.getProperties().addListener(StackDockStation.TAB_PLACEMENT, placementListener); CEclipseBorder border = new CEclipseBorder(controller, CORNER_RADIUS, owner, CEclipseBorder.TOP_LEFT | CEclipseBorder.BOTTOM_RIGHT); if (controller != null) { border.update4Placement(controller.getProperties().get(StackDockStation.TAB_PLACEMENT)); } placementListener.addBorder(border); return (border); } } /** * This factory creates instances of {@link CGlassEclipseTabPainter}. * Normal tab size. */ public static final CTabPainter FACTORY = new CTabPainter(); }