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);