📄 gamewindow.java
字号:
// Implement the PopupContributor interface
//
public boolean allowMoreItems (Component c) { return true; }
public void populatePopupMenu (PopupMenu p, Component comp, int x, int y) {
popupHandler.populatePopup(p, comp, x, y);
}
// This class isn't strictly necessary. It's just here to encapsulate
// some popup menu code. Notably the menu items which may have the same
// names as some in the outer class.
class PopupHandler {
private VariationMenuItem deleteVarItem;
private VariationMenuItem sendVarItem;
private MenuCommand deleteAllItem;
// I'm assuming that it could confuse AWT if a menu item is used in
// more than one menu, therefore creating a second one for "Copy as SGF".
private MenuCommand browseItem;
private MenuCommand copySGFItem;
private MenuCommand statsBlackItem;
private MenuCommand statsWhiteItem;
private MenuCommand showObsItem;
private MenuCommand reloadItem;
// A place to save the row and column (on the goban) where the
// popup was activated, since the actionPerformed() method doesn't
// have access to the X and Y of the mouse click event.
//
// This hack is no longer needed, since the menu items are implemented
// as MenuCommands and their executeCommand methods receive the event
// object, with the X and Y coords of the mouse click. -sigue
private int row, col;
public PopupHandler () {
// Each of the menu items is implemented as an anonymous subclass of MenuCommand.
deleteVarItem = new VariationMenuItem("Delete variation", null) {
public void executeCommand (Object event) {
Move m = getVariation();
Move p = m.parent();
setVariation(null);
if (p != null) {
p.removeVariation(m);
// +++Kludge. I can't remember at the moment how to update the
// board correctly. This (almost) works, but the code below it doesn't.
goBackward(1, false);
goForward(1);
/*
PositionVector placed = m.placedPositions(getSize());
if (placed != null) {
boolean decorate = false;
for (int i = 0; i < placed.size(); i++) {
Position p1 = placed.elementAt(i);
invalidateInternal(p1.row, p1.column);
if (decorations.isMember(p1))
decorate = true;
}
if (decorate)
decorateStone(offg);
updateInternal();
}
*/
}
}
};
sendVarItem = new VariationMenuItem("Insert variation as kibitz", null) {
public void executeCommand (Object event) {
insertVariationAsKibitz(getVariation());
}
};
browseItem = new MenuCommand("Browse to position") {
public void executeCommand (Object event) {
goToMove(game.findMove(row, col));
}
};
deleteAllItem = new MenuCommand("") { // uses setLabel() later
public void executeCommand (Object event) {
// Delete all groups in the region that are the same color as the
// one just clicked on. Generate a RemovalMove for each such group.
SimpleGroupVector deadGroups = game.groupsInRegion(new Position(row, col));
Move parent = game.getCurrentMove();
if (deadGroups != null) {
for (int i = 0; i < deadGroups.size(); i++)
if (conn != null
&& isNetGame()
&& isParticipating()
&& !isBrowsing())
conn.send(deadGroups.elementAt(i).positionAt(0).toString(), false);
else {
RemovalMove move
= new RemovalMove(parent, deadGroups.elementAt(i).positionAt(0),
parent.moveNumber() + 1, true);
placeMove(move, false);
parent = move;
}
game.ss.emit();
}
}
};
copySGFItem = new MenuCommand ("Copy (as SGF)") {
public void executeCommand (Object event) {
copyAsSGF();
}
};
if (Ergo.inApplet)
copySGFItem.setEnabled(false); // causes security violation
statsBlackItem = new MenuCommand("Stats " + game.blackName) {
public void executeCommand (Object event) {
conn.send("stats " + game.blackName, true);
}
};
statsWhiteItem = new MenuCommand("Stats " + game.whiteName) {
public void executeCommand (Object event) {
conn.send("stats " + game.whiteName, true);
}
};
showObsItem = new MenuCommand("Show Observers") {
public void executeCommand (Object event) {
conn.send("all " + gameNumber, true);
}
};
reloadItem = new MenuCommand("Load " + game.whiteName + "-" + game.blackName) {
public void executeCommand (Object event) {
conn.send("load " + game.whiteName + "-" + game.blackName);
}
};
}
public void populatePopup (PopupMenu popup, Component comp, int x, int y) {
row = boardCanvas.ytorow(y);
col = boardCanvas.xtocol(x);
if (comp == boardCanvas) {
int stoneUnderMouse = game.ss.readStone(row, col);
// "Browse to position" -- active on any stone
// +++ Needs to be made to work on empty positions (i.e. browse forward)
if (stoneUnderMouse != Move.EMPTY)
popup.add(browseItem);
// "Delete variation" -- active on variation letters only
for(int i = -1; ; i++) {
Move m = game.getCurrentMove().variationAt(i);
if (m == null)
break;
else {
PositionVector placed = m.placedPositions(game.getSize());
if (placed != null)
for (int j = 0; j < placed.size(); j++) {
Position pos = placed.elementAt(j);
if (pos.row == row && pos.column == col) {
deleteVarItem.setVariation(m);
sendVarItem.setVariation(m);
popup.add(deleteVarItem);
popup.add(sendVarItem);
break;
}
}
}
}
// "Remove All" -- active on stones during scoring mode
if (stoneUnderMouse != Move.EMPTY && game.scoringMode()) {
String text = ("Remove "
+ (stoneUnderMouse == Move.WHITE ? "white" : "black")
+ " groups in region");
deleteAllItem.setLabel(text);
popup.add(deleteAllItem);
}
// Copy as SGF item. Active on goban only.
popup.add(copySGFItem);
} // end if on goban
if (isNetGame()) {
if (popup.getItemCount() > 0)
popup.addSeparator();
popup.add(statsBlackItem);
popup.add(statsWhiteItem);
popup.add(showObsItem);
if (gameStatus == ADJOURNED)
popup.add(reloadItem);
}
}
} // end inner class PopupHandler
/*****************************************************
* Manage changes to Game Status/ Result *
*****************************************************/
// placeMove() also changes gameStatus to PLAYING.
public void adjourn () {
statusPanel.stopTicking();
if (gameStatus != GAMEOVER)
gameStatus = ADJOURNED;
// conn.control.sgc.uninform(this);
statusPanel.refresh();
}
public void resign (String result) {
game.setResult(result);
statusPanel.stopTicking();
gameStatus = GAMEOVER;
// conn.control.sgc.uninform(this);
statusPanel.refresh();
}
public void ensureActive () {
int color = game.currentMove().color();
statusPanel.startTicking(color);
statusPanel.stopTicking(Move.nextColor(color));
if (gameStatus != PLAYING) {
gameStatus = PLAYING;
statusPanel.refresh();
conn.control.sgc.inform(this);
}
}
public int timeLeft () {
// +++ to do
//System.currentTimeMillis()...
return 0;
}
/*****************************************************
* Useful properties of this game *
*****************************************************/
public boolean isOnServer() { return gameStatus == PLAYING && !isLocalGame(); }
// Whether or not the user is a participant in this game.
public boolean isParticipating () { return isParticipating; }
// can return Move.BOTH, indicating we are playing both sides!
public int ourColor() { return ourColor; }
// This may be called after a game begins if users type "fteach".
public void setOurColor (int c) {
if (c == Move.BLACK || c == Move.WHITE || c == Move.BOTH)
ourColor = c;
}
public boolean isTeachingGame () { return ourColor() == Move.BOTH; }
// +++ Uh, isNetGame and isLocalGame should be inverses.
public boolean isNetGame () { return game.isNetGame(); }
public boolean isLocalGame () { return conn == null; }
public boolean isBrowsing () {
return browsing
|| !isNetGame()
|| gameStatus == ADJOURNED
|| gameStatus == GAMEOVER
|| game.finalServerMove() != game.getCurrentMove();
}
public void setBrowsing (boolean b) {
browsing = b;
browsingItem.setState(isBrowsing());
/***
if (browseButton != null)
browseButton.setLabel(browsing ? "Stop Browsing" : "Browse");
***/
}
private void exitBrowsingMode () {
if (isBrowsing()) {
// +++ Extremely heavyweight way to return to the final server move.
goBackward(-1, false);
goToEnd();
}
}
private void setSound (boolean b) {
sound = b;
soundItem.setState(b);
}
/*************************
* Manage Window Title. *
*************************/
public String title () { return title(true); }
public String title (boolean includeGameNumber) {
StringBuffer b = new StringBuffer();
if (includeGameNumber && isNetGame())
b.append("Game " + gameNumber + " -- ");
b.append(game.whiteName + " (W");
if (game.whiteRank != null)
b.append(" " + game.whiteRank);
b.append(") vs " + game.blackName + " (B");
if (game.blackName != null)
b.append(" " + game.blackRank);
b.append(")");
return b.toString();
}
public String toString () { return title(); }
public void updateTitle () { setTitle(title()); }
// The Function Formerly Known As noteMove.
public void noteCurrentMoveChanged () {
updateKibitzArea();
if (game.getCurrentMove() instanceof RootMove)
handicapMenu.setEnabled(true);
else
handicapMenu.setEnabled(false);
}
/***********************************************************
* Move/Variation manipulation *
***********************************************************/
// Insert a variation into the command line as a kibitz.
private void insertVariationAsKibitz (Move m) {
int caret = inputField.getCaretPosition();
String s = m.toVariationString();
String input = inputField.getText();
inputField.setText(input.substring(0, caret) + s + input.substring(caret));
inputField.setCaretPosition(caret + s.length());
}
/**
* Place a move on the board associated with this gamewindow.
* This is called when a move is received from the server.
*/
public void placeMove (Move m, boolean fromServer) {
if (fromServer)
gameStatus = PLAYING; // in case it was ADJOURNED
game.placeMove(m, window, isBrowsing(), fromServer);
if (m instanceof PassMove)
kibitzArea.appendText(m.moveNumber()
+ ((m.color() == Move.BLACK) ? " Black" : " White")
+ " passes");
// if (Ergo.opser.getBooleanOption(Ergo.opser.soundString))
// Toolkit.getDefaultToolkit().beep();
statusPanel.refresh();
noteCurrentMoveChanged();
needsSaving = true;
if (!Ergo.inApplet) {
saveItem.setEnabled(true);
saveAsItem.setEnabled(true);
}
}
/**
* Place a move on the board given the row and column of the move.
* This is called when the local user clicks on a board position.
* Note that if you click on a position that contains a variation
* (whether or not the variation letter is drawn on the board) then
* it has the same effect as choosing that variation from the
* Variations menu, unless it's a server game and you're not browsing.
*
*/
public void placeMove (int row, int column) {
Move parent = game.getCurrentMove();
// It's a local game or the user is browsing. No need to send the
// move to the server. If the user clicked on a variation (whether
// or not the variation letter is showing) then it's the same as if
// they chose that variation from the Variations menu.
if (game.scoringMode()
&& game.ss.readStone(row, column) != Move.EMPTY) {
if (conn != null && isNetGame() && isParticipating() && !isBrowsing())
conn.send(new Position(row, column).toString(), false);
else {
placeMove(new RemovalMove(parent, new Position(row, column),
parent.moveNumber() + 1, true),
false);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -