Improves Curves & Crop UI

bug:7361722

- Use new assets
- Add a margin
- Add a popup menu
- Add a new button showing the current channel
- Add popup menu, new assets, new button for Crop as well

Change-Id: I0e09098e3135d2213f7f4cd64cd75a3a518a07da
diff --git a/res/layout/filtershow_activity.xml b/res/layout/filtershow_activity.xml
index c62e714..e07cb1c 100644
--- a/res/layout/filtershow_activity.xml
+++ b/res/layout/filtershow_activity.xml
@@ -193,34 +193,41 @@
                 android:orientation="horizontal"
                 android:visibility="gone" >
 
-                <com.android.gallery3d.filtershow.ui.ImageButtonTitle
-                    android:id="@+id/aspect"
-                    style="@style/FilterShowBottomButton"
-                    android:layout_gravity="left"
-                    android:layout_weight="0"
-                    android:visibility="gone"
-                    android:src="@drawable/filtershow_button_geometry_straighten"
-                    android:text="@string/aspect" />
+                <FrameLayout
+                    android:layout_width="fill_parent"
+                    android:layout_height="fill_parent" >
+                    <com.android.gallery3d.filtershow.ui.FramedTextButton
+                        android:id="@+id/aspect"
+                        android:layout_width="64dip"
+                        android:layout_height="64dip"
+                        android:layout_gravity="center_vertical|left"
+                        android:background="@android:color/transparent"
+                        android:scaleType="centerInside"
+                        android:visibility="gone"
+                        android:text="@string/aspectOriginal_effect" />
 
-                <ImageButton
-                    android:id="@+id/pickCurvesChannel"
-                    android:layout_width="64dip"
-                    android:layout_height="64dip"
-                    android:layout_gravity="center_vertical|left"
-                    android:scaleType="centerInside"
-                    android:text="@string/curvesRGB"
-                    android:src="@drawable/filtershow_button_show_original" />
+                    <com.android.gallery3d.filtershow.ui.FramedTextButton
+                        android:id="@+id/pickCurvesChannel"
+                        android:layout_width="64dip"
+                        android:layout_height="64dip"
+                        android:layout_gravity="center_vertical|left"
+                        android:background="@android:color/transparent"
+                        android:scaleType="centerInside"
+                        android:visibility="gone"
+                        android:text="@string/curves_channel_rgb" />
 
-                <Button
-                    android:id="@+id/applyEffect"
-                    android:layout_width="wrap_content"
-                    android:layout_height="94dip"
-                    android:layout_gravity="center"
-                    android:layout_weight="1"
-                    android:background="@android:color/transparent"
-                    android:gravity="center"
-                    android:text="@string/apply_effect"
-                    android:textSize="18dip" />
+                    <Button
+                        android:id="@+id/applyEffect"
+                        android:layout_width="wrap_content"
+                        android:layout_height="94dip"
+                        android:layout_gravity="center"
+                        android:layout_weight="1"
+                        android:background="@android:color/transparent"
+                        android:gravity="center"
+                        android:text="@string/apply_effect"
+                        android:textSize="18dip" />
+                </FrameLayout>
+
             </LinearLayout>
 
             <HorizontalScrollView
diff --git a/res/menu/filtershow_menu_crop.xml b/res/menu/filtershow_menu_crop.xml
new file mode 100644
index 0000000..dc85d6f
--- /dev/null
+++ b/res/menu/filtershow_menu_crop.xml
@@ -0,0 +1,24 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <group android:id="@+id/crop_popupmenu" >
+        <item
+            android:id="@+id/crop_menu_1to1"
+            android:title="@string/aspect1to1_effect"/>
+        <item
+            android:id="@+id/crop_menu_4to6"
+            android:title="@string/aspect4to6_effect"/>
+        <item
+            android:id="@+id/crop_menu_5to7"
+            android:title="@string/aspect5to7_effect"/>
+        <item
+            android:id="@+id/crop_menu_9to16"
+            android:title="@string/aspect9to16_effect"/>
+        <item
+            android:id="@+id/crop_menu_none"
+            android:title="@string/aspectNone_effect"/>
+        <item
+            android:id="@+id/crop_menu_original"
+            android:title="@string/aspectOriginal_effect"/>
+    </group>
+
+</menu>
\ No newline at end of file
diff --git a/res/menu/filtershow_menu_curves.xml b/res/menu/filtershow_menu_curves.xml
index fe19021..326df45 100644
--- a/res/menu/filtershow_menu_curves.xml
+++ b/res/menu/filtershow_menu_curves.xml
@@ -1,17 +1,17 @@
 <menu xmlns:android="http://schemas.android.com/apk/res/android" >
 
