Annotation of embedaddon/bmon/src/out_curses.c, revision 1.1.1.3

1.1       misho       1: /*
                      2:  * out_curses.c          Curses Output
                      3:  *
1.1.1.2   misho       4:  * Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch>
                      5:  * Copyright (c) 2013 Red Hat, Inc.
1.1       misho       6:  *
                      7:  * Permission is hereby granted, free of charge, to any person obtaining a
                      8:  * copy of this software and associated documentation files (the "Software"),
                      9:  * to deal in the Software without restriction, including without limitation
                     10:  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
                     11:  * and/or sell copies of the Software, and to permit persons to whom the
                     12:  * Software is furnished to do so, subject to the following conditions:
                     13:  *
                     14:  * The above copyright notice and this permission notice shall be included
                     15:  * in all copies or substantial portions of the Software.
                     16:  *
                     17:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
                     18:  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     19:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     20:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     21:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
                     22:  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
                     23:  * DEALINGS IN THE SOFTWARE.
                     24:  */
                     25: 
                     26: #include <bmon/bmon.h>
                     27: #include <bmon/conf.h>
1.1.1.2   misho      28: #include <bmon/attr.h>
                     29: #include <bmon/element.h>
                     30: #include <bmon/element_cfg.h>
1.1       misho      31: #include <bmon/input.h>
1.1.1.2   misho      32: #include <bmon/history.h>
                     33: #include <bmon/graph.h>
1.1       misho      34: #include <bmon/output.h>
                     35: #include <bmon/utils.h>
                     36: 
1.1.1.2   misho      37: enum {
                     38:        GRAPH_DISPLAY_SIDE_BY_SIDE = 1,
                     39:        GRAPH_DISPLAY_STANDARD = 2,
                     40: };
                     41: 
                     42: enum {
                     43:        KEY_TOGGLE_LIST         = 'l',
                     44:        KEY_TOGGLE_GRAPH        = 'g',
                     45:        KEY_TOGGLE_DETAILS      = 'd',
                     46:        KEY_TOGGLE_INFO         = 'i',
                     47:        KEY_COLLECT_HISTORY     = 'h',
                     48: };
                     49: 
                     50: #define DETAILS_COLS           40
                     51: 
                     52: #define LIST_COL_1             31
                     53: #define LIST_COL_2             55
                     54: 
                     55: /* Set to element_current() before drawing */
                     56: static struct element *current_element;
                     57: 
                     58: static struct attr *current_attr;
                     59: 
                     60: /* Length of list to draw, updated in draw_content() */
                     61: static int list_length;
                     62: 
                     63: static int list_req;
                     64: 
                     65: /* Number of graphs to draw (may be < c_ngraph) */
                     66: static int ngraph;
                     67: 
                     68: /*
                     69:  * Offset in number of lines within the the element list of the currently
                     70:  * selected element. Updated while summing up required lines.
                     71:  */
                     72: static unsigned int selection_offset;
                     73: 
                     74: /*
                     75:  * Offset in number of lines of the first element to be drawn. Updated
                     76:  * in draw_content()
                     77:  */
                     78: static int offset;
                     79: 
                     80: /*
                     81:  * Offset to the first graph to draw in number of attributes with graphs.
                     82:  */
                     83: static unsigned int graph_offset;
                     84: 
                     85: static int graph_display = GRAPH_DISPLAY_STANDARD;
                     86: 
                     87: /*
                     88:  * Number of detail columns
                     89:  */
                     90: static int detail_cols;
                     91: static int info_cols;
                     92: 
1.1       misho      93: static int initialized;
1.1.1.2   misho      94: static int print_help;
                     95: static int quit_mode;
                     96: static int help_page;
                     97: 
                     98: /* Current row */
1.1       misho      99: static int row;
1.1.1.2   misho     100: 
                    101: /* Number of rows */
1.1       misho     102: static int rows;
1.1.1.2   misho     103: 
                    104: /* Number of columns */
1.1       misho     105: static int cols;
                    106: 
1.1.1.2   misho     107: static int c_show_graph = 1;
                    108: static int c_ngraph = 1;
1.1       misho     109: static int c_use_colors = 1;
1.1.1.2   misho     110: static int c_show_details = 0;
                    111: static int c_show_list = 1;
                    112: static int c_show_info = 0;
                    113: static int c_list_min = 6;
                    114: 
                    115: static struct graph_cfg c_graph_cfg = {
                    116:        .gc_width               = 60,
                    117:        .gc_height              = 6,
                    118:        .gc_foreground          = '|',
                    119:        .gc_background          = '.',
                    120:        .gc_noise               = ':',
                    121:        .gc_unknown             = '?',
                    122: };
                    123: 
                    124: #define NEXT_ROW()                     \
                    125:        do {                            \
                    126:                row++;                  \
                    127:                if (row >= rows - 1)    \
                    128:                        return;         \
                    129:                move(row, 0);           \
                    130:        } while(0)
                    131: 
                    132: static void apply_layout(int layout)
                    133: {
                    134:        if (c_use_colors)
                    135:                attrset(COLOR_PAIR(layout) | cfg_layout[layout].l_attr);
                    136:        else
                    137:                attrset(cfg_layout[layout].l_attr);
                    138: }
                    139: 
1.1.1.3 ! misho     140: static char *float2str(double value, int width, int prec, char *buf, size_t len)
1.1.1.2   misho     141: {
                    142:        snprintf(buf, len, "%'*.*f", width, value == 0.0f ? 0 : prec, value);
1.1       misho     143: 
1.1.1.2   misho     144:        return buf;
1.1       misho     145: }
                    146: 
1.1.1.2   misho     147: static void put_line(const char *fmt, ...)
1.1       misho     148: {
1.1.1.2   misho     149:        va_list args;
                    150:        char buf[2048];
1.1.1.3 ! misho     151:        int x, y __unused__;
1.1       misho     152: 
1.1.1.2   misho     153:        memset(buf, 0, sizeof(buf));
                    154:        getyx(stdscr, y, x);
1.1       misho     155: 
1.1.1.2   misho     156:        va_start(args, fmt);
                    157:        vsnprintf(buf, sizeof(buf), fmt, args);
                    158:        va_end(args);
1.1       misho     159: 
1.1.1.2   misho     160:        if (strlen(buf) > cols-x)
                    161:                buf[cols - x] = '\0';
                    162:        else
                    163:                memset(&buf[strlen(buf)], ' ', cols - strlen(buf)-x);
1.1       misho     164: 
1.1.1.2   misho     165:        addstr(buf);
1.1       misho     166: }
                    167: 
1.1.1.2   misho     168: static void center_text(const char *fmt, ...)
1.1       misho     169: {
1.1.1.2   misho     170:        va_list args;
                    171:        char *str;
                    172:        unsigned int col;
                    173: 
                    174:        va_start(args, fmt);
1.1.1.3 ! misho     175:        if (vasprintf(&str, fmt, args) < 0) {
        !           176:                fprintf(stderr, "vasprintf: Out of memory\n");
        !           177:                exit(ENOMEM);
        !           178:        }
1.1.1.2   misho     179:        va_end(args);
                    180: 
                    181:        col = (cols / 2) - (strlen(str) / 2);
                    182:        if (col > cols - 1)
                    183:                col = cols - 1;
                    184: 
                    185:        move(row, col);
                    186:        addstr(str);
                    187:        move(row, 0);
                    188: 
                    189:        free(str);
                    190: }
                    191: 
                    192: static int curses_init(void)
                    193: {
                    194:        if (!initscr()) {
                    195:                fprintf(stderr, "Unable to initialize curses screen\n");
                    196:                return -EOPNOTSUPP;
                    197:        }
1.1       misho     198: 
                    199:        initialized = 1;
                    200:        
                    201:        if (!has_colors())
                    202:                c_use_colors = 0;
                    203: 
                    204:        if (c_use_colors) {
                    205:                int i;
                    206:                
                    207:                start_color();
                    208: 
                    209: #if defined HAVE_USE_DEFAULT_COLORS
                    210:                use_default_colors();
                    211: #endif
1.1.1.2   misho     212:                for (i = 1; i < LAYOUT_MAX+1; i++)
                    213:                        init_pair(i, cfg_layout[i].l_fg, cfg_layout[i].l_bg);
1.1       misho     214:        }
                    215:                
                    216:        keypad(stdscr, TRUE);
                    217:        nonl();
                    218:        cbreak();
                    219:        noecho();
                    220:        nodelay(stdscr, TRUE);    /* getch etc. must be non-blocking */
                    221:        clear();
                    222:        curs_set(0);
1.1.1.2   misho     223: 
                    224:        return 0;
1.1       misho     225: }
                    226: 
                    227: static void curses_shutdown(void)
                    228: {
                    229:        if (initialized)
                    230:                endwin();
                    231: }
                    232: 
1.1.1.2   misho     233: struct detail_arg
1.1       misho     234: {
1.1.1.2   misho     235:        int nattr;
                    236: };
1.1       misho     237: 
1.1.1.2   misho     238: static void draw_attr_detail(struct element *e, struct attr *a, void *arg)
                    239: {
                    240:        char *rx_u, *tx_u, buf1[32], buf2[32];
                    241:        int rxprec, txprec, ncol;
                    242:        struct detail_arg *da = arg;
                    243: 
1.1.1.3 ! misho     244:        double rx = unit_value2str(rate_get_total(&a->a_rx_rate),
1.1.1.2   misho     245:                                   a->a_def->ad_unit,
                    246:                                   &rx_u, &rxprec);
1.1.1.3 ! misho     247:        double tx = unit_value2str(rate_get_total(&a->a_tx_rate),
1.1.1.2   misho     248:                                   a->a_def->ad_unit,
                    249:                                   &tx_u, &txprec);
                    250: 
                    251:        if (da->nattr >= detail_cols) {
                    252:                NEXT_ROW();
                    253:                da->nattr = 0;
                    254:        }
                    255: 
                    256:        ncol = (da->nattr * DETAILS_COLS) - 1;
                    257:        move(row, ncol);
                    258:        if (ncol > 0)
                    259:                addch(ACS_VLINE);
1.1       misho     260: 
1.1.1.3 ! misho     261:        put_line(" %-14.14s %8s%-3s %8s%-3s",
1.1.1.2   misho     262:                 a->a_def->ad_description,
                    263:                 (a->a_flags & ATTR_RX_ENABLED) ?
                    264:                 float2str(rx, 8, rxprec, buf1, sizeof(buf1)) : "-", rx_u,
                    265:                 (a->a_flags & ATTR_TX_ENABLED) ?
                    266:                 float2str(tx, 8, txprec, buf2, sizeof(buf2)) : "-", tx_u);
1.1       misho     267: 
1.1.1.2   misho     268:        da->nattr++;
                    269: }
1.1       misho     270: 
1.1.1.2   misho     271: static void draw_details(void)
                    272: {
                    273:        int i;
                    274:        struct detail_arg arg = {
                    275:                .nattr = 0,
                    276:        };
1.1       misho     277: 
1.1.1.2   misho     278:        if (!current_element->e_nattrs)
                    279:                return;
1.1       misho     280: 
1.1.1.2   misho     281:        for (i = 1; i < detail_cols; i++)
                    282:                mvaddch(row, (i * DETAILS_COLS) - 1, ACS_TTEE);
1.1       misho     283: 
1.1.1.2   misho     284:        NEXT_ROW();
                    285:        put_line("");
                    286:        for (i = 0; i < detail_cols; i++) {
                    287:                if (i > 0)
                    288:                        mvaddch(row, (i * DETAILS_COLS) - 1, ACS_VLINE);
                    289:                move(row, (i * DETAILS_COLS) + 22);
                    290:                put_line("RX          TX");
1.1       misho     291:        }
                    292: 
1.1.1.2   misho     293:        NEXT_ROW();
                    294:        element_foreach_attr(current_element, draw_attr_detail, &arg);
                    295: 
                    296:        /*
                    297:         * If the last row was incomplete, not all vlines have been drawn.
                    298:         * draw them here
                    299:         */
                    300:        for (i = 1; i < detail_cols; i++)
                    301:                mvaddch(row, (i * DETAILS_COLS - 1), ACS_VLINE);
                    302: }
                    303: 
                    304: static void print_message(const char *text)
                    305: {
                    306:        int i, y = (rows/2) - 2;
                    307:        int len = strlen(text);
                    308:        int x = (cols/2) - (len / 2);
                    309: 
                    310:        attrset(A_STANDOUT);
                    311:        mvaddch(y - 2, x - 1, ACS_ULCORNER);
                    312:        mvaddch(y + 2, x - 1, ACS_LLCORNER);
                    313:        mvaddch(y - 2, x + len, ACS_URCORNER);
                    314:        mvaddch(y + 2, x + len, ACS_LRCORNER);
                    315: 
                    316:        for (i = 0; i < 3; i++) {
                    317:                mvaddch(y - 1 + i, x + len, ACS_VLINE);
                    318:                mvaddch(y - 1 + i, x - 1 ,ACS_VLINE);
1.1       misho     319:        }
                    320: 
1.1.1.2   misho     321:        for (i = 0; i < len; i++) {
                    322:                mvaddch(y - 2, x + i, ACS_HLINE);
                    323:                mvaddch(y - 1, x + i, ' ');
                    324:                mvaddch(y + 1, x + i, ' ');
                    325:                mvaddch(y + 2, x + i, ACS_HLINE);
1.1       misho     326:        }
                    327: 
1.1.1.2   misho     328:        mvaddstr(y, x, text);
                    329:        attroff(A_STANDOUT);
                    330: 
                    331:        row = y + 2;
                    332: }
                    333: 
                    334: static void draw_help(void)
                    335: {
                    336: #define HW 46
                    337: #define HH 19
                    338:        int i, y = (rows/2) - (HH/2);
                    339:        int x = (cols/2) - (HW/2);
                    340:        char pad[HW+1];
                    341: 
                    342:        memset(pad, ' ', sizeof(pad));
                    343:        pad[sizeof(pad) - 1] = '\0';
                    344: 
                    345:        attron(A_STANDOUT);
                    346: 
                    347:        for (i = 0; i < HH; i++)
                    348:                mvaddnstr(y + i, x, pad, -1);
                    349: 
                    350:        mvaddch(y  - 1, x - 1, ACS_ULCORNER);
                    351:        mvaddch(y + HH, x - 1, ACS_LLCORNER);
                    352:        
                    353:        mvaddch(y  - 1, x + HW, ACS_URCORNER);
                    354:        mvaddch(y + HH, x + HW, ACS_LRCORNER);
1.1       misho     355: 
1.1.1.2   misho     356:        for (i = 0; i < HH; i++) {
                    357:                mvaddch(y + i, x -  1, ACS_VLINE);
                    358:                mvaddch(y + i, x + HW, ACS_VLINE);
1.1       misho     359:        }
                    360: 
1.1.1.2   misho     361:        for (i = 0; i < HW; i++) {
                    362:                mvaddch(y  - 1, x + i, ACS_HLINE);
                    363:                mvaddch(y + HH, x + i, ACS_HLINE);
1.1       misho     364:        }
                    365: 
1.1.1.2   misho     366:        attron(A_BOLD);
                    367:        mvaddnstr(y- 1, x+15, "QUICK REFERENCE", -1);
                    368:        attron(A_UNDERLINE);
                    369:        mvaddnstr(y+ 0, x+1, "Navigation", -1);
                    370:        attroff(A_BOLD | A_UNDERLINE);
                    371: 
                    372:        mvaddnstr(y+ 1, x+3, "Up, Down      Previous/Next element", -1);
                    373:        mvaddnstr(y+ 2, x+3, "PgUp, PgDown  Scroll up/down entire page", -1);
                    374:        mvaddnstr(y+ 3, x+3, "Left, Right   Previous/Next attribute", -1);
                    375:        mvaddnstr(y+ 4, x+3, "[, ]          Previous/Next group", -1);
                    376:        mvaddnstr(y+ 5, x+3, "?             Toggle quick reference", -1);
                    377:        mvaddnstr(y+ 6, x+3, "q             Quit bmon", -1);
                    378: 
                    379:        attron(A_BOLD | A_UNDERLINE);
                    380:        mvaddnstr(y+ 8, x+1, "Display Settings", -1);
                    381:        attroff(A_BOLD | A_UNDERLINE);
                    382: 
                    383:        mvaddnstr(y+ 9, x+3, "d             Toggle detailed statistics", -1);
                    384:        mvaddnstr(y+10, x+3, "l             Toggle element list", -1);
                    385:        mvaddnstr(y+11, x+3, "i             Toggle additional info", -1);
                    386: 
                    387:        attron(A_BOLD | A_UNDERLINE);
                    388:        mvaddnstr(y+13, x+1, "Graph Settings", -1);
                    389:        attroff(A_BOLD | A_UNDERLINE);
                    390: 
                    391:        mvaddnstr(y+14, x+3, "g             Toggle graphical statistics", -1);
                    392:        mvaddnstr(y+15, x+3, "H             Start recording history data", -1);
                    393:        mvaddnstr(y+16, x+3, "TAB           Switch time unit of graph", -1);
                    394:        mvaddnstr(y+17, x+3, "<, >          Change number of graphs", -1);
1.1.1.3 ! misho     395:        mvaddnstr(y+18, x+3, "r             Reset counter of element", -1);
1.1.1.2   misho     396: 
                    397:        attroff(A_STANDOUT);
                    398: 
                    399:        row = y + HH;
                    400: }
                    401: 
                    402: static int lines_required_for_header(void)
                    403: {
                    404:        return 1;
1.1       misho     405: }
                    406: 
