From ac0d35e053570892e6dd610e73b66fe575347e58 Mon Sep 17 00:00:00 2001
From: Tim Schubert <tim.schubert@tu-bs.de>
Date: Sun, 24 Jan 2016 02:41:50 +0100
Subject: [PATCH] Fix rendering of Gui.

---
 src/Bob.cpp        |  50 ++++++++++++++-----
 src/Bob.hpp        |  35 ++++++++------
 src/Events.cpp     |   9 +++-
 src/Events.hpp     |  27 ++++++++---
 src/Exceptions.hpp |  35 ++++++++------
 src/Gameplay.cpp   |  10 +---
 src/Gameplay.hpp   |  74 +++++++++-------------------
 src/Grid.hpp       |   8 ++-
 src/Gui.cpp        | 118 +++++++++++++++++++++------------------------
 src/Gui.hpp        |  89 +++++++++++++++-------------------
 10 files changed, 228 insertions(+), 227 deletions(-)

diff --git a/src/Bob.cpp b/src/Bob.cpp
index f5fb1bb..a4ecd18 100644
--- a/src/Bob.cpp
+++ b/src/Bob.cpp
@@ -92,22 +92,18 @@ int Game::game_loop()
             SDL_Point move_by = {(this->move[1] - this->move[3]) * 20, (this->move[0] - this->move[2]) * 20};
             this->grid->move(move_by);
         }
-        if (frame_timer->get_timer() > 1000.0)
+        if (frame_timer->get_timer() > 255)
         {
             fps = frame_counter / (frame_timer->reset_timer() / 1000.0);
             frame_counter = 0;
-            std::cout << fps << " fps" << std::endl;
+            this->test_box->load_text(std::to_string(fps));
         }
         SDL_Event event;
         while (SDL_PollEvent(&event))
         {
             this->handle_event(&event);
         }
-        this->renderer->set_draw_color({0x0, 0x0, 0x0, 0xf});
-        this->renderer->clear();
-        this->renderer->set_draw_color({0xff, 0xff, 0xff, 0xff});
         this->render();
-        this->renderer->present();
         frame_counter++;
     }
     this->renderer->clear();
@@ -116,21 +112,53 @@ int Game::game_loop()
 
 void Game::render()
 {
-    SDL_Renderer *renderer = this->renderer->get_renderer();
-    this->grid->render(renderer);
+    try
+    {
+        this->renderer->set_draw_color({0x0, 0x0, 0x0, 0x0});
+        this->renderer->clear();
+        this->grid->render(this->renderer->get_renderer());
+        this->side_bar->render(this->renderer);
+        this->renderer->present();
+    }
+    catch (const SDL_RendererException &err)
+    {
+        std::cerr << "Failed to render: " << err.what() << std::endl;
+    }
+}
+
+void init_sdl(Uint32 flags)
+{
+    if (SDL_Init(flags) != 0)
+    {
+        throw SDL_Exception("Failed to initialize SDL!");
+    }
+}
+
+void init_ttf()
+{
+    if (TTF_Init() == -1)
+    {
+        throw SDL_TTFException();
+    }
 }
 
 int main(int, char **)
 {
-    if (SDL_Init(SDL_INIT_VIDEO) != 0)
+    try
     {
-        logSDLError(std::cerr, "SDL_init");
+        init_sdl(SDL_INIT_VIDEO);
+        init_ttf();
+    }
+    catch (const SDL_Exception &sdl_err)
+    {
+        std::cerr << sdl_err.what() << std::endl;
+        SDL_Quit();
     }
-//    register_events(4);
     SDL_Rect window_dimensions = {SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGTH};
     Game *game = new Game(&window_dimensions, 6);
     int exit_status = game->game_loop();
     delete game;
+    TTF_Quit();
     SDL_Quit();
     return exit_status;
 }
