App

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

ImagePresentationView.java
Go to the documentation of this file.
1 package mhr.appandroid.views.imagepresentationview;
2
3 import java.util.ArrayList;
4 import java.util.LinkedList;
5
6 import mhr.appandroid.R;
7 import mhr.appandroid.adapters.APDBitmap;
8 import mhr.appandroid.views.MaskView;
9 import mhr.appandroid.views.imagepresentationview.ImagePresentationEvent.EventType;
10 import mhr.appandroid.views.imagepresentationview.LayerView.OnLayerViewEventListener;
11 import mhr.appandroid.views.imagepresentationview.LayerView.SelectedState;
12 import mhr.appandroid.views.imagepresentationview.MasterMaskView.OnMasterMaskEventListener;
13 import mhr.appcore.image.ImageSelectedState;
14 import mhr.appcore.image.layers.LayerPDInfo;
15 import mhr.appcore.image.layers.LayerType;
16 import mhr.appcore.interfaces.PDImageDataPresentation;
17 import android.app.Activity;
18 import android.content.Context;
19 import android.content.res.Resources;
20 import android.graphics.Rect;
21 import android.util.AttributeSet;
22 import android.view.DragEvent;
23 import android.view.MenuItem;
24 import android.view.View;
25 import android.view.View.OnClickListener;
26 import android.view.View.OnDragListener;
27 import android.widget.Button;
28 import android.widget.FrameLayout;
29 import android.widget.LinearLayout;
30 import android.widget.PopupMenu;
31 import android.widget.SeekBar;
32 import android.widget.PopupMenu.OnMenuItemClickListener;
33 import android.widget.SeekBar.OnSeekBarChangeListener;
34 import android.widget.TextView;
35
36 public class ImagePresentationView extends FrameLayout implements OnDragListener, OnLayerViewEventListener, OnClickListener, OnSeekBarChangeListener, OnMasterMaskEventListener,
37 OnMenuItemClickListener {
38
39 //===================================================================================================================================================//
40 //===== PUBLIC ==============================================================================================================================//
41 //----- interface a třídy -------------------------------------------------------------------------------------------------------------------//
42 public interface OnImagePresentationEventListener {
43 public void onImagePresentationEvent(ImagePresentationEvent e);
44 }
45
46 //----- pole --------------------------------------------------------------------------------------------------------------------------------//
47 //----- acesory a primitivní metody ---------------------------------------------------------------------------------------------------------//
48 public Rect getLayerPreviewRect() {
49 return new Rect(layerPreviewRect);
50 }
51
52 public Rect getMaskPreviewRect() {
53 return new Rect(maskPreviewRect);
54 }
55
56 public void setImagePresentation(PDImageDataPresentation img) {
57 this.img = img;
58 recreateFromPresentation();
59 }
60
61 public void setOnLayerEventListener(OnImagePresentationEventListener listener) {
62 this.listener = listener;
63 }
64
65 //----- konstruktory ------------------------------------------------------------------------------------------------------------------------//
66 public ImagePresentationView(Context context) {
67 super(context);
68 init();
69 }
70
71 public ImagePresentationView(Context context, AttributeSet attrs) {
72 super(context, attrs);
73 init();
74 }
75
76 public ImagePresentationView(Context context, AttributeSet attrs, int defStyle) {
77 super(context, attrs, defStyle);
78 init();
79 }
80
81 //----- destruktory -------------------------------------------------------------------------------------------------------------------------//
82 //----- metody ------------------------------------------------------------------------------------------------------------------------------//
83
84 // Předpokládá, že během vytváření požadavku se již View připravil, že není nutné provádět žádné změny...
85 // Vzhledem k přidávání na začátek seznamu není optimální, ale k přidávání a odebírání by již teoreticky ani nemělo dojít, je zde pro výjimečné případy
86 public void updateFromPresentation() {
87 if (img == null) {
88 return;
89 }
90 if (selected != null) {
91 selected.setState(SelectedState.SELECTED_NONE);
92 }
93 selected = null;
94 layerOpacitySB.setEnabled(false);
95 synchronized (img) {
96 ArrayList<LayerPDInfo> layers = img.getLayers();
97 int avViewsCount = layersContainer.getChildCount();
98 int reqViewsCount = layers.size();
99 int deltaViews = avViewsCount - reqViewsCount;
100 if (deltaViews > 0) {
101 for (int i = 0; i < deltaViews; i++) {
102 layersContainer.removeViewAt(0); // Odeberu na začátku, tedy ty zobrazené nahoře
103 }
104 } else {
105 deltaViews = -deltaViews;
106 for (int i = 0; i < deltaViews; i++) {
107 LayerView v = new LayerView(getContext());
108 v.setLayerViewEventListener(this);
109 layersContainer.addView(v, 0); // Přidávám na začátek, tedy zobrazené nahoře
110 }
111 }
112 int inversion = layersContainer.getChildCount() - 1;
113 for (int i = 0; i < reqViewsCount; i++) {
114 LayerPDInfo inf = layers.get(i);
115 // LV se samo stará, jesltli se potřebuje změnit... dle id, a isChanged
116 // Beru od zadu, tedy předpokládám, že první inf je poslední v layersContaineru
117 LayerView lv = (LayerView) layersContainer.getChildAt(inversion - i);
118 if (inf.id == img.selectedLayerId) {
119 selected = lv;
120 lv.setState(getLayerStateFromImageState(img.selectedState));
121 layerOpacitySB.setEnabled(true);
122 layerOpacitySB.setProgress((int) (inf.opacity * 100 + 0.5));
123 }
124 lv.presentLayer(inf);
125 }
126 if (img.selectedState == ImageSelectedState.SELECTED_MASTER_MASK) {
127 selected = null;
128 masterMaskV.setState(true, img.masterMaskActive);
129 } else {
130 masterMaskV.setState(false, img.masterMaskActive);
131 }
132 APDBitmap mmsk = (APDBitmap) img.masterMask;
133 if (mmsk != null) {
134 masterMaskV.setMaskPreview(mmsk.getBitmap());
135 }
136 }
137 }
138
139 //===================================================================================================================================================//
140 //===== NON-PUBLIC ==========================================================================================================================//
141 //----- interface a třídy -------------------------------------------------------------------------------------------------------------------//
142 //----- pole --------------------------------------------------------------------------------------------------------------------------------//
143 protected LinearLayout layersContainer;
144 protected Button createLayerBtn;
145 protected Button mergeLayersBtn;
146 protected PDImageDataPresentation img;
147 protected Rect layerPreviewRect;
148 protected Rect maskPreviewRect;
149 protected int dragOrigIndex;
150
151 protected MasterMaskView masterMaskV;
152
153 protected TextView layerOpacityTV;
154 protected SeekBar layerOpacitySB;
155
156 protected LayerView selected;
157 protected OnImagePresentationEventListener listener = null;
158
159 protected PopupMenu popup;
160
161 //----- acesory a primitivní metody ---------------------------------------------------------------------------------------------------------//
162 //----- konstruktory ------------------------------------------------------------------------------------------------------------------------//
163 protected void init() {
164 try {
165 ((Activity) getContext()).getLayoutInflater().inflate(R.layout.view_image_presentation, this, true);
166 } catch (ClassCastException exc) {
167 // Tento kod probehne, pokud je poroblem s pretypovanim, napriklad pro nahled v Eclipse
168 TextView tv = new TextView(getContext());
169 tv.setText("Prewiew not available, requires Activity to be Context.");
170 addView(tv);
171 return;
172 }
173 layersContainer = (LinearLayout) findViewById(R.id.LayersContainerLL);
174 createLayerBtn = (Button) findViewById(R.id.ImageLayersViewCreateLayerBtn);
175 mergeLayersBtn = (Button) findViewById(R.id.ImageLayersViewMergeLayersBtn);
176
177 layerOpacitySB = (SeekBar) findViewById(R.id.LayerOpacityValueSB);
178 layerOpacityTV = (TextView) findViewById(R.id.LayerOpacityValueTV);
179
180 masterMaskV = (MasterMaskView) findViewById(R.id.ImagePresentationMasterMaskView);
181 masterMaskV.setMasterMaskEventListener(this);
182
183 layerOpacitySB.setOnSeekBarChangeListener(this);
184
185 layersContainer.setOnDragListener(this);
186 createLayerBtn.setOnClickListener(this);
187 mergeLayersBtn.setOnClickListener(this);
188
189 Resources r = getResources();
190
191 int size = r.getDimensionPixelSize(R.dimen.LayerThumbSize) - 2 * r.getDimensionPixelSize(R.dimen.LayerThumbPadding);
192
193 layerPreviewRect = new Rect(0, 0, size, size);
194 maskPreviewRect = layerPreviewRect;
195
196 popup = new PopupMenu(getContext(), createLayerBtn);
197 popup.inflate(R.menu.view_image_structure);
198 popup.setOnMenuItemClickListener(this);
199 }
200
201 //----- destruktory -------------------------------------------------------------------------------------------------------------------------//
202 //----- metody ------------------------------------------------------------------------------------------------------------------------------//
203
204 protected void createLayer(LayerType type) {
205 int overId = -1;
206 int atPos = 0;
207 if (selected != null) {
208 atPos = layersContainer.indexOfChild(selected);
209 overId = selected.layerId;
210 }
211 LayerView lv = new LayerView(getContext());
212 lv.setLayerViewEventListener(this);
213 layersContainer.addView(lv, atPos);
214 if (listener != null) {
215 listener.onImagePresentationEvent(new ImagePresentationEvent(EventType.LAYER_CREATED, overId, type));
216 }
217 }
218
219 protected LayerView.SelectedState getLayerStateFromImageState(ImageSelectedState state) {
220 switch (state) {
221 case SELECTED_LAYER:
222 return SelectedState.SELECTED_LAYER;
223 case SELECTED_MASK:
224 return SelectedState.SELECTED_MASK;
225 default:
226 return SelectedState.SELECTED_NONE;
227 }
228 }
229
230 protected void recreateFromPresentation() {
232 if (img == null) {
233 return;
234 }
235 selected = null;
236 layersContainer.removeAllViews();
237 layerOpacitySB.setEnabled(false);
238 synchronized (img) {
239 ArrayList<LayerPDInfo> layers = img.getLayers();
240 for (LayerPDInfo l : layers) {
241 LayerView v = new LayerView(getContext());
242 v.setLayerViewEventListener(this);
243 layersContainer.addView(v, 0);
244 v.presentLayer(l);
245 if (l.id == img.selectedLayerId) {
246 selected = v;
247 v.setState(getLayerStateFromImageState(img.selectedState));
248 layerOpacitySB.setEnabled(true);
249 layerOpacitySB.setProgress((int) (l.opacity * 100 + 0.5));
250 }
251 }
252 if (img.selectedState == ImageSelectedState.SELECTED_MASTER_MASK) {
253 selected = null;
254 masterMaskV.setState(true, img.masterMaskActive);
255 } else {
256 masterMaskV.setState(false, img.masterMaskActive);
257 }
258 APDBitmap mmsk = (APDBitmap) img.masterMask;
259 if (mmsk != null) {
260 masterMaskV.setMaskPreview(mmsk.getBitmap());
261 }
262 }
263 }
264
265 @Override
266 public boolean onDrag(View v, DragEvent event) {
267 int action = event.getAction();
268 switch (event.getAction()) {
269 case DragEvent.ACTION_DRAG_STARTED:
270 dragOrigIndex = layersContainer.indexOfChild((View) event.getLocalState());
271 break;
272 case DragEvent.ACTION_DRAG_LOCATION: {
273 View dragged = (View) event.getLocalState();
274 int oldIndex = layersContainer.indexOfChild(dragged);
275 int h = dragged.getHeight();
276 int posOld = oldIndex * h + h / 2;
277 int posNew = (int) event.getY();
278 int newIndex = oldIndex + (posNew - posOld) / h;
279 if (oldIndex != newIndex) {
280 layersContainer.removeViewAt(oldIndex);
281 layersContainer.addView(dragged, newIndex);
282 }
283
284 break;
285 }
286 case DragEvent.ACTION_DROP: {
287 View dragged = (View) event.getLocalState();
288 int oldIndex = layersContainer.indexOfChild(dragged);
289 int h = dragged.getHeight();
290 int posOld = oldIndex * h + h / 2;
291 int posNew = (int) event.getY();
292 int newIndex = oldIndex + (posNew - posOld) / h;
293 if (oldIndex != newIndex) {
294 layersContainer.removeViewAt(oldIndex);
295 layersContainer.addView(dragged, newIndex);
296 }
297 if (newIndex != dragOrigIndex) {
298 if (listener != null) {
299 int beforeId = (newIndex > 0) ? ((LayerView) layersContainer.getChildAt(newIndex - 1)).layerId : -1;
300 listener.onImagePresentationEvent(new ImagePresentationEvent(EventType.LAYER_MOVED, ((LayerView) dragged).layerId, beforeId));
301 }
302 }
303 dragOrigIndex = -1;
304 }
305 break;
306 case DragEvent.ACTION_DRAG_ENDED:
307 if (dragOrigIndex >= 0) {
308 View dragged = (View) event.getLocalState();
309 int index = layersContainer.indexOfChild(dragged);
310 if (index != dragOrigIndex) {
311 layersContainer.removeViewAt(index);
312 layersContainer.addView(dragged, dragOrigIndex);
313 }
314
315 }
316 break;
317 default:
318 break;
319 }
320 return true;
321 }
322
323 @Override
324 public void onLayerViewEvent(LayerView v, ImagePresentationEvent e) {
325 switch (e.type) {
326 case LAYER_DELETED:
327 layersContainer.removeView(v);
328 break;
329 case LAYER_DUPLICATED:
330 int pos = layersContainer.indexOfChild(v);
331 LayerView lv = new LayerView(getContext());
332 lv.setLayerViewEventListener(this);
333 layersContainer.addView(lv, pos);
334 break;
335 case LAYER_SELECTED:
336 case LAYER_MASK_SELECTED:
337 if (selected != null && selected != v) {
338 masterMaskV.setState(false, masterMaskV.isApplied());
339 selected.setState(SelectedState.SELECTED_NONE);
340 selected = v;
341 }
342 break;
343 default:
344 break;
345 }
346 if (listener != null) {
347 listener.onImagePresentationEvent(e);
348 }
349 }
350
351 @Override
352 public void onClick(View v) {
353 if (v == createLayerBtn) {
354 popup.show();
355 } else if (v == mergeLayersBtn) {
356 if (listener != null) {
357 listener.onImagePresentationEvent(new ImagePresentationEvent(EventType.IMAGE_MERGE_LAYERS, -1));
358 }
359 }
360
361 }
362
363 @Override
364 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
365 layerOpacityTV.setText(Integer.toString(progress));
366 }
367
368 @Override
369 public void onStartTrackingTouch(SeekBar seekBar) {
370 }
371
372 @Override
373 public void onStopTrackingTouch(SeekBar seekBar) {
374 if (listener != null) {
375 listener.onImagePresentationEvent(new ImagePresentationEvent(EventType.LAYER_OPACITY_CHANGED, selected.layerId, seekBar.getProgress() / 100.0));
376 }
377 }
378
379 @Override
380 public void onMasterMaskEvent(MasterMaskView v, ImagePresentationEvent e) {
381 switch (e.type) {
382 case MASTER_MASK_APPLIED_CHANGED:
383 break;
384 case MASTER_MASK_SELECTED:
385 if (selected != null) {
386 selected.setState(SelectedState.SELECTED_NONE);
387 selected = null;
388 }
389 break;
390 default:
391 break;
392 }
393 if (listener != null) {
394 listener.onImagePresentationEvent(e);
395 }
396 }
397
398 @Override
399 public boolean onMenuItemClick(MenuItem item) {
400 final int id = item.getItemId();
401 if (id == R.id.CreateRasterLayerPopUp) {
402 createLayer(LayerType.LAYER_RASTER);
403 } else if (id == R.id.CreateColorLayerPopUp) {
404 createLayer(LayerType.LAYER_COLOR);
405 } else if (id == R.id.BrightnessLUTLayerPopUp) {
406 createLayer(LayerType.LAYER_BRIGHTNESS);
407 } else if (id == R.id.ContrastLUTLayerPopUp) {
408 createLayer(LayerType.LAYER_CONTRAST);
409 } else if (id == R.id.GammaLUTLayerPopUp) {
410 createLayer(LayerType.LAYER_GAMMA);
411 } else if (id == R.id.CurvesLUTLayerPopUp) {
412 createLayer(LayerType.LAYER_CURVES);
413 } else if (id == R.id.GaussianBlurFilterLayerPopUp) {
414 createLayer(LayerType.LAYER_GAUSSIAN_BLUR);
415 } else if (id == R.id.LaplaceSharpenFilterLayerPopUp) {
416 createLayer(LayerType.LAYER_LAPLACE_SHARPEN);
417 } else if (id == R.id.GaussianSharpenFilterLayerPopUp) {
418 createLayer(LayerType.LAYER_GAUSSIAN_SHARPEN);
419 } else if (id == R.id.LaplacianOfGaussianSharpenFilterLayerPopUp) {
420 createLayer(LayerType.LAYER_LAPLACIAN_OF_GAUSSIAN_SHARPEN);
421 } else if (id == R.id.DifferenceOfGaussianSharpenFilterLayerPopUp) {
422 createLayer(LayerType.LAYER_DIFFERENCE_OF_GAUSSIAN_SHARPEN);
423 }
424
425 return true;
426 }
427 //===================================================================================================================================================//
428 //===== DEPRECATED ==========================================================================================================================//
429
430 }