Android Open Source - SpunkyCharts Base Chart Fragment A






From Project

Back to project page SpunkyCharts.

License

The source code is released under:

GNU General Public License

If you think the Android project SpunkyCharts 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

package com.jogden.spunkycharts;
/* /*from   www. j a va2 s.  co m*/
Copyright (C) 2014 Jonathon Ogden     < jeog.dev@gmail.com >

This program 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.

This program 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 this program.  If not, see http://www.gnu.org/licenses.
*/

import java.lang.reflect.InvocationTargetException;

import android.app.Activity;
import android.app.Dialog;
import android.app.Fragment;
import android.database.Cursor;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.Handler;
import android.text.format.Time;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.jogden.spunkycharts.animations.BaseAnimationA;
import com.jogden.spunkycharts.animations.BaseSelectAnimationA;
import com.jogden.spunkycharts.animations.HorizontalBulgeAnimation;
import com.jogden.spunkycharts.animations.HorizontalShakeAnimation;
import com.jogden.spunkycharts.animations.VerticalBulgeAnimation;
import com.jogden.spunkycharts.animations.VerticalShakeAnimation;
import com.jogden.spunkycharts.animations.WiggleAnimation;
import com.jogden.spunkycharts.misc.BorderOverlay;
import com.jogden.spunkycharts.traditionalchart.TraditionalChartFragment;

/**    The abstract base class for all SpunkyChart charts.
 *     This fragment is how the application views chart objects;
 *     to position, move, adjust, stack,close them etc. 
 * </p>
 *     Extend this class and define refresh() to handle updating
 *     internal views and state when the chart is resized. Define
 *     onHoldDown to handle a touch and hold of the screen
 *     within the bounds of the frag view.
 *     </p>
 *        There are certain universal settings/preferences like 
 *        chart opacity and border thickness that are handled within,
 *        with appropriate getters and setters.
 *</p>
 *        When a chart has another stacked on top or removed its
 *        onStacked and onDeStacked handlers are called, 
 *        respectively. Be sure to call down if you override them.
 * </p>
 *     Once you've created a ChartPreferences object, you 
 *     should Override getLocalPreferencesDialog() as public,
 *     pass the dialog returned from calling the base version
 *     and your layout id to mergeLocalPreferencesDialog(),
 *     returning that after you've passed the bundle and callback
 *     to the setup method of the preferences object. ( Use 
 *     the version in TraditionalChartFragment.java as a template. ) *
 */
public abstract class BaseChartFragmentA extends Fragment 
{        
    /* refresh the whole chart */
    public abstract void refresh(); 
    /* what happens when a touch is held for 
     * more than 'hold threshold' milleseconds */
    protected abstract void onHoldDown();
    
    protected static final Handler guiHandler = 
        new Handler();
    
    private BaseChartFragmentA _this;    
    private String _uTag;    
    private boolean _isMin = false;
    private boolean _tabToggleFlag = true;
    private int _tabBrdrMltpl = 3;
    private Bundle _instanceBundle;
    
    /*  'virtual' stack of charts for supporting overlay */    
    private volatile int _stackSize = 1;
    private BaseChartFragmentA _stackBase = this;
    private BaseChartFragmentA _stackTop = this;
    private BaseChartFragmentA _stackLastLink = null;
    
    public final boolean FALSE = false;
    public final boolean TRUE = true;
    
    /* private settings */
    private RelativeLayout.LayoutParams _lParams = 
        new RelativeLayout.LayoutParams(
            RelativeLayout.LayoutParams.MATCH_PARENT,
            RelativeLayout.LayoutParams.MATCH_PARENT
            );
    private GlobalChartPreferences.LineThickness _lineThickness = 
        GlobalChartPreferences.getDefaultLineThickness();
    private int _refreshRate = 
        GlobalChartPreferences.getDefaultRefreshRate();
    private float _alpha = 
        GlobalChartPreferences.getDefaultAlpha();    
    private int _borderSz = 
        GlobalChartPreferences.getDefaultChartBorder();
    
    /* since not in a pref object we'll create our own key */
    private final String BASE_COLOR = 
        "com.jogden.spunkycharts.BASE_COLOR";
    private int _colorId = Color.BLACK;        
    private BorderOverlay _borderOverlay;
    private TotalFragmentTouchListener _totalTouchListener;
    
    protected DockingPanelActivity parentActivity;
    protected ViewGroup ourViewGroup;
    protected BorderOverlay symbolTab;   
    
