fteqw/quakec/csaddon/src/textfield.qc
Spoike ad32917970 tiny fixes (note: also removed workarounds, jogi update fteqcc).
added drawlame3dtext function as per jogi's request.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3987 fc73d0e0-1445-4013-8a0c-d673dee63da5
2012-02-13 09:14:09 +00:00

339 lines
8.8 KiB
C++

/*reusable code to draw/edit/etc some generic text object*/
/*consult the brief blurb above each function to see what it does*/
/*this file deals with textfield_t pointers. allocate your textfield somewhere yourself (probably as a global, this is QC after all), before invoking this code with a pointer to it*/
#define TEXTFIELD_LINES 200i
typedef struct
{
string lines[TEXTFIELD_LINES];
int cursorline;
int cursorcol;
int linecount;
int dirty;
} textfield_t;
/*this is a text description thing*/
typedef struct
{
string name;
string desc;
} textfield_linedesc_t;
/*destroys the contents of a text field, releasing strings to the system (and clears ready for reuse)*/
void(textfield_t *fld) textfield_clean =
{
while(fld->linecount)
{
fld->linecount = fld->linecount - 1i;
strunzone(fld->lines[fld->linecount]);
fld->lines[fld->linecount] = (string)__NULL__;
}
fld->cursorline = 0i;
fld->cursorcol = 0i;
fld->dirty = TRUE; //because its changed
};
/*fill a text field with data from a string. new lines are supported, but leading tabs and spaces will be stripped*/
void(textfield_t *fld, string text) textfield_fill =
{
string line;
float start, end, term;
while(fld->linecount)
{
fld->linecount = fld->linecount - 1i;
strunzone(fld->lines[fld->linecount]);
fld->lines[fld->linecount] = (string)__NULL__;
}
fld->cursorline = -1i;
fld->cursorcol = -1i;
start = 0;
for(;;)
{
end = strstrofs(text, "\n", start);
if (end < 0)
break;
while(text[start] == '\t')
++start;
term = end;
if (term) if (text[term-1] == '\r') term--;
line = substring(text, start, term - start);
end += 1;
if (fld->linecount == TEXTFIELD_LINES)
break;
fld->lines[fld->linecount] = strzone(line);
fld->linecount = fld->linecount + 1i;
start = end;
}
fld->dirty = TRUE;
};
/*draws the text field on the screen at a given position.
there's no size argument, so make sure data doesn't cause the display to overflow intended area (personally I'm just going to put it at the bottom+right of the screen)*/
void(vector pos, textfield_t *fld, textfield_linedesc_t *fields) textfield_draw =
{
string t;
int l;
int nummatches;
int lastmatch;
for (l = 0i; l < fld->linecount; l+=1i, pos_y += 8)
{
if (l == fld->cursorline && ((cltime * 4) & 1))
{
t = substring(fld->lines[l], 0, fld->cursorcol);
drawrawstring(pos, t, '8 8 0', '1 1 1', 1, 0);
drawrawstring(pos + (0+fld->cursorcol) * '8 0 0', "\x0b", '8 8 0', '1 0 0', 1, 0);
t = substring(fld->lines[l], fld->cursorcol+1, -1);
drawrawstring(pos + (1+fld->cursorcol) * '8 0 0', t, '8 8 0', '1 1 1', 1, 0);
}
else
drawrawstring(pos, fld->lines[l], '8 8 0', '1 1 1', 1, 0);
}
if (fld->cursorline < 0)
return;
pos_y += 8;
pos_x += 64;
string cmd = fld->lines[fld->cursorline];
float llen = strstrofs(cmd, " ");
if (llen < 0f)
llen = strlen(cmd);
cmd = substring(cmd, 0, llen);
/*show command completion box*/
for (l = 0; fields[l].name; l++)
{
if (!strncmp(fields[l].name, cmd, llen))
{
nummatches++;
lastmatch = l;
/*if its an exact match, then stop here*/
if (cmd == fields[l].name)
{
nummatches = 1;
break;
}
}
}
if (nummatches == 1 && strlen(fields[lastmatch].name) == llen)
{
drawrawstring(pos, fields[lastmatch].desc, '8 8 0', '0 1 1', 1, 0);
}
else
{
/*show command completion box*/
for (l = 0; fields[l].name; l++)
{
if (!strncmp(fields[l].name, cmd, llen))
{
drawrawstring(pos, fields[l].name, '8 8 0', '0 1 1', 1, 0);
pos_y += 8;
}
}
}
};
/*send the entire text field into the localcmd builtin, newlines and all*/
void(textfield_t *fld) textfield_localcmd =
{
int l;
for (l = 0i; l < fld->linecount; l+=1i)
{
localcmd(fld->lines[l]);
localcmd("\n");
}
};
/*returns the current contents of the text field as a single tempstring (strcat, woo)*/
string(textfield_t *fld) textfield_strcat =
{
int l;
string res;
for (l = 0i; l < fld->linecount; l+=1i)
{
res = strcat(res, fld->lines[l], "\n");
}
return res;
};
/*if the user clicks+presses+etc upon the text field, do the magic here
the caller will need to track selected wigit themselves.*/
float(textfield_t *fld, float keyc, float unic, vector m) textfield_key
{
int i;
string l,r;
/*mouse*/
if (keyc == 512)
{
fld->cursorline = floor(m_y / 8);
fld->cursorcol = floor(m_x / 8);
if (fld->cursorline > fld->linecount && fld->linecount)
fld->cursorline = -1i;
return TRUE;
}
else if (fld->cursorline == -1i)
{
/*if its not active, do nothing*/
return FALSE;
}
/*escape*/
else if (keyc == 27)
{
fld->cursorline = -1i;
return TRUE;
}
/*backspace*/
else if (keyc == 127)
{
if (fld->cursorline >= fld->linecount)
{
/*we're beyond the bounds of the buffer*/
if (fld->cursorline)
fld->cursorline = fld->cursorline - 1i;
}
else if (fld->cursorcol)
{
/*simple delete*/
l = substring(fld->lines[fld->cursorline], 0, fld->cursorcol-1);
r = substring(fld->lines[fld->cursorline], fld->cursorcol, -1);
strunzone(fld->lines[fld->cursorline]);
fld->lines[fld->cursorline] = strzone(strcat(l, r));
fld->cursorcol = fld->cursorcol - 1i;
}
else if (fld->cursorline)
{
/*at the start of the line, merge the line with thee previous*/
l = fld->lines[(fld->cursorline - 1i)];
r = fld->lines[fld->cursorline];
fld->cursorcol = strlen(l);
l = strcat(l, r);
strunzone(fld->lines[fld->cursorline - 1i]);
fld->lines[fld->cursorline - 1i] = strzone(l);
for (i = fld->cursorline; i < fld->linecount - 1i; i++)
{
fld->lines[i] = fld->lines[i + 1i];
}
fld->cursorline = fld->cursorline - 1i;
fld->linecount = fld->linecount - 1i;
}
}
/*delete*/
else if (keyc == 8)
{
if (fld->cursorline >= fld->linecount)
{
/*we're beyond the bounds of the buffer*/
if (fld->cursorline)
fld->cursorline = fld->cursorline - 1i;
}
else if (fld->cursorcol >= strlen(fld->lines[fld->cursorline]))
{
/*we're at the end of the line, merge next line in to this one*/
l = fld->lines[(fld->cursorline)];
r = fld->lines[fld->cursorline + 1i];
fld->cursorcol = strlen(l);
l = strcat(l, r);
strunzone(fld->lines[fld->cursorline]);
fld->lines[fld->cursorline] = strzone(l);
for (i = fld->cursorline + 1i; i < fld->linecount - 1i; i++)
{
fld->lines[i] = fld->lines[i + 1i];
}
fld->linecount = fld->linecount - 1i;
}
else
{
/*simple delete*/
l = substring(fld->lines[fld->cursorline], 0, fld->cursorcol);
r = substring(fld->lines[fld->cursorline], fld->cursorcol + 1, -1);
strunzone(fld->lines[fld->cursorline]);
fld->lines[fld->cursorline] = strzone(strcat(l, r));
fld->cursorcol = fld->cursorcol - 1i;
}
}
/*home*/
else if (keyc == 151)
{
fld->cursorcol = 0;
}
/*end*/
else if (keyc == 152)
{
fld->cursorcol = strlen(fld->lines[fld->cursorline]);
}
/*leftarrow*/
else if (keyc == 130)
{
if (fld->cursorcol)
fld->cursorcol = fld->cursorcol - 1i;
}
/*rightarrow*/
else if (keyc == 131)
{
fld->cursorcol = fld->cursorcol + 1i;
}
/*uparrow*/
else if (keyc == 128)
{
if (fld->cursorline)
fld->cursorline = fld->cursorline - 1i;
}
/*downarrow*/
else if (keyc == 129)
{
if (fld->cursorline < fld->linecount)
fld->cursorline = fld->cursorline + 1i;
}
/*return*/
else if (keyc == 13)
{
if (fld->linecount < TEXTFIELD_LINES)
{
/*shift trailing lines down*/
fld->linecount = fld->linecount + 1i;
for (i = fld->linecount - 1i; i > fld->cursorline; i--)
{
fld->lines[i] = fld->lines[i - 1i];
}
/*set the new line to the second half of the current line*/
fld->lines[fld->cursorline + 1i] = strzone(substring(fld->lines[fld->cursorline], fld->cursorcol, -1));
/*update the old line to be the first half only*/
r = strzone(substring(fld->lines[fld->cursorline], 0, fld->cursorcol));
strunzone(fld->lines[fld->cursorline]);
fld->lines[fld->cursorline] = r;
/*and set the cursor properly*/
fld->cursorline = fld->cursorline + 1i;
fld->cursorcol = 0;
}
}
/*printable char*/
else if (unic)
{
if (fld->cursorline >= fld->linecount)
{
fld->cursorline = fld->linecount;
fld->linecount += 1i;
fld->lines[fld->cursorline] = strzone(chr2str(unic));
fld->cursorcol = 1i;
}
else
{
l = substring(fld->lines[fld->cursorline], 0, fld->cursorcol);
r = substring(fld->lines[fld->cursorline], fld->cursorcol, -1);
strunzone(fld->lines[fld->cursorline]);
fld->lines[fld->cursorline] = strzone(strcat(l, chr2str(unic), r));
fld->cursorcol = fld->cursorcol+1i;
}
}
else
return FALSE;
fld->dirty = TRUE;
return TRUE;
}