1.1.1.2   misho     407: static void draw_header(void)
1.1       misho     408: {
1.1.1.2   misho     409:        apply_layout(LAYOUT_STATUSBAR);
1.1       misho     410: 
1.1.1.2   misho     411:        if (current_element)
                    412:                put_line(" %s %c%s%c",
                    413:                        current_element->e_name,
                    414:                        current_element->e_description ? '(' : ' ',
                    415:                        current_element->e_description ? : "",
                    416:                        current_element->e_description ? ')' : ' ');
                    417:        else
                    418:                put_line("");
                    419: 
                    420:        move(row, COLS - strlen(PACKAGE_STRING) - 1);
                    421:        put_line("%s", PACKAGE_STRING);
                    422:        move(row, 0);
1.1.1.3 ! misho     423:        apply_layout(LAYOUT_LIST);
1.1       misho     424: }
                    425: 
1.1.1.2   misho     426: static int lines_required_for_statusbar(void)
                    427: {
                    428:        return 1;
                    429: }
1.1       misho     430: 
1.1.1.2   misho     431: static void draw_statusbar(void)
1.1       misho     432: {
1.1.1.2   misho     433:        static const char *help_text = "Press ? for help";
                    434:        char s[27];
1.1.1.3 ! misho     435:        time_t t = time(NULL);
1.1       misho     436: 
1.1.1.2   misho     437:        apply_layout(LAYOUT_STATUSBAR);
1.1       misho     438: 
1.1.1.2   misho     439:        asctime_r(localtime(&t), s);
                    440:        s[strlen(s) - 1] = '\0';
                    441:        
                    442:        row = rows-1;
                    443:        move(row, 0);
                    444:        put_line(" %s", s);
                    445: 
                    446:        move(row, COLS - strlen(help_text) - 1);
                    447:        put_line("%s", help_text);
                    448: 
                    449:        move(row, 0);
1.1       misho     450: }
                    451: 
1.1.1.2   misho     452: static void count_attr_graph(struct element *g, struct attr *a, void *arg)
                    453: {
                    454:        if (a == current_attr)
                    455:                graph_offset = ngraph;
                    456: 
                    457:        ngraph++;
                    458: }
1.1       misho     459: 
1.1.1.2   misho     460: static int lines_required_for_graph(void)
1.1       misho     461: {
1.1.1.2   misho     462:        int lines = 0;
1.1       misho     463: 
1.1.1.2   misho     464:        ngraph = 0;
1.1       misho     465: 
1.1.1.2   misho     466:        if (c_show_graph && current_element) {
                    467:                graph_display = GRAPH_DISPLAY_STANDARD;
1.1       misho     468: 
1.1.1.2   misho     469:                element_foreach_attr(current_element, count_attr_graph, NULL);
1.1       misho     470: 
1.1.1.2   misho     471:                if (ngraph > c_ngraph)
                    472:                        ngraph = c_ngraph;
1.1       misho     473: 
1.1.1.2   misho     474:                /* check if we have room to draw graphs on the same level */
                    475:                if (cols > (2 * (c_graph_cfg.gc_width + 10)))
                    476:                        graph_display = GRAPH_DISPLAY_SIDE_BY_SIDE;
1.1       misho     477: 
1.1.1.2   misho     478:                /* +2 = header + time axis */
                    479:                lines = ngraph * (graph_display * (c_graph_cfg.gc_height + 2));
                    480:        }
1.1       misho     481: 
1.1.1.2   misho     482:        return lines + 1;
                    483: }