    /*|--------->         begin PUBLIC interface         <--------|*/
    public int getStackSize()
    {
        return _stackSize;
    }    
    public BaseChartFragmentA getBaseOfStack()
    {
        return _stackBase;
    }
    public BaseChartFragmentA getTopOfStack()
    {
        return _stackTop;
    }
    public BaseChartFragmentA getLastLinkOfStack()
    {
        return _stackLastLink;
    }    
    public void setLayoutParams(
            RelativeLayout.LayoutParams layoutParams
    ){
        _lParams = layoutParams;
        if( ourViewGroup != null)
            ourViewGroup.setLayoutParams(_lParams);        
    }
    public void setTabView(BorderOverlay tabView)
    {
        if(tabView != null)
            tabView.setBorderColor(_colorId);
        this.symbolTab = tabView;        
    }
    public String getUniqueTag()
    {
        return _uTag;
    }
    public BorderOverlay getTabView()
    {
        return this.symbolTab;
    }
    public void releaseTabView(BorderOverlay tabView)
    {
        if(tabView == this.symbolTab)
            this.symbolTab = null;
    }
    public void toggleSymbolTab()
    {        
        if(_tabToggleFlag){        
            symbolTab.setBorderSize(
                symbolTab.getBorderSize() * _tabBrdrMltpl
                );
        } else {
            symbolTab.setBorderSize(
                symbolTab.getBorderSize() / _tabBrdrMltpl
                );
        }
        _tabToggleFlag = _tabToggleFlag ? false : true;
    }    
    private void setIsMinimized(boolean isMin)
    {
        _isMin = isMin;
    }
    public boolean isMinimized()
    {
        return _isMin;
    }
    public void hide()
    {
        ourViewGroup.setVisibility(View.GONE);
        toggleSymbolTab();
        setIsMinimized(true);
    }
    public void hideStack()
    {    
        for( BaseChartFragmentA tmp = _stackTop ; 
                tmp != null ;
                tmp = tmp._stackLastLink )
                    tmp.hide();    
    }
    public void show() 
    {
        ourViewGroup.setVisibility(View.VISIBLE);     
        toggleSymbolTab();
        setIsMinimized(false);
    }
    public void showStack()
    {
        for( BaseChartFragmentA tmp = _stackTop ; 
                tmp != null ;
                tmp = tmp._stackLastLink )
                    tmp.show();    
    }
    public void popOffStackAndMove(
        boolean remove, float newX, float newY
    ){    
        if(!remove){
            RelativeLayout.LayoutParams lParams
                = (RelativeLayout.LayoutParams )( 
                    ourViewGroup.getLayoutParams()
                    );                     
            float shiftRight = 
                newX - ( lParams.leftMargin + 
                    (ourViewGroup.getWidth()/2) );
            float shiftDown =  
                newY - ( lParams.topMargin + 
                    (ourViewGroup.getHeight()/2) );
            parentActivity.resizeAndOrMove( 
                DockingPanelActivity.copyParams(lParams),
                ourViewGroup,
                0, 0, (int)shiftRight, (int)shiftDown
                );    
        }
        popStack();
    }
    public void setSelectAnimation( String animName )
    {
        _totalTouchListener.setSelectAnimation(animName);
    }
    public void resetAnimationPrefs()
    {
        _totalTouchListener.setupSelectAnimation();
    }
    /* for passing temp state to ourselves */
    public void saveInstanceBundle(Bundle bndl, boolean overWrite)
    {
        if(overWrite || _instanceBundle == null)
            _instanceBundle = bndl;
        
    }
    public Bundle loadInstanceBundle()
    {
        return _instanceBundle;
    }
        
    /*|--------->         end PUBLIC interface         <--------|*/
    /*|--------->     begin PROTECTED interface     <--------|*/
        
