diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b87b12..46ec3ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ project(ptf) # Inclusion des fichiers d'en-tête et de source include_directories(include) -file(GLOB SOURCES "src/*.cpp" "src/*.c") +file(GLOB SOURCES "src/*.cpp" "src/*.c" "src/util/*.cpp") # Affichage de tous les avertisements if(MSVC) diff --git a/include/block.hpp b/include/block.hpp index bdc7c9e..7a24a1b 100644 --- a/include/block.hpp +++ b/include/block.hpp @@ -17,10 +17,15 @@ public: Block(); virtual ~Block(); + /** + * Clone cet objet en un objet avec les mêmes propriétés + */ + virtual ObjectPtr clone() const; + /** * Chargement de l'objet depuis le fichier donné */ - static std::shared_ptr load(std::ifstream& file); + static ObjectPtr load(std::ifstream& file); /** * Dessin du bloc dans la fenêtre donnée diff --git a/include/editor.hpp b/include/editor.hpp index a79dc14..c131746 100644 --- a/include/editor.hpp +++ b/include/editor.hpp @@ -1,8 +1,9 @@ -#ifndef __PTF_GAME_HPP__ -#define __PTF_GAME_HPP__ +#ifndef __PTF_EDITOR_HPP__ +#define __PTF_EDITOR_HPP__ #include #include "level.hpp" +#include "util/widget_timer.hpp" /** * La classe Editor permet l'édition de @@ -11,6 +12,7 @@ class Editor : public Level { private: std::unordered_map selection; + WidgetTimer widget_timer; /** * Ajoute un objet du type actuel à la position donnée @@ -30,6 +32,11 @@ private: */ bool updateSelection(sf::Vector2f position); + /** + * Lance le test du niveau + */ + void testLevel(); + protected: /** * Dessine tous les objets, le fond et diff --git a/include/game.hpp b/include/game.hpp index 559af1d..e242a18 100644 --- a/include/game.hpp +++ b/include/game.hpp @@ -2,6 +2,7 @@ #define __PTF_GAME_HPP__ #include "level.hpp" +#include "editor.hpp" /** * La classe Game gère l'affichage et les objets @@ -9,7 +10,10 @@ */ class Game : public Level { private: + WidgetTimer widget_timer; sf::Time next_frame_time; + bool test_mode; + std::shared_ptr return_view; /** * Met à jour les objets du jeu pour @@ -17,6 +21,13 @@ private: */ void update(); +protected: + /** + * Dessine tous les objets, le fond et + * l'interface de jeu + */ + virtual void draw(); + public: Game(Manager& manager); virtual ~Game(); @@ -31,6 +42,12 @@ public: * cette vue */ void frame(); + + /** + * Mise en mode test : l'appui sur espace renvoie + * vers l'éditeur donné + */ + void setTestMode(std::shared_ptr set_return_view); }; #endif diff --git a/include/level.hpp b/include/level.hpp index c158c83..c6b3bc6 100644 --- a/include/level.hpp +++ b/include/level.hpp @@ -15,7 +15,7 @@ */ class Level : public View { private: - std::string name; + sf::String name; int total_time; sf::Sprite background; @@ -45,23 +45,33 @@ public: /** * Récupère le nom du niveau */ - std::string getName(); + sf::String getName() const; /** * Modifie le nom du niveau */ - void setName(std::string set_name); + void setName(sf::String set_name); /** * Récupère le temps total alloué pour terminer le niveau */ - int getTotalTime(); + int getTotalTime() const; /** * Modifie le temps total du niveau */ void setTotalTime(int set_total_time); + /** + * Récupère le fond du niveau + */ + sf::Sprite getBackground() const; + + /** + * Modifie le fond du niveau + */ + void setBackground(sf::Sprite set_background); + /** * Récupère la liste des objets */ diff --git a/include/manager.hpp b/include/manager.hpp index 68cd25e..fa7f6ed 100644 --- a/include/manager.hpp +++ b/include/manager.hpp @@ -14,7 +14,7 @@ private: sf::RenderWindow window; sf::Clock clock; sf::View window_view; - std::string title; + sf::String title; ResourceManager resource_manager; std::vector events; @@ -29,6 +29,11 @@ public: */ void start(); + /** + * Renvoie la vue actuelle du jeu + */ + std::shared_ptr getView(); + /** * Charge la vue donnée dans le jeu */ @@ -68,12 +73,12 @@ public: /** * Renvoie le titre actuel de la fenêtre */ - std::string getTitle(); + sf::String getTitle(); /** * Modifie le titre actuel de la fenêtre */ - void setTitle(std::string set_title); + void setTitle(sf::String set_title); /** * Renvoie un booléen attestant de l'appui sur la diff --git a/include/object.hpp b/include/object.hpp index c342e2f..4d0f016 100644 --- a/include/object.hpp +++ b/include/object.hpp @@ -45,11 +45,16 @@ public: Object(); virtual ~Object(); + /** + * Clone cet objet en un objet avec les mêmes propriétés + */ + virtual ObjectPtr clone() const = 0; + /** * Charge les propriétés communes à tous les objets * depuis le fichier donné dans l'objet donné */ - static void load(std::ifstream& file, std::shared_ptr object); + static void load(std::ifstream& file, ObjectPtr object); /** * Dessine l'objet dans la fenêtre donnée diff --git a/include/player.hpp b/include/player.hpp index 766705e..13b8fa5 100644 --- a/include/player.hpp +++ b/include/player.hpp @@ -24,16 +24,21 @@ public: Player(); virtual ~Player(); + /** + * Clone cet objet en un objet avec les mêmes propriétés + */ + virtual ObjectPtr clone() const; + /** * Chargement de l'objet depuis le fichier donné */ - static std::shared_ptr load(std::ifstream& file); + static ObjectPtr load(std::ifstream& file); /** * Dessine la balle dans la fenêtre donnée */ virtual void draw(Manager& manager); - + /** * Met à jour la position de l'objet selon sa * vitesse actuelle diff --git a/include/util/widget_button.hpp b/include/util/widget_button.hpp new file mode 100644 index 0000000..b13009f --- /dev/null +++ b/include/util/widget_button.hpp @@ -0,0 +1,41 @@ +#ifndef __PTF_UTIL_WIDGET_BUTTON_HPP__ +#define __PTF_UTIL_WIDGET_BUTTON_HPP__ + +#include +#include +#include "manager.hpp" + +/** + * Affiche un bouton pouvant être cliqué + */ +class WidgetButton { +private: + Manager& manager; + std::function click_cb; + + unsigned int shape; + sf::RectangleShape button; + sf::VertexArray button_shape; + +public: + static const unsigned int ARROW_UP; + static const unsigned int ARROW_DOWN; + + WidgetButton( + Manager& manager, std::function click_cb, + sf::Vector2f size, unsigned int shape + ); + + /** + * Process l'événement et renvoie true si + * on s'en est servi + */ + bool processEvent(const sf::Event& event); + + /** + * Dessine le widget à la position (haut-gauche) donnée + */ + void draw(sf::Vector2f position); +}; + +#endif diff --git a/include/util/widget_timer.hpp b/include/util/widget_timer.hpp new file mode 100644 index 0000000..2417c6f --- /dev/null +++ b/include/util/widget_timer.hpp @@ -0,0 +1,58 @@ +#ifndef __PTF_UTIL_WIDGET_TIMER_HPP__ +#define __PTF_UTIL_WIDGET_TIMER_HPP__ + +#include +#include +#include "util/widget_button.hpp" +#include "manager.hpp" + +/** + * Affiche le compteur de temps pouvant (ou non) + * être modifié + */ +class WidgetTimer { +private: + Manager& manager; + bool can_change; + std::function time_left_cb; + int time_left; + + sf::RectangleShape timer_zone; + sf::Text timer_seconds_text; + sf::Text timer_sep_text; + sf::Text timer_minutes_text; + + WidgetButton timer_up; + WidgetButton timer_down; + +public: + WidgetTimer(Manager& manager, bool can_change, std::function time_left_cb = std::function()); + + /** + * Process l'événement et renvoie true si + * on s'en est servi + */ + bool processEvent(const sf::Event& event); + + /** + * Dessine le widget à la position (haut-gauche) donnée + */ + void draw(sf::Vector2f position); + + /** + * Augmente le temps de 5 secondes + */ + void addTime(); + + /** + * Diminue le temps de 5 secondes + */ + void subtractTime(); + + /** + * Modifie le temps restant + */ + void setTimeLeft(int set_time_left); +}; + +#endif diff --git a/levels/level1.dat b/levels/level1.dat index 1b52150..faa343d 100644 Binary files a/levels/level1.dat and b/levels/level1.dat differ diff --git a/res/monoid.ttf b/res/monoid.ttf new file mode 100644 index 0000000..8034ff6 Binary files /dev/null and b/res/monoid.ttf differ diff --git a/res/selection.png b/res/selection.png deleted file mode 100644 index 344428e..0000000 Binary files a/res/selection.png and /dev/null differ diff --git a/src/block.cpp b/src/block.cpp index c961fa1..96b741b 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -16,8 +16,12 @@ Block::Block() : Object() { Block::~Block() {} -std::shared_ptr Block::load(std::ifstream& file) { - std::shared_ptr object = std::shared_ptr(new Block); +ObjectPtr Block::clone() const { + return ObjectPtr(new Block(*this)); +} + +ObjectPtr Block::load(std::ifstream& file) { + ObjectPtr object = ObjectPtr(new Block); // lecture des propriétés communes des objets Object::load(file, object); diff --git a/src/editor.cpp b/src/editor.cpp index b85a81a..d7f338b 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -1,28 +1,32 @@ #include +#include #include "editor.hpp" +#include "game.hpp" #include "block.hpp" #include "constants.hpp" -Editor::Editor(Manager& manager) : Level(manager) { - // activation de la synchronisation verticale - // car, dans l'éditeur, nous n'avons besoin que de dessiner - // (pas de mise à jour physique) - manager.getWindow().setVerticalSyncEnabled(true); -} +Editor::Editor(Manager& manager) : Level(manager), + widget_timer(manager, true, std::bind(&Editor::setTotalTime, this, std::placeholders::_1)) {} Editor::~Editor() {} void Editor::load(std::ifstream& file) { Level::load(file); - manager.setTitle("Edition de " + getName()); + manager.setTitle(sf::String(L"Édition de ") + getName()); } void Editor::frame() { const std::vector& events = manager.getEvents(); + // traitement des événements for (unsigned int i = 0; i < events.size(); i++) { const sf::Event& event = events[i]; + // traitement des événements du widget timer + if (widget_timer.processEvent(event)) { + continue; + } + // lorsque l'on clique dans l'éditeur if (event.type == sf::Event::MouseButtonPressed) { sf::Vector2f position(event.mouseButton.x, event.mouseButton.y); @@ -33,25 +37,36 @@ void Editor::frame() { if (!updateSelection(position)) { addObject(position); } - } - - if (event.mouseButton.button == sf::Mouse::Right) { + } else if (event.mouseButton.button == sf::Mouse::Right) { // clic droit : on supprime l'objet pointé removeObject(position); } } + + // gestion des touches + if (event.type == sf::Event::KeyPressed) { + // appui sur espace : test du niveau en cours d'édition + if (event.key.code == sf::Keyboard::Space) { + testLevel(); + return; // important : ne pas dessiner la frame + // on risque d'avoir perdu le pointeur en changeant de vue + } + } } + // dessin de la frame draw(); + sf::sleep(sf::seconds(1.f / 60)); } void Editor::draw() { Level::draw(); + sf::RenderWindow& window = manager.getWindow(); sf::View window_view = manager.getWindowView(); sf::Color selection_color(255, 50, 41); - // on dessine des carrés de sélection autour des objets sélectionnés + // dessin de la sélection autour des objets sélectionnés for (auto iter = selection.begin(); iter != selection.end(); iter++) { sf::VertexArray selection(sf::LinesStrip, 5); std::unique_ptr aabb = iter->first->getAABB(); @@ -70,6 +85,10 @@ void Editor::draw() { window.draw(selection); } + // dessin du widget timer + widget_timer.setTimeLeft(getTotalTime()); + widget_timer.draw(sf::Vector2f(window_view.getSize().x / 2 - 50, 0)); + // menu sf::RectangleShape menu(sf::Vector2f(window_view.getSize().x, 64)); menu.setPosition(sf::Vector2f(0, window_view.getSize().y - 64)); @@ -87,7 +106,7 @@ void Editor::addObject(sf::Vector2f position) { position *= Constants::GRID; // TODO: ajouter un objet du type choisi, pas uniquement de bloc - std::shared_ptr object = std::shared_ptr(new Block); + ObjectPtr object = ObjectPtr(new Block); object->setPosition(position); // avant d'ajouter l'objet, on vérifie qu'il ne soit @@ -149,3 +168,30 @@ bool Editor::updateSelection(sf::Vector2f position) { return has_changed; } + +void Editor::testLevel() { + std::shared_ptr game = std::shared_ptr(new Game(manager)); + + // copie des propriétés + game->setName(getName()); + game->setTotalTime(getTotalTime()); + game->setBackground(getBackground()); + + // copie des objets du niveau vers le jeu + std::vector& objects = getObjects(); + + for (unsigned int i = 0; i < objects.size(); i++) { + game->getObjects().push_back(objects[i]->clone()); + } + + // copie de la zone de jeu + std::vector>& zone = getZone(); + + for (unsigned int i = 0; i < zone.size(); i++) { + game->getZone().push_back(zone[i]); + } + + // mise en mode test + game->setTestMode(manager.getView()); + manager.setView(game); +} diff --git a/src/game.cpp b/src/game.cpp index cfb02cd..f4d821d 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1,13 +1,10 @@ #include "game.hpp" #include "constants.hpp" -Game::Game(Manager& manager) : Level(manager), next_frame_time(manager.getCurrentTime()) { - // on s'assure que la synchronisation verticale soit - // bien désactivée : on s'occupe de la limitation du - // framerate manuellement dans la fonction frame pour mettre - // une mise à jour fluide de la physique du jeu - manager.getWindow().setVerticalSyncEnabled(false); -} +Game::Game(Manager& manager) : Level(manager), + widget_timer(manager, false), + next_frame_time(manager.getCurrentTime()), + test_mode(false), return_view(nullptr) {} Game::~Game() {} @@ -17,8 +14,22 @@ void Game::load(std::ifstream& file) { } void Game::frame() { + const std::vector& events = manager.getEvents(); sf::Time current_time = manager.getCurrentTime(); + // traitement des événements + for (unsigned int i = 0; i < events.size(); i++) { + const sf::Event& event = events[i]; + + // appui sur espace en mode test : retour à l'éditeur + if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Space && test_mode) { + test_mode = false; + manager.setView(return_view); + return; // important : ne pas dessiner la frame + // on risque d'avoir perdu le pointeur en changeant de vue + } + } + if (current_time >= next_frame_time) { // si nous sommes en retard ou dans les temps // on replanifie la prochaine frame @@ -38,6 +49,16 @@ void Game::frame() { } } +void Game::draw() { + Level::draw(); + + sf::View window_view = manager.getWindowView(); + + // dessin du widget + widget_timer.setTimeLeft(getTotalTime()); + widget_timer.draw(sf::Vector2f(window_view.getSize().x / 2 - 50, 0)); +} + void Game::update() { std::vector colliding; @@ -84,3 +105,8 @@ void Game::update() { getObjects()[i]->updateVelocity(manager, getObjects(), Constants::PHYSICS_TIME.asSeconds() / 2); } } + +void Game::setTestMode(std::shared_ptr set_return_view) { + return_view = set_return_view; + test_mode = true; +} diff --git a/src/level.cpp b/src/level.cpp index 9cdc64f..f76cf12 100644 --- a/src/level.cpp +++ b/src/level.cpp @@ -12,7 +12,7 @@ * à des instances qui seront utilisées pour la * construction d'autres objets de ces types */ -std::map(std::ifstream&)>> object_type_map = { +std::map> object_type_map = { {Player::TYPE_ID, Player::load}, {Block::TYPE_ID, Block::load} }; @@ -49,7 +49,9 @@ void Level::load(std::ifstream& file) { } // lecture du nom du niveau - std::getline(file, name, '\0'); + std::string std_name; + std::getline(file, std_name, '\0'); + name = sf::String(std_name); // lecture du temps total du niveau file.read(reinterpret_cast(&total_time), sizeof(total_time)); @@ -129,22 +131,34 @@ void Level::draw() { } } -std::string Level::getName() { +sf::String Level::getName() const { return name; } -void Level::setName(std::string set_name) { +void Level::setName(sf::String set_name) { name = set_name; } -int Level::getTotalTime() { +int Level::getTotalTime() const { return total_time; } void Level::setTotalTime(int set_total_time) { + // faisons rester le temps entre 10s et 59:59 + set_total_time = std::min(set_total_time, 3599); + set_total_time = std::max(set_total_time, 10); + total_time = set_total_time; } +sf::Sprite Level::getBackground() const { + return background; +} + +void Level::setBackground(sf::Sprite set_background) { + background = set_background; +} + std::vector& Level::getObjects() { return objects; } diff --git a/src/manager.cpp b/src/manager.cpp index 57b753c..65f02f0 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -3,7 +3,7 @@ Manager::Manager() : window( sf::VideoMode(704, 480), "Skizzle", sf::Style::Default, sf::ContextSettings(0, 0, 2) -), window_view(window.getView()), title(""), view(NULL) {} +), window_view(window.getView()), title(sf::String(L"")), view(NULL) {} void Manager::start() { while (window.isOpen()) { @@ -39,6 +39,10 @@ void Manager::start() { } } +std::shared_ptr Manager::getView() { + return view; +} + void Manager::setView(std::shared_ptr set_view) { view = set_view; } @@ -68,17 +72,17 @@ void Manager::setWindowView(sf::View set_window_view) { window_view = set_window_view; } -std::string Manager::getTitle() { +sf::String Manager::getTitle() { return title; } -void Manager::setTitle(std::string set_title) { +void Manager::setTitle(sf::String set_title) { title = set_title; - if (title.empty()) { - window.setTitle("Skizzle"); + if (title.isEmpty()) { + window.setTitle(sf::String(L"Skizzle")); } else { - window.setTitle("Skizzle - " + title); + window.setTitle(sf::String(L"Skizzle ‒ ") + title); } } diff --git a/src/object.cpp b/src/object.cpp index 6a62b3f..b01147f 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -23,7 +23,7 @@ Object::Object() : Object::~Object() {} -void Object::load(std::ifstream& file, std::shared_ptr object) { +void Object::load(std::ifstream& file, ObjectPtr object) { // lecture de la position de l'objet float pos_x, pos_y; diff --git a/src/player.cpp b/src/player.cpp index d4d5a35..1b4009f 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -13,8 +13,12 @@ Player::Player() : Object() { Player::~Player() {} -std::shared_ptr Player::load(std::ifstream& file) { - std::shared_ptr object = std::shared_ptr(new Player); +ObjectPtr Player::clone() const { + return ObjectPtr(new Player(*this)); +} + +ObjectPtr Player::load(std::ifstream& file) { + ObjectPtr object = ObjectPtr(new Player); std::shared_ptr player = std::dynamic_pointer_cast(object); // lecture du numéro de joueur diff --git a/src/util/widget_button.cpp b/src/util/widget_button.cpp new file mode 100644 index 0000000..6a16d5c --- /dev/null +++ b/src/util/widget_button.cpp @@ -0,0 +1,73 @@ +#include "util/widget_button.hpp" + +const unsigned int WidgetButton::ARROW_UP = 0; +const unsigned int WidgetButton::ARROW_DOWN = 1; + +const sf::Color ARROW_COLOR = sf::Color(33, 33, 33); +const sf::Color CLICKED_COLOR = sf::Color(190, 190, 190); +const sf::Color REST_COLOR = sf::Color(230, 230, 230); + +WidgetButton::WidgetButton( + Manager& manager, std::function click_cb, + sf::Vector2f size, unsigned int shape +) : manager(manager), click_cb(click_cb), shape(shape), button(size) { + if (shape == WidgetButton::ARROW_UP || shape == WidgetButton::ARROW_DOWN) { + button_shape.setPrimitiveType(sf::Triangles); + button_shape.resize(3); + + button_shape[0].color = ARROW_COLOR; + button_shape[1].color = ARROW_COLOR; + button_shape[2].color = ARROW_COLOR; + } +} + +bool WidgetButton::processEvent(const sf::Event& event) { + if (event.type == sf::Event::MouseButtonPressed) { + sf::Vector2f position(event.mouseButton.x, event.mouseButton.y); + + if (event.mouseButton.button == sf::Mouse::Left) { + // clic gauche sur le bouton : appel de la callback + if (button.getGlobalBounds().contains(position)) { + click_cb(); + return true; + } + } + } + + return false; +} + +void WidgetButton::draw(sf::Vector2f position) { + sf::RenderWindow& window = manager.getWindow(); + + // positionnement du bouton + button.setPosition(position); + sf::FloatRect box = button.getGlobalBounds(); + sf::Vector2f center(box.left + box.width / 2, box.top + box.height / 2); + + if (shape == WidgetButton::ARROW_UP) { + button_shape[0].position = center + sf::Vector2f(-5, 2); + button_shape[1].position = center + sf::Vector2f(5, 2); + button_shape[2].position = center + sf::Vector2f(0, -2); + } + + if (shape == WidgetButton::ARROW_DOWN) { + button_shape[0].position = center + sf::Vector2f(-5, -2); + button_shape[1].position = center + sf::Vector2f(5, -2); + button_shape[2].position = center + sf::Vector2f(0, 2); + } + + // coloration des boutons si enfoncement + button.setFillColor(REST_COLOR); + + if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) { + sf::Vector2f mouse_position = (sf::Vector2f) sf::Mouse::getPosition(window); + + if (button.getGlobalBounds().contains(mouse_position)) { + button.setFillColor(CLICKED_COLOR); + } + } + + window.draw(button); + window.draw(button_shape); +} diff --git a/src/util/widget_timer.cpp b/src/util/widget_timer.cpp new file mode 100644 index 0000000..d4fd0c2 --- /dev/null +++ b/src/util/widget_timer.cpp @@ -0,0 +1,113 @@ +#include +#include "util/widget_timer.hpp" + +WidgetTimer::WidgetTimer(Manager& manager, bool can_change, std::function time_left_cb) : + manager(manager), can_change(can_change), time_left_cb(time_left_cb), + timer_zone(sf::Vector2f(100, 32)), + timer_up(manager, std::bind(&WidgetTimer::addTime, this), sf::Vector2f(30, 16), WidgetButton::ARROW_UP), + timer_down(manager, std::bind(&WidgetTimer::subtractTime, this), sf::Vector2f(30, 16), WidgetButton::ARROW_DOWN) { + + // initialisation des formes + timer_seconds_text.setFont(manager.getResourceManager().getFont("monoid.ttf")); + timer_seconds_text.setCharacterSize(18); + timer_seconds_text.setColor(sf::Color::Black); + + timer_sep_text.setString(":"); + timer_sep_text.setFont(manager.getResourceManager().getFont("monoid.ttf")); + timer_sep_text.setCharacterSize(18); + timer_sep_text.setColor(sf::Color::Black); + + timer_minutes_text.setFont(manager.getResourceManager().getFont("monoid.ttf")); + timer_minutes_text.setCharacterSize(18); + timer_minutes_text.setColor(sf::Color::Black); +} + +bool WidgetTimer::processEvent(const sf::Event& event) { + // si le timer n'est pas modifiable, pas d'évent à gérer + if (!can_change) { + return false; + } + + // gestion des boutons + if (timer_up.processEvent(event)) { + return true; + } + + if (timer_down.processEvent(event)) { + return true; + } + + if (event.type == sf::Event::MouseButtonPressed) { + sf::Vector2f position(event.mouseButton.x, event.mouseButton.y); + + // clic dans le widget : ne rien faire, mais empêcher le traversement + if (timer_zone.getGlobalBounds().contains(position)) { + return true; + } + } + + if (event.type == sf::Event::MouseWheelScrolled && event.mouseWheelScroll.wheel == sf::Mouse::VerticalWheel) { + // scroll sur le timer : modification du temps alloué au niveau + sf::Vector2f position(event.mouseWheelScroll.x, event.mouseWheelScroll.y); + + if (timer_zone.getGlobalBounds().contains(position)) { + time_left_cb(time_left + round(event.mouseWheelScroll.delta * 10)); + return true; + } + } + + return false; +} + +void WidgetTimer::draw(sf::Vector2f position) { + sf::RenderWindow& window = manager.getWindow(); + + // zone de fond du timer + timer_zone.setPosition(position); + window.draw(timer_zone); + + // affichage du temps du niveau + sf::String minutes = std::to_string(time_left / 60); + sf::String seconds = std::to_string(time_left % 60); + + // ajout d'un zéro devant les secondes si nécessaire + if (minutes.getSize() == 1) { + minutes = "0" + minutes; + } + + if (seconds.getSize() == 1) { + seconds = "0" + seconds; + } + + timer_minutes_text.setString(minutes); + timer_seconds_text.setString(seconds); + + float base_x = can_change ? 30 : 45; + timer_sep_text.setPosition(position + sf::Vector2f(base_x, 6)); + timer_seconds_text.setPosition(position + sf::Vector2f(base_x + 8, 6)); + timer_minutes_text.setPosition(position + sf::Vector2f( + base_x - 3 - floor(timer_minutes_text.getGlobalBounds().width), 6 + )); + + window.draw(timer_sep_text); + window.draw(timer_seconds_text); + window.draw(timer_minutes_text); + + // interface de modification du temps + if (can_change) { + timer_up.draw(position + sf::Vector2f(70, 0)); + timer_down.draw(position + sf::Vector2f(70, 16)); + } +} + +void WidgetTimer::addTime() { + time_left_cb(time_left + 1); +} + +void WidgetTimer::subtractTime() { + time_left_cb(time_left - 1); +} + +void WidgetTimer::setTimeLeft(int set_time_left) { + time_left = set_time_left; +}