mirror of
https://github.com/nzp-team/fteqw.git
synced 2025-02-12 14:55:34 +00:00
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
339 lines
8.8 KiB
C++
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;
|
|
}
|