package com.explodingpixels.widgets.plaf; import java.awt.Component; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.event.MouseListener; import javax.swing.AbstractButton; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JScrollBar; import com.explodingpixels.painter.MacWidgetsPainter; import com.explodingpixels.swingx.EPPanel; /** * A {@link ScrollBarSkin} with the buttons placed at the bottom or right of the scroll bar. */ public class ButtonsTogetherScrollBarSkin implements ScrollBarSkin { private JComponent fCap; private JComponent fThumbContainer = new JPanel(); private EPPanel fThumb = new EPPanel(); private EPPanel fTrack = new EPPanel(); private AbstractButton fDecrementButton; private AbstractButton fIncrementButton; private Dimension fMinimumThumbSize; private int fScrollBarCapRecess; private int fDecrementButtonTrackRecess; private final Dimension fPreferredSize; private static final Rectangle EMPTY_BOUNDS = new Rectangle(0, 0, 0, 0); /** * Creates a {@code ButtonsTogetherScrollBarSkin} using the given parameters. * * @param scrollBarCap the component to draw adjacent to the scroll tracks minimum value side. * @param decrementButton the button to cause a decrement in the scroll bar to occur. * @param incrementButton the button to cause a increment in the scroll bar to occur. * @param trackPainter the {@link com.explodingpixels.painter.MacWidgetsPainter} to use to paint the track. * @param scrollThumbPainter the {@link com.explodingpixels.painter.MacWidgetsPainter} to use to paint the scroll thumb. * @param scrollBarCapRecess the number of pixels to allow the scrollbar to "recess" into the * scroll bar cap. this is useful when using scroll bars with rounded ends. * @param decrementButtonRecess the number of pixels to allow the scrollbar to "recess" into the * decrement button. this is useful when using scroll bars with rounded ends. * @param minimumThumbSize the minimum size that the scroll thumb can be. * @param preferredSize the preferred size of this skin. */ public ButtonsTogetherScrollBarSkin( JComponent scrollBarCap, AbstractButton decrementButton, AbstractButton incrementButton, MacWidgetsPainter<Component> trackPainter, MacWidgetsPainter<Component> scrollThumbPainter, int scrollBarCapRecess, int decrementButtonRecess, Dimension minimumThumbSize, Dimension preferredSize) { fCap = scrollBarCap; fDecrementButton = decrementButton; fIncrementButton = incrementButton; fTrack.setBackgroundPainter(trackPainter); fThumb.setBackgroundPainter(scrollThumbPainter); fScrollBarCapRecess = scrollBarCapRecess; fDecrementButtonTrackRecess = decrementButtonRecess; fMinimumThumbSize = minimumThumbSize; fPreferredSize = preferredSize; fThumbContainer.setLayout(null); fThumbContainer.setOpaque(false); fThumb.setOpaque(false); // fThumbContainer.setBorder(BorderFactory.createLineBorder(Color.RED)); // fTrack.setBorder(BorderFactory.createLineBorder(Color.RED)); } // ScrollBarSkin implementation. ////////////////////////////////////////////////////////////// public Dimension getMinimumThumbSize() { return fMinimumThumbSize; } public Dimension getPreferredSize() { return fPreferredSize; } public Rectangle getScrollThumbBounds() { return fThumb.getBounds(); } public Rectangle getTrackBounds() { return fThumbContainer.getBounds(); } public void installComponents(JScrollBar scrollBar) { // add the components to the scrollbar. order matters here - components added first, are // drawn last (on top). scrollBar.add(fThumbContainer); scrollBar.add(fCap); scrollBar.add(fIncrementButton); scrollBar.add(fDecrementButton); scrollBar.add(fTrack); // add the actual scroller thumb (the component that will be painted) to the scroller thumb // container. fThumbContainer.add(fThumb); } public void layoutTrackOnly(JScrollBar scrollBar, ScrollBarOrientation orientation) { fCap.setBounds(EMPTY_BOUNDS); fIncrementButton.setBounds(EMPTY_BOUNDS); fDecrementButton.setBounds(EMPTY_BOUNDS); fThumbContainer.setBounds(EMPTY_BOUNDS); Rectangle r = scrollBar.getBounds(); fTrack.setBounds(0, 0, r.width, r.height); } public void layoutEverything(JScrollBar scrollBar, ScrollBarOrientation orientation) { // 1) layout the scroll bar cap. int capLength = orientation.getLength(fCap.getPreferredSize()); fCap.setBounds(orientation.createBounds(scrollBar, 0, capLength)); // 2) layout the scrollbar buttons. int incrementButtonHeight = orientation.getLength(fIncrementButton.getPreferredSize()); int decrementButtonHeight = orientation.getLength(fDecrementButton.getPreferredSize()); int scrollBarLength = orientation.getLength(scrollBar.getSize()); int incrementButtonPosition = scrollBarLength - incrementButtonHeight; int decrementButtonPosition = incrementButtonPosition - decrementButtonHeight; fIncrementButton.setBounds( orientation.createBounds(scrollBar, incrementButtonPosition, incrementButtonHeight)); fDecrementButton.setBounds( orientation.createBounds(scrollBar, decrementButtonPosition, decrementButtonHeight)); // 3) layout the track and the scroller thumb container. // start the track and the scroller bar container overlapping the top scroller cap, if a // top cap recess has been specified. this handles a top cap that isn't square and is // intended to receive part of the scroller thumb. int trackAndThumbPosition = capLength - fScrollBarCapRecess; // the height of the track and scroll bar container should be slightly greater than that of // the empty space between the top cap, and the decrement button, if recesses have been // specified. that is, the track and scroll bar container will overlap the top cap and // decrement buttons if a non-zero recess has been specified. int trackLength = decrementButtonPosition + fDecrementButtonTrackRecess - trackAndThumbPosition; Rectangle trackAndThumbBounds = orientation.createBounds(scrollBar, trackAndThumbPosition, trackLength); fTrack.setBounds(trackAndThumbBounds); fThumbContainer.setBounds(trackAndThumbBounds); } public void installMouseListenersOnButtons(MouseListener decrementMoustListener, MouseListener incrementMouseListener) { fDecrementButton.addMouseListener(decrementMoustListener); fIncrementButton.addMouseListener(incrementMouseListener); } public void setScrollThumbBounds(Rectangle bounds) { fThumb.setBounds(bounds); } }