/* calendarCanvas.java Paul Carlisle - November 18, 1997 Given a Julian date, draws a calendar grid for the month in which it occurs. */ import java.awt.*; import JDate; import Moon; public class calendarCanvas extends Canvas { private int Width; private int Height; private Moon moon; private JDate currentDate; private int cellWidth; private int cellHeight; private int moonWidth; private int moonHeight; private int[][] calendarGrid; private Image[][] dayImages; private Image[][] moonImages; private int daySelected; private int downSelect; private boolean Valid = false; private boolean Drawn = false; public calendarCanvas(JDate date, int width, Font dayCellFont) { setFont(dayCellFont); currentDate = date; calendarGrid = new int[6][7]; calendarGrid = currentDate.Grid(); daySelected = 0; downSelect = 0; moon = new Moon(); Width = width; Height = (6 * Width) / 7; cellWidth = Width / 7; cellHeight = Height / 6; moonWidth = (7 * cellWidth) / 10; if (moonWidth % 2 == 0) moonWidth++; moonHeight = (7 * cellHeight) / 10; if (moonHeight % 2 == 0) moonHeight++; dayImages = new Image[6][7]; moonImages = new Image[6][7]; resize(Width, Height); } // Resets to zero after each read, so subsequent reads don't get // the same result. public int getDate() { int temp = daySelected; daySelected = 0; return temp; } public boolean mouseDown(Event e, int mx, int my) { int x = mx / cellWidth; if (x > 6) x = 6; int y = my / cellHeight; if (y > 5) y = 5; if (calendarGrid[y][x] != 0) { daySelected = calendarGrid[y][x]; } return false; } // This routine is not terribly efficient at the moment. We discard, // recreate and redraw all the images and backgrounds everytime // through. It would be better to create the images once, leave // the backgrounds alone, and simply redraw onto the moon images; // there's no need to erase them. Then loop through and paste // the new moon images and dates into place over the existing // background. We need to test whether text has on opaque background; // if not, we have to redraw the backgrounds after all. // // Still, not bad for a first attempt. // // I think we're invoking the garbage collector by explicitly setting // all those images to null... // // 12-4-97 Fixed this so we only create the images once, upon construction. // Redraw is much faster now. We're still redrawing the backgrounds, but // this is staying in until we decide whether to implement 'clickable' // dayCells. These would 'depress' when clicked, unlike the current // implementation, which is static. public void paint(Graphics g) { Graphics gr; double phase; JDate tempDate = new JDate(); // Create images if not already done. if (!Drawn) { for (int y = 0; y < 6; y++) { for (int x = 0; x < 7; x++) { dayImages[y][x] = createImage(cellWidth, cellHeight); moonImages[y][x] = createImage(moonWidth, moonHeight); } } Drawn = true; } if (!Valid) { for (int y = 0; y < 6; y++) { for (int x = 0; x < 7; x++) { // Set backgrounds of cell images. gr = dayImages[y][x].getGraphics(); gr.setColor(Color.lightGray); if (calendarGrid[y][x] == 0) gr.fillRect(0, 0, cellWidth, cellHeight); else gr.fill3DRect(0, 0, cellWidth, cellHeight, true); // Set backgrounds of Moon images. gr = moonImages[y][x].getGraphics(); gr.setColor(Color.lightGray); gr.fillRect(0,0,moonWidth, moonHeight); if (calendarGrid[y][x] != 0) { // Calculate phase, and draw picture of it here. //phase = getPhase(calendarGrid[y][x]); tempDate.setDate(currentDate.getYear(), currentDate.getMonth(), calendarGrid[y][x]) ; moon.setDate(tempDate); moon.position(); phase = moon.phase(); int r = moonWidth / 2; int b = (int)Math.abs((moonWidth * Math.cos(phase))); gr.setColor(Color.white); gr.fillOval(0,0,moonWidth, moonHeight); gr.setColor(Color.darkGray); if ( (phase >= 0) && (phase < Math.PI/2)) { // Semi-circle. gr.fillArc(0,0,moonWidth,moonHeight, 90, 180); // Semi-ellipse. gr.fillArc(r - b/2 - 1, 0, b, moonWidth, 270, 180); } else if ( (phase >= 3*Math.PI/2) && (phase < 2*Math.PI) ) { gr.fillArc(0,0,moonWidth,moonHeight, 270, 180); gr.fillArc(r - b/2, 0, b, moonWidth, 90, 180); // Attempt to fix an anomaly under Solaris. gr.drawLine(r, 0, r, moonHeight); } else if ( (phase >= Math.PI/2) && (phase < Math.PI) ) { gr.fillArc(0,0,moonWidth,moonHeight, 90, 180); gr.setColor(Color.white); gr.fillArc(r - b/2, 0, b, moonHeight, 90, 180); // Attempt to fix an anomaly under Solaris. gr.drawLine(r, 0, r, moonHeight); } else if ( (phase >= Math.PI) && (phase < 3*Math.PI/2) ) { gr.fillArc(0,0,moonWidth,moonHeight, 270, 180); gr.setColor(Color.white); gr.fillArc(r - b/2 - 1, 0, b, moonWidth, 270, 180); } gr.dispose(); // Release Graphics object for the garbage collector. } } } Valid = true; } int px, py, sLength, sHeight; String dString; FontMetrics metrics = g.getFontMetrics(); g.setColor(Color.darkGray); sHeight = metrics.getAscent(); for (int y = 0; y < 6; y++) { py = y * cellHeight; for (int x = 0; x < 7; x++) { px = x * cellWidth; g.drawImage(dayImages[y][x], px, py, cellWidth, cellHeight, this); g.drawImage(moonImages[y][x], px + (cellWidth - moonWidth)/2, py + (cellHeight - moonHeight)/2, moonWidth, moonHeight, this); if (calendarGrid[y][x] != 0) { dString = Integer.toString(calendarGrid[y][x]); sLength = metrics.stringWidth(dString); g.drawString(dString, px + (cellWidth - sLength - 2), py + sHeight + 2); } } } } public void redraw(JDate date) { currentDate = date; calendarGrid = new int[6][7]; // Don't really need to call new here... calendarGrid = currentDate.Grid(); Valid = false; repaint(); } public void update(Graphics g) { paint(g); } }