\ No newline at end of file
diff --git a/src/Bob.hpp b/src/Bob.hpp
index 555c243..e0a6ddf 100644
--- a/src/Bob.hpp
+++ b/src/Bob.hpp
@@ -6,7 +6,7 @@
 #include <unordered_set>
 #include "Exceptions.hpp"
 #include "Gameplay.hpp"
-//#include "Events.hpp"
+#include "Events.hpp"
 #include "Gui.hpp"
 
 #ifndef _BOB_H
@@ -17,24 +17,13 @@ const int SCREEN_HEIGTH = 600;
 const int SIDEBAR_WIDTH = 200;
 const std::string TITLE = "Bob - Battles of Bacteria";
 
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-Uint32 rmask = 0xff000000;
-Uint32 gmask = 0x00ff0000;
-Uint32 bmask = 0x0000ff00;
-Uint32 amask = 0x000000ff;
-#else
-Uint32 rmask = 0x000000ff;
-Uint32 gmask = 0x0000ff00;
-Uint32 bmask = 0x00ff0000;
-Uint32 amask = 0xff000000;
-#endif
-
 class Game
 {
 
 public:
     Game(SDL_Rect *window_dimensions, Sint16 size)
     {
+        this->event_context = new EventContext(4);
         this->layout = new Layout(pointy_orientation, size,
                                   {window_dimensions->w / 2, window_dimensions->h / 2},
                                   {0, 0, window_dimensions->w - SIDEBAR_WIDTH, window_dimensions->h});
@@ -46,10 +35,19 @@ public:
         this->quit = false;
         try
         {
+
+            this->font = load_font_from_file("/usr/share/fonts/dejavu/DejaVuSans.ttf", 12);
             this->window = new Window(TITLE, window_dimensions, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
-            this->renderer = new Renderer(this->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
+            this->renderer = new Renderer(this->window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
+                                                            | SDL_RENDERER_TARGETTEXTURE);
             SDL_Rect side_bar_dimensions = {window_dimensions->x - SIDEBAR_WIDTH, 0, SIDEBAR_WIDTH,
                                             window_dimensions->y};
+            this->side_bar = new Container(this->window, this->renderer, side_bar_dimensions);
+            this->test_box = new TextBox(this->renderer,
+                                         {SCREEN_WIDTH - SIDEBAR_WIDTH, 0, SIDEBAR_WIDTH, SCREEN_HEIGTH},
+                                         {0x00, 0xff, 0x00, 0xff}, this->font);
+            this->side_bar->add(test_box);
+            this->side_bar->set_visible(true);
         }
         catch (const SDL_Exception &sdl_except)
         {
@@ -61,13 +59,15 @@ public:
 
     ~Game()
     {
+        delete this->test_box;
         delete this->move_timer;
         delete this->frame_timer;
-        //       delete this->side_bar;
+        delete this->side_bar;
         delete this->grid;
         delete this->renderer;
         delete this->window;
         delete this->layout;
+        delete this->event_context;
     }
 
     void render();
@@ -77,11 +77,14 @@ public:
     int game_loop();
 
 private:
+    EventContext *event_context;
+    TextBox *test_box;
+    TTF_Font *font;
     Window *window;
     Renderer *renderer;
     HexagonGrid *grid;
     Layout *layout;
-    //   SideBar *side_bar;
+    Container *side_bar;
     bool move[4];
     bool quit;
     Timer *frame_timer;
diff --git a/src/Events.cpp b/src/Events.cpp
index 5dc04c5..6118f1f 100644
--- a/src/Events.cpp
+++ b/src/Events.cpp
@@ -18,7 +18,12 @@ Uint32 Timer::reset_timer()
     return ticks_passed;
 }
 
-Uint32 register_events(Uint32 n)
+Uint32 EventContext::register_events(Uint32 num_events)
 {
-    return SDL_RegisterEvents(n);
+    return SDL_RegisterEvents(num_events);
+}
+
+Uint32 EventContext::get_event(Bob_Event event)
+{
+    return this->base_event + event;
 }
\ No newline at end of file
diff --git a/src/Events.hpp b/src/Events.hpp
index f8a99ad..1b49fb4 100644
--- a/src/Events.hpp
+++ b/src/Events.hpp
@@ -6,6 +6,26 @@
 #ifndef _EVENTS_H
 #define _EVENTS_H
 
+class EventContext
+{
+public:
+    enum Bob_Event
+    {
+        Bob_NextTurnEvent,
+        Bob_FieldUpdateEvent
+    };
+
+    EventContext(Uint32 num_events)
+            : base_event(register_events(num_events)) { }
+
+    Uint32 get_event(Bob_Event event);
+
+private:
+    const Uint32 base_event;
+
+    static Uint32 register_events(Uint32 n);
+};
+
 class Timer
 {
 private:
@@ -24,16 +44,9 @@ struct NextTurn
     Uint32 time_elapsed;
 };
 
-struct MarkerUpdate
-{
-    FieldMeta *field;
-};
-
 struct FieldUpdate
 {
     FieldMeta *field;
 };
 
-Uint32 register_events(Uint32 n);
-
 #endif
\ No newline at end of file
diff --git a/src/Exceptions.hpp b/src/Exceptions.hpp
index 198aacd..ad17fee 100644
--- a/src/Exceptions.hpp
+++ b/src/Exceptions.hpp
@@ -1,42 +1,47 @@
 #include <stdexcept>
+#include <SDL2/SDL_ttf.h>
 
 #ifndef BOB_EXCEPTIONS_H
 #define BOB_EXCEPTIONS_H
 
-class SDL_Exception : public std::exception
+class SDL_Exception : public std::runtime_error
 {
 public:
-    virtual const char *what() const throw()
+    SDL_Exception(const std::string &what_arg)
+            : std::runtime_error(what_arg) { }
+
+    const char *what() const noexcept
     {
-        return "SDL_Exception";
+        return SDL_GetError();
     }
 };
 
 class SDL_WindowException : public SDL_Exception
 {
 public:
-    virtual const char *what() const throw()
-    {
-        return "SDL_WindowException";
-    }
+    SDL_WindowException()
+            : SDL_Exception("SDL_WindowException") { }
 };
 
 class SDL_RendererException : public SDL_Exception
 {
 public:
-    virtual const char *what() const throw()
-    {
-        return "SDL_RendererException";
-    }
+    SDL_RendererException()
+            : SDL_Exception("SDL_RendererException") { }
 };
 
 class SDL_TextureException : public SDL_Exception
 {
 public:
-    virtual const char *what() const throw()
-    {
-        return "SDL_TextureException";
-    }
+    SDL_TextureException()
+            : SDL_Exception("SDL_TextureException") { }
+};
+
+class SDL_TTFException : public SDL_Exception
+{
+public:
+    SDL_TTFException()
+            : SDL_Exception("SDL_TTFException") { }
 };
 
 #endif //BOB_EXCEPTIONS_H
diff --git a/src/Gameplay.cpp b/src/Gameplay.cpp
index e1aeb8d..a6b4fc2 100644
--- a/src/Gameplay.cpp
+++ b/src/Gameplay.cpp
@@ -15,7 +15,7 @@ void FieldMeta::render(SDL_Renderer *renderer, Layout *layout)
         vx[i] = (Sint16) polygon[i].x;
         vy[i] = (Sint16) polygon[i].y;
     }
-    if (this->owner == this->grid->get_default_player())
+    if (*(this->owner) == Player())
         color = {0x77, 0x77, 0x77, 0x77};
     filledPolygonRGBA(renderer, vx, vy, 6, color.r, color.g, color.b, 0x33);
     SDL_Color inverse;
@@ -161,7 +161,7 @@ bool Player::fight(FieldMeta *field)
     {
         return false;
     }
-    if (field->get_owner() == field->get_grid()->get_default_player()) // still to be had
+    if (*(field->get_owner()) == Player()) // still to be had
     {
         field->set_owner(this);
         return true;
@@ -324,9 +324,3 @@ void Grid::update_box(SDL_Point dimensions)
     this->layout->box.w = dimensions.x;
     this->layout->box.h = dimensions.y;
 }
-
-std::ostream &operator<<(std::ostream &os, const Field &rhs)
-{
-    os << "(" << rhs.x << "," << rhs.y << ",";
-    return os;
-}
diff --git a/src/Gameplay.hpp b/src/Gameplay.hpp
index 38b80a4..59b2794 100644
--- a/src/Gameplay.hpp
+++ b/src/Gameplay.hpp
@@ -5,6 +5,7 @@
 #include <unordered_map>
 #include <boost/uuid/uuid.hpp>
 #include <boost/uuid/uuid_generators.hpp>
+#include <boost/random/mersenne_twister.hpp>
 #include <SDL2/SDL_pixels.h>
 #include <SDL2/SDL_render.h>
 #include <bitset>
@@ -152,67 +153,29 @@ const std::unordered_map<Upgrade, Resource> UPGRADE_COSTS(
         }
 );
 
-class Tagged
-{
-private:
-    boost::uuids::uuid tag;
-
-    int state;
-public:
-    // construct new
-    Tagged()
-            : tag(boost::uuids::random_generator()()), state(0) { }
-
-    // construct with state
-    explicit Tagged(int state)
-            : tag(boost::uuids::random_generator()()), state(state) { }
-
-    // clone
-    Tagged(Tagged const &rhs)
-            : tag(rhs.tag), state(rhs.state) { }
-
-    bool operator==(Tagged const &rhs) const
-    {
-        return tag == rhs.tag;
-    }
-
-    bool operator!=(Tagged const &rhs) const
-    {
-        return !(tag == rhs.tag);
-    }
-
-    int get_state() const { return state; }
-
-    void set_state(int new_state) { state = new_state; }
-
-    boost::uuids::uuid get_tag() { return tag; }
-
-    void set_tag(boost::uuids::uuid uuid_) { tag = uuid_; }
-};
-
-class Player;
-
 class FieldMeta;
 
-class Player : public Tagged
+class Player
 {
 
 public:
+    Player()
+            : name("Default Player"), uuid(boost::uuids::nil_uuid()) { }
     Player(std::string name_)
-            : name(name_), Tagged()
+            : name(name_), uuid(boost::uuids::basic_random_generator<boost::mt19937>()())
     {
         // use the last 24 bits of the tag for the color
-        boost::uuids::uuid id = get_tag();
+        boost::uuids::uuid id = this->uuid;
         uint8_t *data = id.data;
         this->color = {data[13], data[14], data[15], 0xff};
     }
 
-    SDL_Color get_color() { return color; }
+    SDL_Color get_color() { return this->color; }
 
     std::string get_name()
     {
         std::ostringstream descriptor;
-        boost::uuids::uuid id = get_tag();
+        boost::uuids::uuid id = this->uuid;
         uint8_t *data = id.data;
         Uint16 number = (data[14] << 8) | (data[15]);
         descriptor << this->name << " (" << std::hex << number << ")";
@@ -221,7 +184,15 @@ public:
 
     bool fight(FieldMeta *field);
 
+    boost::uuids::uuid get_id() { return this->uuid; }
+
+    bool operator==(const Player &rhs) const
+    {
+        return rhs.uuid == this->uuid;
+    }
+
 private:
+    boost::uuids::uuid uuid;
     SDL_Color color;
     std::string name;
 };
@@ -297,8 +268,8 @@ public:
     {
         Field f = {0, 0, 0};
         std::unordered_map<Field, FieldMeta *> fields = std::unordered_map<Field, FieldMeta *>();
-        this->default_player = new Player("Default");
-        this->marker = new FieldMeta(f, default_player);
+        this->default_player = new Player();
+        this->marker = new FieldMeta(f, this->default_player);
     };
 
     ~Grid()
@@ -307,10 +278,9 @@ public:
         {
             delete elem.second;
         }
+        delete this->default_player;
     }
 
-    Player *get_default_player() { return this->default_player; }
-
     void move(SDL_Point move);
 
     void update_marker();
@@ -332,12 +302,11 @@ public:
     FieldMeta *point_to_field(const Point p);
 
 protected:
-    Player *default_player;
     std::unordered_map<Field, FieldMeta *> fields;
     Layout *layout;
     FieldMeta *marker;
     bool panning;
-
+    Player *default_player;
     bool on_rectangle(SDL_Rect *rect);
 };
 
@@ -356,7 +325,7 @@ public:
             {
                 Sint16 z = -x - y;
                 Field new_field = {x, y, z};
-                FieldMeta *meta = new FieldMeta(new_field, default_player);
+                FieldMeta *meta = new FieldMeta(new_field, this->default_player);
                 this->fields.insert({new_field, meta});
             }
         }
