All Downloads are FREE. Search and download functionalities are using the official Maven repository.

META-INF.modules.java.desktop.classes.javax.swing.plaf.synth.SynthSliderUI Maven / Gradle / Ivy

/*
 * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package javax.swing.plaf.synth;

import java.awt.event.*;
import java.awt.Graphics;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Rectangle;
import java.awt.Point;
import java.awt.Insets;
import java.beans.*;
import java.util.Dictionary;
import java.util.Enumeration;
import javax.swing.*;
import javax.swing.plaf.*;
import javax.swing.plaf.basic.BasicSliderUI;
import sun.swing.SwingUtilities2;


/**
 * Provides the Synth L&F UI delegate for
 * {@link JSlider}.
 *
 * @author Joshua Outwater
 * @since 1.7
 */
public class SynthSliderUI extends BasicSliderUI
                           implements PropertyChangeListener, SynthUI {
    private Rectangle valueRect = new Rectangle();
    private boolean paintValue;

    /**
     * When a JSlider is used as a renderer in a JTable, its layout is not
     * being recomputed even though the size is changing. Even though there
     * is a ComponentListener installed, it is not being notified. As such,
     * at times when being asked to paint the layout should first be redone.
     * At the end of the layout method we set this lastSize variable, which
     * represents the size of the slider the last time it was laid out.
     *
     * In the paint method we then check to see that this is accurate, that
     * the slider has not changed sizes since being last laid out. If necessary
     * we recompute the layout.
     */
    private Dimension lastSize;

    private int trackHeight;
    private int trackBorder;
    private int thumbWidth;
    private int thumbHeight;

    private SynthStyle style;
    private SynthStyle sliderTrackStyle;
    private SynthStyle sliderThumbStyle;

    /** Used to determine the color to paint the thumb. */
    private transient boolean thumbActive; //happens on rollover, and when pressed
    private transient boolean thumbPressed; //happens when mouse was depressed while over thumb

    ///////////////////////////////////////////////////
    // ComponentUI Interface Implementation methods
    ///////////////////////////////////////////////////
    /**
     * Creates a new UI object for the given component.
     *
     * @param c component to create UI object for
     * @return the UI object
     */
    public static ComponentUI createUI(JComponent c) {
        return new SynthSliderUI((JSlider)c);
    }

    /**
     * Constructs a {@code SynthSliderUI}.
     * @param c a slider
     */
    protected SynthSliderUI(JSlider c) {
        super(c);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void installDefaults(JSlider slider) {
        updateStyle(slider);
    }

    /**
     * Uninstalls default setting. This method is called when a
     * {@code LookAndFeel} is uninstalled.
     */
    protected void uninstallDefaults(JSlider slider) {
        SynthContext context = getContext(slider, ENABLED);
        style.uninstallDefaults(context);
        style = null;

        context = getContext(slider, Region.SLIDER_TRACK, ENABLED);
        sliderTrackStyle.uninstallDefaults(context);
        sliderTrackStyle = null;

        context = getContext(slider, Region.SLIDER_THUMB, ENABLED);
        sliderThumbStyle.uninstallDefaults(context);
        sliderThumbStyle = null;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void installListeners(JSlider slider) {
        super.installListeners(slider);
        slider.addPropertyChangeListener(this);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void uninstallListeners(JSlider slider) {
        slider.removePropertyChangeListener(this);
        super.uninstallListeners(slider);
    }

    private void updateStyle(JSlider c) {
        SynthContext context = getContext(c, ENABLED);
        SynthStyle oldStyle = style;
        style = SynthLookAndFeel.updateStyle(context, this);

        if (style != oldStyle) {
            thumbWidth =
                style.getInt(context, "Slider.thumbWidth", 30);

            thumbHeight =
                style.getInt(context, "Slider.thumbHeight", 14);

            // handle scaling for sizeVarients for special case components. The
            // key "JComponent.sizeVariant" scales for large/small/mini
            // components are based on Apples LAF
            String scaleKey = (String)slider.getClientProperty(
                    "JComponent.sizeVariant");
            if (scaleKey != null){
                if ("large".equals(scaleKey)){
                    thumbWidth *= 1.15;
                    thumbHeight *= 1.15;
                } else if ("small".equals(scaleKey)){
                    thumbWidth *= 0.857;
                    thumbHeight *= 0.857;
                } else if ("mini".equals(scaleKey)){
                    thumbWidth *= 0.784;
                    thumbHeight *= 0.784;
                }
            }

            trackBorder =
                style.getInt(context, "Slider.trackBorder", 1);

            trackHeight = thumbHeight + trackBorder * 2;

            paintValue = style.getBoolean(context,
                    "Slider.paintValue", true);
            if (oldStyle != null) {
                uninstallKeyboardActions(c);
                installKeyboardActions(c);
            }
        }

        context = getContext(c, Region.SLIDER_TRACK, ENABLED);
        sliderTrackStyle =
            SynthLookAndFeel.updateStyle(context, this);

        context = getContext(c, Region.SLIDER_THUMB, ENABLED);
        sliderThumbStyle =
            SynthLookAndFeel.updateStyle(context, this);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected TrackListener createTrackListener(JSlider s) {
        return new SynthTrackListener();
    }

    private void updateThumbState(int x, int y) {
        setThumbActive(thumbRect.contains(x, y));
    }

    private void updateThumbState(int x, int y, boolean pressed) {
        updateThumbState(x, y);
        setThumbPressed(pressed);
    }

    private void setThumbActive(boolean active) {
        if (thumbActive != active) {
            thumbActive = active;
            slider.repaint(thumbRect);
        }
    }

    private void setThumbPressed(boolean pressed) {
        if (thumbPressed != pressed) {
            thumbPressed = pressed;
            slider.repaint(thumbRect);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int getBaseline(JComponent c, int width, int height) {
        if (c == null) {
            throw new NullPointerException("Component must be non-null");
        }
        if (width < 0 || height < 0) {
            throw new IllegalArgumentException(
                    "Width and height must be >= 0");
        }
        if (slider.getPaintLabels() && labelsHaveSameBaselines()) {
            // Get the insets for the track.
            Insets trackInsets = new Insets(0, 0, 0, 0);
            SynthContext trackContext = getContext(slider,
                                                   Region.SLIDER_TRACK);
            style.getInsets(trackContext, trackInsets);
            if (slider.getOrientation() == JSlider.HORIZONTAL) {
                int valueHeight = 0;
                if (paintValue) {
                    SynthContext context = getContext(slider);
                    valueHeight = context.getStyle().getGraphicsUtils(context).
                            getMaximumCharHeight(context);
                }
                int tickHeight = 0;
                if (slider.getPaintTicks()) {
                    tickHeight = getTickLength();
                }
                int labelHeight = getHeightOfTallestLabel();
                int contentHeight = valueHeight + trackHeight +
                        trackInsets.top + trackInsets.bottom +
                        tickHeight + labelHeight + 4;
                int centerY = height / 2 - contentHeight / 2;
                centerY += valueHeight + 2;
                centerY += trackHeight + trackInsets.top + trackInsets.bottom;
                centerY += tickHeight + 2;
                JComponent label = (JComponent) slider.getLabelTable().elements().nextElement();
                Dimension pref = label.getPreferredSize();
                return centerY + label.getBaseline(pref.width, pref.height);
            }
            else { // VERTICAL
                Integer value = slider.getInverted() ? getLowestValue() :
                                                       getHighestValue();
                if (value != null) {
                    int valueY = insetCache.top;
                    int valueHeight = 0;
                    if (paintValue) {
                        SynthContext context = getContext(slider);
                        valueHeight = context.getStyle().getGraphicsUtils(
                                context).getMaximumCharHeight(context);
                    }
                    int contentHeight = height - insetCache.top -
                            insetCache.bottom;
                    int trackY = valueY + valueHeight;
                    int trackHeight = contentHeight - valueHeight;
                    int yPosition = yPositionForValue(value.intValue(), trackY,
                                                      trackHeight);
                    JComponent label = (JComponent) slider.getLabelTable().get(value);
                    Dimension pref = label.getPreferredSize();
                    return yPosition - pref.height / 2 +
                            label.getBaseline(pref.width, pref.height);
                }
            }
        }
        return -1;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Dimension getPreferredSize(JComponent c)  {
        recalculateIfInsetsChanged();
        Dimension d = new Dimension(contentRect.width, contentRect.height);
        Insets i = slider.getInsets();
        if (slider.getOrientation() == JSlider.VERTICAL) {
            d.height = 200;
            d.height += i.top + i.bottom;
        } else {
            d.width = 200;
            d.width += i.left + i.right;
        }
        return d;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Dimension getMinimumSize(JComponent c) {
        recalculateIfInsetsChanged();
        Dimension d = new Dimension(contentRect.width, contentRect.height);
        if (slider.getOrientation() == JSlider.VERTICAL) {
            d.height = thumbRect.height + insetCache.top + insetCache.bottom;
        } else {
            d.width = thumbRect.width + insetCache.left + insetCache.right;
        }
        return d;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void calculateGeometry() {
        calculateThumbSize();
        layout();
        calculateThumbLocation();
    }

    /**
     * Lays out the slider.
     */
    protected void layout() {
        SynthContext context = getContext(slider);
        SynthGraphicsUtils synthGraphics = style.getGraphicsUtils(context);

        // Get the insets for the track.
        Insets trackInsets = new Insets(0, 0, 0, 0);
        SynthContext trackContext = getContext(slider, Region.SLIDER_TRACK);
        style.getInsets(trackContext, trackInsets);

        if (slider.getOrientation() == JSlider.HORIZONTAL) {
            // Calculate the height of all the subcomponents so we can center
            // them.
            valueRect.height = 0;
            if (paintValue) {
                valueRect.height =
                    synthGraphics.getMaximumCharHeight(context);
            }

            trackRect.height = trackHeight;

            tickRect.height = 0;
            if (slider.getPaintTicks()) {
                tickRect.height = getTickLength();
            }

            labelRect.height = 0;
            if (slider.getPaintLabels()) {
                labelRect.height = getHeightOfTallestLabel();
            }

            contentRect.height = valueRect.height + trackRect.height
                + trackInsets.top + trackInsets.bottom
                + tickRect.height + labelRect.height + 4;
            contentRect.width = slider.getWidth() - insetCache.left
                - insetCache.right;

            // Check if any of the labels will paint out of bounds.
            int pad = 0;
            if (slider.getPaintLabels()) {
                // Calculate the track rectangle.  It is necessary for
                // xPositionForValue to return correct values.
                trackRect.x = insetCache.left;
                trackRect.width = contentRect.width;

                @SuppressWarnings("rawtypes")
                Dictionary dictionary = slider.getLabelTable();
                if (dictionary != null) {
                    int minValue = slider.getMinimum();
                    int maxValue = slider.getMaximum();

                    // Iterate through the keys in the dictionary and find the
                    // first and last labels indices that fall within the
                    // slider range.
                    int firstLblIdx = Integer.MAX_VALUE;
                    int lastLblIdx = Integer.MIN_VALUE;
                    for (Enumeration keys = dictionary.keys();
                            keys.hasMoreElements(); ) {
                        int keyInt = ((Integer)keys.nextElement()).intValue();
                        if (keyInt >= minValue && keyInt < firstLblIdx) {
                            firstLblIdx = keyInt;
                        }
                        if (keyInt <= maxValue && keyInt > lastLblIdx) {
                            lastLblIdx = keyInt;
                        }
                    }
                    // Calculate the pad necessary for the labels at the first
                    // and last visible indices.
                    pad = getPadForLabel(firstLblIdx);
                    pad = Math.max(pad, getPadForLabel(lastLblIdx));
                }
            }
            // Calculate the painting rectangles for each of the different
            // slider areas.
            valueRect.x = trackRect.x = tickRect.x = labelRect.x =
                (insetCache.left + pad);
            valueRect.width = trackRect.width = tickRect.width =
                labelRect.width = (contentRect.width - (pad * 2));

            int centerY = slider.getHeight() / 2 - contentRect.height / 2;

            valueRect.y = centerY;
            centerY += valueRect.height + 2;

            trackRect.y = centerY + trackInsets.top;
            centerY += trackRect.height + trackInsets.top + trackInsets.bottom;

            tickRect.y = centerY;
            centerY += tickRect.height + 2;

            labelRect.y = centerY;
            centerY += labelRect.height;
        } else {
            // Calculate the width of all the subcomponents so we can center
            // them.
            trackRect.width = trackHeight;

            tickRect.width = 0;
            if (slider.getPaintTicks()) {
                tickRect.width = getTickLength();
            }

            labelRect.width = 0;
            if (slider.getPaintLabels()) {
                labelRect.width = getWidthOfWidestLabel();
            }

            valueRect.y = insetCache.top;
            valueRect.height = 0;
            if (paintValue) {
                valueRect.height =
                    synthGraphics.getMaximumCharHeight(context);
            }

            // Get the max width of the min or max value of the slider.
            FontMetrics fm = slider.getFontMetrics(slider.getFont());
            valueRect.width = Math.max(
                synthGraphics.computeStringWidth(context, slider.getFont(),
                    fm, "" + slider.getMaximum()),
                synthGraphics.computeStringWidth(context, slider.getFont(),
                    fm, "" + slider.getMinimum()));

            int l = valueRect.width / 2;
            int w1 = trackInsets.left + trackRect.width / 2;
            int w2 = trackRect.width / 2 + trackInsets.right +
                              tickRect.width + labelRect.width;
            contentRect.width = Math.max(w1, l) + Math.max(w2, l) +
                    2 + insetCache.left + insetCache.right;
            contentRect.height = slider.getHeight() -
                                    insetCache.top - insetCache.bottom;

            // Layout the components.
            trackRect.y = tickRect.y = labelRect.y =
                valueRect.y + valueRect.height;
            trackRect.height = tickRect.height = labelRect.height =
                contentRect.height - valueRect.height;

            int startX = slider.getWidth() / 2 - contentRect.width / 2;
            if (SynthLookAndFeel.isLeftToRight(slider)) {
                if (l > w1) {
                    startX += (l - w1);
                }
                trackRect.x = startX + trackInsets.left;

                startX += trackInsets.left + trackRect.width + trackInsets.right;
                tickRect.x = startX;
                labelRect.x = startX + tickRect.width + 2;
            } else {
                if (l > w2) {
                    startX += (l - w2);
                }
                labelRect.x = startX;

                startX += labelRect.width + 2;
                tickRect.x = startX;
                trackRect.x = startX + tickRect.width + trackInsets.left;
            }
        }
        lastSize = slider.getSize();
    }

    /**
     * Calculates the pad for the label at the specified index.
     *
     * @param i index of the label to calculate pad for.
     * @return padding required to keep label visible.
     */
    private int getPadForLabel(int i) {
        int pad = 0;

        JComponent c = (JComponent) slider.getLabelTable().get(i);
        if (c != null) {
            int centerX = xPositionForValue(i);
            int cHalfWidth = c.getPreferredSize().width / 2;
            if (centerX - cHalfWidth < insetCache.left) {
                pad = Math.max(pad, insetCache.left - (centerX - cHalfWidth));
            }

            if (centerX + cHalfWidth > slider.getWidth() - insetCache.right) {
                pad = Math.max(pad, (centerX + cHalfWidth) -
                        (slider.getWidth() - insetCache.right));
            }
        }
        return pad;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void calculateThumbLocation() {
        super.calculateThumbLocation();
        if (slider.getOrientation() == JSlider.HORIZONTAL) {
            thumbRect.y += trackBorder;
        } else {
            thumbRect.x += trackBorder;
        }
        Point mousePosition = slider.getMousePosition();
        if(mousePosition != null) {
        updateThumbState(mousePosition.x, mousePosition.y);
       }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setThumbLocation(int x, int y) {
        super.setThumbLocation(x, y);
        // Value rect is tied to the thumb location.  We need to repaint when
        // the thumb repaints.
        slider.repaint(valueRect.x, valueRect.y,
                valueRect.width, valueRect.height);
        setThumbActive(false);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected int xPositionForValue(int value) {
        int min = slider.getMinimum();
        int max = slider.getMaximum();
        int trackLeft = trackRect.x + thumbRect.width / 2 + trackBorder;
        int trackRight = trackRect.x + trackRect.width - thumbRect.width / 2
            - trackBorder;
        int trackLength = trackRight - trackLeft;
        double valueRange = (double)max - (double)min;
        double pixelsPerValue = (double)trackLength / valueRange;
        int xPosition;

        if (!drawInverted()) {
            xPosition = trackLeft;
            xPosition += Math.round( pixelsPerValue * ((double)value - min));
        } else {
            xPosition = trackRight;
            xPosition -= Math.round( pixelsPerValue * ((double)value - min));
        }

        xPosition = Math.max(trackLeft, xPosition);
        xPosition = Math.min(trackRight, xPosition);

        return xPosition;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected int yPositionForValue(int value, int trackY, int trackHeight) {
        int min = slider.getMinimum();
        int max = slider.getMaximum();
        int trackTop = trackY + thumbRect.height / 2 + trackBorder;
        int trackBottom = trackY + trackHeight - thumbRect.height / 2 -
                trackBorder;
        int trackLength = trackBottom - trackTop;
        double valueRange = (double)max - (double)min;
        double pixelsPerValue = (double)trackLength / valueRange;
        int yPosition;

        if (!drawInverted()) {
            yPosition = trackTop;
            yPosition += Math.round(pixelsPerValue * ((double)max - value));
        } else {
            yPosition = trackTop;
            yPosition += Math.round(pixelsPerValue * ((double)value - min));
        }

        yPosition = Math.max(trackTop, yPosition);
        yPosition = Math.min(trackBottom, yPosition);

        return yPosition;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int valueForYPosition(int yPos) {
        int value;
        int minValue = slider.getMinimum();
        int maxValue = slider.getMaximum();
        int trackTop = trackRect.y + thumbRect.height / 2 + trackBorder;
        int trackBottom = trackRect.y + trackRect.height
            - thumbRect.height / 2 - trackBorder;
        int trackLength = trackBottom - trackTop;

        if (yPos <= trackTop) {
            value = drawInverted() ? minValue : maxValue;
        } else if (yPos >= trackBottom) {
            value = drawInverted() ? maxValue : minValue;
        } else {
            int distanceFromTrackTop = yPos - trackTop;
            double valueRange = (double)maxValue - (double)minValue;
            double valuePerPixel = valueRange / (double)trackLength;
            int valueFromTrackTop =
                (int)Math.round(distanceFromTrackTop * valuePerPixel);
            value = drawInverted() ?
                minValue + valueFromTrackTop : maxValue - valueFromTrackTop;
        }
        return value;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int valueForXPosition(int xPos) {
        int value;
        int minValue = slider.getMinimum();
        int maxValue = slider.getMaximum();
        int trackLeft = trackRect.x + thumbRect.width / 2 + trackBorder;
        int trackRight = trackRect.x + trackRect.width
            - thumbRect.width / 2 - trackBorder;
        int trackLength = trackRight - trackLeft;

        if (xPos <= trackLeft) {
            value = drawInverted() ? maxValue : minValue;
        } else if (xPos >= trackRight) {
            value = drawInverted() ? minValue : maxValue;
        } else {
            int distanceFromTrackLeft = xPos - trackLeft;
            double valueRange = (double)maxValue - (double)minValue;
            double valuePerPixel = valueRange / (double)trackLength;
            int valueFromTrackLeft =
                (int)Math.round(distanceFromTrackLeft * valuePerPixel);
            value = drawInverted() ?
                maxValue - valueFromTrackLeft : minValue + valueFromTrackLeft;
        }
        return value;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Dimension getThumbSize() {
        Dimension size = new Dimension();

        if (slider.getOrientation() == JSlider.VERTICAL) {
            size.width = thumbHeight;
            size.height = thumbWidth;
        } else {
            size.width = thumbWidth;
            size.height = thumbHeight;
        }
        return size;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void recalculateIfInsetsChanged() {
        SynthContext context = getContext(slider);
        Insets newInsets = style.getInsets(context, null);
        Insets compInsets = slider.getInsets();
        newInsets.left += compInsets.left; newInsets.right += compInsets.right;
        newInsets.top += compInsets.top; newInsets.bottom += compInsets.bottom;
        if (!newInsets.equals(insetCache)) {
            insetCache = newInsets;
            calculateGeometry();
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public SynthContext getContext(JComponent c) {
        return getContext(c, SynthLookAndFeel.getComponentState(c));
    }

    private SynthContext getContext(JComponent c, int state) {
        return SynthContext.getContext(c, style, state);
    }

    private SynthContext getContext(JComponent c, Region subregion) {
        return getContext(c, subregion, getComponentState(c, subregion));
    }

    private SynthContext getContext(JComponent c, Region subregion, int state) {
        SynthStyle style = null;

        if (subregion == Region.SLIDER_TRACK) {
            style = sliderTrackStyle;
        } else if (subregion == Region.SLIDER_THUMB) {
            style = sliderThumbStyle;
        }
        return SynthContext.getContext(c, subregion, style, state);
    }

    private int getComponentState(JComponent c, Region region) {
        if (region == Region.SLIDER_THUMB && thumbActive &&c.isEnabled()) {
            int state = thumbPressed ? PRESSED : MOUSE_OVER;
            if (c.isFocusOwner()) state |= FOCUSED;
            return state;
        }
        return SynthLookAndFeel.getComponentState(c);
    }

    /**
     * Notifies this UI delegate to repaint the specified component.
     * This method paints the component background, then calls
     * the {@link #paint(SynthContext,Graphics)} method.
     *
     * 

In general, this method does not need to be overridden by subclasses. * All Look and Feel rendering code should reside in the {@code paint} method. * * @param g the {@code Graphics} object used for painting * @param c the component being painted * @see #paint(SynthContext,Graphics) */ @Override public void update(Graphics g, JComponent c) { SynthContext context = getContext(c); SynthLookAndFeel.update(context, g); context.getPainter().paintSliderBackground(context, g, 0, 0, c.getWidth(), c.getHeight(), slider.getOrientation()); paint(context, g); } /** * Paints the specified component according to the Look and Feel. *

This method is not used by Synth Look and Feel. * Painting is handled by the {@link #paint(SynthContext,Graphics)} method. * * @param g the {@code Graphics} object used for painting * @param c the component being painted * @see #paint(SynthContext,Graphics) */ @Override public void paint(Graphics g, JComponent c) { SynthContext context = getContext(c); paint(context, g); } /** * Paints the specified component. * * @param context context for the component being painted * @param g the {@code Graphics} object used for painting * @see #update(Graphics,JComponent) */ protected void paint(SynthContext context, Graphics g) { recalculateIfInsetsChanged(); recalculateIfOrientationChanged(); Rectangle clip = g.getClipBounds(); if (lastSize == null || !lastSize.equals(slider.getSize())) { calculateGeometry(); } if (paintValue) { FontMetrics fm = SwingUtilities2.getFontMetrics(slider, g); int labelWidth = context.getStyle().getGraphicsUtils(context). computeStringWidth(context, g.getFont(), fm, "" + slider.getValue()); valueRect.x = thumbRect.x + (thumbRect.width - labelWidth) / 2; // For horizontal sliders, make sure value is not painted // outside slider bounds. if (slider.getOrientation() == JSlider.HORIZONTAL) { if (valueRect.x + labelWidth > insetCache.left + contentRect.width) { valueRect.x = (insetCache.left + contentRect.width) - labelWidth; } valueRect.x = Math.max(valueRect.x, 0); } g.setColor(context.getStyle().getColor( context, ColorType.TEXT_FOREGROUND)); context.getStyle().getGraphicsUtils(context).paintText( context, g, "" + slider.getValue(), valueRect.x, valueRect.y, -1); } if (slider.getPaintTrack() && clip.intersects(trackRect)) { SynthContext subcontext = getContext(slider, Region.SLIDER_TRACK); paintTrack(subcontext, g, trackRect); } if (clip.intersects(thumbRect)) { SynthContext subcontext = getContext(slider, Region.SLIDER_THUMB); paintThumb(subcontext, g, thumbRect); } if (slider.getPaintTicks() && clip.intersects(tickRect)) { paintTicks(g); } if (slider.getPaintLabels() && clip.intersects(labelRect)) { paintLabels(g); } } /** * {@inheritDoc} */ @Override public void paintBorder(SynthContext context, Graphics g, int x, int y, int w, int h) { context.getPainter().paintSliderBorder(context, g, x, y, w, h, slider.getOrientation()); } /** * Paints the slider thumb. * * @param context context for the component being painted * @param g {@code Graphics} object used for painting * @param thumbBounds bounding box for the thumb */ protected void paintThumb(SynthContext context, Graphics g, Rectangle thumbBounds) { int orientation = slider.getOrientation(); SynthLookAndFeel.updateSubregion(context, g, thumbBounds); context.getPainter().paintSliderThumbBackground(context, g, thumbBounds.x, thumbBounds.y, thumbBounds.width, thumbBounds.height, orientation); context.getPainter().paintSliderThumbBorder(context, g, thumbBounds.x, thumbBounds.y, thumbBounds.width, thumbBounds.height, orientation); } /** * Paints the slider track. * * @param context context for the component being painted * @param g {@code Graphics} object used for painting * @param trackBounds bounding box for the track */ protected void paintTrack(SynthContext context, Graphics g, Rectangle trackBounds) { int orientation = slider.getOrientation(); SynthLookAndFeel.updateSubregion(context, g, trackBounds); context.getPainter().paintSliderTrackBackground(context, g, trackBounds.x, trackBounds.y, trackBounds.width, trackBounds.height, orientation); context.getPainter().paintSliderTrackBorder(context, g, trackBounds.x, trackBounds.y, trackBounds.width, trackBounds.height, orientation); } /** * {@inheritDoc} */ @Override public void propertyChange(PropertyChangeEvent e) { if (SynthLookAndFeel.shouldUpdateStyle(e)) { updateStyle((JSlider)e.getSource()); } } ////////////////////////////////////////////////// /// Track Listener Class ////////////////////////////////////////////////// /** * Track mouse movements. */ private class SynthTrackListener extends TrackListener { @Override public void mouseExited(MouseEvent e) { setThumbActive(false); } @Override public void mousePressed(MouseEvent e) { super.mousePressed(e); setThumbPressed(thumbRect.contains(e.getX(), e.getY())); } @Override public void mouseReleased(MouseEvent e) { super.mouseReleased(e); updateThumbState(e.getX(), e.getY(), false); } @Override public void mouseDragged(MouseEvent e) { int thumbMiddle; if (!slider.isEnabled()) { return; } currentMouseX = e.getX(); currentMouseY = e.getY(); if (!isDragging()) { return; } slider.setValueIsAdjusting(true); switch (slider.getOrientation()) { case JSlider.VERTICAL: int halfThumbHeight = thumbRect.height / 2; int thumbTop = e.getY() - offset; int trackTop = trackRect.y; int trackBottom = trackRect.y + trackRect.height - halfThumbHeight - trackBorder; int vMax = yPositionForValue(slider.getMaximum() - slider.getExtent()); if (drawInverted()) { trackBottom = vMax; trackTop = trackTop + halfThumbHeight; } else { trackTop = vMax; } thumbTop = Math.max(thumbTop, trackTop - halfThumbHeight); thumbTop = Math.min(thumbTop, trackBottom - halfThumbHeight); setThumbLocation(thumbRect.x, thumbTop); thumbMiddle = thumbTop + halfThumbHeight; slider.setValue(valueForYPosition(thumbMiddle)); break; case JSlider.HORIZONTAL: int halfThumbWidth = thumbRect.width / 2; int thumbLeft = e.getX() - offset; int trackLeft = trackRect.x + halfThumbWidth + trackBorder; int trackRight = trackRect.x + trackRect.width - halfThumbWidth - trackBorder; int hMax = xPositionForValue(slider.getMaximum() - slider.getExtent()); if (drawInverted()) { trackLeft = hMax; } else { trackRight = hMax; } thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth); thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth); setThumbLocation(thumbLeft, thumbRect.y); thumbMiddle = thumbLeft + halfThumbWidth; slider.setValue(valueForXPosition(thumbMiddle)); break; default: return; } if (slider.getValueIsAdjusting()) { setThumbActive(true); } } @Override public void mouseMoved(MouseEvent e) { updateThumbState(e.getX(), e.getY()); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy