package org.erikaredmark.monkeyshines.menu; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.IOException; import javax.imageio.ImageIO; import javax.sound.sampled.Clip; import javax.sound.sampled.FloatControl; import javax.swing.BoundedRangeModel; import javax.swing.DefaultBoundedRangeModel; import javax.swing.JSlider; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.basic.BasicSliderUI; import org.erikaredmark.monkeyshines.global.SoundSettings; import org.erikaredmark.monkeyshines.global.SoundType; import org.erikaredmark.monkeyshines.global.SoundUtils; /** * * Represents a volume control that allows the user to choose between 0-100 percent. Basically acts exactly * like a slider tool, only graphically skinned to match with Monkey Shines. * * @author Erika Redmark * */ public final class VolumeSlider extends JSlider { private static final long serialVersionUID = 1L; /** * * Creates a new volume slider controlling the designated volume type (music or sound) * * @param type * the sound type to control. * * @param demo * the sound clip to play on each change. This clip represents an idea of how loud/soft the setting is * */ public VolumeSlider(final SoundType type, final Clip demo) { super(); final BoundedRangeModel model = new DefaultBoundedRangeModel(SoundSettings.getVolumePercentForType(type), 0, 0, 100) { private static final long serialVersionUID = 1L; }; model.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { type.adjustPercentage(model.getValue() ); // Don't play demo sound unless slider has come to a rest, or that would get annoying real fast. if (!(model.getValueIsAdjusting() ) && model.getValue() != 0) { float gain = SoundUtils.resolveDecibelOffsetFromPercentage(model.getValue() ); FloatControl gainControl = (FloatControl) demo.getControl(FloatControl.Type.MASTER_GAIN); gainControl.setValue(gain); demo.stop(); demo.setFramePosition(0); demo.start(); } } }); setModel(model); setOpaque(false); setBorder(null); setUI(new MonkeyShinesSliderUI(this) ); } private static class MonkeyShinesSliderUI extends BasicSliderUI { private final BufferedImage SLIDER; private static final int TRACK_HEIGHT = 17; public MonkeyShinesSliderUI(JSlider slider) { super(slider); try { SLIDER = ImageIO.read(VolumeSlider.class.getResourceAsStream("/resources/graphics/mainmenu/sound/sliderControl.png") ); } catch (IOException e) { throw new RuntimeException("Bad .jar: Volume slider resource missing or corrupted: " + e.getMessage(), e); } } @Override public void paintTrack(Graphics g) { // The track is calculated as taking up most of the slider. We only draw TRACK_HEIGHT pixels int offset = super.trackRect.height - TRACK_HEIGHT; int drawY = offset < 0 ? super.trackRect.y : super.trackRect.y + (offset / 2); g.setColor(Color.BLACK); g.drawRect(super.trackRect.x, drawY, super.trackRect.width, TRACK_HEIGHT); g.drawRect(super.trackRect.x + 1, drawY + 1, super.trackRect.width - 2, TRACK_HEIGHT - 2); g.setColor(Color.GRAY); g.fillRect(super.trackRect.x + 2, drawY + 2, super.trackRect.width - 3, TRACK_HEIGHT - 3); } @Override protected Dimension getThumbSize() { return new Dimension(SLIDER.getWidth(), SLIDER.getHeight()); } @Override public void paintThumb(Graphics g) { g.drawImage(SLIDER, super.thumbRect.x, super.thumbRect.y, super.thumbRect.x + super.thumbRect.width, super.thumbRect.y + super.thumbRect.height, 0, 0, SLIDER.getWidth(), SLIDER.getHeight(), null); } } }