themes.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. #include <config.h>
  2. #include "io.h" // get_cfg_filename
  3. #include "pathnames.h"
  4. #include "widget.h"
  5. #include "themes.h"
  6. #include <errno.h>
  7. #include <map>
  8. #ifdef HAVE_COLOR
  9. #define MISSING_COLOR -600
  10. #define NO_COLOR -601
  11. #define SKIP_COLOR -602
  12. // An ATTR structure describes the attributes (color, etc) of
  13. // a single GUI element.
  14. struct ATTR {
  15. int ident;
  16. char *name; // the name of the GUI element in the theme file
  17. // These two members point to a parent ATTR struct
  18. // from which the foreground & background colors will
  19. // be read if they are missing in the theme file.
  20. int fg_parent;
  21. int bg_parent;
  22. int fg; // holds color number
  23. int bg; // "
  24. int extra; // A_BOLD, A_UNDERLINE, etc...
  25. int pair; // init_pair(fg, bg)
  26. void clear()
  27. {
  28. // clear only the properties that are read from disk,
  29. // not those initialized in this file (because the
  30. // latter are unchangeable).
  31. fg = bg = MISSING_COLOR;
  32. extra = 0;
  33. pair = 0;
  34. }
  35. };
  36. ATTR attr_table[] = {
  37. { MENUBAR_ATTR, "menubar", MENU_ATTR, MENU_ATTR,
  38. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  39. { MENU_ATTR, "menu", MENU_ATTR, MENU_ATTR,
  40. -1, -1, 0, 0 },
  41. { MENU_SELECTED_ATTR, "menu.selected", MENU_ATTR, MENU_ATTR,
  42. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  43. { MENU_FRAME_ATTR, "menu.frame", MENU_ATTR, MENU_ATTR,
  44. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  45. { MENU_LETTER_ATTR, "menu.letter", MENU_ATTR, MENU_ATTR,
  46. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  47. { MENU_LETTER_SELECTED_ATTR, "menu.letter.selected", MENU_LETTER_ATTR, MENU_SELECTED_ATTR,
  48. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  49. { MENU_INDICATOR_ATTR, "menu.indicator", MENU_ATTR, MENU_ATTR,
  50. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  51. { MENU_INDICATOR_SELECTED_ATTR, "menu.indicator.selected", MENU_INDICATOR_ATTR, MENU_SELECTED_ATTR,
  52. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  53. { STATUSLINE_ATTR, "statusline", MENUBAR_ATTR, MENUBAR_ATTR,
  54. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  55. { EDIT_ATTR, "edit", EDIT_ATTR, EDIT_ATTR,
  56. -1, -1, 0, 0 },
  57. { DIALOGLINE_ATTR, "dialogline", EDIT_ATTR, EDIT_ATTR,
  58. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  59. { SCROLLBAR_ATTR, "scrollbar", EDIT_ATTR, EDIT_ATTR,
  60. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  61. { SCROLLBAR_THUMB_ATTR, "scrollbar.thumb", MENUBAR_ATTR, MENUBAR_ATTR,
  62. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  63. { EDIT_FAILED_CONV_ATTR, "edit.failed-conversion", EDIT_ATTR, EDIT_ATTR,
  64. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  65. { EDIT_CONTROL_ATTR, "edit.control", EDIT_ATTR, EDIT_ATTR,
  66. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  67. { EDIT_EOP_ATTR, "edit.eop", EDIT_ATTR, EDIT_ATTR,
  68. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  69. { EDIT_EXPLICIT_ATTR, "edit.explicit-bidi", EDIT_EOP_ATTR, EDIT_EOP_ATTR,
  70. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  71. { EDIT_NSM_ATTR, "edit.nsm", EDIT_EXPLICIT_ATTR, EDIT_EXPLICIT_ATTR,
  72. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  73. { EDIT_NSM_HEBREW_ATTR, "edit.nsm.hebrew", EDIT_NSM_ATTR, EDIT_NSM_ATTR,
  74. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  75. { EDIT_NSM_CANTILLATION_ATTR, "edit.nsm.cantillation", EDIT_NSM_HEBREW_ATTR, EDIT_NSM_HEBREW_ATTR,
  76. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  77. { EDIT_NSM_ARABIC_ATTR, "edit.nsm.arabic", EDIT_NSM_ATTR, EDIT_NSM_ATTR,
  78. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  79. { EDIT_TAB_ATTR, "edit.tab", EDIT_EOP_ATTR, EDIT_EOP_ATTR,
  80. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  81. { EDIT_WIDE_ATTR, "edit.wide", EDIT_NSM_ATTR, EDIT_NSM_ATTR,
  82. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  83. { EDIT_TRIM_ATTR, "edit.trim", EDIT_ATTR, EDIT_ATTR,
  84. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  85. { EDIT_WRAP_ATTR, "edit.wrap", EDIT_TRIM_ATTR, EDIT_TRIM_ATTR,
  86. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  87. { EDIT_MAQAF_ATTR, "edit.maqaf", EDIT_EXPLICIT_ATTR, EDIT_EXPLICIT_ATTR,
  88. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  89. { EDIT_UNICODE_LS_ATTR, "edit.unicode-ls", EDIT_EOP_ATTR, EDIT_EOP_ATTR,
  90. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  91. { EDIT_SELECTED_ATTR, "edit.selected", EDIT_ATTR, EDIT_ATTR,
  92. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  93. { EDIT_HTML_TAG_ATTR, "edit.html-tag", EDIT_ATTR, EDIT_ATTR,
  94. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  95. { EDIT_EMPHASIZED_ATTR, "edit.emphasized", EDIT_ATTR, EDIT_ATTR,
  96. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  97. { EDIT_LINKS_ATTR, "edit.links", EDIT_EMPHASIZED_ATTR, EDIT_EMPHASIZED_ATTR,
  98. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  99. { EDIT_EMAIL_QUOTE1_ATTR, "edit.email-quote1", EDIT_ATTR, EDIT_ATTR,
  100. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  101. { EDIT_EMAIL_QUOTE2_ATTR, "edit.email-quote2", EDIT_EMAIL_QUOTE1_ATTR, EDIT_EMAIL_QUOTE1_ATTR,
  102. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  103. { EDIT_EMAIL_QUOTE3_ATTR, "edit.email-quote3", EDIT_EMAIL_QUOTE2_ATTR, EDIT_EMAIL_QUOTE2_ATTR,
  104. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  105. { EDIT_EMAIL_QUOTE4_ATTR, "edit.email-quote4", EDIT_EMAIL_QUOTE3_ATTR, EDIT_EMAIL_QUOTE3_ATTR,
  106. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  107. { EDIT_EMAIL_QUOTE5_ATTR, "edit.email-quote5", EDIT_EMAIL_QUOTE4_ATTR, EDIT_EMAIL_QUOTE4_ATTR,
  108. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  109. { EDIT_EMAIL_QUOTE6_ATTR, "edit.email-quote6", EDIT_EMAIL_QUOTE5_ATTR, EDIT_EMAIL_QUOTE5_ATTR,
  110. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  111. { EDIT_EMAIL_QUOTE7_ATTR, "edit.email-quote7", EDIT_EMAIL_QUOTE6_ATTR, EDIT_EMAIL_QUOTE6_ATTR,
  112. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  113. { EDIT_EMAIL_QUOTE8_ATTR, "edit.email-quote8", EDIT_EMAIL_QUOTE7_ATTR, EDIT_EMAIL_QUOTE7_ATTR,
  114. MISSING_COLOR, MISSING_COLOR, 0, 0 },
  115. { EDIT_EMAIL_QUOTE9_ATTR, "edit.email-quote9", EDIT_EMAIL_QUOTE8_ATTR, EDIT_EMAIL_QUOTE8_ATTR,
  116. MISSING_COLOR, MISSING_COLOR, 0, 0 }
  117. };
  118. #define ARRAY_SIZE(nm) (int)(sizeof(nm)/sizeof(nm[0]))
  119. static const char *default_color_theme[] =
  120. {
  121. "menu = white, cyan",
  122. "menu.frame = black",
  123. "menu.selected = , black",
  124. "menu.letter = yellow",
  125. "menu.indicator = red",
  126. "menubar = black",
  127. "edit = default, default",
  128. "edit.eop = red",
  129. "edit.tab = red",
  130. "edit.explicit-bidi = magenta",
  131. "edit.maqaf = brightmagenta",
  132. "edit.nsm = brightmagenta",
  133. "edit.nsm.hebrew = green",
  134. "edit.nsm.cantillation = blue",
  135. "edit.nsm.arabic = brown",
  136. "edit.unicode-ls = green",
  137. "edit.wide = brightmagenta",
  138. "edit.control = yellow",
  139. "edit.failed-conversion = brightmagenta",
  140. "edit.trim = bold",
  141. "edit.wrap = bold",
  142. "edit.selected = reverse, +bold",
  143. "edit.html-tag = bold",
  144. "edit.email-quote1 = bold",
  145. "edit.emphasized = underline, +bold",
  146. NULL
  147. };
  148. static const char *default_bw_theme[] =
  149. {
  150. "menu = reverse",
  151. "menu.selected = normal",
  152. "menu.letter = normal",
  153. "menu.indicator = reverse",
  154. "menu.indicator.selected = normal",
  155. "edit = normal",
  156. "edit.eop = normal",
  157. "edit.tab = normal",
  158. "edit.explicit-bidi = bold",
  159. "edit.maqaf = bold",
  160. "edit.nsm = bold",
  161. "edit.nsm.hebrew = bold",
  162. "edit.nsm.cantillation = bold",
  163. "edit.nsm.arabic = bold",
  164. "edit.unicode-ls = bold",
  165. "edit.wide = bold",
  166. "edit.control = bold",
  167. "edit.failed-conversion = bold",
  168. "edit.trim = bold",
  169. "edit.wrap = bold",
  170. "edit.selected = reverse",
  171. "edit.html-tag = bold",
  172. "edit.email-quote1 = bold",
  173. "edit.emphasized = underline, +bold",
  174. NULL
  175. };
  176. static u8string theme_name;
  177. const char *get_theme_name()
  178. {
  179. return theme_name.c_str();
  180. }
  181. static ATTR *get_attr_ent(int ident)
  182. {
  183. static std::map<int, ATTR *> hash;
  184. if (hash.empty())
  185. for (int i = 0; i < ARRAY_SIZE(attr_table); i++)
  186. hash[attr_table[i].ident] = &attr_table[i];
  187. std::map<int, ATTR *>::const_iterator it = hash.find(ident);
  188. if (it != hash.end())
  189. return it->second;
  190. else
  191. return NULL;
  192. }
  193. int get_attr(int ident)
  194. {
  195. ATTR *attr = get_attr_ent(ident);
  196. // ASSERT(attr != NULL);
  197. if (attr->pair)
  198. return COLOR_PAIR(attr->pair) | attr->extra;
  199. else
  200. return attr->extra;
  201. }
  202. static int get_name_ident(const char *name)
  203. {
  204. for (int i = 0; i < ARRAY_SIZE(attr_table); i++) {
  205. if (STREQ(attr_table[i].name, name))
  206. return attr_table[i].ident;
  207. }
  208. return -1;
  209. }
  210. // parse_attr() parses a "color" name and puts the
  211. // appropriate values in an ATTR struct.
  212. static bool parse_attr(const char *s, ATTR *attr, bool is_fg)
  213. {
  214. static struct {
  215. const char *name;
  216. int color;
  217. int extra;
  218. } names_arr[] = {
  219. { "black", COLOR_BLACK, 0 },
  220. { "gray", COLOR_BLACK, A_BOLD },
  221. { "grey", COLOR_BLACK, A_BOLD },
  222. { "red", COLOR_RED, 0 },
  223. { "brightred", COLOR_RED, A_BOLD },
  224. { "green", COLOR_GREEN, 0 },
  225. { "brightgreen", COLOR_GREEN, A_BOLD },
  226. { "brown", COLOR_YELLOW, 0 },
  227. { "yellow", COLOR_YELLOW, A_BOLD },
  228. { "blue", COLOR_BLUE, 0 },
  229. { "brightblue", COLOR_BLUE, A_BOLD },
  230. { "magenta", COLOR_MAGENTA, 0 },
  231. { "brightmagenta", COLOR_MAGENTA, A_BOLD },
  232. { "cyan", COLOR_CYAN, 0 },
  233. { "brightcyan", COLOR_CYAN, A_BOLD },
  234. { "lightgray", COLOR_WHITE, 0 },
  235. { "lightgrey", COLOR_WHITE, 0 },
  236. { "white", COLOR_WHITE, A_BOLD },
  237. { "default", -1, 0 },
  238. { "", MISSING_COLOR, 0 },
  239. { "inherit", MISSING_COLOR, 0 },
  240. { "bold", NO_COLOR, A_BOLD },
  241. { "underline", NO_COLOR, A_UNDERLINE },
  242. { "reverse", NO_COLOR, A_REVERSE },
  243. { "normal", NO_COLOR, 0 },
  244. { "+bold", SKIP_COLOR, A_BOLD },
  245. { "+underline", SKIP_COLOR, A_UNDERLINE },
  246. { "+reverse", SKIP_COLOR, A_REVERSE }
  247. };
  248. bool found = false;
  249. for (int i = 0; i < ARRAY_SIZE(names_arr) && !found; i++) {
  250. if (STREQ(s, names_arr[i].name)) {
  251. if (names_arr[i].color != SKIP_COLOR) {
  252. if (is_fg)
  253. attr->fg = names_arr[i].color;
  254. else
  255. attr->bg = names_arr[i].color;
  256. }
  257. attr->extra |= names_arr[i].extra;
  258. found = true;
  259. }
  260. }
  261. return found;
  262. }
  263. #define LINE_TYPE_NONE 0
  264. #define LINE_TYPE_ATTR 1
  265. static bool parse_line(char *ln, int *line_type, ATTR *attr)
  266. {
  267. if (strchr(ln, '#'))
  268. *strchr(ln, '#') = '\0';
  269. if (strchr(ln, '=')) {
  270. *line_type = LINE_TYPE_ATTR;
  271. attr->clear();
  272. char *pos = strchr(ln, '=');
  273. u8string name = u8string(ln, pos).trim();
  274. if ((attr->ident = get_name_ident(name.c_str())) == -1)
  275. return false;
  276. ln = ++pos;
  277. int token_no = 0;
  278. while (pos) {
  279. u8string token;
  280. pos = strchr(ln, ',');
  281. if (!pos)
  282. token = u8string(ln);
  283. else
  284. token = u8string(ln, pos);
  285. token = token.trim();
  286. if (!parse_attr(token.c_str(), attr, token_no == 0))
  287. return false;
  288. ln = pos + 1;
  289. token_no++;
  290. }
  291. } else {
  292. *line_type = LINE_TYPE_NONE;
  293. }
  294. return true;
  295. }
  296. static void clear_table()
  297. {
  298. for (int i = 0; i < ARRAY_SIZE(attr_table); i++)
  299. attr_table[i].clear();
  300. }
  301. // complete_table() is called after the theme file has been parsed
  302. // and attr_table populated. Its function is to get rid of any
  303. // missing colors - by inheritance from the parent elements.
  304. //
  305. // Also, if our curses implementation doesn't support the use of
  306. // default fg & bg colors, we use white & black instead.
  307. static void complete_table()
  308. {
  309. for (int i = 0; i < ARRAY_SIZE(attr_table); i++) {
  310. if (attr_table[i].fg == MISSING_COLOR) {
  311. attr_table[i].fg = get_attr_ent(attr_table[i].fg_parent)->fg;
  312. attr_table[i].extra |= get_attr_ent(attr_table[i].fg_parent)->extra;
  313. }
  314. if (attr_table[i].bg == MISSING_COLOR) {
  315. attr_table[i].bg = get_attr_ent(attr_table[i].bg_parent)->bg;
  316. // No sense in A_BOLD for background.
  317. //attr_table[i].extra |= get_attr_ent(attr_table[i].bg_parent)->extra;
  318. }
  319. if (!terminal::use_default_colors) {
  320. if (attr_table[i].fg == -1)
  321. attr_table[i].fg = COLOR_WHITE;
  322. if (attr_table[i].bg == -1)
  323. attr_table[i].bg = COLOR_BLACK;
  324. }
  325. }
  326. }
  327. // allocate_color_pairs() is called after the theme file
  328. // has been read and parsed. It does the actual color
  329. // allocation, by calling init_pait().
  330. static bool allocate_color_pairs(ThemeError &theme_error)
  331. {
  332. int clrpr = 1; // color pair '0' is reserved and cannot be redefined.
  333. for (int i = 0; i < ARRAY_SIZE(attr_table); i++) {
  334. if (attr_table[i].fg == NO_COLOR || attr_table[i].bg == NO_COLOR) {
  335. attr_table[i].pair = 0;
  336. } else {
  337. if (!terminal::is_color) {
  338. theme_error.what = ThemeError::errNoColorTerminal;
  339. return false;
  340. }
  341. bool already_allocated = false;
  342. for (int j = 0; j < i; j++) {
  343. if (attr_table[j].fg == attr_table[i].fg
  344. && attr_table[j].bg == attr_table[i].bg) {
  345. attr_table[i].pair = attr_table[j].pair;
  346. already_allocated = true;
  347. break;
  348. }
  349. }
  350. if (!already_allocated) {
  351. if (clrpr > COLOR_PAIRS-1) {
  352. theme_error.what = ThemeError::errNotEnoughColorPairs;
  353. return false;
  354. }
  355. init_pair(clrpr, attr_table[i].fg, attr_table[i].bg);
  356. attr_table[i].pair = clrpr;
  357. clrpr++;
  358. }
  359. }
  360. }
  361. return true;
  362. }
  363. bool load_theme(const char *basefilename, ThemeError &theme_error)
  364. {
  365. #define MAX_LINE_LEN 1024
  366. FILE *fp;
  367. u8string filename;
  368. theme_error.what = ThemeError::errNone;
  369. // First, try to load from the user directory.
  370. filename.cformat("%s%s", get_cfg_filename(USER_THEMES_DIR), basefilename);
  371. if ((fp = fopen(filename.c_str(), "r")) == NULL) {
  372. if (errno != ENOENT) {
  373. // File exists, but some IO error occured.
  374. theme_error.what = ThemeError::errIO;
  375. theme_error.sys_errno = errno;
  376. theme_error.filename = filename;
  377. return false;
  378. }
  379. // Now try to load from the system directory.
  380. filename.cformat("%s%s", get_cfg_filename(SYSTEM_THEMES_DIR), basefilename);
  381. if ((fp = fopen(filename.c_str(), "r")) == NULL) {
  382. theme_error.what = ((errno == ENOENT) ? ThemeError::errNotFound : ThemeError::errIO);
  383. theme_error.sys_errno = errno;
  384. theme_error.filename = filename;
  385. return false;
  386. }
  387. }
  388. theme_error.filename = filename; // for possible future errors.
  389. clear_table();
  390. char line[MAX_LINE_LEN];
  391. ATTR prs_attr;
  392. int line_type;
  393. int line_no = 1;
  394. while (fgets(line, MAX_LINE_LEN, fp)) {
  395. if (!parse_line(line, &line_type, &prs_attr)) {
  396. theme_error.what = ThemeError::errSyntax;
  397. theme_error.line_no = line_no;
  398. return false;
  399. } else if (line_type == LINE_TYPE_ATTR) {
  400. ATTR *attr = get_attr_ent(prs_attr.ident);
  401. attr->fg = prs_attr.fg;
  402. attr->bg = prs_attr.bg;
  403. attr->extra = prs_attr.extra;
  404. }
  405. line_no++;
  406. }
  407. fclose(fp);
  408. complete_table();
  409. if (allocate_color_pairs(theme_error)) {
  410. theme_name = basefilename;
  411. return true;
  412. } else {
  413. return false;
  414. }
  415. #undef MAX_LINE_LEN
  416. }
  417. static bool load_default_theme(const char *theme_file_name,
  418. const char **memory_theme,
  419. ThemeError &theme_error)
  420. {
  421. // First, try to load the theme from disk.
  422. if (!load_theme(theme_file_name, theme_error)) {
  423. if (theme_error.what != ThemeError::errNotFound)
  424. // The theme is found on disk, be could not
  425. // be processed.
  426. return false;
  427. } else {
  428. return true;
  429. }
  430. // No theme found on disk. Load from memory.
  431. clear_table();
  432. ATTR prs_attr;
  433. int line_type;
  434. int line_no = 1;
  435. while (*memory_theme) {
  436. char line[1000];
  437. strcpy(line, *memory_theme);
  438. if (!parse_line(line, &line_type, &prs_attr)) {
  439. theme_error.what = ThemeError::errSyntax;
  440. theme_error.filename = "-INTERNAL-";
  441. theme_error.line_no = line_no;
  442. return false;
  443. } else if (line_type == LINE_TYPE_ATTR) {
  444. ATTR *attr = get_attr_ent(prs_attr.ident);
  445. attr->fg = prs_attr.fg;
  446. attr->bg = prs_attr.bg;
  447. attr->extra = prs_attr.extra;
  448. }
  449. memory_theme++;
  450. line_no++;
  451. }
  452. complete_table();
  453. allocate_color_pairs(theme_error);
  454. theme_name = theme_file_name;
  455. return true;
  456. }
  457. bool load_default_theme(ThemeError &theme_error)
  458. {
  459. return load_default_theme(
  460. terminal::is_color ? "default.thm" : "default_bw.thm",
  461. terminal::is_color ? default_color_theme : default_bw_theme,
  462. theme_error);
  463. }
  464. #else
  465. // Some stub functions for VERY primitive curses implementations:
  466. int get_attr(int /*ident*/)
  467. {
  468. return A_NORMAL;
  469. }
  470. bool load_theme(const char * /*basefilename*/, ThemeError &/*theme_error*/)
  471. {
  472. return true;
  473. }
  474. bool load_default_theme(ThemeError &/*theme_error*/)
  475. {
  476. return true;
  477. }
  478. const char *get_theme_name()
  479. {
  480. return "";
  481. }
  482. #endif // HAVE_COLOR
  483. u8string ThemeError::format() const
  484. {
  485. u8string ret;
  486. switch (what) {
  487. case errSyntax:
  488. ret.cformat("Syntax error at line %d of %s", line_no, filename.c_str());
  489. break;
  490. case errNoColorTerminal:
  491. ret.cformat("Your terminal does not support colors, so I can't use theme %s", filename.c_str());
  492. break;
  493. case errNotEnoughColorPairs:
  494. ret.cformat("Your terminal support only %d color pairs, so I can't use theme %s", COLOR_PAIRS, filename.c_str());
  495. break;
  496. case errNotFound:
  497. ret.cformat("File does not exist: %s", filename.c_str());
  498. break;
  499. case errIO:
  500. ret.cformat("Can't open file %s: %s", filename.c_str(), strerror(sys_errno));
  501. break;
  502. case errNone:
  503. // silence the compiler
  504. break;
  505. }
  506. return ret;
  507. }