Implement test drop menu and wrap up menu bar system

This commit is contained in:
NaiJi ✨ 2021-08-26 19:54:30 +03:00
parent be0367bba0
commit 37391cfdfd
17 changed files with 213 additions and 48 deletions

View File

@ -27,7 +27,8 @@ private:
std::shared_ptr<Game> _game;
void exec();
void emplaceState(GUIState::Tag new_state);
void pushState(GUIState::Tag new_state);
void popState();
};
#endif // APPLICATION_H

View File

@ -23,11 +23,12 @@ Application::Application() :
_game_window.setMouseCursorGrabbed(false);
_game_window.setVerticalSyncEnabled(true);
MainMenu::Callbacks callbacks = {[&](){ emplaceState(GUIState::Tag::EDITOR); }};
MainMenu::Callbacks callbacks = {[&](){ pushState(GUIState::Tag::EDITOR); }};
Editor::Callbacks editor_callbacks = {[&](){ popState(); }};
const auto main_menu = std::make_shared<MainMenu>(_game_window, std::move(callbacks));
const auto game_state = std::make_shared<GameState>(_game_window, _game, GameState::Callbacks());
const auto editor = std::make_shared<Editor>(_game_window, Editor::Callbacks(), std::make_unique<MusicSFML>());
const auto editor = std::make_shared<Editor>(_game_window, std::move(editor_callbacks), std::make_unique<MusicSFML>());
_states[GUIState::Tag::MAIN_MENU] = main_menu;
_states[GUIState::Tag::GAME] = game_state;
_states[GUIState::Tag::EDITOR] = editor;
@ -95,9 +96,16 @@ void Application::draw()
_game_window.display();
}
void Application::emplaceState(GUIState::Tag new_state)
void Application::pushState(GUIState::Tag new_state)
{
_state_stack.back()->leave();
_state_stack.emplace_back(_states.at(new_state));
_state_stack.back()->enter();
}
void Application::popState()
{
_state_stack.back()->leave();
_state_stack.pop_back();
_state_stack.back()->enter();
}

View File

@ -16,7 +16,26 @@ Editor::Editor(sf::RenderWindow& game_window, Callbacks&& callbacks, std::unique
const float window_width = game_window.getSize().x;
//const float window_height = game_window.getSize().y;
auto bpm_button = std::make_shared<PushButton>("Calculate BPM");
bpm_button->setCallback([&]()
{
_bpm_calculator->startListening(0);
});
auto quit_button = std::make_shared<PushButton>("Quit");
quit_button->setCallback(callbacks.onLeaveEditorState);
auto test_menu = std::make_shared<MenuDrop>();
test_menu->setRect(sf::FloatRect{0, 0, 200, 27});
_menu_bar->setRect(sf::FloatRect(0, 0, window_width, 27));
_menu_bar->addSubMenu("test", test_menu);
test_menu->addPushButton(bpm_button);
test_menu->addPushButton(quit_button);
_music->openFromFile("Uta-test.flac");
_music->setVolume(5);
}
void Editor::input(const sf::Event& event)

View File

@ -14,7 +14,7 @@ public:
struct Callbacks
{
std::function<void(void)> onAppendGameState;
std::function<void(void)> onLeaveEditorState;
};
explicit Editor(sf::RenderWindow& game_window, Callbacks&& callbacks, std::unique_ptr<Music>&& music);

View File