1.1       misho     484: 
1.1.1.2   misho     485: static int lines_required_for_details(void)
                    486: {
                    487:        int lines = 1;
1.1       misho     488: 
1.1.1.2   misho     489:        if (c_show_details && current_element) {
                    490:                lines++;        /* header */
1.1       misho     491: 
1.1.1.2   misho     492:                detail_cols = cols / DETAILS_COLS;
                    493: 
                    494:                if (!detail_cols)
                    495:                        detail_cols = 1;
                    496: 
                    497:                lines += (current_element->e_nattrs / detail_cols);
                    498:                if (current_element->e_nattrs % detail_cols)
                    499:                        lines++;
1.1       misho     500:        }
                    501: 
1.1.1.2   misho     502:        return lines;
1.1       misho     503: }
                    504: 
1.1.1.2   misho     505: static void count_element_lines(struct element_group *g, struct element *e,
                    506:                                void *arg)
1.1       misho     507: {
1.1.1.2   misho     508:        int *lines = arg;
1.1       misho     509: 
1.1.1.2   misho     510:        if (e == current_element)
                    511:                selection_offset = *lines;
                    512:        
                    513:        (*lines)++;
1.1       misho     514: }
                    515: 
1.1.1.2   misho     516: static void count_group_lines(struct element_group *g, void *arg)
1.1       misho     517: {
1.1.1.2   misho     518:        int *lines = arg;
                    519: 
                    520:        /* group title */
                    521:        (*lines)++;
                    522: 
                    523:        group_foreach_element(g, &count_element_lines, arg);
1.1       misho     524: }
                    525: 
1.1.1.2   misho     526: static int lines_required_for_list(void)
1.1       misho     527: {
1.1.1.2   misho     528:        int lines = 0;
1.1       misho     529: 
1.1.1.2   misho     530:        if (c_show_list)
                    531:                group_foreach(&count_group_lines, &lines);
                    532:        else
                    533:                lines = 1;
1.1       misho     534: 
1.1.1.2   misho     535:        return lines;
                    536: }
1.1       misho     537: 
1.1.1.2   misho     538: static inline int line_visible(int line)
                    539: {
                    540:        return line >= offset && line < (offset + list_length);
                    541: }
1.1       misho     542: 
1.1.1.2   misho     543: static void draw_attr(double rate1, int prec1, char *unit1,
                    544:                      double rate2, int prec2, char *unit2,
                    545:                      float usage, int ncol)
                    546: {
                    547:        char buf[32];
1.1       misho     548: 
1.1.1.2   misho     549:        move(row, ncol);
                    550:        addch(ACS_VLINE);
                    551:        printw("%7s%-3s",
                    552:                float2str(rate1, 7, prec1, buf, sizeof(buf)), unit1);
1.1       misho     553: 
1.1.1.2   misho     554:        printw("%7s%-3s",
                    555:                float2str(rate2, 7, prec2, buf, sizeof(buf)), unit2);
1.1       misho     556: 
1.1.1.2   misho     557:        if (usage != FLT_MAX)
                    558:                printw("%2.0f%%", usage);
                    559:        else
                    560:                printw("%3s", "");
1.1       misho     561: }
                    562: 
1.1.1.2   misho     563: static void draw_element(struct element_group *g, struct element *e,
                    564:                         void *arg)
1.1       misho     565: {
1.1.1.2   misho     566:        int *line = arg;
                    567: 
                    568:        apply_layout(LAYOUT_LIST);
                    569: 
                    570:        if (line_visible(*line)) {
                    571:                char *rxu1 = "", *txu1 = "", *rxu2 = "", *txu2 = "";
                    572:                double rx1 = 0.0f, tx1 = 0.0f, rx2 = 0.0f, tx2 = 0.0f;
                    573:                char pad[IFNAMSIZ + 32];
                    574:                int rx1prec = 0, tx1prec = 0, rx2prec = 0, tx2prec = 0;
                    575:                struct attr *a;
1.1       misho     576: 
1.1.1.2   misho     577:                NEXT_ROW();
1.1       misho     578: 
1.1.1.2   misho     579:                if (e->e_key_attr[GT_MAJOR] &&
                    580:                    (a = attr_lookup(e, e->e_key_attr[GT_MAJOR]->ad_id)))
                    581:                        attr_rate2float(a, &rx1, &rxu1, &rx1prec,
                    582:                                        &tx1, &txu1, &tx1prec);
1.1       misho     583: 
1.1.1.2   misho     584:                if (e->e_key_attr[GT_MINOR] &&
                    585:                    (a = attr_lookup(e, e->e_key_attr[GT_MINOR]->ad_id)))
                    586:                        attr_rate2float(a, &rx2, &rxu2, &rx2prec,
                    587:                                        &tx2, &txu2, &tx2prec);
                    588: 
                    589:                memset(pad, 0, sizeof(pad));
                    590:                memset(pad, ' ', e->e_level < 6 ? e->e_level * 2 : 12);
                    591: 
                    592:                strncat(pad, e->e_name, sizeof(pad) - strlen(pad) - 1);
                    593: 
                    594:                if (e->e_description) {
                    595:                        strncat(pad, " (", sizeof(pad) - strlen(pad) - 1);
                    596:                        strncat(pad, e->e_description, sizeof(pad) - strlen(pad) - 1);
                    597:                        strncat(pad, ")", sizeof(pad) - strlen(pad) - 1);
1.1       misho     598:                }
1.1.1.2   misho     599: 
                    600:                if (*line == offset) {
                    601:                        attron(A_BOLD);
                    602:                        addch(ACS_UARROW);
                    603:                        attroff(A_BOLD);
                    604:                        addch(' ');
                    605:                } else if (e == current_element) {
                    606:                        apply_layout(LAYOUT_SELECTED);
                    607:                        addch(' ');
                    608:                        attron(A_BOLD);
                    609:                        addch(ACS_RARROW);
                    610:                        attroff(A_BOLD);
                    611:                        apply_layout(LAYOUT_LIST);
                    612:                } else if (*line == offset + list_length - 1 &&
                    613:                           *line < (list_req - 1)) {
                    614:                        attron(A_BOLD);
                    615:                        addch(ACS_DARROW);
                    616:                        attroff(A_BOLD);
                    617:                        addch(' ');
                    618:                } else
                    619:                        printw("  ");
                    620: 
                    621:                put_line("%-30.30s", pad);
                    622: 
                    623:                draw_attr(rx1, rx1prec, rxu1, rx2, rx2prec, rxu2,
                    624:                          e->e_rx_usage, LIST_COL_1);
1.1       misho     625:        
1.1.1.2   misho     626:                draw_attr(tx1, tx1prec, txu1, tx2, tx2prec, txu2,
                    627:                          e->e_tx_usage, LIST_COL_2);
                    628:                
                    629:        }
                    630: 
                    631:        (*line)++;
1.1       misho     632: }
                    633: 
