File: HudSliderUI.java

package info (click to toggle)
mac-widgets 0.10.0%2Bsvn416-dfsg1-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,968 kB
  • sloc: java: 9,909; makefile: 13; sh: 12
file content (210 lines) | stat: -rw-r--r-- 7,820 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
package com.explodingpixels.macwidgets.plaf;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.RoundRectangle2D;

import javax.swing.JComponent;
import javax.swing.JSlider;
import javax.swing.plaf.basic.BasicSliderUI;

/**
 * Creates a Heads Up Display (HUD) style slider, similar to that seen in various iApps
 * (e.g. iPhoto).
 * <br>
 * <img src="../../../../../graphics/HUDSliderUI-round.png">
 * <br/>
 * <img src="../../../../../graphics/HUDSliderUI-pointy.png">
 */
public class HudSliderUI extends BasicSliderUI {

    private static final int SLIDER_KNOB_WIDTH = 11;
    private static final int SLIDER_KNOB_HEIGHT_NO_TICKS = 11;
    private static final int SLIDER_KNOB_HEIGHT_WITH_TICKS = 13;
    private static final int TRACK_HEIGHT = 4;

    private static final Color TRACK_BACKGROUND_COLOR = new Color(143, 147, 144, 100);
    private static final Color TRACK_BORDER_COLOR = new Color(255, 255, 255, 200);

    private static final Color TOP_SLIDER_KNOB_COLOR = new Color(0x555555);
    private static final Color BOTTOM_SLIDER_KNOB_COLOR = new Color(0x393939);
    private static final Color TOP_SLIDER_KNOB_PRESSED_COLOR = new Color(0xb0b2b6);
    private static final Color BOTTOM_SLIDER_KNOB_PRESSED_COLOR = new Color(0x86888b);

    private static final HudPaintingUtils.ShapeProvider NO_TICKS_SHAPE_PROVIDER =
            createCircularSliderKnobShapeProvider();

    private static final HudPaintingUtils.ShapeProvider TICKS_SHAPE_PROVIDER =
            createPointedSliderKnobShapeProvider();

    public HudSliderUI(JSlider b) {
        super(b);
    }

    @Override
    protected void installDefaults(JSlider slider) {
        super.installDefaults(slider);
        slider.setOpaque(false);
    }

    @Override
    protected Dimension getThumbSize() {
        int sliderKnobHeight = slider.getPaintTicks()
                ? SLIDER_KNOB_HEIGHT_WITH_TICKS : SLIDER_KNOB_HEIGHT_NO_TICKS;
        return new Dimension(SLIDER_KNOB_WIDTH, sliderKnobHeight);
    }

    @Override
    public void paint(Graphics g, JComponent c) {
        HudPaintingUtils.updateGraphicsToPaintDisabledControlIfNecessary((Graphics2D) g, c);
        super.paint(g, c);
    }

    @Override
    public void paintThumb(Graphics graphics) {
        Paint paint = createSliderKnobButtonPaint(isDragging(), thumbRect.height);
        HudPaintingUtils.ShapeProvider shapeProvider = slider.getPaintTicks()
                ? TICKS_SHAPE_PROVIDER : NO_TICKS_SHAPE_PROVIDER;
        HudPaintingUtils.paintHudControlBackground((Graphics2D) graphics, thumbRect, shapeProvider,
                paint);
    }