@ -1,5 +1,5 @@
#include "mainmenu.h"
#include "widgets/button.h"
#include "widgets/pushbutton.h"
#include "widgets/group.h"
MainMenu::MainMenu(sf::RenderWindow& game_window, Callbacks&& callbacks) :
@ -9,11 +9,11 @@ MainMenu::MainMenu(sf::RenderWindow& game_window, Callbacks&& callbacks) :
const float window_width = game_window.getSize().x;
const float window_height = game_window.getSize().y;
std::shared_ptr<Button> button_start = std::make_shared<Button>("Start");
std::shared_ptr<PushButton> button_start = std::make_shared<PushButton>("Start");
button_start->setRect(sf::FloatRect(window_width / 3., window_height / 7. * 2, window_width / 3., window_height / 7.));
button_start->setCallback(callbacks.onAppendGameState);
std::shared_ptr<Button> button_exit = std::make_shared<Button>("Exit");
std::shared_ptr<PushButton> button_exit = std::make_shared<PushButton>("Exit");
button_exit->setRect(sf::FloatRect(window_width / 3., window_height / 7. * 4, window_width / 3., window_height / 7.));
button_exit->setCallback([&]()
{

View File

@ -13,9 +13,12 @@ void Button::update()
}
void Button::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
if (_is_visible)
{
target.draw(_button_content, states);
target.draw(_button_text, states);
}
Widget::draw(target, states);
}
@ -36,11 +39,6 @@ bool Button::isUnderMouse(int mouse_x, int mouse_y) const
return _is_visible && _button_content.getGlobalBounds().contains(mouse_x, mouse_y);
}
void Button::setFillColor(sf::Color&& color)
{
_button_content.setFillColor(std::move(color));
}
void Button::setText(const std::string& text)
{
_button_text.setString(text);

View File

@ -13,11 +13,11 @@ public:
virtual void input(const sf::Event& event) override = 0;
virtual void update() override final;
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const override final;
virtual void setRect(const sf::FloatRect& rect) override final;
virtual void setPosition(const sf::Vector2f& position) override final;
virtual bool isUnderMouse(int mouse_x, int mouse_y) const override final;
virtual void setFillColor(sf::Color&& color);
virtual void setRect(const sf::FloatRect& rect) override;
virtual void setText(const std::string& text);
protected:

View File

@ -7,7 +7,8 @@ CascadeMenuButton::CascadeMenuButton(const std::string& text) :
void CascadeMenuButton::input(const sf::Event& event)
{
Button::input(event);
if (!_submenu)
return;
switch (event.type)
{
@ -29,7 +30,28 @@ void CascadeMenuButton::input(const sf::Event& event)
}
}
void CascadeMenuButton::setRect(const sf::FloatRect& rect)
{
Button::setRect(rect);
resetRect(_submenu);
}
void CascadeMenuButton::setSubmenu(const std::shared_ptr<MenuDrop>& submenu)
{
_submenu = submenu;
resetRect(_submenu);
}
const std::shared_ptr<MenuDrop> CascadeMenuButton::submenu() const
{
return _submenu;
}
void CascadeMenuButton::resetRect(const std::shared_ptr<MenuDrop>& submenu)
{
if (submenu)
{
submenu->setPosition({_button_content.getPosition().x + _button_content.getSize().x,
_button_content.getPosition().y});
}
}

View File

@ -9,10 +9,14 @@ class CascadeMenuButton : public Button
public:
explicit CascadeMenuButton(const std::string& text);
virtual void input(const sf::Event& event) override final;
virtual void setRect(const sf::FloatRect& rect) override final;
void setSubmenu(const std::shared_ptr<MenuDrop>& submenu);
const std::shared_ptr<MenuDrop> submenu() const;
private:
std::shared_ptr<MenuDrop> _submenu;
void resetRect(const std::shared_ptr<MenuDrop>& submenu);
};

View File

@ -9,6 +9,20 @@ MenuBar::MenuBar() :
void MenuBar::input(const sf::Event &event)
{
switch (event.type)
{
default:
break;
case sf::Event::MouseButtonReleased:
if (!isUnderMouse(event.mouseButton.x, event.mouseButton.y))
{
for (auto& submenu : _submenus)
submenu->unlock();
}
break;
}
Widget::input(event);
}
@ -19,7 +33,9 @@ void MenuBar::update()
void MenuBar::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
if (_is_visible)
target.draw(_bar_rect, states);
Widget::draw(target, states);
}
@ -51,15 +67,32 @@ bool MenuBar::isUnderMouse(int mouse_x, int mouse_y) const
void MenuBar::addSubMenu(std::string name, const std::shared_ptr<MenuDrop>& submenu)
{
const auto new_button = std::make_shared<Button>(name);
const auto new_button = std::make_shared<PushButton>(name);
std::size_t current_index = _amount_buttons;
new_button->setRect(sf::FloatRect(current_index * _button_width, 0, _button_width, _bar_rect.getSize().y));
new_button->setCallback([submenu=submenu]()
{
submenu->trigger();
submenu->setVisibility(true);
submenu->lock();
});
new_button->setFillColor(sf::Color(171, 141, 189));
submenu->setPosition({static_cast<float>(current_index * _button_width),
_bar_rect.getSize().y});
new_button->setFillColors(sf::Color(171, 141, 189), sf::Color(48, 27, 57));
addChild(new_button);
addChild(submenu);
_submenus.emplace_back(submenu);
++_amount_buttons;
}
void MenuBar::setVisibility(bool is_visible)
{
Widget::setVisibility(is_visible);
for (auto& submenu : _submenus)
submenu->setVisibility(false);
}

