foxygit / doom Log in
commit 283f71d0f500541b6273316120e252b03f22fb03
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Mon May 22 00:20:48 2006 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Mon May 22 00:20:48 2006 +0000

    Add a signals architecture to allow callbacks on GUI events.
    Make all widget classes initialise widgets by calling TXT_InitWidget.

    Subversion-branch: /trunk/chocolate-doom
    Subversion-revision: 501
---
 textscreen/guitest.c         |  12 +++++
 textscreen/txt_button.c      |  12 +++--
 textscreen/txt_checkbox.c    |   4 +-
 textscreen/txt_label.c       |   4 +-
 textscreen/txt_radiobutton.c |   4 +-
 textscreen/txt_separator.c   |   3 +-
 textscreen/txt_table.c       |   4 +-
 textscreen/txt_widget.c      | 106 +++++++++++++++++++++++++++++++++++++++++++
 textscreen/txt_widget.h      |   7 +++
 9 files changed, 138 insertions(+), 18 deletions(-)

diff --git a/textscreen/guitest.c b/textscreen/guitest.c
index 27e23b00..2f8c3733 100644
--- a/textscreen/guitest.c
+++ b/textscreen/guitest.c
@@ -22,16 +22,23 @@ int radiobutton_value;
 txt_window_t *firstwin;
 int checkbox_value;

+void CloseWindow(txt_widget_t *widget, void *user_data)
+{
+    TXT_CloseWindow(firstwin);
+}
+
 void SetupWindow(void)
 {
     txt_window_t *window;
     txt_table_t *table;
     txt_table_t *leftpane, *rightpane;
+    txt_button_t *button;
     char buf[100];
     int i;

     window = TXT_NewWindow("Window test");

+    TXT_AddWidget(window, TXT_NewSeparator("Main section"));
     table = TXT_NewTable(3);

     TXT_AddWidget(window, TXT_NewLabel(" This is a multiline label.\n"
@@ -66,6 +73,11 @@ void SetupWindow(void)
     TXT_AddWidget(rightpane, TXT_NewRadioButton("Snake", &radiobutton_value,
                                                 RADIO_VALUE_SNAKE));

+    button = TXT_NewButton("Close Window");
+    TXT_AddWidget(window, button);
+
+    TXT_SignalConnect(button, "pressed", CloseWindow, NULL);
+
     firstwin = window;
 }

diff --git a/textscreen/txt_button.c b/textscreen/txt_button.c
index b7ae1765..e20f462d 100644
--- a/textscreen/txt_button.c
+++ b/textscreen/txt_button.c
@@ -1,6 +1,8 @@

 #include <string.h>

+#include "doomkeys.h"
+
 #include "txt_button.h"
 #include "txt_io.h"
 #include "txt_main.h"
@@ -44,11 +46,15 @@ static void TXT_ButtonDestructor(txt_widget_t *widget)
     txt_button_t *button = (txt_button_t *) widget;

     free(button->label);
-    free(button);
 }

 static int TXT_ButtonKeyPress(txt_widget_t *widget, int key)
 {
+    if (key == KEY_ENTER)
+    {
+        TXT_EmitSignal(widget, "pressed");
+    }
+
     return 0;
 }

@@ -66,9 +72,7 @@ txt_button_t *TXT_NewButton(char *label)

     button = malloc(sizeof(txt_button_t));

-    button->widget.widget_class = &txt_button_class;
-    button->widget.selectable = 1;
-    button->widget.visible = 1;
+    TXT_InitWidget(button, &txt_button_class);
     button->label = strdup(label);

     return button;
diff --git a/textscreen/txt_checkbox.c b/textscreen/txt_checkbox.c
index b413874e..f33781c1 100644
--- a/textscreen/txt_checkbox.c
+++ b/textscreen/txt_checkbox.c
@@ -91,9 +91,7 @@ txt_checkbox_t *TXT_NewCheckBox(char *label, int *variable)

     checkbox = malloc(sizeof(txt_checkbox_t));

-    checkbox->widget.widget_class = &txt_checkbox_class;
-    checkbox->widget.selectable = 1;
-    checkbox->widget.visible = 1;
+    TXT_InitWidget(checkbox, &txt_checkbox_class);
     checkbox->label = strdup(label);
     checkbox->variable = variable;

diff --git a/textscreen/txt_label.c b/textscreen/txt_label.c
index 0534f10a..afdf9b01 100644
--- a/textscreen/txt_label.c
+++ b/textscreen/txt_label.c
@@ -39,7 +39,6 @@ static void TXT_LabelDestructor(txt_widget_t *widget)

     free(label->label);
     free(label->lines);
-    free(label);
 }

 txt_widget_class_t txt_label_class =