1.1.1.2   misho     634: static void draw_group(struct element_group *g, void *arg)
1.1       misho     635: {
1.1.1.3 ! misho     636:        apply_layout(LAYOUT_HEADER);
1.1.1.2   misho     637:        int *line = arg;
1.1       misho     638: 
1.1.1.2   misho     639:        if (line_visible(*line)) {
                    640:                NEXT_ROW();
                    641:                attron(A_BOLD);
                    642:                put_line("%s", g->g_hdr->gh_title);
1.1       misho     643: 
1.1.1.2   misho     644:                attroff(A_BOLD);
                    645:                mvaddch(row, LIST_COL_1, ACS_VLINE);
                    646:                attron(A_BOLD);
                    647:                put_line("%7s   %7s     %%",
                    648:                        g->g_hdr->gh_column[0],
                    649:                        g->g_hdr->gh_column[1]);
1.1       misho     650: 
1.1.1.2   misho     651:                attroff(A_BOLD);
                    652:                mvaddch(row, LIST_COL_2, ACS_VLINE);
                    653:                attron(A_BOLD);
                    654:                put_line("%7s   %7s     %%",
                    655:                        g->g_hdr->gh_column[2],
                    656:                        g->g_hdr->gh_column[3]);
1.1       misho     657:        }
1.1.1.2   misho     658: 
                    659:        (*line)++;
                    660: 
                    661:        group_foreach_element(g, draw_element, arg);
1.1       misho     662: }
                    663: 
1.1.1.2   misho     664: static void draw_element_list(void)
1.1       misho     665: {
1.1.1.2   misho     666:        int line = 0;
1.1       misho     667: 
1.1.1.2   misho     668:        group_foreach(draw_group, &line);
                    669: }
1.1       misho     670: 
1.1.1.2   misho     671: static inline int attr_visible(int nattr)
                    672: {
                    673:        return nattr >= graph_offset && nattr < (graph_offset + ngraph);
                    674: }
1.1       misho     675: 
1.1.1.2   misho     676: static void draw_graph_centered(struct graph *g, int row, int ncol,
                    677:                                const char *text)
                    678: {
                    679:        int hcenter = (g->g_cfg.gc_width / 2) - (strlen(text) / 2) + 8;
                    680: 
                    681:        if (hcenter < 9)
                    682:                hcenter = 9;
                    683: 
                    684:        mvprintw(row, ncol + hcenter, "%.*s", g->g_cfg.gc_width, text);
1.1       misho     685: }
                    686: 
1.1.1.2   misho     687: static void draw_table(struct graph *g, struct graph_table *tbl,
                    688:                       struct attr *a, struct history *h,
1.1.1.3 ! misho     689:                       const char *hdr, int ncol, int layout)
1.1       misho     690: {
1.1.1.2   misho     691:        int i, save_row;
                    692:        char buf[32];
1.1       misho     693: 
1.1.1.2   misho     694:        if (!tbl->gt_table) {
                    695:                for (i = g->g_cfg.gc_height; i >= 0; i--) {
                    696:                        move(++row, ncol);
                    697:                        put_line("");
                    698:                }
                    699:                return;
                    700:        }
1.1       misho     701: 
1.1.1.2   misho     702:        move(++row, ncol);
                    703:        put_line("%8s", tbl->gt_y_unit ? : "");
                    704: 
                    705:        snprintf(buf, sizeof(buf), "(%s %s/%s)",
                    706:                 hdr, a->a_def->ad_description,
                    707:                 h ? h->h_definition->hd_name : "?");
                    708: 
                    709:        draw_graph_centered(g, row, ncol, buf);
                    710: 
                    711:        //move(row, ncol + g->g_cfg.gc_width - 3);
                    712:        //put_line("[err %.2f%%]", rtiming.rt_variance.v_error);
                    713: 
1.1.1.3 ! misho     714:     memset(buf, 0, strlen(buf));
1.1.1.2   misho     715:        for (i = (g->g_cfg.gc_height - 1); i >= 0; i--) {
                    716:                move(++row, ncol);
1.1.1.3 ! misho     717:         sprintf(buf, "%'8.2f ", tbl->gt_scale[i]);
        !           718:         addstr(buf);
        !           719:         apply_layout(layout);
        !           720:         put_line("%s", tbl->gt_table + (i * graph_row_size(&g->g_cfg)));
        !           721:         apply_layout(LAYOUT_LIST);
1.1       misho     722:        }
                    723: 
1.1.1.2   misho     724:        move(++row, ncol);
                    725:        put_line("         1");
                    726: 
                    727:        for (i = 1; i <= g->g_cfg.gc_width; i++) {
                    728:                if (i % 5 == 0) {
                    729:                        move(row, ncol + i + 7);
                    730:                        printw("%2d", i);
                    731:                }
1.1       misho     732:        }
                    733: 
1.1.1.2   misho     734:        if (!h) {
                    735:                const char *t1 = " No history data available. ";
                    736:                const char *t2 = " Press h to start collecting history. ";
                    737:                int vcenter = g->g_cfg.gc_height / 2;
                    738: 
                    739:                save_row = row;
                    740:                draw_graph_centered(g, save_row - vcenter - 1, ncol, t1);
                    741:                draw_graph_centered(g, save_row - vcenter, ncol, t2);
                    742:                row = save_row;
                    743:        }
1.1       misho     744: }
                    745: 
1.1.1.2   misho     746: static void draw_history_graph(struct attr *a, struct history *h)
1.1       misho     747: {
1.1.1.2   misho     748:        struct graph *g;
                    749:        int ncol = 0, save_row;
1.1       misho     750: 
1.1.1.2   misho     751:        g = graph_alloc(h, &c_graph_cfg);
                    752:        graph_refill(g, h);
1.1       misho     753: 
1.1.1.2   misho     754:        save_row = row;
1.1.1.3 ! misho     755:        draw_table(g, &g->g_rx, a, h, "RX", ncol, LAYOUT_RX_GRAPH);
1.1       misho     756: 
1.1.1.2   misho     757:        if (graph_display == GRAPH_DISPLAY_SIDE_BY_SIDE) {
                    758:                ncol = cols / 2;
                    759:                row = save_row;
                    760:        }
1.1       misho     761: 
1.1.1.3 ! misho     762:        draw_table(g, &g->g_tx, a, h, "TX", ncol, LAYOUT_TX_GRAPH);
1.1       misho     763: 
1.1.1.2   misho     764:        graph_free(g);
                    765: }
1.1       misho     766: 
1.1.1.2   misho     767: static void draw_attr_graph(struct element *e, struct attr *a, void *arg)
                    768: {
                    769:        int *nattr = arg;
1.1       misho     770: 
1.1.1.2   misho     771:        if (attr_visible(*nattr)) {
                    772:                struct history_def *sel;
                    773:                struct history *h;
1.1       misho     774: 
1.1.1.2   misho     775:                sel = history_current();
                    776:                c_graph_cfg.gc_unit = a->a_def->ad_unit;
1.1       misho     777: 
1.1.1.2   misho     778:                list_for_each_entry(h, &a->a_history_list, h_list) {
                    779:                        if (h->h_definition != sel)
                    780:                                continue;
1.1       misho     781: 
1.1.1.2   misho     782:                        draw_history_graph(a, h);
                    783:                        goto out;
                    784:                }
1.1       misho     785: 
1.1.1.2   misho     786:                draw_history_graph(a, NULL);
                    787:        }
                    788: 
                    789: out:
                    790:        (*nattr)++;
1.1       misho     791: }
                    792: 
1.1.1.2   misho     793: static void draw_graph(void)
1.1       misho     794: {
1.1.1.2   misho     795:        int nattr = 0;
1.1       misho     796: 
1.1.1.2   misho     797:        element_foreach_attr(current_element, &draw_attr_graph, &nattr);
                    798: }
