From 652b434e7b6887bc476a678425dbf1015c2b3f9d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 9 Jul 2011 09:44:37 +0900 Subject: [PATCH] Rework the inputline wrapper. Use the resource map code for handle management (much safer). Add support for the enter callback (function or method). Unfortunately, it still doesn't work due to poor design of the inputline user data. --- libs/console/bi_inputline.c | 228 +++++++++++++++++++++---------- ruamoko/cl_menu/CvarStringView.r | 8 ++ ruamoko/gui/InputLine.r | 16 +++ ruamoko/include/gui/InputLine.h | 4 + 4 files changed, 185 insertions(+), 71 deletions(-) diff --git a/libs/console/bi_inputline.c b/libs/console/bi_inputline.c index 6a52a4219..e831a1b61 100644 --- a/libs/console/bi_inputline.c +++ b/libs/console/bi_inputline.c @@ -28,8 +28,7 @@ # include "config.h" #endif -static __attribute__ ((used)) const char rcsid[] = - "$Id$"; +static __attribute__ ((used)) const char rcsid[] = "$Id$"; #include #ifdef HAVE_STRING_H @@ -46,116 +45,212 @@ static __attribute__ ((used)) const char rcsid[] = #include "QF/sys.h" #include "QF/zone.h" +typedef struct il_data_s { + struct il_data_s *next; + struct il_data_s **prev; + inputline_t *line; + progs_t *pr; + func_t enter; // enter key callback + pointer_t data[2]; // allow two data params for the callback + int method; // true if method rather than function +} il_data_t; + typedef struct { - inputline_t **lines; - int max_lines; + PR_RESMAP (il_data_t) line_map; + il_data_t *lines; void (*draw)(inputline_t *il); } il_resources_t; -//FIXME need to robustify the interface to avoid segfaults caused by errant -//progs +static il_data_t * +il_data_new (il_resources_t *res) +{ + PR_RESNEW (il_data_t, res->line_map); +} -static inputline_t * +static void +il_data_free (il_resources_t *res, il_data_t *line) +{ + PR_RESFREE (il_data_t, res->line_map, line); +} + +static void +il_data_reset (il_resources_t *res) +{ + PR_RESRESET (il_data_t, res->line_map); +} + +static inline il_data_t * +il_data_get (il_resources_t *res, unsigned index) +{ + PR_RESGET (res->line_map, index); +} + +static inline int +il_data_index (il_resources_t *res, il_data_t *line) +{ + PR_RESINDEX (res->line_map, line); +} + +static void +bi_il_clear (progs_t *pr, void *data) +{ + il_resources_t *res = (il_resources_t *)data; + il_data_t *line; + + for (line = res->lines; line; line = line->next) + Con_DestroyInputLine (line->line); + res->lines = 0; + il_data_reset (res); +} + +static il_data_t * get_inputline (progs_t *pr, int arg, const char *func) { il_resources_t *res = PR_Resources_Find (pr, "InputLine"); - inputline_t *line; + il_data_t *line = il_data_get (res, arg); - if (arg < 0 || arg >= res->max_lines) - PR_RunError (pr, "%s: Invalid inputline_t: $%x $%x", func, arg, - res->max_lines); - - line = res->lines[arg]; - if (!line) - PR_RunError (pr, "Invalid inputline_t"); + // line->prev will be null if the handle is unallocated + if (!line || !line->prev) + PR_RunError (pr, "invalid inputline: passed to %s", func); return line; } +static void +bi_inputline_enter (inputline_t *il) +{ + il_data_t *data = (il_data_t *) il->user_data; + progs_t *pr = data->pr; + const char *line = il->line; + + Sys_Printf ("enter\n"); + if (!data->enter) + return; // no callback defined + + PR_PushFrame (pr); + PR_RESET_PARAMS (pr); + if (data->method) { + P_POINTER (pr, 0) = data->data[0]; + P_POINTER (pr, 1) = data->data[1]; + P_STRING (pr, 2) = PR_SetTempString (pr, line); + } else { + P_STRING (pr, 0) = PR_SetTempString (pr, line); + P_POINTER (pr, 1) = data->data[0]; + } + PR_ExecuteProgram (pr, data->enter); + PR_PopFrame (pr); +} + static void bi_InputLine_Create (progs_t *pr) { il_resources_t *res = PR_Resources_Find (pr, "InputLine"); - inputline_t **line = 0; - int i; + il_data_t *data; + inputline_t *line; int lines = P_INT (pr, 0); int size = P_INT (pr, 1); int prompt = P_INT (pr, 2); - for (i = 0; i < res->max_lines; i++) - if (!res->lines[i]) { - line = &res->lines[i]; - break; - } + line = Con_CreateInputLine (lines, size, prompt); if (!line) { - Sys_Printf ("out of resources\n"); - R_INT (pr) = 0; - return; - } - *line = Con_CreateInputLine (lines, size, prompt); - if (!*line) { Sys_Printf ("failed to create inputline\n"); R_INT (pr) = 0; return; } - (*line)->draw = res->draw; - R_INT (pr) = line - res->lines; + + data = il_data_new (res); + if (!data) { + Con_DestroyInputLine (line); + Sys_Printf ("out of resources\n"); + R_INT (pr) = 0; + return; + } + + data->next = res->lines; + data->prev = &res->lines; + if (res->lines) + res->lines->prev = &data->next; + res->lines = data; + data->line = line; + + line->draw = res->draw; + line->enter = bi_inputline_enter; + line->user_data = data; + + R_INT (pr) = il_data_index (res, data); } static void bi_InputLine_SetUserData (progs_t *pr) { - inputline_t *line = get_inputline (pr, P_INT (pr, 0), - "InputLine_SetUserData"); + il_data_t *line = get_inputline (pr, P_INT (pr, 0), + "InputLine_SetUserData"); pr_type_t *data = P_GPOINTER (pr, 1); - line->user_data = data; + line->line->user_data = data; +} + +static void +bi_InputLine_SetEnter (progs_t *pr) +{ + il_data_t *line = get_inputline (pr, P_INT (pr, 0), + "InputLine_SetEnter"); + + line->data[1] = 0; + + //FIXME look up implementation here? + if (pr->pr_argc == 4) { + line->enter = P_FUNCTION (pr, 1); // implementation + line->data[0] = P_POINTER (pr, 2); // object + line->data[1] = P_POINTER (pr, 3); // selector + line->method = 1; + } else { + line->enter = P_FUNCTION (pr, 1); // function + line->data[0] = P_POINTER (pr, 2); // data + line->data[1] = 0; + line->method = 0; + } } static void bi_InputLine_SetWidth (progs_t *pr) { - inputline_t *line = get_inputline (pr, P_INT (pr, 0), + il_data_t *line = get_inputline (pr, P_INT (pr, 0), "InputLine_SetWidth"); int width = P_INT (pr, 1); - line->width = width; + line->line->width = width; } static void bi_InputLine_Destroy (progs_t *pr) { il_resources_t *res = PR_Resources_Find (pr, "InputLine"); - int arg = P_INT (pr, 0); - inputline_t *line; + il_data_t *line = get_inputline (pr, P_INT (pr, 0), "InputLine_Destroy"); - if (arg < 0 || arg >= res->max_lines) - PR_RunError (pr, "InputLine_Destroy: Invalid inputline_t"); - - line = res->lines[arg]; - if (!line) - PR_RunError (pr, "InputLine_Destroy: Invalid inputline_t"); - - Con_DestroyInputLine (line); - res->lines[arg] = 0; + Con_DestroyInputLine (line->line); + *line->prev = line->next; + if (line->next) + line->next->prev = line->prev; + il_data_free (res, line); } static void bi_InputLine_Clear (progs_t *pr) { - inputline_t *line = get_inputline (pr, P_INT (pr, 0), "InputLine_Clear"); + il_data_t *line = get_inputline (pr, P_INT (pr, 0), "InputLine_Clear"); int save = P_INT (pr, 1); - Con_ClearTyping (line, save); + Con_ClearTyping (line->line, save); } static void bi_InputLine_Process (progs_t *pr) { - inputline_t *line = get_inputline (pr, P_INT (pr, 0), "InputLine_Process"); + il_data_t *line = get_inputline (pr, P_INT (pr, 0), "InputLine_Process"); int ch = P_INT (pr, 1); - Con_ProcessInputLine (line, ch); + Con_ProcessInputLine (line->line, ch); } /* @@ -166,8 +261,9 @@ bi_InputLine_Process (progs_t *pr) static void bi_InputLine_SetText (progs_t *pr) { - inputline_t *il = get_inputline (pr, P_INT (pr, 0), "InputLine_SetText"); - const char *str = P_GSTRING (pr, 1); + il_data_t *line = get_inputline (pr, P_INT (pr, 0), "InputLine_SetText"); + const char *str = P_GSTRING (pr, 1); + inputline_t *il = line->line; /* this was segfault trap: il->lines[il->edit_line][0] is promt character @@ -184,7 +280,8 @@ bi_InputLine_SetText (progs_t *pr) static void bi_InputLine_GetText (progs_t *pr) { - inputline_t *il = get_inputline (pr, P_INT (pr, 0), "InputLine_GetText"); + il_data_t *line = get_inputline (pr, P_INT (pr, 0), "InputLine_GetText"); + inputline_t *il = line->line; RETURN_STRING(pr, il->lines[il->edit_line]+1); } @@ -192,27 +289,18 @@ bi_InputLine_GetText (progs_t *pr) static void bi_InputLine_Draw (progs_t *pr) { - inputline_t *il = get_inputline (pr, P_INT (pr, 0), "InputLine_Draw"); + il_data_t *line = get_inputline (pr, P_INT (pr, 0), "InputLine_Draw"); - il->draw (il); -} - -static void -bi_il_clear (progs_t *pr, void *data) -{ - il_resources_t *res = (il_resources_t *)data; - int i; - - for (i = 0; i < res->max_lines; i++) - if (res->lines[i]) { - Con_DestroyInputLine (res->lines[i]); - res->lines[i] = 0; - } + line->line->draw (line->line); } static builtin_t builtins[] = { {"InputLine_Create", bi_InputLine_Create, -1}, {"InputLine_SetUserData", bi_InputLine_SetUserData, -1}, + {"InputLine_SetEnter|^{tag _inputline_t=}(v*^v)^v", + bi_InputLine_SetEnter, -1}, + {"InputLine_SetEnter|^{tag _inputline_t=}(@@:.)@:", + bi_InputLine_SetEnter, -1}, {"InputLine_SetWidth", bi_InputLine_SetWidth, -1}, {"InputLine_SetText", bi_InputLine_SetText, -1}, {"InputLine_GetText", bi_InputLine_GetText, -1}, @@ -226,9 +314,7 @@ static builtin_t builtins[] = { VISIBLE void InputLine_Progs_Init (progs_t *pr) { - il_resources_t *res = malloc (sizeof (il_resources_t)); - res->max_lines = 64; - res->lines = calloc (sizeof (inputline_t *), res->max_lines); + il_resources_t *res = calloc (1, sizeof (il_resources_t)); PR_Resources_Register (pr, "InputLine", res, bi_il_clear); PR_RegisterBuiltins (pr, builtins); diff --git a/ruamoko/cl_menu/CvarStringView.r b/ruamoko/cl_menu/CvarStringView.r index 32a10c674..3fe95cfaa 100644 --- a/ruamoko/cl_menu/CvarStringView.r +++ b/ruamoko/cl_menu/CvarStringView.r @@ -9,6 +9,13 @@ @implementation CvarStringView +-enter: (string) line +{ + if (line) + [cvstring setString: line]; + return self; +} + -(void)update { [ilb setText: [cvstring value]]; @@ -30,6 +37,7 @@ rect.size.width = (aRect.size.width - rect.size.width) / 8 - 2; rect.size.height = 4; // history lines (stupid interface:P) ilb = [[InputLineBox alloc] initWithBounds:rect promptCharacter:' ']; + [ilb setEnter: self message:@selector(enter:)]; [self addView:title]; [self addView:ilb]; diff --git a/ruamoko/gui/InputLine.r b/ruamoko/gui/InputLine.r index adec69ac9..26b48d58a 100644 --- a/ruamoko/gui/InputLine.r +++ b/ruamoko/gui/InputLine.r @@ -1,9 +1,12 @@ #include "draw.h" +#include "debug.h" #include "gui/InputLine.h" #include "gui/Rect.h" inputline_t (int lines, int size, int prompt) InputLine_Create = #0; void InputLine_SetUserData (inputline_t il, void *data) = #0; +@overload void InputLine_SetEnter (inputline_t il, void (f)(string, void*), void *data) = #0; +@overload void InputLine_SetEnter (inputline_t il, IMP imp, id obj, SEL sel) = #0; void (inputline_t il, int width) InputLine_SetWidth = #0; void (inputline_t il) InputLine_Destroy = #0; void (inputline_t il, int size) InputLine_Clear = #0; @@ -45,6 +48,14 @@ string (inputline_t il) InputLine_GetText = #0; InputLine_SetWidth (il, width); } +- (void) setEnter: obj message:(SEL) msg +{ +traceon(); + IMP imp = [obj methodForSelector: msg]; + InputLine_SetEnter (il, imp, obj, msg); +traceoff(); +} + - (void) processInput: (int)key { InputLine_Process (il, key); @@ -99,6 +110,11 @@ string (inputline_t il) InputLine_GetText = #0; [input_line setWidth:width]; } +- (void) setEnter: obj message:(SEL) msg +{ + [input_line setEnter:obj message: msg]; +} + - (void) cursor: (BOOL)cursor { [input_line cursor:cursor]; diff --git a/ruamoko/include/gui/InputLine.h b/ruamoko/include/gui/InputLine.h index 0f7dfb221..083a17df4 100644 --- a/ruamoko/include/gui/InputLine.h +++ b/ruamoko/include/gui/InputLine.h @@ -8,6 +8,8 @@ typedef struct _inputline_t *inputline_t; @extern inputline_t (int lines, int size, int prompt) InputLine_Create; @extern void InputLine_SetUserData (inputline_t il, void *data); +@extern @overload void InputLine_SetEnter (inputline_t il, void (f)(string, void*), void *data); +@extern @overload void InputLine_SetEnter (inputline_t il, IMP imp, id obj, SEL sel); @extern void (inputline_t il, int width) InputLine_SetWidth; @extern void (inputline_t il) InputLine_Destroy; @extern void (inputline_t il, int save) InputLine_Clear; @@ -31,6 +33,7 @@ struct il_data_t { - (void) setBasePosFromView: (View *) view; - (void) setWidth: (int)width; +- (void) setEnter: obj message:(SEL) msg; - (void) cursor: (BOOL)cursor; - (void) draw; @@ -48,6 +51,7 @@ struct il_data_t { - (id) initWithBounds: (Rect)aRect promptCharacter: (int)char; - (void) setWidth: (int)width; +- (void) setEnter: obj message:(SEL) msg; - (void) cursor: (BOOL)cursor; - (void) processInput: (int)key;