foxygit / doom Log in
commit c754eaf364e411a6903948069727be8c157e538c
Author:     Simon Howard <fraggle@soulsphere.org>
AuthorDate: Fri Jul 10 01:18:23 2015 -0400
Commit:     Simon Howard <fraggle@soulsphere.org>
CommitDate: Fri Jul 10 01:18:23 2015 -0400

    textscreen: Add TXT_SetTableColumns() function.

    It's common to want to divide a window into columns, but this has
    until now only been possible by adding an inner table with multiple
    columns. To simplify laying out windows, this function allows the
    number of columns in a window (or any table) to be changed after it
    is allocated.
---
 textscreen/txt_table.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++
 textscreen/txt_table.h | 16 ++++++++++++++
 2 files changed, 76 insertions(+)

diff --git a/textscreen/txt_table.c b/textscreen/txt_table.c
index b99ecd75..96a19278 100644
--- a/textscreen/txt_table.c
+++ b/textscreen/txt_table.c
@@ -999,6 +999,66 @@ int TXT_SelectWidget(TXT_UNCAST_ARG(table), TXT_UNCAST_ARG(widget))
     return 0;
 }

+void TXT_SetTableColumns(TXT_UNCAST_ARG(table), int new_columns)
+{
+    TXT_CAST_ARG(txt_table_t, table);
+    txt_widget_t **new_widgets;
+    txt_widget_t *widget;
+    int new_num_widgets;
+    int i, j, x;
+
+    // We need as many full rows as are in the current list, plus the
+    // remainder from the last row.
+    new_num_widgets = (table->num_widgets / table->columns) * new_columns
+                    + (table->num_widgets % table->columns);
+    new_widgets = calloc(new_num_widgets, sizeof(txt_widget_t *));
+
+    // Reset and add one by one from the old table.
+    new_num_widgets = 0;
+
+    for (i = 0; i < table->num_widgets; ++i)
+    {
+        widget = table->widgets[i];
+        x = i % table->columns;
+
+        if (x < new_columns)
+        {
+            new_widgets[new_num_widgets] = widget;
+            ++new_num_widgets;
+        }
+        else if (IsActualWidget(widget))
+        {
+            TXT_DestroyWidget(widget);
+        }
+
+        // When we reach the last column of a row, we must pad it out with
+        // extra widgets to reach the next row.
+        if (x == table->columns - 1)
+        {
+            for (j = table->columns; j < new_columns; ++j)
+            {
+                // First row? We need to add struts that are used to apply
+                // the column widths.
+                if (i < table->columns)
+                {
+                    widget = &TXT_NewStrut(0, 0)->widget;
+                }
+                else
+                {
+                    widget = &txt_table_overflow_right;
+                }
+                new_widgets[new_num_widgets] = widget;
+                ++new_num_widgets;
+            }
+        }
+    }
+
+    free(table->widgets);
+    table->widgets = new_widgets;
+    table->num_widgets = new_num_widgets;
+    table->columns = new_columns;
+}
+
 // Sets the widths of columns in a table.

 void TXT_SetColumnWidths(TXT_UNCAST_ARG(table), ...)
diff --git a/textscreen/txt_table.h b/textscreen/txt_table.h
index 94e8556d..98eb30fa 100644
--- a/textscreen/txt_table.h
+++ b/textscreen/txt_table.h
@@ -172,6 +172,22 @@ void TXT_AddWidgets(TXT_UNCAST_ARG(table), ...);

 int TXT_SelectWidget(TXT_UNCAST_ARG(table), TXT_UNCAST_ARG(widget));

+/**
+ * Change the number of columns in the table.
+ *
+ * Existing widgets in the table will be preserved, unless the change
+ * reduces the number of columns, in which case the widgets from the
+ * 'deleted' columns will be freed.
+ *
+ * This function can be useful for changing the number of columns in
+ * a window, which by default are tables containing a single column.
+ *
+ * @param table         The table.
+ * @param new_columns   The new number of columns.
+ */
+
+void TXT_SetTableColumns(TXT_UNCAST_ARG(table), int new_columns);
+
 /**
  * Set the widths of the columns of the table.
  *