1050 lines
22 KiB
C++
1050 lines
22 KiB
C++
#include "../const.h"
|
|
#include "menu.h"
|
|
#include <iostream>
|
|
|
|
// Constructor
|
|
Menu::Menu(SDL_Renderer *renderer, Asset *asset, Input *input, std::string file)
|
|
{
|
|
// Copia punteros
|
|
this->renderer = renderer;
|
|
this->asset = asset;
|
|
this->input = input;
|
|
|
|
// Inicializa punteros
|
|
soundMove = nullptr;
|
|
soundAccept = nullptr;
|
|
soundCancel = nullptr;
|
|
|
|
// Inicializa variables
|
|
name = "";
|
|
selector.index = 0;
|
|
selector.previousIndex = 0;
|
|
itemSelected = MENU_NO_OPTION;
|
|
x = 0;
|
|
y = 0;
|
|
w = 0;
|
|
rectBG.rect = {0, 0, 0, 0};
|
|
rectBG.color = {0, 0, 0};
|
|
rectBG.a = 0;
|
|
backgroundType = MENU_BACKGROUND_SOLID;
|
|
isCenteredOnX = false;
|
|
isCenteredOnY = false;
|
|
areElementsCenteredOnX = false;
|
|
centerX = 0;
|
|
centerY = 0;
|
|
widestItem = 0;
|
|
colorGreyed = {128, 128, 128};
|
|
defaultActionWhenCancel = 0;
|
|
font_png = "";
|
|
font_txt = "";
|
|
|
|
// Selector
|
|
selector.originY = 0;
|
|
selector.targetY = 0;
|
|
selector.despY = 0;
|
|
selector.originH = 0;
|
|
selector.targetH = 0;
|
|
selector.incH = 0;
|
|
selector.y = 0.0f;
|
|
selector.h = 0.0f;
|
|
selector.numJumps = 8;
|
|
selector.moving = false;
|
|
selector.resizing = false;
|
|
selector.rect = {0, 0, 0, 0};
|
|
selector.color = {0, 0, 0};
|
|
selector.itemColor = {0, 0, 0};
|
|
selector.a = 255;
|
|
|
|
// Inicializa las variables desde un fichero
|
|
if (file != "")
|
|
{
|
|
load(file);
|
|
}
|
|
|
|
// Calcula los colores del selector para el degradado
|
|
setSelectorItemColors();
|
|
|
|
// Deja el cursor en el primer elemento
|
|
reset();
|
|
}
|
|
|
|
Menu::~Menu()
|
|
{
|
|
renderer = nullptr;
|
|
asset = nullptr;
|
|
input = nullptr;
|
|
|
|
if (soundMove)
|
|
{
|
|
JA_DeleteSound(soundMove);
|
|
}
|
|
|
|
if (soundAccept)
|
|
{
|
|
JA_DeleteSound(soundAccept);
|
|
}
|
|
|
|
if (soundCancel)
|
|
{
|
|
JA_DeleteSound(soundCancel);
|
|
}
|
|
|
|
if (text != nullptr)
|
|
{
|
|
delete text;
|
|
}
|
|
}
|
|
|
|
// Carga la configuración del menu desde un archivo de texto
|
|
bool Menu::load(std::string file_path)
|
|
{
|
|
// Indicador de éxito en la carga
|
|
bool success = true;
|
|
|
|
// Indica si se ha creado ya el objeto de texto
|
|
bool textAllocated = false;
|
|
|
|
const std::string filename = file_path.substr(file_path.find_last_of("\\/") + 1);
|
|
std::string line;
|
|
std::ifstream file(file_path);
|
|
|
|
// El fichero se puede abrir
|
|
if (file.good())
|
|
{
|
|
// Procesa el fichero linea a linea
|
|
// std::cout << "Reading file " << filename.c_str() << std::endl;
|
|
while (std::getline(file, line))
|
|
{
|
|
if (line == "[item]")
|
|
{
|
|
item_t item;
|
|
item.label = "";
|
|
item.hPaddingDown = 1;
|
|
item.selectable = true;
|
|
item.greyed = false;
|
|
item.linkedDown = false;
|
|
item.visible = true;
|
|
|
|
do
|
|
{
|
|
// Lee la siguiente linea
|
|
std::getline(file, line);
|
|
|
|
// Encuentra la posición del caracter '='
|
|
int pos = line.find("=");
|
|
|
|
// Procesa las dos subcadenas
|
|
if (!setItem(&item, line.substr(0, pos), line.substr(pos + 1, line.length())))
|
|
{
|
|
// std::cout << "Warning: file " << filename.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
|
|
success = false;
|
|
}
|
|
|
|
} while (line != "[/item]");
|
|
|
|
addItem(item.label, item.hPaddingDown, item.selectable, item.greyed, item.linkedDown, item.visible);
|
|
}
|
|
|
|
// En caso contrario se parsea el fichero para buscar las variables y los valores
|
|
else
|
|
{
|
|
// Encuentra la posición del caracter '='
|
|
int pos = line.find("=");
|
|
// Procesa las dos subcadenas
|
|
if (!setVars(line.substr(0, pos), line.substr(pos + 1, line.length())))
|
|
{
|
|
// std::cout << "Warning: file " << filename.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
|
|
success = false;
|
|
}
|
|
|
|
// Crea el objeto text tan pronto como se pueda. Necesario para añadir items
|
|
if (font_png != "" && font_txt != "" && !textAllocated)
|
|
{
|
|
text = new Text(asset->get(font_png), asset->get(font_txt), renderer);
|
|
textAllocated = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cierra el fichero
|
|
// std::cout << "Closing file " << filename.c_str() << std::endl;
|
|
file.close();
|
|
}
|
|
// El fichero no se puede abrir
|
|
else
|
|
{
|
|
// std::cout << "Warning: Unable to open " << filename.c_str() << " file" << std::endl;
|
|
success = false;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// Asigna variables a partir de dos cadenas
|
|
bool Menu::setItem(item_t *item, std::string var, std::string value)
|
|
{
|
|
// Indicador de éxito en la asignación
|
|
bool success = true;
|
|
|
|
if (var == "text")
|
|
{
|
|
item->label = value;
|
|
}
|
|
|
|
else if (var == "hPaddingDown")
|
|
{
|
|
item->hPaddingDown = std::stoi(value);
|
|
}
|
|
|
|
else if (var == "selectable")
|
|
{
|
|
item->selectable = value == "true" ? true : false;
|
|
}
|
|
|
|
else if (var == "greyed")
|
|
{
|
|
item->greyed = value == "true" ? true : false;
|
|
}
|
|
|
|
else if (var == "linkedDown")
|
|
{
|
|
item->linkedDown = value == "true" ? true : false;
|
|
}
|
|
|
|
else if (var == "visible")
|
|
{
|
|
item->visible = value == "true" ? true : false;
|
|
}
|
|
|
|
else if ((var == "") || (var == "[/item]"))
|
|
{
|
|
}
|
|
|
|
else
|
|
{
|
|
success = false;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// Asigna variables a partir de dos cadenas
|
|
bool Menu::setVars(std::string var, std::string value)
|
|
{
|
|
// Indicador de éxito en la asignación
|
|
bool success = true;
|
|
|
|
if (var == "font_png")
|
|
{
|
|
font_png = value;
|
|
}
|
|
|
|
else if (var == "font_txt")
|
|
{
|
|
font_txt = value;
|
|
}
|
|
|
|
else if (var == "sound_cancel")
|
|
{
|
|
soundCancel = JA_LoadSound(asset->get(value).c_str());
|
|
}
|
|
|
|
else if (var == "sound_accept")
|
|
{
|
|
soundAccept = JA_LoadSound(asset->get(value).c_str());
|
|
}
|
|
|
|
else if (var == "sound_move")
|
|
{
|
|
soundMove = JA_LoadSound(asset->get(value).c_str());
|
|
}
|
|
|
|
else if (var == "name")
|
|
{
|
|
name = value;
|
|
}
|
|
|
|
else if (var == "x")
|
|
{
|
|
x = std::stoi(value);
|
|
}
|
|
|
|
else if (var == "centerX")
|
|
{
|
|
centerX = std::stoi(value);
|
|
}
|
|
|
|
else if (var == "centerY")
|
|
{
|
|
centerY = std::stoi(value);
|
|
}
|
|
|
|
else if (var == "y")
|
|
{
|
|
y = std::stoi(value);
|
|
}
|
|
|
|
else if (var == "backgroundType")
|
|
{
|
|
backgroundType = std::stoi(value);
|
|
}
|
|
|
|
else if (var == "backgroundColor")
|
|
{
|
|
// Se introducen los valores separados por comas en un vector
|
|
std::stringstream ss(value);
|
|
std::string tmp;
|
|
getline(ss, tmp, ',');
|
|
rectBG.color.r = std::stoi(tmp);
|
|
getline(ss, tmp, ',');
|
|
rectBG.color.g = std::stoi(tmp);
|
|
getline(ss, tmp, ',');
|
|
rectBG.color.b = std::stoi(tmp);
|
|
getline(ss, tmp, ',');
|
|
rectBG.a = std::stoi(tmp);
|
|
}
|
|
|
|
else if (var == "selector_color")
|
|
{
|
|
// Se introducen los valores separados por comas en un vector
|
|
std::stringstream ss(value);
|
|
std::string tmp;
|
|
getline(ss, tmp, ',');
|
|
selector.color.r = std::stoi(tmp);
|
|
getline(ss, tmp, ',');
|
|
selector.color.g = std::stoi(tmp);
|
|
getline(ss, tmp, ',');
|
|
selector.color.b = std::stoi(tmp);
|
|
getline(ss, tmp, ',');
|
|
selector.a = std::stoi(tmp);
|
|
}
|
|
|
|
else if (var == "selector_text_color")
|
|
{
|
|
// Se introducen los valores separados por comas en un vector
|
|
std::stringstream ss(value);
|
|
std::string tmp;
|
|
getline(ss, tmp, ',');
|
|
selector.itemColor.r = std::stoi(tmp);
|
|
getline(ss, tmp, ',');
|
|
selector.itemColor.g = std::stoi(tmp);
|
|
getline(ss, tmp, ',');
|
|
selector.itemColor.b = std::stoi(tmp);
|
|
}
|
|
|
|
else if (var == "areElementsCenteredOnX")
|
|
{
|
|
areElementsCenteredOnX = value == "true" ? true : false;
|
|
}
|
|
|
|
else if (var == "isCenteredOnX")
|
|
{
|
|
isCenteredOnX = value == "true" ? true : false;
|
|
}
|
|
|
|
else if (var == "isCenteredOnY")
|
|
{
|
|
isCenteredOnY = value == "true" ? true : false;
|
|
}
|
|
|
|
else if (var == "defaultActionWhenCancel")
|
|
{
|
|
defaultActionWhenCancel = std::stoi(value);
|
|
}
|
|
|
|
else if (var == "")
|
|
{
|
|
}
|
|
|
|
else
|
|
{
|
|
success = false;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// Carga los ficheros de audio
|
|
void Menu::loadAudioFile(std::string file, int sound)
|
|
{
|
|
switch (sound)
|
|
{
|
|
case SOUND_ACCEPT:
|
|
soundAccept = JA_LoadSound(file.c_str());
|
|
break;
|
|
|
|
case SOUND_CANCEL:
|
|
soundCancel = JA_LoadSound(file.c_str());
|
|
break;
|
|
|
|
case SOUND_MOVE:
|
|
soundMove = JA_LoadSound(file.c_str());
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Obtiene el nombre del menu
|
|
std::string Menu::getName()
|
|
{
|
|
return name;
|
|
}
|
|
|
|
// Obtiene el valor de la variable
|
|
int Menu::getItemSelected()
|
|
{
|
|
// Al llamar a esta funcion, se obtiene el valor y se borra
|
|
const int temp = itemSelected;
|
|
itemSelected = MENU_NO_OPTION;
|
|
return temp;
|
|
}
|
|
|
|
// Actualiza la posicion y el estado del selector
|
|
void Menu::updateSelector()
|
|
{
|
|
if (selector.moving)
|
|
{
|
|
// Calcula el desplazamiento en Y
|
|
selector.y += selector.despY;
|
|
if (selector.despY > 0) // Va hacia abajo
|
|
{
|
|
if (selector.y > selector.targetY) // Ha llegado al destino
|
|
{
|
|
selector.originY = selector.y = selector.targetY;
|
|
selector.moving = false;
|
|
}
|
|
}
|
|
|
|
else if (selector.despY < 0) // Va hacia arriba
|
|
{
|
|
if (selector.y < selector.targetY) // Ha llegado al destino
|
|
{
|
|
selector.originY = selector.y = selector.targetY;
|
|
selector.moving = false;
|
|
}
|
|
}
|
|
selector.rect.y = int(selector.y);
|
|
|
|
// Actualiza el color del item
|
|
selector.itemColorIndex++;
|
|
selector.itemColorIndex = std::min(selector.numJumps - 1, selector.itemColorIndex);
|
|
selector.itemColor = selector.jumpItemColors[selector.itemColorIndex];
|
|
selector.previousItemColor = selector.jumpItemColors[selector.numJumps - 1 - selector.itemColorIndex];
|
|
}
|
|
else
|
|
{
|
|
selector.rect.y = int(selector.y);
|
|
selector.itemColorIndex = 0;
|
|
selector.itemColor = selector.jumpItemColors[selector.numJumps - 1];
|
|
selector.previousItemColor = selector.jumpItemColors[0];
|
|
}
|
|
|
|
if (selector.resizing)
|
|
{
|
|
// Calcula el incremento en H
|
|
selector.h += selector.incH;
|
|
if (selector.incH > 0) // Crece
|
|
{
|
|
if (selector.h > selector.targetH) // Ha llegado al destino
|
|
{
|
|
// selector.originH = selector.targetH = selector.rect.h = getSelectorHeight(selector.index);
|
|
selector.originH = selector.h = selector.targetH;
|
|
selector.resizing = false;
|
|
}
|
|
}
|
|
|
|
else if (selector.incH < 0) // Decrece
|
|
{
|
|
if (selector.h < selector.targetH) // Ha llegado al destino
|
|
{
|
|
// selector.originH = selector.targetH = selector.rect.h = getSelectorHeight(selector.index);
|
|
selector.originH = selector.h = selector.targetH;
|
|
selector.resizing = false;
|
|
}
|
|
}
|
|
selector.rect.h = int(selector.h);
|
|
}
|
|
else
|
|
{
|
|
selector.rect.h = getSelectorHeight(selector.index);
|
|
}
|
|
}
|
|
|
|
// Coloca el selector en una posición específica
|
|
void Menu::setSelectorPos(int index)
|
|
{
|
|
if (index < (int)item.size())
|
|
{
|
|
selector.index = index;
|
|
selector.rect.y = selector.y = selector.originY = selector.targetY = item[selector.index].rect.y;
|
|
selector.rect.w = rectBG.rect.w;
|
|
selector.rect.x = rectBG.rect.x;
|
|
selector.originH = selector.targetH = selector.rect.h = getSelectorHeight(selector.index);
|
|
selector.moving = false;
|
|
selector.resizing = false;
|
|
}
|
|
}
|
|
|
|
// Obtiene la anchura del elemento más ancho del menu
|
|
int Menu::getWidestItem()
|
|
{
|
|
int result = 0;
|
|
|
|
// Obtenemos la anchura del item mas ancho
|
|
for (auto &i : item)
|
|
{
|
|
result = std::max(result, i.rect.w);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Deja el menu apuntando al primer elemento
|
|
void Menu::reset()
|
|
{
|
|
itemSelected = MENU_NO_OPTION;
|
|
selector.index = 0;
|
|
selector.originY = selector.targetY = selector.y = item[0].rect.y;
|
|
selector.originH = selector.targetH = item[0].rect.h;
|
|
selector.moving = false;
|
|
selector.resizing = false;
|
|
|
|
// Si el primer elemento no es seleccionable, incrementa el selector
|
|
if (!item[selector.index].selectable)
|
|
{
|
|
increaseSelectorIndex();
|
|
setSelectorPos(selector.index);
|
|
}
|
|
}
|
|
|
|
// Actualiza el menu para recolocarlo correctamente y establecer el tamaño
|
|
void Menu::reorganize()
|
|
{
|
|
setRectSize();
|
|
|
|
if (isCenteredOnX)
|
|
{
|
|
centerMenuOnX(centerX);
|
|
}
|
|
|
|
if (isCenteredOnY)
|
|
{
|
|
centerMenuOnY(centerY);
|
|
}
|
|
|
|
if (areElementsCenteredOnX)
|
|
{
|
|
centerMenuElementsOnX();
|
|
}
|
|
}
|
|
|
|
// Deja el menu apuntando al siguiente elemento
|
|
bool Menu::increaseSelectorIndex()
|
|
{
|
|
// Guarda el indice actual antes de modificarlo
|
|
selector.previousIndex = selector.index;
|
|
|
|
// Obten las coordenadas del elemento actual
|
|
selector.y = selector.originY = item[selector.index].rect.y;
|
|
selector.h = selector.originH = getSelectorHeight(selector.index);
|
|
|
|
// Calcula cual es el siguiente elemento
|
|
++selector.index %= item.size();
|
|
while (!item[selector.index].selectable)
|
|
{
|
|
++selector.index %= item.size();
|
|
}
|
|
|
|
// Establece las coordenadas y altura de destino
|
|
selector.targetY = item[selector.index].rect.y;
|
|
selector.despY = (selector.targetY - selector.originY) / selector.numJumps;
|
|
|
|
selector.targetH = getSelectorHeight(selector.index);
|
|
selector.incH = (selector.targetH - selector.originH) / selector.numJumps;
|
|
|
|
selector.moving = true;
|
|
if (selector.incH != 0)
|
|
{
|
|
selector.resizing = true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Deja el menu apuntando al elemento anterior
|
|
bool Menu::decreaseSelectorIndex()
|
|
{
|
|
// Guarda el indice actual antes de modificarlo
|
|
selector.previousIndex = selector.index;
|
|
|
|
// Obten las coordenadas del elemento actual
|
|
selector.y = selector.originY = item[selector.index].rect.y;
|
|
selector.h = selector.originH = getSelectorHeight(selector.index);
|
|
|
|
// Calcula cual es el siguiente elemento
|
|
if (selector.index == 0)
|
|
{
|
|
selector.index = item.size() - 1;
|
|
}
|
|
else
|
|
{
|
|
selector.index--;
|
|
}
|
|
|
|
while (!item[selector.index].selectable)
|
|
{
|
|
if (selector.index == 0)
|
|
{
|
|
selector.index = item.size() - 1;
|
|
}
|
|
else
|
|
{
|
|
selector.index--;
|
|
}
|
|
}
|
|
|
|
// Establece las coordenadas y altura de destino
|
|
selector.targetY = item[selector.index].rect.y;
|
|
selector.despY = (selector.targetY - selector.originY) / selector.numJumps;
|
|
|
|
selector.targetH = getSelectorHeight(selector.index);
|
|
selector.incH = (selector.targetH - selector.originH) / selector.numJumps;
|
|
|
|
selector.moving = true;
|
|
if (selector.incH != 0)
|
|
{
|
|
selector.resizing = true;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Actualiza la logica del menu
|
|
void Menu::update()
|
|
{
|
|
checkInput();
|
|
updateSelector();
|
|
}
|
|
|
|
// Pinta el menu en pantalla
|
|
void Menu::render()
|
|
{
|
|
// Rendereritza el fondo del menu
|
|
if (backgroundType == MENU_BACKGROUND_SOLID)
|
|
{
|
|
SDL_SetRenderDrawColor(renderer, rectBG.color.r, rectBG.color.g, rectBG.color.b, rectBG.a);
|
|
SDL_RenderFillRect(renderer, &rectBG.rect);
|
|
}
|
|
|
|
// Renderiza el rectangulo del selector
|
|
const SDL_Rect temp = {selector.rect.x, selector.rect.y - 1, selector.rect.w, selector.rect.h + 1};
|
|
SDL_SetRenderDrawColor(renderer, selector.color.r, selector.color.g, selector.color.b, selector.a);
|
|
SDL_RenderFillRect(renderer, &temp);
|
|
|
|
// Renderiza el borde del fondo
|
|
if (backgroundType == MENU_BACKGROUND_SOLID)
|
|
{
|
|
SDL_SetRenderDrawColor(renderer, rectBG.color.r, rectBG.color.g, rectBG.color.b, 255);
|
|
SDL_RenderDrawRect(renderer, &rectBG.rect);
|
|
}
|
|
|
|
// Renderiza el texto
|
|
for (int i = 0; i < (int)item.size(); ++i)
|
|
{
|
|
if (item[i].visible)
|
|
{
|
|
if (i == selector.index)
|
|
{
|
|
const color_t color = {selector.itemColor.r, selector.itemColor.g, selector.itemColor.b};
|
|
text->writeColored(item[i].rect.x, item[i].rect.y, item[i].label, color);
|
|
}
|
|
|
|
else if (i == selector.previousIndex)
|
|
{
|
|
const color_t color = {selector.previousItemColor.r, selector.previousItemColor.g, selector.previousItemColor.b};
|
|
text->writeColored(item[i].rect.x, item[i].rect.y, item[i].label, color);
|
|
}
|
|
|
|
else if (item[i].selectable)
|
|
{
|
|
text->write(item[i].rect.x, item[i].rect.y, item[i].label);
|
|
}
|
|
|
|
else if (item[i].greyed)
|
|
{
|
|
text->writeColored(item[i].rect.x, item[i].rect.y, item[i].label, colorGreyed);
|
|
}
|
|
|
|
else
|
|
{ // No seleccionable
|
|
if ((item[i].linkedUp) && (i == selector.index + 1))
|
|
{
|
|
const color_t color = {selector.itemColor.r, selector.itemColor.g, selector.itemColor.b};
|
|
text->writeColored(item[i].rect.x, item[i].rect.y, item[i].label, color);
|
|
}
|
|
else // No enlazado con el de arriba
|
|
{
|
|
text->write(item[i].rect.x, item[i].rect.y, item[i].label);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Establece el rectangulo de fondo del menu y el selector
|
|
void Menu::setRectSize(int w, int h)
|
|
{
|
|
// Establece el ancho
|
|
if (w == 0)
|
|
{ // Si no se pasa un valor, se busca si hay uno prefijado
|
|
if (this->w == 0)
|
|
{ // Si no hay prefijado, coge el item mas ancho
|
|
rectBG.rect.w = findWidth() + text->getCharacterSize();
|
|
}
|
|
else
|
|
{ // Si hay prefijado, coge ese
|
|
rectBG.rect.w = this->w;
|
|
}
|
|
}
|
|
else
|
|
{ // Si se pasa un valor, se usa y se prefija
|
|
rectBG.rect.w = w;
|
|
this->w = w;
|
|
}
|
|
|
|
// Establece el alto
|
|
if (h == 0)
|
|
{ // Si no se pasa un valor, se busca de manera automatica
|
|
rectBG.rect.h = findHeight() + text->getCharacterSize();
|
|
}
|
|
else
|
|
{ // Si se pasa un valor, se aplica
|
|
rectBG.rect.h = h;
|
|
}
|
|
|
|
// La posición X es la del menú menos medio caracter
|
|
if (this->w != 0)
|
|
{ // Si el ancho esta prefijado, la x coinccide
|
|
rectBG.rect.x = x;
|
|
}
|
|
else
|
|
{ // Si el ancho es automatico, se le da un poco de margen
|
|
rectBG.rect.x = x - (text->getCharacterSize() / 2);
|
|
}
|
|
|
|
// La posición Y es la del menu menos la altura de medio caracter
|
|
rectBG.rect.y = y - (text->getCharacterSize() / 2);
|
|
|
|
// Establecemos los valores del rectangulo del selector a partir de los valores del rectangulo de fondo
|
|
setSelectorPos(selector.index);
|
|
}
|
|
|
|
// Establece el color del rectangulo de fondo
|
|
void Menu::setBackgroundColor(color_t color, int alpha)
|
|
{
|
|
rectBG.color = color;
|
|
rectBG.a = alpha;
|
|
}
|
|
|
|
// Establece el color del rectangulo del selector
|
|
void Menu::setSelectorColor(color_t color, int alpha)
|
|
{
|
|
selector.color = color;
|
|
selector.a = alpha;
|
|
}
|
|
|
|
// Establece el color del texto del selector
|
|
void Menu::setSelectorTextColor(color_t color)
|
|
{
|
|
selector.itemColor = color;
|
|
}
|
|
|
|
// Centra el menu respecto un punto en el eje X
|
|
void Menu::centerMenuOnX(int value)
|
|
{
|
|
isCenteredOnX = true;
|
|
if (value != 0)
|
|
{
|
|
centerX = value;
|
|
}
|
|
else if (centerX == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Establece la nueva posición centrada en funcion del elemento más ancho o del ancho fijo del menu
|
|
if (w != 0)
|
|
{ // Si se ha definido un ancho fijo
|
|
x = (centerX) - (w / 2);
|
|
}
|
|
else
|
|
{ // Si se actua en función del elemento más ancho
|
|
x = (centerX) - (findWidth() / 2);
|
|
}
|
|
|
|
// Actualiza el rectangulo de fondo y del selector
|
|
rectBG.rect.x = x;
|
|
selector.rect.x = x;
|
|
|
|
// Reposiciona los elementos del menu
|
|
for (auto &i : item)
|
|
{
|
|
i.rect.x = x;
|
|
}
|
|
|
|
// Recalcula el rectangulo de fondo
|
|
setRectSize();
|
|
|
|
// Vuelve a centrar los elementos si fuera el caso
|
|
if (areElementsCenteredOnX)
|
|
{
|
|
centerMenuElementsOnX();
|
|
}
|
|
}
|
|
|
|
// Centra el menu respecto un punto en el eje Y
|
|
void Menu::centerMenuOnY(int value)
|
|
{
|
|
isCenteredOnY = true;
|
|
centerY = value;
|
|
|
|
// Establece la nueva posición centrada en funcion del elemento más ancho
|
|
y = (value) - (findHeight() / 2);
|
|
|
|
// Reposiciona los elementos del menu
|
|
replaceElementsOnY();
|
|
|
|
// Recalcula el rectangulo de fondo
|
|
setRectSize();
|
|
}
|
|
|
|
// Centra los elementos del menu en el eje X
|
|
void Menu::centerMenuElementsOnX()
|
|
{
|
|
areElementsCenteredOnX = true;
|
|
|
|
for (auto &i : item)
|
|
{
|
|
i.rect.x = (centerX - (i.rect.w / 2));
|
|
}
|
|
}
|
|
|
|
// Añade un item al menu
|
|
void Menu::addItem(std::string text, int hPaddingDown, bool selectable, bool greyed, bool linkedDown, bool visible)
|
|
{
|
|
item_t temp;
|
|
|
|
if (item.empty())
|
|
{ // Si es el primer item coge la posición en el eje Y del propio menu
|
|
temp.rect.y = y;
|
|
}
|
|
else
|
|
{ // En caso contrario, coge la posición en el eje Y a partir del último elemento
|
|
temp.rect.y = item.back().rect.y + item.back().rect.h + item.back().hPaddingDown;
|
|
}
|
|
|
|
temp.rect.x = x;
|
|
temp.hPaddingDown = hPaddingDown;
|
|
temp.selectable = selectable;
|
|
temp.greyed = greyed;
|
|
temp.linkedDown = linkedDown;
|
|
temp.visible = visible;
|
|
|
|
item.push_back(temp);
|
|
|
|
setItemCaption(item.size() - 1, text);
|
|
|
|
if (item.size() > 1)
|
|
{
|
|
if (item[item.size() - 2].linkedDown)
|
|
{
|
|
item.back().linkedUp = true;
|
|
}
|
|
}
|
|
|
|
centerX = x + (findWidth() / 2);
|
|
reorganize();
|
|
}
|
|
|
|
// Elimina un item del menu
|
|
void Menu::removeItem(int index)
|
|
{
|
|
/* POR HACER */
|
|
}
|
|
|
|
// Cambia el texto de un item
|
|
void Menu::setItemCaption(int index, std::string text)
|
|
{
|
|
item[index].label = text;
|
|
item[index].rect.w = this->text->lenght(item[index].label);
|
|
item[index].rect.h = this->text->getCharacterSize();
|
|
reorganize();
|
|
}
|
|
|
|
// Establece el indice del itemm que se usará por defecto al cancelar el menu
|
|
void Menu::setDefaultActionWhenCancel(int item)
|
|
{
|
|
defaultActionWhenCancel = item;
|
|
}
|
|
|
|
// Gestiona la entrada de teclado y mando durante el menu
|
|
void Menu::checkInput()
|
|
{
|
|
if (input->checkInput(input_up, REPEAT_FALSE))
|
|
{
|
|
if (decreaseSelectorIndex())
|
|
{
|
|
if (soundMove)
|
|
{
|
|
JA_PlaySound(soundMove);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (input->checkInput(input_down, REPEAT_FALSE))
|
|
{
|
|
if (increaseSelectorIndex())
|
|
{
|
|
if (soundMove)
|
|
{
|
|
JA_PlaySound(soundMove);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (input->checkInput(input_accept, REPEAT_FALSE))
|
|
{
|
|
itemSelected = selector.index;
|
|
if (soundAccept)
|
|
{
|
|
JA_PlaySound(soundAccept);
|
|
}
|
|
}
|
|
|
|
if (input->checkInput(input_cancel, REPEAT_FALSE))
|
|
{
|
|
itemSelected = defaultActionWhenCancel;
|
|
if (soundCancel)
|
|
{
|
|
JA_PlaySound(soundCancel);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Calcula el ancho del menu
|
|
int Menu::findWidth()
|
|
{
|
|
return getWidestItem();
|
|
}
|
|
|
|
// Calcula el alto del menu
|
|
int Menu::findHeight()
|
|
{
|
|
int height = 0;
|
|
|
|
// Obtenemos la altura de la suma de alturas de los items
|
|
for (auto &i : item)
|
|
{
|
|
height += i.rect.h + i.hPaddingDown;
|
|
}
|
|
|
|
return height - item.back().hPaddingDown;
|
|
}
|
|
|
|
// Recoloca los elementos del menu en el eje Y
|
|
void Menu::replaceElementsOnY()
|
|
{
|
|
item[0].rect.y = y;
|
|
|
|
for (int i = 1; i < (int)item.size(); i++)
|
|
{
|
|
item[i].rect.y = item[i - 1].rect.y + item[i - 1].rect.h + item[i - 1].hPaddingDown;
|
|
}
|
|
}
|
|
|
|
// Establece el estado seleccionable de un item
|
|
void Menu::setSelectable(int index, bool value)
|
|
{
|
|
item[index].selectable = value;
|
|
}
|
|
|
|
// Establece el estado agrisado de un item
|
|
void Menu::setGreyed(int index, bool value)
|
|
{
|
|
item[index].greyed = value;
|
|
}
|
|
|
|
// Establece el estado de enlace de un item
|
|
void Menu::setLinkedDown(int index, bool value)
|
|
{
|
|
item[index].linkedDown = value;
|
|
}
|
|
|
|
// Establece el estado de visibilidad de un item
|
|
void Menu::setVisible(int index, bool value)
|
|
{
|
|
item[index].visible = value;
|
|
}
|
|
|
|
// Calcula la altura del selector
|
|
int Menu::getSelectorHeight(int value)
|
|
{
|
|
if (item[value].linkedDown)
|
|
{
|
|
return item[value].rect.h + item[value].hPaddingDown + item[value + 1].rect.h;
|
|
}
|
|
else
|
|
{
|
|
return item[value].rect.h;
|
|
}
|
|
}
|
|
|
|
// Establece el nombre del menu
|
|
void Menu::setName(std::string name)
|
|
{
|
|
this->name = name;
|
|
}
|
|
|
|
// Establece la posición del menu
|
|
void Menu::setPos(int x, int y)
|
|
{
|
|
this->x = x;
|
|
this->y = y;
|
|
}
|
|
|
|
// Establece el tipo de fondo del menu
|
|
void Menu::setBackgroundType(int value)
|
|
{
|
|
backgroundType = value;
|
|
}
|
|
|
|
// Establece la fuente de texto que se utilizará
|
|
void Menu::setText(std::string font_png, std::string font_txt)
|
|
{
|
|
if (!text)
|
|
{
|
|
text = new Text(asset->get(font_png), asset->get(font_txt), renderer);
|
|
}
|
|
}
|
|
|
|
// Calcula los colores del selector para el degradado
|
|
void Menu::setSelectorItemColors()
|
|
{
|
|
const color_t colorFrom = {255, 255, 255};
|
|
const color_t colorTo = selector.itemColor;
|
|
|
|
for (int i = 0; i < selector.numJumps; ++i)
|
|
{
|
|
const float step = ((float)i / (selector.numJumps - 1));
|
|
const int r = colorFrom.r + ((colorTo.r - colorFrom.r) * step);
|
|
const int g = colorFrom.g + ((colorTo.g - colorFrom.g) * step);
|
|
const int b = colorFrom.b + ((colorTo.b - colorFrom.b) * step);
|
|
selector.jumpItemColors[i].r = r;
|
|
selector.jumpItemColors[i].g = g;
|
|
selector.jumpItemColors[i].b = b;
|
|
}
|
|
|
|
selector.itemColorIndex = 0;
|
|
} |