diff --git a/calculatorpp/AndroidManifest.xml b/calculatorpp/AndroidManifest.xml index 9fe203f6..94a5de6e 100644 --- a/calculatorpp/AndroidManifest.xml +++ b/calculatorpp/AndroidManifest.xml @@ -53,6 +53,9 @@ + + + diff --git a/calculatorpp/res/layout/calc_vars_button.xml b/calculatorpp/res/layout/calc_vars_button.xml index 85db3d2a..351da57b 100644 --- a/calculatorpp/res/layout/calc_vars_button.xml +++ b/calculatorpp/res/layout/calc_vars_button.xml @@ -11,6 +11,7 @@ a:id="@+id/vars_button" c:directionTextScale="0.5" c:textUp="+π" + c:textDown="+m" a:text="π,…" a:textStyle="italic" a:onClick="varsButtonClickHandler" diff --git a/calculatorpp/res/layout/matrix_edit_fragment.xml b/calculatorpp/res/layout/matrix_edit_fragment.xml new file mode 100644 index 00000000..d3133f42 --- /dev/null +++ b/calculatorpp/res/layout/matrix_edit_fragment.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/calculatorpp/res/layout/matrix_edit_fragment_item.xml b/calculatorpp/res/layout/matrix_edit_fragment_item.xml new file mode 100644 index 00000000..880d08b1 --- /dev/null +++ b/calculatorpp/res/layout/matrix_edit_fragment_item.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorButtons.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorButtons.java index 15cc04ef..e510c843 100644 --- a/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorButtons.java +++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/CalculatorButtons.java @@ -2,6 +2,7 @@ package org.solovyev.android.calculator; import android.app.Activity; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; import android.preference.PreferenceManager; @@ -16,6 +17,7 @@ import jscl.NumeralBase; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.solovyev.android.AndroidUtils; +import org.solovyev.android.calculator.matrix.CalculatorMatrixActivity; import org.solovyev.android.calculator.model.AndroidCalculatorEngine; import org.solovyev.android.calculator.view.AngleUnitsButton; import org.solovyev.android.calculator.view.NumeralBasesButton; @@ -134,6 +136,9 @@ public final class CalculatorButtons { if (dragDirection == DragDirection.up) { CalculatorActivityLauncher.createVar(context, Locator.getInstance().getDisplay()); result = true; + } else if ( dragDirection == DragDirection.down ) { + context.startActivity(new Intent(context, CalculatorMatrixActivity.class)); + result = true; } return result; diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/about/CalculatorFragmentType.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/about/CalculatorFragmentType.java index 693f660f..65a33d52 100644 --- a/calculatorpp/src/main/java/org/solovyev/android/calculator/about/CalculatorFragmentType.java +++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/about/CalculatorFragmentType.java @@ -1,76 +1,80 @@ -package org.solovyev.android.calculator.about; - -import android.support.v4.app.Fragment; -import org.jetbrains.annotations.NotNull; -import org.solovyev.android.calculator.CalculatorEditorFragment; -import org.solovyev.android.calculator.R; -import org.solovyev.android.calculator.help.CalculatorHelpFaqFragment; -import org.solovyev.android.calculator.help.CalculatorHelpHintsFragment; -import org.solovyev.android.calculator.help.CalculatorHelpScreensFragment; -import org.solovyev.android.calculator.history.CalculatorHistoryFragment; -import org.solovyev.android.calculator.history.CalculatorSavedHistoryFragment; -import org.solovyev.android.calculator.math.edit.CalculatorFunctionsFragment; -import org.solovyev.android.calculator.math.edit.CalculatorOperatorsFragment; -import org.solovyev.android.calculator.math.edit.CalculatorVarsFragment; -import org.solovyev.android.calculator.plot.CalculatorPlotFragment; - -/** - * User: Solovyev_S - * Date: 03.10.12 - * Time: 11:30 - */ -public enum CalculatorFragmentType { - - editor(CalculatorEditorFragment.class, R.layout.calc_editor, R.string.editor), - //display(CalculatorHistoryFragment.class, "history", R.layout.history_fragment, R.string.c_history), - //keyboard(CalculatorHistoryFragment.class, "history", R.layout.history_fragment, R.string.c_history), - history(CalculatorHistoryFragment.class, R.layout.history_fragment, R.string.c_history), - saved_history(CalculatorSavedHistoryFragment.class, R.layout.history_fragment, R.string.c_saved_history), - variables(CalculatorVarsFragment.class, R.layout.vars_fragment, R.string.c_vars), - functions(CalculatorFunctionsFragment.class, R.layout.math_entities_fragment, R.string.c_functions), - operators(CalculatorOperatorsFragment.class, R.layout.math_entities_fragment, R.string.c_operators), - plotter(CalculatorPlotFragment.class, R.layout.plot_fragment, R.string.c_graph), - about(CalculatorAboutFragment.class, R.layout.about_fragment, R.string.c_about), - faq(CalculatorHelpFaqFragment.class, R.layout.help_faq_fragment, R.string.c_faq), - hints(CalculatorHelpHintsFragment.class, R.layout.help_hints_fragment, R.string.c_hints), - screens(CalculatorHelpScreensFragment.class, R.layout.help_screens_fragment, R.string.c_screens), - release_notes(CalculatorReleaseNotesFragment.class, R.layout.release_notes_fragment, R.string.c_release_notes); - - @NotNull - private Class fragmentClass; - - private final int defaultLayoutId; - - private int defaultTitleResId; - - private CalculatorFragmentType(@NotNull Class fragmentClass, - int defaultLayoutId, - int defaultTitleResId) { - this.fragmentClass = fragmentClass; - this.defaultLayoutId = defaultLayoutId; - this.defaultTitleResId = defaultTitleResId; - } - - @NotNull - public String getFragmentTag() { - return this.name(); - } - - public int getDefaultTitleResId() { - return defaultTitleResId; - } - - @NotNull - public Class getFragmentClass() { - return fragmentClass; - } - - public int getDefaultLayoutId() { - return defaultLayoutId; - } - - @NotNull - public String createSubFragmentTag(@NotNull String subFragmentTag) { - return this.getFragmentTag() + "_" + subFragmentTag; - } -} +package org.solovyev.android.calculator.about; + +import android.support.v4.app.Fragment; +import org.jetbrains.annotations.NotNull; +import org.solovyev.android.calculator.CalculatorEditorFragment; +import org.solovyev.android.calculator.R; +import org.solovyev.android.calculator.help.CalculatorHelpFaqFragment; +import org.solovyev.android.calculator.help.CalculatorHelpHintsFragment; +import org.solovyev.android.calculator.help.CalculatorHelpScreensFragment; +import org.solovyev.android.calculator.history.CalculatorHistoryFragment; +import org.solovyev.android.calculator.history.CalculatorSavedHistoryFragment; +import org.solovyev.android.calculator.math.edit.CalculatorFunctionsFragment; +import org.solovyev.android.calculator.math.edit.CalculatorOperatorsFragment; +import org.solovyev.android.calculator.math.edit.CalculatorVarsFragment; +import org.solovyev.android.calculator.matrix.CalculatorMatrixEditFragment; +import org.solovyev.android.calculator.plot.CalculatorPlotFragment; + +/** + * User: Solovyev_S + * Date: 03.10.12 + * Time: 11:30 + */ +public enum CalculatorFragmentType { + + editor(CalculatorEditorFragment.class, R.layout.calc_editor, R.string.editor), + //display(CalculatorHistoryFragment.class, "history", R.layout.history_fragment, R.string.c_history), + //keyboard(CalculatorHistoryFragment.class, "history", R.layout.history_fragment, R.string.c_history), + history(CalculatorHistoryFragment.class, R.layout.history_fragment, R.string.c_history), + saved_history(CalculatorSavedHistoryFragment.class, R.layout.history_fragment, R.string.c_saved_history), + variables(CalculatorVarsFragment.class, R.layout.vars_fragment, R.string.c_vars), + functions(CalculatorFunctionsFragment.class, R.layout.math_entities_fragment, R.string.c_functions), + operators(CalculatorOperatorsFragment.class, R.layout.math_entities_fragment, R.string.c_operators), + plotter(CalculatorPlotFragment.class, R.layout.plot_fragment, R.string.c_graph), + about(CalculatorAboutFragment.class, R.layout.about_fragment, R.string.c_about), + faq(CalculatorHelpFaqFragment.class, R.layout.help_faq_fragment, R.string.c_faq), + hints(CalculatorHelpHintsFragment.class, R.layout.help_hints_fragment, R.string.c_hints), + screens(CalculatorHelpScreensFragment.class, R.layout.help_screens_fragment, R.string.c_screens), + + // todo serso: strings + matrix_edit(CalculatorMatrixEditFragment.class, R.layout.matrix_edit_fragment, R.string.c_screens), + release_notes(CalculatorReleaseNotesFragment.class, R.layout.release_notes_fragment, R.string.c_release_notes); + + @NotNull + private Class fragmentClass; + + private final int defaultLayoutId; + + private int defaultTitleResId; + + private CalculatorFragmentType(@NotNull Class fragmentClass, + int defaultLayoutId, + int defaultTitleResId) { + this.fragmentClass = fragmentClass; + this.defaultLayoutId = defaultLayoutId; + this.defaultTitleResId = defaultTitleResId; + } + + @NotNull + public String getFragmentTag() { + return this.name(); + } + + public int getDefaultTitleResId() { + return defaultTitleResId; + } + + @NotNull + public Class getFragmentClass() { + return fragmentClass; + } + + public int getDefaultLayoutId() { + return defaultLayoutId; + } + + @NotNull + public String createSubFragmentTag(@NotNull String subFragmentTag) { + return this.getFragmentTag() + "_" + subFragmentTag; + } +} diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/matrix/CalculatorMatrixActivity.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/matrix/CalculatorMatrixActivity.java new file mode 100644 index 00000000..3ec80741 --- /dev/null +++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/matrix/CalculatorMatrixActivity.java @@ -0,0 +1,23 @@ +package org.solovyev.android.calculator.matrix; + +import android.app.ActionBar; +import android.os.Bundle; +import org.solovyev.android.calculator.CalculatorFragmentActivity; +import org.solovyev.android.calculator.R; +import org.solovyev.android.calculator.about.CalculatorFragmentType; + +/** + * User: Solovyev_S + * Date: 12.10.12 + * Time: 10:56 + */ +public class CalculatorMatrixActivity extends CalculatorFragmentActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); + getActivityHelper().setFragment(this, CalculatorFragmentType.matrix_edit, null, R.id.main_layout); + } +} diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/matrix/CalculatorMatrixEditFragment.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/matrix/CalculatorMatrixEditFragment.java new file mode 100644 index 00000000..9f8e3c8e --- /dev/null +++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/matrix/CalculatorMatrixEditFragment.java @@ -0,0 +1,137 @@ +package org.solovyev.android.calculator.matrix; + +import android.os.Bundle; +import android.view.View; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.solovyev.android.calculator.CalculatorFragment; +import org.solovyev.android.calculator.R; +import org.solovyev.android.calculator.about.CalculatorFragmentType; +import org.solovyev.android.view.IntegerRange; +import org.solovyev.android.view.Picker; + +import java.io.Serializable; + +/** + * User: Solovyev_S + * Date: 12.10.12 + * Time: 10:41 + */ +public class CalculatorMatrixEditFragment extends CalculatorFragment implements Picker.OnChangedListener { + + /* + ********************************************************************** + * + * CONSTANTS + * + ********************************************************************** + */ + + private static final int MAX_COUNT = 10; + private static final int MIN_COUNT = 2; + private static final int DEFAULT_ROWS = 2; + private static final int DEFAULT_COLS = 2; + + private static final String MATRIX = "matrix"; + + + /* + ********************************************************************** + * + * CONSTRUCTORS + * + ********************************************************************** + */ + + public CalculatorMatrixEditFragment() { + super(CalculatorFragmentType.matrix_edit); + + setRetainInstance(true); + } + + /* + ********************************************************************** + * + * METHODS + * + ********************************************************************** + */ + + + @Override + public void onViewCreated(View root, @Nullable Bundle in) { + super.onViewCreated(root, in); + + final Picker matrixRowsCountPicker = (Picker) root.findViewById(R.id.matrix_rows_count_picker); + initPicker(matrixRowsCountPicker); + final Picker matrixColsCountPicker = (Picker) root.findViewById(R.id.matrix_cols_count_picker); + initPicker(matrixColsCountPicker); + + Matrix matrix = null; + if (in != null) { + final Object matrixObject = in.getSerializable(MATRIX); + if (matrixObject instanceof Matrix) { + matrix = (Matrix) matrixObject; + } + } + + final MatrixView matrixView = getMatrixView(root); + if (matrix == null) { + matrixView.setMatrixDimensions(DEFAULT_ROWS, DEFAULT_COLS); + } else { + matrixView.setMatrix(matrix.bakingArray); + } + matrixRowsCountPicker.setCurrent(matrixView.getRows()); + matrixColsCountPicker.setCurrent(matrixView.getCols()); + } + + @Override + public void onSaveInstanceState(@NotNull Bundle out) { + super.onSaveInstanceState(out); + + out.putSerializable(MATRIX, new Matrix(getMatrixView(getView()).toMatrix())); + } + + @NotNull + private MatrixView getMatrixView(@NotNull View root) { + return (MatrixView) root.findViewById(R.id.matrix_layout); + } + + private void initPicker(@NotNull Picker picker) { + picker.setRange(new IntegerRange(MIN_COUNT, MAX_COUNT, 1, 0, null)); + picker.setOnChangeListener(this); + } + + @Override + public void onChanged(@NotNull Picker picker, @NotNull Integer value) { + switch (picker.getId()) { + case R.id.matrix_rows_count_picker: + onRowsCountChange(value); + break; + case R.id.matrix_cols_count_picker: + onColsCountChange(value); + break; + } + } + + private void onColsCountChange(@NotNull Integer newCols) { + getMatrixView(getView()).setMatrixCols(newCols); + } + + private void onRowsCountChange(@NotNull Integer newRows) { + getMatrixView(getView()).setMatrixRows(newRows); + } + + public static class Matrix implements Serializable { + + @NotNull + private String[][] bakingArray; + + public Matrix() { + } + + public Matrix(@NotNull String[][] bakingArray) { + this.bakingArray = bakingArray; + } + } +} diff --git a/calculatorpp/src/main/java/org/solovyev/android/calculator/matrix/MatrixView.java b/calculatorpp/src/main/java/org/solovyev/android/calculator/matrix/MatrixView.java new file mode 100644 index 00000000..16d96d65 --- /dev/null +++ b/calculatorpp/src/main/java/org/solovyev/android/calculator/matrix/MatrixView.java @@ -0,0 +1,289 @@ +package org.solovyev.android.calculator.matrix; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.TableLayout; +import android.widget.TableRow; +import android.widget.TextView; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * User: Solovyev_S + * Date: 12.10.12 + * Time: 15:41 + */ +public class MatrixView extends TableLayout { + + /* + ********************************************************************** + * + * CONSTANTS + * + ********************************************************************** + */ + + private static final CharSequence DEFAULT_CELL_TEXT = "0"; + private static final int NUMBER_INDEX = -1; + + + /* + ********************************************************************** + * + * FIELDS + * + ********************************************************************** + */ + + private int rows = 0; + private int cols = 0; + + @Nullable + private CharSequence defaultCellText = DEFAULT_CELL_TEXT; + + private boolean initialized = false; + + /* + ********************************************************************** + * + * CONSTRUCTORS + * + ********************************************************************** + */ + + public MatrixView(Context context) { + super(context); + } + + public MatrixView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + /* + ********************************************************************** + * + * METHODS + * + ********************************************************************** + */ + + public int getRows() { + return rows; + } + + public int getCols() { + return cols; + } + + public void setMatrixCols(int newCols) { + setMatrixDimensions(rows, newCols); + } + + public void setMatrixRows(int newRows) { + setMatrixDimensions(newRows, cols); + } + + public void setMatrixDimensions(int newRows, int newCols) { + if (newRows <= 1) { + throw new IllegalArgumentException("Number of rows must be more than 1: " + newRows); + } + + if (newCols <= 1) { + throw new IllegalArgumentException("Number of columns must be more than 1: " + newCols); + } + + boolean rowsChanged = this.rows != newRows; + boolean colsChanged = this.cols != newCols; + + if (rowsChanged || colsChanged) { + if (!initialized) { + addRow(NUMBER_INDEX, 0); + initialized = true; + } + + if (this.cols > newCols) { + removeCols(newCols); + } else if (this.cols < newCols) { + addCols(newCols); + } + + this.cols = newCols; + + if (this.rows > newRows) { + removeRows(newRows); + } else if (this.rows < newRows) { + addRows(newRows); + } + + this.rows = newRows; + } + } + + public void setMatrix(@NotNull Object[][] matrix) { + final int rows = matrix.length; + final int cols = matrix[0].length; + + setMatrixDimensions(rows, cols); + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + setCell(row, col, matrix[row][col]); + } + } + } + + @NotNull + public String[][] toMatrix() { + final String[][] result = new String[rows][cols]; + + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + final TextView cellTextView = (TextView) getCell(this, row, col); + if (cellTextView != null) { + result[row][col] = cellTextView.getText().toString(); + } + } + } + + return result; + } + + private void setCell(int row, int col, @Nullable Object o) { + final TextView cellTextView = (TextView) getCell(this, row, col); + if (cellTextView != null) { + if (o == null) { + cellTextView.setText(null); + } else { + cellTextView.setText(String.valueOf(o)); + } + } + } + + /* + ********************************************************************** + * + * PRIVATE METHODS + * + ********************************************************************** + */ + + private void addRows(int newRows) { + for (int row = this.rows; row < newRows; row++) { + addRow(row, cols); + } + } + + private void removeRows(int newRows) { + for (int row = this.rows - 1; row >= newRows; row--) { + removeRow(row); + } + } + + private void addCols(int newCols) { + for (int row = NUMBER_INDEX; row < rows; row++) { + final ViewGroup rowView = getRow(row); + if (rowView != null) { + for (int col = this.cols; col < newCols; col++) { + rowView.addView(createCellView(row, col)); + } + } + } + } + + private void removeCols(int newCols) { + for (int row = NUMBER_INDEX; row < rows; row++) { + final ViewGroup rowView = getRow(row); + if (rowView != null) { + for (int col = this.cols - 1; col >= newCols; col--) { + final View cellView = getCell(rowView, row, col); + if (cellView != null) { + rowView.removeView(cellView); + } + } + } + } + } + + private void addRow(int row, int newCols) { + this.addView(createRowView(row, newCols)); + } + + private void removeRow(int row) { + final View rowView = getRow(row); + if (rowView != null) { + this.removeView(rowView); + } + } + + @Nullable + private TableRow getRow(int row) { + return (TableRow) this.findViewWithTag(getRowTag(row)); + } + + @Nullable + private View getCell(@NotNull View view, int row, int col) { + return view.findViewWithTag(getCellTag(row, col)); + } + + @NotNull + private String getRowTag(int row) { + if (row != NUMBER_INDEX) { + return "row_" + row; + } else { + return "row_index"; + } + } + + @NotNull + private View createRowView(int row, int cols) { + final ViewGroup rowView = new TableRow(this.getContext()); + + rowView.setTag(getRowTag(row)); + + if (row != NUMBER_INDEX) { + rowView.addView(createCellView(row, NUMBER_INDEX)); + } else { + // empty cell + rowView.addView(new View(this.getContext())); + } + + for (int col = 0; col < cols; col++) { + rowView.addView(createCellView(row, col)); + } + return rowView; + } + + @NotNull + private View createCellView(int row, int col) { + final TextView result; + + if (row != NUMBER_INDEX && col != NUMBER_INDEX) { + result = new EditText(this.getContext()); + result.setText(defaultCellText); + } else { + result = new TextView(this.getContext()); + if (row == NUMBER_INDEX) { + result.setText(String.valueOf(col + 1)); + } else { + result.setText(String.valueOf(row + 1)); + } + } + + result.setTag(getCellTag(row, col)); + + return result; + + } + + @NotNull + private String getCellTag(int row, int col) { + if (row != NUMBER_INDEX) { + return "cell_" + row + "_" + col; + } else { + return "cell_index_" + col; + } + } + +}