Files
jail_engine/units/on_screen_keyboard.cpp

300 lines
9.4 KiB
C++

#include "on_screen_keyboard.h"
// #include <iostream>
// Constructor
OnScreenKeyboard::OnScreenKeyboard(SDL_Renderer *renderer, Input *input, string bitmapFile, string textFile, options_t *options, int width, int height, string output, color_t color)
{
// Inicializa variables
this->renderer = renderer;
this->options = options;
this->input = input;
this->width = width;
this->height = height;
// Crea objetos
text = new Text(textFile, bitmapFile, renderer);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
textureCursor = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, text->getCharacterSize() * 2, text->getCharacterSize() * 2);
SDL_SetTextureBlendMode(textureCursor, SDL_BLENDMODE_BLEND);
// Inicializa variables
this->output = output;
char_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char_lower = "abcdefghijklmnopqrstuvwxyz";
char_numbers = "0123456789";
char_symbol = " !\"#$%&'()*+,-./:;<=>?@[]";
use_char_upper = true;
use_char_lower = false;
use_char_numbers = false;
use_char_symbol = false;
setLayout();
caption = "";
dest = {(options->screen.nativeWidth - width) / 2, (options->screen.nativeHeight - height) / 2, width, height};
cursor.col = 0;
cursor.row = 0;
cursor.dest = {0, 0, 16, 16};
// Rellena la textura de fondo con el color y el texto
fillTexture();
// Rellena la textura del cursor
SDL_SetRenderTarget(renderer, textureCursor);
color_t c = {192, 0, 0};
SDL_SetRenderDrawColor(renderer, c.r, c.g, c.b, 255);
SDL_RenderClear(renderer);
c = lightenColor(c, 20);
SDL_SetRenderDrawColor(renderer, c.r, c.g, c.b, 255);
SDL_RenderDrawRect(renderer, NULL);
SDL_SetRenderTarget(renderer, nullptr);
}
// Destructor
OnScreenKeyboard::~OnScreenKeyboard()
{
// Libera la memoria de los objetos
if (text != nullptr)
{
delete text;
}
if (texture != nullptr)
{
SDL_DestroyTexture(texture);
}
}
// Rellena la textura de fondo con el color y el texto
void OnScreenKeyboard::fillTexture()
{
// Destruye la textura si la hubiera
if (texture)
SDL_DestroyTexture(texture);
// Crea la textura
height = (text->getCharacterSize() * 4) + (text->getCharacterSize() * rows * 2);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
dest = {(options->screen.nativeWidth - width) / 2, (options->screen.nativeHeight - height) / 2, width, height};
// Empieza a dibujar en la textura
SDL_SetRenderTarget(renderer, texture);
// Establece el color de fondo
SDL_SetRenderDrawColor(renderer, bgColor.r, bgColor.g, bgColor.b, 255);
SDL_RenderClear(renderer);
color_t color = lightenColor(bgColor, 20);
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, 255);
SDL_RenderDrawRect(renderer, NULL);
// Escribe el texto que aparece en el objeto
text->write(text->getCharacterSize(), text->getCharacterSize(), caption);
// Dibuja el cuadro donde va el texto que se escribirá
const color_t darkColor = darkenColor(bgColor, 10);
SDL_SetRenderDrawColor(renderer, darkColor.r, darkColor.g, darkColor.b, 255);
const int x_rect = (text->getCharacterSize() * 2) + text->lenght(caption);
const int y_rect = text->getCharacterSize();
const int w_rect = width - text->getCharacterSize() - x_rect;
const int h_rect = text->getCharacterSize();
outputDest = {x_rect, y_rect, w_rect, h_rect};
SDL_RenderFillRect(renderer, &outputDest);
// Dibuja los caracteres que conformaran el teclado
const int dist = text->getCharacterSize() * 2;
const int offset_x = text->getCharacterSize();
const int offset_y = text->getCharacterSize() * 3;
for (int j = 0; j < rows; ++j)
for (int i = 0; i < columns; ++i)
{
const int pos = i + (j * columns);
if (pos < (int)layout.size())
{
// color_t color = randColor();
// SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, 255);
// SDL_Rect rect = {offset_x + (layout.at(pos).col * dist), offset_y + (layout.at(pos).row * dist), dist, dist};
// SDL_RenderFillRect(renderer, &rect);
// text->write(offset_x + (layout.at(pos).col * dist) + (dist / 2), offset_y + (layout.at(pos).row * dist) + (dist / 2), layout.at(pos).caption);
text->writeCentered(offset_x + (layout.at(pos).col * dist) + (dist / 2), offset_y + (layout.at(pos).row * dist) + (dist / 4), layout.at(pos).caption);
}
}
// Deja de dibujar en la textura
SDL_SetRenderTarget(renderer, nullptr);
}
// Calcula cuantos caracteres se utilizaran para crear el teclado
int OnScreenKeyboard::getTotalChars()
{
int total = 0;
total += use_char_upper ? char_upper.length() : 0;
total += use_char_lower ? char_lower.length() : 0;
total += use_char_numbers ? char_numbers.length() : 0;
total += use_char_symbol ? char_symbol.length() : 0;
return total;
}
// Calcula cuantas columnas necesita el teclado
int OnScreenKeyboard::getColumns()
{
const int keyWidth = text->getCharacterSize() * 2;
int rowWidth = width - text->getCharacterSize();
return rowWidth / keyWidth;
}
// Calcula cuantas filas necesita el teclado
int OnScreenKeyboard::getRows()
{
return (totalChars / getColumns()) + 1;
}
// Establece la disposición del teclado
void OnScreenKeyboard::setLayout()
{
totalChars = getTotalChars();
columns = getColumns();
rows = getRows();
int index_col = 0;
int index_row = 0;
// Establece los caracteres a escribir
string allChars = "";
allChars = use_char_upper ? allChars + char_upper : allChars;
allChars = use_char_lower ? allChars + char_lower : allChars;
allChars = use_char_numbers ? allChars + char_numbers : allChars;
allChars = use_char_symbol ? allChars + char_symbol : allChars;
layout.clear();
for (int i = 0; i < (int)allChars.length(); ++i)
{
key_t key;
key.col = index_col;
key.row = index_row;
key.caption = allChars.substr(i, 1);
layout.push_back(key);
++index_col;
if (index_col == columns)
{
index_col = 0;
++index_row;
}
}
}
// Comprueba las entradas
void OnScreenKeyboard::checkInput()
{
if (input->checkInput(INPUT_LEFT, REPEAT_FALSE))
decCursorCol();
if (input->checkInput(INPUT_RIGHT, REPEAT_FALSE))
incCursorCol();
if (input->checkInput(INPUT_UP, REPEAT_FALSE))
decCursorRow();
if (input->checkInput(INPUT_DOWN, REPEAT_FALSE))
incCursorRow();
if (input->checkInput(INPUT_ACCEPT, REPEAT_FALSE))
addChar();
if (input->checkInput(INPUT_CANCEL, REPEAT_FALSE))
removeChar();
}
// Disminuye en una columna la posición del cursor
void OnScreenKeyboard::decCursorCol()
{
cursor.col = cursor.col > 0 ? cursor.col - 1 : columns - 1;
}
// Incrementa en una columna la posición del cursor
void OnScreenKeyboard::incCursorCol()
{
++cursor.col %= columns;
}
// Disminuye en una fila la posición del cursor
void OnScreenKeyboard::decCursorRow()
{
cursor.row = cursor.row > 0 ? cursor.row - 1 : rows - 1;
}
// Aumenta en una fila la posición del cursor
void OnScreenKeyboard::incCursorRow()
{
++cursor.row %= rows;
}
// Actualiza la posición de la textura del cursor
void OnScreenKeyboard::updateCursor()
{
const int offset_x = text->getCharacterSize();
const int offset_y = text->getCharacterSize() * 3;
cursor.dest.x = dest.x + offset_x + (cursor.col * cursor.dest.w);
cursor.dest.y = dest.y + offset_y + (cursor.row * cursor.dest.h);
}
// Añade un caracter a la salida
void OnScreenKeyboard::addChar()
{
const int pos = cursor.col + cursor.row * columns;
if (pos < (int)layout.size())
output = output + layout.at(pos).caption;
}
// Borra el último caracter de la salida
void OnScreenKeyboard::removeChar()
{
if (output.length() > 0)
output = output.substr(0, output.length() - 1);
}
// Actualiza la lógica del objeto
void OnScreenKeyboard::update()
{
// Comprueba las entradas
checkInput();
// Actualiza la posición de la textura del cursor
updateCursor();
}
// Dibuja el objeto en pantalla
void OnScreenKeyboard::render()
{
SDL_RenderCopy(renderer, texture, nullptr, &dest);
SDL_RenderCopy(renderer, textureCursor, nullptr, &cursor.dest);
const int pos = cursor.col + cursor.row * columns;
const string key = pos < (int)layout.size() ? layout.at(pos).caption : "";
text->writeDX(TXT_CENTER | TXT_COLOR, cursor.dest.x + cursor.dest.w / 2, cursor.dest.y + cursor.dest.w / 4, key, 1, {0, 255, 0});
text->write(dest.x + outputDest.x, dest.y + outputDest.y, output);
}
// Establece el color de fondo
void OnScreenKeyboard::setBgColor(color_t color)
{
bgColor = color;
fillTexture();
}
// Establece el texto a mostrar junto al texto a introducir
void OnScreenKeyboard::setCaption(string text)
{
caption = text;
fillTexture();
}
// Establece qué caracteres ofrecerá el objeto
void OnScreenKeyboard::setChars(Uint8 mode)
{
use_char_upper = ((mode & USE_UPPER) == USE_UPPER);
use_char_lower = ((mode & USE_LOWER) == USE_LOWER);
use_char_numbers = ((mode & USE_NUMBER) == USE_NUMBER);
use_char_symbol = ((mode & USE_SYMBOL) == USE_SYMBOL);
setLayout();
fillTexture();
}