/* * Copyright (C) 2007 Clam <clamisgood@gmail.com> * Copyright (C) 2008, 2011 IsmAvatar <IsmAvatar@gmail.com> * Copyright (C) 2009 Quadduc <quadduc@gmail.com> * Copyright (C) 2013 Robert B. Colton * * This file is part of LateralGM. * LateralGM is free software and comes with ABSOLUTELY NO WARRANTY. * See LICENSE for details. */ package org.lateralgm.components.visual; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Shape; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import org.lateralgm.main.UpdateSource.UpdateEvent; import org.lateralgm.main.UpdateSource.UpdateListener; import org.lateralgm.main.Util; import org.lateralgm.resources.Sprite; import org.lateralgm.resources.Sprite.PSprite; import org.lateralgm.util.PropertyMap.PropertyUpdateEvent; import org.lateralgm.util.PropertyMap.PropertyUpdateListener; public class SubimagePreview extends AbstractImagePreview implements UpdateListener { private static final long serialVersionUID = 1L; private int subIndex = 0; private boolean showBbox = true, showOrigin = true; private final Sprite sprite; private final SpritePropertyListener spl = new SpritePropertyListener(); private static final int ORIGIN_SIZE = 20; private double zoom = 1; private BufferedImage transparentBackground; private BufferedImage transparentImage; private BufferedImage image; public UpdateListener mouseListener; public boolean enablemouse = true; public SubimagePreview(Sprite s) { super(); sprite = s; s.properties.updateSource.addListener(spl); s.reference.updateSource.addListener(mouseListener); enableEvents(MouseEvent.MOUSE_PRESSED); enableEvents(MouseEvent.MOUSE_DRAGGED); } @Override public Dimension getPreferredSize() { BufferedImage img = getImage(); if (img == null) return super.getPreferredSize(); return new Dimension((int) Math.ceil(img.getWidth() * zoom),(int) Math.ceil(img.getHeight() * zoom)); } public Point getTopLeftCentered() { Dimension d = getPreferredSize(); return new Point(this.getWidth() / 2 - d.width / 2,this.getHeight() / 2 - d.height / 2); } public void paintComponent(Graphics g) { if ((Boolean) sprite.get(PSprite.TRANSPARENT)) { if (transparentImage == null) { image = getTransparentImage(); } } else { image = getImage(); transparentImage = null; } //super.paintComponent(g); g.setColor(this.getBackground()); g.fillRect(0,0,this.getWidth(),this.getHeight()); if (image != null) { Dimension d = getPreferredSize(); Graphics2D g2d = (Graphics2D) g; Point pnt = getTopLeftCentered(); g2d.translate(pnt.x,pnt.y); Shape clip = g.getClip(); g.clipRect(0,0,d.width,d.height); Dimension size = getPreferredSize(); int width = (int)Math.ceil(size.getWidth() / 10f); int height = (int)Math.ceil(size.getHeight() / 10f); width = width < 1 ? 1 : width; height = height < 1 ? 1 : height; if (transparentBackground == null || width != transparentBackground.getWidth() || height != transparentBackground.getHeight()) transparentBackground = Util.paintBackground(width, height); g.drawImage(transparentBackground, 0, 0, transparentBackground.getWidth() * 10, transparentBackground.getHeight() * 10, null); g.drawImage(image,0,0,d.width,d.height,null); g.setClip(clip); } else { setPreferredSize(new Dimension(0,0)); } if (image != null && (showBbox || showOrigin)) { //TODO: The rounding that follows is extremely sensitive. int originX = (int) Math.floor((Integer) sprite.get(PSprite.ORIGIN_X) * zoom); int originY = (int) Math.floor((Integer) sprite.get(PSprite.ORIGIN_Y) * zoom); int left = sprite.get(PSprite.BB_LEFT); int right = sprite.get(PSprite.BB_RIGHT); int top = sprite.get(PSprite.BB_TOP); int bottom = sprite.get(PSprite.BB_BOTTOM); left = Math.min(left,right); right = Math.max(left,right); top = Math.min(top,bottom); bottom = Math.max(top,bottom); left = (int) Math.floor(left * zoom); top = (int) Math.floor(top * zoom); right = (int) Math.ceil((right + 1) * zoom) - 1; bottom = (int) Math.ceil((bottom + 1) * zoom) - 1; //Shape oldClip = reclip(g); g.setXORMode(Color.BLACK); //XOR mode so that bbox and origin can counter g.setColor(Color.WHITE); if (showBbox) g.drawRect(left,top,right - left,bottom - top); if (showOrigin) { g.drawLine(originX - ORIGIN_SIZE,originY,originX + ORIGIN_SIZE,originY); g.drawLine(originX,originY - ORIGIN_SIZE,originX,originY + ORIGIN_SIZE); } g.setPaintMode(); //just in case //g.setClip(oldClip); //restore the clip } g.dispose(); } private void setBoundedOrigin(int x, int y) { BufferedImage img = getImage(); int w = 0, h = 0; if (img != null) { w = img.getWidth(); h = img.getHeight(); } x = (int) Math.max(0,Math.min(w,x)); y = (int) Math.max(0,Math.min(h,y)); sprite.put(PSprite.ORIGIN_X,x); sprite.put(PSprite.ORIGIN_Y,y); } public double getZoom() { return zoom; } public void setZoom(double nzoom) { zoom = nzoom; this.setSize(this.getPreferredSize()); updateUI(); } public void setIndex(int i) { subIndex = i; updateUI(); this.repaint(); } public int getIndex() { return subIndex; } public void setShowBbox(boolean show) { showBbox = show; } public void setShowOrigin(boolean show) { showOrigin = show; } protected void processMouseEvent(MouseEvent e) { if (enablemouse) { Point pnt = getTopLeftCentered(); int mx = (int) Math.floor((e.getX() / zoom) - (pnt.x / zoom)); int my = (int) Math.floor((e.getY() / zoom) - (pnt.y / zoom)); if (e.getID() == MouseEvent.MOUSE_PRESSED && e.getButton() == MouseEvent.BUTTON1) setBoundedOrigin(mx,my); } super.processMouseEvent(e); } protected void processMouseMotionEvent(MouseEvent e) { if (enablemouse) { if (e.getID() == MouseEvent.MOUSE_DRAGGED && (e.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) { Point pnt = getTopLeftCentered(); setBoundedOrigin((int) ((e.getX() / zoom) - (pnt.x / zoom)), (int) ((e.getY() / zoom) - (pnt.y / zoom))); } } super.processMouseMotionEvent(e); } protected BufferedImage getImage() { if (sprite == null) return null; int s = sprite.subImages.size(); if (s == 0 || subIndex < 0) return null; BufferedImage bi = sprite.subImages.get(subIndex % s); return bi; } protected BufferedImage getTransparentImage() { if (sprite == null) return null; int s = sprite.subImages.size(); if (s == 0 || subIndex < 0) return null; BufferedImage bi = sprite.subImages.get(subIndex % s); if (!(Boolean) sprite.get(PSprite.TRANSPARENT)) return bi; return Util.getTransparentImage(bi); } public void updated(UpdateEvent e) { updateUI(); } private class SpritePropertyListener extends PropertyUpdateListener<PSprite> { public void updated(PropertyUpdateEvent<PSprite> e) { switch (e.key) { case PRELOAD: case SMOOTH_EDGES: case TRANSPARENT: case SHAPE: return; default: repaint(); } } } }