20 package net.sf.gridarta.model.mapgrid;
22 import java.awt.Point;
23 import java.awt.Rectangle;
24 import java.util.ArrayList;
25 import java.util.List;
28 import org.jetbrains.annotations.NotNull;
29 import org.jetbrains.annotations.Nullable;
75 private final Rectangle
recChange =
new Rectangle();
183 gridFlags =
new int[gridSize.getWidth()][gridSize.getHeight()];
191 listenerList.
add(listener);
199 listenerList.
remove(listener);
216 if (gridSize.
equals(newSize)) {
220 final int[][] newGridFlags =
new int[newSize.getWidth()][newSize.getHeight()];
221 final Point pos =
new Point();
223 if (newSize.getWidth() < gridSize.
getWidth()) {
226 if (newSize.getHeight() < gridSize.
getHeight()) {
229 for (pos.x = 0; pos.x < minSize.
getWidth(); pos.x++) {
230 for (pos.y = 0; pos.y < minSize.
getHeight(); pos.y++) {
231 newGridFlags[pos.x][pos.y] = gridFlags[pos.x][pos.y];
234 gridFlags = newGridFlags;
236 cachedSelectedRecValid =
false;
246 listener.mapGridChanged(e);
256 listener.mapGridResized(e);
280 unsetFlags(pos.x, pos.y, pos.x, pos.y, GRID_FLAG_CURSOR);
281 }
catch (
final ArrayIndexOutOfBoundsException ignored) {
284 if (cachedCursorLoc != null && cachedCursorLoc.equals(pos)) {
285 cachedCursorLoc = null;
299 setFlags(pos.x, pos.y, pos.x, pos.y, GRID_FLAG_CURSOR);
300 cachedCursorLoc =
new Point(pos);
313 public void preSelect(@NotNull
final Point start, @NotNull
final Point end) {
317 setFlags(cornerMin.x, cornerMin.y, cornerMax.x, cornerMax.y, GRID_FLAG_SELECTING);
334 public void updatePreSelect(@NotNull
final Point start, @NotNull
final Point oldEnd, @NotNull
final Point newEnd) {
335 final Point old1 =
new Point(Math.min(start.x, oldEnd.x), Math.min(start.y, oldEnd.y));
336 final Point old2 =
new Point(Math.max(start.x, oldEnd.x), Math.max(start.y, oldEnd.y));
337 final Point new1 =
new Point(Math.min(start.x, newEnd.x), Math.min(start.y, newEnd.y));
338 final Point new2 =
new Point(Math.max(start.x, newEnd.x), Math.max(start.y, newEnd.y));
342 if (old1.x < new1.x) {
343 unsetFlags(old1.x, old1.y, new1.x - 1, old2.y, GRID_FLAG_SELECTING);
346 if (new2.x < old2.x) {
347 unsetFlags(new2.x + 1, old1.y, old2.x, old2.y, GRID_FLAG_SELECTING);
350 if (old1.y < new1.y) {
351 unsetFlags(old1.x, old1.y, old2.x, new1.y - 1, GRID_FLAG_SELECTING);
354 if (new2.y < old2.y) {
355 unsetFlags(old1.x, new2.y + 1, old2.x, old2.y, GRID_FLAG_SELECTING);
360 if (new1.x < old1.x) {
361 setFlags(new1.x, new1.y, old1.x - 1, new2.y, GRID_FLAG_SELECTING);
364 if (old2.x < new2.x) {
365 setFlags(old2.x + 1, new1.y, new2.x, new2.y, GRID_FLAG_SELECTING);
368 if (new1.y < old1.y) {
369 setFlags(new1.x, new1.y, new2.x, old1.y - 1, GRID_FLAG_SELECTING);
372 if (old2.y < new2.y) {
373 setFlags(new1.x, old2.y + 1, new2.x, new2.y, GRID_FLAG_SELECTING);
378 assert old1.x == new1.x;
379 assert old2.x == new2.x;
380 assert old1.y == new1.y;
381 assert old2.y == new2.y;
393 public void unPreSelect(@NotNull
final Point start, @NotNull
final Point end) {
397 unsetFlags(cornerMin.x, cornerMin.y, cornerMax.x, cornerMax.y, GRID_FLAG_SELECTING);
422 switch (selectionMode) {
424 setFlags(cornerMin.x, cornerMin.y, cornerMax.x, cornerMax.y, GRID_FLAG_SELECTION);
427 unsetFlags(cornerMin.x, cornerMin.y, cornerMax.x, cornerMax.y, GRID_FLAG_SELECTION);
430 toggleFlags(cornerMin.x, cornerMin.y, cornerMax.x, cornerMax.y, GRID_FLAG_SELECTION);
444 private void calculateRec(@NotNull
final Point p1, @NotNull
final Point p2) {
467 return (gridFlags[p.x][p.y] & GRID_FLAG_ERROR) != 0;
477 return gridFlags[x][y];
486 return gridFlags[p.x][p.y];
496 return new Rectangle(recChange);
516 if (cachedSelectedRec != null) {
517 return new Rectangle(cachedSelectedRec);
519 if (cachedCursorLoc != null) {
520 return new Rectangle(cachedCursorLoc.x, cachedCursorLoc.y, 1, 1);
529 if (cachedSelectedRecValid) {
532 cachedSelectedRecValid =
true;
535 for (
int x = 0; x < gridSize.
getWidth(); x++) {
536 for (
int y = 0; y < gridSize.
getHeight(); y++) {
537 if ((gridFlags[x][y] & GRID_FLAG_SELECTION) > 0) {
547 cachedSelectedRec = null;
552 for (
int x = gridSize.
getWidth() - 1; x >= x1; x--) {
553 for (
int y = 0; y < gridSize.
getHeight(); y++) {
554 if ((gridFlags[x][y] & GRID_FLAG_SELECTION) > 0) {
564 for (
int y = 0; y < gridSize.
getHeight(); y++) {
565 for (
int x = 0; x < gridSize.
getWidth(); x++) {
566 if ((gridFlags[x][y] & GRID_FLAG_SELECTION) > 0) {
576 for (
int y = gridSize.
getHeight() - 1; y >= y1; y--) {
577 for (
int x = 0; x < gridSize.
getWidth(); x++) {
578 if ((gridFlags[x][y] & GRID_FLAG_SELECTION) > 0) {
587 cachedSelectedRec =
new Rectangle(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
622 setFlags(x, y, x, y, GRID_FLAG_ERROR);
650 recChange.height = 0;
659 if (recChange.x > x) {
662 if (recChange.y > y) {
665 if (recChange.width < x) {
668 if (recChange.height < y) {
669 recChange.height = y;
679 recChange.width = recChange.width - recChange.x + 1;
680 recChange.height = recChange.height - recChange.y + 1;
681 return recChange.width > 0 && recChange.height > 0;
692 private void setFlags(
final int minX,
final int minY,
final int maxX,
final int maxY,
final int flags) {
693 for (
int x = minX; x <= maxX; x++) {
694 for (
int y = minY; y <= maxY; y++) {
695 if ((gridFlags[x][y] & flags) != flags) {
696 if ((flags & GRID_FLAG_SELECTION) != 0 && (gridFlags[x][y] & GRID_FLAG_SELECTION) == 0) {
699 gridFlags[x][y] |= flags;
701 cachedSelectedRecValid =
false;
715 private void unsetFlags(
final int minX,
final int minY,
final int maxX,
final int maxY,
final int flags) {
716 for (
int x = minX; x <= maxX; x++) {
717 for (
int y = minY; y <= maxY; y++) {
718 if ((gridFlags[x][y] & flags) != 0) {
719 if ((flags & GRID_FLAG_SELECTION) != 0 && (gridFlags[x][y] & GRID_FLAG_SELECTION) != 0) {
722 gridFlags[x][y] &= ~flags;
724 cachedSelectedRecValid =
false;
738 private void toggleFlags(
final int minX,
final int minY,
final int maxX,
final int maxY,
final int flags) {
739 for (
int x = minX; x <= maxX; x++) {
740 for (
int y = minY; y <= maxY; y++) {
742 gridFlags[x][y] ^= flags;
745 cachedSelectedRecValid =
false;
757 if (transactionDepth == 0) {
758 transactionThread = Thread.currentThread();
763 if (transactionThread != Thread.currentThread()) {
764 throw new IllegalStateException(
"A transaction must only be used by one thread.");
777 if (transactionDepth <= 0) {
778 throw new IllegalStateException(
"Tried to end a transaction but no transaction was open.");
781 assert transactionDepth >= 0;
782 if (transactionDepth == 0) {
783 transactionDepth = 0;
784 transactionThread = null;
799 updateSelectionFlag(x, y, newState, x, y - 1, GRID_FLAG_SELECTION_NORTH, GRID_FLAG_SELECTION_SOUTH);
800 updateSelectionFlag(x, y, newState, x, y + 1, GRID_FLAG_SELECTION_SOUTH, GRID_FLAG_SELECTION_NORTH);
801 updateSelectionFlag(x, y, newState, x - 1, y, GRID_FLAG_SELECTION_WEST, GRID_FLAG_SELECTION_EAST);
802 updateSelectionFlag(x, y, newState, x + 1, y, GRID_FLAG_SELECTION_EAST, GRID_FLAG_SELECTION_WEST);
816 private void updateSelectionFlag(
final int x,
final int y,
final boolean newState,
final int dx,
final int dy,
final int flag,
final int dFlag) {
820 gridFlags[dx][dy] &= ~dFlag;
823 gridFlags[x][y] |= flag;
828 gridFlags[dx][dy] |= dFlag;
831 gridFlags[x][y] &= ~flag;
843 final List<Point> selection =
new ArrayList<>();
846 if (selectedRec != null) {
847 for (
int x = selectedRec.x; x < selectedRec.x + selectedRec.width; x++) {
848 for (
int y = selectedRec.y; y < selectedRec.y + selectedRec.height; y++) {
849 if ((gridFlags[x][y] & GRID_FLAG_SELECTION) > 0) {
850 selection.add(
new Point(x, y));
854 }
else if (cachedCursorLoc != null) {
855 selection.add(
new Point(cachedCursorLoc));
857 return selection.toArray(
new Point[selection.size()]);
static final int GRID_FLAG_CONNECTION
Flag to highlight as part of a connection group.
void preSelect(@NotNull final Point start, @NotNull final Point end)
Rectangle defined by two points gets preselected.
Rectangle getSelectedRec()
Returns the smallest rectangle containing selection.
void resize(@NotNull final Size2D newSize)
Resizes the MapGrid.
T [] getListeners()
Returns an array of all the listeners.
boolean equals(@Nullable final Object obj)
int [][] gridFlags
2D-array to store grid flags.
void calculateCachedSelectedRec()
Makes sure the value of cachedSelectedRec if up-to-date.
boolean cachedSelectedRecValid
If set, cachedSelectedRec is up-to-date.
void fireMapGridChangedEvent()
Inform all registered listeners that the flags on MapGrid have changed.
static final int GRID_FLAG_SELECTION_NORTH
Selection - is set for squares at the north edge of the selected area.
void selectAll()
Marks all squares as selected.
void selectArea(@NotNull final Point pos1, @NotNull final Point pos2, @NotNull final SelectionMode selectionMode)
Selects or deselects all squares in an area.
static final int GRID_FLAG_ERROR
Flag to highlight as error.
boolean endRecChange()
Ends the set of changes and store the bounding box for all recorded changes in recChange.
void beginRecChange()
Begins a set of changes.
static final int GRID_FLAG_SELECTING
Pre-selection - used to preselect squares.
MapGrid(@NotNull final Size2D gridSize)
Creates a new instance.
int getFlags(final int x, final int y)
Returns the flags of a square.
void removeMapGridListener(@NotNull final MapGridListener listener)
Removes a MapGridListener.
Point cachedCursorLoc
Cached location of the cursor.
Point [] getSelection()
Returns the selection.
void calculateRec(@NotNull final Point p1, @NotNull final Point p2)
Size2D getSize()
Returns size of grid.
void unSelect()
Clears all selection and pre-selection flags from the grid.
void unPreSelect(@NotNull final Point start, @NotNull final Point end)
Pre-selection of rectangle defined by points gets deleted.
void setError(final int x, final int y)
Sets the error flag at given coordinates.
static final int GRID_FLAG_CURSOR
Flag to highlight cursor position.
int getFlags(@NotNull final Point p)
Returns the flags of a square.
Base package of all Gridarta classes.
final Point cornerMax
Right lower coordinates of rectangle that is being processed.
static final int GRID_FLAG_INFORMATION
Flag to highlight as information.
Interface for listeners listening to MapGridEvents.
int transactionDepth
The transaction depth.
void invertSelection()
Inverts all selected squares.
void setCursor(@NotNull final Point pos)
Highlights the given cursor position.
void addMapGridListener(@NotNull final MapGridListener listener)
Registers a MapGridListener.
void fireMapGridResizeEvent()
Informs all registered listeners that the size of MapGrid has changed.
void remove(@NotNull final T listener)
Removes a listener.
final Point cornerMin
Left upper coordinates of rectangle that is being processed.
static final int GRID_FLAG_SELECTION_EAST
Selection - is set for squares at the east edge of the selected area.
Thread transactionThread
The thread that performs the current transaction.
void add(@NotNull final T listener)
Adds a listener.
int getWidth()
Returns the width of the area.
2D-Grid containing flags for selection, pre-selection, cursor, warnings and errors.
void unSetCursor(@NotNull final Point pos)
Un-highlights the given cursor position.
static final int GRID_FLAG_FATAL
Flag to highlight as fatal.
void beginTransaction()
Starts a new transaction.
void clearErrors()
Clears all error flags.
static final int GRID_FLAG_SELECTION_SOUTH
Selection - is set for squares at the south edge of the selected area.
void setFlags(final int minX, final int minY, final int maxX, final int maxY, final int flags)
Sets flags in a rectangle and generate a grid change event.
Type-safe version of EventListenerList.
void select(@NotNull final Point pos, @NotNull final SelectionMode selectionMode)
Selects or deselects a single square.
void endTransaction()
Ends a transaction.
void updateSelectionFlag(final int x, final int y, final boolean newState, final int dx, final int dy, final int flag, final int dFlag)
Updates the border selection flags of a square and one adjacent square.
boolean hasError(@NotNull final Point p)
Checks if a square has the error flag set.
Rectangle cachedSelectedRec
The return value for getSelectedRec().
final EventListenerList2< MapGridListener > listenerList
The MapGridListeners to inform of changes.
void updatePreSelect(@NotNull final Point start, @NotNull final Point oldEnd, @NotNull final Point newEnd)
Update the pre-selection rectangle.
static final int GRID_FLAG_SELECTION_WEST
Selection - is set for squares at the west edge of the selected area.
Modes that describe how squares get selected.
static final int GRID_FLAG_SELECTION
Selection - marks all selected squares.
void unsetFlags(final int minX, final int minY, final int maxX, final int maxY, final int flags)
Resets flags in a rectangle and generate a grid change event.
final Rectangle recChange
Rectangle to store location of last grid change.
static final int GRID_FLAG_WARNING
Flag to highlight as warning.
int getHeight()
Returns the height of the area.
void toggleFlags(final int minX, final int minY, final int maxX, final int maxY, final int flags)
Flips flags in a rectangle and generate a grid change event.
Rectangle getRecChange()
Returns a rectangle where the grid was changed.
void updateRecChange(final int x, final int y)
Adds a point to the set of changes.
Size2D getGridSize()
Returns a Size2D with the dimension of this grid.
The class Size2D represents a 2d rectangular area.
This event is created by MapGrid.
void updateSelectionFlag(final int x, final int y, final boolean newState)
Updates the border selection flags of a square and its adjacent squares.