Current Path : /usr/src/contrib/dialog/ |
FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64 |
Current File : //usr/src/contrib/dialog/buttons.c |
/* * $Id: buttons.c,v 1.86 2011/06/28 10:46:46 tom Exp $ * * buttons.c -- draw buttons, e.g., OK/Cancel * * Copyright 2000-2010,2011 Thomas E. Dickey * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License, version 2.1 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to * Free Software Foundation, Inc. * 51 Franklin St., Fifth Floor * Boston, MA 02110, USA. */ #include <dialog.h> #include <dlg_keys.h> #ifdef NEED_WCHAR_H #include <wchar.h> #endif #define MIN_BUTTON (dialog_state.visit_items ? -1 : 0) static void center_label(char *buffer, int longest, const char *label) { int len = dlg_count_columns(label); int left = 0, right = 0; *buffer = 0; if (len < longest) { left = (longest - len) / 2; right = (longest - len - left); if (left > 0) sprintf(buffer, "%*s", left, " "); } strcat(buffer, label); if (right > 0) sprintf(buffer + strlen(buffer), "%*s", right, " "); } /* * Parse a multibyte character out of the string, set it past the parsed * character. */ static int string_to_char(const char **stringp) { int result; #ifdef USE_WIDE_CURSES const char *string = *stringp; size_t have = strlen(string); size_t check; size_t len; wchar_t cmp2[2]; mbstate_t state; memset(&state, 0, sizeof(state)); len = mbrlen(string, have, &state); if ((int) len > 0 && len <= have) { memset(&state, 0, sizeof(state)); memset(cmp2, 0, sizeof(cmp2)); check = mbrtowc(cmp2, string, len, &state); if ((int) check <= 0) cmp2[0] = 0; *stringp += len; } else { cmp2[0] = UCH(*string); *stringp += 1; } result = cmp2[0]; #else const char *string = *stringp; result = UCH(*string); *stringp += 1; #endif return result; } /* * Print a button */ static void print_button(WINDOW *win, char *label, int y, int x, int selected) { int i; int state = 0; const int *indx = dlg_index_wchars(label); int limit = dlg_count_wchars(label); chtype key_attr = (selected ? button_key_active_attr : button_key_inactive_attr); chtype label_attr = (selected ? button_label_active_attr : button_label_inactive_attr); (void) wmove(win, y, x); wattrset(win, selected ? button_active_attr : button_inactive_attr); (void) waddstr(win, "<"); wattrset(win, label_attr); for (i = 0; i < limit; ++i) { int first = indx[i]; int last = indx[i + 1]; switch (state) { case 0: #ifdef USE_WIDE_CURSES if ((last - first) != 1) { const char *temp = (label + first); int cmp = string_to_char(&temp); if (dlg_isupper(cmp)) { wattrset(win, key_attr); state = 1; } break; } #endif if (dlg_isupper(UCH(label[first]))) { wattrset(win, key_attr); state = 1; } break; case 1: wattrset(win, label_attr); state = 2; break; } waddnstr(win, label + first, last - first); } wattrset(win, selected ? button_active_attr : button_inactive_attr); (void) waddstr(win, ">"); (void) wmove(win, y, x + ((int) strspn(label, " ")) + 1); } /* * Count the buttons in the list. */ int dlg_button_count(const char **labels) { int result = 0; while (*labels++ != 0) ++result; return result; } /* * Compute the size of the button array in columns. Return the total number of * columns in *length, and the longest button's columns in *longest */ void dlg_button_sizes(const char **labels, int vertical, int *longest, int *length) { int n; *length = 0; *longest = 0; for (n = 0; labels[n] != 0; n++) { if (vertical) { *length += 1; *longest = 1; } else { int len = dlg_count_columns(labels[n]); if (len > *longest) *longest = len; *length += len; } } /* * If we can, make all of the buttons the same size. This is only optional * for buttons laid out horizontally. */ if (*longest < 6 - (*longest & 1)) *longest = 6 - (*longest & 1); if (!vertical) *length = *longest * n; } /* * Compute the size of the button array. */ int dlg_button_x_step(const char **labels, int limit, int *gap, int *margin, int *step) { int count = dlg_button_count(labels); int longest; int length; int unused; int used; if (count == 0) return 0; dlg_button_sizes(labels, FALSE, &longest, &length); used = (length + (count * 2)); unused = limit - used; if ((*gap = unused / (count + 3)) <= 0) { if ((*gap = unused / (count + 1)) <= 0) *gap = 1; *margin = *gap; } else { *margin = *gap * 2; } *step = *gap + (used + count - 1) / count; return (*gap > 0) && (unused >= 0); } /* * Make sure there is enough space for the buttons */ void dlg_button_layout(const char **labels, int *limit) { int width = 1; int gap, margin, step; if (labels != 0 && dlg_button_count(labels)) { while (!dlg_button_x_step(labels, width, &gap, &margin, &step)) ++width; width += (4 * MARGIN); if (width > COLS) width = COLS; if (width > *limit) *limit = width; } } /* * Print a list of buttons at the given position. */ void dlg_draw_buttons(WINDOW *win, int y, int x, const char **labels, int selected, int vertical, int limit) { chtype save = dlg_get_attrs(win); int n; int step = 0; int length; int longest; int final_x; int final_y; int gap; int margin; size_t need; char *buffer; dlg_mouse_setbase(getbegx(win), getbegy(win)); getyx(win, final_y, final_x); dlg_button_sizes(labels, vertical, &longest, &length); if (vertical) { y += 1; step = 1; } else { dlg_button_x_step(labels, limit, &gap, &margin, &step); x += margin; } /* * Allocate a buffer big enough for any label. */ need = (size_t) longest; for (n = 0; labels[n] != 0; ++n) { need += strlen(labels[n]) + 1; } buffer = dlg_malloc(char, need); assert_ptr(buffer, "dlg_draw_buttons"); /* * Draw the labels. */ for (n = 0; labels[n] != 0; n++) { center_label(buffer, longest, labels[n]); mouse_mkbutton(y, x, dlg_count_columns(buffer), n); print_button(win, buffer, y, x, (selected == n) || (n == 0 && selected < 0)); if (selected == n) getyx(win, final_y, final_x); if (vertical) { if ((y += step) > limit) break; } else { if ((x += step) > limit) break; } } (void) wmove(win, final_y, final_x); wrefresh(win); free(buffer); wattrset(win, save); } /* * Match a given character against the beginning of the string, ignoring case * of the given character. The matching string must begin with an uppercase * character. */ int dlg_match_char(int ch, const char *string) { if (string != 0) { int cmp2 = string_to_char(&string); #ifdef USE_WIDE_CURSES wint_t cmp1 = dlg_toupper(ch); if (cmp2 != 0 && (wchar_t) cmp1 == (wchar_t) dlg_toupper(cmp2)) { return TRUE; } #else if (ch > 0 && ch < 256) { if (dlg_toupper(ch) == dlg_toupper(cmp2)) return TRUE; } #endif } return FALSE; } /* * Find the first uppercase character in the label, which we may use for an * abbreviation. */ int dlg_button_to_char(const char *label) { int cmp = -1; while (*label != 0) { cmp = string_to_char(&label); if (dlg_isupper(cmp)) { break; } } return cmp; } /* * Given a list of button labels, and a character which may be the abbreviation * for one, find it, if it exists. An abbreviation will be the first character * which happens to be capitalized in the label. */ int dlg_char_to_button(int ch, const char **labels) { if (labels != 0) { int j; ch = (int) dlg_toupper(dlg_last_getc()); for (j = 0; labels[j] != 0; ++j) { int cmp = dlg_button_to_char(labels[j]); if (ch == cmp) { dlg_flush_getc(); return j; } } } return DLG_EXIT_UNKNOWN; } static const char * my_yes_label(void) { return (dialog_vars.yes_label != NULL) ? dialog_vars.yes_label : _("Yes"); } static const char * my_no_label(void) { return (dialog_vars.no_label != NULL) ? dialog_vars.no_label : _("No"); } static const char * my_ok_label(void) { return (dialog_vars.ok_label != NULL) ? dialog_vars.ok_label : _("OK"); } static const char * my_cancel_label(void) { return (dialog_vars.cancel_label != NULL) ? dialog_vars.cancel_label : _("Cancel"); } static const char * my_exit_label(void) { return (dialog_vars.exit_label != NULL) ? dialog_vars.exit_label : _("EXIT"); } static const char * my_extra_label(void) { return (dialog_vars.extra_label != NULL) ? dialog_vars.extra_label : _("Extra"); } static const char * my_help_label(void) { return (dialog_vars.help_label != NULL) ? dialog_vars.help_label : _("Help"); } /* * Return a list of button labels. */ const char ** dlg_exit_label(void) { const char **result; DIALOG_VARS save; if (dialog_vars.extra_button) { dlg_save_vars(&save); dialog_vars.nocancel = TRUE; result = dlg_ok_labels(); dlg_restore_vars(&save); } else { static const char *labels[3]; int n = 0; if (!dialog_vars.nook) labels[n++] = my_exit_label(); if (dialog_vars.help_button) labels[n++] = my_help_label(); if (n == 0) labels[n++] = my_exit_label(); labels[n] = 0; result = labels; } return result; } /* * Map the given button index for dlg_exit_label() into our exit-code. */ int dlg_exit_buttoncode(int button) { int result; DIALOG_VARS save; dlg_save_vars(&save); dialog_vars.nocancel = TRUE; result = dlg_ok_buttoncode(button); dlg_restore_vars(&save); return result; } const char ** dlg_ok_label(void) { static const char *labels[3]; int n = 0; labels[n++] = my_ok_label(); if (dialog_vars.help_button) labels[n++] = my_help_label(); labels[n] = 0; return labels; } /* * Return a list of button labels for the OK/Cancel group. */ const char ** dlg_ok_labels(void) { static const char *labels[5]; int n = 0; if (!dialog_vars.nook) labels[n++] = my_ok_label(); if (dialog_vars.extra_button) labels[n++] = my_extra_label(); if (!dialog_vars.nocancel) labels[n++] = my_cancel_label(); if (dialog_vars.help_button) labels[n++] = my_help_label(); labels[n] = 0; return labels; } /* * Map the given button index for dlg_ok_labels() into our exit-code */ int dlg_ok_buttoncode(int button) { int result = DLG_EXIT_ERROR; int n = !dialog_vars.nook; if (!dialog_vars.nook && (button <= 0)) { result = DLG_EXIT_OK; } else if (dialog_vars.extra_button && (button == n++)) { result = DLG_EXIT_EXTRA; } else if (!dialog_vars.nocancel && (button == n++)) { result = DLG_EXIT_CANCEL; } else if (dialog_vars.help_button && (button == n)) { result = DLG_EXIT_HELP; } return result; } /* * Given that we're using dlg_ok_labels() to list buttons, find the next index * in the list of buttons. The 'extra' parameter if negative provides a way to * enumerate extra active areas on the widget. */ int dlg_next_ok_buttonindex(int current, int extra) { int result = current + 1; if (current >= 0 && dlg_ok_buttoncode(result) < 0) result = extra; return result; } /* * Similarly, find the previous button index. */ int dlg_prev_ok_buttonindex(int current, int extra) { int result = current - 1; if (result < extra) { for (result = 0; dlg_ok_buttoncode(result + 1) >= 0; ++result) { ; } } return result; } /* * Find the button-index for the "OK" or "Cancel" button, according to * whether --defaultno is given. If --nocancel was given, we always return * the index for "OK". */ int dlg_defaultno_button(void) { int result = 0; if (dialog_vars.defaultno && !dialog_vars.nocancel) { while (dlg_ok_buttoncode(result) != DLG_EXIT_CANCEL) ++result; } return result; } /* * Return a list of buttons for Yes/No labels. */ const char ** dlg_yes_labels(void) { const char **result; if (dialog_vars.extra_button) { result = dlg_ok_labels(); } else { static const char *labels[4]; int n = 0; labels[n++] = my_yes_label(); labels[n++] = my_no_label(); if (dialog_vars.help_button) labels[n++] = my_help_label(); labels[n] = 0; result = labels; } return result; } /* * Map the given button index for dlg_yes_labels() into our exit-code. */ int dlg_yes_buttoncode(int button) { int result = DLG_EXIT_ERROR; if (dialog_vars.extra_button) { result = dlg_ok_buttoncode(button); } else if (button == 0) { result = DLG_EXIT_OK; } else if (button == 1) { result = DLG_EXIT_CANCEL; } else if (button == 2 && dialog_vars.help_button) { result = DLG_EXIT_HELP; } return result; } /* * Return the next index in labels[]; */ int dlg_next_button(const char **labels, int button) { if (labels[button + 1] != 0) ++button; else button = MIN_BUTTON; return button; } /* * Return the previous index in labels[]; */ int dlg_prev_button(const char **labels, int button) { if (button > MIN_BUTTON) --button; else { while (labels[button + 1] != 0) ++button; } return button; }