/* * Copyright (C) 2019 Max Regan * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #pragma once #include "macros.h" #include #include "SystemFonts.h" #include "ScreenManager.h" #include "Screen.h" struct MenuScreenItem { enum class Type{ NONE, SCREEN, BACK, }; MenuScreenItem() : m_text(nullptr) , m_screen(nullptr) , m_type(Type::NONE) {} MenuScreenItem(const char *item, Screen &m_screen) : m_text(item) , m_screen(&m_screen) , m_type(Type::SCREEN) {} MenuScreenItem(const char *item) : m_text(item) , m_screen(nullptr) , m_type(Type::BACK) {} const char *m_text; Screen *m_screen; Type m_type; }; class MenuScreen : public Screen { public: static constexpr std::size_t MAX_ITEMS = 10; MenuScreen(BSP::DisplayDriver &display, ScreenManager &manager, std::initializer_list items) : m_driver(display) , m_manager(manager) , m_items() , m_num_items{0} , m_selected{0} { for (auto &item : items) { m_items[m_num_items++] = item; // Leave room for "back" if (m_num_items == MAX_ITEMS - 1) { break; } } new (&m_items[m_num_items++]) MenuScreenItem("Back"); } void render() { const struct font &font = default_font; // const uint32_t font_width = default_font_width; m_driver.clear(); for (std::size_t i = 0; i < m_num_items; i++) { uint32_t x = 0; uint32_t y = 8 + (font.size + 8) * i; const char *spacer = " "; if (i == m_selected) { spacer = ">"; } m_driver.string_at(&x, y, spacer, &font); m_driver.string_at(&x, y, m_items[i].m_text, &font); } m_driver.refresh(); } Common::ReturnCode init() { return Common::ReturnCode::OK; } Common::Schedule::NextTime execute() override { return Common::Schedule::NextTime::never(); } void enable() override { m_selected = 0; render(); } void disable() override { m_driver.clear(); } void notify_up_button() override { if (m_selected == 0) { m_selected = m_num_items - 1; } else { m_selected--; } render(); } void notify_middle_button() override { MenuScreenItem &item = m_items[m_selected]; if (item.m_type == MenuScreenItem::Type::SCREEN) { m_manager.push_screen(*item.m_screen); } else if (item.m_type == MenuScreenItem::Type::BACK) { m_manager.pop_screen(); } } void notify_down_button() override { if (m_selected == m_num_items - 1) { m_selected = 0; } else { m_selected++; } render(); } private: BSP::DisplayDriver &m_driver; ScreenManager &m_manager; MenuScreenItem m_items[MAX_ITEMS]; std::size_t m_num_items; std::size_t m_selected; };