/** * Copyright (C) 2001-2017 by RapidMiner and the contributors * * Complete list of developers available at our web site: * * http://rapidminer.com * * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * This program 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 * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with this program. * If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.gui.look.ui; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.geom.Rectangle2D; import javax.swing.JComponent; import javax.swing.JSlider; import javax.swing.SwingConstants; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicSliderUI; import com.rapidminer.gui.look.Colors; import com.rapidminer.gui.look.RapidLookAndFeel; /** * The UI for sliders. * * @author Ingo Mierswa */ public class SliderUI extends BasicSliderUI { private class ThumbListener extends MouseAdapter { @Override public void mousePressed(MouseEvent e) { if (getThumbBounds().contains(e.getX(), e.getY())) { SliderUI.this.thumbIsPressed = true; getSlider().repaint(); } } @Override public void mouseReleased(MouseEvent e) { SliderUI.this.thumbIsPressed = false; getSlider().repaint(); } } private boolean thumbIsPressed = false; private MouseListener thumbPressedListener; public static ComponentUI createUI(JComponent jcomponent) { return new SliderUI((JSlider) jcomponent); } public SliderUI(JSlider jSlider) { super(jSlider); } @Override public void installUI(JComponent c) { super.installUI(c); } @Override public void paintThumb(Graphics g) { Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.translate(this.thumbRect.x, this.thumbRect.y); g2.setColor(Colors.SLIDER_THUMB_BACKGROUND); if (this.slider.getOrientation() == SwingConstants.HORIZONTAL) { g2.fillRoundRect(0, 2, 11, 14, 3, 3); if (this.thumbIsPressed) { g2.setColor(Colors.SLIDER_THUMB_BORDER_FOCUS); } else { g2.setColor(Colors.SLIDER_THUMB_BORDER); } g2.drawRoundRect(0, 2, 10, 14, 3, 3); g2.drawLine(2, 5, 2, 13); g2.drawLine(4, 5, 4, 13); g2.drawLine(6, 5, 6, 13); g2.drawLine(8, 5, 8, 13); // paint the current value next to thumb int curVal = this.slider.getValue(); String valString = String.valueOf(curVal); Rectangle2D strBounds = g2.getFontMetrics().getStringBounds(valString, g2); float x = (float) -(strBounds.getWidth() / 2) + 5; float y = (float) (thumbRect.height + strBounds.getHeight()); double overflowX = thumbRect.x + x + strBounds.getWidth() - trackRect.getMaxX(); if (overflowX > 0) { x = (float) (x - overflowX); } if (slider.getPaintLabels()) { g2.setColor(Colors.TEXT_FOREGROUND); g2.drawString(valString, x, y); } } else { g2.fillRoundRect(2, 0, 14, 11, 3, 3); if (this.thumbIsPressed) { g2.setColor(Colors.SLIDER_THUMB_BORDER_FOCUS); } else { g2.setColor(Colors.SLIDER_THUMB_BORDER); } g2.drawRoundRect(2, 0, 14, 10, 3, 3); g2.drawLine(5, 2, 13, 2); g2.drawLine(5, 4, 13, 4); g2.drawLine(5, 6, 13, 6); g2.drawLine(5, 8, 13, 8); // paint the current value next to thumb int curVal = this.slider.getValue(); String valString = String.valueOf(curVal); Rectangle2D strBounds = g2.getFontMetrics().getStringBounds(valString, g2); float x = thumbRect.width + 10; float y = (float) (0 + strBounds.getHeight() / 2) + 2; if (slider.getPaintLabels()) { g2.setColor(Colors.TEXT_FOREGROUND); g2.drawString(valString, x, y); } } g2.translate(-this.thumbRect.x, -this.thumbRect.y); } @Override public void paint(Graphics g, JComponent c) { recalculateIfInsetsChanged(); recalculateIfOrientationChanged(); Rectangle clip = g.getClipBounds(); if (!clip.intersects(trackRect) && slider.getPaintTrack()) { calculateGeometry(); } if (slider.getPaintTrack() && clip.intersects(trackRect)) { paintTrack(g); } if (slider.hasFocus() && clip.intersects(focusRect)) { paintFocus(g); } // the ticks are now inside the track so they have to be painted each thumb movement paintTicks(g); // thumb is always painted due to value below thumb paintThumb(g); } @Override public void paintTrack(Graphics g) { Graphics2D g2 = (Graphics2D) g; // make sure slider has same background as container if (slider.getParent() != null) { g2.setColor(slider.getParent().getBackground()); g2.fillRect(0, 0, slider.getWidth(), slider.getHeight()); } if (this.slider.getOrientation() == SwingConstants.HORIZONTAL) { int trackTop = (int) this.trackRect.getY() + 2; int w = this.slider.getWidth(); int length = w - 6; // draw background bar if (this.slider.isEnabled()) { g2.setColor(Colors.SLIDER_TRACK_BACKGROUND); } else { g2.setColor(Colors.SLIDER_TRACK_BACKGROUND_DISABLED); } g2.fillRoundRect(3, trackTop + 1, length, 5, RapidLookAndFeel.CORNER_DEFAULT_RADIUS / 2, RapidLookAndFeel.CORNER_DEFAULT_RADIUS / 2); // draw fill bar int curVal = this.slider.getModel().getValue(); double percentage = (double) curVal / (slider.getModel().getMaximum() - slider.getModel().getExtent()); g2.setColor(Colors.SLIDER_TRACK_FOREGROUND); g2.fill(new Rectangle2D.Double(4, trackTop + 2, (length - trackBuffer) * percentage, 3)); // draw border g2.setColor(Colors.SLIDER_TRACK_BORDER); g2.drawRoundRect(2, trackTop, length, 6, RapidLookAndFeel.CORNER_DEFAULT_RADIUS / 2, RapidLookAndFeel.CORNER_DEFAULT_RADIUS / 2); } else { int trackLeft = (int) this.trackRect.getX() + 2; int h = this.slider.getHeight(); int height = h - 6; // draw background bar if (this.slider.isEnabled()) { g2.setColor(Colors.SLIDER_TRACK_BACKGROUND); } else { g2.setColor(Colors.SLIDER_TRACK_BACKGROUND_DISABLED); } g2.fillRoundRect(trackLeft + 1, 3, 5, height, RapidLookAndFeel.CORNER_DEFAULT_RADIUS / 2, RapidLookAndFeel.CORNER_DEFAULT_RADIUS / 2); // draw fill bar int curVal = this.slider.getModel().getValue(); double percentage = (double) curVal / (slider.getModel().getMaximum() - slider.getModel().getExtent()); g2.setColor(Colors.SLIDER_TRACK_FOREGROUND); g2.fill(new Rectangle2D.Double(trackLeft + 2, (h - trackBuffer) * (1d - percentage), 3, (h - trackBuffer) * percentage)); // draw border g2.setColor(Colors.SLIDER_TRACK_BORDER); g2.drawRoundRect(trackLeft, 2, 6, height, RapidLookAndFeel.CORNER_DEFAULT_RADIUS / 2, RapidLookAndFeel.CORNER_DEFAULT_RADIUS / 2); } } @Override public void paintFocus(Graphics g) {} @Override protected void calculateThumbSize() { Dimension size; if (this.slider.getOrientation() == SwingConstants.HORIZONTAL) { size = new Dimension(13, 18); } else { size = new Dimension(18, 13); } this.thumbRect.setSize(size.width, size.height); } @Override protected void calculateThumbLocation() { super.calculateThumbLocation(); if (this.slider.getOrientation() == SwingConstants.HORIZONTAL) { thumbRect.y -= 4; } else { thumbRect.x -= 4; } } private Rectangle getThumbBounds() { return this.thumbRect; } private JSlider getSlider() { return this.slider; } protected MouseListener createThumbPressedListener() { return new ThumbListener(); } @Override protected void installListeners(JSlider slider) { super.installListeners(slider); if ((this.thumbPressedListener = createThumbPressedListener()) != null) { slider.addMouseListener(this.thumbPressedListener); } } @Override protected void uninstallListeners(JSlider slider) { if (this.thumbPressedListener != null) { slider.removeMouseListener(this.thumbPressedListener); this.thumbPressedListener = null; } super.uninstallListeners(slider); } @Override protected void paintMinorTickForHorizSlider(Graphics g, Rectangle tickBounds, int x) { // we don't want to paint them at all } @Override protected void paintMajorTickForHorizSlider(Graphics g, Rectangle tickBounds, int x) { if (Math.abs(trackRect.x - x) < 10 || Math.abs(trackRect.x + trackRect.width - x) < 10) { return; } Graphics2D g2 = (Graphics2D) g; int curVal = this.slider.getModel().getValue(); double percentage = (double) curVal / (slider.getModel().getMaximum() - slider.getModel().getExtent()); boolean isBackground = false; if (trackRect.width * percentage > x) { g2.setColor(Colors.SLIDER_TRACK_BACKGROUND); } else { isBackground = true; g2.setColor(Colors.SLIDER_TRACK_BORDER); } int trackTop = (int) this.trackRect.getY() + 3; g2.translate(0, -tickBounds.y); g2.fillRect(x, trackTop, isBackground ? 1 : 2, 5); g2.translate(0, tickBounds.y); } @Override protected void calculateTrackBuffer() { trackBuffer = 5; } @Override protected void paintMinorTickForVertSlider(Graphics g, Rectangle tickBounds, int y) { // we don't want to paint them at all } @Override protected void paintMajorTickForVertSlider(Graphics g, Rectangle tickBounds, int y) { if (Math.abs(trackRect.y - y) < 10 || Math.abs(trackRect.y + trackRect.height - y) < 10) { return; } Graphics2D g2 = (Graphics2D) g; int curVal = this.slider.getModel().getValue(); double percentage = (double) curVal / (slider.getModel().getMaximum() - slider.getModel().getExtent()); if (trackRect.height * percentage > trackRect.height - y) { g2.setColor(Colors.SLIDER_TRACK_BACKGROUND); } else { g2.setColor(Colors.SLIDER_TRACK_BORDER); } int trackLeft = (int) this.trackRect.getX() + 3; g2.translate(-tickBounds.x, 0); g2.fillRect(trackLeft, y, 5, 2); g2.translate(tickBounds.x, 0); } }