If you have comments or questions concerning this source file, discuss them in the forum.
/*
Copyright (c) 2002 Nicolai Haehnle
See the license.txt for details. If that file was not included in the
source distributions, please email <prefect@rtts.org>
*/
// gui_inputbox.cpp
#include "library.h"
#include "hal.h"
#include "gui_inputbox.h"
/*
==============
GInputBox::GInputBox
Set default parameters and make focussable
==============
*/
GInputBox::GInputBox(GPanel *pParent, int x, int y, int w, int h,
const char *text, int align)
: GLabel(pParent, x, y, w, h, text, align)
{
SetCanFocus(true);
m_iMaxLen = -1;
m_iCursorPos = 0;
m_iCursorTime = 0;
m_iMode = im_string;
SetBorder(3, 3);
}
/*
==============
GInputBox::IsValid
Returns true if the input matches all criterias
==============
*/
bool GInputBox::IsValid()
{
if (m_iMode == im_string) {
if (m_pszText && (int)strlen(m_pszText) > m_iMaxLen)
return false;
} else {
char *p;
int i;
if (!m_pszText)
return false;
i = strtol(m_pszText, &p, 0);
if (*p)
return false;
if (i < m_iMin || i > m_iMax)
return false;
}
return true;
}
/*
==============
GInputBox::SetMaxLen
Automatically cut the current text if needed
==============
*/
void GInputBox::SetMaxLen(int iMaxLen)
{
if (m_pszText && (int)strlen(m_pszText) > iMaxLen) {
char *buf;
buf = (char *)L_Malloc(iMaxLen+1, TAG_GUI);
xstrcpy(buf, iMaxLen+1, m_pszText);
SetText(buf);
L_Free(buf);
}
m_iMaxLen = iMaxLen;
}
/*
==============
GInputBox::SetModeInteger
Changes the mode to integer and sets the min/max value(s)
==============
*/
void GInputBox::SetModeInteger(int min, int max)
{
m_iMode = im_integer;
m_iMin = min;
m_iMax = max;
}
/*
==============
GInputBox::Draw
Draw the input box text first, then the cursor and outline
==============
*/
void GInputBox::Draw()
{
byte *color;
color = m_color;
if (m_pszText)
doDraw(color[0], color[1], color[2], color[3]);
if (IsFocussed()) {
m_iCursorTime += hal->frametime;
if (!((m_iCursorTime / 500) % 2)) {
LRect rc;
GetCharRect(m_iCursorPos, &rc);
hal->FillRect(rc.pos[0], rc.pos[1], 2, rc.size[1],
color[0], color[1], color[2], color[3]);
}
}
hal->DrawLine(0, 0, m_rc.size[0], 0, color[0], color[1], color[2], color[3]);
hal->DrawLine(m_rc.size[0], 0, m_rc.size[0], m_rc.size[1], color[0], color[1], color[2], color[3]);
hal->DrawLine(m_rc.size[0], m_rc.size[1], 0, m_rc.size[1], color[0], color[1], color[2], color[3]);
hal->DrawLine(0, m_rc.size[1], 0, 0, color[0], color[1], color[2], color[3]);
}
/*
==============
GInputBox::BoundCursor
Ensure a valid cursorpos
==============
*/
void GInputBox::BoundCursor()
{
int len;
if (m_iCursorPos <= 0)
m_iCursorPos = 0;
else {
len = GetTextLength();
if (m_iCursorPos > len)
m_iCursorPos = len;
}
}
/*
==============
GInput::ScrollToCursor
Update scroll position so that the cursor is just visible
==============
*/
void GInputBox::ScrollToCursor()
{
LRect rc;
GetCharRect(m_iCursorPos, &rc);
if (rc.pos[0] < m_iBorderX) {
m_iScrollX -= m_iBorderX - rc.pos[0] + 48;
if (m_iScrollX < 0)
m_iScrollX = 0;
} else if (rc.pos[0]+2 >= m_rc.size[0]-m_iBorderX)
m_iScrollX += rc.pos[0]+2 - (m_rc.size[0]-m_iBorderX) + 48;
if (rc.pos[1] < m_iBorderY)
m_iScrollY -= m_iBorderY - rc.pos[1];
else if (rc.pos[1]+rc.size[1] >= m_rc.size[1]-m_iBorderY)
m_iScrollY += rc.pos[1]+rc.size[1] - (m_rc.size[1]-m_iBorderY);
}
/*
==============
GInputBox::InputChar
Adds the given char at the current cursorpos
==============
*/
void GInputBox::InputChar(char c)
{
int len;
char *buf;
BoundCursor();
len = GetTextLength();
if (m_iMaxLen > 0 && len >= m_iMaxLen)
return;
buf = (char *)L_Malloc(len+2, TAG_GUI);
memcpy(buf, m_pszText, m_iCursorPos);
memcpy(buf+m_iCursorPos+1, m_pszText+m_iCursorPos, len-m_iCursorPos);
buf[m_iCursorPos] = c;
buf[len+1] = 0;
if (m_iMode == im_integer) {
char *p;
int i;
i = strtol(buf, &p, 0);
if (*p || i < m_iMin || i > m_iMax) {
L_Free(buf);
return;
}
}
SetText(buf);
L_Free(buf);
m_iCursorPos++;
m_iCursorTime = 0;
ScrollToCursor();
Changed.Emit();
}
/*
==============
GInputBox::DeleteChar
Delete the char to the cursor's right
==============
*/
void GInputBox::DeleteChar()
{
int len;
len = GetTextLength();
if (m_iCursorPos < 0 || m_iCursorPos >= len)
return;
if (len == 1)
SetText(0);
else {
m_pszText = (char *)L_Realloc(m_pszText, len, TAG_GUI);
memmove(m_pszText+m_iCursorPos, m_pszText+m_iCursorPos+1, len-m_iCursorPos-1);
m_pszText[len-1] = 0;
}
m_iCursorTime = 0;
ScrollToCursor();
Changed.Emit();
}
/*
==============
GInputBox::SetCursorPos
Sets the cursor to the given location
==============
*/
void GInputBox::SetCursorPos(int pos)
{
m_iCursorPos = pos;
m_iCursorTime = 0;
BoundCursor();
ScrollToCursor();
}
/*
==============
GInputBox::MoveCursor
Moves the cursor n characters forward or backward
==============
*/
void GInputBox::MoveCursor(int n)
{
m_iCursorPos += n;
m_iCursorTime = 0;
BoundCursor();
ScrollToCursor();
}
/*
==============
GInputBox::GainFocus
Purely cosmetic: show the cursor immediately
==============
*/
void GInputBox::GainFocus(bool bGain)
{
m_iCursorTime = 0;
}
/*
==============
GInputBox::Key
Handle input etc..
==============
*/
bool GInputBox::Key(int code, char c, bool down)
{
if (down)
{
if (c >= 32) {
InputChar(c);
return true;
}
switch(code) {
case KEY_LEFT:
MoveCursor(-1);
return true;
case KEY_RIGHT:
MoveCursor(1);
return true;
case KEY_BACKSPACE:
if (m_iCursorPos > 0) {
MoveCursor(-1);
DeleteChar();
}
return true;
case KEY_RETURN:
if (m_pParent) {
m_pParent->FocusNext();
return true;
}
break;
case KEY_DELETE:
DeleteChar();
return true;
}
}
return GLabel::Key(code, c, down);
}