-
Notifications
You must be signed in to change notification settings - Fork 0
/
GUI.java
201 lines (168 loc) · 6.65 KB
/
GUI.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/* Skeleton Copyright (C) 2015, 2020 Paul N. Hilfinger and the Regents of the
* University of California. All rights reserved. */
package loa;
import ucb.gui2.TopLevel;
import ucb.gui2.LayoutSpec;
import java.awt.Dimension;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import java.io.InputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.concurrent.ArrayBlockingQueue;
import static loa.Piece.*;
/** The GUI controller for a LOA board and buttons.
* @author Heming Wu
*/
class GUI extends TopLevel implements View, Reporter {
/** Minimum size of board in pixels. */
private static final int MIN_SIZE = 500;
/** Size of pane used to contain help text. */
static final Dimension TEXT_BOX_SIZE = new Dimension(500, 700);
/** Resource name of "About" message. */
static final String ABOUT_TEXT = "loa/About.html";
/** Resource name of Loa help text. */
static final String HELP_TEXT = "loa/Help.html";
/** A new window with given TITLE providing a view of a Loa board. */
GUI(String title) {
super(title, true);
addMenuButton("Game->New", this::newGame);
addMenuButton("Game->Quit", this::quit);
addMenuButton("Help->About", this::about);
addMenuButton("Help->Loa", this::loa);
addMenuButton("Game->Undo", this::undo);
addMenuButton("Settings->Manual White", this::mW);
addMenuButton("Settings->Manual Black", this::mB);
addMenuButton("Settings->Auto White", this::aW);
addMenuButton("Settings->Auto Black", this::aB);
_widget = new BoardWidget(_pendingCommands);
add(_widget,
new LayoutSpec("y", 1,
"height", 1,
"width", 3));
addLabel("To move: White", "CurrentTurn",
new LayoutSpec("x", 0, "y", 0,
"height", 1,
"width", 3));
}
/** Response to "Undo" button click. */
private void undo(String dummy) {
_pendingCommands.offer("undo");
}
/** Response to "Quit" button click. */
private void quit(String dummy) {
_pendingCommands.offer("quit");
}
/** Response to "New Game" button click. */
private void newGame(String dummy) {
_pendingCommands.offer("new");
}
/** Response to "Help->About" button click. */
private void about(String dummy) {
displayText("About", "loa/About.html");
}
/** Response to "Help->Loa" button click. */
private void loa(String dummy) {
displayText("About LOA", "loa/Help.html");
}
/** Response to "Settings -> manual white" button click. */
private void mW(String dummy) {
_pendingCommands.offer("mw");
}
/** Response to "Settings -> manual Black" button click. */
private void mB(String dummy) {
_pendingCommands.offer("mb");
}
/** Response to "Settings -> Auto White" button click. */
private void aW(String dummy) {
_pendingCommands.offer("aw");
}
/** Response to "Settings -> Auto Black" button click. */
private void aB(String dummy) {
_pendingCommands.offer("ab");
}
/** Return the next command from our widget, waiting for it as necessary.
* The BoardWidget uses _pendingCommands to queue up moves that it
* receives. This class uses _pendingCommands to queue up commands that
* are generated by clicking on menu items. */
String readCommand() {
try {
_widget.setMoveCollection(true);
String cmnd = _pendingCommands.take();
_widget.setMoveCollection(false);
return cmnd;
} catch (InterruptedException excp) {
throw new Error("unexpected interrupt");
}
}
@Override
public void update(Game controller) {
Board board = controller.getBoard();
_widget.update(board);
if (board.winner() != null) {
setLabel("CurrentTurn",
String.format("Winner: %s",
board.winner().fullName()));
} else {
setLabel("CurrentTurn",
String.format("To move: %s", board.turn().fullName()));
}
boolean manualWhite = controller.manualWhite(),
manualBlack = controller.manualBlack();
}
/** Display text in resource named TEXTRESOURCE in a new window titled
* TITLE. */
private void displayText(String title, String textResource) {
/* Implementation note: It would have been more convenient to avoid
* having to read the resource and simply use dispPane.setPage on the
* resource's URL. However, we wanted to use this application with
* a nonstandard ClassLoader, and arranging for straight Java to
* understand non-standard URLS that access such a ClassLoader turns
* out to be a bit more trouble than it's worth. */
JFrame frame = new JFrame(title);
JEditorPane dispPane = new JEditorPane();
dispPane.setEditable(false);
dispPane.setContentType("text/html");
InputStream resource =
GUI.class.getClassLoader().getResourceAsStream(textResource);
StringWriter text = new StringWriter();
try {
while (true) {
int c = resource.read();
if (c < 0) {
dispPane.setText(text.toString());
break;
}
text.write(c);
}
} catch (IOException e) {
return;
}
JScrollPane scroller = new JScrollPane(dispPane);
scroller.setVerticalScrollBarPolicy(scroller.VERTICAL_SCROLLBAR_ALWAYS);
scroller.setPreferredSize(TEXT_BOX_SIZE);
frame.add(scroller);
frame.pack();
frame.setVisible(true);
}
@Override
public void reportError(String fmt, Object... args) {
showMessage(String.format(fmt, args), "Loa Error", "error");
}
@Override
public void reportNote(String fmt, Object... args) {
showMessage(String.format(fmt, args), "Loa Message", "information");
}
@Override
public void reportMove(Move unused) {
}
/** The board widget. */
private BoardWidget _widget;
/** Queue of pending commands resulting from menu clicks and moves on the
* board. We use a blocking queue because the responses to clicks
* on the board and on menus happen in parallel to the methods that
* call readCommand, which therefore needs to wait for clicks to happen. */
private ArrayBlockingQueue<String> _pendingCommands =
new ArrayBlockingQueue<>(5);
}