0N/A/*
2362N/A * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage com.sun.java.swing.plaf.windows;
0N/A
0N/Aimport java.awt.*;
0N/Aimport java.awt.event.*;
0N/Aimport java.awt.image.*;
0N/Aimport java.lang.ref.*;
0N/Aimport java.util.*;
0N/Aimport javax.swing.plaf.basic.*;
0N/Aimport javax.swing.*;
0N/Aimport javax.swing.plaf.ComponentUI;
0N/A
0N/Aimport static com.sun.java.swing.plaf.windows.TMSchema.*;
0N/Aimport static com.sun.java.swing.plaf.windows.XPStyle.Skin;
0N/A
0N/A
0N/A/**
0N/A * Windows rendition of the component.
0N/A * <p>
0N/A * <strong>Warning:</strong>
0N/A * Serialized objects of this class will not be compatible with
0N/A * future Swing releases. The current serialization support is appropriate
0N/A * for short term storage or RMI between applications running the same
0N/A * version of Swing. A future release of Swing will provide support for
0N/A * long term persistence.
0N/A */
0N/Apublic class WindowsScrollBarUI extends BasicScrollBarUI {
0N/A private Grid thumbGrid;
0N/A private Grid highlightGrid;
0N/A
0N/A /**
0N/A * Creates a UI for a JScrollBar.
0N/A *
0N/A * @param c the text field
0N/A * @return the UI
0N/A */
0N/A public static ComponentUI createUI(JComponent c) {
0N/A return new WindowsScrollBarUI();
0N/A }
0N/A
0N/A protected void installDefaults() {
0N/A super.installDefaults();
0N/A
0N/A if (XPStyle.getXP() != null) {
0N/A scrollbar.setBorder(null);
0N/A }
0N/A }
0N/A
0N/A public void uninstallUI(JComponent c) {
0N/A super.uninstallUI(c);
0N/A thumbGrid = highlightGrid = null;
0N/A }
0N/A
0N/A protected void configureScrollBarColors() {
0N/A super.configureScrollBarColors();
0N/A Color color = UIManager.getColor("ScrollBar.trackForeground");
0N/A if (color != null && trackColor != null) {
0N/A thumbGrid = Grid.getGrid(color, trackColor);
0N/A }
0N/A
0N/A color = UIManager.getColor("ScrollBar.trackHighlightForeground");
0N/A if (color != null && trackHighlightColor != null) {
0N/A highlightGrid = Grid.getGrid(color, trackHighlightColor);
0N/A }
0N/A }
0N/A
0N/A protected JButton createDecreaseButton(int orientation) {
0N/A return new WindowsArrowButton(orientation,
0N/A UIManager.getColor("ScrollBar.thumb"),
0N/A UIManager.getColor("ScrollBar.thumbShadow"),
0N/A UIManager.getColor("ScrollBar.thumbDarkShadow"),
0N/A UIManager.getColor("ScrollBar.thumbHighlight"));
0N/A }
0N/A
0N/A protected JButton createIncreaseButton(int orientation) {
0N/A return new WindowsArrowButton(orientation,
0N/A UIManager.getColor("ScrollBar.thumb"),
0N/A UIManager.getColor("ScrollBar.thumbShadow"),
0N/A UIManager.getColor("ScrollBar.thumbDarkShadow"),
0N/A UIManager.getColor("ScrollBar.thumbHighlight"));
0N/A }
0N/A
0N/A /**
0N/A * {@inheritDoc}
0N/A * @since 1.6
0N/A */
0N/A @Override
0N/A protected ArrowButtonListener createArrowButtonListener(){
0N/A // we need to repaint the entire scrollbar because state change for each
0N/A // button causes a state change for the thumb and other button on Vista
0N/A if(XPStyle.isVista()) {
0N/A return new ArrowButtonListener() {
0N/A public void mouseEntered(MouseEvent evt) {
0N/A repaint();
0N/A super.mouseEntered(evt);
0N/A }
0N/A public void mouseExited(MouseEvent evt) {
0N/A repaint();
0N/A super.mouseExited(evt);
0N/A }
0N/A private void repaint() {
0N/A scrollbar.repaint();
0N/A }
0N/A };
0N/A } else {
0N/A return super.createArrowButtonListener();
0N/A }
0N/A }
0N/A
0N/A protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds){
0N/A boolean v = (scrollbar.getOrientation() == JScrollBar.VERTICAL);
0N/A
0N/A XPStyle xp = XPStyle.getXP();
0N/A if (xp != null) {
0N/A JScrollBar sb = (JScrollBar)c;
0N/A State state = State.NORMAL;
0N/A // Pending: Implement rollover (hot) and pressed
0N/A if (!sb.isEnabled()) {
0N/A state = State.DISABLED;
0N/A }
0N/A Part part = v ? Part.SBP_LOWERTRACKVERT : Part.SBP_LOWERTRACKHORZ;
0N/A xp.getSkin(sb, part).paintSkin(g, trackBounds, state);
0N/A } else if (thumbGrid == null) {
0N/A super.paintTrack(g, c, trackBounds);
0N/A }
0N/A else {
0N/A thumbGrid.paint(g, trackBounds.x, trackBounds.y, trackBounds.width,
0N/A trackBounds.height);
0N/A if (trackHighlight == DECREASE_HIGHLIGHT) {
0N/A paintDecreaseHighlight(g);
0N/A }
0N/A else if (trackHighlight == INCREASE_HIGHLIGHT) {
0N/A paintIncreaseHighlight(g);
0N/A }
0N/A }
0N/A }
0N/A
0N/A protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) {
0N/A boolean v = (scrollbar.getOrientation() == JScrollBar.VERTICAL);
0N/A
0N/A XPStyle xp = XPStyle.getXP();
0N/A if (xp != null) {
0N/A JScrollBar sb = (JScrollBar)c;
0N/A State state = State.NORMAL;
0N/A if (!sb.isEnabled()) {
0N/A state = State.DISABLED;
0N/A } else if (isDragging) {
0N/A state = State.PRESSED;
0N/A } else if (isThumbRollover()) {
0N/A state = State.HOT;
0N/A } else if (XPStyle.isVista()) {
0N/A if ((incrButton != null && incrButton.getModel().isRollover()) ||
0N/A (decrButton != null && decrButton.getModel().isRollover())) {
0N/A state = State.HOVER;
0N/A }
0N/A }
0N/A // Paint thumb
0N/A Part thumbPart = v ? Part.SBP_THUMBBTNVERT : Part.SBP_THUMBBTNHORZ;
0N/A xp.getSkin(sb, thumbPart).paintSkin(g, thumbBounds, state);
0N/A // Paint gripper
0N/A Part gripperPart = v ? Part.SBP_GRIPPERVERT : Part.SBP_GRIPPERHORZ;
0N/A Skin skin = xp.getSkin(sb, gripperPart);
0N/A Insets gripperInsets = xp.getMargin(c, thumbPart, null, Prop.CONTENTMARGINS);
0N/A if (gripperInsets == null ||
0N/A (v && (thumbBounds.height - gripperInsets.top -
0N/A gripperInsets.bottom >= skin.getHeight())) ||
0N/A (!v && (thumbBounds.width - gripperInsets.left -
0N/A gripperInsets.right >= skin.getWidth()))) {
0N/A skin.paintSkin(g,
0N/A thumbBounds.x + (thumbBounds.width - skin.getWidth()) / 2,
0N/A thumbBounds.y + (thumbBounds.height - skin.getHeight()) / 2,
0N/A skin.getWidth(), skin.getHeight(), state);
0N/A }
0N/A } else {
0N/A super.paintThumb(g, c, thumbBounds);
0N/A }
0N/A }
0N/A
0N/A
0N/A protected void paintDecreaseHighlight(Graphics g) {
0N/A if (highlightGrid == null) {
0N/A super.paintDecreaseHighlight(g);
0N/A }
0N/A else {
0N/A Insets insets = scrollbar.getInsets();
0N/A Rectangle thumbR = getThumbBounds();
0N/A int x, y, w, h;
0N/A
0N/A if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
0N/A x = insets.left;
0N/A y = decrButton.getY() + decrButton.getHeight();
0N/A w = scrollbar.getWidth() - (insets.left + insets.right);
0N/A h = thumbR.y - y;
0N/A }
0N/A else {
0N/A x = decrButton.getX() + decrButton.getHeight();
0N/A y = insets.top;
0N/A w = thumbR.x - x;
0N/A h = scrollbar.getHeight() - (insets.top + insets.bottom);
0N/A }
0N/A highlightGrid.paint(g, x, y, w, h);
0N/A }
0N/A }
0N/A
0N/A
0N/A protected void paintIncreaseHighlight(Graphics g) {
0N/A if (highlightGrid == null) {
0N/A super.paintDecreaseHighlight(g);
0N/A }
0N/A else {
0N/A Insets insets = scrollbar.getInsets();
0N/A Rectangle thumbR = getThumbBounds();
0N/A int x, y, w, h;
0N/A
0N/A if (scrollbar.getOrientation() == JScrollBar.VERTICAL) {
0N/A x = insets.left;
0N/A y = thumbR.y + thumbR.height;
0N/A w = scrollbar.getWidth() - (insets.left + insets.right);
0N/A h = incrButton.getY() - y;
0N/A }
0N/A else {
0N/A x = thumbR.x + thumbR.width;
0N/A y = insets.top;
0N/A w = incrButton.getX() - x;
0N/A h = scrollbar.getHeight() - (insets.top + insets.bottom);
0N/A }
0N/A highlightGrid.paint(g, x, y, w, h);
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * {@inheritDoc}
0N/A * @since 1.6
0N/A */
0N/A @Override
0N/A protected void setThumbRollover(boolean active) {
0N/A boolean old = isThumbRollover();
0N/A super.setThumbRollover(active);
0N/A // we need to repaint the entire scrollbar because state change for thumb
0N/A // causes state change for incr and decr buttons on Vista
0N/A if(XPStyle.isVista() && active != old) {
0N/A scrollbar.repaint();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * WindowsArrowButton is used for the buttons to position the
0N/A * document up/down. It differs from BasicArrowButton in that the
0N/A * preferred size is always a square.
0N/A */
0N/A private class WindowsArrowButton extends BasicArrowButton {
0N/A
0N/A public WindowsArrowButton(int direction, Color background, Color shadow,
0N/A Color darkShadow, Color highlight) {
0N/A super(direction, background, shadow, darkShadow, highlight);
0N/A }
0N/A
0N/A public WindowsArrowButton(int direction) {
0N/A super(direction);
0N/A }
0N/A
0N/A public void paint(Graphics g) {
0N/A XPStyle xp = XPStyle.getXP();
0N/A if (xp != null) {
0N/A ButtonModel model = getModel();
0N/A Skin skin = xp.getSkin(this, Part.SBP_ARROWBTN);
0N/A State state = null;
0N/A
0N/A boolean jointRollover = XPStyle.isVista() && (isThumbRollover() ||
0N/A (this == incrButton && decrButton.getModel().isRollover()) ||
0N/A (this == decrButton && incrButton.getModel().isRollover()));
0N/A
0N/A // normal, rollover, pressed, disabled
0N/A if (model.isArmed() && model.isPressed()) {
0N/A switch (direction) {
0N/A case NORTH: state = State.UPPRESSED; break;
0N/A case SOUTH: state = State.DOWNPRESSED; break;
0N/A case WEST: state = State.LEFTPRESSED; break;
0N/A case EAST: state = State.RIGHTPRESSED; break;
0N/A }
0N/A } else if (!model.isEnabled()) {
0N/A switch (direction) {
0N/A case NORTH: state = State.UPDISABLED; break;
0N/A case SOUTH: state = State.DOWNDISABLED; break;
0N/A case WEST: state = State.LEFTDISABLED; break;
0N/A case EAST: state = State.RIGHTDISABLED; break;
0N/A }
0N/A } else if (model.isRollover() || model.isPressed()) {
0N/A switch (direction) {
0N/A case NORTH: state = State.UPHOT; break;
0N/A case SOUTH: state = State.DOWNHOT; break;
0N/A case WEST: state = State.LEFTHOT; break;
0N/A case EAST: state = State.RIGHTHOT; break;
0N/A }
0N/A } else if (jointRollover) {
0N/A switch (direction) {
0N/A case NORTH: state = State.UPHOVER; break;
0N/A case SOUTH: state = State.DOWNHOVER; break;
0N/A case WEST: state = State.LEFTHOVER; break;
0N/A case EAST: state = State.RIGHTHOVER; break;
0N/A }
0N/A } else {
0N/A switch (direction) {
0N/A case NORTH: state = State.UPNORMAL; break;
0N/A case SOUTH: state = State.DOWNNORMAL; break;
0N/A case WEST: state = State.LEFTNORMAL; break;
0N/A case EAST: state = State.RIGHTNORMAL; break;
0N/A }
0N/A }
0N/A
0N/A skin.paintSkin(g, 0, 0, getWidth(), getHeight(), state);
0N/A } else {
0N/A super.paint(g);
0N/A }
0N/A }
0N/A
0N/A public Dimension getPreferredSize() {
0N/A int size = 16;
0N/A if (scrollbar != null) {
0N/A switch (scrollbar.getOrientation()) {
0N/A case JScrollBar.VERTICAL:
0N/A size = scrollbar.getWidth();
0N/A break;
0N/A case JScrollBar.HORIZONTAL:
0N/A size = scrollbar.getHeight();
0N/A break;
0N/A }
0N/A size = Math.max(size, 5);
0N/A }
0N/A return new Dimension(size, size);
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * This should be pulled out into its own class if more classes need to
0N/A * use it.
0N/A * <p>
0N/A * Grid is used to draw the track for windows scrollbars. Grids
0N/A * are cached in a HashMap, with the key being the rgb components
0N/A * of the foreground/background colors. Further the Grid is held through
0N/A * a WeakRef so that it can be freed when no longer needed. As the
0N/A * Grid is rather expensive to draw, it is drawn in a BufferedImage.
0N/A */
0N/A private static class Grid {
0N/A private static final int BUFFER_SIZE = 64;
614N/A private static HashMap<String, WeakReference<Grid>> map;
0N/A
0N/A private BufferedImage image;
0N/A
0N/A static {
614N/A map = new HashMap<String, WeakReference<Grid>>();
0N/A }
0N/A
0N/A public static Grid getGrid(Color fg, Color bg) {
0N/A String key = fg.getRGB() + " " + bg.getRGB();
614N/A WeakReference<Grid> ref = map.get(key);
614N/A Grid grid = (ref == null) ? null : ref.get();
0N/A if (grid == null) {
0N/A grid = new Grid(fg, bg);
614N/A map.put(key, new WeakReference<Grid>(grid));
0N/A }
0N/A return grid;
0N/A }
0N/A
0N/A public Grid(Color fg, Color bg) {
0N/A int cmap[] = { fg.getRGB(), bg.getRGB() };
0N/A IndexColorModel icm = new IndexColorModel(8, 2, cmap, 0, false, -1,
0N/A DataBuffer.TYPE_BYTE);
0N/A image = new BufferedImage(BUFFER_SIZE, BUFFER_SIZE,
0N/A BufferedImage.TYPE_BYTE_INDEXED, icm);
0N/A Graphics g = image.getGraphics();
0N/A try {
0N/A g.setClip(0, 0, BUFFER_SIZE, BUFFER_SIZE);
0N/A paintGrid(g, fg, bg);
0N/A }
0N/A finally {
0N/A g.dispose();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Paints the grid into the specified Graphics at the specified
0N/A * location.
0N/A */
0N/A public void paint(Graphics g, int x, int y, int w, int h) {
0N/A Rectangle clipRect = g.getClipBounds();
0N/A int minX = Math.max(x, clipRect.x);
0N/A int minY = Math.max(y, clipRect.y);
0N/A int maxX = Math.min(clipRect.x + clipRect.width, x + w);
0N/A int maxY = Math.min(clipRect.y + clipRect.height, y + h);
0N/A
0N/A if (maxX <= minX || maxY <= minY) {
0N/A return;
0N/A }
0N/A int xOffset = (minX - x) % 2;
0N/A for (int xCounter = minX; xCounter < maxX;
0N/A xCounter += BUFFER_SIZE) {
0N/A int yOffset = (minY - y) % 2;
0N/A int width = Math.min(BUFFER_SIZE - xOffset,
0N/A maxX - xCounter);
0N/A
0N/A for (int yCounter = minY; yCounter < maxY;
0N/A yCounter += BUFFER_SIZE) {
0N/A int height = Math.min(BUFFER_SIZE - yOffset,
0N/A maxY - yCounter);
0N/A
0N/A g.drawImage(image, xCounter, yCounter,
0N/A xCounter + width, yCounter + height,
0N/A xOffset, yOffset,
0N/A xOffset + width, yOffset + height, null);
0N/A if (yOffset != 0) {
0N/A yCounter -= yOffset;
0N/A yOffset = 0;
0N/A }
0N/A }
0N/A if (xOffset != 0) {
0N/A xCounter -= xOffset;
0N/A xOffset = 0;
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Actually renders the grid into the Graphics <code>g</code>.
0N/A */
0N/A private void paintGrid(Graphics g, Color fg, Color bg) {
0N/A Rectangle clipRect = g.getClipBounds();
0N/A g.setColor(bg);
0N/A g.fillRect(clipRect.x, clipRect.y, clipRect.width,
0N/A clipRect.height);
0N/A g.setColor(fg);
0N/A g.translate(clipRect.x, clipRect.y);
0N/A int width = clipRect.width;
0N/A int height = clipRect.height;
0N/A int xCounter = clipRect.x % 2;
0N/A for (int end = width - height; xCounter < end; xCounter += 2) {
0N/A g.drawLine(xCounter, 0, xCounter + height, height);
0N/A }
0N/A for (int end = width; xCounter < end; xCounter += 2) {
0N/A g.drawLine(xCounter, 0, width, width - xCounter);
0N/A }
0N/A
0N/A int yCounter = ((clipRect.x % 2) == 0) ? 2 : 1;
0N/A for (int end = height - width; yCounter < end; yCounter += 2) {
0N/A g.drawLine(0, yCounter, width, yCounter + width);
0N/A }
0N/A for (int end = height; yCounter < end; yCounter += 2) {
0N/A g.drawLine(0, yCounter, height - yCounter, height);
0N/A }
0N/A g.translate(-clipRect.x, -clipRect.y);
0N/A }
0N/A }
0N/A}