143 lines
No EOL
4.9 KiB
C++
143 lines
No EOL
4.9 KiB
C++
#pragma once
|
||
#include <SFML/Window.hpp>
|
||
#include <SFML/Graphics.hpp>
|
||
|
||
|
||
/*
|
||
Класс ContextMenu - контекстное меню
|
||
При нажатии правой кнопки мыши на экране появляется контекстное меню
|
||
|
||
Публичные методы:
|
||
ContextMenu(sf::RenderWindow&, const sf::Font&)
|
||
Конструктор принимает окно для отрисовки и шрифт
|
||
|
||
void addButton(const sf::String& name)
|
||
Добавить новый элемент в контекстное меню по имени name
|
||
|
||
void draw()
|
||
Нарисовать контекстное меню в окне, которое было передано в конструктор
|
||
|
||
int handleEvent(const sf::Event& event)
|
||
Обрабатывает событие event и возвращает целое число
|
||
Если это событие MousePressed и был выбран один из вариантов
|
||
контекстного меню, то вернёт номер этого варианта
|
||
Нумерация начинается с нуля
|
||
В ином случае вернёт -1
|
||
|
||
*/
|
||
|
||
|
||
class ContextMenu
|
||
{
|
||
private:
|
||
inline static const sf::Color kDefaultColor {sf::Color(190, 210, 190)};
|
||
inline static const sf::Color kHoverColor {sf::Color(150, 170, 150)};
|
||
inline static const sf::Color kTextColor {sf::Color::Black};
|
||
inline static const int kButtonHeight = 20;
|
||
inline static const int kCharacterSize = 16;
|
||
inline static const float kMenuWidthMultiplier = 1.2;
|
||
|
||
sf::RenderWindow& mRenderWindow;
|
||
sf::RectangleShape mShape;
|
||
sf::RectangleShape mHoverShape;
|
||
sf::Text mText;
|
||
std::vector<sf::String> mButtons;
|
||
|
||
bool mIsOpened = false;
|
||
bool mIsUpdated = false;
|
||
int mHoverPosition = -1;
|
||
|
||
int onMousePressed(const sf::Event& event)
|
||
{
|
||
if (event.mouseButton.button == sf::Mouse::Right) {
|
||
mIsOpened = true;
|
||
sf::Vector2f mousePosition = mRenderWindow.mapPixelToCoords({event.mouseButton.x, event.mouseButton.y});
|
||
mShape.setPosition(mousePosition);
|
||
}
|
||
if (event.mouseButton.button == sf::Mouse::Left && mIsOpened) {
|
||
mIsOpened = false;
|
||
return mHoverPosition;
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
void onMouseMove(const sf::Event& event)
|
||
{
|
||
if (!mIsOpened) {
|
||
return;
|
||
}
|
||
sf::Vector2f mousePosition = mRenderWindow.mapPixelToCoords({event.mouseMove.x, event.mouseMove.y});
|
||
if (mShape.getGlobalBounds().contains(mousePosition)) {
|
||
mHoverPosition = (mousePosition.y - mShape.getPosition().y) / kButtonHeight;
|
||
}
|
||
else {
|
||
mHoverPosition = -1;
|
||
}
|
||
}
|
||
|
||
public:
|
||
|
||
ContextMenu(sf::RenderWindow& window, const sf::Font& font) : mRenderWindow(window)
|
||
{
|
||
mText.setFont(font);
|
||
mText.setCharacterSize(kCharacterSize);
|
||
mText.setFillColor(kTextColor);
|
||
mShape.setFillColor(kDefaultColor);
|
||
mHoverShape.setFillColor(kHoverColor);
|
||
|
||
mIsOpened = false;
|
||
mIsUpdated = false;
|
||
mHoverPosition = -1;
|
||
}
|
||
|
||
void addButton(const sf::String& name)
|
||
{
|
||
mButtons.push_back(name);
|
||
mIsUpdated = false;
|
||
}
|
||
|
||
void draw()
|
||
{
|
||
if (!mIsOpened) {
|
||
return;
|
||
}
|
||
// Если добавили новый вариант, то её текст может быть длиннее
|
||
// чем у других. Нужно расширить прямоугольники.
|
||
if (!mIsUpdated) {
|
||
int maxSizeX = 0;
|
||
for (int i = 0; i < mButtons.size(); i++) {
|
||
mText.setString(mButtons[i]);
|
||
if (mText.getLocalBounds().width > maxSizeX) {
|
||
maxSizeX = mText.getLocalBounds().width;
|
||
}
|
||
}
|
||
maxSizeX *= kMenuWidthMultiplier;
|
||
mShape.setSize({(float)maxSizeX, (float)(kButtonHeight * mButtons.size())});
|
||
mHoverShape.setSize({(float)maxSizeX, (float)(kButtonHeight)});
|
||
mIsUpdated = true;
|
||
}
|
||
|
||
|
||
mRenderWindow.draw(mShape);
|
||
if (mHoverPosition >= 0){
|
||
mHoverShape.setPosition(mShape.getPosition().x, mShape.getPosition().y + mHoverPosition * kButtonHeight);
|
||
mRenderWindow.draw(mHoverShape);
|
||
}
|
||
for (int i = 0; i < mButtons.size(); i++) {
|
||
mText.setString(mButtons[i]);
|
||
mText.setPosition(mShape.getPosition().x, mShape.getPosition().y + i * kButtonHeight);
|
||
mRenderWindow.draw(mText);
|
||
}
|
||
}
|
||
|
||
int handleEvent(const sf::Event& event) {
|
||
if (event.type == sf::Event::MouseMoved) {
|
||
onMouseMove(event);
|
||
}
|
||
else if (event.type == sf::Event::MouseButtonPressed) {
|
||
return onMousePressed(event);
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
}; |