@@ -374,4 +343,5 @@ private:
     Sint16 radius;
 };
 
+
 #endif
diff --git a/src/Grid.hpp b/src/Grid.hpp
index 1036f1c..64aebaf 100644
--- a/src/Grid.hpp
+++ b/src/Grid.hpp
@@ -280,8 +280,6 @@ struct Field
         return (abs(this->x - rhs.x) + abs(this->y - rhs.y) + abs(this->z - rhs.z)) / 2;
     }
 
-    friend std::ostream &operator<<(std::ostream &os, const Field &rhs);
-
     Field get_neighbor(Uint8 direction) const;
 
     Point field_to_point(const Layout *layout) const;
@@ -318,4 +316,10 @@ namespace std
     };
 }
 
+inline std::ostream &operator<<(std::ostream &os, const Field &rhs)
+{
+    os << "(" << rhs.x << "," << rhs.y << ",";
+    return os;
+}
+
 #endif
diff --git a/src/Gui.cpp b/src/Gui.cpp
index a403c75..5a4bcd1 100644
--- a/src/Gui.cpp
+++ b/src/Gui.cpp
@@ -1,67 +1,52 @@
 #include "Gui.hpp"
 
-TTF_Font *load_font_from_file(std::string path_to_file)
+SDL_Color operator!(const SDL_Color &color)
 {
-    TTF_Font *font = TTF_OpenFont(path_to_file.c_str(), 12); // what about memory leaks?
+    Uint8 r = (Uint8) 0xff - color.r;
+    Uint8 g = (Uint8) 0xff - color.g;
+    Uint8 b = (Uint8) 0xff - color.b;
+    Uint8 a = (Uint8) 0xff - color.a;
+    return {r, g, b, a};
+}
+
+TTF_Font *load_font_from_file(std::string path_to_file, int size)
+{
+    TTF_Font *font = TTF_OpenFontIndex(path_to_file.c_str(), size, 0);
     if (font == nullptr)
     {
-        std::cerr << "Failed to load TTF!" << TTF_GetError() << std::endl;
-        return font;
+        throw SDL_TTFException();
     }
     return font;
 }
 
