// This may look like C code, but it is really -*- C++ -*- // ------------------------------------------------------------------ // The Goldware Library // Copyright (C) 1990-1999 Odinn Sorensen // Copyright (C) 1999-2000 Alexander S. Aganichev // ------------------------------------------------------------------ // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this program; if not, write to the Free // Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, // MA 02111-1307, USA // ------------------------------------------------------------------ // $Id$ // ------------------------------------------------------------------ // Based on CXL by Mike Smedley. // Windowing kernel. // ------------------------------------------------------------------ #include <cstdio> #include <cstdarg> #include <cstdlib> #include <cstring> #include <gmemdbg.h> #include <gutlmisc.h> #include <gwinall.h> #include <gkbdcode.h> // ------------------------------------------------------------------ #define GOLD_INLINE inline #define GOLD_WCHK // ------------------------------------------------------------------ // Global window data GWin gwin; // ------------------------------------------------------------------ // Window Class constructor GWin::GWin() { active = NULL; // pointer to active window hidden = NULL; // pointer to last hidden window menu = NULL; // pointer to head menu record cmenu = NULL; // pointer to current menu record helptr = NULL; // pointer to help info record handle = 0; // last handle given to a window help = 0; // pointer to current help category werrno = W_NOERROR; // error num from last window func total = 0; // total number of open windows mlevel = 0; // system variable used in menus ilevel = 0; // system variable used in menus esc = true; // check for Esc in input funcions? tabwidth = 8; // window TTY output tab width fillch = ' '; // character to fill windows with style = STYLE_NORMAL; // window opening style } // ------------------------------------------------------------------ // Window Class destructor GWin::~GWin() { // No action defined yet } // ------------------------------------------------------------------ // Displays a string in centered in active window int wcenters(int wrow, vattr attr, const char* str) { register int window_width, string_length; int start_column, border; // check for active window if(!gwin.total) return gwin.werrno=W_NOACTIVE; // check for valid row if(wchkcoord(wrow,0)) return gwin.werrno=W_INVCOORD; // check for window border border=gwin.active->border; // calculate start column & window width start_column = gwin.active->scol+border; window_width = (gwin.active->ecol-border)-start_column+1; // check length of input string string_length=strlen(str); if(string_length>window_width) return gwin.werrno=W_STRLONG; // display the string vputs( gwin.active->srow+wrow+border, ((window_width/2)+start_column)-(string_length/2), attr, str ); // return normally return gwin.werrno=W_NOERROR; } // ------------------------------------------------------------------ // Smoothly drag a window 1 position in given direction int wdrag(int direction) { int srow, scol, erow, ecol, fill_row, fill_col, i; int nsrow, nscol, nerow, necol; vattr shad_attr = DEFATTR; int chars_per_line, lines_per_win; int vert_movement, horz_movement; vsavebuf* win_image; vsavebuf* wp; vatch* p; register vatch* src; register vatch* dest; // check for active window if(!gwin.total) return(gwin.werrno=W_NOACTIVE); // get window coordinates srow = gwin.active->srow; scol = gwin.active->scol; erow = gwin.active->erow; ecol = gwin.active->ecol; // calculate lines-per-window and characters-per-line lines_per_win = erow - srow + 1; chars_per_line = ecol - scol + 1; // determine facts about direction of move vert_movement=horz_movement=0; switch(direction) { case D_DOWN: vert_movement=1; lines_per_win--; break; case D_UP: vert_movement=-1; lines_per_win--; break; case D_LEFT: horz_movement=-1; chars_per_line--; break; case D_RIGHT: default: horz_movement=1; chars_per_line--; } // calculate new window coordinates nsrow = srow + vert_movement; nscol = scol + horz_movement; nerow = erow + vert_movement; necol = ecol + horz_movement; // if window has shadow, close it before the move if(gwin.active->wsbuf!=NULL) { shad_attr = gwin.active->wsattr; wshadoff(); } // save the current window image win_image = vsave(srow,scol,erow,ecol); if(win_image==NULL) return(gwin.werrno=W_ALLOCERR); // save the area where the window will relocate to wp = vsave(nsrow,nscol,nerow,necol); if(wp==NULL) { throw_xfree(win_image); return(gwin.werrno=W_ALLOCERR); } // restore window to new coordinates vrestore(win_image, nsrow, nscol, nerow, necol); throw_xfree(win_image); // start buffer positions past coordinates src = gwin.active->wbuf->data; dest = wp->data; if(direction==D_DOWN) src += chars_per_line; if(direction==D_UP) dest += chars_per_line; // do the transfer of buffer contents for(i=0; i < lines_per_win; i++) { if(direction==D_LEFT) dest++; if(direction==D_RIGHT) src++; // move 1 line memmove(dest, src, chars_per_line*sizeof(vatch)); src += chars_per_line; dest += chars_per_line; if(direction==D_LEFT) src++; if(direction==D_RIGHT) dest++; } // erase the trail that was left-over p = gwin.active->wbuf->data; if(vert_movement) { if(direction==D_DOWN) fill_row=srow; else { p += (lines_per_win * chars_per_line); fill_row=erow; } vputx(fill_row, scol, vgattr(*p), vgchar(*p), ecol-scol+1); } else { if(direction==D_RIGHT) fill_col=scol; else { p += chars_per_line; fill_col=ecol; } for(i=srow;i<=erow;i++,p+=chars_per_line+1) vputc(i, fill_col, vgattr(*p), vgchar(*p)); } // free old window buffer throw_xfree(gwin.active->wbuf); // update window record gwin.active->wbuf = wp; gwin.active->row = gwin.active->row - gwin.active->srow + nsrow; gwin.active->column = gwin.active->column - gwin.active->scol + nscol; gwin.active->srow = nsrow; gwin.active->scol = nscol; gwin.active->erow = nerow; gwin.active->ecol = necol; // if window has shadow, redraw it if(shad_attr != DEFATTR) wshadow(shad_attr); // reset cursor position vposset(gwin.active->row,gwin.active->column); // return normally return(gwin.werrno=W_NOERROR); } // ------------------------------------------------------------------ // Slides active window to a new location int wslide(int nsrow, int nscol) { vattr shattr = DEFATTR; int err = 0; // check for active windows if(!gwin.total) return gwin.werrno=W_NOACTIVE; // check for valid coordinates if(nsrow<0 or nscol<0) return gwin.werrno=W_INVCOORD; // if window has shadow, close it before the move if(gwin.active->wsbuf!=NULL) { shattr = gwin.active->wsattr; wshadoff(); } // slide it on over while(gwin.active->scol>nscol and !err) err = wdrag(D_LEFT); while(gwin.active->scol<nscol and !err) err = wdrag(D_RIGHT); while(gwin.active->srow>nsrow and !err) err = wdrag(D_UP); while(gwin.active->srow<nsrow and !err) err = wdrag(D_DOWN); // test for error if(gwin.werrno) return gwin.werrno; // if window has shadow, redraw it if(shattr != DEFATTR) wshadow(shattr); // return normally return gwin.werrno=W_NOERROR; } // ------------------------------------------------------------------