foxygit / doom Log in
commit 56824b130b786aab49876a71c6c768a17c5a4f1c
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Fri Dec 10 20:31:46 2010 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Fri Dec 10 20:31:46 2010 +0000

    Replace txt_widget_t#selectable with a callback function to query
    whether the widget is selectable. This stops the table code from
    selecting things that aren't really selectable - eg. empty tables,
    scrollpanes containing unselectable widgets, etc.
    Fixes a bug with the warp menu (thanks Proteh).

    Subversion-branch: /trunk/chocolate-doom
    Subversion-revision: 2207
---
 setup/txt_joybinput.c          |  1 +
 setup/txt_keyinput.c           |  1 +
 setup/txt_mouseinput.c         |  1 +
 textscreen/examples/guitest.c  | 13 ++++++-----
 textscreen/txt_button.c        |  1 +
 textscreen/txt_checkbox.c      |  1 +
 textscreen/txt_dropdown.c      |  1 +
 textscreen/txt_inputbox.c      |  2 ++
 textscreen/txt_label.c         |  2 +-
 textscreen/txt_radiobutton.c   |  1 +
 textscreen/txt_scrollpane.c    | 20 ++++++++++++++++-
 textscreen/txt_separator.c     |  2 +-
 textscreen/txt_spinctrl.c      |  1 +
 textscreen/txt_strut.c         |  2 +-
 textscreen/txt_table.c         | 51 +++++++++++++++++++++++++++++++++++-------
 textscreen/txt_widget.c        | 27 ++++++++++++++++++++--
 textscreen/txt_widget.h        | 14 +++++++++++-
 textscreen/txt_window_action.c |  1 +
 18 files changed, 122 insertions(+), 20 deletions(-)

