Add support for tabbed menu columns
This commit is contained in:
committed by
Pasi Kallinen
parent
44b04064be
commit
ae8b4bf12a
@@ -531,8 +531,10 @@ extern void X11_update_label(Widget);
|
||||
extern void X11_set_attrs(Widget, unsigned);
|
||||
extern void X11_set_highlight(Widget, boolean);
|
||||
extern void X11_set_percent(Widget, unsigned, Pixel);
|
||||
extern void X11_set_column_widths(Widget, const int *, unsigned);
|
||||
extern void X11_blink_labels(void);
|
||||
extern int X11_font_height(X11_Font *);
|
||||
extern int X11_column_width(Display *, X11_Font *, const char *, size_t);
|
||||
|
||||
/*
|
||||
* These are for widgets that use the enhanced label services only for text
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ NetHack*text*borderWidth: 0
|
||||
! These correspond to the .nethackrc settings font_map, font_menu,
|
||||
! font_message, font_status and font_text
|
||||
NetHack.font_map: mono-10
|
||||
NetHack.font_menu: mono-10
|
||||
NetHack.font_menu: sans-10
|
||||
NetHack.font_message: sans-10
|
||||
NetHack.font_status: sans-10
|
||||
NetHack.font_text: mono-10
|
||||
|
||||
+4
-1
@@ -1571,7 +1571,7 @@ static XtResource resources[] = {
|
||||
{ nhStr("font_map"), nhStr("Font_map"), XtRString, sizeof(String),
|
||||
XtOffset(AppResources *, font_map), XtRString, nhStr("mono-10") },
|
||||
{ nhStr("font_menu"), nhStr("Font_menu"), XtRString, sizeof(String),
|
||||
XtOffset(AppResources *, font_menu), XtRString, nhStr("mono-10") },
|
||||
XtOffset(AppResources *, font_menu), XtRString, nhStr("sans-10") },
|
||||
{ nhStr("font_message"), nhStr("Font_message"), XtRString, sizeof(String),
|
||||
XtOffset(AppResources *, font_message), XtRString, nhStr("sans-10") },
|
||||
{ nhStr("font_status"), nhStr("Font_status"), XtRString, sizeof(String),
|
||||
@@ -1646,6 +1646,9 @@ X11_init_nhwindows(int *argcp, char **argv)
|
||||
Arg args[4];
|
||||
uid_t savuid;
|
||||
|
||||
/* Request tabbed menu columns */
|
||||
iflags.menu_tab_sep = TRUE;
|
||||
|
||||
/* Init windows to nothing. */
|
||||
for (i = 0; i < MAX_WINDOWS; i++)
|
||||
window_list[i].type = NHW_NONE;
|
||||
|
||||
+93
-12
@@ -19,7 +19,8 @@
|
||||
#include "winX.h"
|
||||
|
||||
/* Declarations depending on Xft support or none */
|
||||
static int X11_text_width(Display *, X11_Font *, const char *, size_t);
|
||||
static int X11_text_width(Display *, X11_Font *, const char *, size_t,
|
||||
const int *, unsigned);
|
||||
|
||||
/* Data attached to a wrapped widget */
|
||||
typedef struct WidgetData {
|
||||
@@ -41,6 +42,10 @@ typedef struct WidgetData {
|
||||
/* Percentage bar */
|
||||
unsigned percent;
|
||||
Pixel bar_color;
|
||||
|
||||
/* Columns */
|
||||
int *columns;
|
||||
unsigned num_cols;
|
||||
} WidgetData;
|
||||
|
||||
/* Bits for WidgetData::font */
|
||||
@@ -119,6 +124,7 @@ delete_callback(Widget w, XtPointer client_data, XtPointer call_data)
|
||||
XFreePixmap(display, data->pixmap);
|
||||
}
|
||||
free_fonts(w, data);
|
||||
free(data->columns);
|
||||
free(data);
|
||||
}
|
||||
|
||||
@@ -173,6 +179,25 @@ X11_set_percent(Widget w, unsigned percent, Pixel color)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
X11_set_column_widths(Widget w, const int *col_widths, unsigned num_cols)
|
||||
{
|
||||
WidgetData *data = get_widget_data(w);
|
||||
if (data != NULL) {
|
||||
int col_spacing = X11_font_height(data->font[0]) * 2;
|
||||
free(data->columns);
|
||||
data->columns = (int *) alloc(sizeof(data->columns[0]) * num_cols);
|
||||
if (num_cols != 0) {
|
||||
data->columns[0] = 0;
|
||||
for (unsigned i = 1; i < num_cols; ++i) {
|
||||
data->columns[i] = data->columns[i-1] + col_spacing + col_widths[i-1];
|
||||
}
|
||||
}
|
||||
data->num_cols = num_cols;
|
||||
update_label(w, data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the label's pixmap */
|
||||
/* This is called from functions that have altered the data block, and already
|
||||
have a pointer to it */
|
||||
@@ -235,7 +260,8 @@ update_label(Widget w, WidgetData *data)
|
||||
}
|
||||
|
||||
/* Get the width of the line */
|
||||
int lwidth = X11_text_width(display, font, label + i, line2);
|
||||
int lwidth = X11_text_width(display, font, label + i, line2,
|
||||
data->columns, data->num_cols);
|
||||
|
||||
/* Update pixmap dimensions */
|
||||
width = max(lwidth, width);
|
||||
@@ -301,6 +327,7 @@ update_label(Widget w, WidgetData *data)
|
||||
if ((attrs & HL_BLINK) && X11_blink) {
|
||||
values.foreground = values.background;
|
||||
}
|
||||
|
||||
#ifdef USE_XFT
|
||||
Visual *visual = DefaultVisualOfScreen(screen);
|
||||
Colormap cmap = DefaultColormapOfScreen(screen);
|
||||
@@ -357,7 +384,8 @@ update_label(Widget w, WidgetData *data)
|
||||
}
|
||||
|
||||
/* Get the width of the line */
|
||||
int lwidth = X11_text_width(display, font, label + i, line2);
|
||||
int lwidth = X11_text_width(display, font, label + i, line2,
|
||||
data->columns, data->num_cols);
|
||||
|
||||
/* Place the line horizontally */
|
||||
int x = 0;
|
||||
@@ -378,13 +406,38 @@ update_label(Widget w, WidgetData *data)
|
||||
/* Render the line */
|
||||
#ifdef USE_XFT
|
||||
XftDrawRect(draw, &bgcolor, x, y - font->ascent, lwidth, X11_font_height(font));
|
||||
XftDrawString8(draw, &fgcolor, font, x, y,
|
||||
(const FcChar8 *) (label + i), line2);
|
||||
#else
|
||||
XDrawImageString(display, new_pixmap, ggc,
|
||||
x, y,
|
||||
label + i, line2);
|
||||
XSetForeground(display, ggc, values.background);
|
||||
XFillRectangle(display, new_pixmap, ggc, x, y - font->ascent, lwidth, X11_font_height(font));
|
||||
XSetForeground(display, ggc, values.foreground);
|
||||
#endif
|
||||
size_t j = 0;
|
||||
unsigned col = 0;
|
||||
while (j < line2) {
|
||||
size_t line3;
|
||||
int pos;
|
||||
if (data->num_cols == 0) {
|
||||
/* Columns not set */
|
||||
line3 = line2;
|
||||
pos = 0;
|
||||
} else {
|
||||
line3 = min(strcspn(label + i + j, "\t\n"), line2);
|
||||
pos = data->columns[min(col, data->num_cols-1)];
|
||||
}
|
||||
#ifdef USE_XFT
|
||||
XftDrawString8(draw, &fgcolor, font, x + pos, y,
|
||||
(const FcChar8 *) (label + i + j), line3);
|
||||
#else
|
||||
XDrawString(display, new_pixmap, ggc,
|
||||
x + pos, y,
|
||||
label + i + j, line3);
|
||||
#endif
|
||||
j += line3;
|
||||
if (j < line2) {
|
||||
++j;
|
||||
}
|
||||
++col;
|
||||
}
|
||||
|
||||
/* Draw the underline if requested */
|
||||
if (attrs & HL_ULINE) {
|
||||
@@ -488,13 +541,41 @@ free_fonts(Widget w, WidgetData *data)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
X11_text_width(Display *display, X11_Font *font, const char *text, size_t length,
|
||||
const int *columns, unsigned num_cols)
|
||||
{
|
||||
if (num_cols == 0) {
|
||||
/* Columns have not been set */
|
||||
return X11_column_width(display, font, text, length);
|
||||
}
|
||||
|
||||
/* Width is the position of the last column, plus the width of the string
|
||||
in the last column */
|
||||
|
||||
unsigned col = 0;
|
||||
size_t i = 0;
|
||||
while (col < num_cols) {
|
||||
size_t len = strcspn(text + i, "\t\n");
|
||||
if (i+len >= length || text[i+len] != '\t') {
|
||||
break;
|
||||
}
|
||||
++col;
|
||||
i += len + 1;
|
||||
}
|
||||
|
||||
int pos = columns[col] + X11_column_width(display, font, text + i, length - i);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Functions that depend on the font rendering API //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef USE_XFT
|
||||
static int
|
||||
X11_text_width(Display *display, X11_Font *font, const char *text, size_t length)
|
||||
int
|
||||
X11_column_width(Display *display, X11_Font *font, const char *text, size_t length)
|
||||
{
|
||||
XGlyphInfo extents;
|
||||
XftTextExtents8(display, font, (const FcChar8*) text, length, &extents);
|
||||
@@ -507,8 +588,8 @@ X11_font_height(X11_Font *font)
|
||||
return max(font->height, font->ascent + font->descent);
|
||||
}
|
||||
#else /* !USE_XFT */
|
||||
static int
|
||||
X11_text_width(Display *display, X11_Font *font, const char *text, size_t length)
|
||||
int
|
||||
X11_column_width(Display *display, X11_Font *font, const char *text, size_t length)
|
||||
{
|
||||
nhUse(display);
|
||||
return XTextWidth(font, text, length);
|
||||
|
||||
+77
-1
@@ -60,6 +60,7 @@ static unsigned menu_scrollmask(struct xwindow *);
|
||||
static void menu_unscroll(struct xwindow *);
|
||||
static Widget menu_create_buttons(struct xwindow *, Widget, Widget);
|
||||
static void menu_create_entries(struct xwindow *, struct menu *);
|
||||
static unsigned get_col_widths(Widget, X11_Font *, const char *, int **);
|
||||
static void destroy_menu_entry_widgets(struct xwindow *);
|
||||
static void create_menu_translation_tables(void);
|
||||
|
||||
@@ -1317,6 +1318,13 @@ menu_create_entries(struct xwindow *wp, struct menu *curr_menu)
|
||||
Cardinal num_args;
|
||||
Dimension cwidth, maxwidth = 0;
|
||||
|
||||
int *col_widths = NULL;
|
||||
unsigned num_cols = 0;
|
||||
X11_Font *font;
|
||||
#ifdef USE_XFT
|
||||
font = X11_new_font(wp->w, 0, NHW_MENU);
|
||||
#endif
|
||||
|
||||
for (curr = curr_menu->base; curr; curr = curr->next) {
|
||||
char tmpbuf[BUFSZ];
|
||||
Widget linewidget;
|
||||
@@ -1376,13 +1384,42 @@ menu_create_entries(struct xwindow *wp, struct menu *curr_menu)
|
||||
wp->w, args, num_args);
|
||||
X11_wrap_widget(curr->w, NHW_MENU);
|
||||
X11_set_attrs(curr->w, 0x1 << attr);
|
||||
XtManageChild(curr->w);
|
||||
|
||||
if (canpick)
|
||||
XtAddCallback(linewidget, XtNcallback, menu_select,
|
||||
(XtPointer) curr);
|
||||
prevlinewidget = linewidget;
|
||||
|
||||
#ifndef USE_XFT /* If Xft, the font is acquired at the start of the loop */
|
||||
num_args = 0;
|
||||
XtSetArg(args[num_args], XtNfont, &font); num_args++;
|
||||
XtGetValues(curr->w, args, num_args);
|
||||
#endif
|
||||
/* Get column widths for this line */
|
||||
if (strchr(str, '\t') != NULL) { /* Might be a header if no tab */
|
||||
int *col_widths0;
|
||||
unsigned num_cols0 = get_col_widths(curr->w, font, str, &col_widths0);
|
||||
if (num_cols0 > num_cols) {
|
||||
col_widths = (int *) re_alloc((long *) col_widths, num_cols0 * sizeof(col_widths[0]));
|
||||
memset(col_widths + num_cols, 0, sizeof(col_widths[0]) * (num_cols0 - num_cols));
|
||||
num_cols = num_cols0;
|
||||
}
|
||||
for (unsigned i = 0; i < num_cols0; ++i) {
|
||||
col_widths[i] = max(col_widths[i], col_widths0[i]);
|
||||
}
|
||||
free(col_widths0);
|
||||
}
|
||||
}
|
||||
#ifdef USE_XFT
|
||||
X11_release_font(wp->w, font);
|
||||
#endif
|
||||
|
||||
/* Set the column widths */
|
||||
for (curr = curr_menu->base; curr; curr = curr->next) {
|
||||
X11_set_column_widths(curr->w, col_widths, num_cols);
|
||||
XtManageChild(curr->w);
|
||||
|
||||
boolean canpick = (how != PICK_NONE && curr->identifier.a_void);
|
||||
if (canpick) {
|
||||
/* get the current line width */
|
||||
XtSetArg(args[0], XtNwidth, &cwidth);
|
||||
@@ -1392,6 +1429,8 @@ menu_create_entries(struct xwindow *wp, struct menu *curr_menu)
|
||||
}
|
||||
}
|
||||
|
||||
free(col_widths);
|
||||
|
||||
/* set all selectable menu entries to the maximum width */
|
||||
if (how != PICK_NONE) {
|
||||
XtSetArg(args[0], XtNwidth, maxwidth);
|
||||
@@ -1401,6 +1440,43 @@ menu_create_entries(struct xwindow *wp, struct menu *curr_menu)
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine widths of columns */
|
||||
static unsigned
|
||||
get_col_widths(Widget w, X11_Font *font, const char *str, int **col_widths)
|
||||
{
|
||||
/* Determine the number of columns */
|
||||
unsigned num_cols = 1;
|
||||
size_t i = 0;
|
||||
while (str[i] != '\0') {
|
||||
size_t len = strcspn(str + i, "\t");
|
||||
if (str[i+len] == '\0') {
|
||||
break;
|
||||
}
|
||||
++num_cols;
|
||||
i += len + 1;
|
||||
}
|
||||
|
||||
/* Allocate width array */
|
||||
int *cwidths = (int *) alloc(sizeof(cwidths[0]) * num_cols);
|
||||
memset(cwidths, 0, sizeof(cwidths[0]) * num_cols);
|
||||
|
||||
/* Get the widths of the columns */
|
||||
unsigned col = 0;
|
||||
i = 0;
|
||||
while (str[i] != '\0') {
|
||||
size_t len = strcspn(str + i, "\t");
|
||||
cwidths[col++] = X11_column_width(XtDisplay(w), font, str + i, len);
|
||||
i += len;
|
||||
if (str[i] == '\t') {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return */
|
||||
*col_widths = cwidths;
|
||||
return num_cols;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_menu_entry_widgets(struct xwindow *wp)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user