From a369a43d94c3cd31f8b08bd9ea61fccc58ef6a33 Mon Sep 17 00:00:00 2001 From: Yorhel 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 | 29 +++---- src/main.c | 1 + src/util.c | 89 ++++++++++++++++----- src/util.h | 50 +++++++++++- 7 files changed, 276 insertions(+), 139 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); + ' '); + *x += 2; +} - /* create graph (if necessary) */ - if(graph) { - /* percentage */ - if((pc = (float)(show_as ? n->parent->asize : n->parent->size)) < 1) + +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, ']'); +} - if(n->flags & FF_BSEL) - attroff(A_REVERSE); + +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)); + } +} + + +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"); + ncaddstr(13, 42, "Press "); + uic_set(UIC_KEYNUM); + addch('q'); + uic_set(UIC_DEFAULT); + addstr(" 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); + 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 + +/* 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);