-bool TextInfoBox::load_text(std::string text)
+bool TextBox::load_text(std::string text)
 {
-    SDL_DestroyTexture(this->texture);
-    SDL_Surface *surface = TTF_RenderUTF8_Solid(this->font, text.c_str(), color);
-    if (surface == nullptr)
+    SDL_Surface *surface = TTF_RenderUTF8_Solid(this->font, text.c_str(), {0xff, 0xff, 0xff, 0xff});
+    if (surface == nullptr || TTF_SizeUTF8(this->font, text.c_str(), &(this->dimensions.w), &(this->dimensions.h)))
     {
-        std::cerr << "Unable to render text to surface! " << TTF_GetError() << std::endl;
+        SDL_FreeSurface(surface);
+        throw SDL_TTFException();
     }
     else if (surface->w > this->dimensions.w || surface->h > this->dimensions.h)
     {
-        std::cerr << "Overfull TextBox!" << SDL_GetError() << std::endl;
+        std::cerr << "Overfull TextBox!" << std::endl;
     }
-    else
+    if (this->texture != nullptr)
     {
-        this->create_texture_from_surface(surface);
+        SDL_DestroyTexture(this->texture);
     }
-    SDL_FreeSurface(surface);
-    return (this->texture != nullptr);
-}
-
-
-bool InfoBox::create_texture_from_surface(SDL_Surface *surface)
-{
     SDL_SetRenderTarget(this->renderer->get_renderer(), this->texture);
     this->texture = SDL_CreateTextureFromSurface(this->renderer->get_renderer(), surface);
+    SDL_FreeSurface(surface);
     if (this->texture == nullptr)
     {
-        std::cerr << "Unable to render texture from surface!" << SDL_GetError() << std::endl;
+        SDL_DestroyTexture(this->texture);
+        throw SDL_TextureException();
     }
     SDL_SetRenderTarget(this->renderer->get_renderer(), nullptr); // reset the render target
     return (this->texture != nullptr);
 }
 
