static widget_handler_status_T display_checkbox(struct dialog_data *dlg_data, struct widget_data *widget_data) { struct terminal *term = dlg_data->win->term; struct color_pair *color; unsigned char *text; struct el_box *pos = &widget_data->box; int selected = is_selected_widget(dlg_data, widget_data); if (selected) { color = get_bfu_color(term, "dialog.checkbox-selected"); } else { color = get_bfu_color(term, "dialog.checkbox"); } if (!color) return EVENT_PROCESSED; if (widget_data->info.checkbox.checked) text = widget_data->widget->info.checkbox.gid ? "(X)" : "[X]"; else text = widget_data->widget->info.checkbox.gid ? "( )" : "[ ]"; draw_dlg_text(dlg_data, pos->x, pos->y, text, CHECKBOX_LEN, 0, color); if (selected) { set_dlg_cursor(term, dlg_data, pos->x + 1, pos->y, 1); set_dlg_window_ptr(dlg_data, dlg_data->win, pos->x, pos->y); } return EVENT_PROCESSED; }
static void draw_file_download(struct listbox_item *item, struct listbox_context *context, int x, int y, int width) { struct file_download *file_download = item->udata; struct download *download = &file_download->download; unsigned char *stylename; struct color_pair *color; unsigned char *text; int length; int trimmedlen; int meter = DOWNLOAD_METER_WIDTH; /* We have nothing to work with */ if (width < 4) return; stylename = (item == context->box->sel) ? "menu.selected" : ((item->marked) ? "menu.marked" : "menu.normal"); color = get_bfu_color(context->term, stylename); text = get_file_download_text(item, context->term); if (!text) return; length = strlen(text); /* Show atleast the required percentage of the URI */ if (length * DOWNLOAD_URI_PERCENTAGE / 100 < width - meter - 4) { trimmedlen = int_min(length, width - meter - 4); } else { trimmedlen = int_min(length, width - 3); } draw_text(context->term, x, y, text, trimmedlen, 0, color); if (trimmedlen < length) { draw_text(context->term, x + trimmedlen, y, "...", 3, 0, color); trimmedlen += 3; } mem_free(text); if (!download->progress || download->progress->size < 0 || !is_in_state(download->state, S_TRANS) || !has_progress(download->progress)) { /* TODO: Show trimmed error message. */ return; } if (!dialog_has_refresh(context->dlg_data)) refresh_dialog(context->dlg_data, refresh_file_download, NULL); if (trimmedlen + meter >= width) return; x += width - meter; draw_progress_bar(download->progress, context->term, x, y, meter, NULL, NULL); }
void draw_progress_bar(struct progress *progress, struct terminal *term, int x, int y, int width, unsigned char *text, struct color_pair *meter_color) { /* Note : values > 100% are theorically possible and were seen. */ int percent = 0; struct box barprogress; if (progress->size > 0) percent = (int) ((longlong) 100 * progress->pos / progress->size); /* Draw the progress meter part "[### ]" */ if (!text && width > 2) { width -= 2; draw_text(term, x++, y, "[", 1, 0, NULL); draw_text(term, x + width, y, "]", 1, 0, NULL); } if (!meter_color) meter_color = get_bfu_color(term, "dialog.meter"); set_box(&barprogress, x, y, int_min(width * percent / 100, width), 1); draw_box(term, &barprogress, ' ', 0, meter_color); /* On error, will print '?' only, should not occur. */ if (text) { width = int_min(width, strlen(text)); } else if (width > 1) { static unsigned char s[] = "????"; /* Reduce or enlarge at will. */ unsigned int slen = 0; int max = int_min(sizeof(s), width) - 1; if (ulongcat(s, &slen, percent, max, 0)) { s[0] = '?'; slen = 1; } s[slen++] = '%'; /* Draw the percentage centered in the progress meter */ x += (1 + width - slen) / 2; assert(slen <= width); width = slen; text = s; } draw_text(term, x, y, text, width, 0, NULL); }
void dlg_format_checkbox(struct dialog_data *dlg_data, struct widget_data *widget_data, int x, int *y, int w, int *rw, enum format_align align, int format_only) { struct terminal *term = dlg_data->win->term; unsigned char *text = widget_data->widget->text; set_box(&widget_data->box, x, *y, CHECKBOX_LEN, CHECKBOX_HEIGHT); if (w <= CHECKBOX_LS) return; if (text && *text) { if (rw) *rw -= CHECKBOX_LS; dlg_format_text_do(dlg_data, text, x + CHECKBOX_LS, y, w - CHECKBOX_LS, rw, get_bfu_color(term, "dialog.checkbox-label"), align, format_only); if (rw) *rw += CHECKBOX_LS; } }
/* Displays a dialog box */ static widget_handler_status_T display_listbox(struct dialog_data *dlg_data, struct widget_data *widget_data) { struct terminal *term = dlg_data->win->term; struct listbox_data *box = get_listbox_widget_data(widget_data); struct listbox_context data; listbox_sel_move(widget_data, 0); draw_box(term, &widget_data->box, ' ', 0, get_bfu_color(term, (const unsigned char *)"menu.normal")); memset(&data, 0, sizeof(data)); data.term = term; data.widget_data = widget_data; data.box = box; data.dlg_data = dlg_data; traverse_listbox_items_list(box->top, box, widget_data->box.height, 1, display_listbox_item, &data); return EVENT_PROCESSED; }
void dlg_format_group(struct dialog_data *dlg_data, struct widget_data *widget_data, int n, int x, int *y, int w, int *rw, int format_only) { struct terminal *term = dlg_data->win->term; int space_between_widgets = 1; int line_width = 0; int xpos; struct color_pair *color = get_bfu_color(term, "dialog.text"); assert(n > 0); if_assert_failed return; while (n--) { int widget_width; int width; unsigned char *text = widget_data->widget->text; int label_length; int label_padding; #ifdef CONFIG_UTF8 if (term->utf8_cp) { if (text && *text) label_length = utf8_ptr2cells(text, NULL); else label_length = 0; } else #endif /* CONFIG_UTF8 */ label_length = (text && *text) ? strlen(text) : 0; label_padding = (label_length > 0); if (widget_data->widget->type == WIDGET_CHECKBOX) { width = CHECKBOX_LEN; } else if (widget_is_textfield(widget_data)) { #ifdef CONFIG_UTF8 if (term->utf8_cp) { width = utf8_ptr2cells(widget_data->widget->data, NULL); } else #endif /* CONFIG_UTF8 */ width = widget_data->widget->datalen; } else { /* TODO: handle all widget types. */ widget_data++; continue; } int_bounds(&label_length, 0, w - width - label_padding); widget_width = width + label_padding + label_length; if (line_width + widget_width > w) { line_width = 0; (*y) += 2; /* Next line */ } xpos = x + line_width; if (!format_only) { if (widget_data->widget->type == WIDGET_CHECKBOX) { /* Draw text at right of checkbox. */ if (label_length) { #ifdef CONFIG_UTF8 if (term->utf8_cp) { int lb = utf8_cells2bytes( text, label_length, NULL); draw_dlg_text(dlg_data, xpos + width + label_padding, *y, text, lb, 0, color); } else #endif /* CONFIG_UTF8 */ { draw_dlg_text(dlg_data, xpos + width + label_padding, *y, text, label_length, 0, color); } } set_box(&widget_data->box, xpos, *y, width, 1); } else if (widget_is_textfield(widget_data)) { /* Draw label at left of widget. */ if (label_length) { #ifdef CONFIG_UTF8 if (term->utf8_cp) { int lb = utf8_cells2bytes( text, label_length, NULL); draw_dlg_text(dlg_data, xpos, *y, text, lb, 0, color); } else #endif /* CONFIG_UTF8 */ { draw_dlg_text(dlg_data, xpos, *y, text, label_length, 0, color); } } set_box(&widget_data->box, xpos + label_padding + label_length, *y, width, 1); } } line_width += widget_width; if (rw) int_bounds(rw, line_width, w); line_width += space_between_widgets; widget_data++; } (*y)++; }
static widget_handler_status_T display_button(struct dialog_data *dlg_data, struct widget_data *widget_data) { struct terminal *term = dlg_data->win->term; struct color_pair *color, *shortcut_color; struct el_box *pos = &widget_data->box; int len, x; int sel = is_selected_widget(dlg_data, widget_data); if (sel) { shortcut_color = get_bfu_color(term, "dialog.button-shortcut-selected"); color = get_bfu_color(term, "dialog.button-selected"); } else { shortcut_color = get_bfu_color(term, "dialog.button-shortcut"); color = get_bfu_color(term, "dialog.button"); } if (!color || !shortcut_color) return EVENT_PROCESSED; #ifdef CONFIG_UTF8 if (term->utf8_cp) { int button_left_len = utf8_ptr2cells(BUTTON_LEFT, NULL); int button_right_len = utf8_ptr2cells(BUTTON_RIGHT, NULL); x = pos->x + button_left_len; len = widget_data->box.width - (button_left_len + button_right_len); } else #endif /* CONFIG_UTF8 */ { x = pos->x + BUTTON_LEFT_LEN; len = widget_data->box.width - BUTTON_LR_LEN; } draw_dlg_text(dlg_data, pos->x, pos->y, BUTTON_LEFT, BUTTON_LEFT_LEN, 0, color); if (len > 0) { unsigned char *text = widget_data->widget->text; int hk_pos = widget_data->widget->info.button.hotkey_pos; int attr; attr = get_opt_bool("ui.dialogs.underline_button_shortcuts", NULL) ? SCREEN_ATTR_UNDERLINE : 0; #ifdef CONFIG_UTF8 if (term->utf8_cp) { if (hk_pos >= 0) { int hk_bytes = utf8charlen(&text[hk_pos+1]); int cells_to_hk = utf8_ptr2cells(text, &text[hk_pos]); int right = widget_data->widget->info.button.truetextlen - hk_pos - hk_bytes; int hk_cells = utf8_char2cells(&text[hk_pos + 1], NULL); if (hk_pos) draw_dlg_text(dlg_data, x, pos->y, text, hk_pos, 0, color); draw_dlg_text(dlg_data, x + cells_to_hk, pos->y, &text[hk_pos + 1], hk_bytes, attr, shortcut_color); if (right > 1) draw_dlg_text(dlg_data, x+cells_to_hk+hk_cells, pos->y, &text[hk_pos + hk_bytes + 1], right - 1, 0, color); } else { int hk_width = utf8_char2cells(text, NULL); int hk_len = utf8charlen(text); int len_to_display = utf8_cells2bytes(&text[hk_len], len - hk_width, NULL); draw_dlg_text(dlg_data, x, pos->y, text, hk_len, attr, shortcut_color); draw_dlg_text(dlg_data, x + hk_width, pos->y, &text[hk_len], len_to_display, 0, color); } } else #endif /* CONFIG_UTF8 */ if (hk_pos >= 0) { int right = widget_data->widget->info.button.truetextlen - hk_pos - 1; if (hk_pos) { draw_dlg_text(dlg_data, x, pos->y, text, hk_pos, 0, color); } draw_dlg_text(dlg_data, x + hk_pos, pos->y, &text[hk_pos + 1], 1, attr, shortcut_color); if (right > 1) { draw_dlg_text(dlg_data, x + hk_pos + 1, pos->y, &text[hk_pos + 2], right - 1, 0, color); } } else { draw_dlg_text(dlg_data, x, pos->y, text, 1, attr, shortcut_color); draw_dlg_text(dlg_data, x + 1, pos->y, &text[1], len - 1, 0, color); } } #ifdef CONFIG_UTF8 if (term->utf8_cp) { int text_cells = utf8_ptr2cells(widget_data->widget->text, NULL); int hk = (widget_data->widget->info.button.hotkey_pos >= 0); draw_dlg_text(dlg_data, x + text_cells - hk, pos->y, BUTTON_RIGHT, BUTTON_RIGHT_LEN, 0, color); } else #endif /* CONFIG_UTF8 */ draw_dlg_text(dlg_data, x + len, pos->y, BUTTON_RIGHT, BUTTON_RIGHT_LEN, 0, color); if (sel) { set_dlg_cursor(term, dlg_data, x, pos->y, 1); set_dlg_window_ptr(dlg_data, dlg_data->win, pos->x, pos->y); } return EVENT_PROCESSED; }
/* Takes care about rendering of each listbox item. */ static int display_listbox_item(struct listbox_item *item, void *data_, int *offset) { struct listbox_context *data = (struct listbox_context *)data_; int len; /* Length of the current text field. */ struct color_pair *tree_color, *text_color; int depth = item->depth + 1; int d; int x, y; tree_color = get_bfu_color(data->term, (const unsigned char *)"menu.normal"); if (item == data->box->sel) { text_color = get_bfu_color(data->term, (const unsigned char *)"menu.selected"); } else if (item->marked) { text_color = get_bfu_color(data->term, (const unsigned char *)"menu.marked"); } else { text_color = tree_color; } y = data->widget_data->box.y + data->offset; for (d = 0; d < depth - 1; d++) { struct listbox_item *root = item; struct listbox_item *child = item; int i, x; for (i = depth - d; i; i--) { child = root; if (root) root = data->box->ops->get_root(root); } /* XXX */ x = data->widget_data->box.x + d * 5; draw_text(data->term, x, y, (const unsigned char *)" ", 5, 0, tree_color); if (root ? root->child.prev == child : data->box->items->prev == child) continue; /* We were the last branch. */ draw_border_char(data->term, x + 1, y, BORDER_SVLINE, tree_color); } if (depth) { unsigned char str[5] = { 32, BORDER_SRTEE, BORDER_SHLINE, BORDER_SHLINE, 32 }; int i; switch (item->type) { case BI_LEAF: case BI_SEPARATOR: { const struct listbox_item *prev; prev = traverse_listbox_items_list(item, data->box, -1, 1, NULL, NULL); if (item == prev) { /* There is no visible item before @item, so it * must be the first item in the listbox. */ str[1] = BORDER_SULCORNER; } else { const struct listbox_item *next; next = traverse_listbox_items_list(item, data->box, 1, 1, NULL, NULL); if (item == next || item->depth != next->depth) { /* There is no visible item after @item * at the same depth, so it must be the * last in its folder. */ str[1] = BORDER_SDLCORNER; } } break; } case BI_FOLDER: str[0] = '['; str[1] = (item->expanded) ? '-' : '+'; str[2] = ']'; break; default: INTERNAL("Unknown item type"); break; } if (item->marked) str[4] = '*'; x = data->widget_data->box.x + (depth - 1) * 5; for (i = 0; i < 5; i++) { draw_border_char(data->term, x + i, y, str[i], tree_color); } } x = data->widget_data->box.x + depth * 5; if (item->type == BI_SEPARATOR) { int i; int width = data->widget_data->box.width - depth * 5; for (i = 0; i < width; i++) { draw_border_char(data->term, x + i, y, BORDER_SHLINE, text_color); } } else if (data->box->ops && data->box->ops->draw) { int width = data->widget_data->box.width - depth * 5; data->box->ops->draw(item, data, x, y, width); } else { unsigned char *text; const struct listbox_ops *ops = data->box->ops; int len_bytes; assert(ops && ops->get_info); text = ops->get_text(item, data->term); if (!text) return 0; len = strlen((const char *)text); int_upper_bound(&len, int_max(0, data->widget_data->box.width - depth * 5)); #ifdef CONFIG_UTF8 if (data->term->utf8_cp) len_bytes = utf8_cells2bytes(text, len, NULL); else #endif /* CONFIG_UTF8 */ len_bytes = len; draw_text(data->term, x, y, text, len_bytes, 0, text_color); mem_free(text); } if (item == data->box->sel) { /* For blind users: */ x = data->widget_data->box.x + 5 + item->depth * 5; set_cursor(data->term, x, y, 1); set_window_ptr(data->dlg_data->win, x, y); } data->offset++; return 0; }
static void download_dialog_layouter(struct dialog_data *dlg_data) { struct file_download *file_download = dlg_data->dlg->udata; struct terminal *term = dlg_data->win->term; int w = dialog_max_width(term); int rw = w; int x, y = 0; int url_len; unsigned char *url; struct download *download = &file_download->download; struct color_pair *dialog_text_color = get_bfu_color(term, "dialog.text"); unsigned char *msg = get_download_msg(download, term, 1, 1, "\n"); int show_meter = (download_is_progressing(download) && download->progress->size >= 0); #if CONFIG_BITTORRENT int bittorrent = (file_download->uri->protocol == PROTOCOL_BITTORRENT && (show_meter || is_in_state(download->state, S_RESUME))); #endif redraw_windows(REDRAW_BEHIND_WINDOW, dlg_data->win); file_download->dlg_data = dlg_data; if (!msg) return; url = get_uri_string(file_download->uri, URI_PUBLIC); if (!url) { mem_free(msg); return; } #ifdef CONFIG_UTF8 if (term->utf8_cp) decode_uri(url); else #endif /* CONFIG_UTF8 */ decode_uri_for_display(url); url_len = strlen(url); if (show_meter) { int_lower_bound(&w, DOWN_DLG_MIN); } dlg_format_text_do(dlg_data, url, 0, &y, w, &rw, dialog_text_color, ALIGN_LEFT, 1); y++; if (show_meter) y += 2; #if CONFIG_BITTORRENT if (bittorrent) y += 2; #endif dlg_format_text_do(dlg_data, msg, 0, &y, w, &rw, dialog_text_color, ALIGN_LEFT, 1); y++; dlg_format_buttons(dlg_data, dlg_data->widgets_data, dlg_data->number_of_widgets, 0, &y, w, &rw, ALIGN_CENTER, 1); draw_dialog(dlg_data, w, y); w = rw; if (url_len > w) { /* Truncate too long urls */ url_len = w; url[url_len] = '\0'; if (url_len > 4) { url[--url_len] = '.'; url[--url_len] = '.'; url[--url_len] = '.'; } } y = dlg_data->box.y + DIALOG_TB + 1; x = dlg_data->box.x + DIALOG_LB; dlg_format_text_do(dlg_data, url, x, &y, w, NULL, dialog_text_color, ALIGN_LEFT, 0); if (show_meter) { y++; draw_progress_bar(download->progress, term, x, y, w, NULL, NULL); y++; } #if CONFIG_BITTORRENT if (bittorrent) { y++; draw_bittorrent_piece_progress(download, term, x, y, w, NULL, NULL); y++; } #endif y++; dlg_format_text_do(dlg_data, msg, x, &y, w, NULL, dialog_text_color, ALIGN_LEFT, 0); y++; dlg_format_buttons(dlg_data, dlg_data->widgets_data, dlg_data->number_of_widgets, x, &y, w, NULL, ALIGN_CENTER, 0); mem_free(url); mem_free(msg); }
void dlg_format_group(struct terminal *term, struct widget_data *widget_data, int n, int x, int *y, int w, int *rw) { int space_between_widgets = 1; int line_width = 0; int xpos; struct color_pair *color = get_bfu_color(term, "dialog.text"); assert(n > 0); if_assert_failed return; while (n--) { int widget_width; int width; unsigned char *text = widget_data->widget->text; int label_length = (text && *text) ? strlen(text) : 0; int label_padding = (label_length > 0); if (widget_data->widget->type == WIDGET_CHECKBOX) { width = 3; } else if (widget_is_textfield(widget_data)) { width = widget_data->widget->datalen; } else { /* TODO: handle all widget types. */ widget_data++; continue; } int_bounds(&label_length, 0, w - width - label_padding); widget_width = width + label_padding + label_length; if (line_width + widget_width > w) { line_width = 0; (*y) += 2; /* Next line */ } xpos = x + line_width; if (term) { if (widget_data->widget->type == WIDGET_CHECKBOX) { /* Draw text at right of checkbox. */ if (label_length) draw_text(term, xpos + width + label_padding, *y, text, label_length, 0, color); set_box(&widget_data->box, xpos, *y, width, 1); } else if (widget_is_textfield(widget_data)) { /* Draw label at left of widget. */ if (label_length) draw_text(term, xpos, *y, text, label_length, 0, color); set_box(&widget_data->box, xpos + label_padding + label_length, *y, width, 1); } } line_width += widget_width; if (rw) int_bounds(rw, line_width, w); line_width += space_between_widgets; widget_data++; } (*y)++; }