    /* stubs here for convenience, define if you'd like */
    protected void setAxisFontSize(int sp)
    {}
    protected void setAxisFontColor(int colorId)
    {}
    protected void setXAxisPaddingSize(int pixSize)
    {}
    protected void setAxisTimeout(int value)
    {}
    protected void setTimeoutIncrement(int value)
    {}
    static protected void setAxisMarkColor(int colorId)
    {}
    static protected void setAxisMarkThickness(int pixSize)
    {}
    static protected void setShowMinorMark(boolean show)
    {}
    static protected void setShowMajorMark(boolean show)
    {}
    /* getter/setters for private settings */
    protected void setColor(int colorId)
    {
        _colorId = colorId;
        _borderOverlay.setBorderColor(colorId);
        if(symbolTab != null)
            symbolTab.setBorderColor(colorId);
    }
    protected int getColor()
    {
        return _colorId;
    }
    protected void setBorderSize(int borderSize) 
    {        
        _borderSz = borderSize;    
        ourViewGroup.setPadding(
            _borderSz,_borderSz,_borderSz,_borderSz
            );
        _borderOverlay.setBorderSize(borderSize);
    }
    protected int getBorderSize() 
    {
        return _borderSz;
    }
    protected void setAlpha(float alpha) 
    {
        ourViewGroup.setAlpha(alpha);
        _alpha = alpha;        
    }
    protected float getAlpha() 
    {
        return _alpha;
    }
    protected void setLineThickness( 
        GlobalChartPreferences.LineThickness thickness
    ){    
        _lineThickness = thickness;
    }
    protected GlobalChartPreferences.LineThickness 
    getLineThickness()
    {
        return _lineThickness;
    }
    protected void setRefreshRate( int refreshRate)
    {        
        _refreshRate = refreshRate;
    }
    protected int getRefreshRate()
    {
        return _refreshRate;
    }    
    /* should be a mirror of onSavedState handler */
    protected void extractState(Bundle savedState)
    {
        _lineThickness = 
            GlobalChartPreferences.LineThickness.valueOf(
                savedState.getString(
                    GlobalChartPreferences.GLOBAL_LINE_THICKNESS
                    ) 
                );
        _refreshRate = savedState.getInt(
            GlobalChartPreferences.GLOBAL_REFRESH_RATE
            );
        _alpha = savedState.getFloat(
            GlobalChartPreferences.GLOBAL_ALPHA
            );
        _borderSz = savedState.getInt(
            GlobalChartPreferences.GLOBAL_BORDER_SIZE
            );
        _colorId = savedState.getInt( BASE_COLOR);
    }
    
    /* local (to a chart instance) preferences dialog; call 
     * mergeDialogLayout from your fragment to add your 
     * custom preference layout below it (GlobalChartPreferences) */
    protected Dialog mergeLocalPreferencesDialog(
        Dialog dialog, int layoutId 
    ){        
        dialog.getLayoutInflater().inflate(
            layoutId, 
            (ViewGroup)dialog.findViewById(R.id.chart_settings_merged) 
            );    
        return dialog;
    }
    protected Dialog getLocalPreferencesDialog()
    {
        final Dialog prefDialog = new Dialog(parentActivity);
        prefDialog.setTitle("Chart Preferences");
        prefDialog.setContentView(R.layout.chart_settings_merged);    
        Bundle bndl = new Bundle();
        bndl.putFloat(
            GlobalChartPreferences.GLOBAL_ALPHA,
            this.getAlpha()             
            );
        bndl.putString(
            GlobalChartPreferences.GLOBAL_LINE_THICKNESS,
            this.getLineThickness().toString()
            );
        bndl.putInt(
            GlobalChartPreferences.GLOBAL_REFRESH_RATE,
            this.getRefreshRate()
            );    
        bndl.putInt(
            GlobalChartPreferences.GLOBAL_BORDER_SIZE,
            this.getBorderSize()
            );
        GlobalChartPreferences gPref =
            new GlobalChartPreferences();
        MainApplication.ViewFindable finder = 
            new MainApplication.ViewFindable(){
                public View findViewById(int id){
                    return prefDialog.findViewById(id);
                    }
                };
        if( gPref.findViews(finder) )
            gPref.setup(        
                bndl,
                new ApplicationPreferences.ChartPreferencesSetup.Callback(){
                    @Override
                    public <T> void callback(String pref, T val){ 
                        if ( pref.equals(
                            GlobalChartPreferences.GLOBAL_ALPHA
                            )) _this.setAlpha((Float)val);    
                        else if ( pref.equals(
                            GlobalChartPreferences.GLOBAL_LINE_THICKNESS
                            )) _this.setLineThickness( 
                                    GlobalChartPreferences.LineThickness.valueOf( 
                                        (String)val
                                        )
                                    );        
                        else if ( pref.equals(
                            GlobalChartPreferences.GLOBAL_REFRESH_RATE
                            )) _this.setRefreshRate((Integer)val);
                        else if( pref.equals(
                            GlobalChartPreferences.GLOBAL_BORDER_SIZE
                            )) _this.setBorderSize((Integer)val);     
                    }
                },
                this.getActivity()
                );
        return prefDialog;
    }
    /* override these to deal with 'stack' events */
    /* remember oldTop == this */
    protected void onStacked(    
        BaseChartFragmentA base,
        BaseChartFragmentA oldTop,
        BaseChartFragmentA newTop
    ){
        BaseChartFragmentA tmp = newTop.getTopOfStack();
        do{ /*assimilate the views */
            tmp.setBorderSize(_borderSz);                    
        }while( tmp.getLastLinkOfStack() != oldTop && 
            (tmp = tmp.getLastLinkOfStack() ).TRUE );     
    }
    /* currently not reseting prefs changed in onStacked */
    protected void onDeStacked(    
        BaseChartFragmentA base,
        BaseChartFragmentA oldTop,
        BaseChartFragmentA newTop
    ){
    }
    
