robmcmullen-apple2/src/gui/textedit.cpp

254 lines
5.7 KiB
C++

//
// TEXTEDIT.CPP
//
// Graphical User Interface button class
// by James Hammons
//
// JLH = James Hammons <jlhamm@acm.org>
//
// WHO WHEN WHAT
// --- ---------- ------------------------------------------------------------
// JLH 02/17/2006 Created this file
// JLH 03/01/2006 Added basic editing functionality
//
#include "textedit.h"
#include "guimisc.h" // Various support functions
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#define MASK_R 0xFF000000
#define MASK_G 0x00FF0000
#define MASK_B 0x0000FF00
#define MASK_A 0x000000FF
#else
#define MASK_R 0x000000FF
#define MASK_G 0x0000FF00
#define MASK_B 0x00FF0000
#define MASK_A 0xFF000000
#endif
//
// Text edit class implementation
//
TextEdit::TextEdit(uint32_t x/*= 0*/, uint32_t y/*= 0*/, uint32_t w/*= 0*/, uint32_t h/*= 0*/,
std::string s/*= ""*/, Element * parent/*= NULL*/):
Element(x, y, w, h, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x40, 0x40, 0xFF, parent),
activated(false), clicked(false), inside(false),
img(NULL), text(s), caretPos(0), scrollPos(0),
activatedSave(false), clickedSave(false), insideSave(false),
caretPosSave(0), scrollPosSave(0)
{
if (extents.h == 0)
extents.h = GetFontHeight();
// Setup hardwired colors...
uint8_t * c = (uint8_t *)&hiliteColor;
c[0] = 0xFF, c[1] = 0x80, c[2] = 0x00, c[3] = 0xFF;
c = (uint8_t *)&cursorColor;
c[0] = 0x40, c[1] = 0xFF, c[2] = 0x60, c[3] = 0xFF;
// Create the text edit surface here...
img = SDL_CreateRGBSurface(SDL_SWSURFACE, extents.w, extents.h, 32,
MASK_R, MASK_G, MASK_B, MASK_A);
Draw(); // Can we do this in the constructor??? Mebbe.
}
TextEdit::~TextEdit()
{
if (img)
SDL_FreeSurface(img);
}
//Set different filters depending on type passed in on construction, e.g., filename, amount, etc...?
void TextEdit::HandleKey(SDL_Scancode key)
{
if (!activated)
return;
// Punting this for now on SDL 2...
#if 0
SaveStateVariables();
SDLMod keyMod = SDL_GetModState();
if ((key >= SDLK_a && key <= SDLK_z) || (key >= SDLK_0 && key <= SDLK_9)
|| key == SDLK_PERIOD || key == SDLK_SLASH || key == SDLK_SPACE)
{
uint8_t chr = (uint8_t)key;
// Handle shift key as well...
if (keyMod & KMOD_SHIFT)
{
if (key >= SDLK_a && key <= SDLK_z)
chr &= 0xDF; // Set to upper case
}
text.insert(scrollPos + caretPos, 1, chr);
// If we hit the edge, then scroll; else advance the caret
if ((GetFontWidth() * caretPos) > (extents.w - GetFontWidth()))
scrollPos++;
else
caretPos++;
}
else if (key == SDLK_BACKSPACE)
{
// If there's something to delete, go ahead and delete it
if ((scrollPos + caretPos) > 0)
{
text.erase(scrollPos + caretPos - 1, 1);
// Scroll the cursor to the left if possible, otherwise move the scroll position
if (caretPos > 0)
caretPos--;
else
scrollPos--;
}
}
else if (key == SDLK_DELETE)
{
if ((scrollPos + caretPos) < text.length())
text.erase(scrollPos + caretPos, 1);
}
else if (key == SDLK_LEFT)
{
if (caretPos > 0)
caretPos--;
else if (scrollPos > 0)
scrollPos--;
}
else if (key == SDLK_RIGHT)
{
if ((scrollPos + caretPos) < text.length())
{
if ((GetFontWidth() * caretPos) > (extents.w - GetFontWidth()))
scrollPos++;
else
caretPos++;
}
}
else if (key == SDLK_RETURN)
{
clicked = activated = false;
}
CheckStateAndRedrawIfNeeded();
#endif
}
void TextEdit::HandleMouseMove(uint32_t x, uint32_t y)
{
SaveStateVariables();
inside = Inside(x, y);
CheckStateAndRedrawIfNeeded();
}
void TextEdit::HandleMouseButton(uint32_t x, uint32_t y, bool mouseDown)
{
SaveStateVariables();
//Not sure that this is right way to handle this...
//Should set the cursor position based on where in the text box it was clicked...
if (inside)
{
if (mouseDown)
clicked = true;
if (clicked && !mouseDown)
{
clicked = false, activated = true;
// Send a message to our parent widget (if any) that we're activated
if (parent)
parent->Notify(this);
}
}
else
clicked = activated = false;
CheckStateAndRedrawIfNeeded();
}
void TextEdit::Draw(void)
{
if (img == NULL)
return; // Bail out if no surface was created...
SDL_Rect rect = GetScreenCoords();
// Now, draw the appropriate text state!
if (!activated)
{
if (inside)
{
SDL_Rect rect2;
rect2.x = 1;
rect2.y = 1;
rect2.w = extents.w - 2;
rect2.h = extents.h - 2;
SDL_FillRect(img, NULL, hiliteColor);
SDL_FillRect(img, &rect2, bgColor);
}
else
SDL_FillRect(img, NULL, bgColor);
}
else
SDL_FillRect(img, NULL, bgColor);//Make a different color here, so we're clear we're editing...
//Should also draw different text color depending on whether or not we're activated...
if (activated)
DrawStringTrans(img, 0, 0, fgColor, text.c_str() + scrollPos);
else
DrawStringTrans(img, 0, 0, fgColor, text.c_str());
// Draw the cursor, if any
if (activated)
{
SDL_Rect rectCursor;
rectCursor.x = caretPos * GetFontWidth();
rectCursor.y = 0;
rectCursor.w = 2;
rectCursor.h = GetFontHeight();
SDL_FillRect(img, &rectCursor, cursorColor);
}
SDL_BlitSurface(img, NULL, screen, &rect); // This handles alpha blending too! :-D
needToRefreshScreen = true;
}
void TextEdit::Notify(Element *)
{
}
std::string TextEdit::GetText(void)
{
return text;
}
void TextEdit::SaveStateVariables(void)
{
activatedSave = activated;
clickedSave = clicked;
insideSave = inside;
caretPosSave = caretPos;
scrollPosSave = scrollPos;
lengthSave = text.length();
}
void TextEdit::CheckStateAndRedrawIfNeeded(void)
{
// Check to see if any of our state variables changed since we last saved them...
if (activated != activatedSave || clicked != clickedSave || inside != insideSave
|| caretPos != caretPosSave || scrollPos != scrollPosSave
|| text.length() != lengthSave)
Draw();
}