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;