From 283f71d0f500541b6273316120e252b03f22fb03 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 22 May 2006 00:20:48 +0000 Subject: 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 +#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 +#include #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; inum_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; inum_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; inum_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); -- cgit v1.2.3