/* * Copyright (C) 2010 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.photoeditor.actions; import android.content.Context; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; import com.android.gallery3d.R; import com.android.gallery3d.photoeditor.FilterStack; import com.android.gallery3d.photoeditor.OnDoneCallback; import com.android.gallery3d.photoeditor.filters.Filter; /** * An action binding UI controls and effect operation for editing photo. */ public abstract class EffectAction extends LinearLayout { /** * Listener of effect action. */ public interface ActionListener { /** * Invoked when the action is okayed (effect is applied and completed). */ void onOk(); } protected EffectToolKit toolKit; private Toast tooltip; private FilterStack filterStack; private boolean pushedFilter; private boolean disableFilterOutput; private FilterChangedCallback lastFilterChangedCallback; private ActionListener listener; public EffectAction(Context context, AttributeSet attrs) { super(context, attrs); } public void begin(View root, FilterStack filterStack, ActionListener listener) { // This view is already detached from UI view hierarchy by reaching here; findViewById() // could only access its own child views from here. toolKit = new EffectToolKit(root, ((TextView) findViewById(R.id.effect_label)).getText()); this.filterStack = filterStack; this.listener = listener; // Shows the tooltip if it's available. if (getTag() != null) { tooltip = Toast.makeText(getContext(), (String) getTag(), Toast.LENGTH_SHORT); tooltip.setGravity(Gravity.CENTER, 0, 0); tooltip.show(); } prepare(); } /** * Subclasses should create a specific filter and bind the filter to necessary UI controls here * when the action is about to begin. */ protected abstract void prepare(); /** * Ends the effect and then executes the runnable after the effect is finished. */ public void end(final Runnable runnableOnODone) { // Cancel the tooltip if it's still showing. if ((tooltip != null) && (tooltip.getView().getParent() != null)) { tooltip.cancel(); tooltip = null; } // End tool editing by canceling unfinished touch events. toolKit.cancel(); // Output the pushed filter if it wasn't outputted. if (pushedFilter && disableFilterOutput) { outputFilter(); } // Wait till last output callback is done before finishing. if ((lastFilterChangedCallback == null) || lastFilterChangedCallback.done) { finish(runnableOnODone); } else { lastFilterChangedCallback.runnableOnReady = new Runnable() { @Override public void run() { finish(runnableOnODone); } }; } } private void finish(Runnable runnableOnDone) { toolKit.close(); pushedFilter = false; disableFilterOutput = false; lastFilterChangedCallback = null; runnableOnDone.run(); } protected void disableFilterOutput() { // Filter output won't be outputted until this effect has done editing its filter. disableFilterOutput = true; } protected void outputFilter() { // Notify the stack to execute the changed top filter and output the results. lastFilterChangedCallback = new FilterChangedCallback(); filterStack.topFilterChanged(lastFilterChangedCallback); } protected void notifyChanged(Filter filter) { if (!pushedFilter) { filterStack.pushFilter(filter); pushedFilter = true; } if (pushedFilter && !disableFilterOutput) { outputFilter(); } } protected void notifyOk() { listener.onOk(); } /** * Done callback for executing top filter changes. */ private class FilterChangedCallback implements OnDoneCallback { private boolean done; private Runnable runnableOnReady; @Override public void onDone() { done = true; if (runnableOnReady != null) { runnableOnReady.run(); } } } }