shithub: choc

Download patch

ref: 39b7cb7bb2e14169af5dc07c7d429fc939200639
parent: a6be65e608b72b3e08ea66278e3972864c085495
author: Simon Howard <fraggle@gmail.com>
date: Fri Jan 30 18:53:47 EST 2009

Fix layout of widgets within scroll panes. Scroll scroll panes in
response to keyboard events.

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

--- a/textscreen/examples/guitest.c
+++ b/textscreen/examples/guitest.c
@@ -82,6 +82,7 @@
     TXT_AddWidget(window, toplabel);
     TXT_SetWidgetAlign(toplabel, TXT_HORIZ_CENTER);
 
+    //TXT_AddWidget(window, TXT_NewScrollPane(15, 4, table));
     TXT_AddWidget(window, table);
 
     for (i=0; i<5; ++i)
@@ -174,6 +175,35 @@
     TXT_AddWidget(window, scrollpane);
 }
 
+void ScrollingMenu(void)
+{
+    txt_window_t *window;
+    txt_button_t *button;
+    txt_table_t *table;
+
+    window = TXT_NewWindow("Scrollable menu");
+
+    table = TXT_NewTable(1);
+
+    TXT_AddWidgets(table,
+                   TXT_NewButton("Configure display"),
+                   TXT_NewButton("Configure joystick"),
+                   TXT_NewButton("Configure keyboard"),
+                   TXT_NewButton("Configure mouse"),
+                   TXT_NewButton("Configure sound"),
+                   TXT_NewStrut(0, 1),
+                   button = TXT_NewButton("Save Parameters and launch DOOM"),
+                   TXT_NewStrut(0, 1),
+                   TXT_NewButton("Start a network game"),
+                   TXT_NewButton("Join a network game"),
+                   TXT_NewButton("Multiplayer configuration"),
+                   NULL);
+
+    TXT_SignalConnect(button, "pressed", PwnBox, NULL);
+
+    TXT_AddWidget(window, TXT_NewScrollPane(0, 6, table));
+}
+
 int main(int argc, char *argv[])
 {
     if (!TXT_Init())
@@ -184,6 +214,7 @@
 
     TXT_SetDesktopTitle("Not Chocolate Doom Setup");
 
+    ScrollingMenu();
     Window2();
     SetupWindow();
 
--- a/textscreen/txt_scrollpane.c
+++ b/textscreen/txt_scrollpane.c
@@ -29,7 +29,10 @@
 #include "txt_gui.h"
 #include "txt_io.h"
 #include "txt_main.h"
+#include "txt_table.h"
 
+#include "doomkeys.h"
+
 #define SCROLLBAR_VERTICAL   (1 << 0)
 #define SCROLLBAR_HORIZONTAL (1 << 1)
 
@@ -214,18 +217,120 @@
     }
 }
 
