curses_putmixed() initial attempt

The curses interface was using genl_putmixed() which doesn't
preserve the symbol actually used for a glyph on the display.
This is a first-attempt at implementing curses_putmixed().

On Linux you'll need to distribute the Makefiles again
    sh sys/unix/setup.sh sys/unix/hints/linux.370

On macOS, you'll need to distribute the Makefiles again
    sh sys/unix/setup.sh sys/unix/hints/macOS.370
This commit is contained in:
nhmall
2023-06-06 17:50:08 -04:00
parent a5a11c19c9
commit 4034ec915c
6 changed files with 131 additions and 10 deletions

View File

@@ -3119,6 +3119,7 @@ extern int hide_privileges(boolean);
#ifdef ENHANCED_SYMBOLS
extern int glyphrep(const char *);
extern char *mixed_to_utf8(char *buf, size_t bufsz, const char *str, int *);
extern const char *mixed_to_glyphinfo(const char *str, glyph_info *gip);
extern int match_glyph(char *);
extern void dump_all_glyphids(FILE *fp);
extern void fill_glyphid_cache(void);

View File

@@ -79,6 +79,7 @@ extern void curses_display_nhwindow(winid wid, boolean block);
extern void curses_destroy_nhwindow(winid wid);
extern void curses_curs(winid wid, int x, int y);
extern void curses_putstr(winid wid, int attr, const char *text);
extern void curses_putmixed(winid window, int attr, const char *str);
extern void curses_display_file(const char *filename, boolean must_exist);
extern void curses_start_menu(winid wid, unsigned long);
extern void curses_add_menu(winid wid, const glyph_info *,

View File

@@ -542,6 +542,33 @@ mixed_to_utf8(char *buf, size_t bufsz, const char *str, int *retflags)
return buf;
}
/*
* helper routine if a window port wants to extract the unicode
* representation from a glyph representation in the string;
* the returned string is the remainder of the string after
* extracting the \GNNNNNNNN information.
*/
const char *
mixed_to_glyphinfo(const char *str, glyph_info *gip)
{
int dcount, ggv;
if (!str || !gip)
return " ";
*gip = nul_glyphinfo;
if (*str == '\\' && *(str + 1) == 'G') {
if ((dcount = decode_glyph(str + 2, &ggv))) {
map_glyphinfo(0, 0, ggv, 0, gip);
/* 'str' is ready for the next loop iteration and
'*str' should not be copied at the end of this
iteration */
str += (dcount + 2);
}
}
return str;
}
void
dump_all_glyphids(FILE *fp)
{

View File

@@ -90,7 +90,7 @@ WINCFLAGS += -DNOTTYGRAPHICS
endif
ifdef WANT_WIN_CURSES
WINCFLAGS += -DCURSES_GRAPHICS
WINCFLAGS += -DCURSES_GRAPHICS -D_XOPEN_SOURCE_EXTENDED=1
WINSRC += $(WINCURSESSRC)
WINOBJ0 += $(WINCURSESOBJ)
endif

View File

@@ -22,6 +22,8 @@ extern char erase_char, kill_char;
extern long curs_mesg_suppress_seq; /* from cursmesg.c */
extern boolean curs_mesg_no_suppress; /* ditto */
extern int mesg_mixed;
extern glyph_info mesg_gi;
/* stubs for curses_procs{} */
#ifdef POSITIONBAR
@@ -70,7 +72,7 @@ struct window_procs curses_procs = {
curses_destroy_nhwindow,
curses_curs,
curses_putstr,
genl_putmixed,
curses_putmixed,
curses_display_file,
curses_start_menu,
curses_add_menu,
@@ -561,6 +563,19 @@ curses_putstr(winid wid, int attr, const char *text)
curs_mesg_no_suppress = FALSE;
}
void
curses_putmixed(winid window, int attr, const char *str)
{
if (window == WIN_MESSAGE) {
str = mixed_to_glyphinfo(str, &mesg_gi);
mesg_mixed = 1;
}
/* now send it to the normal putstr */
curses_putstr(window, attr, str);
if (window == WIN_MESSAGE)
mesg_mixed = 0;
}
/* Display the file named str. Complain about missing files
iff complain is TRUE.
*/

View File

@@ -26,10 +26,13 @@ long curs_mesg_suppress_seq = -1L;
message triggers More>> for the previous message and the player responds
with ESC; we need to avoid initiating suppression in that situation */
boolean curs_mesg_no_suppress = FALSE;
/* curses_putmixed() will place information in these next two */
int mesg_mixed = 0;
glyph_info mesg_gi;
/* Message window routines for curses interface */
/* Private declatations */
/* Private declarations */
typedef struct nhpm {
char *str; /* Message text */
@@ -43,6 +46,7 @@ static void unscroll_window(winid wid);
static void directional_scroll(winid wid, int nlines);
static void mesg_add_line(const char *mline);
static nhprev_mesg *get_msg_line(boolean reverse, int mindex);
static int curscolor(int nhcolor, boolean *boldon);
static int turn_lines = 0;
static int mx = 0;
@@ -61,8 +65,10 @@ curses_message_win_puts(const char *message, boolean recursed)
int height, width, border_space, linespace;
char *tmpstr;
WINDOW *win = curses_get_nhwin(MESSAGE_WIN);
boolean bold, border = curses_window_has_border(MESSAGE_WIN);
boolean bold, border = curses_window_has_border(MESSAGE_WIN),
have_mixed_leadin = FALSE, adjustbold = FALSE;
int message_length = (int) strlen(message);
cchar_t mixed_leadin_cchar[2];
#if 0
/*
@@ -110,6 +116,36 @@ curses_message_win_puts(const char *message, boolean recursed)
/* -2: for leading " " (if combining this message with preceding one) */
if (mx > border_space)
linespace -= 2;
bold = (height > 1 && !last_messages);
if (mesg_mixed) {
wchar_t w[2];
int leadin_color;
leadin_color = curscolor(mesg_gi.gm.sym.color, &adjustbold);
/*
* curses_putmixed() skipped past the \GNNNNNNNN encoding
* in the string, and filled in the mesg_gi glyphinfo. It
* flagged that to us by setting mesg_mixed.
*/
w[0] = (wchar_t) mesg_gi.ttychar;
#ifdef ENHANCED_SYMBOLS
if ((windowprocs.wincap2 & WC2_U_UTF8STR) && SYMHANDLING(H_UTF8)
&& mesg_gi.gm.u) {
/* FIXME: this won't work with all unicode values (32 bits -> 16
* bits on Windows) */
w[0] = (wchar_t) mesg_gi.gm.u->utf32ch;
}
#endif
w[1] = L'\0';
if (setcchar(mixed_leadin_cchar, w,
(bold || adjustbold) ? A_BOLD : A_NORMAL,
leadin_color, 0) == OK) {
have_mixed_leadin = TRUE;
message_length++; /* account for that additional column */
}
}
if (linespace < message_length) {
if (my - border_space >= height - 1) {
@@ -143,35 +179,76 @@ curses_message_win_puts(const char *message, boolean recursed)
}
}
bold = (height > 1 && !last_messages);
if (bold)
if (bold || adjustbold)
curses_toggle_color_attr(win, NONE, A_BOLD, ON);
/* will this message fit as-is or do we need to split it? */
if (mx == border_space && message_length > width - 3) {
/* split needed */
tmpstr = curses_break_str(message, (width - 3), 1);
if (have_mixed_leadin) {
mvwadd_wch(win, my, mx, mixed_leadin_cchar);
++mx;
message_length--;
have_mixed_leadin = FALSE;
mesg_mixed = 0;
}
mvwprintw(win, my, mx, "%s", tmpstr), mx += (int) strlen(tmpstr);
/* one space to separate first part of message from rest [is this
actually useful?] */
if (mx < width)
++mx;
free(tmpstr);
if (bold)
if (bold || adjustbold)
curses_toggle_color_attr(win, NONE, A_BOLD, OFF);
tmpstr = curses_str_remainder(message, (width - 3), 1);
curses_message_win_puts(tmpstr, TRUE);
free(tmpstr);
} else {
if (have_mixed_leadin) {
mvwadd_wch(win, my, mx, mixed_leadin_cchar);
++mx;
message_length--;
have_mixed_leadin = FALSE;
mesg_mixed = 0;
}
mvwprintw(win, my, mx, "%s", message), mx += message_length;
if (bold)
if (bold || adjustbold)
curses_toggle_color_attr(win, NONE, A_BOLD, OFF);
}
wrefresh(win);
}
void
curses_got_input(void)
static int
curscolor(int nhcolor, boolean *boldon)
{
int curses_color;
*boldon = FALSE;
if (nhcolor == 0) { /* make black fg visible */
#ifdef USE_DARKGRAY
if (iflags.wc2_darkgray) {
if (COLORS > 16) {
/* colorpair for black is already darkgray */
} else { /* Use bold for a bright black */
*boldon = TRUE;
}
} else
#endif /* USE_DARKGRAY */
nhcolor = CLR_BLUE;
}
curses_color = nhcolor + 1;
if (COLORS < 16) {
if (curses_color > 8 && curses_color < 17)
curses_color -= 8;
else if (curses_color > (17 + 16))
curses_color -= 16;
}
return curses_color;
}
void curses_got_input(void)
{
/* if messages are being suppressed, reenable them */
curs_mesg_suppress_seq = -1L;