mirror of
git://projects.qi-hardware.com/gmenu2x.git
synced 2024-11-18 01:26:14 +02:00
182 lines
4.6 KiB
C++
182 lines
4.6 KiB
C++
|
// 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 <algorithm>
|
||
|
|
||
|
|
||
|
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<MenuOption>(
|
||
|
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<MenuOption>(
|
||
|
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<MenuOption>(
|
||
|
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<MenuOption>(
|
||
|
tr.translate("Delete $1 link", app->getTitle().c_str(), NULL),
|
||
|
std::bind(&GMenu2X::deleteLink, &gmenu2x)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
options.push_back(std::make_shared<MenuOption>(
|
||
|
tr["Add section"],
|
||
|
std::bind(&GMenu2X::addSection, &gmenu2x)));
|
||
|
options.push_back(std::make_shared<MenuOption>(
|
||
|
tr["Rename section"],
|
||
|
std::bind(&GMenu2X::renameSection, &gmenu2x)));
|
||
|
options.push_back(std::make_shared<MenuOption>(
|
||
|
tr["Delete section"],
|
||
|
std::bind(&GMenu2X::deleteSection, &gmenu2x)));
|
||
|
options.push_back(std::make_shared<MenuOption>(
|
||
|
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<Sint16>((gmenu2x.resX - w) / 2),
|
||
|
static_cast<Sint16>((gmenu2x.resY - h) / 2),
|
||
|
static_cast<Uint16>(w),
|
||
|
static_cast<Uint16>(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<Sint16>(box.x + 4),
|
||
|
static_cast<Sint16>(box.y + 4 + (h + 2) * selected),
|
||
|
static_cast<Uint16>(box.w - 8),
|
||
|
static_cast<Uint16>(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<int>(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;
|
||
|
}
|