/* Draws error message on the screen or redraws the last message when both * title_arg and message_arg are NULL. */ static void redraw_error_msg(const char title_arg[], const char message_arg[], int prompt_skip) { /* TODO: refactor this function redraw_error_msg() */ static const char *title; static const char *message; static int ctrl_c; int sx, sy; int x, y; int z; const char *text; if(title_arg != NULL && message_arg != NULL) { title = title_arg; message = message_arg; ctrl_c = prompt_skip; } assert(message != NULL); curs_set(FALSE); werase(error_win); getmaxyx(stdscr, sy, sx); y = sy - 3 + !cfg.last_status; x = sx - 2; wresize(error_win, y, x); z = strlen(message); if(z <= x - 2 && strchr(message, '\n') == NULL) { y = 6; wresize(error_win, y, x); mvwin(error_win, (sy - y)/2, (sx - x)/2); checked_wmove(error_win, 2, (x - z)/2); wprint(error_win, message); } else { int i; int cy = 2; i = 0; while(i < z) { int j; char buf[x - 2 + 1]; snprintf(buf, sizeof(buf), "%s", message + i); for(j = 0; buf[j] != '\0'; j++) if(buf[j] == '\n') break; if(buf[j] != '\0') i++; buf[j] = '\0'; i += j; if(buf[0] == '\0') continue; y = cy + 4; mvwin(error_win, (sy - y)/2, (sx - x)/2); wresize(error_win, y, x); checked_wmove(error_win, cy++, 1); wprint(error_win, buf); } } box(error_win, 0, 0); if(title[0] != '\0') mvwprintw(error_win, 0, (x - strlen(title) - 2)/2, " %s ", title); if(curr_stats.errmsg_shown == 1) { if(ctrl_c) { text = "Press Return to continue or Ctrl-C to skip other error messages"; } else { text = "Press Return to continue"; } } else { text = "Enter [y]es or [n]o"; } mvwaddstr(error_win, y - 2, (x - strlen(text))/2, text); }
void draw_menu(menu_info *m) { int i; int win_len; int x, y; getmaxyx(menu_win, y, x); win_len = x; werase(menu_win); normalize_top(m); x = m->top; box(menu_win, 0, 0); wattron(menu_win, A_BOLD); checked_wmove(menu_win, 0, 3); wprint(menu_win, m->title); wattroff(menu_win, A_BOLD); for(i = 1; x < m->len; i++, x++) { int z, off; char *buf; char *ptr = NULL; col_attr_t col; int type = WIN_COLOR; chomp(m->items[x]); if((ptr = strchr(m->items[x], '\n')) || (ptr = strchr(m->items[x], '\r'))) *ptr = '\0'; col = cfg.cs.color[WIN_COLOR]; if(cfg.hl_search && m->matches != NULL && m->matches[x]) { mix_colors(&col, &cfg.cs.color[SELECTED_COLOR]); type = SELECTED_COLOR; } init_pair(DCOLOR_BASE + type, col.fg, col.bg); wattron(menu_win, COLOR_PAIR(DCOLOR_BASE + type) | col.attr); z = m->hor_pos; off = 0; while(z-- > 0 && m->items[x][off] != '\0') { size_t l = get_char_width(m->items[x] + off); off += l; } buf = strdup(m->items[x] + off); for(z = 0; buf[z] != '\0'; z++) if(buf[z] == '\t') buf[z] = ' '; checked_wmove(menu_win, i, 2); if(get_screen_string_length(buf) > win_len - 4) { size_t len = get_normal_utf8_string_widthn(buf, win_len - 3 - 4); memset(buf + len, ' ', strlen(buf) - len); buf[len + 3] = '\0'; wprint(menu_win, buf); mvwaddstr(menu_win, i, win_len - 5, "..."); } else { const size_t len = get_normal_utf8_string_widthn(buf, win_len - 4); buf[len] = '\0'; wprint(menu_win, buf); } waddstr(menu_win, " "); free(buf); wattroff(menu_win, COLOR_PAIR(DCOLOR_BASE + type) | col.attr); if(i + 3 > y) break; } }
void clean_menu_position(menu_info *m) { int x, z; int off = 0; char * buf = (char *)NULL; col_attr_t col; int type = MENU_COLOR; x = getmaxx(menu_win) + get_utf8_overhead(m->items[m->pos]); buf = malloc(x + 2); /* TODO: check if this can ever be false. */ if(m->items[m->pos] != NULL) { z = m->hor_pos; while(z-- > 0 && m->items[m->pos][off] != '\0') { size_t l = get_char_width(m->items[m->pos] + off); off += l; x -= l - 1; } snprintf(buf, x, " %s", m->items[m->pos] + off); } else { buf[0] = '\0'; } for(z = 0; buf[z] != '\0'; z++) if(buf[z] == '\t') buf[z] = ' '; for(z = strlen(buf); z < x; z++) buf[z] = ' '; buf[x] = ' '; buf[x + 1] = '\0'; col = cfg.cs.color[WIN_COLOR]; if(cfg.hl_search && m->matches != NULL && m->matches[m->pos]) { mix_colors(&col, &cfg.cs.color[SELECTED_COLOR]); type = SELECTED_COLOR; } init_pair(DCOLOR_BASE + type, col.fg, col.bg); wattrset(menu_win, COLOR_PAIR(type + DCOLOR_BASE) | col.attr); checked_wmove(menu_win, m->current, 1); if(get_screen_string_length(m->items[m->pos] + off) > getmaxx(menu_win) - 4) { size_t len = get_normal_utf8_string_widthn(buf, getmaxx(menu_win) - 3 - 4 + 1); memset(buf + len, ' ', strlen(buf) - len); buf[len + 3] = '\0'; wprint(menu_win, buf); mvwaddstr(menu_win, m->current, getmaxx(menu_win) - 5, "..."); } else { size_t len = get_normal_utf8_string_widthn(buf, getmaxx(menu_win) - 4 + 1); buf[len] = '\0'; wprint(menu_win, buf); } waddstr(menu_win, " "); wattroff(menu_win, COLOR_PAIR(type + DCOLOR_BASE) | col.attr); free(buf); }
void move_to_menu_pos(int pos, menu_info *m) { /* TODO: refactor this function move_to_menu_pos() */ int redraw = 0; int x, z; char *buf = NULL; col_attr_t col; int off = 0; pos = MIN(m->len - 1, MAX(0, pos)); if(pos < 0) return; normalize_top(m); if(pos > get_last_visible_line(m)) { m->top = pos - (m->win_rows - 2 - 1); redraw = 1; } else if(pos < m->top) { m->top = pos; redraw = 1; } if(cfg.scroll_off > 0) { int s = MIN(DIV_ROUND_UP(m->win_rows - 2, 2), cfg.scroll_off); if(pos - m->top < s && m->top > 0) { m->top -= s - (pos - m->top); normalize_top(m); redraw = 1; } if(pos > get_last_visible_line(m) - s) { m->top += s - (get_last_visible_line(m) - pos); normalize_top(m); redraw = 1; } } m->current = 1 + (pos - m->top); if(redraw) draw_menu(m); x = getmaxx(menu_win) + get_utf8_overhead(m->items[pos]); buf = malloc(x + 2); if(buf == NULL) return; /* TODO: check if this can be false. */ if(m->items[pos] != NULL) { z = m->hor_pos; while(z-- > 0 && m->items[pos][off] != '\0') { size_t l = get_char_width(m->items[pos] + off); off += l; x -= l - 1; } snprintf(buf, x, " %s", m->items[pos] + off); } else { buf[0] = '\0'; } for(z = 0; buf[z] != '\0'; z++) if(buf[z] == '\t') buf[z] = ' '; for(z = strlen(buf); z < x; z++) buf[z] = ' '; buf[x] = ' '; buf[x + 1] = '\0'; col = cfg.cs.color[WIN_COLOR]; if(cfg.hl_search && m->matches != NULL && m->matches[pos]) mix_colors(&col, &cfg.cs.color[SELECTED_COLOR]); mix_colors(&col, &cfg.cs.color[CURR_LINE_COLOR]); init_pair(DCOLOR_BASE + MENU_CURRENT_COLOR, col.fg, col.bg); wattrset(menu_win, COLOR_PAIR(DCOLOR_BASE + MENU_CURRENT_COLOR) | col.attr); checked_wmove(menu_win, m->current, 1); if(get_screen_string_length(m->items[pos] + off) > getmaxx(menu_win) - 4) { size_t len = get_normal_utf8_string_widthn(buf, getmaxx(menu_win) - 3 - 4 + 1); memset(buf + len, ' ', strlen(buf) - len); buf[len + 3] = '\0'; wprint(menu_win, buf); mvwaddstr(menu_win, m->current, getmaxx(menu_win) - 5, "..."); } else { size_t len = get_normal_utf8_string_widthn(buf, getmaxx(menu_win) - 4 + 1); buf[len] = '\0'; wprint(menu_win, buf); } waddstr(menu_win, " "); wattroff(menu_win, COLOR_PAIR(DCOLOR_BASE + MENU_CURRENT_COLOR) | col.attr); m->pos = pos; free(buf); show_position_in_menu(m); }
/* Draws possibly centered formatted message with specified title and control * message on error_win. */ static void draw_msg(const char title[], const char msg[], const char ctrl_msg[], int centered, int recommended_width) { enum { margin = 1 }; int sw, sh; int w, h; int max_h; int len; size_t ctrl_msg_n; size_t wctrl_msg; size_t i; int first_line_x = 1; const int first_line_y = 2; curs_set(0); getmaxyx(stdscr, sh, sw); ctrl_msg_n = MAX(measure_sub_lines(ctrl_msg, &wctrl_msg), 1U); max_h = sh - 2 - ctrl_msg_n + !cfg.display_statusline; h = max_h; /* The outermost condition is for VLA below (to calm static analyzers). */ w = MAX(2 + 2*margin, MIN(sw - 2, MAX(MAX(recommended_width, sw/3), (int)MAX(wctrl_msg, determine_width(msg)) + 4))); wresize(error_win, h, w); werase(error_win); len = strlen(msg); if(len <= w - 2 && strchr(msg, '\n') == NULL) { first_line_x = (w - len)/2; h = 5 + ctrl_msg_n; wresize(error_win, h, w); mvwin(error_win, (sh - h)/2, (sw - w)/2); checked_wmove(error_win, first_line_y, first_line_x); wprint(error_win, msg); } else { int i = 0; int cy = first_line_y; while(i < len) { int j; char buf[w - 2 - 2*margin + 1]; int cx; copy_str(buf, sizeof(buf), msg + i); for(j = 0; buf[j] != '\0'; j++) if(buf[j] == '\n') break; if(buf[j] != '\0') i++; buf[j] = '\0'; i += j; if(buf[0] == '\0') continue; if(cy >= max_h - (int)ctrl_msg_n - 3) { /* Skip trailing part of the message if it's too long, just print how * many lines we're omitting. */ size_t max_len; const int more_lines = 1U + measure_sub_lines(msg + i, &max_len); snprintf(buf, sizeof(buf), "<<%d more line%s not shown>>", more_lines, (more_lines == 1) ? "" : "s"); /* Make sure this is the last iteration of the loop. */ i = len; } h = 1 + cy + 1 + ctrl_msg_n + 1; wresize(error_win, h, w); mvwin(error_win, (sh - h)/2, (sw - w)/2); cx = centered ? (w - utf8_strsw(buf))/2 : (1 + margin); if(cy == first_line_y) { first_line_x = cx; } checked_wmove(error_win, cy++, cx); wprint(error_win, buf); } } box(error_win, 0, 0); if(title[0] != '\0') { mvwprintw(error_win, 0, (w - strlen(title) - 2)/2, " %s ", title); } /* Print control message line by line. */ for(i = ctrl_msg_n; i > 0U; --i) { const size_t len = strcspn(ctrl_msg, "\n"); mvwaddnstr(error_win, h - i - 1, MAX(0, (w - (int)len)/2), ctrl_msg, len); ctrl_msg = skip_char(ctrl_msg + len + 1U, '/'); } checked_wmove(error_win, first_line_y, first_line_x); }