package bmsi.fsp; import java.util.Vector; import java.io.IOException; import java.awt.Rectangle; /** Coordinate PWin windows for a terminal screen. @author Stuart D. Gathman Copyright (C) 2000 Business Management Systems, Inc. */ public class PWinMgr { PScreen ps; /** Associate a handle with each managed window. */ private Vector wtbl = new Vector(); /** Track which windows can skip masking logic because they are not obscured by any other window. */ boolean[] onTop = new boolean[20]; private int cnt; // number of registered windows /** Track which window owns each cell of the screen. */ char[] mask; int cols; /** Track top level windows back to front.*/ private Vector top = new Vector(); /** Background window. */ private PWin bg; public Rectangle getScreenRect() { return new Rectangle(0,0,cols,ps.getRows()); } /** Create a PWin manager. @param ps the physical screen the windows are displayed on */ public PWinMgr(PScreen ps) { this.ps = ps; cols = ps.getCols(); int rows = ps.getRows(); mask = new char[rows * cols]; // the background window is always visible at the back bg = new PWin(this) { public void paint(int x,int y,int w,int h) throws IOException { fill(x,y,w,h,' '); } }; top.addElement(bg); bg.setVisible(true); } /** Register a PWin with this manager. @param w the PWin to register @return the win id */ synchronized int addWin(PWin w) { int id = wtbl.indexOf(this); if (id < 0) { id = wtbl.size(); wtbl.addElement(w); if (id >= onTop.length) { boolean[] nw = new boolean[id+20]; System.arraycopy(onTop,0,nw,0,onTop.length); onTop = nw; } } else wtbl.setElementAt(w,id); ++cnt; //System.err.println("addWin="+id); return id; } public PWin getWin(int id) { try { Object obj = wtbl.elementAt(id); return (obj == this) ? null : (PWin)obj; } catch (ArrayIndexOutOfBoundsException e) { return null; } } /** Unregister a PWin from this manager. @param id the win id of the PWin to unregister. @return the PWin removed */ synchronized PWin delWin(int id) { try { Object obj = wtbl.elementAt(id); if (obj == this) return null; if (id == wtbl.size() - 1) do wtbl.removeElementAt(id--); while (wtbl.elementAt(id) == this); else wtbl.setElementAt(this,id); --cnt; if (top.removeElement(obj)) { PWin w = (PWin)top.elementAt(top.size()-1); w.toFront(); } PWin w = (PWin)obj; return w; } catch (ArrayIndexOutOfBoundsException e) { return null; } } /** Recompute the ownership mask for the area covered by a PWin. */ void reset(Rectangle r) { resetNeeded = true; repaint(r); } private boolean resetNeeded; private Rectangle repaintArea; /** Redraw a section of the screen. */ synchronized void repaint(Rectangle r) { if (repaintArea == null) { repaintArea = r; return; } repaintArea = r.union(repaintArea); } synchronized void sync() throws IOException { Rectangle r = repaintArea; if (r == null) return; if (resetNeeded) { int n = top.size(); for (int i = 0; i < n; ++i) { PWin w1 = (PWin)top.elementAt(i); //if (w1.loc.intersects(w.loc)) w1.set(); } resetNeeded = false; } // find set of windows with pieces visible in rectangle boolean[] wset = new boolean[wtbl.size()]; int erow = r.y + r.height; for (int row = r.y; row < erow; ++row) { int off = row * cols + r.x; int eoff = off + r.width; while (off < eoff) wset[mask[off++]] = true; } // paint them for (int i = 0; i < wset.length; ++i) { if (wset[i]) { PWin w = getWin(i); w.paint(r.x,r.y,r.width,r.height); } } repaintArea = null; } void set(int x,int y,int w,int h,int id) { //System.err.println("set("+x+','+y+','+w+','+h+")="+id); for (int r = y; r < y + h; ++r) { int i = r * cols + x; int len = w; while (len-- > 0) { int o = mask[i]; if (o != id) { onTop[o] = false; mask[i] = (char)id; } ++i; } } onTop[id] = true; } /** A window is onTop if it is not obscured by any other window. This is set to true when PWin.set() is called. It is set to false when a cell owned by a window is overwritten by another window's set(). */ boolean isOnTop(int id) { return onTop[id]; } void toFront(PWin w) { top.removeElement(w); top.addElement(w); if (!w.isOnTop()) { if (!resetNeeded) w.set(); repaint(w.loc); } } void toBack(PWin w) { int i = top.indexOf(w); if (i == 0 || i == 1) return; if (i > 1) top.removeElementAt(i); top.insertElementAt(w,1); reset(w.loc); i = top.size() - 1; w = (PWin)top.elementAt(i); w.toFront(); } }