1
0
Fork 0
mirror of https://codeberg.org/noisytoot/notnotdnethack.git synced 2024-09-19 22:14:48 +01:00
notnotdnethack/win/curses/cursmesg.c
Ron Nazarov 31411a8d66
Convert some files to ANSI declarations
src/allmain.c, src/alloc.c, src/pline.c, win/tty/termcap.c,
win/tty/topl.c, win/tty/wintty.c, win/tty/getline.c

Also convert curses declarations with an empty parameter list from ()
to (void) and get rid of *_P macros in windowport code.
2024-05-03 17:30:17 +01:00

620 lines
17 KiB
C

/* vim:set cin ft=c sw=4 sts=4 ts=8 et ai cino=Ls\:0t0(0 : -*- mode:c;fill-column:80;tab-width:8;c-basic-offset:4;indent-tabs-mode:nil;c-file-style:"k&r" -*-*/
#include "curses.h"
#include "hack.h"
#include "wincurs.h"
#include "cursmesg.h"
#include <ctype.h>
/* Message window routines for curses interface */
/* Private declatations */
typedef struct nhpm {
char *str; /* Message text */
long turn; /* Turn number for message */
struct nhpm *prev_mesg; /* Pointer to previous message */
struct nhpm *next_mesg; /* Pointer to next message */
} nhprev_mesg;
static void scroll_window(winid wid);
static void unscroll_window(winid wid);
static void directional_scroll(winid wid, int nlines);
static void mesg_add_line(char *mline);
static nhprev_mesg *get_msg_line(boolean reverse, int mindex);
static int turn_lines = 1;
static int mx = 0;
static int my = 0; /* message window text location */
static nhprev_mesg *first_mesg = NULL;
static nhprev_mesg *last_mesg = NULL;
static int max_messages;
static int num_messages = 0;
/* Write a string to the message window. Attributes set by calling function. */
void
curses_message_win_puts(const char *message, boolean recursed)
{
int height, width, linespace;
char *tmpstr;
WINDOW *win = curses_get_nhwin(MESSAGE_WIN);
boolean border = curses_window_has_border(MESSAGE_WIN);
int message_length = strlen(message);
int border_space = 0;
static long suppress_turn = -1;
if (strncmp("Count:", message, 6) == 0) {
curses_count_window(message);
return;
}
if (suppress_turn == moves) {
return;
}
curses_get_window_size(MESSAGE_WIN, &height, &width);
if (border) {
border_space = 1;
if (mx < 1) {
mx = 1;
}
if (my < 1) {
my = 1;
}
}
linespace = ((width + border_space) - 3) - mx;
if (strcmp(message, "#") == 0) { /* Extended command or Count: */
if ((strcmp(toplines, "#") != 0) && (my >= (height - 1 + border_space)) && (height != 1)) { /* Bottom of message window */
scroll_window(MESSAGE_WIN);
mx = width;
my--;
strcpy(toplines, message);
}
return;
}
if (!recursed) {
strcpy(toplines, message);
mesg_add_line((char *) message);
}
if (linespace < message_length) {
if (my >= (height - 1 + border_space)) { /* bottom of message win */
if ((turn_lines > height) || (height == 1)) {
/* Pause until key is hit - Esc suppresses any further
messages that turn */
if (curses_more() == DOESCAPE) {
suppress_turn = moves;
return;
}
} else {
scroll_window(MESSAGE_WIN);
turn_lines++;
}
} else {
if (mx != border_space) {
my++;
mx = border_space;
}
}
}
if (height > 1) {
curses_toggle_color_attr(win, NONE, A_BOLD, ON);
}
if ((mx == border_space) && ((message_length + 2) > width)) {
tmpstr = curses_break_str(message, (width - 2), 1);
mvwprintw(win, my, mx, "%s", tmpstr);
mx += strlen(tmpstr);
if (strlen(tmpstr) < (width - 2)) {
mx++;
}
free(tmpstr);
if (height > 1) {
curses_toggle_color_attr(win, NONE, A_BOLD, OFF);
}
curses_message_win_puts(tmpstr = curses_str_remainder(message, (width - 2), 1),
TRUE);
free(tmpstr);
} else {
mvwprintw(win, my, mx, "%s", message);
curses_toggle_color_attr(win, NONE, A_BOLD, OFF);
mx += message_length + 1;
}
wrefresh(win);
}
int
curses_block(boolean require_tab)
{
int height, width, ret;
WINDOW *win = curses_get_nhwin(MESSAGE_WIN);
curses_get_window_size(MESSAGE_WIN, &height, &width);
curses_toggle_color_attr(win, MORECOLOR, NONE, ON);
mvwprintw(win, my, mx, require_tab ? "<TAB!>" : ">>");
curses_toggle_color_attr(win, MORECOLOR, NONE, OFF);
if (require_tab)
curses_alert_main_borders(TRUE);
wrefresh(win);
while ((ret = wgetch(win) != '\t') && require_tab);
if (require_tab)
curses_alert_main_borders(FALSE);
if (height == 1) {
curses_clear_unhighlight_message_window();
} else {
mvwprintw(win, my, mx, " ");
if (!require_tab) {
scroll_window(MESSAGE_WIN);
turn_lines = 1;
}
}
return ret;
}
int
curses_more(void)
{
return curses_block(FALSE);
}
/* Clear the message window if one line; otherwise unhighlight old messages */
void
curses_clear_unhighlight_message_window(void)
{
int mh, mw, count;
boolean border = curses_window_has_border(MESSAGE_WIN);
WINDOW *win = curses_get_nhwin(MESSAGE_WIN);
turn_lines = 1;
curses_get_window_size(MESSAGE_WIN, &mh, &mw);
mx = 0;
if (border) {
mx++;
}
if (mh == 1) {
curses_clear_nhwin(MESSAGE_WIN);
} else {
mx += mw; /* Force new line on new turn */
if (border) {
for (count = 0; count < mh; count++) {
mvwchgat(win, count + 1, 1, mw, COLOR_PAIR(8), A_NORMAL, NULL);
}
} else {
for (count = 0; count < mh; count++) {
mvwchgat(win, count, 0, mw, COLOR_PAIR(8), A_NORMAL, NULL);
}
}
wnoutrefresh(win);
}
}
/* Reset message window cursor to starting position, and display most
recent messages. */
void
curses_last_messages(void)
{
boolean border = curses_window_has_border(MESSAGE_WIN);
if (border) {
mx = 1;
my = 1;
} else {
mx = 0;
my = 0;
}
nhprev_mesg *mesg;
int i;
for (i = (num_messages - 1); i > 0; i--) {
mesg = get_msg_line(TRUE, i);
if (mesg && mesg->str && strcmp(mesg->str, ""))
curses_message_win_puts(mesg->str, TRUE);
}
curses_message_win_puts(toplines, TRUE);
}
/* Initialize list for message history */
void
curses_init_mesg_history(void)
{
max_messages = iflags.msg_history;
if (max_messages < 1) {
max_messages = 1;
}
if (max_messages > MESG_HISTORY_MAX) {
max_messages = MESG_HISTORY_MAX;
}
}
/* Display previous message window messages in reverse chron order */
void
curses_prev_mesg(void)
{
int count;
winid wid;
long turn = 0;
anything identifier;
nhprev_mesg *mesg;
menu_item *selected = NULL;
wid = curses_get_wid(NHW_MENU);
curses_create_nhmenu(wid);
identifier = zeroany;
for (count = 0; count < num_messages; count++) {
mesg = get_msg_line(TRUE, count);
if ((turn != mesg->turn) && (count != 0)) {
curses_add_menu(wid, NO_GLYPH, &identifier, 0, 0, A_NORMAL,
"---", FALSE);
}
curses_add_menu(wid, NO_GLYPH, &identifier, 0, 0, A_NORMAL,
mesg->str, FALSE);
turn = mesg->turn;
}
curses_end_menu(wid, "");
curses_select_menu(wid, PICK_NONE, &selected);
}
/* Shows Count: in a separate window, or at the bottom of the message
window, depending on the user's settings */
void
curses_count_window(const char *count_text)
{
int startx, starty, winx, winy;
int messageh, messagew;
static WINDOW *countwin = NULL;
if ((count_text == NULL) && (countwin != NULL)) {
delwin(countwin);
countwin = NULL;
counting = FALSE;
return;
}
counting = TRUE;
if (iflags.wc_popup_dialog) { /* Display count in popup window */
startx = 1;
starty = 1;
if (countwin == NULL) {
countwin = curses_create_window(25, 1, UP);
}
} else { /* Display count at bottom of message window */
curses_get_window_xy(MESSAGE_WIN, &winx, &winy);
curses_get_window_size(MESSAGE_WIN, &messageh, &messagew);
if (curses_window_has_border(MESSAGE_WIN)) {
winx++;
winy++;
}
winy += messageh - 1;
if (countwin == NULL) {
pline("#");
#ifndef PDCURSES
countwin = newwin(1, 25, winy, winx);
#endif /* !PDCURSES */
}
#ifdef PDCURSES
else {
curses_destroy_win(countwin);
}
countwin = newwin(1, 25, winy, winx);
#endif /* PDCURSES */
startx = 0;
starty = 0;
}
mvwprintw(countwin, starty, startx, "%s", count_text);
wrefresh(countwin);
}
/* Gets a "line" (buffer) of input. */
void
curses_message_win_getline(const char *prompt, char *answer, int buffer)
{
int height, width; /* of window */
char *tmpbuf, *p_answer; /* combined prompt + answer */
int nlines, maxlines, i; /* prompt + answer */
int promptline;
int promptx;
char **linestarts; /* pointers to start of each line */
char *tmpstr; /* for free() */
int maxy, maxx; /* linewrap / scroll */
int ch;
WINDOW *win = curses_get_nhwin(MESSAGE_WIN);
int border_space = 0;
int len = 0; /* of answer string */
boolean border = curses_window_has_border(MESSAGE_WIN);
int orig_cursor = curs_set(0);
curses_get_window_size(MESSAGE_WIN, &height, &width);
if (border) {
border_space = 1;
if (mx < 1) mx = 1;
if (my < 1) my = 1;
}
maxy = height - 1 + border_space;
maxx = width - 1 + border_space;
tmpbuf = (char *)malloc(strlen(prompt) + buffer + 2);
maxlines = buffer / width * 2;
strcpy(tmpbuf, prompt);
strcat(tmpbuf, " ");
nlines = curses_num_lines(tmpbuf,width);
maxlines += nlines * 2;
linestarts = (char **)malloc(sizeof(char*) * maxlines);
p_answer = tmpbuf + strlen(tmpbuf);
linestarts[0] = tmpbuf;
if (mx > border_space) { /* newline */
if (my >= maxy) scroll_window(MESSAGE_WIN);
else my++;
mx = border_space;
}
curses_toggle_color_attr(win, NONE, A_BOLD, ON);
for (i = 0; i < nlines-1; i++) {
tmpstr = curses_break_str(linestarts[i],width-1,1);
linestarts[i+1] = linestarts[i] + strlen(tmpstr);
if (*linestarts[i+1] == ' ') linestarts[i+1]++;
mvwaddstr(win,my,mx,tmpstr);
free(tmpstr);
if (++my >= maxy) {
scroll_window(MESSAGE_WIN);
my--;
}
}
mvwaddstr(win,my,mx,linestarts[nlines-1]);
mx = promptx = strlen(linestarts[nlines-1]) + border_space;
promptline = nlines - 1;
while(1) {
mx = strlen(linestarts[nlines - 1]) + border_space;
if (mx > maxx) {
if (nlines < maxlines) {
tmpstr = curses_break_str(linestarts[nlines - 1], width - 1, 1);
mx = strlen(tmpstr) + border_space;
mvwprintw(win, my, mx, "%*c", maxx - mx + 1, ' ');
if (++my > maxy) {
scroll_window(MESSAGE_WIN);
my--;
}
mx = border_space;
linestarts[nlines] = linestarts[nlines - 1] + strlen(tmpstr);
if (*linestarts[nlines] == ' ') linestarts[nlines]++;
mvwaddstr(win, my, mx, linestarts[nlines]);
mx = strlen(linestarts[nlines]) + border_space;
nlines++;
free(tmpstr);
} else {
p_answer[--len] = '\0';
mvwaddch(win, my, --mx, ' ');
}
}
wmove(win, my, mx);
curs_set(1);
wrefresh(win);
ch = getch();
curs_set(0);
switch(ch) {
case '\033': /* DOESCAPE */
/* blank the input but don't exit */
while(nlines - 1 > promptline) {
if (nlines-- > height) {
unscroll_window(MESSAGE_WIN);
tmpstr = curses_break_str(linestarts[nlines - height], width - 1, 1);
mvwaddstr(win, border_space, border_space, tmpstr);
free(tmpstr);
} else {
mx = border_space;
mvwprintw(win, my, mx, "%*c", maxx - mx, ' ');
my--;
}
}
mx = promptx;
mvwprintw(win, my, mx, "%*c", maxx - mx, ' ');
*p_answer = '\0';
len = 0;
break;
case ERR: /* should not happen */
*answer = '\0';
free(tmpbuf);
free(linestarts);
curs_set(orig_cursor);
curses_toggle_color_attr(win, NONE, A_BOLD, OFF);
return;
case '\r':
case '\n':
free(linestarts);
strncpy(answer, p_answer, buffer);
strcpy(toplines, tmpbuf);
mesg_add_line((char *) tmpbuf);
/* newline */
if (my >= maxy) scroll_window(MESSAGE_WIN);
else my++;
mx = border_space;
free(tmpbuf);
curs_set(orig_cursor);
curses_toggle_color_attr(win, NONE, A_BOLD, OFF);
return;
case '\b':
case KEY_BACKSPACE:
case '\177': /* delete */
if (len < 1) {
len = 1;
mx = promptx;
}
p_answer[--len] = '\0';
mvwaddch(win, my, --mx, ' ');
/* try to unwrap back to the previous line if there is one */
if (nlines > 1 && strlen(linestarts[nlines - 2]) < width) {
mvwaddstr(win, my - 1, border_space, linestarts[nlines - 2]);
if (nlines-- > height) {
unscroll_window(MESSAGE_WIN);
tmpstr = curses_break_str(linestarts[nlines - height], width - 1, 1);
mvwaddstr(win, border_space, border_space, tmpstr);
free(tmpstr);
} else {
/* clean up the leftovers on the next line, if we didn't scroll it away */
mvwprintw(win, my--, border_space, "%*c", (int)strlen(linestarts[nlines]), ' ');
}
}
break;
default:
p_answer[len++] = ch;
if (len >= buffer) len = buffer-1;
else mvwaddch(win, my, mx, ch);
p_answer[len] = '\0';
}
}
}
/* Scroll lines upward in given window, or clear window if only one line. */
static void
scroll_window(winid wid)
{
directional_scroll(wid,1);
}
static void
unscroll_window(winid wid)
{
directional_scroll(wid,-1);
}
static void
directional_scroll(winid wid, int nlines)
{
int wh, ww, s_top, s_bottom;
boolean border = curses_window_has_border(wid);
WINDOW *win = curses_get_nhwin(wid);
curses_get_window_size(wid, &wh, &ww);
if (wh == 1) {
curses_clear_nhwin(wid);
return;
}
if (border) {
s_top = 1;
s_bottom = wh;
} else {
s_top = 0;
s_bottom = wh - 1;
}
scrollok(win, TRUE);
wsetscrreg(win, s_top, s_bottom);
wscrl(win, nlines);
scrollok(win, FALSE);
if (wid == MESSAGE_WIN) {
if (border)
mx = 1;
else
mx = 0;
}
if (border) {
box(win, 0, 0);
}
wrefresh(win);
}
/* Add given line to message history */
static void
mesg_add_line(char *mline)
{
nhprev_mesg *tmp_mesg = NULL;
nhprev_mesg *current_mesg = malloc(sizeof (nhprev_mesg));
current_mesg->str = curses_copy_of(mline);
current_mesg->turn = moves;
current_mesg->next_mesg = NULL;
if (num_messages == 0) {
first_mesg = current_mesg;
}
if (last_mesg != NULL) {
last_mesg->next_mesg = current_mesg;
}
current_mesg->prev_mesg = last_mesg;
last_mesg = current_mesg;
if (num_messages < max_messages) {
num_messages++;
} else {
tmp_mesg = first_mesg->next_mesg;
free(first_mesg->str);
free(first_mesg);
first_mesg = tmp_mesg;
}
}
/* Returns specified line from message history, or NULL if out of bounds */
static nhprev_mesg *
get_msg_line(boolean reverse, int mindex)
{
int count;
nhprev_mesg *current_mesg;
if (reverse) {
current_mesg = last_mesg;
for (count = 0; count < mindex; count++) {
if (current_mesg == NULL) {
return NULL;
}
current_mesg = current_mesg->prev_mesg;
}
return current_mesg;
} else {
current_mesg = first_mesg;
for (count = 0; count < mindex; count++) {
if (current_mesg == NULL) {
return NULL;
}
current_mesg = current_mesg->next_mesg;
}
return current_mesg;
}
}