Home | History | Annotate | Download | only in actions
      1 /*
      2  * Copyright (C) 2010 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.photoeditor.actions;
     18 
     19 import android.content.Context;
     20 import android.util.AttributeSet;
     21 import android.view.Gravity;
     22 import android.view.View;
     23 import android.widget.LinearLayout;
     24 import android.widget.TextView;
     25 import android.widget.Toast;
     26 
     27 import com.android.gallery3d.R;
     28 import com.android.gallery3d.photoeditor.FilterStack;
     29 import com.android.gallery3d.photoeditor.OnDoneCallback;
     30 import com.android.gallery3d.photoeditor.filters.Filter;
     31 
     32 /**
     33  * An action binding UI controls and effect operation for editing photo.
     34  */
     35 public abstract class EffectAction extends LinearLayout {
     36 
     37     /**
     38      * Listener of effect action.
     39      */
     40     public interface Listener {
     41 
     42         void onClick();
     43 
     44         void onDone();
     45     }
     46 
     47     protected EffectToolFactory factory;
     48 
     49     private Listener listener;
     50     private Toast tooltip;
     51     private FilterStack filterStack;
     52     private boolean pushedFilter;
     53     private FilterChangedCallback lastFilterChangedCallback;
     54 
     55     public EffectAction(Context context, AttributeSet attrs) {
     56         super(context, attrs);
     57     }
     58 
     59     public void setListener(Listener l) {
     60         listener = l;
     61         findViewById(R.id.effect_button).setOnClickListener(
     62                 (listener == null) ? null : new View.OnClickListener() {
     63 
     64             @Override
     65             public void onClick(View v) {
     66                 listener.onClick();
     67             }
     68         });
     69     }
     70 
     71     public CharSequence name() {
     72         return ((TextView) findViewById(R.id.effect_label)).getText();
     73     }
     74 
     75     public void begin(FilterStack filterStack, EffectToolFactory factory) {
     76         // This view is already detached from UI view hierarchy by reaching here; findViewById()
     77         // could only access its own child views from here.
     78         this.filterStack = filterStack;
     79         this.factory = factory;
     80 
     81         // Shows the tooltip if it's available.
     82         if (getTag() != null) {
     83             tooltip = Toast.makeText(getContext(), (String) getTag(), Toast.LENGTH_SHORT);
     84             tooltip.setGravity(Gravity.CENTER, 0, 0);
     85             tooltip.show();
     86         }
     87         doBegin();
     88     }
     89 
     90     /**
     91      * Ends the effect and then executes the runnable after the effect is finished.
     92      */
     93     public void end(final Runnable runnableOnODone) {
     94         doEnd();
     95 
     96         // Wait till last output callback is done before finishing.
     97         if ((lastFilterChangedCallback == null) || lastFilterChangedCallback.done) {
     98             finish(runnableOnODone);
     99         } else {
    100             lastFilterChangedCallback.runnableOnReady = new Runnable() {
    101 
    102                 @Override
    103                 public void run() {
    104                     finish(runnableOnODone);
    105                 }
    106             };
    107         }
    108     }
    109 
    110     private void finish(Runnable runnableOnDone) {
    111         // Close the tooltip if it's still showing.
    112         if ((tooltip != null) && (tooltip.getView().getParent() != null)) {
    113             tooltip.cancel();
    114             tooltip = null;
    115         }
    116         pushedFilter = false;
    117         lastFilterChangedCallback = null;
    118 
    119         runnableOnDone.run();
    120     }
    121 
    122     protected void notifyDone() {
    123         if (listener != null) {
    124             listener.onDone();
    125         }
    126     }
    127 
    128     protected void notifyFilterChanged(Filter filter, boolean output) {
    129         if (!pushedFilter && filter.isValid()) {
    130             filterStack.pushFilter(filter);
    131             pushedFilter = true;
    132         }
    133         if (pushedFilter && output) {
    134             // Notify the stack to execute the changed top filter and output the results.
    135             lastFilterChangedCallback = new FilterChangedCallback();
    136             filterStack.topFilterChanged(lastFilterChangedCallback);
    137         }
    138     }
    139 
    140     /**
    141      * Subclasses should creates a specific filter and binds the filter to necessary UI controls
    142      * here when the action is about to begin.
    143      */
    144     protected abstract void doBegin();
    145 
    146     /**
    147      * Subclasses could do specific ending operations here when the action is about to end.
    148      */
    149     protected abstract void doEnd();
    150 
    151     /**
    152      * Done callback for executing top filter changes.
    153      */
    154     private class FilterChangedCallback implements OnDoneCallback {
    155 
    156         private boolean done;
    157         private Runnable runnableOnReady;
    158 
    159         @Override
    160         public void onDone() {
    161             done = true;
    162 
    163             if (runnableOnReady != null) {
    164                 runnableOnReady.run();
    165             }
    166         }
    167     }
    168 }
    169