Home | History | Annotate | Download | only in imageshow
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.gallery3d.filtershow.imageshow;
     18 
     19 import android.content.Context;
     20 import android.graphics.Bitmap;
     21 import android.graphics.Canvas;
     22 import android.graphics.Color;
     23 import android.graphics.Paint;
     24 import android.graphics.Rect;
     25 import android.graphics.RectF;
     26 import android.os.Handler;
     27 import android.util.AttributeSet;
     28 import android.view.GestureDetector;
     29 import android.view.GestureDetector.OnDoubleTapListener;
     30 import android.view.GestureDetector.OnGestureListener;
     31 import android.view.MotionEvent;
     32 import android.view.View;
     33 import android.widget.ArrayAdapter;
     34 import android.widget.SeekBar;
     35 import android.widget.SeekBar.OnSeekBarChangeListener;
     36 
     37 import com.android.gallery3d.R;
     38 import com.android.gallery3d.filtershow.FilterShowActivity;
     39 import com.android.gallery3d.filtershow.HistoryAdapter;
     40 import com.android.gallery3d.filtershow.ImageStateAdapter;
     41 import com.android.gallery3d.filtershow.PanelController;
     42 import com.android.gallery3d.filtershow.cache.ImageLoader;
     43 import com.android.gallery3d.filtershow.filters.ImageFilter;
     44 import com.android.gallery3d.filtershow.presets.ImagePreset;
     45 import com.android.gallery3d.filtershow.ui.SliderController;
     46 import com.android.gallery3d.filtershow.ui.SliderListener;
     47 
     48 import java.io.File;
     49 
     50 public class ImageShow extends View implements OnGestureListener,
     51         OnDoubleTapListener,
     52         SliderListener,
     53         OnSeekBarChangeListener {
     54 
     55     private static final String LOGTAG = "ImageShow";
     56 
     57     protected Paint mPaint = new Paint();
     58     protected static int mTextSize = 24;
     59     protected static int mTextPadding = 20;
     60 
     61     protected ImagePreset mImagePreset = null;
     62     protected ImagePreset mImageGeometryOnlyPreset = null;
     63     protected ImagePreset mImageFiltersOnlyPreset = null;
     64 
     65     protected ImageLoader mImageLoader = null;
     66     private ImageFilter mCurrentFilter = null;
     67     private boolean mDirtyGeometry = false;
     68 
     69     private Bitmap mBackgroundImage = null;
     70     private final boolean USE_BACKGROUND_IMAGE = false;
     71     private static int mBackgroundColor = Color.RED;
     72 
     73     private Bitmap mGeometryOnlyImage = null;
     74     private Bitmap mFiltersOnlyImage = null;
     75     private Bitmap mFilteredImage = null;
     76 
     77     private final boolean USE_SLIDER_GESTURE = false; // set to true to have
     78                                                       // slider gesture
     79     protected SliderController mSliderController = new SliderController();
     80 
     81     private GestureDetector mGestureDetector = null;
     82 
     83     private HistoryAdapter mHistoryAdapter = null;
     84     private ImageStateAdapter mImageStateAdapter = null;
     85 
     86     private Rect mImageBounds = new Rect();
     87 
     88     private boolean mTouchShowOriginal = false;
     89     private long mTouchShowOriginalDate = 0;
     90     private final long mTouchShowOriginalDelayMin = 200; // 200ms
     91     private final long mTouchShowOriginalDelayMax = 300; // 300ms
     92     private int mShowOriginalDirection = 0;
     93     private static int UNVEIL_HORIZONTAL = 1;
     94     private static int UNVEIL_VERTICAL = 2;
     95 
     96     private int mTouchDownX = 0;
     97     private int mTouchDownY = 0;
     98     protected float mTouchX = 0;
     99     protected float mTouchY = 0;
    100 
    101     private static int mOriginalTextMargin = 8;
    102     private static int mOriginalTextSize = 26;
    103     private static String mOriginalText = "Original";
    104 
    105     protected GeometryMetadata getGeometry() {
    106         return new GeometryMetadata(getImagePreset().mGeoData);
    107     }
    108 
    109     public void setGeometry(GeometryMetadata d) {
    110         getImagePreset().mGeoData.set(d);
    111     }
    112 
    113     private boolean mShowControls = false;
    114     private boolean mShowOriginal = false;
    115     private String mToast = null;
    116     private boolean mShowToast = false;
    117     private boolean mImportantToast = false;
    118 
    119     private SeekBar mSeekBar = null;
    120     private PanelController mController = null;
    121 
    122     private FilterShowActivity mActivity = null;
    123 
    124     public static void setDefaultBackgroundColor(int value) {
    125         mBackgroundColor = value;
    126     }
    127 
    128     public int getDefaultBackgroundColor() {
    129         return mBackgroundColor;
    130     }
    131 
    132     public static void setTextSize(int value) {
    133         mTextSize = value;
    134     }
    135 
    136     public static void setTextPadding(int value) {
    137         mTextPadding = value;
    138     }
    139 
    140     public static void setOriginalTextMargin(int value) {
    141         mOriginalTextMargin = value;
    142     }
    143 
    144     public static void setOriginalTextSize(int value) {
    145         mOriginalTextSize = value;
    146     }
    147 
    148     public static void setOriginalText(String text) {
    149         mOriginalText = text;
    150     }
    151 
    152     private final Handler mHandler = new Handler();
    153 
    154     public void select() {
    155         if (getCurrentFilter() != null) {
    156             int parameter = getCurrentFilter().getParameter();
    157             int maxp = getCurrentFilter().getMaxParameter();
    158             int minp = getCurrentFilter().getMinParameter();
    159             updateSeekBar(parameter, minp, maxp);
    160         }
    161         if (mSeekBar != null) {
    162             mSeekBar.setOnSeekBarChangeListener(this);
    163         }
    164     }
    165 
    166     private int parameterToUI(int parameter, int minp, int maxp, int uimax) {
    167         return (uimax * (parameter - minp)) / (maxp - minp);
    168     }
    169 
    170     private int uiToParameter(int ui, int minp, int maxp, int uimax) {
    171         return ((maxp - minp) * ui) / uimax + minp;
    172     }
    173 
    174     public void updateSeekBar(int parameter, int minp, int maxp) {
    175         if (mSeekBar == null) {
    176             return;
    177         }
    178         int seekMax = mSeekBar.getMax();
    179         int progress = parameterToUI(parameter, minp, maxp, seekMax);
    180         mSeekBar.setProgress(progress);
    181         if (getPanelController() != null) {
    182             getPanelController().onNewValue(parameter);
    183         }
    184     }
    185 
    186     public void unselect() {
    187 
    188     }
    189 
    190     public boolean hasModifications() {
    191         if (getImagePreset() == null) {
    192             return false;
    193         }
    194         return getImagePreset().hasModifications();
    195     }
    196 
    197     public void resetParameter() {
    198         ImageFilter currentFilter = getCurrentFilter();
    199         if (currentFilter != null) {
    200             onNewValue(currentFilter.getDefaultParameter());
    201         }
    202         if (USE_SLIDER_GESTURE) {
    203             mSliderController.reset();
    204         }
    205     }
    206 
    207     public void setPanelController(PanelController controller) {
    208         mController = controller;
    209     }
    210 
    211     public PanelController getPanelController() {
    212         return mController;
    213     }
    214 
    215     @Override
    216     public void onNewValue(int parameter) {
    217         int maxp = 100;
    218         int minp = -100;
    219         if (getCurrentFilter() != null) {
    220             getCurrentFilter().setParameter(parameter);
    221             maxp = getCurrentFilter().getMaxParameter();
    222             minp = getCurrentFilter().getMinParameter();
    223         }
    224         if (getImagePreset() != null) {
    225             mImageLoader.resetImageForPreset(getImagePreset(), this);
    226             getImagePreset().fillImageStateAdapter(mImageStateAdapter);
    227         }
    228         if (getPanelController() != null) {
    229             getPanelController().onNewValue(parameter);
    230         }
    231         updateSeekBar(parameter, minp, maxp);
    232         invalidate();
    233     }
    234 
    235     @Override
    236     public void onTouchDown(float x, float y) {
    237         mTouchX = x;
    238         mTouchY = y;
    239         invalidate();
    240     }
    241 
    242     @Override
    243     public void onTouchUp() {
    244     }
    245 
    246     public ImageShow(Context context, AttributeSet attrs) {
    247         super(context, attrs);
    248         if (USE_SLIDER_GESTURE) {
    249             mSliderController.setListener(this);
    250         }
    251         mHistoryAdapter = new HistoryAdapter(context, R.layout.filtershow_history_operation_row,
    252                 R.id.rowTextView);
    253         mImageStateAdapter = new ImageStateAdapter(context,
    254                 R.layout.filtershow_imagestate_row);
    255         setupGestureDetector(context);
    256         mActivity = (FilterShowActivity) context;
    257     }
    258 
    259     public ImageShow(Context context) {
    260         super(context);
    261         if (USE_SLIDER_GESTURE) {
    262             mSliderController.setListener(this);
    263         }
    264         mHistoryAdapter = new HistoryAdapter(context, R.layout.filtershow_history_operation_row,
    265                 R.id.rowTextView);
    266         setupGestureDetector(context);
    267         mActivity = (FilterShowActivity) context;
    268     }
    269 
    270     public void setupGestureDetector(Context context) {
    271         mGestureDetector = new GestureDetector(context, this);
    272     }
    273 
    274     @Override
    275     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    276         int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
    277         int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
    278         setMeasuredDimension(parentWidth, parentHeight);
    279         if (USE_SLIDER_GESTURE) {
    280             mSliderController.setWidth(parentWidth);
    281             mSliderController.setHeight(parentHeight);
    282         }
    283     }
    284 
    285     public void setSeekBar(SeekBar seekBar) {
    286         mSeekBar = seekBar;
    287     }
    288 
    289     public void setCurrentFilter(ImageFilter filter) {
    290         mCurrentFilter = filter;
    291     }
    292 
    293     public ImageFilter getCurrentFilter() {
    294         return mCurrentFilter;
    295     }
    296 
    297     public void setAdapter(HistoryAdapter adapter) {
    298         mHistoryAdapter = adapter;
    299     }
    300 
    301     public void showToast(String text) {
    302         showToast(text, false);
    303     }
    304 
    305     public void showToast(String text, boolean important) {
    306         mToast = text;
    307         mShowToast = true;
    308         mImportantToast = important;
    309         invalidate();
    310 
    311         mHandler.postDelayed(new Runnable() {
    312             @Override
    313             public void run() {
    314                 mShowToast = false;
    315                 invalidate();
    316             }
    317         }, 400);
    318     }
    319 
    320     public Rect getImageBounds() {
    321         Rect dst = new Rect();
    322         getImagePreset().mGeoData.getPhotoBounds().roundOut(dst);
    323         return dst;
    324     }
    325 
    326     public Rect getDisplayedImageBounds() {
    327         return mImageBounds;
    328     }
    329 
    330     public ImagePreset getImagePreset() {
    331         return mImagePreset;
    332     }
    333 
    334     public void drawToast(Canvas canvas) {
    335         if (mShowToast && mToast != null) {
    336             Paint paint = new Paint();
    337             paint.setTextSize(128);
    338             float textWidth = paint.measureText(mToast);
    339             int toastX = (int) ((getWidth() - textWidth) / 2.0f);
    340             int toastY = (int) (getHeight() / 3.0f);
    341 
    342             paint.setARGB(255, 0, 0, 0);
    343             canvas.drawText(mToast, toastX - 2, toastY - 2, paint);
    344             canvas.drawText(mToast, toastX - 2, toastY, paint);
    345             canvas.drawText(mToast, toastX, toastY - 2, paint);
    346             canvas.drawText(mToast, toastX + 2, toastY + 2, paint);
    347             canvas.drawText(mToast, toastX + 2, toastY, paint);
    348             canvas.drawText(mToast, toastX, toastY + 2, paint);
    349             if (mImportantToast) {
    350                 paint.setARGB(255, 200, 0, 0);
    351             } else {
    352                 paint.setARGB(255, 255, 255, 255);
    353             }
    354             canvas.drawText(mToast, toastX, toastY, paint);
    355         }
    356     }
    357 
    358     public void defaultDrawImage(Canvas canvas) {
    359         drawImage(canvas, getFilteredImage());
    360         drawPartialImage(canvas, getGeometryOnlyImage());
    361     }
    362 
    363     @Override
    364     public void onDraw(Canvas canvas) {
    365         drawBackground(canvas);
    366         requestFilteredImages();
    367         defaultDrawImage(canvas);
    368 
    369         if (showTitle() && getImagePreset() != null) {
    370             mPaint.setARGB(200, 0, 0, 0);
    371             mPaint.setTextSize(mTextSize);
    372 
    373             Rect textRect = new Rect(0, 0, getWidth(), mTextSize + mTextPadding);
    374             canvas.drawRect(textRect, mPaint);
    375             mPaint.setARGB(255, 200, 200, 200);
    376             canvas.drawText(getImagePreset().name(), mTextPadding,
    377                     1.5f * mTextPadding, mPaint);
    378         }
    379 
    380         if (showControls()) {
    381             if (USE_SLIDER_GESTURE) {
    382                 mSliderController.onDraw(canvas);
    383             }
    384         }
    385 
    386         drawToast(canvas);
    387     }
    388 
    389     public void resetImageCaches(ImageShow caller) {
    390         if (mImageLoader == null) {
    391             return;
    392         }
    393         updateImagePresets(true);
    394     }
    395 
    396     public void updateImagePresets(boolean force) {
    397         ImagePreset preset = getImagePreset();
    398         if (preset == null) {
    399             return;
    400         }
    401         if (force) {
    402             mImageLoader.resetImageForPreset(getImagePreset(), this);
    403         }
    404         if (force || mImageGeometryOnlyPreset == null) {
    405             ImagePreset newPreset = new ImagePreset(preset);
    406             newPreset.setDoApplyFilters(false);
    407             if (mImageGeometryOnlyPreset == null
    408                     || !newPreset.same(mImageGeometryOnlyPreset)) {
    409                 mImageGeometryOnlyPreset = newPreset;
    410                 mGeometryOnlyImage = null;
    411             }
    412         }
    413         if (force || mImageFiltersOnlyPreset == null) {
    414             ImagePreset newPreset = new ImagePreset(preset);
    415             newPreset.setDoApplyGeometry(false);
    416             if (mImageFiltersOnlyPreset == null
    417                     || !newPreset.same(mImageFiltersOnlyPreset)) {
    418                 mImageFiltersOnlyPreset = newPreset;
    419                 mFiltersOnlyImage = null;
    420             }
    421         }
    422     }
    423 
    424     public void requestFilteredImages() {
    425         if (mImageLoader != null) {
    426             Bitmap bitmap = mImageLoader.getImageForPreset(this,
    427                     getImagePreset(), showHires());
    428 
    429             if (bitmap != null) {
    430                 if (mFilteredImage == null) {
    431                     invalidate();
    432                 }
    433                 mFilteredImage = bitmap;
    434             }
    435 
    436             updateImagePresets(false);
    437             if (mImageGeometryOnlyPreset != null) {
    438                 bitmap = mImageLoader.getImageForPreset(this, mImageGeometryOnlyPreset,
    439                         showHires());
    440                 if (bitmap != null) {
    441                     mGeometryOnlyImage = bitmap;
    442                 }
    443             }
    444             if (mImageFiltersOnlyPreset != null) {
    445                 bitmap = mImageLoader.getImageForPreset(this, mImageFiltersOnlyPreset,
    446                         showHires());
    447                 if (bitmap != null) {
    448                     mFiltersOnlyImage = bitmap;
    449                 }
    450             }
    451         }
    452 
    453         if (mShowOriginal) {
    454             mFilteredImage = mGeometryOnlyImage;
    455         }
    456     }
    457 
    458     public Bitmap getFiltersOnlyImage() {
    459         return mFiltersOnlyImage;
    460     }
    461 
    462     public Bitmap getGeometryOnlyImage() {
    463         return mGeometryOnlyImage;
    464     }
    465 
    466     public Bitmap getFilteredImage() {
    467         return mFilteredImage;
    468     }
    469 
    470     public void drawImage(Canvas canvas, Bitmap image) {
    471         if (image != null) {
    472             Rect s = new Rect(0, 0, image.getWidth(),
    473                     image.getHeight());
    474 
    475             float scale = GeometryMath.scale(image.getWidth(), image.getHeight(), getWidth(),
    476                     getHeight());
    477 
    478             float w = image.getWidth() * scale;
    479             float h = image.getHeight() * scale;
    480             float ty = (getHeight() - h) / 2.0f;
    481             float tx = (getWidth() - w) / 2.0f;
    482 
    483             Rect d = new Rect((int) tx, (int) ty, (int) (w + tx),
    484                     (int) (h + ty));
    485             mImageBounds = d;
    486             canvas.drawBitmap(image, s, d, mPaint);
    487         }
    488     }
    489 
    490     public void drawPartialImage(Canvas canvas, Bitmap image) {
    491         if (!mTouchShowOriginal)
    492             return;
    493         canvas.save();
    494         if (image != null) {
    495             if (mShowOriginalDirection == 0) {
    496                 if ((mTouchY - mTouchDownY) > (mTouchX - mTouchDownX)) {
    497                     mShowOriginalDirection = UNVEIL_VERTICAL;
    498                 } else {
    499                     mShowOriginalDirection = UNVEIL_HORIZONTAL;
    500                 }
    501             }
    502 
    503             int px = 0;
    504             int py = 0;
    505             if (mShowOriginalDirection == UNVEIL_VERTICAL) {
    506                 px = mImageBounds.width();
    507                 py = (int) (mTouchY - mImageBounds.top);
    508             } else {
    509                 px = (int) (mTouchX - mImageBounds.left);
    510                 py = mImageBounds.height();
    511             }
    512 
    513             Rect d = new Rect(mImageBounds.left, mImageBounds.top,
    514                     mImageBounds.left + px, mImageBounds.top + py);
    515             canvas.clipRect(d);
    516             drawImage(canvas, image);
    517             Paint paint = new Paint();
    518             paint.setColor(Color.BLACK);
    519 
    520             if (mShowOriginalDirection == UNVEIL_VERTICAL) {
    521                 canvas.drawLine(mImageBounds.left, mTouchY - 1,
    522                         mImageBounds.right, mTouchY - 1, paint);
    523             } else {
    524                 canvas.drawLine(mTouchX - 1, mImageBounds.top,
    525                         mTouchX - 1, mImageBounds.bottom, paint);
    526             }
    527 
    528             Rect bounds = new Rect();
    529             paint.setTextSize(mOriginalTextSize);
    530             paint.getTextBounds(mOriginalText, 0, mOriginalText.length(), bounds);
    531             paint.setColor(Color.BLACK);
    532             canvas.drawText(mOriginalText, mImageBounds.left + mOriginalTextMargin + 1,
    533                     mImageBounds.top + bounds.height() + mOriginalTextMargin + 1, paint);
    534             paint.setColor(Color.WHITE);
    535             canvas.drawText(mOriginalText, mImageBounds.left + mOriginalTextMargin,
    536                     mImageBounds.top + bounds.height() + mOriginalTextMargin, paint);
    537         }
    538         canvas.restore();
    539     }
    540 
    541     public void drawBackground(Canvas canvas) {
    542         if (USE_BACKGROUND_IMAGE) {
    543             if (mBackgroundImage == null) {
    544                 mBackgroundImage = mImageLoader.getBackgroundBitmap(getResources());
    545             }
    546             if (mBackgroundImage != null) {
    547                 Rect s = new Rect(0, 0, mBackgroundImage.getWidth(),
    548                         mBackgroundImage.getHeight());
    549                 Rect d = new Rect(0, 0, getWidth(), getHeight());
    550                 canvas.drawBitmap(mBackgroundImage, s, d, mPaint);
    551             }
    552         } else {
    553             canvas.drawColor(mBackgroundColor);
    554         }
    555     }
    556 
    557     public ImageShow setShowControls(boolean value) {
    558         mShowControls = value;
    559         if (mShowControls) {
    560             if (mSeekBar != null) {
    561                 mSeekBar.setVisibility(View.VISIBLE);
    562             }
    563         } else {
    564             if (mSeekBar != null) {
    565                 mSeekBar.setVisibility(View.INVISIBLE);
    566             }
    567         }
    568         return this;
    569     }
    570 
    571     public boolean showControls() {
    572         return mShowControls;
    573     }
    574 
    575     public boolean showHires() {
    576         return true;
    577     }
    578 
    579     public boolean showTitle() {
    580         return false;
    581     }
    582 
    583     public void setImagePreset(ImagePreset preset) {
    584         setImagePreset(preset, true);
    585     }
    586 
    587     public void setImagePreset(ImagePreset preset, boolean addToHistory) {
    588         if (preset == null) {
    589             return;
    590         }
    591         mImagePreset = preset;
    592         getImagePreset().setImageLoader(mImageLoader);
    593         updateImagePresets(true);
    594         if (addToHistory) {
    595             mHistoryAdapter.addHistoryItem(getImagePreset());
    596         }
    597         getImagePreset().setEndpoint(this);
    598         updateImage();
    599         mImagePreset.fillImageStateAdapter(mImageStateAdapter);
    600         invalidate();
    601     }
    602 
    603     public void setImageLoader(ImageLoader loader) {
    604         mImageLoader = loader;
    605         if (mImageLoader != null) {
    606             mImageLoader.addListener(this);
    607             if (mImagePreset != null) {
    608                 mImagePreset.setImageLoader(mImageLoader);
    609             }
    610         }
    611     }
    612 
    613     private void setDirtyGeometryFlag() {
    614         mDirtyGeometry = true;
    615     }
    616 
    617     protected void clearDirtyGeometryFlag() {
    618         mDirtyGeometry = false;
    619     }
    620 
    621     protected boolean getDirtyGeometryFlag() {
    622         return mDirtyGeometry;
    623     }
    624 
    625     private void imageSizeChanged(Bitmap image) {
    626         if (image == null || getImagePreset() == null)
    627             return;
    628         float w = image.getWidth();
    629         float h = image.getHeight();
    630         GeometryMetadata geo = getImagePreset().mGeoData;
    631         RectF pb = geo.getPhotoBounds();
    632         if (w == pb.width() && h == pb.height()) {
    633             return;
    634         }
    635         RectF r = new RectF(0, 0, w, h);
    636         getImagePreset().mGeoData.setPhotoBounds(r);
    637         getImagePreset().mGeoData.setCropBounds(r);
    638         setDirtyGeometryFlag();
    639     }
    640 
    641     public boolean updateGeometryFlags() {
    642         return true;
    643     }
    644 
    645     public void updateImage() {
    646         if (!updateGeometryFlags()) {
    647             return;
    648         }
    649         Bitmap bitmap = mImageLoader.getOriginalBitmapLarge();
    650         if (bitmap != null) {
    651             imageSizeChanged(bitmap);
    652             invalidate();
    653         }
    654     }
    655 
    656     public void imageLoaded() {
    657         updateImage();
    658         invalidate();
    659     }
    660 
    661     public void updateFilteredImage(Bitmap bitmap) {
    662         mFilteredImage = bitmap;
    663     }
    664 
    665     public void saveImage(FilterShowActivity filterShowActivity, File file) {
    666         mImageLoader.saveImage(getImagePreset(), filterShowActivity, file);
    667     }
    668 
    669     @Override
    670     public boolean onTouchEvent(MotionEvent event) {
    671         super.onTouchEvent(event);
    672         if (USE_SLIDER_GESTURE) {
    673             mSliderController.onTouchEvent(event);
    674         }
    675         if (mGestureDetector != null) {
    676             mGestureDetector.onTouchEvent(event);
    677         }
    678         int ex = (int) event.getX();
    679         int ey = (int) event.getY();
    680         if (event.getAction() == MotionEvent.ACTION_DOWN) {
    681             mTouchDownX = ex;
    682             mTouchDownY = ey;
    683             mTouchShowOriginalDate = System.currentTimeMillis();
    684             mShowOriginalDirection = 0;
    685         }
    686         if (event.getAction() == MotionEvent.ACTION_MOVE) {
    687             mTouchX = ex;
    688             mTouchY = ey;
    689             if (!mActivity.isShowingHistoryPanel()
    690                     && (System.currentTimeMillis() - mTouchShowOriginalDate
    691                     > mTouchShowOriginalDelayMin)) {
    692                 mTouchShowOriginal = true;
    693             }
    694         }
    695         if (event.getAction() == MotionEvent.ACTION_UP) {
    696             mTouchShowOriginal = false;
    697             mTouchDownX = 0;
    698             mTouchDownY = 0;
    699             mTouchX = 0;
    700             mTouchY = 0;
    701         }
    702         invalidate();
    703         return true;
    704     }
    705 
    706     // listview stuff
    707 
    708     public HistoryAdapter getHistory() {
    709         return mHistoryAdapter;
    710     }
    711 
    712     public ArrayAdapter getImageStateAdapter() {
    713         return mImageStateAdapter;
    714     }
    715 
    716     public void onItemClick(int position) {
    717         setImagePreset(new ImagePreset(mHistoryAdapter.getItem(position)), false);
    718         // we need a copy from the history
    719         mHistoryAdapter.setCurrentPreset(position);
    720     }
    721 
    722     public void showOriginal(boolean show) {
    723         mShowOriginal = show;
    724         invalidate();
    725     }
    726 
    727     public float getImageRotation() {
    728         return getImagePreset().mGeoData.getRotation();
    729     }
    730 
    731     public float getImageRotationZoomFactor() {
    732         return getImagePreset().mGeoData.getScaleFactor();
    733     }
    734 
    735     public void setImageRotation(float r) {
    736         getImagePreset().mGeoData.setRotation(r);
    737     }
    738 
    739     public void setImageRotationZoomFactor(float f) {
    740         getImagePreset().mGeoData.setScaleFactor(f);
    741     }
    742 
    743     public void setImageRotation(float imageRotation,
    744             float imageRotationZoomFactor) {
    745         float r = getImageRotation();
    746         if (imageRotation != r) {
    747             invalidate();
    748         }
    749         setImageRotation(imageRotation);
    750         setImageRotationZoomFactor(imageRotationZoomFactor);
    751     }
    752 
    753     @Override
    754     public void onProgressChanged(SeekBar arg0, int progress, boolean arg2) {
    755         int parameter = progress;
    756         if (getCurrentFilter() != null) {
    757             int maxp = getCurrentFilter().getMaxParameter();
    758             int minp = getCurrentFilter().getMinParameter();
    759             parameter = uiToParameter(progress, minp, maxp, arg0.getMax());
    760         }
    761 
    762         onNewValue(parameter);
    763     }
    764 
    765     @Override
    766     public void onStartTrackingTouch(SeekBar arg0) {
    767         // TODO Auto-generated method stub
    768 
    769     }
    770 
    771     @Override
    772     public void onStopTrackingTouch(SeekBar arg0) {
    773         // TODO Auto-generated method stub
    774 
    775     }
    776 
    777     @Override
    778     public boolean onDoubleTap(MotionEvent arg0) {
    779         // TODO Auto-generated method stub
    780         return false;
    781     }
    782 
    783     @Override
    784     public boolean onDoubleTapEvent(MotionEvent arg0) {
    785         // TODO Auto-generated method stub
    786         return false;
    787     }
    788 
    789     @Override
    790     public boolean onSingleTapConfirmed(MotionEvent arg0) {
    791         // TODO Auto-generated method stub
    792         return false;
    793     }
    794 
    795     @Override
    796     public boolean onDown(MotionEvent arg0) {
    797         // TODO Auto-generated method stub
    798         return false;
    799     }
    800 
    801     @Override
    802     public boolean onFling(MotionEvent startEvent, MotionEvent endEvent, float arg2, float arg3) {
    803         if ((!mActivity.isShowingHistoryPanel() && startEvent.getX() > endEvent.getX())
    804                 || (mActivity.isShowingHistoryPanel() && endEvent.getX() > startEvent.getX())) {
    805             if (!mTouchShowOriginal
    806                     || (mTouchShowOriginal &&
    807                     (System.currentTimeMillis() - mTouchShowOriginalDate
    808                     < mTouchShowOriginalDelayMax))) {
    809                 mActivity.toggleHistoryPanel();
    810             }
    811         }
    812         return true;
    813     }
    814 
    815     @Override
    816     public void onLongPress(MotionEvent arg0) {
    817         // TODO Auto-generated method stub
    818 
    819     }
    820 
    821     @Override
    822     public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2, float arg3) {
    823         // TODO Auto-generated method stub
    824         return false;
    825     }
    826 
    827     @Override
    828     public void onShowPress(MotionEvent arg0) {
    829         // TODO Auto-generated method stub
    830 
    831     }
    832 
    833     @Override
    834     public boolean onSingleTapUp(MotionEvent arg0) {
    835         // TODO Auto-generated method stub
    836         return false;
    837     }
    838 
    839 }
    840