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.
This commit is contained in:
Bill Currie 2011-07-09 09:44:37 +09:00
parent 3dd31b7de9
commit 652b434e7b
4 changed files with 185 additions and 71 deletions

View file

@ -28,8 +28,7 @@
# include "config.h"
#endif
static __attribute__ ((used)) const char rcsid[] =
"$Id$";
static __attribute__ ((used)) const char rcsid[] = "$Id$";
#include <stdlib.h>
#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);

View file

@ -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];

View file

@ -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];

View file

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