    /*|--------->         end PROTECTED interface         <--------|*/
    /*|--------->         begin PRIVATE methods         <--------|*/
    
    private void pushStack( BaseChartFragmentA upper)
    {
        final int sz = 
            _this._stackBase._stackSize 
            + upper._stackBase._stackSize;            
        /* link the base of the new to top of the old */
        upper._stackBase._stackLastLink = _this;        
        /* loop thru the new stack updating size,base, and top*/
        for( BaseChartFragmentA tmp = upper._stackTop ; 
                tmp != null ;
                tmp = tmp._stackLastLink )
                {
                    tmp._stackSize = sz;
                    tmp._stackBase = _this._stackBase;
                    tmp._stackTop = upper._stackTop;
                }        
        onStacked(_this._stackBase,_this, upper);
    }
    /* note: we are only popping one at a time but 
     * can add multi/middle functionality at some point*/
    private void popStack()
    { /* can call even if we are base */
        if(_stackBase != this)
        {        
            BaseChartFragmentA tmpTop = _stackTop;
            BaseChartFragmentA tmpBase = _stackBase;
            BaseChartFragmentA tmpLink = _stackLastLink;
            for( BaseChartFragmentA tmp = _stackTop ; 
                    tmp != null ;
                    tmp = tmp._stackLastLink )
                    {
                        tmp._stackSize--;                
                        tmp._stackTop = _stackLastLink;
                    }    
            _stackBase = this;
            _stackTop = this;
            _stackLastLink = null;
            _stackSize = 1;
            onDeStacked(tmpBase, tmpTop, tmpLink);
        }
    }

    /*|--------->         end PRIVATE methods         <--------|*/
    /*|--------->     begin LIFE-CYCLE handlers     <--------|*/
    
