From a369a43d94c3cd31f8b08bd9ea61fccc58ef6a33 Mon Sep 17 00:00:00 2001
From: Yorhel <git@yorhel.nl>
Date: Sat, 8 Jul 2017 16:29:31 +0200
Subject: [PATCH] Add support for colors and sprinkle some colors around

TODO:
- Add (ls-like) colors to the actual file names
  -> Implement full $LS_COLORS handling or something simple and custom?
- Test on a white/black terminal, and provide an alternate color scheme
  if necessary.
- Make colors opt-in?
---
 src/browser.c    | 204 +++++++++++++++++++++++++++--------------------
 src/delete.c     |   4 +-
 src/dir_common.c |  38 ++++++---
 src/help.c       |  31 +++----
 src/main.c       |   1 +
 src/util.c       |  89 ++++++++++++++++-----
 src/util.h       |  50 +++++++++++-
 7 files changed, 277 insertions(+), 140 deletions(-)

diff --git a/src/browser.c b/src/browser.c
index 38a8afc..a7ab424 100644
--- a/src/browser.c
+++ b/src/browser.c
@@ -42,14 +42,8 @@ static void browse_draw_info(struct dir *dr) {
   nccreate(11, 60, "Item info");
 
   if(dr->hlnk) {
-    if(info_page == 0)
-      attron(A_REVERSE);
-    ncaddstr(0, 41, "1:Info");
-    attroff(A_REVERSE);
-    if(info_page == 1)
-      attron(A_REVERSE);
-    ncaddstr(0, 50, "2:Links");
-    attroff(A_REVERSE);
+    nctab(41, info_page == 0, 1, "Info");
+    nctab(50, info_page == 1, 2, "Links");
   }
 
   switch(info_page) {
@@ -66,8 +60,18 @@ static void browse_draw_info(struct dir *dr) {
     ncaddstr(3,  9, cropstr(getpath(dr->parent), 49));
     ncaddstr(4,  9, dr->flags & FF_DIR ? "Directory"
         : dr->flags & FF_FILE ? "File" : "Other (link, device, socket, ..)");
-    ncprint(6, 18, "%s (%s B)", formatsize(dr->size),  fullsize(dr->size));
-    ncprint(7, 18, "%s (%s B)", formatsize(dr->asize), fullsize(dr->asize));
+
+    ncmove(6, 18);
+    printsize(UIC_DEFAULT, dr->size);
+    addstrc(UIC_DEFAULT, " (");
+    addstrc(UIC_KEYNUM, fullsize(dr->size));
+    addstrc(UIC_DEFAULT, " B)");
+
+    ncmove(7, 18);
+    printsize(UIC_DEFAULT, dr->asize);
+    addstrc(UIC_DEFAULT, " (");
+    addstrc(UIC_KEYNUM, fullsize(dr->asize));
+    addstrc(UIC_DEFAULT, " B)");
     break;
 
   case 1:
@@ -83,35 +87,16 @@ static void browse_draw_info(struct dir *dr) {
     break;
   }
 
-  ncaddstr(9, 32, "Press i to hide this window");
+  ncaddstr(9, 31, "Press ");
+  addchc(UIC_KEYNUM, 'i');
+  addstrc(UIC_DEFAULT, " to hide this window");
 }
 
 
-static void browse_draw_item(struct dir *n, int row) {
-  char ct, dt, *size, gr[11], *items;
-  int i, o, x;
-  float pc = 0.0f;
-
-  if(n->flags & FF_BSEL)
-    attron(A_REVERSE);
-
-  /* reference to parent dir has a different format */
-  if(n == dirlist_parent) {
-    mvhline(row, 0, ' ', wincols);
-    o = graph == 0 ? 13 :
-        graph == 1 ? 25 :
-        graph == 2 ? 21 :
-                     32 ;
-    if(show_items)
-      o += 7;
-    mvaddstr(row, o, "/..");
-    if(n->flags & FF_BSEL)
-      attroff(A_REVERSE);
-    return;
-  }
-
-  /* determine indication character */
-  ct =  n->flags & FF_EXL ? '<' :
+static void browse_draw_flag(struct dir *n, int *x) {
+  addchc(n->flags & FF_BSEL ? UIC_FLAG_SEL : UIC_FLAG,
+      n == dirlist_parent ? ' ' :
+        n->flags & FF_EXL ? '<' :
         n->flags & FF_ERR ? '!' :
        n->flags & FF_SERR ? '.' :
       n->flags & FF_OTHFS ? '>' :
@@ -120,89 +105,138 @@ static void browse_draw_item(struct dir *n, int row) {
     || n->flags & FF_DIR) ? '@' :
         n->flags & FF_DIR
         && n->sub == NULL ? 'e' :
-                            ' ' ;
-  dt = n->flags & FF_DIR ? '/' : ' ';
-  size = formatsize(show_as ? n->asize : n->size);
-
-  /* create graph (if necessary) */
-  if(graph) {
-    /* percentage */
-    if((pc = (float)(show_as ? n->parent->asize : n->parent->size)) < 1)
+                            ' ');
+  *x += 2;
+}
+
+
+static void browse_draw_graph(struct dir *n, int *x) {
+  float pc = 0.0f;
+  int o, i;
+  enum ui_coltype c = n->flags & FF_BSEL ? UIC_SEL : UIC_DEFAULT;
+
+  if(!graph)
+    return;
+
+  *x += graph == 1 ? 13 : graph == 2 ? 9 : 20;
+  if(n == dirlist_parent)
+    return;
+
+  addchc(c, '[');
+
+  /* percentage (6 columns) */
+  if(graph == 2 || graph == 3) {
+    pc = (float)(show_as ? n->parent->asize : n->parent->size);
+    if(pc < 1)
       pc = 1.0f;
-    pc = ((float)(show_as ? n->asize : n->size) / pc) * 100.0f;
-    /* graph */
-    if(graph == 1 || graph == 3) {
-      o = (int)(10.0f*(float)(show_as ? n->asize : n->size) / (float)(show_as ? dirlist_maxa : dirlist_maxs));
-      for(i=0; i<10; i++)
-        gr[i] = i < o ? '#' : ' ';
-      gr[10] = '\0';
-    }
+    uic_set(c == UIC_SEL ? UIC_KEYNUM_SEL : UIC_KEYNUM);
+    printw("%5.1f", ((float)(show_as ? n->asize : n->size) / pc) * 100.0f);
+    addchc(c, '%');
   }
 
-  x = 0;
+  if(graph == 3)
+    addch(' ');
 
-  mvprintw(row, x, "%c %9s ", ct, size);
-  x += 12;
-
-  if (show_items) {
-    if (n->items > 99999)
-      items = "> 100k";
-    else
-      items = n->items ? fullsize(n->items) : "";
-    mvprintw(row, x, "%6s ", items);
-    x += 7;
+  /* graph (10 columns) */
+  if(graph == 1 || graph == 3) {
+    uic_set(c == UIC_SEL ? UIC_GRAPH_SEL : UIC_GRAPH);
+    o = (int)(10.0f*(float)(show_as ? n->asize : n->size) / (float)(show_as ? dirlist_maxa : dirlist_maxs));
+    for(i=0; i<10; i++)
+      addch(i < o ? '#' : ' ');
   }
 
-  /* format and add item to the list */
-  switch(graph) {
-    case 0: mvprintw(row, x, " %c%-*s",                       dt, wincols- 2-x, cropstr(n->name, wincols- 2-x)); break;
-    case 1: mvprintw(row, x, "[%10s] %c%-*s",             gr, dt, wincols-14-x, cropstr(n->name, wincols-14-x)); break;
-    case 2: mvprintw(row, x, "[%5.1f%%] %c%-*s",      pc,     dt, wincols-10-x, cropstr(n->name, wincols-10-x)); break;
-    case 3: mvprintw(row, x, "[%5.1f%% %10s] %c%-*s", pc, gr, dt, wincols-21-x, cropstr(n->name, wincols-21-x));
+  addchc(c, ']');
+}
+
+
+static void browse_draw_items(struct dir *n, int *x) {
+  enum ui_coltype c = n->flags & FF_BSEL ? UIC_SEL : UIC_DEFAULT;
+
+  if(!show_items)
+    return;
+  *x += 7;
+
+  if(n->items > 99999) {
+    addstrc(c, "> ");
+    addstrc(c == UIC_SEL ? UIC_KEYNUM_SEL : UIC_KEYNUM, "100");
+    addchc(c, 'k');
+  } else if(n->items) {
+    uic_set(c == UIC_SEL ? UIC_KEYNUM_SEL : UIC_KEYNUM);
+    printw("%6s", fullsize(n->items));
   }
+}
 
-  if(n->flags & FF_BSEL)
-    attroff(A_REVERSE);
+
+static void browse_draw_item(struct dir *n, int row) {
+  int x = 0;
+
+  enum ui_coltype c = n->flags & FF_BSEL ? UIC_SEL : UIC_DEFAULT;
+  uic_set(c);
+  mvhline(row, 0, ' ', wincols);
+  move(row, 0);
+
+  browse_draw_flag(n, &x);
+  move(row, x);
+
+  if(n != dirlist_parent)
+    printsize(c, show_as ? n->asize : n->size);
+  x += 10;
+  move(row, x);
+
+  browse_draw_graph(n, &x);
+  move(row, x);
+
+  browse_draw_items(n, &x);
+  move(row, x);
+
+  addchc(c == UIC_SEL ? UIC_DIR_SEL : UIC_DIR, n->flags & FF_DIR ? '/' : ' ');
+  addstrc(c, cropstr(n->name, wincols-x-1));
 }
 
 
 void browse_draw() {
   struct dir *t;
-  char fmtsize[10], *tmp;
+  char *tmp;
   int selected = 0, i;
 
   erase();
   t = dirlist_get(0);
 
   /* top line - basic info */
-  attron(A_REVERSE);
+  uic_set(UIC_HD);
   mvhline(0, 0, ' ', wincols);
-  mvhline(winrows-1, 0, ' ', wincols);
-  mvprintw(0,0,"%s %s ~ Use the arrow keys to navigate, press ? for help", PACKAGE_NAME, PACKAGE_VERSION);
+  mvprintw(0,0,"%s %s ~ Use the arrow keys to navigate, press ", PACKAGE_NAME, PACKAGE_VERSION);
+  addchc(UIC_KEYNUM_HD, '?');
+  addstrc(UIC_HD, " for help");
   if(dir_import_active)
     mvaddstr(0, wincols-10, "[imported]");
   else if(read_only)
     mvaddstr(0, wincols-11, "[read-only]");
-  attroff(A_REVERSE);
 
   /* second line - the path */
-  mvhline(1, 0, '-', wincols);
+  mvhlinec(UIC_DEFAULT, 1, 0, '-', wincols);
   if(dirlist_par) {
-    mvaddch(1, 3, ' ');
+    mvaddchc(UIC_DEFAULT, 1, 3, ' ');
     tmp = getpath(dirlist_par);
-    mvaddstr(1, 4, cropstr(tmp, wincols-8));
-    mvaddch(1, 4+((int)strlen(tmp) > wincols-8 ? wincols-8 : (int)strlen(tmp)), ' ');
+    mvaddstrc(UIC_DIR, 1, 4, cropstr(tmp, wincols-8));
+    mvaddchc(UIC_DEFAULT, 1, 4+((int)strlen(tmp) > wincols-8 ? wincols-8 : (int)strlen(tmp)), ' ');
   }
 
   /* bottom line - stats */
-  attron(A_REVERSE);
+  uic_set(UIC_HD);
+  mvhline(winrows-1, 0, ' ', wincols);
   if(t) {
-    strcpy(fmtsize, formatsize(t->parent->size));
-    mvprintw(winrows-1, 0, " Total disk usage: %s  Apparent size: %s  Items: %d",
-      fmtsize, formatsize(t->parent->asize), t->parent->items);
+    mvaddstr(winrows-1, 0, " Total disk usage: ");
+    printsize(UIC_HD, t->parent->size);
+    addstrc(UIC_HD, "  Apparent size: ");
+    uic_set(UIC_KEYNUM_HD);
+    printsize(UIC_HD, t->parent->asize);
+    addstrc(UIC_HD, "  Items: ");
+    uic_set(UIC_KEYNUM_HD);
+    printw("%d", t->parent->items);
   } else
     mvaddstr(winrows-1, 0, " No items to display.");
-  attroff(A_REVERSE);
+  uic_set(UIC_DEFAULT);
 
   /* nothing to display? stop here. */
   if(!t)
diff --git a/src/delete.c b/src/delete.c
index 44cf4a4..8e97992 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -70,7 +70,9 @@ static void delete_draw_progress() {
   nccreate(6, 60, "Deleting...");
 
   ncaddstr(1, 2, cropstr(getpath(curdir), 47));
-  ncaddstr(4, 41, "Press q to abort");
+  ncaddstr(4, 41, "Press ");
+  addchc(UIC_KEYNUM, 'q');
+  addstrc(UIC_DEFAULT, " to abort");
 }
 
 
diff --git a/src/dir_common.c b/src/dir_common.c
index f8c0657..3d733b4 100644
--- a/src/dir_common.c
+++ b/src/dir_common.c
@@ -131,14 +131,26 @@ static void draw_progress() {
 
   nccreate(10, width, antext);
 
-  ncprint(2, 2, "Total items: %-8d", dir_output.items);
-  if(dir_output.size)
-    ncprint(2, 23, "size: %s", formatsize(dir_output.size));
+  ncaddstr(2, 2, "Total items: ");
+  uic_set(UIC_KEYNUM);
+  printw("%-8d", dir_output.items);
+
+  if(dir_output.size) {
+    ncaddstrc(UIC_DEFAULT, 2, 23, "size: ");
+    printsize(UIC_DEFAULT, dir_output.size);
+  }
+
+  uic_set(UIC_DEFAULT);
   ncprint(3, 2, "Current item: %s", cropstr(dir_curpath, width-18));
-  if (confirm_quit_while_scanning_stage_1_passed)
-    ncaddstr(8, width-26, "Press y to confirm abort");
-  else
-    ncaddstr(8, width-18, "Press q to abort");
+  if(confirm_quit_while_scanning_stage_1_passed) {
+    ncaddstr(8, width-26, "Press ");
+    addchc(UIC_KEYNUM, 'y');
+    addstrc(UIC_DEFAULT, " to confirm abort");
+  } else {
+    ncaddstr(8, width-18, "Press ");
+    addchc(UIC_KEYNUM, 'q');
+    addstrc(UIC_DEFAULT, " to abort");
+  }
 
   /* show warning if we couldn't open a dir */
   if(lasterr) {
@@ -181,6 +193,9 @@ static void draw_error(char *cur, char *msg) {
 
 
 void dir_draw() {
+  float f;
+  char *unit;
+
   switch(dir_ui) {
   case 0:
     if(dir_fatalerr)
@@ -189,10 +204,11 @@ void dir_draw() {
   case 1:
     if(dir_fatalerr)
       fprintf(stderr, "\r%s.\n", dir_fatalerr);
-    else if(dir_output.size)
-      fprintf(stderr, "\r%-55s %8d files /%s",
-        cropstr(dir_curpath, 55), dir_output.items, formatsize(dir_output.size));
-    else
+    else if(dir_output.size) {
+      f = formatsize(dir_output.size, &unit);
+      fprintf(stderr, "\r%-55s %8d files /%5.1f %s",
+        cropstr(dir_curpath, 55), dir_output.items, f, unit);
+    } else
       fprintf(stderr, "\r%-65s %8d files", cropstr(dir_curpath, 65), dir_output.items);
     break;
   case 2:
diff --git a/src/help.c b/src/help.c
index 56a6a00..5341cd9 100644
--- a/src/help.c
+++ b/src/help.c
@@ -61,28 +61,23 @@ void help_draw() {
   browse_draw();
 
   nccreate(15, 60, "ncdu help");
-  ncaddstr(13, 42, "Press q to close");
-
-  if(page == 1)
-    attron(A_REVERSE);
-  ncaddstr(0, 30, "1:Keys");
-  attroff(A_REVERSE);
-  if(page == 2)
-    attron(A_REVERSE);
-  ncaddstr(0, 39, "2:Format");
-  attroff(A_REVERSE);
-  if(page == 3)
-    attron(A_REVERSE);
-  ncaddstr(0, 50, "3:About");
-  attroff(A_REVERSE);
+  ncaddstr(13, 42, "Press ");
+  uic_set(UIC_KEYNUM);
+  addch('q');
+  uic_set(UIC_DEFAULT);
+  addstr(" to close");
+
+  nctab(30, page == 1, 1, "Keys");
+  nctab(39, page == 2, 2, "Format");
+  nctab(50, page == 3, 3, "About");
 
   switch(page) {
     case 1:
       line = 1;
       for(i=start*2; i<start*2+20; i+=2) {
-        attron(A_BOLD);
+        uic_set(UIC_KEYNUM);
         ncaddstr(++line, 13-strlen(keys[i]), keys[i]);
-        attroff(A_BOLD);
+        uic_set(UIC_DEFAULT);
         ncaddstr(line, 15, keys[i+1]);
       }
       if(start != KEYS-10)
@@ -93,7 +88,7 @@ void help_draw() {
       ncaddstr(2, 3, "X  [size] [graph] [file or directory]");
       attroff(A_BOLD);
       ncaddstr(3, 4, "The X is only present in the following cases:");
-      attron(A_BOLD);
+      uic_set(UIC_FLAG);
       ncaddch( 5, 4, '!');
       ncaddch( 6, 4, '.');
       ncaddch( 7, 4, '<');
@@ -101,7 +96,7 @@ void help_draw() {
       ncaddch( 9, 4, '@');
       ncaddch(10, 4, 'H');
       ncaddch(11, 4, 'e');
-      attroff(A_BOLD);
+      uic_set(UIC_DEFAULT);
       ncaddstr( 5, 7, "An error occured while reading this directory");
       ncaddstr( 6, 7, "An error occured while reading a subdirectory");
       ncaddstr( 7, 7, "File or directory is excluded from the statistics");
diff --git a/src/main.c b/src/main.c
index 7d361cc..b79c663 100644
--- a/src/main.c
+++ b/src/main.c
@@ -249,6 +249,7 @@ static void init_nc() {
     exit(1);
   }
 
+  uic_init();
   cbreak();
   noecho();
   curs_set(0);
diff --git a/src/util.c b/src/util.c
index 1ae8c6c..f931b41 100644
--- a/src/util.c
+++ b/src/util.c
@@ -60,31 +60,37 @@ char *cropstr(const char *from, int s) {
 }
 
 
-char *formatsize(int64_t from) {
-  static char dat[10]; /* "xxx.x MiB" */
+float formatsize(int64_t from, char **unit) {
   float r = from;
-  char c = ' ';
   if (si) {
-    if(r < 1000.0f)   { }
-    else if(r < 1e6f) { c = 'K'; r/=1e3f; }
-    else if(r < 1e9f) { c = 'M'; r/=1e6f; }
-    else if(r < 1e12f){ c = 'G'; r/=1e9f; }
-    else if(r < 1e15f){ c = 'T'; r/=1e12f; }
-    else if(r < 1e18f){ c = 'P'; r/=1e15f; }
-    else              { c = 'E'; r/=1e18f; }
-    sprintf(dat, "%5.1f %cB", r, c);
+    if(r < 1000.0f)   { *unit = " B"; }
+    else if(r < 1e6f) { *unit = "KB"; r/=1e3f; }
+    else if(r < 1e9f) { *unit = "MB"; r/=1e6f; }
+    else if(r < 1e12f){ *unit = "GB"; r/=1e9f; }
+    else if(r < 1e15f){ *unit = "TB"; r/=1e12f; }
+    else if(r < 1e18f){ *unit = "PB"; r/=1e15f; }
+    else              { *unit = "EB"; r/=1e18f; }
   }
   else {
-    if(r < 1000.0f)      { }
-    else if(r < 1023e3f) { c = 'K'; r/=1024.0f; }
-    else if(r < 1023e6f) { c = 'M'; r/=1048576.0f; }
-    else if(r < 1023e9f) { c = 'G'; r/=1073741824.0f; }
-    else if(r < 1023e12f){ c = 'T'; r/=1099511627776.0f; }
-    else if(r < 1023e15f){ c = 'P'; r/=1125899906842624.0f; }
-    else                 { c = 'E'; r/=1152921504606846976.0f; }
-    sprintf(dat, "%5.1f %c%cB", r, c, c == ' ' ? ' ' : 'i');
+    if(r < 1000.0f)      { *unit = "  B"; }
+    else if(r < 1023e3f) { *unit = "KiB"; r/=1024.0f; }
+    else if(r < 1023e6f) { *unit = "MiB"; r/=1048576.0f; }
+    else if(r < 1023e9f) { *unit = "GiB"; r/=1073741824.0f; }
+    else if(r < 1023e12f){ *unit = "TiB"; r/=1099511627776.0f; }
+    else if(r < 1023e15f){ *unit = "PiB"; r/=1125899906842624.0f; }
+    else                 { *unit = "EiB"; r/=1152921504606846976.0f; }
   }
-  return dat;
+  return r;
+}
+
+
+void printsize(enum ui_coltype t, int64_t from) {
+  char *unit;
+  float r = formatsize(from, &unit);
+  uic_set(t == UIC_HD ? UIC_KEYNUM_HD : t == UIC_SEL ? UIC_KEYNUM_SEL : UIC_KEYNUM);
+  printw("%5.1f", r);
+  addchc(t, ' ');
+  addstrc(t, unit);
 }
 
 
@@ -179,9 +185,9 @@ void nccreate(int height, int width, const char *title) {
   mvvline(subwinr+1, subwinc+width-1, ACS_VLINE, height-2);
 
   /* title */
-  attron(A_BOLD);
+  uic_set(UIC_BOX_TITLE);
   mvaddstr(subwinr, subwinc+4, title);
-  attroff(A_BOLD);
+  uic_set(UIC_DEFAULT);
 }
 
 
@@ -194,6 +200,45 @@ void ncprint(int r, int c, char *fmt, ...) {
 }
 
 
+void nctab(int c, int sel, int num, char *str) {
+  uic_set(sel ? UIC_KEYNUM_HD : UIC_KEYNUM);
+  ncprint(0, c, "%d", num);
+  uic_set(sel ? UIC_HD : UIC_DEFAULT);
+  addch(':');
+  addstr(str);
+  uic_set(UIC_DEFAULT);
+}
+
+
+static int colors[] = {
+#define C(name, fg, bg, attr) 0,
+  UI_COLORS
+#undef C
+  0
+};
+static int lastcolor = 0;
+
+void uic_init() {
+  start_color();
+  use_default_colors();
+
+  int i=0;
+#define C(name, fg, bg, attr) \
+    init_pair(i+1, fg, bg);\
+    colors[i] = attr | COLOR_PAIR(i+1);\
+    i++;
+  UI_COLORS
+#undef C
+}
+
+void uic_set(enum ui_coltype c) {
+  attroff(lastcolor);
+  lastcolor = colors[(int)c];
+  attron(lastcolor);
+}
+
+
+
 /* removes item from the hlnk circular linked list and size counts of the parents */
 static void freedir_hlnk(struct dir *d) {
   struct dir *t, *par, *pt;
diff --git a/src/util.h b/src/util.h
index a327239..bb9e16b 100644
--- a/src/util.h
+++ b/src/util.h
@@ -29,6 +29,35 @@
 #include "global.h"
 #include <ncurses.h>
 
+
+/* UI colors: C(name, foreground, background, attrs) */
+#define UI_COLORS \
+  C(DEFAULT,    -1,            -1,          0     )\
+  C(BOX_TITLE,  COLOR_BLUE,    -1,          A_BOLD)\
+  C(HD,         COLOR_BLACK,   COLOR_CYAN,  0     )    /* header & footer */\
+  C(SEL,        COLOR_WHITE,   COLOR_GREEN, A_BOLD)\
+  C(KEYNUM,     COLOR_YELLOW,  -1,          A_BOLD)\
+  C(KEYNUM_HD,  COLOR_YELLOW,  COLOR_CYAN,  A_BOLD)\
+  C(KEYNUM_SEL, COLOR_YELLOW,  COLOR_GREEN, A_BOLD)\
+  C(DIR,        COLOR_BLUE,    -1,          A_BOLD)\
+  C(DIR_SEL,    COLOR_BLUE,    COLOR_GREEN, A_BOLD)\
+  C(FLAG,       COLOR_RED,     -1,          0     )\
+  C(FLAG_SEL,   COLOR_RED,     COLOR_GREEN, 0     )\
+  C(GRAPH,      COLOR_MAGENTA, -1,          0     )\
+  C(GRAPH_SEL,  COLOR_MAGENTA, COLOR_GREEN, 0     )
+
+enum ui_coltype {
+#define C(name, fg, bg, attr) UIC_##name,
+  UI_COLORS
+#undef C
+  UIC_NONE
+};
+
+/* Color & attribute manipulation */
+void uic_init();
+void uic_set(enum ui_coltype);
+
+
 /* updated when window is resized */
 extern int winrows, wincols;
 
@@ -60,16 +89,31 @@ void nccreate(int, int, const char *);
 /* printf something somewhere in the last created window */
 void ncprint(int, int, char *, ...);
 
-/* same as the w* functions of ncurses */
+/* Add a "tab" to a window */
+void nctab(int, int, int, char *);
+
+/* same as the w* functions of ncurses, with a color */
 #define ncaddstr(r, c, s) mvaddstr(subwinr+(r), subwinc+(c), s)
 #define  ncaddch(r, c, s)  mvaddch(subwinr+(r), subwinc+(c), s)
 #define   ncmove(r, c)        move(subwinr+(r), subwinc+(c))
 
+/* add stuff with a color */
+#define mvaddstrc(t, r, c, s) do { uic_set(t); mvaddstr(r, c, s); } while(0)
+#define  mvaddchc(t, r, c, s) do { uic_set(t);  mvaddch(r, c, s); } while(0)
+#define   addstrc(t,       s) do { uic_set(t);   addstr(      s); } while(0)
+#define    addchc(t,       s) do { uic_set(t);    addch(      s); } while(0)
+#define ncaddstrc(t, r, c, s) do { uic_set(t); ncaddstr(r, c, s); } while(0)
+#define  ncaddchc(t, r, c, s) do { uic_set(t);  ncaddch(r, c, s); } while(0)
+#define  mvhlinec(t, r, c, s, n) do { uic_set(t);  mvhline(r, c, s, n); } while(0)
+
 /* crops a string into the specified length */
 char *cropstr(const char *, int);
 
-/* formats size in the form of xxx.xXB */
-char *formatsize(int64_t );
+/* Converts the given size in bytes into a float (0 <= f < 1000) and a unit string */
+float formatsize(int64_t, char **);
+
+/* print size in the form of xxx.x XB */
+void printsize(enum ui_coltype, int64_t);
 
 /* int2string with thousand separators */
 char *fullsize(int64_t);
-- 
GitLab