From db89415e5b0a9f02fbf2bf9bdfc02c120131a691 Mon Sep 17 00:00:00 2001
From: Sulimov Igor Andreevich <igansulimov@edu.hse.ru>
Date: Mon, 24 Mar 2025 02:39:11 +0300
Subject: [PATCH] Partly completed Button and Menu

---
 include/Application.h           |  6 +++---
 include/Buildings/IRoomSide.h   |  8 -------
 include/Buildings/Room.h        |  8 -------
 include/Draw/Button.h           |  7 ++++---
 include/Draw/IDrawable.h        |  3 ++-
 include/Draw/IPreparable.h      |  9 ++++++++
 include/Draw/Menu.h             |  2 +-
 include/Draw/MyFont.h           |  4 +++-
 include/MazeContent/IEntity.h   | 12 +++++++++++
 include/MazeContent/IRoomSide.h | 11 ++++++++++
 include/MazeContent/Maze.h      | 12 +++++++++++
 include/MazeContent/Pass.h      | 15 +++++++++++++
 include/MazeContent/Room.h      | 20 ++++++++++++++++++
 include/MazeContent/Wall.h      | 15 +++++++++++++
 include/States/SelectState.h    |  8 +++----
 include/config.h                | 26 +++++++++++------------
 source/Application.cpp          |  4 ++++
 source/Draw/Button.cpp          | 21 +++++++++++++++++++
 source/Draw/Menu.cpp            |  1 +
 source/Draw/MyFont.cpp          |  6 +++++-
 source/Maze_Content/Maze.cpp    |  6 ++++++
 source/State/SelectState.cpp    | 37 ++++++++++++++++++++++++++++++++-
 22 files changed, 197 insertions(+), 44 deletions(-)
 delete mode 100644 include/Buildings/IRoomSide.h
 delete mode 100644 include/Buildings/Room.h
 create mode 100644 include/Draw/IPreparable.h
 create mode 100644 include/MazeContent/IEntity.h
 create mode 100644 include/MazeContent/IRoomSide.h
 create mode 100644 include/MazeContent/Maze.h
 create mode 100644 include/MazeContent/Pass.h
 create mode 100644 include/MazeContent/Room.h
 create mode 100644 include/MazeContent/Wall.h
 create mode 100644 source/Maze_Content/Maze.cpp

diff --git a/include/Application.h b/include/Application.h
index 0e85662..7363d50 100644
--- a/include/Application.h
+++ b/include/Application.h
@@ -6,10 +6,10 @@ class Application: public IStateManager{
 private:
     void set_next_state(std::unique_ptr<IState>&& ptr_state) override;
     void apply_differ_state_change() noexcept;
+public:
+    Application();
+    int run();
 private:
     std::unique_ptr<IState> m_ptr_state_next;
     std::unique_ptr<IState> m_ptr_state_current;
-public:
-    Application() {}; ///@todo
-    int run();
 };