-bool InfoBox::render(SDL_Renderer *renderer, const SDL_Rect target)
-{
-    if (this->visible)
-    {
-        if (!SDL_RenderCopy(renderer, this->texture, &(this->dimensions), &target))
-        {
-            std::cerr << "Failed to render TextBox Texture!" << SDL_GetError() << std::endl;
-            return false;
-        }
-    }
-    return true;
-}
-
-void logSDLError(std::ostream &os, const std::string &msg)
-{
-    os << msg << " error:" << SDL_GetError() << std::endl;
-}
-
 SDL_Point Window::toggle_fullscreen()
 {
     SDL_DisplayMode dm;
@@ -111,17 +96,17 @@ void Renderer::present()
     SDL_RenderPresent(this->renderer);
 }
 
-void TextInfoBox::handle_event(const SDL_Event *event)
+void TextBox::handle_event(const SDL_Event *event, EventContext *context)
 {
 }
 
-void SideBar::handle_event(const SDL_Event *event)
+void FieldBox::handle_event(const SDL_Event *event, EventContext *context)
 {
     std::ostringstream output;
     Cluster *cluster = this->field->get_grid()->get_cluster(this->field);
     Resource cluster_resources = this->field->get_grid()->get_resources_of_cluster(cluster);
     Resource field_resources = this->field->get_resources();
-    MarkerUpdate *update = (MarkerUpdate *) event->user.data1;
+    FieldUpdate *update = (FieldUpdate *) event->user.data1;
 /*    switch (event->type)
     {
         case (BOB_FIELD_UPDATE_EVENT):
@@ -139,36 +124,41 @@ void SideBar::handle_event(const SDL_Event *event)
     }*/
 }
 
