org.bidib.jbidibc.ui.LogarithmicJSlider Maven / Gradle / Ivy
/*
* Copyright 2002-2004 Greg Hinkle
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bidib.jbidibc.ui;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.swing.BoundedRangeModel;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.UIManager;
import javax.swing.plaf.SliderUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicSliderUI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This JSlider subclass uses a custom UI to allow a slider to work in logarithmic scale. Major and minor ticks are
* drawn for logarithmic scale as well.
*
* @author Greg Hinkle ([email protected]), Apr 10, 2004
* @version $Revision: 480 $($Author: ghinkl $ / $Date: 2004-10-05 05:17:41 +0000 (Tue, 05 Oct 2004) $)
*/
public class LogarithmicJSlider extends JSlider {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = LoggerFactory.getLogger(LogarithmicJSlider.class);
public static final String UI_CLASS_WINDOWS = "org.bidib.jbidibc.ui.plaf.windows.LogWindowsSliderUI";
public static final String UI_CLASS_METAL = "org.bidib.jbidibc.ui.plaf.metal.LogMetalSliderUI";
public static final String UI_CLASS_SYNTH = "org.bidib.jbidibc.ui.plaf.synth.LogSynthSliderUI";
public static final String UI_CLASS_DEFAULT = "org.bidib.jbidibc.ui.LogarithmicJSlider$LogSliderUI";
public LogarithmicJSlider(int orientation) {
super(orientation);
prepareUiClass();
}
public LogarithmicJSlider(int min, int max) {
super(min, max);
prepareUiClass();
}
public LogarithmicJSlider(int min, int max, int value) {
super(min, max, value);
prepareUiClass();
}
public LogarithmicJSlider(int orientation, int min, int max, int value) {
super(orientation, min, max, value);
prepareUiClass();
}
public LogarithmicJSlider(BoundedRangeModel brm) {
super(brm);
prepareUiClass();
}
public LogarithmicJSlider() {
prepareUiClass();
}
private void prepareUiClass() {
SliderUI ui = null;
if (OS.isWindows()) {
try {
Class> clazz = Class.forName(UI_CLASS_WINDOWS);
ui = (SliderUI) clazz.getConstructor(JSlider.class).newInstance(this);
}
catch (Exception ex) {
LOGGER.warn("Create special sliderUI for windows failed, fallback to default LogSliderUI.", ex);
}
}
else if (OS.isLinux()) {
if ("Metal".equals(UIManager.getLookAndFeel().getName())) {
LOGGER.trace("Linux is running with metal L&F.");
try {
Class> clazz = Class.forName(UI_CLASS_METAL);
ui = (SliderUI) clazz.getConstructor().newInstance();
}
catch (Exception ex) {
LOGGER.warn("Create special sliderUI for metal failed, fallback to default LogSliderUI.", ex);
}
}
else if ("Synth".equals(UIManager.getLookAndFeel().getID())
|| "Nimbus".equals(UIManager.getLookAndFeel().getID())) {
LOGGER.trace("Linux is running with synth L&F.");
try {
Class> clazz = Class.forName(UI_CLASS_SYNTH);
ui = (SliderUI) clazz.getConstructor(JSlider.class).newInstance(this);
}
catch (Exception ex) {
LOGGER.warn("Create special sliderUI for synth failed, fallback to default LogSliderUI.", ex);
}
}
}
if (ui == null) {
ui = new LogSliderUI(this);
}
this.setUI(ui);
}
@Override
public void updateUI() {
prepareUiClass();
// The labels preferred size may be derived from the font
// of the slider, so we must update the UI of the slider first, then
// that of labels. This way when setSize is called the right
// font is used.
updateLabelUIs();
}
public static class LogSliderUI extends BasicSliderUI {
public LogSliderUI(JSlider b) {
super(b);
}
@Override
public int xPositionForValue(int value) {
int min = slider.getMinimum();
int max = slider.getMaximum();
int trackLength = trackRect.width;
double valueRange = Math.log(max) - Math.log(min);
double pixelsPerValue = trackLength / valueRange;
int trackLeft = trackRect.x;
int trackRight = trackRect.x + (trackRect.width - 1);
int xPosition;
if (!drawInverted()) {
xPosition = trackLeft;
xPosition += Math.round(pixelsPerValue * (Math.log(value) - Math.log(min)));
}
else {
xPosition = trackRight;
xPosition -= Math.round(pixelsPerValue * (Math.log(value) - Math.log(min)));
}
xPosition = Math.max(trackLeft, xPosition);
xPosition = Math.min(trackRight, xPosition);
return xPosition;
}
@Override
public int yPositionForValue(int value) {
// TODO GH: Implement to support vertical log sliders
return super.yPositionForValue(value);
}
@Override
public int valueForYPosition(int yPos) {
// TODO GH: Implement to support vertical log sliders
return super.valueForYPosition(yPos);
}
@Override
public int valueForXPosition(int xPos) {
int value;
final int minValue = slider.getMinimum();
final int maxValue = slider.getMaximum();
final int trackLength = trackRect.width;
final int trackLeft = trackRect.x;
final int trackRight = trackRect.x + (trackRect.width - 1);
if (xPos <= trackLeft) {
value = drawInverted() ? maxValue : minValue;
}
else if (xPos >= trackRight) {
value = drawInverted() ? minValue : maxValue;
}
else {
int distanceFromTrackLeft = xPos - trackLeft;
double valueRange = Math.log(maxValue) - Math.log(minValue);
// double valuePerPixel = (double)valueRange / (double)trackLength;
// int valueFromTrackLeft =
// (int)Math.round( Math.pow(3.5,(double)distanceFromTrackLeft * (double)valuePerPixel));
int valueFromTrackLeft =
(int) Math
.round(Math
.pow(Math.E, Math.log(minValue) + (((distanceFromTrackLeft) * valueRange) / trackLength)));
value = drawInverted() ? maxValue - valueFromTrackLeft : (int) Math.log(minValue) + valueFromTrackLeft;
}
return value;
}
@Override
public void paintTicks(Graphics g) {
Rectangle tickBounds = tickRect;
g.setColor(Color.black);
int maj = slider.getMajorTickSpacing();
if (slider.getOrientation() == JSlider.HORIZONTAL) {
g.translate(0, tickBounds.y);
int value = slider.getMinimum();
int xPos = 0;
if (slider.getMinorTickSpacing() > 0) {
int majorValue = slider.getMinimum();
while (value <= slider.getMaximum()) {
if (value >= majorValue) {
value = majorValue;
majorValue *= maj;
}
value += (majorValue / 10.0);
xPos = xPositionForValue(value);
paintMinorTickForHorizSlider(g, tickBounds, xPos);
}
}
if (slider.getMajorTickSpacing() > 0) {
value = slider.getMinimum();
while (value <= slider.getMaximum()) {
xPos = xPositionForValue(value);
paintMajorTickForHorizSlider(g, tickBounds, xPos);
value *= slider.getMajorTickSpacing();
}
}
g.translate(0, -tickBounds.y);
}
else {
g.translate(tickBounds.x, 0);
int value = slider.getMinimum();
int yPos = 0;
if (slider.getMinorTickSpacing() > 0) {
int majorValue = slider.getMinimum();
int offset = 0;
if (!slider.getComponentOrientation().isLeftToRight()) {
offset = tickBounds.width - tickBounds.width / 2;
g.translate(offset, 0);
}
while (value <= slider.getMaximum()) {
if (value >= majorValue) {
value = majorValue;
majorValue *= maj;
}
yPos = yPositionForValue(value);
paintMinorTickForVertSlider(g, tickBounds, yPos);
value += (majorValue / 10.0);
}
if (!slider.getComponentOrientation().isLeftToRight()) {
g.translate(-offset, 0);
}
}
if (slider.getMajorTickSpacing() > 0) {
value = slider.getMinimum();
if (!slider.getComponentOrientation().isLeftToRight()) {
g.translate(2, 0);
}
while (value <= slider.getMaximum()) {
yPos = yPositionForValue(value);
paintMajorTickForVertSlider(g, tickBounds, yPos);
value *= slider.getMajorTickSpacing();
}
if (!slider.getComponentOrientation().isLeftToRight()) {
g.translate(-2, 0);
}
}
g.translate(-tickBounds.x, 0);
}
}
}
/**
* Creates a hashtable holding the text labels for this slider. This implementation uses the increment as a
* log-base.
*
*/
@Override
public Hashtable createStandardLabels(int increment, int start) {
if (start > getMaximum() || start < getMinimum()) {
throw new IllegalArgumentException("Slider label start point out of range.");
}
if (increment <= 0) {
throw new IllegalArgumentException("Label incremement must be > 0");
}
class LabelHashtable extends Hashtable implements PropertyChangeListener {
int increment = 0;
int start = 0;
boolean startAtMin = false;
public LabelHashtable(int increment, int start) {
super();
this.increment = increment;
this.start = start;
startAtMin = start == getMinimum();
createLabels(this, increment, start);
}
@Override
public void propertyChange(PropertyChangeEvent e) {
if (e.getPropertyName().equals("minimum") && startAtMin) {
start = getMinimum();
}
if (e.getPropertyName().equals("minimum") || e.getPropertyName().equals("maximum")) {
Enumeration> keys = getLabelTable().keys();
Object key = null;
Hashtable
© 2015 - 2025 Weber Informatics LLC | Privacy Policy