\ No newline at end of file
diff --git a/include/Buildings/IRoomSide.h b/include/Buildings/IRoomSide.h
deleted file mode 100644
index 381f790..0000000
--- a/include/Buildings/IRoomSide.h
+++ /dev/null
@@ -1,8 +0,0 @@
-//
-// Created by Игорь on 23.03.2025.
-//
-
-#ifndef PAC_MAN_IROOMSIDE_H
-#define PAC_MAN_IROOMSIDE_H
-
-#endif //PAC_MAN_IROOMSIDE_H
diff --git a/include/Buildings/Room.h b/include/Buildings/Room.h
deleted file mode 100644
index f594b3a..0000000
--- a/include/Buildings/Room.h
+++ /dev/null
@@ -1,8 +0,0 @@
-//
-// Created by Игорь on 23.03.2025.
-//
-
-#ifndef PAC_MAN_ROOM_H
-#define PAC_MAN_ROOM_H
-
-#endif //PAC_MAN_ROOM_H
diff --git a/include/Draw/Button.h b/include/Draw/Button.h
index 45f3d1a..573031e 100644
--- a/include/Draw/Button.h
+++ b/include/Draw/Button.h
@@ -6,15 +6,16 @@
 
 class Button: public IDrawable {
 public:
-    void set();  ///@todo
+    void set(const sf::Vector2f& pos, const sf::Vector2f& button_size, const std::string& text,
+             size_t font_size, std::unique_ptr<ISelectCommand> ptr_command);
     void select() noexcept;
     void unselect() noexcept;
     bool is_selected() noexcept;
     bool is_position_in(sf::Vector2f pos) const noexcept;
     void push() const;
-    void draw_into(sf::RenderWindow& window) const override {};  ///@todo
+    void draw_into(sf::RenderWindow& window) const override {};
 public:
-    Button(); ///@todo
+    Button();
 private:
     sf::Text m_text;
     bool m_is_selected = false;
diff --git a/include/Draw/IDrawable.h b/include/Draw/IDrawable.h
index 85b6a20..5b25fe5 100644
--- a/include/Draw/IDrawable.h
+++ b/include/Draw/IDrawable.h
@@ -2,7 +2,8 @@
 
 #include "SFML/Graphics.hpp"
 
-struct IDrawable {
+class IDrawable {
+public:
     virtual void draw_into(sf::RenderWindow& window) const = 0;
     virtual ~IDrawable() = default;
 };
\ No newline at end of file
diff --git a/include/Draw/IPreparable.h b/include/Draw/IPreparable.h
new file mode 100644
index 0000000..780b5ac
--- /dev/null
+++ b/include/Draw/IPreparable.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "IDrawable.h"
+
+class IPreparable: public IDrawable {
+public:
+    virtual void prepare_for_drawing() = 0;
+    virtual ~IPreparable() = default;
+};
\ No newline at end of file
diff --git a/include/Draw/Menu.h b/include/Draw/Menu.h
index 318c55c..bd4815d 100644
--- a/include/Draw/Menu.h
+++ b/include/Draw/Menu.h
@@ -8,7 +8,7 @@ public:
     void draw_into(sf::RenderWindow& window) const override;
     void process_mouse(sf::Vector2f pos, bool is_pressed);
 public:
-    Menu(IStateManager& state_manager) {}  ///@todo
+    Menu(IStateManager& state_manager); ///@todo
 private:
     std::array<Button, 4> m_buttons;
 };
\ No newline at end of file
diff --git a/include/Draw/MyFont.h b/include/Draw/MyFont.h
index 9d065a2..404dacb 100644
--- a/include/Draw/MyFont.h
+++ b/include/Draw/MyFont.h
@@ -3,10 +3,12 @@
 #include "SFML/Graphics/Font.hpp"
 
 class MyFont {
+public:
+    static MyFont& Instance();
+    const sf::Font& get_font() const noexcept;
 public:
     MyFont(const MyFont&) = delete;
     MyFont& operator = (const MyFont&) = delete;
-    static MyFont& Instance();
 private:
     MyFont();
 private:
diff --git a/include/MazeContent/IEntity.h b/include/MazeContent/IEntity.h
new file mode 100644
index 0000000..0f5725b
--- /dev/null
+++ b/include/MazeContent/IEntity.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "Draw/IPreparable.h"
+
+class IEntity: public IPreparable {
+public:
+    virtual void set_location(Room ptr_room) = 0; ///@todo
+    virtual Room get_location() = 0; ///@todo
+    virtual ~IEntity() = default;
+protected:
+    Room* m_ptr_room{ nullptr };
+};
\ No newline at end of file
diff --git a/include/MazeContent/IRoomSide.h b/include/MazeContent/IRoomSide.h
new file mode 100644
index 0000000..1675c08
--- /dev/null
+++ b/include/MazeContent/IRoomSide.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "Draw/IPreparable.h"
+
+class IEntity;
+
+class IRoomSide: public IPreparable {
+public:
+    virtual void enter(IEntity* entity) = 0;
+    virtual ~IRoomSide() = default;
+};
\ No newline at end of file
diff --git a/include/MazeContent/Maze.h b/include/MazeContent/Maze.h
new file mode 100644
index 0000000..5fea69d
--- /dev/null
+++ b/include/MazeContent/Maze.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "Room.h"
+
+class Maze: public IDrawable {
+public:
+    void draw_into(sf::RenderWindow& window) const override; ///@todo
+public:
+    Maze(std::vector<std::unique_ptr<Room>>&& rooms): m_rooms(std::move(rooms)) {}
+private:
+    std::vector<std::unique_ptr<Room>>&& m_rooms;
+};
\ No newline at end of file
diff --git a/include/MazeContent/Pass.h b/include/MazeContent/Pass.h
new file mode 100644
index 0000000..0771782
--- /dev/null
+++ b/include/MazeContent/Pass.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "Room.h"
+
+class Pass : public IRoomSide {
+public:
+    void enter(IEntity* entity) override; ///@todo
+    void prepare_for_drawing() override; ///@todo
+    void draw_into(sf::RenderWindow& window) const override; ///@todo
+public:
+    Pass(Room& room1, Room& room2) : m_room1(room1), m_room2(room2) {}
+private:
+    Room& m_room1;
+    Room& m_room2;
+};
\ No newline at end of file
diff --git a/include/MazeContent/Room.h b/include/MazeContent/Room.h
new file mode 100644
index 0000000..3a8a9de
--- /dev/null
+++ b/include/MazeContent/Room.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "IRoomSide.h"
+
+class Room: public IDrawable {
+public:
+    enum Direction { INVALID = -1, LEFT, RIGHT, UP, DOWN };
+    float get_size(); ///@todo
+    void set_position(sf::Vector2f); ///@todo
+    sf::Vector2f get_position(); ///@todo
+    void set_side(Direction side, IRoomSide prt_side); ///@todo
+    IRoomSide get_side(Direction side); ///@todo
+    Direction get_direction(IRoomSide prt_side); ///@todo
+public:
+    Room(float size); ///@todo
+public:
+    std::array<std::shared_ptr<IRoomSide>, 4> m_sides;
+private:
+    sf::RectangleShape m_rectangle;
+};
\ No newline at end of file
diff --git a/include/MazeContent/Wall.h b/include/MazeContent/Wall.h
new file mode 100644
index 0000000..dd6a544
--- /dev/null
+++ b/include/MazeContent/Wall.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "Room.h"
+
+class Wall : public IRoomSide {
+public:
+    void enter(IEntity* entity) override {};
+    void prepare_for_drawing() override; ///@todo
+    void draw_into(sf::RenderWindow& window) const override; ///@todo
+public:
+    Wall(Room& room) : m_room(room) {}
+private:
+    Room& m_room;
+    sf::Vertex m_line[2];
+};
\ No newline at end of file
diff --git a/include/States/SelectState.h b/include/States/SelectState.h
index 2b366db..de523e9 100644
--- a/include/States/SelectState.h
+++ b/include/States/SelectState.h
@@ -5,10 +5,10 @@
 
 class SelectState: public IState, public IWindowKeeper {
 public:
-    bool do_step() override {return false;} ///@todo
-    void event_handling() override {};  ///@todo
-    void update() override {};  ///@todo
-    void render() override {};  ///@todo
+    bool do_step() override;
+    void event_handling() override;
+    void update() override;
+    void render() override;
 public:
     SelectState(IStateManager& state_manager, const sf::VideoMode& video_mode, const std::string& window_title);
 private:
diff --git a/include/config.h b/include/config.h
index 6599abf..ffdca33 100644
--- a/include/config.h
+++ b/include/config.h
@@ -5,18 +5,18 @@ namespace config {
 // Общее:
 //    const unsigned int FRAME_RATE_LIMIT = 60;
 // Меню:
-//    const sf::Vector2f BUTTON_SIZE = { 250, 100 };
-//    const size_t BUTTON_FONT_SIZE = static_cast<size_t>(BUTTON_SIZE.y / 1.5f);
-//    const float BUTTON_FRAME_THICKNESS = 2.0f;
+    const sf::Vector2f BUTTON_SIZE = { 250, 100 };
+    const size_t BUTTON_FONT_SIZE = static_cast<size_t>(BUTTON_SIZE.y / 1.5f);
+    const float BUTTON_FRAME_THICKNESS = 2.0f;
     const char FONT_FILE[] = "Calibri Light.ttf";
-//    const char SELECT_LEVEL_TITLE[] = "Select Level";
-//    const sf::VideoMode SELECT_LEVEL_VIDEO_MODE{ 400, 600 };
-//    const char BUTTON_TEXT_EASY[] = "Easy";
-//    const char BUTTON_TEXT_MEDIUM[] = "Medium";
-//    const char BUTTON_TEXT_HARD[] = "Hard";
-//    const char BUTTON_TEXT_EXIT[] = "Exit";
+    const char SELECT_LEVEL_TITLE[] = "Select Level";
+    const sf::VideoMode SELECT_LEVEL_VIDEO_MODE{ 400, 600 };
+    const char BUTTON_TEXT_EASY[] = "Easy";
+    const char BUTTON_TEXT_MEDIUM[] = "Medium";
+    const char BUTTON_TEXT_HARD[] = "Hard";
+    const char BUTTON_TEXT_EXIT[] = "Exit";
 // Игра:
-//    const sf::VideoMode GAME_VIDEO_MODE{ 1080, 720 };
+    const sf::VideoMode GAME_VIDEO_MODE{ 1080, 720 };
 //    const char EASY_GAME_TITLE[] = "Level: Easy";
 //    const char MEDIUM_GAME_TITLE[] = "Level: Medium";
 //    const char HARD_GAME_TITLE[] = "Level: Hard";
@@ -33,11 +33,11 @@ namespace config {
 //    const sf::Keyboard::Key KEY_UP = sf::Keyboard::W;
 //    const sf::Keyboard::Key KEY_DOWN = sf::Keyboard::S;
 // Цвета:
-//    const sf::Color BUTTON_COLOR_TEXT{ 0, 0, 0 };
+    const sf::Color BUTTON_COLOR_TEXT{ 0, 0, 0 };
     const sf::Color BUTTON_COLOR_FILL{ 180, 180, 180 };
     const sf::Color BUTTON_COLOR_SELECTION{ 255, 180, 180 };
-//    const sf::Color BUTTON_COLOR_FRAME{ 0, 0, 0 };
-//    const sf::Color SELECT_LEVEL_BACKGROUND_COLOR{ 230,230,230 };
+    const sf::Color BUTTON_COLOR_FRAME{ 0, 0, 0 };
+    const sf::Color SELECT_LEVEL_BACKGROUND_COLOR{ 230,230,230 };
 //    const sf::Color GAME_COLOR_BACKGROUND_INGAME{ 230,230,230 };
 //    const sf::Color GAME_COLOR_BACKGROUND_WIN{ 0, 255, 0 };
 //    const sf::Color GAME_COLOR_BACKGROUND_LOST{ 255, 0, 0 };
diff --git a/source/Application.cpp b/source/Application.cpp
index a9f7d9e..978d8ed 100644
--- a/source/Application.cpp
+++ b/source/Application.cpp
@@ -1,7 +1,11 @@
 #include "Application.h"
+#include "States/SelectState.h"
 
 #include <iostream>
 
+Application::Application(): m_ptr_state_current(std::make_unique<SelectState>
+        (*this, config::SELECT_LEVEL_VIDEO_MODE, config::SELECT_LEVEL_TITLE)) {}
+
 void Application::set_next_state(std::unique_ptr<IState>&& ptr_state) {
     m_ptr_state_next = std::move(ptr_state);
 }
diff --git a/source/Draw/Button.cpp b/source/Draw/Button.cpp
index 9c5f634..5fd6436 100644
--- a/source/Draw/Button.cpp
+++ b/source/Draw/Button.cpp
@@ -1,4 +1,25 @@
 #include "Draw/Button.h"
+#include "Draw/MyFont.h"
+
+Button::Button() {
+    m_text.setFont(MyFont::Instance().get_font());
+    m_text.setCharacterSize(config::BUTTON_FONT_SIZE);
+    m_text.setFillColor(config::BUTTON_COLOR_TEXT);
+    m_rectangle.setFillColor(config::BUTTON_COLOR_FILL);
+    m_rectangle.setOutlineThickness(config::BUTTON_FRAME_THICKNESS);
+    m_rectangle.setOutlineColor(config::BUTTON_COLOR_FRAME);
+}
+
+void Button::set(const sf::Vector2f& pos, const sf::Vector2f& button_size, const std::string& text,
+                 size_t font_size, std::unique_ptr<ISelectCommand> ptr_command) {
+    m_rectangle.setOrigin(m_rectangle.getSize() / 2.f);
+    m_rectangle.setSize(button_size);
+    m_rectangle.setPosition(pos);
+    m_text.setString(text);
+    auto bounds = m_text.getLocalBounds();
+    m_text.setOrigin(bounds.left + bounds.width / 2.0f, bounds.top + bounds.height / 2.0f);
+    m_ptr_command = std::move(ptr_command);
+}
 
 void Button::push() const {
     m_ptr_command->execute();
diff --git a/source/Draw/Menu.cpp b/source/Draw/Menu.cpp
index cb22023..ee7987b 100644
--- a/source/Draw/Menu.cpp
+++ b/source/Draw/Menu.cpp
@@ -1,5 +1,6 @@
 #include "Draw/Menu.h"
 
+
 void Menu::draw_into(sf::RenderWindow& window) const {
     for (const Button& ptr_button : m_buttons)
         ptr_button.draw_into(window);
diff --git a/source/Draw/MyFont.cpp b/source/Draw/MyFont.cpp
index e92fa09..0389c99 100644
--- a/source/Draw/MyFont.cpp
+++ b/source/Draw/MyFont.cpp
@@ -3,11 +3,15 @@
 
 MyFont::MyFont() {
     if (!m_font.loadFromFile(FONT_PATH + std::string(config::FONT_FILE))) {
-        throw std::runtime_error("Could not open the font file!");
+        throw std::runtime_error("Could not open the Font file!");
     }
 }
 
 MyFont& MyFont::Instance() {
     static MyFont instance;
     return instance;
+}
+
+const sf::Font& MyFont::get_font() const noexcept {
+    return m_font;
 }
\ No newline at end of file
diff --git a/source/Maze_Content/Maze.cpp b/source/Maze_Content/Maze.cpp
new file mode 100644
index 0000000..8f80fe6
--- /dev/null
+++ b/source/Maze_Content/Maze.cpp
@@ -0,0 +1,6 @@
+#include "MazeContent/Maze.h"
+
+void Maze::draw_into(sf::RenderWindow& window) const {
+    for (const auto& room : m_rooms)
+        room->draw_into(window);
+}
\ No newline at end of file
diff --git a/source/State/SelectState.cpp b/source/State/SelectState.cpp
index d0e20cb..e4cf73a 100644
--- a/source/State/SelectState.cpp
+++ b/source/State/SelectState.cpp
@@ -1,4 +1,39 @@
 #include "States/SelectState.h"
+#include "States/ExitState.h"
 
 SelectState::SelectState(IStateManager& state_manager, const sf::VideoMode& video_mode, const std::string& window_title):
-        IWindowKeeper(video_mode, window_title), IState(state_manager), m_menu(state_manager) {}
\ No newline at end of file
+        IWindowKeeper(video_mode, window_title), IState(state_manager), m_menu(state_manager) {}
+
+bool SelectState::do_step() {
+    event_handling();
+    update();
+    render();
+    return true;
+}
+
+void SelectState::event_handling() {
+    sf::Event event;
+    while (m_window.pollEvent(event)) {
+        if (event.type == sf::Event::Closed) {
+            m_state_manager.set_next_state(std::make_unique<ExitState>(m_state_manager));
+            break;
+        }
+        if (event.type == sf::Event::Resized) {
+            sf::View view = m_window.getView();
+            view.setSize(event.size.width, event.size.height);
+            m_window.setView(view);
+        }
+    }
+}
+
+void SelectState::update() {
+    sf::Vector2f pos = m_window.mapPixelToCoords(sf::Mouse::getPosition(m_window));
+    bool is_pressed = sf::Mouse::isButtonPressed(sf::Mouse::Button::Left);
+    m_menu.process_mouse(pos, is_pressed);
+}
+
+void SelectState::render() {
+    m_window.clear(config::SELECT_LEVEL_BACKGROUND_COLOR);
+    m_menu.draw_into(m_window);
+    m_window.display();
+}
\ No newline at end of file
-- 
GitLab