-void FieldInfoBox::handle_event(const SDL_Event *event)
+void ButtonInfoBox::handle_event(const SDL_Event *event, EventContext *context)
 {
-}
-
-void ButtonInfoBox::handle_event(const SDL_Event *event)
-{
-    switch (event->type)
-    {
-        case (SDL_MOUSEBUTTONDOWN):
-            this->upgrade_box->set_visible(!(this->upgrade_box->get_visible()));
-            break;
-        default:
-            break;
-    }
 };
 
-void UpgradeInfoBox::handle_event(const SDL_Event *event)
+void UpgradeBox::handle_event(const SDL_Event *event, EventContext *context)
 {
-    TextInfoBox::handle_event(event);
 }
 
-void SideBar::render(SDL_Renderer *renderer)
+void Box::handle_event(const SDL_Event *event, EventContext *context)
 {
-    SDL_Rect f_dimensions = this->field_info->get_dimensions();
-    this->field_info->render(renderer, {this->dimensions.x, this->dimensions.y, f_dimensions.w, f_dimensions.h});
-    for (auto &elem : *upgrades_list)
+}
+
+void Container::render(Renderer *renderer)
+{
+    for (auto info_box : this->elements)
     {
-        f_dimensions = elem->get_dimensions();
-        elem->render(renderer, {this->dimensions.x, this->dimensions.y, f_dimensions.w, f_dimensions.h});
+        info_box->render(renderer);
+    }
+}
+
+void Box::render(Renderer *ext_renderer)
+{
+    if (this->visible && this->texture != nullptr)
+    {
+        if (SDL_RenderCopy(ext_renderer->get_renderer(), this->texture, nullptr, &(this->dimensions)) < 0)
+        {
+            throw SDL_RendererException();
+        }
+    }
+}
+
+void Container::set_visible(bool visible)
+{
+    for (auto box : this->elements)
+    {
+        box->set_visible(visible);
     }
-    f_dimensions = this->upgrade_info->get_dimensions();
-    this->upgrade_info->render(renderer, {this->dimensions.x, this->dimensions.y, f_dimensions.w, f_dimensions.h});
 }
