/*
* WINDOW.C
*
* Written by John Dennis and released to the public domain on 10-Jul-94.
*
* This module contains routines that maintain text windows on the
* screen. Output routines are integrated in relation to the window
* coordinates on the screen. All coordinates have a 0 based origin!
* Please note this!
*
* This is the second level of abstraction from the physical device; it
* should not be necessary to modify this module when porting to other
* operating systems/devices.
*
* History:
*
* 10-Nov-91 JD Started.
* 25-Jul-92 JD Whole package (of which this is a module) was finished
* to a useable degree.
* 13-Aug-92 JD Functions added during the Msged port to this system.
* Should increase the packages' useability.
*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include "specch.h"
#include "memextra.h"
#include "keys.h"
#include "winsys.h"
#include "mcompile.h"
#define XMOD(w) ((w->flags & INSBDR) ? 3 : ((w->flags & NBDR) ? 0 : 1))
#define YMOD(w) ((w->flags & INSBDR) ? 2 : ((w->flags & NBDR) ? 0 : 1))
/* double and single border chars */
/*
unsigned char Dbdr[6] = {SC1, SC2, SC3, SC4, SC5, SC6};
unsigned char Sbdr[6] = {SC7, SC8, SC9, SC10, SC11, SC12};
*/
#define Dbdr(x) SC(((x)+1))
#define Sbdr(x) SC(((x)+7))
#define Bdr(y,x) (((y) != SBDR) ? Dbdr((x)) : Sbdr((x)))
int wnd_bs_127 = 0; /* Is ASCII 127 backspace on ANSI console ? */
int wnd_suppress_shadows = 0; /* do not suppress window shadows */
#ifdef UNIX
int wnd_force_monochrome = 1;
#else
int wnd_force_monochrome = 0; /* do not enforce monochrome output */
#endif
unsigned long wndid = 20; /* unique window ID */
WND *CW = NULL; /* current window */
static void WDrwBox(int x1, int y1, int x2, int y2, int Bdrt, int Battr, int ins);
static char line[255];
int CheckMousePos(int x1, int y1, int x2, int y2)
{
int x, y;
GetMouInfo(&x, &y);
if (x >= x1 && x <= x2)
{
if (y >= y1 && y <= y2)
{
return 1;
}
}
return 0;
}
/*
* WndOpen; Creates and opens a window returning the handle to
* the user, using 0 based coordinates on the screen.
*/
WND *WndOpen(int x1, int y1, int x2, int y2, int Bdr, int BAttr, int Attr)
{
WND *w;
unsigned long ch;
int i, k = 0;
static int first_win = 1;
w = xmalloc(sizeof *w);
if (w == NULL)
{
return NULL;
}
if (wnd_suppress_shadows)
{
Bdr = Bdr & (~SHADOW);
}
/* sanity checks*/
if (x1 < 0) x1 = 0;
if (y1 < 0) y1 = 0;
if (x2 < x1) x2 = x1;
if (y2 < y1) y2 = y1;
w->wid = ++wndid;
w->x1 = (unsigned char)x1;
w->x2 = (unsigned char)x2;
w->y1 = (unsigned char)y1;
w->y2 = (unsigned char)y2;
w->wattr = (unsigned char)Attr;
w->battr = (unsigned char)BAttr;
w->flags = (unsigned char)Bdr;
w->title = NULL;
if (Bdr & SHADOW)
{
x2 += 2;
y2++;
}
MouseOFF();
/* get a copy of the background */
if ((!(Bdr & NOSAVE)) || (Bdr & SHADOW))
{
w->buffer = xmalloc(sizeof(unsigned long *) * ((y2 - y1) + 2));
if (!w->buffer)
{
return NULL;
}
for (i = y1; i <= y2; i++)
{
w->buffer[k] = xmalloc(sizeof(unsigned long) * ((x2 - x1) + 2));
if (!w->buffer[k])
{
return NULL;
}
TTReadStr(w->buffer[k], x2 - x1 + 1, i, x1);
k++;
}
}
else
{
w->buffer = NULL;
}
TTBeginOutput();
/* put out shadow */
if (Bdr & SHADOW)
{
k = 1;
for (i = y1 + 1; i <= y2; i++)
{
ch = (unsigned long)w->buffer[k][x2 - x1];
ch &= 0xFF00FFFFUL;
ch |= ((unsigned long)(DGREY | _BLACK) << 16);
TTWriteStr(&ch, 1, i, x2);
ch = (unsigned long)w->buffer[k][x2 - x1 - 1];
ch &= 0xFF00FFFFUL;
ch |= ((unsigned long)(DGREY | _BLACK) << 16);
TTWriteStr(&ch, 1, i, x2 - 1);
k++;
}
k = y2 - y1;
for (i = 2; i <= (x2 - x1); i++)
{
ch = (unsigned long)w->buffer[k][i];
ch &= 0xFF00FFFFUL;
ch |= ((unsigned long)(DGREY | _BLACK) << 16);
TTWriteStr(&ch, 1, y2, i + x1);
}
}
TTScolor(Attr);
if (!first_win)
{
TTClear(w->x1, w->y1, w->x2, w->y2);
}
else
{
first_win = 0;
}
if (!(Bdr & NBDR))
{
if (Bdr & SBDR)
{
WDrwBox(w->x1, w->y1, w->x2, w->y2, SBDR, BAttr, Bdr & INSBDR ? 1 : 0);
}
else
{
WDrwBox(w->x1, w->y1, w->x2, w->y2, DBDR, BAttr, Bdr & INSBDR ? 1 : 0);
}
}
MouseON();
TTEndOutput();
CW = w;
return CW;
}
/*
* WndPopUp; Opens up a window of the passed size in the middle of the
* screen.
*/
WND *WndPopUp(int wid, int dep, int Bdr, int BAttr, int NAttr)
{
int x1, x2, y1, y2;
x1 = max((term.NCol / 2) - (wid / 2) - 1, 0);
y1 = max((term.NRow / 2) - (dep / 2) - 1, 0);
x2 = min(x1 + wid, term.NCol - 1);
y2 = min(y1 + dep, term.NRow - 1);
return WndOpen(x1, y1, x2, y2, Bdr, BAttr, NAttr);
}
/*
* WndClose; Closes the passed window and restores the screen
* behind it.
*
* Caveats: Since no track is kept of the windows on the screen, it
* is the caller's responsibility to ensure that windows are closed
* in the right order.
*/
void WndClose(WND * w)
{
WND *wnd;
int i, k = 0;
int x2, y2;
/* restore screen buffer */
if (w == NULL)
{
wnd = CW;
}
else
{
wnd = w;
}
if (wnd == NULL)
{
return;
}
x2 = wnd->x2;
y2 = wnd->y2;
if (wnd->flags & SHADOW)
{
x2 += 2;
y2++;
}
TTBeginOutput();
MouseOFF();
if (!(wnd->flags & NOSAVE))
{
for (i = wnd->y1; i <= y2; i++)
{
TTWriteStr(wnd->buffer[k], x2 - wnd->x1 + 1, i, wnd->x1);
xfree(wnd->buffer[k++]);
}
xfree(wnd->buffer);
}
xfree(wnd);
MouseON();
TTEndOutput();
}
/*
* WndDrwBox; Draws a box at the specified position. Internal function.
*/
static void WDrwBox(int x1, int y1, int x2, int y2, int Bdrt, int Battr, int ins)
{
unsigned int i, width;
unsigned long cell, *pcell, *p;
int xmod = ins ? 2 : 0;
int ymod = ins ? 1 : 0;
TTBeginOutput();
MouseOFF();
/* write corner chars */
cell = MAKECELL(Bdr(Bdrt,2), Battr | F_ALTERNATE);
TTWriteStr(&cell, 1, y1 + ymod, x1 + xmod);
cell = MAKECELL(Bdr(Bdrt,3), Battr | F_ALTERNATE);
TTWriteStr(&cell, 1, y1 + ymod, x2 - xmod);
cell = MAKECELL(Bdr(Bdrt,4), Battr | F_ALTERNATE);
TTWriteStr(&cell, 1, y2 - ymod, x1 + xmod);
cell = MAKECELL(Bdr(Bdrt,5), Battr | F_ALTERNATE);
TTWriteStr(&cell, 1, y2 - ymod, x2 - xmod);
/* write top & bottom horiziontal border chars */
width = (x2 - xmod) - (x1 + 1 + xmod);
pcell = xmalloc(width * sizeof *pcell);
p = pcell;
for (i = 0; i < width; i++)
{
*p = MAKECELL(Bdr(Bdrt,1), Battr | F_ALTERNATE);
p++;
}
TTWriteStr(pcell, width, y1 + ymod, x1 + 1 + xmod);
TTWriteStr(pcell, width, y2 - ymod, x1 + 1 + xmod);
xfree(pcell);
/* write left & right vertical border chars */
cell = MAKECELL(Bdr(Bdrt,0), Battr | F_ALTERNATE);
for (i = y1 + 1 + ymod; i < y2 - ymod; i++)
{
TTWriteStr(&cell, 1, i, x1 + xmod);
TTWriteStr(&cell, 1, i, x2 - xmod);
}
TTEndOutput();
MouseON();
}
/*
* WndBox; Draws a box in the window.
*/
void WndBox(int x1, int y1, int x2, int y2, int Attr, int type)
{
int xmod, ymod;
int Bdrt = (type & DBDR) ? DBDR : SBDR;
if (CW == NULL)
{
return;
}
ymod = YMOD(CW);
xmod = XMOD(CW);
if (y1 < 0 || x1 < 0 || CW->x1 + x2 + xmod > CW->x2 || CW->y1 + y2 + ymod > CW->y2)
{
return;
}
WDrwBox(x1 + CW->x1 + xmod, y1 + CW->y1 + ymod, x2 + CW->x1 + xmod, y2 + CW->y1 + ymod, Bdrt, Attr, 0);
}
/*
* WndGetRel; Converts absolute coordinates to coordinates relative
* to the current window.
*/
void WndGetRel(int x, int y, int *wx, int *wy)
{
int xmod, ymod;
if (CW == NULL)
{
return;
}
ymod = YMOD(CW);
xmod = XMOD(CW);
*wx = x - (CW->x1 + xmod);
*wy = y - (CW->y1 + ymod);
}
int WndWidth(void)
{
if (CW == NULL)
{
return 0;
}
return CW->x2 - CW->x1 - (XMOD(CW) * 2);
}
/*
* WndTitle; Writes a title to centre of the *current* window,
* clearing whatever was there initially.
*
* Caveats: Doesn't check to see if there is a border, only for the
* type of border.
*/
void WndTitle(const char *title, int Attr)
{
int cntr;
int pos, i, len;
unsigned long ch;
int ymod;
int Bdrt = SBDR;
int m = 0;
if (CW == NULL)
{
return;
}
if (title == NULL)
{
title = "<-- null pointer passed -->";
}
cntr = (CW->x2 - CW->x1 + 1) / 2;
len = strlen(title);
/* 'cause were writing on the border */
if (CW->flags & INSBDR)
{
ymod = 1;
}
else
{
ymod = 0;
}
if (CheckMousePos(CW->x1, CW->y1, CW->x2, CW->y2))
{
m = 1;
MouseOFF();
}
TTBeginOutput();
if (CW->title)
{
if (!(CW->flags & NBDR))
{
if (CW->flags & SBDR)
{
Bdrt = SBDR;
}
else
{
Bdrt = DBDR;
}
}
ch = MAKECELL(Bdr(Bdrt,1), CW->battr | F_ALTERNATE);
for (i = CW->x1 + 1; i < CW->x2; i++)
{
TTWriteStr(&ch, 1, CW->y1 + ymod, i);
}
xfree(CW->title);
}
pos = (cntr - (len / 2)) + CW->x1;
CW->title = xstrdup(title);
TTScolor(Attr);
TTStrWr((unsigned char *)title, CW->y1 + ymod, pos, -1);
if (m)
{
MouseON();
}
TTEndOutput();
}
/*
* WndWriteStr; Writes a string to the (current) window, using a
* zero-based origin.
*
* Caveats: If string would write past end of line, it won't write
* the string.
*/
void WndWriteStr(int x, int y, int Attr, char *Str)
{
int row, col, len;
int m = 0;
char *PrintStr = Str;
if (Str == NULL)
{
return;
}
len = strlen(Str);
if (CW == NULL)
{
return;
}
/* row and col must be zero-based */
row = CW->y1 + y;
col = CW->x1 + x;
if (x < 0 || y < 0)
{
return;
}
if (!(CW->flags & NBDR))
{
/* check end-of-window overstep */
row += YMOD(CW);
col += XMOD(CW);
if (row >= CW->y2 || col > CW->x2 - XMOD(CW))
{
return;
}
}
else
{
if (row > CW->y2 || col > CW->x2)
{
return;
}
}
if (CheckMousePos(col, row, col + len - 1, row))
{
m = 1;
MouseOFF();
}
if ((col + len - 1) > CW->x2 - XMOD(CW))
{
len = ((CW->x2 - XMOD(CW)) - col + 1);
PrintStr = xmalloc(len + 1);
memcpy(PrintStr, Str, len);
PrintStr[len] = '\0';
}
TTBeginOutput();
TTScolor(Attr);
TTStrWr((unsigned char *)PrintStr, row, col, len);
if (PrintStr != Str)
{
xfree(PrintStr);
}
TTEndOutput();
if (m)
{
MouseON();
}
}
/*
* WndPutsCen; Puts a string in the center of the window at the passed
* line.
*/
void WndPutsCen(int y, int attr, char *str)
{
int cntr;
int col, len;
int mod;
if (CW == NULL)
{
return;
}
if (str == NULL)
{
return;
}
if (y < 0)
{
return;
}
cntr = (CW->x2 - CW->x1 + 1) / 2;
mod = XMOD(CW);
len = strlen(str);
if (len > WndWidth())
{
col = 0;
}
else
{
col = cntr - (len / 2) - mod;
}
WndWriteStr(col, y, attr, str);
}
/*
* WndPrintf; Operates the same as printf(), except it does it to the
* current window, using the passed parameters.
*/
int WndPrintf(int x, int y, int attr, char *str, ...)
{
int rc;
va_list params;
va_start(params, str);
rc = vsprintf(line, str, params);
WndWriteStr(x, y, attr, line);
return rc;
}
/*
* WndPutsn; Puts len of str onto the current window.
*/
void WndPutsn(int x, int y, int len, int attr, char *str)
{
char *s = str, *c = line;
int i = 0;
if (x < 0 || y < 0 || len < 1)
{
return;
}
if (len > 254)
{
len = 254;
}
if (s != NULL)
{
i = strlen(s);
if (i > len)
{
i = len;
}
memcpy(c, s, i);
}
if (i < len)
{
memset(c + i, ' ', len - i);
}
c[len] = '\0';
WndWriteStr(x, y, attr, line);
}
/*
* WndScroll; Scrolls a window at the specified cooridiates using a
* zero-based origin.
*
*/
void WndScroll(int x1, int y1, int x2, int y2, int dir)
{
int xmod, ymod;
int m = 0;
if (CW == NULL)
{
return;
}
if (x1 < 0) x1 = 0;
if (y1 < 0) y1 = 0;
if (x2 < x1 || y2 < y1) return;
xmod = XMOD(CW);
ymod = YMOD(CW);
if (CheckMousePos(CW->x1 + x1 + xmod, CW->y1 + y1 + ymod, CW->x2 + x2 + xmod, CW->y2 + y2 + ymod))
{
m = 1;
MouseOFF();
}
TTBeginOutput();
TTScolor(CW->wattr);
TTScroll(CW->x1 + x1 + xmod, CW->y1 + y1 + ymod, CW->x1 + x2 + xmod,
CW->y1 + y2 + ymod, 1, dir);
TTEndOutput();
if (m)
{
MouseON();
}
}
/*
* WndCurr; Makes the passed window the current window.
*
* Caveats: The windowing system doesn't keep track of the windows
* that exist - the caller must do that.
*/
void WndCurr(WND * hWnd)
{
if (CW == hWnd || hWnd == NULL)
{
return;
}
CW = hWnd;
}
/*
* WndTop; Returns the current window recognized by the windowing system.
*/
WND *WndTop(void)
{
if (CW != NULL)
{
return CW;
}
else
{
return NULL;
}
}
/*
* WndPutc; Puts a char anywhere on the window, ignoring borders, etc.
* Puts it at the current cursor position (virtual or real).
*
* Caveats: The cursor may not even be on the window, but it doesn't
* care. :-)
*/
void WndPutc(int Ch, int attr)
{
if (CW == NULL)
{
return;
}
MouseOFF();
TTScolor(attr);
TTPutChr(Ch);
MouseON();
}
/*
* WndGotoXY; Goes to the passed coordinates, zero-based, starting
* from any borders on the window.
*
* Caveats: No checks for validity of arguments.
*/
void WndGotoXY(int x, int y)
{
int xmod, ymod;
if (CW == NULL)
{
return;
}
xmod = XMOD(CW);
ymod = YMOD(CW);
TTgotoxy(CW->y1 + y + ymod, CW->x1 + x + xmod);
}
/*
* WndClear; Clears the passed coordinates with the passed attribute
* in the current window.
*
* Caveats: No checks for validity of arguments.
*/
void WndClear(int x1, int y1, int x2, int y2, int attr)
{
int xmod, ymod, m = 0;
if (CW == NULL)
{
return;
}
xmod = XMOD(CW);
ymod = YMOD(CW);
if (CheckMousePos(CW->x1 + x1 + xmod, CW->y1 + y1 + ymod, CW->x2 + x2 + xmod, CW->y2 + y2 + ymod))
{
m = 1;
MouseOFF();
}
TTScolor(attr);
TTClear(CW->x1 + x1 + xmod, CW->y1 + y1 + ymod, CW->x1 + x2 + xmod, CW->y1 + y2 + ymod);
if (m)
{
MouseON();
}
}
/*
* WndClearLine; Clears the passed line in the current window.
*/
void WndClearLine(int y, int Att)
{
if (CW == NULL)
{
return;
}
WndClear(0, y, CW->x2 - CW->x1 - (XMOD(CW) * 2), y, Att);
}
/*
* WndFillField; Fills in an edit-field region with char.
*/
void WndFillField(int x, int y, int len, unsigned char ch, int Attr)
{
if (len > sizeof(line) - 1)
{
len = sizeof(line) - 1;
}
memset(line, ch, len);
*(line + len - 1) = '\0';
WndWriteStr(x, y, Attr, line);
}
/*
* WndGetLine; Gets a string from the user on the current window at
* the passed coordinates. Passes mouse events not on itself back to
* the caller via the extra parameters.
*/
int WndGetLine(int x, int y, int len, char *buf, int Attr, int *pos, int nokeys, int fil, int disp, EVT * ev)
{
EVT event;
int done = 0;
int row = y, col = x;
int xmod, ymod, i;
unsigned int ch = 0;
unsigned char fill;
fill= (fil) ? SC13 : (unsigned char) ' ';
if (CW == NULL)
{
return 0;
}
if (x < 0) x = 0;
if (y < 0) y = 0;
if (disp)
{
TTBeginOutput();
WndFillField(col, row, len + 1, fill, Attr | F_ALTERNATE);
WndPutsn(col, row, len, Attr, buf);
TTEndOutput();
}
xmod = XMOD(CW);
ymod = YMOD(CW);
i = *pos;
TTCurSet(1);
while (!done)
{
WndGotoXY(i + col, row);
ch = MnuGetMsg(&event, 0);
switch (event.msgtype)
{
case WND_WM_MOUSE:
case WND_WM_COMMAND:
{
int p1 = event.x, p2 = event.y;
if (p1 < CW->x1 + xmod + x || p1 > CW->x1 + xmod + x + len - 1 || p2 != CW->y1 + ymod + y)
{
done = TRUE;
break;
}
}
break;
case WND_WM_CHAR:
switch (ch)
{
case Key_Up:
case Key_Dwn:
done = TRUE;
break;
case Key_Lft:
if (i > 0)
{
i--;
}
break;
case Key_Rgt:
if (i < strlen(buf))
{
i++;
}
break;
case Key_A_X:
memset(buf, 0, len);
i = 0;
break;
case Key_BS:
if (i > 0)
{
TTBeginOutput();
if (i < strlen(buf))
{
memmove(buf + i - 1, buf + i, strlen(buf + i) + 1);
i--;
WndWriteStr(col + i, row, Attr, buf + i);
WndPrintf(col + strlen(buf), row, Attr | F_ALTERNATE,
"%c", fill);
}
else
{
i--;
*(buf + i) = '\0';
WndGotoXY(i + col, row);
WndPutc(fill, Attr | F_ALTERNATE);
}
TTEndOutput();
}
break;
case Key_Del:
if (i < strlen(buf))
{
TTBeginOutput();
memmove(buf + i, buf + i + 1, strlen(buf + i + 1) + 1);
WndWriteStr(col + i, row, Attr, buf + i);
WndPrintf(col + strlen(buf), row, Attr | F_ALTERNATE,
"%c", fill);
TTEndOutput();
}
break;
case Key_End:
i = strlen(buf);
break;
case Key_Home:
i = 0;
break;
case Key_Ent:
done = 1;
break;
case Key_Esc:
done = 2;
break;
default:
if (ch > 0 && ch < 256 && i < len && strlen(buf) < len)
{
TTBeginOutput();
if (nokeys)
{
strcpy(buf, "");
WndFillField(col, row, len + 1, fill,
Attr | F_ALTERNATE);
i = 0;
WndGotoXY(i + col, row);
}
if (i < strlen(buf))
{
memmove(buf + i + 1, buf + i, strlen(buf + i) + 1);
*(buf + i) = (char)ch;
WndWriteStr(col + i, row, Attr, buf + i);
i++;
}
else
{
*(buf + i) = (char)ch;
*(buf + i + 1) = '\0';
WndPutc((unsigned char)ch, Attr);
i++;
}
TTEndOutput();
}
else
{
done = 1;
}
break;
}
break;
}
nokeys = 0;
}
TTCurSet(0);
if (ev != NULL)
{
*ev = event;
}
*pos = i;
return (int)ch;
}
syntax highlighted by Code2HTML, v. 0.9.1