    @Override
    public void onAttach(Activity activity) 
    {
        super.onAttach(activity); 
        try{
            parentActivity = (DockingPanelActivity)activity;
        }catch( ClassCastException e ){
            throw new ClassCastException( 
                activity.toString() + " must extend DockingPanelActivity."
                );
        }    
        _this = this;
        _uTag = this.getArguments().getString("uTag");            
    }    
    @Override
    public void onCreate(Bundle savedState) 
    {
        this.setRetainInstance(true);
        super.onCreate(savedState);        
    }    
    @Override
    public View onCreateView(
        LayoutInflater inflater, 
        ViewGroup container, 
        Bundle savedState
    ){    
        super.onCreateView(inflater, container, savedState);                 
        ourViewGroup =
            (ViewGroup)inflater.inflate(
                R.layout.chart_fragment_base,
                container, false
                );
        if( ourViewGroup == null)
            throw new IllegalStateException(
                "BaseChartFragmentA failed to return a valid ourViewGroup"
                ); 
        ourViewGroup.setLayoutParams(_lParams);
        ImageButton resizeButton = 
            (ImageButton)ourViewGroup.findViewById(
                R.id.frag_resize_button
                );
        resizeButton.setOnTouchListener( 
            new ResizeButtonTouchListener() 
            );
        _totalTouchListener =  new TotalFragmentTouchListener(
            ApplicationPreferences.getSelectAnimation()
            );
        ourViewGroup.setOnTouchListener( _totalTouchListener);
        //
        ourViewGroup.setAlpha(_alpha);
        ourViewGroup.setPadding(
            _borderSz,_borderSz,_borderSz,_borderSz
            );    
        _borderOverlay = new BorderOverlay(
            this.getActivity(),_borderSz, Color.BLACK, true
            );
        ourViewGroup.addView(
            _borderOverlay,
            new RelativeLayout.LayoutParams(
                RelativeLayout.LayoutParams.MATCH_PARENT,
                RelativeLayout.LayoutParams.MATCH_PARENT
                )
            );
        ourViewGroup.setFocusable(false);        
        return ourViewGroup; 
    }    
    @Override 
    public void onActivityCreated(Bundle savedState)
    {
        super.onActivityCreated(savedState);
        if( this._uTag == null && savedState != null) 
            this._uTag = savedState.getString("uTag");
        if( this._uTag == null)
            throw new IllegalStateException(
                "ChartFragment does not have valid symbol string"
                );    
    }    
    @Override 
    public void onStart()  
    { 
        super.onStart();        
    }    
    @Override 
    public void onResume() 
    {
        super.onResume();        
    }
    @Override 
    public void onPause() 
    {
        super.onPause();        
    }    
    @Override
    public void onStop() 
    {        
        super.onStop();    
    }    
    @Override
    public void onSaveInstanceState(Bundle savedState) 
    {    
        savedState.putString(
            GlobalChartPreferences.GLOBAL_LINE_THICKNESS,
            _lineThickness.toString()
            );
        savedState.putInt(
            GlobalChartPreferences.GLOBAL_REFRESH_RATE, 
            _refreshRate
            );
        savedState.putFloat(
            GlobalChartPreferences.GLOBAL_ALPHA,
            _alpha
            );        
        savedState.putInt(
            GlobalChartPreferences.GLOBAL_BORDER_SIZE,
            _borderSz
            );
        savedState.putInt(BASE_COLOR, _colorId);
        super.onSaveInstanceState(savedState);         
    }
    @Override
    public void onDestroyView() 
    {
        super.onDestroyView();    
    }    
    @Override 
    public void onDestroy() 
    {
        super.onDestroy();        
    }    
    @Override
    public void onDetach() 
    {
        super.onDetach();
    }    
    
    /*|--------->         end LIFE-CYCLE handlers         <--------|*/
    /*|--------->     begin NESTED OBJECT DEFS        <--------|*/
    
    /* attempt to asynchronously wait for our resized frag view
     * to get to its appropriate dimensions before we refresh it*/
    static class AsyncRefresh extends Thread
    {
        private static final Object refLock = new Object();
        private final Handler root;
        private final int width;
        private final int height;
        private final BaseChartFragmentA  frag;
        private int timeOutCount = 0;
        private final int INCR = 
            ApplicationPreferences.getTimeoutIncrement();
        private final int TOUT = 
            ApplicationPreferences.getLongTimeout();
        public AsyncRefresh(
            Handler root, int w, int h, BaseChartFragmentA frag
            ){
                this.root = root;
                this.width = w;
                this.height = h;
                this.frag = frag;
            }
        @Override
        public void run() {        
            do{                
                if( frag.ourViewGroup.getMeasuredHeight() == height && 
                    frag.ourViewGroup.getMeasuredWidth() == width) 
                        break;
                try{
                    Thread.sleep(INCR);
                } catch (InterruptedException e){                                    
                }    
                if((timeOutCount+=INCR) > TOUT){            
                    Log.d("SpunkyCharts","BaseChartFragmentA "
                        + "time out, calling refresh w/o guarantees"
                        );
                    break;
                }                        
            }while(true);
            root.post(
                new Runnable(){
                    @Override
                    public void run(){
                        synchronized(refLock){
                            frag.refresh();
                        }
                    }});                        
        }
    }
    
