// $Log: window.cc,v $ // Revision 1.1.1.1 2000/12/16 20:45:41 stuart // Released TUIPeer sources // // Revision 1.3 1995/01/25 22:54:05 stuart // track dirty rectangle // #pragma implementation "Window.h" /* window.c - screen windows Copyright 1990 Business Management Systems, Inc. Author: Stuart D. Gathman Based on "Advanced C Programming for Displays" by Marc J. Rochkind. Our version allows unlimited windows among other things. (Only the number of *visible* windows is limited.) */ extern "C" { #include } #include #include #include "Window.h" #if 0 #include ostream &operator<<(ostream &os, const Rect &r) { os << "Rect(" << r.r1 << ',' << r.c1 << ',' << r.r2 << ',' << r.c2 << ')'; return os; } #endif class WinId { char winid[Window::MAXWIN]; public: enum State { FREE, USED, TOP }; WinId(); ~WinId(); int alloc(); char &operator[](int i) { return winid[i]; } }; static WinId winid; static Rect dirty(0,0,0,0); static Window *basewin; WinId::WinId() { memset(winid,FREE,sizeof winid); } WinId::~WinId() { if (basewin) PSend(); } int WinId::alloc() { for (int i = 0; i < sizeof winid; ++i) if (winid[i] == FREE) { winid[i] = USED; return i; } return sizeof winid; } bool Window::ontop() const { return !ishidden() && winid[wnum] == winid.TOP; } void Window::sync() { if (!dirty.isempty()) { //cerr << "dirty = " << dirty << endl; int i; for (i = 0; i < numwin; ++i) order[i]->set(dirty); bool visible[MAXWIN]; memset(visible,false,sizeof visible); for (i = dirty.r1; i <= dirty.r2; ++i) { for (int j = dirty.c1; j <= dirty.c2; ++j) visible[mask[i][j]] = true; } for (i = 0; i < numwin; ++i) if (visible[order[i]->wnum]) order[i]->_draw(dirty); order[0]->curtype(order[0]->cur); /* recompute cursor */ dirty = Rect(0,0,-1,-1); } //PSsync(); } bool Window::iscur() const { /* is cursor window? */ if (!cur || ishidden()) return false; int i; for (i = numwin; i > 0;) { if (order[--i]->cur) break; } return (this == order[i]); } void Window::set(const Rect &rs) { /* set owner of rectangle */ //cerr << wnum << ".set(" << rs << ")\n"; Rect r = rs.intersect(screenloc); for (int j = r.r1; j <= r.r2; ++j) { unsigned char far *p = mask[j] + r.c1; for (int n = r.width(); n-- > 0; ++p) if (*p != wnum) winid[*p] = winid.USED, *p = wnum; } } void Window::reset(const Rect &r) { /* recompute ownership mask */ Rect r1 = r.intersect(screen); if (r1.isempty()) return; if (dirty.isempty()) dirty = r1; else dirty = dirty.enclose(r1); } void Window::_draw(const Rect &r) { Rect wr = r.intersect(screenloc).moverel(-loc.r1,-loc.c1); if (!wr.isempty()) draw(wr); } short Window::numwin = 0, Window::totwin = 0; Window *Window::order[MAXWIN]; unsigned char far **Window::mask = 0; Rect Window::screen(0,0,0,0); Window::Window() : loc(screen), screenloc(screen) { wnum = MAXWIN; /* initially hidden */ cur = 1; /* cursor initially on */ row = col = 0; /* initial cursor position */ if (!totwin++) { PSbegin(); mask = new unsigned char far * [PSrows]; mask[0] = new unsigned char far [PSrows * PScols]; for (int i = 1; i < PSrows; ++i) mask[i] = mask[i-1] + PScols; dirty = screenloc = loc = screen = Rect(0,0,PSrows-1,PScols-1); wnum = winid.alloc(); basewin = order[wnum] = this; numwin = 1; set(loc); winid[wnum] = WinId::TOP; } } Window::~Window() { if (!--totwin) { if (wnum < MAXWIN) winid[wnum] = WinId::FREE; basewin = 0; delete [] mask[0]; delete [] mask; PSend(); } else hide(); } void Window::setphys(const Rect &r) { // cerr << wnum << ".setphys(" << r << ")\n"; Rect r1 = r.intersect(screen); if (r1.isempty()) hide(); else if (ishidden()) { // add to top of heap if hidden loc = r; screenloc = r1; top(); return; } else reset(screenloc.enclose(r1)); loc = r; screenloc = r1; } void Window::remove() { --numwin; for (int i = 0; i < numwin; ++i) { if (order[i] == this) { while (i < numwin) { order[i] = order[i+1]; ++i; } break; } } } void Window::hide() { if (!ishidden()) { winid[wnum] = WinId::FREE; wnum = MAXWIN; reset(loc); remove(); } } void Window::top() { //cerr << loc << ".top\n"; if (istop()) return; /* already at top */ if (!ishidden()) remove(); else wnum = winid.alloc(); if (numwin < MAXWIN) { Rect r1 = loc.intersect(screen); if (!r1.isempty()) { order[numwin++] = this; if (winid[wnum] != WinId::TOP) { reset(r1); winid[wnum] = WinId::TOP; } //curtype(); /* recompute cursor position */ } } } void Window::bury() { if (!ishidden()) { if (wnum <= 1) return; /* already at bottom */ remove(); } else wnum = winid.alloc(); if (numwin < MAXWIN) { for (int i = numwin++; i > 1; --i) order[i] = order[i-1]; order[1] = this; reset(loc); } } void Window::curpos(int r,int c) { row = r; col = c; if (iscur()) { r += loc.r1; c += loc.c1; if (Rect(Point(r,c),1).intersect(screen).isempty()) PScurtype(0); else { PScurpos(r,c); /* always position in case can't turn cursor off */ /* if (mask[r][c] == wnum) */ PScurtype(cur); /* else */ /* PScurtype(0); */ } } } void Window::curtype(int t) { cur = t; for (int i = numwin; i > 0;) /* find new cursor window */ if (order[--i]->cur) { order[i]->curpos(); return; } } void Window::write(int row,int col,int ncols,const char *s,CHTYPE attr) { if (ishidden()) return; /* window not visible */ int len = strlen(s); if (len < ncols) { fill(Rect(row,col + len,row,col + ncols - 1),' '|attr); ncols = len; } row += loc.r1; col += loc.c1; Rect r1(screenloc.intersect(Rect(row,col,row,col + ncols - 1))); if (r1.isempty()) return; s -= col - r1.c1; row = r1.r1; col = r1.c1; ncols = r1.width(); if (winid[wnum] == winid.TOP) PSwrite(row,col,ncols,s,attr); else { const unsigned char far *p = mask[row] + col; while (ncols > 0) { int i; for (i = 0; i < ncols && p[i] == wnum; ++i) ; if (i) PSwrite(row,col,i,s,attr); for (;i < ncols && p[i] != wnum; ++i) ; ncols -= i; col += i; s += i; p += i; } } } void Window::write(int row,int col,int ncols,const CHTYPE far *cp) { //cerr << wnum << ".writea(" << row << ',' << col << ',' << ncols; //for (int x = 0; x < ncols; ++x) cerr << ',' << cp[x]; cerr << ")\n"; if (ishidden()) return; /* window not visible */ row += loc.r1; col += loc.c1; Rect r1(screenloc.intersect(Rect(row,col,row,col + ncols - 1))); //cerr << r1 << endl; if (r1.isempty()) return; cp -= col - r1.c1; row = r1.r1; col = r1.c1; ncols = r1.width(); if (winid[wnum] == winid.TOP) PSwrtattr(row,col,ncols,cp); else { const unsigned char far *p = mask[row] + col; //cerr << "mask("; //for (int x = 0; x < ncols; ++x) cerr << ',' << (int)p[x]; cerr << ")\n"; while (ncols > 0) { register int i; for (i = 0; i < ncols && p[i] == wnum; ++i) ; if (i) PSwrtattr(row,col,i,cp); while (i < ncols && p[i] != wnum) ++i; ncols -= i; col += i; cp += i; p += i; } } } void Window::fill(const Rect &r,CHTYPE ch) { //cerr << wnum << ".fill(" << r << ")\n"; Rect wr(r.moverel(loc.r1,loc.c1).intersect(screenloc)); if (wr.isempty()) return; if (winid[wnum] == winid.TOP) PSfill((const RECT *)&wr,ch); else { int ncols = wr.width(); char buf[132]; if (ncols > sizeof buf) ncols = sizeof buf; memset(buf,ch & A_CHARTEXT,ncols); ch &= A_ATTRIBUTES; for (int i = wr.r1; i <= wr.r2; ++i) write(i - loc.r1,wr.c1 - loc.c1,ncols,buf,ch); } } void Window::redraw() { /* redraw entire window */ if (dirty.isempty()) draw(Rect(0,0,loc.height()-1,loc.width()-1)); else reset(loc); } extern "C" void Ksync() { if (basewin && !Kready()) { basewin->sync(); PSsync(); } } Background::Background(CHTYPE c) : color(c) { curtype(0); } void Background::draw(const Rect&r) { fill(r,color); }