From 2f42bd7e2752730b9580da7dc441943b8561742a Mon Sep 17 00:00:00 2001 From: Ray Chason Date: Sun, 30 Aug 2026 19:03:45 -0400 Subject: [PATCH] Display tabs in the text window Actually a menu, but menu windows convert to text if only displaying text. --- win/X11/winlabel.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ win/X11/wintext.c | 4 +-- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/win/X11/winlabel.c b/win/X11/winlabel.c index f8e99510c..5842ef49f 100644 --- a/win/X11/winlabel.c +++ b/win/X11/winlabel.c @@ -54,6 +54,7 @@ enum { font_bold = 1, font_italic = 2 }; static boolean check_label(Widget); static void delete_callback(Widget, XtPointer, XtPointer); static void update_label(Widget, WidgetData *); +static void set_tab_stops(Widget, WidgetData *, const char *); static void allocate_font(Widget, WidgetData *, unsigned); static void free_fonts(Widget, WidgetData *); @@ -242,6 +243,11 @@ update_label(Widget w, WidgetData *data) attrs |= HL_DIM; } + /* Set the tab stops if needed */ + if (data->columns == NULL && strchr(label, '\t') != NULL) { + set_tab_stops(w, data, label); + } + /* Dimensions of pixmap */ Dimension width; Dimension height; @@ -496,6 +502,66 @@ update_label(Widget w, WidgetData *data) data->pixmap = new_pixmap; } +/* Set tab stops for text window */ +static void +set_tab_stops(Widget w, WidgetData *data, const char *label) +{ + /* Count columns */ + unsigned col = 0; + unsigned num_cols = 0; + size_t i = 0; + while (label[i] != '\0') { + size_t len = strcspn(label + i, "\t\n"); + ++col; + i += len; + if (label[i] != '\t') { + /* The last column on its line */ + num_cols = max(num_cols, col); + col = 0; + } + if (label[i] != '\0') { + ++i; + } + } + + int *columns = (int *) alloc(num_cols * sizeof(columns[0])); + memset(columns, 0, num_cols * sizeof(columns[0])); + + /* Determine column sizes */ + col = 0; + i = 0; + Display *display = XtDisplay(w); + while (label[i] != '\0') { + size_t len = strcspn(label + i, "\t\n"); + if (label[i+len] == '\t') { + /* A column from label+i to label+i+len */ + int width = X11_column_width(display, data->font[0], label + i, len); + columns[col] = max(columns[col], width); + ++col; + } else { + /* Last column of the line */ + /* This does not participate in sizing the column */ + col = 0; + } + i += len; + if (label[i] != '\0') { + ++i; + } + } + + /* Convert to column positions */ + int pos = 0; + for (unsigned j = 0; j < num_cols; ++j) { + int rpos = pos + columns[j]; + columns[j] = pos; + pos = rpos; + } + + free(data->columns); + data->columns = columns; + data->num_cols = num_cols; +} + /* Allocate a bold or italic font */ static void allocate_font(Widget w, WidgetData *data, unsigned font_idx) diff --git a/win/X11/wintext.c b/win/X11/wintext.c index ee6247029..a80b6540d 100644 --- a/win/X11/wintext.c +++ b/win/X11/wintext.c @@ -170,7 +170,7 @@ display_text_window(struct xwindow *wp, boolean blocking) XtSetArg(args[num_args], XtNlabel, text_info->text.text); num_args++; XtSetValues(wp->w, args, num_args); - X11_update_label_if_Xft(wp->w); + X11_update_label(wp->w); #ifdef TRANSIENT_TEXT XtRealizeWidget(wp->popup); @@ -259,7 +259,7 @@ create_text_window(struct xwindow *wp) form, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ - X11_wrap_widget_if_Xft(wp->w, NHW_TEXT); + X11_wrap_widget(wp->w, NHW_TEXT); } void