package stu.tnt.gdx.widget; import stu.tnt.gdx.utils.E; import stu.tnt.gdx.widget.callback.OnValueListener; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.InputListener; public class Slider extends Actor { SliderStyle mStyle; int mOrientaion; OnValueListener mValueListener; private float rotation; // ---------------------------------------------- public float min; public float max; public float step; private float value; // ---------------------------------------------- private final float mKnobSizePercent; private final float mKnobWHRatio; private float mKnobX; private float mKnobY; private float mKnobWidth; private float mKnobHeight; private final float mDelta; private float mCurrentValuePercent; // ---------------------------------------------- private TextureRegion tmp; private int regionWidth; private float mProcessWidth; private float mProcessHeight; private final int mFirstWidth; private final int mFirstHeight; public float mFrameDuration; private float mStateTime = 0; private int mKeyFrame = 0; // ---------------------------------------------- boolean isFocusing = false; boolean isAnimating = false; public Slider(SliderStyle style) { super(); mStyle = style; setBounds(0, 0, 100, 13); setRotation(mOrientaion == E.orientation.LANDSCAPE ? 0 : 90); /* ----------------------------- */ min = style.min; max = style.max; step = style.step; value = style.value; mDelta = max - min; mCurrentValuePercent = value / mDelta; /* ----------------------------- */ mKnobSizePercent = style.knobsize; mKnobWHRatio = (float) mStyle.knob.getRegionWidth() / (float) mStyle.knob.getRegionHeight(); mKnobHeight = getHeight() * mKnobSizePercent; mKnobWidth = mKnobWHRatio * mKnobHeight; /* ----------------------------- */ if (mStyle.process != null) { mFirstWidth = mStyle.process[0].getRegionWidth(); mFirstHeight = mStyle.process[0].getRegionHeight(); } else { mFirstWidth = 0; mFirstHeight = 0; } if (mOrientaion == E.orientation.LANDSCAPE) { mKnobX = (mCurrentValuePercent * (getWidth() - mKnobWidth)) + getX(); mKnobY = getY() + getHeight() / 2 - mKnobHeight / 2; mProcessWidth = mKnobX + mKnobWidth / 2 - getX(); mProcessHeight = getHeight(); } else { mKnobX = getX() + getHeight() / 2 - mKnobHeight / 2; mKnobY = (mCurrentValuePercent * (getWidth() - mKnobWidth)) + getY(); mProcessWidth = mKnobY + mKnobWidth / 2 - getY(); mProcessHeight = getHeight(); } addListener(new SliderController()); } /***************************************************** * *****************************************************/ public void setRegion(TextureRegion background, TextureRegion knob, TextureRegion... process) { mStyle.background = background; mStyle.knob = knob; mStyle.process = process; } public void setValueListner(OnValueListener listener) { mValueListener = listener; } public float getValue() { return (float) Math.floor(value / step) * step; } /***************************************************** * *****************************************************/ private void calculatePositionAndValue(float x) { final float width = getWidth(); final float height = getHeight(); if (x < 0) value = min; else if (x > width) value = max; else value = x / width * mDelta; mCurrentValuePercent = value / mDelta; mKnobHeight = height * mKnobSizePercent; mKnobWidth = mKnobWHRatio * mKnobHeight; if (mOrientaion == E.orientation.LANDSCAPE) { mKnobX = (mCurrentValuePercent * (width - mKnobWidth)) + getX(); mKnobY = getY() + height / 2 - mKnobHeight / 2; mProcessWidth = mKnobX + mKnobWidth / 2 - getX(); mProcessHeight = height; } else { mKnobX = getX() + height / 2 - mKnobHeight / 2; mKnobY = (mCurrentValuePercent * (width - mKnobWidth)) + getY(); mProcessWidth = mKnobY + mKnobWidth / 2 - getY(); mProcessHeight = height; } } public void startAnimation(float FrameDuration) { mFrameDuration = FrameDuration; isAnimating = true; } public void disableAnimation() { isAnimating = false; mStateTime = 0; mKeyFrame = 0; } /***************************************************** * *****************************************************/ public void setValue(float value) { calculatePositionAndValue(value / mDelta * getWidth()); } public void setMax(float max) { this.max = max; } public void setMin(float min) { this.min = min; } public void setStep(float step) { this.step = step; } /***************************************************** * *****************************************************/ @Override public void draw(Batch batch, float parentAlpha) { final Color color = getColor(); final float x = getX(); final float y = getY(); final float width = getWidth(); final float height = getHeight(); batch.setColor(color.r, color.g, color.b, color.a * parentAlpha); if (mOrientaion == E.orientation.LANDSCAPE) { rotation = 0; mKnobX = (mCurrentValuePercent * (width - mKnobWidth)) + x; mKnobY = y + height / 2 - mKnobHeight / 2; } else { rotation = 90; mKnobX = x + height / 2 - mKnobHeight / 2; mKnobY = (mCurrentValuePercent * (width - mKnobWidth)) + y; } if (getScaleX() == 1 && getScaleY() == 1 && rotation == 0) { batch.draw(mStyle.background, x, y, width, height); tmp = mStyle.process[mKeyFrame]; regionWidth = (int) (mCurrentValuePercent * mFirstWidth); if (regionWidth < mFirstWidth - mKnobWidth) tmp.setRegion((int) tmp.getRegionX(), (int) tmp.getRegionY(), (int) (mCurrentValuePercent * mFirstWidth) + (int) (mKnobWidth / 2), (int) mFirstHeight); else tmp.setRegion((int) tmp.getRegionX(), (int) tmp.getRegionY(), (int) (mCurrentValuePercent * mFirstWidth) + (int) (mKnobWidth / 4), (int) mFirstHeight); batch.draw(tmp, x, y, mProcessWidth, mProcessHeight); batch.draw(mStyle.knob, mKnobX, mKnobY, mKnobWidth, mKnobHeight); tmp.setRegion(tmp.getRegionX(), tmp.getRegionY(), mFirstWidth, mFirstHeight); } else { batch.draw(mStyle.background, x, y, getOriginX(), getOriginY(), width, height, getScaleX(), getScaleY(), 90); tmp = mStyle.process[mKeyFrame]; regionWidth = (int) (mCurrentValuePercent * mFirstWidth); if (regionWidth < mFirstWidth - mKnobWidth) tmp.setRegion((int) tmp.getRegionX(), (int) tmp.getRegionY(), (int) (mCurrentValuePercent * mFirstWidth) + (int) (mKnobWidth / 2), (int) mFirstHeight); else tmp.setRegion((int) tmp.getRegionX(), (int) tmp.getRegionY(), (int) (mCurrentValuePercent * mFirstWidth) + (int) (mKnobWidth / 4), (int) mFirstHeight); batch.draw(tmp, x, y, getOriginX(), getOriginY(), mProcessWidth, mProcessHeight, getScaleX(), getScaleY(), 90); batch.draw(mStyle.knob, mKnobX, mKnobY, getOriginX(), getOriginY(), mKnobWidth, mKnobHeight, getScaleX(), getScaleY(), 90); tmp.setRegion(tmp.getRegionX(), tmp.getRegionY(), mFirstWidth, mFirstHeight); } } @Override public void act(float delta) { super.act(delta); if (isAnimating) { mStateTime += delta; if (mFrameDuration > 0) { mKeyFrame = (int) (mStateTime / mFrameDuration); mKeyFrame = mKeyFrame % mStyle.process.length; } else mKeyFrame = 0; } } /***************************************************** * *****************************************************/ class SliderController extends InputListener { @Override public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) { if (hit(x, y, true) != null) { isFocusing = true; calculatePositionAndValue(x); if (mValueListener != null) mValueListener.ValueChanged(Slider.this, getValue()); return true; } return false; } @Override public void touchUp(InputEvent event, float x, float y, int pointer, int button) { isFocusing = false; } @Override public void touchDragged(InputEvent event, float x, float y, int pointer) { if (isFocusing) { calculatePositionAndValue(x); if (mValueListener != null) mValueListener.ValueChanged(Slider.this, getValue()); } } @Override public boolean mouseMoved(InputEvent event, float x, float y) { return super.mouseMoved(event, x, y); } } public void dispose() { mStyle = null; mValueListener = null; } public String info() { if (mStyle.process == null) return "min: " + min + " max: " + max + " step: " + step + " value: " + value + " mCurrentValuePercent: " + mCurrentValuePercent + " mDelta " + mDelta + " mProcessWidth " + mProcessWidth + " mProcessHeight " + mProcessHeight; else return "min: " + min + " max: " + max + " step: " + step + " value: " + value + " mCurrentValuePercent: " + mCurrentValuePercent + " mDelta " + mDelta + " mProcessWidth " + mProcessWidth + " mProcessHeight " + mProcessHeight + mStyle.process.length; } /***************************************************** * *****************************************************/ public static class SliderStyle { public TextureRegion background; public TextureRegion knob; public TextureRegion process[]; public int orientation = E.orientation.LANDSCAPE; public float min = 0; public float max = 100; public float step = 1; public float value = 50; public float knobsize = 1f; } }