From 4c595d04392dae2f89f983ffcce20738e88416a9 Mon Sep 17 00:00:00 2001 From: Daniel Evans Date: Wed, 1 Jan 2014 00:37:16 +0000 Subject: [PATCH] Menu directional movement support --- tests/test_menu.cpp | 40 ++++++++++++++++++++++++- viewer/MenuSystem.hpp | 70 ++++++++++++++++++++++++++++++++++--------- viewer/State.hpp | 19 ++++++++++++ viewer/main.cpp | 4 +-- 4 files changed, 116 insertions(+), 17 deletions(-) diff --git a/tests/test_menu.cpp b/tests/test_menu.cpp index 28b4485d..6719d45e 100644 --- a/tests/test_menu.cpp +++ b/tests/test_menu.cpp @@ -34,7 +34,7 @@ BOOST_AUTO_TEST_CASE(menu_test_click_offset) bool clickered = false; sf::Font f; Menu test(f); - test.offset = sf::Vector2f(200.f, 200.f); + test.offset = glm::vec2(200.f, 200.f); test.addEntry(Menu::lambda("Test", [&]{ clickered = true; })); BOOST_CHECK(! clickered ); @@ -55,4 +55,42 @@ BOOST_AUTO_TEST_CASE(menu_test_click_offset) BOOST_CHECK( clickered ); } +BOOST_AUTO_TEST_CASE(menu_test_active_index) +{ + int clickindex = -1; + sf::Font f; + Menu test(f); + test.addEntry(Menu::lambda("Test1", [&]{ clickindex = 0; })); + test.addEntry(Menu::lambda("Test2", [&]{ clickindex = 1; })); + + test.activate(); + + BOOST_CHECK( clickindex == 0 ); + + test.move( 1); + test.activate(); + + BOOST_CHECK( clickindex == 1 ); + + test.move(-1); + test.activate(); + + BOOST_CHECK( clickindex == 0 ); +} + +BOOST_AUTO_TEST_CASE(menu_test_hover_index) +{ + int clickindex = -1; + sf::Font f; + Menu test(f); + test.addEntry(Menu::lambda("Test1", [&]{ clickindex = 0; })); + test.addEntry(Menu::lambda("Test2", [&]{ clickindex = 1; })); + + test.hover(0.f, test.entries[0]->getHeight() - 0.1f); + BOOST_CHECK( test.activeEntry == 0 ); + + test.hover(0.f, test.entries[0]->getHeight() + 0.1f); + BOOST_CHECK( test.activeEntry == 1 ); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/viewer/MenuSystem.hpp b/viewer/MenuSystem.hpp index ce9ed8e8..34fd8f3c 100644 --- a/viewer/MenuSystem.hpp +++ b/viewer/MenuSystem.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include class Menu @@ -12,7 +13,7 @@ class Menu public: Menu(const sf::Font& font) - : font(font) {} + : font(font), activeEntry(-1) {} struct MenuEntry { @@ -20,19 +21,19 @@ public: MenuEntry(const std::string& n) : name(n) {} - float getHeight() { return 30.f; } + float getHeight() { return 38.f; } - virtual void draw(const sf::Font& font, sf::RenderWindow& window, sf::Vector2f& basis) + virtual void draw(const sf::Font& font, sf::RenderWindow& window, glm::vec2& basis) { sf::Text t; t.setFont(font); - t.setPosition(basis); + t.setPosition(basis.x, basis.y); t.setString(name); window.draw(t); basis.y += getHeight(); } - virtual void activate(sf::Vector2f click) = 0; + virtual void activate(float clickX, float clickY) = 0; }; struct Entry : public MenuEntry @@ -42,7 +43,7 @@ public: Entry(const std::string& title, std::function cb) : MenuEntry(title), callback(cb) {} - void activate(sf::Vector2f click) { callback(); } + void activate(float clickX, float clickY) { callback(); } }; static std::shared_ptr lambda(const std::string& n, std::function callback) @@ -52,7 +53,12 @@ public: std::vector> entries; - sf::Vector2f offset; + /** + * Active Entry index + */ + int activeEntry; + + glm::vec2 offset; void addEntry(std::shared_ptr entry) { @@ -61,24 +67,47 @@ public: void draw(sf::RenderWindow& window) { - sf::Vector2f basis(offset); - for(auto it = entries.begin(); - it != entries.end(); - ++it) + glm::vec2 basis(offset); + for(size_t i = 0; + i < entries.size(); + ++i) { - (*it)->draw(font, window, basis); + if(activeEntry >= 0 && i == activeEntry) { + sf::RectangleShape rs(sf::Vector2f(500.f, entries[i]->getHeight())); + rs.setPosition(basis.x, basis.y); + rs.setFillColor(sf::Color::Cyan); + window.draw(rs); + } + entries[i]->draw(font, window, basis); + } + } + + void hover(const float x, const float y) + { + glm::vec2 c(x - offset.x, y - offset.y); + for(size_t i = 0; + i < entries.size(); + ++i) + { + if( c.y > 0.f && c.y < entries[i]->getHeight() ) { + activeEntry = i; + return; + } + else { + c.y -= entries[i]->getHeight(); + } } } void click(const float x, const float y) { - sf::Vector2f c(x - offset.x, y - offset.y); + glm::vec2 c(x - offset.x, y - offset.y); for(auto it = entries.begin(); it != entries.end(); ++it) { if( c.y > 0.f && c.y < (*it)->getHeight() ) { - (*it)->activate(c); + (*it)->activate(c.x, c.y); return; } else { @@ -86,6 +115,19 @@ public: } } } + + // Activates the menu entry at the current active index. + void activate() + { + if(activeEntry < entries.size()) { + entries[activeEntry]->activate(0.f, 0.f); + } + } + + void move(int movement) + { + activeEntry = std::min(entries.size()-1, std::max(0, activeEntry + movement)); + } }; #endif \ No newline at end of file diff --git a/viewer/State.hpp b/viewer/State.hpp index 5bd660b1..5e20dbe3 100644 --- a/viewer/State.hpp +++ b/viewer/State.hpp @@ -38,6 +38,25 @@ struct State currentMenu->click(e.mouseButton.x, e.mouseButton.y); } break; + case sf::Event::MouseMoved: + if(currentMenu) { + currentMenu->hover(e.mouseMove.x, e.mouseMove.y); + } + break; + case sf::Event::KeyPressed: + if(currentMenu) { + switch(e.key.code) { + case sf::Keyboard::Up: + currentMenu->move(-1); + break; + case sf::Keyboard::Down: + currentMenu->move(1); + break; + case sf::Keyboard::Return: + currentMenu->activate(); + break; + } + } default: break; }; } diff --git a/viewer/main.cpp b/viewer/main.cpp index 5291f453..c53b294c 100644 --- a/viewer/main.cpp +++ b/viewer/main.cpp @@ -649,7 +649,7 @@ GenericState pauseState( [](State* self) { Menu *m = new Menu(font); - m->offset = sf::Vector2f(50.f, 100.f); + m->offset = glm::vec2(50.f, 100.f); m->addEntry(Menu::lambda("Continue", [] { StateManager::get().exit(); })); m->addEntry(Menu::lambda("Options", [] { std::cout << "Options" << std::endl; })); m->addEntry(Menu::lambda("Exit", [] { window.close(); })); @@ -719,7 +719,7 @@ GenericState menuState( [](State* self) { Menu *m = new Menu(font); - m->offset = sf::Vector2f(50.f, 100.f); + m->offset = glm::vec2(50.f, 100.f); m->addEntry(Menu::lambda("Test", [] { StateManager::get().enter(&gameState); })); m->addEntry(Menu::lambda("Options", [] { std::cout << "Options" << std::endl; })); m->addEntry(Menu::lambda("Exit", [] { window.close(); }));