Gridarta Editor
ShiftProcessor.java
Go to the documentation of this file.
1 /*
2  * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
3  * Copyright (C) 2000-2015 The Gridarta Developers.
4  *
5  * This program 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 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program 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 along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 package net.sf.gridarta.gui.misc;
21 
22 import java.awt.Point;
23 import java.awt.Rectangle;
24 import java.util.Collection;
25 import java.util.LinkedList;
26 import java.util.List;
37 import net.sf.gridarta.utils.Size2D;
38 import org.jetbrains.annotations.NotNull;
39 import org.jetbrains.annotations.Nullable;
40 
46 public class ShiftProcessor<G extends GameObject<G, A, R>, A extends MapArchObject<A>, R extends Archetype<G, A, R>> {
47 
51  @NotNull
53 
57  @NotNull
58  private final MapView<G, A, R> mapView;
59 
63  @NotNull
64  private final MapModel<G, A, R> mapModel;
65 
69  @NotNull
71 
75  @Nullable
76  private MapGrid mapGrid;
77 
81  @Nullable
82  private Rectangle selRec;
83 
87  private int dx;
88 
92  private int dy;
93 
101  public ShiftProcessor(@NotNull final MapViewSettings mapViewSettings, @NotNull final MapView<G, A, R> mapView, @NotNull final MapModel<G, A, R> mapModel, @NotNull final InsertionModeSet<G, A, R> insertionModeSet) {
102  this.mapViewSettings = mapViewSettings;
103  this.mapView = mapView;
104  this.mapModel = mapModel;
105  this.insertionModeSet = insertionModeSet;
106  }
107 
113  public boolean canShift(@NotNull final Direction dir) {
114  mapGrid = mapView.getMapGrid();
115  selRec = mapGrid.getSelectedRec();
116  if (selRec == null) {
117  return false;
118  }
119 
120  assert mapGrid != null;
121  final Size2D size = mapGrid.getSize();
122 
123  dx = dir.getDx();
124  dy = dir.getDy();
125  if (dx < 0) {
126  assert selRec != null;
127  if (selRec.x + dx < 0) {
128  return false;
129  }
130  } else if (dx > 0) {
131  assert selRec != null;
132  if (selRec.x + selRec.width + dx > size.getWidth()) {
133  return false;
134  }
135  }
136 
137  if (dy < 0) {
138  assert selRec != null;
139  if (selRec.y + dy < 0) {
140  return false;
141  }
142  } else if (dy > 0) {
143  assert selRec != null;
144  if (selRec.y + selRec.height + dy > size.getHeight()) {
145  return false;
146  }
147  }
148 
149  return true;
150  }
151 
157  public void shift(@NotNull final Direction dir) {
158  if (canShift(dir)) {
159  final Point pos = new Point();
160  mapModel.beginTransaction("Shift");
161  try {
162  mapGrid.beginTransaction();
163  try {
164  switch (dir) {
165  case NORTH:
166  for (int x = selRec.x; x < selRec.x + selRec.width; x++) {
167  pos.x = x;
168  pos.y = selRec.y;
169  shift(pos, selRec.height);
170  }
171  break;
172 
173  case EAST:
174  for (int y = selRec.y; y < selRec.y + selRec.height; y++) {
175  pos.x = selRec.x + selRec.width - 1;
176  pos.y = y;
177  shift(pos, selRec.width);
178  }
179  break;
180 
181  case SOUTH:
182  for (int x = selRec.x; x < selRec.x + selRec.width; x++) {
183  pos.x = x;
184  pos.y = selRec.y + selRec.height - 1;
185  shift(pos, selRec.height);
186  }
187  break;
188 
189  case WEST:
190  for (int y = selRec.y; y < selRec.y + selRec.height; y++) {
191  pos.x = selRec.x;
192  pos.y = y;
193  shift(pos, selRec.width);
194  }
195  break;
196 
197  case NORTH_EAST:
198  for (int x = selRec.x; x < selRec.x + selRec.width; x++) {
199  pos.x = x;
200  pos.y = selRec.y;
201  shift(pos, Math.min(x - selRec.x + 1, selRec.height));
202  }
203  for (int y = selRec.y + 1; y < selRec.y + selRec.height; y++) {
204  pos.x = selRec.x + selRec.width - 1;
205  pos.y = y;
206  shift(pos, Math.min(selRec.y + selRec.height - y, selRec.width));
207  }
208  break;
209 
210  case SOUTH_EAST:
211  for (int x = selRec.x; x < selRec.x + selRec.width; x++) {
212  pos.x = x;
213  pos.y = selRec.y + selRec.height - 1;
214  shift(pos, Math.min(x - selRec.x + 1, selRec.height));
215  }
216  for (int y = selRec.y + selRec.height - 2; y >= selRec.y; y--) {
217  pos.x = selRec.x + selRec.width - 1;
218  pos.y = y;
219  shift(pos, Math.min(y - selRec.y + 1, selRec.width));
220  }
221  break;
222 
223  case SOUTH_WEST:
224  for (int y = selRec.y; y < selRec.y + selRec.height; y++) {
225  pos.x = selRec.x;
226  pos.y = y;
227  shift(pos, Math.min(y - selRec.y + 1, selRec.width));
228  }
229  for (int x = selRec.x + 1; x < selRec.x + selRec.width; x++) {
230  pos.x = x;
231  pos.y = selRec.y + selRec.height - 1;
232  shift(pos, Math.min(selRec.x + selRec.width - x, selRec.height));
233  }
234  break;
235 
236  case NORTH_WEST:
237  for (int y = selRec.y + selRec.height - 1; y >= selRec.y; y--) {
238  pos.x = selRec.x;
239  pos.y = y;
240  shift(pos, Math.min(selRec.y + selRec.height - y, selRec.width));
241  }
242  for (int x = selRec.x + 1; x < selRec.x + selRec.width; x++) {
243  pos.x = x;
244  pos.y = selRec.y;
245  shift(pos, Math.min(selRec.x + selRec.width - x, selRec.height));
246  }
247  break;
248 
249  default:
250  throw new IllegalArgumentException();
251  }
252  } finally {
253  mapGrid.endTransaction();
254  }
255  } finally {
256  mapModel.endTransaction();
257  }
258  }
259 
260  mapGrid = null;
261  selRec = null;
262  dx = 0;
263  dy = 0;
264  }
265 
271  private void shift(final Point pos, final int len) {
272  final Collection<G> startGameObjects = new LinkedList<>();
273  final List<GameObject<G, A, R>> gameObjectsToDelete = new LinkedList<>();
274  final Collection<G> gameObjectsToInsert = new LinkedList<>();
275  final Point prevPos = new Point(pos.x + dx, pos.y + dy);
276  final Point startPos = new Point();
277  assert mapGrid != null;
278  final boolean startSelection = (mapGrid.getFlags(prevPos) & MapGrid.GRID_FLAG_SELECTION) > 0;
279  assert !startSelection;
280  boolean isStart = true;
281  for (int i = 0; i < len; i++) {
282  assert mapGrid != null;
283  final boolean thisSelection = (mapGrid.getFlags(pos) & MapGrid.GRID_FLAG_SELECTION) > 0;
284  assert mapGrid != null;
285  mapGrid.select(prevPos, thisSelection ? SelectionMode.ADD : SelectionMode.SUB);
286  gameObjectsToInsert.clear();
287  if (thisSelection) {
288  if (isStart) {
289  isStart = false;
290  startPos.setLocation(prevPos);
291  // [startGameObjects] = [prevPos]
292  assert startGameObjects.isEmpty();
293  for (final G gameObject : mapModel.getMapSquare(prevPos)) {
294  if (gameObject.isHead() && !gameObject.isInContainer() && mapViewSettings.isEditType(gameObject)) {
295  startGameObjects.add(gameObject);
296  gameObjectsToDelete.add(gameObject);
297  }
298  }
299  }
300  // [prevPos] = [pos]
301  for (final G gameObject : mapModel.getMapSquare(pos)) {
302  if (gameObject.isHead() && !gameObject.isInContainer() && mapViewSettings.isEditType(gameObject)) {
303  gameObjectsToInsert.add(gameObject);
304  gameObjectsToDelete.add(gameObject);
305  }
306  }
307  } else {
308  if (isStart) {
309  // ignore
310  } else {
311  isStart = true;
312  // [prevPos] = [startGameObjects]
313  gameObjectsToInsert.addAll(startGameObjects);
314  startGameObjects.clear();
315  }
316  }
317 
318  insertAllAndClear(gameObjectsToInsert, prevPos);
319 
320  while (!gameObjectsToDelete.isEmpty()) {
321  gameObjectsToDelete.remove(0).remove();
322  }
323 
324  prevPos.setLocation(pos);
325  pos.x -= dx;
326  pos.y -= dy;
327  }
328  if (!isStart) {
329  // [prevPos] = [startGameObjects]
330  insertAllAndClear(startGameObjects, prevPos);
331  }
332  assert startGameObjects.isEmpty();
333  assert mapGrid != null;
334  //noinspection ConstantConditions
335  mapGrid.select(prevPos, startSelection ? SelectionMode.ADD : SelectionMode.SUB);
336  }
337 
344  private void insertAllAndClear(@NotNull final Collection<G> gameObjects, @NotNull final Point point) {
345  for (final G gameObject : gameObjects) {
346  assert gameObject.isHead() && !gameObject.isInContainer() && mapViewSettings.isEditType(gameObject);
347  mapModel.insertBaseObject(gameObject, point, true, false, insertionModeSet.getTopmostInsertionMode());
348  }
349  gameObjects.clear();
350  }
351 
352 }
final MapView< G, A, R > mapView
The map view to operate on.
void shift(final Point pos, final int len)
Shift one row.
Rectangle getSelectedRec()
Returns the smallest rectangle containing selection.
Definition: MapGrid.java:514
A MapModel reflects the data of a map.
Definition: MapModel.java:75
Graphical User Interface of Gridarta.
void endTransaction()
End a transaction.
final InsertionModeSet< G, A, R > insertionModeSet
The InsertionModeSet to use.
MapGrid getMapGrid()
Returns the MapGrid of this view.
boolean isEditType(int editType)
Get information on the current state of edit type.
int getFlags(final int x, final int y)
Returns the flags of a square.
Definition: MapGrid.java:476
MapGrid mapGrid
The map grid to operate on.
void insertAllAndClear(@NotNull final Collection< G > gameObjects, @NotNull final Point point)
Inserts a collection of GameObjects into the map and clears the list.
Size2D getSize()
Returns size of grid.
Definition: MapGrid.java:504
G insertBaseObject(@NotNull BaseObject< G, A, R, ?> baseObject, @NotNull Point pos, boolean allowMany, boolean join, @NotNull InsertionMode< G, A, R > insertionMode)
Inserts a BaseObject to a map.
boolean canShift(@NotNull final Direction dir)
Check whether shifting is possible.
Base package of all Gridarta classes.
Reflects a game object (object on a map).
Definition: GameObject.java:36
Container for settings that affect the rendering of maps.
MapSquare< G, A, R > getMapSquare(@NotNull Point pos)
Get the square at a specified location.
InsertionMode< G, A, R > getTopmostInsertionMode()
Returns the "topmost" insertion mode.
GameObjects are the objects based on Archetypes found on maps.
int getWidth()
Returns the width of the area.
Definition: Size2D.java:96
2D-Grid containing flags for selection, pre-selection, cursor, warnings and errors.
Definition: MapGrid.java:45
Rectangle selRec
The selection rectangle to operate on.
Base classes for rendering maps.
void beginTransaction()
Starts a new transaction.
Definition: MapGrid.java:756
void select(@NotNull final Point pos, @NotNull final SelectionMode selectionMode)
Selects or deselects a single square.
Definition: MapGrid.java:408
void endTransaction()
Ends a transaction.
Definition: MapGrid.java:776
A map view consists of a map grid and a map cursor, and is attached to a map control.
Definition: MapView.java:43
ShiftProcessor(@NotNull final MapViewSettings mapViewSettings, @NotNull final MapView< G, A, R > mapView, @NotNull final MapModel< G, A, R > mapModel, @NotNull final InsertionModeSet< G, A, R > insertionModeSet)
Create a new instance.
void shift(@NotNull final Direction dir)
Shift the map contents by one square.
ADD
All squares that are preselected get selected.
final MapViewSettings mapViewSettings
The map view settings instance.
Modes that describe how squares get selected.
static final int GRID_FLAG_SELECTION
Selection - marks all selected squares.
Definition: MapGrid.java:98
SUB
All squares that are preselected get unselected.
void beginTransaction(@NotNull String name)
Starts a new transaction.
int getHeight()
Returns the height of the area.
Definition: Size2D.java:104
final MapModel< G, A, R > mapModel
The map model to operate on.
Performs a "shift" operation in a map: shift all selected squares into the given direction.
The class Size2D represents a 2d rectangular area.
Definition: Size2D.java:30