#include "pdcwin.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
#define USE_UNICODE_ACS_CHARS 1
#include "acs_defs.h"
static const unsigned short starting_ascii_to_unicode[32] = {
0,
0x263a,
0x263b,
0x2665,
0x2666,
0x2663,
0x2660,
0x2024,
0x25d8,
0x25bc,
0x25d9,
0x2642,
0x2640,
0x266a,
0x266c,
0x263c,
0x25b6,
0x25c0,
0x2195,
0x203c,
0x00b6,
0xa7,
0x2582,
0x280d,
0x2191,
0x2193,
0x2192,
0x2190,
0x2319,
0x280c,
0x25b2,
0x25bc};
#define N_CURSORS 9
static void redraw_cursor_from_index( const HDC hdc, const int idx)
{
const char *shapes[N_CURSORS] = {
"",
"08-488",
"0088",
"0088;0+10+18-18-1",
"28-368;4-10+34+18-3;2060+3",
"0488",
"2266",
"0385;3053;3558",
"0088;0+10+48-18-4" };
const char *sptr = shapes[idx];
LONG left, top;
extern int PDC_cxChar, PDC_cyChar;
left = SP->curscol * PDC_cxChar;
top = SP->cursrow * PDC_cyChar;
while( *sptr)
{
int i;
LONG coords[4];
RECT rect;
for( i = 0; i < 4; i++)
{
coords[i] = (( i & 1) ?
top + (PDC_cyChar * (*sptr - '0') + 4) / 8 :
left + (PDC_cxChar * (*sptr - '0') + 4) / 8);
sptr++;
if( *sptr == '+' || *sptr == '-')
{
if( *sptr == '+')
coords[i] += sptr[1] - '0';
else
coords[i] -= sptr[1] - '0';
sptr += 2;
}
}
rect.left = coords[0];
rect.top = coords[1];
rect.right = coords[2];
rect.bottom = coords[3];
InvertRect( hdc, &rect);
if( *sptr == ';')
sptr++;
}
}
static int PDC_current_cursor_state( void)
{
extern int PDC_blink_state;
extern HWND PDC_hWnd;
const int shift_amount = (PDC_blink_state ? 0 : 8);
const int cursor_style_for_unfocussed_window =
PDC_CURSOR( PDC_CURSOR_OUTLINE, PDC_CURSOR_OUTLINE);
int cursor_style;
if( SP->visibility && (PDC_hWnd != GetForegroundWindow( )))
cursor_style = cursor_style_for_unfocussed_window;
else
cursor_style = SP->visibility;
return( (cursor_style >> shift_amount) & 0xff);
}
static void redraw_cursor( const HDC hdc)
{
const int cursor_style = PDC_current_cursor_state( );
if( cursor_style > 0 && cursor_style < N_CURSORS)
redraw_cursor_from_index( hdc, cursor_style);
}
void PDC_gotoyx(int row, int col)
{
PDC_LOG(("PDC_gotoyx() - called: row %d col %d from row %d col %d\n",
row, col, SP->cursrow, SP->curscol));
if( SP->cursrow >= 0 && SP->curscol >= 0 &&
SP->cursrow < SP->lines && SP->curscol < SP->cols)
{
const int temp_visibility = SP->visibility;
SP->visibility = 0;
PDC_transform_line( SP->cursrow, SP->curscol, 1,
curscr->_y[SP->cursrow] + SP->curscol);
SP->visibility = temp_visibility;
}
if( SP->visibility)
{
extern HWND PDC_hWnd;
HDC hdc = GetDC( PDC_hWnd) ;
SP->curscol = col;
SP->cursrow = row;
redraw_cursor( hdc);
ReleaseDC( PDC_hWnd, hdc) ;
}
}
int PDC_font_size = 12;
TCHAR PDC_font_name[80];
static LOGFONT PDC_get_logical_font( const int font_idx)
{
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
lf.lfHeight = -PDC_font_size;
#ifdef PDC_WIDE
if( !*PDC_font_name)
wcscpy( PDC_font_name, _T("Courier New"));
if( font_idx & 4)
wcscpy( lf.lfFaceName, _T("Unifont"));
else
wcscpy( lf.lfFaceName, PDC_font_name );
#else
if( !*PDC_font_name)
strcpy( PDC_font_name, "Courier New");
if( font_idx & 4)
strcpy( lf.lfFaceName, "Unifont");
else
strcpy( lf.lfFaceName, PDC_font_name);
#endif
lf.lfPitchAndFamily = FF_MODERN;
lf.lfWeight = ((font_idx & 1) ? FW_EXTRABOLD : FW_NORMAL);
lf.lfItalic = ((font_idx & 2) ? TRUE : FALSE);
lf.lfCharSet = ANSI_CHARSET;
lf.lfQuality = PROOF_QUALITY;
lf.lfOutPrecision = OUT_RASTER_PRECIS;
return( lf);
}
HFONT PDC_get_font_handle( const int font_idx)
{
LOGFONT lf = PDC_get_logical_font( font_idx);
return( CreateFontIndirect( &lf));
}
int debug_printf( const char *format, ...);
int PDC_choose_a_new_font( void)
{
LOGFONT lf = PDC_get_logical_font( 0);
CHOOSEFONT cf;
int rval;
extern HWND PDC_hWnd;
lf.lfHeight = -PDC_font_size;
debug_printf( "In PDC_choose_a_new_font: %d\n", lf.lfHeight);
memset( &cf, 0, sizeof( CHOOSEFONT));
cf.lStructSize = sizeof( CHOOSEFONT);
cf.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
cf.hwndOwner = PDC_hWnd;
cf.lpLogFont = &lf;
cf.rgbColors = RGB( 0, 0, 0);
rval = ChooseFont( &cf);
if( rval)
#ifdef PDC_WIDE
wcscpy( PDC_font_name, lf.lfFaceName);
#else
strcpy( PDC_font_name, lf.lfFaceName);
#endif
debug_printf( "rval %d; %ld\n", rval, CommDlgExtendedError( ));
debug_printf( "output size: %d\n", lf.lfHeight);
PDC_font_size = -lf.lfHeight;
return( rval);
}
static COLORREF intensified_color( COLORREF ival)
{
int rgb, i;
COLORREF oval = 0;
for( i = 0; i < 3; i++, ival >>= 8)
{
rgb = (int)( ival & 0xff);
if( rgb >= 192)
rgb = 255;
else
rgb = 85 + rgb * (255 - 85) / 192;
oval |= ((COLORREF)rgb << (i * 8));
}
return( oval);
}
static COLORREF dimmed_color( COLORREF ival)
{
unsigned i;
COLORREF oval = 0;
for( i = 0; i < 3; i++, ival >>= 8)
{
unsigned rgb = (unsigned)( ival & 0xff);
rgb -= (rgb / 3);
oval |= ((COLORREF)rgb << (i * 8));
}
return( oval);
}
#if defined( CHTYPE_LONG) && CHTYPE_LONG >= 2
#ifdef PDC_WIDE
#define USING_COMBINING_CHARACTER_SCHEME
int PDC_expand_combined_characters( const cchar_t c, cchar_t *added);
#endif
static COLORREF extract_packed_rgb( const chtype color)
{
const int red = (int)( (color << 3) & 0xf8);
const int green = (int)( (color >> 2) & 0xf8);
const int blue = (int)( (color >> 7) & 0xf8);
return( RGB( red, green, blue));
}
#endif
void PDC_get_rgb_values( const chtype srcp,
COLORREF *foreground_rgb, COLORREF *background_rgb)
{
const int color = (int)(( srcp & A_COLOR) >> PDC_COLOR_SHIFT);
bool reverse_colors = ((srcp & A_REVERSE) ? TRUE : FALSE);
bool intensify_backgnd = FALSE;
#if defined( CHTYPE_LONG) && CHTYPE_LONG >= 2
if( srcp & A_RGB_COLOR)
{
*background_rgb = extract_packed_rgb( srcp >> PDC_COLOR_SHIFT);
*foreground_rgb = extract_packed_rgb( srcp >> (PDC_COLOR_SHIFT + 15));
}
else
#endif
{
extern COLORREF *pdc_rgbs;
short foreground_index, background_index;
PDC_pair_content( (short)color, &foreground_index, &background_index);
*foreground_rgb = pdc_rgbs[foreground_index];
*background_rgb = pdc_rgbs[background_index];
}
if( srcp & A_BLINK)
{
extern int PDC_really_blinking;
extern int PDC_blink_state;
if( !PDC_really_blinking)
intensify_backgnd = TRUE;
else if( PDC_blink_state)
reverse_colors = !reverse_colors;
}
if( reverse_colors)
{
const COLORREF temp = *foreground_rgb;
*foreground_rgb = *background_rgb;
*background_rgb = temp;
}
if( srcp & A_BOLD)
*foreground_rgb = intensified_color( *foreground_rgb);
if( intensify_backgnd)
*background_rgb = intensified_color( *background_rgb);
if( srcp & A_DIM)
*foreground_rgb = dimmed_color( *foreground_rgb);
if( srcp & A_DIM)
*background_rgb = dimmed_color( *background_rgb);
}
#ifdef PDC_WIDE
const chtype MAX_UNICODE = 0x110000;
#endif
#ifdef USE_FALLBACK_FONT
GLYPHSET *PDC_unicode_range_data = NULL;
static bool character_is_in_font( chtype ichar)
{
int i;
WCRANGE *wptr = PDC_unicode_range_data->ranges;
if( (ichar & A_ALTCHARSET) && (ichar & A_CHARTEXT) < 0x80)
ichar = acs_map[ichar & 0x7f];
ichar &= A_CHARTEXT;
if( ichar > MAX_UNICODE)
return( FALSE);
if( ichar > 0xffff)
return( TRUE);
for( i = PDC_unicode_range_data->cRanges; i; i--, wptr++)
if( wptr->wcLow > ichar)
return( FALSE);
else if( wptr->wcLow + wptr->cGlyphs > ichar)
return( TRUE);
return( FALSE);
}
#endif
#define N_CACHED_FONTS 8
static HFONT hFonts[N_CACHED_FONTS];
#define BUFFSIZE 50
int PDC_find_ends_of_selected_text( const int line,
const RECT *rect, int *x);
void PDC_transform_line_given_hdc( const HDC hdc, const int lineno,
int x, int len, const chtype *srcp)
{
HFONT hOldFont = (HFONT)0;
extern int PDC_cxChar, PDC_cyChar;
int i, curr_color = -1;
attr_t font_attrib = (attr_t)-1;
int cursor_overwritten = FALSE;
COLORREF foreground_rgb = 0;
chtype prev_ch = 0;
extern RECT PDC_mouse_rect;
int selection[2];
if( !srcp)
{
for( i = 0; i < N_CACHED_FONTS; i++)
if( hFonts[i])
{
DeleteObject( hFonts[i]);
hFonts[i] = NULL;
}
#ifdef USE_FALLBACK_FONT
if( PDC_unicode_range_data)
{
free( PDC_unicode_range_data);
PDC_unicode_range_data = NULL;
}
#endif
return;
}
if( x < 0)
{
len += x;
srcp -= x;
x = 0;
}
len++;
if( len > SP->cols - x)
len = SP->cols - x;
if( lineno >= SP->lines || len <= 0 || lineno < 0)
return;
if( x)
{
x--;
len++;
srcp--;
}
if( lineno == SP->cursrow && SP->curscol >= x && SP->curscol < x + len)
if( PDC_current_cursor_state( ))
cursor_overwritten = TRUE;
while( len)
{
extern int PDC_really_blinking;
const attr_t attrib = (attr_t)( *srcp >> PDC_REAL_ATTR_SHIFT);
const int color = (int)(( *srcp & A_COLOR) >> PDC_COLOR_SHIFT);
attr_t new_font_attrib = (*srcp & (A_BOLD | A_ITALIC));
RECT clip_rect;
wchar_t buff[BUFFSIZE];
int lpDx[BUFFSIZE + 1];
int olen = 0;
#ifdef USE_FALLBACK_FONT
const bool in_font = character_is_in_font( *srcp);
#endif
for( i = 0; i < len && olen < BUFFSIZE - 1
#ifdef USE_FALLBACK_FONT
&& (in_font == character_is_in_font( srcp[i])
|| (srcp[i] & A_CHARTEXT) == MAX_UNICODE)
#endif
&& attrib == (attr_t)( srcp[i] >> PDC_REAL_ATTR_SHIFT); i++)
{
chtype ch = srcp[i] & A_CHARTEXT;
#if( defined( PDC_WIDE) && defined( CHTYPE_LONG))
if( ch > 0xffff && ch < MAX_UNICODE)
{
ch -= 0x10000;
buff[olen] = (wchar_t)( 0xd800 | (ch >> 10));
lpDx[olen] = 0;
olen++;
ch = (wchar_t)( 0xdc00 | (ch & 0x3ff));
}
#if( CHTYPE_LONG >= 2)
if( ch > MAX_UNICODE)
{
cchar_t added[10], root = ch;
int n_combined = 0;
while( (root = PDC_expand_combined_characters( root,
&added[n_combined])) > MAX_UNICODE)
{
n_combined++;
}
buff[olen] = (wchar_t)root;
lpDx[olen] = 0;
olen++;
ch = (wchar_t)added[n_combined];
while( n_combined)
{
n_combined--;
buff[olen] = (wchar_t)added[n_combined];
lpDx[olen] = 0;
olen++;
}
}
#endif
#endif
if( (srcp[i] & A_ALTCHARSET) && ch < 0x80)
ch = acs_map[ch & 0x7f];
else if( ch < 32)
ch = starting_ascii_to_unicode[ch];
#ifndef PDC_WIDE
else if( ch <= 0xff)
{
char c = (char)ch;
wchar_t z;
mbtowc( &z, &c, 1);
ch = (chtype)z;
}
assert( "We should never get here");
#endif
buff[olen] = (wchar_t)ch;
lpDx[olen] = PDC_cxChar;
#ifdef PDC_WIDE
if( ch != MAX_UNICODE)
olen++;
else if( olen)
lpDx[olen - 1] = 2 * PDC_cxChar;
#else
olen++;
#endif
}
lpDx[olen] = PDC_cxChar;
if( color != curr_color || ((prev_ch ^ *srcp) & (A_REVERSE | A_BLINK | A_BOLD | A_DIM)))
{
COLORREF background_rgb;
PDC_get_rgb_values( *srcp, &foreground_rgb, &background_rgb);
curr_color = color;
SetTextColor( hdc, foreground_rgb);
SetBkColor( hdc, background_rgb);
}
if( !PDC_really_blinking && (*srcp & A_BLINK))
new_font_attrib &= ~A_BLINK;
#ifdef USE_FALLBACK_FONT
if( !in_font)
new_font_attrib |= 1;
#endif
if( new_font_attrib != font_attrib)
{
HFONT hFont;
int idx = 0;
font_attrib = new_font_attrib;
if( font_attrib & A_BOLD)
idx |= 1;
if( font_attrib & A_ITALIC)
idx |= 2;
if( font_attrib & 1)
idx |= 4;
if( !hFonts[idx])
hFonts[idx] = PDC_get_font_handle( idx);
hFont = SelectObject( hdc, hFonts[idx]);
if( !hOldFont)
hOldFont = hFont;
}
prev_ch = *srcp;
clip_rect.left = x * PDC_cxChar;
clip_rect.top = lineno * PDC_cyChar;
clip_rect.right = clip_rect.left + i * PDC_cxChar;
clip_rect.bottom = clip_rect.top + PDC_cyChar;
ExtTextOutW( hdc, clip_rect.left, clip_rect.top,
ETO_CLIPPED | ETO_OPAQUE, &clip_rect,
buff, olen, (olen > 1 ? lpDx : NULL));
#ifdef A_OVERLINE
if( *srcp & (A_UNDERLINE | A_RIGHTLINE | A_LEFTLINE | A_OVERLINE | A_STRIKEOUT))
#else
if( *srcp & (A_UNDERLINE | A_RIGHTLINE | A_LEFTLINE))
#endif
{
const int y1 = clip_rect.top;
const int y2 = clip_rect.bottom - 1;
const int x1 = clip_rect.left;
const int x2 = clip_rect.right;
int j;
extern COLORREF *pdc_rgbs;
const HPEN pen = CreatePen( PS_SOLID, 1, (SP->line_color == -1 ?
foreground_rgb : pdc_rgbs[SP->line_color]));
const HPEN old_pen = SelectObject( hdc, pen);
if( *srcp & A_UNDERLINE)
{
MoveToEx( hdc, x1, y2, NULL);
LineTo( hdc, x2, y2);
}
#ifdef A_OVERLINE
if( *srcp & A_OVERLINE)
{
MoveToEx( hdc, x1, y1, NULL);
LineTo( hdc, x2, y1);
}
if( *srcp & A_STRIKEOUT)
{
MoveToEx( hdc, x1, (y1 + y2) / 2, NULL);
LineTo( hdc, x2, (y1 + y2) / 2);
}
#endif
if( *srcp & A_RIGHTLINE)
for( j = 0; j < i; j++)
{
MoveToEx( hdc, x2 - j * PDC_cxChar - 1, y1, NULL);
LineTo( hdc, x2 - j * PDC_cxChar - 1, y2);
}
if( *srcp & A_LEFTLINE)
for( j = 0; j < i; j++)
{
MoveToEx( hdc, x1 + j * PDC_cxChar, y1, NULL);
LineTo( hdc, x1 + j * PDC_cxChar, y2);
}
SelectObject( hdc, old_pen);
DeleteObject( pen);
}
if( PDC_find_ends_of_selected_text( lineno, &PDC_mouse_rect, selection))
if( x <= selection[1] + 1 && x + i >= selection[0])
{
RECT rect;
rect.top = lineno * PDC_cyChar;
rect.bottom = rect.top + PDC_cyChar;
rect.right = max( x, selection[0]);
rect.left = min( x + i, selection[1] + 1);
rect.right *= PDC_cxChar;
rect.left *= PDC_cxChar;
InvertRect( hdc, &rect);
}
len -= i;
x += i;
srcp += i;
}
SelectObject( hdc, hOldFont);
if( cursor_overwritten)
redraw_cursor( hdc);
}
void PDC_transform_line(int lineno, int x, int len, const chtype *srcp)
{
if( !srcp)
PDC_transform_line_given_hdc( 0, 0, 0, 0, NULL);
else
{
extern HWND PDC_hWnd;
const HDC hdc = GetDC( PDC_hWnd) ;
PDC_transform_line_given_hdc( hdc, lineno, x, len, srcp);
ReleaseDC( PDC_hWnd, hdc);
}
}