    @Override
    public void paintTrack(Graphics graphics) {
        Graphics2D graphics2d = (Graphics2D) graphics;
        graphics2d.setRenderingHint(
                RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        double trackY = slider.getHeight() / 2.0 - TRACK_HEIGHT / 2.0;
        RoundRectangle2D track = new RoundRectangle2D.Double(
                0, trackY, slider.getWidth() - 1, TRACK_HEIGHT - 1, 4, 2);

        graphics.setColor(TRACK_BACKGROUND_COLOR);
        graphics2d.fill(track);
        graphics2d.setColor(TRACK_BORDER_COLOR);
        graphics2d.draw(track);
    }

    @Override
    protected int getTickLength() {
        return 5;
    }

    @Override
    protected void calculateThumbLocation() {
        super.calculateThumbLocation();

        if (slider.getOrientation() == JSlider.HORIZONTAL
                && slider.getPaintTicks()) {
            // shift the thumb down three pixels if we're drawing the pointy style thumb.
            thumbRect.y += 3;
        } else {
            // TODO handle vertical slider.
        }
    }

    @Override
    protected void calculateTickRect() {
        super.calculateTickRect();

        if (slider.getOrientation() == JSlider.HORIZONTAL) {
            // shift the ticks down by two pixels so they aren't right up agains the track.
            tickRect.y += 1;
        } else {
            // TODO handle vertical slider.
        }
    }

    @Override
    protected void paintMajorTickForHorizSlider(Graphics g, Rectangle tickBounds, int x) {
        g.setColor(Color.WHITE);
        super.paintMajorTickForHorizSlider(g, tickBounds, x);
    }

    @Override
    public void setThumbLocation(int x, int y) {
        super.setThumbLocation(x, y);
        // repaint the whole slider -- it's easier than trying to figure out whats dirty, especially
        // since the thumb will be drawn outside of the thumbRect (the shadow part).
        slider.repaint();
    }

    @Override
    public void paintFocus(Graphics g) {
        // don't paint focus.
    }

    private static Paint createSliderKnobButtonPaint(boolean isPressed, int height) {
        Color topColor = isPressed ? TOP_SLIDER_KNOB_PRESSED_COLOR : TOP_SLIDER_KNOB_COLOR;
        Color bottomColor = isPressed ? BOTTOM_SLIDER_KNOB_PRESSED_COLOR : BOTTOM_SLIDER_KNOB_COLOR;
        // compenstate for the two pixel shadow drawn below the slider thumb.
        int bottomY = height - 2;
        return new GradientPaint(0, 0, topColor, 0, bottomY, bottomColor);
    }

    /**
     * Creates a simple circle.
     */
    private static HudPaintingUtils.ShapeProvider createCircularSliderKnobShapeProvider() {
        return new HudPaintingUtils.ShapeProvider() {
            public Shape createShape(double x, double y, double width, double height) {
                return new Ellipse2D.Double(x, y, width, height);
            }
        };
    }

    /**
     * Cerates a pointy slider thumb:
     * <pre>
     *     +----+
     *    /      \
     *    +      +
     *    |      |
     *    +      +
     *      \  /
     *       \/
     * </pre>
     */
    private static HudPaintingUtils.ShapeProvider createPointedSliderKnobShapeProvider() {
        return new HudPaintingUtils.ShapeProvider() {
            public Shape createShape(double x, double y, double width, double height) {
                float xFloat = (float) x;
                float yFloat = (float) y;
                float widthFloat = (float) width;
                float heightFloat = (float) height;

                // draw the thumb shape based on the given height and width.
                GeneralPath path = new GeneralPath();
                // move in two pixels so that we can curve down to the next point.
                path.moveTo(xFloat + 2.0f, yFloat);
                // curve down to the second point.
                path.curveTo(xFloat + 0.25f, yFloat + 0.25f, xFloat - 0.25f,
                        yFloat + 2.0f, xFloat, yFloat + 2.0f);
                // move straight down to the next point.
                path.lineTo(xFloat, yFloat + heightFloat / 1.60f);
                // move down and right to form the left half of the pointy section.
                path.lineTo(xFloat + widthFloat / 2, yFloat + heightFloat);
                // move up and right to form the right half of the pointy section.
                path.lineTo(xFloat + widthFloat, yFloat + heightFloat / 1.60f);
                // move straight up to the point to curve from.
                path.lineTo(xFloat + widthFloat, yFloat + 2.0f);
                // curve up and right to the top of the thumb.
                path.curveTo(xFloat + widthFloat - 0.25f, yFloat + 2.0f,
                        xFloat + widthFloat - 0.25f, yFloat + 0.25f,
                        xFloat + widthFloat - 2.0f, yFloat);
                path.closePath();

                return path;
            }
        };
    }
}