@Override public void paint(Graphics2D graphics) { ScrollBar scrollBar = (ScrollBar) getComponent(); int width = getWidth(); int height = getHeight(); graphics.setPaint(scrollButtonImageColor); graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); GeneralPath arrow = new GeneralPath(GeneralPath.WIND_EVEN_ODD); if (scrollBar.getOrientation() == Orientation.HORIZONTAL) { arrow.moveTo(0, 0); arrow.lineTo(width + 0.5f, height / 2.0f); arrow.lineTo(0, height); } else { arrow.moveTo(0, 0); arrow.lineTo(width / 2.0f, height + 0.5f); arrow.lineTo(width, 0); } arrow.closePath(); // TODO Use Graphics#fillPolygon() as optimization? graphics.fill(arrow); }
@Override public void install(Component component) { super.install(component); ScrollBar scrollBar = (ScrollBar) component; scrollBar.getScrollBarListeners().add(this); scrollBar.getScrollBarValueListeners().add(this); scrollBar.add(scrollUpButton); scrollBar.add(scrollDownButton); scrollBar.add(handle); TerraTheme theme = (TerraTheme) Theme.getTheme(); Color backgroundColor = theme.getColor(9); Color brightBackgroundColor = TerraTheme.brighten(backgroundColor); GradientPaint backgroundPaint; if (scrollBar.getOrientation() == Orientation.HORIZONTAL) { backgroundPaint = new GradientPaint(0, 1, backgroundColor, 0, DEFAULT_THICKNESS - 2, brightBackgroundColor); } else { backgroundPaint = new GradientPaint(1, 0, backgroundColor, DEFAULT_THICKNESS - 2, 0, brightBackgroundColor); } setBackgroundPaint(backgroundPaint); enabledChanged(scrollBar); }
@Override public boolean mouseMove(Component component, int x, int y) { boolean consumed = super.mouseMove(component, x, y); if (Mouse.getCapturer() == component) { ScrollBar scrollBar = (ScrollBar) TerraScrollBarSkin.this.getComponent(); Orientation orientation = scrollBar.getOrientation(); // Calculate the new scroll bar value int pixelValue; if (orientation == Orientation.HORIZONTAL) { pixelValue = component.getX() - scrollUpButton.getWidth() + x - dragOffset; } else { pixelValue = component.getY() - scrollUpButton.getHeight() + y - dragOffset; } int realValue = (int) (pixelValue / getValueScale()); // Bound the value int end = scrollBar.getEnd(); int extent = scrollBar.getExtent(); realValue = Math.min(Math.max(realValue, 0), end - extent); // Update the scroll bar scrollBar.setValue(realValue); } return consumed; }
/** * Gets the scale factor that allows us to translate pixel values to scroll bar values and vice * versa. This assumes that the range of pixels spans from the last pixel of * <tt>scrollUpButton</tt> to the first pixel of <tt>scrollDownButton</tt> and excludes the pixels * taken up by <tt>handle</tt>. * * <p>To map from scroll bar values (<i>real values</i>) to pixel values, you multiply by the * value scale. To map from pixel values back to real values, you divide by the value scale. * * @return <tt><number of legal pixel values> / <number of legal real values></tt> */ private float getValueScale() { ScrollBar scrollBar = (ScrollBar) getComponent(); float valueScale; int start = scrollBar.getStart(); int end = scrollBar.getEnd(); int extent = scrollBar.getExtent(); int maxLegalRealValue = end - extent; int numLegalRealValues = maxLegalRealValue - start + 1; int numLegalPixelValues; if (scrollBar.getOrientation() == Orientation.HORIZONTAL) { int availableWidth = getWidth() - scrollUpButton.getWidth() - scrollDownButton.getWidth() + 2; numLegalPixelValues = availableWidth - handle.getWidth() + 1; } else { int availableHeight = getHeight() - scrollUpButton.getHeight() - scrollDownButton.getHeight() + 2; numLegalPixelValues = availableHeight - handle.getHeight() + 1; } // the number of segments is one less than the number of values valueScale = numLegalPixelValues / ((float) numLegalRealValues - 1); return valueScale; }
@Override public void paint(Graphics2D graphics) { // Apply scroll bar styles to the button ScrollButton scrollButton = (ScrollButton) getComponent(); ScrollBar scrollBar = (ScrollBar) TerraScrollBarSkin.this.getComponent(); Orientation orientation = scrollBar.getOrientation(); int width = getWidth(); int height = getHeight(); Color backgroundColor; if (scrollButton.isEnabled()) { if (pressed) { backgroundColor = scrollButtonPressedBackgroundColor; } else if (highlighted) { backgroundColor = scrollButtonHighlightedBackgroundColor; } else { backgroundColor = scrollButtonBackgroundColor; } } else { backgroundColor = scrollButtonDisabledBackgroundColor; } Color brightBackgroundColor = TerraTheme.brighten(backgroundColor); // Paint the background Color gradientStartColor = pressed ? backgroundColor : brightBackgroundColor; Color gradientEndColor = pressed ? brightBackgroundColor : backgroundColor; if (orientation == Orientation.HORIZONTAL) { graphics.setPaint( new GradientPaint(0, 1, gradientStartColor, 0, height - 2, gradientEndColor)); } else { graphics.setPaint( new GradientPaint(1, 0, gradientStartColor, width - 2, 0, gradientEndColor)); } graphics.fillRect(1, 1, width - 2, height - 2); // Paint the border graphics.setPaint(borderColor); GraphicsUtilities.drawRect(graphics, 0, 0, width, height); // Determine the button image size ScrollButtonImage buttonImage = scrollButton.getButtonImage(); int buttonImageWidth = buttonImage.getWidth(); int buttonImageHeight = buttonImage.getHeight(); // Paint the image Graphics2D imageGraphics = (Graphics2D) graphics.create(); int buttonImageX = (width - buttonImageWidth) / 2; int buttonImageY = (height - buttonImageHeight) / 2; imageGraphics.translate(buttonImageX, buttonImageY); imageGraphics.clipRect(0, 0, buttonImageWidth, buttonImageHeight); buttonImage.paint(imageGraphics); imageGraphics.dispose(); }
@Override public void paint(Graphics2D graphics) { ScrollBar scrollBar = (ScrollBar) TerraScrollBarSkin.this.getComponent(); Orientation orientation = scrollBar.getOrientation(); int width = getWidth(); int height = getHeight(); // Paint the background Color backgroundColor = highlighted ? scrollButtonHighlightedBackgroundColor : scrollButtonBackgroundColor; Color brightBackgroundColor = TerraTheme.brighten(backgroundColor); Color darkBackgroundColor = TerraTheme.darken(backgroundColor); if (orientation == Orientation.HORIZONTAL) { graphics.setPaint( new GradientPaint(0, 1, brightBackgroundColor, 0, height - 2, backgroundColor)); } else { graphics.setPaint( new GradientPaint(1, 0, brightBackgroundColor, width - 2, 0, backgroundColor)); } graphics.fillRect(1, 1, width - 2, height - 2); // Paint the border graphics.setPaint(borderColor); graphics.setStroke(new BasicStroke()); GraphicsUtilities.drawRect(graphics, 0, 0, width, height); // Paint the hash marks if (orientation == Orientation.HORIZONTAL) { int middle = width / 2; graphics.setPaint(darkBackgroundColor); graphics.drawLine(middle - 3, 4, middle - 3, height - 5); graphics.drawLine(middle, 4, middle, height - 5); graphics.drawLine(middle + 3, 4, middle + 3, height - 5); graphics.setPaint(brightBackgroundColor); graphics.drawLine(middle - 2, 4, middle - 2, height - 5); graphics.drawLine(middle + 1, 4, middle + 1, height - 5); graphics.drawLine(middle + 4, 4, middle + 4, height - 5); } else { int middle = height / 2; graphics.setPaint(darkBackgroundColor); graphics.drawLine(4, middle - 3, width - 5, middle - 3); graphics.drawLine(4, middle, width - 5, middle); graphics.drawLine(4, middle + 3, width - 5, middle + 3); graphics.setPaint(brightBackgroundColor); graphics.drawLine(4, middle - 2, width - 5, middle - 2); graphics.drawLine(4, middle + 1, width - 5, middle + 1); graphics.drawLine(4, middle + 4, width - 5, middle + 4); } }
@Override public int getPreferredHeight(int width) { ScrollBar scrollBar = (ScrollBar) getComponent(); int preferredHeight = 0; if (scrollBar.getOrientation() == Orientation.HORIZONTAL) { preferredHeight = DEFAULT_THICKNESS; } else { preferredHeight = DEFAULT_LENGTH; } return preferredHeight; }
@Override public boolean mouseDown(Component component, Mouse.Button button, int x, int y) { boolean consumed = super.mouseDown(component, button, x, y); if (button == Mouse.Button.LEFT) { ScrollBar scrollBar = (ScrollBar) TerraScrollBarSkin.this.getComponent(); Orientation orientation = scrollBar.getOrientation(); dragOffset = (orientation == Orientation.HORIZONTAL ? x : y); Mouse.capture(component); consumed = true; } return consumed; }
/** * Initiates automatic block scrolling. This only happens if the handle is visible since whether * the user clicked before or after the handle determines the direction of the scrolling. * * @param component The scroll bar. * @param button The button that was pressed. * @param x The x-coordinate of the event in the scroll bar's coordinate space. * @param y The y-coordinate of the event in the scroll bar's coordinate space. */ @Override public boolean mouseDown(Component component, Mouse.Button button, int x, int y) { boolean consumed = super.mouseDown(component, button, x, y); if (button == Mouse.Button.LEFT && handle.isVisible()) { ScrollBar scrollBar = (ScrollBar) getComponent(); // Begin automatic block scrolling. Calculate the direction of // the scroll by checking to see if the user pressed the mouse // in the area "before" the handle or "after" it. int direction; int realStopValue; if (scrollBar.getOrientation() == Orientation.HORIZONTAL) { direction = x < handle.getX() ? -1 : 1; int pixelStopValue = x - scrollUpButton.getWidth() + 1; if (direction == 1) { // If we're scrolling down, account for the width of the // handle in our pixel stop value so that we stop as soon // as the *bottom* of the handle reaches our click point pixelStopValue -= handle.getWidth(); } realStopValue = (int) (pixelStopValue / getValueScale()); } else { direction = y < handle.getY() ? -1 : 1; int pixelStopValue = y - scrollUpButton.getHeight() + 1; if (direction == 1) { // If we're scrolling down, account for the height of the // handle in our pixel stop value so that we stop as soon // as the *bottom* of the handle reaches our click point pixelStopValue -= handle.getHeight(); } realStopValue = (int) (pixelStopValue / getValueScale()); } // Start the automatic scroller automaticScroller.start(direction, Mouse.ScrollType.BLOCK, realStopValue); consumed = true; } return consumed; }
@Override public void paint(Graphics2D graphics) { super.paint(graphics); ScrollBar scrollBar = (ScrollBar) getComponent(); int width = getWidth(); int height = getHeight(); graphics.setPaint(borderColor); // Paint the scroll bar border lines if (scrollBar.getOrientation() == Orientation.HORIZONTAL) { int scrollUpButtonWidth = scrollUpButton.getWidth(); int scrollDownButtonWidth = scrollDownButton.getWidth(); GraphicsUtilities.drawLine( graphics, scrollUpButtonWidth, 0, width - scrollDownButtonWidth - scrollUpButtonWidth, Orientation.HORIZONTAL); GraphicsUtilities.drawLine( graphics, scrollUpButtonWidth, height - 1, width - scrollDownButtonWidth - scrollUpButtonWidth, Orientation.HORIZONTAL); } else { int scrollUpButtonHeight = scrollUpButton.getHeight(); int scrollDownButtonHeight = scrollDownButton.getHeight(); GraphicsUtilities.drawLine( graphics, 0, scrollUpButtonHeight, height - scrollDownButtonHeight - scrollUpButtonHeight, Orientation.VERTICAL); GraphicsUtilities.drawLine( graphics, width - 1, scrollUpButtonHeight, height - scrollDownButtonHeight - scrollUpButtonHeight, Orientation.VERTICAL); } }
@Override public Dimensions getPreferredSize() { ScrollBar scrollBar = (ScrollBar) getComponent(); int preferredWidth = 0; int preferredHeight = 0; if (scrollBar.getOrientation() == Orientation.HORIZONTAL) { preferredWidth = DEFAULT_LENGTH; preferredHeight = DEFAULT_THICKNESS; } else { preferredWidth = DEFAULT_THICKNESS; preferredHeight = DEFAULT_LENGTH; } return new Dimensions(preferredWidth, preferredHeight); }
@Override public void valueChanged(ScrollBar scrollBar, int previousValue) { // Invalidating the component would yield the correct behavior but // would be overkill. If all that has changed is the value, we can just // update the handle's location and save the work of full invalidation. if (handle.isVisible()) { int value = scrollBar.getValue(); if (scrollBar.getOrientation() == Orientation.HORIZONTAL) { int handleX = (int) (value * getValueScale()) + scrollUpButton.getWidth() - 1; handle.setLocation(handleX, 0); } else { int handleY = (int) (value * getValueScale()) + scrollUpButton.getHeight() - 1; handle.setLocation(0, handleY); } } }
@Override public void layout() { ScrollBar scrollBar = (ScrollBar) getComponent(); int width = getWidth(); int height = getHeight(); int start = scrollBar.getStart(); int end = scrollBar.getEnd(); int extent = scrollBar.getExtent(); int value = scrollBar.getValue(); int maxLegalRealValue = end - extent; int numLegalRealValues = maxLegalRealValue - start + 1; float extentPercentage = (float) extent / (float) (end - start); if (scrollBar.getOrientation() == Orientation.HORIZONTAL) { scrollUpButton.setSize(scrollUpButton.getPreferredWidth(-1), height); scrollUpButton.setLocation(0, 0); scrollDownButton.setSize(scrollDownButton.getPreferredWidth(-1), height); scrollDownButton.setLocation(width - scrollDownButton.getWidth(), 0); if (scrollBar.isEnabled()) { // Calculate the handle width first, as it dictates how much // room is left to represent the range of legal values. Note // that the handle may overlap each scroll button by 1px so // that its borders merge into the borders of the scroll buttons int availableWidth = width - scrollUpButton.getWidth() - scrollDownButton.getWidth() + 2; int handleWidth = Math.max(minimumHandleLength, Math.round(extentPercentage * availableWidth)); // Calculate the position of the handle by calculating the // scale that maps logical value to pixel value int numLegalPixelValues = availableWidth - handleWidth + 1; float valueScale = (float) numLegalPixelValues / (float) numLegalRealValues; int handleX = (int) (value * valueScale) + scrollUpButton.getWidth() - 1; if (handleWidth > availableWidth) { // If we can't fit the handle, we hide it handle.setVisible(false); } else { handle.setVisible(true); handle.setSize(handleWidth, height); handle.setLocation(handleX, 0); } } else { handle.setVisible(false); } } else { scrollUpButton.setSize(width, scrollUpButton.getPreferredHeight(-1)); scrollUpButton.setLocation(0, 0); scrollDownButton.setSize(width, scrollDownButton.getPreferredHeight(-1)); scrollDownButton.setLocation(0, height - scrollDownButton.getHeight()); if (scrollBar.isEnabled()) { // Calculate the handle height first, as it dictates how much // room is left to represent the range of legal values. Note // that the handle may overlap each scroll button by 1px so // that its borders merge into the borders of the scroll buttons int availableHeight = height - scrollUpButton.getHeight() - scrollDownButton.getHeight() + 2; int handleHeight = Math.max(minimumHandleLength, Math.round(extentPercentage * availableHeight)); // Calculate the position of the handle by calculating the // scale maps logical value to pixel value int numLegalPixelValues = availableHeight - handleHeight + 1; float valueScale = (float) numLegalPixelValues / (float) numLegalRealValues; int handleY = (int) (value * valueScale) + scrollUpButton.getHeight() - 1; if (handleHeight > availableHeight) { // If we can't fit the handle, we hide it handle.setVisible(false); } else { handle.setVisible(true); handle.setSize(width, handleHeight); handle.setLocation(0, handleY); } } else { handle.setVisible(false); } } }
@Override public int getHeight() { ScrollBar scrollBar = (ScrollBar) getComponent(); Orientation orientation = scrollBar.getOrientation(); return (orientation == Orientation.HORIZONTAL ? 7 : 5); }