OSDN Git Service

New state panel
authornicolasroard <nicolasroard@google.com>
Mon, 15 Apr 2013 21:41:00 +0000 (14:41 -0700)
committernicolasroard <nicolasroard@google.com>
Tue, 16 Apr 2013 06:13:37 +0000 (23:13 -0700)
bug:8620913
bug:8503386

Change-Id: I35c95103e3b5097df93fa3f48e5562a479915f06

14 files changed:
res/layout-land/filtershow_activity.xml
res/layout/filtershow_state_panel_new.xml [new file with mode: 0644]
res/values/filtershow_strings.xml
src/com/android/gallery3d/filtershow/FilterShowActivity.java
src/com/android/gallery3d/filtershow/PanelController.java
src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
src/com/android/gallery3d/filtershow/presets/ImagePreset.java
src/com/android/gallery3d/filtershow/state/DragListener.java [new file with mode: 0644]
src/com/android/gallery3d/filtershow/state/PanelTrack.java [new file with mode: 0644]
src/com/android/gallery3d/filtershow/state/State.java [new file with mode: 0644]
src/com/android/gallery3d/filtershow/state/StateAdapter.java [new file with mode: 0644]
src/com/android/gallery3d/filtershow/state/StatePanel.java [new file with mode: 0644]
src/com/android/gallery3d/filtershow/state/StatePanelTrack.java [new file with mode: 0644]
src/com/android/gallery3d/filtershow/state/StateView.java [new file with mode: 0644]

index f1294f5..311a3e6 100644 (file)
             android:orientation="horizontal"
             android:animateLayoutChanges="true">
 
-    <LinearLayout
-            android:layout_weight="1"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:orientation="horizontal">
+        <LinearLayout
+                android:layout_weight="1"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:orientation="horizontal">
 
-        <FrameLayout
-                android:id="@+id/editorContainer"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_weight="1"  />
+            <FrameLayout
+                    android:id="@+id/editorContainer"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"/>
 
-        <com.android.gallery3d.filtershow.imageshow.ImageShow
-                android:id="@+id/imageShow"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
+            <com.android.gallery3d.filtershow.imageshow.ImageShow
+                    android:id="@+id/imageShow"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1" />
 
-        <com.android.gallery3d.filtershow.imageshow.ImageTinyPlanet
-                android:id="@+id/imageTinyPlanet"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content" />
+            <com.android.gallery3d.filtershow.imageshow.ImageTinyPlanet
+                    android:id="@+id/imageTinyPlanet"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1" />
 
         </LinearLayout>
 
         <LinearLayout
                 android:id="@+id/mainPanel"
-                android:layout_width="650dip"
+                android:layout_width="350dip"
                 android:layout_height="match_parent"
-                android:layout_weight="1"
-                android:orientation="vertical" >
+                android:orientation="vertical">
 
-            <ViewStub android:id="@+id/statePanelStub"
-                      android:inflatedId="@+id/imageStatePanel"
-                      android:layout="@layout/filtershow_state_panel"
-                      android:layout_width="match_parent"
-                      android:layout_height="wrap_content"
-                      android:visibility="visible" />
+            <FrameLayout android:id="@+id/state_panel_container"
+                         android:layout_width="350dip"
+                         android:layout_height="0dip"
+                         android:layout_weight="1" />
 
             <ViewStub android:id="@+id/historyPanelStub"
                       android:inflatedId="@+id/historyPanel"
                       android:layout="@layout/filtershow_history_panel"
                       android:layout_width="match_parent"
-                      android:layout_height="match_parent"
-                      android:visibility="gone"  />
+                      android:layout_height="0dip"
+                      android:visibility="gone"/>
 
             <FrameLayout
                     android:layout_gravity="bottom"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
-                    android:layout_weight="1" >
+                    android:visibility="gone">
 
 
                 <ProgressBar
@@ -88,7 +87,7 @@
                         android:layout_gravity="center"
                         android:indeterminate="true"
                         android:indeterminateOnly="true"
-                        android:background="@color/background_screen" />
+                        android:background="@color/background_screen"/>
 
             </FrameLayout>
 
                     xmlns:custom="http://schemas.android.com/apk/res/com.android.gallery3d"
                     android:id="@+id/filtersPanel"
                     android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center"
+                    android:layout_height="177dip"
+                    android:layout_gravity="center|bottom"
                     custom:max_width="600dip"
                     android:orientation="vertical">
 
                 <FrameLayout
                         android:id="@+id/secondRowPanel"
                         android:layout_width="fill_parent"
-                        android:layout_height="wrap_content" >
+                        android:layout_height="128dip">
 
                     <LinearLayout
                             android:id="@+id/filterButtonsList"
                             android:layout_width="fill_parent"
                             android:layout_height="@dimen/thumbnail_size"
                             android:orientation="horizontal"
-                            android:visibility="gone" >
+                            android:visibility="gone">
 
                         <ViewStub android:id="@+id/editorPanelStub"
-                            android:inflatedId="@+id/editorPanel"
-                            android:layout="@layout/filtershow_editor_panel"
-                            android:layout_width="match_parent"
-                            android:layout_height="wrap_content"
-                            android:visibility="visible"  />
+                                  android:inflatedId="@+id/editorPanel"
+                                  android:layout="@layout/filtershow_editor_panel"
+                                  android:layout_width="match_parent"
+                                  android:layout_height="wrap_content"
+                                  android:visibility="visible"/>
 
                     </LinearLayout>
 
                             android:layout_width="match_parent"
                             android:layout_height="@dimen/thumbnail_size"
                             android:background="@color/background_main_toolbar"
