diff --git a/android-app/src/main/java/org/solovyev/android/calculator/AndroidNumeralBase.java b/android-app/src/main/java/org/solovyev/android/calculator/AndroidNumeralBase.java index 0677a7a0..bc030e35 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/AndroidNumeralBase.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/AndroidNumeralBase.java @@ -28,8 +28,8 @@ import jscl.NumeralBase; import javax.annotation.Nonnull; import org.solovyev.android.calculator.units.CalculatorNumeralBase; -import org.solovyev.android.view.drag.DirectionDragButton; -import org.solovyev.android.view.drag.DragDirection; +import org.solovyev.android.calculator.drag.DirectionDragButton; +import org.solovyev.android.calculator.drag.DragDirection; import java.util.ArrayList; import java.util.Arrays; diff --git a/android-app/src/main/java/org/solovyev/android/calculator/BaseUi.java b/android-app/src/main/java/org/solovyev/android/calculator/BaseUi.java index 5055b619..40bce812 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/BaseUi.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/BaseUi.java @@ -34,13 +34,13 @@ import android.view.MotionEvent; import android.view.View; import android.widget.TextView; import org.solovyev.android.Views; +import org.solovyev.android.calculator.drag.*; import org.solovyev.android.calculator.history.CalculatorHistoryState; +import org.solovyev.android.calculator.history.HistoryDragProcessor; import org.solovyev.android.calculator.view.AngleUnitsButton; +import org.solovyev.android.calculator.view.DragListenerVibrator; import org.solovyev.android.calculator.view.NumeralBasesButton; -import org.solovyev.android.calculator.view.OnDragListenerVibrator; import org.solovyev.android.calculator.view.ViewsCache; -import org.solovyev.android.history.HistoryDragProcessor; -import org.solovyev.android.view.drag.*; import org.solovyev.common.listeners.JListeners; import org.solovyev.common.listeners.Listeners; import org.solovyev.common.math.Point2d; @@ -123,20 +123,21 @@ public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChan dpclRegister.removeListeners(); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); - final SimpleOnDragListener.Preferences dragPreferences = SimpleOnDragListener.getPreferences(preferences, activity); + final SimpleDragListener.Preferences dragPreferences = SimpleDragListener.getPreferences(preferences, activity); final ViewsCache views = ViewsCache.forView(root); setOnDragListeners(views, dragPreferences, preferences); - final OnDragListener historyOnDragListener = new OnDragListenerVibrator(newOnDragListener(new HistoryDragProcessor(getCalculator()), dragPreferences), vibrator, preferences); + HistoryDragProcessor historyDragProcessor = new HistoryDragProcessor<>(getCalculator()); + final DragListener historyDragListener = new DragListenerVibrator(newOnDragListener(historyDragProcessor, dragPreferences), vibrator, preferences); final DragButton historyButton = getButton(views, R.id.cpp_button_history); if (historyButton != null) { - historyButton.setOnDragListener(historyOnDragListener); + historyButton.setOnDragListener(historyDragListener); } final DragButton subtractionButton = getButton(views, R.id.cpp_button_subtraction); if (subtractionButton != null) { - subtractionButton.setOnDragListener(new OnDragListenerVibrator(newOnDragListener(new SimpleOnDragListener.DragProcessor() { + subtractionButton.setOnDragListener(new DragListenerVibrator(newOnDragListener(new SimpleDragListener.DragProcessor() { @Override public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) { if (dragDirection == DragDirection.down) { @@ -148,46 +149,46 @@ public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChan }, dragPreferences), vibrator, preferences)); } - final OnDragListener toPositionOnDragListener = new OnDragListenerVibrator(new SimpleOnDragListener(new CursorDragProcessor(), dragPreferences), vibrator, preferences); + final DragListener toPositionDragListener = new DragListenerVibrator(new SimpleDragListener(new CursorDragProcessor(), dragPreferences), vibrator, preferences); final DragButton rightButton = getButton(views, R.id.cpp_button_right); if (rightButton != null) { - rightButton.setOnDragListener(toPositionOnDragListener); + rightButton.setOnDragListener(toPositionDragListener); } final DragButton leftButton = getButton(views, R.id.cpp_button_left); if (leftButton != null) { - leftButton.setOnDragListener(toPositionOnDragListener); + leftButton.setOnDragListener(toPositionDragListener); } final DragButton equalsButton = getButton(views, R.id.cpp_button_equals); if (equalsButton != null) { - equalsButton.setOnDragListener(new OnDragListenerVibrator(newOnDragListener(new EqualsDragProcessor(), dragPreferences), vibrator, preferences)); + equalsButton.setOnDragListener(new DragListenerVibrator(newOnDragListener(new EqualsDragProcessor(), dragPreferences), vibrator, preferences)); } angleUnitsButton = getButton(views, R.id.cpp_button_6); if (angleUnitsButton != null) { - angleUnitsButton.setOnDragListener(new OnDragListenerVibrator(newOnDragListener(new CalculatorButtons.AngleUnitsChanger(activity), dragPreferences), vibrator, preferences)); + angleUnitsButton.setOnDragListener(new DragListenerVibrator(newOnDragListener(new CalculatorButtons.AngleUnitsChanger(activity), dragPreferences), vibrator, preferences)); } clearButton = getButton(views, R.id.cpp_button_clear); if (clearButton != null) { - clearButton.setOnDragListener(new OnDragListenerVibrator(newOnDragListener(new CalculatorButtons.NumeralBasesChanger(activity), dragPreferences), vibrator, preferences)); + clearButton.setOnDragListener(new DragListenerVibrator(newOnDragListener(new CalculatorButtons.NumeralBasesChanger(activity), dragPreferences), vibrator, preferences)); } final DragButton varsButton = getButton(views, R.id.cpp_button_vars); if (varsButton != null) { - varsButton.setOnDragListener(new OnDragListenerVibrator(newOnDragListener(new CalculatorButtons.VarsDragProcessor(activity), dragPreferences), vibrator, preferences)); + varsButton.setOnDragListener(new DragListenerVibrator(newOnDragListener(new CalculatorButtons.VarsDragProcessor(activity), dragPreferences), vibrator, preferences)); } final DragButton functionsButton = getButton(views, R.id.cpp_button_functions); if (functionsButton != null) { - functionsButton.setOnDragListener(new OnDragListenerVibrator(newOnDragListener(new CalculatorButtons.FunctionsDragProcessor(activity), dragPreferences), vibrator, preferences)); + functionsButton.setOnDragListener(new DragListenerVibrator(newOnDragListener(new CalculatorButtons.FunctionsDragProcessor(activity), dragPreferences), vibrator, preferences)); } final DragButton roundBracketsButton = getButton(views, R.id.cpp_button_round_brackets); if (roundBracketsButton != null) { - roundBracketsButton.setOnDragListener(new OnDragListenerVibrator(newOnDragListener(new CalculatorButtons.RoundBracketsDragProcessor(), dragPreferences), vibrator, preferences)); + roundBracketsButton.setOnDragListener(new DragListenerVibrator(newOnDragListener(new CalculatorButtons.RoundBracketsDragProcessor(), dragPreferences), vibrator, preferences)); } if (layout == simple || layout == simple_mobile) { @@ -246,14 +247,14 @@ public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChan } - private void setOnDragListeners(@Nonnull ViewsCache views, @Nonnull SimpleOnDragListener.Preferences dragPreferences, @Nonnull SharedPreferences preferences) { - final OnDragListener onDragListener = new OnDragListenerVibrator(newOnDragListener(new DigitButtonDragProcessor(getKeyboard()), dragPreferences), vibrator, preferences); + private void setOnDragListeners(@Nonnull ViewsCache views, @Nonnull SimpleDragListener.Preferences dragPreferences, @Nonnull SharedPreferences preferences) { + final DragListener dragListener = new DragListenerVibrator(newOnDragListener(new DigitButtonDragProcessor(getKeyboard()), dragPreferences), vibrator, preferences); final List viewIds = getViewIds(); for (Integer viewId : viewIds) { final View view = views.findViewById(viewId); if (view instanceof DragButton) { - ((DragButton) view).setOnDragListener(onDragListener); + ((DragButton) view).setOnDragListener(dragListener); } } } @@ -286,9 +287,9 @@ public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChan } @Nonnull - private SimpleOnDragListener newOnDragListener(@Nonnull SimpleOnDragListener.DragProcessor dragProcessor, - @Nonnull SimpleOnDragListener.Preferences dragPreferences) { - final SimpleOnDragListener onDragListener = new SimpleOnDragListener(dragProcessor, dragPreferences); + private SimpleDragListener newOnDragListener(@Nonnull SimpleDragListener.DragProcessor dragProcessor, + @Nonnull SimpleDragListener.Preferences dragPreferences) { + final SimpleDragListener onDragListener = new SimpleDragListener(dragProcessor, dragPreferences); dpclRegister.addListener(onDragListener); return onDragListener; } @@ -296,7 +297,7 @@ public abstract class BaseUi implements SharedPreferences.OnSharedPreferenceChan @Override public void onSharedPreferenceChanged(SharedPreferences preferences, String key) { if (key.startsWith("org.solovyev.android.calculator.DragButtonCalibrationActivity")) { - final SimpleOnDragListener.Preferences dragPreferences = SimpleOnDragListener.getPreferences(preferences, CalculatorApplication.getInstance()); + final SimpleDragListener.Preferences dragPreferences = SimpleDragListener.getPreferences(preferences, CalculatorApplication.getInstance()); for (DragPreferencesChangeListener dragPreferencesChangeListener : dpclRegister.getListeners()) { dragPreferencesChangeListener.onDragPreferencesChange(dragPreferences); } diff --git a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorButtons.java b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorButtons.java index f6b1002e..1b8006b5 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/CalculatorButtons.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/CalculatorButtons.java @@ -37,13 +37,12 @@ import jscl.AngleUnit; import jscl.NumeralBase; import org.solovyev.android.Views; -import org.solovyev.android.calculator.R; import org.solovyev.android.calculator.model.AndroidCalculatorEngine; import org.solovyev.android.calculator.view.AngleUnitsButton; import org.solovyev.android.calculator.view.NumeralBasesButton; -import org.solovyev.android.view.drag.DragButton; -import org.solovyev.android.view.drag.DragDirection; -import org.solovyev.android.view.drag.SimpleOnDragListener; +import org.solovyev.android.calculator.drag.DragButton; +import org.solovyev.android.calculator.drag.DragDirection; +import org.solovyev.android.calculator.drag.SimpleDragListener; import org.solovyev.common.math.Point2d; import javax.annotation.Nonnull; @@ -118,7 +117,7 @@ public final class CalculatorButtons { ********************************************************************** */ - static class RoundBracketsDragProcessor implements SimpleOnDragListener.DragProcessor { + static class RoundBracketsDragProcessor implements SimpleDragListener.DragProcessor { @Override public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) { final boolean result; @@ -139,7 +138,7 @@ public final class CalculatorButtons { return Locator.getInstance().getKeyboard(); } - static class VarsDragProcessor implements SimpleOnDragListener.DragProcessor { + static class VarsDragProcessor implements SimpleDragListener.DragProcessor { @Nonnull private Context context; @@ -167,7 +166,7 @@ public final class CalculatorButtons { } } - static class AngleUnitsChanger implements SimpleOnDragListener.DragProcessor { + static class AngleUnitsChanger implements SimpleDragListener.DragProcessor { @Nonnull private final DigitButtonDragProcessor processor; @@ -216,7 +215,7 @@ public final class CalculatorButtons { } } - static class NumeralBasesChanger implements SimpleOnDragListener.DragProcessor { + static class NumeralBasesChanger implements SimpleDragListener.DragProcessor { @Nonnull private final Context context; @@ -257,7 +256,7 @@ public final class CalculatorButtons { } } - static class FunctionsDragProcessor implements SimpleOnDragListener.DragProcessor { + static class FunctionsDragProcessor implements SimpleDragListener.DragProcessor { @Nonnull private Context context; diff --git a/android-app/src/main/java/org/solovyev/android/calculator/CursorDragProcessor.java b/android-app/src/main/java/org/solovyev/android/calculator/CursorDragProcessor.java index a34fa768..4a6c6ea2 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/CursorDragProcessor.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/CursorDragProcessor.java @@ -23,10 +23,10 @@ package org.solovyev.android.calculator; import android.view.MotionEvent; -import org.solovyev.android.view.drag.DirectionDragButton; -import org.solovyev.android.view.drag.DragButton; -import org.solovyev.android.view.drag.DragDirection; -import org.solovyev.android.view.drag.SimpleOnDragListener; +import org.solovyev.android.calculator.drag.DirectionDragButton; +import org.solovyev.android.calculator.drag.DragButton; +import org.solovyev.android.calculator.drag.DragDirection; +import org.solovyev.android.calculator.drag.SimpleDragListener; import org.solovyev.common.math.Point2d; import javax.annotation.Nonnull; @@ -36,7 +36,7 @@ import javax.annotation.Nonnull; * Date: 9/16/11 * Time: 11:45 PM */ -public class CursorDragProcessor implements SimpleOnDragListener.DragProcessor { +public class CursorDragProcessor implements SimpleDragListener.DragProcessor { public CursorDragProcessor() { } diff --git a/android-app/src/main/java/org/solovyev/android/calculator/DigitButtonDragProcessor.java b/android-app/src/main/java/org/solovyev/android/calculator/DigitButtonDragProcessor.java index f8a124bf..cd37b398 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/DigitButtonDragProcessor.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/DigitButtonDragProcessor.java @@ -23,10 +23,10 @@ package org.solovyev.android.calculator; import android.view.MotionEvent; -import org.solovyev.android.view.drag.DirectionDragButton; -import org.solovyev.android.view.drag.DragButton; -import org.solovyev.android.view.drag.DragDirection; -import org.solovyev.android.view.drag.SimpleOnDragListener; +import org.solovyev.android.calculator.drag.DirectionDragButton; +import org.solovyev.android.calculator.drag.DragButton; +import org.solovyev.android.calculator.drag.DragDirection; +import org.solovyev.android.calculator.drag.SimpleDragListener; import org.solovyev.common.math.Point2d; import javax.annotation.Nonnull; @@ -36,7 +36,7 @@ import javax.annotation.Nonnull; * Date: 9/16/11 * Time: 11:48 PM */ -public class DigitButtonDragProcessor implements SimpleOnDragListener.DragProcessor { +public class DigitButtonDragProcessor implements SimpleDragListener.DragProcessor { @Nonnull private CalculatorKeyboard calculatorKeyboard; diff --git a/android-app/src/main/java/org/solovyev/android/calculator/EqualsDragProcessor.java b/android-app/src/main/java/org/solovyev/android/calculator/EqualsDragProcessor.java index 041be069..5c33d4e6 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/EqualsDragProcessor.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/EqualsDragProcessor.java @@ -26,10 +26,10 @@ import android.view.MotionEvent; import javax.annotation.Nonnull; -import org.solovyev.android.view.drag.DirectionDragButton; -import org.solovyev.android.view.drag.DragButton; -import org.solovyev.android.view.drag.DragDirection; -import org.solovyev.android.view.drag.SimpleOnDragListener; +import org.solovyev.android.calculator.drag.DirectionDragButton; +import org.solovyev.android.calculator.drag.DragButton; +import org.solovyev.android.calculator.drag.DragDirection; +import org.solovyev.android.calculator.drag.SimpleDragListener; import org.solovyev.common.math.Point2d; /** @@ -37,7 +37,7 @@ import org.solovyev.common.math.Point2d; * Date: 10/24/11 * Time: 9:52 PM */ -public class EqualsDragProcessor implements SimpleOnDragListener.DragProcessor { +public class EqualsDragProcessor implements SimpleDragListener.DragProcessor { public EqualsDragProcessor() { } diff --git a/android-app/src/main/java/org/solovyev/android/calculator/drag/DirectionDragButton.java b/android-app/src/main/java/org/solovyev/android/calculator/drag/DirectionDragButton.java new file mode 100644 index 00000000..5e0a5581 --- /dev/null +++ b/android-app/src/main/java/org/solovyev/android/calculator/drag/DirectionDragButton.java @@ -0,0 +1,411 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.android.calculator.drag; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.text.TextPaint; +import android.util.AttributeSet; +import org.solovyev.common.math.Point2d; +import org.solovyev.common.text.NumberParser; +import org.solovyev.common.text.StringCollections; +import org.solovyev.common.text.Strings; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class DirectionDragButton extends DragButton { + + @Nonnull + private final static Float DEFAULT_DIRECTION_TEXT_SCALE_FLOAT = 0.33f; + + @Nonnull + private final static Integer DEFAULT_DIRECTION_TEXT_ALPHA = 140; + + private final static int DEFAULT_DIRECTION_TEXT_COLOR = Color.WHITE; + + @Nonnull + private final static String DEFAULT_DIRECTION_TEXT_SCALE = "0.33;0.33;0.33;0.33"; + + protected static class DirectionTextData { + + @Nonnull + private final GuiDragDirection direction; + + @Nonnull + private String text; + + @Nonnull + private Point2d position; + + @Nonnull + private final TextPaint paint = new TextPaint(); + + @Nonnull + private Float scale = 0.5f; + + private boolean show = true; + + private DirectionTextData(@Nonnull GuiDragDirection direction, @Nonnull String text) { + this.direction = direction; + this.text = text; + } + + protected void init(@Nonnull Paint basePaint, + int color, + int alpha) { + paint.set(basePaint); + paint.setColor(color); + paint.setAlpha(alpha); + paint.setTextSize(basePaint.getTextSize() * scale); + } + + @Nonnull + public GuiDragDirection getDirection() { + return direction; + } + + @Nonnull + public String getText() { + return text; + } + + @Nonnull + public Point2d getPosition() { + return position; + } + + @Nonnull + public TextPaint getPaint() { + return paint; + } + + @Nonnull + public Float getScale() { + return scale; + } + + public boolean isShow() { + return show; + } + } + + protected static enum GuiDragDirection { + up(DragDirection.up, 0) { + @Override + public int getAttributeId() { + return org.solovyev.android.view.R.styleable.DirectionDragButton_textUp; + } + + @Nonnull + @Override + public Point2d getTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, int w, int h) { + return getUpDownTextPosition(paint, basePaint, text, baseText, 1, w, h); + } + }, + down(DragDirection.down, 2) { + @Override + public int getAttributeId() { + return org.solovyev.android.view.R.styleable.DirectionDragButton_textDown; + } + + @Nonnull + @Override + public Point2d getTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, int w, int h) { + return getUpDownTextPosition(paint, basePaint, text, baseText, -1, w, h); + } + }, + left(DragDirection.left, 3) { + @Override + public int getAttributeId() { + return org.solovyev.android.view.R.styleable.DirectionDragButton_textLeft; + } + + @Nonnull + @Override + public Point2d getTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, int w, int h) { + return getLeftRightTextPosition(paint, basePaint, text, baseText, w, h, true); + } + }, + + right(DragDirection.right, 1) { + @Override + public int getAttributeId() { + return org.solovyev.android.view.R.styleable.DirectionDragButton_textRight; + } + + @Nonnull + @Override + public Point2d getTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, int w, int h) { + return getLeftRightTextPosition(paint, basePaint, text, baseText, w, h, false); + } + }; + + @Nonnull + private final DragDirection dragDirection; + + private final int attributePosition; + + GuiDragDirection(@Nonnull DragDirection dragDirection, int attributePosition) { + this.dragDirection = dragDirection; + this.attributePosition = attributePosition; + } + + public abstract int getAttributeId(); + + public int getAttributePosition() { + return attributePosition; + } + + @Nonnull + public abstract Point2d getTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, int w, int h); + + @Nonnull + private static Point2d getLeftRightTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, CharSequence text, @Nonnull CharSequence baseText, int w, int h, boolean left) { + final Point2d result = new Point2d(); + + if (left) { + float width = paint.measureText(" "); + result.setX(width); + } else { + float width = paint.measureText(text.toString() + " "); + result.setX(w - width); + } + + float selfHeight = paint.ascent() + paint.descent(); + + basePaint.measureText(Strings.getNotEmpty(baseText, "|")); + + result.setY(h / 2 - selfHeight / 2); + + return result; + } + + @Nonnull + private static Point2d getUpDownTextPosition(@Nonnull Paint paint, @Nonnull Paint basePaint, @Nonnull CharSequence text, CharSequence baseText, float direction, int w, int h) { + final Point2d result = new Point2d(); + + float width = paint.measureText(text.toString() + " "); + result.setX(w - width); + + float selfHeight = paint.ascent() + paint.descent(); + + basePaint.measureText(Strings.getNotEmpty(baseText, "|")); + + if (direction < 0) { + result.setY(h / 2 + h / 3 - selfHeight / 2); + } else { + result.setY(h / 2 - h / 3 - selfHeight / 2); + } + + return result; + } + + @Nullable + public static GuiDragDirection valueOf(@Nonnull DragDirection dragDirection) { + for (GuiDragDirection guiDragDirection : values()) { + if (guiDragDirection.dragDirection == dragDirection) { + return guiDragDirection; + } + } + return null; + } + } + + @Nonnull + private final Map textDataMap = new EnumMap(GuiDragDirection.class); + + @Nonnull + protected String directionTextScale = DEFAULT_DIRECTION_TEXT_SCALE; + + @Nonnull + protected Integer directionTextAlpha = DEFAULT_DIRECTION_TEXT_ALPHA; + + protected int directionTextColor = DEFAULT_DIRECTION_TEXT_COLOR; + + private boolean initialized = false; + + public DirectionDragButton(Context context, @Nonnull AttributeSet attrs) { + super(context, attrs); + init(context, attrs); + } + + private void init(@Nonnull Context context, @Nonnull AttributeSet attrs) { + + TypedArray a = context.obtainStyledAttributes(attrs, org.solovyev.android.view.R.styleable.DirectionDragButton); + + for (int i = 0; i < a.getIndexCount(); i++) { + int attr = a.getIndex(i); + + if (a.hasValue(attr)) { + if (attr == org.solovyev.android.view.R.styleable.DirectionDragButton_directionTextColor) { + this.directionTextColor = a.getColor(attr, DEFAULT_DIRECTION_TEXT_COLOR); + } else if (attr == org.solovyev.android.view.R.styleable.DirectionDragButton_directionTextScale) { + this.directionTextScale = a.getString(attr); + } else if (attr == org.solovyev.android.view.R.styleable.DirectionDragButton_directionTextAlpha) { + this.directionTextAlpha = a.getInt(attr, DEFAULT_DIRECTION_TEXT_ALPHA); + } else { + // try drag direction text + for (GuiDragDirection guiDragDirection : GuiDragDirection.values()) { + if (guiDragDirection.getAttributeId() == attr) { + this.textDataMap.put(guiDragDirection, new DirectionTextData(guiDragDirection, a.getString(attr))); + break; + } + } + } + } + } + + a.recycle(); + + for (Map.Entry entry : getDirectionTextScales().entrySet()) { + final DirectionTextData td = textDataMap.get(entry.getKey()); + if (td != null) { + td.scale = entry.getValue(); + } + } + + initialized = true; + } + + @Override + public void onSizeChanged(int w, int h, int oldW, int oldH) { + measureText(); + } + + @Override + protected void onTextChanged(CharSequence text, int start, int before, int after) { + measureText(); + } + + protected void measureText() { + if (initialized) { + final Paint basePaint = getPaint(); + for (DirectionTextData textData : textDataMap.values()) { + initDirectionTextPaint(basePaint, textData); + textData.position = textData.direction.getTextPosition(textData.paint, basePaint, textData.text, getText(), getWidth(), getHeight()); + } + } + } + + protected void initDirectionTextPaint(@Nonnull Paint basePaint, @Nonnull DirectionTextData textData) { + textData.init(basePaint, directionTextColor, directionTextAlpha); + } + + @Override + public void onDraw(Canvas canvas) { + super.onDraw(canvas); + + final TextPaint paint = getPaint(); + for (DirectionTextData td : textDataMap.values()) { + if (td.show) { + initDirectionTextPaint(paint, td); + final String text = td.text; + final Point2d position = td.position; + canvas.drawText(text, 0, text.length(), position.getX(), position.getY(), td.paint); + } + } + } + + @SuppressWarnings("UnusedDeclaration") + @Nullable + public String getTextUp() { + return getText(GuiDragDirection.up); + } + + @SuppressWarnings("UnusedDeclaration") + @Nullable + public String getTextDown() { + return getText(GuiDragDirection.down); + } + + @Nullable + public String getText(@Nonnull DragDirection direction) { + final GuiDragDirection guiDragDirection = GuiDragDirection.valueOf(direction); + return guiDragDirection == null ? null : getText(guiDragDirection); + } + + @SuppressWarnings("UnusedDeclaration") + public void showDirectionText(boolean show, @Nonnull DragDirection direction) { + final GuiDragDirection guiDragDirection = GuiDragDirection.valueOf(direction); + final DirectionTextData td = this.textDataMap.get(guiDragDirection); + if (td != null) { + td.show = show; + } + } + + @Nullable + private String getText(@Nonnull GuiDragDirection direction) { + DirectionTextData td = this.textDataMap.get(direction); + if (td == null) { + return null; + } else { + if (td.show) { + return td.text; + } else { + return null; + } + } + } + + + @Nonnull + public String getDirectionTextScale() { + return directionTextScale; + } + + @Nonnull + private Map getDirectionTextScales() { + final List scales = StringCollections.split(getDirectionTextScale(), ";", NumberParser.of(Float.class)); + + final Map result = new HashMap(); + for (GuiDragDirection direction : GuiDragDirection.values()) { + result.put(direction, DEFAULT_DIRECTION_TEXT_SCALE_FLOAT); + } + + if (scales.size() == 1) { + final Float scale = scales.get(0); + for (Map.Entry entry : result.entrySet()) { + entry.setValue(scale); + } + } else { + for (int i = 0; i < scales.size(); i++) { + for (GuiDragDirection direction : GuiDragDirection.values()) { + if (direction.getAttributePosition() == i) { + result.put(direction, scales.get(i)); + } + } + } + } + + return result; + } + +} diff --git a/android-app/src/main/java/org/solovyev/android/calculator/drag/DragButton.java b/android-app/src/main/java/org/solovyev/android/calculator/drag/DragButton.java new file mode 100644 index 00000000..b167ef5f --- /dev/null +++ b/android-app/src/main/java/org/solovyev/android/calculator/drag/DragButton.java @@ -0,0 +1,134 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.android.calculator.drag; + +import android.content.Context; +import android.graphics.Canvas; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.widget.Button; +import org.solovyev.android.view.AndroidViewUtils; +import org.solovyev.common.math.Point2d; +import org.solovyev.common.text.Strings; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class DragButton extends Button { + + @Nullable + private Point2d startPoint = null; + + @Nullable + private DragListener onDragListener; + + private boolean showText = true; + + @Nullable + private CharSequence textBackup; + + public DragButton(@Nonnull Context context, @Nonnull AttributeSet attrs) { + super(context, attrs); + } + + public void setOnDragListener(@Nullable DragListener onDragListener) { + this.onDragListener = onDragListener; + } + + @Override + public boolean onTouchEvent(@Nonnull MotionEvent event) { + boolean consumed = false; + + // in order to avoid possible NPEs + final Point2d localStartPoint = startPoint; + final DragListener localOnDragListener = onDragListener; + + if (localOnDragListener != 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_CANCEL: + case MotionEvent.ACTION_UP: + // stop tracking + + startPoint = null; + if (localStartPoint != null) { + consumed = localOnDragListener.onDrag(DragButton.this, new DragEvent(localStartPoint, event)); + if (consumed && localOnDragListener.isSuppressOnClickEvent()) { + final MotionEvent newEvent = MotionEvent.obtain(event); + newEvent.setAction(MotionEvent.ACTION_CANCEL); + super.onTouchEvent(newEvent); + newEvent.recycle(); + return true; + } + } + break; + } + } + + return super.onTouchEvent(event) || consumed; + } + + @Override + public boolean dispatchTouchEvent(@Nonnull MotionEvent event) { + return super.dispatchTouchEvent(event); + } + + @Override + protected void onDraw(Canvas canvas) { + CharSequence text = getText(); + if (!Strings.isEmpty(text)) { + super.onDraw(canvas); + } else { + if (!AndroidViewUtils.drawDrawables(canvas, this)) { + super.onDraw(canvas); + } + } + } + + + public boolean isShowText() { + return showText; + } + + public void setShowText(boolean showText) { + if (this.showText != showText) { + if (showText) { + setText(textBackup); + textBackup = null; + } else { + textBackup = this.getText(); + setText(null); + } + this.showText = showText; + } + } +} diff --git a/android-app/src/main/java/org/solovyev/android/calculator/drag/DragDirection.java b/android-app/src/main/java/org/solovyev/android/calculator/drag/DragDirection.java new file mode 100644 index 00000000..7a9d5dab --- /dev/null +++ b/android-app/src/main/java/org/solovyev/android/calculator/drag/DragDirection.java @@ -0,0 +1,31 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.android.calculator.drag; + +public enum DragDirection { + + up, + down, + left, + right; +} diff --git a/android-app/src/main/java/org/solovyev/android/calculator/drag/DragEvent.java b/android-app/src/main/java/org/solovyev/android/calculator/drag/DragEvent.java new file mode 100644 index 00000000..33254d6b --- /dev/null +++ b/android-app/src/main/java/org/solovyev/android/calculator/drag/DragEvent.java @@ -0,0 +1,60 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.android.calculator.drag; + +import android.view.MotionEvent; +import org.solovyev.common.math.Point2d; + +import javax.annotation.Nonnull; + +public class DragEvent { + + @Nonnull + private final Point2d startPoint; + + @Nonnull + private final MotionEvent motionEvent; + + public DragEvent(@Nonnull Point2d startPoint, @Nonnull MotionEvent motionEvent) { + this.startPoint = startPoint; + this.motionEvent = motionEvent; + } + + /** + * @return motion event started at start point + */ + @Nonnull + public MotionEvent getMotionEvent() { + return motionEvent; + } + + /** + * @return start point of dragging + */ + @Nonnull + public Point2d getStartPoint() { + return startPoint; + } + + +} diff --git a/android-app/src/main/java/org/solovyev/android/calculator/drag/DragListener.java b/android-app/src/main/java/org/solovyev/android/calculator/drag/DragListener.java new file mode 100644 index 00000000..5a8173ac --- /dev/null +++ b/android-app/src/main/java/org/solovyev/android/calculator/drag/DragListener.java @@ -0,0 +1,43 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.android.calculator.drag; + +import javax.annotation.Nonnull; +import java.util.EventListener; + + +public interface DragListener extends EventListener { + + /** + * @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(@Nonnull DragButton dragButton, @Nonnull DragEvent event); + +} diff --git a/android-app/src/main/java/org/solovyev/android/calculator/drag/DragListenerWrapper.java b/android-app/src/main/java/org/solovyev/android/calculator/drag/DragListenerWrapper.java new file mode 100644 index 00000000..e9ff4ee9 --- /dev/null +++ b/android-app/src/main/java/org/solovyev/android/calculator/drag/DragListenerWrapper.java @@ -0,0 +1,50 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.android.calculator.drag; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 10/26/11 + * Time: 10:37 PM + */ +public class DragListenerWrapper implements DragListener { + + @Nonnull + private final DragListener dragListener; + + public DragListenerWrapper(@Nonnull DragListener dragListener) { + this.dragListener = dragListener; + } + + @Override + public boolean isSuppressOnClickEvent() { + return this.dragListener.isSuppressOnClickEvent(); + } + + @Override + public boolean onDrag(@Nonnull DragButton dragButton, @Nonnull DragEvent event) { + return this.dragListener.onDrag(dragButton, event); + } +} diff --git a/android-app/src/main/java/org/solovyev/android/calculator/drag/DragPreferencesChangeListener.java b/android-app/src/main/java/org/solovyev/android/calculator/drag/DragPreferencesChangeListener.java new file mode 100644 index 00000000..7691b494 --- /dev/null +++ b/android-app/src/main/java/org/solovyev/android/calculator/drag/DragPreferencesChangeListener.java @@ -0,0 +1,36 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.android.calculator.drag; + +import javax.annotation.Nonnull; +import java.util.EventListener; + +/** + * User: serso + * Date: 9/18/11 + * Time: 8:48 PM + */ +public interface DragPreferencesChangeListener extends EventListener { + + void onDragPreferencesChange(@Nonnull SimpleDragListener.Preferences preferences); +} diff --git a/android-app/src/main/java/org/solovyev/android/calculator/drag/SimpleDragListener.java b/android-app/src/main/java/org/solovyev/android/calculator/drag/SimpleDragListener.java new file mode 100644 index 00000000..0c509b24 --- /dev/null +++ b/android-app/src/main/java/org/solovyev/android/calculator/drag/SimpleDragListener.java @@ -0,0 +1,295 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.android.calculator.drag; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Log; +import android.view.MotionEvent; +import org.solovyev.common.MutableObject; +import org.solovyev.common.interval.Interval; +import org.solovyev.common.interval.Intervals; +import org.solovyev.common.math.Maths; +import org.solovyev.common.math.Point2d; +import org.solovyev.common.text.Mapper; +import org.solovyev.common.text.NumberIntervalMapper; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + +public class SimpleDragListener implements DragListener, DragPreferencesChangeListener { + + @Nonnull + public static final Point2d axis = new Point2d(0, 1); + + @Nonnull + private DragProcessor dragProcessor; + + @Nonnull + private Preferences preferences; + + public SimpleDragListener(@Nonnull DragProcessor dragProcessor, @Nonnull Preferences preferences) { + this.dragProcessor = dragProcessor; + this.preferences = preferences; + } + + @Override + public boolean onDrag(@Nonnull DragButton dragButton, @Nonnull DragEvent event) { + boolean result = false; + + logDragEvent(dragButton, event); + + final Point2d startPoint = event.getStartPoint(); + final MotionEvent motionEvent = event.getMotionEvent(); + + // init end point + final Point2d endPoint = new Point2d(motionEvent.getX(), motionEvent.getY()); + + final float distance = Maths.getDistance(startPoint, endPoint); + + final MutableObject right = new MutableObject(); + final double angle = Math.toDegrees(Maths.getAngle(startPoint, Maths.sum(startPoint, axis), endPoint, right)); + Log.d(String.valueOf(dragButton.getId()), "Angle: " + angle); + Log.d(String.valueOf(dragButton.getId()), "Is right?: " + right.getObject()); + + final double duration = motionEvent.getEventTime() - motionEvent.getDownTime(); + + final Preference distancePreferences = preferences.getPreferencesMap().get(PreferenceType.distance); + final Preference anglePreferences = preferences.getPreferencesMap().get(PreferenceType.angle); + + DragDirection direction = null; + for (Map.Entry directionEntry : distancePreferences.getDirectionPreferences().entrySet()) { + + Log.d(String.valueOf(dragButton.getId()), "Drag direction: " + directionEntry.getKey()); + Log.d(String.valueOf(dragButton.getId()), "Trying direction interval: " + directionEntry.getValue().getInterval()); + + if (directionEntry.getValue().getInterval().contains(distance)) { + final DragPreference anglePreference = anglePreferences.getDirectionPreferences().get(directionEntry.getKey()); + + Log.d(String.valueOf(dragButton.getId()), "Trying angle interval: " + anglePreference.getInterval()); + + if (directionEntry.getKey() == DragDirection.left && right.getObject()) { + } else if (directionEntry.getKey() == DragDirection.right && !right.getObject()) { + } else { + if (anglePreference.getInterval().contains((float) angle)) { + direction = directionEntry.getKey(); + Log.d(String.valueOf(dragButton.getId()), "MATCH! Direction: " + direction); + break; + } + } + } + + } + + if (direction != null) { + final Preference durationPreferences = preferences.getPreferencesMap().get(PreferenceType.duration); + + final DragPreference durationDragPreferences = durationPreferences.getDirectionPreferences().get(direction); + + Log.d(String.valueOf(dragButton.getId()), "Trying time interval: " + durationDragPreferences.getInterval()); + if (durationDragPreferences.getInterval().contains((float) duration)) { + Log.d(String.valueOf(dragButton.getId()), "MATCH!"); + result = dragProcessor.processDragEvent(direction, dragButton, startPoint, motionEvent); + } + } + + return result; + } + + @Override + public boolean isSuppressOnClickEvent() { + return true; + } + + private void logDragEvent(@Nonnull DragButton dragButton, @Nonnull 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: " + Maths.getDistance(startPoint, endPoint)); + final MutableObject right = new MutableObject(); + Log.d(String.valueOf(dragButton.getId()), "Angle: " + Math.toDegrees(Maths.getAngle(startPoint, Maths.sum(startPoint, axis), endPoint, right))); + Log.d(String.valueOf(dragButton.getId()), "Is right angle? " + right); + Log.d(String.valueOf(dragButton.getId()), "Axis: " + axis + " Vector: " + Maths.subtract(endPoint, startPoint)); + Log.d(String.valueOf(dragButton.getId()), "Total time: " + (motionEvent.getEventTime() - motionEvent.getDownTime()) + " ms"); + } + + @Override + public void onDragPreferencesChange(@Nonnull Preferences preferences) { + this.preferences = preferences; + } + + public interface DragProcessor { + + boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent); + } + + // todo serso: currently we do not use direction + public static String getPreferenceId(@Nonnull PreferenceType preferenceType, @Nonnull DragDirection direction) { + return "org.solovyev.android.calculator.DragButtonCalibrationActivity" + "_" + preferenceType.name() /*+ "_" + direction.name()*/; + } + + @Nonnull + public static Preferences getDefaultPreferences(@Nonnull Context context) { + return getPreferences0(null, context); + } + + @Nonnull + public static Preferences getPreferences(@Nonnull final SharedPreferences preferences, @Nonnull Context context) { + return getPreferences0(preferences, context); + } + + @Nonnull + private static Preferences getPreferences0(@Nullable final SharedPreferences preferences, @Nonnull Context context) { + + final Mapper> mapper = NumberIntervalMapper.of(Float.class); + + final Preferences result = new Preferences(); + + for (PreferenceType preferenceType : PreferenceType.values()) { + for (DragDirection dragDirection : DragDirection.values()) { + + final String preferenceId = getPreferenceId(preferenceType, dragDirection); + + final String defaultValue; + switch (preferenceType) { + case angle: + defaultValue = context.getResources().getString(org.solovyev.android.view.R.string.p_drag_angle); + break; + case distance: + defaultValue = context.getResources().getString(org.solovyev.android.view.R.string.p_drag_distance); + break; + case duration: + defaultValue = context.getResources().getString(org.solovyev.android.view.R.string.p_drag_duration); + break; + default: + defaultValue = null; + Log.e(SimpleDragListener.class.getName(), "New preference type added: default preferences should be defined. Preference id: " + preferenceId); + } + + final String value = preferences == null ? defaultValue : preferences.getString(preferenceId, defaultValue); + + if (value != null) { + final Interval intervalPref = transformInterval(preferenceType, dragDirection, mapper.parseValue(value)); + + Log.d(SimpleDragListener.class.getName(), "Preference loaded for " + dragDirection + ". Id: " + preferenceId + ", value: " + intervalPref.toString()); + + final DragPreference directionPreference = new DragPreference(intervalPref); + + Preference preference = result.getPreferencesMap().get(preferenceType); + if (preference == null) { + preference = new Preference(); + result.getPreferencesMap().put(preferenceType, preference); + } + + preference.getDirectionPreferences().put(dragDirection, directionPreference); + } + } + } + + return result; + } + + @Nonnull + public static Interval transformInterval(@Nonnull PreferenceType preferenceType, + @Nonnull DragDirection dragDirection, + @Nonnull Interval interval) { + + if (preferenceType == PreferenceType.angle) { + final Float leftLimit = interval.getLeftLimit(); + final Float rightLimit = interval.getRightLimit(); + + if (leftLimit != null && rightLimit != null) { + final Float newLeftLimit; + final Float newRightLimit; + + if (dragDirection == DragDirection.up) { + newLeftLimit = 180f - rightLimit; + newRightLimit = 180f - leftLimit; + } else if (dragDirection == DragDirection.left) { + newLeftLimit = 90f - rightLimit; + newRightLimit = 90f + rightLimit; + } else if (dragDirection == DragDirection.right) { + newLeftLimit = 90f - rightLimit; + newRightLimit = 90f + rightLimit; + } else { + newLeftLimit = leftLimit; + newRightLimit = rightLimit; + } + + return Intervals.newClosedInterval(newLeftLimit, newRightLimit); + } + } + + return interval; + } + + + public static enum PreferenceType { + angle, + distance, + duration + } + + public static class DragPreference { + + @Nonnull + private Interval interval; + + + public DragPreference(@Nonnull Interval interval) { + this.interval = interval; + } + + @Nonnull + public Interval getInterval() { + return interval; + } + + } + + public static class Preference { + + @Nonnull + private Map directionPreferences = new HashMap(); + + + @Nonnull + public Map getDirectionPreferences() { + return directionPreferences; + } + + } + + public static class Preferences { + + private final Map preferencesMap = new HashMap<>(); + + public Map getPreferencesMap() { + return preferencesMap; + } + } +} \ No newline at end of file diff --git a/android-app/src/main/java/org/solovyev/android/calculator/history/HistoryDragProcessor.java b/android-app/src/main/java/org/solovyev/android/calculator/history/HistoryDragProcessor.java new file mode 100644 index 00000000..1817b3a8 --- /dev/null +++ b/android-app/src/main/java/org/solovyev/android/calculator/history/HistoryDragProcessor.java @@ -0,0 +1,72 @@ +/* + * Copyright 2013 serso aka se.solovyev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * Contact details + * + * Email: se.solovyev@gmail.com + * Site: http://se.solovyev.org + */ + +package org.solovyev.android.calculator.history; + +import android.util.Log; +import android.view.MotionEvent; +import org.solovyev.android.calculator.drag.DragButton; +import org.solovyev.android.calculator.drag.DragDirection; +import org.solovyev.android.calculator.drag.SimpleDragListener; +import org.solovyev.common.history.HistoryAction; +import org.solovyev.common.history.HistoryControl; +import org.solovyev.common.math.Point2d; + +import javax.annotation.Nonnull; + +/** + * User: serso + * Date: 9/16/11 + * Time: 11:36 PM + */ +public class HistoryDragProcessor implements SimpleDragListener.DragProcessor { + + @Nonnull + private final HistoryControl historyControl; + + public HistoryDragProcessor(@Nonnull HistoryControl historyControl) { + this.historyControl = historyControl; + } + + @Override + public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, @Nonnull Point2d startPoint2d, @Nonnull MotionEvent motionEvent) { + boolean result = false; + + Log.d(String.valueOf(dragButton.getId()), "History on drag event start: " + dragDirection); + + final HistoryAction historyAction; + if (dragDirection == DragDirection.up) { + historyAction = HistoryAction.undo; + } else if (dragDirection == DragDirection.down) { + historyAction = HistoryAction.redo; + } else { + historyAction = null; + } + + if (historyAction != null) { + result = true; + historyControl.doHistoryAction(historyAction); + } + + return result; + } +} diff --git a/android-app/src/main/java/org/solovyev/android/calculator/preferences/BasePreferencesActivity.java b/android-app/src/main/java/org/solovyev/android/calculator/preferences/BasePreferencesActivity.java index e31fb86d..5ee85cbf 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/preferences/BasePreferencesActivity.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/preferences/BasePreferencesActivity.java @@ -9,6 +9,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; +import android.widget.ListView; import org.solovyev.android.calculator.ActivityUi; import org.solovyev.android.calculator.AdView; import org.solovyev.android.calculator.App; @@ -22,6 +23,7 @@ import javax.annotation.Nonnull; public abstract class BasePreferencesActivity extends PreferenceActivity { + private static boolean SUPPORT_HEADERS = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; private final ActivityCheckout checkout = Checkout.forActivity(this, App.getBilling(), App.getProducts()); private Inventory inventory; private AdView adView; @@ -66,29 +68,37 @@ public abstract class BasePreferencesActivity extends PreferenceActivity { } protected void onShowAd(boolean show) { - if(!supportsAds()) { + if (!supportsHeaders()) { return; } + + final ListView listView = getListView(); if (show) { if (adView != null) { return; } adView = (AdView) LayoutInflater.from(this).inflate(R.layout.ad, null); adView.show(); - getListView().addHeaderView(adView); + try { + listView.addHeaderView(adView); + } catch (IllegalStateException e) { + // doesn't support header views + SUPPORT_HEADERS = false; + adView.hide(); + adView = null; + } } else { if (adView == null) { return; } - getListView().removeHeaderView(adView); + listView.removeHeaderView(adView); adView.hide(); adView = null; } } - private boolean supportsAds() { - // on Android 2.3 the headers in the list view are not supported - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; + private boolean supportsHeaders() { + return SUPPORT_HEADERS; } @Override diff --git a/android-app/src/main/java/org/solovyev/android/calculator/view/AngleUnitsButton.java b/android-app/src/main/java/org/solovyev/android/calculator/view/AngleUnitsButton.java index c138de07..eb546751 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/view/AngleUnitsButton.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/view/AngleUnitsButton.java @@ -30,7 +30,7 @@ import android.util.AttributeSet; import jscl.AngleUnit; import org.solovyev.android.calculator.Locator; import org.solovyev.android.calculator.R; -import org.solovyev.android.view.drag.DirectionDragButton; +import org.solovyev.android.calculator.drag.DirectionDragButton; import javax.annotation.Nonnull; diff --git a/android-app/src/main/java/org/solovyev/android/calculator/view/OnDragListenerVibrator.java b/android-app/src/main/java/org/solovyev/android/calculator/view/DragListenerVibrator.java similarity index 74% rename from android-app/src/main/java/org/solovyev/android/calculator/view/OnDragListenerVibrator.java rename to android-app/src/main/java/org/solovyev/android/calculator/view/DragListenerVibrator.java index 85f10bb8..9a1d56a2 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/view/OnDragListenerVibrator.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/view/DragListenerVibrator.java @@ -24,36 +24,36 @@ package org.solovyev.android.calculator.view; import android.content.SharedPreferences; import android.os.Vibrator; +import org.solovyev.android.calculator.drag.DragButton; +import org.solovyev.android.calculator.drag.DragEvent; +import org.solovyev.android.calculator.drag.DragListener; +import org.solovyev.android.calculator.drag.DragListenerWrapper; +import org.solovyev.android.view.VibratorContainer; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import org.solovyev.android.view.VibratorContainer; -import org.solovyev.android.view.drag.DragButton; -import org.solovyev.android.view.drag.OnDragListener; -import org.solovyev.android.view.drag.OnDragListenerWrapper; - /** * User: serso * Date: 4/20/12 * Time: 3:27 PM */ -public class OnDragListenerVibrator extends OnDragListenerWrapper { +public class DragListenerVibrator extends DragListenerWrapper { private static final float VIBRATION_TIME_SCALE = 0.5f; @Nonnull private final VibratorContainer vibrator; - public OnDragListenerVibrator(@Nonnull OnDragListener onDragListener, - @Nullable Vibrator vibrator, - @Nonnull SharedPreferences preferences) { - super(onDragListener); + public DragListenerVibrator(@Nonnull DragListener dragListener, + @Nullable Vibrator vibrator, + @Nonnull SharedPreferences preferences) { + super(dragListener); this.vibrator = new VibratorContainer(vibrator, preferences, VIBRATION_TIME_SCALE); } @Override - public boolean onDrag(@Nonnull DragButton dragButton, @Nonnull org.solovyev.android.view.drag.DragEvent event) { + public boolean onDrag(@Nonnull DragButton dragButton, @Nonnull DragEvent event) { boolean result = super.onDrag(dragButton, event); if (result) { diff --git a/android-app/src/main/java/org/solovyev/android/calculator/view/NumeralBasesButton.java b/android-app/src/main/java/org/solovyev/android/calculator/view/NumeralBasesButton.java index d2640977..d40fbbd9 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/view/NumeralBasesButton.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/view/NumeralBasesButton.java @@ -29,7 +29,7 @@ import android.util.AttributeSet; import jscl.NumeralBase; import org.solovyev.android.calculator.Locator; import org.solovyev.android.calculator.R; -import org.solovyev.android.view.drag.DirectionDragButton; +import org.solovyev.android.calculator.drag.DirectionDragButton; import javax.annotation.Nonnull; diff --git a/android-app/src/main/java/org/solovyev/android/calculator/wizard/DragButtonWizardStep.java b/android-app/src/main/java/org/solovyev/android/calculator/wizard/DragButtonWizardStep.java index c199bd6c..0154cd79 100644 --- a/android-app/src/main/java/org/solovyev/android/calculator/wizard/DragButtonWizardStep.java +++ b/android-app/src/main/java/org/solovyev/android/calculator/wizard/DragButtonWizardStep.java @@ -23,16 +23,14 @@ package org.solovyev.android.calculator.wizard; import android.os.Bundle; -import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; -import android.view.ViewGroup; import android.widget.TextView; import org.solovyev.android.calculator.R; -import org.solovyev.android.view.drag.DirectionDragButton; -import org.solovyev.android.view.drag.DragButton; -import org.solovyev.android.view.drag.DragDirection; -import org.solovyev.android.view.drag.SimpleOnDragListener; +import org.solovyev.android.calculator.drag.DirectionDragButton; +import org.solovyev.android.calculator.drag.DragButton; +import org.solovyev.android.calculator.drag.DragDirection; +import org.solovyev.android.calculator.drag.SimpleDragListener; import org.solovyev.common.math.Point2d; import javax.annotation.Nonnull; @@ -86,7 +84,7 @@ public class DragButtonWizardStep extends WizardFragment { dragButton = (DirectionDragButton) root.findViewById(R.id.wizard_dragbutton); dragButton.setOnClickListener(new DragButtonOnClickListener()); - dragButton.setOnDragListener(new SimpleOnDragListener(new DragButtonProcessor(), SimpleOnDragListener.getDefaultPreferences(getActivity()))); + dragButton.setOnDragListener(new SimpleDragListener(new DragButtonProcessor(), SimpleDragListener.getDefaultPreferences(getActivity()))); actionTextView = (TextView) root.findViewById(R.id.wizard_dragbutton_action_textview); descriptionTextView = (TextView) root.findViewById(R.id.wizard_dragbutton_description_textview); @@ -151,7 +149,7 @@ public class DragButtonWizardStep extends WizardFragment { setAction(action.getNextAction()); } - private class DragButtonProcessor implements SimpleOnDragListener.DragProcessor { + private class DragButtonProcessor implements SimpleDragListener.DragProcessor { @Override public boolean processDragEvent(@Nonnull DragDirection dragDirection, @Nonnull DragButton dragButton, diff --git a/android-app/src/main/res/layout/cpp_drag_button_0.xml b/android-app/src/main/res/layout/cpp_drag_button_0.xml index a8626ece..208fc905 100644 --- a/android-app/src/main/res/layout/cpp_drag_button_0.xml +++ b/android-app/src/main/res/layout/cpp_drag_button_0.xml @@ -22,7 +22,7 @@ ~ Site: http://se.solovyev.org --> - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/android-app/src/main/res/layout/cpp_drag_button_equals.xml b/android-app/src/main/res/layout/cpp_drag_button_equals.xml index 383f49ff..0e9ad24e 100644 --- a/android-app/src/main/res/layout/cpp_drag_button_equals.xml +++ b/android-app/src/main/res/layout/cpp_drag_button_equals.xml @@ -21,7 +21,7 @@ ~ Email: se.solovyev@gmail.com ~ Site: http://se.solovyev.org --> - - - - - - - - - - - - - -