View File

@ -17,6 +17,7 @@ public:
virtual void setRect(const sf::FloatRect& rect) override;
virtual void setPosition(const sf::Vector2f& position) override;
virtual bool isUnderMouse(int mouse_x, int mouse_y) const override;
virtual void setVisibility(bool is_visible = true) override;
void addSubMenu(std::string name, const std::shared_ptr<MenuDrop>& submenu);
@ -24,4 +25,6 @@ private:
sf::RectangleShape _bar_rect;
std::size_t _amount_buttons;
std::size_t _button_width;
std::vector<std::shared_ptr<MenuDrop>> _submenus;
};

View File

@ -5,32 +5,43 @@ MenuDrop::MenuDrop() :
_is_locked(false),
_button_height(27),
_button_index(0)
{}
{
setVisibility(false);
_content_rect.setFillColor(sf::Color(200, 200, 200));
}
void MenuDrop::input(const sf::Event& event)
{
if (!_is_visible)
return;
Widget::input(event);
switch (event.type)
{
default:
break;
case sf::Event::MouseButtonReleased:
case sf::Event::MouseMoved:
if (isUnderMouse(event.mouseButton.x, event.mouseButton.y))
if (!isUnderMouse(event.mouseButton.x, event.mouseButton.y))
{
Widget::input(event);
}
else
{
if (!isLocked())
if (!isLocked() && !hasActiveSubmenus())
setVisibility(false);
}
break;
}
}
bool MenuDrop::hasActiveSubmenus() const
{
return std::any_of(_submenus.begin(), _submenus.end(),
[](const auto& submenu) -> bool
{
return submenu->_is_visible;
});
}
void MenuDrop::update()
{
Widget::update();
@ -38,7 +49,9 @@ void MenuDrop::update()
void MenuDrop::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
if (_is_visible)
target.draw(_content_rect);
Widget::draw(target, states);
}
@ -58,8 +71,24 @@ bool MenuDrop::isUnderMouse(int mouse_x, int mouse_y) const
return _is_visible && _content_rect.getGlobalBounds().contains(mouse_x, mouse_y);
}
void MenuDrop::addButton(const std::shared_ptr<Button>& button)
void MenuDrop::setVisibility(bool is_visible)
{
Widget::setVisibility(is_visible);
if (!is_visible)
_is_locked = false;
}
void MenuDrop::addPushButton(const std::shared_ptr<PushButton>& button)
{
add(button);
}
void MenuDrop::addCascadeButton(const std::shared_ptr<CascadeMenuButton>& button)
{
auto& submenu = button->submenu();
submenu->setParent(_parent);
_submenus.emplace_back();
add(button);
}
@ -79,6 +108,7 @@ void MenuDrop::add(const std::shared_ptr<Widget> &widget)
_button_height));
addChild(widget);
++_button_index;
}
void MenuDrop::lock()

View File

@ -1,7 +1,8 @@
#pragma once
#include "widget.h"
#include "button.h"
#include "pushbutton.h"
#include "cascademenubutton.h"
#include <SFML/Graphics/RectangleShape.hpp>
class MenuDrop : public Widget
@ -15,8 +16,10 @@ public:
virtual void setRect(const sf::FloatRect& rect) override;
virtual void setPosition(const sf::Vector2f& position) override;
virtual bool isUnderMouse(int mouse_x, int mouse_y) const override;
virtual void setVisibility(bool is_visible = true) override;
void addButton(const std::shared_ptr<Button>& button);
void addPushButton(const std::shared_ptr<PushButton>& button);
void addCascadeButton(const std::shared_ptr<CascadeMenuButton>& button);
void addSeparator();
void lock();
@ -30,5 +33,8 @@ private:
std::size_t _button_height;
std::size_t _button_index;
std::vector<std::shared_ptr<MenuDrop>> _submenus;
void add(const std::shared_ptr<Widget>& widget);
bool hasActiveSubmenus() const;
};