    /* handle resize touches (drags and double tap 
     *  of the resize button - bottom right corner)*/
    class ResizeButtonTouchListener 
        implements View.OnTouchListener
    {
        private float startX = 0;
        private float startY = 0;
        private boolean hasBeenTouched = false;
        private boolean hasMoved = false;        
        public boolean onTouch(View v, MotionEvent event)                        
        {
            int action = event.getAction();
            switch(action)
            {
            case(MotionEvent.ACTION_DOWN):                 
                if(hasBeenTouched)    {    
                    /* since we share params only need this once */
                    parentActivity.resizeAndOrMove(
                        (RelativeLayout.LayoutParams )ourViewGroup.getLayoutParams(),
                        ourViewGroup,
                        LayoutParams.MATCH_PARENT, 
                        LayoutParams.MATCH_PARENT,
                        0, 0
                        );
                    /* make sure we refresh the entire stack */    
                    final View conn = (View)ourViewGroup.getParent();
                    for( BaseChartFragmentA tmp = getTopOfStack() ; 
                            tmp != null;     
                            tmp = tmp.getLastLinkOfStack() 
                            ){                                        
                                tmp.ourViewGroup.invalidate();
                                new AsyncRefresh(
                                    guiHandler,
                                    conn.getMeasuredWidth(),
                                    conn.getMeasuredHeight(),                                    
                                    tmp
                                    ).start();                
                                }                                            
                    hasBeenTouched = false;
                    return true;
                }
                hasBeenTouched = true;
                startX = event.getX();
                startY = event.getY();
                break;
            case(MotionEvent.ACTION_MOVE):    
                float moveX = event.getX();
            float moveY = event.getY();
            if( Math.abs(moveX-startX) > 
                    MainApplication.TMOVE_THRSHLD ||
                 Math.abs(moveY-startY) > 
                    MainApplication.TMOVE_THRSHLD 
                ){
                    hasMoved = true;
                }
                break;
            case(MotionEvent.ACTION_CANCEL):
            case(MotionEvent.ACTION_UP):
                if( hasBeenTouched && hasMoved ){
                    float x = ourViewGroup.getWidth();
                    float y = ourViewGroup.getHeight();
                    float newX = x + (event.getX() - startX);
                    float newY = y + (event.getY() - startY);                
                    if( newX >= 0 && newY >= 0){        
                        parentActivity.resizeAndOrMove( 
                            (RelativeLayout.LayoutParams )
                                ourViewGroup.getLayoutParams(),
                            ourViewGroup,     (int)newX, (int)newY, 0, 0
                            );
                    }                            
                    /* make sure we refresh the entire stack */                                
                    for( BaseChartFragmentA tmp = getTopOfStack() ; 
                            tmp != null;     
                            tmp = tmp.getLastLinkOfStack() 
                            ){        
                                tmp.ourViewGroup.invalidate();
                                new AsyncRefresh(
                                    guiHandler, (int)newX, (int)newY, tmp
                                    ).start();        
                            }
                    hasBeenTouched = false;
                    hasMoved = false;
                }                            
            }                        
            return true;
        }
    }

