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.photoeditor; 18 19 import android.content.Context; 20 import android.util.AttributeSet; 21 import android.view.View; 22 import android.view.ViewGroup; 23 import android.widget.ScrollView; 24 import android.widget.TextView; 25 26 import com.android.photoeditor.actions.AutoFixAction; 27 import com.android.photoeditor.actions.ColorTemperatureAction; 28 import com.android.photoeditor.actions.CropAction; 29 import com.android.photoeditor.actions.CrossProcessAction; 30 import com.android.photoeditor.actions.DocumentaryAction; 31 import com.android.photoeditor.actions.DoodleAction; 32 import com.android.photoeditor.actions.DuotoneAction; 33 import com.android.photoeditor.actions.FillLightAction; 34 import com.android.photoeditor.actions.FilterAction; 35 import com.android.photoeditor.actions.FisheyeAction; 36 import com.android.photoeditor.actions.FlipAction; 37 import com.android.photoeditor.actions.GrainAction; 38 import com.android.photoeditor.actions.GrayscaleAction; 39 import com.android.photoeditor.actions.HighlightAction; 40 import com.android.photoeditor.actions.LomoishAction; 41 import com.android.photoeditor.actions.NegativeAction; 42 import com.android.photoeditor.actions.PosterizeAction; 43 import com.android.photoeditor.actions.RedEyeAction; 44 import com.android.photoeditor.actions.RotateAction; 45 import com.android.photoeditor.actions.SaturationAction; 46 import com.android.photoeditor.actions.SepiaAction; 47 import com.android.photoeditor.actions.ShadowAction; 48 import com.android.photoeditor.actions.SharpenAction; 49 import com.android.photoeditor.actions.StraightenAction; 50 import com.android.photoeditor.actions.TintAction; 51 import com.android.photoeditor.actions.VignetteAction; 52 import com.android.photoeditor.actions.WarmifyAction; 53 54 import java.util.ArrayList; 55 import 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 */ 61 public 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