Android Open Source - QuMixDroid Fader






From Project

Back to project page QuMixDroid.

License

The source code is released under:

GNU General Public License

If you think the Android project QuMixDroid listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*******************************************************************************
 * Copyright (c) 2013 george wieggers.//from   w  w  w  .  jav a 2  s . c o  m
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *     george wieggers - initial API and implementation
 ******************************************************************************/
package org.wieggers.qu_apps.controls;

import java.util.HashMap;
import java.util.Map;

import org.wieggers.qu_apps.qumixdroid.R;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class Fader extends View {

  private int mMaxValue, mProgress;
  private String mChannelName;
  
  private static final int mMargin = 50;
  private static final int mDesiredWidth = 30;
  private static final int mDesiredHeight = 300;

  private static Bitmap mKnobBmp = null;
  private static int mKnobWidth, mKnobHeight;

  private int mCenterX, mFaderKnobRangeY;
  private int mFaderKnobX1, mFaderKnobX2, mFaderKnobY1, mFaderKnobY2, mFaderKnobMinY1, mFaderKnobMaxY1; // fader knob coordinates
  private int mLevelX1, mLevelX2; // db scale X coordinates

  private double mProgressPercentage;
  private Paint mPaint;
  private Boolean mIsActive;

  private static final HashMap<Integer, String> faderLevels;
  static {
    HashMap<Integer, String> initMap = new HashMap<Integer, String>();
    initMap.put(0x7F, "10");
    initMap.put(0x72, "5");
    initMap.put(0x60, "0");
    initMap.put(0x4D, "-5");
    initMap.put(0x3D, "-10");
    initMap.put(0x2E, "-20");
    initMap.put(0x1F, "-30");
    initMap.put(0x0F, "-40");
    initMap.put(0, "-?");
    faderLevels = initMap;
  }
  
  public Fader(Context context) {
    super(context);
    init(null, 0);
  }

  public Fader(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(attrs, 0);
  }

  public Fader(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(attrs, defStyle);
  }

  private void init(AttributeSet attrs, int defStyle) {
    // Load attributes
    final TypedArray a = getContext().obtainStyledAttributes(attrs,
        R.styleable.Fader, defStyle, 0);

    mChannelName = a.getString(R.styleable.Fader_channel_name);
    setMaxValue(a.getInt(R.styleable.Fader_max, 127));
    setProgress(a.getInt(R.styleable.Fader_progress, 0), false);
    a.recycle();

    mIsActive = false;

    mFaderKnobRangeY = 1;    

    mPaint = new Paint();
    mPaint.setColor(Color.WHITE);
    mPaint.setTextSize((float)12.0);
    mPaint.setTypeface(Typeface.DEFAULT_BOLD);
  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    if (mKnobBmp == null) {
      mKnobBmp = BitmapFactory.decodeResource (getResources(), R.drawable.fader_knob);
      mKnobWidth = mKnobBmp.getWidth();
      mKnobHeight = mKnobBmp.getHeight();
    }

    mCenterX = (getWidth() / 2); // + 8; 
    mFaderKnobX1 = mCenterX - mKnobWidth / 2;      // left value of fader knob
    mFaderKnobX2 = mCenterX + mKnobWidth / 2;                                
    
    mFaderKnobMinY1 = mMargin - (mKnobHeight / 2);
    mFaderKnobMaxY1 = getHeight() - mMargin - (mKnobHeight / 2);    // max value for top position of fader knob
    mFaderKnobRangeY = mFaderKnobMaxY1 - mFaderKnobMinY1;  // max possible sliding range for fader
    
    mLevelX1 = mCenterX - (mKnobWidth / 2) - 2;      // left value of DB scale lines
    mLevelX2 = mCenterX + (mKnobWidth / 2);        // right value of DB scale lines

    // draw the channel name
    mPaint.setColor(Color.WHITE);
    mPaint.setAlpha(255);
    
    mPaint.setTextAlign(Paint.Align.CENTER);
    mPaint.setTextSize((float)16.0);
    
    if (mIsActive) {
      int value = mProgress + 8;
      while (value >= 0) {
        if (faderLevels.containsKey(value)) {
          String level = faderLevels.get(value);
          canvas.drawText(level, mCenterX, 20, mPaint);
          canvas.drawText(level, mCenterX, getHeight() - 20, mPaint);
          break;
        }
        --value;
      }
    } else if (mChannelName != null) {      
      canvas.drawText (mChannelName, mCenterX, 20, mPaint);
    }

    mPaint.setTextSize((float)12.0);

    // draw the DB scale with corresponding text labels
    mPaint.setTextAlign(Paint.Align.RIGHT);
    for(Map.Entry<Integer, String> entry : faderLevels.entrySet()) {
      
      double factorLevel = (double)entry.getKey() / (double)mMaxValue;
      int levelY = mFaderKnobMaxY1 - (int)(factorLevel * (double)mFaderKnobRangeY) + (mKnobHeight / 2);

      canvas.drawRect (mLevelX1, levelY - 1, mLevelX2, levelY, mPaint);
      //canvas.drawText (entry.getValue(), mLevelX1 - 4, levelY + 3, mPaint);
    }
    

    // draw the long vertical rectangle (in which our virtual fader can slide)
    canvas.drawRect(mCenterX - 3, mMargin, mCenterX + 3, getHeight() - mMargin, mPaint);

    if (!mIsActive) { // when not presssed, fill the vertical rectangle black 
      mPaint.setColor(Color.BLACK);     
      canvas.drawRect(mCenterX - 2, mMargin + 1, mCenterX + 2, getHeight() - mMargin - 1, mPaint);
    }
    // so when pressed, the vertical rectangle lights up in white

    // determine position of the fader knob
    mFaderKnobY1 = mFaderKnobMaxY1 - (int)(mProgressPercentage * (double)mFaderKnobRangeY);
    mFaderKnobY2 = mFaderKnobY1 + mKnobHeight;
    
    if (!mIsActive)
      mPaint.setAlpha(190);
    // and draw it
    canvas.drawBitmap (mKnobBmp, mFaderKnobX1, mFaderKnobY1, mPaint);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    int width;
    int height;

    //Measure Width
    if (widthMode == MeasureSpec.EXACTLY) {
      //Must be this size
      width = widthSize;
    } else if (widthMode == MeasureSpec.AT_MOST) {
      //Can't be bigger than...
      width = Math.min(mDesiredWidth, widthSize);
    } else {
      //Be whatever you want
      width = mDesiredWidth;
    }

    //Measure Height
    if (heightMode == MeasureSpec.EXACTLY) {
      //Must be this size
      height = heightSize;
    } else if (heightMode == MeasureSpec.AT_MOST) {
      //Can't be bigger than...
      height = Math.min(mDesiredHeight, heightSize);
    } else {
      //Be whatever you want
      height = mDesiredHeight;
    }

    //MUST CALL THIS
    setMeasuredDimension(width, height);
  }
  
  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    
  }  
  
  int startX, startY;
  int mixerValueStart;
  
  @Override
  public boolean onTouchEvent(MotionEvent e) {
    
    if (!isEnabled())
      return false;

    switch (e.getAction()) {
    case MotionEvent.ACTION_DOWN:
      startX = (int)e.getX ();
      startY = (int)e.getY ();
      mIsActive = (startX >= mFaderKnobX1
        && startX <= mFaderKnobX2
        && startY >= mFaderKnobY1
        && startY <= mFaderKnobY2);
      
      if (mIsActive)
        getParent().requestDisallowInterceptTouchEvent(true);
      
      mixerValueStart = mProgress;
      safeInvalidate();
      break;
    case MotionEvent.ACTION_MOVE:
      if (mIsActive) {
        int newY = (int)e.getY ();
        int diffY = startY - newY;

        float factor = (float)diffY / (float)mFaderKnobRangeY;
        int mixerValueDelta = (int) (factor * (float) mMaxValue);
        int newMixerValue = mixerValueStart + mixerValueDelta;
        if (newMixerValue < 0)
          newMixerValue = 0;
        if (newMixerValue > mMaxValue)
          newMixerValue = mMaxValue;

        setProgress(newMixerValue, true);
        safeInvalidate ();
      }
      break;
    case MotionEvent.ACTION_UP:
    case MotionEvent.ACTION_CANCEL:
      mIsActive = false;
      getParent().requestDisallowInterceptTouchEvent(false);
      safeInvalidate ();
      break;
    }    
    
    return true;
  }
  
  public String getChannelName() {
    return mChannelName;
  }

  public void setChannelName(String mChannelName) {
    this.mChannelName = mChannelName;
    safeInvalidate();
  }

  public int getMaxValue() {
    return mMaxValue;
  }

  public void setMaxValue(int mMaxValue) {
    if (mMaxValue <= 0)  
      throw new IllegalArgumentException("MaxValue should be greater than zero");
    
    this.mMaxValue = mMaxValue;
    safeInvalidate();
  }
  
  public int getProgress() {
    return mProgress;
  }

  public void setProgress(int mProgress, Boolean triggerEvent) {
    this.mProgress = mProgress;
    mProgressPercentage = (double)mProgress / (double)getMaxValue();    
    safeInvalidate();
    if (triggerEvent)
      onProgressChanged();
  }
  
  private void safeInvalidate() {
    this.post(new Runnable() {
      
      @Override
      public void run() {
        Fader.this.invalidate();        
      }
    });
  }
  
  protected void onProgressChanged() {
  
  }
}




