shithub: choc

Download patch

ref: ec81c27ef5af20761afb2295cdd7c92b213a5807
parent: 1715116ef17946f1c77fb2da220384e7889f1329
author: Simon Howard <fraggle@gmail.com>
date: Thu Aug 27 19:27:47 EDT 2009

Allow PGUP/PGDN to scroll up and down in scroll panes (thanks
LionsPhil).

Subversion-branch: /trunk/chocolate-doom
Subversion-revision: 1631

--- a/textscreen/txt_scrollpane.c
+++ b/textscreen/txt_scrollpane.c
@@ -254,10 +254,53 @@
     }
 }
 
+// Another hack for tables - when scrolling in 'pages', the normal key press
+// event does not provide children with enough information to know how far
+// to move their selection to reach a new page. This function does so.
+// Note that it *only* affects scrolling in pages, not with arrows!
+// A side-effect of this, rather than 'pulling' the selection to fit within
+// the new page, is that we will jump straight over ranges of unselectable
+// items longer than a page, but that is also true of arrow-key scrolling.
+// The other unfortunate effect of doing things this way is that page keys
+// have no effect on tables _not_ in scrollpanes: not even home/end.
+
+static int PageSelectedWidget(txt_scrollpane_t *scrollpane, int key)
+{
+    int pagex = 0; // No page left/right yet, but some keyboards have them
+    int pagey = 0;
+
+    // Subtract one from the absolute page distance as this is slightly more
+    // intuitive: a page down first jumps to the bottom of the current page,
+    // then proceeds to scroll onwards.
+
+    switch (key)
+    {
+        case KEY_PGUP:
+            pagey = 1 - scrollpane->h;
+            break;
+
+        case KEY_PGDN:
+            pagey = scrollpane->h - 1;
+            break;
+
+        default: // We shouldn't even be in this function
+            return 0;
+    }
+
+    if (scrollpane->child->widget_class == &txt_table_class)
+    {
+        return TXT_PageTable(scrollpane->child, pagex, pagey);
+    }
+
+    return 0;
+}
+
 // Interpret arrow key presses as scroll commands
 
 static int InterpretScrollKey(txt_scrollpane_t *scrollpane, int key)
 {
+    int maxy;
+
     switch (key)
     {
         case KEY_UPARROW:
@@ -292,6 +335,31 @@
             }
             break;
 
+        case KEY_PGUP:
+            if (scrollpane->y > 0)
+            {
+                scrollpane->y -= scrollpane->h;
+                if (scrollpane->y < 0)
+                {
+                    scrollpane->y = 0;
+                }
+                return 1;
+            }
+            break;
+
+        case KEY_PGDN:
+            maxy = FullHeight(scrollpane) - scrollpane->h;
+            if (scrollpane->y < maxy)
+            {
+                scrollpane->y += scrollpane->h;
+                if (scrollpane->y > maxy)
+                {
+                    scrollpane->y = maxy;
+                }
+                return 1;
+            }
+            break;
+
         default:
             break;
     }
@@ -316,8 +384,14 @@
 
         if (scrollpane->child->widget_class == &txt_table_class
          && (key == KEY_UPARROW || key == KEY_DOWNARROW
-          || key == KEY_LEFTARROW || key == KEY_RIGHTARROW))
+          || key == KEY_LEFTARROW || key == KEY_RIGHTARROW
+          || key == KEY_PGUP || key == KEY_PGDN))
         {
+            if (PageSelectedWidget(scrollpane, key))
+            {
+                result = 1;
+            }
+
             ShowSelectedWidget(scrollpane);
         }
 
--- a/textscreen/txt_table.c
+++ b/textscreen/txt_table.c
@@ -770,3 +770,85 @@
     va_end(args);
 }
 
+// Moves the select by at least the given number of characters.
+// Currently quietly ignores pagex, as we don't use it.
+
+int TXT_PageTable(TXT_UNCAST_ARG(table), int pagex, int pagey)
+{
+    TXT_CAST_ARG(txt_table_t, table);
+    unsigned int *column_widths;
+    unsigned int *row_heights;
+    int rows;
+    int changed = 0;
+
+    rows = TableRows(table);
+
+    row_heights = malloc(sizeof(int) * rows);
+    column_widths = malloc(sizeof(int) * table->columns);
+
+    CalcRowColSizes(table, row_heights, column_widths);
+
+    if (pagex)
+    {
+        // @todo Jump selection to the left or right as needed
+    }
+
+    if (pagey)
+    {
+        int new_x, new_y;
+        int distance = 0;
+        int dir;
+
+        // What direction are we moving?
+
+        if (pagey > 0)
+        {
+            dir = 1;
+        }
+        else
+        {
+            dir = -1;
+        }
+
+        // Move the cursor until the desired distance is reached.
+
+        new_y = table->selected_y;
+
+        while (new_y >= 0 && new_y < rows)
+        {
+            // We are about to travel a distance equal to the height of the row
+            // we are about to leave.
+
+            distance += row_heights[new_y];
+
+            // *Now* increment the loop.
+
+            new_y += dir;
+
+            new_x = FindSelectableColumn(table, new_y, table->selected_x);
+
+            if (new_x >= 0)
+            {
+                // Found a selectable widget in this column!
+                // Select it anyway in case we don't find something better.
+
+                table->selected_x = new_x;
+                table->selected_y = new_y;
+                changed = 1;
+
+                // ...but is it far enough away?
+
+                if (distance >= abs(pagey))
+                {
+                    break;
+                }
+            }
+        }
+    }
+
+    free(row_heights);
+    free(column_widths);
+
+    return changed;
+}
+
--- a/textscreen/txt_table.h
+++ b/textscreen/txt_table.h
@@ -178,6 +178,19 @@
 
 void TXT_ClearTable(TXT_UNCAST_ARG(table));
 
+/**
+ * Hack to move the selection in a table by a 'page', triggered by the
+ * scrollpane. This acts as per the keyboard events for the arrows, but moves
+ * the selection by at least the specified number of characters.
+ *
+ * @param table    The table.
+ * @param pagex    Minimum distance to move the selection horizontally.
+ * @param pagey    Minimum distance to move the selection vertically.
+ * @return         Non-zero if the selection has been changed.
+ */
+
+int TXT_PageTable(TXT_UNCAST_ARG(table), int pagex, int pagey);
+
 #endif /* #ifndef TXT_TABLE_T */