0001: /*
0002: * Copyright (c) 2005-2008 Substance Kirill Grouchnikov. All Rights Reserved.
0003: *
0004: * Redistribution and use in source and binary forms, with or without
0005: * modification, are permitted provided that the following conditions are met:
0006: *
0007: * o Redistributions of source code must retain the above copyright notice,
0008: * this list of conditions and the following disclaimer.
0009: *
0010: * o Redistributions in binary form must reproduce the above copyright notice,
0011: * this list of conditions and the following disclaimer in the documentation
0012: * and/or other materials provided with the distribution.
0013: *
0014: * o Neither the name of Substance Kirill Grouchnikov nor the names of
0015: * its contributors may be used to endorse or promote products derived
0016: * from this software without specific prior written permission.
0017: *
0018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
0020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
0022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
0025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
0026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
0027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
0028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0029: */
0030: package org.jvnet.substance;
0031:
0032: import java.awt.*;
0033: import java.awt.event.*;
0034: import java.awt.geom.GeneralPath;
0035: import java.awt.image.BufferedImage;
0036: import java.beans.PropertyChangeEvent;
0037: import java.beans.PropertyChangeListener;
0038: import java.util.*;
0039:
0040: import javax.swing.*;
0041: import javax.swing.plaf.ComponentUI;
0042: import javax.swing.plaf.UIResource;
0043: import javax.swing.plaf.basic.BasicScrollBarUI;
0044:
0045: import org.jvnet.lafwidget.animation.*;
0046: import org.jvnet.lafwidget.layout.TransitionLayout;
0047: import org.jvnet.substance.border.SimplisticSoftBorderPainter;
0048: import org.jvnet.substance.border.SubstanceBorderPainter;
0049: import org.jvnet.substance.button.*;
0050: import org.jvnet.substance.color.ColorScheme;
0051: import org.jvnet.substance.painter.*;
0052: import org.jvnet.substance.scroll.SubstanceScrollBarButton;
0053: import org.jvnet.substance.theme.SubstanceTheme;
0054: import org.jvnet.substance.utils.*;
0055: import org.jvnet.substance.utils.ComponentState.ColorSchemeKind;
0056: import org.jvnet.substance.utils.SubstanceConstants.ScrollPaneButtonPolicyKind;
0057: import org.jvnet.substance.utils.SubstanceConstants.Side;
0058: import org.jvnet.substance.utils.icon.TransitionAwareIcon;
0059:
0060: /**
0061: * UI for scroll bars in <b>Substance </b> look and feel.
0062: *
0063: * @author Kirill Grouchnikov
0064: */
0065: public class SubstanceScrollBarUI extends BasicScrollBarUI implements
0066: Trackable {
0067: /**
0068: * The second decrease button. Is shown under
0069: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#ADJACENT},
0070: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#MULTIPLE} and
0071: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#MULTIPLE_BOTH}
0072: * modes.
0073: *
0074: * @since version 3.1
0075: */
0076: protected JButton mySecondDecreaseButton;
0077:
0078: /**
0079: * The second increase button. Is shown only under
0080: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#MULTIPLE_BOTH} mode.
0081: *
0082: * @since version 3.1
0083: */
0084: protected JButton mySecondIncreaseButton;
0085:
0086: /**
0087: * Surrogate button model for tracking the thumb transitions.
0088: */
0089: private ButtonModel thumbModel;
0090:
0091: /**
0092: * Stores computed images for vertical thumbs.
0093: */
0094: private static Map<String, BufferedImage> thumbVerticalMap = new SoftHashMap<String, BufferedImage>();
0095:
0096: /**
0097: * Stores computed images for horizontal thumbs.
0098: */
0099: private static Map<String, BufferedImage> thumbHorizontalMap = new SoftHashMap<String, BufferedImage>();
0100:
0101: /**
0102: * Stores computed images for full vertical tracks under
0103: * {@link DefaultControlBackgroundComposite}.
0104: */
0105: private static Map<String, BufferedImage> trackFullVerticalMap = new SoftHashMap<String, BufferedImage>();
0106:
0107: /**
0108: * Stores computed images for full horizontal tracks under
0109: * {@link DefaultControlBackgroundComposite}.
0110: */
0111: private static Map<String, BufferedImage> trackFullHorizontalMap = new SoftHashMap<String, BufferedImage>();
0112:
0113: /**
0114: * Stores computed images for full vertical thumbs under
0115: * {@link DefaultControlBackgroundComposite}.
0116: */
0117: private static Map<String, BufferedImage> thumbFullVerticalMap = new SoftHashMap<String, BufferedImage>();
0118:
0119: /**
0120: * Stores computed images for full horizontal thumbs under
0121: * {@link DefaultControlBackgroundComposite}.
0122: */
0123: private static Map<String, BufferedImage> thumbFullHorizontalMap = new SoftHashMap<String, BufferedImage>();
0124:
0125: /**
0126: * Mouse listener on the associated scroll bar.
0127: */
0128: private MouseListener substanceMouseListener;
0129:
0130: /**
0131: * Listener for thumb fade animations.
0132: */
0133: private RolloverControlListener substanceThumbRolloverListener;
0134:
0135: /**
0136: * Listener for fade animations.
0137: */
0138: protected FadeStateListener substanceFadeStateListener;
0139:
0140: /**
0141: * Property change listener. Listens to changes to the
0142: * {@link SubstanceLookAndFeel#THEME_PROPERTY} property.
0143: *
0144: */
0145: private PropertyChangeListener substancePropertyListener;
0146:
0147: /**
0148: * Scroll bar width.
0149: */
0150: protected int scrollBarWidth;
0151:
0152: /**
0153: * Cache of images for horizontal tracks.
0154: */
0155: private static Map<String, BufferedImage> trackHorizontalMap = new SoftHashMap<String, BufferedImage>();
0156:
0157: /**
0158: * Cache of images for vertical tracks.
0159: */
0160: private static Map<String, BufferedImage> trackVerticalMap = new SoftHashMap<String, BufferedImage>();
0161:
0162: /**
0163: * Listener for debui UI mode.
0164: */
0165: protected MouseListener substanceDebugUiListener;
0166:
0167: /**
0168: * Listener on adjustments made to the scrollbar model - this is for the
0169: * overlay mode (see {@link SubstanceLookAndFeel#OVERLAY_PROPERTY} and
0170: * repaiting both scrollbars with the viewport.
0171: *
0172: * @since version 3.2
0173: */
0174: protected AdjustmentListener substanceAdjustmentListener;
0175:
0176: /**
0177: * Surrogate model to sync between rollover effects of scroll buttons and
0178: * scroll track / scroll thumb.
0179: *
0180: * @since version 3.2
0181: */
0182: protected CompositeButtonModel compositeScrollTrackModel;
0183:
0184: /**
0185: * Surrogate model to sync between rollover effects of scroll buttons and
0186: * scroll track / scroll thumb.
0187: *
0188: * @since version 3.2
0189: */
0190: protected CompositeButtonModel compositeButtonsModel;
0191:
0192: /**
0193: * Resets image maps (used when setting new theme).
0194: *
0195: * @see SubstanceLookAndFeel#setCurrentTheme(String)
0196: * @see SubstanceLookAndFeel#setCurrentTheme(SubstanceTheme)
0197: */
0198: public static synchronized void reset() {
0199: thumbHorizontalMap.clear();
0200: thumbVerticalMap.clear();
0201: thumbFullHorizontalMap.clear();
0202: thumbFullVerticalMap.clear();
0203: trackFullHorizontalMap.clear();
0204: trackFullVerticalMap.clear();
0205: trackHorizontalMap.clear();
0206: trackVerticalMap.clear();
0207: }
0208:
0209: /*
0210: * (non-Javadoc)
0211: *
0212: * @see javax.swing.plaf.ComponentUI#createUI(javax.swing.JComponent)
0213: */
0214: public static ComponentUI createUI(JComponent b) {
0215: return new SubstanceScrollBarUI(b);
0216: }
0217:
0218: /**
0219: * Simple constructor.
0220: *
0221: * @param b
0222: * Associated component.
0223: */
0224: protected SubstanceScrollBarUI(JComponent b) {
0225: super ();
0226: this .thumbModel = new DefaultButtonModel();
0227: this .thumbModel.setArmed(false);
0228: this .thumbModel.setSelected(false);
0229: this .thumbModel.setPressed(false);
0230: this .thumbModel.setRollover(false);
0231:
0232: b.setOpaque(false);
0233: }
0234:
0235: /**
0236: * Creates a decrease button.
0237: *
0238: * @param orientation
0239: * Button orientation.
0240: * @param isRegular
0241: * if <code>true</code>, the regular (upper / left) decrease
0242: * button is created, if <code>false</code>, the additional
0243: * (lower / right) decrease button is created for
0244: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#ADJACENT},
0245: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#MULTIPLE}
0246: * and
0247: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#MULTIPLE_BOTH}
0248: * kinds.
0249: * @return Decrease button.
0250: */
0251: protected JButton createGeneralDecreaseButton(
0252: final int orientation, boolean isRegular) {
0253: JButton result = new SubstanceScrollBarButton(orientation);
0254: Icon icon = new TransitionAwareIcon(result,
0255: new TransitionAwareIcon.Delegate() {
0256: public Icon getThemeIcon(SubstanceTheme theme) {
0257: return SubstanceImageCreator
0258: .getArrowIcon(
0259: SubstanceSizeUtils
0260: .getComponentFontSize(scrollbar),
0261: orientation, theme);
0262: }
0263: });
0264: result.setIcon(icon);
0265: result.setFont(scrollbar.getFont());
0266:
0267: result.setPreferredSize(new Dimension(this .scrollBarWidth,
0268: this .scrollBarWidth));
0269:
0270: this .synchDecreaseButtonTheme(result, isRegular);
0271:
0272: Set<Side> openSides = new HashSet<Side>();
0273: Set<Side> straightSides = new HashSet<Side>();
0274: switch (orientation) {
0275: case NORTH:
0276: openSides.add(Side.BOTTOM);
0277: if (!isRegular)
0278: openSides.add(Side.TOP);
0279: if (isRegular)
0280: straightSides.add(Side.TOP);
0281: break;
0282: case EAST:
0283: openSides.add(Side.LEFT);
0284: if (!isRegular)
0285: openSides.add(Side.RIGHT);
0286: if (isRegular)
0287: straightSides.add(Side.RIGHT);
0288: break;
0289: case WEST:
0290: openSides.add(Side.RIGHT);
0291: if (!isRegular)
0292: openSides.add(Side.LEFT);
0293: if (isRegular)
0294: straightSides.add(Side.LEFT);
0295: break;
0296: }
0297: result.putClientProperty(
0298: SubstanceLookAndFeel.BUTTON_OPEN_SIDE_PROPERTY,
0299: openSides);
0300: result.putClientProperty(
0301: SubstanceLookAndFeel.BUTTON_SIDE_PROPERTY,
0302: straightSides);
0303:
0304: return result;
0305: }
0306:
0307: /*
0308: * (non-Javadoc)
0309: *
0310: * @see javax.swing.plaf.basic.BasicScrollBarUI#createDecreaseButton(int)
0311: */
0312: @Override
0313: protected JButton createDecreaseButton(int orientation) {
0314: return this .createGeneralDecreaseButton(orientation, true);
0315: }
0316:
0317: /**
0318: * Synchronizes the theme for the specified decrease button.
0319: *
0320: * @param button
0321: * Decrease button.
0322: * @param isRegular
0323: * if <code>true</code>, the regular (upper / left) decrease
0324: * button is synchronized, if <code>false</code>, the
0325: * additional (lower / right) decrease button is synchronized for
0326: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#ADJACENT},
0327: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#MULTIPLE}
0328: * and
0329: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#MULTIPLE_BOTH}
0330: * kinds.
0331: */
0332: private void synchDecreaseButtonTheme(JButton button,
0333: boolean isRegular) {
0334: SubstanceTheme theme = SubstanceThemeUtilities
0335: .getTheme(this .scrollbar);
0336:
0337: if (this .scrollbar.getOrientation() == JScrollBar.VERTICAL) {
0338: if (isRegular) {
0339: button.putClientProperty(
0340: SubstanceLookAndFeel.THEME_PROPERTY, theme
0341: .getSecondTheme());
0342: } else {
0343: button.putClientProperty(
0344: SubstanceLookAndFeel.THEME_PROPERTY, theme
0345: .getFirstTheme());
0346: }
0347: } else {
0348: if (this .scrollbar.getComponentOrientation()
0349: .isLeftToRight()) {
0350: if (isRegular) {
0351: button.putClientProperty(
0352: SubstanceLookAndFeel.THEME_PROPERTY, theme
0353: .getFirstTheme());
0354: } else {
0355: button.putClientProperty(
0356: SubstanceLookAndFeel.THEME_PROPERTY, theme
0357: .getSecondTheme());
0358: }
0359: } else {
0360: if (isRegular) {
0361: button.putClientProperty(
0362: SubstanceLookAndFeel.THEME_PROPERTY, theme
0363: .getSecondTheme());
0364: } else {
0365: button.putClientProperty(
0366: SubstanceLookAndFeel.THEME_PROPERTY, theme
0367: .getFirstTheme());
0368: }
0369: }
0370: }
0371: }
0372:
0373: /*
0374: * (non-Javadoc)
0375: *
0376: * @see javax.swing.plaf.basic.BasicScrollBarUI#createIncreaseButton(int)
0377: */
0378: @Override
0379: protected JButton createIncreaseButton(int orientation) {
0380: return this .createGeneralIncreaseButton(orientation, true);
0381: }
0382:
0383: /**
0384: * Creates a increase button.
0385: *
0386: * @param orientation
0387: * Button orientation.
0388: * @param isRegular
0389: * if <code>true</code>, the regular (lower / right) increase
0390: * button is created, if <code>false</code>, the additional
0391: * (upper / left) increase button is created for
0392: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#MULTIPLE_BOTH}
0393: * kind.
0394: * @return Increase button.
0395: */
0396: protected JButton createGeneralIncreaseButton(
0397: final int orientation, boolean isRegular) {
0398: JButton result = new SubstanceScrollBarButton(orientation);
0399: Icon icon = new TransitionAwareIcon(result,
0400: new TransitionAwareIcon.Delegate() {
0401: public Icon getThemeIcon(SubstanceTheme theme) {
0402: return SubstanceImageCreator
0403: .getArrowIcon(
0404: SubstanceSizeUtils
0405: .getComponentFontSize(scrollbar),
0406: orientation, theme);
0407: }
0408: });
0409: result.setIcon(icon);
0410: result.setFont(scrollbar.getFont());
0411: // JButton result = new SubstanceScrollBarButton(icon, orientation);
0412: result.setPreferredSize(new Dimension(this .scrollBarWidth,
0413: this .scrollBarWidth));
0414:
0415: this .synchIncreaseButtonTheme(result, isRegular);
0416:
0417: Set<Side> openSides = new HashSet<Side>();
0418: Set<Side> straightSides = new HashSet<Side>();
0419: switch (orientation) {
0420: case SOUTH:
0421: openSides.add(Side.TOP);
0422: if (!isRegular)
0423: openSides.add(Side.BOTTOM);
0424: if (isRegular)
0425: straightSides.add(Side.BOTTOM);
0426: break;
0427: case EAST:
0428: openSides.add(Side.LEFT);
0429: if (!isRegular)
0430: openSides.add(Side.RIGHT);
0431: if (isRegular)
0432: straightSides.add(Side.RIGHT);
0433: break;
0434: case WEST:
0435: openSides.add(Side.RIGHT);
0436: if (!isRegular)
0437: openSides.add(Side.LEFT);
0438: if (isRegular)
0439: straightSides.add(Side.LEFT);
0440: break;
0441: }
0442: result.putClientProperty(
0443: SubstanceLookAndFeel.BUTTON_OPEN_SIDE_PROPERTY,
0444: openSides);
0445: result.putClientProperty(
0446: SubstanceLookAndFeel.BUTTON_SIDE_PROPERTY,
0447: straightSides);
0448: return result;
0449: }
0450:
0451: /**
0452: * Synchronizes the theme for the specified increase button.
0453: *
0454: * @param button
0455: * Increase button.
0456: * @param isRegular
0457: * if <code>true</code>, the regular (lower / right) decrease
0458: * button is synchronized, if <code>false</code>, the
0459: * additional (upper / left) decrease button is synchronized for
0460: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#MULTIPLE_BOTH}
0461: * kind.
0462: */
0463: private void synchIncreaseButtonTheme(JButton button,
0464: boolean isRegular) {
0465: SubstanceTheme theme = SubstanceThemeUtilities
0466: .getTheme(this .scrollbar);
0467:
0468: if (this .scrollbar.getOrientation() == JScrollBar.VERTICAL) {
0469: if (isRegular)
0470: button.putClientProperty(
0471: SubstanceLookAndFeel.THEME_PROPERTY, theme
0472: .getFirstTheme());
0473: else
0474: button.putClientProperty(
0475: SubstanceLookAndFeel.THEME_PROPERTY, theme
0476: .getSecondTheme());
0477: } else {
0478: if (this .scrollbar.getComponentOrientation()
0479: .isLeftToRight()) {
0480: if (isRegular)
0481: button.putClientProperty(
0482: SubstanceLookAndFeel.THEME_PROPERTY, theme
0483: .getSecondTheme());
0484: else
0485: button.putClientProperty(
0486: SubstanceLookAndFeel.THEME_PROPERTY, theme
0487: .getFirstTheme());
0488: } else {
0489: if (isRegular)
0490: button.putClientProperty(
0491: SubstanceLookAndFeel.THEME_PROPERTY, theme
0492: .getFirstTheme());
0493: else
0494: button.putClientProperty(
0495: SubstanceLookAndFeel.THEME_PROPERTY, theme
0496: .getSecondTheme());
0497: }
0498: }
0499: }
0500:
0501: /**
0502: * Returns the image for a horizontal track.
0503: *
0504: * @param trackBounds
0505: * Track bounds.
0506: * @param leftActiveButton
0507: * The closest left button in the scroll bar. May be
0508: * <code>null</code>.
0509: * @param rightActiveButton
0510: * The closest right button in the scroll bar. May be
0511: * <code>null</code>.
0512: * @return Horizontal track image.
0513: */
0514: private BufferedImage getTrackHorizontal(Rectangle trackBounds,
0515: SubstanceScrollBarButton leftActiveButton,
0516: SubstanceScrollBarButton rightActiveButton) {
0517: ControlBackgroundComposite controlComposite = SubstanceCoreUtilities
0518: .getControlBackgroundComposite(this .scrollbar);
0519: boolean useCache = (controlComposite.getClass() == DefaultControlBackgroundComposite.class);
0520:
0521: int width = Math.max(1, trackBounds.width);
0522: int height = Math.max(1, trackBounds.height);
0523:
0524: ComponentState compLeftState = this .getState(leftActiveButton);
0525: ComponentState compRightState = this
0526: .getState(rightActiveButton);
0527:
0528: Component tracked = SubstanceFadeUtilities.getTracked(
0529: FadeKind.ROLLOVER, this .scrollbar, this .decrButton,
0530: this .incrButton, this .mySecondDecreaseButton,
0531: this .mySecondIncreaseButton);
0532: if (tracked != null) {
0533:
0534: ComponentState state = (tracked == this .scrollbar) ? ComponentState
0535: .getState(this .thumbModel, null)
0536: : ComponentState
0537: .getState(((AbstractButton) tracked)
0538: .getModel(), null);
0539:
0540: float cyclePos = state.getCycleCount();
0541: FadeState highest = SubstanceFadeUtilities
0542: .getFadeStateWithHighestFadeCycle(
0543: FadeKind.ROLLOVER, this .scrollbar,
0544: this .decrButton, this .incrButton,
0545: this .mySecondDecreaseButton,
0546: this .mySecondIncreaseButton);
0547: if (highest != null) {
0548: cyclePos = highest.getFadePosition();
0549: // if (!highest.isFadingIn())
0550: // cyclePos = 10.0f - cyclePos;
0551: }
0552:
0553: String key = null;
0554: if (useCache) {
0555: SubstanceButtonShaper shaper = SubstanceLookAndFeel
0556: .getCurrentButtonShaper();
0557: key = cyclePos
0558: + ":"
0559: + width
0560: + ":"
0561: + height
0562: + ":"
0563: + ((leftActiveButton == null) ? "null"
0564: : ComponentState.getState(
0565: leftActiveButton.getModel(),
0566: leftActiveButton).name())
0567: + ":"
0568: + ((leftActiveButton == null) ? "null"
0569: : SubstanceCoreUtilities
0570: .getPrevComponentState(
0571: leftActiveButton)
0572: .name())
0573: + ":"
0574: + ((rightActiveButton == null) ? "null"
0575: : ComponentState.getState(
0576: rightActiveButton.getModel(),
0577: rightActiveButton).name())
0578: + ":"
0579: + ((rightActiveButton == null) ? "null"
0580: : SubstanceCoreUtilities
0581: .getPrevComponentState(
0582: rightActiveButton)
0583: .name())
0584: + ":"
0585: + ((compLeftState == null) ? "null"
0586: : compLeftState.name())
0587: + ":"
0588: + ((compRightState == null) ? "null"
0589: : compRightState.name())
0590: + ":"
0591: + ((compLeftState == null) ? "null"
0592: : SubstanceThemeUtilities
0593: .getTheme(leftActiveButton,
0594: compLeftState)
0595: .getDisplayName())
0596: + ":"
0597: + ((compRightState == null) ? "null"
0598: : SubstanceThemeUtilities.getTheme(
0599: rightActiveButton,
0600: compRightState)
0601: .getDisplayName())
0602: + ":"
0603: + SubstanceThemeUtilities.getTheme(
0604: this .scrollbar).getDisplayName()
0605: + ":"
0606: + shaper.getDisplayName()
0607: + ":"
0608: + SubstanceSizeUtils
0609: .getBorderStrokeWidth(SubstanceSizeUtils
0610: .getComponentFontSize(scrollbar));
0611: // System.out.println(key);
0612: if (trackFullHorizontalMap.containsKey(key)) {
0613: // System.out.println("Cache hit");
0614: return trackFullHorizontalMap.get(key);
0615: }
0616: // System.out.println("Cache miss");
0617: }
0618:
0619: Composite defaultComposite = controlComposite
0620: .getBackgroundComposite(this .scrollbar,
0621: this .scrollbar.getParent(), -1, false);
0622: Composite activeComposite = controlComposite
0623: .getBackgroundComposite(this .scrollbar,
0624: this .scrollbar.getParent(), -1, true);
0625:
0626: BufferedImage imageBack = getTrackBackHorizontal(
0627: this .scrollbar, leftActiveButton,
0628: rightActiveButton, width, height);
0629: Graphics2D backGraphics = imageBack.createGraphics();
0630:
0631: BufferedImage imageDefault = getTrackHorizontal(
0632: this .scrollbar, compLeftState, compRightState,
0633: width, height, defaultComposite);
0634:
0635: // Use DstOut to subtract the scroll track from the scroll
0636: // background - this removes the colored part of the scroll
0637: // background from the track but leaves it on the button ears.
0638: BufferedImage scrollTrackImageOut = getTrackHorizontal(
0639: this .scrollbar, compLeftState, compRightState,
0640: width, height, AlphaComposite.SrcOver);
0641: backGraphics.setComposite(AlphaComposite.DstOut);
0642: backGraphics.drawImage(scrollTrackImageOut, 0, 0, null);
0643:
0644: backGraphics.setComposite(AlphaComposite.SrcOver);
0645: backGraphics.drawImage(imageDefault, 0, 0, null);
0646: BufferedImage imageActive = getTrackHorizontal(
0647: this .scrollbar, compLeftState, compRightState,
0648: width, height, activeComposite);
0649: backGraphics.setComposite(AlphaComposite.getInstance(
0650: AlphaComposite.SRC_OVER, cyclePos / 10.0f));
0651: // System.out.println("Painting " + cyclePos / 10.0f);
0652: backGraphics.drawImage(imageActive, 0, 0, null);
0653:
0654: if (useCache) {
0655: // System.out.println("Cache update");
0656: trackFullHorizontalMap.put(key, imageBack);
0657: }
0658: return imageBack;
0659: }
0660:
0661: String key = null;
0662: if (useCache) {
0663: SubstanceButtonShaper shaper = SubstanceLookAndFeel
0664: .getCurrentButtonShaper();
0665: key = width
0666: + ":"
0667: + height
0668: + ":"
0669: + ((compLeftState == null) ? "null"
0670: : ComponentState.getState(
0671: leftActiveButton.getModel(),
0672: leftActiveButton).name())
0673: + ":"
0674: + ((compLeftState == null) ? "null"
0675: : SubstanceCoreUtilities
0676: .getPrevComponentState(
0677: leftActiveButton).name())
0678: + ":"
0679: + ((compRightState == null) ? "null"
0680: : ComponentState.getState(
0681: rightActiveButton.getModel(),
0682: rightActiveButton).name())
0683: + ":"
0684: + ((compRightState == null) ? "null"
0685: : SubstanceCoreUtilities
0686: .getPrevComponentState(
0687: rightActiveButton).name())
0688: + ":"
0689: + ((compLeftState == null) ? "null" : compLeftState
0690: .name())
0691: + ":"
0692: + ((compRightState == null) ? "null"
0693: : compRightState.name())
0694: + ":"
0695: + ((compLeftState == null) ? "null"
0696: : SubstanceThemeUtilities.getTheme(
0697: leftActiveButton, compLeftState)
0698: .getDisplayName())
0699: + ":"
0700: + ((compRightState == null) ? "null"
0701: : SubstanceThemeUtilities.getTheme(
0702: rightActiveButton, compRightState)
0703: .getDisplayName())
0704: + ":"
0705: + SubstanceThemeUtilities.getTheme(this .scrollbar)
0706: .getDisplayName()
0707: + ":"
0708: + shaper.getDisplayName()
0709: + ":"
0710: + SubstanceSizeUtils
0711: .getBorderStrokeWidth(SubstanceSizeUtils
0712: .getComponentFontSize(scrollbar));
0713:
0714: // System.out.println(key);
0715: if (trackFullHorizontalMap.containsKey(key)) {
0716: // System.out.println("Cache hit");
0717: return trackFullHorizontalMap.get(key);
0718: }
0719: // System.out.println("Cache miss");
0720: }
0721:
0722: Composite graphicsComposite = controlComposite
0723: .getBackgroundComposite(
0724: this .scrollbar,
0725: this .scrollbar.getParent(),
0726: 0,
0727: ComponentState.getState(
0728: this .compositeScrollTrackModel, null)
0729: .getColorSchemeKind() == ColorSchemeKind.CURRENT);
0730:
0731: BufferedImage trackBack = getTrackBackHorizontal(
0732: this .scrollbar, leftActiveButton, rightActiveButton,
0733: width, height);
0734: Graphics2D backGraphics = trackBack.createGraphics();
0735:
0736: // Use DstOut to subtract the scroll track from the scroll background -
0737: // this removes the colored part of the scroll background from
0738: // the track but leaves it on the button ears.
0739: BufferedImage scrollTrackImageOut = getTrackHorizontal(
0740: this .scrollbar, compLeftState, compRightState, width,
0741: height, AlphaComposite.SrcOver);
0742: backGraphics.setComposite(AlphaComposite.DstOut);
0743: backGraphics.drawImage(scrollTrackImageOut, 0, 0, null);
0744:
0745: BufferedImage scrollTrackImage = getTrackHorizontal(
0746: this .scrollbar, compLeftState, compRightState, width,
0747: height, graphicsComposite);
0748: backGraphics.setComposite(AlphaComposite.SrcOver);
0749: backGraphics.drawImage(scrollTrackImage, 0, 0, null);
0750: backGraphics.dispose();
0751:
0752: if (useCache) {
0753: // System.out.println("Cache update");
0754: trackFullHorizontalMap.put(key, trackBack);
0755: }
0756: return trackBack;
0757: }
0758:
0759: /**
0760: * Returns the image for a horizontal track.
0761: *
0762: * @param scrollBar
0763: * Scroll bar.
0764: * @param trackBounds
0765: * Track bounds.
0766: * @param compLeftState
0767: * The state of the left button in the scroll bar.
0768: * @param compRightState
0769: * The state of the closest right button in the scroll bar.
0770: * @param width
0771: * Scroll track width.
0772: * @param height
0773: * Scroll track height.
0774: * @param graphicsComposite
0775: * Composite to apply before painting the track.
0776: * @return Horizontal track image.
0777: */
0778: private static synchronized BufferedImage getTrackHorizontal(
0779: JScrollBar scrollBar, ComponentState compLeftState,
0780: ComponentState compRightState, int width, int height,
0781: Composite graphicsComposite) {
0782: SubstanceButtonShaper shaper = SubstanceLookAndFeel
0783: .getCurrentButtonShaper();
0784: String key = SubstanceThemeUtilities.getTheme(scrollBar)
0785: .getDisplayName()
0786: + ":"
0787: + width
0788: + "*"
0789: + height
0790: + ":"
0791: + ((compLeftState == null) ? "null" : compLeftState
0792: .name())
0793: + ":"
0794: + ((compRightState == null) ? "null" : compRightState
0795: .name()) + ":" + shaper.getDisplayName();
0796: float radius = height / 2;
0797: if (shaper instanceof ClassicButtonShaper)
0798: radius = SubstanceSizeUtils
0799: .getClassicButtonCornerRadius(SubstanceSizeUtils
0800: .getComponentFontSize(scrollBar));
0801:
0802: int borderDelta = (int) Math.floor(SubstanceSizeUtils
0803: .getBorderStrokeWidth(SubstanceSizeUtils
0804: .getComponentFontSize(scrollBar)) / 2.0);
0805: Shape contour = BaseButtonShaper.getBaseOutline(width, height,
0806: radius, null, borderDelta);
0807: ColorScheme mainScheme = SubstanceThemeUtilities.getTheme(
0808: scrollBar,
0809: scrollBar.isEnabled() ? ComponentState.DEFAULT
0810: : ComponentState.DISABLED_UNSELECTED)
0811: .getBorderTheme().getColorScheme();
0812: // scrollBar.isEnabled() ? SubstanceCoreUtilities
0813: // .getDefaultTheme(scrollBar, true, true).getBorderTheme()
0814: // .getColorScheme() : SubstanceCoreUtilities.getDisabledTheme(
0815: // scrollBar, true).getBorderTheme().getColorScheme();
0816: BufferedImage opaque = SubstanceScrollBarUI.trackHorizontalMap
0817: .get(key);
0818: if (opaque == null) {
0819: opaque = new SimplisticGradientPainter()
0820: .getContourBackground(width, height, contour,
0821: false, mainScheme, mainScheme, 0, true,
0822: false);
0823: SubstanceScrollBarUI.trackHorizontalMap.put(key, opaque);
0824: }
0825:
0826: BufferedImage result = SubstanceCoreUtilities.getBlankImage(
0827: opaque.getWidth(), opaque.getHeight());
0828: Graphics2D resultGr = result.createGraphics();
0829: resultGr.setComposite(graphicsComposite);
0830: resultGr.drawImage(opaque, 0, 0, null);
0831:
0832: SubstanceBorderPainter borderPainter = new SimplisticSoftBorderPainter();
0833: borderPainter.paintBorder(resultGr, scrollBar, width, height,
0834: contour, null, mainScheme, mainScheme, 0, false);
0835:
0836: resultGr.dispose();
0837: return result;
0838: }
0839:
0840: /**
0841: * Returns the image for a horizontal track.
0842: *
0843: * @param scrollBar
0844: * Scroll bar.
0845: * @param trackBounds
0846: * Track bounds.
0847: * @param leftActiveButton
0848: * The closest left button in the scroll bar. May be
0849: * <code>null</code>.
0850: * @param rightActiveButton
0851: * The closest right button in the scroll bar. May be
0852: * <code>null</code>.
0853: * @param width
0854: * Scroll track width.
0855: * @param height
0856: * Scroll track height.
0857: * @param graphicsComposite
0858: * Composite to apply before painting the track.
0859: * @return Horizontal track image.
0860: */
0861: private static synchronized BufferedImage getTrackBackHorizontal(
0862: JScrollBar scrollBar, AbstractButton leftActiveButton,
0863: AbstractButton rightActiveButton, int width, int height) {
0864: SubstanceButtonShaper shaper = SubstanceLookAndFeel
0865: .getCurrentButtonShaper();
0866: int radius = height / 2;
0867: if (shaper instanceof ClassicButtonShaper)
0868: radius = 2;
0869: BufferedImage opaque = SubstanceImageCreator
0870: .getCompositeRoundedBackground(scrollBar, width,
0871: height, radius, leftActiveButton,
0872: rightActiveButton, false);
0873: return opaque;
0874: }
0875:
0876: /**
0877: * Returns the image for a vertical track.
0878: *
0879: * @param trackBounds
0880: * Track bounds.
0881: * @param scrollBar
0882: * Scroll bar.
0883: * @param topActiveButton
0884: * The closest top button in the scroll bar. May be
0885: * <code>null</code>.
0886: * @param bottomActiveButton
0887: * The closest bottom button in the scroll bar. May be
0888: * <code>null</code>.
0889: * @return Vertical track image.
0890: */
0891: private BufferedImage getTrackVertical(Rectangle trackBounds,
0892: SubstanceScrollBarButton topActiveButton,
0893: SubstanceScrollBarButton bottomActiveButton) {
0894: ControlBackgroundComposite controlComposite = SubstanceCoreUtilities
0895: .getControlBackgroundComposite(this .scrollbar);
0896: boolean useCache = (controlComposite.getClass() == DefaultControlBackgroundComposite.class);
0897: // System.out.println(controlComposite.getClass() + "->" + useCache);
0898:
0899: int width = Math.max(1, trackBounds.width);
0900: int height = Math.max(1, trackBounds.height);
0901:
0902: ComponentState compTopState = this .getState(topActiveButton);
0903: ComponentState compBottomState = this
0904: .getState(bottomActiveButton);
0905:
0906: Component tracked = SubstanceFadeUtilities.getTracked(
0907: FadeKind.ROLLOVER, this .scrollbar, this .decrButton,
0908: this .incrButton, this .mySecondDecreaseButton,
0909: this .mySecondIncreaseButton);
0910:
0911: if (tracked != null) {
0912: Composite defaultComposite = controlComposite
0913: .getBackgroundComposite(this .scrollbar,
0914: this .scrollbar.getParent(), -1, false);
0915: Composite activeComposite = controlComposite
0916: .getBackgroundComposite(this .scrollbar,
0917: this .scrollbar.getParent(), -1, true);
0918: ComponentState state = (tracked == this .scrollbar) ? ComponentState
0919: .getState(this .thumbModel, null)
0920: : ComponentState
0921: .getState(((AbstractButton) tracked)
0922: .getModel(), null);
0923:
0924: float cyclePos = state.getCycleCount();
0925: FadeState highest = SubstanceFadeUtilities
0926: .getFadeStateWithHighestFadeCycle(
0927: FadeKind.ROLLOVER, this .scrollbar,
0928: this .decrButton, this .incrButton,
0929: this .mySecondDecreaseButton,
0930: this .mySecondIncreaseButton);
0931: if (highest != null) {
0932: cyclePos = highest.getFadePosition();
0933: // if (!highest.isFadingIn())
0934: // cyclePos = 10.0f - cyclePos;
0935: }
0936:
0937: String key = null;
0938: if (useCache) {
0939: SubstanceButtonShaper shaper = SubstanceLookAndFeel
0940: .getCurrentButtonShaper();
0941: key = cyclePos
0942: + ":"
0943: + width
0944: + ":"
0945: + height
0946: + ":"
0947: + ((topActiveButton == null) ? "null"
0948: : ComponentState.getState(
0949: topActiveButton.getModel(),
0950: topActiveButton).name())
0951: + ":"
0952: + ((topActiveButton == null) ? "null"
0953: : SubstanceCoreUtilities
0954: .getPrevComponentState(
0955: topActiveButton).name())
0956: + ":"
0957: + ((bottomActiveButton == null) ? "null"
0958: : ComponentState.getState(
0959: bottomActiveButton.getModel(),
0960: bottomActiveButton).name())
0961: + ":"
0962: + ((bottomActiveButton == null) ? "null"
0963: : SubstanceCoreUtilities
0964: .getPrevComponentState(
0965: bottomActiveButton)
0966: .name())
0967: + ":"
0968: + ((compTopState == null) ? "null"
0969: : compTopState.name())
0970: + ":"
0971: + ((compBottomState == null) ? "null"
0972: : compBottomState.name())
0973: + ":"
0974: + ((compBottomState == null) ? "null"
0975: : SubstanceThemeUtilities.getTheme(
0976: bottomActiveButton,
0977: compBottomState)
0978: .getDisplayName())
0979: + ":"
0980: + ((compTopState == null) ? "null"
0981: : SubstanceThemeUtilities.getTheme(
0982: topActiveButton, compTopState)
0983: .getDisplayName())
0984: + ":"
0985: + SubstanceThemeUtilities.getTheme(
0986: this .scrollbar).getDisplayName()
0987: + ":"
0988: + shaper.getDisplayName()
0989: + ":"
0990: + SubstanceSizeUtils
0991: .getBorderStrokeWidth(SubstanceSizeUtils
0992: .getComponentFontSize(scrollbar));
0993:
0994: // System.out.println(key);
0995: if (trackFullVerticalMap.containsKey(key)) {
0996: // System.out.println("Cache hit");
0997: return trackFullVerticalMap.get(key);
0998: }
0999: // System.out.println("Cache miss");
1000: }
1001:
1002: BufferedImage imageBack = getTrackBackVertical(
1003: this .scrollbar, topActiveButton,
1004: bottomActiveButton, width, height);
1005: Graphics2D backGraphics = imageBack.createGraphics();
1006:
1007: // Use DstOut to subtract the scroll track from the scroll
1008: // background - this removes the colored part of the scroll
1009: // background from the track but leaves it on the button ears.
1010: BufferedImage scrollTrackImageOut = getTrackVertical(
1011: this .scrollbar, compTopState, compBottomState,
1012: width, height, AlphaComposite.SrcOver);
1013: backGraphics.setComposite(AlphaComposite.DstOut);
1014: backGraphics.drawImage(scrollTrackImageOut, 0, 0, null);
1015:
1016: backGraphics.setComposite(AlphaComposite.SrcOver);
1017: BufferedImage imageDefault = getTrackVertical(
1018: this .scrollbar, compTopState, compBottomState,
1019: width, height, defaultComposite);
1020: backGraphics.drawImage(imageDefault, 0, 0, null);
1021: BufferedImage imageActive = getTrackVertical(
1022: this .scrollbar, compTopState, compBottomState,
1023: width, height, activeComposite);
1024: backGraphics.setComposite(AlphaComposite.getInstance(
1025: AlphaComposite.SRC_OVER, cyclePos / 10.0f));
1026: // System.out.println("Painting " + cyclePos / 10.0f);
1027: backGraphics.drawImage(imageActive, 0, 0, null);
1028:
1029: if (useCache) {
1030: // System.out.println("Cache update");
1031: trackFullVerticalMap.put(key, imageBack);
1032: }
1033: return imageBack;
1034: }
1035:
1036: String key = null;
1037: if (useCache) {
1038: SubstanceButtonShaper shaper = SubstanceLookAndFeel
1039: .getCurrentButtonShaper();
1040: key = width
1041: + ":"
1042: + height
1043: + ":"
1044: + ((compTopState == null) ? "null" : ComponentState
1045: .getState(topActiveButton.getModel(),
1046: topActiveButton).name())
1047: + ":"
1048: + ((compTopState == null) ? "null"
1049: : SubstanceCoreUtilities
1050: .getPrevComponentState(
1051: topActiveButton).name())
1052: + ":"
1053: + ((compBottomState == null) ? "null"
1054: : ComponentState.getState(
1055: bottomActiveButton.getModel(),
1056: bottomActiveButton).name())
1057: + ":"
1058: + ((compBottomState == null) ? "null"
1059: : SubstanceCoreUtilities
1060: .getPrevComponentState(
1061: bottomActiveButton).name())
1062: + ":"
1063: + ((compTopState == null) ? "null" : compTopState
1064: .name())
1065: + ":"
1066: + ((compBottomState == null) ? "null"
1067: : compBottomState.name())
1068: + ":"
1069: + ((compBottomState == null) ? "null"
1070: : SubstanceThemeUtilities
1071: .getTheme(bottomActiveButton,
1072: compBottomState)
1073: .getDisplayName())
1074: + ":"
1075: + ((compTopState == null) ? "null"
1076: : SubstanceThemeUtilities.getTheme(
1077: topActiveButton, compTopState)
1078: .getDisplayName())
1079: + ":"
1080: + SubstanceThemeUtilities.getTheme(this .scrollbar)
1081: .getDisplayName()
1082: + ":"
1083: + shaper.getDisplayName()
1084: + ":"
1085: + SubstanceSizeUtils
1086: .getBorderStrokeWidth(SubstanceSizeUtils
1087: .getComponentFontSize(scrollbar));
1088: if (trackFullVerticalMap.containsKey(key)) {
1089: // System.out.println("Cache hit");
1090: return trackFullVerticalMap.get(key);
1091: }
1092: // System.out.println("Cache miss");
1093: }
1094:
1095: Composite graphicsComposite = controlComposite
1096: .getBackgroundComposite(
1097: this .scrollbar,
1098: this .scrollbar.getParent(),
1099: 0,
1100: ComponentState.getState(
1101: this .compositeScrollTrackModel, null)
1102: .getColorSchemeKind() == ColorSchemeKind.CURRENT);
1103: BufferedImage trackBack = getTrackBackVertical(this .scrollbar,
1104: topActiveButton, bottomActiveButton, width, height);
1105: Graphics2D backGraphics = trackBack.createGraphics();
1106:
1107: // Use DstOut to subtract the scroll track from the scroll background -
1108: // this removes the colored part of the scroll background from
1109: // the track but leaves it on the button ears.
1110: BufferedImage scrollTrackImageOut = getTrackVertical(
1111: this .scrollbar, compTopState, compBottomState, width,
1112: height, AlphaComposite.SrcOver);
1113: backGraphics.setComposite(AlphaComposite.DstOut);
1114: backGraphics.drawImage(scrollTrackImageOut, 0, 0, null);
1115:
1116: BufferedImage scrollTrackImage = getTrackVertical(
1117: this .scrollbar, compTopState, compBottomState, width,
1118: height, graphicsComposite);
1119: backGraphics.setComposite(AlphaComposite.SrcOver);
1120: backGraphics.drawImage(scrollTrackImage, 0, 0, null);
1121: backGraphics.dispose();
1122:
1123: if (useCache) {
1124: trackFullVerticalMap.put(key, trackBack);
1125: // System.out.println("Cache update");
1126: }
1127: return trackBack;
1128: }
1129:
1130: /**
1131: * Returns the image for a vertical track.
1132: *
1133: * @param trackBounds
1134: * Track bounds.
1135: * @param scrollBar
1136: * Scroll bar.
1137: * @param compTopState
1138: * The state of the top button in the scroll bar.
1139: * @param compBottomState
1140: * The state of the closest bottom button in the scroll bar.
1141: * @param width
1142: * Scroll track width.
1143: * @param height
1144: * Scroll track height.
1145: * @param graphicsComposite
1146: * Composite to apply before painting the track.
1147: * @return Vertical track image.
1148: */
1149: private static synchronized BufferedImage getTrackVertical(
1150: JScrollBar scrollBar, ComponentState compTopState,
1151: ComponentState compBottomState, int width, int height,
1152: Composite graphicsComposite) {
1153: SubstanceButtonShaper shaper = SubstanceLookAndFeel
1154: .getCurrentButtonShaper();
1155: String key = SubstanceThemeUtilities.getTheme(scrollBar)
1156: .getDisplayName()
1157: + ":"
1158: + width
1159: + "*"
1160: + height
1161: + ":"
1162: + ((compTopState == null) ? "null" : compTopState
1163: .name())
1164: + ":"
1165: + ((compBottomState == null) ? "null" : compBottomState
1166: .name()) + ":" + shaper.getDisplayName();
1167: BufferedImage opaque = SubstanceScrollBarUI.trackVerticalMap
1168: .get(key);
1169: if (opaque == null) {
1170: float radius = width / 2;
1171: if (shaper instanceof ClassicButtonShaper)
1172: radius = SubstanceSizeUtils
1173: .getClassicButtonCornerRadius(SubstanceSizeUtils
1174: .getComponentFontSize(scrollBar));
1175:
1176: ColorScheme mainScheme = SubstanceThemeUtilities.getTheme(
1177: scrollBar,
1178: scrollBar.isEnabled() ? ComponentState.DEFAULT
1179: : ComponentState.DISABLED_UNSELECTED)
1180: .getBorderTheme().getColorScheme();
1181: // ColorScheme mainScheme = scrollBar.isEnabled() ?
1182: // SubstanceCoreUtilities
1183: // .getDefaultTheme(scrollBar, true, true).getBorderTheme()
1184: // .getColorScheme()
1185: // : SubstanceCoreUtilities.getDisabledTheme(scrollBar, true)
1186: // .getBorderTheme().getColorScheme();
1187:
1188: int borderDelta = (int) Math.floor(SubstanceSizeUtils
1189: .getBorderStrokeWidth(SubstanceSizeUtils
1190: .getComponentFontSize(scrollBar)) / 2.0);
1191: Shape contour = BaseButtonShaper.getBaseOutline(height,
1192: width, radius, null, borderDelta);
1193:
1194: opaque = new SimplisticGradientPainter()
1195: .getContourBackground(height, width, contour,
1196: false, mainScheme, mainScheme, 0, true,
1197: false);
1198: SubstanceBorderPainter borderPainter = new SimplisticSoftBorderPainter();
1199: borderPainter.paintBorder(opaque.getGraphics(), scrollBar,
1200: height, width, contour, null, mainScheme,
1201: mainScheme, 0, false);
1202: opaque = SubstanceImageCreator.getRotated(opaque, 3);
1203:
1204: SubstanceScrollBarUI.trackVerticalMap.put(key, opaque);
1205: }
1206:
1207: BufferedImage result = SubstanceCoreUtilities.getBlankImage(
1208: opaque.getWidth(), opaque.getHeight());
1209: Graphics2D resultGr = result.createGraphics();
1210: resultGr.setComposite(graphicsComposite);
1211: resultGr.drawImage(opaque, 0, 0, null);
1212:
1213: resultGr.dispose();
1214: return result;
1215: }
1216:
1217: /**
1218: * Returns the image for a vertical track.
1219: *
1220: * @param trackBounds
1221: * Track bounds.
1222: * @param scrollBar
1223: * Scroll bar.
1224: * @param topActiveButton
1225: * The closest top button in the scroll bar. May be
1226: * <code>null</code>.
1227: * @param bottomActiveButton
1228: * The closest bottom button in the scroll bar. May be
1229: * <code>null</code>.
1230: * @param width
1231: * Scroll track width.
1232: * @param height
1233: * Scroll track height.
1234: * @param graphicsComposite
1235: * Composite to apply before painting the track.
1236: * @return Vertical track image.
1237: */
1238: private static synchronized BufferedImage getTrackBackVertical(
1239: JScrollBar scrollBar, AbstractButton topActiveButton,
1240: AbstractButton bottomActiveButton, int width, int height) {
1241: SubstanceButtonShaper shaper = SubstanceLookAndFeel
1242: .getCurrentButtonShaper();
1243: int radius = width / 2;
1244: if (shaper instanceof ClassicButtonShaper)
1245: radius = 2;
1246: BufferedImage opaque = SubstanceImageCreator.getRotated(
1247: SubstanceImageCreator.getCompositeRoundedBackground(
1248: scrollBar, height, width, radius,
1249: topActiveButton, bottomActiveButton, true), 3);
1250:
1251: return opaque;
1252: }
1253:
1254: /**
1255: * Retrieves image for vertical thumb.
1256: *
1257: * @param thumbBounds
1258: * Thumb bounding rectangle.
1259: * @return Image for vertical thumb.
1260: */
1261: private BufferedImage getThumbVertical(Rectangle thumbBounds) {
1262: int width = Math.max(1, thumbBounds.width);
1263: int height = Math.max(1, thumbBounds.height);
1264:
1265: ControlBackgroundComposite controlComposite = SubstanceCoreUtilities
1266: .getControlBackgroundComposite(this .scrollbar);
1267: // System.out.println(ComponentState.getState(buttonModel, null)
1268: // .getColorSchemeKind().name());
1269:
1270: Component tracked = SubstanceFadeUtilities.getTracked(
1271: FadeKind.ROLLOVER, this .scrollbar, this .decrButton,
1272: this .incrButton, this .mySecondDecreaseButton,
1273: this .mySecondIncreaseButton);
1274: ComponentState state = ComponentState.getState(
1275: this .compositeScrollTrackModel, null);
1276: if (state.isKindActive(FadeKind.PRESS))
1277: tracked = null;
1278:
1279: if (tracked != null) {
1280: Composite defaultComposite = controlComposite
1281: .getBackgroundComposite(this .scrollbar,
1282: this .scrollbar.getParent(), -1, false);
1283: Composite activeComposite = controlComposite
1284: .getBackgroundComposite(this .scrollbar,
1285: this .scrollbar.getParent(), -1, true);
1286:
1287: ComponentState trackedState = (tracked == this .scrollbar) ? ComponentState
1288: .getState(this .thumbModel, null)
1289: : ComponentState
1290: .getState(((AbstractButton) tracked)
1291: .getModel(), null);
1292: ComponentState prevState = SubstanceCoreUtilities
1293: .getPrevComponentState(this .scrollbar);
1294: // enhancement 206 - support for non-active painted scrollbars
1295: // when they are in default state
1296: if (!SubstanceCoreUtilities.hasPropertySetTo(
1297: this .scrollbar,
1298: SubstanceLookAndFeel.PAINT_ACTIVE_PROPERTY, false,
1299: true)) {
1300: if (trackedState == ComponentState.DEFAULT)
1301: trackedState = ComponentState.ACTIVE;
1302: if (prevState == ComponentState.DEFAULT)
1303: prevState = ComponentState.ACTIVE;
1304: }
1305:
1306: float cyclePos = trackedState.getCycleCount();
1307: FadeState highest = SubstanceFadeUtilities
1308: .getFadeStateWithHighestFadeCycle(
1309: FadeKind.ROLLOVER, this .scrollbar,
1310: this .decrButton, this .incrButton,
1311: this .mySecondDecreaseButton,
1312: this .mySecondIncreaseButton);
1313: if (highest != null) {
1314: cyclePos = highest.getFadePosition();
1315: // if (!highest.isFadingIn())
1316: // cyclePos = 10.0f - cyclePos;
1317: }
1318: // if (state == ComponentState.DEFAULT) {
1319: // // Came from rollover state
1320: // // colorScheme = activeScheme;
1321: // // colorScheme2 = activeScheme;
1322: // cyclePos =
1323: // SubstanceFadeUtilities.getFadeStateWithHighestFadeCycle(FadeKind.ROLLOVER,
1324: // this.scrollbar, this.decrButton, this.incrButton,
1325: // this.mySecondDecreaseButton,
1326: // this.mySecondIncreaseButton);
1327: // }
1328: // if (state == ComponentState.ROLLOVER_UNSELECTED) {
1329: // // Came from default state
1330: // // colorScheme2 = activeScheme;
1331: // // colorScheme = activeScheme;
1332: // cyclePos =
1333: // SubstanceFadeUtilities.getFadeStateWithHighestFadeCycle(FadeKind.ROLLOVER,
1334: // this.scrollbar, this.decrButton, this.incrButton,
1335: // this.mySecondDecreaseButton,
1336: // this.mySecondIncreaseButton);
1337: // }
1338:
1339: SubstanceTheme theme2 = SubstanceThemeUtilities.getTheme(
1340: this .scrollbar, trackedState);
1341: SubstanceTheme theme1 = SubstanceThemeUtilities.getTheme(
1342: this .scrollbar, prevState);
1343: BufferedImage imageActive = getThumbVertical(
1344: this .scrollbar, width, height, 0, theme1, theme1,
1345: controlComposite, defaultComposite);
1346: BufferedImage imageRollover = getThumbVertical(
1347: this .scrollbar, width, height, 0, theme2, theme2,
1348: controlComposite, activeComposite);
1349:
1350: Graphics2D graphics = imageActive.createGraphics();
1351: graphics.setComposite(AlphaComposite.getInstance(
1352: AlphaComposite.SRC_OVER, cyclePos / 10.0f));
1353: // System.out.println("Painting " + cyclePos / 10.0f);
1354: graphics.drawImage(imageRollover, 0, 0, null);
1355: return imageActive;
1356: }
1357:
1358: ComponentState prevState = SubstanceCoreUtilities
1359: .getPrevComponentState(this .scrollbar);
1360: ComponentState.ColorSchemeKind kind = state
1361: .getColorSchemeKind();
1362: // SubstanceTheme scrollBarTheme = SubstanceCoreUtilities.getTheme(
1363: // scrollBar, true);
1364: // if (scrollBarTheme.toPaintActive(scrollBar))
1365: if (kind == ColorSchemeKind.REGULAR)
1366: kind = ColorSchemeKind.CURRENT;
1367: float cyclePos = state.getCycleCount();
1368:
1369: Composite graphicsComposite = controlComposite
1370: .getBackgroundComposite(
1371: this .scrollbar,
1372: this .scrollbar.getParent(),
1373: 0,
1374: ComponentState.getState(
1375: this .compositeScrollTrackModel, null)
1376: .getColorSchemeKind() == ColorSchemeKind.CURRENT);
1377: // enhancement 206 - see comments inside after the condition check
1378: if (!SubstanceCoreUtilities
1379: .hasPropertySetTo(this .scrollbar,
1380: SubstanceLookAndFeel.PAINT_ACTIVE_PROPERTY,
1381: false, true)) {
1382: // unless the SubstanceLookAndFeel.PAINT_ACTIVE_PROPERTY
1383: // is explicitly set to Boolean.FALSE, the scrollbar is painted
1384: // as active when it's in the default state.
1385: if (state == ComponentState.DEFAULT)
1386: state = ComponentState.ACTIVE;
1387: if (prevState == ComponentState.DEFAULT)
1388: prevState = ComponentState.ACTIVE;
1389: }
1390: SubstanceTheme colorTheme = SubstanceThemeUtilities.getTheme(
1391: this .scrollbar, state);
1392: SubstanceTheme colorTheme2 = colorTheme;
1393: FadeTracker fadeTracker = FadeTracker.getInstance();
1394: FadeState fadeState = fadeTracker.getFadeState(this .scrollbar,
1395: FadeKind.PRESS);
1396: if (fadeState != null) {
1397: colorTheme2 = SubstanceThemeUtilities.getTheme(
1398: this .scrollbar, prevState);
1399: cyclePos = fadeState.getFadePosition();
1400: if (fadeState.isFadingIn()) {
1401: cyclePos = 10.0f - cyclePos;
1402: }
1403: }
1404: return getThumbVertical(this .scrollbar, width, height,
1405: cyclePos, colorTheme, colorTheme2, controlComposite,
1406: graphicsComposite);
1407: }
1408:
1409: /**
1410: * Retrieves image for vertical thumb.
1411: *
1412: * @param scrollBar
1413: * Scroll bar.
1414: * @param width
1415: * Thumb width.
1416: * @param height
1417: * Thumb height.
1418: * @param kind
1419: * Color scheme kind.
1420: * @param cyclePos
1421: * Cycle position.
1422: * @param theme
1423: * The first theme.
1424: * @param theme2
1425: * The second theme.
1426: * @param composite
1427: * Background composite.
1428: * @param graphicsComposite
1429: * Composite to apply before painting the thumb.
1430: * @return Image for vertical thumb.
1431: */
1432: private static synchronized BufferedImage getThumbVertical(
1433: JScrollBar scrollBar, int width, int height,
1434: float cyclePos, SubstanceTheme theme,
1435: SubstanceTheme theme2,
1436: ControlBackgroundComposite composite,
1437: Composite graphicsComposite) {
1438: SubstanceGradientPainter painter = SubstanceLookAndFeel
1439: .getCurrentGradientPainter();
1440: SubstanceButtonShaper shaper = SubstanceLookAndFeel
1441: .getCurrentButtonShaper();
1442: SubstanceBorderPainter borderPainter = SubstanceCoreUtilities
1443: .getBorderPainter(scrollBar);
1444: // GripPainter gripPainter = SubstanceCoreUtilities.getGripPainter(
1445: // scrollBar, null);
1446: // // System.out.println(state.name());
1447: // String compositeKey = "" + graphicsComposite.hashCode();
1448: // if (graphicsComposite instanceof AlphaComposite) {
1449: // AlphaComposite ac = (AlphaComposite) graphicsComposite;
1450: // compositeKey = "[" + ac.getRule() + ":" + ac.getAlpha() + "]";
1451: // }
1452: String key = width
1453: + ":"
1454: + height
1455: + ":"
1456: + SubstanceCoreUtilities.getSchemeId(theme
1457: .getColorScheme())
1458: + ":"
1459: + SubstanceCoreUtilities.getSchemeId(theme2
1460: .getColorScheme())
1461: + ":"
1462: + SubstanceCoreUtilities.getSchemeId(theme
1463: .getBorderTheme().getColorScheme())
1464: + ":"
1465: + SubstanceCoreUtilities.getSchemeId(theme2
1466: .getBorderTheme().getColorScheme()) + ":"
1467: + cyclePos + ":" + painter.getDisplayName() + ":"
1468: + shaper.getDisplayName() + ":"
1469: + borderPainter.getDisplayName();
1470: // + ":"
1471: // + ((gripPainter != null) ? gripPainter.getDisplayName()
1472: // : "null");
1473: // ":"
1474: // +
1475: // compositeKey;
1476: // System.out.println("Asking " + key);
1477: BufferedImage opaque = null;// SubstanceScrollBarUI.thumbVerticalMap.get(key);
1478: if (opaque == null) {
1479: // System.out.println("Cache miss - computing");
1480: float radius = width / 2;
1481: if (shaper instanceof ClassicButtonShaper)
1482: radius = SubstanceSizeUtils
1483: .getClassicButtonCornerRadius(SubstanceSizeUtils
1484: .getComponentFontSize(scrollBar));
1485:
1486: int borderDelta = (int) Math.floor(SubstanceSizeUtils
1487: .getBorderStrokeWidth(SubstanceSizeUtils
1488: .getComponentFontSize(scrollBar)) / 2.0);
1489: GeneralPath contour = BaseButtonShaper.getBaseOutline(
1490: height, width, radius, null, borderDelta);
1491:
1492: // new StandardGradientPainter();
1493: opaque = painter.getContourBackground(height, width,
1494: contour, false, theme.getColorScheme(), theme2
1495: .getColorScheme(), cyclePos, true,
1496: theme != theme2);
1497: int borderThickness = (int) SubstanceSizeUtils
1498: .getBorderStrokeWidth(SubstanceSizeUtils
1499: .getComponentFontSize(scrollBar));
1500: GeneralPath contourInner = BaseButtonShaper.getBaseOutline(
1501: height, width, radius, null, borderThickness
1502: + borderDelta);
1503: borderPainter.paintBorder(opaque.getGraphics(), scrollBar,
1504: height, width, contour, contourInner, theme
1505: .getBorderTheme().getColorScheme(), theme2
1506: .getBorderTheme().getColorScheme(),
1507: cyclePos, theme != theme2);
1508: opaque = SubstanceImageCreator.getRotated(opaque, 3);
1509: // if (gripPainter != null) {
1510: // gripPainter.paintGrip(scrollBar, opaque.getGraphics(), theme,
1511: // new Rectangle(0, 0, width, height), true, scrollBar
1512: // .getComponentOrientation());
1513: // }
1514: // SubstanceScrollBarUI.thumbVerticalMap.put(key, opaque);
1515: // System.out.println("Cache " + key + " -> @" + opaque.hashCode());
1516: }
1517:
1518: if (composite.getClass() == DefaultControlBackgroundComposite.class) {
1519: // System.out.println("Returning @" + opaque.hashCode());
1520: return opaque;
1521: }
1522:
1523: BufferedImage result = SubstanceCoreUtilities.getBlankImage(
1524: opaque.getWidth(), opaque.getHeight());
1525: Graphics2D resultGr = result.createGraphics();
1526: resultGr.setComposite(graphicsComposite);
1527: resultGr.drawImage(opaque, 0, 0, null);
1528: resultGr.dispose();
1529: return result;
1530: }
1531:
1532: /**
1533: * Retrieves image for horizontal thumb.
1534: *
1535: * @param thumbBounds
1536: * Thumb bounding rectangle.
1537: * @return Image for horizontal thumb.
1538: */
1539: private BufferedImage getThumbHorizontal(Rectangle thumbBounds) {
1540: int width = Math.max(1, thumbBounds.width);
1541: int height = Math.max(1, thumbBounds.height);
1542:
1543: // ComponentState state = ComponentState.getState(
1544: // this.compositeScrollTrackModel, null);
1545: // ComponentState.ColorSchemeKind kind = state.getColorSchemeKind();
1546: // if (kind == ColorSchemeKind.REGULAR)
1547: // kind = ColorSchemeKind.CURRENT;
1548: // float cyclePos = state.getCycleCount();
1549: //
1550: ControlBackgroundComposite controlComposite = SubstanceCoreUtilities
1551: .getControlBackgroundComposite(this .scrollbar);
1552:
1553: // ColorScheme colorScheme = SubstanceCoreUtilities.getComponentTheme(
1554: // this.scrollbar, kind).getColorScheme();
1555: // // SubstanceCoreUtilities.getTheme(kind)
1556: // // .getColorScheme();
1557: // ColorScheme colorScheme2 = colorScheme;
1558: //
1559: Component tracked = SubstanceFadeUtilities.getTracked(
1560: FadeKind.ROLLOVER, this .scrollbar, this .decrButton,
1561: this .incrButton, this .mySecondDecreaseButton,
1562: this .mySecondIncreaseButton);
1563: ComponentState state = ComponentState.getState(
1564: this .compositeScrollTrackModel, null);
1565: if (state.isKindActive(FadeKind.PRESS))
1566: tracked = null;
1567:
1568: if (tracked != null) {
1569: Composite defaultComposite = controlComposite
1570: .getBackgroundComposite(this .scrollbar,
1571: this .scrollbar.getParent(), -1, false);
1572: Composite activeComposite = controlComposite
1573: .getBackgroundComposite(this .scrollbar,
1574: this .scrollbar.getParent(), -1, true);
1575: ComponentState trackedState = (tracked == this .scrollbar) ? ComponentState
1576: .getState(this .thumbModel, null)
1577: : ComponentState
1578: .getState(((AbstractButton) tracked)
1579: .getModel(), null);
1580: ComponentState prevState = SubstanceCoreUtilities
1581: .getPrevComponentState(this .scrollbar);
1582: // enhancement 206 - support for non-active painted scrollbars
1583: // when they are in default state
1584: if (!SubstanceCoreUtilities.hasPropertySetTo(
1585: this .scrollbar,
1586: SubstanceLookAndFeel.PAINT_ACTIVE_PROPERTY, false,
1587: true)) {
1588: if (trackedState == ComponentState.DEFAULT)
1589: trackedState = ComponentState.ACTIVE;
1590: if (prevState == ComponentState.DEFAULT)
1591: prevState = ComponentState.ACTIVE;
1592: }
1593:
1594: float cyclePos = trackedState.getCycleCount();
1595: FadeState highest = SubstanceFadeUtilities
1596: .getFadeStateWithHighestFadeCycle(
1597: FadeKind.ROLLOVER, this .scrollbar,
1598: this .decrButton, this .incrButton,
1599: this .mySecondDecreaseButton,
1600: this .mySecondIncreaseButton);
1601: if (highest != null) {
1602: cyclePos = highest.getFadePosition();
1603: // System.out.println(cyclePos + ":" + highest.isFadingIn);
1604: // if (!highest.isFadingIn())
1605: // cyclePos = 10.0f - cyclePos;
1606: }
1607:
1608: // enhancement 206 - support for non-active painted scrollbars
1609: // when they are in default state
1610: // SubstanceTheme activeTheme = SubstanceCoreUtilities
1611: // .hasPropertySetTo(this.scrollbar,
1612: // SubstanceLookAndFeel.PAINT_ACTIVE_PROPERTY, false,
1613: // true) ? SubstanceCoreUtilities.getTheme(
1614: // this.scrollbar, ComponentState.DEFAULT, true, false)
1615: // : SubstanceCoreUtilities.getTheme(this.scrollbar,
1616: // ComponentState.ACTIVE, true, false);
1617: // SubstanceTheme rolloverTheme = SubstanceCoreUtilities.getTheme(
1618: // this.scrollbar, ComponentState.ROLLOVER_UNSELECTED, true,
1619: // false);
1620:
1621: SubstanceTheme theme2 = SubstanceThemeUtilities.getTheme(
1622: this .scrollbar, trackedState);
1623: SubstanceTheme theme1 = SubstanceThemeUtilities.getTheme(
1624: this .scrollbar, prevState);
1625:
1626: BufferedImage imageActive = getThumbHorizontal(
1627: this .scrollbar, width, height, 0, theme1, theme1,
1628: controlComposite, defaultComposite);
1629: BufferedImage imageRollover = getThumbHorizontal(
1630: this .scrollbar, width, height, 0, theme2, theme2,
1631: controlComposite, activeComposite);
1632:
1633: // System.out.println(theme1.getDisplayName() + "[" +
1634: // prevState.name()
1635: // + "]:" + theme2.getDisplayName() + "[" + state.name()
1636: // + "]:" + cyclePos);
1637:
1638: Graphics2D graphics = imageActive.createGraphics();
1639: graphics.setComposite(AlphaComposite.getInstance(
1640: AlphaComposite.SRC_OVER, cyclePos / 10.0f));
1641: // System.out.println("Painting " + cyclePos / 10.0f);
1642: graphics.drawImage(imageRollover, 0, 0, null);
1643: return imageActive;
1644:
1645: }
1646:
1647: ComponentState prevState = SubstanceCoreUtilities
1648: .getPrevComponentState(this .scrollbar);
1649: // ComponentState.ColorSchemeKind kind = state.getColorSchemeKind();
1650: // if (kind == ColorSchemeKind.REGULAR)
1651: // kind = ColorSchemeKind.CURRENT;
1652: float cyclePos = state.getCycleCount();
1653: // ColorScheme colorScheme = SubstanceCoreUtilities.getComponentTheme(
1654: // this.scrollbar, kind).getColorScheme();
1655: Composite graphicsComposite = controlComposite
1656: .getBackgroundComposite(
1657: this .scrollbar,
1658: this .scrollbar.getParent(),
1659: 0,
1660: ComponentState.getState(
1661: this .compositeScrollTrackModel, null)
1662: .getColorSchemeKind() == ColorSchemeKind.CURRENT);
1663: // enhancement 206 - see comments inside after the condition check
1664: if (!SubstanceCoreUtilities
1665: .hasPropertySetTo(this .scrollbar,
1666: SubstanceLookAndFeel.PAINT_ACTIVE_PROPERTY,
1667: false, true)) {
1668: // unless the SubstanceLookAndFeel.PAINT_ACTIVE_PROPERTY
1669: // is explicitly set to Boolean.FALSE, the scrollbar is painted
1670: // as active when it's in the default state.
1671: if (state == ComponentState.DEFAULT)
1672: state = ComponentState.ACTIVE;
1673: if (prevState == ComponentState.DEFAULT)
1674: prevState = ComponentState.ACTIVE;
1675: }
1676: SubstanceTheme colorTheme = SubstanceThemeUtilities.getTheme(
1677: this .scrollbar, state);
1678: SubstanceTheme colorTheme2 = colorTheme;
1679: FadeTracker fadeTracker = FadeTracker.getInstance();
1680: FadeState fadeState = fadeTracker.getFadeState(this .scrollbar,
1681: FadeKind.PRESS);
1682: if (fadeState != null) {
1683: colorTheme2 = SubstanceThemeUtilities.getTheme(
1684: this .scrollbar, prevState);
1685: cyclePos = fadeState.getFadePosition();
1686: if (fadeState.isFadingIn()) {
1687: cyclePos = 10.0f - cyclePos;
1688: }
1689: }
1690: return getThumbHorizontal(this .scrollbar, width, height,
1691: cyclePos, colorTheme, colorTheme2, controlComposite,
1692: graphicsComposite);
1693: }
1694:
1695: /**
1696: * Retrieves image for horizontal thumb.
1697: *
1698: * @param scrollBar
1699: * Scroll bar.
1700: * @param width
1701: * Thumb width.
1702: * @param height
1703: * Thumb height.
1704: * @param kind
1705: * Color scheme kind.
1706: * @param cyclePos
1707: * Cycle position.
1708: * @param theme
1709: * The first theme.
1710: * @param theme2
1711: * The second theme.
1712: * @param composite
1713: * Background composite.
1714: * @param graphicsComposite
1715: * Composite to apply before painting the thumb.
1716: * @return Image for horizontal thumb.
1717: */
1718: private static BufferedImage getThumbHorizontal(
1719: JScrollBar scrollBar,
1720: int width,
1721: int height, // ComponentState.ColorSchemeKind kind,
1722: float cyclePos, SubstanceTheme theme,
1723: SubstanceTheme theme2,
1724: ControlBackgroundComposite composite,
1725: Composite graphicsComposite) {
1726: SubstanceGradientPainter painter = SubstanceLookAndFeel
1727: .getCurrentGradientPainter();
1728: SubstanceButtonShaper shaper = SubstanceLookAndFeel
1729: .getCurrentButtonShaper();
1730: SubstanceBorderPainter borderPainter = SubstanceCoreUtilities
1731: .getBorderPainter(scrollBar);
1732: // GripPainter gripPainter = SubstanceCoreUtilities.getGripPainter(
1733: // scrollBar, null);
1734: // System.out.println(state.name());
1735: String key = width + ":" + height + ":"
1736: + theme.getDisplayName() + ":"
1737: + theme2.getDisplayName() + ":" + cyclePos + ":"
1738: + painter.getDisplayName() + ":"
1739: + shaper.getDisplayName() + ":"
1740: + borderPainter.getDisplayName();
1741: // + ":"
1742: // + ((gripPainter != null) ? gripPainter.getDisplayName()
1743: // : "null");
1744:
1745: float radius = height / 2;
1746: if (shaper instanceof ClassicButtonShaper)
1747: radius = SubstanceSizeUtils
1748: .getClassicButtonCornerRadius(SubstanceSizeUtils
1749: .getComponentFontSize(scrollBar));
1750: int borderDelta = (int) Math.floor(SubstanceSizeUtils
1751: .getBorderStrokeWidth(SubstanceSizeUtils
1752: .getComponentFontSize(scrollBar)) / 2.0);
1753: GeneralPath contour = BaseButtonShaper.getBaseOutline(width,
1754: height, radius, null, borderDelta);
1755: BufferedImage opaque = SubstanceScrollBarUI.thumbHorizontalMap
1756: .get(key);
1757: if (opaque == null) {
1758: // new StandardGradientPainter();
1759: opaque = painter.getContourBackground(width, height,
1760: contour, false, theme.getColorScheme(), theme2
1761: .getColorScheme(), cyclePos, true,
1762: theme != theme2);
1763: int borderThickness = (int) SubstanceSizeUtils
1764: .getBorderStrokeWidth(SubstanceSizeUtils
1765: .getComponentFontSize(scrollBar));
1766: GeneralPath contourInner = BaseButtonShaper.getBaseOutline(
1767: width, height, radius, null, borderThickness
1768: + borderDelta);
1769: borderPainter.paintBorder(opaque.getGraphics(), scrollBar,
1770: width, height, contour, contourInner, theme
1771: .getBorderTheme().getColorScheme(), theme2
1772: .getBorderTheme().getColorScheme(),
1773: cyclePos, theme != theme2);
1774: // if (gripPainter != null) {
1775: // gripPainter.paintGrip(scrollBar, opaque.getGraphics(), theme,
1776: // new Rectangle(0, 0, width, height), false, scrollBar
1777: // .getComponentOrientation());
1778: // }
1779:
1780: // SubstanceScrollBarUI.thumbHorizontalMap.put(key, opaque);
1781: }
1782:
1783: if (composite.getClass() == DefaultControlBackgroundComposite.class)
1784: return opaque;
1785:
1786: BufferedImage result = SubstanceCoreUtilities.getBlankImage(
1787: opaque.getWidth(), opaque.getHeight());
1788: Graphics2D resultGr = result.createGraphics();
1789: resultGr.setComposite(graphicsComposite);
1790: resultGr.drawImage(opaque, 0, 0, null);
1791: resultGr.dispose();
1792: return result;
1793: }
1794:
1795: /**
1796: * Returns the scroll button state.
1797: *
1798: * @param scrollButton
1799: * Scroll button.
1800: * @return Scroll button state.
1801: */
1802: protected ComponentState getState(JButton scrollButton) {
1803: if (scrollButton == null)
1804: return null;
1805:
1806: // ComponentState result = null;
1807: //
1808: ComponentState result = ComponentState.getState(scrollButton
1809: .getModel(), scrollButton);
1810: // new CompositeButtonModel(scrollButton.getModel(),
1811: // this.thumbModel), scrollButton);
1812: if ((result == ComponentState.DEFAULT)
1813: && SubstanceCoreUtilities.hasFlatAppearance(
1814: this .scrollbar, false)) {
1815: result = null;
1816: }
1817: if (SubstanceCoreUtilities.isButtonNeverPainted(scrollButton)) {
1818: result = null;
1819: }
1820: // if ((result == ComponentState.DEFAULT)
1821: // && SubstanceCoreUtilities.isControlAlwaysPaintedActive(
1822: // scrollButton, true)) {
1823: // result = ComponentState.ROLLOVER_UNSELECTED;
1824: // }
1825: return result;
1826: }
1827:
1828: /*
1829: * (non-Javadoc)
1830: *
1831: * @see javax.swing.plaf.basic.BasicScrollBarUI#paintTrack(java.awt.Graphics,
1832: * javax.swing.JComponent, java.awt.Rectangle)
1833: */
1834: @Override
1835: protected void paintTrack(Graphics g, JComponent c,
1836: Rectangle trackBounds) {
1837: // if (!c.isEnabled()) {
1838: // return;
1839: // }
1840: //
1841: Graphics2D graphics = (Graphics2D) g.create();
1842:
1843: // System.out.println("Track");
1844: ScrollPaneButtonPolicyKind buttonPolicy = SubstanceCoreUtilities
1845: .getScrollPaneButtonsPolicyKind(this .scrollbar);
1846: SubstanceScrollBarButton compTopState = null;
1847: SubstanceScrollBarButton compBottomState = null;
1848: if (this .decrButton.isShowing() && this .incrButton.isShowing()
1849: && this .mySecondDecreaseButton.isShowing()
1850: && this .mySecondIncreaseButton.isShowing()) {
1851: switch (buttonPolicy) {
1852: case OPPOSITE:
1853: compTopState = (SubstanceScrollBarButton) this .decrButton;
1854: compBottomState = (SubstanceScrollBarButton) this .incrButton;
1855: break;
1856: case ADJACENT:
1857: compBottomState = (SubstanceScrollBarButton) this .mySecondDecreaseButton;
1858: break;
1859: case MULTIPLE:
1860: compTopState = (SubstanceScrollBarButton) this .decrButton;
1861: compBottomState = (SubstanceScrollBarButton) this .mySecondDecreaseButton;
1862: break;
1863: case MULTIPLE_BOTH:
1864: compTopState = (SubstanceScrollBarButton) this .mySecondIncreaseButton;
1865: compBottomState = (SubstanceScrollBarButton) this .mySecondDecreaseButton;
1866: break;
1867: }
1868: }
1869:
1870: // ControlBackgroundComposite composite = SubstanceCoreUtilities
1871: // .getControlBackgroundComposite(this.scrollbar);
1872: // graphics.setComposite(composite.getBackgroundComposite(this.scrollbar,
1873: // this.scrollbar.getParent(), -1, false));
1874:
1875: if (this .scrollbar.getOrientation() == Adjustable.VERTICAL) {
1876: BufferedImage bi = this .getTrackVertical(trackBounds,
1877: compTopState, compBottomState);
1878: // BufferedImage result = SubstanceCoreUtilities.getBlankImage(bi
1879: // .getWidth(), bi.getHeight());
1880: // Graphics2D resultGr = (Graphics2D) result.createGraphics();
1881: // Container parent = this.scrollbar.getParent();
1882: // if (parent instanceof JScrollPane) {
1883: // JScrollPane jsp = ((JScrollPane) parent);
1884: // if (SubstanceCoreUtilities.hasOverlayProperty(jsp)) {
1885: // JViewport viewport = jsp.getViewport();
1886: // int dx = -viewport.getX() + viewport.getViewRect().x
1887: // + this.scrollbar.getX() + trackBounds.x;
1888: // int dy = viewport.getY() - viewport.getViewRect().y
1889: // - this.scrollbar.getY() - trackBounds.y;
1890: // resultGr.translate(-dx, dy);
1891: // JComponent view = (JComponent) viewport.getView();
1892: // boolean wasDb = view.isDoubleBuffered();
1893: // view.setDoubleBuffered(false);
1894: // view.paint(resultGr);
1895: // view.setDoubleBuffered(wasDb);
1896: // resultGr.translate(dx, -dy);
1897: // }
1898: // }
1899: // resultGr.setComposite(composite.getBackgroundComposite(
1900: // this.scrollbar, this.scrollbar.getParent(), -1, false));
1901: // resultGr.drawImage(bi, 0, 0, null);
1902: graphics.drawImage(bi, trackBounds.x, trackBounds.y, null);
1903: // resultGr.dispose();
1904: } else {
1905: BufferedImage bi = this .scrollbar.getComponentOrientation()
1906: .isLeftToRight() ? this .getTrackHorizontal(
1907: trackBounds, compTopState, compBottomState) : this
1908: .getTrackHorizontal(trackBounds, compBottomState,
1909: compTopState);
1910: // BufferedImage result = SubstanceCoreUtilities.getBlankImage(bi
1911: // .getWidth(), bi.getHeight());
1912: // Graphics2D resultGr = (Graphics2D) result.createGraphics();
1913: // Container parent = this.scrollbar.getParent();
1914: // if (parent instanceof JScrollPane) {
1915: // JScrollPane jsp = ((JScrollPane) parent);
1916: // if (SubstanceCoreUtilities.hasOverlayProperty(jsp)) {
1917: // JViewport viewport = jsp.getViewport();
1918: // int dx = -viewport.getX() + viewport.getViewRect().x
1919: // + this.scrollbar.getX() + trackBounds.x;
1920: // int dy = viewport.getY() - viewport.getViewRect().y
1921: // - this.scrollbar.getY();
1922: // resultGr.translate(-dx, dy);
1923: // JComponent view = (JComponent) viewport.getView();
1924: // boolean wasDb = view.isDoubleBuffered();
1925: // view.setDoubleBuffered(false);
1926: // view.paint(resultGr);
1927: // view.setDoubleBuffered(wasDb);
1928: // resultGr.translate(dx, -dy);
1929: // }
1930: // }
1931: // resultGr.setComposite(composite.getBackgroundComposite(
1932: // this.scrollbar, this.scrollbar.getParent(), -1, false));
1933: // resultGr.drawImage(bi, 0, 0, null);
1934: graphics.drawImage(bi, trackBounds.x, trackBounds.y, null);
1935: // resultGr.dispose();
1936: }
1937:
1938: graphics.dispose();
1939: }
1940:
1941: /*
1942: * (non-Javadoc)
1943: *
1944: * @see javax.swing.plaf.basic.BasicScrollBarUI#paintThumb(java.awt.Graphics,
1945: * javax.swing.JComponent, java.awt.Rectangle)
1946: */
1947: @Override
1948: protected void paintThumb(Graphics g, JComponent c,
1949: Rectangle thumbBounds) {
1950: // if (!c.isEnabled()) {
1951: // return;
1952: // }
1953: //
1954:
1955: // System.out.println("Thumb");
1956: Graphics2D graphics = (Graphics2D) g.create();
1957: // ControlBackgroundComposite composite = SubstanceCoreUtilities
1958: // .getControlBackgroundComposite(this.scrollbar);
1959:
1960: // JScrollBar scrollBar = (JScrollBar) c;
1961: this .thumbModel.setSelected(this .thumbModel.isSelected()
1962: || this .isDragging);
1963: this .thumbModel.setEnabled(c.isEnabled());
1964: boolean isVertical = (this .scrollbar.getOrientation() == Adjustable.VERTICAL);
1965: if (isVertical) {
1966: Rectangle adjustedBounds = new Rectangle(thumbBounds.x,
1967: thumbBounds.y, thumbBounds.width,
1968: thumbBounds.height);
1969: BufferedImage thumbImage = this
1970: .getThumbVertical(adjustedBounds);
1971: // BufferedImage result = SubstanceCoreUtilities.getBlankImage(
1972: // thumbImage.getWidth(), thumbImage.getHeight());
1973: // Graphics2D resultGr = (Graphics2D) result.createGraphics();
1974:
1975: // Container parent = this.scrollbar.getParent();
1976: // if (parent instanceof JScrollPane) {
1977: // JScrollPane jsp = ((JScrollPane) parent);
1978: // if (SubstanceCoreUtilities.isScrollPaneOverlay(jsp)) {
1979: // JViewport viewport = jsp.getViewport();
1980: // int dx = -viewport.getX() + viewport.getViewRect().x
1981: // + this.scrollbar.getX() + thumbBounds.x;
1982: // int dy = viewport.getY() - viewport.getViewRect().y
1983: // - this.scrollbar.getY() - thumbBounds.y;
1984: // resultGr.translate(-dx, dy);
1985: // JComponent view = (JComponent) viewport.getView();
1986: // boolean wasDb = view.isDoubleBuffered();
1987: // view.setDoubleBuffered(false);
1988: // view.paint(resultGr);
1989: // view.setDoubleBuffered(wasDb);
1990: // resultGr.translate(dx, -dy);
1991: // }
1992: // }
1993: // resultGr.setComposite(composite.getBackgroundComposite(
1994: // this.scrollbar, this.scrollbar.getParent(), -1,
1995: // ComponentState.getState(thumbModel, null)
1996: // .getColorSchemeKind() == ColorSchemeKind.CURRENT));
1997: // resultGr.drawImage(thumbImage, 0, 0, null);
1998: graphics.drawImage(thumbImage, adjustedBounds.x,
1999: adjustedBounds.y, null);
2000: // resultGr.dispose();
2001:
2002: // g.drawImage(thumbImage, adjustedBounds.x, adjustedBounds.y,
2003: // null);
2004: } else {
2005: Rectangle adjustedBounds = new Rectangle(thumbBounds.x,
2006: thumbBounds.y, thumbBounds.width,
2007: thumbBounds.height);
2008: BufferedImage thumbImage = this
2009: .getThumbHorizontal(adjustedBounds);
2010: // BufferedImage result = SubstanceCoreUtilities.getBlankImage(
2011: // thumbImage.getWidth(), thumbImage.getHeight());
2012: // Graphics2D resultGr = (Graphics2D) result.createGraphics();
2013: //
2014: // // Container parent = this.scrollbar.getParent();
2015: // // if (parent instanceof JScrollPane) {
2016: // // JScrollPane jsp = ((JScrollPane) parent);
2017: // // if (SubstanceCoreUtilities.isScrollPaneOverlay(jsp)) {
2018: // // JViewport viewport = jsp.getViewport();
2019: // // int dx = -viewport.getX() + viewport.getViewRect().x
2020: // // + this.scrollbar.getX() + thumbBounds.x;
2021: // // int dy = viewport.getY() - viewport.getViewRect().y
2022: // // - this.scrollbar.getY();
2023: // // resultGr.translate(-dx, dy);
2024: // // JComponent view = (JComponent) viewport.getView();
2025: // // boolean wasDb = view.isDoubleBuffered();
2026: // // view.setDoubleBuffered(false);
2027: // // view.paint(resultGr);
2028: // // view.setDoubleBuffered(wasDb);
2029: // // resultGr.translate(dx, -dy);
2030: // // }
2031: // // }
2032: // resultGr.setComposite(composite.getBackgroundComposite(
2033: // this.scrollbar, this.scrollbar.getParent(), -1,
2034: // ComponentState.getState(thumbModel, null)
2035: // .getColorSchemeKind() == ColorSchemeKind.CURRENT));
2036: // resultGr.drawImage(thumbImage, 0, 0, null);
2037: graphics.drawImage(thumbImage, adjustedBounds.x,
2038: adjustedBounds.y, null);
2039: // resultGr.dispose();
2040:
2041: // g.drawImage(thumbImage, adjustedBounds.x, adjustedBounds.y,
2042: // null);
2043: }
2044: graphics.dispose();
2045: }
2046:
2047: @Override
2048: public void paint(Graphics g, JComponent c) {
2049: Graphics2D graphics = (Graphics2D) g.create();
2050: SubstanceFillBackgroundDelegate.GLOBAL_INSTANCE.update(
2051: graphics, c, false);
2052: float themeAlpha = SubstanceThemeUtilities.getTheme(
2053: this .scrollbar).getThemeAlpha(
2054: this .scrollbar,
2055: ComponentState
2056: .getState(this .thumbModel, this .scrollbar));
2057: graphics.setComposite(TransitionLayout.getAlphaComposite(c,
2058: themeAlpha, g));
2059: super .paint(graphics, c);
2060: graphics.dispose();
2061: }
2062:
2063: /*
2064: * (non-Javadoc)
2065: *
2066: * @see javax.swing.plaf.basic.BasicScrollBarUI#installDefaults()
2067: */
2068: @Override
2069: protected void installDefaults() {
2070: super .installDefaults();
2071: this .scrollBarWidth = SubstanceSizeUtils
2072: .getScrollBarWidth(SubstanceSizeUtils
2073: .getComponentFontSize(this .scrollbar));
2074: }
2075:
2076: /*
2077: * (non-Javadoc)
2078: *
2079: * @see javax.swing.plaf.basic.BasicScrollBarUI#installComponents()
2080: */
2081: @Override
2082: protected void installComponents() {
2083: super .installComponents();
2084: switch (this .scrollbar.getOrientation()) {
2085: case JScrollBar.VERTICAL:
2086: this .mySecondDecreaseButton = this
2087: .createGeneralDecreaseButton(NORTH, false);
2088: this .mySecondIncreaseButton = this
2089: .createGeneralIncreaseButton(SOUTH, false);
2090: this .synchDecreaseButtonTheme(this .mySecondDecreaseButton,
2091: false);
2092: this .synchIncreaseButtonTheme(this .mySecondIncreaseButton,
2093: false);
2094: break;
2095:
2096: case JScrollBar.HORIZONTAL:
2097: if (this .scrollbar.getComponentOrientation()
2098: .isLeftToRight()) {
2099: this .mySecondDecreaseButton = this
2100: .createGeneralDecreaseButton(WEST, false);
2101: this .mySecondIncreaseButton = this
2102: .createGeneralIncreaseButton(EAST, false);
2103: this .synchDecreaseButtonTheme(
2104: this .mySecondDecreaseButton, false);
2105: this .synchIncreaseButtonTheme(
2106: this .mySecondIncreaseButton, false);
2107: } else {
2108: this .mySecondDecreaseButton = this
2109: .createGeneralDecreaseButton(EAST, false);
2110: this .mySecondIncreaseButton = this
2111: .createGeneralIncreaseButton(WEST, false);
2112: this .synchDecreaseButtonTheme(
2113: this .mySecondDecreaseButton, false);
2114: this .synchIncreaseButtonTheme(
2115: this .mySecondIncreaseButton, false);
2116: }
2117: break;
2118: }
2119: this .scrollbar.add(this .mySecondDecreaseButton);
2120: this .scrollbar.add(this .mySecondIncreaseButton);
2121:
2122: this .compositeScrollTrackModel = new CompositeButtonModel(
2123: this .thumbModel, this .incrButton, this .decrButton,
2124: this .mySecondDecreaseButton,
2125: this .mySecondIncreaseButton);
2126: this .compositeButtonsModel = new CompositeButtonModel(
2127: new DefaultButtonModel(), this .incrButton,
2128: this .decrButton, this .mySecondDecreaseButton,
2129: this .mySecondIncreaseButton);
2130: }
2131:
2132: /*
2133: * (non-Javadoc)
2134: *
2135: * @see javax.swing.plaf.basic.BasicScrollBarUI#uninstallComponents()
2136: */
2137: @Override
2138: protected void uninstallComponents() {
2139: this .scrollbar.remove(this .mySecondDecreaseButton);
2140: this .scrollbar.remove(this .mySecondIncreaseButton);
2141: super .uninstallComponents();
2142: }
2143:
2144: /*
2145: * (non-Javadoc)
2146: *
2147: * @see javax.swing.plaf.basic.BasicScrollBarUI#installListeners()
2148: */
2149: @Override
2150: protected void installListeners() {
2151: super .installListeners();
2152: // scrollbar.addMouseListener(new MouseAdapter());
2153: // BasicButtonListener incrListener = RolloverScrollBarButtonListener
2154: // .getListener(this.scrollbar, incrButton);
2155: this .substanceMouseListener = new MouseAdapter() {
2156: @Override
2157: public void mouseEntered(MouseEvent e) {
2158: SubstanceScrollBarUI.this .scrollbar.repaint();
2159: }
2160:
2161: @Override
2162: public void mouseExited(MouseEvent e) {
2163: SubstanceScrollBarUI.this .scrollbar.repaint();
2164: }
2165:
2166: @Override
2167: public void mousePressed(MouseEvent e) {
2168: SubstanceScrollBarUI.this .scrollbar.repaint();
2169: }
2170:
2171: @Override
2172: public void mouseReleased(MouseEvent e) {
2173: SubstanceScrollBarUI.this .scrollbar.repaint();
2174: }
2175: };
2176:
2177: this .incrButton.addMouseListener(this .substanceMouseListener);
2178: this .decrButton.addMouseListener(this .substanceMouseListener);
2179: this .mySecondDecreaseButton
2180: .addMouseListener(this .substanceMouseListener);
2181: this .mySecondIncreaseButton
2182: .addMouseListener(this .substanceMouseListener);
2183:
2184: this .substanceThumbRolloverListener = new RolloverControlListener(
2185: this , this .thumbModel);
2186: this .scrollbar
2187: .addMouseListener(this .substanceThumbRolloverListener);
2188: this .scrollbar
2189: .addMouseMotionListener(this .substanceThumbRolloverListener);
2190:
2191: this .substanceFadeStateListener = new FadeStateListener(
2192: this .scrollbar, this .thumbModel, SubstanceCoreUtilities
2193: .getFadeCallback(this .scrollbar,
2194: this .thumbModel, false, false,
2195: this .scrollbar));
2196: this .substanceFadeStateListener.registerListeners(false);
2197:
2198: this .substancePropertyListener = new PropertyChangeListener() {
2199: public void propertyChange(PropertyChangeEvent evt) {
2200: if (SubstanceLookAndFeel.THEME_PROPERTY.equals(evt
2201: .getPropertyName())) {
2202: SubstanceScrollBarUI.this .synchDecreaseButtonTheme(
2203: SubstanceScrollBarUI.this .decrButton, true);
2204: SubstanceScrollBarUI.this
2205: .synchDecreaseButtonTheme(
2206: SubstanceScrollBarUI.this .mySecondDecreaseButton,
2207: false);
2208: SubstanceScrollBarUI.this .synchIncreaseButtonTheme(
2209: SubstanceScrollBarUI.this .incrButton, true);
2210: SubstanceScrollBarUI.this
2211: .synchIncreaseButtonTheme(
2212: SubstanceScrollBarUI.this .mySecondIncreaseButton,
2213: true);
2214: return;
2215: }
2216:
2217: if ("font".equals(evt.getPropertyName())) {
2218: SwingUtilities.invokeLater(new Runnable() {
2219: public void run() {
2220: scrollbar.updateUI();
2221: }
2222: });
2223: }
2224: if ("background".equals(evt.getPropertyName())) {
2225: // propagate application-specific background color to the
2226: // scroll buttons.
2227: Color newBackgr = (Color) evt.getNewValue();
2228: if (!(newBackgr instanceof UIResource)) {
2229: if (mySecondDecreaseButton != null) {
2230: if (mySecondDecreaseButton.getBackground() instanceof UIResource) {
2231: mySecondDecreaseButton
2232: .setBackground(newBackgr);
2233: }
2234: }
2235: if (mySecondIncreaseButton != null) {
2236: if (mySecondIncreaseButton.getBackground() instanceof UIResource) {
2237: mySecondIncreaseButton
2238: .setBackground(newBackgr);
2239: }
2240: }
2241: if (incrButton != null) {
2242: if (incrButton.getBackground() instanceof UIResource) {
2243: incrButton.setBackground(newBackgr);
2244: }
2245: }
2246: if (decrButton != null) {
2247: if (decrButton.getBackground() instanceof UIResource) {
2248: decrButton.setBackground(newBackgr);
2249: }
2250: }
2251: }
2252: }
2253: }
2254: };
2255: this .scrollbar
2256: .addPropertyChangeListener(this .substancePropertyListener);
2257:
2258: this .mySecondDecreaseButton
2259: .addMouseListener(this .buttonListener);
2260: this .mySecondIncreaseButton
2261: .addMouseListener(this .buttonListener);
2262:
2263: this .substanceAdjustmentListener = new AdjustmentListener() {
2264: public void adjustmentValueChanged(AdjustmentEvent e) {
2265: Component parent = SubstanceScrollBarUI.this .scrollbar
2266: .getParent();
2267: if (parent instanceof JScrollPane) {
2268: JScrollPane jsp = (JScrollPane) parent;
2269: JScrollBar hor = jsp.getHorizontalScrollBar();
2270: JScrollBar ver = jsp.getVerticalScrollBar();
2271:
2272: JScrollBar other = null;
2273: if (SubstanceScrollBarUI.this .scrollbar == hor) {
2274: other = ver;
2275: }
2276: if (SubstanceScrollBarUI.this .scrollbar == ver) {
2277: other = hor;
2278: }
2279:
2280: if ((other != null) && other.isVisible())
2281: other.repaint();
2282: SubstanceScrollBarUI.this .scrollbar.repaint();
2283: }
2284: }
2285: };
2286: this .scrollbar
2287: .addAdjustmentListener(this .substanceAdjustmentListener);
2288:
2289: if (SubstanceLookAndFeel.isDebugUiMode()) {
2290: this .substanceDebugUiListener = new MouseAdapter() {
2291: @Override
2292: public void mousePressed(MouseEvent e) {
2293: this .process(e);
2294: }
2295:
2296: @Override
2297: public void mouseReleased(MouseEvent e) {
2298: this .process(e);
2299: }
2300:
2301: protected void process(MouseEvent e) {
2302: if (e.isPopupTrigger()) {
2303: JPopupMenu popup = new JPopupMenu();
2304: JMenuItem policyNone = new JMenuItem(
2305: "Empty policy");
2306: policyNone.addActionListener(new PolicyChanger(
2307: ScrollPaneButtonPolicyKind.NONE));
2308: popup.add(policyNone);
2309: JMenuItem policyOpposite = new JMenuItem(
2310: "Opposite policy");
2311: policyOpposite
2312: .addActionListener(new PolicyChanger(
2313: ScrollPaneButtonPolicyKind.OPPOSITE));
2314: popup.add(policyOpposite);
2315: JMenuItem policyAdjacent = new JMenuItem(
2316: "Adjacent policy");
2317: policyAdjacent
2318: .addActionListener(new PolicyChanger(
2319: ScrollPaneButtonPolicyKind.ADJACENT));
2320: popup.add(policyAdjacent);
2321: JMenuItem policyMultiple = new JMenuItem(
2322: "Multiple policy");
2323: policyMultiple
2324: .addActionListener(new PolicyChanger(
2325: ScrollPaneButtonPolicyKind.MULTIPLE));
2326: popup.add(policyMultiple);
2327: JMenuItem policyMultipleBoth = new JMenuItem(
2328: "Multiple both policy");
2329: policyMultipleBoth
2330: .addActionListener(new PolicyChanger(
2331: ScrollPaneButtonPolicyKind.MULTIPLE_BOTH));
2332: popup.add(policyMultipleBoth);
2333: popup.show(SubstanceScrollBarUI.this .scrollbar,
2334: e.getX(), e.getY());
2335: }
2336: }
2337: };
2338: this .scrollbar
2339: .addMouseListener(this .substanceDebugUiListener);
2340: }
2341: }
2342:
2343: /*
2344: * (non-Javadoc)
2345: *
2346: * @see javax.swing.plaf.basic.BasicScrollBarUI#uninstallListeners()
2347: */
2348: @Override
2349: protected void uninstallListeners() {
2350: // fix for defect 109 - memory leak on changing theme
2351: this .incrButton
2352: .removeMouseListener(this .substanceMouseListener);
2353: this .decrButton
2354: .removeMouseListener(this .substanceMouseListener);
2355: this .mySecondDecreaseButton
2356: .removeMouseListener(this .substanceMouseListener);
2357: this .mySecondIncreaseButton
2358: .removeMouseListener(this .substanceMouseListener);
2359: this .substanceMouseListener = null;
2360:
2361: this .scrollbar
2362: .removeMouseListener(this .substanceThumbRolloverListener);
2363: this .scrollbar
2364: .removeMouseMotionListener(this .substanceThumbRolloverListener);
2365: this .substanceThumbRolloverListener = null;
2366:
2367: this .substanceFadeStateListener.unregisterListeners();
2368: this .substanceFadeStateListener = null;
2369:
2370: this .scrollbar
2371: .removePropertyChangeListener(this .substancePropertyListener);
2372: this .substancePropertyListener = null;
2373:
2374: this .mySecondDecreaseButton
2375: .removeMouseListener(this .buttonListener);
2376: this .mySecondIncreaseButton
2377: .removeMouseListener(this .buttonListener);
2378:
2379: this .scrollbar
2380: .removeAdjustmentListener(this .substanceAdjustmentListener);
2381: this .substanceAdjustmentListener = null;
2382:
2383: if (this .substanceDebugUiListener != null) {
2384: this .scrollbar
2385: .removeMouseListener(this .substanceDebugUiListener);
2386: this .substanceDebugUiListener = null;
2387: }
2388:
2389: super .uninstallListeners();
2390: }
2391:
2392: /*
2393: * (non-Javadoc)
2394: *
2395: * @see org.jvnet.substance.Trackable#isInside(java.awt.event.MouseEvent)
2396: */
2397: public boolean isInside(MouseEvent me) {
2398: // Rectangle thumbB = this.getThumbBounds();
2399: Rectangle trackB = this .getTrackBounds();
2400: if (trackB == null)
2401: return false;
2402: return trackB.contains(me.getX(), me.getY());
2403: }
2404:
2405: /*
2406: * (non-Javadoc)
2407: *
2408: * @see javax.swing.plaf.basic.BasicScrollBarUI#scrollByBlock(int)
2409: */
2410: @Override
2411: public void scrollByBlock(int direction) {
2412: // This method is called from SubstanceScrollPaneUI to implement wheel
2413: // scrolling.
2414: int oldValue = this .scrollbar.getValue();
2415: int blockIncrement = this .scrollbar
2416: .getBlockIncrement(direction);
2417: int delta = blockIncrement * ((direction > 0) ? +1 : -1);
2418: int newValue = oldValue + delta;
2419:
2420: // Check for overflow.
2421: if ((delta > 0) && (newValue < oldValue)) {
2422: newValue = this .scrollbar.getMaximum();
2423: } else if ((delta < 0) && (newValue > oldValue)) {
2424: newValue = this .scrollbar.getMinimum();
2425: }
2426:
2427: this .scrollbar.setValue(newValue);
2428: }
2429:
2430: /**
2431: * Scrolls the associated scroll bar.
2432: *
2433: * @param direction
2434: * Direction.
2435: * @param units
2436: * Scroll units.
2437: */
2438: public void scrollByUnits(int direction, int units) {
2439: // This method is called from SubstanceScrollPaneUI to implement wheel
2440: // scrolling.
2441: int delta;
2442:
2443: for (int i = 0; i < units; i++) {
2444: if (direction > 0) {
2445: delta = this .scrollbar.getUnitIncrement(direction);
2446: } else {
2447: delta = -this .scrollbar.getUnitIncrement(direction);
2448: }
2449:
2450: int oldValue = this .scrollbar.getValue();
2451: int newValue = oldValue + delta;
2452:
2453: // Check for overflow.
2454: if ((delta > 0) && (newValue < oldValue)) {
2455: newValue = this .scrollbar.getMaximum();
2456: } else if ((delta < 0) && (newValue > oldValue)) {
2457: newValue = this .scrollbar.getMinimum();
2458: }
2459: if (oldValue == newValue) {
2460: break;
2461: }
2462: this .scrollbar.setValue(newValue);
2463: }
2464: }
2465:
2466: /*
2467: * (non-Javadoc)
2468: *
2469: * @see javax.swing.plaf.basic.BasicScrollBarUI#layoutVScrollbar(javax.swing.JScrollBar)
2470: */
2471: @Override
2472: protected void layoutVScrollbar(JScrollBar sb) {
2473: ScrollPaneButtonPolicyKind buttonPolicy = SubstanceCoreUtilities
2474: .getScrollPaneButtonsPolicyKind(this .scrollbar);
2475: this .mySecondDecreaseButton.setBounds(0, 0, 0, 0);
2476: this .mySecondIncreaseButton.setBounds(0, 0, 0, 0);
2477: switch (buttonPolicy) {
2478: case OPPOSITE:
2479: super .layoutVScrollbar(sb);
2480: break;
2481: case NONE:
2482: this .layoutVScrollbarNone(sb);
2483: break;
2484: case ADJACENT:
2485: this .layoutVScrollbarAdjacent(sb);
2486: break;
2487: case MULTIPLE:
2488: this .layoutVScrollbarMultiple(sb);
2489: break;
2490: case MULTIPLE_BOTH:
2491: this .layoutVScrollbarMultipleBoth(sb);
2492: break;
2493: }
2494: }
2495:
2496: /*
2497: * (non-Javadoc)
2498: *
2499: * @see javax.swing.plaf.basic.BasicScrollBarUI#layoutHScrollbar(javax.swing.JScrollBar)
2500: */
2501: @Override
2502: protected void layoutHScrollbar(JScrollBar sb) {
2503: this .mySecondDecreaseButton.setBounds(0, 0, 0, 0);
2504: this .mySecondIncreaseButton.setBounds(0, 0, 0, 0);
2505: ScrollPaneButtonPolicyKind buttonPolicy = SubstanceCoreUtilities
2506: .getScrollPaneButtonsPolicyKind(this .scrollbar);
2507: switch (buttonPolicy) {
2508: case OPPOSITE:
2509: super .layoutHScrollbar(sb);
2510: break;
2511: case NONE:
2512: this .layoutHScrollbarNone(sb);
2513: break;
2514: case ADJACENT:
2515: this .layoutHScrollbarAdjacent(sb);
2516: break;
2517: case MULTIPLE:
2518: this .layoutHScrollbarMultiple(sb);
2519: break;
2520: case MULTIPLE_BOTH:
2521: this .layoutHScrollbarMultipleBoth(sb);
2522: break;
2523: }
2524: }
2525:
2526: /**
2527: * Lays out the vertical scroll bar when the button policy is
2528: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#ADJACENT}.
2529: *
2530: * @param sb
2531: * Scroll bar.
2532: */
2533: protected void layoutVScrollbarAdjacent(JScrollBar sb) {
2534: Dimension sbSize = sb.getSize();
2535: Insets sbInsets = sb.getInsets();
2536:
2537: /*
2538: * Width and left edge of the buttons and thumb.
2539: */
2540: int itemW = sbSize.width - (sbInsets.left + sbInsets.right);
2541: int itemX = sbInsets.left;
2542:
2543: /*
2544: * Nominal locations of the buttons, assuming their preferred size will
2545: * fit.
2546: */
2547: int incrButtonH = itemW;
2548: int incrButtonY = sbSize.height
2549: - (sbInsets.bottom + incrButtonH);
2550:
2551: int decrButton2H = itemW;
2552: int decrButton2Y = incrButtonY - decrButton2H;
2553:
2554: /*
2555: * The thumb must fit within the height left over after we subtract the
2556: * preferredSize of the buttons and the insets.
2557: */
2558: int sbInsetsH = sbInsets.top + sbInsets.bottom;
2559: int sbButtonsH = decrButton2H + incrButtonH;
2560: float trackH = sbSize.height - (sbInsetsH + sbButtonsH);
2561:
2562: /*
2563: * Compute the height and origin of the thumb. The case where the thumb
2564: * is at the bottom edge is handled specially to avoid numerical
2565: * problems in computing thumbY. Enforce the thumbs min/max dimensions.
2566: * If the thumb doesn't fit in the track (trackH) we'll hide it later.
2567: */
2568: float min = sb.getMinimum();
2569: float extent = sb.getVisibleAmount();
2570: float range = sb.getMaximum() - min;
2571: float value = sb.getValue();
2572:
2573: int thumbH = (range <= 0) ? this .getMaximumThumbSize().height
2574: : (int) (trackH * (extent / range));
2575: thumbH = Math.max(thumbH, this .getMinimumThumbSize().height);
2576: thumbH = Math.min(thumbH, this .getMaximumThumbSize().height);
2577:
2578: int thumbY = decrButton2Y - thumbH;
2579: if (value < (sb.getMaximum() - sb.getVisibleAmount())) {
2580: float thumbRange = trackH - thumbH;
2581: thumbY = (int) (0.5f + (thumbRange * ((value - min) / (range - extent))));
2582: }
2583:
2584: /*
2585: * If the buttons don't fit, allocate half of the available space to
2586: * each and move the lower one (incrButton) down.
2587: */
2588: int sbAvailButtonH = (sbSize.height - sbInsetsH);
2589: if (sbAvailButtonH < sbButtonsH) {
2590: incrButtonH = decrButton2H = sbAvailButtonH / 2;
2591: incrButtonY = sbSize.height
2592: - (sbInsets.bottom + incrButtonH);
2593: }
2594: this .mySecondIncreaseButton.setBounds(0, 0, 0, 0);
2595: this .decrButton.setBounds(0, 0, 0, 0);
2596: this .mySecondDecreaseButton.setBounds(itemX, incrButtonY
2597: - decrButton2H, itemW, decrButton2H);
2598: this .incrButton.setBounds(itemX, incrButtonY, itemW,
2599: incrButtonH);
2600:
2601: /*
2602: * Update the trackRect field.
2603: */
2604: int itrackY = 0;
2605: int itrackH = decrButton2Y - itrackY;
2606: this .trackRect.setBounds(itemX, itrackY, itemW, itrackH);
2607:
2608: /*
2609: * If the thumb isn't going to fit, zero it's bounds. Otherwise make
2610: * sure it fits between the buttons. Note that setting the thumbs bounds
2611: * will cause a repaint.
2612: */
2613: if (thumbH >= (int) trackH) {
2614: this .setThumbBounds(0, 0, 0, 0);
2615: } else {
2616: if ((thumbY + thumbH) > decrButton2Y) {
2617: thumbY = decrButton2Y - thumbH;
2618: }
2619: if (thumbY < 0) {
2620: thumbY = 0;
2621: }
2622: this .setThumbBounds(itemX, thumbY, itemW, thumbH);
2623: }
2624: }
2625:
2626: /**
2627: * Lays out the vertical scroll bar when the button policy is
2628: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#ADJACENT}.
2629: *
2630: * @param sb
2631: * Scroll bar.
2632: */
2633: protected void layoutVScrollbarNone(JScrollBar sb) {
2634: Dimension sbSize = sb.getSize();
2635: Insets sbInsets = sb.getInsets();
2636:
2637: /*
2638: * Width and left edge of the buttons and thumb.
2639: */
2640: int itemW = sbSize.width - (sbInsets.left + sbInsets.right);
2641: int itemX = sbInsets.left;
2642:
2643: /*
2644: * Nominal locations of the buttons, assuming their preferred size will
2645: * fit.
2646: */
2647: int incrButtonH = 0;
2648: int incrButtonY = sbSize.height
2649: - (sbInsets.bottom + incrButtonH);
2650:
2651: int decrButton2H = 0;
2652: int decrButton2Y = incrButtonY - decrButton2H;
2653:
2654: /*
2655: * The thumb must fit within the height left over after we subtract the
2656: * preferredSize of the buttons and the insets.
2657: */
2658: int sbInsetsH = sbInsets.top + sbInsets.bottom;
2659: int sbButtonsH = decrButton2H + incrButtonH;
2660: float trackH = sbSize.height - (sbInsetsH + sbButtonsH);
2661:
2662: /*
2663: * Compute the height and origin of the thumb. The case where the thumb
2664: * is at the bottom edge is handled specially to avoid numerical
2665: * problems in computing thumbY. Enforce the thumbs min/max dimensions.
2666: * If the thumb doesn't fit in the track (trackH) we'll hide it later.
2667: */
2668: float min = sb.getMinimum();
2669: float extent = sb.getVisibleAmount();
2670: float range = sb.getMaximum() - min;
2671: float value = sb.getValue();
2672:
2673: int thumbH = (range <= 0) ? this .getMaximumThumbSize().height
2674: : (int) (trackH * (extent / range));
2675: thumbH = Math.max(thumbH, this .getMinimumThumbSize().height);
2676: thumbH = Math.min(thumbH, this .getMaximumThumbSize().height);
2677:
2678: int thumbY = decrButton2Y - thumbH;
2679: if (value < (sb.getMaximum() - sb.getVisibleAmount())) {
2680: float thumbRange = trackH - thumbH;
2681: thumbY = (int) (0.5f + (thumbRange * ((value - min) / (range - extent))));
2682: }
2683:
2684: /*
2685: * If the buttons don't fit, allocate half of the available space to
2686: * each and move the lower one (incrButton) down.
2687: */
2688: int sbAvailButtonH = (sbSize.height - sbInsetsH);
2689: if (sbAvailButtonH < sbButtonsH) {
2690: incrButtonH = decrButton2H = 0;
2691: incrButtonY = sbSize.height
2692: - (sbInsets.bottom + incrButtonH);
2693: }
2694: this .decrButton.setBounds(0, 0, 0, 0);
2695: this .mySecondDecreaseButton.setBounds(0, 0, 0, 0);
2696: this .incrButton.setBounds(0, 0, 0, 0);
2697: this .mySecondIncreaseButton.setBounds(0, 0, 0, 0);
2698:
2699: /*
2700: * Update the trackRect field.
2701: */
2702: int itrackY = 0;
2703: int itrackH = decrButton2Y - itrackY;
2704: this .trackRect.setBounds(itemX, itrackY, itemW, itrackH);
2705:
2706: /*
2707: * If the thumb isn't going to fit, zero it's bounds. Otherwise make
2708: * sure it fits between the buttons. Note that setting the thumbs bounds
2709: * will cause a repaint.
2710: */
2711: if (thumbH >= (int) trackH) {
2712: this .setThumbBounds(0, 0, 0, 0);
2713: } else {
2714: if ((thumbY + thumbH) > decrButton2Y) {
2715: thumbY = decrButton2Y - thumbH;
2716: }
2717: if (thumbY < 0) {
2718: thumbY = 0;
2719: }
2720: this .setThumbBounds(itemX, thumbY, itemW, thumbH);
2721: }
2722: }
2723:
2724: /**
2725: * Lays out the vertical scroll bar when the button policy is
2726: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#MULTIPLE}.
2727: *
2728: * @param sb
2729: * Scroll bar.
2730: */
2731: protected void layoutVScrollbarMultiple(JScrollBar sb) {
2732: Dimension sbSize = sb.getSize();
2733: Insets sbInsets = sb.getInsets();
2734:
2735: /*
2736: * Width and left edge of the buttons and thumb.
2737: */
2738: int itemW = sbSize.width - (sbInsets.left + sbInsets.right);
2739: int itemX = sbInsets.left;
2740:
2741: /*
2742: * Nominal locations of the buttons, assuming their preferred size will
2743: * fit.
2744: */
2745: int incrButtonH = itemW;
2746: int incrButtonY = sbSize.height
2747: - (sbInsets.bottom + incrButtonH);
2748:
2749: int decrButton2H = itemW;
2750: int decrButton2Y = incrButtonY - decrButton2H;
2751:
2752: int decrButtonH = itemW;
2753: int decrButtonY = sbInsets.top;
2754:
2755: /*
2756: * The thumb must fit within the height left over after we subtract the
2757: * preferredSize of the buttons and the insets.
2758: */
2759: int sbInsetsH = sbInsets.top + sbInsets.bottom;
2760: int sbButtonsH = decrButton2H + incrButtonH + decrButtonH;
2761: float trackH = sbSize.height - (sbInsetsH + sbButtonsH);
2762:
2763: /*
2764: * Compute the height and origin of the thumb. The case where the thumb
2765: * is at the bottom edge is handled specially to avoid numerical
2766: * problems in computing thumbY. Enforce the thumbs min/max dimensions.
2767: * If the thumb doesn't fit in the track (trackH) we'll hide it later.
2768: */
2769: float min = sb.getMinimum();
2770: float extent = sb.getVisibleAmount();
2771: float range = sb.getMaximum() - min;
2772: float value = sb.getValue();
2773:
2774: int thumbH = (range <= 0) ? this .getMaximumThumbSize().height
2775: : (int) (trackH * (extent / range));
2776: thumbH = Math.max(thumbH, this .getMinimumThumbSize().height);
2777: thumbH = Math.min(thumbH, this .getMaximumThumbSize().height);
2778:
2779: int thumbY = decrButton2Y - thumbH;
2780: if (value < (sb.getMaximum() - sb.getVisibleAmount())) {
2781: float thumbRange = trackH - thumbH;
2782: thumbY = (int) (0.5f + (thumbRange * ((value - min) / (range - extent))));
2783: thumbY += decrButtonY + decrButtonH;
2784: }
2785:
2786: /*
2787: * If the buttons don't fit, allocate half of the available space to
2788: * each and move the lower one (incrButton) down.
2789: */
2790: int sbAvailButtonH = (sbSize.height - sbInsetsH);
2791: if (sbAvailButtonH < sbButtonsH) {
2792: incrButtonH = decrButton2H = decrButtonH = sbAvailButtonH / 2;
2793: incrButtonY = sbSize.height
2794: - (sbInsets.bottom + incrButtonH);
2795: }
2796: this .decrButton.setBounds(itemX, decrButtonY, itemW,
2797: decrButtonH);
2798: this .mySecondDecreaseButton.setBounds(itemX, incrButtonY
2799: - decrButton2H, itemW, decrButton2H);
2800: this .incrButton.setBounds(itemX, incrButtonY, itemW,
2801: incrButtonH);
2802: this .mySecondIncreaseButton.setBounds(0, 0, 0, 0);
2803:
2804: /*
2805: * Update the trackRect field.
2806: */
2807: int itrackY = decrButtonY + decrButtonH;
2808: int itrackH = decrButton2Y - itrackY;
2809: this .trackRect.setBounds(itemX, itrackY, itemW, itrackH);
2810:
2811: /*
2812: * If the thumb isn't going to fit, zero it's bounds. Otherwise make
2813: * sure it fits between the buttons. Note that setting the thumbs bounds
2814: * will cause a repaint.
2815: */
2816: if (thumbH >= (int) trackH) {
2817: this .setThumbBounds(0, 0, 0, 0);
2818: } else {
2819: if ((thumbY + thumbH) > decrButton2Y) {
2820: thumbY = decrButton2Y - thumbH;
2821: }
2822: if (thumbY < (decrButtonY + decrButtonH)) {
2823: thumbY = decrButtonY + decrButtonH + 1;
2824: }
2825: this .setThumbBounds(itemX, thumbY, itemW, thumbH);
2826: }
2827: }
2828:
2829: /**
2830: * Lays out the vertical scroll bar when the button policy is
2831: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#MULTIPLE_BOTH}.
2832: *
2833: * @param sb
2834: * Scroll bar.
2835: */
2836: protected void layoutVScrollbarMultipleBoth(JScrollBar sb) {
2837: Dimension sbSize = sb.getSize();
2838: Insets sbInsets = sb.getInsets();
2839:
2840: /*
2841: * Width and left edge of the buttons and thumb.
2842: */
2843: int itemW = sbSize.width - (sbInsets.left + sbInsets.right);
2844: int itemX = sbInsets.left;
2845:
2846: /*
2847: * Nominal locations of the buttons, assuming their preferred size will
2848: * fit.
2849: */
2850: int incrButtonH = itemW;
2851: int incrButtonY = sbSize.height
2852: - (sbInsets.bottom + incrButtonH);
2853:
2854: int decrButton2H = itemW;
2855: int decrButton2Y = incrButtonY - decrButton2H;
2856:
2857: int decrButtonH = itemW;
2858: int decrButtonY = sbInsets.top;
2859:
2860: int incrButton2H = itemW;
2861: int incrButton2Y = decrButtonY + decrButtonH;
2862:
2863: /*
2864: * The thumb must fit within the height left over after we subtract the
2865: * preferredSize of the buttons and the insets.
2866: */
2867: int sbInsetsH = sbInsets.top + sbInsets.bottom;
2868: int sbButtonsH = decrButton2H + incrButtonH + decrButtonH
2869: + incrButton2H;
2870: float trackH = sbSize.height - (sbInsetsH + sbButtonsH);
2871:
2872: /*
2873: * Compute the height and origin of the thumb. The case where the thumb
2874: * is at the bottom edge is handled specially to avoid numerical
2875: * problems in computing thumbY. Enforce the thumbs min/max dimensions.
2876: * If the thumb doesn't fit in the track (trackH) we'll hide it later.
2877: */
2878: float min = sb.getMinimum();
2879: float extent = sb.getVisibleAmount();
2880: float range = sb.getMaximum() - min;
2881: float value = sb.getValue();
2882:
2883: int thumbH = (range <= 0) ? this .getMaximumThumbSize().height
2884: : (int) (trackH * (extent / range));
2885: thumbH = Math.max(thumbH, this .getMinimumThumbSize().height);
2886: thumbH = Math.min(thumbH, this .getMaximumThumbSize().height);
2887:
2888: int thumbY = decrButton2Y - thumbH;
2889: if (value < (sb.getMaximum() - sb.getVisibleAmount())) {
2890: float thumbRange = trackH - thumbH;
2891: thumbY = (int) (0.5f + (thumbRange * ((value - min) / (range - extent))));
2892: thumbY += incrButton2Y + incrButton2H;
2893: }
2894:
2895: /*
2896: * If the buttons don't fit, allocate half of the available space to
2897: * each and move the lower one (incrButton) down.
2898: */
2899: int sbAvailButtonH = (sbSize.height - sbInsetsH);
2900: if (sbAvailButtonH < sbButtonsH) {
2901: incrButtonH = decrButton2H = decrButtonH = incrButton2H = sbAvailButtonH / 4;
2902: incrButtonY = sbSize.height
2903: - (sbInsets.bottom + incrButtonH);
2904: }
2905: this .decrButton.setBounds(itemX, decrButtonY, itemW,
2906: decrButtonH);
2907: this .mySecondDecreaseButton.setBounds(itemX, incrButtonY
2908: - decrButton2H, itemW, decrButton2H);
2909: this .incrButton.setBounds(itemX, incrButtonY, itemW,
2910: incrButtonH);
2911: this .mySecondIncreaseButton.setBounds(itemX, decrButtonY
2912: + decrButtonH, itemW, incrButton2H);
2913:
2914: /*
2915: * Update the trackRect field.
2916: */
2917: int itrackY = incrButton2Y + incrButton2H;
2918: int itrackH = decrButton2Y - itrackY;
2919: this .trackRect.setBounds(itemX, itrackY, itemW, itrackH);
2920:
2921: /*
2922: * If the thumb isn't going to fit, zero it's bounds. Otherwise make
2923: * sure it fits between the buttons. Note that setting the thumbs bounds
2924: * will cause a repaint.
2925: */
2926: if (thumbH >= (int) trackH) {
2927: this .setThumbBounds(0, 0, 0, 0);
2928: } else {
2929: if ((thumbY + thumbH) > decrButton2Y) {
2930: thumbY = decrButton2Y - thumbH;
2931: }
2932: if (thumbY < (incrButton2Y + incrButton2H)) {
2933: thumbY = incrButton2Y + incrButton2H + 1;
2934: }
2935: this .setThumbBounds(itemX, thumbY, itemW, thumbH);
2936: }
2937: }
2938:
2939: /**
2940: * Lays out the horizontal scroll bar when the button policy is
2941: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#ADJACENT}.
2942: *
2943: * @param sb
2944: * Scroll bar.
2945: */
2946: protected void layoutHScrollbarAdjacent(JScrollBar sb) {
2947: Dimension sbSize = sb.getSize();
2948: Insets sbInsets = sb.getInsets();
2949:
2950: /*
2951: * Height and top edge of the buttons and thumb.
2952: */
2953: int itemH = sbSize.height - (sbInsets.top + sbInsets.bottom);
2954: int itemY = sbInsets.top;
2955:
2956: boolean ltr = sb.getComponentOrientation().isLeftToRight();
2957:
2958: /*
2959: * Nominal locations of the buttons, assuming their preferred size will
2960: * fit.
2961: */
2962: int decrButton2W = itemH;
2963: int incrButtonW = itemH;
2964: int incrButtonX = ltr ? sbSize.width
2965: - (sbInsets.right + incrButtonW) : sbInsets.left;
2966: int decrButton2X = ltr ? incrButtonX - decrButton2W
2967: : incrButtonX + decrButton2W;
2968:
2969: /*
2970: * The thumb must fit within the width left over after we subtract the
2971: * preferredSize of the buttons and the insets.
2972: */
2973: int sbInsetsW = sbInsets.left + sbInsets.right;
2974: int sbButtonsW = decrButton2W + incrButtonW;
2975: float trackW = sbSize.width - (sbInsetsW + sbButtonsW);
2976:
2977: /*
2978: * Compute the width and origin of the thumb. Enforce the thumbs min/max
2979: * dimensions. The case where the thumb is at the right edge is handled
2980: * specially to avoid numerical problems in computing thumbX. If the
2981: * thumb doesn't fit in the track (trackH) we'll hide it later.
2982: */
2983: float min = sb.getMinimum();
2984: float max = sb.getMaximum();
2985: float extent = sb.getVisibleAmount();
2986: float range = max - min;
2987: float value = sb.getValue();
2988:
2989: int thumbW = (range <= 0) ? this .getMaximumThumbSize().width
2990: : (int) (trackW * (extent / range));
2991: thumbW = Math.max(thumbW, this .getMinimumThumbSize().width);
2992: thumbW = Math.min(thumbW, this .getMaximumThumbSize().width);
2993:
2994: int thumbX = ltr ? decrButton2X - thumbW : sbInsets.left;
2995: if (value < (max - sb.getVisibleAmount())) {
2996: float thumbRange = trackW - thumbW;
2997: if (ltr) {
2998: thumbX = (int) (0.5f + (thumbRange * ((value - min) / (range - extent))));
2999: } else {
3000: thumbX = (int) (0.5f + (thumbRange * ((max - extent - value) / (range - extent))));
3001: thumbX += decrButton2X + decrButton2W;
3002: }
3003: }
3004:
3005: /*
3006: * If the buttons don't fit, allocate half of the available space to
3007: * each and move the right one over.
3008: */
3009: int sbAvailButtonW = (sbSize.width - sbInsetsW);
3010: if (sbAvailButtonW < sbButtonsW) {
3011: incrButtonW = decrButton2W = sbAvailButtonW / 2;
3012: incrButtonX = ltr ? sbSize.width
3013: - (sbInsets.right + incrButtonW) : sbInsets.left;
3014: }
3015:
3016: this .mySecondDecreaseButton.setBounds(decrButton2X, itemY,
3017: decrButton2W, itemH);
3018: this .incrButton.setBounds(incrButtonX, itemY, incrButtonW,
3019: itemH);
3020: this .decrButton.setBounds(0, 0, 0, 0);
3021: this .mySecondIncreaseButton.setBounds(0, 0, 0, 0);
3022:
3023: /*
3024: * Update the trackRect field.
3025: */
3026: if (ltr) {
3027: int itrackX = sbInsets.left;
3028: int itrackW = decrButton2X - itrackX;
3029: this .trackRect.setBounds(itrackX, itemY, itrackW, itemH);
3030: } else {
3031: int itrackX = decrButton2X + decrButton2W;
3032: int itrackW = sbSize.width - itrackX;
3033: this .trackRect.setBounds(itrackX, itemY, itrackW, itemH);
3034: }
3035:
3036: /*
3037: * Make sure the thumb fits between the buttons. Note that setting the
3038: * thumbs bounds causes a repaint.
3039: */
3040: if (thumbW >= (int) trackW) {
3041: this .setThumbBounds(0, 0, 0, 0);
3042: } else {
3043: if (ltr) {
3044: if (thumbX + thumbW > decrButton2X) {
3045: thumbX = decrButton2X - thumbW;
3046: }
3047: if (thumbX < 0) {
3048: thumbX = 1;
3049: }
3050: } else {
3051: if (thumbX + thumbW > (sbSize.width - sbInsets.left)) {
3052: thumbX = sbSize.width - sbInsets.left - thumbW;
3053: }
3054: if (thumbX < (decrButton2X + decrButton2W)) {
3055: thumbX = decrButton2X + decrButton2W + 1;
3056: }
3057: }
3058: this .setThumbBounds(thumbX, itemY, thumbW, itemH);
3059: }
3060: }
3061:
3062: /**
3063: * Lays out the horizontal scroll bar when the button policy is
3064: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#NONE}.
3065: *
3066: * @param sb
3067: * Scroll bar.
3068: */
3069: protected void layoutHScrollbarNone(JScrollBar sb) {
3070: Dimension sbSize = sb.getSize();
3071: Insets sbInsets = sb.getInsets();
3072:
3073: /*
3074: * Height and top edge of the buttons and thumb.
3075: */
3076: int itemH = sbSize.height - (sbInsets.top + sbInsets.bottom);
3077: int itemY = sbInsets.top;
3078:
3079: boolean ltr = sb.getComponentOrientation().isLeftToRight();
3080:
3081: /*
3082: * Nominal locations of the buttons, assuming their preferred size will
3083: * fit.
3084: */
3085: int decrButton2W = 0;
3086: int incrButtonW = 0;
3087: int incrButtonX = ltr ? sbSize.width
3088: - (sbInsets.right + incrButtonW) : sbInsets.left;
3089: int decrButton2X = ltr ? incrButtonX - decrButton2W
3090: : incrButtonX + decrButton2W;
3091:
3092: /*
3093: * The thumb must fit within the width left over after we subtract the
3094: * preferredSize of the buttons and the insets.
3095: */
3096: int sbInsetsW = sbInsets.left + sbInsets.right;
3097: int sbButtonsW = decrButton2W + incrButtonW;
3098: float trackW = sbSize.width - (sbInsetsW + sbButtonsW);
3099:
3100: /*
3101: * Compute the width and origin of the thumb. Enforce the thumbs min/max
3102: * dimensions. The case where the thumb is at the right edge is handled
3103: * specially to avoid numerical problems in computing thumbX. If the
3104: * thumb doesn't fit in the track (trackH) we'll hide it later.
3105: */
3106: float min = sb.getMinimum();
3107: float max = sb.getMaximum();
3108: float extent = sb.getVisibleAmount();
3109: float range = max - min;
3110: float value = sb.getValue();
3111:
3112: int thumbW = (range <= 0) ? this .getMaximumThumbSize().width
3113: : (int) (trackW * (extent / range));
3114: thumbW = Math.max(thumbW, this .getMinimumThumbSize().width);
3115: thumbW = Math.min(thumbW, this .getMaximumThumbSize().width);
3116:
3117: int thumbX = ltr ? decrButton2X - thumbW : sbInsets.left;
3118: if (value < (max - sb.getVisibleAmount())) {
3119: float thumbRange = trackW - thumbW;
3120: if (ltr) {
3121: thumbX = (int) (0.5f + (thumbRange * ((value - min) / (range - extent))));
3122: } else {
3123: thumbX = (int) (0.5f + (thumbRange * ((max - extent - value) / (range - extent))));
3124: thumbX += decrButton2X + decrButton2W;
3125: }
3126: }
3127:
3128: /*
3129: * If the buttons don't fit, allocate half of the available space to
3130: * each and move the right one over.
3131: */
3132: int sbAvailButtonW = (sbSize.width - sbInsetsW);
3133: if (sbAvailButtonW < sbButtonsW) {
3134: incrButtonW = decrButton2W = 0;
3135: incrButtonX = ltr ? sbSize.width
3136: - (sbInsets.right + incrButtonW) : sbInsets.left;
3137: }
3138:
3139: this .incrButton.setBounds(0, 0, 0, 0);
3140: this .decrButton.setBounds(0, 0, 0, 0);
3141: this .mySecondIncreaseButton.setBounds(0, 0, 0, 0);
3142: this .mySecondDecreaseButton.setBounds(0, 0, 0, 0);
3143:
3144: /*
3145: * Update the trackRect field.
3146: */
3147: if (ltr) {
3148: int itrackX = sbInsets.left;
3149: int itrackW = decrButton2X - itrackX;
3150: this .trackRect.setBounds(itrackX, itemY, itrackW, itemH);
3151: } else {
3152: int itrackX = decrButton2X + decrButton2W;
3153: int itrackW = sbSize.width - itrackX;
3154: this .trackRect.setBounds(itrackX, itemY, itrackW, itemH);
3155: }
3156:
3157: /*
3158: * Make sure the thumb fits between the buttons. Note that setting the
3159: * thumbs bounds causes a repaint.
3160: */
3161: if (thumbW >= (int) trackW) {
3162: this .setThumbBounds(0, 0, 0, 0);
3163: } else {
3164: if (ltr) {
3165: if (thumbX + thumbW > decrButton2X) {
3166: thumbX = decrButton2X - thumbW;
3167: }
3168: if (thumbX < 0) {
3169: thumbX = 1;
3170: }
3171: } else {
3172: if (thumbX + thumbW > (sbSize.width - sbInsets.left)) {
3173: thumbX = sbSize.width - sbInsets.left - thumbW;
3174: }
3175: if (thumbX < (decrButton2X + decrButton2W)) {
3176: thumbX = decrButton2X + decrButton2W + 1;
3177: }
3178: }
3179: this .setThumbBounds(thumbX, itemY, thumbW, itemH);
3180: }
3181: }
3182:
3183: /**
3184: * Lays out the horizontal scroll bar when the button policy is
3185: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#MULTIPLE}.
3186: *
3187: * @param sb
3188: * Scroll bar.
3189: */
3190: protected void layoutHScrollbarMultiple(JScrollBar sb) {
3191: Dimension sbSize = sb.getSize();
3192: Insets sbInsets = sb.getInsets();
3193:
3194: /*
3195: * Height and top edge of the buttons and thumb.
3196: */
3197: int itemH = sbSize.height - (sbInsets.top + sbInsets.bottom);
3198: int itemY = sbInsets.top;
3199:
3200: boolean ltr = sb.getComponentOrientation().isLeftToRight();
3201:
3202: /*
3203: * Nominal locations of the buttons, assuming their preferred size will
3204: * fit.
3205: */
3206: int decrButton2W = itemH;
3207: int decrButtonW = itemH;
3208: int incrButtonW = itemH;
3209: int incrButtonX = ltr ? sbSize.width
3210: - (sbInsets.right + incrButtonW) : sbInsets.left;
3211: int decrButton2X = ltr ? incrButtonX - decrButton2W
3212: : incrButtonX + decrButton2W;
3213: int decrButtonX = ltr ? sbInsets.left : sbSize.width
3214: - sbInsets.right - decrButtonW;
3215:
3216: /*
3217: * The thumb must fit within the width left over after we subtract the
3218: * preferredSize of the buttons and the insets.
3219: */
3220: int sbInsetsW = sbInsets.left + sbInsets.right;
3221: int sbButtonsW = decrButton2W + incrButtonW + decrButtonW;
3222: float trackW = sbSize.width - (sbInsetsW + sbButtonsW);
3223:
3224: /*
3225: * Compute the width and origin of the thumb. Enforce the thumbs min/max
3226: * dimensions. The case where the thumb is at the right edge is handled
3227: * specially to avoid numerical problems in computing thumbX. If the
3228: * thumb doesn't fit in the track (trackH) we'll hide it later.
3229: */
3230: float min = sb.getMinimum();
3231: float max = sb.getMaximum();
3232: float extent = sb.getVisibleAmount();
3233: float range = max - min;
3234: float value = sb.getValue();
3235:
3236: int thumbW = (range <= 0) ? this .getMaximumThumbSize().width
3237: : (int) (trackW * (extent / range));
3238: thumbW = Math.max(thumbW, this .getMinimumThumbSize().width);
3239: thumbW = Math.min(thumbW, this .getMaximumThumbSize().width);
3240:
3241: int thumbX = ltr ? decrButton2X - thumbW : sbInsets.left;
3242: if (value < (max - sb.getVisibleAmount())) {
3243: float thumbRange = trackW - thumbW;
3244: if (ltr) {
3245: thumbX = (int) (0.5f + (thumbRange * ((value - min) / (range - extent))));
3246: thumbX += decrButtonX + decrButtonW;
3247: } else {
3248: thumbX = (int) (0.5f + (thumbRange * ((max - extent - value) / (range - extent))));
3249: thumbX += decrButton2X + decrButton2W;
3250: }
3251: }
3252:
3253: /*
3254: * If the buttons don't fit, allocate half of the available space to
3255: * each and move the right one over.
3256: */
3257: int sbAvailButtonW = (sbSize.width - sbInsetsW);
3258: if (sbAvailButtonW < sbButtonsW) {
3259: incrButtonW = decrButton2W = decrButtonW = sbAvailButtonW / 2;
3260: incrButtonX = ltr ? sbSize.width
3261: - (sbInsets.right + incrButtonW) : sbInsets.left;
3262: }
3263:
3264: this .mySecondDecreaseButton.setBounds(decrButton2X, itemY,
3265: decrButton2W, itemH);
3266: this .incrButton.setBounds(incrButtonX, itemY, incrButtonW,
3267: itemH);
3268: this .decrButton.setBounds(decrButtonX, itemY, decrButtonW,
3269: itemH);
3270: this .mySecondIncreaseButton.setBounds(0, 0, 0, 0);
3271:
3272: /*
3273: * Update the trackRect field.
3274: */
3275: if (ltr) {
3276: int itrackX = decrButtonX + decrButtonW;
3277: int itrackW = decrButton2X - itrackX;
3278: this .trackRect.setBounds(itrackX, itemY, itrackW, itemH);
3279: } else {
3280: int itrackX = decrButton2X + decrButton2W;
3281: int itrackW = decrButtonX - itrackX;
3282: this .trackRect.setBounds(itrackX, itemY, itrackW, itemH);
3283: }
3284:
3285: /*
3286: * Make sure the thumb fits between the buttons. Note that setting the
3287: * thumbs bounds causes a repaint.
3288: */
3289: if (thumbW >= (int) trackW) {
3290: this .setThumbBounds(0, 0, 0, 0);
3291: } else {
3292: if (ltr) {
3293: if (thumbX + thumbW > decrButton2X) {
3294: thumbX = decrButton2X - thumbW;
3295: }
3296: if (thumbX < (decrButtonX + decrButtonW)) {
3297: thumbX = decrButtonX + decrButtonW + 1;
3298: }
3299: } else {
3300: if (thumbX + thumbW > decrButtonX) {
3301: thumbX = decrButtonX - thumbW;
3302: }
3303: if (thumbX < (decrButton2X + decrButton2W)) {
3304: thumbX = decrButton2X + decrButton2W + 1;
3305: }
3306: }
3307: this .setThumbBounds(thumbX, itemY, thumbW, itemH);
3308: }
3309: }
3310:
3311: /**
3312: * Lays out the horizontal scroll bar when the button policy is
3313: * {@link SubstanceConstants.ScrollPaneButtonPolicyKind#MULTIPLE}.
3314: *
3315: * @param sb
3316: * Scroll bar.
3317: */
3318: protected void layoutHScrollbarMultipleBoth(JScrollBar sb) {
3319: Dimension sbSize = sb.getSize();
3320: Insets sbInsets = sb.getInsets();
3321:
3322: /*
3323: * Height and top edge of the buttons and thumb.
3324: */
3325: int itemH = sbSize.height - (sbInsets.top + sbInsets.bottom);
3326: int itemY = sbInsets.top;
3327:
3328: boolean ltr = sb.getComponentOrientation().isLeftToRight();
3329:
3330: /*
3331: * Nominal locations of the buttons, assuming their preferred size will
3332: * fit.
3333: */
3334: int decrButton2W = itemH;
3335: int incrButton2W = itemH;
3336: int decrButtonW = itemH;
3337: int incrButtonW = itemH;
3338:
3339: int incrButtonX = ltr ? sbSize.width
3340: - (sbInsets.right + incrButtonW) : sbInsets.left;
3341: int decrButton2X = ltr ? incrButtonX - decrButton2W
3342: : incrButtonX + decrButton2W;
3343: int decrButtonX = ltr ? sbInsets.left : sbSize.width
3344: - sbInsets.right - decrButtonW;
3345: int incrButton2X = ltr ? decrButtonX + decrButtonW
3346: : decrButtonX - incrButton2W;
3347:
3348: /*
3349: * The thumb must fit within the width left over after we subtract the
3350: * preferredSize of the buttons and the insets.
3351: */
3352: int sbInsetsW = sbInsets.left + sbInsets.right;
3353: int sbButtonsW = decrButton2W + incrButtonW + decrButtonW
3354: + incrButton2W;
3355: float trackW = sbSize.width - (sbInsetsW + sbButtonsW);
3356:
3357: /*
3358: * Compute the width and origin of the thumb. Enforce the thumbs min/max
3359: * dimensions. The case where the thumb is at the right edge is handled
3360: * specially to avoid numerical problems in computing thumbX. If the
3361: * thumb doesn't fit in the track (trackH) we'll hide it later.
3362: */
3363: float min = sb.getMinimum();
3364: float max = sb.getMaximum();
3365: float extent = sb.getVisibleAmount();
3366: float range = max - min;
3367: float value = sb.getValue();
3368:
3369: int thumbW = (range <= 0) ? this .getMaximumThumbSize().width
3370: : (int) (trackW * (extent / range));
3371: thumbW = Math.max(thumbW, this .getMinimumThumbSize().width);
3372: thumbW = Math.min(thumbW, this .getMaximumThumbSize().width);
3373:
3374: int thumbX = ltr ? decrButton2X - thumbW : sbInsets.left;
3375: if (value < (max - sb.getVisibleAmount())) {
3376: float thumbRange = trackW - thumbW;
3377: if (ltr) {
3378: thumbX = (int) (0.5f + (thumbRange * ((value - min) / (range - extent))));
3379: thumbX += incrButton2X + incrButton2W;
3380: } else {
3381: thumbX = (int) (0.5f + (thumbRange * ((max - extent - value) / (range - extent))));
3382: thumbX += decrButton2X + decrButton2W;
3383: }
3384: }
3385:
3386: /*
3387: * If the buttons don't fit, allocate half of the available space to
3388: * each and move the right one over.
3389: */
3390: int sbAvailButtonW = (sbSize.width - sbInsetsW);
3391: if (sbAvailButtonW < sbButtonsW) {
3392: incrButtonW = decrButton2W = decrButtonW = incrButton2W = sbAvailButtonW / 4;
3393: incrButtonX = ltr ? sbSize.width
3394: - (sbInsets.right + incrButtonW) : sbInsets.left;
3395: }
3396:
3397: this .mySecondDecreaseButton.setBounds(decrButton2X, itemY,
3398: decrButton2W, itemH);
3399: this .mySecondIncreaseButton.setBounds(incrButton2X, itemY,
3400: incrButton2W, itemH);
3401: this .incrButton.setBounds(incrButtonX, itemY, incrButtonW,
3402: itemH);
3403: this .decrButton.setBounds(decrButtonX, itemY, decrButtonW,
3404: itemH);
3405:
3406: /*
3407: * Update the trackRect field.
3408: */
3409: if (ltr) {
3410: int itrackX = incrButton2X + incrButton2W;
3411: int itrackW = decrButton2X - itrackX;
3412: this .trackRect.setBounds(itrackX, itemY, itrackW, itemH);
3413: } else {
3414: int itrackX = decrButton2X + decrButton2W;
3415: int itrackW = incrButton2X - itrackX;
3416: this .trackRect.setBounds(itrackX, itemY, itrackW, itemH);
3417: }
3418:
3419: /*
3420: * Make sure the thumb fits between the buttons. Note that setting the
3421: * thumbs bounds causes a repaint.
3422: */
3423: if (thumbW >= (int) trackW) {
3424: this .setThumbBounds(0, 0, 0, 0);
3425: } else {
3426: if (ltr) {
3427: if (thumbX + thumbW > decrButton2X) {
3428: thumbX = decrButton2X - thumbW;
3429: }
3430: if (thumbX < (incrButton2X + incrButton2W)) {
3431: thumbX = incrButton2X + incrButton2W + 1;
3432: }
3433: } else {
3434: if (thumbX + thumbW > incrButton2X) {
3435: thumbX = incrButton2X - thumbW;
3436: }
3437: if (thumbX < (decrButton2X + decrButton2W)) {
3438: thumbX = decrButton2X + decrButton2W + 1;
3439: }
3440: }
3441: this .setThumbBounds(thumbX, itemY, thumbW, itemH);
3442: }
3443: }
3444:
3445: /**
3446: * Returns the memory usage string.
3447: *
3448: * @return The memory usage string.
3449: */
3450: public static String getMemoryUsage() {
3451: StringBuffer sb = new StringBuffer();
3452: sb.append("SubstanceScrollBarUI: \n");
3453: sb.append("\t" + thumbHorizontalMap.size()
3454: + " thumb horizontal, " + thumbVerticalMap.size()
3455: + " thumb vertical");
3456: sb.append("\t" + thumbFullHorizontalMap.size()
3457: + " thumb full horizontal, "
3458: + thumbFullVerticalMap.size() + " thumb full vertical");
3459: sb.append("\t" + trackHorizontalMap.size()
3460: + " track horizontal, " + trackVerticalMap.size()
3461: + " track vertical");
3462: sb.append("\t" + trackFullHorizontalMap.size()
3463: + " track full horizontal, "
3464: + trackFullVerticalMap.size() + " track full vertical");
3465: return sb.toString();
3466: }
3467:
3468: /*
3469: * (non-Javadoc)
3470: *
3471: * @see javax.swing.plaf.basic.BasicScrollBarUI#createTrackListener()
3472: */
3473: @Override
3474: protected TrackListener createTrackListener() {
3475: return new SubstanceTrackListener();
3476: }
3477:
3478: /**
3479: * Track mouse drags. Had to take this one from BasicScrollBarUI since the
3480: * setValueForm method is private.
3481: */
3482: protected class SubstanceTrackListener extends TrackListener {
3483: /**
3484: * Current scroll direction.
3485: */
3486: private transient int direction = +1;
3487:
3488: /*
3489: * (non-Javadoc)
3490: *
3491: * @see javax.swing.plaf.basic.BasicScrollBarUI$TrackListener#mouseReleased(java.awt.event.MouseEvent)
3492: */
3493: @Override
3494: public void mouseReleased(MouseEvent e) {
3495: if (SubstanceScrollBarUI.this .isDragging) {
3496: SubstanceScrollBarUI.this .updateThumbState(e.getX(), e
3497: .getY());
3498: }
3499: if (SwingUtilities.isRightMouseButton(e)
3500: || (!SubstanceScrollBarUI.this
3501: .getSupportsAbsolutePositioning() && SwingUtilities
3502: .isMiddleMouseButton(e)))
3503: return;
3504: if (!SubstanceScrollBarUI.this .scrollbar.isEnabled())
3505: return;
3506:
3507: Rectangle r = SubstanceScrollBarUI.this .getTrackBounds();
3508: SubstanceScrollBarUI.this .scrollbar.repaint(r.x, r.y,
3509: r.width, r.height);
3510:
3511: SubstanceScrollBarUI.this .trackHighlight = NO_HIGHLIGHT;
3512: SubstanceScrollBarUI.this .isDragging = false;
3513: this .offset = 0;
3514: SubstanceScrollBarUI.this .scrollTimer.stop();
3515: SubstanceScrollBarUI.this .scrollbar
3516: .setValueIsAdjusting(false);
3517: }
3518:
3519: /*
3520: * (non-Javadoc)
3521: *
3522: * @see javax.swing.plaf.basic.BasicScrollBarUI$TrackListener#mousePressed(java.awt.event.MouseEvent)
3523: */
3524: @Override
3525: public void mousePressed(MouseEvent e) {
3526: // If the mouse is pressed above the "thumb" component then reduce
3527: // the scrollbars value by one page ("page up"), otherwise increase
3528: // it by one page. If there is no thumb then page up if the mouse is
3529: // in the upper half of the track.
3530: if (SwingUtilities.isRightMouseButton(e)
3531: || (!SubstanceScrollBarUI.this
3532: .getSupportsAbsolutePositioning() && SwingUtilities
3533: .isMiddleMouseButton(e)))
3534: return;
3535: if (!SubstanceScrollBarUI.this .scrollbar.isEnabled())
3536: return;
3537:
3538: if (!SubstanceScrollBarUI.this .scrollbar.hasFocus()
3539: && SubstanceScrollBarUI.this .scrollbar
3540: .isRequestFocusEnabled()) {
3541: SubstanceScrollBarUI.this .scrollbar.requestFocus();
3542: }
3543:
3544: SubstanceScrollBarUI.this .scrollbar
3545: .setValueIsAdjusting(true);
3546:
3547: this .currentMouseX = e.getX();
3548: this .currentMouseY = e.getY();
3549:
3550: // Clicked in the Thumb area?
3551: if (SubstanceScrollBarUI.this .getThumbBounds().contains(
3552: this .currentMouseX, this .currentMouseY)) {
3553: switch (SubstanceScrollBarUI.this .scrollbar
3554: .getOrientation()) {
3555: case JScrollBar.VERTICAL:
3556: this .offset = this .currentMouseY
3557: - SubstanceScrollBarUI.this
3558: .getThumbBounds().y;
3559: break;
3560: case JScrollBar.HORIZONTAL:
3561: this .offset = this .currentMouseX
3562: - SubstanceScrollBarUI.this
3563: .getThumbBounds().x;
3564: break;
3565: }
3566: SubstanceScrollBarUI.this .isDragging = true;
3567: return;
3568: } else if (SubstanceScrollBarUI.this
3569: .getSupportsAbsolutePositioning()
3570: && SwingUtilities.isMiddleMouseButton(e)) {
3571: switch (SubstanceScrollBarUI.this .scrollbar
3572: .getOrientation()) {
3573: case JScrollBar.VERTICAL:
3574: this .offset = SubstanceScrollBarUI.this
3575: .getThumbBounds().height / 2;
3576: break;
3577: case JScrollBar.HORIZONTAL:
3578: this .offset = SubstanceScrollBarUI.this
3579: .getThumbBounds().width / 2;
3580: break;
3581: }
3582: SubstanceScrollBarUI.this .isDragging = true;
3583: this .setValueFrom(e);
3584: return;
3585: }
3586: SubstanceScrollBarUI.this .isDragging = false;
3587:
3588: Dimension sbSize = SubstanceScrollBarUI.this .scrollbar
3589: .getSize();
3590: this .direction = +1;
3591:
3592: switch (SubstanceScrollBarUI.this .scrollbar
3593: .getOrientation()) {
3594: case JScrollBar.VERTICAL:
3595: if (SubstanceScrollBarUI.this .getThumbBounds()
3596: .isEmpty()) {
3597: int scrollbarCenter = sbSize.height / 2;
3598: this .direction = (this .currentMouseY < scrollbarCenter) ? -1
3599: : +1;
3600: } else {
3601: int thumbY = SubstanceScrollBarUI.this
3602: .getThumbBounds().y;
3603: this .direction = (this .currentMouseY < thumbY) ? -1
3604: : +1;
3605: }
3606: break;
3607: case JScrollBar.HORIZONTAL:
3608: if (SubstanceScrollBarUI.this .getThumbBounds()
3609: .isEmpty()) {
3610: int scrollbarCenter = sbSize.width / 2;
3611: this .direction = (this .currentMouseX < scrollbarCenter) ? -1
3612: : +1;
3613: } else {
3614: int thumbX = SubstanceScrollBarUI.this
3615: .getThumbBounds().x;
3616: this .direction = (this .currentMouseX < thumbX) ? -1
3617: : +1;
3618: }
3619: if (!SubstanceScrollBarUI.this .scrollbar
3620: .getComponentOrientation().isLeftToRight()) {
3621: this .direction = -this .direction;
3622: }
3623: break;
3624: }
3625: SubstanceScrollBarUI.this .scrollByBlock(this .direction);
3626:
3627: SubstanceScrollBarUI.this .scrollTimer.stop();
3628: SubstanceScrollBarUI.this .scrollListener
3629: .setDirection(this .direction);
3630: SubstanceScrollBarUI.this .scrollListener
3631: .setScrollByBlock(true);
3632: this .startScrollTimerIfNecessary();
3633: }
3634:
3635: /*
3636: * (non-Javadoc)
3637: *
3638: * @see javax.swing.plaf.basic.BasicScrollBarUI$TrackListener#mouseDragged(java.awt.event.MouseEvent)
3639: */
3640: @Override
3641: public void mouseDragged(MouseEvent e) {
3642: // Set the models value to the position of the thumb's top of
3643: // Vertical scrollbar, or the left/right of Horizontal scrollbar in
3644: // LTR / RTL scrollbar relative to the origin of
3645: // the track.
3646: if (SwingUtilities.isRightMouseButton(e)
3647: || (!SubstanceScrollBarUI.this
3648: .getSupportsAbsolutePositioning() && SwingUtilities
3649: .isMiddleMouseButton(e)))
3650: return;
3651: if (!SubstanceScrollBarUI.this .scrollbar.isEnabled()
3652: || SubstanceScrollBarUI.this .getThumbBounds()
3653: .isEmpty()) {
3654: return;
3655: }
3656: if (SubstanceScrollBarUI.this .isDragging) {
3657: this .setValueFrom(e);
3658: } else {
3659: this .currentMouseX = e.getX();
3660: this .currentMouseY = e.getY();
3661: SubstanceScrollBarUI.this .updateThumbState(
3662: this .currentMouseX, this .currentMouseY);
3663: this .startScrollTimerIfNecessary();
3664: }
3665: }
3666:
3667: /**
3668: * Sets the scrollbar value based on the specified mouse event.
3669: *
3670: * @param e
3671: * Mouse event.
3672: */
3673: private void setValueFrom(MouseEvent e) {
3674: boolean active = SubstanceScrollBarUI.this
3675: .isThumbRollover();
3676: BoundedRangeModel model = SubstanceScrollBarUI.this .scrollbar
3677: .getModel();
3678: Rectangle thumbR = SubstanceScrollBarUI.this
3679: .getThumbBounds();
3680: int thumbMin = 0, thumbMax = 0, thumbPos;
3681:
3682: ScrollPaneButtonPolicyKind buttonPolicy = SubstanceCoreUtilities
3683: .getScrollPaneButtonsPolicyKind(SubstanceScrollBarUI.this .scrollbar);
3684:
3685: if (SubstanceScrollBarUI.this .scrollbar.getOrientation() == JScrollBar.VERTICAL) {
3686: switch (buttonPolicy) {
3687: case OPPOSITE:
3688: thumbMin = SubstanceScrollBarUI.this .decrButton
3689: .getY()
3690: + SubstanceScrollBarUI.this .decrButton
3691: .getHeight();
3692: thumbMax = SubstanceScrollBarUI.this .incrButton
3693: .getY()
3694: - thumbR.height;
3695: break;
3696: case ADJACENT:
3697: thumbMin = 0;
3698: thumbMax = SubstanceScrollBarUI.this .mySecondDecreaseButton
3699: .getY()
3700: - thumbR.height;
3701: break;
3702: case NONE:
3703: thumbMin = 0;
3704: thumbMax = SubstanceScrollBarUI.this .scrollbar
3705: .getSize().height
3706: - SubstanceScrollBarUI.this .scrollbar
3707: .getInsets().bottom - thumbR.height;
3708: break;
3709: case MULTIPLE:
3710: thumbMin = SubstanceScrollBarUI.this .decrButton
3711: .getY()
3712: + SubstanceScrollBarUI.this .decrButton
3713: .getHeight();
3714: thumbMax = SubstanceScrollBarUI.this .mySecondDecreaseButton
3715: .getY()
3716: - thumbR.height;
3717: break;
3718: case MULTIPLE_BOTH:
3719: thumbMin = SubstanceScrollBarUI.this .mySecondIncreaseButton
3720: .getY()
3721: + SubstanceScrollBarUI.this .mySecondIncreaseButton
3722: .getHeight();
3723: thumbMax = SubstanceScrollBarUI.this .mySecondDecreaseButton
3724: .getY()
3725: - thumbR.height;
3726: break;
3727: }
3728:
3729: thumbPos = Math.min(thumbMax, Math.max(thumbMin, (e
3730: .getY() - this .offset)));
3731: SubstanceScrollBarUI.this .setThumbBounds(thumbR.x,
3732: thumbPos, thumbR.width, thumbR.height);
3733: } else {
3734: if (SubstanceScrollBarUI.this .scrollbar
3735: .getComponentOrientation().isLeftToRight()) {
3736: switch (buttonPolicy) {
3737: case OPPOSITE:
3738: thumbMin = SubstanceScrollBarUI.this .decrButton
3739: .getX()
3740: + SubstanceScrollBarUI.this .decrButton
3741: .getWidth();
3742: thumbMax = SubstanceScrollBarUI.this .incrButton
3743: .getX()
3744: - thumbR.width;
3745: break;
3746: case ADJACENT:
3747: thumbMin = 0;
3748: thumbMax = SubstanceScrollBarUI.this .mySecondDecreaseButton
3749: .getX()
3750: - thumbR.width;
3751: break;
3752: case MULTIPLE:
3753: thumbMin = SubstanceScrollBarUI.this .decrButton
3754: .getX()
3755: + SubstanceScrollBarUI.this .decrButton
3756: .getWidth();
3757: thumbMax = SubstanceScrollBarUI.this .mySecondDecreaseButton
3758: .getX()
3759: - thumbR.width;
3760: break;
3761: case MULTIPLE_BOTH:
3762: thumbMin = SubstanceScrollBarUI.this .mySecondIncreaseButton
3763: .getX()
3764: + SubstanceScrollBarUI.this .mySecondIncreaseButton
3765: .getWidth();
3766: thumbMax = SubstanceScrollBarUI.this .mySecondDecreaseButton
3767: .getX()
3768: - thumbR.width;
3769: break;
3770: case NONE:
3771: thumbMin = 0;
3772: thumbMax = SubstanceScrollBarUI.this .scrollbar
3773: .getSize().width
3774: - SubstanceScrollBarUI.this .scrollbar
3775: .getInsets().right
3776: - thumbR.width;
3777: break;
3778: }
3779: } else {
3780: switch (buttonPolicy) {
3781: case OPPOSITE:
3782: thumbMin = SubstanceScrollBarUI.this .incrButton
3783: .getX()
3784: + SubstanceScrollBarUI.this .incrButton
3785: .getWidth();
3786: thumbMax = SubstanceScrollBarUI.this .decrButton
3787: .getX()
3788: - thumbR.width;
3789: break;
3790: case ADJACENT:
3791: thumbMin = SubstanceScrollBarUI.this .mySecondDecreaseButton
3792: .getX()
3793: + SubstanceScrollBarUI.this .mySecondDecreaseButton
3794: .getWidth();
3795: thumbMax = SubstanceScrollBarUI.this .scrollbar
3796: .getSize().width
3797: - SubstanceScrollBarUI.this .scrollbar
3798: .getInsets().right
3799: - thumbR.width;
3800: break;
3801: case MULTIPLE:
3802: thumbMin = SubstanceScrollBarUI.this .mySecondDecreaseButton
3803: .getX()
3804: + SubstanceScrollBarUI.this .mySecondDecreaseButton
3805: .getWidth();
3806: thumbMax = SubstanceScrollBarUI.this .decrButton
3807: .getX()
3808: - thumbR.width;
3809: break;
3810: case MULTIPLE_BOTH:
3811: thumbMin = SubstanceScrollBarUI.this .mySecondDecreaseButton
3812: .getX()
3813: + SubstanceScrollBarUI.this .mySecondDecreaseButton
3814: .getWidth();
3815: thumbMax = SubstanceScrollBarUI.this .mySecondIncreaseButton
3816: .getX()
3817: - thumbR.width;
3818: break;
3819: case NONE:
3820: thumbMin = 0;
3821: thumbMax = SubstanceScrollBarUI.this .scrollbar
3822: .getSize().width
3823: - SubstanceScrollBarUI.this .scrollbar
3824: .getInsets().right
3825: - thumbR.width;
3826: break;
3827: }
3828: }
3829: // System.out.println(thumbMin + " : " + thumbMax + " : "
3830: // + (e.getX() - offset));
3831: thumbPos = Math.min(thumbMax, Math.max(thumbMin, (e
3832: .getX() - this .offset)));
3833: SubstanceScrollBarUI.this .setThumbBounds(thumbPos,
3834: thumbR.y, thumbR.width, thumbR.height);
3835: }
3836:
3837: /*
3838: * Set the scrollbars value. If the thumb has reached the end of the
3839: * scrollbar, then just set the value to its maximum. Otherwise
3840: * compute the value as accurately as possible.
3841: */
3842: if (thumbPos == thumbMax) {
3843: if (SubstanceScrollBarUI.this .scrollbar
3844: .getOrientation() == JScrollBar.VERTICAL
3845: || SubstanceScrollBarUI.this .scrollbar
3846: .getComponentOrientation()
3847: .isLeftToRight()) {
3848: SubstanceScrollBarUI.this .scrollbar.setValue(model
3849: .getMaximum()
3850: - model.getExtent());
3851: } else {
3852: SubstanceScrollBarUI.this .scrollbar.setValue(model
3853: .getMinimum());
3854: }
3855: } else {
3856: float valueMax = model.getMaximum() - model.getExtent();
3857: float valueRange = valueMax - model.getMinimum();
3858: float thumbValue = thumbPos - thumbMin;
3859: float thumbRange = thumbMax - thumbMin;
3860: int value;
3861: if (SubstanceScrollBarUI.this .scrollbar
3862: .getOrientation() == JScrollBar.VERTICAL
3863: || SubstanceScrollBarUI.this .scrollbar
3864: .getComponentOrientation()
3865: .isLeftToRight()) {
3866: value = (int) (0.5 + ((thumbValue / thumbRange) * valueRange));
3867: } else {
3868: value = (int) (0.5 + (((thumbMax - thumbPos) / thumbRange) * valueRange));
3869: }
3870:
3871: SubstanceScrollBarUI.this .scrollbar.setValue(value
3872: + model.getMinimum());
3873: }
3874: SubstanceScrollBarUI.this .setThumbRollover(active);
3875: }
3876:
3877: /**
3878: * If necessary, starts the scroll timer.
3879: */
3880: private void startScrollTimerIfNecessary() {
3881: if (SubstanceScrollBarUI.this .scrollTimer.isRunning()) {
3882: return;
3883: }
3884: switch (SubstanceScrollBarUI.this .scrollbar
3885: .getOrientation()) {
3886: case JScrollBar.VERTICAL:
3887: if (this .direction > 0) {
3888: if (SubstanceScrollBarUI.this .getThumbBounds().y
3889: + SubstanceScrollBarUI.this
3890: .getThumbBounds().height < ((SubstanceTrackListener) SubstanceScrollBarUI.this .trackListener).currentMouseY) {
3891: SubstanceScrollBarUI.this .scrollTimer.start();
3892: }
3893: } else if (SubstanceScrollBarUI.this .getThumbBounds().y > ((SubstanceTrackListener) SubstanceScrollBarUI.this .trackListener).currentMouseY) {
3894: SubstanceScrollBarUI.this .scrollTimer.start();
3895: }
3896: break;
3897: case JScrollBar.HORIZONTAL:
3898: if (this .direction > 0) {
3899: if (SubstanceScrollBarUI.this .getThumbBounds().x
3900: + SubstanceScrollBarUI.this
3901: .getThumbBounds().width < ((SubstanceTrackListener) SubstanceScrollBarUI.this .trackListener).currentMouseX) {
3902: SubstanceScrollBarUI.this .scrollTimer.start();
3903: }
3904: } else if (SubstanceScrollBarUI.this .getThumbBounds().x > ((SubstanceTrackListener) SubstanceScrollBarUI.this .trackListener).currentMouseX) {
3905: SubstanceScrollBarUI.this .scrollTimer.start();
3906: }
3907: break;
3908: }
3909: }
3910:
3911: /*
3912: * (non-Javadoc)
3913: *
3914: * @see javax.swing.plaf.basic.BasicScrollBarUI$TrackListener#mouseMoved(java.awt.event.MouseEvent)
3915: */
3916: @Override
3917: public void mouseMoved(MouseEvent e) {
3918: if (!SubstanceScrollBarUI.this .isDragging) {
3919: SubstanceScrollBarUI.this .updateThumbState(e.getX(), e
3920: .getY());
3921: }
3922: }
3923:
3924: /*
3925: * (non-Javadoc)
3926: *
3927: * @see javax.swing.plaf.basic.BasicScrollBarUI$TrackListener#mouseExited(java.awt.event.MouseEvent)
3928: */
3929: @Override
3930: public void mouseExited(MouseEvent e) {
3931: if (!SubstanceScrollBarUI.this .isDragging) {
3932: SubstanceScrollBarUI.this .setThumbRollover(false);
3933: }
3934: }
3935: }
3936:
3937: // protected class SubstanceScrollListener extends ScrollListener {
3938: // @Override
3939: // public void actionPerformed(ActionEvent e) {
3940: // System.out.println(System.currentTimeMillis() + ":action");
3941: // super.actionPerformed(e);
3942: // }
3943: // }
3944: //
3945: // @Override
3946: // protected ScrollListener createScrollListener() {
3947: // return new SubstanceScrollListener();
3948: // }
3949: //
3950: /*
3951: * (non-Javadoc)
3952: *
3953: * @see javax.swing.plaf.basic.BasicScrollBarUI#createArrowButtonListener()
3954: */
3955: @Override
3956: protected ArrowButtonListener createArrowButtonListener() {
3957: return new SubstanceArrowButtonListener();
3958: }
3959:
3960: /**
3961: * Listener on arrow buttons. Need to override the super implementation for
3962: * the {@link ScrollPaneButtonPolicyKind#MULTIPLE_BOTH} policy.
3963: *
3964: * @author Kirill Grouchnikov
3965: */
3966: protected class SubstanceArrowButtonListener extends
3967: ArrowButtonListener {
3968: /**
3969: * Because we are handling both mousePressed and Actions we need to make
3970: * sure we don't fire under both conditions. (keyfocus on scrollbars
3971: * causes action without mousePress
3972: */
3973: boolean handledEvent;
3974:
3975: /*
3976: * (non-Javadoc)
3977: *
3978: * @see javax.swing.plaf.basic.BasicScrollBarUI$ArrowButtonListener#mousePressed(java.awt.event.MouseEvent)
3979: */
3980: @Override
3981: public void mousePressed(MouseEvent e) {
3982: if (!SubstanceScrollBarUI.this .scrollbar.isEnabled()) {
3983: return;
3984: }
3985: // not an unmodified left mouse button
3986: // if(e.getModifiers() != InputEvent.BUTTON1_MASK) {return; }
3987: if (!SwingUtilities.isLeftMouseButton(e)) {
3988: return;
3989: }
3990:
3991: int direction = ((e.getSource() == SubstanceScrollBarUI.this .incrButton) || (e
3992: .getSource() == SubstanceScrollBarUI.this .mySecondIncreaseButton)) ? 1
3993: : -1;
3994:
3995: SubstanceScrollBarUI.this .scrollByUnit(direction);
3996: SubstanceScrollBarUI.this .scrollTimer.stop();
3997: SubstanceScrollBarUI.this .scrollListener
3998: .setDirection(direction);
3999: SubstanceScrollBarUI.this .scrollListener
4000: .setScrollByBlock(false);
4001: SubstanceScrollBarUI.this .scrollTimer.start();
4002:
4003: this .handledEvent = true;
4004: if (!SubstanceScrollBarUI.this .scrollbar.hasFocus()
4005: && SubstanceScrollBarUI.this .scrollbar
4006: .isRequestFocusEnabled()) {
4007: SubstanceScrollBarUI.this .scrollbar.requestFocus();
4008: }
4009: }
4010:
4011: /*
4012: * (non-Javadoc)
4013: *
4014: * @see javax.swing.plaf.basic.BasicScrollBarUI$ArrowButtonListener#mouseReleased(java.awt.event.MouseEvent)
4015: */
4016: @Override
4017: public void mouseReleased(MouseEvent e) {
4018: SubstanceScrollBarUI.this .scrollTimer.stop();
4019: this .handledEvent = false;
4020: SubstanceScrollBarUI.this .scrollbar
4021: .setValueIsAdjusting(false);
4022: }
4023: }
4024:
4025: /**
4026: * Updates the thumb state based on the coordinates.
4027: *
4028: * @param x
4029: * X coordinate.
4030: * @param y
4031: * Y coordinate.
4032: */
4033: private void updateThumbState(int x, int y) {
4034: Rectangle rect = this .getThumbBounds();
4035:
4036: this .setThumbRollover(rect.contains(x, y));
4037: }
4038:
4039: /**
4040: * Listener on policy change menu items in debug UI mode.
4041: *
4042: * @author Kirill Grouchnikov
4043: */
4044: protected class PolicyChanger implements ActionListener {
4045: /**
4046: * Policy to set.
4047: */
4048: protected ScrollPaneButtonPolicyKind newPolicy;
4049:
4050: /**
4051: * Creates a new policy change listener.
4052: *
4053: * @param newPolicy
4054: * Policy to set.
4055: */
4056: public PolicyChanger(ScrollPaneButtonPolicyKind newPolicy) {
4057: super ();
4058: this .newPolicy = newPolicy;
4059: }
4060:
4061: /*
4062: * (non-Javadoc)
4063: *
4064: * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
4065: */
4066: public void actionPerformed(ActionEvent e) {
4067: SwingUtilities.invokeLater(new Runnable() {
4068: public void run() {
4069: SubstanceScrollBarUI.this .scrollbar
4070: .putClientProperty(
4071: SubstanceLookAndFeel.SCROLL_PANE_BUTTONS_POLICY,
4072: PolicyChanger.this .newPolicy);
4073: SubstanceScrollBarUI.this .scrollbar.doLayout();
4074: SubstanceScrollBarUI.this .scrollbar.repaint();
4075: }
4076: });
4077: }
4078: }
4079:
4080: /*
4081: * (non-Javadoc)
4082: *
4083: * @see javax.swing.plaf.basic.BasicScrollBarUI#getPreferredSize(javax.swing.JComponent)
4084: */
4085: @Override
4086: public Dimension getPreferredSize(JComponent c) {
4087: if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
4088: return new Dimension(scrollBarWidth, Math.max(48,
4089: 5 * scrollBarWidth));
4090: } else {
4091: return new Dimension(Math.max(48, 5 * scrollBarWidth),
4092: scrollBarWidth);
4093: }
4094: }
4095:
4096: // /*
4097: // * (non-Javadoc)
4098: // *
4099: // * @see javax.swing.plaf.ComponentUI#update(java.awt.Graphics,
4100: // * javax.swing.JComponent)
4101: // */
4102: // @Override
4103: // public void update(Graphics g, JComponent c) {
4104: // super.update(g, c);
4105: // GhostPaintingUtils.paintGhostImages(c, g);
4106: // }
4107: }
|