\ No newline at end of file
diff --git a/src/Gui.hpp b/src/Gui.hpp
index d56445b..864ffe5 100644
--- a/src/Gui.hpp
+++ b/src/Gui.hpp
@@ -13,7 +13,7 @@
 #ifndef _GUI_H
 #define _GUI_H
 
-void logSDLError(std::ostream &os, const std::string &msg);
+SDL_Color operator!(const SDL_Color &color);
 
 class Window
 {
@@ -78,56 +78,44 @@ private:
     SDL_Renderer *renderer;
 };
 
-class InfoBox
+class Box
 {
 public:
-    InfoBox(Renderer *renderer_, SDL_Rect dimensions_, SDL_Color color_)
+    Box(Renderer *renderer_, SDL_Rect dimensions_, SDL_Color color_)
             : renderer(renderer_), color(color_), dimensions(dimensions_)
     {
-        this->texture = SDL_CreateTexture(renderer->get_renderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
-                                          dimensions.w, dimensions.h);
-        if (this->texture == nullptr)
-        {
-            SDL_DestroyTexture(texture);
-            throw SDL_TextureException();
-        }
+        this->texture = nullptr;
         this->visible = false;
     }
 
-    ~InfoBox()
+    ~Box()
     {
-        SDL_DestroyTexture(texture);
+        SDL_DestroyTexture(this->texture);
     }
 
-    virtual void handle_event(const SDL_Event *event) const = 0;
+    virtual void handle_event(const SDL_Event *event, EventContext *context);
 
-    bool render(SDL_Renderer *renderer, const SDL_Rect target);
+    virtual void render(Renderer *renderer);
 
     void set_visible(bool visibility) { this->visible = visibility; }
 
-    bool get_visible() { return this->visible; }
-
-    SDL_Renderer *get_renderer() { return this->renderer->get_renderer(); }
-
     SDL_Rect get_dimensions() { return this->dimensions; }
 
 protected:
-    SDL_Rect dimensions;
-    SDL_Texture *texture; // buffered texture
     Renderer *renderer;
+    SDL_Texture *texture;
+    SDL_Rect dimensions;
     SDL_Color color;
     bool visible;
-
-    bool create_texture_from_surface(SDL_Surface *surface);
 };
 