@@ -98,9 +97,8 @@ txt_label_t *TXT_NewLabel(char *text)

     label = malloc(sizeof(txt_label_t));

-    label->widget.widget_class = &txt_label_class;
+    TXT_InitWidget(label, &txt_label_class);
     label->widget.selectable = 0;
-    label->widget.visible = 1;
     label->label = strdup(text);

     TXT_SplitLabel(label);
diff --git a/textscreen/txt_radiobutton.c b/textscreen/txt_radiobutton.c
index 80911a46..45412f28 100644
--- a/textscreen/txt_radiobutton.c
+++ b/textscreen/txt_radiobutton.c
@@ -91,9 +91,7 @@ txt_radiobutton_t *TXT_NewRadioButton(char *label, int *variable, int value)

     radiobutton = malloc(sizeof(txt_radiobutton_t));

-    radiobutton->widget.widget_class = &txt_radiobutton_class;
-    radiobutton->widget.selectable = 1;
-    radiobutton->widget.visible = 1;
+    TXT_InitWidget(radiobutton, &txt_radiobutton_class);
     radiobutton->label = strdup(label);
     radiobutton->variable = variable;
     radiobutton->value = value;
diff --git a/textscreen/txt_separator.c b/textscreen/txt_separator.c
index 2013edac..038fa19b 100644
--- a/textscreen/txt_separator.c
+++ b/textscreen/txt_separator.c
@@ -71,9 +71,8 @@ txt_separator_t *TXT_NewSeparator(char *label)

     separator = malloc(sizeof(txt_separator_t));

-    separator->widget.widget_class = &txt_separator_class;
+    TXT_InitWidget(separator, &txt_separator_class);
     separator->widget.selectable = 0;
