/* TODO: Make creation of Hcube, Ring, etc more streamlined Create grouped objects, particularly for text Special selection for text, with double click. Selectors should have priority for events Launch an Item from its selected text name. Incorporate Quikwriting variant Put in more active applets (eg: planet) */ import java.awt.*; import java.awt.image.*; import java.util.*; public class Zoom5 extends BufferedApplet { WhiteBoard whiteBoard = new WhiteBoard(this); public boolean mouseDown(Event e, int x, int y) { return whiteBoard.mouseDown(e, x, y); } public boolean mouseDrag(Event e, int x, int y) { return whiteBoard.mouseDrag(e, x, y); } public boolean mouseUp(Event e, int x, int y) { return whiteBoard.mouseUp(e, x, y); } public boolean keyUp(Event e, int key) { return whiteBoard.keyUp(e, key); } public void render(Graphics g) { if (! damage && ! whiteBoard.isDamage) return; whiteBoard.width = bounds().width; whiteBoard.height = bounds().height; whiteBoard.render(g); } } class WhiteBoard extends Item { WhiteBoard(java.applet.Applet applet) { super(); this.applet = applet; /* Item item = new Hcube(); item.parent = this; item.color = color; item.init(width/2, height/2, 1); items.addElement(item); */ } java.applet.Applet applet; Vector selectors = new Vector(); Item activeItem = null; Selector activeSelector = null; int nChars = 0, nLines = 0, x, y, border; Stroke s; boolean isTap = false, tapOnSelector = false; int count = 0, x1 = -1, y1; ///////////// CONVENIENT ACCESS FUNCTIONS FOR COMMON ITEM TYPES Stroke stroke(int n) { return (Stroke)item(n); } Selector selector(int n) { return (Selector)item(n); } Stroke lastStroke() { return stroke(lastStrokeIndex()); } int lastStrokeIndex() { for (int i = items.size()-1 ; i >= 0 ; i--) if (item(i) instanceof Stroke) return i; return -1; } void removeLastStroke(int n) { int i = lastStrokeIndex(); if (i >= 0) items.removeElementAt(i); } ///////////// SUPPORT FOR ZOOMING FROM JAVASCRIPT BUTTONS String name = ""; int jsX, jsY; // this is the center-of-zoom, when zooming from javascript void jsSet(int x, int y) { jsX = x; jsY = y; name = ""; } public void up() { zoomSurface(jsX, jsY, 2); } public void down() { zoomSurface(jsX, jsY,.5); } ///////////// ZOOMING LOGIC double ZOOM = 1; public void zoomSurface(int x, int y, double z) { if (z != 1) { S /= z; X += (x - X) * (1 - 1/z); Y += (y - Y) * (1 - 1/z); nChars = nLines = 0; isDamage = true; } } public void zoomSelector(Selector sel, int x, int y, double z) { double dx, dy; dx = (x - X) * (1 - z); dy = (y - Y) * (1 - z); sel.X += dx * sel.S / S; sel.Y += dy * sel.S / S; sel.S *= z; for (int i = 0 ; i < sel.items.size() ; i++) { Item s = sel.item(i); s.X += dx * s.S / S; s.Y += dy * s.S / S; s.S *= z; } } ///////////// EVENT HANDLERS boolean setColor = false; boolean panOrZoomSurface = false, zoomSurface = false, panSurface = false, panSelector = false; int px = 0, py = 0, zy, nd; // *************** MOUSE DOWN public boolean mouseDown(Event e, int x, int y) { // begin a new stroke activeItem = null; nChars = nLines = 0; px = x; py = y; nd = 0; for (int j = items.size()-1 ; j >= 0 ; j--) { Item item = item(j); if (!(item instanceof Stroke)) { int ix = item.xFromScreen(x); int iy = item.yFromScreen(y); if (item.handles(ix, iy)) { // starting to drag within a selector moves that selector if (item instanceof Selector) { activeSelector = (Selector)item; activeSelector.sticky = false; panSelector = true; ZOOM = 1; count = 0; return true; } // check for procedural objects else if (item.mouseDown(e, ix, iy)) { activeItem = item; if (activeItem.isDamage) isDamage = true; activeItem.isDamage = false; return true; } } } } // tap creates a new selector if (isTap) { activeSelector = new Selector(); activeSelector.parent = this; activeSelector.init((x-X)/S, (y-Y)/S, 1); items.addElement(activeSelector); } // select a color from the color palette else if (y >= height-border && x >= width/2-3*border && x < width/2+3*border) { if (x < width/2-border) color = Color.white; else if (x < width/2) color = Color.red; else if (x < width/2+border) color = Color.green.darker(); else if (x < width/2+2*border) color = Color.blue; else color = Color.black; setColor = true; } // starting to drag on the border drags the whole surface else if (x < border || y < border || x >= width-border || y >= height-border) { panOrZoomSurface = true; panSurface = zoomSurface = false; ZOOM = 1; } // default: start drawing a new stroke else { items.addElement(s = new Stroke()); s.parent = this; s.color = color; s.fat = (color == Color.white ? 32 : 4); s.S = S; s.addPoint(x, y); } return true; } // *************** MOUSE DRAG public boolean mouseDrag(Event e, int x, int y) { // add a point to the stroke nd++; nChars = nLines = 0; if (activeItem != null) { activeItem.mouseDrag(e, activeItem.xFromScreen(x), activeItem.yFromScreen(y)); if (activeItem.isDamage) isDamage = true; activeItem.isDamage = false; } else if (setColor) ; // dragging after a tap rubber-bands the new selector else if (isTap) { count++; activeSelector.set(px, py, x, y); isDamage = true; return true; } // dragging a selected region else if (panSelector) { count++; Selector sel = activeSelector; if (sel.loX() + (x-px) < border/2 || sel.loY() + (y-py) < border/2 || sel.hiX() + (x-px) >= width-border/2 || sel.hiY() + (y-py) >= height-border/2) sel.sticky = true; else { sel.X += (px - x) * sel.S / S; sel.Y += (py - y) * sel.S / S; for (int i = 0 ; i < sel.items.size() ; i++) { Item s = sel.item(i); s.X += (px - x) * s.S / S; s.Y += (py - y) * s.S / S; } sel.sticky = sel.loX() < border || sel.loY() < border || sel.hiX() >= width - border || sel.hiY() >= height - border; if (ZOOM < 1 || (sel.hiX()-sel.loX()) * (sel.hiY()-sel.loY()) * ZOOM >= 4*border*border) zoomSelector(sel, x, y, ZOOM); } isDamage = true; px = x; py = y; return true; } // dragging the entire surface else if (panOrZoomSurface) { if (zoomSurface || (!panSurface && (x < border || x > width-border) && Math.abs(y-py) > Math.abs(x-px))) { zoomSurface = true; panSurface = false; ZOOM = y > py ? 1/1.03 : 1.03; zoomSurface(width/2, height/2, ZOOM); for (int j = 0 ; j < items.size() ; j++) if (item(j) instanceof Selector) { Selector sel = selector(j); if (sel.sticky) { zoomSelector(sel, width/2, height/2, 1/ZOOM); } } } else { panSurface = true; zoomSurface = false; X += x - px; Y += y - py; for (int j = 0 ; j < items.size() ; j++) if (item(j) instanceof Selector) { Selector sel = selector(j); if (sel.sticky) { sel.X += (x - px) * sel.S / S; sel.Y += (y - py) * sel.S / S; for (int i = 0 ; i < sel.items.size() ; i++) { Item s = sel.item(i); s.X += (x - px) * s.S / S; s.Y += (y - py) * s.S / S; } } } } isDamage = true; px = x; py = y; return true; } else { // checking whether we've entered a selected region from the top or bottom activeSelector = null; for (int j = 0 ; j < items.size() ; j++) if (item(j) instanceof Selector) { Selector sel = selector(j); if (sel.contains(x, y) && (py < sel.loY() || py > sel.hiY())) { removeLastStroke(0); ZOOM = (py < sel.loY()) ? 1.02 : 1/1.02; //top=shrink, bottom=drag activeSelector = sel; panSelector = true; px = x; py = y; isDamage = true; return true; } } // otherwise, dragging extends the current stroke s.addPoint(x, y); } isDamage = true; return true; } // *************** MOUSE UP public boolean mouseUp(Event e, int x, int y) { jsSet(x, y); // if we had tapped on a selector before, and it's not sticky, then just delete it if (tapOnSelector) { if (count < 2) { items.removeElement(activeSelector); activeSelector = null; } panSelector = tapOnSelector = false; isDamage = true; return true; } if (panSelector) { if (count < 2) { tapOnSelector = true; select(activeSelector); } panSelector = false; } else if (panOrZoomSurface) panOrZoomSurface = false; else if (setColor) setColor = false; else if (activeItem != null) { activeItem.mouseUp(e, activeItem.xFromScreen(x), activeItem.yFromScreen(y)); if (activeItem.isDamage) isDamage = true; activeItem.isDamage = false; activeItem = null; } // finished dragging over selector else if (isTap) { isTap = false; Selector sel = activeSelector; // if this was another tap - then make a small touch box if (count < 2) { sel.set(px-border/2, py-border/2, px+border/2, py+border/2); sel.isTouchBox = true; select(sel); } // else if the area was too small to be useful, then don't make a selection box else if (sel.hiX() - sel.loX() < border && sel.hiY() - sel.loY() < border) items.removeElement(sel); // otherwise we must select all items that lie completely within this box else select(sel); activeSelector = null; isDamage = true; return true; } else if (items.size() == 0) return true; // IF THIS WAS A TAP else if (items.size() > 0 && lastStroke().k <= 6) { removeLastStroke(3); // tap on background to indicate we're about to define a new selector if (! isTap) { count = 0; isTap = true; } isDamage = true; } // IF THIS WAS A STROKE else { // for hand-drawn strokes: end the stroke lastStroke().end(); // Check for gestures involving selection boxes // compute first point in stroke in screen coords int x0 = s.a(0); int y0 = s.a(1); int xn = s.a(s.k-2); int yn = s.a(s.k-1); // compute stroke bounds in screen coords int loX = s.loX(); int loY = s.loY(); int hiX = s.hiX(); int hiY = s.hiY(); for (int j = 0 ; j < items.size() ; j++) if (item(j) instanceof Selector) { Selector sel = selector(j); // stroke inward from either side - duplicate if (y0 > sel.loY() && y0 < sel.hiY() && yn > sel.loY() && yn < sel.hiY() && (x0 < sel.loX() && xn >= sel.loX() || x0 >= sel.hiX() && xn < sel.hiX())) { removeLastStroke(9); Selector sel2 = (Selector)sel.clone(); items.addElement(sel2); sel2.items = new Vector(); Item item; for (int i = 0 ; i < sel.items.size() ; i++) { item = (Item)sel.item(i).clone(); items.addElement(item); sel2.items.addElement(item); } isDamage = true; return true; } // stroke through from side and back again deletes selector and all its contents else if (y0 > sel.loY() && y0 < sel.hiY() && yn > sel.loY() && yn < sel.hiY() && (x0 < sel.loX() && xn < sel.loX() || x0 >= sel.hiX() && xn >= sel.hiX())) { removeLastStroke(8); if (loX < sel.loX() && hiX >= sel.hiX()) { for (int i = 0 ; i < sel.items.size() ; i++) items.removeElement(sel.item(i)); items.removeElement(sel); } isDamage = true; return true; } // stroke through box from left to down - convert to surroundBox else if (loY > sel.loY() && hiY < sel.hiY() && x0 > sel.hiX() && loX < sel.loX()) { removeLastStroke(7); sel.isTouchBox = false; select(sel); isDamage = true; return true; } // stroke through box from left to up - convert to touchBox else if (loY > sel.loY() && hiY < sel.hiY() && x0 < sel.loX() && hiX > sel.hiX()) { removeLastStroke(6); sel.isTouchBox = true; select(sel); isDamage = true; return true; } } } return true; } // *************** KEY UP public boolean keyUp(Event e, int key) { // key-up event isTap = false; switch (key) { case '\n': nLines++; nChars = 0; name = ""; break; case 27: for (int i = 0 ; i < name.length() ; i++) items.removeElementAt(items.size()-1); String className = name; name = ""; try { try { try { Item item = (Item)Class.forName(className).newInstance(); item.parent = this; item.color = color; item.init((jsX-X)/S, (jsY-Y)/S, 1/S); items.addElement(item); } catch (InstantiationException ex) { System.out.println(ex); } } catch (IllegalAccessException ex) { System.out.println(ex); } } catch (ClassNotFoundException ex) { System.out.println(ex); } break; case '\b': if (nChars > 0) { removeLastStroke(12); nChars--; } break; default: if ( !(key >= 0 && key < Stroke.font.length && Stroke.font[key] != null) ) key = 0; items.addElement(s = new Stroke()); s.parent = this; s.init(-8 * nChars++ - jsX + X, -16 * nLines - jsY + Y, S); if (key > 32 && key < 128) name += (char)key; s.color = color; s.a = Stroke.font[key]; s.computeBounds(); tryToSelect(activeSelector, lastStroke()); } isDamage = true; return true; } ///////////// STROKE SELECTION LOGIC void select(Selector sel) { sel.items = new Vector(); for (int i = 0 ; i < items.size() ; i++) if (! (item(i) instanceof Selector)) tryToSelect(sel, item(i)); } void tryToSelect(Selector sel, Item s) { if (sel == null) return; boolean isSelected = false; int loX = s.loX(); int loY = s.loY(); int hiX = s.hiX(); int hiY = s.hiY(); if (sel.isTouchBox ? s.touches(sel) : sel.contains(loX, loY) && sel.contains(hiX, hiY)) sel.items.addElement(s); } ///////////// RENDERING THE IMAGE public void render(Graphics g) { if (! isDamage) return; isDamage = false; // clear the background border = height/20; g.setColor(Color.white); g.fillRect(border, border, width-2*border, height-2*border); g.setColor(Color.black); // draw the selectors for (int j = 0 ; j < items.size() ; j++) if (item(j) instanceof Selector) selector(j).render(g); // render all the items for (int i = 0 ; i < items.size() ; i++) { Item s = item(i); if (! (s instanceof Selector)) { /* int w = (int)(s.hiX() - s.loX()); int h = (int)(s.hiY() - s.loY()); if (s.im == null || s.imWidth != w) { s.imWidth = w; s.im = applet.createImage(w, h); } */ s.render(g); } } // draw the border g.setColor(Color.gray); g.fillRect(0, 0, width, border); g.fillRect(0, height-border, width, border); g.fillRect(0, 0, border, height); g.fillRect(width-border, 0, border, height); g.setColor(Color.white); g.fillRect(width/2-3*border+1, height-border+1, 2*border-2, border-2); g.setColor(Color.red); g.fillRect(width/2-border+1, height-border+1, border-2, border-2); g.setColor(Color.green.darker()); g.fillRect(width/2+1, height-border+1, border-2, border-2); g.setColor(Color.blue); g.fillRect(width/2+border+1, height-border+1, border-2, border-2); g.setColor(Color.black); g.fillRect(width/2+2*border+1, height-border+1, border-2, border-2); g.setColor(Color.gray.brighter()); g.drawLine(0, 0, width, 0); g.drawLine(0, 0, 0, height); g.drawLine(border, height-border, width-border, height-border); g.drawLine(width-border, border, width-border, height-border); g.setColor(Color.black); g.drawLine(border-1, border-1, width-border, border-1); g.drawLine(border-1, border-1, border-1, height-border); g.drawLine(0, height-1, width, height-1); g.drawLine(width-1, 0, width-1, height); // show the zoom level in the bottom-left corner g.drawString("S=" + S, 2, height-2); } } class Selector extends Item { static Color selectColor = new Color(240, 220, 120); static Color stickyColor = new Color(192, 176, 96); boolean isTouchBox = false, sticky = false; public void init(double x, double y, double s) { loX = hiX = x; loY = hiY = y; S = s; } void set(double x1, double y1, double x2, double y2) { x1 = xFromParent(x1); y1 = yFromParent(y1); x2 = xFromParent(x2); y2 = yFromParent(y2); loX = Math.min(x1, x2); hiX = Math.max(x1, x2); loY = Math.min(y1, y2); hiY = Math.max(y1, y2); } public void render(Graphics g) { int x1 = loX(); int y1 = loY(); int x2 = hiX(); int y2 = hiY(); g.setColor(sticky ? stickyColor : selectColor); g.fillRect(x1, y1, x2-x1, y2-y1); g.setColor((sticky ? stickyColor : selectColor).brighter()); g.drawLine(x1, y1, x2, y1); g.drawLine(x1, y1, x1, y2); g.setColor(Color.black); g.drawLine(x1, y2, x2, y2); g.drawLine(x2, y1, x2, y2); if (isTouchBox) { g.drawLine(x1+1, y1+1, x2-1, y1+1); g.drawLine(x1+1, y1+1, x1+1, y2-1); g.setColor((sticky ? stickyColor : selectColor).brighter()); g.drawLine(x1+1, y2-1, x2-1, y2-1); g.drawLine(x2-1, y1+1, x2-1, y2-1); } } } class Stroke extends Item { static final int NULL = -100000; static int tmpbuf[] = new int[10000]; // maximum coords in any one drawn line int a[], k = 0; double fat = 1; void init(double x, double y, double s) { X = x; Y = y; S = s; } int a(int j) { return j%2 == 0 ? xToScreen(a[j]) : yToScreen(a[j]); } void addPoint(int x, int y) { // extend the currently drawn line by one point x = xFromScreen(x); y = yFromScreen(y); if (k == 0) a = tmpbuf; a[k+2] = NULL; // always pad the buffer with NULL a[k ] = x; a[k+1] = y; loX = Math.min(loX, x); loY = Math.min(loY, y); hiX = Math.max(hiX, x); hiY = Math.max(hiY, y); k += 2; } void end() { if (a == tmpbuf) a = copyPoints(); } int[] copyPoints() { int b[] = new int[k+3]; for (int j = 0 ; j < k+3 ; j++) b[j] = a[j]; return b; } void computeBounds() { for (int i = 0 ; a[2*i] != NULL ; i++) { int x = a[2*i]; int y = a[2*i+1]; if (y >= 0) { loX = Math.min(loX, x); loY = Math.min(loY, y); hiX = Math.max(hiX, x); hiY = Math.max(hiY, y); } } } boolean touches(Item s) { if (super.touches(s)) for (int j = 0 ; a[j+2] != NULL ; j += 2) if (a[j+1] != NULL && a[j+3] != NULL && s.contains(a(j), a(j+1))) return true; return false; } int sx[] = new int[4]; int sy[] = new int[4]; public void render(Graphics g) { double mag = parent.S / S; int x1 = loX(); int y1 = loY(); int x2 = hiX(); int y2 = hiY(); if (x1 >= parent.width || y1 >= parent.height || x2 < 0 || y2 < 0) return; if (x2-x1 <= 1 && y2-y1 <= 1) { g.fillRect(x1, y1, 1, 1); return; } int w = (int)(mag * fat); g.setColor(color); if (w > 2) { x1 = xToScreen(a[0]); y1 = yToScreen(a[1]); g.fillOval(x1-w/2, y1-w/2, w-1, w-1); } for (int j = 0 ; a[j+2] != NULL ; j += 2) if (a[j+1] != NULL && a[j+3] != NULL) { x1 = a(j ); y1 = a(j+1); x2 = a(j+2); y2 = a(j+3); if (w <= 1) { if (x1 != x2 || y1 != y2) g.drawLine(x1, y1, x2, y2); } else if (w < 4) { computeThickLine(x1, y1, x2, y2, 2, sx, sy); g.fillPolygon(sx, sy, 4); } else { computeThickLine(x1, y1, x2, y2, w, sx, sy); if (isVisible(sx, sy)) g.fillPolygon(sx, sy, 4); // draw a magnified segment g.fillOval(x2-w/2, y2-w/2, w-1, w-1); } } } boolean isVisible(int[] x, int[] y) { int loX = 10 * parent.width; int loY = 10 * parent.height; int hiX = -10 * parent.width; int hiY = -10 * parent.height; for (int j = 0 ; j < x.length ; j++) { loX = Math.min(loX, x[j]); loY = Math.min(loY, y[j]); hiX = Math.max(hiX, x[j]); hiY = Math.max(hiY, y[j]); } return loX < parent.width && loY < parent.height && hiX >= 0 && hiY >= 0; } void computeThickLine(int ax, int ay, int bx, int by, int w, int[] x, int[] y) { double lx = bx - ax; double ly = by - ay; double len = Math.sqrt(lx * lx + ly * ly); int wx = (int)(2 * -ly * w / len); int wy = (int)(2 * lx * w / len); x[0] = ((ax<<2)-wx)>>2; x[1] = ((ax<<2)+wx)>>2; x[2] = ((bx<<2)+wx)>>2; x[3] = ((bx<<2)-wx)>>2; y[0] = ((ay<<2)-wy)>>2; y[1] = ((ay<<2)+wy)>>2; y[2] = ((by<<2)+wy)>>2; y[3] = ((by<<2)-wy)>>2; } ///////////// KEN'S HANDY-DANDY LINE FONT static public int font[][] = new int[256][]; static int fontData[][] = { { 0 }, {0, 0, 6, 0, 6,10, 0,10, 0, 0,-1}, {' '}, {NULL}, {'`'}, {2, 0, 4, 2,NULL}, {'~'}, {0, 5, 2, 4, 4, 5, 6, 4,NULL}, {'!'}, {3, 0, 3, 7, 0,NULL, 3, 9, 3,10,NULL}, {'@'}, {6, 8, 4,10, 2,10, 0, 8, 0, 2, 2, 0, 4, 0, 6, 2, 6, 6, 4, 8, 2, 6, 2, 4, 4, 3, 4, 8,NULL}, {'#'}, {2, 0, 1,10, 0,NULL, 5, 0, 4,10, 0,NULL, 0, 3, 6, 3, 0,NULL, 0, 7, 6, 7,NULL}, {'$'}, {5, 2, 4, 1, 2, 1, 1, 2, 1, 4, 2, 5, 4, 5, 5, 6, 5, 8, 4, 9, 2, 9, 1, 8, 0,NULL, 3, 0, 3,10,NULL}, {'%'}, {0,10, 6, 0, 0,NULL, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0,NULL, 4, 8, 4,10, 6,10, 6, 8, 4, 8,NULL}, {'^'}, {1, 2, 3, 0, 5, 2,NULL}, {'&'}, {6,10, 1, 3, 1, 1, 2, 0, 3, 0, 4, 1, 4, 3, 0, 8, 0, 9, 1,10, 3,10, 6, 7,NULL}, {'*'}, {3, 0, 3, 3, 0,NULL, 0, 2, 3, 3, 0,NULL, 6, 2, 3, 3, 0, NULL, 1, 6, 3, 3, 0,NULL, 5, 6, 3, 3,NULL}, {'('}, {4, 0, 3, 3, 3, 7, 4,10,NULL}, {')'}, {2, 0, 3, 3, 3, 7, 2,10,NULL}, {'-'}, {1, 5, 5, 5,NULL}, {'_'}, {0,11, 6,11,NULL}, {'='}, {1, 4, 5, 4, 0,NULL, 1, 6, 5, 6,NULL}, {'+'}, {0, 5, 6, 5, 0,NULL, 3, 2, 3, 8,NULL}, {'['}, {4, 0, 2, 0, 2,10, 4,10,NULL}, {'{'}, {4, 0, 3, 1, 3, 4, 2, 5, 3, 6, 3, 9, 4,10,NULL}, {']'}, {2, 0, 4, 0, 4,10, 2,10,NULL}, {'}'}, {2, 0, 3, 1, 3, 4, 4, 5, 3, 6, 3, 9, 2,10,NULL}, {'\\'},{1, 0, 5,10,NULL}, {'|'}, {3, 0, 3,10,NULL}, {';'}, {3, 3, 3, 4, 0,NULL, 3, 8, 3, 9, 2,11,NULL}, {':'}, {3, 3, 3, 4, 0,NULL, 3, 8, 3, 9,NULL}, {'\''},{4, 0, 2, 2,NULL}, {'"'}, {2, 0, 2, 2, 0,NULL, 4, 0, 4, 2,NULL}, {','}, {3, 8, 3, 9, 2,11,NULL}, {'<'}, {5, 1, 1, 5, 5, 9,NULL}, {'.'}, {3, 9, 3,10,NULL}, {'>'}, {1, 1, 5, 5, 1, 9,NULL}, {'/'}, {5, 0, 1,10,NULL}, {'?'}, {0, 1, 1, 0, 5, 0, 6, 1, 6, 4, 3, 6, 3, 7, 0,NULL, 3, 9, 3,10,NULL}, {'0'}, {6, 5, 6, 2, 4, 0, 2, 0, 0, 2, 0, 8, 2,10,4,10, 6, 8, 6, 5,NULL}, {'1'}, {1, 2, 3, 0, 3,10,NULL}, {'2'}, {0, 1, 1, 0, 5, 0, 6, 1, 6, 4, 0,10, 6,10,NULL}, {'3'}, {0, 1, 1, 0, 5, 0, 6, 1, 6, 4, 4, 5, 6, 6, 6, 9, 5,10, 1,10, 0, 9,NULL}, {'4'}, {5,10, 5, 0, 0, 5, 6, 5,NULL}, {'5'}, {6, 0, 0, 0, 0, 5, 5, 5, 6, 6, 6, 9, 5,10, 1,10, 0, 9,NULL}, {'6'}, {6, 1, 5, 0, 1, 0, 0, 1, 0, 9, 1,10, 5,10, 6, 9, 6, 6, 5, 5, 0, 5,NULL}, {'7'}, {0, 0, 6, 0, 3,10,NULL}, {'8'}, {2, 5, 1, 5, 0, 4, 0, 1, 1, 0, 5, 0, 6, 1, 6, 4, 5, 5, 1, 5, 0, 6, 0, 9, 1,10, 5,10, 6, 9, 6, 6, 5, 5, 3, 5,NULL}, {'9'}, {0, 9, 1,10, 5,10, 6, 9, 6, 1, 5, 0, 1, 0, 0, 1, 0, 4, 1, 5, 6, 5,NULL}, {'a'}, {0, 5, 1, 4, 5, 4, 6, 5, 6,10, 0,NULL, 6, 8, 4,10, 1,10, 0, 9, 0, 8, 1, 7, 6, 7,NULL}, {'A'}, {0,10, 3, 0, 6,10, 0,NULL, 1, 7, 5, 7,NULL}, {'b'}, {0, 0, 0,10, 0,NULL, 0, 6, 2, 4, 5, 4, 6, 5, 6, 9, 5,10, 2,10, 0, 8,NULL}, {'B'}, {0, 5, 0, 0, 5, 0, 6, 1, 6, 4, 5, 5, 0,NULL, 0, 5, 0,10, 5,10, 6, 9, 6, 6, 5, 5, 0, 5,NULL}, {'c'}, {6, 5, 5, 4, 1, 4, 0, 5, 0, 9, 1,10, 5,10, 6, 9,NULL}, {'C'}, {6, 1, 5, 0, 1, 0, 0, 1, 0, 9, 1,10, 5,10, 6, 9,NULL}, {'d'}, {6, 0, 6,10, 0,NULL, 6, 6, 4, 4, 1, 4, 0, 5, 0, 9, 1,10, 4,10, 6, 8,NULL}, {'D'}, {0, 5, 0, 0, 4, 0, 6, 2, 6, 8, 4,10, 0,10, 0, 5,NULL}, {'e'}, {0, 7, 6, 7, 6, 5, 5, 4, 1, 4, 0, 5, 0, 9, 1,10, 5,10, 6, 9,NULL}, {'E'}, {6, 0, 0, 0, 0,10, 6,10, 0,NULL, 0, 5, 4, 5,NULL}, {'f'}, {2,10, 2, 1, 3, 0, 5, 0, 6, 1, 0,NULL, 0, 4, 6, 4,NULL}, {'F'}, {6, 0, 0, 0, 0,10, 0,NULL, 0, 5, 4, 5,NULL}, {'g'}, {0,12, 1,13, 5,13, 6,12, 6, 4, 0,NULL, 6, 6, 4, 4, 1, 4, 0, 5, 0, 9, 1,10, 4,10, 6, 8,NULL}, {'G'}, {6, 1, 5, 0, 1, 0, 0, 1, 0, 9, 1,10, 5,10, 6, 9, 6, 5, 3, 5,NULL}, {'h'}, {0, 0, 0,10, 0,NULL, 0, 6, 2, 4, 5, 4, 6, 5, 6,10,NULL}, {'H'}, {0, 0, 0,10, 0,NULL, 6, 0, 6,10, 0,NULL, 0, 5, 6, 5,NULL}, {'i'}, {3,10, 3, 4, 0,NULL, 3, 1, 3, 0,NULL}, {'I'}, {3,10, 3, 0, 0,NULL, 1, 0, 5, 0, 0,NULL, 1,10, 5,10,NULL}, {'j'}, {5, 4, 5,12, 4,13, 1,13, 0,12, 0,NULL, 5, 1, 5, 0,NULL}, {'J'}, {6, 0, 6, 9, 5,10, 1,10, 0, 9, 0, 8,NULL}, {'k'}, {0, 0, 0,10, 0,NULL, 6, 4, 1, 7, 6,10,NULL}, {'K'}, {0, 0, 0,10, 0,NULL, 6, 0, 1, 5, 6,10,NULL}, {'l'}, {2, 0, 3, 0, 3,10,NULL}, {'L'}, {0, 0, 0,10, 6,10,NULL}, {'m'}, {0,10, 0, 4, 0,NULL, 0, 4, 2, 4, 3, 5, 3,10, 3, 5, 4, 4, 5, 4, 6, 5, 6,10,NULL}, {'M'}, {0,10, 0, 0, 3, 4, 6, 0, 6,10,NULL}, {'n'}, {0,10, 0, 4, 0,NULL, 0, 6, 2, 4, 5, 4, 6, 5, 6,10,NULL}, {'N'}, {0,10, 0, 0, 6,10, 6, 0,NULL}, {'o'}, {6, 7, 6, 5, 5, 4, 1, 4, 0, 5, 0, 9, 1,10,5,10, 6, 9, 6, 7,NULL}, {'O'}, {6, 5, 6, 1, 5, 0, 1, 0, 0, 1, 0, 9, 1,10,5,10, 6, 9, 6, 5,NULL}, {'p'}, {0, 4, 0,13, 0,NULL, 0, 6, 2, 4, 5, 4, 6, 5, 6, 9, 5,10, 2,10, 0, 8,NULL}, {'P'}, {0,10, 0, 0, 5, 0, 6, 1, 6, 4, 5, 5, 0, 5,NULL}, {'q'}, {6, 4, 6,13, 0,NULL, 6, 6, 4, 4, 1, 4, 0, 5, 0, 9, 1,10, 4,10, 6, 8,NULL}, {'Q'}, {6, 5, 6, 1, 5, 0, 1, 0, 0, 1, 0, 9, 1,10,4,10, 6, 8, 6, 5, 0,NULL, 3, 7, 6,10,NULL}, {'r'}, {0,10, 0, 4, 0,NULL, 0, 6, 2, 4, 5, 4, 6, 5,NULL}, {'R'}, {0,10, 0, 0, 5, 0, 6, 1, 6, 4, 5, 5, 0, 5, 0,NULL, 3, 5, 6,10,NULL}, {'s'}, {6, 5, 5, 4, 1, 4, 0, 5, 0, 6, 1, 7, 5, 7, 6, 8, 6, 9, 5,10, 1,10, 0, 9,NULL}, {'S'}, {6, 1, 5, 0, 1, 0, 0, 1, 0, 4, 1, 5, 5, 5, 6, 6, 6, 9, 5,10, 1,10, 0, 9,NULL}, {'t'}, {2, 2, 2, 9, 3,10, 5,10, 6, 9, 0,NULL, 0, 4, 6, 4,NULL}, {'T'}, {0, 0, 6, 0, 0,NULL, 3, 0, 3,10,NULL}, {'u'}, {6, 4, 6,10, 0,NULL, 6, 8, 4,10, 1,10, 0, 9, 0, 4,NULL}, {'U'}, {0, 0, 0, 9, 1,10, 5,10, 6, 9, 6, 0,NULL}, {'v'}, {0, 4, 3,10, 6, 4,NULL}, {'V'}, {0, 0, 3,10, 6, 0,NULL}, {'w'}, {0, 4, 1,10, 3, 7, 5,10, 6, 4,NULL}, {'W'}, {0, 0, 1,10, 3, 5, 5,10, 6, 0,NULL}, {'x'}, {0, 4, 6,10, 0,NULL, 0,10, 6, 4,NULL}, {'X'}, {0, 0, 6,10, 0,NULL, 0,10, 6, 0,NULL}, {'y'}, {0, 4, 3,10, 0,NULL, 6, 4, 2,13,NULL}, {'Y'}, {0, 0, 3, 5, 0,NULL, 6, 0, 3, 5, 0,NULL, 3, 5, 3,10,NULL}, {'z'}, {0, 4, 6, 4, 0,10, 6,10,NULL}, {'Z'}, {0, 0, 6, 0, 0,10, 6,10,NULL}, }; static boolean initFont = initFont(); static boolean initFont() { for (int i = 0 ; i < fontData.length ; i += 2) font[fontData[i][0]] = fontData[i+1]; return true; } }