-class TextInfoBox : public InfoBox
+class TextBox : public Box
 {
 public:
-    TextInfoBox(Renderer *renderer, SDL_Rect dimensions, SDL_Color color, TTF_Font *font_)
-            : InfoBox(renderer, dimensions, color), font(font_) { }
+    TextBox(Renderer *renderer, SDL_Rect dimensions, SDL_Color color, TTF_Font *font_)
+            : Box(renderer, dimensions, color), font(font_) { }
 
-    virtual void handle_event(const SDL_Event *event);
+    virtual void handle_event(const SDL_Event *event, EventContext *context);
 
     bool load_text(std::string text);
 
@@ -135,60 +123,61 @@ protected:
     TTF_Font *font;
 };
 
-class FieldInfoBox : public TextInfoBox
+class FieldBox : public TextBox
 {
 public:
-    FieldInfoBox(Renderer *renderer, SDL_Rect dimensions, FieldMeta *field_, SDL_Color color, TTF_Font *font)
-            : TextInfoBox(renderer, dimensions, color, font), field(field_) { }
+    FieldBox(Renderer *renderer, SDL_Rect dimensions, SDL_Color color, TTF_Font *font, FieldMeta *field_)
+            : TextBox(renderer, dimensions, color, font), field(field_) { }
 
-    void handle_event(const SDL_Event *event);
+    void handle_event(const SDL_Event *event, EventContext *context);
 
 private:
     FieldMeta *field;
 };
 
-class UpgradeInfoBox : public TextInfoBox
+class UpgradeBox : public TextBox
 {
 public:
-    UpgradeInfoBox(Renderer *renderer, SDL_Rect dimensions, FieldMeta *field_, SDL_Color color, TTF_Font *font)
-            : TextInfoBox(renderer, dimensions, color, font) { }
+    UpgradeBox(Renderer *renderer, SDL_Rect dimensions, FieldMeta *field_, SDL_Color color, TTF_Font *font)
+            : TextBox(renderer, dimensions, color, font) { }
 
-    void handle_event(const SDL_Event *event);
+    void handle_event(const SDL_Event *event, EventContext *context);
 };
 
-class ButtonInfoBox : public TextInfoBox
+class ButtonInfoBox : public TextBox
 {
 public:
     ButtonInfoBox(Renderer *renderer, SDL_Rect dimensions, FieldMeta *field_, SDL_Color color, TTF_Font *font,
-                  UpgradeInfoBox *upgrade_box_)
-            : TextInfoBox(renderer, dimensions, color, font), upgrade_box(upgrade_box_) { }
+                  UpgradeBox *upgrade_box_)
+            : TextBox(renderer, dimensions, color, font), upgrade_box(upgrade_box_) { }
 
-    void handle_event(const SDL_Event *event);
+    void handle_event(const SDL_Event *event, EventContext *context);
 
 private:
-    UpgradeInfoBox *upgrade_box;
+    UpgradeBox *upgrade_box;
 };
 
-class SideBar
+class Container
 {
 public:
-    SideBar(Renderer *renderer, SDL_Rect dimensions_, SDL_Color color)
-            : dimensions(dimensions_)
+    Container(Window *window_, Renderer *renderer_, SDL_Rect dimensions_)
+            : window(window_), renderer(renderer_)
     {
+        this->elements = std::vector<Box *>();
     }
 
-    void handle_event(const SDL_Event *event);
+    void add(Box *box) { this->elements.push_back(box); }
 
-    void render(SDL_Renderer *renderer);
+    void render(Renderer *renderer);
+
+    void set_visible(bool visible);
 
 private:
-    SDL_Rect dimensions;
-    FieldMeta *field;
-    FieldInfoBox *field_info;
-    std::vector<ButtonInfoBox *> *upgrades_list;
-    UpgradeInfoBox *upgrade_info;
+    Window *window;
+    Renderer *renderer;
+    std::vector<Box *> elements;
 };
 
-TTF_Font *load_font_from_file(std::string path_to_file);
+TTF_Font *load_font_from_file(std::string path_to_file, int size);
 
 #endif
\ No newline at end of file