#include "on_screen_keyboard.h" // #include // 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 < allChars.length(); ++i) { key_t key; key.col = index_col; key.row = index_row; key.caption = allChars.substr(i, 1); layout.push_back(key); // std::cout << key.caption << " " << key.col << " " << key.row << " " << std::endl; ++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 : 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 : 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 < 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 < 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(); }