App
PathPickerView.java
Go to the documentation of this file.
1 package mhr.appandroid.views.pathpicker;
2 
3 import mhr.appandroid.R;
4 import mhr.appandroid.adapters.APDBitmap;
5 import mhr.appandroid.views.MaskView;
6 import mhr.appandroid.views.MaskView.OnMaskCanvasChangedListener;
7 import mhr.appandroid.views.brushpicker.RoundBrushPickerView;
8 import mhr.appandroid.views.brushpicker.RoundBrushPickerView.RoundBrushPickerEvent;
9 import mhr.appandroid.views.brushpicker.RoundBrushPickerView.RoundBrushPickerViewEventListener;
10 import mhr.appcore.bitmap.Depth;
11 import mhr.appcore.bitmap.NBitmap;
12 import mhr.appcore.blending.Blender;
13 import mhr.appcore.generators.BrushGenerator;
14 import mhr.appcore.utils.Rect;
15 import android.app.Activity;
16 import android.content.Context;
17 import android.graphics.BitmapFactory;
18 import android.graphics.BitmapShader;
19 import android.graphics.Paint;
20 import android.graphics.Shader.TileMode;
21 import android.os.Bundle;
22 import android.os.Parcelable;
23 import android.util.AttributeSet;
24 import android.view.View;
25 import android.view.View.OnClickListener;
26 import android.widget.Button;
27 import android.widget.CheckBox;
28 import android.widget.CompoundButton;
29 import android.widget.FrameLayout;
30 import android.widget.SeekBar;
31 import android.widget.TextView;
32 import android.widget.CompoundButton.OnCheckedChangeListener;
33 import android.widget.SeekBar.OnSeekBarChangeListener;
34 
40 public class PathPickerView extends FrameLayout implements OnSeekBarChangeListener, OnMaskCanvasChangedListener, OnCheckedChangeListener, OnClickListener {
41 
42  //===== INTERFACES, CLASSES, ENUMS ==========================================================================================================//
43  //----- NON-PUBLIC --------------------------------------------------------------------------------------------------------------------------//
47  protected enum redrawScope {
48  REDRAW_NONE, REDRAW_JUST_OPACITY, REDRAW_ALL,
49  }
50 
51  //----- PUBLIC ------------------------------------------------------------------------------------------------------------------------------//
55  public static enum PathPickerEvent {
59  EVENT_LIVE_PREVIEW_STATE_CHANGED
60  }
61 
65  public static interface PathPickerViewEventListener {
72  }
73 
79  public static class PathParams {
80  public int opacity = 100;
81  public int flow = 100;
82  public int spacing = 50;
83 
84  public PathParams() {
85 
86  }
87 
88  public PathParams(int opacity, int flow, int spacing) {
89  this.opacity = opacity;
90  this.flow = flow;
91  this.spacing = spacing;
92  }
93 
94  public PathParams(PathParams other) {
95  opacity = other.opacity;
96  flow = other.flow;
97  spacing = other.spacing;
98  }
99  }
100 
101  //===== FIELDS ==============================================================================================================================//
102  //----- NON-PUBLIC --------------------------------------------------------------------------------------------------------------------------//
103  protected SeekBar opacitySB;
104  protected SeekBar flowSB;
105  protected SeekBar spacingSB;
106  protected CheckBox livePreviewChB;
107  protected Button selectBtn;
108  protected Button cancelBtn;
109 
111  protected TextView opacityTV;
112  protected TextView flowTV;
113  protected TextView spacingTV;
114 
115  protected boolean livePreviewOn;
116 
117  protected NBitmap previewCanvas = null;
118 
119  protected NBitmap brush = null;
120 
121  protected PathParams oldParams = new PathParams();
122  protected PathParams newParams = new PathParams();
123 
125 
126  //----- PUBLIC ------------------------------------------------------------------------------------------------------------------------------//
127 
128  //===== CONSTRUCTORS, DESTRUCTORS, RELATED METHODS ==========================================================================================//
129  //----- NON-PUBLIC --------------------------------------------------------------------------------------------------------------------------//
133  protected void init() {
134  try {
135  ((Activity) getContext()).getLayoutInflater().inflate(R.layout.view_path_picker, this, true);
136  } catch (ClassCastException exc) {
137  // Tento kod probehne, pokud je poroblem s pretypovanim, napriklad pro nahled v Eclipse
138  TextView tv = new TextView(getContext());
139  tv.setText("Prewiew not available, requires Activity to be Context.");
140  addView(tv);
141  return;
142  }
143 
144  // Nalezení potomků pro rychlý přístup
145  opacitySB = (SeekBar) findViewById(R.id.OpacityValueSB);
146  flowSB = (SeekBar) findViewById(R.id.FlowValueSB);
147  spacingSB = (SeekBar) findViewById(R.id.SpacingValueSB);
148  livePreviewChB = (CheckBox) findViewById(R.id.PathLivePreviewChckB);
149  opacityTV = (TextView) findViewById(R.id.OpacityValueTV);
150  flowTV = (TextView) findViewById(R.id.FlowValueTV);
151  spacingTV = (TextView) findViewById(R.id.SpacingValueTV);
152  previewMskV = (MaskView) findViewById(R.id.PathPreviewMskV);
153  selectBtn = (Button) findViewById(R.id.PathPickerSelectBtn);
154  cancelBtn = (Button) findViewById(R.id.PathPickerCancelBtn);
155 
156  // Inicializace stavu třídy
157  livePreviewOn = livePreviewChB.isChecked();
158 
159  // Nastavení vzhledu komponent
160  BitmapShader bsh = new BitmapShader(BitmapFactory.decodeResource(getResources(), R.drawable.checkboard), TileMode.REPEAT, TileMode.REPEAT);
161  previewMskV.getMaskViewBackground().setShader(bsh);
162 
163  // Nastavení sebe jako posluchačů příslušných událostí.
164  opacitySB.setOnSeekBarChangeListener(this);
165  flowSB.setOnSeekBarChangeListener(this);
166  spacingSB.setOnSeekBarChangeListener(this);
168  livePreviewChB.setOnCheckedChangeListener(this);
169  selectBtn.setOnClickListener(this);
170  cancelBtn.setOnClickListener(this);
171 
172  updateLabels();
173  updateSeekBars();
174 
176  }
177 
179  @Override
180  protected void onDetachedFromWindow() {
181  if (previewCanvas != null) {
183  previewCanvas = null;
184  }
185  if (brush != null) {
186  brush.dispose();
187  brush = null;
188  }
189  }
190 
191  //----- PUBLIC ------------------------------------------------------------------------------------------------------------------------------//
192  public PathPickerView(Context context) {
193  super(context);
194  init();
195  }
196 
197  public PathPickerView(Context context, AttributeSet attrs) {
198  super(context, attrs);
199  init();
200  }
201 
202  public PathPickerView(Context context, AttributeSet attrs, int defStyle) {
203  super(context, attrs, defStyle);
204  init();
205  }
206 
207  //===== METHODS =============================================================================================================================//
208  //----- NON-PUBLIC --------------------------------------------------------------------------------------------------------------------------//
209 
213  protected void updateSeekBars() {
214  opacitySB.setProgress(newParams.opacity);
215  flowSB.setProgress(newParams.flow);
216  spacingSB.setProgress((int) ((500.0 / 3.0) * Math.log10(newParams.spacing) + 0.5));
217  }
218 
222  protected void redrawPath(redrawScope scope) {
223  if (brush == null) {
224  return;
225  }
226  if (previewCanvas == null) {
228  return;
229  }
230  }
231  if (scope == redrawScope.REDRAW_NONE) {
232  return;
233  }
234 
235  previewMskV.getMaskViewForeground().setAlpha((int) (newParams.opacity * 255 / 100.0 + 0.5));
236 
237  if (scope == redrawScope.REDRAW_JUST_OPACITY) {
238  previewMskV.invalidate();
239  return;
240  }
241 
243 
244  int cw = previewCanvas.getWidth();
245  int tly = (previewCanvas.getHeight() - brush.getHeight()) / 2;
246  int bw = brush.getWidth();
247  int space = (int) (bw * newParams.spacing / 100.0 + 0.5);
248  if (space < 1) {
249  space = 1;
250  }
251  Rect brushRect = brush.getRect();
252  double flow = newParams.flow / 100.0;
253 
254  int iMax = cw - bw;
255  for (int i = 0; i <= iMax; i += space) {
256  Blender.addTo(previewCanvas, brush, brushRect, i, tly, flow);
257  }
258  previewMskV.invalidate();
259  }
260 
266  protected boolean initPreviewCanvas(MaskView view) {
267  if (previewCanvas != null) {
269  previewCanvas = null;
270  }
271  APDBitmap maskCanvas = view.getMaskCanvas();
272  if (maskCanvas == null) {
273  return false;
274  } else {
275  previewCanvas = new NBitmap(maskCanvas);
276  return true;
277  }
278  }
279 
283  protected redrawScope updateValues() {
285  int tmp;
286  tmp = newParams.opacity;
287  newParams.opacity = opacitySB.getProgress();
288  if (tmp != newParams.opacity) {
290  }
291 
292  tmp = newParams.flow;
293  newParams.flow = flowSB.getProgress();
294  if (tmp != newParams.flow) {
295  scope = redrawScope.REDRAW_ALL;
296  }
297 
298  tmp = newParams.spacing;
299  newParams.spacing = (int) (Math.pow(500, spacingSB.getProgress() / 500.0) + 0.5);
300  if (tmp != newParams.spacing) {
301  scope = redrawScope.REDRAW_ALL;
302  }
303  return scope;
304  }
305 
309  protected void updateLabels() {
310  opacityTV.setText(Integer.toString(newParams.opacity));
311  flowTV.setText(Integer.toString(newParams.flow));
312  spacingTV.setText(Integer.toString(newParams.spacing));
313  }
314 
318  protected void updateStateFromSeekbars(redrawScope forceParam) {
319  if (forceParam != null) {
320  updateValues();
321  redrawPath(forceParam);
322  updateLabels();
323  } else {
325  updateLabels();
326  }
327  }
328 
332  protected void updateStateFromParams() {
333  updateSeekBars();
335  updateLabels();
336  }
337 
338  //----- PUBLIC ------------------------------------------------------------------------------------------------------------------------------//
339 
344  public void setZoom(double zoom) {
345  previewMskV.setZoom(zoom);
346  }
347 
352  public double getZoom() {
353  return previewMskV.getZoom();
354  }
355 
360  public void setPathParams(PathParams params) {
361  newParams = new PathParams(params);
363  }
364 
370  return new PathParams(newParams);
371  }
372 
378  return new PathParams(newParams);
379  }
380 
385  public void setState(PathParams params) {
386  newParams = new PathParams(params);
387  oldParams = new PathParams(params);
389  }
390 
395  public void setBrush(NBitmap brush) {
396  if (this.brush != null) {
397  this.brush.dispose();
398  this.brush = null;
399  }
400  this.brush = new NBitmap(brush);
402  }
403 
408  public Paint getPreviewBackground() {
410  }
411 
416  public Paint getPreviewForeground() {
418  }
419 
424  public boolean isLivePreviewOn() {
425  return livePreviewOn;
426  }
427 
432  public void setLivePreviewOn(boolean val) {
433  livePreviewOn = val;
434  livePreviewChB.setChecked(val);
435  }
436 
442  listener = l;
443  }
444 
445  @Override
446  public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
447  if (fromUser) {
448  if (livePreviewOn) {
450  } else {
451  updateValues();
452  updateLabels();
453  }
454  if (listener != null) {
456  }
457  }
458  }
459 
460  @Override
461  public void onStartTrackingTouch(SeekBar seekBar) {
462  // Nepouzity callback
463  }
464 
465  @Override
466  public void onStopTrackingTouch(SeekBar seekBar) {
467  if (!livePreviewOn) {
468  if (seekBar == opacitySB) {
469  updateStateFromSeekbars(redrawScope.REDRAW_JUST_OPACITY); // Hypoteticky může zbytečně překreslit stejnou stoupu
470  } else {
472  }
473  if (listener != null) {
475  }
476  }
477  }
478 
479  @Override
480  public void onMaskCanvasChanged(MaskView v) {
483  }
484 
485  @Override
486  public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
487  livePreviewOn = isChecked;
488  if (listener != null) {
490  }
491  }
492 
493  @Override
494  public void onClick(View v) {
495  if (v == selectBtn) {
497  if (listener != null) {
499  }
500  } else if (v == cancelBtn) {
502  updateSeekBars();
504  if (listener != null) {
506  }
507  if (listener != null) {
509  }
510  }
511  }
512 
513 }