    /* hand touches (drags, source-tap, destination-tap, 
     *  add-to-stack tap of the entire view, except the 
     *  resize touch(above); also deals with setting up
     *  and controlling user-defined default and custom 
     *  animations*/
    class TotalFragmentTouchListener 
        implements View.OnTouchListener
    {
        private float yDistFromUpper = 0;
        private float yDistFromLower = 0;             
        private float xDistFromLeft = 0;
        private float xDistFromRight = 0;    
        private float startX = 0;
        private float startY = 0;
        private boolean hasMoved = false;
        private BaseSelectAnimationA onSelectedAnimation; 
      

        
        public TotalFragmentTouchListener(String animName)
        {
            super();
            setSelectAnimation(animName);
        }                
        // TODO: interrupt redraw ops while moving / resizing 
        //
        public synchronized boolean onTouch(
            View v, MotionEvent event
        ){
            BaseChartFragmentA downFrag = 
                parentActivity.getActiveFrag(); 
            int action = event.getAction(); 
            if( _stackTop != _this)        
                return false;  /* if we're not the top of the chart 'stack' */        
            switch(action)
            {
            case(MotionEvent.ACTION_DOWN): 
                yDistFromLower = 
                    parentActivity.getPanelHeight() - ourViewGroup.getBottom();    
                yDistFromUpper = ourViewGroup.getTop(); 
                xDistFromLeft = ourViewGroup.getLeft();
                xDistFromRight =
                    parentActivity.getPanelWidth() - ourViewGroup.getRight();
                startX = event.getX(); 
                startY = event.getY();
                break;
            case(MotionEvent.ACTION_MOVE):    
                float moveX = event.getX();
                float moveY = event.getY();
                if( Math.abs(moveX-startX) > 
                        MainApplication.TMOVE_THRSHLD ||
                     Math.abs(moveY-startY) > 
                        MainApplication.TMOVE_THRSHLD 
                    ){
                        parentActivity.setActiveFrag( null); 
                        hasMoved = true;
                }
                break;
            case(MotionEvent.ACTION_CANCEL):
            case(MotionEvent.ACTION_UP):    
                if( hasMoved){    
                    final float shiftX = event.getX() - startX;
                    final float shiftY = event.getY() - startY;   
                    final float overAllow = 
                        ApplicationPreferences.getPanelOverflowAllowed() 
                        * ourViewGroup.getMeasuredHeight();
                    final float snapThrshld = 
                        ApplicationPreferences.getPanelSnapThreshold();
                    /* if 'too far' up : minimize */
                    if( (shiftY*-1) >= yDistFromUpper + overAllow ) {            
                        parentActivity.minimizeChartFragment(_this._uTag);  
                    /* if 'too far' down : remove */
                    } else if( shiftY >= yDistFromLower + overAllow ){                    
                            parentActivity.removeChartFragment(_this._uTag);                                    
                    } else { 
                        float snapShiftX = shiftX;
                        float snapShiftY = shiftY;                             
                        /* if 'close' to top: snap in */   
                        if( (shiftY*-1) >= yDistFromUpper - snapThrshld
                            && (shiftY*-1) <= yDistFromUpper + snapThrshld ){
                                snapShiftY = yDistFromUpper * -1;
                        /* if 'close' to bottom: snap in */
                        } else if( shiftY >= yDistFromLower - snapThrshld
                            && shiftY <= yDistFromLower + snapThrshld ){
                                snapShiftY = yDistFromLower;                
                        }                         
                        /* if 'close' to left: snap in */
                        if( (shiftX*-1) >= xDistFromLeft - snapThrshld
                            && (shiftX*-1) <= xDistFromLeft + snapThrshld ){
                                snapShiftX = xDistFromLeft * -1;
                        /* if 'close' to right: snap in */
                        } else if( shiftX >= xDistFromRight - snapThrshld
                            && shiftX <= xDistFromRight + snapThrshld ){                        
                                snapShiftX = xDistFromRight;
                        }                        
                        /*note: not copying params */
                        parentActivity.resizeAndOrMove( 
                            (RelativeLayout.LayoutParams )
                                ourViewGroup.getLayoutParams(),
                            ourViewGroup,
                            0, 0,
                            (int)snapShiftX, (int)snapShiftY
                            );                                        
                    }                    
                    parentActivity.setActiveFrag( null); 
                    hasMoved = false;
                } else if( (event.getEventTime() - event.getDownTime()) 
                        > ApplicationPreferences.getChartHoldThreshold() 
                        ){
                            onHoldDown();
                 } else {
                         if(downFrag == null){
                             parentActivity.setActiveFrag( _this); 
                             (new timeoutThreadTy()).start();    
                             onSelectedAnimation.start();     
                         } else if( downFrag != _this) {
                             parentActivity.setActiveFrag( null); 
                             pushStack(downFrag);
                             for( BaseChartFragmentA tmp = downFrag ; 
                                     tmp != downFrag.getBaseOfStack();     
                                     tmp = tmp.getLastLinkOfStack() 
                                     ){
                                         RelativeLayout.LayoutParams lp = 
                                             (RelativeLayout.LayoutParams)
                                                 ourViewGroup.getLayoutParams();     
                                         /* note: not copying params */
                                         tmp.setLayoutParams( lp    );        
                                          tmp.ourViewGroup.invalidate();
                                          new AsyncRefresh(
                                             guiHandler, (int)lp.width, (int)lp.height, tmp
                                             ).start();        
                                         }                        
                         } else { /* if we click on 'ourself' pass the event 'down' */
                             parentActivity.setActiveFrag( null); 
                             return false; 
                         }                               
                     
                 }
                     
            }                        
            return true;
        }        
        public void setSelectAnimation( String animName)
        {
            Class<? extends BaseSelectAnimationA>animCls =
                MainApplication.metaSelectAnimTypes.get(
                    animName
                    );
            if(animCls == null)
                throw new
                    BaseSelectAnimationA.SelectAnimationException(
                        "invalid animation string"
                        );
            Exception exc = null;
            try {
                onSelectedAnimation = animCls.getConstructor(
                    View.class, 
                    BaseSelectAnimationA.AbortSignalCallback.class
                    ).newInstance(
                        ourViewGroup,
                        new BaseSelectAnimationA.AbortSignalCallback(){
                            public boolean check(){
                                return (parentActivity.getActiveFrag() != _this);
                                }
                            }                        
                        );
            } catch (java.lang.InstantiationException e) {                
                e.printStackTrace();
                exc = e;
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                exc = e;
            } catch (IllegalArgumentException e) {        
                e.printStackTrace();
                exc = e;
            } catch (InvocationTargetException e) {        
                e.printStackTrace();
                exc = e;
            } catch (NoSuchMethodException e) {                
                e.printStackTrace();
                exc = e;
            } finally {
                if( exc != null)
                    throw new 
                        BaseSelectAnimationA.SelectAnimationException(
                            exc.getMessage()
                        );
            }
             setupSelectAnimation();
        }
        public void setupSelectAnimation()
        {
            if(onSelectedAnimation != null)
                onSelectedAnimation.setup( 
                    ApplicationPreferences.getSelectAnimationFrequency(), 
                    ApplicationPreferences.getSelectAnimationSeverity(),
                    ApplicationPreferences.getSelectAnimationTimeout()
                    );
        }
        private class timeoutThreadTy extends Thread
        {            
            public void run(){
                try {
                    Thread.sleep( 
                        ApplicationPreferences.getSelectAnimationTimeout() 
                        );                    
                    parentActivity.setActiveFrag( null);     
                } catch (InterruptedException e) {}    
                }                        
        };
    }

}