-    <group android:id="@+id/group_popupmenu" >
+    <group android:id="@+id/curves_popupmenu" >
         <item
-            android:id="@+id/menu1"
+            android:id="@+id/curve_menu_rgb"
             android:title="@string/curves_channel_rgb"/>
         <item
-            android:id="@+id/menu2"
+            android:id="@+id/curve_menu_red"
             android:title="@string/curves_channel_red"/>
         <item
-            android:id="@+id/menu3"
+            android:id="@+id/curve_menu_green"
             android:title="@string/curves_channel_green"/>
         <item
-            android:id="@+id/menu4"
+            android:id="@+id/curve_menu_blue"
             android:title="@string/curves_channel_blue"/>
     </group>
 
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index 9d4635e..a15a305 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -6,7 +6,6 @@
 import android.app.Activity;
 import android.app.ProgressDialog;
 import android.content.ContentValues;
-import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -137,7 +136,7 @@
         ImageSmallFilter.setMargin((int) getPixelsFromDip(3));
         ImageSmallFilter.setTextMargin((int) getPixelsFromDip(4));
         mImageBorderSize = (int) getPixelsFromDip(20);
-        Drawable curveHandle = getResources().getDrawable(R.drawable.camera_crop_holo);
+        Drawable curveHandle = getResources().getDrawable(R.drawable.camera_crop);
         int curveHandleSize = (int) getResources().getDimension(R.dimen.crop_indicator_size);
         Spline.setCurveHandle(curveHandle, curveHandleSize);
         Spline.setCurveWidth((int) getPixelsFromDip(3));
diff --git a/src/com/android/gallery3d/filtershow/PanelController.java b/src/com/android/gallery3d/filtershow/PanelController.java
index 1dbaca2..45ee235 100644
--- a/src/com/android/gallery3d/filtershow/PanelController.java
+++ b/src/com/android/gallery3d/filtershow/PanelController.java
@@ -3,9 +3,11 @@
 
 import android.content.Context;
 import android.text.Html;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewPropertyAnimator;
+import android.widget.PopupMenu;
 import android.widget.TextView;
 
 import com.android.gallery3d.R;
@@ -25,6 +27,7 @@
 import com.android.gallery3d.filtershow.imageshow.ImageCrop;
 import com.android.gallery3d.filtershow.imageshow.ImageShow;
 import com.android.gallery3d.filtershow.presets.ImagePreset;
+import com.android.gallery3d.filtershow.ui.FramedTextButton;
 import com.android.gallery3d.filtershow.ui.ImageButtonTitle;
 import com.android.gallery3d.filtershow.ui.ImageCurves;
 
@@ -142,6 +145,43 @@
             return mSelected;
         }
 
+        public void setAspectButton(FramedTextButton button, int itemId) {
+            ImageCrop imageCrop = (ImageCrop) mCurrentImage;
+            switch (itemId) {
+                case R.id.crop_menu_1to1: {
+                    button.setText(mContext.getString(R.string.aspect1to1_effect));
+                    imageCrop.apply(1, 1);
+                    break;
+                }
+                case R.id.crop_menu_4to6: {
+                    button.setText(mContext.getString(R.string.aspect4to6_effect));
+                    imageCrop.apply(6, 4);
+                    break;
+                }
+                case R.id.crop_menu_5to7: {
+                    button.setText(mContext.getString(R.string.aspect5to7_effect));
+                    imageCrop.apply(7, 5);
+                    break;
+                }
+                case R.id.crop_menu_9to16: {
+                    button.setText(mContext.getString(R.string.aspect9to16_effect));
+                    imageCrop.apply(16, 9);
+                    break;
+                }
+                case R.id.crop_menu_none: {
+                    button.setText(mContext.getString(R.string.aspectNone_effect));
+                    imageCrop.applyClear();
+                    break;
+                }
+                case R.id.crop_menu_original: {
+                    button.setText(mContext.getString(R.string.aspectOriginal_effect));
+                    imageCrop.applyOriginal();
+                    break;
+                }
+            }
+            imageCrop.invalidate();
+        }
+
         public void nextAspectButton() {
             if (mAspectButton instanceof ImageButtonTitle
                     && mCurrentImage instanceof ImageCrop) {
@@ -201,7 +241,7 @@
             }
         }
 
