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

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

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