Java Source Code List

com.jogden.spunkycharts.ApplicationPreferences.java
com.jogden.spunkycharts.BaseChartFragmentA.java
com.jogden.spunkycharts.ChartPanelSurfaceView.java
com.jogden.spunkycharts.DockingPanelActivity.java
com.jogden.spunkycharts.GlobalChartPreferences.java
com.jogden.spunkycharts.InitActivity.java
com.jogden.spunkycharts.MainApplication.java
com.jogden.spunkycharts.OpeningView.java
com.jogden.spunkycharts.animations.BaseAnimationA.java
com.jogden.spunkycharts.animations.BaseEntExAnimationA.java
com.jogden.spunkycharts.animations.BaseSelectAnimationA.java
com.jogden.spunkycharts.animations.HorizontalBulgeAnimation.java
com.jogden.spunkycharts.animations.HorizontalShakeAnimation.java
com.jogden.spunkycharts.animations.VerticalBulgeAnimation.java
com.jogden.spunkycharts.animations.VerticalShakeAnimation.java
com.jogden.spunkycharts.animations.WiggleAnimation.java
com.jogden.spunkycharts.data.DataClientLocalDebug.java
com.jogden.spunkycharts.data.DataContentService.java
com.jogden.spunkycharts.misc.BorderOverlay.java
com.jogden.spunkycharts.misc.ColorPaletteDialog.java
com.jogden.spunkycharts.misc.HideHorizontalLeftOverflowWrapper.java
com.jogden.spunkycharts.misc.OHLC.java
com.jogden.spunkycharts.misc.Pair.java
com.jogden.spunkycharts.misc.TextInput.java
com.jogden.spunkycharts.misc.Triple.java
com.jogden.spunkycharts.pricebyvolumechart.PriceByVolumeChartFragmentAdapter.java
com.jogden.spunkycharts.pricebyvolumechart.PriceByVolumeChartFragment.java
com.jogden.spunkycharts.pricebyvolumechart.PriceByVolumeChartPanel.java
com.jogden.spunkycharts.pricebyvolumechart.PriceByVolumeChartPreferences.java
com.jogden.spunkycharts.pricebyvolumechart.draw.DrawSemanticsA.java
com.jogden.spunkycharts.pricebyvolumechart.draw.DrawSemantics_SILO.java
com.jogden.spunkycharts.traditionalchart.InnerXAxis.java
com.jogden.spunkycharts.traditionalchart.TraditionalChartFragmentAdapter.java
com.jogden.spunkycharts.traditionalchart.TraditionalChartFragment.java
com.jogden.spunkycharts.traditionalchart.TraditionalChartPanel.java
com.jogden.spunkycharts.traditionalchart.TraditionalChartPreferences.java
com.jogden.spunkycharts.traditionalchart.XAxisTimeLabel.java
com.jogden.spunkycharts.traditionalchart.YAxisPriceLabel.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemanticsA_C.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemanticsA.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemantics_CANDLE.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemantics_LINE.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemantics_OC.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemantics_OHLC.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemantics_POINT.java
com.jogden.spunkycharts.traditionalchart.draw.DrawSemantics_SILO.java