-    separator->widget.visible = 1;

     if (label != NULL)
     {
diff --git a/textscreen/txt_table.c b/textscreen/txt_table.c
index 5ae9ee62..4e2d1f96 100644
--- a/textscreen/txt_table.c
+++ b/textscreen/txt_table.c
@@ -408,12 +408,10 @@ txt_widget_class_t txt_table_class =

 void TXT_InitTable(txt_table_t *table, int columns)
 {
+    TXT_InitWidget(table, &txt_table_class);
     table->columns = columns;
     table->widgets = NULL;
     table->num_widgets = 0;
-    table->widget.widget_class = &txt_table_class;
-    table->widget.visible = 1;
-    table->widget.selectable = 1;
     table->selected_x = 0;
     table->selected_y = 0;
 }
diff --git a/textscreen/txt_widget.c b/textscreen/txt_widget.c
index c10699b5..d257ee75 100644
--- a/textscreen/txt_widget.c
+++ b/textscreen/txt_widget.c
@@ -1,7 +1,111 @@
 #include <stdlib.h>
+#include <string.h>

 #include "txt_widget.h"

+typedef struct
+{
+    char *signal_name;
+    TxtWidgetSignalFunc func;
+    void *user_data;
+} txt_callback_t;
+
+struct txt_callback_table_s
+{
+    txt_callback_t *callbacks;
+    int num_callbacks;
+};
+
+txt_callback_table_t *TXT_NewCallbackTable(void)
+{
+    txt_callback_table_t *table;
+
+    table = malloc(sizeof(txt_callback_table_t));
+    table->callbacks = NULL;
+    table->num_callbacks = 0;
+
+    return table;
+}
+
+void TXT_DestroyCallbackTable(txt_callback_table_t *table)
+{
+    int i;
+
+    for (i=0; i<table->num_callbacks; ++i)
+    {
+        free(table->callbacks[i].signal_name);
+    }
+
+    free(table->callbacks);
+    free(table);
+}
+
+void TXT_InitWidget(void *uncast_widget, txt_widget_class_t *widget_class)
+{
+    txt_widget_t *widget = (txt_widget_t *) uncast_widget;
+
+    widget->widget_class = widget_class;
+    widget->callback_table = TXT_NewCallbackTable();
+
+    // Default values: visible and selectable
+
+    widget->selectable = 1;
+    widget->visible = 1;
+}
+
+void TXT_SignalConnect(txt_widget_t *widget,
+                       char *signal_name,
+                       TxtWidgetSignalFunc func,
+                       void *user_data)
+{
+    txt_callback_table_t *table;
+    txt_callback_t *callback;
+    int i;
+
+    table = widget->callback_table;
+
+    for (i=0; i<table->num_callbacks; ++i)
+    {
+        if (!strcmp(signal_name, table->callbacks[i].signal_name))
+        {
+            // Replace existing signal
+
+            table->callbacks[i].func = func;
+            table->callbacks[i].user_data = user_data;
+            break;
+        }
+    }
+
+    // Add a new callback to the table
+
+    table->callbacks
+            = realloc(table->callbacks,
+                      sizeof(txt_callback_t) * (table->num_callbacks + 1));
+    callback = &table->callbacks[table->num_callbacks];
+    ++table->num_callbacks;
+
+    callback->signal_name = strdup(signal_name);
+    callback->func = func;
+    callback->user_data = user_data;
+}
+
+void TXT_EmitSignal(txt_widget_t *widget, char *signal_name)
+{
+    txt_callback_table_t *table;
+    int i;
+
+    table = widget->callback_table;
+
+    for (i=0; i<table->num_callbacks; ++i)
+    {
+        if (!strcmp(table->callbacks[i].signal_name, signal_name))
+        {
+            table->callbacks[i].func(widget, table->callbacks[i].user_data);
+            break;
+        }
+    }
+}
+
 void TXT_CalcWidgetSize(txt_widget_t *widget, int *w, int *h)
 {
     return widget->widget_class->size_calc(widget, w, h);
@@ -15,6 +119,8 @@ void TXT_DrawWidget(txt_widget_t *widget, int w, int selected)
 void TXT_DestroyWidget(txt_widget_t *widget)
 {
     widget->widget_class->destructor(widget);
+    TXT_DestroyCallbackTable(widget->callback_table);
+    free(widget);
 }

 int TXT_WidgetKeyPress(txt_widget_t *widget, int key)
diff --git a/textscreen/txt_widget.h b/textscreen/txt_widget.h
index d852ccd1..a166791a 100644
--- a/textscreen/txt_widget.h
+++ b/textscreen/txt_widget.h
@@ -29,11 +29,13 @@

 typedef struct txt_widget_class_s txt_widget_class_t;
 typedef struct txt_widget_s txt_widget_t;
+typedef struct txt_callback_table_s txt_callback_table_t;

 typedef void (*TxtWidgetSizeCalc)(txt_widget_t *widget, int *w, int *h);
 typedef void (*TxtWidgetDrawer)(txt_widget_t *widget, int w, int selected);
 typedef void (*TxtWidgetDestroy)(txt_widget_t *widget);
 typedef int (*TxtWidgetKeyPress)(txt_widget_t *widget, int key);
+typedef void (*TxtWidgetSignalFunc)(txt_widget_t *widget, void *user_data);

 struct txt_widget_class_s
 {
@@ -46,12 +48,17 @@ struct txt_widget_class_s
 struct txt_widget_s
 {
     txt_widget_class_t *widget_class;
+    txt_callback_table_t *callback_table;
     int selectable;
     int visible;
 };

+void TXT_InitWidget(void *widget, txt_widget_class_t *widget_class);
 void TXT_CalcWidgetSize(txt_widget_t *widget, int *w, int *h);
 void TXT_DrawWidget(txt_widget_t *widget, int w, int selected);
+void TXT_SignalConnect(txt_widget_t *widget, char *signal_name,
+                       TxtWidgetSignalFunc func, void *user_data);
+void TXT_EmitSignal(txt_widget_t *widget, char *signal_name);
 int TXT_WidgetKeyPress(txt_widget_t *widget, int key);
 void TXT_DestroyWidget(txt_widget_t *widget);