blob: c8e5d7d598a05963e615335e1f88c5e32157d010 [file] [log] [blame]
Yuli Huang6a12ad72011-09-12 22:25:30 +08001/*
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
17package com.android.gallery3d.photoeditor.actions;
18
19import android.content.Context;
20import android.util.AttributeSet;
21import android.view.Gravity;
22import android.view.View;
23import android.widget.LinearLayout;
24import android.widget.TextView;
25import android.widget.Toast;
26
27import com.android.gallery3d.R;
28import com.android.gallery3d.photoeditor.FilterStack;
29import com.android.gallery3d.photoeditor.OnDoneCallback;
30import com.android.gallery3d.photoeditor.filters.Filter;
31
32/**
33 * An action binding UI controls and effect operation for editing photo.
34 */
35public 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 /**
Jorge Ruesgaa901f882012-06-12 23:28:58 +0200152 * Checks if the action effect is present in the system.
153 *
154 * @return boolean true if an action effect is present in the system and can be loaded
155 */
156 public boolean isPresent() {
157 return true;
158 }
159
160 /**
Yuli Huang6a12ad72011-09-12 22:25:30 +0800161 * Done callback for executing top filter changes.
162 */
163 private class FilterChangedCallback implements OnDoneCallback {
164
165 private boolean done;
166 private Runnable runnableOnReady;
167
168 @Override
169 public void onDone() {
170 done = true;
171
172 if (runnableOnReady != null) {
173 runnableOnReady.run();
174 }
175 }
176 }
177}