1.1       misho     799: 
1.1.1.2   misho     800: static int lines_required_for_info(void)
                    801: {
                    802:        int lines = 1;
1.1       misho     803: 
1.1.1.2   misho     804:        if (c_show_info) {
                    805:                info_cols = cols / DETAILS_COLS;
1.1       misho     806: 
1.1.1.2   misho     807:                if (!info_cols)
                    808:                        info_cols = 1;
1.1       misho     809: 
1.1.1.2   misho     810:                lines += (current_element->e_ninfo / info_cols);
                    811:                if (current_element->e_ninfo % info_cols)
                    812:                        lines++;
1.1       misho     813:        }
                    814: 
1.1.1.2   misho     815:        return lines;
                    816: }
                    817: 
                    818: static void __draw_info(struct element *e, struct info *info, int *ninfo)
                    819: {
                    820:        int ncol;
                    821: 
                    822:        ncol = ((*ninfo) * DETAILS_COLS) - 1;
                    823:        move(row, ncol);
                    824:        if (ncol > 0)
                    825:                addch(ACS_VLINE);
                    826: 
                    827:        put_line(" %-14.14s %22.22s", info->i_name, info->i_value);
                    828: 
                    829:        if (++(*ninfo) >= info_cols) {
                    830:                NEXT_ROW();
                    831:                *ninfo = 0;
1.1       misho     832:        }
1.1.1.2   misho     833: }
1.1       misho     834: 
1.1.1.2   misho     835: static void draw_info(void)
                    836: {
                    837:        struct info *info;
                    838:        int i, ninfo = 0;
1.1       misho     839: 
1.1.1.2   misho     840:        if (!current_element->e_ninfo)
                    841:                return;
1.1       misho     842: 
1.1.1.2   misho     843:        for (i = 1; i < detail_cols; i++)
                    844:                mvaddch(row, (i * DETAILS_COLS) - 1,
                    845:                        c_show_details ? ACS_PLUS : ACS_TTEE);
                    846: 
                    847:        NEXT_ROW();
                    848:        list_for_each_entry(info, &current_element->e_info_list, i_list)
                    849:                __draw_info(current_element, info, &ninfo);
1.1       misho     850: 
1.1.1.2   misho     851:        /*
                    852:         * If the last row was incomplete, not all vlines have been drawn.
                    853:         * draw them here
                    854:         */
                    855:        for (i = 1; i < info_cols; i++)
                    856:                mvaddch(row, (i * DETAILS_COLS - 1), ACS_VLINE);
1.1       misho     857: }
                    858: 
1.1.1.2   misho     859: static void draw_content(void)
1.1       misho     860: {
1.1.1.2   misho     861:        int graph_req, details_req, lines_available, total_req;
                    862:        int info_req, empty_lines;
                    863:        int disable_graph = 0, disable_details = 0, disable_info = 0;
1.1       misho     864: 
1.1.1.2   misho     865:        if (!current_element)
1.1       misho     866:                return;
                    867: 
1.1.1.2   misho     868:        /*
                    869:         * Reset selection offset. Will be set in lines_required_for_list().
                    870:         */
                    871:        selection_offset = 0;
                    872:        offset = 0;
1.1       misho     873: 
1.1.1.2   misho     874:        /* Reset graph offset, will be set in lines_required_for_graph() */
                    875:        graph_offset = 0;
1.1       misho     876: 
1.1.1.2   misho     877:        lines_available = rows - lines_required_for_statusbar()
                    878:                          - lines_required_for_header();
1.1       misho     879: 
1.1.1.2   misho     880:        list_req = lines_required_for_list();
                    881:        graph_req = lines_required_for_graph();
                    882:        details_req = lines_required_for_details();
                    883:        info_req = lines_required_for_info();
                    884: 
                    885:        total_req = list_req + graph_req + details_req + info_req;
                    886: 
                    887:        if (total_req <= lines_available) {
                    888:                /*
                    889:                 * Enough lines available for all data to displayed, all
                    890:                 * is good. Display the full list.
                    891:                 */
                    892:                list_length = list_req;
                    893:                goto draw;
1.1       misho     894:        }
                    895: 
                    896:        /*
1.1.1.2   misho     897:         * Not enough lines available for full list and all details
                    898:         * requested...
1.1       misho     899:         */
                    900: 
1.1.1.2   misho     901:        if (c_show_list) {
                    902:                /*
                    903:                 * ... try shortening the list first.
                    904:                 */
                    905:                list_length = lines_available - (total_req - list_req);
                    906:                if (list_length >= c_list_min)
                    907:                        goto draw;
                    908:        }
                    909: 
                    910:        if (c_show_info) {
                    911:                /* try disabling info */
                    912:                list_length = lines_available - (total_req - info_req + 1);
                    913:                if (list_length >= c_list_min) {
                    914:                        disable_info = 1;
                    915:                        goto draw;
                    916:                }
                    917:        }
                    918: 
                    919:        if (c_show_details) {
                    920:                /* ... try disabling details */
                    921:                list_length = lines_available - (total_req - details_req + 1);
                    922:                if (list_length >= c_list_min) {
                    923:                        disable_details = 1;
                    924:                        goto draw;
                    925:                }
                    926:        }
1.1       misho     927: 
1.1.1.2   misho     928:        /* ... try disabling graph, details, and info */
                    929:        list_length = lines_available - 1 - 1 - 1;
                    930:        if (list_length >= c_list_min) {
                    931:                disable_graph = 1;
                    932:                disable_details = 1;
                    933:                disable_info = 1;
                    934:                goto draw;
                    935:        }
                    936: 
                    937:        NEXT_ROW();
                    938:        put_line("A minimum of %d lines is required to display content.\n",
                    939:                 (rows - lines_available) + c_list_min + 2);
                    940:        return;
                    941: 
                    942: draw:
                    943:        if (selection_offset && list_length > 0) {
1.1       misho     944:                /*
1.1.1.2   misho     945:                 * Vertically align the selected element in the middle
                    946:                 * of the list.
1.1       misho     947:                 */
1.1.1.2   misho     948:                offset = selection_offset - (list_length / 2);
1.1       misho     949: 
                    950:                /*
1.1.1.2   misho     951:                 * If element 0..(list_length/2) is selected, offset is
                    952:                 * negative here. Start drawing from first element.
1.1       misho     953:                 */
1.1.1.2   misho     954:                if (offset < 0)
                    955:                        offset = 0;
1.1       misho     956: 
1.1.1.2   misho     957:                /*
                    958:                 * Ensure the full list length is used if one of the
                    959:                 * last (list_length/2) elements is selected.
                    960:                 */
                    961:                if (offset > (list_req - list_length))
                    962:                        offset = (list_req - list_length);
1.1       misho     963: 
1.1.1.2   misho     964:                if (offset >= list_req)
                    965:                        BUG();
                    966:        }
                    967: 
                    968:        if (c_show_list) {
                    969:                draw_element_list();
                    970:        } else {
                    971:                NEXT_ROW();
                    972:                hline(ACS_HLINE, cols);
                    973:                center_text(" Press %c to enable list view ",
                    974:                            KEY_TOGGLE_LIST);
1.1       misho     975:        }
                    976: 
                    977:        /*
1.1.1.2   misho     978:         * Graphical statistics
1.1       misho     979:         */
1.1.1.2   misho     980:        NEXT_ROW();
                    981:        hline(ACS_HLINE, cols);
                    982:        mvaddch(row, LIST_COL_1, ACS_BTEE);
                    983:        mvaddch(row, LIST_COL_2, ACS_BTEE);
                    984: 
                    985:        if (!c_show_graph)
                    986:                center_text(" Press %c to enable graphical statistics ",
                    987:                            KEY_TOGGLE_GRAPH);
                    988:        else {
                    989:                if (disable_graph)
                    990:                        center_text(" Increase screen height to see graphical statistics ");
                    991:                else
                    992:                        draw_graph();
                    993:        }
                    994: 
                    995:        empty_lines = rows - row - details_req - info_req
                    996:                      - lines_required_for_statusbar() - 1;
                    997: 
                    998:        while (empty_lines-- > 0) {
                    999:                NEXT_ROW();
                   1000:                put_line("");
1.1       misho    1001:        }
                   1002: 
1.1.1.2   misho    1003:        /*
                   1004:         * Detailed statistics
                   1005:         */
                   1006:        NEXT_ROW();
1.1       misho    1007:        hline(ACS_HLINE, cols);
                   1008: 
1.1.1.2   misho    1009:        if (!c_show_details)
                   1010:                center_text(" Press %c to enable detailed statistics ",
                   1011:                            KEY_TOGGLE_DETAILS);
                   1012:        else {
                   1013:                if (disable_details)
                   1014:                        center_text(" Increase screen height to see detailed statistics ");
                   1015:                else
                   1016:                        draw_details();
1.1       misho    1017:        }
                   1018: 
1.1.1.2   misho    1019:        /*
                   1020:         * Additional information
                   1021:         */
                   1022:        NEXT_ROW();
1.1       misho    1023:        hline(ACS_HLINE, cols);
                   1024: 
1.1.1.2   misho    1025:        if (!c_show_info)
                   1026:                center_text(" Press %c to enable additional information ",
                   1027:                            KEY_TOGGLE_INFO);
                   1028:        else {
                   1029:                if (disable_info)
                   1030:                        center_text(" Increase screen height to see additional information ");
                   1031:                else
                   1032:                        draw_info();
1.1       misho    1033:        }
                   1034: }
                   1035: 
                   1036: 
                   1037: static void curses_draw(void)
                   1038: {
                   1039:        row = 0;
                   1040:        move(0,0);
                   1041:        
                   1042:        getmaxyx(stdscr, rows, cols);
1.1.1.2   misho    1043: 
                   1044:        if (rows < 4) {
1.1       misho    1045:                clear();
1.1.1.2   misho    1046:                put_line("Screen must be at least 4 rows in height");
                   1047:                goto out;
1.1       misho    1048:        }
                   1049: 
1.1.1.2   misho    1050:        if (cols < 48) {
                   1051:                clear();
                   1052:                put_line("Screen must be at least 48 columns width");
                   1053:                goto out;
                   1054:        }
                   1055: 
                   1056:        current_element = element_current();
                   1057:        current_attr = attr_current();
1.1       misho    1058: 
1.1.1.2   misho    1059:        draw_header();
                   1060: 
                   1061:        apply_layout(LAYOUT_DEFAULT);
                   1062:        draw_content();
                   1063: 
                   1064:        /* fill empty lines with blanks */
                   1065:        while (row < (rows - 1 - lines_required_for_statusbar())) {
                   1066:                move(++row, 0);
                   1067:                put_line("");
1.1       misho    1068:        }
                   1069: 
1.1.1.2   misho    1070:        draw_statusbar();
1.1       misho    1071: 
                   1072:        if (quit_mode)
1.1.1.2   misho    1073:                print_message(" Really Quit? (y/n) ");
1.1       misho    1074:        else if (print_help) {
                   1075:                if (help_page == 0)
                   1076:                        draw_help();
1.1.1.2   misho    1077: #if 0
1.1       misho    1078:                else
                   1079:                        draw_help_2();
1.1.1.2   misho    1080: #endif
1.1       misho    1081:        }
                   1082: 
1.1.1.2   misho    1083: out:
1.1       misho    1084:        attrset(0);
                   1085:        refresh();
                   1086: }
                   1087: 