-                            android:scrollbars="none" >
+                            android:scrollbars="none">
 
                         <LinearLayout
                                 android:id="@+id/listFilters"
                                 android:layout_width="wrap_content"
                                 android:layout_height="match_parent"
                                 android:layout_marginLeft="@dimen/thumbnail_margin"
-                                android:orientation="horizontal" >
+                                android:orientation="horizontal">
                         </LinearLayout>
                     </HorizontalScrollView>
 
                             android:layout_height="@dimen/thumbnail_size"
                             android:background="@color/background_main_toolbar"
                             android:visibility="gone"
-                            android:scrollbars="none" >
+                            android:scrollbars="none">
 
                         <LinearLayout
                                 android:id="@+id/listBorders"
                                 android:layout_width="wrap_content"
                                 android:layout_height="match_parent"
                                 android:layout_marginLeft="@dimen/thumbnail_margin"
-                                android:orientation="horizontal" >
+                                android:orientation="horizontal">
                         </LinearLayout>
                     </HorizontalScrollView>
 
                             android:layout_height="@dimen/thumbnail_size"
                             android:background="@color/background_main_toolbar"
                             android:visibility="gone"
-                            android:scrollbars="none" >
+                            android:scrollbars="none">
 
                         <LinearLayout
                                 android:id="@+id/listGeometry"
                                 android:layout_width="wrap_content"
                                 android:layout_height="fill_parent"
                                 android:layout_gravity="left"
-                                android:orientation="horizontal" />
+                                android:orientation="horizontal"/>
 
                     </HorizontalScrollView>
 
                             android:layout_height="wrap_content"
                             android:background="@color/background_main_toolbar"
                             android:visibility="gone"
-                            android:scrollbars="none" >
+                            android:scrollbars="none">
 
                         <LinearLayout
                                 android:id="@+id/listColorsFx"
                                 android:layout_height="@dimen/thumbnail_size"
                                 android:background="@color/background_main_toolbar"
                                 android:layout_marginLeft="@dimen/thumbnail_margin"
-                                android:orientation="horizontal" >
+                                android:orientation="horizontal">
 
                         </LinearLayout>
                     </HorizontalScrollView>
                 <View
                         android:background="@color/toolbar_separation_line"
                         android:layout_height="1dip"
-                        android:layout_width="match_parent" />
+                        android:layout_width="match_parent"/>
 
                 <com.android.gallery3d.filtershow.CenteredLinearLayout
-                        xmlns:custom="http://schemas.android.com/apk/res/com.android.gallery3d"
                         android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
+                        android:layout_height="48dip"
                         android:layout_gravity="center"
                         custom:max_width="400dip"
                         android:orientation="vertical">
 
-                       <ViewStub android:id="@+id/stateCategoryStub"
-                          android:inflatedId="@+id/imageCategoryPanel"
-                          android:layout="@layout/filtershow_category_panel"
-                          android:layout_width="match_parent"
-                          android:layout_height="48dip"
-                          android:visibility="visible" />
+                    <ViewStub android:id="@+id/stateCategoryStub"
+                              android:inflatedId="@+id/imageCategoryPanel"
+                              android:layout="@layout/filtershow_category_panel"
+                              android:layout_width="match_parent"
+                              android:layout_height="48dip"
+                              android:visibility="visible"/>
 
                 </com.android.gallery3d.filtershow.CenteredLinearLayout>
 
diff --git a/res/layout/filtershow_state_panel_new.xml b/res/layout/filtershow_state_panel_new.xml
new file mode 100644 (file)
index 0000000..7711221
--- /dev/null
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="horizontal"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <!--
+    <com.example.StatePanel.VerticalStatePanelTrack
+            android:id="@+id/listStates"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_margin="8dip"
+            android:background="@android:color/holo_red_dark" />
+            -->
+
+    <ScrollView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:scrollbars="none">
+
+    <com.android.gallery3d.filtershow.state.StatePanelTrack
+            android:id="@+id/listStates"
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_margin="8dip"
+            android:animateLayoutChanges="true" />
+
+    </ScrollView>
+
+    <!--
+    <HorizontalScrollView
+            android:layout_width="match_parent"
+            android:layout_height="128dip"
+            android:scrollbars="none">
+
+        <com.example.StatePanel.StatePanelTrack
+                android:id="@+id/listStates"
+                android:layout_width="match_parent"
+                android:layout_height="128dip"
+                android:animateLayoutChanges="true" />
+
+    </HorizontalScrollView>
+    -->
+
+</LinearLayout>
index a7bc92d..11f27cf 100644 (file)
     <!--  The accept the draw size [CHAR LIMIT=20] -->
     <string name="draw_size_accept">OK</string>
 
+    <!--  Name used to indicate the original image in the state panel [CHAR LIMIT=20] -->
+    <string name="state_panel_original">Original</string>
+
+    <!--  Name used to indicate the final image in the state panel [CHAR LIMIT=20] -->
+    <string name="state_panel_result">Result</string>
+
 </resources>
index 1a7d200..e445a5d 100644 (file)
@@ -17,7 +17,6 @@
 package com.android.gallery3d.filtershow;
 
 import android.app.ActionBar;
-import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.ProgressDialog;
 import android.app.WallpaperManager;
