package scriptbuilder.gui.panels; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.MouseEvent; import javax.swing.JPanel; import javax.swing.event.MouseInputAdapter; import scriptbuilder.gui.ScriptBuilderFrame; import scriptbuilder.gui.ScriptBuilderGuiConstants; import scriptbuilder.gui.drawers.EventIconDrawer; import scriptbuilder.structures.ScriptIncident; import scriptbuilder.structures.SimulationScript; /** * Represents the underlying panel on the main timeline. All the * IncidentTimelinePanel objects sit over it. This panel draws all the * per-minute ticks on the timeline, and adjusts and scales them as necessary. * * @author Greg Eddington * @author Bryan McGuffin */ public class TimelineTickPanel extends JPanel { private int longestLength = ScriptBuilderGuiConstants.TICK_TIMELINE_SMALLEST_LENGTH; private int x, y; private boolean focused = false; public void setZoom(float zoom) { repaint(); } /** * Listener for the mouse. Is notified when the mouse enters, exits, or * moves around on the panel. */ public class TimelineTickMouseListener extends MouseInputAdapter { /** * When the mouse enters the panel, the panel gets focus. * * @param e the mouse event */ @Override public void mouseEntered(MouseEvent e) { focused = true; } /** * When the mouse leaves the panel, the panel loses focus and refreshes. * * @param e the mouse event */ @Override public void mouseExited(MouseEvent e) { focused = false; repaint(); } /** * When the mouse moves around in the panel, the panel refreshes and * updates its mouse tracker. * * @param e */ @Override public void mouseMoved(MouseEvent e) { x = e.getX(); y = e.getY(); repaint(); } } /** * Constructor. Set up the mouse listener. */ public TimelineTickPanel() { super(); TimelineTickMouseListener mouseListener = new TimelineTickMouseListener(); addMouseMotionListener(mouseListener); addMouseListener(mouseListener); } /** * Update the panel's dimensions based on number of events, zoom level, and * which events are collapsed. * * @param script The main script model */ public void update(SimulationScript script) { longestLength = ScriptBuilderGuiConstants.TICK_TIMELINE_SMALLEST_LENGTH; // Get the stats on the incidents int height = ScriptBuilderGuiConstants.TICK_TOP_MARGIN * 4; for (ScriptIncident incident : script.incidents) { if (incident != null) { height += incident.collapsed ? ScriptBuilderGuiConstants.TIMELINE_OPENED_HEIGHT : ScriptBuilderGuiConstants.TIMELINE_OPENED_HEIGHT; if ((incident.length + incident.offset) > longestLength) { longestLength = incident.length + incident.offset; } } } Dimension newSize = new Dimension(longestLength / ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION * ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK + ScriptBuilderGuiConstants.TICK_TIMELINE_LEFT_MARGIN + 50, height); this.setPreferredSize(newSize); this.setSize(newSize); this.invalidate(); } /** * Refresh the panel. Redraw the ticks based on zoom level, panel * dimensions, and offset. If the user is trying to add an event, draw that * event's icon under the mouse. * * @param g The graphics component */ @Override public void paint(Graphics g) { super.paint(g); Graphics2D g2d = (Graphics2D) g; // Draw the horizontal line g2d.setFont(ScriptBuilderGuiConstants.TIMELINE_TICK_TIME_FONT); g2d.setColor(ScriptBuilderGuiConstants.TIMELINE_TICK_COLOR); g2d.fillRect(0, ScriptBuilderGuiConstants.TICK_TIMELINE_TOP_MARGIN, longestLength, ScriptBuilderGuiConstants.TICK_TIMELINE_HEIGHT); // Draw the ticks int longestLengthPlusMargin = longestLength / ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION * ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK + ScriptBuilderGuiConstants.TICK_TIMELINE_LEFT_MARGIN; // Minutes g2d.setColor(ScriptBuilderGuiConstants.MINOR_TICK_COLOR); int seconds = 0; for (int i = ScriptBuilderGuiConstants.TICK_TIMELINE_LEFT_MARGIN; i <= longestLengthPlusMargin; i += ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK, seconds += ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION) { g2d.drawLine(i, ScriptBuilderGuiConstants.TICK_TOP_MARGIN, i, ScriptBuilderGuiConstants.TICK_HEIGHT); } // Major Ticks g2d.setColor(ScriptBuilderGuiConstants.TIMELINE_TICK_COLOR); seconds = 0; for (int i = ScriptBuilderGuiConstants.TICK_TIMELINE_LEFT_MARGIN; i <= longestLengthPlusMargin; i += ScriptBuilderGuiConstants.PIXEL_WIDTH_PER_HORIZONTAL_TICK * ScriptBuilderGuiConstants.TICKS_PER_MAJOR_TICK, seconds += ScriptBuilderGuiConstants.HORIZONTAL_TICK_RESOLUTION * ScriptBuilderGuiConstants.TICKS_PER_MAJOR_TICK) { g2d.drawLine(i, ScriptBuilderGuiConstants.TICK_TOP_MARGIN, i, ScriptBuilderGuiConstants.TICK_HEIGHT); } paintChildren(g); if (focused && ((ScriptBuilderFrame) this.getTopLevelAncestor()).currentEventType != null) { EventIconDrawer.DrawEventIcon(g2d, ((ScriptBuilderFrame) this.getTopLevelAncestor()).currentEventType, x, y); } } }