mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-22 02:11:19 +00:00
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:
parent
3dd31b7de9
commit
652b434e7b
4 changed files with 185 additions and 71 deletions
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue