changes, changes, changes

This commit is contained in:
serso
2011-10-13 01:46:44 +04:00
parent c2e15ee08c
commit 5b074bdf85
24 changed files with 375 additions and 192 deletions

View File

@@ -13,7 +13,8 @@ import android.util.Log;
import android.view.ContextMenu;
import android.widget.EditText;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.model.ParseException;
import org.solovyev.android.calculator.model.TextProcessor;
/**
* User: serso
@@ -24,10 +25,8 @@ public class CalculatorEditor extends EditText {
private boolean highlightText = true;
private final static int BASE_COLOUR = Color.WHITE;
private final static int BASE_COLOUR_RED_COMPONENT = Color.red(BASE_COLOUR);
private final static int BASE_COLOUR_GREEN_COMPONENT = Color.green(BASE_COLOUR);
private final static int BASE_COLOUR_BLUE_COMPONENT = Color.blue(BASE_COLOUR);
@NotNull
private final static TextProcessor textHighlighter = new TextHighlighter(Color.WHITE);
public CalculatorEditor(Context context) {
super(context);
@@ -54,9 +53,7 @@ public class CalculatorEditor extends EditText {
menu.removeItem(android.R.id.startSelectingText);
}
public void redraw() {
public synchronized void redraw() {
String text = getText().toString();
int selectionStart = getSelectionStart();
@@ -64,107 +61,24 @@ public class CalculatorEditor extends EditText {
if (highlightText) {
text = highlightText(text);
Log.d(this.getClass().getName(), text);
try {
text = textHighlighter.process(text);
} catch (ParseException e) {
Log.e(this.getClass().getName(), e.getMessage(), e);
}
Log.d(this.getClass().getName(), text);
super.setText(Html.fromHtml(text), BufferType.EDITABLE);
} else {
super.setText(text, BufferType.EDITABLE);
}
Log.d(this.getClass().getName(), getText().toString());
setSelection(selectionStart, selectionEnd);
}
private String highlightText(@NotNull final String text) {
final String result;
int maxNumberOfOpenGroupSymbols = 0;
int numberOfOpenGroupSymbols = 0;
final StringBuilder text1 = new StringBuilder();
for (int i = 0; i < text.length(); i++) {
final MathType.Result mathType = MathType.getType(text, i);
switch (mathType.getMathType()) {
case open_group_symbol:
numberOfOpenGroupSymbols++;
maxNumberOfOpenGroupSymbols = Math.max(maxNumberOfOpenGroupSymbols, numberOfOpenGroupSymbols);
text1.append(text.charAt(i));
break;
case close_group_symbol:
numberOfOpenGroupSymbols--;
text1.append(text.charAt(i));
break;
case function:
i = processHighlightedText(text1, i, mathType.getMatch(), "i");
break;
case constant:
i = processHighlightedText(text1, i, mathType.getMatch(), "b");
break;
default:
text1.append(text.charAt(i));
}
}
if (maxNumberOfOpenGroupSymbols > 0) {
final StringBuilder text2 = new StringBuilder();
processBracketGroup(text2, text1.toString(), 0, 0, maxNumberOfOpenGroupSymbols);
Log.d(CalculatorEditor.class.getName(), text2.toString());
result = text2.toString();
} else {
result = text1.toString();
}
return result;
}
private int processHighlightedText(@NotNull StringBuilder result, int i, @NotNull String functionName, @NotNull String tag) {
result.append("<").append(tag).append(">").append(functionName).append("</").append(tag).append(">");
return i + functionName.length() - 1;
}
private int processBracketGroup(@NotNull StringBuilder result, @NotNull String s, int i, int numberOfOpenings, int maxNumberOfGroups) {
result.append("<font color=\"").append(getColor(maxNumberOfGroups, numberOfOpenings)).append("\">");
for (; i < s.length(); i++) {
char ch = s.charAt(i);
if (MathType.openGroupSymbols.contains(ch)) {
result.append(ch);
result.append("</font>");
i = processBracketGroup(result, s, i + 1, numberOfOpenings + 1, maxNumberOfGroups);
result.append("<font color=\"").append(getColor(maxNumberOfGroups, numberOfOpenings)).append("\">");
if (i < s.length() && MathType.closeGroupSymbols.contains(s.charAt(i))) {
result.append(s.charAt(i));
}
} else if (MathType.closeGroupSymbols.contains(ch)) {
break;
} else {
result.append(ch);
}
}
result.append("</font>");
return i;
}
private String getColor(int numberOfOpenGroupSymbols, int numberOfOpenings) {
double c = 0.7;
int offset = ((int) (255 * c)) * numberOfOpenings / (numberOfOpenGroupSymbols + 1);
int result = Color.rgb(BASE_COLOUR_RED_COMPONENT - offset, BASE_COLOUR_GREEN_COMPONENT - offset, BASE_COLOUR_BLUE_COMPONENT - offset);
return "#" + Integer.toHexString(result).substring(2);
}
public boolean isHighlightText() {
return highlightText;
}

View File

@@ -39,6 +39,8 @@ public class CalculatorVarsActivity extends ListActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.vars);
adapter = new VarsArrayAdapter(this, R.layout.var, R.id.var_text, new ArrayList<Var>(CalculatorModel.instance.getVarsRegister().getVars()));
setListAdapter(adapter);
@@ -68,6 +70,12 @@ public class CalculatorVarsActivity extends ListActivity {
}
@SuppressWarnings({"UnusedDeclaration"})
public void addVarButtonClickHandler(@NotNull View v) {
createEditVariableDialog(null, null, null, null);
}
private void createEditVariableDialog(@Nullable final Var var, @Nullable final String name, @Nullable final String value, @Nullable final String description) {
if (var == null || !var.isSystem()) {

View File

@@ -107,7 +107,7 @@ public class CalculatorView implements CursorControl, HistoryControl<CalculatorH
@NotNull
private final MutableObject<Runnable> currentRunner = new MutableObject<Runnable>();
public void doTextOperation(@NotNull TextOperation operation) {
public synchronized void doTextOperation(@NotNull TextOperation operation) {
final String editorStateBefore = this.editor.getText().toString();
operation.doOperation(this.editor);

View File

@@ -0,0 +1,132 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import android.graphics.Color;
import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.model.ParseException;
import org.solovyev.android.calculator.model.TextProcessor;
/**
* User: serso
* Date: 10/12/11
* Time: 9:47 PM
*/
public class TextHighlighter implements TextProcessor {
private final int color;
private final int colorRed;
private final int colorGreen;
private final int colorBlue;
public TextHighlighter(int baseColor) {
this.color = baseColor;
this.colorRed = Color.red(baseColor);
this.colorGreen = Color.green(baseColor);
this.colorBlue = Color.blue(baseColor);
}
@NotNull
@Override
public String process(@NotNull String text) throws ParseException {
final String result;
int maxNumberOfOpenGroupSymbols = 0;
int numberOfOpenGroupSymbols = 0;
final StringBuilder text1 = new StringBuilder();
for (int i = 0; i < text.length(); i++) {
final MathType.Result mathType = MathType.getType(text, i);
switch (mathType.getMathType()) {
case open_group_symbol:
numberOfOpenGroupSymbols++;
maxNumberOfOpenGroupSymbols = Math.max(maxNumberOfOpenGroupSymbols, numberOfOpenGroupSymbols);
text1.append(text.charAt(i));
break;
case close_group_symbol:
numberOfOpenGroupSymbols--;
text1.append(text.charAt(i));
break;
case function:
i = processHighlightedText(text1, i, mathType.getMatch(), "i");
break;
case constant:
i = processHighlightedText(text1, i, mathType.getMatch(), "b");
break;
default:
text1.append(text.charAt(i));
}
}
if (maxNumberOfOpenGroupSymbols > 0) {
final StringBuilder text2 = new StringBuilder();
String s = text1.toString();
int i = processBracketGroup(text2, s, 0, 0, maxNumberOfOpenGroupSymbols);
for (; i < s.length(); i++) {
text2.append(s.charAt(i));
}
//Log.d(CalculatorEditor.class.getName(), text2.toString());
result = text2.toString();
} else {
result = text1.toString();
}
return result;
}
private int processHighlightedText(@NotNull StringBuilder result, int i, @NotNull String functionName, @NotNull String tag) {
result.append("<").append(tag).append(">").append(functionName).append("</").append(tag).append(">");
return i + functionName.length() - 1;
}
private int processBracketGroup(@NotNull StringBuilder result, @NotNull String s, int i, int numberOfOpenings, int maxNumberOfGroups) {
result.append("<font color=\"").append(getColor(maxNumberOfGroups, numberOfOpenings)).append("\">");
for (; i < s.length(); i++) {
char ch = s.charAt(i);
if (MathType.openGroupSymbols.contains(ch)) {
result.append(ch);
result.append("</font>");
i = processBracketGroup(result, s, i + 1, numberOfOpenings + 1, maxNumberOfGroups);
result.append("<font color=\"").append(getColor(maxNumberOfGroups, numberOfOpenings)).append("\">");
if (i < s.length() && MathType.closeGroupSymbols.contains(s.charAt(i))) {
result.append(s.charAt(i));
}
} else if (MathType.closeGroupSymbols.contains(ch)) {
break;
} else {
result.append(ch);
}
}
result.append("</font>");
return i;
}
private String getColor(int totalNumberOfOpenings, int numberOfOpenings) {
double c = 0.8;
int offset = ((int) (255 * c)) * numberOfOpenings / (totalNumberOfOpenings + 1);
// for tests:
// innt result = Color.rgb(BASE_COLOUR_RED_COMPONENT - offset, BASE_COLOUR_GREEN_COMPONENT - offset, BASE_COLOUR_BLUE_COMPONENT - offset);
int result = (0xFF << 24) | ((colorRed - offset) << 16) | ((colorGreen - offset) << 8) | (colorBlue - offset);
return "#" + Integer.toHexString(result).substring(2);
}
}

