/**
Copyright 2015 Tim Engler, Rareventure LLC
This file is part of Tiny Travel Tracker.
Tiny Travel Tracker is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Tiny Travel Tracker 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tiny Travel Tracker. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rareventure.android.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import com.rareventure.gps2.R;
public class SeekBarWithText extends RelativeLayout {
private String printfFormat;
private float minValue;
private float maxValue;
private int divisions;
private SeekBar seekBar;
private TextView textView;
private double logScale;
private CustomUpdateTextView customUpdateTextView;
public static interface CustomUpdateTextView
{
String updateText(float value);
}
public SeekBarWithText(Context context, AttributeSet attrs, int defStyle) {
this(context,attrs,defStyle,null);
}
public SeekBarWithText(Context context, AttributeSet attrs, int defStyle, CustomUpdateTextView customUpdateTextView) {
super(context, attrs, defStyle);
View.inflate(context, R.layout.seek_bar_with_text, this);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.com_rareventure_android_widget_SeekBarWithText);
minValue = a.getFloat(R.styleable.com_rareventure_android_widget_SeekBarWithText_minValue, 0);
maxValue = a.getFloat(R.styleable.com_rareventure_android_widget_SeekBarWithText_maxValue, 100);
divisions = a.getInt(R.styleable.com_rareventure_android_widget_SeekBarWithText_steps, Math.round(maxValue - minValue * 10));
logScale = a.getFloat(R.styleable.com_rareventure_android_widget_SeekBarWithText_steps, 0);
printfFormat = a.getString(R.styleable.com_rareventure_android_widget_SeekBarWithText_printfFormat);
if(printfFormat == null)
printfFormat = "%.1f";
this.customUpdateTextView = customUpdateTextView;
seekBar = ((SeekBar)findViewById(R.id.seekBar));
textView = ((TextView)findViewById(R.id.textView));
seekBar.setMax(divisions-1);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar arg0) {
}
@Override
public void onStartTrackingTouch(SeekBar arg0) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
updateTextView();
}
});
updateTextView();
}
private void updateTextView()
{
float value = calcValue(seekBar.getProgress());
if(customUpdateTextView != null)
textView.setText(customUpdateTextView.updateText(value));
else
textView.setText(String.format(printfFormat, value));
}
private float calcValue(int progress)
{
if(logScale == 0)
return minValue + (maxValue - minValue) * progress / (divisions-1);
else
return (float) (minValue + (maxValue - minValue) * (Math.exp((double)progress / logScale)-1) /
(Math.exp((double)(divisions-1)/logScale)-1));
}
public float getValue()
{
return calcValue(seekBar.getProgress());
}
/**
* Will round to the nearest step
* @param value
*/
public void setValue(float value)
{
if(logScale == 0)
seekBar.setProgress(Math.round((value - minValue) * (divisions-1) / (maxValue - minValue)));
else
{
// (float) (minValue + (maxValue - minValue) * (Math.exp((double)progress / logScale)-1) / (Math.exp((double)divisions/logScale)-1));
//
// m = minValue
// n = maxValue
// p = progress
// l = logScale
// d = divisions
// x = scale value
//
// m + (n - m) * ((e^(p/l))-1) / ((e^(d/l))-1) = x
// x - m = (n - m) * ((e^(p/l))-1) / ((e^(d/l))-1)
// (x - m) * ((e^(d/l))-1) = (n - m) * ((e^(p/l))-1)
// (x - m) * ((e^(d/l))-1) / (n - m) = (e^(p/l))-1
// (x - m) * ((e^(d/l))-1) / (n - m) + 1 = e^(p/l)
// lg((x - m) * ((e^(d/l))-1) / (n - m) + 1) = p/l
// lg((x - m) * ((e^(d/l))-1) / (n - m) + 1) * l = p
seekBar.setProgress((int) Math.round((Math.log((value - minValue) * (Math.exp((divisions-1)/logScale)-1)/ (maxValue - minValue) + 1)) * logScale));
}
}
public SeekBarWithText(Context context, AttributeSet attrs) {
this(context, attrs,0,null);
}
public SeekBarWithText(Context context) {
this(context, null);
}
public void setAttrs(float minValue, float maxValue, int divisions,
float logScale, CharSequence printfFormat, CustomUpdateTextView customUpdateTextView) {
if(printfFormat != null)
this.printfFormat = printfFormat.toString();
this.minValue = minValue;
this.maxValue = maxValue;
this.divisions = divisions;
this.logScale = logScale;
this.customUpdateTextView = customUpdateTextView;
seekBar.setMax(divisions-1);
updateTextView();
}
}