@@ -35,6 +34,8 @@ import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.provider.MediaStore;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentTransaction;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.TypedValue;
@@ -75,6 +76,8 @@ import com.android.gallery3d.filtershow.imageshow.ImageTinyPlanet;
 import com.android.gallery3d.filtershow.imageshow.MasterImage;
 import com.android.gallery3d.filtershow.presets.ImagePreset;
 import com.android.gallery3d.filtershow.provider.SharedImageProvider;
+import com.android.gallery3d.filtershow.state.StateAdapter;
+import com.android.gallery3d.filtershow.state.StatePanel;
 import com.android.gallery3d.filtershow.tools.BitmapTask;
 import com.android.gallery3d.filtershow.tools.SaveCopyTask;
 import com.android.gallery3d.filtershow.ui.FilterIconButton;
@@ -88,9 +91,11 @@ import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.util.Vector;
 
-public class FilterShowActivity extends Activity implements OnItemClickListener,
+public class FilterShowActivity extends FragmentActivity implements OnItemClickListener,
         OnShareTargetSelectedListener {
 
+    private String mPanelFragmentTag = "StatePanel";
+
     // fields for supporting crop action
     public static final String CROP_ACTION = "com.android.camera.action.CROP";
     private CropExtras mCropExtras = null;
@@ -157,10 +162,8 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
         } else {
             findViewById(R.id.historyPanel).setVisibility(View.GONE);
         }
-        if (mShowingImageStatePanel) {
-            findViewById(R.id.imageStatePanel).setVisibility(View.VISIBLE);
-        } else {
-            findViewById(R.id.imageStatePanel).setVisibility(View.GONE);
+        if (mShowingImageStatePanel && (savedInstanceState == null)) {
+            loadImageStatePanel();
         }
 
         setDefaultPreset();
@@ -174,7 +177,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
         ((ViewStub) findViewById(R.id.stateCategoryStub)).inflate();
         ((ViewStub) findViewById(R.id.editorPanelStub)).inflate();
         ((ViewStub) findViewById(R.id.historyPanelStub)).inflate();
-        ((ViewStub) findViewById(R.id.statePanelStub)).inflate();
 
         ActionBar actionBar = getActionBar();
         actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
@@ -242,8 +244,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
     }
 
     public void setupStatePanel() {
-        ListView imageStateList = (ListView) findViewById(R.id.imageStateList);
-        imageStateList.setAdapter(mMasterImage.getState());
         mImageLoader.setAdapter(mMasterImage.getHistory());
         mPanelController.setRowPanel(findViewById(R.id.secondRowPanel));
         mPanelController.setUtilityPanel(this, findViewById(R.id.filterButtonsList));
@@ -849,21 +849,16 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
     }
 
     private void toggleImageStatePanel() {
-        final View viewList = findViewById(R.id.imageStatePanel);
+        invalidateOptionsMenu();
+    }
 
-        if (mShowingHistoryPanel) {
-            findViewById(R.id.historyPanel).setVisibility(View.GONE);
-            mShowingHistoryPanel = false;
+    private void loadImageStatePanel() {
+        StatePanel statePanel = new StatePanel();
+        if (findViewById(R.id.state_panel_container) != null) {
+            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
+            transaction.replace(R.id.state_panel_container, statePanel, mPanelFragmentTag);
+            transaction.commit();
         }
-
-        if (!mShowingImageStatePanel) {
-            mShowingImageStatePanel = true;
-            viewList.setVisibility(View.VISIBLE);
-        } else {
-            mShowingImageStatePanel = false;
-            viewList.setVisibility(View.GONE);
-        }
-        invalidateOptionsMenu();
     }
 
     @Override
@@ -878,6 +873,9 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
         } else if (mShowingImageStatePanel) {
             toggleImageStatePanel();
         }
+        if (mShowingImageStatePanel) {
+            loadImageStatePanel();
+        }
         if (mShowingHistoryPanel) {
             toggleHistoryPanel();
         }
@@ -897,9 +895,8 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
         HistoryAdapter mHistoryAdapter = new HistoryAdapter(
                 this, R.layout.filtershow_history_operation_row,
                 R.id.rowTextView);
-        ImageStateAdapter mImageStateAdapter = new ImageStateAdapter(this,
-                R.layout.filtershow_imagestate_row);
 
+        StateAdapter mImageStateAdapter = new StateAdapter(this, 0);
         MasterImage.reset();
         mMasterImage = MasterImage.getImage();
         mMasterImage.setHistoryAdapter(mHistoryAdapter);
@@ -921,10 +918,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
         final View view = findViewById(R.id.mainPanel);
         final View viewList = findViewById(R.id.historyPanel);
 
-        if (mShowingImageStatePanel) {
-            findViewById(R.id.imageStatePanel).setVisibility(View.GONE);
-        }
-
         int translate = translateMainPanel(viewList);
         if (!mShowingHistoryPanel) {
             mShowingHistoryPanel = true;
@@ -968,10 +961,6 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
             } else {
                 viewList.setVisibility(View.GONE);
                 findViewById(R.id.filtersPanel).setVisibility(View.VISIBLE);
-                // In landscape, bring back the state panel if it was there
-                if (mShowingImageStatePanel) {
-                    findViewById(R.id.imageStatePanel).setVisibility(View.VISIBLE);
-                }
             }
         }
         invalidateOptionsMenu();
