View Javadoc

1   /**********************************************
2    * Copyright (C) 2009 Lukas Laag
3    * This file is part of Vectomatic.
4    * 
5    * Vectomatic is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    * 
10   * Vectomatic is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   * 
15   * You should have received a copy of the GNU General Public License
16   * along with Vectomatic.  If not, see http://www.gnu.org/licenses/
17   **********************************************/
18  package org.vectomatic.client.rep.controller;
19  
20  import java.util.ArrayList;
21  import java.util.HashSet;
22  import java.util.Iterator;
23  import java.util.Set;
24  
25  import org.vectomatic.client.rep.RepApplication;
26  import org.vectomatic.client.rep.command.DeleteVertexCommand;
27  import org.vectomatic.client.rep.command.ICommand;
28  import org.vectomatic.client.rep.command.MoveVertexCommand;
29  import org.vectomatic.client.rep.view.Cursor;
30  import org.vectomatic.client.rep.view.DrawingView;
31  import org.vectomatic.common.events.IDrawingModelListener;
32  import org.vectomatic.common.model.Attribute;
33  import org.vectomatic.common.model.CloneShapeVisitor;
34  import org.vectomatic.common.model.DrawingModel;
35  import org.vectomatic.common.model.FloatAttributeValue;
36  import org.vectomatic.common.model.Shape;
37  import org.vectomatic.common.model.geometry.Point;
38  import org.vectomatic.common.model.geometry.Polyline;
39  import org.vectomatic.common.model.geometry.TransformMatrix;
40  import org.vectomatic.common.model.style.Color;
41  
42  import com.google.gwt.user.client.ui.KeyboardListener;
43  
44  /**
45   * Controller to respond to polyline edition requests and turn
46   * them into MoveVertexCommand and DeleteVertexCommand
47   */
48  public class EditPolylineController extends ControllerBase implements IDrawingModelListener {
49  	private static final int VERTEX_SIZE = 3;
50  	private CloneShapeVisitor _cloner;
51  	private MouseControllerButton _button;
52  	private Set<Integer> _vertexIndices;
53  	private Polyline _polyline;
54  	private Polyline _clone;
55  	private Point _p0;
56  	private TransformMatrix _mInv;
57  	private int _pickedVertex;
58  	
59  	public EditPolylineController(RepApplication app) {
60  		super(app);
61  		_cloner = new CloneShapeVisitor();
62  		_vertexIndices = new HashSet<Integer>();
63  		_p0 = new Point();
64  		_mInv = new TransformMatrix();
65  		_button = new MouseControllerButton(_app.getIcons().editPolylineIcon().createImage(), _app.getConstants().editPolylineCommand(), this);
66  		_app.getModel().addDrawingModelListener(this);
67  	}
68  	
69  	public MouseControllerButton getButton() {
70  		return _button;
71  	}
72  	
73  	@Override
74  	public void activate(DrawingView view) {
75  		view.setCursor(Cursor.CURSOR_POINTER);
76  		_app.getSelection().select(new ArrayList<Shape>());
77  		selectPolyline(null, null);
78  		_pickedVertex = -1;
79  	}
80  
81  	@Override
82  	public void deactivate(DrawingView view) {
83  		if (_pickedVertex != -1) {
84  			Point[] vertices = _polyline.getVertices();
85  			Point[] cloneVertices = _clone.getVertices();
86  			if (!vertices[_pickedVertex].equals(cloneVertices[_pickedVertex])) {
87  				ICommand command = new MoveVertexCommand(_app, this, _polyline, _clone, _vertexIndices);
88  				command.execute();
89  				_app.getHistory().addCommand(command);
90  			}
91  			_pickedVertex = -1;			
92  		}
93  	}
94  
95  	@Override
96  	public void render(DrawingView view) {
97  		if (_clone != null) {
98  			view.getRenderer().visitPolyline(_clone);
99  			Color.BLACK.acceptVisitor(view.getStrokeStyleVisitor());
100 			Point[] cloneVertices = _clone.getVertices();
101 			int length = cloneVertices.length - (_polyline.isClosed() ?  1 : 0);
102 			for (int i = 0; i < length; i++) {
103 				cloneVertices[i].transform(_clone.getTransform(), _p0);
104 				if (_vertexIndices.contains(new Integer(i))) {
105 					Color.GREEN.acceptVisitor(view.getFillStyleVisitor());
106 				} else {
107 					Color.WHITE.acceptVisitor(view.getFillStyleVisitor());
108 				}
109 				view.fillRect(_p0.x - VERTEX_SIZE, _p0.y - VERTEX_SIZE, VERTEX_SIZE * 2, VERTEX_SIZE * 2);
110 				view.strokeRect(_p0.x - VERTEX_SIZE, _p0.y - VERTEX_SIZE, VERTEX_SIZE * 2, VERTEX_SIZE * 2);
111 			}
112 		}
113 	}
114 
115 	@Override
116 	public void keyDown(DrawingView view, char keyCode, int modifiers) {
117 		if (keyCode == KeyboardListener.KEY_DELETE ||  keyCode == KeyboardListener.KEY_BACKSPACE && _app.getSelection().getSelectedShapes().size() > 0) {
118 			if (_polyline != null) {
119 				int size = _vertexIndices.size();
120 				if (size > 0) {
121 					int vertexCount = _polyline.getVertices().length - size;
122 					int minVertex = _polyline.isClosed() ? 4 : 2;
123 					if (vertexCount >= minVertex) {
124 						ICommand command = new DeleteVertexCommand(_app, this, _polyline, _vertexIndices);
125 						command.execute();
126 						_app.getHistory().addCommand(command);
127 					}
128 				}
129 			}
130 		}
131 	}
132 	
133 	public void selectPolyline(Polyline polyline, Set<Integer> vertexIndices) {
134 		if (polyline == null) {
135 			_polyline = null;
136 			_clone = null;
137 			_vertexIndices.clear();
138 		} else {
139 			_polyline = polyline;
140 			_cloner.visitPolyline(_polyline);
141 			_clone = (Polyline)_cloner.getClone();
142 			_clone.setAttribute(Attribute.FILL_OPACITY, new FloatAttributeValue(0.2f));
143 			_polyline.getTransform().invert(_mInv);
144 			_vertexIndices.clear();
145 			_vertexIndices.addAll(vertexIndices);
146 		}
147 	}
148 
149 	@Override
150 	public void mouseDown(DrawingView view, Point p, int modifiers) {
151 		view.toModelCoordinates(p);
152 		if (_polyline == null) {
153 			Shape shape = view.getPicker().pick(p, _app.getModel().reverseIterator());
154 			if (shape instanceof Polyline) {
155 				selectPolyline((Polyline)shape, new HashSet<Integer>());
156 			}
157 		} else {
158 			_pickedVertex = pickVertex(p);
159 			if (_pickedVertex == -1) {
160 				Shape shape = view.getPicker().pick(p, _app.getModel().reverseIterator());
161 				if (shape instanceof Polyline) {
162 					selectPolyline((Polyline)shape, new HashSet<Integer>());
163 				} else {
164 					selectPolyline(null, new HashSet<Integer>());
165 				}
166 			} else {
167 				Integer vertex = new Integer(_pickedVertex);
168 				boolean ctrlPressed = (modifiers & KeyboardListener.MODIFIER_CTRL) != 0;
169 				if (ctrlPressed) {
170 					if (_vertexIndices.contains(vertex)) {
171 						_vertexIndices.remove(vertex);						
172 					} else {
173 						_vertexIndices.add(vertex);
174 					}
175 				} else {
176 					_vertexIndices.add(vertex);
177 				}
178 			}
179 		}
180 	}
181 
182 	@Override
183 	public void mouseMove(DrawingView view, Point p, int modifiers) {
184 		view.toModelCoordinates(p);
185 		if (_pickedVertex != -1) {
186 			if (_vertexIndices.size() > 0) {
187 				p.transform(_mInv, _p0);
188 				Point[] vertices = _polyline.getVertices();
189 				_p0.subtract(vertices[_pickedVertex]);
190 				Point[] cloneVertices = _clone.getVertices();
191 				boolean closed = _polyline.isClosed();
192 				Iterator<Integer> iterator = _vertexIndices.iterator();
193 				while (iterator.hasNext()) {
194 					int index = iterator.next().intValue();
195 					vertices[index].add(_p0, cloneVertices[index]);
196 					if (index == 0 && closed) {
197 						vertices[vertices.length - 1].add(_p0, cloneVertices[vertices.length - 1]);
198 					}
199 				}
200 			}
201 		} else if (_polyline != null) {
202 			float tol = VERTEX_SIZE;
203 			p.transform(_mInv, _p0);
204 			Point[] vertices = _polyline.getVertices();
205 			for (int i = 0; i < vertices.length; i++) {
206 				if ((vertices[i].x - tol < _p0.x) && (_p0.x < vertices[i].x + tol)
207 				 && (vertices[i].y - tol < _p0.y) && (_p0.y < vertices[i].y + tol)) {
208 					view.setCursor(Cursor.CURSOR_MOVE);
209 					return;
210 				}
211 			}
212 			view.setCursor(Cursor.CURSOR_POINTER);
213 		}
214 	}
215 
216 	@Override
217 	public void mouseUp(DrawingView view, Point p, int modifiers) {
218 		deactivate(view);
219 	}
220 	
221 	private int pickVertex(Point p) {
222 		int pickedVertex = -1;
223 		p.transform(_mInv, _p0);
224 		Point[] vertices = _polyline.getVertices();
225 		float tol = VERTEX_SIZE;
226 		for (int i = 0; i < vertices.length; i++) {
227 			if ((vertices[i].x - tol < _p0.x) && (_p0.x < vertices[i].x + tol)
228 			 && (vertices[i].y - tol < _p0.y) && (_p0.y < vertices[i].y + tol)) {
229 				pickedVertex = i;
230 				break;
231 			}
232 		}
233 		return pickedVertex;
234 	}
235 
236 	public void modelHasChanged(DrawingModel model) {
237 		if (_polyline != null && (!model.contains(_polyline))) {
238 			selectPolyline(null, null);
239 		}
240 	}
241 }