package com.kartoflane.superluminal2.mvc.models; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import com.kartoflane.superluminal2.components.interfaces.Boundable; import com.kartoflane.superluminal2.components.interfaces.Collidable; import com.kartoflane.superluminal2.components.interfaces.Deletable; import com.kartoflane.superluminal2.components.interfaces.Disposable; import com.kartoflane.superluminal2.components.interfaces.Movable; import com.kartoflane.superluminal2.components.interfaces.Pinnable; import com.kartoflane.superluminal2.components.interfaces.Resizable; import com.kartoflane.superluminal2.mvc.Model; import com.kartoflane.superluminal2.utils.Utils; public class BaseModel implements Model, Movable, Resizable, Disposable, Deletable, Collidable, Boundable, Pinnable { protected Rectangle bounds = null; protected Point position = null; protected Point size = null; protected Point followOffset = null; protected Rectangle boundingArea = null; protected int collisionTolerance = 0; protected boolean disposed = false; protected boolean deletable = true; protected boolean bounded = false; protected boolean pinned = false; protected boolean collidable = false; protected boolean followableActive = true; protected boolean locModifiable = true; public BaseModel() { bounds = new Rectangle(0, 0, 0, 0); position = new Point(0, 0); size = new Point(0, 0); } @Override public void setPinned(boolean pin) { pinned = pin; } @Override public final boolean isPinned() { return pinned; } /** * Sets the object's center at the given coordinates.<br> * If modifying both size and location, change the size first. */ @Override public boolean setLocation(int x, int y) { position.x = x; position.y = y; recalculateBounds(); return true; } /** * Sets the object's center at the given coordinates.<br> * If modifying both size and location, change the size first. */ public boolean setLocation(Point loc) { return setLocation(loc.x, loc.y); } @Override public boolean translate(int dx, int dy) { position.x += dx; position.y += dy; recalculateBounds(); return true; } public boolean translate(Point displacement) { return translate(displacement.x, displacement.y); } @Override public Point getLocation() { return Utils.copy(position); } @Override public int getX() { return position.x; } @Override public int getY() { return position.y; } /** @return a new point representing the box's dimensions. */ @Override public Point getSize() { return Utils.copy(size); } /** @return width of the box */ @Override public int getW() { return size.x; } /** @return height of the box */ @Override public int getH() { return size.y; } /** * Sets the model's dimensions to the given values.<br> * If modifying both size and location, change the size first. */ @Override public boolean setSize(int w, int h) { if (w < 0 || h < 0) throw new IllegalArgumentException("Model's ddimensions must be non-negative integers."); size.x = w; size.y = h; recalculateBounds(); return true; } /** * Sets the model's dimensions to the given values.<br> * If modifying both size and location, change the size first. */ public boolean setSize(Point size) { return setSize(size.x, size.y); } @Override public Rectangle getBounds() { return Utils.copy(bounds); } protected void recalculateBounds() { bounds.x = position.x - size.x / 2 - 1; bounds.y = position.y - size.y / 2 - 1; bounds.width = size.x + 2; bounds.height = size.y + 2; } @Override public boolean contains(int x, int y) { return bounds.contains(x, y); } public boolean contains(Point p) { return contains(p.x, p.y); } @Override public boolean intersects(Rectangle rect) { return bounds.intersects(rect); } @Override public void setCollidable(boolean collidable) { this.collidable = collidable; } @Override public boolean isCollidable() { return collidable; } @Override public boolean collides(int x, int y, int w, int h) { Rectangle rect = new Rectangle(x, y, w, h); return rect.intersects(getBounds()); } @Override public boolean isBounded() { return bounded; } @Override public void setBounded(boolean bound) { bounded = bound; if (bound && boundingArea == null) boundingArea = new Rectangle(0, 0, 0, 0); } public Rectangle getBoundingArea() { if (boundingArea == null) boundingArea = new Rectangle(0, 0, 0, 0); return Utils.copy(boundingArea); } public int getBoundingAreaX() { return boundingArea == null ? 0 : boundingArea.x; } public int getBoundingAreaY() { return boundingArea == null ? 0 : boundingArea.y; } public int getBoundingAreaW() { return boundingArea == null ? 0 : boundingArea.width; } public int getBoundingAreaH() { return boundingArea == null ? 0 : boundingArea.height; } public void setBoundingArea(int x, int y, int w, int h) { if (boundingArea == null) boundingArea = new Rectangle(0, 0, 0, 0); boundingArea.x = x; boundingArea.y = y; boundingArea.width = w; boundingArea.height = h; } public void setBoundingArea(Rectangle r) { setBoundingArea(r.x, r.y, r.width, r.height); } public void setBoundingArea(Point start, Point end) { setBoundingArea(start.x, start.y, end.x - start.x, end.y - start.y); } @Override public boolean isWithinBoundingArea(int x, int y) { return x >= boundingArea.x && x <= boundingArea.x + boundingArea.width && y >= boundingArea.y && y <= boundingArea.y + boundingArea.height; } @Override public Point limitToBoundingArea(int x, int y) { Point p = new Point(x, y); int t = 0; if (x < boundingArea.x) p.x = boundingArea.x; else if (x > (t = boundingArea.x + boundingArea.width)) p.x = t; if (y < boundingArea.y) p.y = boundingArea.y; else if (y > (t = boundingArea.y + boundingArea.height)) p.y = t; return p; } @Override public void dispose() { disposed = true; } public boolean isDisposed() { return disposed; } @Override public void delete() { // nothing to do here } @Override public void restore() { // nothing to do here } @Override public void setDeletable(boolean deletable) { this.deletable = deletable; } @Override public boolean isDeletable() { return deletable; } @Override public void setTolerance(int px) { collisionTolerance = px; } @Override public int getTolerance() { return collisionTolerance; } /** * Flags this model's location value as modifiable via the sidebar UI.<br> * True by default. */ public void setLocModifiable(boolean b) { locModifiable = b; } /** @return true if this model's location value can be modified via the sidebar UI, false otherwise. */ public final boolean isLocModifiable() { return locModifiable; } }