diff --git a/bootloader/interface.h b/bootloader/interface.h index b21eb0e38..b89c3ce25 100644 --- a/bootloader/interface.h +++ b/bootloader/interface.h @@ -6,13 +6,10 @@ #include namespace Bootloader { - class Interface { -private: - static void drawImage(KDContext * ctx, const Image * image, int offset); - public: + static void drawImage(KDContext * ctx, const Image * image, int offset); static void drawLoading(); static void drawHeader(); static void drawMenu(); diff --git a/bootloader/interface/menus/about/about.cpp b/bootloader/interface/menus/about/about.cpp new file mode 100644 index 000000000..4c73b95bc --- /dev/null +++ b/bootloader/interface/menus/about/about.cpp @@ -0,0 +1,13 @@ +#include "about.h" + +Bootloader::AboutMenu::AboutMenu() : Menu(KDColorBlack, KDColorWhite, Messages::aboutMenuTitle, Messages::bootloaderVersion) { + setup(); +} + +void Bootloader::AboutMenu::setup() { + m_colomns[0] = Colomn("This is the bootloader of", k_small_font, 0, true); + m_colomns[1] = Colomn("the Upsilon Calculator.", k_small_font, 0, true); + m_colomns[2] = Colomn("It is used to install", k_small_font, 0, true); + m_colomns[3] = Colomn("and select the OS", k_small_font, 0, true); + m_colomns[4] = Colomn("to boot.", k_small_font, 0, true); +} \ No newline at end of file diff --git a/bootloader/interface/menus/about/about.h b/bootloader/interface/menus/about/about.h new file mode 100644 index 000000000..96dc86c11 --- /dev/null +++ b/bootloader/interface/menus/about/about.h @@ -0,0 +1,17 @@ +#ifndef _BOOTLOADER_INTERFACE_ABOUT_ABOUT_H_ +#define _BOOTLOADER_INTERFACE_ABOUT_ABOUT_H_ + +#include + +namespace Bootloader { + class AboutMenu : public Menu { + public: + AboutMenu(); + + void setup() override; + + }; +} + + +#endif \ No newline at end of file diff --git a/bootloader/interface/menus/home/home.cpp b/bootloader/interface/menus/home/home.cpp new file mode 100644 index 000000000..df909d06f --- /dev/null +++ b/bootloader/interface/menus/home/home.cpp @@ -0,0 +1,62 @@ +#include "home.h" +#include +#include + +Bootloader::AboutMenu * Bootloader::HomeMenu::aboutMenu() { + static AboutMenu * aboutMenu = new AboutMenu(); + return aboutMenu; +} + +Bootloader::HomeMenu::HomeMenu() : Menu(KDColorBlack, KDColorWhite, Messages::mainMenuTitle, Messages::mainTitle) { + setup(); +} + +bool slotA_submenu() { + if (Bootloader::Slot::isFullyValid(Bootloader::Slot::A())) { + + } + return false; +} + +bool slotKhi_submenu() { + if (Bootloader::Slot::isFullyValid(Bootloader::Slot::Khi())) { + + } + return false; +} + +bool slotB_submenu() { + if (Bootloader::Slot::isFullyValid(Bootloader::Slot::B())) { + + } + return false; +} + +bool installer_submenu() { + +} + +bool about_submenu() { + Bootloader::HomeMenu::aboutMenu()->open(); + return true; +} + +const char * Bootloader::HomeMenu::slotA_text() { + return Slot::isFullyValid(Slot::A()) ? "1 - Slot A" : Messages::invalidSlot; +} + +const char * Bootloader::HomeMenu::slotKhi_text() { + return Slot::isFullyValid(Slot::Khi()) ? "2 - Slot Khi" : Messages::invalidSlot; +} + +const char * Bootloader::HomeMenu::slotB_text() { + return Slot::isFullyValid(Slot::B()) ? "3 - Slot B" : Messages::invalidSlot; +} + +void Bootloader::HomeMenu::setup() { + m_colomns[0] = Colomn(slotA_text(), Ion::Keyboard::Key::One, k_large_font, 10, false, &slotA_submenu); + m_colomns[1] = Colomn(slotKhi_text(), Ion::Keyboard::Key::Two, k_large_font, 10, false, &slotKhi_submenu); + m_colomns[2] = Colomn(slotB_text(), Ion::Keyboard::Key::Three, k_large_font, 10, false, &slotB_submenu); + m_colomns[3] = Colomn("4- installer", Ion::Keyboard::Key::Four, k_large_font, 10, false, &installer_submenu); + m_colomns[4] = Colomn("5- about", Ion::Keyboard::Key::Five, k_large_font, 10, false, &about_submenu); +} \ No newline at end of file diff --git a/bootloader/interface/menus/home/home.h b/bootloader/interface/menus/home/home.h new file mode 100644 index 000000000..6f6c43037 --- /dev/null +++ b/bootloader/interface/menus/home/home.h @@ -0,0 +1,23 @@ +#ifndef _BOOTLOADER_INTERFACE_HOME_HOME_H_ +#define _BOOTLOADER_INTERFACE_HOME_HOME_H_ + +#include +#include + +namespace Bootloader { + class HomeMenu : public Menu { + public: + HomeMenu(); + + void setup() override; + static AboutMenu * aboutMenu(); + + private: + const char * slotA_text(); + const char * slotKhi_text(); + const char * slotB_text(); + + }; +} + +#endif diff --git a/bootloader/interface/menus/installer/installer.h b/bootloader/interface/menus/installer/installer.h new file mode 100644 index 000000000..be9f49fb4 --- /dev/null +++ b/bootloader/interface/menus/installer/installer.h @@ -0,0 +1,15 @@ +#ifndef _BOOTLOADER_INTERFACE_MENUS_INSTALLER_INSTALLER_H_ +#define _BOOTLOADER_INTERFACE_MENUS_INSTALLER_INSTALLER_H_ + +#include + +namespace Bootloader { + class InstallerMenu : public Menu { + public: + InstallerMenu(); + + void setup() override; + }; +} + +#endif \ No newline at end of file diff --git a/bootloader/interface/src/menu.cpp b/bootloader/interface/src/menu.cpp new file mode 100644 index 000000000..09ccaa15a --- /dev/null +++ b/bootloader/interface/src/menu.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include + +#include "computer.h" + +void Bootloader::Menu::setup() { + // Here we add the colomns to the menu. +} + +void Bootloader::Menu::open() { + showMenu(); + + uint64_t scan = 0; + bool exit = false; + + while(!exit) { + scan = Ion::Keyboard::scan(); + exit = !handleKey(scan); + } +} + +int Bootloader::Menu::calculateCenterX(const char * text, int fontWidth) { + return (k_screen.width() - fontWidth * strlen(text)) / 2; +} + +void Bootloader::Menu::showMenu() { + KDContext * ctx = KDIonContext::sharedContext(); + ctx->fillRect(k_screen, m_background); + Interface::drawImage(ctx, ImageStore::Computer, 25); + int y = ImageStore::Computer->height() + 25 + 10; + int x = calculateCenterX(m_title, largeFontWidth()); + ctx->drawString(m_title, KDPoint(x, y), k_large_font, m_foreground, m_background); + y += largeFontHeight() + 10; + + //TODO: center the colomns if m_centerY is true + + for (Colomn & colomn : m_colomns) { + if (colomn.isNull()) { + break; + } + y += colomn.draw(ctx, y, m_background, m_foreground) + k_colomns_margin; + } + + if (m_bottom != nullptr) { + y = k_screen.height() - smallFontHeight() - 10; + x = calculateCenterX(m_bottom, smallFontWidth()); + ctx->drawString(m_bottom, KDPoint(x, y), k_small_font, m_foreground, m_background); + } +} + +bool Bootloader::Menu::handleKey(uint64_t key) { + for (Ion::Keyboard::Key breaking : this->k_breaking_keys) { + if (Ion::Keyboard::State(breaking) == key) { + return false; + } + } + if (key == Ion::Keyboard::State(Ion::Keyboard::Key::Power)) { + Ion::Power::standby(); + return false; + } + for (Colomn & colomn : this->m_colomns) { + if (colomn.isNull() || !colomn.isClickable()) { + continue; + } else { + colomn.didHandledEvent(key); + } + } + return true; +} + +bool Bootloader::Menu::Colomn::didHandledEvent(uint64_t key) { + if (isMyKey(key) && isClickable()) { + return m_callback(); + } + return false; +} + +int Bootloader::Menu::Colomn::draw(KDContext * ctx, int y, KDColor background, KDColor foreground) { + int x = m_extraX; + if (m_center) { + x += Bootloader::Menu::calculateCenterX(m_text, m_font->glyphSize().width()); + } + ctx->drawString(m_text, KDPoint(x, y), m_font, foreground, background); + return m_font->glyphSize().height(); +} diff --git a/bootloader/interface/src/menu.h b/bootloader/interface/src/menu.h new file mode 100644 index 000000000..9b9c5bf00 --- /dev/null +++ b/bootloader/interface/src/menu.h @@ -0,0 +1,83 @@ +#ifndef _BOOTLOADER_MENU_H_ +#define _BOOTLOADER_MENU_H_ + +#include +#include +#include + +namespace Bootloader { + class Menu { + public: + Menu() : m_colomns(), m_background(KDColorWhite), m_title(Messages::mainTitle), m_foreground(KDColorBlack), m_bottom(nullptr), m_centerY(false) { + setup(); + }; + Menu(KDColor forground, KDColor background, const char * title) : m_colomns(), m_background(background), m_title(title), m_foreground(forground), m_bottom(nullptr), m_centerY(false) { + setup(); + }; + Menu(KDColor forground, KDColor background, const char * title, const char * bottom) : m_colomns(), m_background(background), m_title(title), m_foreground(forground), m_bottom(bottom), m_centerY(false) { + setup(); + }; + Menu(KDColor forground, KDColor background, const char * title, const char * bottom, bool centerY) : m_colomns(), m_background(background), m_title(title), m_foreground(forground), m_bottom(bottom), m_centerY(centerY) { + setup(); + } + + virtual void setup() = 0; + + class Colomn { + public: + Colomn() : m_text(nullptr), m_key(Ion::Keyboard::Key::None), m_font(KDFont::SmallFont), m_extraX(0), m_center(false), m_callback(nullptr) {}; + Colomn(const char * t, Ion::Keyboard::Key k, const KDFont * font, int extraX, bool center, bool(*pointer)()) : m_text(t), m_key(k), m_font(font), m_extraX(extraX), m_center(center), m_callback(pointer), m_clickable(true) {}; + Colomn(const char * t, const KDFont * font, int extraX, bool center) : m_text(t), m_key(Ion::Keyboard::Key::None), m_font(font), m_extraX(extraX), m_center(center), m_callback(nullptr), m_clickable(false) {}; + + bool isNull() const { return m_text == nullptr; }; + bool isClickable() const { return m_clickable; }; + bool didHandledEvent(uint64_t key); + int draw(KDContext * ctx, int y, KDColor background, KDColor foreground); + + private: + bool isMyKey(uint64_t key) const { return Ion::Keyboard::State(m_key) == key; }; + + const char * m_text; + Ion::Keyboard::Key m_key; + const KDFont * m_font; + int m_extraX; + bool m_center; + bool m_clickable; + bool (*m_callback)(); + }; + + void open(); + void redraw() { showMenu(); }; + + static int calculateCenterX(const char * text, int fontWidth); + + static constexpr const KDFont * k_small_font = KDFont::SmallFont; + static constexpr const KDFont * k_large_font = KDFont::LargeFont; + + private: + static const int k_max_colomns = 5; + static const int k_colomns_margin = 5; + + static constexpr Ion::Keyboard::Key k_breaking_keys[] = {Ion::Keyboard::Key::Back, Ion::Keyboard::Key::Home}; + static constexpr KDRect k_screen = KDRect(0, 0, 320, 240); + + int smallFontHeight() const { return k_small_font->glyphSize().height(); }; + int largeFontHeight() const { return k_large_font->glyphSize().height(); }; + + int smallFontWidth() const { return k_small_font->glyphSize().width(); }; + int largeFontWidth() const { return k_large_font->glyphSize().width(); }; + + bool handleKey(uint64_t key); + void showMenu(); + + protected: + Colomn m_colomns[k_max_colomns]; + KDColor m_background; + KDColor m_foreground; + const char * m_title; + const char * m_bottom; + bool m_centerY; + }; +} + +#endif // _BOOTLOADER_MENU_H_ \ No newline at end of file diff --git a/bootloader/messages.h b/bootloader/messages.h index 9f2f01808..6d8e90c39 100644 --- a/bootloader/messages.h +++ b/bootloader/messages.h @@ -45,6 +45,7 @@ public: constexpr static const char * epsilonWarningText5 = "EXE - Yes"; constexpr static const char * epsilonWarningText6 = "BACK - No"; constexpr static const char * bootloaderVersion = "Version 1.0.0 - FREEDOM"; + constexpr static const char * aboutMenuTitle = "About"; //USB NAMES diff --git a/bootloader/slot.h b/bootloader/slot.h index f82b5b6d9..0550b0222 100644 --- a/bootloader/slot.h +++ b/bootloader/slot.h @@ -24,6 +24,10 @@ public: static const Slot B(); static const Slot Khi(); + static bool isFullyValid(const Slot& slot) { + return slot.kernelHeader()->isValid() && slot.userlandHeader()->isValid(); + } + private: const KernelHeader* m_kernelHeader; const UserlandHeader* m_userlandHeader;