This repository has been archived on 2023-05-13. You can view files and clone it, but cannot push or open issues or pull requests.
mipt_cpp/seminar11_events/01_select_move_delete/context_menu.hpp
2023-01-04 00:36:53 +03:00

143 lines
No EOL
4.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}
};