blob: fdaec7682181af6514585b6e35993580e9485a9e [file] [log] [blame]
/* PDCurses */
#include "pdcwin.h"
#include <stdlib.h>
#include <string.h>
#ifdef PDC_WIDE
# include "../common/acsuni.h"
#else
# include "../common/acs437.h"
#endif
DWORD pdc_last_blink;
static bool blinked_off = FALSE;
static bool in_italic = FALSE;
/* position hardware cursor at (y, x) */
void PDC_gotoyx(int row, int col)
{
COORD coord;
PDC_LOG(("PDC_gotoyx() - called: row %d col %d from row %d col %d\n",
row, col, SP->cursrow, SP->curscol));
coord.X = col;
coord.Y = row;
SetConsoleCursorPosition(pdc_con_out, coord);
}
void _set_ansi_color(short f, short b, attr_t attr)
{
char esc[64], *p;
short tmp, underline;
bool italic;
if (f < 16 && !pdc_color[f].mapped)
f = pdc_curstoansi[f];
if (b < 16 && !pdc_color[b].mapped)
b = pdc_curstoansi[b];
if (attr & A_REVERSE)
{
tmp = f;
f = b;
b = tmp;
}
attr &= SP->termattrs;
italic = !!(attr & A_ITALIC);
underline = !!(attr & A_UNDERLINE);
p = esc + sprintf(esc, "\x1b[");
if (f != pdc_oldf)
{
if (f < 8 && !pdc_color[f].mapped)
p += sprintf(p, "%d", f + 30);
else if (f < 16 && !pdc_color[f].mapped)
p += sprintf(p, "%d", f + 82);
else if (f < 256 && !pdc_color[f].mapped)
p += sprintf(p, "38;5;%d", f);
else
{
short red = DIVROUND(pdc_color[f].r * 255, 1000);
short green = DIVROUND(pdc_color[f].g * 255, 1000);
short blue = DIVROUND(pdc_color[f].b * 255, 1000);
p += sprintf(p, "38;2;%d;%d;%d", red, green, blue);
}
pdc_oldf = f;
}
if (b != pdc_oldb)
{
if (strlen(esc) > 2)
p += sprintf(p, ";");
if (b < 8 && !pdc_color[b].mapped)
p += sprintf(p, "%d", b + 40);
else if (b < 16 && !pdc_color[b].mapped)
p += sprintf(p, "%d", b + 92);
else if (b < 256 && !pdc_color[b].mapped)
p += sprintf(p, "48;5;%d", b);
else
{
short red = DIVROUND(pdc_color[b].r * 255, 1000);
short green = DIVROUND(pdc_color[b].g * 255, 1000);
short blue = DIVROUND(pdc_color[b].b * 255, 1000);
p += sprintf(p, "48;2;%d;%d;%d", red, green, blue);
}
pdc_oldb = b;
}
if (italic != in_italic)
{
if (strlen(esc) > 2)
p += sprintf(p, ";");
if (italic)
p += sprintf(p, "3");
else
p += sprintf(p, "23");
in_italic = italic;
}
if (underline != pdc_oldu)
{
if (strlen(esc) > 2)
p += sprintf(p, ";");
if (underline)
p += sprintf(p, "4");
else
p += sprintf(p, "24");
pdc_oldu = underline;
}
if (strlen(esc) > 2)
{
sprintf(p, "m");
if (!pdc_conemu)
SetConsoleMode(pdc_con_out, 0x0015);
WriteConsoleA(pdc_con_out, esc, strlen(esc), NULL, NULL);
if (!pdc_conemu)
SetConsoleMode(pdc_con_out, 0x0010);
}
}
void _new_packet(attr_t attr, int lineno, int x, int len, const chtype *srcp)
{
int j;
short fore, back;
bool blink, ansi;
if (pdc_ansi && (lineno == (SP->lines - 1)) && ((x + len) == SP->cols))
{
len--;
if (len)
_new_packet(attr, lineno, x, len, srcp);
pdc_ansi = FALSE;
_new_packet(attr, lineno, x + len, 1, srcp + len);
pdc_ansi = TRUE;
return;
}
pair_content(PAIR_NUMBER(attr), &fore, &back);
ansi = pdc_ansi || (fore >= 16 || back >= 16);
blink = (SP->termattrs & A_BLINK) && (attr & A_BLINK);
if (blink)
{
attr &= ~A_BLINK;
if (blinked_off)
attr &= ~(A_UNDERLINE | A_RIGHT | A_LEFT);
}
if (attr & A_BOLD)
fore |= 8;
if (attr & A_BLINK)
back |= 8;
if (ansi)
{
#ifdef PDC_WIDE
WCHAR buffer[512];
#else
char buffer[512];
#endif
for (j = 0; j < len; j++)
{
chtype ch = srcp[j];
if (ch & A_ALTCHARSET && !(ch & 0xff80))
{
ch = acs_map[ch & 0x7f];
if (pdc_wt && (ch & A_CHARTEXT) < ' ')
goto NONANSI;
}
if (blink && blinked_off)
ch = ' ';
buffer[j] = ch & A_CHARTEXT;
}
PDC_gotoyx(lineno, x);
_set_ansi_color(fore, back, attr);
#ifdef PDC_WIDE
WriteConsoleW(pdc_con_out, buffer, len, NULL, NULL);
#else
WriteConsoleA(pdc_con_out, buffer, len, NULL, NULL);
#endif
}
else
NONANSI:
{
CHAR_INFO buffer[512];
COORD bufSize, bufPos;
SMALL_RECT sr;
WORD mapped_attr;
fore = pdc_curstoreal[fore];
back = pdc_curstoreal[back];
if (attr & A_REVERSE)
mapped_attr = back | (fore << 4);
else
mapped_attr = fore | (back << 4);
if (attr & A_UNDERLINE)
mapped_attr |= 0x8000; /* COMMON_LVB_UNDERSCORE */
if (attr & A_LEFT)
mapped_attr |= 0x0800; /* COMMON_LVB_GRID_LVERTICAL */
if (attr & A_RIGHT)
mapped_attr |= 0x1000; /* COMMON_LVB_GRID_RVERTICAL */
for (j = 0; j < len; j++)
{
chtype ch = srcp[j];
if (ch & A_ALTCHARSET && !(ch & 0xff80))
ch = acs_map[ch & 0x7f];
if (blink && blinked_off)
ch = ' ';
buffer[j].Attributes = mapped_attr;
buffer[j].Char.UnicodeChar = ch & A_CHARTEXT;
}
bufPos.X = bufPos.Y = 0;
bufSize.X = len;
bufSize.Y = 1;
sr.Top = sr.Bottom = lineno;
sr.Left = x;
sr.Right = x + len - 1;
WriteConsoleOutput(pdc_con_out, buffer, bufSize, bufPos, &sr);
}
}
/* update the given physical line to look like the corresponding line in
curscr */
void PDC_transform_line(int lineno, int x, int len, const chtype *srcp)
{
attr_t old_attr, attr;
int i, j;
PDC_LOG(("PDC_transform_line() - called: lineno=%d\n", lineno));
old_attr = *srcp & (A_ATTRIBUTES ^ A_ALTCHARSET);
for (i = 1, j = 1; j < len; i++, j++)
{
attr = srcp[i] & (A_ATTRIBUTES ^ A_ALTCHARSET);
if (attr != old_attr)
{
_new_packet(old_attr, lineno, x, i, srcp);
old_attr = attr;
srcp += i;
x += i;
i = 0;
}
}
_new_packet(old_attr, lineno, x, i, srcp);
}
void PDC_blink_text(void)
{
CONSOLE_CURSOR_INFO cci;
int i, j, k;
bool oldvis;
GetConsoleCursorInfo(pdc_con_out, &cci);
oldvis = cci.bVisible;
if (oldvis)
{
cci.bVisible = FALSE;
SetConsoleCursorInfo(pdc_con_out, &cci);
}
if (!(SP->termattrs & A_BLINK))
blinked_off = FALSE;
else
blinked_off = !blinked_off;
for (i = 0; i < SP->lines; i++)
{
const chtype *srcp = curscr->_y[i];
for (j = 0; j < SP->cols; j++)
if (srcp[j] & A_BLINK)
{
k = j;
while (k < SP->cols && (srcp[k] & A_BLINK))
k++;
PDC_transform_line(i, j, k - j, srcp + j);
j = k;
}
}
PDC_gotoyx(SP->cursrow, SP->curscol);
if (oldvis)
{
cci.bVisible = TRUE;
SetConsoleCursorInfo(pdc_con_out, &cci);
}
pdc_last_blink = GetTickCount();
}
void PDC_doupdate(void)
{
}