/* Position - Hipbone game, rules, ideas, etc. Copyright (C) Charles Cameron Copyright (C) 2004 John Comeau This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package com.jcomeau.hipbone; import java.applet.*; import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import java.awt.font.*; import java.net.*; import java.util.*; import com.jcomeau.*; public class Position extends Panel implements ComponentListener, MouseListener { static int[] size = {20, 20}; public String RCSId = "$Id: Position.java,v 1.1 2004/05/03 01:03:41 jcomeau Exp $"; public static void main(String[] args) { // let this be used as an app Common.debugging = true; CloseableFrame frame = new CloseableFrame(); Position panel = new Position(); frame.add(panel); frame.setSize(size[0], size[1]); frame.show(); } public void paint(Graphics graphics) { if (!parent.display) return; try { Graphics2D graphics2D = (Graphics2D)graphics; if (false) graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); FontMetrics fontMetrics = null; graphics2D.setPaint(Color.white); // fill board background first graphics2D.fill(new Rectangle2D.Double(0, 0, boardHeight, boardWidth)); fillTriangles(graphics2D); graphics2D.setPaint(Color.black); graphics2D.setStroke(new BasicStroke(1)); Common.debugprintln("drawing border square"); drawLine(graphics2D, 0, 0, 0, boardHeight); drawLine(graphics2D, 0, 0, boardWidth, 0); drawLine(graphics2D, 0, boardHeight, boardWidth, boardHeight); drawLine(graphics2D, boardWidth, 0, boardWidth, boardHeight); Common.debugprintln("drawing inner square"); double offset = displayedJointWidth / 2; // radius, plus... offset += (offset * (Math.sqrt(2) / 2)); // where bullet meets bone drawLine(graphics2D, offset, offset, offset, boardHeight - offset); drawLine(graphics2D, offset, offset, boardWidth - offset, offset); drawLine(graphics2D, offset, boardHeight - offset, boardWidth - offset, boardHeight - offset); drawLine(graphics2D, boardWidth - offset, offset, boardWidth - offset, boardHeight - offset); graphics2D.setStroke(new BasicStroke(2)); Common.debugprintln("drawing " + joints.length + " joints"); for (int i = 0; i < joints.length; i++) { for (int j = 0; j < jointConnections[i].length; j++) { int k = jointConnections[i][j] - 1; // zero-base the connection number drawLine(graphics2D, jointCenters[i][0], jointCenters[i][1], jointCenters[k][0], jointCenters[k][1]); } } // fill first, to white out the lines where the circles will be graphics2D.setPaint(Color.white); for (int i = 0; i < joints.length; i++) { graphics2D.fill(joints[i]); } // now draw the bold circles in black /* if we had done this first, the fill would white out all but * the outermost pixel of the circle */ graphics2D.setPaint(Color.black); for (int i = 0; i < joints.length; i++) { graphics2D.draw(joints[i]); } Common.debugprintln("Drawing in numbers"); graphics2D.setFont(condensedFont("TimesNewRoman", Font.BOLD, (int)(displayedJointHeight / 6))); for (int i = 0; i < joints.length; i++) { centerShow(graphics2D, Integer.toString(i + 1), jointCenters[i], (int)(displayedJointHeight / 2) - 3); } Common.debugprintln("Drawing in conceptions"); graphics2D.setFont(graphics2D.getFont().deriveFont(Font.PLAIN)); for (int i = 0; i < joints.length; i++) { String conception = gamelog.getConception(i); if (conception != null && conception.length() > 0) { centerShow(graphics2D, '"' + conception + '"', jointCenters[i], (int)(jointHeight / 10)); } } Common.debugprintln("Drawing in names and play numbers"); graphics2D.setFont(graphics2D.getFont().deriveFont(Font.BOLD)); for (int i = 0; i < joints.length; i++) { String userInfo = gamelog.getPlayer(i % 2) + ": " + (i + 1); int joint = gamelog.playOrder[i] - 1; if (joint > -1) { centerShow(graphics2D, userInfo, jointCenters[joint], -(int)(jointHeight / 20)); } } try { showStatus(state); } catch (Exception noShow) { Common.debugprintln("cannot show status " + state + ": " + noShow); } } catch (Throwable ignored) { Common.debugprintln("Cannot draw yet: " + ignored); // probably init() code not yet finished... so why is it painting? // found out why; running as app, and set visible before applet.init() } } public void centerShow(Graphics2D graphics2D, String text, double[] center, int yOffset) { FontMetrics fontMetrics = graphics2D.getFontMetrics(); int x = (int)center[0] - (int)(fontMetrics.stringWidth(text) / 2); int y = (int)center[1] + yOffset; graphics2D.drawString(text, x, y); } public Font condensedFont(String name, int style, int size) { Hashtable attributes = new Hashtable(); Font baseFont = new Font(name, style, size); attributes.put(TextAttribute.WIDTH, TextAttribute.WIDTH_CONDENSED); return baseFont.deriveFont(attributes); } public int whichJoint(int x, int y) { int[] xy = {x, y}; return whichJoint(xy); } public int whichJoint(int[] xy) { int x, y; x = xy[0]; y = xy[1]; for (int i = 0; i < joints.length; i++) { if (joints[i].contains(x, y)) return i; } return -1; } public void componentMoved(ComponentEvent event) {} public void componentHidden(ComponentEvent event) {} public void componentShown(ComponentEvent event) {} public void componentResized(ComponentEvent event) { Common.debugprintln("resized"); setSize(); repaint(); } public void mouseEntered(MouseEvent event) { mouseInside = true; } public void mousePressed(MouseEvent event) { Common.debugprintln("mouse pressed: " + event); if (event.isPopupTrigger()) { lastMouseDown[0] = -1; lastMouseDown[1] = -1; lastMouseDown[2] = 0; Common.debugprintln("show popup menu"); } else { lastMouseDown[0] = event.getX(); lastMouseDown[1] = event.getY(); lastMouseDown[2] = event.getButton(); } } public void mouseReleased(MouseEvent event) { if (event.isPopupTrigger()) { lastMouseDown[0] = -1; lastMouseDown[1] = -1; lastMouseDown[2] = 0; Common.debugprintln("show popup menu"); } else { lastMouseUp[0] = event.getX(); lastMouseUp[1] = event.getY(); lastMouseUp[2] = event.getButton(); } } public void mouseExited(MouseEvent event) { mouseInside = false; } public void mouseClicked(MouseEvent event) { int down = whichJoint(lastMouseDown); int up = whichJoint(lastMouseUp); boolean sameButton = (lastMouseDown[2] == lastMouseUp[2]); if (down != -1 && down == up && sameButton) { state = "Joint " + (down + 1) + " clicked"; repaint(); new NamesDialog(dialogFrame, this, down + 1); } } }