You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
220 lines
6.2 KiB
C
220 lines
6.2 KiB
C
/* PDCurses */
|
|
|
|
/* Palette management code used by VT, WinGUI, SDL1/2, and X11 for
|
|
'full color' (24-bit). It may eventually be used by DOSVGA, WinCon,
|
|
and/or the Plan9 platform, all of which have full color capability.
|
|
It will presumably never be useful for the DOS or OS/2 platforms.
|
|
See 'pdccolor.txt' for a rationale of how this works. */
|
|
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
|
|
#define PACKED_RGB uint32_t
|
|
|
|
#ifndef PACK_RGB
|
|
#define PACK_RGB( red, green, blue) ((red) | ((green)<<8) | ((PACKED_RGB)(blue) << 16))
|
|
#endif
|
|
|
|
#include <curspriv.h>
|
|
#include "pdccolor.h"
|
|
|
|
int PDC_blink_state = 0;
|
|
|
|
static PACKED_RGB *rgbs; /* the 'standard' 256-color palette, plus any allocated */
|
|
static int _palette_size;
|
|
|
|
PACKED_RGB PDC_default_color( int idx)
|
|
{
|
|
PACKED_RGB rval;
|
|
|
|
assert( idx >= 0);
|
|
if( idx < 16)
|
|
{
|
|
if( idx == 8)
|
|
rval = PACK_RGB( 0x80, 0x80, 0x80);
|
|
else
|
|
{
|
|
const int intensity = ((idx & 8) ? 0xff : 0xc0);
|
|
|
|
rval = PACK_RGB( ((idx & COLOR_RED) ? intensity : 0),
|
|
((idx & COLOR_GREEN) ? intensity : 0),
|
|
((idx & COLOR_BLUE) ? intensity : 0));
|
|
}
|
|
}
|
|
else if( idx < 216 + 16)
|
|
{ /* colors 16-231 are a 6x6x6 color cube */
|
|
int r, g, b;
|
|
|
|
idx -= 16;
|
|
r = idx / 36;
|
|
g = (idx / 6) % 6;
|
|
b = idx % 6;
|
|
rval = PACK_RGB( r ? r * 40 + 55 : 0,
|
|
g ? g * 40 + 55 : 0,
|
|
b ? b * 40 + 55 : 0);
|
|
}
|
|
else if( idx < 256) /* colors 232-255 are 24 shades of gray */
|
|
{
|
|
const int intensity = (idx - 232) * 10 + 8;
|
|
|
|
rval = PACK_RGB( intensity, intensity, intensity);
|
|
}
|
|
else /* colors 256 to 256+2^24 are RGB values */
|
|
rval = idx - 256;
|
|
return( rval);
|
|
}
|
|
|
|
int PDC_init_palette( void)
|
|
{
|
|
return( 0);
|
|
}
|
|
|
|
void PDC_free_palette( void)
|
|
{
|
|
if( rgbs)
|
|
free( rgbs);
|
|
rgbs = NULL;
|
|
}
|
|
|
|
PACKED_RGB PDC_get_palette_entry( const int idx)
|
|
{
|
|
PACKED_RGB rval;
|
|
|
|
if( idx < _palette_size)
|
|
{
|
|
assert( idx >= 0);
|
|
rval = rgbs[idx];
|
|
}
|
|
else
|
|
rval = PDC_default_color( idx);
|
|
return( rval);
|
|
}
|
|
|
|
/* Return value is -1 if no palette could be allocated, 0 if the color
|
|
didn't change (new RGB matched the old one), and 1 if the color changed. */
|
|
|
|
int PDC_set_palette_entry( const int idx, const PACKED_RGB rgb)
|
|
{
|
|
int rval, i;
|
|
|
|
if( idx >= _palette_size)
|
|
{
|
|
int new_size = _palette_size;
|
|
const int initial_palette_size = 8;
|
|
|
|
if( !new_size)
|
|
new_size = initial_palette_size;
|
|
while( new_size <= idx)
|
|
new_size *= 2;
|
|
rgbs = (PACKED_RGB *)realloc( rgbs, new_size * sizeof( PACKED_RGB));
|
|
assert( rgbs);
|
|
if( !rgbs)
|
|
return( -1);
|
|
for( i = _palette_size; i < new_size; i++)
|
|
rgbs[i] = PDC_default_color( i);
|
|
_palette_size = new_size;
|
|
}
|
|
rval = (rgbs[idx] == rgb ? 1 : 0);
|
|
rgbs[idx] = rgb;
|
|
return( rval);
|
|
}
|
|
|
|
/* This function 'intensifies' a color by shifting it toward white. */
|
|
/* It used to average the input color with white. Then it did a */
|
|
/* weighted average: 2/3 of the input color, 1/3 white, for a */
|
|
/* lower "intensification" level. */
|
|
/* Then Mark Hessling suggested that the output level should */
|
|
/* remap zero to 85 (= 255 / 3, so one-third intensity), and input */
|
|
/* of 192 or greater should be remapped to 255 (full intensity). */
|
|
/* Assuming we want a linear response between zero and 192, that */
|
|
/* leads to output = 85 + input * (255-85)/192. */
|
|
/* This should lead to proper handling of bold text in legacy */
|
|
/* apps, where "bold" means "high intensity". */
|
|
|
|
static PACKED_RGB intensified_color( PACKED_RGB ival)
|
|
{
|
|
int rgb, i;
|
|
PACKED_RGB 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 |= ((PACKED_RGB)rgb << (i * 8));
|
|
}
|
|
return( oval);
|
|
}
|
|
|
|
/* For use in adjusting colors for A_DIMmed characters. Just */
|
|
/* knocks down the intensity of R, G, and B by 1/3. */
|
|
|
|
static PACKED_RGB dimmed_color( PACKED_RGB ival)
|
|
{
|
|
unsigned i;
|
|
PACKED_RGB oval = 0;
|
|
|
|
for( i = 0; i < 3; i++, ival >>= 8)
|
|
{
|
|
unsigned rgb = (unsigned)( ival & 0xff);
|
|
|
|
rgb -= (rgb / 3);
|
|
oval |= ((PACKED_RGB)rgb << (i * 8));
|
|
}
|
|
return( oval);
|
|
}
|
|
|
|
|
|
void PDC_get_rgb_values( const chtype srcp,
|
|
PACKED_RGB *foreground_rgb, PACKED_RGB *background_rgb)
|
|
{
|
|
const int color = (int)(( srcp & A_COLOR) >> PDC_COLOR_SHIFT);
|
|
bool reverse_colors = ((srcp & A_REVERSE) ? TRUE : FALSE);
|
|
bool intensify_backgnd = FALSE;
|
|
bool default_foreground = FALSE, default_background = FALSE;
|
|
int foreground_index, background_index;
|
|
|
|
extended_pair_content( color, &foreground_index, &background_index);
|
|
if( foreground_index < 0 && SP->orig_attr)
|
|
default_foreground = TRUE;
|
|
else
|
|
*foreground_rgb = PDC_get_palette_entry( foreground_index);
|
|
if( background_index < 0 && SP->orig_attr)
|
|
default_background = TRUE;
|
|
else
|
|
*background_rgb = PDC_get_palette_entry( background_index);
|
|
|
|
if( srcp & A_BLINK)
|
|
{
|
|
if( !(SP->termattrs & A_BLINK)) /* convert 'blinking' to 'bold' */
|
|
intensify_backgnd = TRUE;
|
|
else if( PDC_blink_state)
|
|
reverse_colors ^= 1;
|
|
}
|
|
if( default_foreground)
|
|
*foreground_rgb = (PACKED_RGB)-1;
|
|
else if( srcp & A_BOLD & ~SP->termattrs)
|
|
*foreground_rgb = intensified_color( *foreground_rgb);
|
|
|
|
if( default_background)
|
|
*background_rgb = (PACKED_RGB)-1;
|
|
else if( intensify_backgnd)
|
|
*background_rgb = intensified_color( *background_rgb);
|
|
if( srcp & A_DIM)
|
|
{
|
|
if( !default_foreground)
|
|
*foreground_rgb = dimmed_color( *foreground_rgb);
|
|
if( !default_background)
|
|
*background_rgb = dimmed_color( *background_rgb);
|
|
}
|
|
if( reverse_colors)
|
|
{
|
|
const PACKED_RGB temp = *foreground_rgb;
|
|
|
|
*foreground_rgb = *background_rgb;
|
|
*background_rgb = temp;
|
|
}
|
|
}
|