diff --git a/setup/txt_joybinput.c b/setup/txt_joybinput.c
index 1e132962..cde3d2c2 100644
--- a/setup/txt_joybinput.c
+++ b/setup/txt_joybinput.c
@@ -206,6 +206,7 @@ static void TXT_JoystickInputMousePress(TXT_UNCAST_ARG(widget), int x, int y, in

 txt_widget_class_t txt_joystick_input_class =
 {
+    TXT_AlwaysSelectable,
     TXT_JoystickInputSizeCalc,
     TXT_JoystickInputDrawer,
     TXT_JoystickInputKeyPress,
diff --git a/setup/txt_keyinput.c b/setup/txt_keyinput.c
index 483c325f..08eb9d8c 100644
--- a/setup/txt_keyinput.c
+++ b/setup/txt_keyinput.c
@@ -171,6 +171,7 @@ static void TXT_KeyInputMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b)

 txt_widget_class_t txt_key_input_class =
 {
+    TXT_AlwaysSelectable,
     TXT_KeyInputSizeCalc,
     TXT_KeyInputDrawer,
     TXT_KeyInputKeyPress,
diff --git a/setup/txt_mouseinput.c b/setup/txt_mouseinput.c
index 8b87e651..4f454c8c 100644
--- a/setup/txt_mouseinput.c
+++ b/setup/txt_mouseinput.c
@@ -164,6 +164,7 @@ static void TXT_MouseInputMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b

 txt_widget_class_t txt_mouse_input_class =
 {
+    TXT_AlwaysSelectable,
     TXT_MouseInputSizeCalc,
     TXT_MouseInputDrawer,
     TXT_MouseInputKeyPress,
diff --git a/textscreen/examples/guitest.c b/textscreen/examples/guitest.c
index 5a931949..df79be2d 100644
--- a/textscreen/examples/guitest.c
+++ b/textscreen/examples/guitest.c
@@ -163,8 +163,8 @@ void Window2(void)
 {
     txt_window_t *window;
     txt_table_t *table;
+    txt_table_t *unselectable_table;
     txt_scrollpane_t *scrollpane;
-    int i;

     window = TXT_NewWindow("Another test");
     TXT_SetWindowPosition(window,
@@ -172,10 +172,13 @@ void Window2(void)
                           TXT_VERT_TOP,
                           TXT_SCREEN_W - 1, 1);

-    for (i=0; i<5; ++i)
-    {
-        TXT_AddWidget(window, TXT_NewButton("hello there blah blah blah blah"));
-    }
+    TXT_AddWidgets(window,
+                   TXT_NewScrollPane(40, 1,
+                        TXT_NewLabel("* Unselectable scroll pane *")),
+                   unselectable_table = TXT_NewTable(1),
+                   NULL);
+
+    TXT_AddWidget(unselectable_table, TXT_NewLabel("* Unselectable table *"));

     TXT_AddWidget(window, TXT_NewSeparator("Input boxes"));
     table = TXT_NewTable(2);
diff --git a/textscreen/txt_button.c b/textscreen/txt_button.c
index a7a2d25a..85517b3d 100644
--- a/textscreen/txt_button.c
+++ b/textscreen/txt_button.c
@@ -96,6 +96,7 @@ static void TXT_ButtonMousePress(TXT_UNCAST_ARG(button), int x, int y, int b)

 txt_widget_class_t txt_button_class =
 {
+    TXT_AlwaysSelectable,
     TXT_ButtonSizeCalc,
     TXT_ButtonDrawer,
     TXT_ButtonKeyPress,
diff --git a/textscreen/txt_checkbox.c b/textscreen/txt_checkbox.c
index 0cb06bad..75afa986 100644
--- a/textscreen/txt_checkbox.c
+++ b/textscreen/txt_checkbox.c
@@ -117,6 +117,7 @@ static void TXT_CheckBoxMousePress(TXT_UNCAST_ARG(checkbox), int x, int y, int b

 txt_widget_class_t txt_checkbox_class =
 {
+    TXT_AlwaysSelectable,
     TXT_CheckBoxSizeCalc,
     TXT_CheckBoxDrawer,
     TXT_CheckBoxKeyPress,
diff --git a/textscreen/txt_dropdown.c b/textscreen/txt_dropdown.c
index efed8d67..c8103302 100644
--- a/textscreen/txt_dropdown.c
+++ b/textscreen/txt_dropdown.c
@@ -262,6 +262,7 @@ static void TXT_DropdownListMousePress(TXT_UNCAST_ARG(list),

 txt_widget_class_t txt_dropdown_list_class =
 {
+    TXT_AlwaysSelectable,
     TXT_DropdownListSizeCalc,
     TXT_DropdownListDrawer,
     TXT_DropdownListKeyPress,
diff --git a/textscreen/txt_inputbox.c b/textscreen/txt_inputbox.c
index 3e52bae9..852346f3 100644
--- a/textscreen/txt_inputbox.c
+++ b/textscreen/txt_inputbox.c
@@ -232,6 +232,7 @@ static void TXT_InputBoxMousePress(TXT_UNCAST_ARG(inputbox),

 txt_widget_class_t txt_inputbox_class =
 {
+    TXT_AlwaysSelectable,
     TXT_InputBoxSizeCalc,
     TXT_InputBoxDrawer,
     TXT_InputBoxKeyPress,
@@ -242,6 +243,7 @@ txt_widget_class_t txt_inputbox_class =

 txt_widget_class_t txt_int_inputbox_class =
 {
+    TXT_AlwaysSelectable,
     TXT_InputBoxSizeCalc,
     TXT_InputBoxDrawer,
     TXT_IntInputBoxKeyPress,
diff --git a/textscreen/txt_label.c b/textscreen/txt_label.c
index 7ae29c3d..0deea803 100644
--- a/textscreen/txt_label.c
+++ b/textscreen/txt_label.c
@@ -104,6 +104,7 @@ static void TXT_LabelDestructor(TXT_UNCAST_ARG(label))

 txt_widget_class_t txt_label_class =
 {
+    TXT_NeverSelectable,
     TXT_LabelSizeCalc,
     TXT_LabelDrawer,
     NULL,
@@ -170,7 +171,6 @@ txt_label_t *TXT_NewLabel(char *text)
     label = malloc(sizeof(txt_label_t));

     TXT_InitWidget(label, &txt_label_class);
-    label->widget.selectable = 0;
     label->label = NULL;
     label->lines = NULL;

diff --git a/textscreen/txt_radiobutton.c b/textscreen/txt_radiobutton.c
index 7ede7211..efebbf9e 100644
--- a/textscreen/txt_radiobutton.c
+++ b/textscreen/txt_radiobutton.c
@@ -121,6 +121,7 @@ static void TXT_RadioButtonMousePress(TXT_UNCAST_ARG(radiobutton),

 txt_widget_class_t txt_radiobutton_class =
 {
+    TXT_AlwaysSelectable,
     TXT_RadioButtonSizeCalc,
     TXT_RadioButtonDrawer,
     TXT_RadioButtonKeyPress,
diff --git a/textscreen/txt_scrollpane.c b/textscreen/txt_scrollpane.c
index d81cce4b..17c9bcbf 100644
--- a/textscreen/txt_scrollpane.c
+++ b/textscreen/txt_scrollpane.c
@@ -138,7 +138,7 @@ static void TXT_ScrollPaneSizeCalc(TXT_UNCAST_ARG(scrollpane))
     }
     if (scrollpane->expand_h)
     {
-        scrollpane->h = FullWidth(scrollpane);
+        scrollpane->h = FullHeight(scrollpane);
     }

     scrollpane->widget.w = scrollpane->w;
@@ -486,8 +486,26 @@ static void TXT_ScrollPaneLayout(TXT_UNCAST_ARG(scrollpane))
     }
 }

+static int TXT_ScrollPaneSelectable(TXT_UNCAST_ARG(scrollpane))
+{
+    TXT_CAST_ARG(txt_scrollpane_t, scrollpane);
+
+    // If scroll bars are displayed, the scroll pane must be selectable
+    // so that we can use the arrow keys to scroll around.
+
+    if (NeedsScrollbars(scrollpane))
+    {
+        return 1;
+    }
+
+    // Otherwise, whether this is selectable depends on the child widget.
+
+    return TXT_SelectableWidget(scrollpane->child);
+}
+
 txt_widget_class_t txt_scrollpane_class =
 {
+    TXT_ScrollPaneSelectable,
     TXT_ScrollPaneSizeCalc,
     TXT_ScrollPaneDrawer,
     TXT_ScrollPaneKeyPress,
diff --git a/textscreen/txt_separator.c b/textscreen/txt_separator.c
index 2bf74b8f..6b779626 100644
--- a/textscreen/txt_separator.c
+++ b/textscreen/txt_separator.c
@@ -82,6 +82,7 @@ static void TXT_SeparatorDestructor(TXT_UNCAST_ARG(separator))

 txt_widget_class_t txt_separator_class =
 {
+    TXT_NeverSelectable,
     TXT_SeparatorSizeCalc,
     TXT_SeparatorDrawer,
     NULL,
@@ -97,7 +98,6 @@ txt_separator_t *TXT_NewSeparator(char *label)
     separator = malloc(sizeof(txt_separator_t));

     TXT_InitWidget(separator, &txt_separator_class);
-    separator->widget.selectable = 0;

     if (label != NULL)
     {
diff --git a/textscreen/txt_spinctrl.c b/textscreen/txt_spinctrl.c
index 2b99f535..d775aecf 100644
--- a/textscreen/txt_spinctrl.c
+++ b/textscreen/txt_spinctrl.c
@@ -358,6 +358,7 @@ static void TXT_SpinControlMousePress(TXT_UNCAST_ARG(spincontrol),

 txt_widget_class_t txt_spincontrol_class =
 {
+    TXT_AlwaysSelectable,
     TXT_SpinControlSizeCalc,
     TXT_SpinControlDrawer,
     TXT_SpinControlKeyPress,
diff --git a/textscreen/txt_strut.c b/textscreen/txt_strut.c
index e7fe6328..f3a618f3 100644
--- a/textscreen/txt_strut.c
+++ b/textscreen/txt_strut.c
@@ -55,6 +55,7 @@ static int TXT_StrutKeyPress(TXT_UNCAST_ARG(strut), int key)

 txt_widget_class_t txt_strut_class =
 {
+    TXT_NeverSelectable,
     TXT_StrutSizeCalc,
     TXT_StrutDrawer,
     TXT_StrutKeyPress,
@@ -70,7 +71,6 @@ txt_strut_t *TXT_NewStrut(int width, int height)
     strut = malloc(sizeof(txt_strut_t));

     TXT_InitWidget(strut, &txt_strut_class);
-    strut->widget.selectable = 0;
     strut->width = width;
     strut->height = height;

diff --git a/textscreen/txt_table.c b/textscreen/txt_table.c
index 1b432681..ffe6fd14 100644
--- a/textscreen/txt_table.c
+++ b/textscreen/txt_table.c
@@ -202,7 +202,7 @@ void TXT_AddWidgets(TXT_UNCAST_ARG(table), ...)
     va_end(args);
 }

-static int SelectableWidget(txt_table_t *table, int x, int y)
+static int SelectableCell(txt_table_t *table, int x, int y)
 {
     txt_widget_t *widget;
     int i;
@@ -217,7 +217,9 @@ static int SelectableWidget(txt_table_t *table, int x, int y)
     if (i >= 0 && i < table->num_widgets)
     {
         widget = table->widgets[i];
-        return widget != NULL && widget->selectable && widget->visible;
+        return widget != NULL
+            && TXT_SelectableWidget(widget)
+            && widget->visible;
     }

     return 0;
@@ -237,14 +239,14 @@ static int FindSelectableColumn(txt_table_t *table, int row, int start_col)
     {
         // Search to the right

-        if (SelectableWidget(table, start_col + x, row))
+        if (SelectableCell(table, start_col + x, row))
         {
             return start_col + x;
         }

         // Search to the left

-        if (SelectableWidget(table, start_col - x, row))
+        if (SelectableCell(table, start_col - x, row))
         {
             return start_col - x;
         }
@@ -270,7 +272,7 @@ static int TXT_TableKeyPress(TXT_UNCAST_ARG(table), int key)
     if (selected >= 0 && selected < table->num_widgets)
     {
         if (table->widgets[selected] != NULL
-         && table->widgets[selected]->selectable
+         && TXT_SelectableWidget(table->widgets[selected])
          && TXT_WidgetKeyPress(table->widgets[selected], key))
         {
             return 1;
@@ -329,7 +331,7 @@ static int TXT_TableKeyPress(TXT_UNCAST_ARG(table), int key)

         for (new_x = table->selected_x - 1; new_x >= 0; --new_x)
         {
-            if (SelectableWidget(table, new_x, table->selected_y))
+            if (SelectableCell(table, new_x, table->selected_y))
             {
                 // Found a selectable widget!

@@ -348,7 +350,7 @@ static int TXT_TableKeyPress(TXT_UNCAST_ARG(table), int key)

         for (new_x = table->selected_x + 1; new_x < table->columns; ++new_x)
         {
-            if (SelectableWidget(table, new_x, table->selected_y))
+            if (SelectableCell(table, new_x, table->selected_y))
             {
                 // Found a selectable widget!

@@ -547,7 +549,7 @@ static void TXT_TableMousePress(TXT_UNCAST_ARG(table), int x, int y, int b)

                 // Select the cell if the widget is selectable

-                if (widget->selectable)
+                if (TXT_SelectableWidget(widget))
                 {
                     table->selected_x = i % table->columns;
                     table->selected_y = i / table->columns;
@@ -563,8 +565,41 @@ static void TXT_TableMousePress(TXT_UNCAST_ARG(table), int x, int y, int b)
     }
 }

+// Determine whether the table is selectable.
+
+static int TXT_TableSelectable(TXT_UNCAST_ARG(table))
+{
+    TXT_CAST_ARG(txt_table_t, table);
+    int i;
+
+    // Is the currently-selected cell selectable?
+
+    if (SelectableCell(table, table->selected_x, table->selected_y))
+    {
+        return 1;
+    }
+
+    // Find the first selectable cell and set selected_x, selected_y.
+
+    for (i = 0; i < table->num_widgets; ++i)
+    {
+        if (table->widgets[i] != NULL
+         && TXT_SelectableWidget(table->widgets[i]))
+        {
+            table->selected_x = i % table->columns;
+            table->selected_y = i / table->columns;
+            return 1;
+        }
+    }
+
+    // No selectable widgets exist within the table.
+
+    return 0;
+}
+
 txt_widget_class_t txt_table_class =
 {
+    TXT_TableSelectable,
     TXT_CalcTableSize,
     TXT_TableDrawer,
     TXT_TableKeyPress,
diff --git a/textscreen/txt_widget.c b/textscreen/txt_widget.c
index 2300b32c..760943d5 100644
--- a/textscreen/txt_widget.c
+++ b/textscreen/txt_widget.c
@@ -83,9 +83,8 @@ void TXT_InitWidget(TXT_UNCAST_ARG(widget), txt_widget_class_t *widget_class)
     widget->widget_class = widget_class;
     widget->callback_table = TXT_NewCallbackTable();

-    // Default values: visible and selectable
+    // Visible by default.

-    widget->selectable = 1;
     widget->visible = 1;

     // Align left by default
@@ -214,3 +213,27 @@ void TXT_LayoutWidget(TXT_UNCAST_ARG(widget))
     }
 }

+int TXT_AlwaysSelectable(TXT_UNCAST_ARG(widget))
+{
+    return 1;
+}
+
+int TXT_NeverSelectable(TXT_UNCAST_ARG(widget))
+{
+    return 0;
+}
+
+int TXT_SelectableWidget(TXT_UNCAST_ARG(widget))
+{
+    TXT_CAST_ARG(txt_widget_t, widget);
+
+    if (widget->widget_class->selectable != NULL)
+    {
+        return widget->widget_class->selectable(widget);
+    }
+    else
+    {
+        return 0;
+    }
+}
+
diff --git a/textscreen/txt_widget.h b/textscreen/txt_widget.h
index 9688829d..bb895f92 100644
--- a/textscreen/txt_widget.h
+++ b/textscreen/txt_widget.h
@@ -77,9 +77,11 @@ typedef int (*TxtWidgetKeyPress)(TXT_UNCAST_ARG(widget), int key);
 typedef void (*TxtWidgetSignalFunc)(TXT_UNCAST_ARG(widget), void *user_data);
 typedef void (*TxtMousePressFunc)(TXT_UNCAST_ARG(widget), int x, int y, int b);
 typedef void (*TxtWidgetLayoutFunc)(TXT_UNCAST_ARG(widget));
+typedef int (*TxtWidgetSelectableFunc)(TXT_UNCAST_ARG(widget));

 struct txt_widget_class_s
 {
+    TxtWidgetSelectableFunc selectable;
     TxtWidgetSizeCalc size_calc;
     TxtWidgetDrawer drawer;
     TxtWidgetKeyPress key_press;
@@ -92,7 +94,6 @@ struct txt_widget_s
 {
     txt_widget_class_t *widget_class;
     txt_callback_table_t *callback_table;
-    int selectable;
     int visible;
     txt_horiz_align_t align;

@@ -111,6 +112,8 @@ int TXT_WidgetKeyPress(TXT_UNCAST_ARG(widget), int key);
 void TXT_WidgetMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b);
 void TXT_DestroyWidget(TXT_UNCAST_ARG(widget));
 void TXT_LayoutWidget(TXT_UNCAST_ARG(widget));
+int TXT_AlwaysSelectable(TXT_UNCAST_ARG(widget));
+int TXT_NeverSelectable(TXT_UNCAST_ARG(widget));

 /**
  * Set a callback function to be invoked when a signal occurs.
@@ -134,6 +137,15 @@ void TXT_SignalConnect(TXT_UNCAST_ARG(widget), const char *signal_name,

 void TXT_SetWidgetAlign(TXT_UNCAST_ARG(widget), txt_horiz_align_t horiz_align);

+/**
+ * Query whether a widget is selectable with the cursor.
+ *
+ * @param widget       The widget.
+ * @return             Non-zero if the widget is selectable.
+ */
+
+int TXT_SelectableWidget(TXT_UNCAST_ARG(widget));
+
 #endif /* #ifndef TXT_WIDGET_H */


diff --git a/textscreen/txt_window_action.c b/textscreen/txt_window_action.c
index a326a5ed..e593b7b6 100644
--- a/textscreen/txt_window_action.c
+++ b/textscreen/txt_window_action.c
@@ -93,6 +93,7 @@ static void TXT_WindowActionMousePress(TXT_UNCAST_ARG(action),

 txt_widget_class_t txt_window_action_class =
 {
+    TXT_AlwaysSelectable,
     TXT_WindowActionSizeCalc,
     TXT_WindowActionDrawer,
     TXT_WindowActionKeyPress,