new plotter

This commit is contained in:
Sergey Solovyev 2013-01-19 18:12:44 +04:00
parent 4e6d49abf4
commit e321155585
10 changed files with 204 additions and 137 deletions

View File

@ -0,0 +1,31 @@
package org.solovyev.android.calculator;
import android.app.Activity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* User: serso
* Date: 1/19/13
* Time: 5:04 PM
*/
public final class Threads {
private Threads() {
throw new AssertionError();
}
public static void tryRunOnUiThread(@Nullable final Activity activity, @NotNull final Runnable runnable) {
if (activity != null && !activity.isFinishing()) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
// some time may pass and activity might be closing
if (!activity.isFinishing()) {
runnable.run();
}
}
});
}
}
}

View File

@ -6,7 +6,7 @@ import android.preference.PreferenceManager;
import jscl.math.Generic; import jscl.math.Generic;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.calculator.CalculatorPreferences; import org.solovyev.android.calculator.*;
import java.util.List; import java.util.List;
@ -158,6 +158,11 @@ public class AndroidCalculatorPlotter implements CalculatorPlotter, SharedPrefer
plotter.setPlotImag(plotImag); plotter.setPlotImag(plotImag);
} }
@Override
public void setPlotBoundaries(@NotNull PlotBoundaries plotBoundaries) {
plotter.setPlotBoundaries(plotBoundaries);
}
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (CalculatorPreferences.Graph.plotImag.getKey().equals(key)) { if (CalculatorPreferences.Graph.plotImag.getKey().equals(key)) {

View File

@ -12,7 +12,7 @@
c:textUp="≡" c:textUp="≡"
a:text="=" a:text="="
c:textDown="@string/cpp_plot_button_text" c:textDown="@string/cpp_plot_button_text"
c:directionTextScale="0.5" c:directionTextScale="0.5;0.5;0.33;0.5"
a:layout_width="fill_parent" a:layout_width="fill_parent"
a:layout_height="fill_parent" a:layout_height="fill_parent"
style="?cpp_control_button_style" style="?cpp_control_button_style"

View File

@ -6,24 +6,16 @@ import android.graphics.Bitmap;
import android.graphics.Paint; import android.graphics.Paint;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.os.Handler;
import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentActivity;
import android.view.View; import android.view.View;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem; import com.actionbarsherlock.view.MenuItem;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.solovyev.android.AndroidUtils2; import org.solovyev.android.AndroidUtils2;
import org.solovyev.android.calculator.CalculatorApplication; import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.CalculatorEventData;
import org.solovyev.android.calculator.CalculatorEventHolder;
import org.solovyev.android.calculator.CalculatorEventListener;
import org.solovyev.android.calculator.CalculatorEventType;
import org.solovyev.android.calculator.CalculatorFragment;
import org.solovyev.android.calculator.CalculatorUtils;
import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.R;
import org.solovyev.android.menu.AMenuItem; import org.solovyev.android.menu.AMenuItem;
import org.solovyev.android.menu.ActivityMenu; import org.solovyev.android.menu.ActivityMenu;
import org.solovyev.android.menu.IdentifiableMenuItem; import org.solovyev.android.menu.IdentifiableMenuItem;
@ -33,7 +25,6 @@ import org.solovyev.common.JPredicate;
import org.solovyev.common.msg.MessageType; import org.solovyev.common.msg.MessageType;
import java.io.File; import java.io.File;
import java.io.Serializable;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -59,12 +50,6 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
protected static final String TAG = "CalculatorPlotFragment"; protected static final String TAG = "CalculatorPlotFragment";
protected static final String PLOT_BOUNDARIES = "plot_boundaries";
private static final int DEFAULT_MIN_NUMBER = -10;
private static final int DEFAULT_MAX_NUMBER = 10;
/* /*
********************************************************************** **********************************************************************
* *
@ -75,16 +60,8 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
private int bgColor; private int bgColor;
// thread for applying UI changes
@NotNull @NotNull
private final Handler uiHandler = new Handler(); private PlotData plotData = new PlotData(Collections.<PlotFunction>emptyList(), false, PlotBoundaries.newDefaultInstance());
@NotNull
private PlotData plotData = new PlotData(Collections.<PlotFunction>emptyList(), false);
@NotNull
private PlotBoundaries initialPlotBoundaries;
@NotNull @NotNull
private ActivityMenu<Menu, MenuItem> fragmentMenu; private ActivityMenu<Menu, MenuItem> fragmentMenu;
@ -103,7 +80,7 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
@Override @Override
public void onCreate(Bundle in) { public void onCreate(@Nullable Bundle in) {
super.onCreate(in); super.onCreate(in);
if (isPaneFragment()) { if (isPaneFragment()) {
@ -112,42 +89,33 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
this.bgColor = getResources().getColor(android.R.color.transparent); this.bgColor = getResources().getColor(android.R.color.transparent);
} }
final PlotBoundaries savedPlotBoundaries;
if (in != null) {
savedPlotBoundaries = (PlotBoundaries) in.getSerializable(PLOT_BOUNDARIES);
} else {
savedPlotBoundaries = null;
}
if (savedPlotBoundaries != null) {
initialPlotBoundaries = savedPlotBoundaries;
} else {
initialPlotBoundaries = PlotBoundaries.newDefaultInstance();
}
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
@Override private void saveBoundaries(@NotNull PlotBoundaries boundaries) {
public void onSaveInstanceState(Bundle out) { Locator.getInstance().getPlotter().setPlotBoundaries(boundaries);
super.onSaveInstanceState(out);
final PlotBoundaries plotBoundaries = getPlotBoundaries();
if (plotBoundaries != null) {
out.putSerializable(PLOT_BOUNDARIES, plotBoundaries);
}
} }
@Nullable @Nullable
protected abstract PlotBoundaries getPlotBoundaries(); protected abstract PlotBoundaries getPlotBoundaries();
@Override
public void onPause() {
final PlotBoundaries plotBoundaries = getPlotBoundaries();
if (plotBoundaries != null) {
saveBoundaries(plotBoundaries);
}
super.onPause();
}
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
plotData = Locator.getInstance().getPlotter().getPlotData(); plotData = Locator.getInstance().getPlotter().getPlotData();
createChart(plotData, initialPlotBoundaries); createChart(plotData);
createGraphicalView(getView(), plotData, initialPlotBoundaries); createGraphicalView(getView(), plotData);
getSherlockActivity().invalidateOptionsMenu(); getSherlockActivity().invalidateOptionsMenu();
} }
@ -164,16 +132,17 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
private void onNewPlotData(@NotNull final PlotData plotData) { private void onNewPlotData(@NotNull final PlotData plotData) {
this.plotData = plotData; this.plotData = plotData;
getUiHandler().post(new Runnable() { final SherlockFragmentActivity activity = getSherlockActivity();
Threads.tryRunOnUiThread(activity, new Runnable() {
@Override @Override
public void run() { public void run() {
getSherlockActivity().invalidateOptionsMenu(); activity.invalidateOptionsMenu();
createChart(plotData, initialPlotBoundaries); createChart(plotData);
final View view = getView(); final View view = getView();
if (view != null) { if (view != null) {
createGraphicalView(view, plotData, initialPlotBoundaries); createGraphicalView(view, plotData);
} }
} }
}); });
@ -181,18 +150,9 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
protected abstract void onError(); protected abstract void onError();
protected abstract void createGraphicalView(@NotNull View view, @NotNull PlotData plotData, @NotNull PlotBoundaries plotBoundaries); protected abstract void createGraphicalView(@NotNull View view, @NotNull PlotData plotData);
protected abstract void createChart(@NotNull PlotData plotData, @NotNull PlotBoundaries plotBoundaries); protected abstract void createChart(@NotNull PlotData plotData);
protected double getMaxXValue(@Nullable PlotBoundaries plotBoundaries) {
return plotBoundaries == null ? DEFAULT_MAX_NUMBER : plotBoundaries.getXMax();
}
protected double getMinXValue(@Nullable PlotBoundaries plotBoundaries) {
return plotBoundaries == null ? DEFAULT_MIN_NUMBER : plotBoundaries.getXMin();
}
/* /*
********************************************************************** **********************************************************************
@ -202,11 +162,6 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
********************************************************************** **********************************************************************
*/ */
@NotNull
public Handler getUiHandler() {
return uiHandler;
}
public int getBgColor() { public int getBgColor() {
return bgColor; return bgColor;
} }
@ -380,65 +335,6 @@ public abstract class AbstractCalculatorPlotFragment extends CalculatorFragment
} }
} }
public static final class PlotBoundaries implements Serializable {
private double xMin;
private double xMax;
private double yMin;
private double yMax;
public PlotBoundaries() {
}
private PlotBoundaries(double xMin, double xMax, double yMin, double yMax) {
this.xMin = xMin;
this.xMax = xMax;
this.yMin = yMin;
this.yMax = yMax;
}
@NotNull
public static PlotBoundaries newInstance(double xMin, double xMax, double yMin, double yMax) {
return new PlotBoundaries(xMin, xMax, yMin, yMax);
}
public double getXMin() {
return xMin;
}
public double getXMax() {
return xMax;
}
public double getYMin() {
return yMin;
}
public double getYMax() {
return yMax;
}
@Override
public String toString() {
return "PlotBoundaries{" +
"yMax=" + yMax +
", yMin=" + yMin +
", xMax=" + xMax +
", xMin=" + xMin +
'}';
}
@NotNull
public static PlotBoundaries newDefaultInstance() {
PlotBoundaries plotBoundaries = new PlotBoundaries();
plotBoundaries.xMin = DEFAULT_MIN_NUMBER;
plotBoundaries.yMin = DEFAULT_MIN_NUMBER;
plotBoundaries.xMax = DEFAULT_MAX_NUMBER;
plotBoundaries.yMax = DEFAULT_MAX_NUMBER;
return plotBoundaries;
}
}
public static void applyToPaint(@NotNull PlotLineDef plotLineDef, @NotNull Paint paint) { public static void applyToPaint(@NotNull PlotLineDef plotLineDef, @NotNull Paint paint) {
paint.setColor(plotLineDef.getLineColor()); paint.setColor(plotLineDef.getLineColor());
paint.setStyle(Paint.Style.STROKE); paint.setStyle(Paint.Style.STROKE);

View File

@ -29,7 +29,7 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment {
} }
@Override @Override
protected void createGraphicalView(@NotNull View root, @NotNull PlotData plotData, @NotNull PlotBoundaries plotBoundaries) { protected void createGraphicalView(@NotNull View root, @NotNull PlotData plotData) {
// remove old // remove old
final ViewGroup graphContainer = (ViewGroup) root.findViewById(R.id.main_fragment_layout); final ViewGroup graphContainer = (ViewGroup) root.findViewById(R.id.main_fragment_layout);
@ -47,7 +47,7 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment {
// todo serso: investigate (after switching from 3d to 2d - blank screen) // todo serso: investigate (after switching from 3d to 2d - blank screen)
graphView.init(PlotViewDef.newInstance(Color.WHITE, Color.WHITE, Color.DKGRAY, getBgColor())); graphView.init(PlotViewDef.newInstance(Color.WHITE, Color.WHITE, Color.DKGRAY, getBgColor()));
//graphView.setXRange((float)plotBoundaries.getXMin(), (float)plotBoundaries.getXMax()); graphView.setXRange(plotData.getBoundaries().getXMin(), plotData.getBoundaries().getXMax());
graphView.setPlotFunctions(plotData.getFunctions()); graphView.setPlotFunctions(plotData.getFunctions());
if (graphView instanceof View) { if (graphView instanceof View) {
@ -56,7 +56,7 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment {
} }
@Override @Override
protected void createChart(@NotNull PlotData plotData, @NotNull PlotBoundaries plotBoundaries) { protected void createChart(@NotNull PlotData plotData) {
} }
@Override @Override
@ -97,10 +97,11 @@ public class CalculatorPlotFragment extends AbstractCalculatorPlotFragment {
@Override @Override
public void onPause() { public void onPause() {
super.onPause();
if (this.graphView != null) { if (this.graphView != null) {
this.graphView.onPause(); this.graphView.onPause();
} }
super.onPause();
} }
} }

View File

@ -160,6 +160,8 @@ public enum CalculatorEventType {
show_create_function_dialog, show_create_function_dialog,
plot_graph, plot_graph,
/** {@link org.solovyev.android.calculator.plot.PlotData} */
plot_data_changed, plot_data_changed,
//String //String

View File

@ -62,4 +62,6 @@ public interface CalculatorPlotter {
void removeAllUnpinned(); void removeAllUnpinned();
void setPlotImag(boolean plotImag); void setPlotImag(boolean plotImag);
void setPlotBoundaries(@NotNull PlotBoundaries plotBoundaries);
} }

View File

@ -35,6 +35,9 @@ public class CalculatorPlotterImpl implements CalculatorPlotter {
private int arity = 0; private int arity = 0;
@NotNull
private PlotBoundaries plotBoundaries = PlotBoundaries.newDefaultInstance();
public CalculatorPlotterImpl(@NotNull Calculator calculator) { public CalculatorPlotterImpl(@NotNull Calculator calculator) {
this.calculator = calculator; this.calculator = calculator;
} }
@ -42,7 +45,7 @@ public class CalculatorPlotterImpl implements CalculatorPlotter {
@NotNull @NotNull
@Override @Override
public PlotData getPlotData() { public PlotData getPlotData() {
return new PlotData(getVisibleFunctions(), plot3d); return new PlotData(getVisibleFunctions(), plot3d, plotBoundaries);
} }
@Override @Override
@ -298,6 +301,11 @@ public class CalculatorPlotterImpl implements CalculatorPlotter {
plot3d = false; plot3d = false;
} }
if ( functions.isEmpty() ) {
// no functions => new plot => default boundaries
this.plotBoundaries = PlotBoundaries.newDefaultInstance();
}
arity = maxArity; arity = maxArity;
firePlotDataChangedEvent(); firePlotDataChangedEvent();
@ -374,6 +382,14 @@ public class CalculatorPlotterImpl implements CalculatorPlotter {
} }
} }
@Override
public void setPlotBoundaries(@NotNull PlotBoundaries plotBoundaries) {
if ( !this.plotBoundaries.equals(plotBoundaries) ) {
this.plotBoundaries = plotBoundaries;
firePlotDataChangedEvent();
}
}
private boolean toggleImagFunctions(boolean show) { private boolean toggleImagFunctions(boolean show) {
boolean changed = false; boolean changed = false;

View File

@ -0,0 +1,103 @@
package org.solovyev.android.calculator.plot;
import org.jetbrains.annotations.NotNull;
import java.io.Serializable;
/**
* User: serso
* Date: 1/19/13
* Time: 4:51 PM
*/
public final class PlotBoundaries implements Serializable {
private static final float DEFAULT_MIN_NUMBER = -10f;
private static final float DEFAULT_MAX_NUMBER = 10f;
private float xMin;
private float xMax;
private float yMin;
private float yMax;
public PlotBoundaries() {
}
PlotBoundaries(float xMin, float xMax, float yMin, float yMax) {
this.xMin = xMin;
this.xMax = xMax;
this.yMin = yMin;
this.yMax = yMax;
}
@NotNull
public static PlotBoundaries newInstance(float xMin, float xMax, float yMin, float yMax) {
return new PlotBoundaries(xMin, xMax, yMin, yMax);
}
@NotNull
public static PlotBoundaries newInstance(float xMin, float xMax) {
return newInstance(xMin, xMax, DEFAULT_MIN_NUMBER, DEFAULT_MAX_NUMBER);
}
public float getXMin() {
return xMin;
}
public float getXMax() {
return xMax;
}
public float getYMin() {
return yMin;
}
public float getYMax() {
return yMax;
}
@Override
public String toString() {
return "PlotBoundaries{" +
"yMax=" + yMax +
", yMin=" + yMin +
", xMax=" + xMax +
", xMin=" + xMin +
'}';
}
@NotNull
public static PlotBoundaries newDefaultInstance() {
PlotBoundaries plotBoundaries = new PlotBoundaries();
plotBoundaries.xMin = DEFAULT_MIN_NUMBER;
plotBoundaries.yMin = DEFAULT_MIN_NUMBER;
plotBoundaries.xMax = DEFAULT_MAX_NUMBER;
plotBoundaries.yMax = DEFAULT_MAX_NUMBER;
return plotBoundaries;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PlotBoundaries)) return false;
PlotBoundaries that = (PlotBoundaries) o;
if (Float.compare(that.xMax, xMax) != 0) return false;
if (Float.compare(that.xMin, xMin) != 0) return false;
if (Float.compare(that.yMax, yMax) != 0) return false;
if (Float.compare(that.yMin, yMin) != 0) return false;
return true;
}
@Override
public int hashCode() {
int result = (xMin != +0.0f ? Float.floatToIntBits(xMin) : 0);
result = 31 * result + (xMax != +0.0f ? Float.floatToIntBits(xMax) : 0);
result = 31 * result + (yMin != +0.0f ? Float.floatToIntBits(yMin) : 0);
result = 31 * result + (yMax != +0.0f ? Float.floatToIntBits(yMax) : 0);
return result;
}
}

View File

@ -16,9 +16,15 @@ public class PlotData {
private boolean plot3d; private boolean plot3d;
public PlotData(@NotNull List<PlotFunction> functions, boolean plot3d) { @NotNull
private PlotBoundaries boundaries;
public PlotData(@NotNull List<PlotFunction> functions,
boolean plot3d,
@NotNull PlotBoundaries boundaries) {
this.functions = functions; this.functions = functions;
this.plot3d = plot3d; this.plot3d = plot3d;
this.boundaries = boundaries;
} }
@NotNull @NotNull
@ -29,4 +35,9 @@ public class PlotData {
public boolean isPlot3d() { public boolean isPlot3d() {
return plot3d; return plot3d;
} }
@NotNull
public PlotBoundaries getBoundaries() {
return boundaries;
}
} }