package bibliothek.extension.gui.dock.theme.flat; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Paint; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.border.Border; import javax.swing.event.MouseInputListener; import bibliothek.extension.gui.dock.theme.FlatTheme; import bibliothek.gui.DockController; import bibliothek.gui.Dockable; import bibliothek.gui.dock.DockElement; import bibliothek.gui.dock.event.DockableFocusEvent; import bibliothek.gui.dock.event.DockableFocusListener; import bibliothek.gui.dock.station.stack.CombinedTab; import bibliothek.gui.dock.station.stack.action.DockActionDistributor.Target; import bibliothek.gui.dock.station.stack.action.DockActionDistributorSource; import bibliothek.gui.dock.station.stack.tab.Tab; import bibliothek.gui.dock.station.stack.tab.TabComponentLayoutManager; import bibliothek.gui.dock.station.stack.tab.TabConfiguration; import bibliothek.gui.dock.station.stack.tab.TabPane; import bibliothek.gui.dock.station.stack.tab.TabPaneComponent; import bibliothek.gui.dock.station.stack.tab.TabPaneTabBackgroundComponent; import bibliothek.gui.dock.station.stack.tab.layouting.TabPlacement; import bibliothek.gui.dock.themes.ThemeManager; import bibliothek.gui.dock.themes.basic.action.buttons.ButtonPanel; import bibliothek.gui.dock.themes.color.TabColor; import bibliothek.gui.dock.themes.font.TabFont; import bibliothek.gui.dock.util.BackgroundAlgorithm; import bibliothek.gui.dock.util.ConfiguredBackgroundPanel; import bibliothek.gui.dock.util.Transparency; import bibliothek.gui.dock.util.color.ColorCodes; import bibliothek.gui.dock.util.font.DockFont; import bibliothek.gui.dock.util.font.FontModifier; import bibliothek.gui.dock.util.render.DockRenderingHints; import bibliothek.gui.dock.util.swing.OrientedLabel; /** * A small button which can be clicked by the user. * @author Benjamin Sigg */ @ColorCodes({ "stack.tab.border.out.selected", "stack.tab.border.center.selected", "stack.tab.border.out.focused", "stack.tab.border.center.focused", "stack.tab.border.out", "stack.tab.border.center", "stack.tab.border.out.disabled", "stack.tab.border.center.disabled", "stack.tab.border", "stack.tab.background.top.selected", "stack.tab.background.bottom.selected", "stack.tab.background.top.focused", "stack.tab.background.bottom.focused", "stack.tab.background.top", "stack.tab.background.bottom", "stack.tab.background.top.disabled", "stack.tab.background.bottom.disabled", "stack.tab.background", "stack.tab.foreground.selected", "stack.tab.foreground.focused", "stack.tab.foreground.disabled", "stack.tab.foreground" }) public class FlatTab extends ConfiguredBackgroundPanel implements CombinedTab, DockableFocusListener{ /** the dockable for which this button is shown */ private Dockable dockable; /** the current controller */ private DockController controller; /** the parent of this tab */ private FlatTabPane pane; /** the label which paints the content of this tab */ private OrientedLabel label = new OrientedLabel(){ @Override protected void updateFonts(){ FlatTab.this.updateFonts(); } }; /** the algorithm painting the background of this tab */ private Background backgroundAlgorithm = new Background(); /** whether {@link #dockable} is currently focused */ private boolean focused = false; private TabColor borderSelectedOut; private TabColor borderSelectedCenter; private TabColor borderFocusedOut; private TabColor borderFocusedCenter; private TabColor borderOut; private TabColor borderCenter; private TabColor borderDisabledOut; private TabColor borderDisabledCenter; private TabColor border; private TabColor backgroundSelectedTop; private TabColor backgroundSelectedBottom; private TabColor backgroundFocusedTop; private TabColor backgroundFocusedBottom; private TabColor backgroundTop; private TabColor backgroundBottom; private TabColor backgroundDisabledTop; private TabColor backgroundDisabledBottom; private TabColor background; private TabColor foreground; private TabColor foregroundSelected; private TabColor foregroundFocused; private TabColor foregroundDisabled; private TabFont fontFocused; private TabFont fontSelected; private TabFont fontUnselected; private int zOrder; private TabPlacement orientation = TabPlacement.BOTTOM_OF_DOCKABLE; /** a panel showing additional actions on this tab */ private ButtonPanel actions = new ButtonPanel( false ); /** the actions shown on {@link #actions} */ private DockActionDistributorSource actionsSource; /** layout manager for {@link #label} and {@link #actions} */ private TabComponentLayoutManager layoutManager; /** all the {@link MouseInputListener}s that were added to this tab */ private List<MouseInputListener> mouseInputListeners = new ArrayList<MouseInputListener>(); /** * Constructs a new button * @param pane the owner of this tab * @param dockable the Dockable for which this tab is displayed */ public FlatTab( FlatTabPane pane, Dockable dockable ){ super( Transparency.SOLID ); this.pane = pane; this.dockable = dockable; add( label ); add( actions ); layoutManager = new TabComponentLayoutManager( label, actions, pane.getConfiguration( dockable ) ); layoutManager.setFreeSpaceToSideBorder( 2 ); layoutManager.setFreeSpaceToParallelBorder( 2 ); layoutManager.setFreeSpaceToOpenSide( 2 ); layoutManager.setFreeSpaceBetweenLabelAndActions( 2 ); setLayout( layoutManager ); label.setBackground( backgroundAlgorithm ); setBackground( backgroundAlgorithm ); borderSelectedOut = new FlatTabColor( "stack.tab.border.out.selected", dockable ); borderSelectedCenter = new FlatTabColor( "stack.tab.border.center.selected", dockable ); borderFocusedOut = new FlatTabColor( "stack.tab.border.out.focused", dockable ); borderFocusedCenter = new FlatTabColor( "stack.tab.border.center.focused", dockable ); borderOut = new FlatTabColor( "stack.tab.border.out", dockable ); borderCenter = new FlatTabColor( "stack.tab.border.center", dockable ); borderDisabledOut = new FlatTabColor( "stack.tab.border.out.disabled", dockable ); borderDisabledCenter = new FlatTabColor( "stack.tab.border.center.disabled", dockable ); border = new FlatTabColor( "stack.tab.border", dockable ); backgroundSelectedTop = new FlatTabColor( "stack.tab.background.top.selected", dockable ); backgroundSelectedBottom = new FlatTabColor( "stack.tab.background.bottom.selected", dockable ); backgroundFocusedTop = new FlatTabColor( "stack.tab.background.top.focused", dockable ); backgroundFocusedBottom = new FlatTabColor( "stack.tab.background.bottom.focused", dockable ); backgroundTop = new FlatTabColor( "stack.tab.background.top", dockable ); backgroundBottom = new FlatTabColor( "stack.tab.background.bottom", dockable ); backgroundDisabledTop = new FlatTabColor( "stack.tab.background.top.disabled", dockable ); backgroundDisabledBottom = new FlatTabColor( "stack.tab.background.bottom.disabled", dockable ); background = new FlatTabColor( "stack.tab.background", dockable ); foreground = new FlatTabColor( "stack.tab.foreground", dockable ){ @Override protected void changed( Color oldColor, Color newColor ) { if( !isSelected() && isEnabled() ) setForeground( newColor ); } }; foregroundSelected = new FlatTabColor( "stack.tab.foreground.selected", dockable ){ @Override protected void changed( Color oldColor, Color newColor ) { if( isSelected() && !focused && isEnabled() ){ setForeground( newColor ); } } }; foregroundFocused = new FlatTabColor( "stack.tab.foreground.focused", dockable ){ @Override protected void changed( Color oldColor, Color newColor ) { if( focused && isEnabled() ){ setForeground( newColor ); } } }; foregroundDisabled = new FlatTabColor( "stack.tab.foreground.disabled", dockable ){ @Override protected void changed( Color oldColor, Color newColor ){ if( !isEnabled() ){ setForeground( newColor ); } } }; fontFocused = new FlatTabFont( DockFont.ID_TAB_FOCUSED, dockable ); fontSelected = new FlatTabFont( DockFont.ID_TAB_SELECTED, dockable ); fontUnselected = new FlatTabFont( DockFont.ID_TAB_UNSELECTED, dockable ); setController( pane.getController() ); // setOpaque( false ); setFocusable( true ); addMouseListener( new MouseAdapter(){ @Override public void mousePressed( MouseEvent e ){ FlatTab.this.pane.setSelectedDockable( FlatTab.this.dockable ); } }); setBorder( new Border(){ public void paintBorder(Component c, Graphics g, int x, int y, int w, int h){ Graphics2D g2 = (Graphics2D)g; Paint oldPaint = g2.getPaint(); Color out = null; Color center = null; if( !isEnabled() ){ out = borderDisabledOut.value(); center = borderDisabledCenter.value(); } else if( focused ){ out = borderFocusedOut.value(); center = borderFocusedCenter.value(); } if( isSelected() ){ if( out == null ) out = borderSelectedOut.value(); if( center == null ) center = borderSelectedCenter.value(); } if( out == null ) out = borderOut.value(); if( center == null ) center = borderCenter.value(); if( out == null || center == null ){ Color background = border.value(); if( background == null ) background = FlatTab.this.background.value(); if( background == null ) background = getBackground(); if( out == null ) out = background; if( center == null ){ if( isSelected() ){ center = background.brighter(); } else{ center = background.darker(); } } } if( orientation.isHorizontal() ){ g2.setPaint( new GradientPaint( x, y, out, x, y+h/2, center )); g.drawLine( x, y, x, y+h/2 ); g.drawLine( x+w-1, y, x+w-1, y+h/2 ); g2.setPaint( new GradientPaint( x, y+h, out, x, y+h/2, center )); g.drawLine( x, y+h, x, y+h/2 ); g.drawLine( x+w-1, y+h, x+w-1, y+h/2 ); } else{ g2.setPaint( new GradientPaint( x, y, out, x+w/2, y, center )); g.drawLine( x, y, x+w/2, y ); g.drawLine( x, y+h-1, x+w/2, y+h-1 ); g2.setPaint( new GradientPaint( x+w, y, out, x+w/2, y, center )); g.drawLine( x+w, y, x+w/2, y ); g.drawLine( x+w, y+h-1, x+w/2, y+h-1 ); } g2.setPaint( oldPaint ); } public Insets getBorderInsets(Component c){ return new Insets( 0, 1, 0, 1 ); } public boolean isBorderOpaque(){ return false; } }); } public void setConfiguration( TabConfiguration configuration ){ layoutManager.setConfiguration( configuration ); } public void updateForeground(){ if( !isEnabled() ){ setForeground( foregroundDisabled.value() ); } else if( focused ){ setForeground( foregroundFocused.value() ); } else if( isSelected() ){ setForeground( foregroundSelected.value() ); } else{ setForeground( foreground.value() ); } } @Override public void setForeground( Color fg ) { super.setForeground( fg ); if( label != null ){ label.setForeground( fg ); } } public void updateFonts(){ if( focused ){ setFontModifier( fontFocused.font() ); } else if( isSelected() ){ setFontModifier( fontSelected.font() ); } else{ setFontModifier( fontUnselected.font() ); } } /** * Sets the modifier which modifies the font of this tab, this modifier * may be replaced any time. * @param modifier the modifier */ public void setFontModifier( FontModifier modifier ){ label.setFontModifier( modifier ); } /** * Gets the font modifier of this tab. * @return the modifier */ public FontModifier getFontModifier(){ return label.getFontModifier(); } public void setIcon( Icon icon ){ label.setIcon( icon ); } /** * Gets the icon shown on this tab. * @return the icon */ public Icon getIcon(){ return label.getIcon(); } public void setText( String text ){ label.setText( text ); } /** * Gets the text shown on this tab. * @return the text */ public String getText(){ return label.getText(); } /** * Connects this tab with <code>controller</code>. * @param controller the controller in whose realm this tab is used, * can be <code>null</code> */ public void setController( DockController controller ){ if( this.controller != null ) this.controller.removeDockableFocusListener( this ); this.controller = controller; actions.setController( controller ); if( controller == null ){ if( actionsSource != null ){ actions.set( null ); actionsSource.setDockable( null ); actionsSource = null; } } else{ controller.addDockableFocusListener( this ); focused = controller.getFocusedDockable() == dockable; if( actionsSource == null ){ actionsSource = new DockActionDistributorSource( Target.TAB, FlatTheme.ACTION_DISTRIBUTOR ); actionsSource.setDockable( getDockable() ); actions.set( getDockable(), actionsSource ); } } borderSelectedOut.connect( controller ); borderSelectedCenter.connect( controller ); borderFocusedOut.connect( controller ); borderFocusedCenter.connect( controller ); borderOut.connect( controller ); borderCenter.connect( controller ); borderDisabledOut.connect( controller ); borderDisabledCenter.connect( controller ); border.connect( controller ); backgroundSelectedTop.connect( controller ); backgroundSelectedBottom.connect( controller ); backgroundFocusedTop.connect( controller ); backgroundFocusedBottom.connect( controller ); backgroundTop.connect( controller ); backgroundBottom.connect( controller ); backgroundDisabledTop.connect( controller ); backgroundDisabledBottom.connect( controller ); background.connect( controller ); foregroundSelected.connect( controller ); foregroundFocused.connect( controller ); foregroundDisabled.connect( controller ); foreground.connect( controller ); fontFocused.connect( controller ); fontSelected.connect( controller ); fontUnselected.connect( controller ); backgroundAlgorithm.setController( controller ); } public Point getPopupLocation( Point click, boolean popupTrigger ) { if( popupTrigger ) return click; return null; } public void dockableFocused( DockableFocusEvent event ) { focused = this.dockable == event.getNewFocusOwner(); updateForeground(); updateFonts(); repaint(); } public TabPane getTabParent(){ return pane; } public Dockable getDockable(){ return dockable; } public JComponent getComponent(){ return this; } public DockElement getElement() { return dockable; } public boolean isUsedAsTitle() { return false; } public boolean shouldFocus(){ return true; } public boolean shouldTransfersFocus(){ return true; } @Override public void setEnabled( boolean enabled ){ if( isEnabled() != enabled ){ label.setEnabled( enabled ); super.setEnabled( enabled ); if( enabled ){ for( MouseInputListener listener : mouseInputListeners ){ doAddMouseInputListener( listener ); } } else{ for( MouseInputListener listener : mouseInputListeners ){ doRemoveMouseInputListener( listener ); } } updateFonts(); updateForeground(); repaint(); } } public void addMouseInputListener( MouseInputListener listener ) { mouseInputListeners.add( listener ); if( isEnabled() ){ doAddMouseInputListener( listener ); } } private void doAddMouseInputListener( MouseInputListener listener ){ addMouseListener( listener ); addMouseMotionListener( listener ); label.addMouseListener( listener ); label.addMouseMotionListener( listener ); } public void removeMouseInputListener( MouseInputListener listener ) { mouseInputListeners.remove( listener ); if( isEnabled() ){ doRemoveMouseInputListener( listener ); } } private void doRemoveMouseInputListener( MouseInputListener listener ){ removeMouseListener( listener ); removeMouseMotionListener( listener ); label.removeMouseListener( listener ); label.removeMouseMotionListener( listener ); } public Dimension getPreferredSize( Tab[] tabs ){ return getPreferredSize(); } @Override public Dimension getPreferredSize() { Dimension preferred = super.getPreferredSize(); if( preferred.width < 10 || preferred.height < 10 ){ preferred = new Dimension( preferred ); preferred.width = Math.max( preferred.width, 10 ); preferred.height = Math.max( preferred.height, 10 ); } return preferred; } public Dimension getMinimumSize( Tab[] tabs ){ return getMinimumSize(); } @Override public Dimension getMinimumSize() { Dimension min = super.getMinimumSize(); if( min.width < 10 || min.height < 10 ){ min = new Dimension( min ); min.width = Math.max( min.width, 10 ); min.height = Math.max( min.height, 10 ); } return min; } public void setTooltip( String tooltip ) { setToolTipText( tooltip ); } public void setPaneVisible( boolean visible ){ pane.getTabHandler().setVisible( this, visible ); } public boolean isPaneVisible(){ return pane.getTabHandler().isVisible( this ); } /** * Determines whether this button is selected or not. * @return <code>true</code> if the button is selected */ public boolean isSelected() { return pane.getSelectedDockable() == dockable; } public void setZOrder( int order ){ this.zOrder = order; } public int getZOrder(){ return zOrder; } public Insets getOverlap( TabPaneComponent other ){ return new Insets( 0, 0, 0, 0 ); } public void setOrientation( TabPlacement orientation ){ if( orientation == null ) throw new IllegalArgumentException( "orientation is null" ); if( this.orientation != orientation ){ this.orientation = orientation; layoutManager.setOrientation( orientation ); revalidate(); repaint(); } } /** * Gets the orientation of this tab. * @return the orientation, not <code>null</code> */ public TabPlacement getOrientation(){ return orientation; } @Override protected void setupRenderingHints( Graphics g ) { if( controller != null ){ DockRenderingHints renderingHints = controller.getProperties().get( DockRenderingHints.RENDERING_HINTS ); renderingHints.setupGraphics( g ); } } @Override public void paintBackground( Graphics g ){ if( getTransparency() != Transparency.TRANSPARENT ){ super.paintBackground( g ); Graphics2D g2 = (Graphics2D)g; Paint oldPaint = g2.getPaint(); int w = getWidth(); int h = getHeight(); Color top = null; Color bottom = null; if( !isEnabled() ){ top = backgroundDisabledTop.value(); bottom = backgroundFocusedBottom.value(); } else if( focused ){ top = backgroundFocusedTop.value(); bottom = backgroundFocusedBottom.value(); } if( isSelected() ){ if( top == null ) top = backgroundSelectedTop.value(); if( bottom == null ) bottom = backgroundSelectedBottom.value(); } if( top == null ) top = backgroundTop.value(); if( bottom == null ) bottom = backgroundBottom.value(); if( top == null || bottom == null ){ Color background = FlatTab.this.background.value(); if( background == null ) background = getBackground(); if( bottom == null ) bottom = background; if( top == null ){ if( isSelected() ){ top = background.brighter(); } else{ top = background; } } } if( top.equals( bottom )) g.setColor( top ); else{ if( orientation.isHorizontal() ) g2.setPaint( new GradientPaint( 0, 0, top, 0, h, bottom ) ); else g2.setPaint( new GradientPaint( 0, 0, top, w, 0, bottom ) ); } g.fillRect( 0, 0, w, h ); g2.setPaint( oldPaint ); } } /** * A color of this tab. * @author Benjamin Sigg */ private class FlatTabColor extends TabColor{ /** * Creates a new color. * @param id the id of the color * @param dockable the element for which the color is used */ public FlatTabColor( String id, Dockable dockable ){ super( id, pane.getStation(), dockable, null ); } @Override protected void changed( Color oldColor, Color newColor ) { repaint(); } } /** * A font of this tab. * @author Benjamin Sigg */ private class FlatTabFont extends TabFont{ /** * Creates a new font * @param id the identifier of the font * @param dockable the element for which the font is used */ public FlatTabFont( String id, Dockable dockable ){ super( id, pane.getStation(), dockable ); } @Override protected void changed( FontModifier oldValue, FontModifier newValue ) { updateFonts(); } } /** * The background algorithm of this tab. * @author Benjamin Sigg */ private class Background extends BackgroundAlgorithm implements TabPaneTabBackgroundComponent{ public Background(){ super( TabPaneTabBackgroundComponent.KIND, ThemeManager.BACKGROUND_PAINT + ".tabPane.child.tab" ); } public Tab getTab(){ return FlatTab.this; } public TabPaneComponent getChild(){ return FlatTab.this; } public TabPane getPane(){ return FlatTab.this.getTabParent(); } public Component getComponent(){ return FlatTab.this; } } }