index 1d0118f..e9a9136 100644 (file)
@@ -544,6 +544,9 @@ public class PanelController implements OnClickListener {
         if (filterRepresentation == null) {
             return;
         }
+        if (filterRepresentation == MasterImage.getImage().getCurrentFilterRepresentation()) {
+            return;
+        }
         Set<View> views = mViews.keySet();
         for (View view : views) {
             if (view instanceof FilterIconButton) {
index 94573bc..c36befc 100644 (file)
@@ -22,11 +22,11 @@ import android.os.Message;
 
 import com.android.gallery3d.filtershow.FilterShowActivity;
 import com.android.gallery3d.filtershow.HistoryAdapter;
-import com.android.gallery3d.filtershow.ImageStateAdapter;
 import com.android.gallery3d.filtershow.cache.*;
 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
 import com.android.gallery3d.filtershow.filters.ImageFilter;
 import com.android.gallery3d.filtershow.presets.ImagePreset;
+import com.android.gallery3d.filtershow.state.StateAdapter;
 
 import java.util.Vector;
 
@@ -55,7 +55,7 @@ public class MasterImage implements RenderingRequestCaller {
 
     private ImageLoader mLoader = null;
     private HistoryAdapter mHistory = null;
-    private ImageStateAdapter mState = null;
+    private StateAdapter mState = null;
 
     private FilterShowActivity mActivity = null;
 
@@ -192,7 +192,7 @@ public class MasterImage implements RenderingRequestCaller {
         return mHistory;
     }
 
-    public ImageStateAdapter getState() {
+    public StateAdapter getState() {
         return mState;
     }
 
@@ -200,7 +200,7 @@ public class MasterImage implements RenderingRequestCaller {
         mHistory = adapter;
     }
 
-    public void setStateAdapter(ImageStateAdapter adapter) {
+    public void setStateAdapter(StateAdapter adapter) {
         mState = adapter;
     }
 
index 00f5977..bd2f494 100644 (file)
@@ -21,15 +21,14 @@ import android.graphics.Rect;
 import android.support.v8.renderscript.Allocation;
 import android.util.Log;
 
-import com.android.gallery3d.filtershow.ImageStateAdapter;
 import com.android.gallery3d.filtershow.cache.CachingPipeline;
 import com.android.gallery3d.filtershow.cache.ImageLoader;
 import com.android.gallery3d.filtershow.filters.BaseFiltersManager;
 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
-import com.android.gallery3d.filtershow.filters.FiltersManager;
 import com.android.gallery3d.filtershow.filters.ImageFilter;
 import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
 import com.android.gallery3d.filtershow.imageshow.MasterImage;
+import com.android.gallery3d.filtershow.state.StateAdapter;
 
 import java.util.Vector;
 
@@ -533,14 +532,11 @@ public class ImagePreset {
         return true;
     }
 
-    public void fillImageStateAdapter(ImageStateAdapter imageStateAdapter) {
+    public void fillImageStateAdapter(StateAdapter imageStateAdapter) {
         if (imageStateAdapter == null) {
             return;
         }
-        imageStateAdapter.clear();
-        // TODO: re-enable the state panel
         imageStateAdapter.addAll(mFilters);
-        imageStateAdapter.notifyDataSetChanged();
     }
 
     public void setPartialRendering(boolean partialRendering, Rect bounds) {
diff --git a/src/com/android/gallery3d/filtershow/state/DragListener.java b/src/com/android/gallery3d/filtershow/state/DragListener.java
new file mode 100644 (file)
index 0000000..1aa81ed
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.state;
+
+import android.view.DragEvent;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+
+class DragListener implements View.OnDragListener {
+
+    private static final String LOGTAG = "DragListener";
+    private PanelTrack mStatePanelTrack;
+    private static float sSlope = 0.2f;
+
+    public DragListener(PanelTrack statePanelTrack) {
+        mStatePanelTrack = statePanelTrack;
+    }
+
+    private void setState(DragEvent event) {
+        float translation = event.getY() - mStatePanelTrack.getTouchPoint().y;
+        float alpha = 1.0f - (Math.abs(translation)
+                / mStatePanelTrack.getCurrentView().getHeight());
+        if (mStatePanelTrack.getOrientation() == LinearLayout.VERTICAL) {
+            translation = event.getX() - mStatePanelTrack.getTouchPoint().x;
+            alpha = 1.0f - (Math.abs(translation)
+                    / mStatePanelTrack.getCurrentView().getWidth());
+            mStatePanelTrack.getCurrentView().setTranslationX(translation);
+        } else {
+            mStatePanelTrack.getCurrentView().setTranslationY(translation);
+        }
+        mStatePanelTrack.getCurrentView().setBackgroundAlpha(alpha);
+    }
+
+    @Override
+    public boolean onDrag(View v, DragEvent event) {
+        switch (event.getAction()) {
+            case DragEvent.ACTION_DRAG_STARTED: {
+                break;
+            }
+            case DragEvent.ACTION_DRAG_LOCATION: {
+                if (mStatePanelTrack.getCurrentView() != null) {
+                    setState(event);
+                    View over = mStatePanelTrack.findChildAt((int) event.getX(),
+                                                             (int) event.getY());
+                    if (over != null && over != mStatePanelTrack.getCurrentView()) {
+                        StateView stateView = (StateView) over;
+                        if (stateView != mStatePanelTrack.getCurrentView()) {
+                            int pos = mStatePanelTrack.findChild(over);
+                            int origin = mStatePanelTrack.findChild(
+                                    mStatePanelTrack.getCurrentView());
+                            ArrayAdapter array = (ArrayAdapter) mStatePanelTrack.getAdapter();
+                            if (origin != -1 && pos != -1) {
+                                State current = (State) array.getItem(origin);
+                                array.remove(current);
+                                array.insert(current, pos);
+                                mStatePanelTrack.fillContent(false);
+                                mStatePanelTrack.setCurrentView(mStatePanelTrack.getChildAt(pos));
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+            case DragEvent.ACTION_DRAG_ENTERED: {
+                mStatePanelTrack.setExited(false);
+                if (mStatePanelTrack.getCurrentView() != null) {
+                    mStatePanelTrack.getCurrentView().setVisibility(View.VISIBLE);
+                }
+                return true;
+            }
+            case DragEvent.ACTION_DRAG_EXITED: {
+                if (mStatePanelTrack.getCurrentView() != null) {
+                    setState(event);
+                    mStatePanelTrack.getCurrentView().setVisibility(View.INVISIBLE);
+                }
+                mStatePanelTrack.setExited(true);
+                break;
+            }
+            case DragEvent.ACTION_DROP: {
+                break;
+            }
+            case DragEvent.ACTION_DRAG_ENDED: {
+                if (mStatePanelTrack.getCurrentView() != null
+                        && mStatePanelTrack.getCurrentView().getAlpha() > sSlope) {
+                    setState(event);
+                }
+                mStatePanelTrack.checkEndState();
+                break;
+            }
+            default:
+                break;
+        }
+        return true;
+    }
+}
diff --git a/src/com/android/gallery3d/filtershow/state/PanelTrack.java b/src/com/android/gallery3d/filtershow/state/PanelTrack.java
new file mode 100644 (file)
index 0000000..d02207d
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.state;
+
+import android.graphics.Point;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.Adapter;
+
+public interface PanelTrack {
+    public int getOrientation();
+    public void onTouch(MotionEvent event, StateView view);
+    public StateView getCurrentView();
+    public void setCurrentView(View view);
+    public Point getTouchPoint();
+    public View findChildAt(int x, int y);
+    public int findChild(View view);
+    public Adapter getAdapter();
+    public void fillContent(boolean value);
+    public View getChildAt(int pos);
+    public void setExited(boolean value);
+    public void checkEndState();
+}
diff --git a/src/com/android/gallery3d/filtershow/state/State.java b/src/com/android/gallery3d/filtershow/state/State.java
new file mode 100644 (file)
index 0000000..a853371
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.state;
+
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+
+public class State {
+    private String mText;
+    private int mType;
+    private FilterRepresentation mFilterRepresentation;
+
+    public State(State state) {
+        this(state.getText(), state.getType());
+    }
+
+    public State(String text) {
+       this(text, StateView.DEFAULT);
+    }
+
+    State(String text, int type) {
+        mText = text;
+        mType = type;
+    }
+
+    public boolean isDraggable() {
+        return mFilterRepresentation != null;
+    }
+
+    String getText() {
+        return mText;
+    }
+
+    void setText(String text) {
+        mText = text;
+    }
+
+    int getType() {
+        return mType;
+    }
+
+    void setType(int type) {
+        mType = type;
+    }
+
+    public FilterRepresentation getFilterRepresentation() {
+        return mFilterRepresentation;
+    }
+
+    public void setFilterRepresentation(FilterRepresentation filterRepresentation) {
+        mFilterRepresentation = filterRepresentation;
+    }
+}
diff --git a/src/com/android/gallery3d/filtershow/state/StateAdapter.java b/src/com/android/gallery3d/filtershow/state/StateAdapter.java
new file mode 100644 (file)
index 0000000..ae81e0b
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.state;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+
+import java.util.Vector;
+
+public class StateAdapter extends ArrayAdapter<State> {
+
+    private int mOrientation;
+    private PanelTrack mListener;
+    private String mOriginalText;
+    private String mResultText;
+
+    public StateAdapter(Context context, int textViewResourceId) {
+        super(context, textViewResourceId);
+        mOriginalText = context.getString(R.string.state_panel_original);
+        mResultText = context.getString(R.string.state_panel_result);
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        StateView view = null;
+        if (convertView == null) {
+            convertView = new StateView(getContext());
+        }
+        view = (StateView) convertView;
+        State state = getItem(position);
+        view.setState(state);
+        view.setOrientation(mOrientation);
+        view.setBackgroundAlpha(1.0f);
+        return view;
+    }
+
+    public boolean contains(State state) {
+        for (int i = 0; i < getCount(); i++) {
+            if (state == getItem(i)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void setOrientation(int orientation) {
+        mOrientation = orientation;
+    }
+
+    @Override
+    public void notifyDataSetChanged() {
+        if (mListener != null) {
+            mListener.fillContent(false);
+        }
+    }
+
+    public void addAll(Vector<FilterRepresentation> filters) {
+        clear();
+        add(new State(mOriginalText));
+        for (FilterRepresentation filter : filters) {
+            State state = new State(filter.getName());
+            state.setFilterRepresentation(filter);
+            add(state);
+        }
+        add(new State(mResultText));
+        notifyDataSetChanged();
+    }
+
+    void setListener(PanelTrack listener) {
+        mListener = listener;
+    }
+
+    @Override
+    public void remove(State state) {
+        super.remove(state);
+        FilterRepresentation filterRepresentation = state.getFilterRepresentation();
+        FilterShowActivity activity = (FilterShowActivity) getContext();
+        activity.getPanelController().removeFilterRepresentation(filterRepresentation);
+    }
+}
diff --git a/src/com/android/gallery3d/filtershow/state/StatePanel.java b/src/com/android/gallery3d/filtershow/state/StatePanel.java
new file mode 100644 (file)
index 0000000..fd33b05
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.state;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
+
+public class StatePanel extends Fragment {
+    private static final String LOGTAG = "StatePanel";
+    StatePanelTrack track;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        LinearLayout main = (LinearLayout) inflater.inflate(
+                R.layout.filtershow_state_panel_new, container,
+                false);
+
+        View panel = main.findViewById(R.id.listStates);
+        track = (StatePanelTrack) panel;
+        track.setAdapter(MasterImage.getImage().getState());
+        return main;
+    }
+}
diff --git a/src/com/android/gallery3d/filtershow/state/StatePanelTrack.java b/src/com/android/gallery3d/filtershow/state/StatePanelTrack.java
new file mode 100644 (file)
index 0000000..1f6c272
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.state;
+
+import android.animation.LayoutTransition;
+import android.content.Context;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.Adapter;
+import android.widget.LinearLayout;
+import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+
+public class StatePanelTrack extends LinearLayout implements PanelTrack {
+
+    private static final String LOGTAG = "StatePanelTrack";
+    private Point mTouchPoint;
+    private StateView mCurrentView;
+    private StateView mCurrentSelectedView;
+    private boolean mExited = false;
+    private boolean mStartedDrag = false;
+    private StateAdapter mAdapter;
+    private DragListener mDragListener = new DragListener(this);
+    GestureDetector mGestureDetector;
+    private int mContainerWidth = 668; // TODO: get this from XML
+    private int mContainerHeight = 200;
+
+    public StatePanelTrack(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        GestureDetector.SimpleOnGestureListener simpleOnGestureListener
+                = new GestureDetector.SimpleOnGestureListener(){
+            @Override
+            public void onLongPress(MotionEvent e) {
+                longPress(e);
+            }
+            @Override
+            public boolean onDoubleTap(MotionEvent e) {
+                addDuplicate(e);
+                return true;
+            }
+        };
+        mGestureDetector = new GestureDetector(context, simpleOnGestureListener);
+    }
+
+    private void addDuplicate(MotionEvent e) {
+        if (mCurrentSelectedView == null) {
+            return;
+        }
+        int pos = findChild(mCurrentSelectedView);
+        if (pos != -1) {
+            mAdapter.insert(new State(mCurrentSelectedView.getState()), pos);
+            fillContent(true);
+        }
+    }
+
+    private void longPress(MotionEvent e) {
+        View view = findChildAt((int) e.getX(), (int) e.getY());
+        if (view == null) {
+            return;
+        }
+        if (view instanceof StateView) {
+            StateView stateView = (StateView) view;
+            stateView.setDuplicateButton(true);
+        }
+    }
+
+    public void setAdapter(StateAdapter adapter) {
+        mAdapter = adapter;
+        mAdapter.setListener(this);
+        mAdapter.setOrientation(getOrientation());
+        fillContent(false);
+        requestLayout();
+    }
+
+    public StateView findChildWithState(State state) {
+        for (int i = 0; i < getChildCount(); i++) {
+            StateView view = (StateView) getChildAt(i);
+            if (view.getState() == state) {
+                return view;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
+        int w = MeasureSpec.getSize(widthMeasureSpec);
+        if (w > 0) {
+            mContainerWidth = w;
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        fillContent(false);
+    }
+
+    public void fillContent(boolean animate) {
+        if (!animate) {
+            this.setLayoutTransition(null);
+        }
+        int n = mAdapter.getCount();
+        int w = mContainerWidth;
+        int h = mContainerHeight;
+        for (int i = 0; i < getChildCount(); i++) {
+            StateView child = (StateView) getChildAt(i);
+            child.resetPosition();
+            if (!mAdapter.contains(child.getState())) {
+                removeView(child);
+            }
+        }
+        LayoutParams params;
+        params = new LayoutParams(w, h);
+        LayoutParams paramsEnds;
+        paramsEnds = new LayoutParams(w, h/2);
+        for (int i = 0; i < n; i++) {
+            State s = mAdapter.getItem(i);
+            if (findChildWithState(s) == null) {
+                View view = mAdapter.getView(i, null, this);
+                addView(view, i, params);
+            }
+        }
+        for (int i = 0; i < n; i++) {
+            State state = mAdapter.getItem(i);
+            StateView view = (StateView) getChildAt(i);
+            view.setState(state);
+            if (i == 0) {
+                view.setType(StateView.BEGIN);
+            } else if (i == n - 1) {
+                view.setType(StateView.END);
+            }
+            view.resetPosition();
+            if (i == 0 || (i == n -1)) {
+                if (view.getWidth() != w || view.getHeight() != h/2) {
+                    view.setLayoutParams(paramsEnds);
+                    requestLayout();
+                }
+            } else {
+                if (view.getWidth() != w || view.getHeight() != h) {
+                    view.setLayoutParams(params);
+                    requestLayout();
+                }
+            }
+        }
+
+        if (!animate) {
+            this.setLayoutTransition(new LayoutTransition());
+        }
+    }
+
+    public void onTouch(MotionEvent event, StateView view) {
+        if (!view.isDraggable()) {
+            return;
+        }
+        mCurrentView = view;
+        if (mCurrentSelectedView == mCurrentView) {
+            return;
+        }
+        if (mCurrentSelectedView != null) {
+            mCurrentSelectedView.setSelected(false);
+        }
+        // We changed the current view -- let's reset the
+        // gesture detector.
+        MotionEvent cancelEvent = MotionEvent.obtain(event);
+        cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
+        mGestureDetector.onTouchEvent(cancelEvent);
+        mCurrentSelectedView = mCurrentView;
+        mCurrentSelectedView.setSelected(true);
+        // We have to send the event to the gesture detector
+        mGestureDetector.onTouchEvent(event);
+        FilterShowActivity activity = (FilterShowActivity) getContext();
+        activity.getPanelController().showComponentWithRepresentation(
+                mCurrentSelectedView.getState().getFilterRepresentation());
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        if (mCurrentView != null) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (mCurrentView == null) {
+            return false;
+        }
+        mGestureDetector.onTouchEvent(event);
+        if (mTouchPoint == null) {
+            mTouchPoint = new Point();
+            mTouchPoint.x = (int) event.getX();
+            mTouchPoint.y = (int) event.getY();
+        }
+        if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
+            float translation = event.getY() - mTouchPoint.y;
+            float alpha = 1.0f - (Math.abs(translation) / mCurrentView.getHeight());
+            if (getOrientation() == LinearLayout.VERTICAL) {
+                translation = event.getX() - mTouchPoint.x;
+                alpha = 1.0f - (Math.abs(translation) / mCurrentView.getWidth());
+                mCurrentView.setTranslationX(translation);
+            } else {
+                mCurrentView.setTranslationY(translation);
+            }
+            mCurrentView.setBackgroundAlpha(alpha);
+            if (alpha < 0.7) {
+                setOnDragListener(mDragListener);
+                DragShadowBuilder shadowBuilder = new DragShadowBuilder(mCurrentView);
+                mCurrentView.startDrag(null, shadowBuilder, mCurrentView, 0);
+                mStartedDrag = true;
+            }
+        }
+        if (event.getActionMasked() == MotionEvent.ACTION_UP
+                || (!mStartedDrag && event.getActionMasked() == MotionEvent.ACTION_CANCEL)) {
+            checkEndState();
+        }
+        return true;
+    }
+
+    public void checkEndState() {
+        mTouchPoint = null;
+        if (mExited || mCurrentView.getAlpha() < 0.2) {
+            int origin = findChild(mCurrentView);
+            if (origin != -1) {
+                State current = mAdapter.getItem(origin);
+                mAdapter.remove(current);
+                fillContent(true);
+            }
+        } else {
+            mCurrentView.setBackgroundAlpha(1.0f);
+            mCurrentView.setTranslationX(0);
+            mCurrentView.setTranslationY(0);
+        }
+        mCurrentView = null;
+        mExited = false;
+        mStartedDrag = false;
+    }
+
+    public View findChildAt(int x, int y) {
+        Rect frame = new Rect();
+        int scrolledXInt = getScrollX() + x;
+        int scrolledYInt = getScrollY() + y;
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            child.getHitRect(frame);
+            if (frame.contains(scrolledXInt, scrolledYInt)) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    public int findChild(View view) {
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            if (child == view) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    public StateView getCurrentView() {
+        return mCurrentView;
+    }
+
+    public void setCurrentView(View currentView) {
+        mCurrentView = (StateView) currentView;
+    }
+
+    public void setExited(boolean value) {
+        mExited = value;
+    }
+
+    public Point getTouchPoint() {
+        return mTouchPoint;
+    }
+
+    public Adapter getAdapter() {
+        return mAdapter;
+    }
+}
diff --git a/src/com/android/gallery3d/filtershow/state/StateView.java b/src/com/android/gallery3d/filtershow/state/StateView.java
new file mode 100644 (file)
index 0000000..eb19b52
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.filtershow.state;
+
+import android.content.Context;
+import android.graphics.*;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewParent;
+import android.widget.LinearLayout;
+import com.android.gallery3d.filtershow.FilterShowActivity;
+
+public class StateView extends View {
+
+    private Path mPath = new Path();
+    private Paint mPaint = new Paint();
+
+    public static int DEFAULT = 0;
+    public static int BEGIN = 1;
+    public static int END = 2;
+
+    public static int UP = 1;
+    public static int DOWN = 2;
+    public static int LEFT = 3;
+    public static int RIGHT = 4;
+
+    private int mType = DEFAULT;
+    private float mAlpha = 1.0f;
+    private String mText = "Default";
+    private float mTextSize = 32;
+    private static int sMargin = 16;
+    private static int sArrowHeight = 16;
+    private static int sArrowWidth = 8;
+    private int mOrientation = LinearLayout.VERTICAL;
+    private int mDirection = DOWN;
+    private boolean mDuplicateButton;
+    private State mState;
+
+    public StateView(Context context) {
+        this(context, DEFAULT);
+    }
+
+    public StateView(Context context, int type) {
+        super(context);
+        mType = type;
+    }
+
+    public StateView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public String getText() {
+        return mText;
+    }
+
+    public void setText(String text) {
+        mText = text;
+        invalidate();
+    }
+
+    public void setType(int type) {
+        mType = type;
+        invalidate();
+    }
+
+    @Override
+    public void setSelected(boolean value) {
+        super.setSelected(value);
+        if (!value) {
+            mDuplicateButton = false;
+        }
+        invalidate();
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+            ViewParent parent = getParent();
+            if (parent instanceof PanelTrack) {
+                ((PanelTrack) getParent()).onTouch(event, this);
+            }
+        }
+        return true;
+    }
+
+    public void drawText(Canvas canvas) {
+        if (mText == null) {
+            return;
+        }
+        mPaint.reset();
+        if (isSelected()) {
+            mPaint.setColor(Color.BLACK);
+        } else {
+            mPaint.setColor(Color.WHITE);
+        }
+        mPaint.setTextSize(mTextSize);
+        float textWidth = mPaint.measureText(mText);
+        int x = (int) ((canvas.getWidth() - textWidth) / 2);
+        int y = canvas.getHeight() - sMargin;
+        if (canvas.getHeight() > canvas.getWidth()) {
+            y = canvas.getHeight() - (canvas.getHeight() - canvas.getWidth() - 2 * sMargin) / 2;
+        }
+        canvas.drawText(mText, x, y, mPaint);
+    }
+
+    public void onDraw(Canvas canvas) {
+        canvas.drawARGB(0, 0, 0, 0);
+        mPath.reset();
+
+        float w = canvas.getWidth();
+        float h = canvas.getHeight();
+        float r = sArrowHeight;
+        float d = sArrowWidth;
+
+        if (mOrientation == LinearLayout.HORIZONTAL) {
+            drawHorizontalPath(w, h, r, d);
+        } else {
+            if (mDirection == DOWN) {
+                drawVerticalDownPath(w, h, r, d);
+            } else {
+                drawVerticalPath(w, h, r, d);
+            }
+        }
+
+        if (mType == DEFAULT) {
+            if (mDuplicateButton) {
+                mPaint.setARGB(255, 200, 0, 0);
+            } else if (isSelected()) {
+                mPaint.setARGB(255, 200, 200, 200);
+            } else {
+                mPaint.setARGB(255, 70, 70, 70);
+            }
+        } else {
+            mPaint.setARGB(255, 150, 150, 150);
+        }
+        canvas.drawPath(mPath, mPaint);
+        drawText(canvas);
+    }
+
+    private void drawHorizontalPath(float w, float h, float r, float d) {
+        mPath.moveTo(0, 0);
+        if (mType == END) {
+            mPath.lineTo(w, 0);
+            mPath.lineTo(w, h);
+        } else {
+            mPath.lineTo(w - d, 0);
+            mPath.lineTo(w - d, r);
+            mPath.lineTo(w, r + d);
+            mPath.lineTo(w - d, r + d + r);
+            mPath.lineTo(w - d, h);
+        }
+        mPath.lineTo(0, h);
+        if (mType != BEGIN) {
+            mPath.lineTo(0, r + d + r);
+            mPath.lineTo(d, r + d);
+            mPath.lineTo(0, r);
+        }
+        mPath.close();
+    }
+
+    private void drawVerticalPath(float w, float h, float r, float d) {
+        if (mType == BEGIN) {
+            mPath.moveTo(0, 0);
+            mPath.lineTo(w, 0);
+        } else {
+            mPath.moveTo(0, d);
+            mPath.lineTo(r, d);
+            mPath.lineTo(r + d, 0);
+            mPath.lineTo(r + d + r, d);
+            mPath.lineTo(w, d);
+        }
+        mPath.lineTo(w, h);
+        if (mType != END) {
+            mPath.lineTo(r + d + r, h);
+            mPath.lineTo(r + d, h - d);
+            mPath.lineTo(r, h);
+        }
+        mPath.lineTo(0, h);
+        mPath.close();
+    }
+
+    private void drawVerticalDownPath(float w, float h, float r, float d) {
+        mPath.moveTo(0, 0);
+        if (mType != BEGIN) {
+            mPath.lineTo(r, 0);
+            mPath.lineTo(r + d, d);
+            mPath.lineTo(r + d + r, 0);
+        }
+        mPath.lineTo(w, 0);
+
+        if (mType != END) {
+            mPath.lineTo(w, h - d);
+
+            mPath.lineTo(r + d + r, h - d);
+            mPath.lineTo(r + d, h);
+            mPath.lineTo(r, h - d);
+
+            mPath.lineTo(0, h - d);
+        } else {
+            mPath.lineTo(w, h);
+            mPath.lineTo(0, h);
+        }
+
+        mPath.close();
+    }
+
+    public void setBackgroundAlpha(float alpha) {
+        if (mType != DEFAULT) {
+            return;
+        }
+        mAlpha = alpha;
+        invalidate();
+    }
+
+    public float getAlpha() {
+        return mAlpha;
+    }
+
+    public void setOrientation(int orientation) {
+        mOrientation = orientation;
+    }
+
+    public void setDuplicateButton(boolean b) {
+        mDuplicateButton = b;
+        invalidate();
+    }
+
+    public State getState() {
+        return mState;
+    }
+
+    public void setState(State state) {
+        mState = state;
+        mText = mState.getText();
+        mType = mState.getType();
+        setBackgroundAlpha(1.0f);
+        invalidate();
+    }
+
+    public void resetPosition() {
+        setTranslationX(0);
+        setTranslationY(0);
+    }
+
+    public boolean isDraggable() {
+        return mState.isDraggable();
+    }
+}