-        void setCurrentAspectButton(int n){
+        void setCurrentAspectButton(int n) {
             mCurrentAspectButton = n;
         }
 
@@ -331,9 +371,11 @@
     }
 
     public void resetParameters() {
-        mCurrentImage.resetParameter();
         showPanel(mCurrentPanel);
-        mCurrentImage.select();
+        if (mCurrentImage != null) {
+            mCurrentImage.resetParameter();
+            mCurrentImage.select();
+        }
     }
 
     public boolean onBackPressed() {
@@ -343,6 +385,8 @@
         HistoryAdapter adapter = mMasterImage.getHistory();
         int position = adapter.undo();
         mMasterImage.onItemClick(position);
+        showPanel(mCurrentPanel);
+        mCurrentImage.select();
         return false;
     }
 
@@ -462,6 +506,7 @@
             mMasterImage.setImagePreset(copy);
             filter = copy.getFilter(name);
         }
+
         if (filter == null && name.equalsIgnoreCase(
                 mCurrentImage.getContext().getString(R.string.curvesRGB))) {
             filter = setImagePreset(new ImageFilterCurves(), name);
@@ -514,6 +559,33 @@
         mMasterImage.setCurrentFilter(filter);
     }
 
+    private void showCurvesPopupMenu(final ImageCurves curves, final FramedTextButton anchor) {
+        PopupMenu popupMenu = new PopupMenu(mCurrentImage.getContext(), anchor);
+        popupMenu.getMenuInflater().inflate(R.menu.filtershow_menu_curves, popupMenu.getMenu());
+        popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+            @Override
+            public boolean onMenuItemClick(MenuItem item) {
+                curves.setChannel(item.getItemId());
+                anchor.setTextFrom(item.getItemId());
+                return true;
+            }
+        });
+        popupMenu.show();
+    }
+
+    private void showCropPopupMenu(final FramedTextButton anchor) {
+        PopupMenu popupMenu = new PopupMenu(mCurrentImage.getContext(), anchor);
+        popupMenu.getMenuInflater().inflate(R.menu.filtershow_menu_crop, popupMenu.getMenu());
+        popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+            @Override
+            public boolean onMenuItemClick(MenuItem item) {
+                mUtilityPanel.setAspectButton(anchor, item.getItemId());
+                return true;
+            }
+        });
+        popupMenu.show();
+    }
+
     public void showComponent(View view) {
         if (mUtilityPanel != null && !mUtilityPanel.selected()) {
             Panel current = mPanels.get(mCurrentPanel);
@@ -527,7 +599,12 @@
 
         if (view.getId() == R.id.pickCurvesChannel) {
             ImageCurves curves = (ImageCurves) showImageView(R.id.imageCurves);
-            curves.nextChannel();
+            showCurvesPopupMenu(curves, (FramedTextButton) view);
+            return;
+        }
+
+        if (view.getId() == R.id.aspect) {
+            showCropPopupMenu((FramedTextButton) view);
             return;
         }
 
@@ -586,8 +663,8 @@
                 mUtilityPanel.setEffectName(ename);
                 mUtilityPanel.setShowParameter(false);
                 mUtilityPanel.showCurvesButtons();
-                ensureFilter("Curves");
                 mCurrentImage = curves;
+                ensureFilter(ename);
                 break;
             }
             case R.id.sharpenButton: {
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
index 2a570aa..3f8326d 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
@@ -20,12 +20,14 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
+
 import com.android.gallery3d.R;
 
 public class ImageCrop extends ImageGeometry {
@@ -63,9 +65,9 @@
     public ImageCrop(Context context) {
         super(context);
         Resources resources = context.getResources();
-        cropIndicator = resources.getDrawable(R.drawable.camera_crop_holo);
+        cropIndicator = resources.getDrawable(R.drawable.camera_crop);
         indicatorSize = (int) resources.getDimension(R.dimen.crop_indicator_size);
-        int borderColor = resources.getColor(R.color.opaque_cyan);
+        int borderColor = Color.argb(128, 255,  255,  255);
         borderPaint = new Paint();
         borderPaint.setStyle(Paint.Style.STROKE);
         borderPaint.setColor(borderColor);
@@ -75,9 +77,9 @@
     public ImageCrop(Context context, AttributeSet attrs) {
         super(context, attrs);
         Resources resources = context.getResources();
-        cropIndicator = resources.getDrawable(R.drawable.camera_crop_holo);
+        cropIndicator = resources.getDrawable(R.drawable.camera_crop);
         indicatorSize = (int) resources.getDimension(R.dimen.crop_indicator_size);
-        int borderColor = resources.getColor(R.color.opaque_cyan);
+        int borderColor = Color.argb(128, 255,  255,  255);
         borderPaint = new Paint();
         borderPaint.setStyle(Paint.Style.STROKE);
         borderPaint.setColor(borderColor);
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
index 58f72e1..6a81fce 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
@@ -48,9 +48,9 @@
 import java.io.File;
 
 public class ImageShow extends View implements OnGestureListener,
-                                               OnDoubleTapListener,
-                                               SliderListener,
-                                               OnSeekBarChangeListener {
+        OnDoubleTapListener,
+        SliderListener,
+        OnSeekBarChangeListener {
 
     private static final String LOGTAG = "ImageShow";
 
@@ -80,6 +80,13 @@
     private HistoryAdapter mHistoryAdapter = null;
     private ImageStateAdapter mImageStateAdapter = null;
 
+    private Rect mImageBounds = null;
+
+    private boolean mTouchShowOriginal = false;
+    private long mTouchShowOriginalDate = 0;
+    private final long mTouchShowOriginalDelay = 1000; // 1s
+    private int mTouchDownX = 0;
+
     protected GeometryMetadata getGeometry() {
         return new GeometryMetadata(getImagePreset().mGeoData);
     }
@@ -121,26 +128,27 @@
             int parameter = getCurrentFilter().getParameter();
             int maxp = getCurrentFilter().getMaxParameter();
             int minp = getCurrentFilter().getMinParameter();
-            updateSeekBar(parameter,minp,maxp);
+            updateSeekBar(parameter, minp, maxp);
         }
         if (mSeekBar != null) {
             mSeekBar.setOnSeekBarChangeListener(this);
         }
     }
 
-    private int parameterToUI(int parameter,int minp,int maxp,int uimax){
-        return (uimax*(parameter-minp))/(maxp-minp);
+    private int parameterToUI(int parameter, int minp, int maxp, int uimax) {
+        return (uimax * (parameter - minp)) / (maxp - minp);
     }
 
-    private int uiToParameter(int ui,int minp,int maxp,int uimax){
-        return  ((maxp-minp)*ui)/uimax+minp;
+    private int uiToParameter(int ui, int minp, int maxp, int uimax) {
+        return ((maxp - minp) * ui) / uimax + minp;
     }
-    public void updateSeekBar(int parameter,int minp,int maxp) {
+
+    public void updateSeekBar(int parameter, int minp, int maxp) {
         if (mSeekBar == null) {
             return;
         }
-        int seekMax  = mSeekBar.getMax();
-        int progress = parameterToUI(parameter,minp,maxp,seekMax);
+        int seekMax = mSeekBar.getMax();
+        int progress = parameterToUI(parameter, minp, maxp, seekMax);
         mSeekBar.setProgress(progress);
         if (getPanelController() != null) {
             getPanelController().onNewValue(parameter);
@@ -160,7 +168,7 @@
 
     public void resetParameter() {
         ImageFilter currentFilter = getCurrentFilter();
-        if (currentFilter!=null) {
+        if (currentFilter != null) {
             onNewValue(currentFilter.getDefaultParameter());
         }
         if (USE_SLIDER_GESTURE) {
@@ -192,7 +200,7 @@
         if (getPanelController() != null) {
             getPanelController().onNewValue(parameter);
         }
-        updateSeekBar(parameter,minp,maxp);
+        updateSeekBar(parameter, minp, maxp);
         invalidate();
     }
 
@@ -327,6 +335,7 @@
         drawBackground(canvas);
         getFilteredImage();
         drawImage(canvas, mFilteredImage);
+        drawPartialImage(canvas, mForegroundImage);
 
         if (showTitle() && getImagePreset() != null) {
             mPaint.setARGB(200, 0, 0, 0);
@@ -385,11 +394,31 @@
             }
             Rect d = new Rect((int) tx, (int) ty, (int) (w + tx),
                     (int) (h + ty));
-
+            mImageBounds = d;
             canvas.drawBitmap(image, s, d, mPaint);
         }
     }
 
+    public void drawPartialImage(Canvas canvas, Bitmap image) {
+        if (!mTouchShowOriginal)
+            return;
+        canvas.save();
+        if (image != null) {
+            int px = mTouchDownX - mImageBounds.left;
+            int py = mImageBounds.height();
+            Rect d = new Rect(mImageBounds.left, mImageBounds.top,
+                    mImageBounds.left + px, mImageBounds.top + py);
+            canvas.clipRect(d);
+            Paint paint = new Paint();
+            paint.setColor(Color.BLACK);
+            canvas.drawLine(px, mImageBounds.top, px, mImageBounds.bottom, paint);
+            paint.setColor(Color.WHITE);
+            canvas.drawText("Original", mImageBounds.left, mImageBounds.top + 100, paint);
+        }
+        drawImage(canvas, image);
+        canvas.restore();
+    }
+
     public void drawBackground(Canvas canvas) {
         if (USE_BACKGROUND_IMAGE) {
             if (mBackgroundImage == null) {
@@ -504,7 +533,25 @@
         if (USE_SLIDER_GESTURE) {
             mSliderController.onTouchEvent(event);
         }
-        mGestureDetector.onTouchEvent(event);
+        if (mGestureDetector != null) {
+            mGestureDetector.onTouchEvent(event);
+        }
+        int ex = (int) event.getX();
+        if (event.getAction() == MotionEvent.ACTION_DOWN) {
+            mTouchDownX = ex;
+            if (!mActivity.isShowingHistoryPanel() && mImageBounds != null
+                    && mImageBounds.left < ex && mImageBounds.right > ex) {
+                mTouchShowOriginal = true;
+                mTouchShowOriginalDate = System.currentTimeMillis();
+            }
+        }
+        if (event.getAction() == MotionEvent.ACTION_MOVE) {
+            mTouchDownX = ex;
+        }
+        if (event.getAction() == MotionEvent.ACTION_UP) {
+            mTouchShowOriginal = false;
+            mTouchDownX = 0;
+        }
         invalidate();
         return true;
     }
@@ -559,10 +606,10 @@
     @Override
     public void onProgressChanged(SeekBar arg0, int progress, boolean arg2) {
         int parameter = progress;
-        if (getCurrentFilter()!=null){
+        if (getCurrentFilter() != null) {
             int maxp = getCurrentFilter().getMaxParameter();
             int minp = getCurrentFilter().getMinParameter();
-            parameter = uiToParameter(progress,minp,maxp,arg0.getMax());
+            parameter = uiToParameter(progress, minp, maxp, arg0.getMax());
         }
 
         onNewValue(parameter);
@@ -607,8 +654,12 @@
     @Override
     public boolean onFling(MotionEvent startEvent, MotionEvent endEvent, float arg2, float arg3) {
         if ((!mActivity.isShowingHistoryPanel() && startEvent.getX() > endEvent.getX())
-                || (mActivity.isShowingHistoryPanel() && endEvent.getX() > startEvent.getX())){
-            mActivity.toggleHistoryPanel();
+                || (mActivity.isShowingHistoryPanel() && endEvent.getX() > startEvent.getX())) {
+            if (!mTouchShowOriginal
+                    || (mTouchShowOriginal
+                    && System.currentTimeMillis() - mTouchShowOriginalDate < mTouchShowOriginalDelay)) {
+                mActivity.toggleHistoryPanel();
+            }
         }
         return true;
     }
diff --git a/src/com/android/gallery3d/filtershow/ui/FramedTextButton.java b/src/com/android/gallery3d/filtershow/ui/FramedTextButton.java
new file mode 100644
index 0000000..43f97d2
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/ui/FramedTextButton.java
@@ -0,0 +1,88 @@
+package com.android.gallery3d.filtershow.ui;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.widget.ImageButton;
+
+import com.android.gallery3d.R;
+
+public class FramedTextButton extends ImageButton {
+    private static final String LOGTAG = "FramedTextButton";
+    private String mText = null;
+    private static int mTextSize = 24;
+    private static int mTextPadding = 20;
+    private static Paint gPaint = new Paint();
+    private Context mContext = null;
+
+    public static void setTextSize(int value) {
+        mTextSize = value;
+    }
+
+    public static void setTextPadding(int value) {
+        mTextPadding = value;
+    }
+
+    public void setText(String text) {
+        mText = text;
+        invalidate();
+    }
+
+    public void setTextFrom(int itemId) {
+        switch (itemId) {
+            case R.id.curve_menu_rgb: {
+                setText(mContext.getString(R.string.curves_channel_rgb));
+                break;
+            }
+            case R.id.curve_menu_red: {
+                setText(mContext.getString(R.string.curves_channel_red));
+                break;
+            }
+            case R.id.curve_menu_green: {
+                setText(mContext.getString(R.string.curves_channel_green));
+                break;
+            }
+            case R.id.curve_menu_blue: {
+                setText(mContext.getString(R.string.curves_channel_blue));
+                break;
+            }
+        }
+        invalidate();
+    }
+
+    public FramedTextButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+        TypedArray a = getContext().obtainStyledAttributes(
+                attrs, R.styleable.ImageButtonTitle);
+
+        mText = a.getString(R.styleable.ImageButtonTitle_android_text);
+    }
+
+    public String getText(){
+        return mText;
+    }
+
+    @Override
+    public void onDraw(Canvas canvas) {
+        gPaint.setARGB(255, 255, 255, 255);
+        gPaint.setStrokeWidth(2);
+        gPaint.setStyle(Paint.Style.STROKE);
+        canvas.drawRect(mTextPadding, mTextPadding, getWidth() - mTextPadding,
+                getHeight() - mTextPadding, gPaint);
+        if (mText != null) {
+            gPaint.setTextSize(mTextSize);
+            float textWidth = gPaint.measureText(mText);
+            Rect bounds = new Rect();
+            gPaint.getTextBounds(mText, 0, mText.length(), bounds);
+            int x = (int) ((getWidth() - textWidth) / 2);
+            int y = (getHeight() + bounds.height()) / 2;
+
+            canvas.drawText(mText, x, y, gPaint);
+        }
+    }
+
+}
diff --git a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java
index 84edf23..7889861 100644
--- a/src/com/android/gallery3d/filtershow/ui/ImageCurves.java
+++ b/src/com/android/gallery3d/filtershow/ui/ImageCurves.java
@@ -13,6 +13,7 @@
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 
+import com.android.gallery3d.R;
 import com.android.gallery3d.filtershow.filters.ImageFilterCurves;
 import com.android.gallery3d.filtershow.imageshow.ImageSlave;
 import com.android.gallery3d.filtershow.presets.ImagePreset;
@@ -23,7 +24,7 @@
     Paint gPaint = new Paint();
     Path gPathSpline = new Path();
 
-    private int mCurrentCurveIndex = 0;
+    private int mCurrentCurveIndex = Spline.RGB;
     private boolean mDidAddPoint = false;
     private boolean mDidDelete = false;
     private ControlPoint mCurrentControlPoint = null;
@@ -33,6 +34,8 @@
     int[] blueHistogram = new int[256];
     Path gHistoPath = new Path();
 
+    boolean mDoingTouchMove = false;
+
     public ImageCurves(Context context) {
         super(context);
         resetCurve();
@@ -107,14 +110,15 @@
                 if (i != mCurrentCurveIndex && !spline.isOriginal()) {
                     // And we only display a curve if it has more than two
                     // points
-                    spline.draw(canvas, Spline.colorForCurve(i), getWidth(), getHeight(), false);
+                    spline.draw(canvas, Spline.colorForCurve(i), getWidth(),
+                            getHeight(), false, mDoingTouchMove);
                 }
             }
         }
         // ...but we always display the current curve.
         getSpline(mCurrentCurveIndex)
                 .draw(canvas, Spline.colorForCurve(mCurrentCurveIndex), getWidth(), getHeight(),
-                        true);
+                        true, mDoingTouchMove);
         drawToast(canvas);
 
     }
@@ -168,8 +172,10 @@
             if (mDidDelete) {
                 mDidDelete = false;
             }
+            mDoingTouchMove = false;
             return true;
         }
+        mDoingTouchMove = true;
 
         if (mDidDelete) {
             return true;
@@ -190,7 +196,8 @@
         if (spline.isPointContained(posX, pick)) {
             mCurrentControlPoint.x = posX;
             mCurrentControlPoint.y = posY;
-        } else if (pick != -1) {
+            spline.didMovePoint(mCurrentControlPoint);
+        } else if (pick != -1 && spline.getNbPoints() > 2) {
             spline.deletePoint(pick);
             mDidDelete = true;
         }
@@ -285,4 +292,26 @@
         paint2.setARGB(255, 200, 200, 200);
         canvas.drawPath(gHistoPath, paint2);
     }
+
+    public void setChannel(int itemId) {
+        switch (itemId) {
+            case R.id.curve_menu_rgb: {
+                mCurrentCurveIndex = Spline.RGB;
+                break;
+            }
+            case R.id.curve_menu_red: {
+                mCurrentCurveIndex = Spline.RED;
+                break;
+            }
+            case R.id.curve_menu_green: {
+                mCurrentCurveIndex = Spline.GREEN;
+                break;
+            }
+            case R.id.curve_menu_blue: {
+                mCurrentCurveIndex = Spline.BLUE;
+                break;
+            }
+        }
+        invalidate();
+    }
 }
diff --git a/src/com/android/gallery3d/filtershow/ui/Spline.java b/src/com/android/gallery3d/filtershow/ui/Spline.java
index ddbf97c..67840dc 100644
--- a/src/com/android/gallery3d/filtershow/ui/Spline.java
+++ b/src/com/android/gallery3d/filtershow/ui/Spline.java
@@ -24,6 +24,7 @@
     private static final String LOGTAG = "Spline";
 
     private final Paint gPaint = new Paint();
+    private ControlPoint mCurrentControlPoint = null;
 
     public Spline() {
         mPoints = new Vector<ControlPoint>();
@@ -63,6 +64,10 @@
         return Color.WHITE;
     }
 
+    public void didMovePoint(ControlPoint point) {
+        mCurrentControlPoint = point;
+    }
+
     public boolean isOriginal() {
         if (this.getNbPoints() > 2) {
             return false;
@@ -169,10 +174,10 @@
     }
 
     public void draw(Canvas canvas, int color, int canvasWidth, int canvasHeight,
-            boolean showHandles) {
-        float w = canvasWidth;
+            boolean showHandles, boolean moving) {
+        float w = canvasWidth - mCurveHandleSize;
         float h = canvasHeight - mCurveHandleSize;
-        float dx = 0;
+        float dx = mCurveHandleSize / 2;
         float dy = mCurveHandleSize / 2;
 
         // The cubic spline equation is (from numerical recipes in C):
@@ -249,6 +254,20 @@
         paint.setStrokeWidth(curveWidth + 2);
         paint.setColor(Color.BLACK);
         canvas.drawPath(path, paint);
+
+        if (moving && mCurrentControlPoint != null) {
+            float px = mCurrentControlPoint.x * w;
+            float py = mCurrentControlPoint.y * h;
+            paint.setStrokeWidth(3);
+            paint.setColor(Color.BLACK);
+            canvas.drawLine(px, py, px, h, paint);
+            canvas.drawLine(0, py, px, py, paint);
+            paint.setStrokeWidth(1);
+            paint.setColor(color);
+            canvas.drawLine(px, py, px, h, paint);
+            canvas.drawLine(0, py, px, py, paint);
+        }
+
         paint.setStrokeWidth(curveWidth);
         paint.setColor(color);
         canvas.drawPath(path, paint);