package shipmaker.render; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.util.ArrayList; import dcpu.WorldPauseHandler; import physics.XYTSource; import render.CollectionRemoval; import render.MouseEventType; import render.OverlayManager; import render.RenderNode; import render.RenderPreferences; import render.XYTRenderNode; import shipmaker.EditorShip; import shipmaker.EditorShip.EditorShipPart; import shipmaker.EditorShip.ShipWatcher; import shipmaker.partplacer.BlueprintPositionEditor; import env.Entity; import env.Space; import equipment.Structure; import equipment.StructureNode; public class ShipContents extends XYTRenderNode implements ShipWatcher { private static final int ROW_HEIGHT = 20; EditorShip ship; Space space; OverlayManager om; EditorShipPart selected; BlueprintPositionEditor editor; RenderNode options; private ArrayList<PartLabel> labels; private class PartLabel extends XYTRenderNode implements XYTSource { int index; EditorShipPart part; public PartLabel(EditorShipPart p) { super(0, 0, 0); src = this; this.part = p; if (p.part.type().deletable()) { addChild(new XYTRenderNode(-20, 0, 0) { public void draw(Graphics2D g, RenderPreferences prefs) { g.setColor(Color.red); g.setStroke(new BasicStroke(3)); g.drawLine(5, 5, 15, 15); g.drawLine(5, 15, 15, 5); } public boolean interacted(AffineTransform root, MouseEvent e, MouseEventType t) { if (t == MouseEventType.MOUSE_PRESS) { Point2D.Float pt = RenderNode.reverse(root, e); if (pt.x > 0 && pt.x < 20 && pt.y > 0 && pt.y < 20) { ship.removePart(part); return true; } } return false; } }); } } public float position_x() { return 0; } public float position_y() { return index * ROW_HEIGHT; } public float alignment_theta() { return 0; } public void draw(Graphics2D g, RenderPreferences prefs) { g.setColor(selected == part ? Color.orange : Color.white); int fh = 14; g.setFont(new Font("SansSerif", Font.BOLD, fh)); int mid = ROW_HEIGHT / 2; g.drawString(part.part.type().name(), 0, mid + fh / 2); } public boolean interacted(AffineTransform root, MouseEvent e, MouseEventType t) { if (t == MouseEventType.MOUSE_PRESS) { Point2D.Float pt = RenderNode.reverse(root, e); if (pt.x > 0 && pt.x < 200 && pt.y > 0 && pt.y < ROW_HEIGHT) { setSelected(part); return true; } } return false; } } public ShipContents(final EditorShip ship, Space space, OverlayManager om) { super(-200, 0, 0); this.ship = ship; this.space = space; this.om = om; ship.addWatcher(this); labels = new ArrayList<ShipContents.PartLabel>(); om.nonproductiveClick = new Runnable() { public void run() { setSelected(null); } }; for (EditorShipPart p : ship.parts()) { partAdded(p); } XYTSource cmass = new XYTSource() { public float position_y() { return ship.massCenterY(); } public float position_x() { return ship.massCenterX(); } public float alignment_theta() { return 0; } }; final XYTRenderNode centerMass = new XYTRenderNode(cmass) { public void draw(Graphics2D g, RenderPreferences prefs) { g.setColor(Color.white); g.setStroke(new BasicStroke(1)); g.drawLine(-5, -5, 5, 5); g.drawLine(-5, 5, 5, -5); } }; space.addEntity(new Entity() { public void tickPhysics(int msPerTick, WorldPauseHandler handler) { } public void tickInternals(int msPerTick, WorldPauseHandler handler) { } public RenderNode getVisuals() { return centerMass; } }); final RenderNode structNode = new XYTRenderNode(0,0,0) { public void draw(Graphics2D g, RenderPreferences prefs) { if (ship.editingStructure) Structure.draw(g, prefs, ship.structLocations()); g.setColor(prefs.overlayTextColor()); if (ship.editingStructure) for (StructureNode node : ship.structLocations()) { for (int dx = -1; dx <= 1; dx++) for (int dy = -1; dy <= 1; dy++) if ((dx ==0 ^ dy==0) ||( dx==0 && dy==0)) { g.fillRect(Structure.STRUCT_SIZE*(node.x+dx)-2, Structure.STRUCT_SIZE*(node.y+dy)-2, 4, 4); } } } public boolean interacted(AffineTransform root, MouseEvent e, MouseEventType t) { if (t!=MouseEventType.MOUSE_PRESS) return false; Point2D.Float pt = RenderNode.reverse(root, e); float nx = Math.round(pt.x/Structure.STRUCT_SIZE)*Structure.STRUCT_SIZE; float ny = Math.round(pt.y/Structure.STRUCT_SIZE)*Structure.STRUCT_SIZE; if (Math.abs(nx - pt.x)<5 && Math.abs(ny - pt.y)<5) { StructureNode node = new StructureNode(Math.round(pt.x/Structure.STRUCT_SIZE), Math.round(pt.y/Structure.STRUCT_SIZE)); if (ship.structLocations().contains(node)) { ship.structLocations().remove(node); if (!ship.validateStructureContinuity()) ship.structLocations().add(node); } else { ship.structLocations().add(node); if (!ship.validateStructureContinuity()) ship.structLocations().remove(node); } return true; } return false; } public int layer() { return 2; } }; space.addEntity(new Entity() { public void tickPhysics(int msPerTick, WorldPauseHandler handler) { } public void tickInternals(int msPerTick, WorldPauseHandler handler) { } public RenderNode getVisuals() { return structNode; } }); } private void setSelected(EditorShipPart p) { selected = p; if (options != null) { om.topLeft().removeChild(options); } if (p == null && editor != null) { om.afterInteraction(space.removeEntityLater(editor)); editor = null; return; } if (p != null && p.part.type().placeable()) { if (editor == null) { editor = new BlueprintPositionEditor(p.location); space.addEntity(editor); } editor.bpl(p.location); space.addEntity(p); } else if (editor != null) { space.removeEntity(editor); editor = null; } if (p != null) { options = p.part.getOptionsOverlay(om, p.location); om.topLeft().addChild(options); } } public void partAdded(final EditorShipPart p) { final PartLabel pl = new PartLabel(p); pl.index = labels.size(); labels.add(pl); addChild(pl); setSelected(p); p.getVisuals().addChild(new RenderNode() { protected void transform(AffineTransform root) { } public boolean interacted(AffineTransform root, MouseEvent e, MouseEventType t) { if (t != MouseEventType.MOUSE_PRESS) return false; Point2D.Float pt = RenderNode.reverse(root, e); if (pt.distance(0, 0) < 20 && p != selected && (selected == null || selected.location .distance(p.location) > 20)) { if (om.lowPriorityInteraction == null) { om.lowPriorityInteraction = new Runnable() { public void run() { setSelected(p); } }; } } return false; } public void draw(Graphics2D g, RenderPreferences prefs) { g.setColor(new Color(255, 255, 255, 20)); g.setStroke(new BasicStroke(1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER, 10, new float[] { 5 }, 0)); g.drawArc(-p.part.partRadius(), -p.part.partRadius(), 2*p.part.partRadius(), 2*p.part.partRadius(), 0, 360); } }); } public void partRemoved(EditorShipPart p) { PartLabel pl = null; for (PartLabel pli : labels) { if (pli.part == p) { pl = pli; break; } } if (pl != null) { labels.remove(pl); final PartLabel fpl = pl; om.afterInteraction(new CollectionRemoval<RenderNode>(children, pl)); om.afterInteraction(space.removeEntityAction(fpl.part)); if (fpl.part == selected) { setSelected(null); } for (int i = 0; i < labels.size(); i++) { labels.get(i).index = i; } } } }