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