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}