View File

@@ -37,6 +37,7 @@ public class Functions {
public final static String EXP = "exp";
public final static String SQRT_SIGN = "";
public final static String SQRT = "sqrt";
public final static String E = "E";
public final static String E_POWER = "10^";

View File

@@ -34,8 +34,11 @@ public enum MathType {
public static final String IMAGINARY_NUMBER_DEF = "sqrt(-1)";
public static final String PI = "π";
public static final String E = "e";
public final static String NAN = "NaN";
public final static String INFINITY = "";
public final static String INFINITY_DEF = "Infinity";
public static final List<String> constants = Arrays.asList(E, PI, IMAGINARY_NUMBER);
public static final List<String> constants = Arrays.asList(E, PI, IMAGINARY_NUMBER, NAN, INFINITY);
public static final List<String> digits = Arrays.asList("0", "1", "2", "3", "4", "5", "6", "7", "8", "9");

View File

@@ -22,7 +22,12 @@ class FromJsclTextProcessor implements TextProcessor {
@Override
public String process(@NotNull String result) throws ParseException {
try {
result = String.valueOf(round(result));
final Double roundedValue = round(result);
if ( roundedValue.isInfinite() ) {
result = MathType.INFINITY;
} else {
result = String.valueOf(roundedValue);
}
} catch (NumberFormatException e) {
if (result.contains(MathType.IMAGINARY_NUMBER_DEF)) {
try {

View File

@@ -144,7 +144,7 @@ class VarsRegisterImpl implements VarsRegister {
final Var.Builder builder;
final Integer varDescription;
if ( systemVarName.equals(MathType.E) ){
if (systemVarName.equals(MathType.E)) {
builder = new Var.Builder(systemVarName, Math.E);
varDescription = R.string.c_e_description;
} else if (systemVarName.equals(MathType.PI)) {
@@ -153,6 +153,12 @@ class VarsRegisterImpl implements VarsRegister {
} else if (systemVarName.equals(MathType.IMAGINARY_NUMBER)) {
builder = new Var.Builder(systemVarName, MathType.IMAGINARY_NUMBER_DEF);
varDescription = R.string.c_i_description;
} else if (systemVarName.equals(MathType.NAN)) {
builder = new Var.Builder(systemVarName, MathType.NAN);
varDescription = R.string.c_nan_description;
} else if (systemVarName.equals(MathType.INFINITY)) {
builder = new Var.Builder(systemVarName, MathType.INFINITY_DEF);
varDescription = R.string.c_infinity_description;
} else {
throw new IllegalArgumentException(systemVarName + " is not supported yet!");
}

View File

@@ -26,6 +26,7 @@ import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Button;
@@ -33,6 +34,7 @@ import org.jetbrains.annotations.NotNull;
import org.solovyev.android.calculator.R;
import org.solovyev.android.view.FontSizeAdjuster;
import org.solovyev.common.utils.Point2d;
import org.solovyev.common.utils.StringUtils;
/**
* NOTE: copied from com.android.calculator2.ColorButton
@@ -42,14 +44,15 @@ import org.solovyev.common.utils.Point2d;
* Button with click-animation effect.
*/
public class ColorButton extends Button {
int CLICK_FEEDBACK_COLOR;
static final int CLICK_FEEDBACK_INTERVAL = 10;
static final int CLICK_FEEDBACK_DURATION = 350;
private int CLICK_FEEDBACK_COLOR;
private static final int CLICK_FEEDBACK_INTERVAL = 10;
private static final int CLICK_FEEDBACK_DURATION = 350;
@NotNull
private Point2d textPosition;
private long mAnimStart;
private Paint mFeedbackPaint;
private long animationStart;
private Paint feedbackPaint;
public ColorButton(Context context, AttributeSet attrs) {
this(context, attrs, true);
@@ -66,12 +69,12 @@ public class ColorButton extends Button {
Resources res = getResources();
CLICK_FEEDBACK_COLOR = res.getColor(org.solovyev.android.calculator.R.color.magic_flame);
mFeedbackPaint = new Paint();
mFeedbackPaint.setStyle(Style.STROKE);
mFeedbackPaint.setStrokeWidth(2);
feedbackPaint = new Paint();
feedbackPaint.setStyle(Style.STROKE);
feedbackPaint.setStrokeWidth(2);
getPaint().setColor(res.getColor(R.color.button_text_color));
mAnimStart = -1;
animationStart = -1;
if (context instanceof FontSizeAdjuster) {
((FontSizeAdjuster) context).adjustFontSize(this);
@@ -113,17 +116,17 @@ public class ColorButton extends Button {
int alpha = 255 - 255 * duration / CLICK_FEEDBACK_DURATION;
int color = CLICK_FEEDBACK_COLOR | (alpha << 24);
mFeedbackPaint.setColor(color);
canvas.drawRect(1, 1, getWidth() - 1, getHeight() - 1, mFeedbackPaint);
feedbackPaint.setColor(color);
canvas.drawRect(1, 1, getWidth() - 1, getHeight() - 1, feedbackPaint);
}
@Override
public void onDraw(Canvas canvas) {
if (mAnimStart != -1) {
int animDuration = (int) (System.currentTimeMillis() - mAnimStart);
if (animationStart != -1) {
int animDuration = (int) (System.currentTimeMillis() - animationStart);
if (animDuration >= CLICK_FEEDBACK_DURATION) {
mAnimStart = -1;
animationStart = -1;
} else {
drawMagicFlame(animDuration, canvas);
postInvalidateDelayed(CLICK_FEEDBACK_INTERVAL);
@@ -131,13 +134,48 @@ public class ColorButton extends Button {
}
CharSequence text = getText();
if (text != null && textPosition != null) {
if (!StringUtils.isEmpty(text) && textPosition != null) {
canvas.drawText(text, 0, text.length(), textPosition.getX(), textPosition.getY(), getPaint());
} else {
drawDrawables(canvas);
}
}
private void drawDrawables(Canvas canvas) {
final int compoundPaddingLeft = getCompoundPaddingLeft();
final int compoundPaddingTop = getCompoundPaddingTop();
final int compoundPaddingRight = getCompoundPaddingRight();
final int compoundPaddingBottom = getCompoundPaddingBottom();
final int scrollX = getScrollX();
final int scrollY = getScrollY();
final int right = getRight();
final int left = getLeft();
final int bottom = getBottom();
final int top = getTop();
final Drawable[] drawables = getCompoundDrawables();
if (drawables != null) {
int vspace = bottom - top - compoundPaddingBottom - compoundPaddingTop;
int hspace = right - left - compoundPaddingRight - compoundPaddingLeft;
Drawable topDr = drawables[1];
// IMPORTANT: The coordinates computed are also used in invalidateDrawable()
// Make sure to update invalidateDrawable() when changing this code.
if (topDr != null) {
canvas.save();
canvas.translate(scrollX + compoundPaddingLeft + (hspace - topDr.getBounds().width()) / 2,
scrollY + getPaddingTop() + vspace / 2);
topDr.draw(canvas);
canvas.restore();
}
}
}
public void animateClickFeedback() {
mAnimStart = System.currentTimeMillis();
animationStart = System.currentTimeMillis();
invalidate();
}

View File

@@ -126,11 +126,10 @@ public class DirectionDragButton extends DragButton {
basePaint.measureText(StringUtils.getNotEmpty(baseText, "|"));
float height = h - basePaint.ascent() - basePaint.descent();
if (direction < 0) {
result.setY(height / 2 + height / 3 + selfHeight);
result.setY(h / 2 + h / 3 - selfHeight / 2);
} else {
result.setY(height / 2 - height / 3);
result.setY(h / 2 - h / 3 - selfHeight / 2);
}
return result;
@@ -158,7 +157,7 @@ public class DirectionDragButton extends DragButton {
upDownTextPaint = new TextPaint(paint);
upDownTextPaint.setAlpha(150);
upDownTextPaint.setTextSize(paint.getTextSize() / 2);
upDownTextPaint.setTextSize(paint.getTextSize() / 3);
}
private String getStyledUpDownText(@Nullable String text) {

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2009-2011. Created by serso aka se.solovyev.
* For more information, please, contact se.solovyev@gmail.com
* or visit http://se.solovyev.org
*/
package org.solovyev.android.calculator;
import junit.framework.Assert;
import org.junit.Test;
import org.solovyev.android.calculator.model.TextProcessor;
import java.util.Date;
import java.util.Random;
/**
* User: serso
* Date: 10/12/11
* Time: 10:07 PM
*/
public class TextHighlighterTest {
@Test
public void testProcess() throws Exception {
final TextProcessor textHighlighter = new TextHighlighter(0);
final Random random = new Random(new Date().getTime());
for (int i = 0; i < 1000; i++) {
final StringBuilder sb = new StringBuilder();
for (int j = 0; j < 1000; j++) {
sb.append(random.nextBoolean() ? "(" : ")");
}
try {
textHighlighter.process(sb.toString());
} catch (Exception e) {
System.out.println(sb.toString());
throw e;
}
}
Assert.assertEquals("<font color=\"#000000\"></font>)(((())())", textHighlighter.process(")(((())())"));
Assert.assertEquals(")", textHighlighter.process(")"));
Assert.assertEquals(")()(", textHighlighter.process(")()("));
}
}