1.1.1.3 ! misho    1088: static void __reset_attr_counter(struct element *e, struct attr *a, void *arg)
        !          1089: {
        !          1090:        attr_reset_counter(a);
        !          1091: }
        !          1092: 
        !          1093: static void reset_counters(void)
        !          1094: {
        !          1095:        element_foreach_attr(current_element, __reset_attr_counter, NULL);
        !          1096: }
        !          1097: 
1.1       misho    1098: static int handle_input(int ch)
                   1099: {
                   1100:        switch (ch) 
                   1101:        {
                   1102:                case 'q':
1.1.1.2   misho    1103:                        if (print_help)
                   1104:                                print_help = 0;
                   1105:                        else
                   1106:                                quit_mode = quit_mode ? 0 : 1;
1.1       misho    1107:                        return 1;
                   1108: 
                   1109:                case 0x1b:
                   1110:                        quit_mode = 0;
                   1111:                        print_help = 0;
                   1112:                        return 1;
                   1113: 
                   1114:                case 'y':
                   1115:                        if (quit_mode)
                   1116:                                exit(0);
                   1117:                        break;
                   1118: 
                   1119:                case 'n':
                   1120:                        if (quit_mode)
                   1121:                                quit_mode = 0;
                   1122:                        return 1;
                   1123: 
                   1124:                case 12:
                   1125:                case KEY_CLEAR:
                   1126: #ifdef HAVE_REDRAWWIN
                   1127:                        redrawwin(stdscr);
                   1128: #endif
                   1129:                        clear();
                   1130:                        return 1;
                   1131: 
1.1.1.2   misho    1132:                case '?':
1.1       misho    1133:                        clear();
1.1.1.3 ! misho    1134:                        print_help = print_help ? 0 : 1;
1.1       misho    1135:                        return 1;
                   1136: 
1.1.1.2   misho    1137:                case KEY_TOGGLE_GRAPH:
                   1138:                        c_show_graph = !c_show_graph;
                   1139:                        if (c_show_graph && !c_ngraph)
                   1140:                                c_ngraph = 1;
1.1       misho    1141:                        return 1;
                   1142: 
1.1.1.2   misho    1143:                case KEY_TOGGLE_DETAILS:
                   1144:                        c_show_details = !c_show_details;
1.1       misho    1145:                        return 1;
                   1146: 
1.1.1.2   misho    1147:                case KEY_TOGGLE_LIST:
                   1148:                        c_show_list = !c_show_list;
1.1       misho    1149:                        return 1;
                   1150: 
1.1.1.2   misho    1151:                case KEY_TOGGLE_INFO:
                   1152:                        c_show_info = !c_show_info;
1.1       misho    1153:                        return 1;
                   1154: 
1.1.1.2   misho    1155:                case KEY_COLLECT_HISTORY:
                   1156:                        if (current_attr) {
                   1157:                                attr_start_collecting_history(current_attr);
                   1158:                                return 1;
                   1159:                        }
                   1160:                        break;
                   1161: 
                   1162:                case KEY_PPAGE:
                   1163:                        {
                   1164:                                int i;
                   1165:                                for (i = 1; i < list_length; i++)
                   1166:                                        element_select_prev();
                   1167:                        }
1.1       misho    1168:                        return 1;
                   1169: 
1.1.1.2   misho    1170:                case KEY_NPAGE:
                   1171:                        {
                   1172:                                int i;
                   1173:                                for (i = 1; i < list_length; i++)
                   1174:                                        element_select_next();
                   1175:                        }
1.1       misho    1176:                        return 1;
                   1177: 
1.1.1.2   misho    1178:                case KEY_DOWN:
                   1179:                        element_select_next();
1.1       misho    1180:                        return 1;
                   1181: 
1.1.1.2   misho    1182:                case KEY_UP:
                   1183:                        element_select_prev();
1.1       misho    1184:                        return 1;
                   1185: 
1.1.1.2   misho    1186:                case KEY_LEFT:
                   1187:                        attr_select_prev();
1.1       misho    1188:                        return 1;
                   1189: 
1.1.1.2   misho    1190:                case KEY_RIGHT:
                   1191:                        attr_select_next();
1.1       misho    1192:                        return 1;
                   1193: 
1.1.1.2   misho    1194:                case ']':
                   1195:                        group_select_next();
1.1       misho    1196:                        return 1;
                   1197: 
1.1.1.2   misho    1198:                case '[':
                   1199:                        group_select_prev();
1.1       misho    1200:                        return 1;
                   1201: 
1.1.1.2   misho    1202:                case '<':
                   1203:                        c_ngraph--;
                   1204:                        if (c_ngraph <= 1)
                   1205:                                c_ngraph = 1;
1.1       misho    1206:                        return 1;
                   1207: 
                   1208:                case '>':
1.1.1.2   misho    1209:                        c_ngraph++;
                   1210:                        if (c_ngraph > 32)
                   1211:                                c_ngraph = 32;
1.1       misho    1212:                        return 1;
                   1213: 
1.1.1.2   misho    1214:                case '\t':
                   1215:                        history_select_next();
1.1       misho    1216:                        return 1;
1.1.1.3 ! misho    1217: 
        !          1218:                case 'r':
        !          1219:                        reset_counters();
        !          1220:                        return 1;
1.1       misho    1221:        }
                   1222: 
                   1223:        return 0;
                   1224: }
                   1225: 
                   1226: static void curses_pre(void)
                   1227: {
1.1.1.2   misho    1228:        static int init = 0;
                   1229: 
                   1230:        if (!init) {
                   1231:                curses_init();
                   1232:                init = 1;
                   1233:        }
                   1234: 
1.1       misho    1235:        for (;;) {
                   1236:                int ch = getch();
                   1237: 
                   1238:                if (ch == -1)
                   1239:                        break;
                   1240: 
                   1241:                if (handle_input(ch))
                   1242:                        curses_draw();
                   1243:        }
                   1244: }
                   1245: 
                   1246: static void print_module_help(void)
                   1247: {
                   1248:        printf(
                   1249:        "curses - Curses Output\n" \
                   1250:        "\n" \
1.1.1.2   misho    1251:        "  Interactive curses UI. Press '?' to see help.\n" \
1.1       misho    1252:        "  Author: Thomas Graf <tgraf@suug.ch>\n" \
                   1253:        "\n" \
                   1254:        "  Options:\n" \
                   1255:        "    fgchar=CHAR    Foreground character (default: '*')\n" \
                   1256:        "    bgchar=CHAR    Background character (default: '.')\n" \
                   1257:        "    nchar=CHAR     Noise character (default: ':')\n" \
                   1258:        "    uchar=CHAR     Unknown character (default: '?')\n" \
1.1.1.2   misho    1259:        "    gheight=NUM    Height of graph (default: 6)\n" \
                   1260:        "    gwidth=NUM     Width of graph (default: 60)\n" \
                   1261:        "    ngraph=NUM     Number of graphs (default: 1)\n" \
1.1       misho    1262:        "    nocolors       Do not use colors\n" \
                   1263:        "    graph          Show graphical stats by default\n" \
1.1.1.2   misho    1264:        "    details        Show detailed stats by default\n" \
1.1.1.3 ! misho    1265:        "    info           Show additional info screen by default\n" \
1.1.1.2   misho    1266:        "    minlist=INT    Minimum item list length\n");
1.1       misho    1267: }
                   1268: 
