Android project initiated
This commit is contained in:
196
src/org/solovyev/android/calculator/Calculator.java
Normal file
196
src/org/solovyev/android/calculator/Calculator.java
Normal file
@@ -0,0 +1,196 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.R;
|
||||
import org.solovyev.android.view.DragButton;
|
||||
import org.solovyev.android.view.DragEvent;
|
||||
import org.solovyev.android.view.OnDragListener;
|
||||
import org.solovyev.android.view.SimpleOnDragListener;
|
||||
import org.solovyev.util.StringUtils;
|
||||
import org.solovyev.util.math.MathEntityType;
|
||||
|
||||
import bsh.EvalError;
|
||||
import bsh.Interpreter;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
|
||||
public class Calculator extends Activity {
|
||||
|
||||
@NotNull
|
||||
private EditText editText;
|
||||
|
||||
@NotNull
|
||||
private EditText resultEditText;
|
||||
|
||||
@NotNull
|
||||
private Interpreter interpreter;
|
||||
|
||||
@NotNull
|
||||
private HistoryHelper<EditorHistoryState> historyHelper;
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main);
|
||||
|
||||
this.editText = (EditText) findViewById(R.id.editText);
|
||||
|
||||
this.resultEditText = (EditText) findViewById(R.id.resultEditText);
|
||||
|
||||
final SimpleOnDragListener onDragListener = new SimpleOnDragListener();
|
||||
|
||||
// todo serso: check if there is more convenient method for doing this
|
||||
final R.id ids = new R.id();
|
||||
for (Field field : R.id.class.getDeclaredFields()) {
|
||||
int modifiers = field.getModifiers();
|
||||
if (Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers)) {
|
||||
try {
|
||||
final View view = findViewById(field.getInt(ids));
|
||||
if (view instanceof DragButton) {
|
||||
((DragButton) view).setOnDragListener(onDragListener);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(Calculator.class.getName(), e.getMessage());
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.e(Calculator.class.getName(), e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
((DragButton) findViewById(R.id.historyButton)).setOnDragListener(new HistoryOnDragListener());
|
||||
|
||||
this.interpreter = new Interpreter();
|
||||
|
||||
try {
|
||||
interpreter.eval(Preprocessor.wrap(JsclOperation.importCommands, "/jscl/editorengine/commands"));
|
||||
} catch (EvalError e) {
|
||||
Log.e(Calculator.class.getName(), e.getMessage());
|
||||
}
|
||||
|
||||
this.historyHelper = new SimpleHistoryHelper<EditorHistoryState>();
|
||||
this.historyHelper.addState(getCurrentHistoryState());
|
||||
}
|
||||
|
||||
public void elementaryButtonClickHandler(@NotNull View v) {
|
||||
eval(JsclOperation.elementary);
|
||||
}
|
||||
|
||||
public void numericButtonClickHandler(@NotNull View v) {
|
||||
eval(JsclOperation.numeric);
|
||||
}
|
||||
|
||||
public void simplifyButtonClickHandler(@NotNull View v) {
|
||||
eval(JsclOperation.simplify);
|
||||
}
|
||||
|
||||
private void eval(@NotNull JsclOperation operation) {
|
||||
try {
|
||||
final String preprocessedString = Preprocessor.process(String.valueOf(editText.getText()));
|
||||
resultEditText.setText(String.valueOf(interpreter.eval(Preprocessor.wrap(operation, preprocessedString))));
|
||||
} catch (EvalError e) {
|
||||
Log.e(Calculator.class.getName(), e.getMessage());
|
||||
resultEditText.setText(R.string.syntax_error);
|
||||
}
|
||||
}
|
||||
|
||||
public void digitButtonClickHandler(@NotNull View v) {
|
||||
processButtonAction(v, ((DragButton) v).getTextMiddle());
|
||||
}
|
||||
|
||||
private final class HistoryOnDragListener implements OnDragListener {
|
||||
@Override
|
||||
public void onDrag(@NotNull DragButton dragButton, @NotNull DragEvent event) {
|
||||
Log.d(String.valueOf(dragButton.getId()), "History on drag event start: " + event.getDirection());
|
||||
|
||||
String actionText = getActionText(dragButton, event);
|
||||
if (!StringUtils.isEmpty(actionText)) {
|
||||
try {
|
||||
final HistoryAction historyAction = HistoryAction.valueOf(actionText);
|
||||
if ( historyHelper.isActionAvailable(historyAction) ){
|
||||
final EditorHistoryState newState = historyHelper.doAction(historyAction, getCurrentHistoryState());
|
||||
if (newState != null) {
|
||||
setCurrentHistoryState(newState);
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(String.valueOf(dragButton.getId()), "Unsupported history action: " + actionText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getActionText(@NotNull DragButton dragButton, @NotNull DragEvent event) {
|
||||
final String result;
|
||||
|
||||
switch(event.getDirection()) {
|
||||
case up:
|
||||
result = dragButton.getTextUp();
|
||||
break;
|
||||
|
||||
case down:
|
||||
result = dragButton.getTextDown();
|
||||
break;
|
||||
|
||||
default:
|
||||
result = null;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setCurrentHistoryState(@Nullable EditorHistoryState editorHistoryState) {
|
||||
this.editText.setText(editorHistoryState.getText());
|
||||
this.editText.setSelection(editorHistoryState.getCursorPosition(), editorHistoryState.getCursorPosition());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public EditorHistoryState getCurrentHistoryState() {
|
||||
final EditorHistoryState result = new EditorHistoryState();
|
||||
|
||||
result.setText(String.valueOf(this.editText.getText()));
|
||||
result.setCursorPosition(this.editText.getSelectionStart());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void processButtonAction(@NotNull View v, @Nullable String text) {
|
||||
//Toast.makeText(Calculator.this, text, Toast.LENGTH_SHORT).show();
|
||||
|
||||
if (!StringUtils.isEmpty(text)) {
|
||||
final MathEntityType type = MathEntityType.getType(text);
|
||||
|
||||
int cursorPositionOffset = 0;
|
||||
|
||||
if (type != null) {
|
||||
switch (type) {
|
||||
case function:
|
||||
text += "()";
|
||||
cursorPositionOffset = -1;
|
||||
break;
|
||||
case group_symbols:
|
||||
cursorPositionOffset = -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.editText.getText().insert(this.editText.getSelectionStart(), text);
|
||||
this.editText.setSelection(this.editText.getSelectionStart() + cursorPositionOffset, this.editText.getSelectionEnd() + cursorPositionOffset);
|
||||
this.historyHelper.addState(getCurrentHistoryState());
|
||||
}
|
||||
}
|
||||
}
|
37
src/org/solovyev/android/calculator/EditorHistoryState.java
Normal file
37
src/org/solovyev/android/calculator/EditorHistoryState.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class EditorHistoryState {
|
||||
|
||||
private int cursorPosition;
|
||||
|
||||
@Nullable
|
||||
private String text;
|
||||
|
||||
public EditorHistoryState() {
|
||||
}
|
||||
|
||||
public EditorHistoryState( int cursorPosition, @Nullable String text ) {
|
||||
this.cursorPosition = cursorPosition;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public void setCursorPosition(int cursorPosition) {
|
||||
this.cursorPosition = cursorPosition;
|
||||
}
|
||||
|
||||
public int getCursorPosition() {
|
||||
return cursorPosition;
|
||||
}
|
||||
|
||||
|
||||
}
|
8
src/org/solovyev/android/calculator/HistoryAction.java
Normal file
8
src/org/solovyev/android/calculator/HistoryAction.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
public enum HistoryAction {
|
||||
|
||||
redo,
|
||||
undo;
|
||||
|
||||
}
|
24
src/org/solovyev/android/calculator/HistoryHelper.java
Normal file
24
src/org/solovyev/android/calculator/HistoryHelper.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface HistoryHelper<T> {
|
||||
|
||||
boolean isUndoAvailable();
|
||||
|
||||
@Nullable
|
||||
T undo (@Nullable T currentState);
|
||||
|
||||
boolean isRedoAvailable();
|
||||
|
||||
@Nullable
|
||||
T redo (@Nullable T currentState);
|
||||
|
||||
boolean isActionAvailable(@NotNull HistoryAction historyAction);
|
||||
|
||||
@Nullable
|
||||
T doAction(@NotNull HistoryAction historyAction, @Nullable T currentState);
|
||||
|
||||
void addState(@Nullable T currentState);
|
||||
}
|
10
src/org/solovyev/android/calculator/JsclOperation.java
Normal file
10
src/org/solovyev/android/calculator/JsclOperation.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
public enum JsclOperation {
|
||||
|
||||
simplify,
|
||||
elementary,
|
||||
importCommands,
|
||||
numeric;
|
||||
|
||||
}
|
31
src/org/solovyev/android/calculator/Preprocessor.java
Normal file
31
src/org/solovyev/android/calculator/Preprocessor.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class Preprocessor {
|
||||
|
||||
@NotNull
|
||||
public static String process(@NotNull String s) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char ch = s.charAt(i);
|
||||
|
||||
if (ch == '[' || ch == '{') {
|
||||
sb.append('(');
|
||||
} else if (ch == ']' || ch == '}') {
|
||||
sb.append(')');
|
||||
} else if ( ch == ',' ) {
|
||||
sb.append('.');
|
||||
} else {
|
||||
sb.append(ch);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String wrap (@NotNull JsclOperation operation, @NotNull String s) {
|
||||
return operation.name() + "(\"" + s + "\");";
|
||||
}
|
||||
}
|
91
src/org/solovyev/android/calculator/SimpleHistoryHelper.java
Normal file
91
src/org/solovyev/android/calculator/SimpleHistoryHelper.java
Normal file
@@ -0,0 +1,91 @@
|
||||
package org.solovyev.android.calculator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class SimpleHistoryHelper<T> implements HistoryHelper<T> {
|
||||
|
||||
private List<T> history = new ArrayList<T>();
|
||||
|
||||
private int currentStateIndex = -1;
|
||||
|
||||
@Override
|
||||
public T undo(@Nullable T currentState) {
|
||||
if ( !isUndoAvailable() ) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
currentStateIndex--;
|
||||
|
||||
return history.get(currentStateIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T redo(@Nullable T currentState) {
|
||||
if (!isRedoAvailable()) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
currentStateIndex++;
|
||||
return history.get(currentStateIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addState(@Nullable T currentState) {
|
||||
if (currentStateIndex == history.size() - 1) {
|
||||
currentStateIndex++;
|
||||
history.add(currentState);
|
||||
} else {
|
||||
assert currentStateIndex < history.size() - 1 : "Invalid history state index!";
|
||||
currentStateIndex++;
|
||||
history.set(currentStateIndex, currentState);
|
||||
while( history.size() > currentStateIndex + 1 ) {
|
||||
history.remove(history.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUndoAvailable() {
|
||||
return currentStateIndex > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRedoAvailable() {
|
||||
return currentStateIndex < history.size() - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActionAvailable(@NotNull HistoryAction historyAction) {
|
||||
boolean result = false;
|
||||
|
||||
switch (historyAction) {
|
||||
case undo:
|
||||
result = isUndoAvailable();
|
||||
break;
|
||||
case redo:
|
||||
result = isRedoAvailable();
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T doAction(@NotNull HistoryAction historyAction, @Nullable T currentState) {
|
||||
T result = null;
|
||||
|
||||
switch (historyAction) {
|
||||
case undo:
|
||||
result = undo(currentState);
|
||||
break;
|
||||
case redo:
|
||||
result = redo(currentState);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
168
src/org/solovyev/android/view/DragButton.java
Normal file
168
src/org/solovyev/android/view/DragButton.java
Normal file
@@ -0,0 +1,168 @@
|
||||
package org.solovyev.android.view;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.android.calculator.R;
|
||||
import org.solovyev.util.StringUtils;
|
||||
import org.solovyev.util.math.MathUtils;
|
||||
import org.solovyev.util.math.Point2d;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.text.Html;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
|
||||
public class DragButton extends Button {
|
||||
|
||||
// max time in ms to register drag event
|
||||
private long maxTime = 700;
|
||||
|
||||
@Nullable
|
||||
private Point2d startPoint = null;
|
||||
|
||||
@Nullable
|
||||
private OnDragListener onDragListener;
|
||||
|
||||
private final OnTouchListener onTouchListener = new OnTouchListenerImpl();
|
||||
|
||||
@Nullable
|
||||
private String textUp;
|
||||
|
||||
@Nullable
|
||||
private String textDown;
|
||||
|
||||
@Nullable
|
||||
private String textMiddle;
|
||||
|
||||
public DragButton(Context context, @NotNull AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
public DragButton(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
private void init(@NotNull Context context, @NotNull AttributeSet attrs) {
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DragButton);
|
||||
|
||||
final int N = a.getIndexCount();
|
||||
for (int i = 0; i < N; i++) {
|
||||
int attr = a.getIndex(i);
|
||||
switch (attr) {
|
||||
case R.styleable.DragButton_textUp:
|
||||
this.textUp = a.getString(attr);
|
||||
break;
|
||||
case R.styleable.DragButton_textDown:
|
||||
this.textDown = a.getString(attr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// backup text
|
||||
this.textMiddle = String.valueOf(getText());
|
||||
|
||||
setText(Html.fromHtml(getStyledUpDownText(this.textUp) + "<br><b>" + StringUtils.getNotEmpty(this.textMiddle, " ") + "</b><br>" + getStyledUpDownText(this.textDown)));
|
||||
|
||||
// change top padding in order to show all text
|
||||
setPadding(getPaddingLeft(), -7, getPaddingRight(), getPaddingBottom());
|
||||
|
||||
setOnTouchListener(this.onTouchListener);
|
||||
}
|
||||
|
||||
private String getStyledUpDownText(@Nullable String text) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("<font color='#585858'><small><small>");
|
||||
sb.append(StringUtils.getNotEmpty(text, " "));
|
||||
sb.append("</small></small></font>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void setOnDragListener(@Nullable OnDragListener onDragListener) {
|
||||
this.onDragListener = onDragListener;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public OnDragListener getOnDragListener() {
|
||||
return onDragListener;
|
||||
}
|
||||
|
||||
public void setTextUp(String textUp) {
|
||||
this.textUp = textUp;
|
||||
}
|
||||
|
||||
public String getTextUp() {
|
||||
return textUp;
|
||||
}
|
||||
|
||||
public void setTextDown(String textDown) {
|
||||
this.textDown = textDown;
|
||||
}
|
||||
|
||||
public String getTextDown() {
|
||||
return textDown;
|
||||
}
|
||||
|
||||
public void setTextMiddle(String textMiddle) {
|
||||
this.textMiddle = textMiddle;
|
||||
}
|
||||
|
||||
public String getTextMiddle() {
|
||||
return textMiddle;
|
||||
}
|
||||
|
||||
/**
|
||||
* OnTouchListener implementation that fires onDrag()
|
||||
*
|
||||
* @author serso
|
||||
*
|
||||
*/
|
||||
private final class OnTouchListenerImpl implements OnTouchListener {
|
||||
|
||||
@Override
|
||||
public boolean onTouch(@NotNull View v, @NotNull MotionEvent event) {
|
||||
// processing on touch event
|
||||
|
||||
if (onDragListener != null) {
|
||||
// only if onDrag() listener specified
|
||||
|
||||
Log.d(String.valueOf(getId()), "onTouch() for: " + getId() + " . Motion event: " + event);
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
// start tracking: set start point
|
||||
startPoint = new Point2d(event.getX(), event.getY());
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (event.getEventTime() - event.getDownTime() > maxTime) {
|
||||
// do not allow very long touch movements
|
||||
startPoint = null;
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
// stop tracking
|
||||
|
||||
if (onDragListener.onDrag(DragButton.this, new DragEvent(startPoint, event))) {
|
||||
if (onDragListener.isSuppressOnClickEvent()) {
|
||||
// prevent on click action
|
||||
setPressed(false);
|
||||
}
|
||||
}
|
||||
|
||||
startPoint = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
7
src/org/solovyev/android/view/DragDirection.java
Normal file
7
src/org/solovyev/android/view/DragDirection.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package org.solovyev.android.view;
|
||||
|
||||
public enum DragDirection {
|
||||
|
||||
up,
|
||||
down;
|
||||
}
|
33
src/org/solovyev/android/view/DragEvent.java
Normal file
33
src/org/solovyev/android/view/DragEvent.java
Normal file
@@ -0,0 +1,33 @@
|
||||
package org.solovyev.android.view;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.solovyev.util.math.Point2d;
|
||||
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class DragEvent {
|
||||
|
||||
@NotNull
|
||||
private final Point2d startPoint;
|
||||
|
||||
@NotNull
|
||||
private final MotionEvent motionEvent;
|
||||
|
||||
public DragEvent(@NotNull Point2d startPoint, @NotNull MotionEvent motionEvent) {
|
||||
this.startPoint = startPoint;
|
||||
this.motionEvent = motionEvent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public MotionEvent getMotionEvent() {
|
||||
return motionEvent;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Point2d getStartPoint() {
|
||||
return startPoint;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
22
src/org/solovyev/android/view/OnDragListener.java
Normal file
22
src/org/solovyev/android/view/OnDragListener.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package org.solovyev.android.view;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
public interface OnDragListener {
|
||||
|
||||
/**
|
||||
*
|
||||
* @return 'true': if drag event has taken place (i.e. onDrag() method returned true) then click action will be suppresed
|
||||
*/
|
||||
boolean isSuppressOnClickEvent();
|
||||
|
||||
/**
|
||||
* @param dragButton drag button object for which onDrag listener was set
|
||||
* @param event drag event
|
||||
*
|
||||
* @return 'true' if drag event occurred, 'false' otherwise
|
||||
*/
|
||||
boolean onDrag(@NotNull DragButton dragButton, @NotNull DragEvent event);
|
||||
|
||||
}
|
93
src/org/solovyev/android/view/SimpleOnDragListener.java
Normal file
93
src/org/solovyev/android/view/SimpleOnDragListener.java
Normal file
@@ -0,0 +1,93 @@
|
||||
package org.solovyev.android.view;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.solovyev.util.StringUtils;
|
||||
import org.solovyev.util.math.MathUtils;
|
||||
import org.solovyev.util.math.Point2d;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
public class SimpleOnDragListener implements OnDragListener {
|
||||
|
||||
@NotNull
|
||||
private final Point2d axis = new Point2d(0, 1);
|
||||
|
||||
private float minDragDist = 20f;
|
||||
|
||||
private float maxDragDist = 80f;
|
||||
|
||||
// max angle (in degrees!) between start and end point vector and axis
|
||||
// vector to register drag event
|
||||
private double maxAngle = 30;
|
||||
|
||||
@Override
|
||||
public boolean onDrag(@NotNull DragButton dragButton, @NotNull DragEvent event) {
|
||||
logDragEvent(dragButton, event);
|
||||
|
||||
processButtonAction(dragButton, getActionText(dragButton, event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuppressOnClickEvent() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method creates drag event in case if all conditions are satisfied
|
||||
*
|
||||
* @param event
|
||||
* motion event
|
||||
*
|
||||
* @return filled drag event object only if drag event is possible, null
|
||||
* otherwise
|
||||
*/
|
||||
@Nullable
|
||||
protected DragEvent getDragEvent(@NotNull MotionEvent event) {
|
||||
DragEvent result = null;
|
||||
|
||||
if (startPoint != null) {
|
||||
final Point2d endPoint = new Point2d(event.getX(), event.getY());
|
||||
float distance = MathUtils.getDistance(startPoint, endPoint);
|
||||
|
||||
if (minDragDist < distance && distance < maxDragDist) {
|
||||
double angle = Math.toDegrees(MathUtils.getAngle(startPoint, MathUtils.sum(startPoint, axis), endPoint));
|
||||
|
||||
final DragDirection direction;
|
||||
if (angle < maxAngle) {
|
||||
direction = DragDirection.down;
|
||||
} else if (180 - angle < maxAngle) {
|
||||
direction = DragDirection.up;
|
||||
} else {
|
||||
direction = null;
|
||||
}
|
||||
|
||||
if (direction != null) {
|
||||
if ( direction == DragDirection.up && StringUtils.isEmpty(textUp) ) {
|
||||
// no action if text is empty
|
||||
} else if (direction == DragDirection.down && StringUtils.isEmpty(textDown)) {
|
||||
// no action if text is empty
|
||||
} else {
|
||||
result = new DragEvent(direction);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void logDragEvent(@NotNull DragButton dragButton, @NotNull DragEvent event) {
|
||||
final Point2d startPoint = event.getStartPoint();
|
||||
final MotionEvent motionEvent = event.getMotionEvent();
|
||||
final Point2d endPoint = new Point2d(motionEvent.getX(), motionEvent.getY());
|
||||
|
||||
Log.d(String.valueOf(dragButton.getId()), "Start point: " + startPoint + ", End point: " + endPoint);
|
||||
Log.d(String.valueOf(dragButton.getId()), "Distance: " + MathUtils.getDistance(startPoint, endPoint));
|
||||
Log.d(String.valueOf(dragButton.getId()), "Angle: " + Math.toDegrees(MathUtils.getAngle(startPoint, MathUtils.sum(startPoint, axis), endPoint)));
|
||||
Log.d(String.valueOf(dragButton.getId()), "Axis: " + axis + " Vector: " + MathUtils.subtract(endPoint, startPoint));
|
||||
Log.d(String.valueOf(dragButton.getId()), "Total time: " + (motionEvent.getEventTime() - motionEvent.getDownTime()) + " ms");
|
||||
}
|
||||
}
|
17
src/org/solovyev/util/StringUtils.java
Normal file
17
src/org/solovyev/util/StringUtils.java
Normal file
@@ -0,0 +1,17 @@
|
||||
package org.solovyev.util;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class StringUtils {
|
||||
|
||||
public static boolean isEmpty ( @Nullable String s ){
|
||||
return s == null || s.length() == 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getNotEmpty ( @Nullable String s, @NotNull String defaultValue ){
|
||||
return isEmpty(s) ? defaultValue : s;
|
||||
}
|
||||
}
|
||||
|
11
src/org/solovyev/util/date/DateUtils.java
Normal file
11
src/org/solovyev/util/date/DateUtils.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package org.solovyev.util.date;
|
||||
|
||||
public class DateUtils {
|
||||
|
||||
public static long MS_IN_SECONDS = 1000l;
|
||||
|
||||
public static long msToSeconds (long ms) {
|
||||
return ms / 1000l;
|
||||
}
|
||||
|
||||
}
|
37
src/org/solovyev/util/math/MathEntity.java
Normal file
37
src/org/solovyev/util/math/MathEntity.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package org.solovyev.util.math;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public enum MathEntity {
|
||||
|
||||
minus("-"),
|
||||
equals("="),
|
||||
factorial("!"),
|
||||
plus("+"),
|
||||
multiply("*"),
|
||||
divide("/"),
|
||||
power("^"),
|
||||
sin("sin"),
|
||||
asin("asin"),
|
||||
cos("cos"),
|
||||
acos("acos"),
|
||||
tg("tg"),
|
||||
atg("atg"),
|
||||
exp("exp"),
|
||||
log("log"),
|
||||
ln("ln"),
|
||||
mod("mod"),
|
||||
sqrt("sqrt");
|
||||
|
||||
@NotNull
|
||||
private final String text;
|
||||
|
||||
private MathEntity (@NotNull String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
}
|
57
src/org/solovyev/util/math/MathEntityType.java
Normal file
57
src/org/solovyev/util/math/MathEntityType.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package org.solovyev.util.math;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public enum MathEntityType {
|
||||
|
||||
digit,
|
||||
function,
|
||||
unary_operation,
|
||||
binary_operation,
|
||||
group_symbols,
|
||||
group_symbol;
|
||||
|
||||
private static final List<Character> unaryOperations = Arrays.asList('-', '=', '!');
|
||||
|
||||
private static final List<Character> binaryOperations = Arrays.asList('-', '+', '*', '/', '^' );
|
||||
|
||||
private static final List<String> functions = Arrays.asList("sin", "asin", "cos", "acos", "tg", "atg", "exp", "log", "ln", "mod", "sqrt");
|
||||
|
||||
private static final List<String> groupSymbols = Arrays.asList("[]", "()", "{}");
|
||||
|
||||
private static final List<Character> singleGroupSymbols = Arrays.asList('[', ']', '(', ')', '{', '}');
|
||||
|
||||
@Nullable
|
||||
public static MathEntityType getType( @NotNull String s ) {
|
||||
MathEntityType result = null;
|
||||
|
||||
if ( s.length() == 1 ) {
|
||||
char ch = s.charAt(0);
|
||||
|
||||
if ( Character.isDigit(ch) ) {
|
||||
result = MathEntityType.digit;
|
||||
} else if ( unaryOperations.contains(ch) ) {
|
||||
result = MathEntityType.unary_operation;
|
||||
} else if ( binaryOperations.contains(ch) ) {
|
||||
result = MathEntityType.binary_operation;
|
||||
} else if ( singleGroupSymbols.contains(ch) ) {
|
||||
result = MathEntityType.group_symbol;
|
||||
}
|
||||
}
|
||||
|
||||
if ( result == null ) {
|
||||
if ( functions.contains(s) ) {
|
||||
result = MathEntityType.function;
|
||||
} else if ( groupSymbols.contains(s) ) {
|
||||
result = MathEntityType.group_symbols;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
39
src/org/solovyev/util/math/MathUtils.java
Normal file
39
src/org/solovyev/util/math/MathUtils.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package org.solovyev.util.math;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class MathUtils {
|
||||
|
||||
public static float getDistance(@NotNull Point2d startPoint,
|
||||
@NotNull Point2d endPoint) {
|
||||
return getNorm(subtract(endPoint, startPoint));
|
||||
}
|
||||
|
||||
public static Point2d subtract(@NotNull Point2d p1, @NotNull Point2d p2) {
|
||||
return new Point2d(p1.getX() - p2.getX(), p1.getY() - p2.getY());
|
||||
}
|
||||
|
||||
public static Point2d sum(@NotNull Point2d p1, @NotNull Point2d p2) {
|
||||
return new Point2d(p1.getX() + p2.getX(), p1.getY() + p2.getY());
|
||||
}
|
||||
|
||||
public static float getNorm(@NotNull Point2d point) {
|
||||
return (float) Math.pow(
|
||||
Math.pow(point.getX(), 2) + Math.pow(point.getY(), 2), 0.5);
|
||||
}
|
||||
|
||||
public static float getAngle(@NotNull Point2d startPoint,
|
||||
@NotNull Point2d axisEndPoint, @NotNull Point2d endPoint) {
|
||||
final Point2d axisVector = subtract(axisEndPoint, startPoint);
|
||||
final Point2d vector = subtract(endPoint, startPoint);
|
||||
|
||||
double a_2 = Math.pow(getDistance(vector, axisVector), 2);
|
||||
double b = getNorm(vector);
|
||||
double b_2 = Math.pow(b, 2);
|
||||
double c = getNorm(axisVector);
|
||||
double c_2 = Math.pow(c, 2);
|
||||
|
||||
return (float) Math.acos((-a_2 + b_2 + c_2) / (2 * b * c));
|
||||
}
|
||||
|
||||
}
|
37
src/org/solovyev/util/math/Point2d.java
Normal file
37
src/org/solovyev/util/math/Point2d.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package org.solovyev.util.math;
|
||||
|
||||
public class Point2d {
|
||||
|
||||
private float x = 0;
|
||||
|
||||
private float y = 0;
|
||||
|
||||
public Point2d() {
|
||||
}
|
||||
|
||||
public Point2d( float x, float y ) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(float x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(float y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Point2d [x=" + x + ", y=" + y + "]";
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user