View File

@ -3,12 +3,13 @@
PushButton::PushButton(const std::string& text) :
Button(text),
_pressed(false)
{}
{
_color_idle = sf::Color(230, 230, 230);
_color_pressed = sf::Color(200, 200, 200);
}
void PushButton::input(const sf::Event& event)
{
Button::input(event);
switch (event.type)
{
default:
@ -18,14 +19,14 @@ void PushButton::input(const sf::Event& event)
if (isUnderMouse(event.mouseButton.x, event.mouseButton.y))
{
_pressed = true;
_button_content.setFillColor(sf::Color(155, 155, 155));
_button_content.setFillColor(sf::Color(_color_pressed));
}
break;
case sf::Event::MouseButtonReleased:
if (_pressed)
{
_button_content.setFillColor(sf::Color::White);
_button_content.setFillColor(_color_idle);
_pressed = false;
if (isUnderMouse(event.mouseButton.x, event.mouseButton.y))
_on_click_callback();
@ -38,3 +39,11 @@ void PushButton::setCallback(std::function<void(void)> callback)
{
_on_click_callback = callback;
}
void PushButton::setFillColors(sf::Color&& idle_color, sf::Color&& pressed_color)
{
_color_idle = idle_color;
_color_pressed = pressed_color;
_button_content.setFillColor(_pressed ? pressed_color : idle_color);
}

View File

@ -9,8 +9,12 @@ public:
virtual void input(const sf::Event& event) override final;
void setCallback(std::function<void(void)> callback);
void setFillColors(sf::Color&& idle_color, sf::Color&& pressed_color);
private:
sf::Color _color_idle;
sf::Color _color_pressed;
bool _pressed;
std::function<void(void)> _on_click_callback;
};

View File

@ -1,10 +1,15 @@
#include "widget.h"
void Widget::input(const sf::Event &event)
{
if (_blocker)
_blocker->input(event);
else
{
for (auto& child : _children)
child->input(event);
}
}
void Widget::update()
{
@ -14,9 +19,6 @@ void Widget::update()
void Widget::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
if (!_is_visible)
return;
for (auto& child : _children)
child->draw(target, states);
}
@ -25,11 +27,33 @@ void Widget::setVisibility(bool is_visible)
{
_is_visible = is_visible;
for (auto& child : _children)
child->setVisibility(false);
child->setVisibility(_is_visible);
}
void Widget::addChild(const std::shared_ptr<Widget>& child)
{
child->_parent = shared_from_this();
child->setParent(shared_from_this());
const auto iterator = std::find(_children.begin(), _children.end(), child);
if (iterator == _children.end())
_children.emplace_back(child);
}
void Widget::setParent(const std::shared_ptr<Widget>& parent)
{
if (_parent != parent)
{
_parent = parent;
_parent->addChild(shared_from_this());
}
}
void Widget::blockBy(const std::shared_ptr<Widget>& blocker)
{
_blocker = blocker;
}
void Widget::unblock()
{
_blocker = nullptr;
}

View File

@ -18,12 +18,16 @@ public:
virtual void setPosition(const sf::Vector2f& position) = 0;
virtual bool isUnderMouse(int mouse_x, int mouse_y) const = 0;
void setVisibility(bool is_visible = true);
virtual void setVisibility(bool is_visible = true);
void addChild(const std::shared_ptr<Widget>& child);
void setParent(const std::shared_ptr<Widget>& parent);
void blockBy(const std::shared_ptr<Widget>& blocker);
void unblock();
protected:
std::vector<std::shared_ptr<Widget>> _children;
std::shared_ptr<Widget> _parent;
std::shared_ptr<Widget> _blocker;
bool _is_visible = true;
};