diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/ChessBoardPlayListener.java b/DroidFishApp/src/main/java/org/petero/droidfish/ChessBoardPlayListener.java new file mode 100644 index 0000000..b5c53d3 --- /dev/null +++ b/DroidFishApp/src/main/java/org/petero/droidfish/ChessBoardPlayListener.java @@ -0,0 +1,196 @@ +/* + DroidFish - An Android chess program. + Copyright (C) 2020 Peter Ă–sterlund, peterosterlund2@gmail.com + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +package org.petero.droidfish; + +import android.os.Handler; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; + +import org.petero.droidfish.gamelogic.DroidChessController; +import org.petero.droidfish.gamelogic.Move; +import org.petero.droidfish.view.ChessBoard; + +public class ChessBoardPlayListener implements View.OnTouchListener, + ChessBoard.OnTrackballListener { + private DroidFish df; + private ChessBoardPlay cb; + + private boolean pending = false; + private boolean pendingClick = false; + private int sq0 = -1; + private float scrollX = 0; + private float scrollY = 0; + private float prevX = 0; + private float prevY = 0; + private Handler handler = new Handler(); + private Runnable runnable = new Runnable() { + public void run() { + pending = false; + handler.removeCallbacks(runnable); + df.reShowDialog(DroidFish.BOARD_MENU_DIALOG); + } + }; + + ChessBoardPlayListener(DroidFish df, ChessBoardPlay cb) { + this.df = df; + this.cb = cb; + } + + @Override + public boolean onTouch(View v, MotionEvent event) { + int action = event.getActionMasked(); + switch (action) { + case MotionEvent.ACTION_DOWN: + handler.postDelayed(runnable, ViewConfiguration.getLongPressTimeout()); + pending = true; + pendingClick = true; + sq0 = cb.eventToSquare(event); + scrollX = 0; + scrollY = 0; + prevX = event.getX(); + prevY = event.getY(); + break; + case MotionEvent.ACTION_MOVE: + if (pending) { + int sq = cb.eventToSquare(event); + if (sq != sq0) { + handler.removeCallbacks(runnable); + pendingClick = false; + } + float currX = event.getX(); + float currY = event.getY(); + if (onScroll(currX - prevX, currY - prevY)) { + handler.removeCallbacks(runnable); + pendingClick = false; + } + prevX = currX; + prevY = currY; + } + break; + case MotionEvent.ACTION_UP: + if (pending) { + pending = false; + handler.removeCallbacks(runnable); + if (!pendingClick) + break; + int sq = cb.eventToSquare(event); + if (sq == sq0) { + if (df.ctrl.humansTurn()) { + Move m = cb.mousePressed(sq); + if (m != null) { + df.setAutoMode(DroidFish.AutoMode.OFF); + df.ctrl.makeHumanMove(m); + } + df.setEgtbHints(cb.getSelectedSquare()); + } + } + } + break; + case MotionEvent.ACTION_CANCEL: + pending = false; + handler.removeCallbacks(runnable); + break; + } + return true; + } + + private boolean onScroll(float distanceX, float distanceY) { + if (df.invertScrollDirection) { + distanceX = -distanceX; + distanceY = -distanceY; + } + if ((df.scrollSensitivity > 0) && (cb.sqSize > 0)) { + scrollX += distanceX; + scrollY += distanceY; + final float scrollUnit = cb.sqSize * df.scrollSensitivity; + if (Math.abs(scrollX) >= Math.abs(scrollY)) { + // Undo/redo + int nRedo = 0, nUndo = 0; + while (scrollX > scrollUnit) { + nRedo++; + scrollX -= scrollUnit; + } + while (scrollX < -scrollUnit) { + nUndo++; + scrollX += scrollUnit; + } + if (nUndo + nRedo > 0) { + scrollY = 0; + df.setAutoMode(DroidFish.AutoMode.OFF); + } + if (nRedo + nUndo > 1) { + boolean analysis = df.gameMode.analysisMode(); + boolean human = df.gameMode.playerWhite() || df.gameMode.playerBlack(); + if (analysis || !human) + df.ctrl.setGameMode(new GameMode(GameMode.TWO_PLAYERS)); + } + if (df.scrollGames) { + if (nRedo > 0) { + UIAction nextGame = df.actionFactory.getAction("nextGame"); + if (nextGame.enabled()) + for (int i = 0; i < nRedo; i++) + nextGame.run(); + } + if (nUndo > 0) { + UIAction prevGame = df.actionFactory.getAction("prevGame"); + if (prevGame.enabled()) + for (int i = 0; i < nUndo; i++) + prevGame.run(); + } + } else { + for (int i = 0; i < nRedo; i++) df.ctrl.redoMove(); + for (int i = 0; i < nUndo; i++) df.ctrl.undoMove(); + } + df.ctrl.setGameMode(df.gameMode); + return nRedo + nUndo > 0; + } else { + // Next/previous variation + int varDelta = 0; + while (scrollY > scrollUnit) { + varDelta++; + scrollY -= scrollUnit; + } + while (scrollY < -scrollUnit) { + varDelta--; + scrollY += scrollUnit; + } + if (varDelta != 0) { + scrollX = 0; + df.setAutoMode(DroidFish.AutoMode.OFF); + df.ctrl.changeVariation(varDelta); + } + return varDelta != 0; + } + } + return false; + } + + @Override + public void onTrackballEvent(MotionEvent event) { + if (df.ctrl.humansTurn()) { + Move m = cb.handleTrackballEvent(event); + if (m != null) { + df.setAutoMode(DroidFish.AutoMode.OFF); + df.ctrl.makeHumanMove(m); + } + df.setEgtbHints(cb.getSelectedSquare()); + } + } +} diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/DroidFish.java b/DroidFishApp/src/main/java/org/petero/droidfish/DroidFish.java index 509623d..7d1d767 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/DroidFish.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/DroidFish.java @@ -60,7 +60,6 @@ import org.petero.droidfish.gamelogic.GameTree.Node; import org.petero.droidfish.gamelogic.TimeControlData; import org.petero.droidfish.tb.Probe; import org.petero.droidfish.tb.ProbeResult; -import org.petero.droidfish.view.ChessBoard; import org.petero.droidfish.view.MoveListView; import org.petero.droidfish.view.ChessBoard.SquareDecoration; @@ -119,7 +118,6 @@ import android.preference.PreferenceManager; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; -import androidx.core.view.MotionEventCompat; import androidx.drawerlayout.widget.DrawerLayout; import android.text.Editable; import android.text.Html; @@ -128,7 +126,6 @@ import android.text.TextWatcher; import android.util.Pair; import android.util.TypedValue; import android.view.Gravity; -import android.view.ViewConfiguration; import android.view.KeyEvent; import android.view.Menu; import android.view.MotionEvent; @@ -173,7 +170,7 @@ public class DroidFish extends Activity // FIXME!!! Use two engines in engine/engine games private ChessBoardPlay cb; - private DroidChessController ctrl = null; + DroidChessController ctrl = null; private boolean mShowThinking; private boolean mShowStats; private boolean fullPVLines; @@ -182,7 +179,7 @@ public class DroidFish extends Activity private boolean mShowBookHints; private int mEcoHints; private int maxNumArrows; - private GameMode gameMode; + GameMode gameMode; private boolean mPonderMode; private int timeControl; private int movesPerSession; @@ -214,9 +211,9 @@ public class DroidFish extends Activity private SharedPreferences settings; private ObjectCache cache; - private float scrollSensitivity; - private boolean invertScrollDirection; - private boolean scrollGames; + float scrollSensitivity; + boolean invertScrollDirection; + boolean scrollGames; private boolean autoScrollMoveList; private boolean leftHanded; @@ -274,7 +271,7 @@ public class DroidFish extends Activity /** Defines all configurable button actions. */ - private ActionFactory actionFactory = new ActionFactory() { + ActionFactory actionFactory = new ActionFactory() { private HashMap actions; private void addAction(UIAction a) { @@ -976,164 +973,9 @@ public class DroidFish extends Activity cb.setClickable(true); cb.setPgnOptions(pgnOptions); - cb.setOnTouchListener(new OnTouchListener() { - private boolean pending = false; - private boolean pendingClick = false; - private int sq0 = -1; - private float scrollX = 0; - private float scrollY = 0; - private float prevX = 0; - private float prevY = 0; - private Handler handler = new Handler(); - private Runnable runnable = new Runnable() { - public void run() { - pending = false; - handler.removeCallbacks(runnable); - reShowDialog(BOARD_MENU_DIALOG); - } - }; - - @Override - public boolean onTouch(View v, MotionEvent event) { - int action = MotionEventCompat.getActionMasked(event); - switch (action) { - case MotionEvent.ACTION_DOWN: - handler.postDelayed(runnable, ViewConfiguration.getLongPressTimeout()); - pending = true; - pendingClick = true; - sq0 = cb.eventToSquare(event); - scrollX = 0; - scrollY = 0; - prevX = event.getX(); - prevY = event.getY(); - break; - case MotionEvent.ACTION_MOVE: - if (pending) { - int sq = cb.eventToSquare(event); - if (sq != sq0) { - handler.removeCallbacks(runnable); - pendingClick = false; - } - float currX = event.getX(); - float currY = event.getY(); - if (onScroll(currX - prevX, currY - prevY)) { - handler.removeCallbacks(runnable); - pendingClick = false; - } - prevX = currX; - prevY = currY; - } - break; - case MotionEvent.ACTION_UP: - if (pending) { - pending = false; - handler.removeCallbacks(runnable); - if (!pendingClick) - break; - int sq = cb.eventToSquare(event); - if (sq == sq0) { - if (ctrl.humansTurn()) { - Move m = cb.mousePressed(sq); - if (m != null) { - setAutoMode(AutoMode.OFF); - ctrl.makeHumanMove(m); - } - setEgtbHints(cb.getSelectedSquare()); - } - } - } - break; - case MotionEvent.ACTION_CANCEL: - pending = false; - handler.removeCallbacks(runnable); - break; - } - return true; - } - - private boolean onScroll(float distanceX, float distanceY) { - if (invertScrollDirection) { - distanceX = -distanceX; - distanceY = -distanceY; - } - if ((scrollSensitivity > 0) && (cb.sqSize > 0)) { - scrollX += distanceX; - scrollY += distanceY; - final float scrollUnit = cb.sqSize * scrollSensitivity; - if (Math.abs(scrollX) >= Math.abs(scrollY)) { - // Undo/redo - int nRedo = 0, nUndo = 0; - while (scrollX > scrollUnit) { - nRedo++; - scrollX -= scrollUnit; - } - while (scrollX < -scrollUnit) { - nUndo++; - scrollX += scrollUnit; - } - if (nUndo + nRedo > 0) { - scrollY = 0; - setAutoMode(AutoMode.OFF); - } - if (nRedo + nUndo > 1) { - boolean analysis = gameMode.analysisMode(); - boolean human = gameMode.playerWhite() || gameMode.playerBlack(); - if (analysis || !human) - ctrl.setGameMode(new GameMode(GameMode.TWO_PLAYERS)); - } - if (scrollGames) { - if (nRedo > 0) { - UIAction nextGame = actionFactory.getAction("nextGame"); - if (nextGame.enabled()) - for (int i = 0; i < nRedo; i++) - nextGame.run(); - } - if (nUndo > 0) { - UIAction prevGame = actionFactory.getAction("prevGame"); - if (prevGame.enabled()) - for (int i = 0; i < nUndo; i++) - prevGame.run(); - } - } else { - for (int i = 0; i < nRedo; i++) ctrl.redoMove(); - for (int i = 0; i < nUndo; i++) ctrl.undoMove(); - } - ctrl.setGameMode(gameMode); - return nRedo + nUndo > 0; - } else { - // Next/previous variation - int varDelta = 0; - while (scrollY > scrollUnit) { - varDelta++; - scrollY -= scrollUnit; - } - while (scrollY < -scrollUnit) { - varDelta--; - scrollY += scrollUnit; - } - if (varDelta != 0) { - scrollX = 0; - setAutoMode(AutoMode.OFF); - ctrl.changeVariation(varDelta); - } - return varDelta != 0; - } - } - return false; - } - }); - cb.setOnTrackballListener(new ChessBoard.OnTrackballListener() { - public void onTrackballEvent(MotionEvent event) { - if (ctrl.humansTurn()) { - Move m = cb.handleTrackballEvent(event); - if (m != null) { - setAutoMode(AutoMode.OFF); - ctrl.makeHumanMove(m); - } - setEgtbHints(cb.getSelectedSquare()); - } - } - }); + ChessBoardPlayListener cbpListener = new ChessBoardPlayListener(this, cb); + cb.setOnTouchListener(cbpListener); + cb.setOnTrackballListener(cbpListener); moveList.setOnLongClickListener(v -> { reShowDialog(MOVELIST_MENU_DIALOG); @@ -1579,7 +1421,7 @@ public class DroidFish extends Activity engineOptions.networkID = id; } - private void setEgtbHints(int sq) { + void setEgtbHints(int sq) { if (!engineOptions.hints || (sq < 0)) { cb.setSquareDecorations(null); return; @@ -2164,7 +2006,7 @@ public class DroidFish extends Activity } static private final int PROMOTE_DIALOG = 0; - static private final int BOARD_MENU_DIALOG = 1; + static final int BOARD_MENU_DIALOG = 1; static private final int ABOUT_DIALOG = 2; static private final int SELECT_BOOK_DIALOG = 4; static private final int SELECT_ENGINE_DIALOG = 5; @@ -2192,7 +2034,7 @@ public class DroidFish extends Activity static private final int SELECT_FEN_FILE_DIALOG = 27; /** Remove and show a dialog. */ - private void reShowDialog(int id) { + void reShowDialog(int id) { removeDialog(id); showDialog(id); } diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/activities/EditBoard.java b/DroidFishApp/src/main/java/org/petero/droidfish/activities/EditBoard.java index f1df5d5..f4a3399 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/activities/EditBoard.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/activities/EditBoard.java @@ -228,6 +228,7 @@ public class EditBoard extends Activity { } }); cb.setOnTrackballListener(new ChessBoard.OnTrackballListener() { + @Override public void onTrackballEvent(MotionEvent event) { Move m = cb.handleTrackballEvent(event); if (m != null) diff --git a/DroidFishApp/src/main/java/org/petero/droidfish/view/ChessBoard.java b/DroidFishApp/src/main/java/org/petero/droidfish/view/ChessBoard.java index dd186c5..80517af 100644 --- a/DroidFishApp/src/main/java/org/petero/droidfish/view/ChessBoard.java +++ b/DroidFishApp/src/main/java/org/petero/droidfish/view/ChessBoard.java @@ -562,8 +562,8 @@ public abstract class ChessBoard extends View { protected abstract Move mousePressed(int sq); - public static class OnTrackballListener { - public void onTrackballEvent(MotionEvent event) { } + public interface OnTrackballListener { + void onTrackballEvent(MotionEvent event); } private OnTrackballListener otbl = null; public final void setOnTrackballListener(OnTrackballListener onTrackballListener) {