001package jmri.jmrit.throttle;
002
003import java.awt.*;
004import java.awt.geom.GeneralPath;
005
006import javax.swing.*;
007import javax.swing.plaf.basic.BasicSliderUI;
008
009/**
010 * A custom slider UI to be used for throttle control panel speed slider
011 * Very graphical display to be used on a large screen
012 * 
013 * @author Lionel Jeanson - 2018
014 * 
015 */
016
017public class ControlPanelCustomSliderUI extends BasicSliderUI {
018    
019    // Color are coming from the Tango themes color palette (as well as icons on the Throttle window, for look consistency)
020    private final static Color TRACK_COLOR_BACK = new Color(0x88, 0x8a, 0x85, 0x88);
021    private final static Color TRACK_COLOR_FRONT = new Color(0xf5, 0x79, 0x00, 0xCC);
022    private final static Color TRACK_COLOR_FRONT_DISABLED = new Color(0xf5, 0xf5, 0xf5, 0xCC);
023    private final static Color TRACK_COLOR_TICKS = new Color(0x888a85);
024    private final static Color THUMB_INNER_COLOR_STOP = new Color(0xcc0000);
025    private final static Color THUMB_INNER_COLOR_RUN = new Color(0xd7d27A);
026    private final static Color THUMB_INNER_COLOR_DISABLED = new Color(0x101010);
027    private final static Color THUMB_CONTOUR_COLOR = new Color(0x555753);
028    
029    public ControlPanelCustomSliderUI(JSlider b) {
030        super(b);
031    }
032    
033    @Override
034    public void paint(Graphics g, JComponent c) {     
035        if (g instanceof Graphics2D) {
036            Graphics2D g2d = (Graphics2D) g;
037            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);            
038        }
039        super.paint(g,c);
040    }
041
042    @Override
043    protected Dimension getThumbSize() {
044        if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
045            return new Dimension(16, contentRect.height - tickRect.height - labelRect.height -trackBuffer*2);
046        } else {
047            return new Dimension(contentRect.width  - tickRect.width - labelRect.width - trackBuffer*2, 16);
048        }
049    }
050
051    @Override
052    public void paintTrack(Graphics g) {
053        if (!(g instanceof Graphics2D)) {
054            return;
055        }
056        Graphics2D g2d = (Graphics2D) g;
057        Paint oldPaint = g2d.getPaint();
058        // Track back rectangle
059        g2d.setPaint(TRACK_COLOR_BACK);
060        g2d.fillRect(trackRect.x, trackRect.y, trackRect.width, trackRect.height);
061        // Track ticks                 
062        int[] ticksAt = { 3*slider.getMinimum()/4, slider.getMinimum()/2 , slider.getMinimum()/4, 0, slider.getMaximum()/4, slider.getMaximum()/2, 3*slider.getMaximum()/4 };        
063        // only if it fits 
064        g2d.setPaint(TRACK_COLOR_TICKS);
065        if (slider.getOrientation() == SwingConstants.VERTICAL && trackRect.height > ticksAt.length*8) {
066            for (int n : ticksAt ) {
067                g2d.drawLine( trackRect.x , 
068                        trackRect.y + trackRect.height / ((slider.getMaximum()-slider.getMinimum())/(slider.getMaximum())) - n*trackRect.height / (slider.getMaximum()-slider.getMinimum()) , 
069                        trackRect.x + trackRect.width-1, 
070                        trackRect.y + trackRect.height / ((slider.getMaximum()-slider.getMinimum())/(slider.getMaximum())) - n*trackRect.height / (slider.getMaximum()-slider.getMinimum()) );
071            }
072        } else if (slider.getOrientation() == SwingConstants.HORIZONTAL && trackRect.width  > ticksAt.length*8) {
073           for (int n : ticksAt ) {
074                g2d.drawLine( trackRect.x + trackRect.width - trackRect.width / ((slider.getMaximum()-slider.getMinimum())/(slider.getMaximum())) + n*trackRect.width / (slider.getMaximum()-slider.getMinimum()) , 
075                        trackRect.y, 
076                        trackRect.x + trackRect.width - trackRect.width / ((slider.getMaximum()-slider.getMinimum())/(slider.getMaximum())) + n*trackRect.width / (slider.getMaximum()-slider.getMinimum()),
077                        trackRect.y + trackRect.height );
078            }            
079        }
080        // Track front
081        if (slider.isEnabled()) {
082            g2d.setPaint(TRACK_COLOR_FRONT);
083        } else {
084            g2d.setPaint(TRACK_COLOR_FRONT_DISABLED);
085        }
086        if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
087            if (slider.getMinimum()<0 && slider.getMaximum()>0) {
088                double doublerel0Pos = Math.abs((double)slider.getMinimum()) / ((double)slider.getMaximum() - (double)slider.getMinimum());
089                double x0 = trackRect.x + trackRect.width * doublerel0Pos;
090                double widthRect = thumbRect.x + (double)thumbRect.width/2 - x0;
091                if (widthRect>0) {
092                    g2d.fillRect( (int)Math.round(x0), trackRect.y, (int)Math.round(widthRect), trackRect.height );
093                } else {
094                    g2d.fillRect( (int)Math.round(x0+widthRect), trackRect.y, (int)Math.round(-widthRect), trackRect.height );
095                }
096            } else {           
097                g2d.fillRect(trackRect.x, trackRect.y, thumbRect.x-thumbRect.width/2, trackRect.height );
098            }
099        } else {
100            if (slider.getMinimum()<0 && slider.getMaximum()>0) {
101                double doublerel0Pos = Math.abs((double)slider.getMaximum()) / ((double)slider.getMaximum() - (double)slider.getMinimum());
102                double y0 = trackRect.y + trackRect.height * doublerel0Pos ;
103                double heightRect = thumbRect.y + (double)thumbRect.height/2 - y0;
104                if (heightRect>0) {
105                    g2d.fillRect( trackRect.x, (int)Math.round(y0), trackRect.width, (int)Math.round(heightRect));
106                } else {
107                    g2d.fillRect( trackRect.x, (int)Math.round(y0+heightRect), trackRect.width, (int)Math.round(-heightRect));
108                }                
109            } else {
110                g2d.fillRect(trackRect.x, thumbRect.y +thumbRect.height/2, trackRect.width, trackRect.height - ( thumbRect.y-trackRect.y +thumbRect.height/2)  );
111            }
112        }
113        g2d.setPaint(oldPaint);
114    }
115
116    @Override
117    public void paintThumb(Graphics g) {
118        if (!(g instanceof Graphics2D)) {
119            return;
120        }
121        Graphics2D g2d = (Graphics2D) g;
122        Paint oldPaint = g2d.getPaint();
123        int x1 = thumbRect.x + 3;
124        int x2 = thumbRect.x + thumbRect.width - 5;
125        int y1 = thumbRect.y+1;
126        int y2 = thumbRect.y+thumbRect.height-2;        
127        if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
128            x1 = thumbRect.x + 1;
129            x2 = thumbRect.x + thumbRect.width - 2;
130            y1 = thumbRect.y+3;
131            y2 = thumbRect.y+thumbRect.height-5;          
132        }
133        GeneralPath shape = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
134        shape.moveTo(x1, y1);        
135        shape.lineTo(x2, y1);
136        shape.lineTo(x2, y2);
137        shape.lineTo(x1, y2);        
138        shape.closePath();
139        if (slider.isEnabled()) {
140            if (slider.getValue()==0) {
141                g2d.setPaint(THUMB_INNER_COLOR_STOP);
142            } else {             
143                g2d.setPaint( new Color(THUMB_INNER_COLOR_RUN.getRed() - Math.abs(slider.getValue())*100/slider.getMaximum(),THUMB_INNER_COLOR_RUN.getGreen(), THUMB_INNER_COLOR_RUN.getBlue() - Math.abs(slider.getValue()*100/slider.getMaximum()) ));
144            }
145        } else {
146            g2d.setPaint(THUMB_INNER_COLOR_DISABLED);
147        }
148        g2d.fill(shape);
149        Stroke old = g2d.getStroke();
150        g2d.setStroke(new BasicStroke(2f));
151        g2d.setPaint(THUMB_CONTOUR_COLOR);
152        g2d.draw(shape);
153        g2d.setStroke(old);
154        g2d.setPaint(oldPaint);
155    }
156}