config: Sliders
This commit is contained in:
@@ -68,8 +68,10 @@ import javax.swing.JPanel;
|
||||
import javax.swing.JPasswordField;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.JSpinner;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
import javax.swing.SpinnerModel;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
@@ -79,6 +81,7 @@ import javax.swing.border.CompoundBorder;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.MatteBorder;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.swing.plaf.basic.BasicSpinnerUI;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.events.ConfigButtonClicked;
|
||||
@@ -509,6 +512,7 @@ class ConfigPanel extends PluginPanel
|
||||
{
|
||||
int value = Integer.parseInt(configManager.getConfiguration(cd.getGroup().value(), cid.getItem().keyName()));
|
||||
|
||||
Units units = cid.getUnits();
|
||||
Range range = cid.getRange();
|
||||
int min = 0, max = Integer.MAX_VALUE;
|
||||
if (range != null)
|
||||
@@ -520,20 +524,122 @@ class ConfigPanel extends PluginPanel
|
||||
// Config may previously have been out of range
|
||||
value = Ints.constrainToRange(value, min, max);
|
||||
|
||||
SpinnerModel model = new SpinnerNumberModel(value, min, max, 1);
|
||||
JSpinner spinner = new JSpinner(model);
|
||||
Component editor = spinner.getEditor();
|
||||
JFormattedTextField spinnerTextField = ((JSpinner.DefaultEditor) editor).getTextField();
|
||||
spinnerTextField.setColumns(SPINNER_FIELD_WIDTH);
|
||||
spinner.addChangeListener(ce -> changeConfiguration(spinner, cd, cid));
|
||||
|
||||
Units units = cid.getUnits();
|
||||
if (units != null)
|
||||
if (max < Integer.MAX_VALUE)
|
||||
{
|
||||
spinnerTextField.setFormatterFactory(new UnitFormatterFactory(units));
|
||||
}
|
||||
JLabel sliderValueLabel = new JLabel();
|
||||
JSlider slider = new JSlider(min, max, value);
|
||||
slider.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
if (units != null)
|
||||
{
|
||||
sliderValueLabel.setText(slider.getValue() + units.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
sliderValueLabel.setText(String.valueOf(slider.getValue()));
|
||||
}
|
||||
slider.setPreferredSize(new Dimension(80, 25));
|
||||
slider.addChangeListener((l) ->
|
||||
{
|
||||
if (units != null)
|
||||
{
|
||||
sliderValueLabel.setText(slider.getValue() + units.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
sliderValueLabel.setText(String.valueOf(slider.getValue()));
|
||||
}
|
||||
|
||||
item.add(spinner, BorderLayout.EAST);
|
||||
if (!slider.getValueIsAdjusting())
|
||||
{
|
||||
changeConfiguration(slider, cd, cid);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
SpinnerModel model = new SpinnerNumberModel(value, min, max, 1);
|
||||
JSpinner spinner = new JSpinner(model);
|
||||
Component editor = spinner.getEditor();
|
||||
JFormattedTextField spinnerTextField = ((JSpinner.DefaultEditor) editor).getTextField();
|
||||
spinnerTextField.setColumns(SPINNER_FIELD_WIDTH);
|
||||
spinner.setUI(new BasicSpinnerUI()
|
||||
{
|
||||
protected Component createNextButton()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Component createPreviousButton()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
JPanel subPanel = new JPanel();
|
||||
subPanel.setPreferredSize(new Dimension(110, 25));
|
||||
subPanel.setLayout(new BorderLayout());
|
||||
|
||||
spinner.addChangeListener((ce) ->
|
||||
{
|
||||
changeConfiguration(spinner, cd, cid);
|
||||
|
||||
if (units != null)
|
||||
{
|
||||
sliderValueLabel.setText(spinner.getValue() + units.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
sliderValueLabel.setText(String.valueOf(spinner.getValue()));
|
||||
}
|
||||
slider.setValue((Integer) spinner.getValue());
|
||||
|
||||
subPanel.add(sliderValueLabel, BorderLayout.WEST);
|
||||
subPanel.add(slider, BorderLayout.EAST);
|
||||
subPanel.remove(spinner);
|
||||
|
||||
validate();
|
||||
repaint();
|
||||
});
|
||||
|
||||
sliderValueLabel.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
public void mouseClicked(MouseEvent e)
|
||||
{
|
||||
spinner.setValue(slider.getValue());
|
||||
|
||||
subPanel.remove(sliderValueLabel);
|
||||
subPanel.remove(slider);
|
||||
subPanel.add(spinner, BorderLayout.EAST);
|
||||
|
||||
validate();
|
||||
repaint();
|
||||
|
||||
final JTextField tf = ((JSpinner.DefaultEditor) spinner.getEditor()).getTextField();
|
||||
tf.requestFocusInWindow();
|
||||
SwingUtilities.invokeLater(tf::selectAll);
|
||||
}
|
||||
});
|
||||
|
||||
subPanel.add(sliderValueLabel, BorderLayout.WEST);
|
||||
subPanel.add(slider, BorderLayout.EAST);
|
||||
|
||||
item.add(subPanel, BorderLayout.EAST);
|
||||
}
|
||||
else
|
||||
{
|
||||
SpinnerModel model = new SpinnerNumberModel(value, min, max, 1);
|
||||
JSpinner spinner = new JSpinner(model);
|
||||
Component editor = spinner.getEditor();
|
||||
JFormattedTextField spinnerTextField = ((JSpinner.DefaultEditor) editor).getTextField();
|
||||
spinnerTextField.setColumns(SPINNER_FIELD_WIDTH);
|
||||
spinner.addChangeListener(ce -> changeConfiguration(spinner, cd, cid));
|
||||
|
||||
if (units != null)
|
||||
{
|
||||
spinnerTextField.setFormatterFactory(new UnitFormatterFactory(units));
|
||||
}
|
||||
|
||||
item.add(spinner, BorderLayout.EAST);
|
||||
}
|
||||
}
|
||||
|
||||
if (cid.getType() == String.class)
|
||||
@@ -895,6 +1001,11 @@ class ConfigPanel extends PluginPanel
|
||||
JSpinner spinner = (JSpinner) component;
|
||||
configManager.setConfiguration(cd.getGroup().value(), cid.getItem().keyName(), "" + spinner.getValue());
|
||||
}
|
||||
else if (component instanceof JSlider)
|
||||
{
|
||||
JSlider slider = (JSlider) component;
|
||||
configManager.setConfiguration(cd.getGroup().value(), cid.getItem().keyName(), slider.getValue());
|
||||
}
|
||||
else if (component instanceof JTextComponent)
|
||||
{
|
||||
JTextComponent textField = (JTextComponent) component;
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
package net.runelite.client.ui.components;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicSliderUI;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
|
||||
public class SliderUI extends BasicSliderUI
|
||||
{
|
||||
private final Color rangeColor = ColorScheme.BRAND_BLUE;
|
||||
private final BasicStroke stroke = new BasicStroke(2f);
|
||||
|
||||
private transient boolean upperDragging;
|
||||
|
||||
public SliderUI(JSlider b)
|
||||
{
|
||||
super(b);
|
||||
}
|
||||
|
||||
public static ComponentUI createUI(JComponent c)
|
||||
{
|
||||
return new SliderUI((JSlider) c);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateThumbSize()
|
||||
{
|
||||
super.calculateThumbSize();
|
||||
thumbRect.setSize(thumbRect.width, thumbRect.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a listener to handle track events in the specified slider.
|
||||
*/
|
||||
@Override
|
||||
protected TrackListener createTrackListener(JSlider slider)
|
||||
{
|
||||
return new RangeTrackListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calculateThumbLocation()
|
||||
{
|
||||
// Call superclass method for lower thumb location.
|
||||
super.calculateThumbLocation();
|
||||
|
||||
// Adjust upper value to snap to ticks if necessary.
|
||||
if (slider.getSnapToTicks())
|
||||
{
|
||||
int upperValue = slider.getValue() + slider.getExtent();
|
||||
int snappedValue = upperValue;
|
||||
int majorTickSpacing = slider.getMajorTickSpacing();
|
||||
int minorTickSpacing = slider.getMinorTickSpacing();
|
||||
int tickSpacing = 0;
|
||||
|
||||
if (minorTickSpacing > 0)
|
||||
{
|
||||
tickSpacing = minorTickSpacing;
|
||||
}
|
||||
else if (majorTickSpacing > 0)
|
||||
{
|
||||
tickSpacing = majorTickSpacing;
|
||||
}
|
||||
|
||||
if (tickSpacing != 0)
|
||||
{
|
||||
// If it's not on a tick, change the value
|
||||
if ((upperValue - slider.getMinimum()) % tickSpacing != 0)
|
||||
{
|
||||
float temp = (float) (upperValue - slider.getMinimum()) / (float) tickSpacing;
|
||||
int whichTick = Math.round(temp);
|
||||
snappedValue = slider.getMinimum() + (whichTick * tickSpacing);
|
||||
}
|
||||
|
||||
if (snappedValue != upperValue)
|
||||
{
|
||||
slider.setExtent(snappedValue - slider.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate upper thumb location. The thumb is centered over its
|
||||
// value on the track.
|
||||
if (slider.getOrientation() == JSlider.HORIZONTAL)
|
||||
{
|
||||
int upperPosition = xPositionForValue(slider.getValue() + slider.getExtent());
|
||||
thumbRect.x = upperPosition - (thumbRect.width / 2);
|
||||
thumbRect.y = trackRect.y;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
int upperPosition = yPositionForValue(slider.getValue() + slider.getExtent());
|
||||
thumbRect.x = trackRect.x;
|
||||
thumbRect.y = upperPosition - (thumbRect.height / 2);
|
||||
}
|
||||
slider.repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of a thumb.
|
||||
* Parent method not use size from LaF
|
||||
*
|
||||
* @return size of trumb
|
||||
*/
|
||||
@Override
|
||||
protected Dimension getThumbSize()
|
||||
{
|
||||
return new Dimension(16, 16);
|
||||
}
|
||||
|
||||
private Shape createThumbShape(int width, int height)
|
||||
{
|
||||
return new Ellipse2D.Double(0, 0, width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintTrack(Graphics g)
|
||||
{
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
Stroke old = g2d.getStroke();
|
||||
g2d.setStroke(stroke);
|
||||
g2d.setPaint(ColorScheme.LIGHT_GRAY_COLOR);
|
||||
Color oldColor = ColorScheme.LIGHT_GRAY_COLOR;
|
||||
Rectangle trackBounds = trackRect;
|
||||
if (slider.getOrientation() == SwingConstants.HORIZONTAL)
|
||||
{
|
||||
g2d.drawLine(trackRect.x, trackRect.y + trackRect.height / 2,
|
||||
trackRect.x + trackRect.width, trackRect.y + trackRect.height / 2);
|
||||
int lowerX = thumbRect.width / 2;
|
||||
int upperX = thumbRect.x + (thumbRect.width / 2);
|
||||
int cy = (trackBounds.height / 2) - 2;
|
||||
g2d.translate(trackBounds.x, trackBounds.y + cy);
|
||||
g2d.setColor(rangeColor);
|
||||
g2d.drawLine(lowerX - trackBounds.x, 2, upperX - trackBounds.x, 2);
|
||||
g2d.translate(-trackBounds.x, -(trackBounds.y + cy));
|
||||
g2d.setColor(oldColor);
|
||||
}
|
||||
g2d.setStroke(old);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides superclass method to do nothing. Thumb painting is handled
|
||||
* within the <code>paint()</code> method.
|
||||
*/
|
||||
@Override
|
||||
public void paintThumb(Graphics g)
|
||||
{
|
||||
Rectangle knobBounds = thumbRect;
|
||||
int w = knobBounds.width;
|
||||
int h = knobBounds.height;
|
||||
Graphics2D g2d = (Graphics2D) g.create();
|
||||
Shape thumbShape = createThumbShape(w - 1, h - 1);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
||||
RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2d.translate(knobBounds.x, knobBounds.y);
|
||||
g2d.setColor(ColorScheme.BRAND_BLUE);
|
||||
g2d.fill(thumbShape);
|
||||
|
||||
g2d.setColor(ColorScheme.DARK_GRAY_COLOR);
|
||||
g2d.draw(thumbShape);
|
||||
g2d.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener to handle mouse movements in the slider track.
|
||||
*/
|
||||
public class RangeTrackListener extends TrackListener
|
||||
{
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e)
|
||||
{
|
||||
if (!slider.isEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
currentMouseX -= thumbRect.width / 2; // Because we want the mouse location correspond to middle of the "thumb", not left side of it.
|
||||
moveUpperThumb();
|
||||
}
|
||||
|
||||
public void mousePressed(MouseEvent e)
|
||||
{
|
||||
if (!slider.isEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
currentMouseX = e.getX();
|
||||
currentMouseY = e.getY();
|
||||
|
||||
if (slider.isRequestFocusEnabled())
|
||||
{
|
||||
slider.requestFocus();
|
||||
}
|
||||
|
||||
boolean upperPressed = false;
|
||||
if (thumbRect.contains(currentMouseX, currentMouseY))
|
||||
{
|
||||
upperPressed = true;
|
||||
}
|
||||
|
||||
if (upperPressed)
|
||||
{
|
||||
switch (slider.getOrientation())
|
||||
{
|
||||
case JSlider.VERTICAL:
|
||||
offset = currentMouseY - thumbRect.y;
|
||||
break;
|
||||
case JSlider.HORIZONTAL:
|
||||
offset = currentMouseX - thumbRect.x;
|
||||
break;
|
||||
}
|
||||
//upperThumbSelected = true;
|
||||
upperDragging = true;
|
||||
return;
|
||||
}
|
||||
|
||||
upperDragging = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e)
|
||||
{
|
||||
upperDragging = false;
|
||||
slider.setValueIsAdjusting(false);
|
||||
super.mouseReleased(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e)
|
||||
{
|
||||
if (!slider.isEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
currentMouseX = e.getX();
|
||||
currentMouseY = e.getY();
|
||||
|
||||
if (upperDragging)
|
||||
{
|
||||
slider.setValueIsAdjusting(true);
|
||||
moveUpperThumb();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldScroll(int direction)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the location of the upper thumb, and sets its corresponding value in the slider.
|
||||
*/
|
||||
public void moveUpperThumb()
|
||||
{
|
||||
int thumbMiddle;
|
||||
if (slider.getOrientation() == JSlider.HORIZONTAL)
|
||||
{
|
||||
int halfThumbWidth = thumbRect.width / 2;
|
||||
int thumbLeft = currentMouseX - offset;
|
||||
int trackLeft = trackRect.x;
|
||||
int trackRight = trackRect.x + (trackRect.width - 1);
|
||||
int hMax = xPositionForValue(slider.getMaximum() -
|
||||
slider.getExtent());
|
||||
|
||||
if (drawInverted())
|
||||
{
|
||||
trackLeft = hMax;
|
||||
}
|
||||
else
|
||||
{
|
||||
trackRight = hMax;
|
||||
}
|
||||
thumbLeft = Math.max(thumbLeft, trackLeft - halfThumbWidth);
|
||||
thumbLeft = Math.min(thumbLeft, trackRight - halfThumbWidth);
|
||||
|
||||
setThumbLocation(thumbLeft, thumbRect.y);//setThumbLocation
|
||||
|
||||
thumbMiddle = thumbLeft + halfThumbWidth;
|
||||
slider.setValue(valueForXPosition(thumbMiddle));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.NavigationButton;
|
||||
import net.runelite.client.ui.components.CustomScrollBarUI;
|
||||
import net.runelite.client.ui.components.SliderUI;
|
||||
import org.pushingpixels.substance.internal.SubstanceSynapse;
|
||||
|
||||
/**
|
||||
@@ -90,6 +91,7 @@ public class SwingUtil
|
||||
UIManager.put("FormattedTextField.selectionForeground", Color.WHITE);
|
||||
UIManager.put("TextArea.selectionBackground", ColorScheme.BRAND_BLUE_TRANSPARENT);
|
||||
UIManager.put("TextArea.selectionForeground", Color.WHITE);
|
||||
UIManager.put("SliderUI", SliderUI.class.getName());
|
||||
|
||||
// Do not render shadows under popups/tooltips.
|
||||
// Fixes black boxes under popups that are above the game applet.
|
||||
|
||||
Reference in New Issue
Block a user