diff --git a/source/common/notify.cpp b/source/common/notify.cpp new file mode 100644 index 0000000..28e63ad --- /dev/null +++ b/source/common/notify.cpp @@ -0,0 +1,285 @@ +#include "notify.h" +#include +#include +#include + +// Constructor +Notify::Notify(SDL_Renderer *renderer, std::string iconFile, std::string bitmapFile, std::string textFile, std::string soundFile, options_t *options) +{ + // Inicializa variables + this->renderer = renderer; + this->options = options; + bgColor = options->notification.color; + waitTime = 300; + + // Crea objetos + iconTexture = new Texture(renderer, iconFile); + textTexture = new Texture(renderer, bitmapFile); + text = new Text(textFile, textTexture, renderer); + sound = JA_LoadSound(soundFile.c_str()); +} + +// Destructor +Notify::~Notify() +{ + // Libera la memoria de los objetos + delete textTexture; + delete iconTexture; + delete text; + JA_DeleteSound(sound); + + for (auto notification : notifications) + { + delete notification.sprite; + delete notification.texture; + } +} + +// Dibuja las notificaciones por pantalla +void Notify::render() +{ + for (int i = (int)notifications.size() - 1; i >= 0; --i) + { + notifications[i].sprite->render(); + } +} + +// Actualiza el estado de las notificaiones +void Notify::update() +{ + for (int i = 0; i < (int)notifications.size(); ++i) + { + // Si la notificación anterior está "saliendo", no hagas nada + if (i > 0) + { + if (notifications[i - 1].state == ns_rising) + { + break; + } + } + + notifications[i].counter++; + + // Hace sonar la notificación en el primer frame + if (notifications[i].counter == 1) + { + if (options->notification.sound) + { + if (notifications[i].state == ns_rising) + { // Reproduce el sonido de la notificación + JA_PlaySound(sound); + } + } + } + + // Comprueba los estados + if (notifications[i].state == ns_rising) + { + const float step = ((float)notifications[i].counter / notifications[i].travelDist); + const int alpha = 255 * step; + + if (options->notification.posV == pos_top) + { + notifications[i].rect.y++; + } + else + { + notifications[i].rect.y--; + } + notifications[i].texture->setAlpha(alpha); + + if (notifications[i].rect.y == notifications[i].y) + { + notifications[i].state = ns_stay; + notifications[i].texture->setAlpha(255); + notifications[i].counter = 0; + } + } + + else if (notifications[i].state == ns_stay) + { + if (notifications[i].counter == waitTime) + { + notifications[i].state = ns_vanishing; + notifications[i].counter = 0; + } + } + else if (notifications[i].state == ns_vanishing) + { + + const float step = (notifications[i].counter / (float)notifications[i].travelDist); + const int alpha = 255 * (1 - step); + + if (options->notification.posV == pos_top) + { + notifications[i].rect.y--; + } + else + { + notifications[i].rect.y++; + } + notifications[i].texture->setAlpha(alpha); + + if (notifications[i].rect.y == notifications[i].y - notifications[i].travelDist) + { + notifications[i].state = ns_finished; + } + } + + notifications[i].sprite->setRect(notifications[i].rect); + } + + clearFinishedNotifications(); +} + +// Elimina las notificaciones finalizadas +void Notify::clearFinishedNotifications() +{ + for (int i = (int)notifications.size() - 1; i >= 0; --i) + { + if (notifications[i].state == ns_finished) + { + delete notifications[i].sprite; + delete notifications[i].texture; + notifications.erase(notifications.begin() + i); + } + } +} + +// Muestra una notificación de texto por pantalla; +void Notify::showText(std::string text1, std::string text2, int icon) +{ + // Inicializa variables + const int iconSize = 16; + const int padding = text->getCharacterSize(); + const int iconSpace = icon >= 0 ? iconSize + padding : 0; + const std::string txt = text1.length() > text2.length() ? text1 : text2; + const int width = text->lenght(txt) + (padding * 2) + iconSpace; + const int height = (text->getCharacterSize() * 2) + (padding * 2); + + // Posición horizontal + int despH = 0; + if (options->notification.posH == pos_left) + { + despH = padding; + } + else if (options->notification.posH == pos_middle) + { + despH = ((options->video.gameWidth / 2) - (width / 2)); + } + else + { + despH = options->video.gameWidth - width - padding; + } + + // Posición vertical + int despV = 0; + if (options->notification.posV == pos_top) + { + despV = padding; + } + else + { + despV = options->video.gameHeight - height - padding; + } + + const int travelDist = height + padding; + + // Offset + int offset = 0; + if (options->notification.posV == pos_top) + { + offset = (int)notifications.size() > 0 ? notifications.back().y + travelDist : despV; + } + else + { + offset = (int)notifications.size() > 0 ? notifications.back().y - travelDist : despV; + } + + // Crea la notificacion + notification_t n; + + // Inicializa variables + n.y = offset; + n.travelDist = travelDist; + n.counter = 0; + n.state = ns_rising; + n.text1 = text1; + n.text2 = text2; + if (options->notification.posV == pos_top) + { + n.rect = {despH, offset - travelDist, width, height}; + } + else + { + n.rect = {despH, offset + travelDist, width, height}; + } + + // Crea la textura + n.texture = new Texture(renderer); + n.texture->createBlank(width, height, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET); + n.texture->setBlendMode(SDL_BLENDMODE_BLEND); + + // Prepara para dibujar en la textura + n.texture->setAsRenderTarget(renderer); + + // Dibuja el fondo de la notificación + SDL_SetRenderDrawColor(renderer, bgColor.r, bgColor.g, bgColor.b, 255); + SDL_Rect rect; + rect = {4, 0, width - (4 * 2), height}; + SDL_RenderFillRect(renderer, &rect); + + rect = {4 / 2, 1, width - 4, height - 2}; + SDL_RenderFillRect(renderer, &rect); + + rect = {1, 4 / 2, width - 2, height - 4}; + SDL_RenderFillRect(renderer, &rect); + + rect = {0, 4, width, height - (4 * 2)}; + SDL_RenderFillRect(renderer, &rect); + + // Dibuja el icono de la notificación + if (icon >= 0) + { + Sprite *sp = new Sprite({0, 0, iconSize, iconSize}, iconTexture); + sp->setPos({padding, padding, iconSize, iconSize}); + sp->setSpriteClip({iconSize * (icon % 10), iconSize * (icon / 10), iconSize, iconSize}); + sp->render(); + delete sp; + } + + // Escribe el texto de la notificación + color_t color = {255, 255, 255}; + if (text2 != "") + { // Dos lineas de texto + text->writeColored(padding + iconSpace, padding, text1, color); + text->writeColored(padding + iconSpace, padding + text->getCharacterSize() + 1, text2, color); + } + else + { // Una linea de texto + text->writeColored(padding + iconSpace, (height / 2) - (text->getCharacterSize() / 2), text1, color); + } + + // Deja de dibujar en la textura + SDL_SetRenderTarget(renderer, nullptr); + + // Crea el sprite de la notificación + n.sprite = new Sprite(n.rect, n.texture, renderer); + + // Deja la notificación invisible + n.texture->setAlpha(0); + + // Añade la notificación a la lista + notifications.push_back(n); +} + +// Indica si hay notificaciones activas +bool Notify::active() +{ + if ((int)notifications.size() > 0) + { + return true; + } + + return false; +} \ No newline at end of file diff --git a/source/common/notify.h b/source/common/notify.h new file mode 100644 index 0000000..d73a0b6 --- /dev/null +++ b/source/common/notify.h @@ -0,0 +1,87 @@ +#pragma once + +#include +#include "jail_audio.h" +#include "sprite.h" +#include "text.h" +#include "texture.h" +#include "utils.h" +#include + +#ifndef NOTIFY_H +#define NOTIFY_H + +class Notify +{ +private: + enum notification_state_e + { + ns_rising, + ns_stay, + ns_vanishing, + ns_finished + }; + + enum notification_position_e + { + upperLeft, + upperCenter, + upperRight, + middleLeft, + middleRight, + bottomLeft, + bottomCenter, + bottomRight + }; + + struct notification_t + { + std::string text1; + std::string text2; + int counter; + notification_state_e state; + notification_position_e position; + Texture *texture; + Sprite *sprite; + SDL_Rect rect; + int y; + int travelDist; + }; + + // Objetos y punteros + SDL_Renderer *renderer; // El renderizador de la ventana + Texture *textTexture; // Textura para la fuente de las notificaciones + Texture *iconTexture; // Textura para los iconos de las notificaciones + Text *text; // Objeto para dibujar texto + options_t *options; // Variable con todas las opciones del programa + + // Variables + color_t bgColor; // Color de fondo de las notificaciones + int waitTime; // Tiempo que se ve la notificación + std::vector notifications; // La lista de notificaciones activas + JA_Sound_t *sound; // Sonido a reproducir cuando suena la notificación + + // Elimina las notificaciones finalizadas + void clearFinishedNotifications(); + +public: + // Dibuja las notificaciones por pantalla + void render(); + + // Actualiza el estado de las notificaiones + void update(); + + // Constructor + Notify(SDL_Renderer *renderer, std::string iconFile, std::string bitmapFile, std::string textFile, std::string soundFile, options_t *options); + + // Destructor + ~Notify(); + + // Muestra una notificación de texto por pantalla; + void showText(std::string text1 = "", std::string text2 = "", int icon = -1); + + // Indica si hay notificaciones activas + bool active(); +}; + +#endif