diff --git a/src/Makefile.am b/src/Makefile.am index 0ce802a..70a635d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,7 +13,7 @@ gmenu2x_SOURCES = font.cpp button.cpp cpu.cpp dirdialog.cpp filedialog.cpp \ utilities.cpp wallpaperdialog.cpp \ browsedialog.cpp buttonbox.cpp dialog.cpp \ imageio.cpp powersaver.cpp monitor.cpp mediamonitor.cpp clock.cpp \ - helppopup.cpp background.cpp battery.cpp + helppopup.cpp contextmenu.cpp background.cpp battery.cpp noinst_HEADERS = font.h button.h cpu.h dirdialog.h \ filedialog.h filelister.h gmenu2x.h gp2x.h iconbutton.h imagedialog.h \ @@ -27,7 +27,7 @@ noinst_HEADERS = font.h button.h cpu.h dirdialog.h \ touchscreen.h translator.h utilities.h wallpaperdialog.h \ browsedialog.h buttonbox.h dialog.h \ imageio.h powersaver.h monitor.h mediamonitor.h clock.h \ - layer.h helppopup.h background.h battery.h + layer.h helppopup.h contextmenu.h background.h battery.h AM_CFLAGS= @CFLAGS@ @SDL_CFLAGS@ diff --git a/src/contextmenu.cpp b/src/contextmenu.cpp new file mode 100644 index 0000000..acfdde9 --- /dev/null +++ b/src/contextmenu.cpp @@ -0,0 +1,181 @@ +// Various authors. +// License: GPL version 2 or later. + +#include "contextmenu.h" + +#include "delegate.h" +#include "gmenu2x.h" +#include "linkapp.h" +#include "menu.h" +#include "utilities.h" + +#include + + +struct ContextMenu::MenuOption { + MenuOption(std::string text, function_t action) + : text(text), action(action) {} + std::string text; + function_t action; +}; + +ContextMenu::ContextMenu(GMenu2X &gmenu2x, Menu &menu) + : gmenu2x(gmenu2x) + , menu(menu) + , fadeAlpha(0) + , selected(0) +{ + Translator &tr = gmenu2x.tr; + Font *font = gmenu2x.font; + LinkApp* app = menu.selLinkApp(); + + // Init menu options: + + options.push_back(std::make_shared( + tr.translate("Add link in $1", menu.selSection().c_str(), NULL), + std::bind(&GMenu2X::addLink, &gmenu2x))); + + if (app && !app->getManual().empty()) { + options.push_back(std::make_shared( + tr.translate("Show manual of $1", app->getTitle().c_str(), NULL), + std::bind(&GMenu2X::showManual, &gmenu2x))); + } + + if (app && app->isEditable()) { + + /* FIXME(percuei): This permits to mask the "Edit link" entry + * on the contextual menu in case CPUFREQ support is + * not compiled in and the link corresponds to an OPK. + * This is not a good idea as it'll break things if + * a new config option is added to the contextual menu. + */ +#if defined(HAVE_LIBOPK) && !defined(ENABLE_CPUFREQ) + if (!app->isOpk() || !app->getSelectorDir().empty()) +#endif + { + options.push_back(std::make_shared( + tr.translate("Edit $1", app->getTitle().c_str(), NULL), + std::bind(&GMenu2X::editLink, &gmenu2x))); + } +#ifdef HAVE_LIBOPK + if (!app->isOpk()) +#endif + { + options.push_back(std::make_shared( + tr.translate("Delete $1 link", app->getTitle().c_str(), NULL), + std::bind(&GMenu2X::deleteLink, &gmenu2x))); + } + } + + options.push_back(std::make_shared( + tr["Add section"], + std::bind(&GMenu2X::addSection, &gmenu2x))); + options.push_back(std::make_shared( + tr["Rename section"], + std::bind(&GMenu2X::renameSection, &gmenu2x))); + options.push_back(std::make_shared( + tr["Delete section"], + std::bind(&GMenu2X::deleteSection, &gmenu2x))); + options.push_back(std::make_shared( + tr["Scan for applications and games"], + std::bind(&GMenu2X::scanner, &gmenu2x))); + + // Compute bounding box. + int w = 0; + for (auto option : options) { + w = std::max(w, font->getTextWidth(option->text)); + } + w += 23; + const int h = (font->getHeight() + 2) * options.size() + 8; + box = { + static_cast((gmenu2x.resX - w) / 2), + static_cast((gmenu2x.resY - h) / 2), + static_cast(w), + static_cast(h) + }; + + // Init background fade animation. + tickStart = SDL_GetTicks(); + startAnimating(); +} + +void ContextMenu::runAnimations() +{ + if (fadeAlpha < 200) { + const long tickNow = SDL_GetTicks(); + fadeAlpha = intTransition(0, 200, tickStart, 500, tickNow); + if (fadeAlpha == 200) { + stopAnimating(); + } + } +} + +void ContextMenu::paint(Surface &s) +{ + runAnimations(); + + Font *font = gmenu2x.font; + + // Darken background. + s.box(0, 0, gmenu2x.resX, gmenu2x.resY, 0, 0, 0, fadeAlpha); + + // Draw popup box. + s.box(box, gmenu2x.skinConfColors[COLOR_MESSAGE_BOX_BG]); + s.rectangle(box.x + 2, box.y + 2, box.w - 4, box.h - 4, + gmenu2x.skinConfColors[COLOR_MESSAGE_BOX_BORDER]); + + // Draw selection background. + const int h = font->getHeight(); + SDL_Rect selbox = { + static_cast(box.x + 4), + static_cast(box.y + 4 + (h + 2) * selected), + static_cast(box.w - 8), + static_cast(h + 2) + }; + s.box(selbox, gmenu2x.skinConfColors[COLOR_MESSAGE_BOX_SELECTION]); + + // List options. + for (uint i = 0; i < options.size(); i++) { + s.write(font, options[i]->text, box.x + 12, box.y + 5 + (h + 2) * i, + Font::HAlignLeft, Font::VAlignTop); + } +} + +bool ContextMenu::handleButtonPress(InputManager::Button button) { + switch (button) { + case InputManager::MENU: + dismiss(); + break; + case InputManager::UP: + selected = std::max(0, selected - 1); + break; + case InputManager::DOWN: + selected = std::min((int)options.size() - 1, selected + 1); + break; + case InputManager::ACCEPT: + options[selected]->action(); + dismiss(); + break; + default: + break; + } + return true; +} + +bool ContextMenu::handleTouchscreen(Touchscreen &ts) { + if (ts.inRect(box)) { + int i = std::max(0, std::min(static_cast(options.size()) - 1, + (ts.getY() - (box.y + 4)) / (gmenu2x.font->getHeight() + 2))); + if (ts.released()) { + options[i]->action(); + dismiss(); + } else if (ts.pressed()) { + selected = i; + } + } else { + if (ts.released()) { + dismiss(); + } + } + return true; +} diff --git a/src/contextmenu.h b/src/contextmenu.h new file mode 100644 index 0000000..bb2b2be --- /dev/null +++ b/src/contextmenu.h @@ -0,0 +1,43 @@ +// Various authors. +// License: GPL version 2 or later. + +#ifndef __CONTEXTMENU_H__ +#define __CONTEXTMENU_H__ + +#include "layer.h" + +#include +#include + +class GMenu2X; +class Menu; + + +/** + * A popup dialog containing action on the current section or link. + */ +class ContextMenu : public Layer { +public: + ContextMenu(GMenu2X &gmenu2x, Menu &menu); + + // Layer implementation: + virtual void paint(Surface &s); + virtual bool handleButtonPress(InputManager::Button button); + virtual bool handleTouchscreen(Touchscreen &ts); + +private: + struct MenuOption; + + void runAnimations(); + + GMenu2X &gmenu2x; + Menu &menu; + std::vector> options; + SDL_Rect box; + + int fadeAlpha; + int selected; + long tickStart; +}; + +#endif // __CONTEXTMENU_H__ diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 3b597b0..dfea743 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -81,13 +81,6 @@ #include -struct MenuOption { - MenuOption(std::string text, function_t action) - : text(text), action(action) {} - std::string text; - function_t action; -}; - using namespace std; #ifndef DEFAULT_WALLPAPER_PATH @@ -840,157 +833,8 @@ void GMenu2X::showManual() { menu->selLinkApp()->showManual(); } -void GMenu2X::contextMenu() { - vector> options; - LinkApp* app = menu->selLinkApp(); - - options.push_back(make_shared( - tr.translate("Add link in $1", menu->selSection().c_str(), NULL), - BIND(&GMenu2X::addLink))); - - if (app && !app->getManual().empty()) { - options.push_back(make_shared( - tr.translate("Show manual of $1", app->getTitle().c_str(), NULL), - BIND(&GMenu2X::showManual))); - } - - if (app && app->isEditable()) { - - /* FIXME(percuei): This permits to mask the "Edit link" entry - * on the contextual menu in case CPUFREQ support is - * not compiled in and the link corresponds to an OPK. - * This is not a good idea as it'll break things if - * a new config option is added to the contextual menu. - */ -#if defined(HAVE_LIBOPK) && !defined(ENABLE_CPUFREQ) - if (!app->isOpk() || !app->getSelectorDir().empty()) -#endif - { - options.push_back(make_shared( - tr.translate("Edit $1", app->getTitle().c_str(), NULL), - BIND(&GMenu2X::editLink))); - } -#ifdef HAVE_LIBOPK - if (!app->isOpk()) -#endif - { - options.push_back(make_shared( - tr.translate("Delete $1 link", app->getTitle().c_str(), NULL), - BIND(&GMenu2X::deleteLink))); - } - } - - options.push_back(make_shared( - tr["Add section"], BIND(&GMenu2X::addSection))); - options.push_back(make_shared( - tr["Rename section"], BIND(&GMenu2X::renameSection))); - options.push_back(make_shared( - tr["Delete section"], BIND(&GMenu2X::deleteSection))); - options.push_back(make_shared( - tr["Scan for applications and games"], BIND(&GMenu2X::scanner))); - - const int h = font->getHeight(); - SDL_Rect box; - box.h = (h + 2) * options.size() + 8; - box.w = 0; - for (auto option : options) { - box.w = max(box.w, static_cast(font->getTextWidth(option->text))); - } - box.w += 23; - box.x = halfX - box.w / 2; - box.y = halfY - box.h / 2; - - SDL_Rect selbox = { - static_cast(box.x + 4), - 0, - static_cast(box.w - 8), - static_cast(h + 2) - }; - const long tickStart = SDL_GetTicks(); - - Surface bg(s); - /*//Darken background - bg.box(0, 0, resX, resY, 0,0,0,150); - bg.box(box.x, box.y, box.w, box.h, skinConfColors["messageBoxBg"]); - bg.rectangle( box.x+2, box.y+2, box.w-4, box.h-4, skinConfColors["messageBoxBorder"] );*/ - - uint fadeAlpha = 0; - int sel = 0; - bool close = false; - while (!close) { - const long tickNow = SDL_GetTicks(); - - selbox.y = box.y + 4 + (h + 2) * sel; - bg.blit(s, 0, 0); - - if (fadeAlpha < 200) - fadeAlpha = intTransition(0, 200, tickStart, 500, tickNow); - s->box(0, 0, resX, resY, 0, 0, 0, fadeAlpha); - s->box(box.x, box.y, box.w, box.h, skinConfColors[COLOR_MESSAGE_BOX_BG]); - s->rectangle(box.x + 2, box.y + 2, box.w - 4, box.h - 4, - skinConfColors[COLOR_MESSAGE_BOX_BORDER]); - - //draw selection rect - s->box(selbox, skinConfColors[COLOR_MESSAGE_BOX_SELECTION]); - for (uint i = 0; i < options.size(); i++) - s->write(font, options[i]->text, box.x + 12, box.y + 5 + (h + 2) * i, - Font::HAlignLeft, Font::VAlignTop); - s->flip(); - - //touchscreen - if (ts.available()) { - ts.poll(); - if (ts.released()) { - if (!ts.inRect(box)) - close = true; - else if (ts.getX() >= selbox.x - && ts.getX() <= selbox.x + selbox.w) - for (uint i = 0; i < options.size(); i++) { - selbox.y = box.y + 4 + (h + 2) * i; - if (ts.getY() >= selbox.y - && ts.getY() <= selbox.y + selbox.h) { - options[i]->action(); - close = true; - i = options.size(); - } - } - } else if (ts.pressed() && ts.inRect(box)) { - for (uint i = 0; i < options.size(); i++) { - selbox.y = box.y + 4 + (h + 2) * i; - if (ts.getY() >= selbox.y - && ts.getY() <= selbox.y + selbox.h) { - sel = i; - i = options.size(); - } - } - } - } - - InputManager::ButtonEvent event; - if (fadeAlpha < 200) { - if (!input.pollEvent(&event) || event.state != InputManager::PRESSED) continue; - } else { - event.button = input.waitForPressedButton(); - } - - switch(event.button) { - case InputManager::MENU: - close = true; - break; - case InputManager::UP: - sel = std::max(0, sel - 1); - break; - case InputManager::DOWN: - sel = std::min((int)options.size() - 1, sel + 1); - break; - case InputManager::ACCEPT: - options[sel]->action(); - close = true; - break; - default: - break; - } - } +void GMenu2X::showContextMenu() { + layers.push_back(make_shared(*this, *menu)); } void GMenu2X::changeWallpaper() { diff --git a/src/gmenu2x.h b/src/gmenu2x.h index 83b0bfa..8d36428 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -21,6 +21,7 @@ #ifndef GMENU2X_H #define GMENU2X_H +#include "contextmenu.h" #include "surfacecollection.h" #include "translator.h" #include "touchscreen.h" @@ -90,10 +91,6 @@ private: #endif void browsePath(const std::string &path, std::vector* directories, std::vector* files); /*! - Starts the scanning of the nand and sd filesystems, searching for dge and gpu files and creating the links in 2 dedicated sections. - */ - void scanner(); - /*! Performs the actual scan in the given path and populates the files vector with the results. The creation of the links is not performed here. @see scanner */ @@ -119,8 +116,6 @@ private: void initFont(); void initMenu(); - void showManual(); - public: GMenu2X(); ~GMenu2X(); @@ -156,12 +151,18 @@ public: //Status functions void main(); + /** + * Starts the scanning of the nand and sd filesystems, searching for dge + * and gpu files and creating the links in 2 dedicated sections. + */ + void scanner(); + void showContextMenu(); void showHelpPopup(); + void showManual(); void showSettings(); void skinMenu(); void about(); void viewLog(); - void contextMenu(); void changeWallpaper(); #ifdef ENABLE_CPUFREQ diff --git a/src/menu.cpp b/src/menu.cpp index b372277..055d834 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -101,7 +101,7 @@ Menu::Menu(GMenu2X *gmenu2x, Touchscreen &ts) orderLinks(); btnContextMenu->setPosition(gmenu2x->resX - 38, gmenu2x->bottomBarIconY); - btnContextMenu->setAction(std::bind(&GMenu2X::contextMenu, gmenu2x)); + btnContextMenu->setAction(std::bind(&GMenu2X::showContextMenu, gmenu2x)); } Menu::~Menu() { @@ -306,7 +306,7 @@ bool Menu::handleButtonPress(InputManager::Button button) { incSectionIndex(); return true; case InputManager::MENU: - gmenu2x->contextMenu(); + gmenu2x->showContextMenu(); return true; default: return false;