Updated italian translation
[midnight-commander.git] / src / color.c
blobe91d400ccdddb9ec970d996ae86f0d1a33adbd12
1 /* Color setup
2 Copyright (C) 1994 Miguel de Icaza.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 #include <config.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include "global.h"
22 #include "tty.h"
23 #include "setup.h" /* For the externs */
24 #include "color.h"
26 /* Set to force black and white display at program startup */
27 int disable_colors = 0;
29 /* Set if we are actually using colors */
30 int use_colors = 0;
32 /* Color styles for normal and error dialogs */
33 int dialog_colors [4];
34 int alarm_colors [4];
36 #define ELEMENTS(arr) ( sizeof(arr) / sizeof((arr)[0]) )
38 #ifdef HAVE_SLANG
39 # define color_map_fg(n) color_map[n].fg
40 # define color_map_bg(n) color_map[n].bg
41 #else
42 # define color_map_fg(n) (color_map[n].fg & COLOR_WHITE)
43 # define color_map_bg(n) (color_map[n].bg & COLOR_WHITE)
44 #endif
46 struct colorpair {
47 char *name; /* Name of the entry */
48 CTYPE fg; /* foreground color */
49 CTYPE bg; /* background color */
52 static struct colorpair color_map [] = {
53 { "normal=", 0, 0 }, /* normal */ /* 1 */
54 { "selected=", 0, 0 }, /* selected */
55 { "marked=", 0, 0 }, /* marked */
56 { "markselect=", 0, 0 }, /* marked/selected */
57 { "errors=", 0, 0 }, /* errors */
58 { "menu=", 0, 0 }, /* menu entry */
59 { "reverse=", 0, 0 }, /* reverse */
61 /* Dialog colors */
62 { "dnormal=", 0, 0 }, /* Dialog normal */ /* 8 */
63 { "dfocus=", 0, 0 }, /* Dialog focused */
64 { "dhotnormal=", 0, 0 }, /* Dialog normal/hot */
65 { "dhotfocus=", 0, 0 }, /* Dialog focused/hot */
67 { "viewunderline=", 0, 0 }, /* _\b? sequence in view, underline in editor */
68 { "menusel=", 0, 0 }, /* Menu selected color */ /* 13 */
69 { "menuhot=", 0, 0 }, /* Color for menu hotkeys */
70 { "menuhotsel=", 0, 0 }, /* Menu hotkeys/selected entry */
72 { "helpnormal=", 0, 0 }, /* Help normal */ /* 16 */
73 { "helpitalic=", 0, 0 }, /* Italic in help */
74 { "helpbold=", 0, 0 }, /* Bold in help */
75 { "helplink=", 0, 0 }, /* Not selected hyperlink */
76 { "helpslink=", 0, 0 }, /* Selected hyperlink */
78 { "gauge=", 0, 0 }, /* Color of the progress bar (percentage) *//* 21 */
79 { "input=", 0, 0 },
81 /* Per file types colors */
82 { "directory=", 0, 0 }, /* 23 */
83 { "executable=", 0, 0 },
84 { "link=", 0, 0 }, /* symbolic link (neither stale nor link to directory) */
85 { "stalelink=", 0, 0 }, /* stale symbolic link */
86 { "device=", 0, 0 },
87 { "special=", 0, 0 }, /* sockets, fifo */
88 { "core=", 0, 0 }, /* core files */ /* 29 */
90 { 0, 0, 0 }, /* not usable (DEFAULT_COLOR_INDEX) *//* 30 */
91 { 0, 0, 0 }, /* unused */
92 { 0, 0, 0 }, /* not usable (A_REVERSE) */
93 { 0, 0, 0 }, /* not usable (A_REVERSE_BOLD) */
95 /* editor colors start at 34 */
96 { "editnormal=", 0, 0 }, /* normal */ /* 34 */
97 { "editbold=", 0, 0 }, /* search->found */
98 { "editmarked=", 0, 0 }, /* marked/selected */
101 struct color_table_s {
102 char *name;
103 int value;
107 static struct color_table_s const color_table [] = {
108 { "black", COLOR_BLACK },
109 { "gray", COLOR_BLACK | A_BOLD },
110 { "red", COLOR_RED },
111 { "brightred", COLOR_RED | A_BOLD },
112 { "green", COLOR_GREEN },
113 { "brightgreen", COLOR_GREEN | A_BOLD },
114 { "brown", COLOR_YELLOW },
115 { "yellow", COLOR_YELLOW | A_BOLD },
116 { "blue", COLOR_BLUE },
117 { "brightblue", COLOR_BLUE | A_BOLD },
118 { "magenta", COLOR_MAGENTA },
119 { "brightmagenta", COLOR_MAGENTA | A_BOLD },
120 { "cyan", COLOR_CYAN },
121 { "brightcyan", COLOR_CYAN | A_BOLD },
122 { "lightgray", COLOR_WHITE },
123 { "white", COLOR_WHITE | A_BOLD },
124 { "default", 0 } /* default color of the terminal */
127 static char *default_colors =
128 "normal=lightgray,blue:"
129 "selected=black,cyan:"
130 "marked=yellow,blue:"
131 "markselect=yellow,cyan:"
132 "errors=white,red:"
133 "menu=white,cyan:"
134 "reverse=black,lightgray:"
135 "dnormal=black,lightgray:"
136 "dfocus=black,cyan:"
137 "dhotnormal=blue,lightgray:"
138 "dhotfocus=blue,cyan:"
139 "viewunderline=brightred,blue:"
140 "menuhot=yellow,cyan:"
141 "menusel=white,black:"
142 "menuhotsel=yellow,black:"
143 "helpnormal=black,lightgray:"
144 "helpitalic=red,lightgray:"
145 "helpbold=blue,lightgray:"
146 "helplink=black,cyan:"
147 "helpslink=yellow,blue:"
148 "gauge=white,black:"
149 "input=black,cyan:"
150 "directory=white,blue:"
151 "executable=brightgreen,blue:"
152 "link=lightgray,blue:"
153 "stalelink=brightred,blue:"
154 "device=brightmagenta,blue:"
155 "core=red,blue:"
156 "special=black,blue:"
157 "editnormal=lightgray,blue:"
158 "editbold=yellow,blue:"
159 "editmarked=black,cyan";
161 #ifdef HAVE_SLANG
162 # define color_value(i) color_table [i].name
163 # define color_name(i) color_table [i].name
164 #else
165 # define color_value(i) color_table [i].value
166 # define color_name(i) color_table [i].name
167 #endif
169 static void get_color (char *cpp, CTYPE *colp)
171 int i;
173 for (i = 0; i < ELEMENTS(color_table); i++){
174 if (strcmp (cpp, color_name (i)) == 0){
175 *colp = color_value (i);
176 return;
181 static void get_two_colors (char **cpp, struct colorpair *colorpairp)
183 char *p = *cpp;
184 int state;
186 state = 0;
188 for (; *p; p++){
189 if (*p == ':'){
190 *p = 0;
191 get_color (*cpp, state ? &colorpairp->bg : &colorpairp->fg);
192 *p = ':';
193 *cpp = p + 1;
194 return;
197 if (*p == ','){
198 state = 1;
199 *p = 0;
200 get_color (*cpp, &colorpairp->fg);
201 *p = ',';
202 *cpp = p + 1;
205 get_color (*cpp, state ? &colorpairp->bg : &colorpairp->fg);
208 static void configure_colors_string (char *the_color_string)
210 char *color_string, *p;
211 int i, found;
213 if (!the_color_string)
214 return;
216 p = color_string = g_strdup (the_color_string);
217 while (color_string && *color_string){
218 while (*color_string == ' ' || *color_string == '\t')
219 color_string++;
221 found = 0;
222 for (i = 0; i < ELEMENTS(color_map); i++){
223 int klen;
225 if (!color_map [i].name)
226 continue;
227 klen = strlen (color_map [i].name);
229 if (strncmp (color_string, color_map [i].name, klen) == 0){
230 color_string += klen;
231 get_two_colors (&color_string, &color_map [i]);
232 found = 1;
235 if (!found){
236 while (*color_string && *color_string != ':')
237 color_string++;
238 if (*color_string)
239 color_string++;
242 g_free (p);
245 static void configure_colors (void)
247 extern char *command_line_colors;
249 configure_colors_string (default_colors);
250 configure_colors_string (setup_color_string);
251 configure_colors_string (term_color_string);
252 configure_colors_string (getenv ("MC_COLOR_TABLE"));
253 configure_colors_string (command_line_colors);
256 #ifndef HAVE_SLANG
257 #define MAX_PAIRS 64
258 int attr_pairs [MAX_PAIRS];
259 #endif
261 static void
262 load_dialog_colors (void)
264 dialog_colors [0] = COLOR_NORMAL;
265 dialog_colors [1] = COLOR_FOCUS;
266 dialog_colors [2] = COLOR_HOT_NORMAL;
267 dialog_colors [3] = COLOR_HOT_FOCUS;
269 alarm_colors [0] = ERROR_COLOR;
270 alarm_colors [1] = REVERSE_COLOR;
271 alarm_colors [2] = ERROR_COLOR;
272 alarm_colors [3] = COLOR_HOT_NORMAL;
275 void init_colors (void)
277 int i;
279 int hascolors;
281 /* FIXME: if S-Lang is used, this function must be called regardless
282 of whether we are interested in its result */
283 hascolors = has_colors ();
285 if (!disable_colors && hascolors){
286 use_colors = 1;
289 if (use_colors){
290 start_color ();
291 configure_colors ();
293 #ifndef HAVE_SLANG
294 if (ELEMENTS (color_map) > MAX_PAIRS){
295 /* This message should only be seen by the developers */
296 fprintf (stderr,
297 "Too many defined colors, resize MAX_PAIRS on color.c");
298 exit (1);
300 #endif /* !HAVE_SLANG */
302 if (use_colors) {
303 #ifdef HAVE_SLANG
305 * We are relying on undocumented feature of
306 * S-Lang to make COLOR_PAIR(DEFAULT_COLOR_INDEX)
307 * the default fg/bg of the terminal.
308 * Hopefully, future versions of S-Lang will
309 * document this feature.
311 SLtt_set_color (DEFAULT_COLOR_INDEX, NULL, "default", "default");
312 #else
313 /* Always white on black */
314 mc_init_pair(DEFAULT_COLOR_INDEX, COLOR_WHITE, COLOR_BLACK);
315 #endif /* !HAVE_SLANG */
318 for (i = 0; i < ELEMENTS (color_map); i++){
319 if (!color_map [i].name)
320 continue;
322 mc_init_pair (i+1, color_map_fg(i), color_map_bg(i));
324 #ifndef HAVE_SLANG
326 * ncurses doesn't remember bold attribute in the color pairs,
327 * so we should keep track of it in a separate array.
329 attr_pairs [i+1] = color_map [i].fg & A_BOLD;
330 #endif /* !HAVE_SLANG */
333 load_dialog_colors ();
336 /* Functions necessary to implement syntax highlighting */
338 static int max_index = 0;
340 static int
341 alloc_color_pair (CTYPE foreground, CTYPE background)
343 mc_init_pair (++max_index, foreground, background);
344 return max_index;
347 static struct colors_avail {
348 struct colors_avail *next;
349 char *fg, *bg;
350 int index;
351 } c = { 0, 0, 0, 0 };
353 #ifdef HAVE_SLANG
354 void
355 mc_init_pair (int index, CTYPE foreground, CTYPE background)
357 if (!background)
358 background = "default";
360 if (!foreground)
361 foreground = "default";
363 SLtt_set_color (index, "", foreground, background);
364 if (index > max_index)
365 max_index = index;
369 try_alloc_color_pair (char *fg, char *bg)
371 struct colors_avail *p = &c;
373 c.index = EDITOR_NORMAL_COLOR_INDEX;
374 for (;;) {
375 if (((fg && p->fg) ? !strcmp (fg, p->fg) : fg == p->fg) != 0
376 && ((bg && p->bg) ? !strcmp (bg, p->bg) : bg == p->bg) != 0)
377 return p->index;
378 if (!p->next)
379 break;
380 p = p->next;
382 p->next = g_new (struct colors_avail, 1);
383 p = p->next;
384 p->next = 0;
385 p->fg = fg ? g_strdup (fg) : 0;
386 p->bg = bg ? g_strdup (bg) : 0;
387 if (!fg)
388 /* Index in color_map array = COLOR_INDEX - 1 */
389 fg = color_map[EDITOR_NORMAL_COLOR_INDEX - 1].fg;
390 if (!bg)
391 bg = color_map[EDITOR_NORMAL_COLOR_INDEX - 1].bg;
392 p->index = alloc_color_pair (fg, bg);
393 return p->index;
396 #else /* !HAVE_SLANG */
397 void
398 mc_init_pair (int index, CTYPE foreground, CTYPE background)
400 init_pair (index, foreground, background);
401 if (index > max_index)
402 max_index = index;
406 try_alloc_color_pair (char *fg, char *bg)
408 int fg_index, bg_index;
409 int bold_attr;
410 struct colors_avail *p = &c;
412 c.index = EDITOR_NORMAL_COLOR_INDEX;
413 for (;;) {
414 if (((fg && p->fg) ? !strcmp (fg, p->fg) : fg == p->fg) != 0
415 && ((bg && p->bg) ? !strcmp (bg, p->bg) : bg == p->bg) != 0)
416 return p->index;
417 if (!p->next)
418 break;
419 p = p->next;
421 p->next = g_new (struct colors_avail, 1);
422 p = p->next;
423 p->next = 0;
424 p->fg = fg ? g_strdup (fg) : 0;
425 p->bg = bg ? g_strdup (bg) : 0;
426 if (!fg)
427 /* Index in color_map array = COLOR_INDEX - 1 */
428 fg_index = color_map[EDITOR_NORMAL_COLOR_INDEX - 1].fg;
429 else
430 get_color (fg, &fg_index);
432 if (!bg)
433 bg_index = color_map[EDITOR_NORMAL_COLOR_INDEX - 1].bg;
434 else
435 get_color (bg, &bg_index);
437 bold_attr = fg_index & A_BOLD;
438 fg_index = fg_index & COLOR_WHITE;
439 bg_index = bg_index & COLOR_WHITE;
441 p->index = alloc_color_pair (fg_index, bg_index);
442 attr_pairs [p->index] = bold_attr;
443 return p->index;
445 #endif /* !HAVE_SLANG */
447 void
448 done_colors (void)
450 struct colors_avail *p, *next;
452 for (p = c.next; p; p = next) {
453 next = p->next;
454 if (p->fg)
455 g_free (p->fg);
456 if (p->bg)
457 g_free (p->bg);
458 g_free (p);
460 c.next = NULL;