Move chessboard input event handler code to separate file

This commit is contained in:
Peter Osterlund 2020-01-27 23:39:23 +01:00
parent 2367a67b02
commit b9f9dff315
4 changed files with 211 additions and 172 deletions

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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());
}
}
}

View File

@ -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<String, UIAction> 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);
}

View File

@ -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)

View File

@ -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) {