1.1.1.2   misho    1269: static void curses_parse_opt(const char *type, const char *value)
1.1       misho    1270: {
1.1.1.2   misho    1271:        if (!strcasecmp(type, "fgchar") && value)
                   1272:                c_graph_cfg.gc_foreground = value[0];
                   1273:        else if (!strcasecmp(type, "bgchar") && value)
                   1274:                c_graph_cfg.gc_background = value[0];
                   1275:        else if (!strcasecmp(type, "nchar") && value)
                   1276:                c_graph_cfg.gc_noise = value[0];
                   1277:        else if (!strcasecmp(type, "uchar") && value)
                   1278:                c_graph_cfg.gc_unknown = value[0];
                   1279:        else if (!strcasecmp(type, "gheight") && value)
                   1280:                c_graph_cfg.gc_height = strtol(value, NULL, 0);
                   1281:        else if (!strcasecmp(type, "gwidth") && value)
                   1282:                c_graph_cfg.gc_width = strtol(value, NULL, 0);
1.1.1.3 ! misho    1283:        else if (!strcasecmp(type, "ngraph") && value) {
1.1.1.2   misho    1284:                c_ngraph = strtol(value, NULL, 0);
                   1285:                c_show_graph = !!c_ngraph;
                   1286:        } else if (!strcasecmp(type, "details"))
                   1287:                c_show_details = 1;
1.1.1.3 ! misho    1288:        else if (!strcasecmp(type, "info"))
        !          1289:                c_show_info = 1;
1.1.1.2   misho    1290:        else if (!strcasecmp(type, "nocolors"))
                   1291:                c_use_colors = 0;
                   1292:        else if (!strcasecmp(type, "minlist") && value)
                   1293:                c_list_min = strtol(value, NULL, 0);
                   1294:        else if (!strcasecmp(type, "help")) {
                   1295:                print_module_help();
                   1296:                exit(0);
1.1       misho    1297:        }
                   1298: }
                   1299: 
1.1.1.2   misho    1300: static struct bmon_module curses_ops = {
                   1301:        .m_name         = "curses",
                   1302:        .m_flags        = BMON_MODULE_DEFAULT,
                   1303:        .m_shutdown     = curses_shutdown,
                   1304:        .m_pre          = curses_pre,
                   1305:        .m_do           = curses_draw,
                   1306:        .m_parse_opt    = curses_parse_opt,
1.1       misho    1307: };
                   1308: 
                   1309: static void __init do_curses_init(void)
                   1310: {
1.1.1.2   misho    1311:        output_register(&curses_ops);
1.1       misho    1312: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>