329 lines
8.5 KiB
C++
329 lines
8.5 KiB
C++
// 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$
|
|
// ------------------------------------------------------------------
|
|
// GCUI: Golded+ Character-oriented User Interface.
|
|
// Windowing kernel.
|
|
// Based on CXL by Mike Smedley.
|
|
// ------------------------------------------------------------------
|
|
|
|
#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;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|