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
17package com.android.photoeditor;
18
19import android.content.Context;
20import android.util.AttributeSet;
21import android.view.View;
22import android.view.ViewGroup;
23import android.widget.ScrollView;
24import android.widget.TextView;
25
26import com.android.photoeditor.actions.AutoFixAction;
27import com.android.photoeditor.actions.ColorTemperatureAction;
28import com.android.photoeditor.actions.CropAction;
29import com.android.photoeditor.actions.CrossProcessAction;
30import com.android.photoeditor.actions.DocumentaryAction;
31import com.android.photoeditor.actions.DoodleAction;
32import com.android.photoeditor.actions.DuotoneAction;
33import com.android.photoeditor.actions.FillLightAction;
34import com.android.photoeditor.actions.FilterAction;
35import com.android.photoeditor.actions.FisheyeAction;
36import com.android.photoeditor.actions.FlipAction;
37import com.android.photoeditor.actions.GrainAction;
38import com.android.photoeditor.actions.GrayscaleAction;
39import com.android.photoeditor.actions.HighlightAction;
40import com.android.photoeditor.actions.LomoishAction;
41import com.android.photoeditor.actions.NegativeAction;
42import com.android.photoeditor.actions.PosterizeAction;
43import com.android.photoeditor.actions.RedEyeAction;
44import com.android.photoeditor.actions.RotateAction;
45import com.android.photoeditor.actions.SaturationAction;
46import com.android.photoeditor.actions.SepiaAction;
47import com.android.photoeditor.actions.ShadowAction;
48import com.android.photoeditor.actions.SharpenAction;
49import com.android.photoeditor.actions.StraightenAction;
50import com.android.photoeditor.actions.TintAction;
51import com.android.photoeditor.actions.VignetteAction;
52import com.android.photoeditor.actions.WarmifyAction;
53
54import java.util.ArrayList;
55import java.util.List;
56
57/**
58 * Scroll view that contains all effects for editing photo by mapping each effect to trigger one
59 * corresponding FilterAction.
60 */
61public class EffectsBar extends ScrollView {
62
63    private final List<Effect> effects = new ArrayList<Effect>();
64    private TextView effectName;
65
66    public EffectsBar(Context context, AttributeSet attrs) {
67        super(context, attrs);
68    }
69
70    public void initialize(FilterStack filterStack, PhotoView photoView, ViewGroup tools) {
71        effects.add(new Effect(R.id.autofix_effect,
72                new AutoFixAction(filterStack, tools)));
73
74        effects.add(new Effect(R.id.crop_effect,
75                new CropAction(filterStack, tools)));
76
77        effects.add(new Effect(R.id.crossprocess_effect,
78                new CrossProcessAction(filterStack, tools)));
79
80        effects.add(new Effect(R.id.documentary_effect,
81                new DocumentaryAction(filterStack, tools)));
82
83        effects.add(new Effect(R.id.doodle_effect,
84                new DoodleAction(filterStack, tools)));
85
86        effects.add(new Effect(R.id.duotone_effect,
87                new DuotoneAction(filterStack, tools)));
88
89        effects.add(new Effect(R.id.filllight_effect,
90                new FillLightAction(filterStack, tools)));
91
92        effects.add(new Effect(R.id.fisheye_effect,
93                new FisheyeAction(filterStack, tools)));
94
95        effects.add(new Effect(R.id.flip_effect,
96                new FlipAction(filterStack, tools)));
97
98        effects.add(new Effect(R.id.grain_effect,
99                new GrainAction(filterStack, tools)));
100
101        effects.add(new Effect(R.id.grayscale_effect,
102                new GrayscaleAction(filterStack, tools)));
103
104        effects.add(new Effect(R.id.highlight_effect,
105                new HighlightAction(filterStack, tools)));
106
107        effects.add(new Effect(R.id.lomoish_effect,
108                new LomoishAction(filterStack, tools)));
109
110        effects.add(new Effect(R.id.negative_effect,
111                new NegativeAction(filterStack, tools)));
112
113        effects.add(new Effect(R.id.posterize_effect,
114                new PosterizeAction(filterStack, tools)));
115
116        effects.add(new Effect(R.id.redeye_effect,
117                new RedEyeAction(filterStack, tools)));
118
119        effects.add(new Effect(R.id.rotate_effect,
120                new RotateAction(filterStack, tools)));
121
122        effects.add(new Effect(R.id.saturation_effect,
123                new SaturationAction(filterStack, tools)));
124
125        effects.add(new Effect(R.id.sepia_effect,
126                new SepiaAction(filterStack, tools)));
127
128        effects.add(new Effect(R.id.shadow_effect,
129                new ShadowAction(filterStack, tools)));
130
131        effects.add(new Effect(R.id.sharpen_effect,
132                new SharpenAction(filterStack, tools)));
133
134        effects.add(new Effect(R.id.straighten_effect,
135                new StraightenAction(filterStack, tools)));
136
137        effects.add(new Effect(R.id.temperature_effect,
138                new ColorTemperatureAction(filterStack, tools)));
139
140        effects.add(new Effect(R.id.tint_effect,
141                new TintAction(filterStack, tools)));
142
143        effects.add(new Effect(R.id.vignette_effect,
144                new VignetteAction(filterStack, tools)));
145
146        effects.add(new Effect(R.id.warmify_effect,
147                new WarmifyAction(filterStack, tools)));
148
149        effectName = (TextView) tools.findViewById(R.id.action_effect_name);
150
151        // Disable hardware acceleration on this view to make alpha animations work for idle fading.
152        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
153
154        setEnabled(false);
155    }
156
157    public void effectsOff(Runnable runnableOnEffectsOff) {
158        for (Effect effect : effects) {
159            if (effect.on) {
160                effect.turnOff(runnableOnEffectsOff);
161                return;
162            }
163        }
164        // Just execute the runnable right away if all effects are already off.
165        if (runnableOnEffectsOff != null) {
166            runnableOnEffectsOff.run();
167        }
168    }
169
170    public boolean hasEffectOn() {
171        for (Effect effect : effects) {
172            if (effect.on) {
173                return true;
174            }
175        }
176        return false;
177    }
178
179    private class Effect implements FilterAction.FilterActionListener {
180
181        private final FilterAction action;
182        private final CharSequence name;
183        private final IconIndicator button;
184        private boolean on;
185        private Runnable runnableOnODone;
186
187        public Effect(int effectId, FilterAction action) {
188            this.action = action;
189
190            View view = findViewById(effectId);
191            name = ((TextView) view.findViewById(R.id.effect_label)).getText();
192            button = (IconIndicator) view.findViewById(R.id.effect_button);
193            button.setOnClickListener(new View.OnClickListener() {
194
195                @Override
196                public void onClick(View v) {
197                    if (isEnabled()) {
198                        if (on) {
199                            turnOff(null);
200                        } else {
201                            // Have other effects done turning off first and then turn on itself.
202                            effectsOff(new Runnable() {
203
204                                @Override
205                                public void run() {
206                                    turnOn();
207                                }
208                            });
209                        }
210                    }
211                }
212            });
213        }
214
215        private void turnOn() {
216            effectName.setText(name);
217            button.setMode("on");
218            on = true;
219            action.begin(this);
220        }
221
222        private void turnOff(Runnable runnableOnODone) {
223            this.runnableOnODone = runnableOnODone;
224            action.end();
225        }
226
227        @Override
228        public void onDone() {
229            if (on) {
230                effectName.setText("");
231                button.setMode("off");
232                on = false;
233
234                if (runnableOnODone != null) {
235                    runnableOnODone.run();
236                    runnableOnODone = null;
237                }
238            }
239        }
240    }
241}
242