Source Code Cross Referenced for SubstanceScrollBarUI.java in  » Swing-Library » substance-look-feel » org » jvnet » substance » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Swing Library » substance look feel » org.jvnet.substance 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.