package bmsi.fsp; import java.io.IOException; import java.awt.*; import java.awt.image.*; import bmsi.tui.TUIFontMetrics; /** A TUI implementation of java.awt.Graphics. This class is abstract so that it will compile in JDK1.1 or Java 2. The appropriate instance of FSToolkit will create a compatible instance of this class. @see FSToolkit#createGraphics */ abstract class FSGraphics extends Graphics { private FSToolkit toolkit; private FSComponent target; private int posx, posy; // origin private Rectangle clipRect; private Font font; private Color color; private int attr = TI.A_NORMAL; private int fg = 2; private boolean XORmode; private final int sx; private final int sy; static final char ULCORNER = '\u250c', URCORNER = '\u2510', LLCORNER = '\u2514', LRCORNER = '\u2518', VLINE = '\u2502', HLINE = '\u2500', PLUS = '\u253c', BTEE = '\u2534', TTEE = '\u252c', LTEE= '\u251c', RTEE = '\u2524'; /** We send all graphics commands to the remote component. */ FSGraphics(FSComponent comp) { target = comp; toolkit = comp.toolkit; attr = comp.getAttr(fg); //Point p = target.getLocationOnScreen(); //posx = p.x; //posy = p.y; sx = toolkit.scale.width; sy = toolkit.scale.height; } public Graphics create() { FSGraphics g = toolkit.createGraphics(target); g.clipRect = clipRect; g.translate(posx,posy); return g; } public void translate(int x,int y) { posx += x; posy += y; } /* jdk 1.0 compatibility */ public final Rectangle getClipRect() { return getClipBounds(); } public Rectangle getClipBounds() { return clipRect; } public void clipRect(int x,int y,int width,int height) { x += posx; y += posy; Rectangle newclip = new Rectangle(x,y,width,height); if (clipRect == null) setClip(newclip); else setClip(clipRect.intersection(newclip)); } public void setClip(int x,int y,int width,int height) { setClip(new Rectangle(x,y,width,height)); } public void setClip(Shape s) { // FIXME: I think the clipRect is relative to the FSComponent bounds clipRect = s.getBounds(); } public Shape getClip() { return clipRect; } public Color getColor() { return color; } public void setColor(Color c) { color = c; if (c != null) { fg = target.pixelFromColor(c); attr = target.getAttr(fg); System.err.println("fg="+fg+" attr="+Integer.toHexString(attr)); } } public void setPaintMode() { XORmode = false; } public void setXORMode(Color c) { XORmode = true; } public Font getFont() { return font; } public void setFont(Font f) { font = f; } public FontMetrics getFontMetrics(Font f) { return toolkit.getFontMetrics(f); } private void fill(int x,int y,int w,int h,char c) { try { x += posx; y += posy; // clip to bounds if (clipRect != null) { int x1 = clipRect.x; int x2 = x1 + clipRect.width; if (x < x1) { w -= x1 - x; x = x1; } if (x + w > x2) { w = x2 - x; } if (w <= 0) return; int y1 = clipRect.y; int y2 = y1 + clipRect.height; if (y < y1) { h -= y1 - y; y = y1; } if (y + h > y2) { h = y2 - y; } if (h <= 0) return; } target.fill(x/sx,y/sy,w/sx,h/sy,c); } catch (IOException e) { throw new AWTError("IO Error writing screen"); } } private void write(int x,int y,char[] c,int pos,int w) { try { x += posx; y += posy; // clip to bounds int h = sy; if (clipRect != null) { int y1 = clipRect.y; int y2 = y1 + clipRect.height; if (y < y1) { h -= y1 - y; y = y1; } if (y + h > y2) { h = y2 - y; } //System.err.println( // "x="+x+" y="+y+" w="+w+" h="+h+" y1="+y1+" y2="+y2+" posy="+posy); if (h <= 0) return; int x1 = clipRect.x; int x2 = x1 + clipRect.width; if (x < x1) { int d = (x1 - x)/sx; w -= d; pos += d; x = x1; } if (x + w*sx > x2) { w = (x2 - x)/sx; } if (w <= 0) return; } target.setAttr(attr); target.write(x/sx,y/sy,c,pos,w); } catch (IOException e) { throw new AWTError("IO Error writing screen"); } } /* Our TUI can do a lot of things like draw lines and boxes. And don't forget text! FIXME: for multiple TUIGraphics instances to work with multiple threads, each drawing command needs synchronized (target). */ public void copyArea(int x,int y,int width,int height,int dx,int dy) { x += posx; y += posy; // FIXME: not done yet } public void drawLine(int x1,int y1,int x2,int y2) { target.setAttr(attr); if (x1 == x2) // vertical line fill(x1,y1,sx,y2 - y1,VLINE); else if (y1 == y2) fill(x1,y1,x2 - x1,sy,HLINE); } public void fillRect(int x,int y,int width,int height) { target.setAttr(target.getAttr(0,fg)); fill(x,y,width,height,' '); } public void fill3DRect(int x,int y,int width,int height,boolean raised) { fillRect(x,y,width,height); } public void drawRect(int x,int y,int width,int height) { if (width == 0 || height == 0) return; if (width <= sx) { drawLine(x,y,x,y+height-sy); return; } if (height == sy) { drawLine(x,y,x+width-sx,y); return; } int x2 = x + width - sx; int y2 = y + height - sy; target.setAttr(attr); fill(x,y,sx,sy,ULCORNER); fill(x + sx,y,width - 2*sx,sy,HLINE); fill(x2,y,sx,sy,URCORNER); fill(x,y+sy,sx,height - 2*sy,VLINE); fill(x2,y+sy,sx,height - 2*sy,VLINE); fill(x,y2,sx,sy,LLCORNER); fill(x+sx,y2,width - 2*sx,sy,HLINE); fill(x2,y2,sx,sy,LRCORNER); } public void draw3DRect(int x,int y,int width,int height,boolean raised) { drawRect(x,y,width,height); } /** Clear area to background color. On screen drawing gets background color from component. */ public void clearRect(int x,int y,int width,int height) { target.setAttr(target.getAttr(0)); fill(x,y,width,height,' '); } public void drawRoundRect(int x,int y,int w,int h,int arcw,int arch) { drawRect(x,y,w,h); } public void fillRoundRect(int x,int y,int w,int h,int arcw,int arch) { fillRect(x,y,w,h); } public void drawString(String str,int x,int y) { int len = str.length(); if (len > 0) write(x,y - sy,str.toCharArray(),0,len); } public void drawPolyline(int[] x,int[] y,int n) { for (int i = 1; i < n; ++i) drawLine(x[i-1],y[i-1],x[i],y[i]); } public void drawPolygon(int[] x,int[] y,int n) { drawPolyline(x,y,n--); if (x[0] != x[n] || y[0] != y[n]) drawLine(x[n],y[n],x[0],y[0]); } /* Real garbage gets thrown away fast! :-) */ public void drawOval(int x,int y,int width,int height) { } public void fillOval(int x,int y,int width,int height) { } public void drawArc(int x,int y,int w,int h,int startang,int arcang) { } public void fillArc(int x,int y,int w,int h,int startang,int arcang) { } public void fillPolygon(int [] xpoints,int [] ypoints,int npoints) { } public boolean drawImage(Image img,int x,int y, ImageObserver obs) { obs.imageUpdate(img,obs.ERROR|obs.ABORT,x+posx,y+posy,0,0); return false; } public boolean drawImage(Image img,int x,int y,int w,int h, ImageObserver obs) { obs.imageUpdate(img,obs.ERROR|obs.ABORT,x+posx,y+posy,w,h); return false; } public boolean drawImage(Image img,int x,int y,Color c,ImageObserver obs) { obs.imageUpdate(img,obs.ERROR|obs.ABORT,x+posx,y+posy,0,0); return false; } public boolean drawImage(Image img,int x,int y,int w,int h,Color c, ImageObserver obs) { obs.imageUpdate(img,obs.ERROR|obs.ABORT,x+posx,y+posy,w,h); return false; } public boolean drawImage(Image img,int dx1,int dy1,int dx2,int dy2, int sx1,int sy1,int sx2,int sy2, ImageObserver obs) { obs.imageUpdate(img,obs.ERROR|obs.ABORT,sx1+posx,sy1+posy,sx2-sx1,sy2-sy1); return false; } public boolean drawImage(Image img, int dx1,int dy1,int dx2,int dy2, int sx1,int sy1,int sx2,int sy2, Color c, ImageObserver obs) { obs.imageUpdate(img,obs.ERROR|obs.ABORT,sx1+posx,sy1+posy,sx2-sx1,sy2-sy1); return false; } /** null out references to speed GC */ public void dispose() { toolkit.syncit.queue(); target = null; toolkit = null; } }