color.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /* PDCurses */
  2. #include <curspriv.h>
  3. /*man-start**************************************************************
  4. color
  5. -----
  6. ### Synopsis
  7. bool has_colors(void);
  8. int start_color(void);
  9. int init_pair(short pair, short fg, short bg);
  10. int pair_content(short pair, short *fg, short *bg);
  11. bool can_change_color(void);
  12. int init_color(short color, short red, short green, short blue);
  13. int color_content(short color, short *red, short *green, short *blue);
  14. int alloc_pair(int fg, int bg);
  15. int assume_default_colors(int f, int b);
  16. int find_pair(int fg, int bg);
  17. int free_pair(int pair);
  18. int use_default_colors(void);
  19. int PDC_set_line_color(short color);
  20. ### Description
  21. To use these routines, first, call start_color(). Colors are always
  22. used in pairs, referred to as color-pairs. A color-pair is created by
  23. init_pair(), and consists of a foreground color and a background
  24. color. After initialization, COLOR_PAIR(n) can be used like any other
  25. video attribute.
  26. has_colors() reports whether the terminal supports color.
  27. start_color() initializes eight basic colors (black, red, green,
  28. yellow, blue, magenta, cyan, and white), and two global variables:
  29. COLORS and COLOR_PAIRS (respectively defining the maximum number of
  30. colors and color-pairs the terminal is capable of displaying).
  31. init_pair() changes the definition of a color-pair. It takes three
  32. arguments: the number of the color-pair to be redefined, and the new
  33. values of the foreground and background colors. The pair number must
  34. be between 0 and COLOR_PAIRS - 1, inclusive. The foreground and
  35. background must be between 0 and COLORS - 1, inclusive. If the color
  36. pair was previously initialized, the screen is refreshed, and all
  37. occurrences of that color-pair are changed to the new definition.
  38. pair_content() is used to determine what the colors of a given color-
  39. pair consist of.
  40. can_change_color() indicates if the terminal has the capability to
  41. change the definition of its colors.
  42. init_color() is used to redefine a color, if possible. Each of the
  43. components -- red, green, and blue -- is specified in a range from 0
  44. to 1000, inclusive.
  45. color_content() reports the current definition of a color in the same
  46. format as used by init_color().
  47. assume_default_colors() and use_default_colors() emulate the ncurses
  48. extensions of the same names. assume_default_colors(f, b) is
  49. essentially the same as init_pair(0, f, b) (which isn't allowed); it
  50. redefines the default colors. use_default_colors() allows the use of
  51. -1 as a foreground or background color with init_pair(), and calls
  52. assume_default_colors(-1, -1); -1 represents the foreground or
  53. background color that the terminal had at startup. If the environment
  54. variable PDC_ORIGINAL_COLORS is set at the time start_color() is
  55. called, that's equivalent to calling use_default_colors().
  56. alloc_pair(), find_pair() and free_pair() are also from ncurses.
  57. free_pair() marks a pair as unused; find_pair() returns an existing
  58. pair with the specified foreground and background colors, if one
  59. exists. And alloc_pair() returns such a pair whether or not it was
  60. previously set, overwriting the oldest initialized pair if there are
  61. no free pairs.
  62. PDC_set_line_color() is used to set the color, globally, for the
  63. color of the lines drawn for the attributes: A_UNDERLINE, A_LEFT and
  64. A_RIGHT. A value of -1 (the default) indicates that the current
  65. foreground color should be used.
  66. NOTE: COLOR_PAIR() and PAIR_NUMBER() are implemented as macros.
  67. ### Return Value
  68. Most functions return OK on success and ERR on error. has_colors()
  69. and can_change_colors() return TRUE or FALSE. alloc_pair() and
  70. find_pair() return a pair number, or -1 on error.
  71. ### Portability
  72. X/Open ncurses NetBSD
  73. has_colors Y Y Y
  74. start_color Y Y Y
  75. init_pair Y Y Y
  76. pair_content Y Y Y
  77. can_change_color Y Y Y
  78. init_color Y Y Y
  79. color_content Y Y Y
  80. alloc_pair - Y -
  81. assume_default_colors - Y Y
  82. find_pair - Y -
  83. free_pair - Y -
  84. use_default_colors - Y Y
  85. PDC_set_line_color - - -
  86. **man-end****************************************************************/
  87. #include <stdlib.h>
  88. #include <string.h>
  89. int COLORS = 0;
  90. int COLOR_PAIRS = PDC_COLOR_PAIRS;
  91. static bool default_colors = FALSE;
  92. static short first_col = 0;
  93. static int allocnum = 0;
  94. int start_color(void)
  95. {
  96. PDC_LOG(("start_color() - called\n"));
  97. if (!SP || SP->mono)
  98. return ERR;
  99. SP->color_started = TRUE;
  100. PDC_set_blink(FALSE); /* Also sets COLORS */
  101. if (!default_colors && SP->orig_attr && getenv("PDC_ORIGINAL_COLORS"))
  102. default_colors = TRUE;
  103. PDC_init_atrtab();
  104. return OK;
  105. }
  106. static void _normalize(short *fg, short *bg)
  107. {
  108. if (*fg == -1)
  109. *fg = SP->orig_attr ? SP->orig_fore : COLOR_WHITE;
  110. if (*bg == -1)
  111. *bg = SP->orig_attr ? SP->orig_back : COLOR_BLACK;
  112. }
  113. static void _init_pair_core(short pair, short fg, short bg)
  114. {
  115. PDC_PAIR *p = SP->atrtab + pair;
  116. _normalize(&fg, &bg);
  117. /* To allow the PDC_PRESERVE_SCREEN option to work, we only reset
  118. curscr if this call to init_pair() alters a color pair created by
  119. the user. */
  120. if (p->set)
  121. {
  122. if (p->f != fg || p->b != bg)
  123. curscr->_clear = TRUE;
  124. }
  125. p->f = fg;
  126. p->b = bg;
  127. p->count = allocnum++;
  128. p->set = TRUE;
  129. }
  130. int init_pair(short pair, short fg, short bg)
  131. {
  132. PDC_LOG(("init_pair() - called: pair %d fg %d bg %d\n", pair, fg, bg));
  133. if (!SP || !SP->color_started || pair < 1 || pair >= COLOR_PAIRS ||
  134. fg < first_col || fg >= COLORS || bg < first_col || bg >= COLORS)
  135. return ERR;
  136. _init_pair_core(pair, fg, bg);
  137. return OK;
  138. }
  139. bool has_colors(void)
  140. {
  141. PDC_LOG(("has_colors() - called\n"));
  142. return SP ? !(SP->mono) : FALSE;
  143. }
  144. int init_color(short color, short red, short green, short blue)
  145. {
  146. PDC_LOG(("init_color() - called\n"));
  147. if (!SP || color < 0 || color >= COLORS || !PDC_can_change_color() ||
  148. red < -1 || red > 1000 || green < -1 || green > 1000 ||
  149. blue < -1 || blue > 1000)
  150. return ERR;
  151. SP->dirty = TRUE;
  152. return PDC_init_color(color, red, green, blue);
  153. }
  154. int color_content(short color, short *red, short *green, short *blue)
  155. {
  156. PDC_LOG(("color_content() - called\n"));
  157. if (color < 0 || color >= COLORS || !red || !green || !blue)
  158. return ERR;
  159. if (PDC_can_change_color())
  160. return PDC_color_content(color, red, green, blue);
  161. else
  162. {
  163. /* Simulated values for platforms that don't support palette
  164. changing */
  165. short maxval = (color & 8) ? 1000 : 680;
  166. *red = (color & COLOR_RED) ? maxval : 0;
  167. *green = (color & COLOR_GREEN) ? maxval : 0;
  168. *blue = (color & COLOR_BLUE) ? maxval : 0;
  169. return OK;
  170. }
  171. }
  172. bool can_change_color(void)
  173. {
  174. PDC_LOG(("can_change_color() - called\n"));
  175. return PDC_can_change_color();
  176. }
  177. int pair_content(short pair, short *fg, short *bg)
  178. {
  179. PDC_LOG(("pair_content() - called\n"));
  180. if (pair < 0 || pair >= COLOR_PAIRS || !fg || !bg)
  181. return ERR;
  182. *fg = SP->atrtab[pair].f;
  183. *bg = SP->atrtab[pair].b;
  184. return OK;
  185. }
  186. int assume_default_colors(int f, int b)
  187. {
  188. PDC_LOG(("assume_default_colors() - called: f %d b %d\n", f, b));
  189. if (f < -1 || f >= COLORS || b < -1 || b >= COLORS)
  190. return ERR;
  191. if (SP->color_started)
  192. _init_pair_core(0, f, b);
  193. return OK;
  194. }
  195. int use_default_colors(void)
  196. {
  197. PDC_LOG(("use_default_colors() - called\n"));
  198. default_colors = TRUE;
  199. first_col = -1;
  200. return assume_default_colors(-1, -1);
  201. }
  202. int PDC_set_line_color(short color)
  203. {
  204. PDC_LOG(("PDC_set_line_color() - called: %d\n", color));
  205. if (!SP || color < -1 || color >= COLORS)
  206. return ERR;
  207. SP->line_color = color;
  208. return OK;
  209. }
  210. void PDC_init_atrtab(void)
  211. {
  212. PDC_PAIR *p = SP->atrtab;
  213. short i, fg, bg;
  214. if (SP->color_started && !default_colors)
  215. {
  216. fg = COLOR_WHITE;
  217. bg = COLOR_BLACK;
  218. }
  219. else
  220. fg = bg = -1;
  221. _normalize(&fg, &bg);
  222. for (i = 0; i < PDC_COLOR_PAIRS; i++)
  223. {
  224. p[i].f = fg;
  225. p[i].b = bg;
  226. p[i].set = FALSE;
  227. }
  228. }
  229. int free_pair(int pair)
  230. {
  231. if (pair < 1 || pair >= PDC_COLOR_PAIRS || !(SP->atrtab[pair].set))
  232. return ERR;
  233. SP->atrtab[pair].set = FALSE;
  234. return OK;
  235. }
  236. int find_pair(int fg, int bg)
  237. {
  238. int i;
  239. PDC_PAIR *p = SP->atrtab;
  240. for (i = 0; i < PDC_COLOR_PAIRS; i++)
  241. if (p[i].set && p[i].f == fg && p[i].b == bg)
  242. return i;
  243. return -1;
  244. }
  245. static int _find_oldest()
  246. {
  247. int i, lowind = 0, lowval = 0;
  248. PDC_PAIR *p = SP->atrtab;
  249. for (i = 1; i < PDC_COLOR_PAIRS; i++)
  250. {
  251. if (!p[i].set)
  252. return i;
  253. if (!lowval || (p[i].count < lowval))
  254. {
  255. lowind = i;
  256. lowval = p[i].count;
  257. }
  258. }
  259. return lowind;
  260. }
  261. int alloc_pair(int fg, int bg)
  262. {
  263. int i = find_pair(fg, bg);
  264. if (-1 == i)
  265. {
  266. i = _find_oldest();
  267. if (ERR == init_pair(i, fg, bg))
  268. return -1;
  269. }
  270. return i;
  271. }