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.actions; 18 19 import android.view.View; 20 import android.view.ViewGroup; 21 import android.widget.Toast; 22 23 import com.android.photoeditor.FilterStack; 24 import com.android.photoeditor.Photo; 25 import com.android.photoeditor.PhotoOutputCallback; 26 import com.android.photoeditor.PhotoView; 27 import com.android.photoeditor.R; 28 import com.android.photoeditor.SpinnerProgressDialog; 29 import com.android.photoeditor.filters.Filter; 30 31 /** 32 * An action binding UI controls and filter operation for editing photo. 33 */ 34 public abstract class FilterAction { 35 36 /** 37 * Listens to when this FilterAction has done editing and should be ended. 38 */ 39 public interface FilterActionListener { 40 onDone()41 void onDone(); 42 } 43 44 protected final FilterStack filterStack; 45 protected final PhotoView photoView; 46 protected final ScaleWheel scaleWheel; 47 protected final ColorWheel colorWheel; 48 protected final DoodleView doodleView; 49 protected final TouchView touchView; 50 protected final RotateView rotateView; 51 protected final CropView cropView; 52 private final ViewGroup tools; 53 54 private Toast tooltip; 55 private boolean pushedFilter; 56 private OutputCallback lastOutputCallback; 57 private FilterActionListener listener; 58 FilterAction(FilterStack filterStack, ViewGroup tools)59 public FilterAction(FilterStack filterStack, ViewGroup tools) { 60 this.filterStack = filterStack; 61 this.tools = tools; 62 63 photoView = (PhotoView) tools.findViewById(R.id.photo_view); 64 scaleWheel = (ScaleWheel) tools.findViewById(R.id.scale_wheel); 65 colorWheel = (ColorWheel) tools.findViewById(R.id.color_wheel); 66 doodleView = (DoodleView) tools.findViewById(R.id.doodle_view); 67 touchView = (TouchView) tools.findViewById(R.id.touch_view); 68 rotateView = (RotateView) tools.findViewById(R.id.rotate_view); 69 cropView = (CropView) tools.findViewById(R.id.crop_view); 70 } 71 FilterAction(FilterStack filterStack, ViewGroup tools, int tooltipId)72 public FilterAction(FilterStack filterStack, ViewGroup tools, int tooltipId) { 73 this(filterStack, tools); 74 75 tooltip = Toast.makeText(tools.getContext(), tooltipId, Toast.LENGTH_SHORT); 76 } 77 notifyFilterChanged(Filter filter, boolean output)78 protected void notifyFilterChanged(Filter filter, boolean output) { 79 if (!pushedFilter && filter.isValid()) { 80 filterStack.pushFilter(filter); 81 pushedFilter = true; 82 } 83 if (pushedFilter && output) { 84 // Notify the stack to output the changed top filter. 85 lastOutputCallback = new OutputCallback(); 86 filterStack.topFilterChanged(lastOutputCallback); 87 } 88 } 89 begin(FilterActionListener listener)90 public void begin(FilterActionListener listener) { 91 this.listener = listener; 92 if (tooltip != null) { 93 tooltip.show(); 94 } 95 onBegin(); 96 } 97 end()98 public void end() { 99 onEnd(); 100 101 // Wait till last output callback is done before finishing. 102 if ((lastOutputCallback == null) || lastOutputCallback.done) { 103 finish(); 104 } else { 105 final SpinnerProgressDialog progressDialog = SpinnerProgressDialog.show(tools); 106 lastOutputCallback.runnableOnDone = new Runnable() { 107 108 @Override 109 public void run() { 110 progressDialog.dismiss(); 111 finish(); 112 } 113 }; 114 } 115 } 116 finish()117 private void finish() { 118 // Close the tooltip if it's still showing. 119 if ((tooltip != null) && (tooltip.getView().getParent() != null)) { 120 tooltip.cancel(); 121 } 122 if (scaleWheel.getVisibility() == View.VISIBLE) { 123 scaleWheel.setOnScaleChangeListener(null); 124 scaleWheel.setVisibility(View.INVISIBLE); 125 } 126 if (colorWheel.getVisibility() == View.VISIBLE) { 127 colorWheel.setOnColorChangeListener(null); 128 colorWheel.setVisibility(View.INVISIBLE); 129 } 130 if (doodleView.getVisibility() == View.VISIBLE) { 131 doodleView.setOnDoodleChangeListener(null); 132 doodleView.setVisibility(View.INVISIBLE); 133 } 134 if (touchView.getVisibility() == View.VISIBLE) { 135 touchView.setSingleTapListener(null); 136 touchView.setSwipeListener(null); 137 touchView.setVisibility(View.INVISIBLE); 138 } 139 if (rotateView.getVisibility() == View.VISIBLE) { 140 rotateView.setOnAngleChangeListener(null); 141 rotateView.setVisibility(View.INVISIBLE); 142 } 143 if (cropView.getVisibility() == View.VISIBLE) { 144 cropView.setOnCropChangeListener(null); 145 cropView.setVisibility(View.INVISIBLE); 146 } 147 photoView.clipPhoto(null); 148 // Notify the listener that this action is done finishing. 149 listener.onDone(); 150 listener = null; 151 lastOutputCallback = null; 152 pushedFilter = false; 153 } 154 155 /** 156 * Called when the action is about to begin; subclasses should creates a specific filter and 157 * binds the filter to necessary UI controls here. 158 */ onBegin()159 protected abstract void onBegin(); 160 161 /** 162 * Called when the action is about to end; subclasses could do specific ending operations here. 163 */ onEnd()164 protected abstract void onEnd(); 165 166 /** 167 * Output callback for top filter changes. 168 */ 169 private class OutputCallback implements PhotoOutputCallback { 170 171 private boolean done; 172 private Runnable runnableOnDone; 173 174 @Override onReady(Photo photo)175 public void onReady(Photo photo) { 176 photoView.update(photo); 177 done = true; 178 179 if (runnableOnDone != null) { 180 runnableOnDone.run(); 181 } 182 } 183 } 184 } 185