-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEditor.java
320 lines (290 loc) · 9.84 KB
/
Editor.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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
* Client-server graphical editor
*
* @author Chris Bailey-Kellogg, Dartmouth CS 10, Fall 2012; loosely based on CS 5 code by Tom Cormen
* @author CBK, winter 2014, overall structure substantially revised
* @author Travis Peters, Dartmouth CS 10, Winter 2015; remove EditorCommunicatorStandalone (use echo server for testing)
* @author CBK, spring 2016 and Fall 2016, restructured Shape and some of the GUI
*
* Code completed by:
* @author Josh Pfefferkorn
* CS10, Fall 2020
*/
public class Editor extends JFrame {
private static String serverIP = "localhost"; // IP address of sketch server
// "localhost" for your own machine;
// or ask a friend for their IP address
private static final int width = 800, height = 800; // canvas size
// Current settings on GUI
public enum Mode {
DRAW, MOVE, RECOLOR, DELETE
}
private Mode mode = Mode.DRAW; // drawing/moving/recoloring/deleting objects
private String shapeType = "ellipse"; // type of object to add
private Color color = Color.black; // current drawing color
// Drawing state
// these are remnants of my implementation; take them as possible suggestions or ignore them
private Shape curr = null; // current shape (if any) being drawn
private Sketch sketch; // holds and handles all the completed objects
private int movingId = -1; // current shape id (if any; else -1) being moved
private Point drawFrom = null; // where the drawing started
private Point moveFrom = null; // where object is as it's being dragged
// Communication
private EditorCommunicator comm; // communication with the sketch server
public Editor() {
super("Graphical Editor");
sketch = new Sketch();
// Connect to server
comm = new EditorCommunicator(serverIP, this);
comm.start();
// Helpers to create the canvas and GUI (buttons, etc.)
JComponent canvas = setupCanvas();
JComponent gui = setupGUI();
// Put the buttons and canvas together into the window
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
cp.add(canvas, BorderLayout.CENTER);
cp.add(gui, BorderLayout.NORTH);
// Usual initialization
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
/**
* Creates a component to draw into
*/
private JComponent setupCanvas() {
JComponent canvas = new JComponent() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawSketch(g);
}
};
canvas.setPreferredSize(new Dimension(width, height));
canvas.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent event) {
handlePress(event.getPoint());
}
public void mouseReleased(MouseEvent event) {
handleRelease();
}
});
canvas.addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent event) {
handleDrag(event.getPoint());
}
});
return canvas;
}
/**
* Creates a panel with all the buttons
*/
private JComponent setupGUI() {
// Select type of shape
String[] shapes = {"ellipse", "freehand", "rectangle", "segment"};
JComboBox<String> shapeB = new JComboBox<String>(shapes);
shapeB.addActionListener(e -> shapeType = (String)((JComboBox<String>)e.getSource()).getSelectedItem());
// Select drawing/recoloring color
// Following Oracle example
JButton chooseColorB = new JButton("choose color");
JColorChooser colorChooser = new JColorChooser();
JLabel colorL = new JLabel();
colorL.setBackground(Color.black);
colorL.setOpaque(true);
colorL.setBorder(BorderFactory.createLineBorder(Color.black));
colorL.setPreferredSize(new Dimension(25, 25));
JDialog colorDialog = JColorChooser.createDialog(chooseColorB,
"Pick a Color",
true, //modal
colorChooser,
e -> { color = colorChooser.getColor(); colorL.setBackground(color); }, // OK button
null); // no CANCEL button handler
chooseColorB.addActionListener(e -> colorDialog.setVisible(true));
// Mode: draw, move, recolor, or delete
JRadioButton drawB = new JRadioButton("draw");
drawB.addActionListener(e -> mode = Mode.DRAW);
drawB.setSelected(true);
JRadioButton moveB = new JRadioButton("move");
moveB.addActionListener(e -> mode = Mode.MOVE);
JRadioButton recolorB = new JRadioButton("recolor");
recolorB.addActionListener(e -> mode = Mode.RECOLOR);
JRadioButton deleteB = new JRadioButton("delete");
deleteB.addActionListener(e -> mode = Mode.DELETE);
ButtonGroup modes = new ButtonGroup(); // make them act as radios -- only one selected
modes.add(drawB);
modes.add(moveB);
modes.add(recolorB);
modes.add(deleteB);
JPanel modesP = new JPanel(new GridLayout(1, 0)); // group them on the GUI
modesP.add(drawB);
modesP.add(moveB);
modesP.add(recolorB);
modesP.add(deleteB);
// Put all the stuff into a panel
JComponent gui = new JPanel();
gui.setLayout(new FlowLayout());
gui.add(shapeB);
gui.add(chooseColorB);
gui.add(colorL);
gui.add(modesP);
return gui;
}
/**
* Getter for the sketch instance variable
*/
public Sketch getSketch() {
return sketch;
}
/**
* Draws all the shapes in the sketch,
* along with the object currently being drawn in this editor (not yet part of the sketch)
*/
public void drawSketch(Graphics g) {
// TODO: DRAW sketch
// call sketch's draw method to draw all its shapes
sketch.draw(g);
// draw the current shape if it exists
if (curr != null) {
curr.draw(g);
}
}
// Helpers for event handlers
/**
* Helper method for press at point
* In drawing mode, start a new object;
* in moving mode, (request to) start dragging if clicked in a shape;
* in recoloring mode, (request to) change clicked shape's color
* in deleting mode, (request to) delete clicked shape
*/
private void handlePress(Point p) {
// TODO: YOUR CODE HERE
// in drawing mode, start drawing a new shape
if (mode == Mode.DRAW) {
// if ellipse, make curr an "empty" ellipse using the one point constructor
if (shapeType.equals("ellipse")) {
curr = new Ellipse((int) p.getX(), (int) p.getY(), color);
}
// if rectangle, make curr an "empty" rectangle using the one point constructor
else if (shapeType.equals("rectangle")) {
curr = new Rectangle((int) p.getX(), (int) p.getY(), color);
}
// if segment, make curr an "empty" segment using the one point constructor
else if (shapeType.equals("segment")) {
curr = new Segment((int) p.getX(), (int) p.getY(), color);
}
// if freehand, make curr an "empty" polyline using the one point constructor
else if (shapeType.equals("freehand")) {
curr = new Polyline((int) p.getX(), (int) p.getY(), color);
}
drawFrom = p;
}
// in moving mode, start dragging if clicked in the shape
else if (mode == Mode.MOVE) {
// get the ID of the clicked shape
int selectedID = sketch.getID((int)p.getX(),(int)p.getY());
// if a shape is selected
if (selectedID != -1) {
// update moving ID and moveFrom
movingId = selectedID;
moveFrom = p;
}
}
// in recoloring mode, change the shape's color if clicked in it
else if (mode == Mode.RECOLOR) {
// get the ID of the clicked shape
int selectedID = sketch.getID((int)p.getX(),(int)p.getY());
// if a shape is selected
if (selectedID != -1) {
// request to recolor it
comm.send("recolor " + selectedID + " " + color.getRGB());
}
}
// in deleting mode, delete the shape if clicked in it
else if (mode == Mode.DELETE) {
// get the ID of the clicked shape
int selectedID = sketch.getID((int)p.getX(),(int)p.getY());
// if a shape is selected
if (selectedID != -1) {
// request to delete it
comm.send("delete " + selectedID);
}
}
// repaint the editor
repaint();
}
/**
* Helper method for drag to new point
* In drawing mode, update the other corner of the object;
* in moving mode, (request to) drag the object
*/
private void handleDrag(Point p) {
// TODO: YOUR CODE HERE
// in drawing mode, revise the shape as it is stretched out
if (mode == Mode.DRAW) {
// if ellipse, continuously update the corner that hadn't yet been defined
if (shapeType.equals("ellipse")) {
((Ellipse)curr).setCorners((int)drawFrom.getX(), (int)drawFrom.getY(),(int)p.getX(),(int)p.getY());
}
else if (shapeType.equals("rectangle")) {
// if rectangle, continuously update the corner that hadn't yet been defined
((Rectangle)curr).setCorners((int)drawFrom.getX(), (int)drawFrom.getY(),(int)p.getX(),(int)p.getY());
}
else if (shapeType.equals("segment")) {
// if segment, continuously update the endpoint
((Segment)curr).setEnd((int)p.getX(),(int)p.getY());
}
else if (shapeType.equals("freehand")) {
// if freehand, continuously add points
((Polyline)curr).addPoint(p);
}
}
// in moving mode, shift the object and keep track of where next step is from
else if (mode == mode.MOVE) {
// if a shape designated to be moved
if (movingId != -1) {
// request to move it
comm.send("move " + movingId + " " + (int)(p.getX() - moveFrom.getX()) + " " + (int)(p.getY() - moveFrom.getY()));
// continuously update moveFrom
moveFrom = p;
}
}
// repaint editor
repaint();
}
/**
* Helper method for release
* In drawing mode, pass the add new object request on to the server;
* in moving mode, release it
*/
private void handleRelease() {
// TODO: YOUR CODE HERE
// in drawing mode
if (mode == Mode.DRAW) {
// request to add the completed shape
comm.send("add " + curr);
// null out curr
curr = null;
}
// in moving mode, stop dragging the object
else if (mode == Mode.MOVE) {
// reset cur, drawFrom, moveFrom, and movingId
curr = null;
drawFrom = null;
moveFrom = null;
movingId = -1;
}
// repaint editor
repaint();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Editor();
}
});
}
}