freebsd-dev/contrib/dialog/textbox.c
Nathan Whitehorn 1971864966 Revert r241818 that updated dialog to 20120706. This turns out to horribly
break mixed form dialogs in conjunction with the FreeBSD termcap, making
the bsdinstall partition editor Add dialog, among other things, completely
nonfunctional. This restores dialog 20110707.
2012-12-30 04:22:34 +00:00

949 lines
24 KiB
C

/*
* $Id: textbox.c,v 1.101 2011/06/29 09:53:03 tom Exp $
*
* textbox.c -- implements the text box
*
* 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.
*
* An earlier version of this program lists as authors:
* Savio Lam (lam836@cs.cuhk.hk)
*/
#include <dialog.h>
#include <dlg_keys.h>
#define PAGE_LENGTH (height - 4)
#define PAGE_WIDTH (width - 2)
typedef struct {
DIALOG_CALLBACK obj;
WINDOW *text;
const char **buttons;
int hscroll;
char line[MAX_LEN + 1];
int fd;
long file_size;
long fd_bytes_read;
long bytes_read;
long buffer_len;
bool begin_reached;
bool buffer_first;
bool end_reached;
long page_length; /* lines on the page which is shown */
long in_buf; /* ending index into buf[] for page */
char *buf;
} MY_OBJ;
static long
lseek_obj(MY_OBJ * obj, long offset, int mode)
{
long fpos;
if ((fpos = (long) lseek(obj->fd, (off_t) offset, mode)) == -1) {
switch (mode) {
case SEEK_CUR:
dlg_exiterr("Cannot get file position");
break;
case SEEK_END:
dlg_exiterr("Cannot seek to end of file");
break;
case SEEK_SET:
dlg_exiterr("Cannot set file position to %ld", offset);
break;
}
}
return fpos;
}
static long
ftell_obj(MY_OBJ * obj)
{
return lseek_obj(obj, 0L, SEEK_CUR);
}
static char *
xalloc(size_t size)
{
char *result = dlg_malloc(char, size);
assert_ptr(result, "xalloc");
return result;
}
/*
* read_high() substitutes read() for tab->spaces conversion
*
* buffer_len, fd_bytes_read, bytes_read are modified
* buf is allocated
*
* fd_bytes_read is the effective number of bytes read from file
* bytes_read is the length of buf, that can be different if tab_correct
*/
static void
read_high(MY_OBJ * obj, size_t size_read)
{
char *buftab, ch;
int i = 0, j, n, tmpint;
long begin_line;
/* Allocate space for read buffer */
buftab = xalloc(size_read + 1);
if ((obj->fd_bytes_read = read(obj->fd, buftab, size_read)) != -1) {
buftab[obj->fd_bytes_read] = '\0'; /* mark end of valid data */
if (dialog_vars.tab_correct) {
/* calculate bytes_read by buftab and fd_bytes_read */
obj->bytes_read = begin_line = 0;
for (j = 0; j < obj->fd_bytes_read; j++)
if (buftab[j] == TAB)
obj->bytes_read += dialog_state.tab_len
- ((obj->bytes_read - begin_line)
% dialog_state.tab_len);
else if (buftab[j] == '\n') {
obj->bytes_read++;
begin_line = obj->bytes_read;
} else
obj->bytes_read++;
if (obj->bytes_read > obj->buffer_len) {
if (obj->buffer_first)
obj->buffer_first = FALSE; /* disp = 0 */
else {
free(obj->buf);
}
obj->buffer_len = obj->bytes_read;
/* Allocate space for read buffer */
obj->buf = xalloc((size_t) obj->buffer_len + 1);
}
} else {
if (obj->buffer_first) {
obj->buffer_first = FALSE;
/* Allocate space for read buffer */
obj->buf = xalloc(size_read + 1);
}
obj->bytes_read = obj->fd_bytes_read;
}
j = 0;
begin_line = 0;
while (j < obj->fd_bytes_read)
if (((ch = buftab[j++]) == TAB) && (dialog_vars.tab_correct != 0)) {
tmpint = (dialog_state.tab_len
- ((int) ((long) i - begin_line) % dialog_state.tab_len));
for (n = 0; n < tmpint; n++)
obj->buf[i++] = ' ';
} else {
if (ch == '\n')
begin_line = i + 1;
obj->buf[i++] = ch;
}
obj->buf[i] = '\0'; /* mark end of valid data */
}
if (obj->bytes_read == -1)
dlg_exiterr("Error reading file");
free(buftab);
}
static long
find_first(MY_OBJ * obj, char *buffer, long length)
{
long recount = obj->page_length;
long result = 0;
while (length > 0) {
if (buffer[length] == '\n') {
if (--recount < 0) {
result = length;
break;
}
}
--length;
}
return result;
}
static long
tabize(MY_OBJ * obj, long val, long *first_pos)
{
long fpos;
long i, count, begin_line;
char *buftab;
if (!dialog_vars.tab_correct)
return val;
fpos = ftell_obj(obj);
lseek_obj(obj, fpos - obj->fd_bytes_read, SEEK_SET);
/* Allocate space for read buffer */
buftab = xalloc((size_t) val + 1);
if ((read(obj->fd, buftab, (size_t) val)) == -1)
dlg_exiterr("Error reading file in tabize().");
begin_line = count = 0;
if (first_pos != 0)
*first_pos = 0;
for (i = 0; i < val; i++) {
if ((first_pos != 0) && (count >= val)) {
*first_pos = find_first(obj, buftab, i);
break;
}
if (buftab[i] == TAB)
count += dialog_state.tab_len
- ((count - begin_line) % dialog_state.tab_len);
else if (buftab[i] == '\n') {
count++;
begin_line = count;
} else
count++;
}
lseek_obj(obj, fpos, SEEK_SET);
free(buftab);
return count;
}
/*
* Return current line of text.
* 'page' should point to start of current line before calling, and will be
* updated to point to start of next line.
*/
static char *
get_line(MY_OBJ * obj)
{
int i = 0;
long fpos;
obj->end_reached = FALSE;
while (obj->buf[obj->in_buf] != '\n') {
if (obj->buf[obj->in_buf] == '\0') { /* Either end of file or end of buffer reached */
fpos = ftell_obj(obj);
if (fpos < obj->file_size) { /* Not end of file yet */
/* We've reached end of buffer, but not end of file yet, so
* read next part of file into buffer
*/
read_high(obj, BUF_SIZE);
obj->in_buf = 0;
} else {
if (!obj->end_reached)
obj->end_reached = TRUE;
break;
}
} else if (i < MAX_LEN)
obj->line[i++] = obj->buf[obj->in_buf++];
else {
if (i == MAX_LEN) /* Truncate lines longer than MAX_LEN characters */
obj->line[i++] = '\0';
obj->in_buf++;
}
}
if (i <= MAX_LEN)
obj->line[i] = '\0';
if (!obj->end_reached)
obj->in_buf++; /* move past '\n' */
return obj->line;
}
static bool
match_string(MY_OBJ * obj, char *string)
{
char *match = get_line(obj);
return strstr(match, string) != 0;
}
/*
* Go back 'n' lines in text file. Called by dialog_textbox().
* 'in_buf' will be updated to point to the desired line in 'buf'.
*/
static void
back_lines(MY_OBJ * obj, long n)
{
int i;
long fpos;
long val_to_tabize;
obj->begin_reached = FALSE;
/* We have to distinguish between end_reached and !end_reached since at end
* of file, the line is not ended by a '\n'. The code inside 'if'
* basically does a '--in_buf' to move one character backward so as to
* skip '\n' of the previous line */
if (!obj->end_reached) {
/* Either beginning of buffer or beginning of file reached? */
if (obj->in_buf == 0) {
fpos = ftell_obj(obj);
if (fpos > obj->fd_bytes_read) { /* Not beginning of file yet */
/* We've reached beginning of buffer, but not beginning of file
* yet, so read previous part of file into buffer. Note that
* we only move backward for BUF_SIZE/2 bytes, but not BUF_SIZE
* bytes to avoid re-reading again in print_page() later
*/
/* Really possible to move backward BUF_SIZE/2 bytes? */
if (fpos < BUF_SIZE / 2 + obj->fd_bytes_read) {
/* No, move less than */
lseek_obj(obj, 0L, SEEK_SET);
val_to_tabize = fpos - obj->fd_bytes_read;
} else { /* Move backward BUF_SIZE/2 bytes */
lseek_obj(obj, -(BUF_SIZE / 2 + obj->fd_bytes_read), SEEK_CUR);
val_to_tabize = BUF_SIZE / 2;
}
read_high(obj, BUF_SIZE);
obj->in_buf = tabize(obj, val_to_tabize, (long *) 0);
} else { /* Beginning of file reached */
obj->begin_reached = TRUE;
return;
}
}
obj->in_buf--;
if (obj->buf[obj->in_buf] != '\n')
/* Something's wrong... */
dlg_exiterr("Internal error in back_lines().");
}
/* Go back 'n' lines */
for (i = 0; i < n; i++) {
do {
if (obj->in_buf == 0) {
fpos = ftell_obj(obj);
if (fpos > obj->fd_bytes_read) {
/* Really possible to move backward BUF_SIZE/2 bytes? */
if (fpos < BUF_SIZE / 2 + obj->fd_bytes_read) {
/* No, move less than */
lseek_obj(obj, 0L, SEEK_SET);
val_to_tabize = fpos - obj->fd_bytes_read;
} else { /* Move backward BUF_SIZE/2 bytes */
lseek_obj(obj, -(BUF_SIZE / 2 + obj->fd_bytes_read), SEEK_CUR);
val_to_tabize = BUF_SIZE / 2;
}
read_high(obj, BUF_SIZE);
obj->in_buf = tabize(obj, val_to_tabize, (long *) 0);
} else { /* Beginning of file reached */
obj->begin_reached = TRUE;
return;
}
}
} while (obj->buf[--(obj->in_buf)] != '\n');
}
obj->in_buf++;
}
/*
* Print a new line of text.
*/
static void
print_line(MY_OBJ * obj, int row, int width)
{
if (wmove(obj->text, row, 0) != ERR) {
int i, y, x;
char *line = get_line(obj);
const int *cols = dlg_index_columns(line);
const int *indx = dlg_index_wchars(line);
int limit = dlg_count_wchars(line);
int first = 0;
int last = limit;
if (width > getmaxx(obj->text))
width = getmaxx(obj->text);
--width; /* for the leading ' ' */
for (i = 0; i <= limit && cols[i] < obj->hscroll; ++i)
first = i;
for (i = first; (i <= limit) && ((cols[i] - cols[first]) < width); ++i)
last = i;
(void) waddch(obj->text, ' ');
(void) waddnstr(obj->text, line + indx[first], indx[last] - indx[first]);
getyx(obj->text, y, x);
if (y == row) { /* Clear 'residue' of previous line */
for (i = 0; i <= width - x; i++) {
(void) waddch(obj->text, ' ');
}
}
}
}
/*
* Print a new page of text.
*/
static void
print_page(MY_OBJ * obj, int height, int width)
{
int i, passed_end = 0;
obj->page_length = 0;
for (i = 0; i < height; i++) {
print_line(obj, i, width);
if (!passed_end)
obj->page_length++;
if (obj->end_reached && !passed_end)
passed_end = 1;
}
(void) wnoutrefresh(obj->text);
}
/*
* Print current position
*/
static void
print_position(MY_OBJ * obj, WINDOW *win, int height, int width)
{
long fpos;
long size;
long first = -1;
fpos = ftell_obj(obj);
if (dialog_vars.tab_correct)
size = tabize(obj, obj->in_buf, &first);
else
first = find_first(obj, obj->buf, size = obj->in_buf);
dlg_draw_scrollbar(win,
first,
fpos - obj->fd_bytes_read + size,
fpos - obj->fd_bytes_read + size,
obj->file_size,
0, PAGE_WIDTH,
0, PAGE_LENGTH + 1,
border_attr,
border_attr);
}
/*
* Display a dialog box and get the search term from user.
*/
static int
get_search_term(WINDOW *dialog, char *input, int height, int width)
{
/* *INDENT-OFF* */
static DLG_KEYS_BINDING binding[] = {
INPUTSTR_BINDINGS,
HELPKEY_BINDINGS,
ENTERKEY_BINDINGS,
END_KEYS_BINDING
};
/* *INDENT-ON* */
int old_x, old_y;
int box_x, box_y;
int box_height, box_width;
int offset = 0;
int key = 0;
int fkey = 0;
bool first = TRUE;
int result = DLG_EXIT_UNKNOWN;
const char *caption = _("Search");
int len_caption = dlg_count_columns(caption);
const int *indx;
int limit;
WINDOW *widget;
getbegyx(dialog, old_y, old_x);
box_height = 1 + (2 * MARGIN);
box_width = len_caption + (2 * (MARGIN + 2));
box_width = MAX(box_width, 30);
box_width = MIN(box_width, getmaxx(dialog) - 2 * MARGIN);
len_caption = MIN(len_caption, box_width - (2 * (MARGIN + 1)));
box_x = (width - box_width) / 2;
box_y = (height - box_height) / 2;
widget = dlg_new_modal_window(dialog,
box_height, box_width,
old_y + box_y, old_x + box_x);
keypad(widget, TRUE);
dlg_register_window(widget, "searchbox", binding);
dlg_draw_box(widget, 0, 0, box_height, box_width,
searchbox_attr,
searchbox_border_attr);
wattrset(widget, searchbox_title_attr);
(void) wmove(widget, 0, (box_width - len_caption) / 2);
indx = dlg_index_wchars(caption);
limit = dlg_limit_columns(caption, len_caption, 0);
(void) waddnstr(widget, caption + indx[0], indx[limit] - indx[0]);
box_y++;
box_x++;
box_width -= 2;
offset = dlg_count_columns(input);
while (result == DLG_EXIT_UNKNOWN) {
if (!first) {
key = dlg_getc(widget, &fkey);
if (fkey) {
switch (fkey) {
#ifdef KEY_RESIZE
case KEY_RESIZE:
result = DLG_EXIT_CANCEL;
continue;
#endif
case DLGK_ENTER:
result = DLG_EXIT_OK;
continue;
}
} else if (key == ESC) {
result = DLG_EXIT_ESC;
continue;
} else if (key == ERR) {
napms(50);
continue;
}
}
if (dlg_edit_string(input, &offset, key, fkey, first)) {
dlg_show_string(widget, input, offset, searchbox_attr,
1, 1, box_width, FALSE, first);
first = FALSE;
}
}
dlg_del_window(widget);
return result;
}
static bool
perform_search(MY_OBJ * obj, int height, int width, int key, char *search_term)
{
int dir;
long tempinx;
long fpos;
int result;
bool found;
bool temp, temp1;
bool moved = FALSE;
/* set search direction */
dir = (key == '/' || key == 'n') ? 1 : 0;
if (dir ? !obj->end_reached : !obj->begin_reached) {
if (key == 'n' || key == 'N') {
if (search_term[0] == '\0') { /* No search term yet */
(void) beep();
return FALSE;
}
/* Get search term from user */
} else if ((result = get_search_term(obj->text, search_term,
PAGE_LENGTH,
PAGE_WIDTH)) != DLG_EXIT_OK
|| search_term[0] == '\0') {
#ifdef KEY_RESIZE
if (result == DLG_EXIT_CANCEL) {
ungetch(key);
ungetch(KEY_RESIZE);
/* FALLTHRU */
}
#endif
/* ESC pressed, or no search term, reprint page to clear box */
wattrset(obj->text, dialog_attr);
back_lines(obj, obj->page_length);
return TRUE;
}
/* Save variables for restoring in case search term can't be found */
tempinx = obj->in_buf;
temp = obj->begin_reached;
temp1 = obj->end_reached;
fpos = ftell_obj(obj) - obj->fd_bytes_read;
/* update 'in_buf' to point to next (previous) line before
forward (backward) searching */
back_lines(obj, (dir
? obj->page_length - 1
: obj->page_length + 1));
found = FALSE;
if (dir) { /* Forward search */
while ((found = match_string(obj, search_term)) == FALSE) {
if (obj->end_reached)
break;
}
} else { /* Backward search */
while ((found = match_string(obj, search_term)) == FALSE) {
if (obj->begin_reached)
break;
back_lines(obj, 2L);
}
}
if (found == FALSE) { /* not found */
(void) beep();
/* Restore program state to that before searching */
lseek_obj(obj, fpos, SEEK_SET);
read_high(obj, BUF_SIZE);
obj->in_buf = tempinx;
obj->begin_reached = temp;
obj->end_reached = temp1;
/* move 'in_buf' to point to start of current page to
* re-print current page. Note that 'in_buf' always points
* to start of next page, so this is necessary
*/
back_lines(obj, obj->page_length);
} else { /* Search term found */
back_lines(obj, 1L);
}
/* Reprint page */
wattrset(obj->text, dialog_attr);
moved = TRUE;
} else { /* no need to find */
(void) beep();
}
return moved;
}
/*
* Display text from a file in a dialog box.
*/
int
dialog_textbox(const char *title, const char *file, int height, int width)
{
/* *INDENT-OFF* */
static DLG_KEYS_BINDING binding[] = {
HELPKEY_BINDINGS,
ENTERKEY_BINDINGS,
DLG_KEYS_DATA( DLGK_GRID_DOWN, 'J' ),
DLG_KEYS_DATA( DLGK_GRID_DOWN, 'j' ),
DLG_KEYS_DATA( DLGK_GRID_DOWN, KEY_DOWN ),
DLG_KEYS_DATA( DLGK_GRID_LEFT, 'H' ),
DLG_KEYS_DATA( DLGK_GRID_LEFT, 'h' ),
DLG_KEYS_DATA( DLGK_GRID_LEFT, KEY_LEFT ),
DLG_KEYS_DATA( DLGK_GRID_RIGHT, 'L' ),
DLG_KEYS_DATA( DLGK_GRID_RIGHT, 'l' ),
DLG_KEYS_DATA( DLGK_GRID_RIGHT, KEY_RIGHT ),
DLG_KEYS_DATA( DLGK_GRID_UP, 'K' ),
DLG_KEYS_DATA( DLGK_GRID_UP, 'k' ),
DLG_KEYS_DATA( DLGK_GRID_UP, KEY_UP ),
DLG_KEYS_DATA( DLGK_PAGE_FIRST, 'g' ),
DLG_KEYS_DATA( DLGK_PAGE_FIRST, KEY_HOME ),
DLG_KEYS_DATA( DLGK_PAGE_LAST, 'G' ),
DLG_KEYS_DATA( DLGK_PAGE_LAST, KEY_END ),
DLG_KEYS_DATA( DLGK_PAGE_LAST, KEY_LL ),
DLG_KEYS_DATA( DLGK_PAGE_NEXT, ' ' ),
DLG_KEYS_DATA( DLGK_PAGE_NEXT, KEY_NPAGE ),
DLG_KEYS_DATA( DLGK_PAGE_PREV, 'B' ),
DLG_KEYS_DATA( DLGK_PAGE_PREV, 'b' ),
DLG_KEYS_DATA( DLGK_PAGE_PREV, KEY_PPAGE ),
DLG_KEYS_DATA( DLGK_BEGIN, '0' ),
DLG_KEYS_DATA( DLGK_BEGIN, KEY_BEG ),
DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ),
DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ),
END_KEYS_BINDING
};
/* *INDENT-ON* */
#ifdef KEY_RESIZE
int old_height = height;
int old_width = width;
#endif
long fpos;
int x, y, cur_x, cur_y;
int key = 0, fkey;
int next = 0;
int i, code, passed_end;
char search_term[MAX_LEN + 1];
MY_OBJ obj;
WINDOW *dialog;
bool moved;
int result = DLG_EXIT_UNKNOWN;
int button = dialog_vars.extra_button ? dlg_defaultno_button() : 0;
int min_width = 12;
search_term[0] = '\0'; /* no search term entered yet */
memset(&obj, 0, sizeof(obj));
obj.begin_reached = TRUE;
obj.buffer_first = TRUE;
obj.end_reached = FALSE;
obj.buttons = dlg_exit_label();
/* Open input file for reading */
if ((obj.fd = open(file, O_RDONLY)) == -1)
dlg_exiterr("Can't open input file %s", file);
/* Get file size. Actually, 'file_size' is the real file size - 1,
since it's only the last byte offset from the beginning */
obj.file_size = lseek_obj(&obj, 0L, SEEK_END);
/* Restore file pointer to beginning of file after getting file size */
lseek_obj(&obj, 0L, SEEK_SET);
read_high(&obj, BUF_SIZE);
dlg_button_layout(obj.buttons, &min_width);
#ifdef KEY_RESIZE
retry:
#endif
moved = TRUE;
dlg_auto_sizefile(title, file, &height, &width, 2, min_width);
dlg_print_size(height, width);
dlg_ctl_size(height, width);
x = dlg_box_x_ordinate(width);
y = dlg_box_y_ordinate(height);
dialog = dlg_new_window(height, width, y, x);
dlg_register_window(dialog, "textbox", binding);
dlg_register_buttons(dialog, "textbox", obj.buttons);
dlg_mouse_setbase(x, y);
/* Create window for text region, used for scrolling text */
obj.text = dlg_sub_window(dialog, PAGE_LENGTH, PAGE_WIDTH, y + 1, x + 1);
/* register the new window, along with its borders */
dlg_mouse_mkbigregion(0, 0, PAGE_LENGTH + 2, width, KEY_MAX, 1, 1, 1 /* lines */ );
dlg_draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
dlg_draw_bottom_box(dialog);
dlg_draw_title(dialog, title);
dlg_draw_buttons(dialog, PAGE_LENGTH + 2, 0, obj.buttons, button, FALSE, width);
(void) wnoutrefresh(dialog);
getyx(dialog, cur_y, cur_x); /* Save cursor position */
dlg_attr_clear(obj.text, PAGE_LENGTH, PAGE_WIDTH, dialog_attr);
while (result == DLG_EXIT_UNKNOWN) {
/*
* Update the screen according to whether we shifted up/down by a line
* or not.
*/
if (moved) {
if (next < 0) {
(void) scrollok(obj.text, TRUE);
(void) scroll(obj.text); /* Scroll text region up one line */
(void) scrollok(obj.text, FALSE);
print_line(&obj, PAGE_LENGTH - 1, PAGE_WIDTH);
(void) wnoutrefresh(obj.text);
} else if (next > 0) {
/*
* We don't call print_page() here but use scrolling to ensure
* faster screen update. However, 'end_reached' and
* 'page_length' should still be updated, and 'in_buf' should
* point to start of next page. This is done by calling
* get_line() in the following 'for' loop.
*/
(void) scrollok(obj.text, TRUE);
(void) wscrl(obj.text, -1); /* Scroll text region down one line */
(void) scrollok(obj.text, FALSE);
obj.page_length = 0;
passed_end = 0;
for (i = 0; i < PAGE_LENGTH; i++) {
if (!i) {
print_line(&obj, 0, PAGE_WIDTH); /* print first line of page */
(void) wnoutrefresh(obj.text);
} else
(void) get_line(&obj); /* Called to update 'end_reached' and 'in_buf' */
if (!passed_end)
obj.page_length++;
if (obj.end_reached && !passed_end)
passed_end = 1;
}
} else {
print_page(&obj, PAGE_LENGTH, PAGE_WIDTH);
}
print_position(&obj, dialog, height, width);
(void) wmove(dialog, cur_y, cur_x); /* Restore cursor position */
wrefresh(dialog);
}
moved = FALSE; /* assume we'll not move */
next = 0; /* ...but not scroll by a line */
key = dlg_mouse_wgetch(dialog, &fkey);
if (dlg_result_key(key, fkey, &result))
break;
if (!fkey && (code = dlg_char_to_button(key, obj.buttons)) >= 0) {
result = dlg_ok_buttoncode(code);
break;
}
if (fkey) {
switch (key) {
default:
if (is_DLGK_MOUSE(key)) {
result = dlg_exit_buttoncode(key - M_EVENT);
if (result < 0)
result = DLG_EXIT_OK;
} else {
beep();
}
break;
case DLGK_FIELD_NEXT:
button = dlg_next_button(obj.buttons, button);
if (button < 0)
button = 0;
dlg_draw_buttons(dialog,
height - 2, 0,
obj.buttons, button,
FALSE, width);
break;
case DLGK_FIELD_PREV:
button = dlg_prev_button(obj.buttons, button);
if (button < 0)
button = 0;
dlg_draw_buttons(dialog,
height - 2, 0,
obj.buttons, button,
FALSE, width);
break;
case DLGK_ENTER:
if (dialog_vars.nook)
result = DLG_EXIT_OK;
else
result = dlg_exit_buttoncode(button);
break;
case DLGK_PAGE_FIRST:
if (!obj.begin_reached) {
obj.begin_reached = 1;
/* First page not in buffer? */
fpos = ftell_obj(&obj);
if (fpos > obj.fd_bytes_read) {
/* Yes, we have to read it in */
lseek_obj(&obj, 0L, SEEK_SET);
read_high(&obj, BUF_SIZE);
}
obj.in_buf = 0;
moved = TRUE;
}
break;
case DLGK_PAGE_LAST:
obj.end_reached = TRUE;
/* Last page not in buffer? */
fpos = ftell_obj(&obj);
if (fpos < obj.file_size) {
/* Yes, we have to read it in */
lseek_obj(&obj, -BUF_SIZE, SEEK_END);
read_high(&obj, BUF_SIZE);
}
obj.in_buf = obj.bytes_read;
back_lines(&obj, (long) PAGE_LENGTH);
moved = TRUE;
break;
case DLGK_GRID_UP: /* Previous line */
if (!obj.begin_reached) {
back_lines(&obj, obj.page_length + 1);
next = 1;
moved = TRUE;
}
break;
case DLGK_PAGE_PREV: /* Previous page */
case DLGK_MOUSE(KEY_PPAGE):
if (!obj.begin_reached) {
back_lines(&obj, obj.page_length + PAGE_LENGTH);
moved = TRUE;
}
break;
case DLGK_GRID_DOWN: /* Next line */
if (!obj.end_reached) {
obj.begin_reached = 0;
next = -1;
moved = TRUE;
}
break;
case DLGK_PAGE_NEXT: /* Next page */
case DLGK_MOUSE(KEY_NPAGE):
if (!obj.end_reached) {
obj.begin_reached = 0;
moved = TRUE;
}
break;
case DLGK_BEGIN: /* Beginning of line */
if (obj.hscroll > 0) {
obj.hscroll = 0;
/* Reprint current page to scroll horizontally */
back_lines(&obj, obj.page_length);
moved = TRUE;
}
break;
case DLGK_GRID_LEFT: /* Scroll left */
if (obj.hscroll > 0) {
obj.hscroll--;
/* Reprint current page to scroll horizontally */
back_lines(&obj, obj.page_length);
moved = TRUE;
}
break;
case DLGK_GRID_RIGHT: /* Scroll right */
if (obj.hscroll < MAX_LEN) {
obj.hscroll++;
/* Reprint current page to scroll horizontally */
back_lines(&obj, obj.page_length);
moved = TRUE;
}
break;
#ifdef KEY_RESIZE
case KEY_RESIZE:
/* reset data */
height = old_height;
width = old_width;
back_lines(&obj, obj.page_length);
moved = TRUE;
/* repaint */
dlg_clear();
dlg_del_window(dialog);
refresh();
dlg_mouse_free_regions();
goto retry;
#endif
}
} else {
switch (key) {
case '/': /* Forward search */
case 'n': /* Repeat forward search */
case '?': /* Backward search */
case 'N': /* Repeat backward search */
moved = perform_search(&obj, height, width, key, search_term);
fkey = FALSE;
break;
default:
beep();
break;
}
}
}
dlg_del_window(dialog);
free(obj.buf);
(void) close(obj.fd);
dlg_mouse_free_regions();
return result;
}