package com.kartoflane.superluminal2.mvc.views; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.graphics.Transform; import com.kartoflane.superluminal2.components.interfaces.Disposable; import com.kartoflane.superluminal2.components.interfaces.Redrawable; import com.kartoflane.superluminal2.core.Cache; import com.kartoflane.superluminal2.core.LayeredPainter; import com.kartoflane.superluminal2.core.LayeredPainter.Layers; import com.kartoflane.superluminal2.mvc.Controller; import com.kartoflane.superluminal2.mvc.Model; import com.kartoflane.superluminal2.mvc.View; import com.kartoflane.superluminal2.mvc.controllers.AbstractController; import com.kartoflane.superluminal2.mvc.controllers.ObjectController; import com.kartoflane.superluminal2.mvc.models.BaseModel; import com.kartoflane.superluminal2.utils.Utils; public abstract class BaseView implements View, Disposable, Redrawable { public static final RGB SELECT_RGB = new RGB(0, 0, 255); public static final RGB HIGHLIGHT_RGB = new RGB(0, 128, 192); public static final RGB DENY_RGB = new RGB(230, 100, 100); public static final RGB ALLOW_RGB = new RGB(50, 230, 50); public static final RGB PIN_RGB = new RGB(192, 192, 0); protected AbstractController controller = null; protected BaseModel model = null; protected Layers layer = null; protected Transform transform = null; protected String imagePath = null; protected Image image = null; protected Rectangle cachedImageBounds = null; protected Color borderColor = null; protected Color backgroundColor = null; protected int borderThickness = 0; protected RGB defaultBorder = null; protected RGB defaultBackground = null; protected float rotation = 0; protected int alpha = 255; protected boolean flipX = false; protected boolean flipY = false; protected boolean visible = true; protected boolean highlighted = false; private boolean disposed = false; public BaseView() { } public void setController(ObjectController controller) { this.controller = controller; } public final Layers getLayerId() { return layer; } @Override public void setController(Controller controller) { this.controller = (AbstractController) controller; } @Override public void setModel(Model model) { this.model = (BaseModel) model; } /** In degrees, 0 = north */ public void setRotation(float rotation) { this.rotation = rotation; } /** In degrees, 0 = north */ public float getRotation() { return rotation; } public void setVisible(boolean vis) { visible = vis; } public boolean isVisible() { return visible; } public void setAlpha(int alpha) { if (alpha < 0 || alpha > 255) throw new IllegalArgumentException("Argument is not within allowed range: " + alpha); this.alpha = alpha; } public int getAlpha() { return alpha; } public void setFlippedX(boolean flip) { flipX = flip; } public void setFlippedY(boolean flip) { flipY = flip; } public boolean isFlippedX() { return flipX; } public boolean isFlippedY() { return flipY; } public void setHighlighted(boolean high) { this.highlighted = high; } public boolean isHighlighted() { return highlighted; } public void setImage(String path) { if (imagePath != null && path != null && imagePath.equals(path)) return; // don't do anything if it's the same thing if (image != null) { Cache.checkInImage(this, imagePath); } imagePath = null; image = null; if (path != null) { image = Cache.checkOutImage(this, path); if (image != null) cachedImageBounds = image.getBounds(); imagePath = path; } } public String getImagePath() { return imagePath; } public Rectangle getImageBounds() { return image == null ? new Rectangle(0, 0, 0, 0) : Utils.copy(cachedImageBounds); } public void setBorderColor(RGB rgb) { if (borderColor != null) Cache.checkInColor(this, borderColor.getRGB()); borderColor = null; if (rgb != null) borderColor = Cache.checkOutColor(this, rgb); } public void setBorderColor(int red, int green, int blue) { if (borderColor != null) Cache.checkInColor(this, borderColor.getRGB()); RGB rgb = new RGB(red, green, blue); borderColor = Cache.checkOutColor(this, rgb); } public RGB getBorderRGB() { return borderColor == null ? null : borderColor.getRGB(); } public void setDefaultBorderColor(RGB rgb) { defaultBorder = rgb; } public void setDefaultBorderColor(int red, int green, int blue) { defaultBorder = new RGB(red, green, blue); } public RGB getDefaultBorderRGB() { return defaultBorder == null ? null : Utils.copy(defaultBorder); } public void setBackgroundColor(RGB rgb) { if (backgroundColor != null) Cache.checkInColor(this, backgroundColor.getRGB()); backgroundColor = null; if (rgb != null) backgroundColor = Cache.checkOutColor(this, rgb); } public void setBackgroundColor(int red, int green, int blue) { if (backgroundColor != null) Cache.checkInColor(this, backgroundColor.getRGB()); RGB rgb = new RGB(red, green, blue); backgroundColor = Cache.checkOutColor(this, rgb); } public RGB getBackgroundRGB() { return backgroundColor == null ? null : backgroundColor.getRGB(); } public void setDefaultBackgroundColor(RGB rgb) { defaultBackground = rgb; } public void setDefaultBackgroundColor(int red, int green, int blue) { defaultBackground = new RGB(red, green, blue); } public RGB getDefaultBackgroundRGB() { return defaultBackground == null ? null : Utils.copy(defaultBackground); } public void setBorderThickness(int borderThickness) { this.borderThickness = borderThickness; } public int getBorderThickness() { return borderThickness; } @Override public void redraw(PaintEvent e) { if (visible) { boolean trans = getRotation() % 360 != 0 || flipX || flipY; if (trans) { e.gc.setAdvanced(true); transform = new Transform(e.gc.getDevice()); Point p = model.getLocation(); transform.translate(p.x, p.y); transform.rotate(getRotation()); transform.scale(flipX ? -1 : 1, flipY ? -1 : 1); transform.translate(-p.x, -p.y); e.gc.setTransform(transform); } paintControl(e); if (trans) { e.gc.setTransform(null); transform.dispose(); transform = null; e.gc.setAdvanced(false); } } } public void paintControl(PaintEvent e) { } /* * ==================================================================================== * XXX: Paint image methods * ==================================================================================== */ /** * Paints the image in the given area, modifying the image to fit. */ protected void paintImageResize(PaintEvent e, Image image, Rectangle cachedBounds, int x, int y, int w, int h, int alpha) { if (image != null) { int prevAlpha = e.gc.getAlpha(); e.gc.setAlpha(alpha); e.gc.drawImage(image, 0, 0, cachedBounds.width, cachedBounds.height, x, y, w, h); e.gc.setAlpha(prevAlpha); } } /** * Paints the image in the given area, modifying the image to fit. */ protected void paintImageResize(PaintEvent e, Image image, Rectangle cachedBounds, Rectangle rect, int alpha) { if (image != null) { paintImageResize(e, image, cachedBounds, rect.x, rect.y, rect.width, rect.height, alpha); } } /** * Paints the image without any modifications at the center of the View. */ protected void paintImage(PaintEvent e, Image image, Rectangle cachedBounds, int alpha) { if (image != null) { paintImageResize(e, image, cachedBounds, model.getX() - cachedBounds.width / 2, model.getY() - cachedBounds.height / 2, cachedBounds.width, cachedBounds.height, alpha); } } /** * Paints the image without any modifications, centered at the given location (relative to the canvas) */ protected void paintImage(PaintEvent e, Image image, Rectangle cachedBounds, int x, int y, int alpha) { if (image != null) { int prevAlpha = e.gc.getAlpha(); e.gc.setAlpha(alpha); e.gc.drawImage(image, 0, 0, cachedBounds.width, cachedBounds.height, x - cachedBounds.width / 2, y - cachedBounds.height / 2, cachedBounds.width, cachedBounds.height); e.gc.setAlpha(prevAlpha); } } /** * Paints part of the image without any modifications, centered at the given location (relative to the canvas). * * @param srcX * x coordinate in the source image to copy from * @param srcY * y coordinate in the source image to copy from * @param srcW * width of the area that will be copied * @param srcH * height of the area that will be copied * @param x * x coordinate of the destination location at which the image will be drawn * @param y * y coordinate of the destination location at which the image will be drawn * @param w * width of the destination area at which the image will be drawn * @param h * height of the destination area at which the image will be drawn */ protected void paintImageResize(PaintEvent e, Image image, int srcX, int srcY, int srcW, int srcH, int x, int y, int w, int h, int alpha) { if (image != null) { int prevAlpha = e.gc.getAlpha(); e.gc.setAlpha(alpha); e.gc.drawImage(image, srcX, srcY, srcW, srcH, x - w / 2, y - h / 2, w, h); e.gc.setAlpha(prevAlpha); } } /** * Paints the image without any modifications, with the image's top left corner at the given location. */ protected void paintImageCorner(PaintEvent e, Image image, Rectangle cachedBounds, int x, int y, int alpha) { if (image != null) { int prevAlpha = e.gc.getAlpha(); e.gc.setAlpha(alpha); e.gc.drawImage(image, 0, 0, cachedBounds.width, cachedBounds.height, x, y, cachedBounds.width, cachedBounds.height); e.gc.setAlpha(prevAlpha); } } /** * Paints part of the image without any modifications, with the image's top left corner at the given location. * * @param srcX * x coordinate in the source image to copy from * @param srcY * y coordinate in the source image to copy from * @param srcW * width of the area that will be copied * @param srcH * height of the area that will be copied * @param x * x coordinate of the destination location at which the image will be drawn * @param y * y coordinate of the destination location at which the image will be drawn * @param w * width of the destination area at which the image will be drawn * @param h * height of the destination area at which the image will be drawn */ protected void paintImageCorner(PaintEvent e, Image image, Rectangle cachedBounds, int srcX, int srcY, int srcW, int srcH, int x, int y, int w, int h, int alpha) { if (image != null) { int prevAlpha = e.gc.getAlpha(); e.gc.setAlpha(alpha); srcW = Math.min(srcW, cachedBounds.width); srcH = Math.min(srcH, cachedBounds.height); e.gc.drawImage(image, srcX, srcY, srcW, srcH, x, y, w, h); e.gc.setAlpha(prevAlpha); } } /* * ==================================================================================== * XXX: Paint background methods * ==================================================================================== */ protected void paintBackgroundSquare(PaintEvent e, Color backgroundColor, int alpha) { if (backgroundColor != null) { paintBackgroundSquare(e, model.getX() - model.getW() / 2, model.getY() - model.getH() / 2, model.getW(), model.getH(), backgroundColor, alpha); } } protected void paintBackgroundSquare(PaintEvent e, Rectangle rect, Color backgroundColor, int alpha) { if (backgroundColor != null) { paintBackgroundSquare(e, rect.x, rect.y, rect.width, rect.height, backgroundColor, alpha); } } protected void paintBackgroundSquare(PaintEvent e, int x, int y, int w, int h, Color backgroundColor, int alpha) { if (backgroundColor != null) { Color prevBgColor = e.gc.getBackground(); int prevAlpha = e.gc.getAlpha(); e.gc.setBackground(backgroundColor); e.gc.setAlpha(alpha); e.gc.fillRectangle(x, y, w, h); e.gc.setBackground(prevBgColor); e.gc.setAlpha(prevAlpha); } } protected void paintBackgroundOval(PaintEvent e, Color backgroundColor, int alpha) { if (backgroundColor != null) { paintBackgroundOval(e, model.getX() - model.getW() / 2, model.getY() - model.getH() / 2, model.getW(), model.getH(), backgroundColor, alpha); } } protected void paintBackgroundOval(PaintEvent e, Rectangle rect, Color backgroundColor, int alpha) { if (backgroundColor != null) { paintBackgroundOval(e, rect.x, rect.y, rect.width, rect.height, backgroundColor, alpha); } } protected void paintBackgroundOval(PaintEvent e, int x, int y, int w, int h, Color backgroundColor, int alpha) { if (backgroundColor != null) { Color prevBgColor = e.gc.getBackground(); int prevAlpha = e.gc.getAlpha(); e.gc.setBackground(backgroundColor); e.gc.setAlpha(alpha); e.gc.fillOval(x, y, w, h); e.gc.setBackground(prevBgColor); e.gc.setAlpha(prevAlpha); } } protected void paintBackgroundPolygon(PaintEvent e, int[] polygon, Color backgroundColor, int alpha) { if (backgroundColor != null) { Color prevBgColor = e.gc.getBackground(); int prevAlpha = e.gc.getAlpha(); e.gc.setBackground(backgroundColor); e.gc.setAlpha(alpha); e.gc.fillPolygon(polygon); e.gc.setBackground(prevBgColor); e.gc.setAlpha(prevAlpha); } } /* * ==================================================================================== * XXX: Paint border methods * ==================================================================================== */ protected void paintBorderSquare(PaintEvent e, Color borderColor, int borderThickness, int alpha) { paintBorderSquare(e, model.getX() - model.getW() / 2, model.getY() - model.getH() / 2, model.getW(), model.getH(), borderColor, borderThickness, alpha); } protected void paintBorderSquare(PaintEvent e, Rectangle rect, Color borderColor, int borderThickness, int alpha) { paintBorderSquare(e, rect.x, rect.y, rect.width, rect.height, borderColor, borderThickness, alpha); } protected void paintBorderSquare(PaintEvent e, int x, int y, int w, int h, Color borderColor, int borderThickness, int alpha) { if (borderColor != null) { Color prevFgColor = e.gc.getForeground(); int prevAlpha = e.gc.getAlpha(); int prevWidth = e.gc.getLineWidth(); e.gc.setForeground(borderColor); e.gc.setAlpha(alpha); e.gc.setLineWidth(borderThickness); // Lines are drawn from the center, which makes the math a little funky e.gc.drawRectangle(x + borderThickness / 2, y + borderThickness / 2, w - 1 - borderThickness / 2, h - 1 - borderThickness / 2); e.gc.setForeground(prevFgColor); e.gc.setAlpha(prevAlpha); e.gc.setLineWidth(prevWidth); } } protected void paintBorderOval(PaintEvent e, Color borderColor, int borderThickness, int alpha) { paintBorderOval(e, model.getX() - model.getW() / 2, model.getY() - model.getH() / 2, model.getW(), model.getH(), borderColor, borderThickness, alpha); } protected void paintBorderOval(PaintEvent e, Rectangle rect, Color borderColor, int borderThickness, int alpha) { paintBorderOval(e, rect.x, rect.y, rect.width, rect.height, borderColor, borderThickness, alpha); } protected void paintBorderOval(PaintEvent e, int x, int y, int w, int h, Color borderColor, int borderThickness, int alpha) { if (borderColor != null) { Color prevFgColor = e.gc.getForeground(); int prevAlpha = e.gc.getAlpha(); int prevWidth = e.gc.getLineWidth(); e.gc.setForeground(borderColor); e.gc.setAlpha(alpha); e.gc.setLineWidth(borderThickness); // Lines are drawn from the center, which makes the math a little funky e.gc.drawOval(x + borderThickness / 2, y + borderThickness / 2, w - 1 - borderThickness / 2, h - 1 - borderThickness / 2); e.gc.setForeground(prevFgColor); e.gc.setAlpha(prevAlpha); e.gc.setLineWidth(prevWidth); } } protected void paintBorderPolygon(PaintEvent e, int[] polygon, Color borderColor, int borderThickness, int alpha) { if (borderColor != null) { Color prevFgColor = e.gc.getForeground(); int prevAlpha = e.gc.getAlpha(); int prevWidth = e.gc.getLineWidth(); e.gc.setForeground(borderColor); e.gc.setAlpha(alpha); e.gc.setLineWidth(borderThickness); e.gc.drawPolygon(polygon); e.gc.setForeground(prevFgColor); e.gc.setAlpha(prevAlpha); e.gc.setLineWidth(prevWidth); } } /* * ==================================================================================== * XXX: Paint line methods * ==================================================================================== */ /** * Line is always drawn from <tt>(rect.x, rect.y)</tt> to <tt>(rect.x + rect.width, rect.y + rect.height)</tt>. * The rect can have negative width or height, however. */ protected void paintLine(PaintEvent e, Rectangle rect, Color borderColor, int borderThickness, int alpha) { paintLine(e, rect.x, rect.y, rect.x + rect.width, rect.y + rect.height, borderColor, borderThickness, alpha); } protected void paintLine(PaintEvent e, int sx, int sy, int ex, int ey, Color borderColor, int borderThickness, int alpha) { if (borderColor != null) { Color prevFgColor = e.gc.getForeground(); int prevAlpha = e.gc.getAlpha(); int prevWidth = e.gc.getLineWidth(); e.gc.setForeground(borderColor); e.gc.setAlpha(alpha); e.gc.setLineWidth(borderThickness); e.gc.drawLine(sx, sy, ex, ey); e.gc.setForeground(prevFgColor); e.gc.setAlpha(prevAlpha); e.gc.setLineWidth(prevWidth); } } /** * Registers this view with the LayeredPainter object. * * @param layer * Id of the layer to which the view will be added */ public void addToPainter(Layers layer) { LayeredPainter painter = LayeredPainter.getInstance(); if (layer == null || !painter.getLayers().contains(layer)) throw new IllegalArgumentException("Illegal layer."); this.layer = layer; painter.add(controller, layer); } public void addToPainterBottom(Layers layer) { LayeredPainter painter = LayeredPainter.getInstance(); if (layer == null || !painter.getLayers().contains(layer)) throw new IllegalArgumentException("Illegal layer."); this.layer = layer; painter.addToBottom(controller, layer); } /** Unregisters this view from the LayeredPainter object */ public void removeFromPainter() { LayeredPainter.getInstance().remove(controller); } /** Unregisters this view from the specfied layer */ public void removeFromPainter(Layers layer) { LayeredPainter.getInstance().remove(controller, layer); } public void dispose() { removeFromPainter(); setVisible(false); if (borderColor != null) Cache.checkInColor(this, borderColor.getRGB()); if (backgroundColor != null) Cache.checkInColor(this, backgroundColor.getRGB()); if (image != null) Cache.checkInImage(this, imagePath); borderColor = null; backgroundColor = null; image = null; imagePath = null; disposed = true; } public boolean isDisposed() { return disposed; } }