Java Source Code List

org.wieggers.qu_apps.communication.Connected_Device.java
org.wieggers.qu_apps.controls.Fader.java
org.wieggers.qu_apps.controls.RotaryKnob.java
org.wieggers.qu_apps.controls.bound.BoundMixFader.java
org.wieggers.qu_apps.controls.bound.BoundMixRotaryKnob.java
org.wieggers.qu_apps.controls.bound.BoundMixSeekbar.java
org.wieggers.qu_apps.controls.bound.BoundMixToggleButton.java
org.wieggers.qu_apps.controls.bound.BoundMuteToggleButton.java
org.wieggers.qu_apps.qu16.Qu16_MeteringValues.java
org.wieggers.qu_apps.qu16.Qu16_Midi_Parser.java
org.wieggers.qu_apps.qu16.Qu16_MixValue.java
org.wieggers.qu_apps.qu16.Qu16_Mixer.java
org.wieggers.qu_apps.qu16.Qu16_UI.java
org.wieggers.qu_apps.qu16.midi.Qu16_GEQ_Bands.java
org.wieggers.qu_apps.qu16.midi.Qu16_Id_Parameters.java
org.wieggers.qu_apps.qu16.midi.Qu16_Input_Channels.java
org.wieggers.qu_apps.qu16.midi.Qu16_VA_Ranges.java
org.wieggers.qu_apps.qu16.midi.Qu16_VX_Buses.java
org.wieggers.qu_apps.qumixdroid.ConnectingFragment.java
org.wieggers.qu_apps.qumixdroid.LoginActivity.java
org.wieggers.qu_apps.qumixdroid.MainActivity.java
org.wieggers.qu_apps.qumixdroid.MixerFragment.java