shithub: choc

Download patch

ref: 283f71d0f500541b6273316120e252b03f22fb03
parent: d90a63ed267516f8d35b4d8399dbcb5e52a1e692
author: Simon Howard <fraggle@gmail.com>
date: Sun May 21 20:20:48 EDT 2006

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

--- a/textscreen/guitest.c
+++ b/textscreen/guitest.c
@@ -22,16 +22,23 @@
 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 @@
     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;
 }
 
--- 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 @@
     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 @@
 
     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;
--- a/textscreen/txt_checkbox.c
+++ b/textscreen/txt_checkbox.c
@@ -91,9 +91,7 @@
 
     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;
 
--- a/textscreen/txt_label.c
+++ b/textscreen/txt_label.c
@@ -39,7 +39,6 @@
 
     free(label->label);
     free(label->lines);
-    free(label);
 }
 
 txt_widget_class_t txt_label_class =
@@ -98,9 +97,8 @@
 
     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);
--- a/textscreen/txt_radiobutton.c
+++ b/textscreen/txt_radiobutton.c
@@ -91,9 +91,7 @@
 
     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;
--- a/textscreen/txt_separator.c
+++ b/textscreen/txt_separator.c
@@ -71,9 +71,8 @@
 
     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)
     {
--- a/textscreen/txt_table.c
+++ b/textscreen/txt_table.c
@@ -408,12 +408,10 @@
 
 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;
 }
--- 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_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)
--- 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_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);