ref: ec81c27ef5af20761afb2295cdd7c92b213a5807
parent: 1715116ef17946f1c77fb2da220384e7889f1329
author: Simon Howard <[email protected]>
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 */