/* This file was contributed by Suzanne Skinner and is copyrighted under the GNU General Public License. (C) 2002 Suzanne Skinner. The code contained in this file is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ #include <stdio.h> #include <stdlib.h> #include <ncurses.h> #include <string.h> #include "dynstr.h" #include "getline.h" #include "defines.h" /* for NAP_MIN(), NAP_MAX() */ #include "nap.h" #include "winio.h" #include "dlul_screen.h" #include "colors.h" #include "status_line.h" /*** Private Function Prototypes ***/ static void sl_scroll_left(void); static void sl_scroll_right(void); static void sl_scroll_to(int); static dynstr sl_text = NULL; static dynstr sl_input_text = NULL; static int sl_scroll_pos = 0; static bool sl_input_mode_on = FALSE; static int sl_input_cursor = 0; static const char *sl_input_mode_prefix = "/search "; /* Set the text of the status line to "str". Note: input-mode keeps a separate * buffer which will not be effected by sl_set or sl_sprintf. This function * has the side effect of setting sl_scroll_pos to 0, unless str is identical * to the original status-line text or input-mode is on. */ void sl_set(const char *str) { if (!sl_input_mode_on && strcmp(ds_get(&sl_text), str) != 0) sl_scroll_pos = 0; ds_set(&sl_text, str); sl_draw(); } /* sprintf text into the status line (there is no length limit). Note: * input-mode keeps a separate buffer which will not be effected by sl_set or * sl_sprintf. This function has the side effect of setting sl_scroll_pos to 0 * (unless input-mode is on). */ void sl_sprintf(const char *format, ...) { va_list args; va_start(args, format); ds_vsprintf(&sl_text, format, args); va_end(args); if (!sl_input_mode_on) { sl_scroll_pos = 0; sl_draw(); } } /* Draws the status line to the bottom line of the current window (determined * by checking the "screen" global variable). This function is called by any * sl_ function that changes the contents (or scroll-state) of the status line, * and may also be called externally as needed (e.g. after a screen switch). * * The status line will be displayed in white-on-red, unless input-mode is * active, in which case it is displayed in inverse video. * * Note: sl_draw will never call wrefresh, nor will any sl_ function. * Screen refreshing is left to the higher level. */ void sl_draw(void) { WINDOW *win; int attrib; const char *text; switch (screen) { case RESULT_SCREEN: win = swin; break; case DLUL_SCREEN: win = dlul_win; break; default: return; } if (sl_input_mode_on) { attrib = A_REVERSE; text = ds_get(&sl_input_text); } else { attrib = COLOR_PAIR(CPWR); text = ds_get(&sl_text); } wattron(win, attrib); wmove(win, LINES-1, 0); whline(win, ' ', COLS); waddnstr(win, text + sl_scroll_pos, NAP_MIN(COLS, strlen(text + sl_scroll_pos))); if (sl_input_mode_on) wmove(win, LINES-1, sl_input_cursor - sl_scroll_pos); wattroff(win, attrib); } /* Call this function any time a keystroke is received on a screen that uses * status_line.c. It will return TRUE if the keystroke applied to the * status line (left/right scrolling, input mode, etc.), in which case no * further handling should be done. If it returns FALSE, the keystroke was not * of interest and should be handled by the caller instead. * * If input-mode is active and the user types ENTER after entering a search * command, the command will be executed via cmds.c:parseout(). Input mode is * then exited and the scroll position is set back to 0. * * Note: This function will grab *all* keystrokes if input-mode is on. */ bool sl_handle_keystroke(chtype ch) { sock_t *sock_data; int sock; if (sl_input_mode_on) { sl_input_cursor = gl_handle_keystroke(&sl_input_text, strlen(sl_input_mode_prefix), sl_input_cursor, ch); if (sl_input_cursor == GL_DONE) { sl_input_mode_on = FALSE; sl_scroll_pos = sl_input_cursor = 0; sl_set(""); if (ds_len(&sl_input_text) > strlen(sl_input_mode_prefix)) { sock_data = findsock("server"); sock = (sock_data ? sock_data->fd : -1); parseout(sock, ds_get(&sl_input_text), wchan); } } else if (sl_input_cursor == GL_ABORT) { sl_input_mode_on = FALSE; sl_scroll_pos = sl_input_cursor = 0; sl_set("Input aborted."); } else { sl_scroll_to(sl_input_cursor); } sl_draw(); return TRUE; } switch (ch) { case KEY_LEFT: sl_scroll_left(); sl_draw(); return TRUE; case KEY_RIGHT: sl_scroll_right(); sl_draw(); return TRUE; case ' ': sl_input_mode_on = TRUE; ds_set(&sl_input_text, sl_input_mode_prefix); sl_scroll_pos = 0; sl_input_cursor = ds_len(&sl_input_text); sl_draw(); return TRUE; } return FALSE; } /*** Private ***/ static void sl_scroll_left(void) { sl_scroll_pos -= NAP_MAX(COLS/2, 1); if (sl_scroll_pos < 0) sl_scroll_pos = 0; } static void sl_scroll_right(void) { int len; len = ds_len(sl_input_mode_on ? &sl_input_text : &sl_text); if (sl_scroll_pos + COLS > len) return; sl_scroll_pos += NAP_MAX(COLS/2, 1); if (sl_scroll_pos > len) sl_scroll_pos = len; } /* scoll so that cursor is visible. For a very long line, this "while" implementation is slower than an equivalent "modulo" calculation, but conceptually simpler. */ static void sl_scroll_to(int cursor) { while (cursor < sl_scroll_pos) { sl_scroll_left(); } while (cursor >= sl_scroll_pos + COLS) { sl_scroll_right(); } }