1 //  This may look like C code, but it is really -*- C++ -*-
2 
3 //  ------------------------------------------------------------------
4 //  The Goldware Library
5 //  Copyright (C) 1990-1999 Odinn Sorensen
6 //  Copyright (C) 1999-2000 Alexander S. Aganichev
7 //  Copyright (C) 2000 Jacobo Tarrio
8 //  ------------------------------------------------------------------
9 //  This library is free software; you can redistribute it and/or
10 //  modify it under the terms of the GNU Library General Public
11 //  License as published by the Free Software Foundation; either
12 //  version 2 of the License, or (at your option) any later version.
13 //
14 //  This library is distributed in the hope that it will be useful,
15 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 //  Library General Public License for more details.
18 //
19 //  You should have received a copy of the GNU Library General Public
20 //  License along with this program; if not, write to the Free
21 //  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22 //  MA 02111-1307, USA
23 //  ------------------------------------------------------------------
24 //  $Id: gwinbase.cpp,v 1.1 2011/02/18 19:46:02 stas_degteff Exp $
25 //  ------------------------------------------------------------------
26 //  GCUI: Golded+ Character-oriented User Interface.
27 //  Windowing kernel.
28 //  Based on CXL by Mike Smedley.
29 //  ------------------------------------------------------------------
30 
31 #include <cstdio>
32 #include <cstdarg>
33 #include <cstdlib>
34 #include <cstring>
35 #include <gmemdbg.h>
36 #include <gutlmisc.h>
37 #include <gwinall.h>
38 #include <gkbdcode.h>
39 
40 
41 //  ------------------------------------------------------------------
42 //  Local optimizations
43 
44 #define GOLD_INLINE inline
45 #define GOLD_WCHK
46 
47 
48 //  ------------------------------------------------------------------
49 
_wchkrow(int wrow)50 static GOLD_INLINE int _wchkrow(int wrow) {
51 
52   return ((wrow<0) or (wrow>((gwin.active->erow-gwin.active->border)-(gwin.active->srow+gwin.active->border))));
53 }
54 
_wchkcol(int wcol)55 static GOLD_INLINE int _wchkcol(int wcol) {
56 
57   return ((wcol<0) or (wcol>((gwin.active->ecol-gwin.active->border)-(gwin.active->scol+gwin.active->border))));
58 }
59 
_wchkcoord(int wrow,int wcol)60 static GOLD_INLINE int _wchkcoord(int wrow, int wcol) {
61 
62   return (_wchkrow(wrow) or _wchkcol(wcol));
63 }
64 
65 
66 //  ------------------------------------------------------------------
67 //  Checks validity of given window row coordinate
68 
wchkrow(int wrow)69 int wchkrow(int wrow) {
70 
71   return _wchkrow(wrow);
72 }
73 
74 
75 //  ------------------------------------------------------------------
76 //  Checks validity of given window column coordinate
77 
wchkcol(int wcol)78 int wchkcol(int wcol) {
79 
80   return _wchkcol(wcol);
81 }
82 
83 
84 //  ------------------------------------------------------------------
85 //  Checks validity of given window coordinates
86 
wchkcoord(int wrow,int wcol)87 int wchkcoord(int wrow, int wcol) {
88 
89   return _wchkcoord(wrow, wcol);
90 }
91 
92 
93 //  ------------------------------------------------------------------
94 //  Checks for valid window box coordinates
95 
wchkbox(int wsrow,int wscol,int werow,int wecol)96 int wchkbox(int wsrow, int wscol, int werow, int wecol) {
97 
98   return (_wchkcoord(wsrow,wscol) or _wchkcoord(werow,wecol) or (wsrow>werow) or (wscol>wecol));
99 }
100 
101 
102 //  ------------------------------------------------------------------
103 //  Sets window cursor coordinates
104 
wgotoxy(int wrow,int wcol)105 int wgotoxy(int wrow, int wcol) {
106 
107   // check for valid cursor coordinates
108   #ifdef GOLD_WCHK
109   if(wchkcoord(wrow,wcol))
110     return gwin.werrno=W_INVCOORD;
111   #endif
112 
113   // calculate effective cursor coordinates and update window record
114   const int &row = gwin.active->row    = gwin.active->srow + wrow + gwin.active->border;
115   const int &col = gwin.active->column = gwin.active->scol + wcol + gwin.active->border;
116 
117   // set cursor location
118   vposset(row,col);
119 
120   // return with no error
121   return gwin.werrno=W_NOERROR;
122 }
123 
124 
125 //  ------------------------------------------------------------------
126 //  Opens a window and makes it active
127 
wopen(int srow,int scol,int erow,int ecol,int btype,vattr battr,vattr wattr,vattr sbattr,vattr loattr)128 int wopen(int srow, int scol, int erow, int ecol, int btype, vattr battr, vattr wattr, vattr sbattr, vattr loattr) {
129 
130   // check for valid box type
131   if(btype<0 or btype>7) {
132     gwin.werrno=W_INVBTYPE;
133     return 0;
134   }
135 
136   if (ecol >= gvid->numcols)
137     ecol = gvid->numcols - 1;
138 
139   // see if window is to have a border
140   int border = (btype==5) ? NO : YES;
141 
142   // check for valid coordinates
143   if(srow>(erow-border) or scol>(ecol-border)) {
144     gwin.werrno=W_INVCOORD;
145     return 0;
146   }
147 
148   // allocate memory for new record
149   _wrec_t* wrec = (_wrec_t*)throw_xmalloc(sizeof(_wrec_t));
150   if(wrec==NULL) {
151     gwin.werrno=W_ALLOCERR;
152     return 0;
153   }
154 
155   // save affected area of screen
156   vsavebuf* wbuf = vsave(srow,scol,erow,ecol);
157   if(wbuf==NULL) {
158     throw_xrelease(wrec);
159     gwin.werrno=W_ALLOCERR;
160     return 0;
161   }
162 
163   // add new record to linked list
164   if(gwin.active!=NULL)
165     gwin.active->next=wrec;
166   wrec->prev=gwin.active;
167   wrec->next=NULL;
168   gwin.active=wrec;
169 
170   // draw and fill text box on screen
171   switch(gwin.style) {
172     case STYLE_NORMAL:
173       if(border)
174         vbox(srow,scol,erow,ecol,btype,battr,loattr);
175       vfill(srow+border,scol+border,erow-border,ecol-border,gwin.fillch,wattr);
176       break;
177   }
178 
179   // increment window handle counter
180   gwin.handle++;
181 
182   // save window info in window record
183   gwin.active->wbuf     = wbuf;
184   gwin.active->whandle  = gwin.handle;
185   gwin.active->srow     = srow;
186   gwin.active->scol     = scol;
187   gwin.active->erow     = erow;
188   gwin.active->ecol     = ecol;
189   gwin.active->btype    = btype;
190   gwin.active->wattr    = wattr;
191   gwin.active->battr    = battr;
192   gwin.active->loattr   = loattr;
193   gwin.active->sbattr   = sbattr;
194   gwin.active->border   = border;
195   gwin.active->row      = srow+border;
196   gwin.active->column   = scol+border;
197   gwin.active->attr     = wattr;
198   gwin.active->title    = NULL;
199   gwin.active->tpos     = 0;
200   gwin.active->help     = 0;
201   gwin.active->form     = NULL;
202   gwin.active->wsbuf    = NULL;
203 
204   // increment total number of open windows
205   gwin.total++;
206 
207   // initialize cursor location to window row 0 column 0
208   wgotoxy(0,0);
209 
210   // return normally
211   gwin.werrno=W_NOERROR;
212   return gwin.handle;
213 }
214 
215 
216 //  ------------------------------------------------------------------
217 //  Closes a window
218 
wclose()219 int wclose() {
220 
221   // check for active window
222   if(!gwin.total or !gwin.active)
223     return(gwin.werrno=W_NOACTIVE);
224 
225   // if window has a shadow, close shadow first
226   if(gwin.active->wsbuf!=NULL)
227     wshadoff();
228 
229   // restore contents of and free memory held by window
230   vrestore(gwin.active->wbuf);
231   throw_xrelease(gwin.active->wbuf);
232 
233   // decrement total number of open windows
234   gwin.total--;
235 
236   // free memory held by window's record and update linked list
237   _wrec_t *wrec = gwin.active->prev;
238   throw_xrelease(gwin.active);
239   gwin.active=wrec;
240   if(gwin.active!=NULL)
241     gwin.active->next=NULL;
242 
243   // update cursor location and help category
244   if(gwin.active!=NULL) {
245     vposset(gwin.active->row,gwin.active->column);
246     if(gwin.active->help)
247       gwin.help=gwin.active->help;
248   }
249 
250   // return normally
251   return gwin.werrno=W_NOERROR;
252 }
253 
254 
255 //  ------------------------------------------------------------------
256 //  Closes all open windows
257 
wcloseall()258 int wcloseall() {
259 
260   if(!gwin.total)
261     return gwin.werrno=W_NOACTIVE;
262 
263   while(gwin.total)
264     if(wclose())
265       return gwin.werrno;
266 
267   // close hidden windows too
268   _wrec_t* prev;
269   while(gwin.hidden!=NULL) {
270     prev = gwin.hidden->prev;
271     throw_xfree(gwin.hidden->wbuf);
272     throw_xfree(gwin.hidden);
273     gwin.hidden = prev;
274   }
275 
276   return gwin.werrno=W_NOERROR;
277 }
278 
279 
280 //  ------------------------------------------------------------------
281 //  Gives active window a shadow
282 
wshadow(vattr attr)283 int wshadow(vattr attr) {
284 
285   // check for active window
286   if(!gwin.total)
287     return gwin.werrno=W_NOACTIVE;
288 
289   // see if window already has a shadow
290   if(gwin.active->wsbuf!=NULL)
291     return gwin.werrno=W_NOERROR;
292 
293   // get window coordinates from the window's record
294   const int &srow = gwin.active->srow;
295   const int &scol = gwin.active->scol;
296   const int &erow = gwin.active->erow;
297   const int &ecol = gwin.active->ecol;
298 
299   // allocate buffer to hold shadow's contents
300   vatch* wsbuf = (vatch*)throw_xmalloc((((erow-srow)*sizeof(vatch))+ecol-scol+1)*sizeof(vatch));
301 
302   if(wsbuf == NULL)
303     return gwin.werrno=W_ALLOCERR;
304 
305   // start at upper right corner of shadow and work down
306   int crow = srow+1;
307   int ccol = ecol+1;
308   vatch* q = wsbuf;
309 
310   // draw shadow to right of window
311   while(crow<=erow) {
312 
313     // read current screen characters/attributes and save in shadow's buffer
314     vatch tmp[2];
315     *q = vgetw(crow, ccol);
316 #if defined(__USE_NCURSES__) || !defined(__UNIX__)
317     tmp[0] = vsattr(*q, attr);
318 #else
319     tmp[0] = vsattr(' ', attr);
320 #endif
321     q++;
322     *q = vgetw(crow, ccol + 1);
323 #if defined(__USE_NCURSES__) || !defined(__UNIX__)
324     tmp[1] = vsattr(*q, attr);
325 #else
326     tmp[1] = vsattr(' ', attr);
327 #endif
328     q++;
329 
330     // write characters back to screen using shadow's attribute
331     vputws(crow++, ccol, tmp, 2);
332   }
333 
334   // start at lower left corner of shadow and work right
335   crow = erow+1;
336   ccol = scol+2;
337   int stop = ecol+2;
338   int len = stop - ccol + 1;
339   vatch* wptr = (vatch*)gvid->bufwrd;
340 
341   // draw bottom shadow
342   while(ccol<=stop) {
343 
344     // read attribs/chars and store in buffers
345     *q = vgetw(crow, ccol++);
346 #if defined(__USE_NCURSES__) || !defined(__UNIX__)
347     *wptr++ = vsattr(*q, attr);
348 #else
349     *wptr++ = vsattr(' ', attr);
350 #endif
351     q++;
352   }
353 
354   // display complete buffer
355   vputws(crow, scol+2, gvid->bufwrd, len);
356 
357   // save info in window's record
358   gwin.active->wsbuf  = wsbuf;
359   gwin.active->wsattr = attr;
360 
361   // reset cursor
362   vposset(gwin.active->row,gwin.active->column);
363 
364   // return with no error
365   return gwin.werrno=W_NOERROR;
366 }
367 
368 
369 //  ------------------------------------------------------------------
370 //  Removes shadow from active window
371 
wshadoff()372 int wshadoff() {
373 
374   // check for active window
375   if(!gwin.total)
376     return gwin.werrno=W_NOACTIVE;
377 
378   // if window doesn't have a shadow, ignore request
379   if(gwin.active->wsbuf==NULL)
380     return gwin.werrno=W_NOERROR;
381 
382   // get window coordinates from the window's record
383   const int &srow = gwin.active->srow;
384   const int &scol = gwin.active->scol;
385   const int &erow = gwin.active->erow;
386   const int &ecol = gwin.active->ecol;
387 
388   // start at upper right corner of shadow and work down
389   int crow = srow+1;
390   int ccol = ecol+1;
391   vatch* q = gwin.active->wsbuf;
392 
393   // delete shadow to right of window
394   while(crow<=erow) {
395     vputw(crow,   ccol,   *q++);
396     vputw(crow++, ccol+1, *q++);
397   }
398 
399   // start at lower left corner of shadow and work right
400   crow = erow+1;
401   ccol = scol+2;
402   int stop = ecol+2;
403 
404   // delete bottom shadow
405   while(ccol<=stop)
406     vputw(crow,ccol++,*q++);
407 
408   // free memory held by shadow
409   throw_xrelease(gwin.active->wsbuf);
410 
411   // update window's record
412   gwin.active->wsattr = WHITE_|_WHITE;
413 
414   // return with no error
415   return gwin.werrno=W_NOERROR;
416 }
417 
418 
419 //  ------------------------------------------------------------------
420 //  Scrolls the active window up or down
421 
wscroll(int count,int direction)422 int wscroll(int count, int direction) {
423 
424   // check for window border
425   const int &border = gwin.active->border;
426 
427   vscroll(
428     gwin.active->srow + border,
429     gwin.active->scol + border,
430     gwin.active->erow - border,
431     gwin.active->ecol - ((border or (gwin.active->sbattr != DEFATTR)) ? 1 : 0),
432     gwin.active->wattr,
433     direction == SUP ? count : -count
434   );
435 
436   // return with no error
437   return gwin.werrno = W_NOERROR;
438 }
439 
440 
441 //  ------------------------------------------------------------------
442 //  Scrolls a region of the active window up or down
443 
wscrollbox(int wsrow,int wscol,int werow,int wecol,int count,int direction)444 int wscrollbox(int wsrow, int wscol, int werow, int wecol, int count, int direction) {
445 
446   // check for window border
447   const int &border = gwin.active->border;
448 
449   vscroll(
450     gwin.active->srow+wsrow+border,
451     gwin.active->scol+wscol+border,
452     gwin.active->srow+werow+border,
453     gwin.active->scol+wecol+border,
454     gwin.active->wattr,
455     direction == SUP ? count : -count
456   );
457 
458   // return with no error
459   return gwin.werrno=W_NOERROR;
460 }
461 
462 
463 //  ------------------------------------------------------------------
464 //  Displays a character inside active window
465 
wputc(char ch)466 int wputc(char ch) {
467 
468   int cwcol;
469 
470   // check for active window
471   if(!gwin.total)
472     return gwin.werrno=W_NOACTIVE;
473 
474   // get coordinates from window's record
475   int crow = gwin.active->row;
476   int ccol = gwin.active->column;
477   const int &scol = gwin.active->scol;
478   const int &border = gwin.active->border;
479 
480   // test the input character for control characters
481   switch(ch) {
482     case '\n':
483       crow++;
484     case '\r':
485       ccol=scol+border;
486       break;
487     case '\b':
488       if(ccol==(scol+border)) {
489         ccol=gwin.active->ecol-border;
490         crow--;
491         if(crow<(gwin.active->srow+border))
492           crow++;
493       }
494       else {
495         ccol--;
496       }
497       break;
498     case '\t':
499       cwcol=ccol-border-scol;
500       ccol+=(tabstop(cwcol,gwin.tabwidth)-cwcol);
501       break;
502     default:
503       vputc(crow, ccol++, gwin.active->attr, ch);
504   }
505 
506   // see if wrap-around is needed
507   if(ccol > (gwin.active->ecol-border)) {
508     ccol = scol+border;
509     crow++;
510   }
511 
512   // see if scroll is needed
513   if(crow > (gwin.active->erow-border)) {
514     wscroll(1,SUP);
515     crow--;
516   }
517 
518   // update window's record
519   gwin.active->row=crow;
520   gwin.active->column=ccol;
521 
522   // reset cursor position
523   vposset(crow,ccol);
524 
525   // return normally
526   return gwin.werrno=W_NOERROR;
527 }
528 
529 
530 //  ------------------------------------------------------------------
531 //  Reads current cursor location inside window
532 
wreadcur(int * wrow,int * wcol)533 int wreadcur(int* wrow, int* wcol) {
534 
535   // check for active window
536   if(!gwin.total)
537     return gwin.werrno=W_NOACTIVE;
538 
539   // read effective cursor coordinates
540   int row,col;
541   vposget(&row,&col);
542 
543   // calculate window cursor coordinates
544   const int &border = gwin.active->border;
545   *wrow = row - gwin.active->srow - border;
546   *wcol = col - gwin.active->scol - border;
547 
548   // return normally
549   return gwin.werrno=W_NOERROR;
550 }
551 
552 
553 //  ------------------------------------------------------------------
554 //  Display a character specified number of times
555 
wdupc(char ch,int count)556 int wdupc(char ch, int count) {
557 
558   // check for active window
559   if(!gwin.total)
560     return(gwin.werrno=W_NOACTIVE);
561 
562   // display ch for count times
563   while(count--)
564     wputc(ch);
565 
566   // return with gwin.werrno set by wputc()
567   return(gwin.werrno);
568 }
569 
570 
571 //  ------------------------------------------------------------------
572 //  Clears the active window in specified attribute
573 
wcclear(vattr attr)574 int wcclear(vattr attr) {
575 
576   // check for active window
577 
578   if(!gwin.total)
579     return gwin.werrno=W_NOACTIVE;
580 
581   // check for window border
582 
583   const int &border = gwin.active->border;
584 
585   vfill(
586     gwin.active->srow+border,
587     gwin.active->scol+border,
588     gwin.active->erow-border,
589     gwin.active->ecol-border,
590     gwin.fillch,
591     attr
592   );
593 
594   // home the cursor
595 
596   wgotoxy(0,0);
597 
598   return gwin.werrno=W_NOERROR;
599 }
600 
601 
602 //  ------------------------------------------------------------------
603 //  Clears from cursor postion to end of window's line
604 
wclreol()605 int wclreol() {
606 
607   // check for active window
608   if(!gwin.total)
609     return gwin.werrno=W_NOACTIVE;
610 
611   // clear to end of window's line
612   const int &column = gwin.active->column;
613   vputx(
614     gwin.active->row,
615     column,
616     gwin.active->attr,
617     gwin.fillch,
618     gwin.active->ecol - gwin.active->border - column + 1
619   );
620 
621   // return normally
622   return gwin.werrno=W_NOERROR;
623 }
624 
625 
626 //  ------------------------------------------------------------------
627 //  Clears from cursor postion to end of window
628 
wclreos()629 int wclreos() {
630 
631   int wrow, werow, wr, wc;
632 
633   // check for active window
634   if(!gwin.total)
635     return gwin.werrno=W_NOACTIVE;
636 
637   // save current window row and column
638   wreadcur(&wr, &wc);
639 
640   wrow = wr;
641   werow = gwin.active->erow - gwin.active->srow - gwin.active->border;
642   wclreol();
643   wrow++;
644 
645   while(wrow <= werow) {
646     wgotoxy(wrow,0);
647     wclreol();
648     wrow++;
649   }
650 
651   // restore window row and column
652   wgotoxy(wr,wc);
653 
654   // return normally
655   return gwin.werrno=W_NOERROR;
656 }
657 
658 
659 //  ------------------------------------------------------------------
660 //  This function will process an Escape sequence when encountered
661 
process_esc(const char * str)662 static const char* process_esc(const char* str)
663 {
664   int wrow,wcol;
665 
666   const char *p = str;
667   for(; *p==ESC; p++) {
668 
669     vattr attr = gwin.active->attr;
670 
671     switch(*(++p)) {
672 
673       case '+':   // increase text attribute
674         wtextattr(++attr);
675         break;
676 
677       case '-':   // decrease text attribute
678         wtextattr(--attr);
679         break;
680 
681       case 'A':   // change attribute
682         wtextattr(*++p);
683         break;
684 
685       case 'F':   // change foreground attribute
686         wtextattr((int)((*++p & 0x07) | (attr & ~0x07)));
687         break;
688 
689       case 'B':   // change background attribute
690         wtextattr((int)((*++p & 0x70) | (attr & ~0x70)));
691         break;
692 
693       case 'I':   // toggle intensity bit
694         wtextattr((int)(attr ^ INTENSE));
695         break;
696 
697       case 'L':   // toggle blinking bit
698         wtextattr((int)(attr ^ BLINK));
699         break;
700 
701       case 'X':   // reverse attribute
702         wtextattr(revsattr(attr));
703         break;
704 
705       case 'R':   // set cursor row
706         wreadcur(&wrow,&wcol);
707         wgotoxy(*++p,wcol);
708         break;
709 
710       case 'C':   // set cursor column
711         wreadcur(&wrow,&wcol);
712         wgotoxy(wrow,*++p);
713         break;
714 
715       case 'E':   // erase
716         switch(*++p) {
717           case 'W':   // erase window
718             wclear();
719             break;
720           case 'S':   // erase to end of window
721             wclreos();
722             break;
723           case 'L':   // erase to end of window's line
724             wclreol();
725             break;
726         }
727         break;
728 
729       case 'D':   // duplicate character
730         {
731           char ch = *++p;
732           wdupc(ch,*++p);
733         }
734         break;
735 
736       default:
737         p--;
738     }
739   }
740 
741   return --p;
742 }
743 
744 
745 //  ------------------------------------------------------------------
746 //  Displays a string inside active window
747 
wputs(const char * str)748 int wputs(const char* str) {
749 
750   int cwcol;
751   const char* q;
752 
753   // get effective coordinates from window's record
754   int &crow = gwin.active->row;
755   int &ccol = gwin.active->column;
756   const int &scol = gwin.active->scol;
757   const int &border = gwin.active->border;
758 
759   // do while not end of string
760   for(q=str; *q; q++) {
761 
762     // test the input character for control characters
763     switch(*q) {
764       case '\n':
765         crow++;
766       case '\r':
767         ccol=scol+border;
768         break;
769       case '\b':
770         if(ccol==(scol+border)) {
771           ccol=gwin.active->ecol-border;
772           crow--;
773           if(crow<(gwin.active->srow+border))
774             crow++;
775         }
776         else {
777           ccol--;
778         }
779         break;
780       case '\t':
781         cwcol=ccol-border-scol;
782         ccol+=(tabstop(cwcol,gwin.tabwidth)-cwcol);
783         break;
784       case ESC:
785         q=process_esc(q);
786         break;
787       default:
788         vputc(crow, ccol++, gwin.active->attr, *q);
789     }
790 
791     // see if wrap-around is needed
792     if(ccol > (gwin.active->ecol-border)) {
793       ccol=scol+border;
794       crow++;
795     }
796 
797     // see if scroll is needed
798     if(crow > (gwin.active->erow-border)) {
799       wscroll(1,SUP);
800       crow--;
801     }
802   }
803 
804   // reset cursor position
805   vposset(crow,ccol);
806 
807   // return normally
808   return(gwin.werrno=W_NOERROR);
809 }
810 
811 
812 //  ------------------------------------------------------------------
813 //  Displays a character inside active window
814 
wprintc(int wrow,int wcol,vattr atr,vchar chr)815 int wprintc(int wrow, int wcol, vattr atr, vchar chr) {
816 
817   // check for active window
818   if(!gwin.total)
819     return gwin.werrno=W_NOACTIVE;
820 
821   // check for valid coordinates
822   #ifdef GOLD_WCHK
823   if(wchkcoord(wrow,wcol))
824     return gwin.werrno=W_INVCOORD;
825   #endif
826 
827   vputc(wrow+gwin.active->srow+gwin.active->border, wcol+gwin.active->scol+gwin.active->border, atr, chr);
828 
829   // return normally
830   return gwin.werrno=W_NOERROR;
831 }
832 
833 
834 //  ------------------------------------------------------------------
835 //  Outputs a formatted string to active window
836 
wprintf(const char * format,...)837 int wprintf(const char* format, ...) {
838 
839   va_list argptr;
840   char buf[255];
841 
842   // format string using specified parameters into buffer
843   va_start(argptr,format);            // access argument list
844   int result = vsprintf(buf,format,argptr);        // create string using argument list
845   va_end(argptr);                     // end access of argument list
846 
847   // display the created string
848   wputs(buf);
849 
850   return result;
851 }
852 
853 
854 //  ------------------------------------------------------------------
855 //  Print a formatted string at a specific position and attribute
856 
wprintfs(int wrow,int wcol,vattr attr,const char * format,...)857 int wprintfs(int wrow, int wcol, vattr attr, const char* format, ...) {
858 
859   va_list argptr;
860   char buf[256];
861 
862   *buf = NUL;
863   va_start(argptr, format);
864   int result = vsprintf(buf, format, argptr);
865   va_end(argptr);
866 
867   wprints(wrow, wcol, attr, buf);
868 
869   return result;
870 }
871 
872 
873 //  ------------------------------------------------------------------
874 //  Displays a string inside active window
875 
wprints(int wrow,int wcol,vattr attr,const char * str)876 int wprints(int wrow, int wcol, vattr attr, const char* str) {
877 
878   // check for active window
879   if(!gwin.total)
880     return gwin.werrno=W_NOACTIVE;
881 
882   // check for valid coordinates
883   #ifdef GOLD_WCHK
884   if(wchkcoord(wrow,wcol))
885     return gwin.werrno=W_INVCOORD;
886   #endif
887 
888   const int &border = gwin.active->border;
889   vputs(gwin.active->srow+wrow+border,gwin.active->scol+wcol+border,attr,str);
890   return gwin.werrno=W_NOERROR;
891 }
892 
wprints_box(int wrow,int wcol,vattr attr,const char * str)893 int wprints_box(int wrow, int wcol, vattr attr, const char* str) {
894 
895   // check for active window
896   if(!gwin.total)
897     return gwin.werrno=W_NOACTIVE;
898 
899   // check for valid coordinates
900   #ifdef GOLD_WCHK
901   if(wchkcoord(wrow,wcol))
902     return gwin.werrno=W_INVCOORD;
903   #endif
904 
905   const int &border = gwin.active->border;
906   vputs_box(gwin.active->srow+wrow+border,gwin.active->scol+wcol+border,attr,str);
907   return gwin.werrno=W_NOERROR;
908 }
909 
910 
911 //  ------------------------------------------------------------------
912 //  Displays a string inside active window
913 
wprintvs(int wrow,int wcol,vattr attr,const vchar * str)914 int wprintvs(int wrow, int wcol, vattr attr, const vchar* str) {
915 
916   // check for active window
917   if(!gwin.total)
918     return gwin.werrno=W_NOACTIVE;
919 
920   // check for valid coordinates
921   #ifdef GOLD_WCHK
922   if(wchkcoord(wrow,wcol))
923     return gwin.werrno=W_INVCOORD;
924   #endif
925 
926   const int &border = gwin.active->border;
927   vputvs(gwin.active->srow+wrow+border,gwin.active->scol+wcol+border,attr,str);
928   return gwin.werrno=W_NOERROR;
929 }
930 
931 
932 //  ------------------------------------------------------------------
933 
wputx(int wrow,int wcol,vattr attr,vchar chr,uint len)934 int wputx(int wrow, int wcol, vattr attr, vchar chr, uint len) {
935 
936   const int &border = gwin.active->border;
937   vputx(gwin.active->srow+wrow+border,gwin.active->scol+wcol+border,attr,chr,len);
938   return gwin.werrno=W_NOERROR;
939 }
940 
941 
942 //  ------------------------------------------------------------------
943 
wputy(int wrow,int wcol,vattr attr,vchar chr,uint len)944 int wputy(int wrow, int wcol, vattr attr, vchar chr, uint len) {
945 
946   const int &border = gwin.active->border;
947   vputy(gwin.active->srow+wrow+border,gwin.active->scol+wcol+border,attr,chr,len);
948   return gwin.werrno=W_NOERROR;
949 }
950 
951 
952 //  ------------------------------------------------------------------
953 //  Displays a string inside active window
954 
wprintns(int wrow,int wcol,vattr attr,const std::string & str,uint len,vchar fill,vattr fill_attr)955 int wprintns(int wrow, int wcol, vattr attr,  const std::string &str, uint len, vchar fill, vattr fill_attr)
956 {
957   char* istr = throw_xstrdup(str.c_str());
958   char* ostr = istr;
959   char och = *ostr;
960   uint olen = strlen(istr);
961   if(len < olen) {
962     ostr += len;
963     och = *ostr;
964     *ostr = NUL;
965   }
966   int retval = wprints(wrow, wcol, attr, istr);
967   if(len < olen)
968     *ostr = och;
969   else if(len > olen)
970     retval = wputx(wrow, wcol+olen, (fill_attr != DEFATTR) ? fill_attr : attr, fill, len-olen);
971   throw_xfree(istr);
972   return retval;
973 }
974 
975 
976 //  ------------------------------------------------------------------
977 //  Displays attrib/char buffer inside active window
978 
wprintws(int wrow,int wcol,vatch * buf,uint len)979 int wprintws(int wrow, int wcol, vatch* buf, uint len) {
980 
981   // check for active window
982   if(!gwin.total)
983     return gwin.werrno=W_NOACTIVE;
984 
985   // check for valid coordinates
986   #ifdef GOLD_WCHK
987   if(wchkcoord(wrow,wcol))
988     return gwin.werrno=W_INVCOORD;
989   #endif
990 
991   // see if window has border
992   const int &border = gwin.active->border;
993 
994   // calculate effective coordinates
995   int row = gwin.active->srow+wrow+border;
996   int col = gwin.active->scol+wcol+border;
997 
998   // display buffer
999   vputws(row, col, buf, len);
1000 
1001   return gwin.werrno=W_NOERROR;
1002 }
1003 
1004 
1005 //  ------------------------------------------------------------------
1006 //  Returns address of record of given window handle
1007 
wfindrec(int whandle)1008 _wrec_t* wfindrec(int whandle) {
1009 
1010   _wrec_t *wrec;
1011 
1012   // scan through linked list for record belonging to requested handle
1013 
1014   wrec = gwin.active;
1015   while(wrec) {
1016     if(whandle==wrec->whandle)
1017       break;
1018     wrec=wrec->prev;
1019   }
1020 
1021   if(wrec == NULL) {
1022 
1023     // Search through the hidden windows
1024 
1025     wrec = gwin.hidden;
1026     while(wrec) {
1027       if(whandle==wrec->whandle)
1028         break;
1029       wrec=wrec->prev;
1030     }
1031   }
1032 
1033   // return address of found record
1034   return wrec;
1035 }
1036 
1037 
1038 //  ------------------------------------------------------------------
1039 //  Hides active window
1040 
whide()1041 int whide() {
1042 
1043   vsavebuf  *p;
1044   vattr     shattr;
1045   _wrec_t   *temp;
1046 
1047   // check for active window
1048   if(!gwin.total)
1049     return(gwin.werrno=W_NOACTIVE);
1050 
1051   // save active window
1052   p = vsave(gwin.active->srow,gwin.active->scol,gwin.active->erow,gwin.active->ecol);
1053 
1054   // check for/close window's shadow
1055   if(gwin.active->wsbuf!=NULL) {
1056     shattr = gwin.active->wsattr;
1057     wshadoff();
1058     gwin.active->wsattr = shattr;
1059   }
1060   else {
1061     gwin.active->wsattr = DEFATTR;
1062   }
1063 
1064   // restore contents of active window's buffer
1065   vrestore(gwin.active->wbuf);
1066   throw_xfree(gwin.active->wbuf);
1067   gwin.active->wbuf = p;
1068 
1069   // update visible window record linked list
1070   temp = gwin.active;
1071   gwin.active = gwin.active->prev;
1072   if(gwin.active)
1073     gwin.active->next = NULL;
1074   gwin.total--;
1075 
1076   // update hidden window record linked list
1077   if(gwin.hidden)
1078     gwin.hidden->next = temp;
1079   temp->prev = gwin.hidden;
1080   temp->next = NULL;
1081   gwin.hidden = temp;
1082 
1083   // update cursor location and help category
1084   if(gwin.active) {
1085     vposset(gwin.active->row,gwin.active->column);
1086     if(gwin.active->help)
1087       gwin.help = gwin.active->help;
1088   }
1089 
1090   // return normally
1091   return(gwin.werrno=W_NOERROR);
1092 }
1093 
1094 
1095 //  ------------------------------------------------------------------
1096 //  Unhides a previously hidden window
1097 
wunhide(int whandle)1098 int wunhide(int whandle) {
1099 
1100   vsavebuf* p;
1101   _wrec_t* found;
1102 
1103   // check pointer to hidden window linked list ; must not be NULL
1104   if(gwin.hidden==NULL)
1105     return gwin.werrno=W_NOHIDDEN;
1106 
1107   // check to see if input window handle == 0.  if so, then
1108   // that means to unhide the most recently hidden window.
1109   if(!whandle)
1110     whandle=gwin.hidden->whandle;
1111 
1112   // scan through linked list for record belonging to requested handle
1113   found=gwin.hidden;
1114   while(found!=NULL) {
1115     if(whandle==found->whandle)
1116       break;
1117     found=found->prev;
1118   }
1119 
1120   // was handle found in hidden window record linked list?
1121   if(found==NULL) {
1122 
1123     // see if handle is in visible window record linked list
1124     if(wfindrec(whandle)==NULL)
1125       return gwin.werrno=W_NOTFOUND;
1126     else
1127       return gwin.werrno=W_NOTHIDD;
1128   }
1129 
1130   // save area of screen where window is to unhide at
1131   if((p=vsave(found->srow,found->scol,found->erow,found->ecol))==NULL)
1132     return gwin.werrno=W_ALLOCERR;
1133 
1134   // restore contents of hidden window back to screen
1135   vrestore(found->wbuf);
1136   throw_xfree(found->wbuf);
1137   found->wbuf=p;
1138 
1139   // update hidden window record linked list
1140   if(found->prev!=NULL)
1141     found->prev->next=found->next;
1142   if(found->next==NULL)
1143     gwin.hidden=found->prev;
1144   else
1145     found->next->prev=found->prev;
1146 
1147   // update visible window record linked list
1148   if(gwin.active!=NULL)
1149     gwin.active->next=found;
1150   found->prev=gwin.active;
1151   found->next=NULL;
1152   gwin.active=found;
1153   gwin.total++;
1154 
1155   // if window had a shadow before hiding, give it one again
1156   if(gwin.active->wsattr != DEFATTR)
1157     wshadow(gwin.active->wsattr);
1158 
1159   // update help category
1160   if(gwin.active->help)
1161     gwin.help=gwin.active->help;
1162 
1163   // reset cursor
1164   vposset(gwin.active->row,gwin.active->column);
1165 
1166   // return normally
1167   return gwin.werrno=W_NOERROR;
1168 }
1169 
1170 
1171 //  ------------------------------------------------------------------
1172 //  Unlinks and frees a window from memory, but does not manipulate
1173 //  the screen at all
1174 
wunlink(int w)1175 int wunlink(int w) {
1176 
1177   _wrec_t *found, *prev, *next;
1178 
1179   // check to see if input window handle == 0.  if
1180   // so, then that means to unlink the active window.
1181   if(!w)
1182     w=gwin.active->whandle;
1183 
1184   // find address of window record for given window handle
1185   if((found=wfindrec(w))==NULL)
1186     return gwin.werrno=W_NOTFOUND;
1187 
1188   // free memory held by shadow's buffer (if shadow exists)
1189   if(found->wsbuf!=NULL)
1190     throw_xrelease(found->wsbuf);
1191 
1192   // free memory held by window's buffer
1193   throw_xrelease(found->wbuf);
1194 
1195   // decrement total number of open windows
1196   gwin.total--;
1197 
1198   // re-link list pointers around window record to remove
1199   prev=found->prev;
1200   next=found->next;
1201   if(prev!=NULL)
1202     prev->next=next;
1203   if(next!=NULL)
1204     next->prev=prev;
1205 
1206   // free memory held by window record
1207   throw_xfree(found);
1208 
1209   // see if active window has changed
1210   if(next==NULL) {
1211     if(prev!=NULL) {
1212       gwin.active=prev;
1213       if(gwin.active->help)
1214         gwin.help=gwin.active->help;
1215     }
1216   }
1217 
1218   // return normally
1219   return gwin.werrno=W_NOERROR;
1220 }
1221 
1222 
1223 //  ------------------------------------------------------------------
1224 //  Local variables
1225 
1226 static _wrec_t *__curr, *__found;
1227 static int    __crow, __ccol;
1228 static vattr  __gattr;
1229 static const char* __p;
1230 
1231 
1232 //  ------------------------------------------------------------------
1233 //  This function dectects if given window is blocking the current
1234 //  window or its shadow at specified coordinates
1235 
window_blocking()1236 static GOLD_INLINE int window_blocking() {
1237 
1238   return (__crow>=__curr->srow and __crow<=__curr->erow and __ccol>=__curr->scol and __ccol<=__curr->ecol) ? YES : NO;
1239 }
1240 
1241 
1242 //  ------------------------------------------------------------------
1243 //  This function detects if a given window's bottom shadow is
1244 //  blocking the current window or its shadow at specified coordinates
1245 
bshadow_blocking()1246 static GOLD_INLINE int bshadow_blocking() {
1247 
1248   if(__crow==(__curr->erow+1))
1249     if((__ccol>=(__curr->scol+2)) and (__ccol<=(__curr->ecol+2)))
1250       return YES;
1251     else
1252       return NO;
1253 
1254   return NO;
1255 }
1256 
1257 
1258 //  ------------------------------------------------------------------
1259 //  This function detects if a given window's right shadow is blocking
1260 //  the current window or its shadow at specified coordinates
1261 
rshadow_blocking()1262 static GOLD_INLINE int rshadow_blocking() {
1263 
1264   if(__ccol==(__curr->ecol+1) or __ccol==(__curr->ecol+2))
1265     if((__crow>=(__curr->srow+1)) and (__crow<=__curr->erow))
1266       return YES;
1267     else
1268       return NO;
1269 
1270   return NO;
1271 }
1272 
1273 
1274 //  ------------------------------------------------------------------
1275 
calc_window(_wrec_t * wrec)1276 static GOLD_INLINE vatch* calc_window(_wrec_t *wrec) {
1277 
1278   return wrec->wbuf->data+((__crow-wrec->srow)*(wrec->ecol-wrec->scol+1))+(__ccol-wrec->scol);
1279 }
1280 
1281 
1282 //  ------------------------------------------------------------------
1283 
calc_bshadow(_wrec_t * wrec)1284 static GOLD_INLINE vatch* calc_bshadow(_wrec_t *wrec) {
1285 
1286   return wrec->wsbuf+((((__crow-wrec->srow-1)*2)+(__ccol-wrec->scol-2)));
1287 }
1288 
1289 
1290 //  ------------------------------------------------------------------
1291 
calc_rshadow(_wrec_t * wrec)1292 static GOLD_INLINE vatch* calc_rshadow(_wrec_t *wrec) {
1293 
1294   return wrec->wsbuf+((((__crow-wrec->srow-1)*2)+(__ccol-wrec->ecol-1)));
1295 }
1296 
1297 
1298 //  ------------------------------------------------------------------
1299 //  This function will exchange the contents of the applicable buffers
1300 
swap_contents(vatch * pfound,vatch * pcurr,int shadow)1301 static void swap_contents(vatch* pfound, vatch* pcurr, int shadow) {
1302 
1303   register _wrec_t *wptr;
1304   register vatch temp, chat;
1305 
1306   // display character from current position in window to
1307   // activate on the screen.  if character is part of a
1308   // shadow, reflect the character on the screen.
1309 
1310   temp = vgetw(__crow, __ccol);
1311 
1312   if(shadow&2)
1313     *pcurr = vschar(*pcurr, vgchar(temp));
1314   chat = ((vgattr(temp) & BLINK) and shadow) ? vsattr(*pcurr, vgattr(*pcurr) | BLINK) : *pcurr;
1315   vputw(__crow, __ccol, chat);
1316 
1317   // let window position directly above position
1318   // to activate have the character that it holds
1319 
1320   *pcurr = *pfound;
1321 
1322   // if current character position to activate will
1323   // activate over a shadow in another window
1324 
1325   if(shadow&1) {
1326 
1327     // resolve all shadows upwards
1328 
1329     wptr = __curr;
1330     chat = vsattr(*pfound, __curr->wsattr);
1331 
1332     for(__curr=__curr->next;__curr!=NULL;__curr=__curr->next) {
1333 
1334       if(window_blocking()) {
1335         *(calc_window(__curr)) = chat;
1336         chat = temp;
1337         break;
1338       }
1339       else {
1340         if(bshadow_blocking())
1341           *(calc_bshadow(__curr)) = chat;
1342         else {
1343           if(rshadow_blocking())
1344             *(calc_rshadow(__curr)) = chat;
1345         }
1346       }
1347     }
1348 
1349     temp = chat;
1350     __curr = wptr;
1351   }
1352 
1353   // let character position activated hold character
1354   // that was on the screen in the same position
1355 
1356   *pfound = temp;
1357 }
1358 
1359 
1360 //  ------------------------------------------------------------------
1361 
wactiv(int whandle)1362 int wactiv(int whandle) {
1363 
1364   register int startcol, stopcol;
1365   _wrec_t *prev, *next;
1366 
1367   // check for active window
1368 
1369   if(!gwin.total)
1370     return gwin.werrno=W_NOACTIVE;
1371 
1372   // if window is already active, ignore request
1373 
1374   if(whandle==gwin.active->whandle)
1375     return gwin.werrno=W_NOERROR;
1376 
1377   // find address of window's record
1378 
1379   __found=wfindrec(whandle);
1380   if(__found==NULL)
1381     return gwin.werrno=W_NOTFOUND;
1382 
1383   // check every character position in window to activate
1384 
1385   for(__crow=__found->srow;__crow<=__found->erow;__crow++) {
1386     for(__ccol=__found->scol;__ccol<=__found->ecol;__ccol++) {
1387 
1388       // check all window records "above" window to activate
1389 
1390       for(__curr=__found->next;__curr!=NULL;__curr=__curr->next) {
1391 
1392         // see if current position in window to activate
1393         // is blocked by same position in test window
1394 
1395         if(window_blocking()) {
1396 
1397           // calculate buffer addresses and swap contents
1398 
1399           swap_contents(calc_window(__found),calc_window(__curr),0);
1400           break;
1401         }
1402 
1403         // see if test window has a shadow
1404 
1405         if(__curr->wsbuf!=NULL) {
1406 
1407           // see if shadow to the right of test window is
1408           // blocking the current position of window to activate
1409 
1410           if(rshadow_blocking()) {
1411             swap_contents(calc_window(__found),calc_rshadow(__curr),1);
1412             break;
1413           }
1414 
1415           // see if shadow to the bottom of test window is
1416           // blocking the current position of window to activate
1417 
1418           if(bshadow_blocking()) {
1419             swap_contents(calc_window(__found),calc_bshadow(__curr),1);
1420             break;
1421           }
1422         }
1423       }
1424     }
1425   }
1426 
1427   // if window to activate has a shadow, then check
1428   // every character position in the shadow to see
1429   // if it is blocked by another window or window shadow
1430 
1431   if(__found->wsbuf!=NULL) {
1432 
1433     // search the right shadow of window to activiate
1434 
1435     startcol=__found->ecol+1;
1436     stopcol=startcol+1;
1437     for(__crow=__found->srow+1;__crow<=__found->erow;__crow++) {
1438       for(__ccol=startcol;__ccol<=stopcol;__ccol++) {
1439 
1440         // check all window records "above" shadow to activate
1441 
1442         for(__curr=__found->next;__curr!=NULL;__curr=__curr->next) {
1443 
1444           // see if current position in shadow to activate
1445           // is blocked by same position in current window
1446 
1447           if(window_blocking()) {
1448 
1449             // calculate buffer addresses and swap contents
1450 
1451             swap_contents(calc_rshadow(__found),calc_window(__curr),2);
1452             break;
1453           }
1454 
1455           // see if test window has a shadow
1456 
1457           if(__curr->wsbuf!=NULL) {
1458 
1459             // see if current position of window to activate is
1460             // blocked by the right shadow of the test window
1461 
1462             if(rshadow_blocking()) {
1463               swap_contents(calc_rshadow(__found),calc_rshadow(__curr),3);
1464               break;
1465             }
1466 
1467             // see if current position of window to activate is
1468             // blocked by the bottom shadow of the test window
1469 
1470             if(bshadow_blocking()) {
1471               swap_contents(calc_rshadow(__found),calc_bshadow(__curr),3);
1472               break;
1473             }
1474           }
1475         }
1476       }
1477     }
1478 
1479     // search bottom shadow
1480 
1481     startcol=__found->scol+2;
1482     stopcol=__found->ecol+2;
1483     __crow=__found->erow+1;
1484     for(__ccol=startcol;__ccol<=stopcol;__ccol++) {
1485 
1486       // check all window records "above" shadow to activate
1487 
1488       for(__curr=__found->next;__curr!=NULL;__curr=__curr->next) {
1489 
1490         // see if current position in shadow to activate
1491         // is blocked by same position in test window
1492 
1493         if(window_blocking()) {
1494 
1495           // calculate buffer addresses and swap contents
1496 
1497           swap_contents(calc_bshadow(__found),calc_window(__curr),2);
1498           break;
1499         }
1500 
1501         // see if test window has a shadow
1502 
1503         if(__curr->wsbuf!=NULL) {
1504           if(rshadow_blocking()) {
1505             swap_contents(calc_bshadow(__found),calc_rshadow(__curr),3);
1506             break;
1507           }
1508           if(bshadow_blocking()) {
1509             swap_contents(calc_bshadow(__found),calc_bshadow(__curr),3);
1510             break;
1511           }
1512         }
1513       }
1514     }
1515   }
1516 
1517   // re-link pointer to window record to be activated
1518 
1519   prev=__found->prev;
1520   next=__found->next;
1521   if(prev!=NULL)
1522     prev->next=next;
1523   next->prev=prev;
1524   gwin.active->next=__found;
1525   __found->prev=gwin.active;
1526   __found->next=NULL;
1527   gwin.active=__found;
1528 
1529   // update help category
1530 
1531   if(gwin.active->help)
1532     gwin.help=gwin.active->help;
1533 
1534   // reset cursor position
1535 
1536   vposset(gwin.active->row,gwin.active->column);
1537 
1538   // return normally
1539 
1540   return gwin.werrno=W_NOERROR;
1541 }
1542 
1543 
1544 //  ------------------------------------------------------------------
1545 //  Activates a window without overlap checking
1546 
wactiv_(int whandle)1547 int wactiv_(int whandle) {
1548 
1549   // if window is already active, ignore request
1550   if(gwin.active and (whandle == gwin.active->whandle))
1551     return gwin.werrno = W_NOERROR;
1552 
1553   // find address of window's record
1554   __found = wfindrec(whandle);
1555   if(__found == NULL)
1556     return gwin.werrno = W_NOTFOUND;
1557 
1558   // re-link pointer to window record to be activated
1559   _wrec_t* prev = __found->prev;
1560   _wrec_t* next = __found->next;
1561   if(prev)
1562     prev->next = next;
1563   next->prev = prev;
1564   gwin.active->next = __found;
1565   __found->prev = gwin.active;
1566   __found->next = NULL;
1567   gwin.active = __found;
1568 
1569   // update help category
1570   if(gwin.active->help)
1571     gwin.help = gwin.active->help;
1572 
1573   // reset cursor position
1574   vposset(gwin.active->row,gwin.active->column);
1575 
1576   // return normally
1577   return gwin.werrno = W_NOERROR;
1578 }
1579 
1580 
1581 //  ------------------------------------------------------------------
1582 //  this function will update buffers above window string will be displayed in
1583 
update_buffers(vatch * pcurr,int shadow)1584 static void update_buffers(vatch* pcurr, int shadow) {
1585 
1586   _wrec_t *tcurr;
1587   vattr   tgattr;
1588 
1589   // put current string character and attribute into found window's buffer
1590 
1591   *pcurr = vcatch(*__p, __gattr);
1592 
1593   // if window's shadow is what's blocking, check to see
1594   // if it is the highest shadow.  If it is, display the
1595   // character in the shadow's attribute, otherwise search
1596   // for other blocking windows
1597 
1598   if(shadow) {
1599     if(__curr->next==NULL) {
1600       vputc(__crow, __ccol, __gattr & BLINK ? (__curr->wsattr | BLINK) : __curr->wsattr, *__p);
1601     }
1602     else {
1603       tcurr = __curr;
1604       __curr = __curr->next;
1605       tgattr = __gattr;
1606       __gattr = __curr->wsattr;
1607       if(window_blocking())
1608         update_buffers(calc_window(__curr), 0);
1609       else {
1610         if(bshadow_blocking())
1611           update_buffers(calc_bshadow(__curr), 1);
1612         else {
1613           if(rshadow_blocking())
1614             update_buffers(calc_rshadow(__curr), 1);
1615         }
1616       }
1617       __gattr = tgattr;
1618       __curr = tcurr;
1619     }
1620   }
1621 }
1622 
1623 //  ------------------------------------------------------------------
1624 
wwprintc(int whandle,int wrow,int wcol,vattr attr,const vchar chr)1625 int wwprintc(int whandle, int wrow, int wcol, vattr attr, const vchar chr) {
1626 
1627   // check for existance of active window or hidden windows
1628   if(!gwin.total and gwin.hidden==NULL)
1629     return gwin.werrno=W_NOACTIVE;
1630 
1631   // find address of window's record
1632   _wrec_t* found = wfindrec(whandle);
1633   if(found==NULL) {
1634     found = gwin.hidden;
1635     while(found) {
1636       if(whandle==found->whandle)
1637         break;
1638       found = found->prev;
1639     }
1640     if(found==NULL)
1641       return gwin.werrno=W_NOTFOUND;
1642   }
1643 
1644   // display character
1645   vputc(found->srow+wrow+found->border, found->scol+wcol+found->border, attr, chr);
1646 
1647   // return to caller
1648   return gwin.werrno = W_NOERROR;
1649 }
1650 
1651 //  ------------------------------------------------------------------
1652 
wwprints(int whandle,int wrow,int wcol,vattr attr,const char * str)1653 int wwprints(int whandle, int wrow, int wcol, vattr attr, const char* str) {
1654 
1655   // check for existance of active window or hidden windows
1656   if(!gwin.total and gwin.hidden==NULL)
1657     return gwin.werrno=W_NOACTIVE;
1658 
1659   // find address of window's record
1660   int hidden = NO;
1661   _wrec_t* found = wfindrec(whandle);
1662   if(found==NULL) {
1663     found = gwin.hidden;
1664     while(found) {
1665       if(whandle==found->whandle)
1666         break;
1667       found = found->prev;
1668     }
1669     if(found==NULL)
1670       return gwin.werrno=W_NOTFOUND;
1671     hidden = YES;
1672   }
1673 
1674   // see if window has a border
1675   int border = found->border;
1676 
1677   // calculate effective coordinates
1678   int ecol = found->ecol-border;
1679   __crow  = found->srow+wrow+border;
1680   __ccol  = found->scol+wcol+border;
1681   __gattr = attr;
1682   __p     = str;
1683 
1684   // check for valid coordinates
1685   if((__crow > (found->erow-border)) or (__ccol > ecol))
1686     return gwin.werrno=W_INVCOORD;
1687 
1688   // save current cursor position
1689   int oldrow, oldcol;
1690   if(gvid->isbios())
1691     vposget(&oldrow,&oldcol);
1692 
1693   // do while not end-of-string and not end-of-window
1694   while(__ccol <= ecol and *__p) {
1695 
1696     // see if output window is hidden.  if so, then there
1697     // is no need to check for blocking windows/shadows
1698     if(hidden)
1699       *(calc_window(found)) = vcatch(*__p, attr);
1700     else {
1701 
1702       // check all window records "above" window to activate
1703       for(__curr=found->next; __curr!=NULL; __curr=__curr->next) {
1704 
1705         // see if current position in window to activate
1706         // is blocked by same position in test window
1707         if(window_blocking()) {
1708 
1709           // calculate buffer addresses and swap contents
1710           update_buffers(calc_window(__curr), 0);
1711           break;
1712         }
1713 
1714         // see if test window has a shadow
1715         if(__curr->wsbuf!=NULL) {
1716 
1717           // see if shadow to the right of test window is
1718           // blocking the current position of window to activate
1719           if(rshadow_blocking()) {
1720             update_buffers(calc_rshadow(__curr), 1);
1721             break;
1722           }
1723 
1724           // see if shadow to the bottom of test window is
1725           // blocking the current position of window to activate
1726           if(bshadow_blocking()) {
1727             update_buffers(calc_bshadow(__curr), 1);
1728             break;
1729           }
1730         }
1731       }
1732 
1733       // if current position is not blocked,
1734       // then display char to screen
1735       if(__curr==NULL)
1736         vputc(__crow, __ccol, attr, *__p);
1737     }
1738 
1739     // update pointer into string and current column
1740     __ccol++;
1741     __p++;
1742   }
1743 
1744   // restore old cursor position
1745   if(gvid->isbios())
1746     vposset(oldrow,oldcol);
1747 
1748   // return to caller
1749   return gwin.werrno = *__p ? W_STRLONG : W_NOERROR;
1750 }
1751 
1752 
1753 //  ------------------------------------------------------------------
1754 
wwprintstr(int whandle,int wrow,int wcol,vattr attr,const char * str)1755 int wwprintstr(int whandle, int wrow, int wcol, vattr attr, const char* str) {
1756 
1757   // check for existance of active window or hidden windows
1758   if(!gwin.total and gwin.hidden==NULL)
1759     return gwin.werrno=W_NOACTIVE;
1760 
1761   // find address of window's record
1762   _wrec_t* found = wfindrec(whandle);
1763   if(found==NULL) {
1764     found = gwin.hidden;
1765     while(found) {
1766       if(whandle==found->whandle)
1767         break;
1768       found = found->prev;
1769     }
1770     if(found==NULL)
1771       return gwin.werrno=W_NOTFOUND;
1772   }
1773 
1774   // display string
1775   vputs(found->srow+wrow+found->border, found->scol+wcol+found->border, attr, str);
1776 
1777   // return to caller
1778   return gwin.werrno = W_NOERROR;
1779 }
1780 
1781 
1782 //  ------------------------------------------------------------------
1783 //  Changes the active window's border box type
1784 
wborder(int btype)1785 int wborder(int btype) {
1786 
1787   register int border;
1788 
1789   // check for active window
1790   if(!gwin.total)
1791     return gwin.werrno=W_NOACTIVE;
1792 
1793   // check for valid box type
1794   if((btype<0) or (btype>7))
1795     return gwin.werrno=W_INVBTYPE;
1796 
1797   // see if window is to have a border
1798   border = (btype==5) ? NO : YES;
1799 
1800   // redraw window's border
1801   vbox(
1802     gwin.active->srow,
1803     gwin.active->scol,
1804     gwin.active->erow,
1805     gwin.active->ecol,
1806     btype,
1807     border ? gwin.active->battr : gwin.active->wattr,
1808     border ? gwin.active->loattr : gwin.active->wattr
1809   );
1810 
1811   // update window's record
1812   gwin.active->btype=btype;
1813   gwin.active->border=border;
1814 
1815   // see if cursor position needs to be updated
1816   if((gwin.active->row==gwin.active->srow)   or
1817     (gwin.active->row==gwin.active->erow)    or
1818     (gwin.active->column==gwin.active->scol) or
1819     (gwin.active->column==gwin.active->ecol)) {
1820     wgotoxy(0,0);
1821   }
1822 
1823   // re-display title if one exists
1824   if(gwin.active->title!=NULL)
1825     wtitle(gwin.active->title,gwin.active->tpos,gwin.active->tattr);
1826 
1827   // return normally
1828   return gwin.werrno=W_NOERROR;
1829 }
1830 
1831 
1832 //  ------------------------------------------------------------------
1833 //  Fills a region of active window w/specified char/attribute
1834 
wfill(int wsrow,int wscol,int werow,int wecol,vchar chr,vattr atr)1835 int wfill(int wsrow, int wscol, int werow, int wecol, vchar chr, vattr atr) {
1836 
1837   // check for active window
1838   if(!gwin.total)
1839     return gwin.werrno=W_NOACTIVE;
1840 
1841   // check for valid coordinates
1842   if(wchkbox(wsrow,wscol,werow,wecol))
1843     return gwin.werrno=W_INVCOORD;
1844 
1845   // check for window border
1846   const int &border = gwin.active->border;
1847 
1848   // fill in specified region
1849   vfill(
1850     gwin.active->srow+wsrow+border,
1851     gwin.active->scol+wscol+border,
1852     gwin.active->srow+werow+border,
1853     gwin.active->scol+wecol+border,
1854     chr,
1855     atr
1856   );
1857 
1858   // return with no error
1859   return gwin.werrno=W_NOERROR;
1860 }
1861 
1862 
1863 //  ------------------------------------------------------------------
1864 //  Returns the handle of the active window
1865 
whandle()1866 int whandle() {
1867 
1868   // test for active window
1869   if(!gwin.total) {
1870     gwin.werrno=W_NOACTIVE;
1871     return 0;
1872   }
1873 
1874   // return normally
1875   gwin.werrno = W_NOERROR;
1876   return gwin.active->whandle;
1877 }
1878 
1879 
1880 //  ------------------------------------------------------------------
1881 //  Displays text on window's top or bottom border
1882 
wmessage(const char * str,int border,int leftofs,vattr attr)1883 int wmessage(const char* str, int border, int leftofs, vattr attr) {
1884 
1885   // check for active window
1886   if(!gwin.total)
1887     return gwin.werrno=W_NOACTIVE;
1888 
1889   // make sure window has a border
1890   if(!gwin.active->border)
1891     return gwin.werrno=W_NOBORDER;
1892 
1893   int left  = gwin.active->scol+1;
1894   int right = gwin.active->ecol-1;
1895   int width = right-left+1;
1896   int len   = strlen(str);
1897 
1898   // Center string
1899   if(leftofs < 0)
1900     leftofs = (len > (width-2)) ? left : (((width/2)+left)-(len/2));
1901 
1902   // make sure string fits in window
1903   if((gwin.active->scol+leftofs+len-1) > (gwin.active->ecol))
1904     return gwin.werrno=W_STRLONG;
1905 
1906   // display string
1907   vputs(border ? gwin.active->erow : gwin.active->srow, gwin.active->scol+leftofs, attr, str);
1908 
1909   // return normally
1910   return gwin.werrno=W_NOERROR;
1911 }
1912 
1913 
1914 //  ------------------------------------------------------------------
1915 //  Proportion bar
1916 
wpropbar(int xx,int yy,long len,vattr attr,long pos,long size)1917 void wpropbar(int xx, int yy, long len, vattr attr, long pos, long size) {
1918 
1919   //  xx, yy = start position in window.
1920   //  len    = length (in chars) of progress field.
1921   //  attr   = color to use for progress field.
1922   //  pos    = present position.
1923   //  size   = total size of field.
1924 
1925   const vchar barchar   = _box_table(gwin.active->btype, 13);
1926 #ifdef __UNIX__ // prefferable under xterm
1927   const vchar thumbchar = ' ';
1928   vattr thumbattr       = revsattr(attr);
1929 #else
1930   const vchar thumbchar = '\xDB';
1931   vattr thumbattr       = attr;
1932 #endif
1933 
1934   long thumblen = (pos*len)/size;
1935 
1936   int x = xx;
1937   if(thumblen != 0) {
1938     wputx(yy, x, thumbattr|ACSET, thumbchar, thumblen);
1939     x += thumblen;
1940   }
1941   if(thumblen != len)
1942     wputx(yy, x, attr|ACSET, barchar, len-thumblen);
1943 }
1944 
1945 
1946 //  ------------------------------------------------------------------
1947 //  Gives active window a title
1948 
wtitle(const char * str,int tpos,vattr tattr)1949 int wtitle(const char* str, int tpos, vattr tattr) {
1950 
1951   // check for active window
1952   if(!gwin.total)
1953     return gwin.werrno=W_NOACTIVE;
1954 
1955   // redraw box if deleting or moving title
1956   if(str==NULL or gwin.active->title!=NULL) {
1957     if(gwin.active->border) {
1958       vputx(
1959         ((tpos&TBOTTOM) ? gwin.active->erow : gwin.active->srow),
1960         gwin.active->scol+1,
1961         gwin.active->battr|ACSET,
1962         _box_table(gwin.active->btype, (tpos&TBOTTOM)?6:1),
1963         gwin.active->ecol-gwin.active->scol-1
1964       );
1965     }
1966   }
1967 
1968   // if not deleting the title, calculate position and display it
1969   if(str) {
1970 
1971     int left  = gwin.active->scol+1;
1972     int right = gwin.active->ecol-1;
1973     int width = right-left+1;
1974     int len   = strlen(str);
1975 
1976     // don't display title if window is borderless
1977     if(gwin.active->border) {
1978 
1979       int start;
1980 
1981       switch(tpos&~TBOTTOM) {
1982         case TLEFT:
1983           //start = (len>(width-3)) ? left : (left+1);
1984           start = left;
1985           break;
1986         case TCENTER:
1987           start = (len>(width-2)) ? left : (((width/2)+left)-(len/2));
1988           break;
1989         default:        // default is TRIGHT
1990           {
1991             int offs = width-len;
1992             if(offs>2)
1993               offs--;
1994             start = (len>width) ? left : (left+offs+1);
1995           }
1996       }
1997 
1998       // allocate space for window title string, and copy it there
1999       char* p = (char*)throw_xmalloc(((width>len) ? width : len)+1);
2000       if(p==NULL)
2001         return gwin.werrno=W_ALLOCERR;
2002       strcpy(p, str);
2003       *(p+width) = NUL;
2004 
2005       // display title string
2006       vputs((tpos&TBOTTOM)?gwin.active->erow:gwin.active->srow, start, tattr, p);
2007 
2008       // free allocated space
2009       throw_xfree(p);
2010 
2011     }
2012   }
2013 
2014   // update window's record
2015   gwin.active->title=str;
2016   gwin.active->tpos=tpos;
2017   gwin.active->tattr=tattr;
2018 
2019   // return normally
2020   return gwin.werrno=W_NOERROR;
2021 }
2022 
2023 
2024 //  ------------------------------------------------------------------
2025 
wscrollbar(int orientation,uint total,uint maxpos,uint pos,int sadd)2026 void wscrollbar(int orientation, uint total, uint maxpos, uint pos, int sadd) {
2027 
2028   vattr attr = (gwin.active->sbattr == DEFATTR) ? gwin.active->battr : gwin.active->sbattr;
2029   vattr invattr              = revsattr(attr);
2030 
2031   const vchar barchar        = _box_table(gwin.active->btype, 13);
2032   const vchar arrowupchar    = '\x18';
2033   const vchar arrowdownchar  = '\x19';
2034   const vchar arrowleftchar  = '\x1B';
2035   const vchar arrowrightchar = '\x1A';
2036 #ifdef __UNIX__ // prefferable under xterm
2037   const vchar thumbchar      = ' ';
2038   vattr thumbattr            = revsattr(attr);
2039 #else
2040   const vchar thumbchar      = '\xDB';
2041   vattr thumbattr            = attr;
2042 #endif
2043 
2044   if(maxpos == 0)
2045     maxpos = 1;
2046 
2047   uint visiblelen;
2048   if(orientation == W_VERT)
2049     visiblelen = (gwin.active->erow - (gwin.active->srow+sadd)) + 1 - (gwin.active->border?2:0);
2050   else
2051     visiblelen = (gwin.active->ecol - (gwin.active->scol+sadd)) + 1 - (gwin.active->border?2:0) - 2;
2052   uint barlen = visiblelen - 2;
2053   uint thumblen = (visiblelen*barlen) / total;
2054   if(thumblen == 0)
2055     thumblen = 1;
2056   else if(thumblen > barlen)
2057     thumblen = barlen;
2058   uint maxthumbpos = barlen - thumblen;
2059   uint thumbpos = (pos*maxthumbpos) / maxpos;
2060   uint thumbdiv = (pos*maxthumbpos) % maxpos;
2061   if((thumbdiv >= (maxpos/2)) and (maxpos > 1))
2062     thumbpos++;
2063   if(thumbpos > maxthumbpos)
2064     thumbpos = maxthumbpos;
2065   barlen -= thumbpos + thumblen;
2066 
2067   if(orientation == W_VERT) {
2068     uint scol = gwin.active->ecol - gwin.active->scol - gwin.active->border;
2069     vputc((sadd++)+gwin.active->srow+gwin.active->border, gwin.active->ecol, invattr|ACSET, arrowupchar);
2070     if(thumbpos != 0) {
2071       wputy(sadd, scol, attr|ACSET, barchar, thumbpos);
2072       sadd += thumbpos;
2073     }
2074     if(thumblen != 0) {
2075       wputy(sadd, scol, thumbattr|ACSET, thumbchar, thumblen);
2076       sadd += thumblen;
2077     }
2078     if(barlen != 0) {
2079       wputy(sadd, scol, attr|ACSET, barchar, barlen);
2080       sadd += barlen;
2081     }
2082     vputc(sadd+gwin.active->srow+gwin.active->border, gwin.active->ecol, invattr|ACSET, arrowdownchar);
2083   }
2084   else {
2085     uint srow = gwin.active->erow - gwin.active->srow - gwin.active->border;
2086     vputc(gwin.active->erow, (sadd++)+gwin.active->scol+gwin.active->border, invattr|ACSET, arrowleftchar);
2087     if(thumbpos != 0) {
2088       wputx(srow, sadd, attr|ACSET, barchar, thumbpos);
2089       sadd += thumbpos;
2090     }
2091     if(thumblen != 0) {
2092       wputx(srow, sadd, thumbattr|ACSET, thumbchar, thumblen);
2093       sadd += thumblen;
2094     }
2095     if(barlen != 0) {
2096       wputx(srow, sadd, attr|ACSET, barchar, barlen);
2097       sadd += barlen;
2098     }
2099     vputc(gwin.active->erow, sadd+gwin.active->scol+gwin.active->border, invattr|ACSET, arrowrightchar);
2100   }
2101 }
2102 
2103 
2104 //  ------------------------------------------------------------------
2105