001package jmri.jmrit.throttle.panels;
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 * <hr>
014 * This file is part of JMRI.
015 * <p>
016 * JMRI is free software; you can redistribute it and/or modify it under the
017 * terms of version 2 of the GNU General Public License as published by the Free
018 * Software Foundation. See the "COPYING" file for a copy of this license.
019 * <p>
020 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY
021 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
022 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
023 *
024 * @author Lionel Jeanson - 2018
025 * 
026 */
027
028public class ControlPanelCustomSliderUI extends BasicSliderUI {
029    
030    // Color are coming from the Tango themes color palette (as well as icons on the Throttle window, for look consistency)
031    private static final Color TRACK_COLOR_BACK = new Color(0x88, 0x8a, 0x85, 0x88);
032    private static final Color TRACK_COLOR_FRONT = new Color(0xf5, 0x79, 0x00, 0xCC);
033    private static final Color TRACK_COLOR_FRONT_DISABLED = new Color(0xf5, 0xf5, 0xf5, 0xCC);
034    private static final Color TRACK_COLOR_TICKS = new Color(0x888a85);
035    private static final Color THUMB_INNER_COLOR_STOP = new Color(0xcc0000);
036    private static final Color THUMB_INNER_COLOR_RUN = new Color(0xd7d27A);
037    private static final Color THUMB_INNER_COLOR_DISABLED = new Color(0x101010);
038    private static final Color THUMB_CONTOUR_COLOR = new Color(0x555753);
039    
040    public ControlPanelCustomSliderUI(JSlider b) {
041        super(b);
042    }
043    
044    @Override
045    public void paint(Graphics g, JComponent c) {     
046        if (g instanceof Graphics2D) {
047            Graphics2D g2d = (Graphics2D) g;
048            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);            
049        }
050        super.paint(g,c);
051    }
052
053    @Override
054    protected Dimension getThumbSize() {
055        if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
056            return new Dimension(16, contentRect.height - tickRect.height - labelRect.height -trackBuffer*2);
057        } else {
058            return new Dimension(contentRect.width  - tickRect.width - labelRect.width - trackBuffer*2, 16);
059        }
060    }
061
062    @Override
063    public void paintTrack(Graphics g) {
064        if (!(g instanceof Graphics2D)) {
065            return;
066        }
067        Graphics2D g2d = (Graphics2D) g;
068        Paint oldPaint = g2d.getPaint();
069        // Track back rectangle
070        g2d.setPaint(TRACK_COLOR_BACK);
071        g2d.fillRect(trackRect.x, trackRect.y, trackRect.width, trackRect.height);
072        // Track ticks                 
073        int[] ticksAt = { 3*slider.getMinimum()/4, slider.getMinimum()/2 , slider.getMinimum()/4, 0, slider.getMaximum()/4, slider.getMaximum()/2, 3*slider.getMaximum()/4 };        
074        // only if it fits 
075        g2d.setPaint(TRACK_COLOR_TICKS);
076        if (slider.getOrientation() == SwingConstants.VERTICAL && trackRect.height > ticksAt.length*8) {
077            for (int n : ticksAt ) {
078                g2d.drawLine( trackRect.x , 
079                        trackRect.y + trackRect.height / ((slider.getMaximum()-slider.getMinimum())/(slider.getMaximum())) - n*trackRect.height / (slider.getMaximum()-slider.getMinimum()) , 
080                        trackRect.x + trackRect.width-1, 
081                        trackRect.y + trackRect.height / ((slider.getMaximum()-slider.getMinimum())/(slider.getMaximum())) - n*trackRect.height / (slider.getMaximum()-slider.getMinimum()) );
082            }
083        } else if (slider.getOrientation() == SwingConstants.HORIZONTAL && trackRect.width  > ticksAt.length*8) {
084           for (int n : ticksAt ) {
085                g2d.drawLine( trackRect.x + trackRect.width - trackRect.width / ((slider.getMaximum()-slider.getMinimum())/(slider.getMaximum())) + n*trackRect.width / (slider.getMaximum()-slider.getMinimum()) , 
086                        trackRect.y, 
087                        trackRect.x + trackRect.width - trackRect.width / ((slider.getMaximum()-slider.getMinimum())/(slider.getMaximum())) + n*trackRect.width / (slider.getMaximum()-slider.getMinimum()),
088                        trackRect.y + trackRect.height );
089            }            
090        }
091        // Track front
092        if (slider.isEnabled()) {
093            g2d.setPaint(TRACK_COLOR_FRONT);
094        } else {
095            g2d.setPaint(TRACK_COLOR_FRONT_DISABLED);
096        }
097        if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
098            if (slider.getMinimum()<0 && slider.getMaximum()>0) {
099                double doublerel0Pos = Math.abs((double)slider.getMinimum()) / ((double)slider.getMaximum() - (double)slider.getMinimum());
100                double x0 = trackRect.x + trackRect.width * doublerel0Pos;
101                double widthRect = thumbRect.x + (double)thumbRect.width/2 - x0;
102                if (widthRect>0) {
103                    g2d.fillRect( (int)Math.round(x0), trackRect.y, (int)Math.round(widthRect), trackRect.height );
104                } else {
105                    g2d.fillRect( (int)Math.round(x0+widthRect), trackRect.y, (int)Math.round(-widthRect), trackRect.height );
106                }
107            } else {           
108                g2d.fillRect(trackRect.x, trackRect.y, thumbRect.x-thumbRect.width/2, trackRect.height );
109            }
110        } else {
111            if (slider.getMinimum()<0 && slider.getMaximum()>0) {
112                double doublerel0Pos = Math.abs((double)slider.getMaximum()) / ((double)slider.getMaximum() - (double)slider.getMinimum());
113                double y0 = trackRect.y + trackRect.height * doublerel0Pos ;
114                double heightRect = thumbRect.y + (double)thumbRect.height/2 - y0;
115                if (heightRect>0) {
116                    g2d.fillRect( trackRect.x, (int)Math.round(y0), trackRect.width, (int)Math.round(heightRect));
117                } else {
118                    g2d.fillRect( trackRect.x, (int)Math.round(y0+heightRect), trackRect.width, (int)Math.round(-heightRect));
119                }                
120            } else {
121                g2d.fillRect(trackRect.x, thumbRect.y +thumbRect.height/2, trackRect.width, trackRect.height - ( thumbRect.y-trackRect.y +thumbRect.height/2)  );
122            }
123        }
124        g2d.setPaint(oldPaint);
125    }
126
127    @Override
128    public void paintThumb(Graphics g) {
129        if (!(g instanceof Graphics2D)) {
130            return;
131        }
132        Graphics2D g2d = (Graphics2D) g;
133        Paint oldPaint = g2d.getPaint();
134        int x1 = thumbRect.x + 3;
135        int x2 = thumbRect.x + thumbRect.width - 5;
136        int y1 = thumbRect.y+1;
137        int y2 = thumbRect.y+thumbRect.height-2;        
138        if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
139            x1 = thumbRect.x + 1;
140            x2 = thumbRect.x + thumbRect.width - 2;
141            y1 = thumbRect.y+3;
142            y2 = thumbRect.y+thumbRect.height-5;          
143        }
144        GeneralPath shape = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
145        shape.moveTo(x1, y1);        
146        shape.lineTo(x2, y1);
147        shape.lineTo(x2, y2);
148        shape.lineTo(x1, y2);        
149        shape.closePath();
150        if (slider.isEnabled()) {
151            if (slider.getValue()==0) {
152                g2d.setPaint(THUMB_INNER_COLOR_STOP);
153            } else {             
154                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()) ));
155            }
156        } else {
157            g2d.setPaint(THUMB_INNER_COLOR_DISABLED);
158        }
159        g2d.fill(shape);
160        Stroke old = g2d.getStroke();
161        g2d.setStroke(new BasicStroke(2f));
162        g2d.setPaint(THUMB_CONTOUR_COLOR);
163        g2d.draw(shape);
164        g2d.setStroke(old);
165        g2d.setPaint(oldPaint);
166    }
167}