+// Hack for tables - when browsing a table inside a scroll pane,
+// automatically scroll the window to show the newly-selected
+// item.
+
+static void ShowSelectedWidget(txt_scrollpane_t *scrollpane)
+{
+    txt_widget_t *selected;
+
+    selected = TXT_GetSelectedWidget(scrollpane->child);
+
+    // Scroll up or down?
+
+    if (selected->y <= scrollpane->widget.y)
+    {
+        scrollpane->y -= scrollpane->widget.y - selected->y;
+    }
+    else if (selected->y + selected->h >
+             scrollpane->widget.y + scrollpane->h)
+    {
+        scrollpane->y += (selected->y + selected->h)
+                       - (scrollpane->widget.y + scrollpane->h);
+    }
+
+    // Scroll left or right?
+
+    if (selected->x <= scrollpane->widget.x)
+    {
+        scrollpane->x -= scrollpane->widget.x - selected->x;
+    }
+    else if (selected->x + selected->w >
+             scrollpane->widget.x + scrollpane->w)
+    {
+        scrollpane->x += (selected->x + selected->w)
+                       - (scrollpane->widget.x + scrollpane->w);
+    }
+}
+
+// Interpret arrow key presses as scroll commands
+
+static int InterpretScrollKey(txt_scrollpane_t *scrollpane, int key)
+{
+    switch (key)
+    {
+        case KEY_UPARROW:
+            if (scrollpane->y > 0)
+            {
+                --scrollpane->y;
+                return 1;
+            }
+            break;
+
+        case KEY_DOWNARROW:
+            if (scrollpane->y < FullHeight(scrollpane) - scrollpane->h)
+            {
+                ++scrollpane->y;
+                return 1;
+            }
+            break;
+
+        case KEY_LEFTARROW:
+            if (scrollpane->x > 0)
+            {
+                --scrollpane->x;
+                return 1;
+            }
+            break;
+
+        case KEY_RIGHTARROW:
+            if (scrollpane->x < FullWidth(scrollpane) - scrollpane->w)
+            {
+                ++scrollpane->x;
+                return 1;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    return 0;
+}
+
 static int TXT_ScrollPaneKeyPress(TXT_UNCAST_ARG(scrollpane), int key)
 {
     TXT_CAST_ARG(txt_scrollpane_t, scrollpane);
+    int result;
 
+    result = 0;
+
     if (scrollpane->child != NULL)
     {
-        return TXT_WidgetKeyPress(scrollpane->child, key);
+        result = TXT_WidgetKeyPress(scrollpane->child, key);
+
+        // Gross hack - if we're scrolling in a menu with the keyboard,
+        // automatically move the scroll pane to show the new
+        // selected item.
+
+        if (scrollpane->child->widget_class == &txt_table_class
+         && (key == KEY_UPARROW || key == KEY_DOWNARROW
+          || key == KEY_LEFTARROW || key == KEY_RIGHTARROW))
+        {
+            ShowSelectedWidget(scrollpane);
+        }
+
+        // If the child widget didn't use the keypress, we can see 
+        // if it can be interpreted as a scrolling command.
+
+        if (result == 0)
+        {
+            result = InterpretScrollKey(scrollpane, key);
+        }
     }
-    else
-    {
-        return 0;
-    }
+
+    return result;
 }
 
 static void TXT_ScrollPaneMousePress(TXT_UNCAST_ARG(scrollpane),
@@ -284,10 +389,7 @@
 
     if (scrollpane->child != NULL)
     {
-        TXT_WidgetMousePress(scrollpane->child,
-                             x - scrollpane->x,
-                             y - scrollpane->y,
-                             b);
+        TXT_WidgetMousePress(scrollpane->child, x, y, b);
     }
 
 }
@@ -305,6 +407,8 @@
     {
         scrollpane->child->x = scrollpane->widget.x - scrollpane->x;
         scrollpane->child->y = scrollpane->widget.y - scrollpane->y;
+
+        TXT_LayoutWidget(scrollpane->child);
     }
 }
 
--- a/textscreen/txt_table.c
+++ b/textscreen/txt_table.c
@@ -674,6 +674,32 @@
     return result;
 }
 
+// Get the currently-selected widget in a table, recursively searching
+// through sub-tables if necessary.
+
+txt_widget_t *TXT_GetSelectedWidget(TXT_UNCAST_ARG(table))
+{
+    TXT_CAST_ARG(txt_table_t, table);
+    txt_widget_t *result;
+    int index;
+
+    index = table->selected_y * table->columns + table->selected_x;
+
+    result = NULL;
+
+    if (index >= 0 && index < table->num_widgets)
+    {
+        result = table->widgets[index];
+    }
+
+    if (result != NULL && result->widget_class == &txt_table_class)
+    {
+        result = TXT_GetSelectedWidget(result);
+    }
+
+    return result;
+}
+
 // Selects a given widget in a table, recursively searching any tables
 // within this table.  Returns 1 if successful, 0 if unsuccessful.
 
--- a/textscreen/txt_table.h
+++ b/textscreen/txt_table.h
@@ -46,9 +46,12 @@
     int selected_y;
 };
 
+extern txt_widget_class_t txt_table_class;
+
 txt_table_t *TXT_NewTable(int columns);
 txt_table_t *TXT_NewHorizBox(TXT_UNCAST_ARG(first_widget), ...);
 void TXT_InitTable(txt_table_t *table, int columns);
+txt_widget_t *TXT_GetSelectedWidget(TXT_UNCAST_ARG(table));
 void TXT_AddWidget(TXT_UNCAST_ARG(table), TXT_UNCAST_ARG(widget));
 void TXT_AddWidgets(TXT_UNCAST_ARG(table), ...);
 int TXT_SelectWidget(TXT_UNCAST_ARG(table), TXT_UNCAST_ARG(widget));